From 2dcdbb5a927e395653e00a7d5c2a104b77a0a6d9 Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 26 Feb 2015 12:07:51 +0900 Subject: [PATCH 0001/1783] Only set a font-size in the root No need to select `html` and `body` when trying to override it. Issue: #5735 --- static/bootstrap-overrides.less | 5 +++++ static/workspace-view.less | 7 +++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/static/bootstrap-overrides.less b/static/bootstrap-overrides.less index 1ac35ab79..258de6320 100644 --- a/static/bootstrap-overrides.less +++ b/static/bootstrap-overrides.less @@ -21,3 +21,8 @@ h5, h6 { font-family: inherit; // inherit from themes } + +body { + font-family: inherit; // inherit from html + font-size: inherit; // inherit from html +} diff --git a/static/workspace-view.less b/static/workspace-view.less index 9f988bf46..668a30777 100644 --- a/static/workspace-view.less +++ b/static/workspace-view.less @@ -3,13 +3,16 @@ @font-face { .octicon-font(); } +html { + font-family: @font-family; + font-size: @font-size; +} + html, body { width: 100%; height: 100%; overflow: hidden; - font-family: @font-family; - font-size: @font-size; } atom-workspace { From ad0669d814e01967997358319bbf16ebcb7158f6 Mon Sep 17 00:00:00 2001 From: Mostafa Eweda Date: Fri, 27 Feb 2015 15:49:18 -0800 Subject: [PATCH 0002/1783] Default directory provider should handle only local filesystem directories --- src/default-directory-provider.coffee | 5 ++++- src/project.coffee | 11 +++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/default-directory-provider.coffee b/src/default-directory-provider.coffee index 7ecdbd354..5ddc89cca 100644 --- a/src/default-directory-provider.coffee +++ b/src/default-directory-provider.coffee @@ -21,7 +21,10 @@ class DefaultDirectoryProvider else path.dirname(projectPath) - new Directory(directoryPath) + if fs.isDirectorySync(projectPath) + return new Directory(directoryPath) + else + return null # Public: Create a Directory that corresponds to the specified URI. # diff --git a/src/project.coffee b/src/project.coffee index c92462ead..946ae4c55 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -39,6 +39,7 @@ class Project extends Model @emitter = new Emitter @buffers ?= [] @rootDirectories = [] + @packageRootDirectoryPaths = [] @repositories = [] @directoryProviders = [new DefaultDirectoryProvider()] @@ -203,10 +204,12 @@ class Project extends Model for provider in @directoryProviders break if directory = provider.directoryForURISync?(projectPath) if directory is null - # This should never happen because DefaultDirectoryProvider should always - # return a Directory. - throw new Error(projectPath + ' could not be resolved to a directory') - @rootDirectories.push(directory) + # DefaultDirectoryProvider doesn't handle specific directory protocols + # Atom Packages may use packageDirectoryPaths to add thier own paths later. + @packageRootDirectoryPaths.push(projectPath) + return + else + @rootDirectories.push(directory) repo = null for provider in @repositoryProviders From ed8433cda45ab802fcb9b9ed30376f6645ce9325 Mon Sep 17 00:00:00 2001 From: Mostafa Eweda Date: Fri, 27 Feb 2015 17:47:40 -0800 Subject: [PATCH 0003/1783] nit: their --- src/project.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/project.coffee b/src/project.coffee index 946ae4c55..79cd7439b 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -205,7 +205,7 @@ class Project extends Model break if directory = provider.directoryForURISync?(projectPath) if directory is null # DefaultDirectoryProvider doesn't handle specific directory protocols - # Atom Packages may use packageDirectoryPaths to add thier own paths later. + # Atom Packages may use packageDirectoryPaths to add their own paths later. @packageRootDirectoryPaths.push(projectPath) return else From 71272f538d36c08195a94896f2913710486c3ea3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=C5=BDu=C5=BEak?= Date: Mon, 2 Mar 2015 14:27:43 +0100 Subject: [PATCH 0004/1783] :arrow_up: welcome@0.25.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dbcedb53a..4d807f29e 100644 --- a/package.json +++ b/package.json @@ -118,7 +118,7 @@ "timecop": "0.31.0", "tree-view": "0.164.0", "update-package-dependencies": "0.8.0", - "welcome": "0.24.0", + "welcome": "0.25.0", "whitespace": "0.29.0", "wrap-guide": "0.31.0", "language-c": "0.41.0", From c8f072b59cc5c9bafc07ea1f86df4ed1b7bd4222 Mon Sep 17 00:00:00 2001 From: Scott Chacon Date: Mon, 2 Mar 2015 14:57:14 +0100 Subject: [PATCH 0005/1783] remove docs that have moved to atom/docs, update README --- docs/README.md | 20 +- docs/advanced/configuration.md | 58 -- docs/advanced/keymaps.md | 171 ----- docs/advanced/node-modules.md | 24 - docs/advanced/scopes-and-scope-descriptors.md | 87 --- docs/advanced/serialization.md | 75 --- docs/converting-a-text-mate-bundle.md | 52 -- docs/converting-a-text-mate-theme.md | 68 -- docs/creating-a-package.md | 515 --------------- docs/creating-a-theme.md | 148 ----- docs/customizing-atom.md | 193 ------ docs/debugging.md | 133 ---- docs/getting-started.md | 109 --- docs/index.md | 30 - docs/publishing-a-package.md | 114 ---- docs/theme-variables.md | 116 ---- docs/upgrading/upgrading-your-package.md | 625 ------------------ docs/upgrading/upgrading-your-syntax-theme.md | 24 - docs/upgrading/upgrading-your-ui-theme.md | 137 ---- docs/writing-specs.md | 136 ---- docs/your-first-package.md | 158 ----- 21 files changed, 18 insertions(+), 2975 deletions(-) delete mode 100644 docs/advanced/configuration.md delete mode 100644 docs/advanced/keymaps.md delete mode 100644 docs/advanced/node-modules.md delete mode 100644 docs/advanced/scopes-and-scope-descriptors.md delete mode 100644 docs/advanced/serialization.md delete mode 100644 docs/converting-a-text-mate-bundle.md delete mode 100644 docs/converting-a-text-mate-theme.md delete mode 100644 docs/creating-a-package.md delete mode 100644 docs/creating-a-theme.md delete mode 100644 docs/customizing-atom.md delete mode 100644 docs/debugging.md delete mode 100644 docs/getting-started.md delete mode 100644 docs/index.md delete mode 100644 docs/publishing-a-package.md delete mode 100644 docs/theme-variables.md delete mode 100644 docs/upgrading/upgrading-your-package.md delete mode 100644 docs/upgrading/upgrading-your-syntax-theme.md delete mode 100644 docs/upgrading/upgrading-your-ui-theme.md delete mode 100644 docs/writing-specs.md delete mode 100644 docs/your-first-package.md diff --git a/docs/README.md b/docs/README.md index e8863f520..c66788d87 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,5 +1,21 @@ -# Welcome to the Atom Docs +# Atom Docs ![Atom](https://cloud.githubusercontent.com/assets/72919/2874231/3af1db48-d3dd-11e3-98dc-6066f8bc766f.png) -TODO: Write when docs move to a dedicated repo. +Most of the Atom user and developer documentation is contained in the [Atom Docs](https://github.com/atom/docs) repository. + +In this directory you can only find very specific build and API level documentation. Some of this may eventually move to the docs repository as well. + +## Build documentation + +Instructions for building Atom on various platforms from source. + +* [OS X](build-instructions/os-x.md) +* [Windows](build-instructions/windows.md) +* [Linux](build-instructions/linux.md) +* [FreeBSD](build-instructions/freebsd.md) + +## Other documentation here + +* [apm REST API](apm-rest-api.md) +* [Tips for contributing to packages](contributing-to-packages.md) diff --git a/docs/advanced/configuration.md b/docs/advanced/configuration.md deleted file mode 100644 index 82d821eb0..000000000 --- a/docs/advanced/configuration.md +++ /dev/null @@ -1,58 +0,0 @@ -## Configuration API - -### Reading Config Settings - -If you are writing a package that you want to make configurable, you'll need to -read config settings via the `atom.config` global. You can read the current -value of a namespaced config key with `atom.config.get`: - -```coffeescript -# read a value with `config.get` -@showInvisibles() if atom.config.get "editor.showInvisibles" -``` - -Or you can subscribe via `atom.config.observe` to track changes from any view -object. - -```coffeescript -{View} = require 'space-pen' - -class MyView extends View - attached: -> - @fontSizeObserveSubscription = - atom.config.observe 'editor.fontSize', (newValue, {previous}) => - @adjustFontSize() - - detached: -> - @fontSizeObserveSubscription.dispose() -``` - -The `atom.config.observe` method will call the given callback immediately with -the current value for the specified key path, and it will also call it in the -future whenever the value of that key path changes. If you only want to invoke -the callback when the next time the value changes, use `atom.config.onDidChange` -instead. - -Subscription methods return *disposable* subscription objects. Note in the -example above how we save the subscription to the `@fontSizeObserveSubscription` -instance variable and dispose of it when the view is detached. To group multiple -subscriptions together, you can add them all to a -[`CompositeDisposable`][composite-disposable] that you dispose when the view is -detached. - -### Writing Config Settings - -The `atom.config` database is populated on startup from `~/.atom/config.cson`, -but you can programmatically write to it with `atom.config.set`: - -```coffeescript -# basic key update -atom.config.set("core.showInvisibles", true) -``` - -If you're exposing package configuration via specific key paths, you'll want to -associate them with a schema in your package's main module. Read more about -schemas in the [config API docs][config-api]. - -[composite-disposable]: https://atom.io/docs/api/latest/CompositeDisposable -[config-api]: https://atom.io/docs/api/latest/Config diff --git a/docs/advanced/keymaps.md b/docs/advanced/keymaps.md deleted file mode 100644 index ee966a45d..000000000 --- a/docs/advanced/keymaps.md +++ /dev/null @@ -1,171 +0,0 @@ -# Keymaps In-Depth - -## Structure of a Keymap File - -Keymap files are encoded as JSON or CSON files containing nested hashes. They -work much like style sheets, but instead of applying style properties to elements -matching the selector, they specify the meaning of keystrokes on elements -matching the selector. Here is an example of some bindings that apply when -keystrokes pass through `atom-text-editor` elements: - -```coffee -'atom-text-editor': - 'cmd-delete': 'editor:delete-to-beginning-of-line' - 'alt-backspace': 'editor:delete-to-beginning-of-word' - 'ctrl-A': 'editor:select-to-first-character-of-line' - 'ctrl-shift-e': 'editor:select-to-end-of-line' - 'cmd-left': 'editor:move-to-first-character-of-line' - -'atom-text-editor:not([mini])': - 'cmd-alt-[': 'editor:fold-current-row' - 'cmd-alt-]': 'editor:unfold-current-row' -``` - -Beneath the first selector are several bindings, mapping specific *keystroke -patterns* to *commands*. When an element with the `atom-text-editor` class is focused and -`cmd-delete` is pressed, an custom DOM event called -`editor:delete-to-beginning-of-line` is emitted on the `atom-text-editor` element. - -The second selector group also targets editors, but only if they don't have the -`mini` attribute. In this example, the commands for code folding don't really -make sense on mini-editors, so the selector restricts them to regular editors. - -### Keystroke Patterns - -Keystroke patterns express one or more keystrokes combined with optional -modifier keys. For example: `ctrl-w v`, or `cmd-shift-up`. A keystroke is -composed of the following symbols, separated by a `-`. A multi-keystroke pattern -can be expressed as keystroke patterns separated by spaces. - - -| Type | Examples -| --------------------|---------------------------- -| Character literals | `a` `4` `$` -| Modifier keys | `cmd` `ctrl` `alt` `shift` -| Special keys | `enter` `escape` `backspace` `delete` `tab` `home` `end` `pageup` `pagedown` `left` `right` `up` `down` - -### Commands - -Commands are custom DOM events that are triggered when a keystroke matches a -binding. This allows user interface code to listen for named commands without -specifying the specific keybinding that triggers it. For example, the following -code creates a command to insert the current date in an editor: - -```coffee -atom.commands.add 'atom-text-editor', - 'user:insert-date': (event) -> - editor = @getModel() - editor.insertText(new Date().toLocaleString()) -``` - -`atom.commands` refers to the global {CommandRegistry} instance where all commands -are set and consequently picked up by the command palette. - -When you are looking to bind new keys, it is often useful to use the command -palette (`ctrl-shift-p`) to discover what commands are being listened for in a -given focus context. Commands are "humanized" following a simple algorithm, so a -command like `editor:fold-current-row` would appear as "Editor: Fold Current -Row". - -### "Composed" Commands - -A common question is, "How do I make a single keybinding execute two or more -commands?" There isn't any direct support for this in Atom, but it can be -achieved by creating a custom command that performs the multiple actions -you desire and then creating a keybinding for that command. For example, let's -say I want to create a "composed" command that performs a Select Line followed -by Cut. You could add the following to your `init.coffee`: - -```coffee -atom.commands.add 'atom-text-editor', 'custom:cut-line', -> - editor = atom.workspace.getActiveTextEditor() - editor.selectLinesContainingCursors() - editor.cutSelectedText() -``` - -Then let's say we want to map this custom command to `alt-ctrl-z`, you could -add the following to your keymap: - -```coffee -'atom-text-editor': - 'alt-ctrl-z': 'custom:cut-line' -``` - -### Specificity and Cascade Order - -As is the case with CSS applying styles, when multiple bindings match for a -single element, the conflict is resolved by choosing the most *specific* -selector. If two matching selectors have the same specificity, the binding -for the selector appearing later in the cascade takes precedence. - -Currently, there's no way to specify selector ordering within a single keymap, -because JSON objects do not preserve order. We eventually plan to introduce a -custom CSS-like file format for keymaps that allows for ordering within a single -file. For now, we've opted to handle cases where selector ordering is critical -by breaking the keymap into two separate files, such as `snippets-1.cson` and -`snippets-2.cson`. - -## Removing Bindings - -When the keymap system encounters a binding with the `unset!` directive as its -command, it will treat the current element as if it had no key bindings matching -the current keystroke sequence and continue searching from its parent. If you -want to remove a binding from a keymap you don't control, such as keymaps in -Atom core or in packages, use the `unset!` directive. - -For example, the following code removes the keybinding for `a` in the Tree View, -which is normally used to trigger the `tree-view:add-file` command: - -```coffee -'.tree-view': - 'a': 'unset!' -``` - -![](https://cloud.githubusercontent.com/assets/38924/3174771/e7f6ce64-ebf4-11e3-922d-f280bffb3fc5.png) - -## Forcing Chromium's Native Keystroke Handling - -If you want to force the native browser behavior for a given keystroke, use the -`native!` directive as the command of a binding. This can be useful to enable -the correct behavior in native input elements, for example. If you apply the -`.native-key-bindings` class to an element, all the keystrokes typically handled -by the browser will be assigned the `native!` directive. - -## Overloading Key Bindings - -Occasionally, it makes sense to layer multiple actions on top of the same key -binding. An example of this is the snippets package. Snippets are inserted by -typing a snippet prefix such as `for` and then pressing `tab`. Every time `tab` -is pressed, we want to execute code attempting to expand a snippet if one exists -for the text preceding the cursor. If a snippet *doesn't* exist, we want `tab` -to actually insert whitespace. - -To achieve this, the snippets package makes use of the `.abortKeyBinding()` -method on the event object representing the `snippets:expand` command. - -```coffee-script -# pseudo-code -editor.command 'snippets:expand', (e) => - if @cursorFollowsValidPrefix() - @expandSnippet() - else - e.abortKeyBinding() -``` - -When the event handler observes that the cursor does not follow a valid prefix, -it calls `e.abortKeyBinding()`, telling the keymap system to continue searching -for another matching binding. - -## Step-by-Step: How Keydown Events are Mapped to Commands - -* A keydown event occurs on a *focused* element. -* Starting at the focused element, the keymap walks upward towards the root of - the document, searching for the most specific CSS selector that matches the - current DOM element and also contains a keystroke pattern matching the keydown - event. -* When a matching keystroke pattern is found, the search is terminated and the - pattern's corresponding command is triggered on the current element. -* If `.abortKeyBinding()` is called on the triggered event object, the search - is resumed, triggering a binding on the next-most-specific CSS selector for - the same element or continuing upward to parent elements. -* If no bindings are found, the event is handled by Chromium normally. diff --git a/docs/advanced/node-modules.md b/docs/advanced/node-modules.md deleted file mode 100644 index 173713803..000000000 --- a/docs/advanced/node-modules.md +++ /dev/null @@ -1,24 +0,0 @@ -## Developing Node Modules - -Atom contains a number of packages that are Node modules instead of Atom packages. If you want to -make changes to the Node modules, for instance `atom-keymap`, you have to link them into the -development environment differently than you would a normal Atom package. - -### Linking a Node Module Into Your Atom Dev Environment - -Here are the steps to run a local version of a node module *not an apm* within Atom. We're using -`atom-keymap` as an example: - -```bash -$ git clone https://github.com/atom/atom-keymap.git -$ cd atom-keymap -$ npm install -$ npm link -$ apm rebuild # This is the special step, it makes the npm work with Atom's version of Node -$ cd WHERE-YOU-CLONED-ATOM -$ npm link atom-keymap -$ atom # Should work! -``` - -After this, you'll have to `npm install` and `apm rebuild` when you make a change to the node -module's code. diff --git a/docs/advanced/scopes-and-scope-descriptors.md b/docs/advanced/scopes-and-scope-descriptors.md deleted file mode 100644 index 7ee82995e..000000000 --- a/docs/advanced/scopes-and-scope-descriptors.md +++ /dev/null @@ -1,87 +0,0 @@ -# Scoped Settings, Scopes and Scope Descriptors - -Atom supports language-specific settings. You can soft wrap only Markdown files, or set the tab length to 4 in Python files. - -Language-specific settings are a subset of something more general we call "scoped settings". Scoped settings allow targeting down to a specific syntax token type. For example, you could conceivably set a setting to target only Ruby comments, only code inside Markdown files, or even only JavaScript function names. - -## Scope names in syntax tokens - -Each token in the editor has a collection of scope names. For example, the aformentioned JavaScript function name might have the scope names `function` and `name`. An open paren might have the scope names `punctuation`, `parameters`, `begin`. - -Scope names work just like CSS classes. In fact, in the editor, scope names are attached to a token's DOM node as CSS classes. - -Take this piece of JavaScript: - -```js -function functionName() { - console.log('Log it out'); -} -``` - -In the dev tools, the first line's markup looks like this. - -![screen shot 2014-10-14 at 11 21 35 am](https://cloud.githubusercontent.com/assets/69169/4634321/2b1b923c-53cf-11e4-9268-6e57bcb14ec8.png) - -All the class names on the spans are scope names. Any scope name can be used to target a setting's value. - -## Scope Selectors - -Scope selectors allow you to target specific tokens just like a CSS selector targets specific nodes in the DOM. Some examples: - -```coffee -'.source.js' # selects all javascript tokens -'.source.js .function.name' # selects all javascript function names -'.function.name' # selects all function names in any language -``` - -[Config::set][config-set] accepts a `scopeSelector`. If you'd like to set a setting for JavaScript function names, you can give it the js function name `scopeSelector`: - -```coffee -atom.config.set('.source.js .function.name', 'my-package.my-setting', 'special value') -``` - -## Scope Descriptors - -A scope descriptor is an [Object][scope-descriptor] that wraps an `Array` of -`String`s. The Array describes a path from the root of the syntax tree to a -token including _all_ scope names for the entire path. - -In our JavaScript example above, a scope descriptor for the function name token would be: - -```coffee -['source.js', 'meta.function.js', 'entity.name.function.js'] -``` - -[Config::get][config-get] accepts a `scopeDescriptor`. You can get the value for your setting scoped to JavaScript function names via: - -```coffee -scopeDescriptor = ['source.js', 'meta.function.js', 'entity.name.function.js'] -value = atom.config.get(scopeDescriptor, 'my-package.my-setting') -``` - -But, you do not need to generate scope descriptors by hand. There are a couple methods available to get the scope descriptor from the editor: - -* [Editor::getRootScopeDescriptor][editor-getRootScopeDescriptor] to get the language's descriptor. eg. `[".source.js"]` -* [Editor::scopeDescriptorForBufferPosition][editor-scopeDescriptorForBufferPosition] to get the descriptor at a specific position in the buffer. -* [Cursor::getScopeDescriptor][cursor-getScopeDescriptor] to get a cursor's descriptor based on position. eg. if the cursor were in the name of the method in our example it would return `["source.js", "meta.function.js", "entity.name.function.js"]` - -Let's revisit our example using these methods: - -```coffee -editor = atom.workspace.getActiveTextEditor() -cursor = editor.getLastCursor() -valueAtCursor = atom.config.get(cursor.getScopeDescriptor(), 'my-package.my-setting') -valueForLanguage = atom.config.get(editor.getRootScopeDescriptor(), 'my-package.my-setting') -``` - - -[config]:https://atom.io/docs/api/latest/Config -[config-get]:https://atom.io/docs/api/latest/Config#instance-get -[config-set]:https://atom.io/docs/api/latest/Config#instance-set -[config-observe]:https://atom.io/docs/api/latest/Config#instance-observe - -[editor-getRootScopeDescriptor]:https://atom.io/docs/api/latest/TextEditor#instance-getRootScopeDescriptor -[editor-scopeDescriptorForBufferPosition]:https://atom.io/docs/api/latest/TextEditor#instance-scopeDescriptorForBufferPosition - -[cursor-getScopeDescriptor]:https://atom.io/docs/api/latest/Cursor#instance-getScopeDescriptor -[scope-descriptor]:https://atom.io/docs/api/latest/ScopeDescriptor diff --git a/docs/advanced/serialization.md b/docs/advanced/serialization.md deleted file mode 100644 index c2a5f303a..000000000 --- a/docs/advanced/serialization.md +++ /dev/null @@ -1,75 +0,0 @@ -## Serialization in Atom - -When a window is refreshed or restored from a previous session, the view and its -associated objects are *deserialized* from a JSON representation that was stored -during the window's previous shutdown. For your own views and objects to be -compatible with refreshing, you'll need to make them play nicely with the -serializing and deserializing. - -### Package Serialization Hook - -Your package's main module can optionally include a `serialize` method, which -will be called before your package is deactivated. You should return JSON, which -will be handed back to you as an argument to `activate` next time it is called. -In the following example, the package keeps an instance of `MyObject` in the -same state across refreshes. - -```coffee-script -module.exports = - activate: (state) -> - @myObject = - if state - atom.deserializers.deserialize(state) - else - new MyObject("Hello") - - serialize: -> - @myObject.serialize() -``` - -### Serialization Methods - -```coffee-script -class MyObject - atom.deserializers.add(this) - - @deserialize: ({data}) -> new MyObject(data) - constructor: (@data) -> - serialize: -> { deserializer: 'MyObject', data: @data } -``` - -#### .serialize() -Objects that you want to serialize should implement `.serialize()`. This method -should return a serializable object, and it must contain a key named -`deserializer` whose value is the name of a registered deserializer that can -convert the rest of the data to an object. It's usually just the name of the -class itself. - -#### @deserialize(data) -The other side of the coin is the `deserialize` method, which is usually a -class-level method on the same class that implements `serialize`. This method's -job is to convert a state object returned from a previous call `serialize` back -into a genuine object. - -#### atom.deserializers.add(klass) -You need to call the `atom.deserializers.add` method with your class in -order to make it available to the deserialization system. Now you can call the -global `deserialize` method with state returned from `serialize`, and your -class's `deserialize` method will be selected automatically. - -### Versioning - -```coffee-script -class MyObject - atom.deserializers.add(this) - - @version: 2 - @deserialize: (state) -> ... - serialize: -> { version: @constructor.version, ... } -``` - -Your serializable class can optionally have a class-level `@version` property -and include a `version` key in its serialized state. When deserializing, Atom -will only attempt to call deserialize if the two versions match, and otherwise -return undefined. We plan on implementing a migration system in the future, but -this at least protects you from improperly deserializing old state. diff --git a/docs/converting-a-text-mate-bundle.md b/docs/converting-a-text-mate-bundle.md deleted file mode 100644 index 3471bc83b..000000000 --- a/docs/converting-a-text-mate-bundle.md +++ /dev/null @@ -1,52 +0,0 @@ -## Converting a TextMate Bundle - -This guide will show you how to convert a [TextMate][TextMate] bundle to an -Atom package. - -Converting a TextMate bundle will allow you to use its editor preferences, -snippets, and colorization inside Atom. - -### Install apm - -The `apm` command line utility that ships with Atom supports converting -a TextMate bundle to an Atom package. - -Check that you have `apm` installed by running the following command in your -terminal: - -```sh -apm help init -``` - -You should see a message print out with details about the `apm init` command. - -If you do not, launch Atom and run the _Atom > Install Shell Commands_ menu -to install the `apm` and `atom` commands. - -### Convert the Package - -Let's convert the TextMate bundle for the [R][R] programming language. You can find other existing TextMate bundles [here][TextMateOrg]. - -You can convert the R bundle with the following command: - -```sh -apm init --package ~/.atom/packages/language-r --convert https://github.com/textmate/r.tmbundle -``` - -You can now browse to `~/.atom/packages/language-r` to see the converted bundle. - -:tada: Your new package is now ready to use, launch Atom and open a `.r` file in -the editor to see it in action! - -### Further Reading - -* Check out [Publishing a Package](publishing-a-package.html) for more information - on publishing the package you just created to [atom.io][atomio]. - -[atomio]: https://atom.io -[CSS]: https://en.wikipedia.org/wiki/Cascading_Style_Sheets -[Less]: http://lesscss.org -[plist]: https://en.wikipedia.org/wiki/Property_list -[R]: https://en.wikipedia.org/wiki/R_(programming_language) -[TextMate]: http://macromates.com -[TextMateOrg]: https://github.com/textmate diff --git a/docs/converting-a-text-mate-theme.md b/docs/converting-a-text-mate-theme.md deleted file mode 100644 index 79dacd523..000000000 --- a/docs/converting-a-text-mate-theme.md +++ /dev/null @@ -1,68 +0,0 @@ -## Converting a TextMate Theme - -This guide will show you how to convert a [TextMate][TextMate] theme to an Atom -theme. - -### Differences - -TextMate themes use [plist][plist] files while Atom themes use [CSS][CSS] or -[Less][Less] to style the UI and syntax in the editor. - -The utility that converts the theme first parses the theme's plist file and -then creates comparable CSS rules and properties that will style Atom similarly. - -### Install apm - -The `apm` command line utility that ships with Atom supports converting -a TextMate theme to an Atom theme. - -Check that you have `apm` installed by running the following command in your -terminal: - -```sh -apm help init -``` - -You should see a message print out with details about the `apm init` command. - -If you do not, launch Atom and run the _Atom > Install Shell Commands_ menu -to install the `apm` and `atom` commands. - -You can now run `apm help init` to see all the options for initializing new -packages and themes. - -### Convert the Theme - -Download the theme you wish to convert, you can browse existing TextMate themes -[here][TextMateThemes]. - -Now, let's say you've downloaded the theme to `~/Downloads/MyTheme.tmTheme`, -you can convert the theme with the following command: - -```sh -apm init --theme ~/.atom/packages/my-theme --convert ~/Downloads/MyTheme.tmTheme -``` - -You can browse to `~/.atom/packages/my-theme` to see the converted theme. - -### Activate the Theme - -Now that your theme is installed to `~/.atom/packages` you can enable it -by launching Atom and selecting the _Atom > Preferences..._ menu. - -Select the _Themes_ link on the left side and choose _My Theme_ from the -__Syntax Theme__ dropdown menu to enable your new theme. - -:tada: Your theme is now enabled, open an editor to see it in action! - -### Further Reading - -* Check out [Publishing a Package](publishing-a-package.html) for more information - on publishing the theme you just created to [atom.io][atomio]. - -[atomio]: https://atom.io -[CSS]: https://en.wikipedia.org/wiki/Cascading_Style_Sheets -[Less]: http://lesscss.org -[plist]: https://en.wikipedia.org/wiki/Property_list -[TextMate]: http://macromates.com -[TextMateThemes]: http://wiki.macromates.com/Themes/UserSubmittedThemes diff --git a/docs/creating-a-package.md b/docs/creating-a-package.md deleted file mode 100644 index d00f6ecc1..000000000 --- a/docs/creating-a-package.md +++ /dev/null @@ -1,515 +0,0 @@ -# Creating Packages - -Packages are at the core of Atom. Nearly everything outside of the main editor -is handled by a package. That includes "core" pieces like the [file tree][file-tree], -[status bar][status-bar], [syntax highlighting][cs-syntax], and more. - -A package can contain a variety of different resource types to change Atom's -behavior. The basic package layout is as follows: - -```text -my-package/ - grammars/ - keymaps/ - lib/ - menus/ - spec/ - snippets/ - styles/ - index.coffee - package.json -``` - -Not every package will have (or need) all of these directories. - -We have [a tutorial on creating your first package][first-package]. - -There are also guides for converting [TextMate bundles][convert-bundle] and -[TextMate themes][convert-theme] so they work in Atom. - -## package.json - -Similar to [npm packages][npm], Atom packages contain a _package.json_ file -in their top-level directory. This file contains metadata about the package, -such as the path to its "main" module, library dependencies, and manifests -specifying the order in which its resources should be loaded. - -In addition to the regular [npm package.json keys][npm-keys] available, Atom -package.json files have their own additions. - -- `main` (**Required**): the path to the CoffeeScript file that's the entry point -to your package. -- `styles` (**Optional**): an Array of Strings identifying the order of the -style sheets your package needs to load. If not specified, style sheets in the -_styles_ directory are added alphabetically. -- `keymaps`(**Optional**): an Array of Strings identifying the order of the -key mappings your package needs to load. If not specified, mappings in the -_keymaps_ directory are added alphabetically. -- `menus`(**Optional**): an Array of Strings identifying the order of -the menu mappings your package needs to load. If not specified, mappings -in the _menus_ directory are added alphabetically. -- `snippets` (**Optional**): an Array of Strings identifying the order of the -snippets your package needs to load. If not specified, snippets in the -_snippets_ directory are added alphabetically. -- `activationCommands` (**Optional**): an Array of Strings identifying commands that -trigger your package's activation. You can delay the loading of your package -until one of these events is triggered. -- `providedServices` (**Optional**): an Object describing the services that your -package provides, which can be used by other packages. The keys of this object -are the names of the services, and the values are Objects with the following -keys: - - `description` (**Optional**) a String describing the service - - `versions` (**Required**) an Object whose keys are Semver version strings, - and whose values are names of methods in your package's top-level module - that return a value implementing the service. -- `consumedServices` (**Optional**): an Object describing the services that your -package uses, which can be provided by other packages. The keys of this object -are the names of the services, and the values are Objects with the following -keys: - - `versions` (**Required**) an Object whose keys are Semver version ranges - and whose values are names of methods in your package's top-level module - that are called with values implementing the service. - -## Source Code - -If you want to extend Atom's behavior, your package should contain a single -top-level module, which you export from _index.coffee_ (or whichever file is -indicated by the `main` key in your _package.json_ file). The remainder of your -code should be placed in the `lib` directory, and required from your top-level -file. - -Your package's top-level module is a singleton object that manages the lifecycle -of your extensions to Atom. Even if your package creates ten different views and -appends them to different parts of the DOM, it's all managed from your top-level -object. - -Your package's top-level module should implement the following methods: - -- `activate(state)`: This **required** method is called when your -package is activated. It is passed the state data from the last time the window -was serialized if your module implements the `serialize()` method. Use this to -do initialization work when your package is started (like setting up DOM -elements or binding events). - -- `serialize()`: This **optional** method is called when the window is shutting -down, allowing you to return JSON to represent the state of your component. When -the window is later restored, the data you returned is passed to your -module's `activate` method so you can restore your view to where the user left -off. - -- `deactivate()`: This **optional** method is called when the window is shutting -down, or when your package is being updated or disabled. If your package is -watching any files, holding external resources, providing commands or subscribing -to events, release them here. - -### Simple Package Code - -Your directory would look like this: - -```text -my-package/ - package.json - index.coffee - lib/ - my-package.coffee -``` - -`index.coffee` might be: -```coffeescript -module.exports = require "./lib/my-package" -``` - -`my-package/my-package.coffee` might start: -```coffeescript -module.exports = - activate: (state) -> # ... - deactivate: -> # ... - serialize: -> # ... -``` - -Beyond this simple contract, your package has access to [Atom's API][api]. Be aware -that the Atom 1.0 API is mostly frozen. Refer to the API documentation for what -is public. That said, please collaborate with us if you need an API that doesn't -exist. Our goal is to build out Atom's API organically based on the needs of -package authors like you. - -## Style Sheets - -Style sheets for your package should be placed in the _styles_ directory. -Any style sheets in this directory will be loaded and attached to the DOM when -your package is activated. Style sheets can be written as CSS or [Less], but -Less is recommended. - -Ideally, you won't need much in the way of styling. We've provided a standard -set of components which define both the colors and UI elements for any package -that fits into Atom seamlessly. You can view all of Atom's UI components by -opening the styleguide: open the command palette (`cmd-shift-P`) and search for -_styleguide_, or just type `cmd-ctrl-shift-G`. - -If you _do_ need special styling, try to keep only structural styles in the -package style sheets. If you _must_ specify colors and sizing, these should be -taken from the active theme's [ui-variables.less][ui-variables]. For more -information, see the [theme variables docs][theme-variables]. If you follow this -guideline, your package will look good out of the box with any theme! - -An optional `styleSheets` array in your _package.json_ can list the style sheets -by name to specify a loading order; otherwise, style sheets are loaded -alphabetically. - -## Keymaps - -It's recommended that you provide key bindings for commonly used actions for -your extension, especially if you're also adding a new command: - -```coffeescript -'.tree-view-scroller': - 'ctrl-V': 'changer:magic' -``` - -Keymaps are placed in the _keymaps_ subdirectory. By default, all keymaps are -loaded in alphabetical order. An optional `keymaps` array in your _package.json_ -can specify which keymaps to load and in what order. - - -Keybindings are executed by determining which element the keypress occurred on. -In the example above, `changer:magic` command is executed when pressing `ctrl-V` -on the `.tree-view-scroller` element. - -See the [main keymaps documentation][keymaps] for more detailed information on -how keymaps work. - -## Menus - -Menus are placed in the _menus_ subdirectory. By default, all menus are loaded -in alphabetical order. An optional `menus` array in your _package.json_ can -specify which menus to load and in what order. - -### Application Menu - -It's recommended that you create an application menu item for common actions -with your package that aren't tied to a specific element: - -```coffeescript -'menu': [ - { - 'label': 'Packages' - 'submenu': [ - { - 'label': 'My Package' - 'submenu': [ - { - 'label': 'Toggle' - 'command': 'my-package:toggle' - } - ] - } - ] - } -] -``` - -To add your own item to the application menu, simply create a top level `menu` -key in any menu configuration file in _menus_. This can be a JSON or [CSON] -file. - -The menu templates you specify are merged with all other templates provided -by other packages in the order which they were loaded. - -### Context Menu - -It's recommended to specify a context menu item for commands that are linked to -specific parts of the interface, like adding a file in the tree-view: - -```coffeescript -'context-menu': - '.tree-view': [ - {label: 'Add file', command: 'tree-view:add-file'} - ] - 'atom-workspace': [ - {label: 'Inspect Element', command: 'core:inspect'} - ] -``` - -To add your own item to the application menu simply create a top level -`context-menu` key in any menu configuration file in _menus_. This can be a -JSON or [CSON] file. - -Context menus are created by determining which element was selected and then -adding all of the menu items whose selectors match that element (in the order -which they were loaded). The process is then repeated for the elements until -reaching the top of the DOM tree. - -In the example above, the `Add file` item will only appear when the focused item -or one of its parents has the `tree-view` class applied to it. - -You can also add separators and submenus to your context menus. To add a -submenu, provide a `submenu` key instead of a command. To add a separator, add -an item with a single `type: 'separator'` key/value pair. - -```coffeescript -'context-menu': - 'atom-workspace': [ - { - label: 'Text' - submenu: [ - {label: 'Inspect Element', command: 'core:inspect'} - {type: 'separator'} - {label: 'Selector All', command: 'core:select-all'} - {type: 'separator'} - {label: 'Deleted Selected Text', command: 'core:delete'} - ] - } - ] -``` - -## Snippets - -An extension can supply language snippets in the _snippets_ directory which -allows the user to enter repetitive text quickly: - -```coffeescript -".source.coffee .specs": - "Expect": - prefix: "ex" - body: "expect($1).to$2" - "Describe": - prefix: "de" - body: """ - describe "${1:description}", -> - ${2:body} - """ -``` - -A snippets file contains scope selectors at its top level (`.source.coffee -.spec`). Each scope selector contains a hash of snippets keyed by their name -(`Expect`, `Describe`). Each snippet also specifies a `prefix` and a `body` key. -The `prefix` represents the first few letters to type before hitting the `tab` -key to autocomplete. The `body` defines the autofilled text. You can use -placeholders like `$1`, `$2`, to indicate regions in the body the user can -navigate to every time they hit `tab`. - -All files in the directory are automatically loaded, unless the _package.json_ -supplies a `snippets` key. As with all scoped items, snippets loaded later take -precedence over earlier snippets when two snippets match a scope with the same -specificity. - -## Language Grammars - -If you're developing a new language grammar, you'll want to place your file in -the _grammars_ directory. Each grammar is a pairing of two keys, `match` and -`captures`. `match` is a regular expression identifying the pattern to -highlight, while `captures` is an object representing what to do with each -matching group. - -For example: - - -```coffeescript -{ - 'match': '(?:^|\\s)(__[^_]+__)' - 'captures': - '1': 'name': 'markup.bold.gfm' -} -``` - -This indicates that the first matching capture (`(__[^_]+__)`) should have the -`markup.bold.gfm` token applied to it. - -To capture a single group, simply use the `name` key instead: - -```coffeescript -{ - 'match': '^#{1,6}\\s+.+$' - 'name': 'markup.heading.gfm' -} -``` - -This indicates that Markdown header lines (`#`, `##`, `###`) should be applied -with the `markup.heading.gfm` token. - -More information about the significance of these tokens can be found in -[section 12.4 of the TextMate Manual][tm-tokens]. - -Your grammar should also include a `filetypes` array, which is a list of file -extensions your grammar supports: - -```coffeescript -'fileTypes': [ - 'markdown' - 'md' - 'mkd' - 'mkdown' - 'ron' -] -``` - -## Adding Configuration Settings - -You can support config settings in your package that are editable in the -settings view. Specify a `config` key in your package main: - -```coffeescript -module.exports = - # Your config schema! - config: - someInt: - type: 'integer' - default: 23 - minimum: 1 - activate: (state) -> # ... - # ... -``` - -To define the configuration, we use [json schema][json-schema] which allows you -to indicate the type your value should be, its default, etc. - -See the [Config API Docs](https://atom.io/docs/api/latest/Config) for more -details specifying your configuration. - -## Interacting With Other Packages Via Services - -Atom packages can interact with each other through versioned APIs called -*services*. To provide a service, in your `package.json`, specify one or more -version numbers, each paired with the name of a method on your package's main module: - -```json -{ - "providedServices": { - "my-service": { - "description": "Does a useful thing", - "versions": { - "1.2.3": "provideMyServiceV1", - "2.3.4": "provideMyServiceV2", - } - } - } -} -``` - -In your package's main module, implement the methods named above. These methods -will be called any time a package is activated that consumes their corresponding -service. They should return a value that implements the service's API. - - -```coffeescript -module.exports = - activate: -> # ... - - provideMyServiceV1: -> - adaptToLegacyAPI(myService) - - provideMyServiceV2: -> - myService -``` - -Similarly, to consume a service, specify one or more [version *ranges*][version-ranges], -each paired with the name of a method on the package's main module: - -```json -{ - "consumedServices": { - "another-service": { - "versions": { - "^1.2.3": "consumeAnotherServiceV1", - ">=2.3.4 <2.5": "consumeAnotherServiceV2", - } - } - } -} -``` - -These methods will be called any time a package is activated that *provides* their -corresponding service. They will receive the service object as an argument. You -will usually need to perform some kind of cleanup in the event that the package -providing the service is deactivated. To do this, return a `Disposable` from -your service-consuming method: - -```coffeescript -{Disposable} = require 'atom' - -module.exports = - activate: -> # ... - - consumeAnotherServiceV1: (service) -> - useService(adaptServiceFromLegacyAPI(service)) - new Disposable -> stopUsingService(service) - - consumeAnotherServiceV2: (service) -> - useService(service) - new Disposable -> stopUsingService(service) -``` - -## Bundle External Resources - -It's common to ship external resources like images and fonts in the package, to -make it easy to reference the resources in HTML or CSS, you can use the `atom` -protocol URLs to load resources in the package. - -The URLs should be in the format of -`atom://package-name/relative-path-to-package-of-resource`, for example, the -`atom://image-view/images/transparent-background.gif` would be equivalent to -`~/.atom/packages/image-view/images/transparent-background.gif`. - -You can also use the `atom` protocol URLs in themes. - -## Writing Tests - -Your package **should** have tests, and if they're placed in the _spec_ -directory, they can be run by Atom. - -Under the hood, [Jasmine] executes your tests, so you can assume that any DSL -available there is also available to your package. - -## Running Tests - -Once you've got your test suite written, you can run it by pressing -`cmd-alt-ctrl-p` or via the _Developer > Run Package Specs_ menu. - -You can also use the `apm test` command to run them from the command line. It -prints the test output and results to the console and returns the proper status -code depending on whether the tests passed or failed. - -## Publishing - -Atom bundles a command line utility called apm which can be used to publish -Atom packages to the public registry. - -Once your package is written and ready for distribution you can run the -following to publish your package: - -```sh -cd my-package -apm publish minor -``` - -This will update your `package.json` to have a new minor `version`, commit the -change, create a new [Git tag][git-tag], and then upload the package to the -registry. - -Run `apm help publish` to see all the available options and `apm help` to see -all the other available commands. - -[api]: https://atom.io/docs/api/latest -[file-tree]: https://github.com/atom/tree-view -[status-bar]: https://github.com/atom/status-bar -[cs-syntax]: https://github.com/atom/language-coffee-script -[npm]: https://en.wikipedia.org/wiki/Npm_(software) -[npm-keys]: https://docs.npmjs.com/files/package.json -[git-tag]: http://git-scm.com/book/en/Git-Basics-Tagging -[wrap-guide]: https://github.com/atom/wrap-guide/ -[keymaps]: advanced/keymaps.md -[theme-variables]: theme-variables.md -[tm-tokens]: http://manual.macromates.com/en/language_grammars.html -[spacepen]: https://github.com/nathansobo/space-pen -[path]: http://nodejs.org/docs/latest/api/path.html -[jquery]: http://jquery.com/ -[underscore]: http://underscorejs.org/ -[jasmine]: http://jasmine.github.io -[cson]: https://github.com/atom/season -[Less]: http://lesscss.org -[ui-variables]: https://github.com/atom/atom-dark-ui/blob/master/styles/ui-variables.less -[first-package]: your-first-package.html -[convert-bundle]: converting-a-text-mate-bundle.html -[convert-theme]: converting-a-text-mate-theme.html -[json-schema]: http://json-schema.org/ -[version-ranges]: https://docs.npmjs.com/misc/semver#ranges diff --git a/docs/creating-a-theme.md b/docs/creating-a-theme.md deleted file mode 100644 index 6e8ab1dc4..000000000 --- a/docs/creating-a-theme.md +++ /dev/null @@ -1,148 +0,0 @@ -# Creating a Theme - -Atom's interface is rendered using HTML, and it's styled via [Less] which is a -superset of CSS. Don't worry if you haven't heard of Less before; it's just like -CSS, but with a few handy extensions. - -Atom supports two types of themes: _UI_ and _syntax_. UI themes style -elements such as the tree view, the tabs, drop-down lists, and the status bar. -Syntax themes style the code inside the editor. - -Themes can be installed and changed from the settings view which you can open -by selecting the _Atom > Preferences..._ menu and navigating to the _Install_ -section and the _Themes_ section on the left hand side. - -## Getting Started - -Themes are pretty straightforward but it's still helpful to be familiar with -a few things before starting: - -* Less is a superset of CSS, but it has some really handy features like - variables. If you aren't familiar with its syntax, take a few minutes - to [familiarize yourself][less-tutorial]. -* You may also want to review the concept of a _[package.json]_, too. This file - is used to help distribute your theme to Atom users. -* Your theme's _package.json_ must contain a `"theme"` key with a value - of `"ui"` or `"syntax"` for Atom to recognize and load it as a theme. -* You can find existing themes to install or fork on - [atom.io][atomio-themes]. - -## Creating a Syntax Theme - -Let's create your first theme. - -To get started, hit `cmd-shift-P`, and start typing "Generate Syntax Theme" to -generate a new theme package. Select "Generate Syntax Theme," and you'll be -asked for the path where your theme will be created. Let's call ours -_motif-syntax_. __Tip:__ syntax themes should end with _-syntax_. - -Atom will pop open a new window, showing the _motif-syntax_ theme, with a -default set of folders and files created for us. If you open the settings view -(`cmd-,`) and navigate to the _Themes_ section on the left, you'll see the -_Motif_ theme listed in the _Syntax Theme_ drop-down. Select it from the menu to -activate it, now when you open an editor you should see that your new -_motif-syntax_ theme in action. - -Open up _styles/colors.less_ to change the various colors variables which -have been already been defined. For example, turn `@red` into `#f4c2c1`. - -Then open _styles/base.less_ and modify the various selectors that have -been already been defined. These selectors style different parts of code in the -editor such as comments, strings and the line numbers in the gutter. - -As an example, let's make the `.gutter` `background-color` into `@red`. - -Reload Atom by pressing `cmd-alt-ctrl-l` to see the changes you made reflected -in your Atom window. Pretty neat! - -__Tip:__ You can avoid reloading to see changes you make by opening an atom -window in dev mode. To open a Dev Mode Atom window run `atom --dev .` in the -terminal, use `cmd-shift-o` or use the _View > Developer > Open in Dev Mode_ -menu. When you edit your theme, changes will instantly be reflected! - -> Note: It's advised to _not_ specify a `font-family` in your syntax theme because it will override the Font Family field in Atom's settings. If you still like to recommend a font that goes well with your theme, we recommend you do so in your README. - -## Creating an Interface Theme - -Interface themes **must** provide a `ui-variables.less` file which contains all -of the variables provided by the [core themes][ui-variables]. - -To create an interface UI theme, do the following: - -1. Fork one of the following repositories: - * [atom-dark-ui] - * [atom-light-ui] -2. Clone the forked repository to the local filesystem -3. Open a terminal in the forked theme's directory -4. Open your new theme in a Dev Mode Atom window run `atom --dev .` in the - terminal or use the _View > Developer > Open in Dev Mode_ menu -5. Change the name of the theme in the theme's `package.json` file -6. Name your theme end with a `-ui`. i.e. `super-white-ui` -7. Run `apm link` to symlink your repository to `~/.atom/packages` -8. Reload Atom using `cmd-alt-ctrl-L` -9. Enable the theme via _UI Theme_ drop-down in the _Themes_ section of the - settings view -10. Make changes! Since you opened the theme in a Dev Mode window, changes will - be instantly reflected in the editor without having to reload. - -## Development workflow - -There are a few of tools to help make theme development faster and easier. - -### Live Reload - -Reloading by hitting `cmd-alt-ctrl-L` after you make changes to your theme is -less than ideal. Atom supports [live updating][livereload] of styles on Dev Mode -Atom windows. - -To enable a Dev Mode window: - -1. Open your theme directory in a dev window by either going to the - __View > Developer > Open in Dev Mode__ menu or by hitting the `cmd-shift-o` - shortcut -2. Make a change to your theme file and save it. Your change should be - immediately applied! - -If you'd like to reload all the styles at any time, you can use the shortcut -`cmd-ctrl-shift-r`. - -### Developer Tools - -Atom is based on the Chrome browser, and supports Chrome's Developer Tools. You -can open them by selecting the _View > Toggle Developer Tools_ menu, or by -using the `cmd-alt-i` shortcut. - -The dev tools allow you to inspect elements and take a look at their CSS -properties. - -![devtools-img] - -Check out Google's [extensive tutorial][devtools-tutorial] for a short -introduction. - -### Atom Styleguide - -If you are creating an interface theme, you'll want a way to see how your theme -changes affect all the components in the system. The [styleguide] is a page that -renders every component Atom supports. - -To open the styleguide, open the command palette (`cmd-shift-P`) and search for -_styleguide_, or use the shortcut `cmd-ctrl-shift-g`. - -![styleguide-img] - -[atomio-themes]: https://atom.io/themes -[Less]: http://lesscss.org/ -[git]: http://git-scm.com/ -[atom]: https://atom.io/ -[package.json]: ./creating-a-package.html#package-json -[less-tutorial]: https://speakerdeck.com/danmatthews/less-css -[devtools-tutorial]: https://developer.chrome.com/devtools/docs/dom-and-styles -[ui-variables]: ./theme-variables.html -[livereload]: https://github.com/atom/dev-live-reload -[styleguide]: https://github.com/atom/styleguide -[atom-dark-ui]: https://github.com/atom/atom-dark-ui -[atom-light-ui]: https://github.com/atom/atom-light-ui -[styleguide-img]: https://f.cloud.github.com/assets/69169/1347390/2d431d98-36af-11e3-8f8e-3f4ce1e67adb.png -[devtools-img]: https://f.cloud.github.com/assets/69169/1347391/2d51f91c-36af-11e3-806f-f7b334af43e9.png -[themesettings-img]: https://f.cloud.github.com/assets/69169/1347569/3150bd0c-36b2-11e3-9d69-423503acfe3f.png diff --git a/docs/customizing-atom.md b/docs/customizing-atom.md deleted file mode 100644 index d56bd640a..000000000 --- a/docs/customizing-atom.md +++ /dev/null @@ -1,193 +0,0 @@ -# Customizing Atom - -To change a setting, configure a theme, or install a package just open the -Settings view in the current window by pressing `cmd-,`. - -## Changing The Theme - -Atom comes with both light and dark UI themes as well as several syntax themes. -You are also encouraged to [create or fork][create-theme] your own theme. - -To change the active theme just open the Settings view (`cmd-,`) and select the -`Themes` section from the left hand side. You will see a drop-down menu to -change the active _Syntax_ and _UI_ themes. - -You can also install more themes from here by browsing the featured themes or -searching for a specific theme. - -## Installing Packages - -You can install non-bundled packages by going to the `Packages` section on left -hand side of the Settings view (`cmd-,`). You will see several featured packages -and you can also search for packages from here. The packages listed here have -been published to [atom.io](http://atom.io/packages) which is the official -registry for Atom packages. - -You can also install packages from the command line using `apm`. - -Check that you have `apm` installed by running the following command in your -terminal: - -```sh -apm help install -``` - -You should see a message print out with details about the `apm install` command. - -If you do not, launch Atom and run the _Atom > Install Shell Commands_ menu -to install the `apm` and `atom` commands. - -You can also install packages by using the `apm install` command: - -* `apm install ` to install the latest version. - -* `apm install @` to install a specific version. - -For example `apm install emmet@0.1.5` installs the `0.1.5` release of the -[Emmet](https://github.com/atom/emmet) package into `~/.atom/packages`. - -You can also use `apm` to find new packages to install: - -* `apm search coffee` to search for CoffeeScript packages. - -* `apm view emmet` to see more information about a specific package. - -## Customizing Key Bindings - -Atom keymaps work similarly to style sheets. Just as style sheets use selectors -to apply styles to elements, Atom keymaps use selectors to associate keystrokes -with events in specific contexts. Here's a small example, excerpted from Atom's -built-in keymaps: - -```coffee -'atom-text-editor': - 'enter': 'editor:newline' - -'atom-text-editor[mini] input': - 'enter': 'core:confirm' -``` - -This keymap defines the meaning of `enter` in two different contexts. In a -normal editor, pressing `enter` emits the `editor:newline` event, which causes -the editor to insert a newline. But if the same keystroke occurs inside of a -select list's mini-editor, it instead emits the `core:confirm` event based on -the binding in the more-specific selector. - -By default, `~/.atom/keymap.cson` is loaded when Atom is started. It will always -be loaded last, giving you the chance to override bindings that are defined by -Atom's core keymaps or third-party packages. - -You can open this file in an editor from the _Atom > Open Your Keymap_ menu. - -You'll want to know all the commands available to you. Open the Settings panel -(`cmd-,`) and select the _Keybindings_ tab. It will show you all the keybindings -currently in use. - -## Advanced Configuration - -Atom loads configuration settings from the `config.cson` file in your _~/.atom_ -directory, which contains [CoffeeScript-style JSON][CSON] (CSON): - -```coffee -'core': - 'excludeVcsIgnoredPaths': true -'editor': - 'fontSize': 18 -``` - -The configuration itself is grouped by the package name or one of the two core -namespaces: `core` and `editor`. - -You can open this file in an editor from the _Atom > Open Your Config_ menu. - -### Custom Configuration Location - -You can override the location that Atom stores configuration files and folders -in by setting the `ATOM_HOME` environment variable. The `ATOM_HOME` path will be -used instead of `~/.atom` when it is set. - -This option can be useful when you want to make Atom portable across machines. - -### Configuration Key Reference - -- `core` - - `disabledPackages`: An array of package names to disable - - `excludeVcsIgnoredPaths`: Don't search within files specified by _.gitignore_ - - `followSymlinks`: Follow symlinks when searching and scanning root directory - - `ignoredNames`: File names to ignore across all of Atom - - `projectHome`: The directory where projects are assumed to be located - - `themes`: An array of theme names to load, in cascading order -- `editor` - - `autoIndent`: Enable/disable basic auto-indent (defaults to `true`) - - `nonWordCharacters`: A string of non-word characters to define word boundaries - - `fontSize`: The editor font size - - `fontFamily`: The editor font family - - `invisibles`: Specify characters that Atom renders for invisibles in this hash - - `tab`: Hard tab characters - - `cr`: Carriage return (for Microsoft-style line endings) - - `eol`: `\n` characters - - `space`: Leading and trailing space characters - - `preferredLineLength`: Identifies the length of a line (defaults to `80`) - - `showInvisibles`: Whether to render placeholders for invisible characters (defaults to `false`) - - `showIndentGuide`: Show/hide indent indicators within the editor - - `showLineNumbers`: Show/hide line numbers within the gutter - - `softWrap`: Enable/disable soft wrapping of text within the editor - - `softWrapAtPreferredLineLength`: Enable/disable soft line wrapping at `preferredLineLength` - - `tabLength`: Number of spaces within a tab (defaults to `2`) -- `fuzzyFinder` - - `ignoredNames`: Files to ignore *only* in the fuzzy-finder -- `whitespace` - - `ensureSingleTrailingNewline`: Whether to reduce multiple newlines to one at the end of files - - `removeTrailingWhitespace`: Enable/disable striping of whitespace at the end of lines (defaults to `true`) -- `wrap-guide` - - `columns`: Array of hashes with a `pattern` and `column` key to match the - the path of the current editor to a column position. - -### Quick Personal Hacks - -### init.coffee - -When Atom finishes loading, it will evaluate _init.coffee_ in your _~/.atom_ -directory, giving you a chance to run arbitrary personal [CoffeeScript][] code to -make customizations. You have full access to Atom's API from code in this file. -If customizations become extensive, consider [creating a package][creating-a-package]. - -You can open this file in an editor from the _Atom > Open Your Init Script_ -menu. - -For example, if you have the Audio Beep configuration setting enabled, you -could add the following code to your _~/.atom/init.coffee_ file to have Atom -greet you with an audio beep every time it loads: - -```coffee -atom.beep() -``` - -This file can also be named _init.js_ and contain JavaScript code. - -### styles.less - -If you want to apply quick-and-dirty personal styling changes without creating -an entire theme that you intend to publish, you can add styles to the -_styles.less_ file in your _~/.atom_ directory. - -You can open this file in an editor from the _Atom > Open Your Stylesheet_ menu. - -For example, to change the color of the cursor, you could add the following -rule to your _~/.atom/styles.less_ file: - -```less -atom-text-editor::shadow .cursor { - border-color: pink; -} -``` - -Unfamiliar with Less? Read more about it [here][Less]. - -This file can also be named _styles.css_ and contain CSS. - -[creating-a-package]: creating-a-package.md -[create-theme]: creating-a-theme.md -[Less]: http://www.lesscss.org -[CSON]: https://github.com/atom/season -[CoffeeScript]: http://coffeescript.org/ diff --git a/docs/debugging.md b/docs/debugging.md deleted file mode 100644 index ec202e7f8..000000000 --- a/docs/debugging.md +++ /dev/null @@ -1,133 +0,0 @@ -# Debugging - -Atom provides several tools to help you understand unexpected behavior and debug problems. This guide describes some of those tools and a few approaches to help you debug and provide more helpful information when [submitting issues]: - -* [Update to the latest version](#update-to-the-latest-version) -* [Check for linked packages](#check-for-linked-packages) -* [Check Atom and package settings](#check-atom-and-package-settings) -* [Check the keybindings](#check-the-keybindings) -* [Check if the problem shows up in safe mode](#check-if-the-problem-shows-up-in-safe-mode) -* [Check your config files](#check-your-config-files) -* [Check for errors in the developer tools](#check-for-errors-in-the-developer-tools) - -## Update to the latest version - -You might be running into an issue which was already fixed in a more recent version of Atom than the one you're using. - -If you're building Atom from source, pull down the latest version of master and [re-build][building atom]. - -If you're using released version, check which version of Atom you're using: - -```shell -$ atom --version -0.99.0 -``` - -Head on over to the [list of releases][atom releases] and see if there's a more recent release. You can update to the most recent release by downloading Atom from the releases page, or with the in-app auto-updater. The in-app auto-updater checks for and downloads a new version after you restart Atom, or if you use the Atom > Check for Update menu option. - -## Check for linked packages - -If you develop or contribute to Atom packages, there may be left-over packages linked to your `~/.atom/packages` or `~/.atom/dev/packages` directories. You can use: - -```shell -$ apm links -``` - -to list all linked development packages. You can remove the links using the `apm unlink` command. See `apm unlink --help` for details. - -## Check Atom and package settings - -In some cases, unexpected behavior might be caused by misconfigured or unconfigured settings in Atom or in one of the packages. - -Open Atom's Settings View with `cmd-,` or the Atom > Preferences menu option. - -![Settings View] - -Check Atom's settings in the Settings pane, there's a description of each configuration option [here][customizing guide]. For example, if you want Atom to use hard tabs (real tabs) and not soft tabs (spaces), disable the "Soft Tabs" option. - -Since Atom ships with a set of packages and you can install additional packages yourself, check the list of packages and their settings. For example, if you'd like to get rid of the vertical line in the middle of the editor, disable the [Wrap Guide package]. And if you don't like it when Atom strips trailing whitespace or ensures that there's a single trailing newline in the file, you can configure that in the [Whitespace packages'][whitespace package] settings. - -![Package Settings] - -## Check the keybindings - -If a command is not executing when you hit a keystroke or the wrong command is executing, there might be an issue with the keybindings for that keystroke. Atom ships with the [Keybinding resolver][keybinding resolver package], a neat package which helps you understand which keybindings are executed. - -Show the keybinding resolver with cmd-. or with "Key Binding Resolver: Show" from the Command palette. With the keybinding resolver shown, hit a keystroke: - -![Keybinding Resolver] - -The keybinding resolver shows you a list of keybindings that exist for the keystroke, where each item in the list has the following: -* the command for the keybinding, -* the CSS selector used to define the context in which the keybinding is valid, and -* the file in which the keybinding is defined. - -Of all the keybinding that are listed (grey color), at most one keybinding is matched and executed (green color). If the command you wanted to trigger isn't listed, then a keybinding for that command hasn't been defined. More keybindings are provided by [packages] and you can [define your own keybindings][customizing keybindings]. - -If multiple keybindings are matched, Atom determines which keybinding will be executed based on the [specificity of the selectors and the order in which they were loaded][specificity and order]. If the command you wanted to trigger is listed in the Keybinding resolver, but wasn't the one that was executed, this is normally explained by one of two causes: -* the keystroke was not used in the context defined by the keybinding's selector. For example, you can't trigger the "Tree View: Add File" command if the Tree View is not focused, or -* there is another keybinding that took precedence. This often happens when you install a package which defines keybinding that conflict with existing keybindings. If the package's keybindings have selectors with higher specificity or were loaded later, they'll have priority over existing ones. - -Atom loads core Atom keybindings and package keybindings first, and user-defined keybindings after last. Since user-defined keybindings are loaded last, you can use your `keymap.cson` file to tweak the keybindings and sort out problems like these. For example, you can remove keybindings with [the `unset!` directive][unset directive]. - -If you notice that a package's keybindings are taking precedence over core Atom keybindings, it might be a good idea to report the issue on the package's GitHub repository. - -## Check if the problem shows up in safe mode - -A large part of Atom's functionality comes from packages you can install. In some cases, these packages might be causing unexpected behavior, problems, or performance issues. - -To determine if a package you installed is causing problems, start Atom from the terminal in safe mode: - -``` -$ atom --safe -``` - -This starts Atom, but does not load packages from `~/.atom/packages` or `~/.atom/dev/packages`. If you can no longer reproduce the problem in safe mode, it's likely it was caused by one of the packages. - -To figure out which package is causing trouble, start Atom normally again and open Settings (`cmd-,`). Since Settings allow you to disable each installed package, you can disable packages one by one until you can no longer reproduce the issue. Restart (`cmd-q`) or reload (`cmd-ctrl-alt-l`) Atom after you disable each package to make sure it's completely gone. - -When you find the problematic package, you can disable or uninstall the package, and consider creating an issue on the package's GitHub repository. - -## Check your config files - -You might have defined some custom functionality or styles in Atom's [Init script or Stylesheet]. In some situations, these personal hacks might be causing problems so try clearing those files and restarting Atom. - -## Check for errors in the developer tools - -When an error is thrown in Atom, the developer tools are automatically shown with the error logged in the Console tab. However, if the dev tools are open before the error is triggered, a full stack trace for the error will be logged: - -![devtools error] - -If you can reproduce the error, use this approach to get the full stack trace. The stack trace might point to a problem in your [Init script][init script or stylesheet] or a specific package you installed, which you can then disable and report an issue on its GitHub repository. - -## Check that you have a build toolchain installed - -If you are having issues installing a package using `apm install`, this could be -because the package has dependencies on libraries that contain native code -and so you will need to have a C++ compiler and Python installed to be able to -install it. - -You can run `apm install --check` to see if [apm][apm] can build native code on -your machine. - -Check out the pre-requisites in the [build instructions][build-instructions] for -your platform for more details. - -[apm]: https://github.com/atom/apm -[build-instructions]: https://github.com/atom/atom/tree/master/docs/build-instructions -[submitting issues]: https://github.com/atom/atom/blob/master/CONTRIBUTING.md#submitting-issues -[building atom]: https://github.com/atom/atom#building -[atom releases]: https://github.com/atom/atom/releases -[customizing guide]: https://atom.io/docs/latest/customizing-atom#configuration-key-reference -[settings view]: https://f.cloud.github.com/assets/671378/2241795/ba4827d8-9ce4-11e3-93a8-6666ee100917.png -[package settings]: https://cloud.githubusercontent.com/assets/38924/3173588/7e5f6b0c-ebe8-11e3-9ec3-e8d140967e79.png -[wrap guide package]: https://atom.io/packages/wrap-guide -[whitespace package]: https://atom.io/packages/whitespace -[keybinding resolver package]: https://atom.io/packages/keybinding-resolver -[keybinding resolver]: https://f.cloud.github.com/assets/671378/2241702/5dd5a102-9cde-11e3-9e3f-1d999930492f.png -[customizing keybindings]: https://atom.io/docs/latest/customizing-atom#customizing-key-bindings -[packages]: https://atom.io/packages -[specificity and order]: https://atom.io/docs/latest/advanced/keymaps#specificity-and-cascade-order -[unset directive]: https://atom.io/docs/latest/advanced/keymaps#removing-bindings -[init script or stylesheet]: https://atom.io/docs/latest/customizing-atom#quick-personal-hacks -[devtools error]: https://cloud.githubusercontent.com/assets/38924/3177710/11b4e510-ec13-11e3-96db-a2e8a7891773.png diff --git a/docs/getting-started.md b/docs/getting-started.md deleted file mode 100644 index 03e0a5abe..000000000 --- a/docs/getting-started.md +++ /dev/null @@ -1,109 +0,0 @@ -# Getting Started - -Welcome to Atom! This guide provides a quick introduction so you can be -productive as quickly as possible. There are also guides which cover -[configuring], [theming], and [extending] Atom. - -## The Command Palette - -If there's one key-command you remember in Atom, it should be `cmd-shift-P`. You -can always press `cmd-shift-P` to bring up a list of commands (and key bindings) -that are relevant to the currently focused interface element. This is a great -way to explore the system and learn key bindings interactively. For information -about adding or changing a key binding refer to the [customizing key -bindings][key-bindings] section. - -![Command Palette] - -## The Basics - -### Working With Files - -Atom windows are scoped to a single directory on disk. If you launch Atom from -the command line via the `atom` command and don't specify a path, Atom opens a -window for the current working directory. The current window's directory will be -visible as the root of the tree view on the left, and also serve as the context -for all file-related operations. - -#### Finding Files - -The fastest way to find a file is to use the fuzzy finder. Press `cmd-t` and -begin typing the name of the file you're looking for. If you are looking for a -file that is already open press `cmd-b` to bring up a searchable list of open -files. If you are using Git you can use `cmd-shift-b` to search the list of -files modified and untracked in your project's repository. - -You can also use the tree view to navigate to a file. To open and focus the -tree view, press `ctrl-0`. The tree view can be toggled open and closed with -`cmd-\`. - -#### Adding, Moving, Deleting Files - -You can add, move, and delete files and folders by right-clicking them in the -tree view and selecting the desired operation from the context menu. You can -also perform these operations from the keyboard by selecting a file or folder -and using `a` to add, `m` to move, and `delete` to delete. - -### Searching - -#### Find and Replace - -To search within a buffer use `cmd-f`. To search the entire project use -`cmd-shift-f`. - -#### Navigating By Symbols - -To jump to a symbol such as a method definition, press `cmd-r`. This opens a -list of all symbols in the current file, which you can fuzzy filter similarly to -`cmd-t`. - -To search for symbols across your project, use `cmd-shift-r`. First you'll need -to make sure you have `tags` (or `TAGS`) file generated for your project. -This can be done by installing [ctags](http://ctags.sourceforge.net/) and -running a command such as `ctags -R src/` from the command line in your -project's root directory. Using [Homebrew](http://brew.sh/)? Just run -`brew install ctags`. - -You can customize how tags are generated by creating your own `.ctags` file -in your home directory (`~/.ctags`). Here is [a good example][ctags] to start -from. - -### Split Panes - -You can split any editor pane horizontally or vertically by using `cmd-k right` -or `cmd-k down`. Once you have a split pane, you can move focus between them -with `cmd-k cmd-right` or `cmd-k cmd-down`. To close a pane, close all its -editors with `cmd-w`, then press `cmd-w` one more time to close the pane. You -can configure panes to auto-close when empty in the Settings view. - -### Folding - -You can fold blocks of code by clicking the arrows that appear when you hover -your mouse cursor over the gutter. You can also fold and unfold from the -keyboard with `alt-cmd-[` and `alt-cmd-]`. To fold everything, use -`alt-cmd-shift-{` and to unfold everything use `alt-cmd-shift-}`. You can also -fold at a specific indentation level with `cmd-k cmd-N` where N is the -indentation depth. - -### Soft-Wrap - -If you want to toggle soft wrap, trigger the command from the command palette. -Press `cmd-shift-P` to open the palette, then type "wrap" to find the correct -command. By default, lines will wrap based on the size of the editor. If you -prefer to wrap at a specific line length, toggle "Wrap at preferred line length" -in preferences. - -## Configuration - -Press `cmd-,` to open the Settings view. This is the place to change settings, -install packages, and change the theme. - -For more advanced configuration see the [customization guide][customization]. - -[configuring]: customizing-atom.md -[theming]: creating-a-theme.md -[extending]: creating-a-package.md -[customization]: customizing-atom.md -[key-bindings]: customizing-atom.md#customizing-key-bindings -[command palette]: https://f.cloud.github.com/assets/1424/1091618/ee7c3554-166a-11e3-9955-aaa61bb5509c.png -[ctags]: https://github.com/atom/symbols-view/blob/master/lib/.ctags diff --git a/docs/index.md b/docs/index.md deleted file mode 100644 index e034e5784..000000000 --- a/docs/index.md +++ /dev/null @@ -1,30 +0,0 @@ -## Guides - -* [Getting Started](getting-started.md) -* [Customizing Atom](customizing-atom.md) -* [Creating a Package](creating-a-package.md) -* [Creating a Theme](creating-a-theme.md) -* [Publishing a Package](publishing-a-package.md) -* [Writing Specs](writing-specs.md) -* [Converting a TextMate Bundle](converting-a-text-mate-bundle.md) -* [Converting a TextMate Theme](converting-a-text-mate-theme.md) -* [Contributing](contributing.md) -* [Contributing to Core Packages](contributing-to-packages.md) -* [Debugging](debugging.md) -* [Your First Package](your-first-package.md) - -### Advanced Topics - -* [Configuration](advanced/configuration.md) -* [Developing Node Modules](advanced/node-modules.md) -* [Keymaps](advanced/keymaps.md) -* [Serialization](advanced/serialization.md) -* [Scopes and Scope Descriptors](advanced/scopes-and-scope-descriptors.md) -* [Theme Variables](theme-variables.md) -* [apm REST API](apm-rest-api.md) - -### Upgrading to 1.0 APIs - -* [Upgrading Your Package](upgrading/upgrading-your-package.md) -* [Upgrading Your UI Theme Or Package Selectors](upgrading/upgrading-your-ui-theme.md) -* [Upgrading Your Syntax Theme](upgrading/upgrading-your-syntax-theme.md) diff --git a/docs/publishing-a-package.md b/docs/publishing-a-package.md deleted file mode 100644 index 264876c7a..000000000 --- a/docs/publishing-a-package.md +++ /dev/null @@ -1,114 +0,0 @@ -## Publishing a Package - -This guide will show you how to publish a package or theme to the -[atom.io][atomio] package registry. - -Publishing a package allows other people to install it and use it in Atom. It -is a great way to share what you've made and get feedback and contributions from -others. - -This guide assumes your package's name is `my-package` but you should pick a -better name. - -### Install apm - -The `apm` command line utility that ships with Atom supports publishing packages -to the atom.io registry. - -Check that you have `apm` installed by running the following command in your -terminal: - -```sh -apm help publish -``` - -You should see a message print out with details about the `apm publish` command. - -If you do not, launch Atom and run the _Atom > Install Shell Commands_ menu -to install the `apm` and `atom` commands. - -### Prepare Your Package - -If you've followed the steps in the [your first package][your-first-package] -doc then you should be ready to publish and you can skip to the next step. - -If not, there are a few things you should check before publishing: - - * Your *package.json* file has `name`, `description`, and `repository` fields. - * Your *package.json* file has a `version` field with a value of `"0.0.0"`. - * Your *package.json* file has an `engines` field that contains an entry - for Atom such as: `"engines": {"atom": ">=0.50.0"}`. - * Your package has a `README.md` file at the root. - * Your package is in a Git repository that has been pushed to - [GitHub][github]. Follow [this guide][repo-guide] if your package isn't - already on GitHub. - -### Publish Your Package - -Before you publish a package it is a good idea to check ahead of time if -a package with the same name has already been published to atom.io. You can do -that by visiting `https://atom.io/packages/my-package` to see if the package -already exists. If it does, update your package's name to something that is -available before proceeding. - -Now let's review what the `apm publish` command does: - - 1. Registers the package name on atom.io if it is being published for the - first time. - 2. Updates the `version` field in the *package.json* file and commits it. - 3. Creates a new [Git tag][git-tag] for the version being published. - 4. Pushes the tag and current branch up to GitHub. - 5. Updates atom.io with the new version being published. - -Now run the following commands to publish your package: - -```sh -cd ~/github/my-package -apm publish minor -``` - -If this is the first package you are publishing, the `apm publish` command may -prompt you for your GitHub username and password. This is required to publish -and you only need to enter this information the first time you publish. The -credentials are stored securely in your [keychain][keychain] once you login. - -:tada: Your package is now published and available on atom.io. Head on over to -`https://atom.io/packages/my-package` to see your package's page. - -With `apm publish`, you can bump the version and publish by using -```sh -apm publish -``` -where `` can be `major`, `minor` and `patch`. - -The `major` option to the publish command tells apm to increment the first -digit of the version before publishing so the published version will be `1.0.0` -and the Git tag created will be `v1.0.0`. - -The `minor` option to the publish command tells apm to increment the second -digit of the version before publishing so the published version will be `0.1.0` -and the Git tag created will be `v0.1.0`. - -The `patch` option to the publish command tells apm to increment the third -digit of the version before publishing so the published version will be `0.0.1` -and the Git tag created will be `v0.0.1`. - -Use `major` when you make a huge change, like a rewrite, or a large change to the functionality or interface. -Use `minor` when adding or removing a feature. -Use `patch` when you make a small change like a bug fix that does not add or remove features. - -### Further Reading - -* Check out [semantic versioning][semver] to learn more about versioning your - package releases. -* Consult the [Atom.io package API docs][apm-rest-api] to learn more about how - `apm` works. - -[atomio]: https://atom.io -[github]: https://github.com -[git-tag]: http://git-scm.com/book/en/Git-Basics-Tagging -[keychain]: https://en.wikipedia.org/wiki/Keychain_(Apple) -[repo-guide]: http://guides.github.com/overviews/desktop -[semver]: http://semver.org -[your-first-package]: your-first-package.html -[apm-rest-api]: apm-rest-api.md diff --git a/docs/theme-variables.md b/docs/theme-variables.md deleted file mode 100644 index 0316fc215..000000000 --- a/docs/theme-variables.md +++ /dev/null @@ -1,116 +0,0 @@ -# Style variables - -Atom's UI provides a set of variables you can use in your own themes and packages. - -## Use in Themes - -Each custom theme must specify a `ui-variables.less` file with all of the -following variables defined. The top-most theme specified in the theme settings -will be loaded and available for import. - -## Use in Packages - -In any of your package's `.less` files, you can access the theme variables -by importing the `ui-variables` file from Atom. - -Your package should generally only specify structural styling, and these should -come from [the style guide][styleguide]. Your package shouldn't specify colors, -padding sizes, or anything in absolute pixels. You should instead use the theme -variables. If you follow this guideline, your package will look good out of the -box with any theme! - -Here's an example `.less` file that a package can define using theme variables: - -```css -@import "ui-variables"; - -.my-selector { - background-color: @base-background-color; - padding: @component-padding; -} -``` - -## Variables - -### Text colors - -* `@text-color` -* `@text-color-subtle` -* `@text-color-highlight` -* `@text-color-selected` -* `@text-color-info` - A blue -* `@text-color-success`- A green -* `@text-color-warning`- An orange or yellow -* `@text-color-error` - A red - -### Background colors - -* `@background-color-info` - A blue -* `@background-color-success` - A green -* `@background-color-warning` - An orange or yellow -* `@background-color-error` - A red -* `@background-color-highlight` -* `@background-color-selected` -* `@app-background-color` - The app's background under all the editor components - -### Component colors - -* `@base-background-color` - -* `@base-border-color` - - -* `@pane-item-background-color` - -* `@pane-item-border-color` - - -* `@input-background-color` - -* `@input-border-color` - - -* `@tool-panel-background-color` - -* `@tool-panel-border-color` - - -* `@inset-panel-background-color` - -* `@inset-panel-border-color` - - -* `@panel-heading-background-color` - -* `@panel-heading-border-color` - - -* `@overlay-background-color` - -* `@overlay-border-color` - - -* `@button-background-color` - -* `@button-background-color-hover` - -* `@button-background-color-selected` - -* `@button-border-color` - - -* `@tab-bar-background-color` - -* `@tab-bar-border-color` - -* `@tab-background-color` - -* `@tab-background-color-active` - -* `@tab-border-color` - - -* `@tree-view-background-color` - -* `@tree-view-border-color` - - -* `@ui-site-color-1` - -* `@ui-site-color-2` - -* `@ui-site-color-3` - -* `@ui-site-color-4` - -* `@ui-site-color-5` - - -### Component sizes - -* `@disclosure-arrow-size` - - -* `@component-padding` - -* `@component-icon-padding` - -* `@component-icon-size` - -* `@component-line-height` - -* `@component-border-radius` - - -* `@tab-height` - - -### Fonts - -* `@font-size` - -* `@font-family` - - -[styleguide]: https://github.com/atom/styleguide diff --git a/docs/upgrading/upgrading-your-package.md b/docs/upgrading/upgrading-your-package.md deleted file mode 100644 index e7d603a36..000000000 --- a/docs/upgrading/upgrading-your-package.md +++ /dev/null @@ -1,625 +0,0 @@ -# Upgrading Your Package - -Atom is rapidly approaching 1.0. Much of the effort leading up to the 1.0 has been cleaning up APIs in an attempt to future proof, and make a more pleasant experience developing packages. - -This document will guide you through the large bits of upgrading your package to work with 1.0 APIs. - -## TL;DR - -We've set deprecation messages and errors in strategic places to help make sure you don't miss anything. You should be able to get 95% of the way to an updated package just by fixing errors and deprecations. There are a couple of things you can do to get the full effect of all the errors and deprecations. - -### Use atom-space-pen-views - -If you use any class from `require 'atom'` with a `$` or `View` in the name, add the `atom-space-pen-views` module to your package's `package.json` file's dependencies: - -```js -{ - "dependencies": { - "atom-space-pen-views": "^2.0.3" - } -} -``` - -Then run `apm install` in your package directory. - -### Require views from atom-space-pen-views - -Anywhere you are requiring one of the following from `atom` you need to require them from `atom-space-pen-views` instead. - -```coffee -# require these from 'atom-space-pen-views' rather than 'atom' -$ -$$ -$$$ -View -TextEditorView -ScrollView -SelectListView -``` - -So this: - -```coffee -# Old way -{$, TextEditorView, View, GitRepository} = require 'atom' -``` - -Would be replaced by this: - -```coffee -# New way -{GitRepository} = require 'atom' -{$, TextEditorView, View} = require 'atom-space-pen-views' -``` - -### Run specs and test your package - -You wrote specs, right!? Here's where they shine. Run them with `cmd-shift-P`, and search for `run package specs`. It will show all the deprecation messages and errors. - -### Update the engines field in package.json - -When you are deprecation free and all done converting, upgrade the `engines` field in your package.json: - -```json -{ - "engines": { - "atom": ">=0.174.0 <2.0.0" - } -} -``` - -### Examples - -We have upgraded all the core packages. Please see [this issue](https://github.com/atom/atom/issues/4011) for a link to all the upgrade PRs. - -## Deprecations - -All of the methods in Atom core that have changes will emit deprecation messages when called. These messages are shown in two places: your **package specs**, and in **Deprecation Cop**. - -### Specs - -Just run your specs, and all the deprecations will be displayed in yellow. - -![spec-deps](https://cloud.githubusercontent.com/assets/69169/5637943/b85114ba-95b5-11e4-8681-b81ea8f556d7.png) - -### Deprecation Cop - -Run an atom window in dev mode (`atom -d`) with your package loaded, and open Deprecation Cop (search for `deprecation` in the command palette). Deprecated methods will be appear in Deprecation Cop only after they have been called. - -![dep-cop](https://cloud.githubusercontent.com/assets/69169/5637914/6e702fa2-95b5-11e4-92cc-a236ddacee21.png) - -When deprecation cop is open, and deprecated methods are called, a `Refresh` button will appear in the top right of the Deprecation Cop interface. So exercise your package, then come back to Deprecation Cop and click the `Refresh` button. - -## Upgrading your Views - -Previous to 1.0, views were baked into Atom core. These views were based on jQuery and `space-pen`. They looked something like this: - -```coffee -# The old way: getting views from atom -{$, TextEditorView, View} = require 'atom' - -module.exports = -class SomeView extends View - @content: -> - @div class: 'find-and-replace', => - @div class: 'block', => - @subview 'myEditor', new TextEditorView(mini: true) - #... -``` - -### The New - -`require 'atom'` no longer provides view helpers or jQuery. Atom core is now 'view agnostic'. The preexisting view system is available from a new npm package: `atom-space-pen-views`. - -`atom-space-pen-views` now provides jQuery, `space-pen` views, and Atom specific views: - - -```coffee -# These are now provided by atom-space-pen-views -$ -$$ -$$$ -View -TextEditorView -ScrollView -SelectListView -``` - -### Adding the module dependencies - -To use the new views, you need to specify the `atom-space-pen-views` module in your package's `package.json` file's dependencies: - -```js -{ - "dependencies": { - "atom-space-pen-views": "^2.0.3" - } -} -``` - -`space-pen` bundles jQuery. If you do not need `space-pen` or any of the views, you can require jQuery directly. - -```js -{ - "dependencies": { - "jquery": "^2" - } -} -``` - -### Converting your views - -Sometimes it is as simple as converting the requires at the top of each view page. I assume you read the 'TL;DR' section and have updated all of your requires. - -### Upgrading classes extending any space-pen View - -#### `afterAttach` and `beforeRemove` updated - -The `afterAttach` and `beforeRemove` hooks have been replaced with -`attached` and `detached` and the semantics have changed. - -`afterAttach` was called whenever the node was attached to another DOM node, even if that parent node wasn't present in the DOM. `afterAttach` also was called with a boolean indicating whether or not the element and its parents were on the DOM. Now the `attached` hook is _only_ called when the node and all of its parents are actually on the DOM, and is not called with a boolean. - -`beforeRemove` was only called when `$.fn.remove` was called, which was typically used when the node was completely removed from the DOM. The new `detached` hook is called whenever the DOM node is _detached_, which could happen if the node is being detached for reattachment later. In short, if `beforeRemove` is called the node is never coming back. With `detached` it might be attached again later. - -```coffee -# Old way -{View} = require 'atom' -class MyView extends View - afterAttach: (onDom) -> - #... - - beforeRemove: -> - #... -``` - -```coffee -# New way -{View} = require 'atom-space-pen-views' -class MyView extends View - attached: -> - # Always called with the equivalent of @afterAttach(true)! - #... - - detached: -> - #... -``` - -#### `subscribe` and `subscribeToCommand` methods removed - -The `subscribe` and `subscribeToCommand` methods have been removed. See the Eventing and Disposables section for more info. - -### Upgrading to the new TextEditorView - -All of the atom-specific methods available on the `TextEditorView` have been moved to the `TextEditor`, available via `TextEditorView::getModel`. See the [`TextEditorView` docs][TextEditorView] and [`TextEditor` docs][TextEditor] for more info. - -### Upgrading classes extending ScrollView - -The `ScrollView` has very minor changes. - -You can no longer use `@off` to remove default behavior for `core:move-up`, `core:move-down`, etc. - -```coffee -# Old way to turn off default behavior -class ResultsView extends ScrollView - initialize: (@model) -> - super() - # turn off default scrolling behavior from ScrollView - @off 'core:move-up' - @off 'core:move-down' - @off 'core:move-left' - @off 'core:move-right' -``` - -```coffee -# New way to turn off default behavior -class ResultsView extends ScrollView - initialize: (@model) -> - disposable = super() - # turn off default scrolling behavior from ScrollView - disposable.dispose() -``` - -* Check out [an example](https://github.com/atom/find-and-replace/pull/311/files#diff-9) from find-and-replace. -* See the [docs][ScrollView] for all the options. - -### Upgrading classes extending SelectListView - -Your SelectListView might look something like this: - -```coffee -# Old! -class CommandPaletteView extends SelectListView - initialize: -> - super() - @addClass('command-palette overlay from-top') - atom.workspaceView.command 'command-palette:toggle', => @toggle() - - confirmed: ({name, jQuery}) -> - @cancel() - # do something with the result - - toggle: -> - if @hasParent() - @cancel() - else - @attach() - - attach: -> - @storeFocusedElement() - - items = [] # TODO: build items - @setItems(items) - - atom.workspaceView.append(this) - @focusFilterEditor() - - confirmed: ({name, jQuery}) -> - @cancel() -``` - -This attaches and detaches itself from the dom when toggled, canceling magically detaches it from the DOM, and it uses the classes `overlay` and `from-top`. - -The new SelectListView no longer automatically detaches itself from the DOM when cancelled. It's up to you to implement whatever cancel beahavior you want. Using the new APIs to mimic the sematics of the old class, it should look like this: - -```coffee -# New! -class CommandPaletteView extends SelectListView - initialize: -> - super() - # no more need for the `overlay` and `from-top` classes - @addClass('command-palette') - atom.commands.add 'atom-workspace', 'command-palette:toggle', => @toggle() - - # You need to implement the `cancelled` method and hide. - cancelled: -> - @hide() - - confirmed: ({name, jQuery}) -> - @cancel() - # do something with the result - - toggle: -> - # Toggling now checks panel visibility, - # and hides / shows rather than attaching to / detaching from the DOM. - if @panel?.isVisible() - @cancel() - else - @show() - - show: -> - # Now you will add your select list as a modal panel to the workspace - @panel ?= atom.workspace.addModalPanel(item: this) - @panel.show() - - @storeFocusedElement() - - items = [] # TODO: build items - @setItems(items) - - @focusFilterEditor() - - hide: -> - @panel?.hide() -``` - -* And check out the [conversion of CommandPaletteView][selectlistview-example] as a real-world example. -* See the [SelectListView docs][SelectListView] for all options. - -## Using the model layer rather than the view layer - -The API no longer exposes any specialized view objects or view classes. `atom.workspaceView`, and all the view classes: `WorkspaceView`, `EditorView`, `PaneView`, etc. have been globally deprecated. - -Nearly all of the atom-specific actions performed by the old view objects can now be managed via the model layer. For example, here's adding a panel to the interface using the `atom.workspace` model instead of the `workspaceView`: - -```coffee -# Old! -div = document.createElement('div') -atom.workspaceView.appendToTop(div) -``` - -```coffee -# New! -div = document.createElement('div') -atom.workspace.addTopPanel(item: div) -``` - -For actions that still require the view, such as dispatching commands or munging css classes, you'll access the view via the `atom.views.getView()` method. This will return a subclass of `HTMLElement` rather than a jQuery object or an instance of a deprecated view class (e.g. `WorkspaceView`). - -```coffee -# Old! -workspaceView = atom.workspaceView -editorView = workspaceView.getActiveEditorView() -paneView = editorView.getPaneView() -``` - -```coffee -# New! -# Generally, just use the models -workspace = atom.workspace -editor = workspace.getActiveTextEditor() -pane = editor.getPane() - -# If you need views, get them with `getView` -workspaceElement = atom.views.getView(atom.workspace) -editorElement = atom.views.getView(editor) -paneElement = atom.views.getView(pane) -``` - -## Updating Specs - -`atom.workspaceView`, the `WorkspaceView` class and the `EditorView` class have been deprecated. These two objects are used heavily throughout specs, mostly to dispatch events and commands. This section will explain how to remove them while still retaining the ability to dispatch events and commands. - -### Removing WorkspaceView references - -`WorkspaceView` has been deprecated. Everything you could do on the view, you can now do on the `Workspace` model. - -Requiring `WorkspaceView` from `atom` and accessing any methods on it will throw a deprecation warning. Many specs lean heavily on `WorkspaceView` to trigger commands and fetch `EditorView` objects. - -Your specs might contain something like this: - -```coffee -# Old! -{WorkspaceView} = require 'atom' -describe 'FindView', -> - beforeEach -> - atom.workspaceView = new WorkspaceView() -``` - -Instead, we will use the `atom.views.getView()` method. This will return a plain `HTMLElement`, not a `WorkspaceView` or jQuery object. - -```coffee -# New! -describe 'FindView', -> - workspaceElement = null - beforeEach -> - workspaceElement = atom.views.getView(atom.workspace) -``` - -### Attaching the workspace to the DOM - -The workspace needs to be attached to the DOM in some cases. For example, view hooks only work (`attached()` on `View`, `attachedCallback()` on custom elements) when there is a descendant attached to the DOM. - -You might see this in your specs: - -```coffee -# Old! -atom.workspaceView.attachToDom() -``` - -Change it to: - -```coffee -# New! -jasmine.attachToDOM(workspaceElement) -``` - -### Removing EditorView references - -Like `WorkspaceView`, `EditorView` has been deprecated. Everything you needed to do on the view you are now able to do on the `TextEditor` model. - -In many cases, you will not even need to get the editor's view anymore. Any of those instances should be updated to use the `TextEditor` instance instead. You should really only need the editor's view when you plan on triggering a command on the view in a spec. - -Your specs might contain something like this: - -```coffee -# Old! -describe 'Something', -> - [editorView] = [] - beforeEach -> - editorView = atom.workspaceView.getActiveView() -``` - -We're going to use `atom.views.getView()` again to get the editor element. As in the case of the `workspaceElement`, `getView` will return a subclass of `HTMLElement` rather than an `EditorView` or jQuery object. - -```coffee -# New! -describe 'Something', -> - [editor, editorElement] = [] - beforeEach -> - editor = atom.workspace.getActiveTextEditor() - editorElement = atom.views.getView(editor) -``` - -### Dispatching commands - -Since the `editorElement` objects are no longer `jQuery` objects, they no longer support `trigger()`. Additionally, Atom has a new command dispatcher, `atom.commands`, that we use rather than commandeering jQuery's `trigger` method. - -From this: - -```coffee -# Old! -workspaceView.trigger 'a-package:toggle' -editorView.trigger 'find-and-replace:show' -``` - -To this: - -```coffee -# New! -atom.commands.dispatch workspaceElement, 'a-package:toggle' -atom.commands.dispatch editorElement, 'find-and-replace:show' -``` - -## Eventing and Disposables - -A couple large things changed with respect to events: - -1. All model events are now exposed as event subscription methods that return [`Disposable`][disposable] objects -1. The `subscribe()` method is no longer available on `space-pen` `View` objects -1. An Emitter is now provided from `require 'atom'` - -### Consuming Events - -All events from the Atom API are now methods that return a [`Disposable`][disposable] object, on which you can call `dispose()` to unsubscribe. - -```coffee -# Old! -editor.on 'changed', -> -``` - -```coffee -# New! -disposable = editor.onDidChange -> - -# You can unsubscribe at some point in the future via `dispose()` -disposable.dispose() -``` - -Deprecation warnings will guide you toward the correct methods. - -#### Using a CompositeDisposable - -You can group multiple disposables into a single disposable with a `CompositeDisposable`. - -```coffee -{CompositeDisposable} = require 'atom' - -class Something - constructor: -> - editor = atom.workspace.getActiveTextEditor() - @disposables = new CompositeDisposable - @disposables.add editor.onDidChange -> - @disposables.add editor.onDidChangePath -> - - destroy: -> - @disposables.dispose() -``` - -### Removing View::subscribe and Subscriber::subscribe calls - -There were a couple permutations of `subscribe()`. In these examples, a `CompositeDisposable` is used as it will commonly be useful where conversion is necessary. - -#### subscribe(unsubscribable) - -This one is very straight forward. - -```coffee -# Old! -@subscribe editor.on 'changed', -> -``` - -```coffee -# New! -disposables = new CompositeDisposable -disposables.add editor.onDidChange -> -``` - -#### subscribe(modelObject, event, method) - -When the modelObject is an Atom model object, the change is very simple. Just use the correct event method, and add it to your CompositeDisposable. - -```coffee -# Old! -@subscribe editor, 'changed', -> -``` - -```coffee -# New! -disposables = new CompositeDisposable -disposables.add editor.onDidChange -> -``` - -#### subscribe(jQueryObject, selector(optional), event, method) - -Things are a little more complicated when subscribing to a DOM or jQuery element. Atom no longer provides helpers for subscribing to elements. You can use jQuery or the native DOM APIs, whichever you prefer. - -```coffee -# Old! -@subscribe $(window), 'focus', -> -``` - -```coffee -# New! -{Disposable, CompositeDisposable} = require 'atom' -disposables = new CompositeDisposable - -# New with jQuery -focusCallback = -> -$(window).on 'focus', focusCallback -disposables.add new Disposable -> - $(window).off 'focus', focusCallback - -# New with native APIs -focusCallback = -> -window.addEventListener 'focus', focusCallback -disposables.add new Disposable -> - window.removeEventListener 'focus', focusCallback -``` - -### Providing Events: Using the Emitter - -You no longer need to require `emissary` to get an emitter. We now provide an `Emitter` class from `require 'atom'`. We have a specific pattern for use of the `Emitter`. Rather than mixing it in, we instantiate a member variable, and create explicit subscription methods. For more information see the [`Emitter` docs][emitter]. - -```coffee -# New! -{Emitter} = require 'atom' - -class Something - constructor: -> - @emitter = new Emitter - - destroy: -> - @emitter.dispose() - - onDidChange: (callback) -> - @emitter.on 'did-change', callback - - methodThatFiresAChange: -> - @emitter.emit 'did-change', {data: 2} - -# Using the evented class -something = new Something -something.onDidChange (eventObject) -> - console.log eventObject.data # => 2 -something.methodThatFiresAChange() -``` - -## Subscribing To Commands - -`$.fn.command` and `View::subscribeToCommand` are no longer available. Now we use `atom.commands.add`, and collect the results in a `CompositeDisposable`. See [the docs][commands-add] for more info. - -```coffee -# Old! -atom.workspaceView.command 'core:close core:cancel', -> - -# When inside a View class, you might see this -@subscribeToCommand 'core:close core:cancel', -> -``` - -```coffee -# New! -@disposables.add atom.commands.add 'atom-workspace', - 'core:close': -> - 'core:cancel': -> - -# You can register commands directly on individual DOM elements in addition to -# using selectors. When in a View class, you should have a `@element` object -# available. `@element` is a plain HTMLElement object -@disposables.add atom.commands.add @element, - 'core:close': -> - 'core:cancel': -> -``` - -## Upgrading your stylesheet's selectors - -Many selectors have changed, and we have introduced the [Shadow DOM][shadowdom] to the editor. See the [Upgrading Your UI Theme And Package Selectors guide][upgrading-selectors] for more information in upgrading your package stylesheets. - -## Help us improve this guide! - -Did you hit something painful that wasn't in here? Want to reword some bit of it? Find something incorrect? Please edit [this file][guide], and send a pull request. Contributions are greatly appreciated. - - - - -[texteditorview]:https://github.com/atom/atom-space-pen-views#texteditorview -[scrollview]:https://github.com/atom/atom-space-pen-views#scrollview -[selectlistview]:https://github.com/atom/atom-space-pen-views#selectlistview -[selectlistview-example]:https://github.com/atom/command-palette/pull/19/files -[emitter]:https://atom.io/docs/api/latest/Emitter -[texteditor]:https://atom.io/docs/api/latest/TextEditor -[disposable]:https://atom.io/docs/api/latest/Disposable -[commands-add]:https://atom.io/docs/api/latest/CommandRegistry#instance-add -[upgrading-selectors]:https://atom.io/docs/latest/upgrading/upgrading-your-ui-theme -[shadowdom]:http://blog.atom.io/2014/11/18/avoiding-style-pollution-with-the-shadow-dom.html -[guide]:https://github.com/atom/atom/blob/master/docs/upgrading/upgrading-your-package.md diff --git a/docs/upgrading/upgrading-your-syntax-theme.md b/docs/upgrading/upgrading-your-syntax-theme.md deleted file mode 100644 index 3a8241ca0..000000000 --- a/docs/upgrading/upgrading-your-syntax-theme.md +++ /dev/null @@ -1,24 +0,0 @@ -# Upgrading Your Syntax Theme - -Text editor content is now rendered in the shadow DOM, which shields it from being styled by global style sheets to protect against accidental style pollution. For more background on the shadow DOM, check out the [Shadow DOM 101][shadow-dom-101] on HTML 5 Rocks. - -Syntax themes are specifically intended to style only text editor content, so they are automatically loaded directly into the text editor's shadow DOM when it is enabled. This happens automatically when the the theme's `package.json` contains a `theme: "syntax"` declaration, so you don't need to change anything to target the appropriate context. - -When theme style sheets are loaded into the text editor's shadow DOM, selectors intended to target the editor from the *outside* no longer make sense. Styles targeting the `.editor` and `.editor-colors` classes instead need to target the `:host` pseudo-element, which matches against the containing `atom-text-editor` node. Check out the [Shadow DOM 201][host-pseudo-element] article for more information about the `:host` pseudo-element. - -Here's an example from Atom's light syntax theme. Note that the `atom-text-editor` selector intended to target the editor from the outside has been retained to allow the theme to keep working during the transition phase when it is possible to disable the shadow DOM. - -```css -atom-text-editor, :host { /* :host added */ - background-color: @syntax-background-color; - color: @syntax-text-color; - - .invisible-character { - color: @syntax-invisible-character-color; - } - /* more nested selectors... */ -} -``` - -[shadow-dom-101]: http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom -[host-pseudo-element]: http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom-201#toc-style-host diff --git a/docs/upgrading/upgrading-your-ui-theme.md b/docs/upgrading/upgrading-your-ui-theme.md deleted file mode 100644 index 5be0344bb..000000000 --- a/docs/upgrading/upgrading-your-ui-theme.md +++ /dev/null @@ -1,137 +0,0 @@ -# Upgrading Your UI Theme Or Package Selectors - -In addition to changes in Atom's scripting API, we'll also be making some breaking changes to Atom's DOM structure, requiring style sheets and keymaps in both packages and themes to be updated. - -## Deprecation Cop - -Deprecation cop will list usages of deprecated selector patterns to guide you. You can access it via the command palette (`cmd-shift-p`, then search for `Deprecation`). It breaks the deprecations down by package: - -![dep-cop](https://cloud.githubusercontent.com/assets/69169/5078860/d38a5df4-6e64-11e4-95b6-eb585ee9bbfc.png) - -## Custom Tags - -Rather than adding classes to standard HTML elements to indicate their role, Atom now uses custom element names. For example, `
` has now been replaced with ``. Selectors should be updated accordingly. Note that tag names have lower specificity than classes in CSS, so you'll need to take care in converting things. - -Old Selector | New Selector ---------------------|-------------------------------- -`.editor` | `atom-text-editor` -`.editor.mini` | `atom-text-editor[mini]` -`.workspace` | `atom-workspace` -`.horizontal` | `atom-workspace-axis.horizontal` -`.vertical` | `atom-workspace-axis.vertical` -`.pane-container` | `atom-pane-container` -`.pane` | `atom-pane` -`.tool-panel` | `atom-panel` -`.panel-top` | `atom-panel.top` -`.panel-bottom` | `atom-panel.bottom` -`.panel-left` | `atom-panel.left` -`.panel-right` | `atom-panel.right` -`.overlay` | `atom-panel.modal` - -## Supporting the Shadow DOM - -Text editor content is now rendered in the shadow DOM, which shields it from being styled by global style sheets to protect against accidental style pollution. For more background on the shadow DOM, check out the [Shadow DOM 101][shadow-dom-101] on HTML 5 Rocks. If you need to style text editor content in a UI theme, you'll need to circumvent this protection for any rules that target the text editor's content. Some examples of the kinds of UI theme styles needing to be updated: - -* Highlight decorations -* Gutter decorations -* Line decorations -* Scrollbar styling -* Anything targeting a child selector of `.editor` - -During a transition phase, it will be possible to enable or disable the text editor's shadow DOM in the settings, so themes will need to be compatible with both approaches. - -### Shadow DOM Selectors - -Chromium provides two tools for bypassing shadow boundaries, the `::shadow` pseudo-element and the `/deep/` combinator. For an in-depth explanation of styling the shadow DOM, see the [Shadow DOM 201][shadow-dom-201] article on HTML 5 Rocks. - -#### ::shadow - -The `::shadow` pseudo-element allows you to bypass a single shadow root. For example, say you want to update a highlight decoration for a linter package. Initially, the style looks as follows: - -```css -// Without shadow DOM support -atom-text-editor .highlight.my-linter { - background: hotpink; -} -``` - -In order for this style to apply with the shadow DOM enabled, you will need to add a second selector with the `::shadow` pseudo-element. You should leave the original selector in place so your theme continues to work with the shadow DOM disabled during the transition period. - -```css -// With shadow DOM support -atom-text-editor .highlight.my-linter, -atom-text-editor::shadow .highlight.my-linter { - background: hotpink; -} -``` - -Check out the [find-and-replace][find-and-replace] package for another example of using `::shadow` to pierce the shadow DOM. - -#### /deep/ - -The `/deep/` combinator overrides *all* shadow boundaries, making it useful for rules you want to apply globally such as scrollbar styling. Here's a snippet containing scrollbar styling for the Atom Dark UI theme before shadow DOM support: - -```css -// Without shadow DOM support -.scrollbars-visible-always { - ::-webkit-scrollbar { - width: 8px; - height: 8px; - } - - ::-webkit-scrollbar-track, - ::-webkit-scrollbar-corner { - background: @scrollbar-background-color; - } - - ::-webkit-scrollbar-thumb { - background: @scrollbar-color; - border-radius: 5px; - box-shadow: 0 0 1px black inset; - } -} -``` - -To style scrollbars even inside of the shadow DOM, each rule needs to be prefixed with `/deep/`. We use `/deep/` instead of `::shadow` because we don't care about the selector of the host element in this case. We just want our styling to apply everywhere. - -```css -// With shadow DOM support using /deep/ -.scrollbars-visible-always { - /deep/ ::-webkit-scrollbar { - width: 8px; - height: 8px; - } - - /deep/ ::-webkit-scrollbar-track, - /deep/ ::-webkit-scrollbar-corner { - background: @scrollbar-background-color; - } - - /deep/ ::-webkit-scrollbar-thumb { - background: @scrollbar-color; - border-radius: 5px; - box-shadow: 0 0 1px black inset; - } -} -``` - -### Context-Targeted Style Sheets - -The selector features discussed above allow you to target shadow DOM content with specific selectors, but Atom also allows you to target a specific shadow DOM context with an entire style sheet. The context into which a style sheet is loaded is based on the file name. If you want to load a style sheet into the editor, name it with the `.atom-text-editor.less` or `.atom-text-editor.css` extensions. - -``` -my-ui-theme/ - styles/ - index.less # loaded globally - index.atom-text-editor.less # loaded in the text editor shadow DOM -``` - -Check out this [style sheet](https://github.com/atom/decoration-example/blob/master/styles/decoration-example.atom-text-editor.less) from the decoration-example package for an example of context-targeting. - -Inside a context-targeted style sheet, there's no need to use the `::shadow` or `/deep/` expressions. If you want to refer to the element containing the shadow root, you can use the `::host` pseudo-element. - -During the transition phase, style sheets targeting the `atom-text-editor` context will *also* be loaded globally. Make sure you update your selectors in a way that maintains compatibility with the shadow DOM being disabled. That means if you use a `::host` pseudo element, you should also include the same style rule matches against `atom-text-editor`. - -[shadow-dom-101]: http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom -[shadow-dom-201]: http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom-201#toc-style-cat-hat -[find-and-replace]: https://github.com/atom/find-and-replace/blob/95351f261bc384960a69b66bf12eae8002da63f9/styles/find-and-replace.less#L10 diff --git a/docs/writing-specs.md b/docs/writing-specs.md deleted file mode 100644 index 38db57439..000000000 --- a/docs/writing-specs.md +++ /dev/null @@ -1,136 +0,0 @@ -# Writing specs - -Atom uses [Jasmine](http://jasmine.github.io/1.3/introduction.html) as its spec framework. Any new functionality should have specs to guard against regressions. - -## Create a new spec - -[Atom specs](https://github.com/atom/atom/tree/master/spec) and [package specs](https://github.com/atom/markdown-preview/tree/master/spec) are added to their respective `spec` directory. The example below creates a spec for Atom core. - -0. Create a spec file - - Spec files **must** end with `-spec` so add `sample-spec.coffee` to `atom/spec`. - -0. Add one or more `describe` methods - - The `describe` method takes two arguments, a description and a function. If the description explains a behavior it typically begins with `when`; if it is more like a unit test it begins with the method name. - - ```coffee - describe "when a test is written", -> - # contents - ``` - - or - - ```coffee - describe "Editor::moveUp", -> - # contents - ``` - -0. Add one or more `it` method - - The `it` method also takes two arguments, a description and a function. Try and make the description flow with the `it` method. For example, a description of `this should work` doesn't read well as `it this should work`. But a description of `should work` sounds great as `it should work`. - - ```coffee - describe "when a test is written", -> - it "has some expectations that should pass", -> - # Expectations - ``` - -0. Add one or more expectations - - The best way to learn about expectations is to read the [jasmine documentation](http://jasmine.github.io/1.3/introduction.html#section-Expectations) about them. Below is a simple example. - - ```coffee - describe "when a test is written", -> - it "has some expectations that should pass", -> - expect("apples").toEqual("apples") - expect("oranges").not.toEqual("apples") - ``` - -## Asynchronous specs - -Writing Asynchronous specs can be tricky at first. Some examples. - -0. Promises - - Working with promises is rather easy in Atom. You can use our `waitsForPromise` function. - - ```coffee - describe "when we open a file", -> - it "should be opened in an editor", -> - waitsForPromise -> - atom.workspace.open('c.coffee').then (editor) -> - expect(editor.getPath()).toContain 'c.coffee' - ``` - - This method can be used in the `describe`, `it`, `beforeEach` and `afterEach` functions. - - ```coffee - describe "when we open a file", -> - beforeEach -> - waitsForPromise -> - atom.workspace.open 'c.coffee' - - it "should be opened in an editor", -> - expect(atom.workspace.getActiveTextEditor().getPath()).toContain 'c.coffee' - - ``` - - If you need to wait for multiple promises use a new `waitsForPromise` function for each promise. (Caution: Without `beforeEach` this example will fail!) - - ```coffee - describe "waiting for the packages to load", -> - - beforeEach -> - waitsForPromise -> - atom.workspace.open('sample.js') - waitsForPromise -> - atom.packages.activatePackage('tabs') - waitsForPromise -> - atom.packages.activatePackage('tree-view') - - it 'should have waited long enough', -> - expect(atom.packages.isPackageActive('tabs')).toBe true - expect(atom.packages.isPackageActive('tree-view')).toBe true - ``` - -0. Asynchronous functions with callbacks - - Specs for asynchronous functions can be done using the `waitsFor` and `runs` functions. A simple example. - - ```coffee - describe "fs.readdir(path, cb)", -> - it "is async", -> - spy = jasmine.createSpy('fs.readdirSpy') - - fs.readdir('/tmp/example', spy) - waitsFor -> - spy.callCount > 0 - runs -> - exp = [null, ['example.coffee']] - expect(spy.mostRecentCall.args).toEqual exp - expect(spy).toHaveBeenCalledWith(null, ['example.coffee']) - ``` - -For a more detailed documentation on asynchronous tests please visit the [jasmine documentation](http://jasmine.github.io/1.3/introduction.html#section-Asynchronous_Support). - - -## Running specs - -Most of the time you'll want to run specs by triggering the `window:run-package-specs` command. This command is not only to run package specs, it is also for Atom core specs. This will run all the specs in the current project's spec directory. If you want to run the Atom core specs and **all** the default package specs trigger the `window:run-all-specs` command. - -To run a limited subset of specs use the `fdescribe` or `fit` methods. You can use those to focus a single spec or several specs. In the example above, focusing an individual spec looks like this: - -```coffee -describe "when a test is written", -> - fit "has some expectations that should pass", -> - expect("apples").toEqual("apples") - expect("oranges").not.toEqual("apples") -``` - -### Running on CI - -It is now easy to run the specs in a CI environment like Travis and AppVeyor. See the -[Travis CI For Your Packages](http://blog.atom.io/2014/04/25/ci-for-your-packages.html) -and [AppVeyor CI For Your Packages](http://blog.atom.io/2014/07/28/windows-ci-for-your-packages.html) -posts for more details. diff --git a/docs/your-first-package.md b/docs/your-first-package.md deleted file mode 100644 index 42aca7c31..000000000 --- a/docs/your-first-package.md +++ /dev/null @@ -1,158 +0,0 @@ -# Create Your First Package - -This tutorial will guide you though creating a simple command that replaces the -selected text with [ascii art](https://en.wikipedia.org/wiki/ASCII_art). When you -run our new command with the word "cool" selected, it will be replaced with: - -``` - ___ - /\_ \ - ___ ___ ___\//\ \ - /'___\ / __`\ / __`\\ \ \ -/\ \__//\ \L\ \/\ \L\ \\_\ \_ -\ \____\ \____/\ \____//\____\ - \/____/\/___/ \/___/ \/____/ -``` - -The final package can be viewed at -[https://github.com/atom/ascii-art](https://github.com/atom/ascii-art). - -To begin, press `cmd-shift-P` to bring up the [Command -Palette](https://github.com/atom/command-palette). Type "generate package" and -select the "Package Generator: Generate Package" command. Now we need to name -the package. Try to avoid naming your package with the *atom-* prefix, for -example we are going to call this package _ascii-art_. - -Atom will open a new window with the contents of our new _ascii-art_ package -displayed in the Tree View. Because this window is opened **after** the package -is created, the ASCII Art package will be loaded and available in our new -window. To verify this, toggle the Command Palette (`cmd-shift-P`) and type -"ASCII Art". You'll see a new `ASCII Art: Toggle` command. When triggered, this -command displays a default message. - -Now let's edit the package files to make our ASCII Art package do something -interesting. Since this package doesn't need any UI, we can remove all -view-related code. Start by opening up _lib/ascii-art.coffee_. Remove all view -code, so the `module.exports` section looks like this: - -```coffeescript -module.exports = - activate: -> -``` - -## Create a Command - -Now let's add a command. We recommend that you namespace your commands with the -package name followed by a `:`, so we'll call our command `ascii-art:convert`. -Register the command in _lib/ascii-art.coffee_: - -```coffeescript -module.exports = - activate: -> - atom.commands.add 'atom-workspace', "ascii-art:convert", => @convert() - - convert: -> - # This assumes the active pane item is an editor - editor = atom.workspace.getActivePaneItem() - editor.insertText('Hello, World!') -``` - -The `atom.commands.add` method takes a selector, command name, and a callback. -The callback executes when the command is triggered on an element matching the -selector. In this case, when the command is triggered the callback will call the -`convert` method and insert 'Hello, World!'. - -## Reload the Package - -Before we can trigger `ascii-art:convert`, we need to load the latest code for -our package by reloading the window. Run the command `window:reload` from the -command palette or by pressing `ctrl-alt-cmd-l`. - -## Trigger the Command - -Now open the command panel and search for the `ascii-art:convert` command. But -it's not there! To fix this, open _package.json_ and find the property called -`activationCommands`. Activation Commands speed up Atom's load time by allowing it to -delay a package's activation until it's needed. So remove the existing command -and add `ascii-art:convert` to the `activationCommands` array: - -```json -"activationCommands": ["ascii-art:convert"], -``` - -First, reload the window by running the command `window:reload`. Now when you -run the `ascii-art:convert` command it will output 'Hello, World!' - -## Add a Key Binding - -Now let's add a key binding to trigger the `ascii-art:convert` command. Open -_keymaps/ascii-art.cson_ and add a key binding linking `ctrl-alt-a` to the -`ascii-art:convert` command. You can delete the pre-existing key binding since -you don't need it anymore. When finished, the file will have this: - -```coffeescript -'atom-text-editor': - 'ctrl-alt-a': 'ascii-art:convert' -``` - -Notice `atom-text-editor` on the first line. Just like CSS, keymap selectors -*scope* key bindings so they only apply to specific elements. In this case, our -binding is only active for elements matching the `atom-text-editor` selector. If -the Tree View has focus, pressing `ctrl-alt-a` won't trigger the -`ascii-art:convert` command. But if the editor has focus, the -`ascii-art:convert` method *will* be triggered. More information on key bindings -can be found in the [keymaps](advanced/keymaps.html) documentation. - -Now reload the window and verify that the key binding works! You can also verify -that it **doesn't** work when the Tree View is focused. - -## Add the ASCII Art - -Now we need to convert the selected text to ASCII art. To do this we will use -the [figlet](https://npmjs.org/package/figlet) [node](http://nodejs.org/) module -from [npm](https://npmjs.org/). Open _package.json_ and add the latest version of -figlet to the dependencies: - -```json -"dependencies": { - "figlet": "1.0.8" -} -``` - -After saving the file, run the command 'update-package-dependencies:update' from -the Command Palette. This will install the package's node module dependencies, -only figlet in this case. You will need to run -'update-package-dependencies:update' whenever you update the dependencies field -in your _package.json_ file. - -Now require the figlet node module in _lib/ascii-art.coffee_ and instead of -inserting 'Hello, World!' convert the selected text to ASCII art. - -```coffeescript -convert: -> - # This assumes the active pane item is an editor - editor = atom.workspace.getActivePaneItem() - selection = editor.getLastSelection() - - figlet = require 'figlet' - figlet selection.getText(), {font: "Larry 3D 2"}, (error, asciiArt) -> - if error - console.error(error) - else - selection.insertText("\n#{asciiArt}\n") -``` - -Select some text in an editor window and hit `ctrl-alt-a`. :tada: You're now an -ASCII art professional! - -## Further reading - -* [Getting your project on GitHub guide](http://guides.github.com/overviews/desktop) - -* [Writing specs](writing-specs.md) for your package - -* [Creating a package guide](creating-a-package.html) for more information - on the mechanics of packages - -* [Publishing a package guide](publishing-a-package.html) for more information - on publishing your package to [atom.io](https://atom.io) From 9e369b5efc16eab92b6ead8eac2f2e8dd8c80f7c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 2 Mar 2015 09:01:18 -0800 Subject: [PATCH 0006/1783] :arrow_up: language-gfm@0.65 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4d807f29e..d80124592 100644 --- a/package.json +++ b/package.json @@ -126,7 +126,7 @@ "language-coffee-script": "0.39.0", "language-csharp": "0.5.0", "language-css": "0.28.0", - "language-gfm": "0.64.0", + "language-gfm": "0.65.0", "language-git": "0.10.0", "language-go": "0.21.0", "language-html": "0.29.0", From 9921d55724e80cb4e618c7fadaec9815d072cf6d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 2 Mar 2015 09:02:55 -0800 Subject: [PATCH 0007/1783] :arrow_up: apm@0.142 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index f735cb6f4..7d894d573 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.141.0" + "atom-package-manager": "0.142.0" } } From 66141a6a1822b858dcc751324ffc603d53bb638f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 2 Mar 2015 09:10:11 -0800 Subject: [PATCH 0008/1783] Remove empty param list --- src/scrollbar-corner-component.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scrollbar-corner-component.coffee b/src/scrollbar-corner-component.coffee index c0fbdfd60..986d28f17 100644 --- a/src/scrollbar-corner-component.coffee +++ b/src/scrollbar-corner-component.coffee @@ -1,6 +1,6 @@ module.exports = class ScrollbarCornerComponent - constructor: () -> + constructor: -> @domNode = document.createElement('div') @domNode.classList.add('scrollbar-corner') From e5048b5ede251a9030260b0a0bc434d5671841fb Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 2 Mar 2015 13:05:38 -0800 Subject: [PATCH 0009/1783] :arrow_up: language-gfm@0.66 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d80124592..c7de1dafc 100644 --- a/package.json +++ b/package.json @@ -126,7 +126,7 @@ "language-coffee-script": "0.39.0", "language-csharp": "0.5.0", "language-css": "0.28.0", - "language-gfm": "0.65.0", + "language-gfm": "0.66.0", "language-git": "0.10.0", "language-go": "0.21.0", "language-html": "0.29.0", From d21ae2c8694d3655797049eb68a3e55b9e27cfcd Mon Sep 17 00:00:00 2001 From: Ivan Zuzak Date: Sat, 28 Feb 2015 22:14:37 +0100 Subject: [PATCH 0010/1783] Select buffer lines for mouse clicks on gutter --- src/text-editor-component.coffee | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 9536bcaad..75a9a5136 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -404,29 +404,33 @@ class TextEditorComponent onGutterClick: (event) => clickedRow = @screenPositionForMouseEvent(event).row + clickedBufferRow = @editor.bufferRowForScreenRow(clickedRow) - @editor.setSelectedScreenRange([[clickedRow, 0], [clickedRow + 1, 0]], preserveFolds: true) + @editor.setSelectedBufferRange([[clickedBufferRow, 0], [clickedBufferRow + 1, 0]], preserveFolds: true) @handleDragUntilMouseUp event, (screenPosition) => dragRow = screenPosition.row - if dragRow < clickedRow # dragging up - @editor.setSelectedScreenRange([[dragRow, 0], [clickedRow + 1, 0]], preserveFolds: true) + dragBufferRow = @editor.bufferRowForScreenRow(dragRow) + if dragBufferRow < clickedBufferRow # dragging up + @editor.setSelectedBufferRange([[dragBufferRow, 0], [clickedBufferRow + 1, 0]], preserveFolds: true) else - @editor.setSelectedScreenRange([[clickedRow, 0], [dragRow + 1, 0]], preserveFolds: true) + @editor.setSelectedBufferRange([[clickedBufferRow, 0], [dragBufferRow + 1, 0]], preserveFolds: true) onGutterMetaClick: (event) => clickedRow = @screenPositionForMouseEvent(event).row + clickedBufferRow = @editor.bufferRowForScreenRow(clickedRow) - bufferRange = @editor.bufferRangeForScreenRange([[clickedRow, 0], [clickedRow + 1, 0]]) + bufferRange = new Range([clickedBufferRow, 0], [clickedBufferRow + 1, 0]) rowSelection = @editor.addSelectionForBufferRange(bufferRange, preserveFolds: true) @handleDragUntilMouseUp event, (screenPosition) => dragRow = screenPosition.row + dragBufferRow = @editor.bufferRowForScreenRow(dragRow) - if dragRow < clickedRow # dragging up - rowSelection.setScreenRange([[dragRow, 0], [clickedRow + 1, 0]], preserveFolds: true) + if dragBufferRow < clickedBufferRow # dragging up + rowSelection.setBufferRange([[dragBufferRow, 0], [clickedBufferRow + 1, 0]], preserveFolds: true) else - rowSelection.setScreenRange([[clickedRow, 0], [dragRow + 1, 0]], preserveFolds: true) + rowSelection.setBufferRange([[clickedBufferRow, 0], [dragBufferRow + 1, 0]], preserveFolds: true) # After updating the selected screen range, merge overlapping selections @editor.mergeIntersectingSelections(preserveFolds: true) @@ -439,19 +443,23 @@ class TextEditorComponent onGutterShiftClick: (event) => clickedRow = @screenPositionForMouseEvent(event).row + clickedBufferRow = @editor.bufferRowForScreenRow(clickedRow) tailPosition = @editor.getLastSelection().getTailScreenPosition() + tailBufferPosition = @editor.bufferPositionForScreenPosition(tailPosition) if clickedRow < tailPosition.row - @editor.selectToScreenPosition([clickedRow, 0]) + @editor.selectToBufferPosition([clickedBufferRow, 0]) else - @editor.selectToScreenPosition([clickedRow + 1, 0]) + @editor.selectToBufferPosition([clickedBufferRow + 1, 0]) @handleDragUntilMouseUp event, (screenPosition) => dragRow = screenPosition.row + dragBufferRow = @editor.bufferRowForScreenRow(dragRow) if dragRow < tailPosition.row # dragging up - @editor.setSelectedScreenRange([[dragRow, 0], tailPosition], preserveFolds: true) + @editor.setSelectedBufferRange([[dragBufferRow, 0], tailBufferPosition], preserveFolds: true) else - @editor.setSelectedScreenRange([tailPosition, [dragRow + 1, 0]], preserveFolds: true) + @editor.setSelectedBufferRange([tailBufferPosition, [dragBufferRow + 1, 0]], preserveFolds: true) + onStylesheetsChanged: (styleElement) => return unless @performedInitialMeasurement From 2987d37373596ceaa8872cef88550b5c5660e38c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 2 Mar 2015 14:16:09 -0800 Subject: [PATCH 0011/1783] :fire: ; --- src/project.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/project.coffee b/src/project.coffee index c92462ead..b0c1ffb0b 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -53,7 +53,7 @@ class Project extends Model # to either a {Repository} or null. Ideally, the {Directory} would be used # as the key; however, there can be multiple {Directory} objects created for # the same real path, so it is not a good key. - @repositoryPromisesByPath = new Map(); + @repositoryPromisesByPath = new Map() # Note that the GitRepositoryProvider is registered synchronously so that # it is available immediately on startup. From b74a688baa1a23fcfda9d5715e74301deb83cfbd Mon Sep 17 00:00:00 2001 From: Mostafa Eweda Date: Mon, 2 Mar 2015 14:28:01 -0800 Subject: [PATCH 0012/1783] Bare minimum fix to the default directory provider --- spec/project-spec.coffee | 14 ++++++++++++++ src/default-directory-provider.coffee | 11 ++++------- src/project.coffee | 11 ++++------- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/spec/project-spec.coffee b/spec/project-spec.coffee index 0d115f56f..476d731ee 100644 --- a/spec/project-spec.coffee +++ b/spec/project-spec.coffee @@ -78,6 +78,20 @@ describe "Project", -> expect(directories.length).toBe 1 expect(directories[0].getPath()).toBe tmp + it "gets the parent directory from the default directory provider if it's a local directory", -> + tmp = temp.mkdirSync() + atom.project.setPaths([path.join(tmp, "not-existing")]) + directories = atom.project.getDirectories() + expect(directories.length).toBe 1 + expect(directories[0].getPath()).toBe tmp + + it "only normalizes the directory path if it isn't on the local filesystem", -> + nonLocalFsDirectory = "custom_proto://abc/def" + atom.project.setPaths([nonLocalFsDirectory]) + directories = atom.project.getDirectories() + expect(directories.length).toBe 1 + expect(directories[0].getPath()).toBe path.normalize(nonLocalFsDirectory) + it "tries to update repositories when a new RepositoryProvider is registered", -> tmp = temp.mkdirSync('atom-project') atom.project.setPaths([tmp]) diff --git a/src/default-directory-provider.coffee b/src/default-directory-provider.coffee index 5ddc89cca..a05c532a9 100644 --- a/src/default-directory-provider.coffee +++ b/src/default-directory-provider.coffee @@ -16,15 +16,12 @@ class DefaultDirectoryProvider directoryForURISync: (uri) -> projectPath = path.normalize(uri) - directoryPath = if fs.isDirectorySync(projectPath) - projectPath - else + directoryPath = if !fs.isDirectorySync(projectPath) and fs.isDirectorySync(path.dirname(projectPath)) path.dirname(projectPath) - - if fs.isDirectorySync(projectPath) - return new Directory(directoryPath) else - return null + projectPath + + new Directory(directoryPath) # Public: Create a Directory that corresponds to the specified URI. # diff --git a/src/project.coffee b/src/project.coffee index 79cd7439b..c92462ead 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -39,7 +39,6 @@ class Project extends Model @emitter = new Emitter @buffers ?= [] @rootDirectories = [] - @packageRootDirectoryPaths = [] @repositories = [] @directoryProviders = [new DefaultDirectoryProvider()] @@ -204,12 +203,10 @@ class Project extends Model for provider in @directoryProviders break if directory = provider.directoryForURISync?(projectPath) if directory is null - # DefaultDirectoryProvider doesn't handle specific directory protocols - # Atom Packages may use packageDirectoryPaths to add their own paths later. - @packageRootDirectoryPaths.push(projectPath) - return - else - @rootDirectories.push(directory) + # This should never happen because DefaultDirectoryProvider should always + # return a Directory. + throw new Error(projectPath + ' could not be resolved to a directory') + @rootDirectories.push(directory) repo = null for provider in @repositoryProviders From 03a064b6e9f4170ce9ffe52b74ff8cdd433e3c9e Mon Sep 17 00:00:00 2001 From: Ivan Zuzak Date: Tue, 3 Mar 2015 13:59:46 +0100 Subject: [PATCH 0013/1783] Add specs for mouse interactions on gutter with soft wrap --- spec/text-editor-component-spec.coffee | 129 +++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 86aab0856..548c88105 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -1845,6 +1845,135 @@ describe "TextEditorComponent", -> nextAnimationFrame() expect(editor.getSelectedScreenRange()).toEqual [[3, 4], [9, 0]] + describe "when soft wrap is enabled", -> + beforeEach -> + gutterNode = componentNode.querySelector('.gutter') + + editor.setSoftWrapped(true) + nextAnimationFrame() + componentNode.style.width = 21 * charWidth + editor.getVerticalScrollbarWidth() + 'px' + component.measureHeightAndWidth() + nextAnimationFrame() + + describe "when the gutter is clicked", -> + it "selects the clicked buffer row", -> + gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(1))) + expect(editor.getSelectedScreenRange()).toEqual [[0, 0], [2, 0]] + + describe "when the gutter is meta-clicked", -> + it "creates a new selection for the clicked buffer row", -> + editor.setSelectedScreenRange([[1, 0], [1, 2]]) + + gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(2), metaKey: true)) + expect(editor.getSelectedScreenRanges()).toEqual [[[1, 0], [1, 2]], [[2, 0], [5, 0]]] + + gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(7), metaKey: true)) + expect(editor.getSelectedScreenRanges()).toEqual [[[1, 0], [1, 2]], [[2, 0], [5, 0]], [[5, 0], [10, 0]]] + + describe "when the gutter is shift-clicked", -> + beforeEach -> + editor.setSelectedScreenRange([[7, 4], [7, 6]]) + + describe "when the clicked row is before the current selection's tail", -> + it "selects to the beginning of the clicked buffer row", -> + gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(1), shiftKey: true)) + expect(editor.getSelectedScreenRange()).toEqual [[0, 0], [7, 4]] + + describe "when the clicked row is after the current selection's tail", -> + it "selects to the beginning of the buffer row following the clicked buffer row", -> + gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(11), shiftKey: true)) + expect(editor.getSelectedScreenRange()).toEqual [[7, 4], [16, 0]] + + describe "when the gutter is clicked and dragged", -> + describe "when dragging downward", -> + it "selects the buffer rows between the start and end of the drag", -> + gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(1))) + gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(6))) + nextAnimationFrame() + gutterNode.dispatchEvent(buildMouseEvent('mouseup', clientCoordinatesForScreenRowInGutter(6))) + expect(editor.getSelectedScreenRange()).toEqual [[0, 0], [10, 0]] + + describe "when dragging upward", -> + it "selects the buffer rows between the start and end of the drag", -> + gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(6))) + gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(1))) + nextAnimationFrame() + gutterNode.dispatchEvent(buildMouseEvent('mouseup', clientCoordinatesForScreenRowInGutter(1))) + expect(editor.getSelectedScreenRange()).toEqual [[0, 0], [10, 0]] + + describe "when the gutter is meta-clicked and dragged", -> + beforeEach -> + editor.setSelectedScreenRange([[7, 4], [7, 6]]) + + describe "when dragging downward", -> + it "selects the buffer rows between the start and end of the drag", -> + gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(1), metaKey: true)) + gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(3), metaKey: true)) + nextAnimationFrame() + gutterNode.dispatchEvent(buildMouseEvent('mouseup', clientCoordinatesForScreenRowInGutter(3), metaKey: true)) + expect(editor.getSelectedScreenRanges()).toEqual [[[7, 4], [7, 6]], [[0, 0], [5, 0]]] + + it "merges overlapping selections", -> + gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(1), metaKey: true)) + gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(7), metaKey: true)) + nextAnimationFrame() + gutterNode.dispatchEvent(buildMouseEvent('mouseup', clientCoordinatesForScreenRowInGutter(7), metaKey: true)) + expect(editor.getSelectedScreenRanges()).toEqual [[[0, 0], [10, 0]]] + + describe "when dragging upward", -> + it "selects the buffer rows between the start and end of the drag", -> + gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(17), metaKey: true)) + gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(11), metaKey: true)) + nextAnimationFrame() + gutterNode.dispatchEvent(buildMouseEvent('mouseup', clientCoordinatesForScreenRowInGutter(11), metaKey: true)) + expect(editor.getSelectedScreenRanges()).toEqual [[[7, 4], [7, 6]], [[10, 0], [20, 0]]] + + it "merges overlapping selections", -> + gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(17), metaKey: true)) + gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(9), metaKey: true)) + nextAnimationFrame() + gutterNode.dispatchEvent(buildMouseEvent('mouseup', clientCoordinatesForScreenRowInGutter(9), metaKey: true)) + expect(editor.getSelectedScreenRanges()).toEqual [[[5, 0], [20, 0]]] + + describe "when the gutter is shift-clicked and dragged", -> + describe "when the shift-click is below the existing selection's tail", -> + describe "when dragging downward", -> + it "selects the buffer rows between the existing selection's tail and the end of the drag", -> + editor.setSelectedScreenRange([[1, 4], [1, 7]]) + gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(7), shiftKey: true)) + + gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(11))) + nextAnimationFrame() + expect(editor.getSelectedScreenRange()).toEqual [[1, 4], [16, 0]] + + describe "when dragging upward", -> + it "selects the buffer rows between the end of the drag and the tail of the existing selection", -> + editor.setSelectedScreenRange([[1, 4], [1, 7]]) + gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(11), shiftKey: true)) + + gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(7))) + nextAnimationFrame() + expect(editor.getSelectedScreenRange()).toEqual [[1, 4], [10, 0]] + + describe "when the shift-click is above the existing selection's tail", -> + describe "when dragging upward", -> + it "selects the buffer rows between the end of the drag and the tail of the existing selection", -> + editor.setSelectedScreenRange([[7, 4], [7, 6]]) + gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(3), shiftKey: true)) + + gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(1))) + nextAnimationFrame() + expect(editor.getSelectedScreenRange()).toEqual [[0, 0], [7, 4]] + + describe "when dragging downward", -> + it "selects the buffer rows between the existing selection's tail and the end of the drag", -> + editor.setSelectedScreenRange([[7, 4], [7, 6]]) + gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(1), shiftKey: true)) + + gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(3))) + nextAnimationFrame() + expect(editor.getSelectedScreenRange()).toEqual [[2, 0], [7, 4]] + describe "focus handling", -> inputNode = null From 00023709d3a3652aafb96bcfb4803c735bed98df Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 09:54:42 -0800 Subject: [PATCH 0014/1783] :arrow_up: grunt-atom-shell-installer@0.24 --- build/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/package.json b/build/package.json index ea5b8e6de..6ef5d86ae 100644 --- a/build/package.json +++ b/build/package.json @@ -12,7 +12,7 @@ "fs-plus": "2.x", "github-releases": "~0.2.0", "grunt": "~0.4.1", - "grunt-atom-shell-installer": "^0.23.0", + "grunt-atom-shell-installer": "^0.24.0", "grunt-cli": "~0.1.9", "grunt-coffeelint": "git+https://github.com/atom/grunt-coffeelint.git#cfb99aa99811d52687969532bd5a98011ed95bfe", "grunt-contrib-coffee": "~0.12.0", From b23800084b64e7cdabe0519ff1a03cad17537aa2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 10:30:07 -0800 Subject: [PATCH 0015/1783] Don't write to path when reading is blocked Closes #5092 --- src/browser/squirrel-update.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/browser/squirrel-update.coffee b/src/browser/squirrel-update.coffee index df786af69..600f3c41b 100644 --- a/src/browser/squirrel-update.coffee +++ b/src/browser/squirrel-update.coffee @@ -81,6 +81,10 @@ getPath = (callback) -> spawnReg ['query', environmentKeyPath, '/v', 'Path'], (error, stdout) -> if error? if error.code is 1 + # Don't overwrite path when reading value is disabled + if stdout.indexOf('ERROR: Registry editing has been disabled by your administrator.') isnt -1 + return callback(error) + # The query failed so the Path does not exist yet in the registry return callback(null, '') else From 16c32a64dd35c6d9d1f4c07466a637fe10f0cd42 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 10:38:12 -0800 Subject: [PATCH 0016/1783] Don't corrupt non-ASCII paths Stopgap until a long-term solution is found Closes #5063 --- src/browser/squirrel-update.coffee | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/browser/squirrel-update.coffee b/src/browser/squirrel-update.coffee index 600f3c41b..ae50e7e3c 100644 --- a/src/browser/squirrel-update.coffee +++ b/src/browser/squirrel-update.coffee @@ -76,6 +76,13 @@ installContextMenu = (callback) -> installMenu directoryKeyPath, '%1', -> installMenu(backgroundKeyPath, '%V', callback) +isAscii = (text) -> + index = 0 + while index < text.length + return false if text.charCodeAt(index) > 127 + index++ + true + # Get the user's PATH environment variable registry value. getPath = (callback) -> spawnReg ['query', environmentKeyPath, '/v', 'Path'], (error, stdout) -> @@ -100,7 +107,10 @@ getPath = (callback) -> segments = lines[lines.length - 1]?.split(' ') if segments[1] is 'Path' and segments.length >= 3 pathEnv = segments?[3..].join(' ') - callback(null, pathEnv) + if isAscii(pathEnv) + callback(null, pathEnv) + else + callback(new Error('PATH contains non-ASCII values')) else callback(new Error('Registry query for PATH failed')) From 51f1a697885f3012f098d9a348c4ddc5402c3b27 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 10:41:15 -0800 Subject: [PATCH 0017/1783] Link to issues --- src/browser/squirrel-update.coffee | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/browser/squirrel-update.coffee b/src/browser/squirrel-update.coffee index ae50e7e3c..1603a7c0a 100644 --- a/src/browser/squirrel-update.coffee +++ b/src/browser/squirrel-update.coffee @@ -88,7 +88,8 @@ getPath = (callback) -> spawnReg ['query', environmentKeyPath, '/v', 'Path'], (error, stdout) -> if error? if error.code is 1 - # Don't overwrite path when reading value is disabled + # FIXME Don't overwrite path when reading value is disabled + # https://github.com/atom/atom/issues/5092 if stdout.indexOf('ERROR: Registry editing has been disabled by your administrator.') isnt -1 return callback(error) @@ -110,6 +111,8 @@ getPath = (callback) -> if isAscii(pathEnv) callback(null, pathEnv) else + # FIXME Don't corrupt non-ASCII PATH values + # https://github.com/atom/atom/issues/5063 callback(new Error('PATH contains non-ASCII values')) else callback(new Error('Registry query for PATH failed')) From 3296a3f9e841712b1803f89f1f993264d3bace4f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 11:09:33 -0800 Subject: [PATCH 0018/1783] :arrow_up: grunt-atom-shell-installer@0.25 --- build/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/package.json b/build/package.json index 6ef5d86ae..aa3742e40 100644 --- a/build/package.json +++ b/build/package.json @@ -12,7 +12,7 @@ "fs-plus": "2.x", "github-releases": "~0.2.0", "grunt": "~0.4.1", - "grunt-atom-shell-installer": "^0.24.0", + "grunt-atom-shell-installer": "^0.25.0", "grunt-cli": "~0.1.9", "grunt-coffeelint": "git+https://github.com/atom/grunt-coffeelint.git#cfb99aa99811d52687969532bd5a98011ed95bfe", "grunt-contrib-coffee": "~0.12.0", From 80cd20193a0eaa8bd920a67270267ba3be5fc9cc Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 2 Mar 2015 18:38:25 -0800 Subject: [PATCH 0019/1783] Move the logic for opening empty initial buffer to renderer --- spec/atom-spec.coffee | 43 ++++++++++++++++++++++++++++++++++ src/atom.coffee | 6 +++++ src/browser/atom-window.coffee | 3 ++- 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/spec/atom-spec.coffee b/spec/atom-spec.coffee index 12d094428..27040bcfb 100644 --- a/spec/atom-spec.coffee +++ b/spec/atom-spec.coffee @@ -152,3 +152,46 @@ describe "the `atom` global", -> loadSettings.initialPaths = [dir2, dir1] atom2 = Atom.loadOrCreate("editor") expect(atom2.state.stuff).toBe("cool") + + describe "openInitialEmptyEditorIfNecessary", -> + describe "when there are no paths set", -> + oldPaths = null + + beforeEach -> + oldPaths = atom.project.getPaths() + atom.project.setPaths([]) + + afterEach -> + atom.project.setPaths(oldPaths) + + it "opens an empty buffer", -> + spyOn(atom.workspace, 'open') + atom.openInitialEmptyEditorIfNecessary() + expect(atom.workspace.open).toHaveBeenCalledWith(null, {isInitialEmptyEditor: true}) + + describe "when there is already a buffer open", -> + beforeEach -> + waitsForPromise -> atom.workspace.open() + + it "does not open an empty buffer", -> + spyOn(atom.workspace, 'open') + atom.openInitialEmptyEditorIfNecessary() + expect(atom.workspace.open).not.toHaveBeenCalled() + + describe "when the project has a path", -> + beforeEach -> + spyOn(atom.workspace, 'open') + + it "does not open an empty buffer", -> + atom.openInitialEmptyEditorIfNecessary() + expect(atom.workspace.open).not.toHaveBeenCalled() + + describe "when there is already a buffer open", -> + beforeEach -> + waitsForPromise -> + atom.workspace.open() + + it "does not open an empty buffer", -> + spyOn(atom.workspace, 'open') + atom.openInitialEmptyEditorIfNecessary() + expect(atom.workspace.open).not.toHaveBeenCalled() diff --git a/src/atom.coffee b/src/atom.coffee index 303b0cfe7..a08a4b983 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -605,6 +605,8 @@ class Atom extends Model @setAutoHideMenuBar(newValue) @setAutoHideMenuBar(true) if @config.get('core.autoHideMenuBar') + @openInitialEmptyEditorIfNecessary() + maximize = dimensions?.maximized and process.platform isnt 'darwin' @displayWindow({maximize}) @@ -629,6 +631,10 @@ class Atom extends Model @windowEventHandler?.unsubscribe() + openInitialEmptyEditorIfNecessary: -> + if @project.getPaths().length is 0 and @workspace.getPaneItems().length is 0 + @workspace.open(null, {isInitialEmptyEditor: true}) + ### Section: Messaging the User ### diff --git a/src/browser/atom-window.coffee b/src/browser/atom-window.coffee index 77888fed4..785c11147 100644 --- a/src/browser/atom-window.coffee +++ b/src/browser/atom-window.coffee @@ -73,7 +73,8 @@ class AtomWindow @browserWindow.loadUrl @getUrl(loadSettings) @browserWindow.focusOnWebView() if @isSpec - @openLocations(locationsToOpen) unless @isSpecWindow() + hasPathToOpen = not (locationsToOpen.length is 1 and not locationsToOpen[0].pathToOpen?) + @openLocations(locationsToOpen) if hasPathToOpen and not @isSpecWindow() getUrl: (loadSettingsObj) -> # Ignore the windowState when passing loadSettings via URL, since it could From 80b1d89c62b71ca9b02b6156379d240fba7147a2 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 3 Mar 2015 12:34:54 -0800 Subject: [PATCH 0020/1783] Check getLoadSettings to decide to open initial buffer --- spec/atom-spec.coffee | 19 ++----------------- src/atom.coffee | 2 +- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/spec/atom-spec.coffee b/spec/atom-spec.coffee index 27040bcfb..8603f008b 100644 --- a/spec/atom-spec.coffee +++ b/spec/atom-spec.coffee @@ -155,14 +155,8 @@ describe "the `atom` global", -> describe "openInitialEmptyEditorIfNecessary", -> describe "when there are no paths set", -> - oldPaths = null - beforeEach -> - oldPaths = atom.project.getPaths() - atom.project.setPaths([]) - - afterEach -> - atom.project.setPaths(oldPaths) + spyOn(atom, 'getLoadSettings').andReturn(initialPaths: []) it "opens an empty buffer", -> spyOn(atom.workspace, 'open') @@ -180,18 +174,9 @@ describe "the `atom` global", -> describe "when the project has a path", -> beforeEach -> + spyOn(atom, 'getLoadSettings').andReturn(initialPaths: ['something']) spyOn(atom.workspace, 'open') it "does not open an empty buffer", -> atom.openInitialEmptyEditorIfNecessary() expect(atom.workspace.open).not.toHaveBeenCalled() - - describe "when there is already a buffer open", -> - beforeEach -> - waitsForPromise -> - atom.workspace.open() - - it "does not open an empty buffer", -> - spyOn(atom.workspace, 'open') - atom.openInitialEmptyEditorIfNecessary() - expect(atom.workspace.open).not.toHaveBeenCalled() diff --git a/src/atom.coffee b/src/atom.coffee index a08a4b983..7f2626fa9 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -632,7 +632,7 @@ class Atom extends Model @windowEventHandler?.unsubscribe() openInitialEmptyEditorIfNecessary: -> - if @project.getPaths().length is 0 and @workspace.getPaneItems().length is 0 + if @getLoadSettings().initialPaths?.length is 0 and @workspace.getPaneItems().length is 0 @workspace.open(null, {isInitialEmptyEditor: true}) ### From 5f2f4c10fc342a6d9d0469c2e777b52b0fa30df8 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 12:57:04 -0800 Subject: [PATCH 0021/1783] Prepare 0.186 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c7de1dafc..1bf0b174d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "0.185.0", + "version": "0.186.0", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From 5f7015f30386d6c396acfb1e5c587a999f5d7c5e Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 3 Mar 2015 13:18:02 -0800 Subject: [PATCH 0022/1783] Remove isInitialEmptyEditor --- spec/atom-spec.coffee | 2 +- src/atom.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/atom-spec.coffee b/spec/atom-spec.coffee index 8603f008b..1fca9cf28 100644 --- a/spec/atom-spec.coffee +++ b/spec/atom-spec.coffee @@ -161,7 +161,7 @@ describe "the `atom` global", -> it "opens an empty buffer", -> spyOn(atom.workspace, 'open') atom.openInitialEmptyEditorIfNecessary() - expect(atom.workspace.open).toHaveBeenCalledWith(null, {isInitialEmptyEditor: true}) + expect(atom.workspace.open).toHaveBeenCalledWith(null) describe "when there is already a buffer open", -> beforeEach -> diff --git a/src/atom.coffee b/src/atom.coffee index 7f2626fa9..b59f9252a 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -633,7 +633,7 @@ class Atom extends Model openInitialEmptyEditorIfNecessary: -> if @getLoadSettings().initialPaths?.length is 0 and @workspace.getPaneItems().length is 0 - @workspace.open(null, {isInitialEmptyEditor: true}) + @workspace.open(null) ### Section: Messaging the User From bb9d264e0ce174062d444289a02ba9b08733e159 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 13:49:18 -0800 Subject: [PATCH 0023/1783] Prepare 0.187 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1bf0b174d..b7fc2b820 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "0.186.0", + "version": "0.187.0", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From 3952831ff192b3be678c4af153c0377c77b9ff79 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 13:53:18 -0800 Subject: [PATCH 0024/1783] Add custom notification for ENOSPC save errors Closes #5825 --- src/pane.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pane.coffee b/src/pane.coffee index 15f6fa0da..5cdc3016a 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -683,6 +683,8 @@ class Pane extends Model atom.notifications.addWarning("Unable to save file '#{error.path}'", detail: error.message) else if error.code is 'EROFS' and error.path? atom.notifications.addWarning("Unable to save file: Read-only file system '#{error.path}'") + else if error.code is 'ENOSPC' and error.path? + atom.notifications.addWarning("Unable to save file: No space left on device '#{error.path}'") else if errorMatch = /ENOTDIR, not a directory '([^']+)'/.exec(error.message) fileName = errorMatch[1] atom.notifications.addWarning("Unable to save file: A directory in the path '#{fileName}' could not be written to") From fbde8e1970a34742ce7a95600462b34cbf25dae7 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 17:41:27 -0800 Subject: [PATCH 0025/1783] Disable colors on RPM CI build --- script/rpmbuild | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/rpmbuild b/script/rpmbuild index 0e0f4882c..9613e428d 100755 --- a/script/rpmbuild +++ b/script/rpmbuild @@ -3,4 +3,4 @@ set -e script/build -script/grunt mkrpm publish-build --stack --install-dir /usr +script/grunt mkrpm publish-build --stack --install-dir --no-color /usr From f122125efcc0d0afccf7dcfb827e88f5dfac57e5 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 17:49:28 -0800 Subject: [PATCH 0026/1783] Return early if fs-plus is not installed --- script/cibuild | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/script/cibuild b/script/cibuild index 678e2f123..af5f789e1 100755 --- a/script/cibuild +++ b/script/cibuild @@ -31,8 +31,15 @@ function readEnvironmentVariables() { } function removeNodeModules() { + var fsPlus; try { - require('fs-plus').removeSync(path.resolve(__dirname, '..', 'node_modules')); + fsPlus = require('fs-plus'); + } catch (error) { + return; + } + + try { + fsPlus.removeSync(path.resolve(__dirname, '..', 'node_modules')); } catch (error) { console.error(error.message); process.exit(1); From b6eec80c9f421b5280efb5ad60abb180f6fc8213 Mon Sep 17 00:00:00 2001 From: Alex Mayer Date: Fri, 16 Jan 2015 12:13:08 -0500 Subject: [PATCH 0027/1783] Add ._* to ignored file names Macs generate ._ files when saving to a filesystem other then HFS In shared environments this is a big problem --- src/config-schema.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config-schema.coffee b/src/config-schema.coffee index 1796bb64c..078d7a40b 100644 --- a/src/config-schema.coffee +++ b/src/config-schema.coffee @@ -9,7 +9,7 @@ module.exports = properties: ignoredNames: type: 'array' - default: [".git", ".hg", ".svn", ".DS_Store", "Thumbs.db"] + default: [".git", ".hg", ".svn", ".DS_Store", "._*", "Thumbs.db"] items: type: 'string' excludeVcsIgnoredPaths: From 482b36d4cbfb0be1b1e9379aa4f4d2d36b4f4fbd Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 18:05:09 -0800 Subject: [PATCH 0028/1783] Use proper placement of --no-color arg --- script/rpmbuild | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/rpmbuild b/script/rpmbuild index 9613e428d..1b33bb86e 100755 --- a/script/rpmbuild +++ b/script/rpmbuild @@ -3,4 +3,4 @@ set -e script/build -script/grunt mkrpm publish-build --stack --install-dir --no-color /usr +script/grunt mkrpm publish-build --stack --no-color --install-dir /usr From a0a4dac5712228820f44640bf29b7f4a2923cc45 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Tue, 3 Mar 2015 16:48:58 -0800 Subject: [PATCH 0029/1783] Fix a bug when a URI is passed to atom.project.removePath(). --- spec/project-spec.coffee | 17 +++++++++++++++++ src/project.coffee | 4 +++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/spec/project-spec.coffee b/spec/project-spec.coffee index 476d731ee..02ea81ff4 100644 --- a/spec/project-spec.coffee +++ b/spec/project-spec.coffee @@ -436,6 +436,23 @@ describe "Project", -> expect(atom.project.getPaths()).toEqual([path.join(__dirname, "..", "src")]) expect(atom.project.getRepositories()[0].isSubmodule("src")).toBe false + it "removes a path that is represented as a URI", -> + ftpURI = "ftp://example.com/some/folder" + directoryProvider = + directoryForURISync: (uri) -> + # Dummy implementation of Directory for which GitRepositoryProvider + # will not try to create a GitRepository. + getPath: -> ftpURI + getSubdirectory: -> {} + isRoot: -> true + off: -> + atom.packages.serviceHub.provide( + "atom.directory-provider", "0.1.0", directoryProvider) + atom.project.setPaths([ftpURI]) + expect(atom.project.getPaths()).toEqual [ftpURI] + atom.project.removePath(ftpURI) + expect(atom.project.getPaths()).toEqual [] + describe ".relativize(path)", -> it "returns the path, relative to whichever root directory it is inside of", -> atom.project.addPath(temp.mkdirSync("another-path")) diff --git a/src/project.coffee b/src/project.coffee index b0c1ffb0b..8958b6d43 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -221,7 +221,9 @@ class Project extends Model # # * `projectPath` {String} The path to remove. removePath: (projectPath) -> - projectPath = path.normalize(projectPath) + # The projectPath may be a URI, in which case it should not be normalized. + unless projectPath in @getPaths() + projectPath = path.normalize(projectPath) indexToRemove = null for directory, i in @rootDirectories From 1bda787e0d936500e9acebe353722f5cdd49f1a6 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 4 Mar 2015 08:13:16 -0800 Subject: [PATCH 0030/1783] :arrow_up: snippets to destroy expansion when cursor is destroyed --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b7fc2b820..06f5b2e87 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "package-generator": "0.38.0", "release-notes": "0.51.0", "settings-view": "0.183.0", - "snippets": "0.78.0", + "snippets": "0.79.0", "spell-check": "0.55.0", "status-bar": "0.60.0", "styleguide": "0.44.0", From 4ce6bea00345daa93fed0e0f00f7878311c46bf6 Mon Sep 17 00:00:00 2001 From: Mostafa Eweda Date: Wed, 4 Mar 2015 09:51:29 -0800 Subject: [PATCH 0031/1783] Export TextBuffer for external package usage --- exports/atom.coffee | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/exports/atom.coffee b/exports/atom.coffee index 36b69d892..5afa04022 100644 --- a/exports/atom.coffee +++ b/exports/atom.coffee @@ -1,4 +1,5 @@ -{Point, Range} = require 'text-buffer' +TextBuffer = require 'text-buffer' +{Point, Range} = TextBuffer {Emitter, Disposable, CompositeDisposable} = require 'event-kit' {deprecate} = require 'grim' @@ -7,6 +8,7 @@ module.exports = BufferedProcess: require '../src/buffered-process' GitRepository: require '../src/git-repository' Notification: require '../src/notification' + TextBuffer: TextBuffer Point: Point Range: Range Emitter: Emitter From 8ba098b6407934803f92786fd5176fd61e5f9aaa Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 14:38:15 -0800 Subject: [PATCH 0032/1783] Throw an error when adding an invalid selector --- spec/command-registry-spec.coffee | 10 ++++++++++ src/command-registry.coffee | 16 ++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/spec/command-registry-spec.coffee b/spec/command-registry-spec.coffee index 2af185b16..b92d3e6b0 100644 --- a/spec/command-registry-spec.coffee +++ b/spec/command-registry-spec.coffee @@ -148,6 +148,16 @@ describe "CommandRegistry", -> grandchild.dispatchEvent(new CustomEvent('command-2', bubbles: true)) expect(calls).toEqual [] + describe "::add(selector, commandName, callback)", -> + it "throws an error when called with an invalid selector", -> + badSelector = '<>' + addError = null + try + registry.add badSelector, 'foo:bar', -> + catch error + addError = error + expect(addError.message).toContain(badSelector) + describe "::findCommands({target})", -> it "returns commands that can be invoked on the target or its ancestors", -> registry.add '.parent', 'namespace:command-1', -> diff --git a/src/command-registry.coffee b/src/command-registry.coffee index 71e35f7e5..8d4b86dd5 100644 --- a/src/command-registry.coffee +++ b/src/command-registry.coffee @@ -87,6 +87,8 @@ class CommandRegistry return disposable if typeof target is 'string' + unless @isSelectorValid(target) + throw new Error("'#{target}' is not a valid selector") @addSelectorBasedListener(target, commandName, callback) else @addInlineListener(target, commandName, callback) @@ -235,6 +237,20 @@ class CommandRegistry window.addEventListener(commandName, @handleCommandEvent, true) @registeredCommands[commandName] = true + isSelectorValid: (selector) -> + @selectorCache ?= {} + cachedValue = @selectorCache[selector] + return cachedValue if cachedValue? + + @testElement ?= document.createElement('div') + try + @testElement.webkitMatchesSelector(selector) + @selectorCache[selector] = true + true + catch selectorError + @selectorCache[selector] = false + false + class SelectorBasedListener constructor: (@selector, @callback) -> @specificity = (SpecificityCache[@selector] ?= specificity(@selector)) From 333a495d55493d093452266e34ec6395c15a5e97 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 14:38:30 -0800 Subject: [PATCH 0033/1783] Catch errors adding activation commands --- .../package.json | 9 +++++++++ .../packages/package-with-invalid-selectors/package.json | 9 +++++++++ spec/package-manager-spec.coffee | 5 +++++ src/package.coffee | 5 ++++- 4 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 spec/fixtures/packages/package-with-invalid-activation-commands/package.json create mode 100644 spec/fixtures/packages/package-with-invalid-selectors/package.json diff --git a/spec/fixtures/packages/package-with-invalid-activation-commands/package.json b/spec/fixtures/packages/package-with-invalid-activation-commands/package.json new file mode 100644 index 000000000..d98b7ef92 --- /dev/null +++ b/spec/fixtures/packages/package-with-invalid-activation-commands/package.json @@ -0,0 +1,9 @@ +{ + "name": "package-with-invalid-selectors", + "version": "1.0.0", + "activationCommands": { + "<>": [ + "foo:bar" + ] + } +} diff --git a/spec/fixtures/packages/package-with-invalid-selectors/package.json b/spec/fixtures/packages/package-with-invalid-selectors/package.json new file mode 100644 index 000000000..d98b7ef92 --- /dev/null +++ b/spec/fixtures/packages/package-with-invalid-selectors/package.json @@ -0,0 +1,9 @@ +{ + "name": "package-with-invalid-selectors", + "version": "1.0.0", + "activationCommands": { + "<>": [ + "foo:bar" + ] + } +} diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index d9898505c..4d6c56d4e 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -212,6 +212,11 @@ describe "PackageManager", -> runs -> expect(mainModule.activate.callCount).toBe 1 + it "logs a warning when the activation commands are invalid", -> + spyOn(console, 'warn') + expect(-> atom.packages.activatePackage('package-with-invalid-activation-commands')).not.toThrow() + expect(console.warn.callCount).toBe(1) + describe "when the package has no main module", -> it "does not throw an exception", -> spyOn(console, "error") diff --git a/src/package.coffee b/src/package.coffee index d8ba4a1d8..e47b0038a 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -146,7 +146,10 @@ class Package @measure 'activateTime', => @activateResources() if @hasActivationCommands() - @subscribeToActivationCommands() + try + @subscribeToActivationCommands() + catch e + console.warn "Failed to subscribe to activation commands for package '#{@name}'", e.stack else @activateNow() From 2a12f7779d8c4abc3b138335d4fe6493db6b41dc Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 14:46:35 -0800 Subject: [PATCH 0034/1783] Add selector parser helper class --- src/command-registry.coffee | 17 ++--------------- src/selector-parser.coffee | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 15 deletions(-) create mode 100644 src/selector-parser.coffee diff --git a/src/command-registry.coffee b/src/command-registry.coffee index 8d4b86dd5..ac77bcc27 100644 --- a/src/command-registry.coffee +++ b/src/command-registry.coffee @@ -2,6 +2,7 @@ {specificity} = require 'clear-cut' _ = require 'underscore-plus' {$} = require './space-pen-extensions' +{isSelectorValid} = require './selector-parser' SequenceCount = 0 SpecificityCache = {} @@ -87,7 +88,7 @@ class CommandRegistry return disposable if typeof target is 'string' - unless @isSelectorValid(target) + unless isSelectorValid(target) throw new Error("'#{target}' is not a valid selector") @addSelectorBasedListener(target, commandName, callback) else @@ -237,20 +238,6 @@ class CommandRegistry window.addEventListener(commandName, @handleCommandEvent, true) @registeredCommands[commandName] = true - isSelectorValid: (selector) -> - @selectorCache ?= {} - cachedValue = @selectorCache[selector] - return cachedValue if cachedValue? - - @testElement ?= document.createElement('div') - try - @testElement.webkitMatchesSelector(selector) - @selectorCache[selector] = true - true - catch selectorError - @selectorCache[selector] = false - false - class SelectorBasedListener constructor: (@selector, @callback) -> @specificity = (SpecificityCache[@selector] ?= specificity(@selector)) diff --git a/src/selector-parser.coffee b/src/selector-parser.coffee new file mode 100644 index 000000000..fc3744a1f --- /dev/null +++ b/src/selector-parser.coffee @@ -0,0 +1,16 @@ +selectorCache = null +testElement = null + +exports.isSelectorValid = (selector) -> + selectorCache ?= {} + cachedValue = selectorCache[selector] + return cachedValue if cachedValue? + + testElement ?= document.createElement('div') + try + testElement.webkitMatchesSelector(selector) + selectorCache[selector] = true + true + catch selectorError + selectorCache[selector] = false + false From 5902bc42e983289aa0fd080940b19b81e2636ca1 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 14:52:18 -0800 Subject: [PATCH 0035/1783] Throw error when adding context menu with invalid selector --- spec/context-menu-manager-spec.coffee | 8 ++++++++ src/context-menu-manager.coffee | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/spec/context-menu-manager-spec.coffee b/spec/context-menu-manager-spec.coffee index 1c3c1f21a..ab1f05080 100644 --- a/spec/context-menu-manager-spec.coffee +++ b/spec/context-menu-manager-spec.coffee @@ -151,6 +151,14 @@ describe "ContextMenuManager", -> shouldDisplay = false expect(contextMenu.templateForEvent(dispatchedEvent)).toEqual [] + it "throws an error when the selector is invalid", -> + addError = null + try + contextMenu.add '<>': [{label: 'A', command: 'a'}] + catch error + addError = error + expect(addError.message).toContain('<>') + describe "when the menus are specified in a legacy format", -> beforeEach -> jasmine.snapshotDeprecations() diff --git a/src/context-menu-manager.coffee b/src/context-menu-manager.coffee index b890fc29a..f6d2d7f96 100644 --- a/src/context-menu-manager.coffee +++ b/src/context-menu-manager.coffee @@ -8,6 +8,7 @@ fs = require 'fs-plus' {Disposable} = require 'event-kit' Grim = require 'grim' MenuHelpers = require './menu-helpers' +{isSelectorValid} = require './selector-parser' SpecificityCache = {} @@ -123,6 +124,9 @@ class ContextMenuManager addedItemSets = [] for selector, items of itemsBySelector + unless isSelectorValid(selector) + throw new Error("'#{selector}' is not a valid selector") + itemSet = new ContextMenuItemSet(selector, items) addedItemSets.push(itemSet) @itemSets.push(itemSet) From a7bd20f08f3728ed41e388ebe3df9273bc29fbdb Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 14:53:50 -0800 Subject: [PATCH 0036/1783] Remove unused fixture --- .../packages/package-with-invalid-selectors/package.json | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 spec/fixtures/packages/package-with-invalid-selectors/package.json diff --git a/spec/fixtures/packages/package-with-invalid-selectors/package.json b/spec/fixtures/packages/package-with-invalid-selectors/package.json deleted file mode 100644 index d98b7ef92..000000000 --- a/spec/fixtures/packages/package-with-invalid-selectors/package.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "package-with-invalid-selectors", - "version": "1.0.0", - "activationCommands": { - "<>": [ - "foo:bar" - ] - } -} From c172f78ab54fd8d399e1d472000d0bb70d706e0e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 16:06:38 -0800 Subject: [PATCH 0037/1783] Use consistent selector error --- src/command-registry.coffee | 5 ++--- src/context-menu-manager.coffee | 5 ++--- src/selector-parser.coffee | 7 +++++++ 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/command-registry.coffee b/src/command-registry.coffee index ac77bcc27..07ebcd812 100644 --- a/src/command-registry.coffee +++ b/src/command-registry.coffee @@ -2,7 +2,7 @@ {specificity} = require 'clear-cut' _ = require 'underscore-plus' {$} = require './space-pen-extensions' -{isSelectorValid} = require './selector-parser' +{validateSelector} = require './selector-parser' SequenceCount = 0 SpecificityCache = {} @@ -88,8 +88,7 @@ class CommandRegistry return disposable if typeof target is 'string' - unless isSelectorValid(target) - throw new Error("'#{target}' is not a valid selector") + validateSelector(target) @addSelectorBasedListener(target, commandName, callback) else @addInlineListener(target, commandName, callback) diff --git a/src/context-menu-manager.coffee b/src/context-menu-manager.coffee index f6d2d7f96..0cc56079b 100644 --- a/src/context-menu-manager.coffee +++ b/src/context-menu-manager.coffee @@ -8,7 +8,7 @@ fs = require 'fs-plus' {Disposable} = require 'event-kit' Grim = require 'grim' MenuHelpers = require './menu-helpers' -{isSelectorValid} = require './selector-parser' +{validateSelector} = require './selector-parser' SpecificityCache = {} @@ -124,8 +124,7 @@ class ContextMenuManager addedItemSets = [] for selector, items of itemsBySelector - unless isSelectorValid(selector) - throw new Error("'#{selector}' is not a valid selector") + validateSelector(selector) itemSet = new ContextMenuItemSet(selector, items) addedItemSets.push(itemSet) diff --git a/src/selector-parser.coffee b/src/selector-parser.coffee index fc3744a1f..ddb7c337a 100644 --- a/src/selector-parser.coffee +++ b/src/selector-parser.coffee @@ -1,6 +1,13 @@ selectorCache = null testElement = null +exports.validateSelector = (selector) -> + return if exports.isSelectorValid(selector) + + error = new Error("'#{selector}' is not a valid selector") + error.code = 'EBADSELECTOR' + throw error + exports.isSelectorValid = (selector) -> selectorCache ?= {} cachedValue = selectorCache[selector] From 8ba434f4c42604a369aa089ea1885874ee9f9ff5 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 16:08:10 -0800 Subject: [PATCH 0038/1783] Show notifications on load/activate errors --- src/package.coffee | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/package.coffee b/src/package.coffee index e47b0038a..530a06c2b 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -126,9 +126,8 @@ class Package @loadStylesheets() @settingsPromise = @loadSettings() @requireMainModule() unless @hasActivationCommands() - catch error - console.warn "Failed to load package named '#{@name}'", error.stack ? error + @handleError("Failed to load the #{@name} package", error) this reset: -> @@ -148,8 +147,12 @@ class Package if @hasActivationCommands() try @subscribeToActivationCommands() - catch e - console.warn "Failed to subscribe to activation commands for package '#{@name}'", e.stack + catch error + if error.code is 'EBADSELECTOR' + metadataPath = path.join(@path, 'package.json') + error.message += " in #{metadataPath}" + error.stack += "\n at #{metadataPath}:1:1" + @handleError("Failed to activate the #{@name} package", error) else @activateNow() @@ -163,8 +166,8 @@ class Package @mainModule.activate?(atom.packages.getPackageState(@name) ? {}) @mainActivated = true @activateServices() - catch e - console.warn "Failed to activate package named '#{@name}'", e.stack + catch error + @handleError("Failed to activate the #{@name} package", error) @activationDeferred?.resolve() @@ -531,3 +534,18 @@ class Package @compatible = @incompatibleModules.length is 0 else @compatible = true + + handleError: (message, error) -> + if error.filename and error.location and (error instanceof SyntaxError) + location = "#{error.filename}:#{error.location.first_line + 1}:#{error.location.first_column + 1}" + detail = "#{error.message} in #{location}" + stack = """ + SyntaxError: #{error.message} + at #{location} + """ + else + detail = error.message + stack = error.stack ? error + + console.trace() + atom.notifications.addFatalError(message, {stack, detail, dismissable: true}) From 33e01256a7c6f56dea0c68cb042f62c96762da35 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 16:08:30 -0800 Subject: [PATCH 0039/1783] Only manipulate stack for selector errors --- src/package.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package.coffee b/src/package.coffee index 530a06c2b..07726aa0a 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -151,7 +151,7 @@ class Package if error.code is 'EBADSELECTOR' metadataPath = path.join(@path, 'package.json') error.message += " in #{metadataPath}" - error.stack += "\n at #{metadataPath}:1:1" + error.stack += "\n at #{metadataPath}:1:1" @handleError("Failed to activate the #{@name} package", error) else @activateNow() From cb0bf287935b71528bf1d8dd331f2868f4348003 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 16:21:53 -0800 Subject: [PATCH 0040/1783] Remove stray trace --- src/package.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/package.coffee b/src/package.coffee index 07726aa0a..6d1e674b3 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -547,5 +547,4 @@ class Package detail = error.message stack = error.stack ? error - console.trace() atom.notifications.addFatalError(message, {stack, detail, dismissable: true}) From fa2eab5b7ef379204f9da7b97cb0242b0415e60a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 16:28:48 -0800 Subject: [PATCH 0041/1783] Show notification when parsing package.json fails --- spec/package-manager-spec.coffee | 8 ++++---- src/package-manager.coffee | 24 +++++++++++++++--------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 4d6c56d4e..bab5bb260 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -18,7 +18,6 @@ describe "PackageManager", -> expect(pack.metadata.name).toBe "package-with-index" it "returns the package if it has an invalid keymap", -> - spyOn(console, 'warn') pack = atom.packages.loadPackage("package-with-broken-keymap") expect(pack instanceof Package).toBe true expect(pack.metadata.name).toBe "package-with-broken-keymap" @@ -30,10 +29,11 @@ describe "PackageManager", -> expect(pack.stylesheets.length).toBe 0 it "returns null if the package has an invalid package.json", -> - spyOn(console, 'warn') + addErrorHandler = jasmine.createSpy() + atom.notifications.onDidAddNotification(addErrorHandler) expect(atom.packages.loadPackage("package-with-broken-package-json")).toBeNull() - expect(console.warn.callCount).toBe(1) - expect(console.warn.argsForCall[0][0]).toContain("Failed to load package.json") + expect(addErrorHandler.callCount).toBe 1 + expect(addErrorHandler.argsForCall[0][0].message).toContain("Failed to load the package-with-broken-package-json package") it "returns null if the package is not found in any package directory", -> spyOn(console, 'warn') diff --git a/src/package-manager.coffee b/src/package-manager.coffee index bcd7dc28e..22c62e9b4 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -343,16 +343,22 @@ class PackageManager try metadata = Package.loadMetadata(packagePath) ? {} - if metadata.theme - pack = new ThemePackage(packagePath, metadata) - else - pack = new Package(packagePath, metadata) - pack.load() - @loadedPackages[pack.name] = pack - @emitter.emit 'did-load-package', pack - return pack catch error - console.warn "Failed to load package.json '#{path.basename(packagePath)}'", error.stack ? error + metadataPath = path.join(packagePath, 'package.json') + detail = error.message + " in #{metadataPath}" + stack = error.stack + "\n at #{metadataPath}:1:1" + message = "Failed to load the #{path.basename(packagePath)} package" + atom.notifications.addFatalError(message, {stack, detail, dismissable: true}) + return null + + if metadata.theme + pack = new ThemePackage(packagePath, metadata) + else + pack = new Package(packagePath, metadata) + pack.load() + @loadedPackages[pack.name] = pack + @emitter.emit 'did-load-package', pack + return pack else console.warn "Could not resolve '#{nameOrPath}' to a package path" null From 6c87dc05f3a0866d0ec6b38770a70985b9c6fddf Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 16:33:58 -0800 Subject: [PATCH 0042/1783] Migrate specs from console.warn to notifications --- spec/package-manager-spec.coffee | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index bab5bb260..58392ccbc 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -213,9 +213,11 @@ describe "PackageManager", -> expect(mainModule.activate.callCount).toBe 1 it "logs a warning when the activation commands are invalid", -> - spyOn(console, 'warn') + addErrorHandler = jasmine.createSpy() + atom.notifications.onDidAddNotification(addErrorHandler) expect(-> atom.packages.activatePackage('package-with-invalid-activation-commands')).not.toThrow() - expect(console.warn.callCount).toBe(1) + expect(addErrorHandler.callCount).toBe 1 + expect(addErrorHandler.argsForCall[0][0].message).toContain("Failed to activate the package-with-invalid-activation-commands package") describe "when the package has no main module", -> it "does not throw an exception", -> @@ -262,11 +264,14 @@ describe "PackageManager", -> runs -> expect(activatedPackage.name).toBe 'package-with-main' describe "when the package throws an error while loading", -> - it "logs a warning instead of throwing an exception", -> + fit "adds a notification instead of throwing an exception", -> atom.config.set("core.disabledPackages", []) - spyOn(console, "warn") + addErrorHandler = jasmine.createSpy() + atom.notifications.onDidAddNotification(addErrorHandler) expect(-> atom.packages.activatePackage("package-that-throws-an-exception")).not.toThrow() - expect(console.warn).toHaveBeenCalled() + expect(addErrorHandler.callCount).toBe 2 + expect(addErrorHandler.argsForCall[0][0].message).toContain("Failed to load the package-that-throws-an-exception package") + expect(addErrorHandler.argsForCall[1][0].message).toContain("Failed to activate the package-that-throws-an-exception package") describe "when the package is not found", -> it "rejects the promise", -> From 628380ff3dd5c091374cc95338df2470604e619b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 16:35:58 -0800 Subject: [PATCH 0043/1783] Unfocus spec --- spec/package-manager-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 58392ccbc..773f8ffa5 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -264,7 +264,7 @@ describe "PackageManager", -> runs -> expect(activatedPackage.name).toBe 'package-with-main' describe "when the package throws an error while loading", -> - fit "adds a notification instead of throwing an exception", -> + it "adds a notification instead of throwing an exception", -> atom.config.set("core.disabledPackages", []) addErrorHandler = jasmine.createSpy() atom.notifications.onDidAddNotification(addErrorHandler) From a2d9ba2d2e7f1ff14b820dd8520917b34a1943e6 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 16:40:39 -0800 Subject: [PATCH 0044/1783] Only try to require main module once --- spec/package-manager-spec.coffee | 5 ++--- src/package.coffee | 6 ++++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 773f8ffa5..5855006dd 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -2,7 +2,7 @@ Package = require '../src/package' {Disposable} = require 'atom' -describe "PackageManager", -> +fdescribe "PackageManager", -> workspaceElement = null beforeEach -> @@ -269,9 +269,8 @@ describe "PackageManager", -> addErrorHandler = jasmine.createSpy() atom.notifications.onDidAddNotification(addErrorHandler) expect(-> atom.packages.activatePackage("package-that-throws-an-exception")).not.toThrow() - expect(addErrorHandler.callCount).toBe 2 + expect(addErrorHandler.callCount).toBe 1 expect(addErrorHandler.argsForCall[0][0].message).toContain("Failed to load the package-that-throws-an-exception package") - expect(addErrorHandler.argsForCall[1][0].message).toContain("Failed to activate the package-that-throws-an-exception package") describe "when the package is not found", -> it "rejects the promise", -> diff --git a/src/package.coffee b/src/package.coffee index 6d1e674b3..ef4cc9c42 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -376,7 +376,7 @@ class Package @activateStylesheets() requireMainModule: -> - return @mainModule if @mainModule? + return @mainModule if @mainModuleRequired unless @isCompatible() console.warn """ Failed to require the main module of '#{@name}' because it requires an incompatible native module. @@ -384,7 +384,9 @@ class Package """ return mainModulePath = @getMainModulePath() - @mainModule = require(mainModulePath) if fs.isFileSync(mainModulePath) + if fs.isFileSync(mainModulePath) + @mainModuleRequired = true + @mainModule = require(mainModulePath) getMainModulePath: -> return @mainModulePath if @resolvedMainModulePath From 59c3dea77bcdd8d67cc030fb85621bb8e6e071d9 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 16:51:38 -0800 Subject: [PATCH 0045/1783] Show notification for invalid context menu selector --- .../menus/menu.json | 10 +++++ .../package.json | 4 ++ spec/package-manager-spec.coffee | 11 +++++- src/package.coffee | 39 ++++++++++++------- 4 files changed, 49 insertions(+), 15 deletions(-) create mode 100644 spec/fixtures/packages/package-with-invalid-context-menu/menus/menu.json create mode 100644 spec/fixtures/packages/package-with-invalid-context-menu/package.json diff --git a/spec/fixtures/packages/package-with-invalid-context-menu/menus/menu.json b/spec/fixtures/packages/package-with-invalid-context-menu/menus/menu.json new file mode 100644 index 000000000..67197f8fe --- /dev/null +++ b/spec/fixtures/packages/package-with-invalid-context-menu/menus/menu.json @@ -0,0 +1,10 @@ +{ + "context-menu": { + "<>": [ + { + "label": "Hello", + "command:": "world" + } + ] + } +} diff --git a/spec/fixtures/packages/package-with-invalid-context-menu/package.json b/spec/fixtures/packages/package-with-invalid-context-menu/package.json new file mode 100644 index 000000000..c742d422a --- /dev/null +++ b/spec/fixtures/packages/package-with-invalid-context-menu/package.json @@ -0,0 +1,4 @@ +{ + "name": "package-with-invalid-context-menu", + "version": "1.0.0" +} diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 5855006dd..a021f979a 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -2,7 +2,7 @@ Package = require '../src/package' {Disposable} = require 'atom' -fdescribe "PackageManager", -> +describe "PackageManager", -> workspaceElement = null beforeEach -> @@ -212,13 +212,20 @@ fdescribe "PackageManager", -> runs -> expect(mainModule.activate.callCount).toBe 1 - it "logs a warning when the activation commands are invalid", -> + it "adds a notification when the activation commands are invalid", -> addErrorHandler = jasmine.createSpy() atom.notifications.onDidAddNotification(addErrorHandler) expect(-> atom.packages.activatePackage('package-with-invalid-activation-commands')).not.toThrow() expect(addErrorHandler.callCount).toBe 1 expect(addErrorHandler.argsForCall[0][0].message).toContain("Failed to activate the package-with-invalid-activation-commands package") + it "adds a notification when the context menu is invalid", -> + addErrorHandler = jasmine.createSpy() + atom.notifications.onDidAddNotification(addErrorHandler) + expect(-> atom.packages.activatePackage('package-with-invalid-context-menu')).not.toThrow() + expect(addErrorHandler.callCount).toBe 1 + expect(addErrorHandler.argsForCall[0][0].message).toContain("Failed to activate the package-with-invalid-context-menu package") + describe "when the package has no main module", -> it "does not throw an exception", -> spyOn(console, "error") diff --git a/src/package.coffee b/src/package.coffee index ef4cc9c42..148e5d4e4 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -143,18 +143,14 @@ class Package unless @activationDeferred? @activationDeferred = Q.defer() @measure 'activateTime', => - @activateResources() - if @hasActivationCommands() - try + try + @activateResources() + if @hasActivationCommands() @subscribeToActivationCommands() - catch error - if error.code is 'EBADSELECTOR' - metadataPath = path.join(@path, 'package.json') - error.message += " in #{metadataPath}" - error.stack += "\n at #{metadataPath}:1:1" - @handleError("Failed to activate the #{@name} package", error) - else - @activateNow() + else + @activateNow() + catch error + @handleError("Failed to activate the #{@name} package", error) Q.all([@grammarsPromise, @settingsPromise, @activationDeferred.promise]) @@ -206,7 +202,16 @@ class Package activateResources: -> @activationDisposables = new CompositeDisposable @activationDisposables.add(atom.keymaps.add(keymapPath, map)) for [keymapPath, map] in @keymaps - @activationDisposables.add(atom.contextMenu.add(map['context-menu'])) for [menuPath, map] in @menus when map['context-menu']? + + for [menuPath, map] in @menus when map['context-menu']? + try + @activationDisposables.add(atom.contextMenu.add(map['context-menu'])) + catch error + if error.code is 'EBADSELECTOR' + error.message += " in #{menuPath}" + error.stack += "\n at #{menuPath}:1:1" + throw error + @activationDisposables.add(atom.menu.add(map['menu'])) for [menuPath, map] in @menus when map['menu']? unless @grammarsActivated @@ -417,7 +422,15 @@ class Package do (selector, command) => # Add dummy command so it appears in menu. # The real command will be registered on package activation - @activationCommandSubscriptions.add atom.commands.add selector, command, -> + try + @activationCommandSubscriptions.add atom.commands.add selector, command, -> + catch error + if error.code is 'EBADSELECTOR' + metadataPath = path.join(@path, 'package.json') + error.message += " in #{metadataPath}" + error.stack += "\n at #{metadataPath}:1:1" + throw error + @activationCommandSubscriptions.add atom.commands.onWillDispatch (event) => return unless event.type is command currentTarget = event.target From 1bb011deed3bb23ddf3573db4732970fb2b30ea4 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 16:55:37 -0800 Subject: [PATCH 0046/1783] :art: --- src/context-menu-manager.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/context-menu-manager.coffee b/src/context-menu-manager.coffee index 0cc56079b..56f85199f 100644 --- a/src/context-menu-manager.coffee +++ b/src/context-menu-manager.coffee @@ -125,7 +125,6 @@ class ContextMenuManager for selector, items of itemsBySelector validateSelector(selector) - itemSet = new ContextMenuItemSet(selector, items) addedItemSets.push(itemSet) @itemSets.push(itemSet) From 7b38750b95e0925b6681445f5d859a0a7d7969d4 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 16:57:25 -0800 Subject: [PATCH 0047/1783] :memo: Doc selector parser --- src/selector-parser.coffee | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/selector-parser.coffee b/src/selector-parser.coffee index ddb7c337a..6b2afffc1 100644 --- a/src/selector-parser.coffee +++ b/src/selector-parser.coffee @@ -1,13 +1,8 @@ selectorCache = null testElement = null -exports.validateSelector = (selector) -> - return if exports.isSelectorValid(selector) - - error = new Error("'#{selector}' is not a valid selector") - error.code = 'EBADSELECTOR' - throw error - +# Parses CSS selectors and memoizes their validity so each selector will only +# be parsed once. exports.isSelectorValid = (selector) -> selectorCache ?= {} cachedValue = selectorCache[selector] @@ -21,3 +16,11 @@ exports.isSelectorValid = (selector) -> catch selectorError selectorCache[selector] = false false + +# Parse the given selector and throw an error if it is invalid +exports.validateSelector = (selector) -> + return if exports.isSelectorValid(selector) + + error = new Error("'#{selector}' is not a valid selector") + error.code = 'EBADSELECTOR' + throw error From 346e66960158a25ff594fe260838a3fc6cdc5760 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 16:59:36 -0800 Subject: [PATCH 0048/1783] :memo: Mention css --- src/selector-parser.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/selector-parser.coffee b/src/selector-parser.coffee index 6b2afffc1..df8ff0350 100644 --- a/src/selector-parser.coffee +++ b/src/selector-parser.coffee @@ -17,7 +17,7 @@ exports.isSelectorValid = (selector) -> selectorCache[selector] = false false -# Parse the given selector and throw an error if it is invalid +# Parse the given CSS selector and throw an error if it is invalid. exports.validateSelector = (selector) -> return if exports.isSelectorValid(selector) From f611e235e9002b02eb6df797beae51c61a934e05 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 17:00:55 -0800 Subject: [PATCH 0049/1783] Extract notification helper --- src/package-manager.coffee | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 22c62e9b4..58cade753 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -344,11 +344,7 @@ class PackageManager try metadata = Package.loadMetadata(packagePath) ? {} catch error - metadataPath = path.join(packagePath, 'package.json') - detail = error.message + " in #{metadataPath}" - stack = error.stack + "\n at #{metadataPath}:1:1" - message = "Failed to load the #{path.basename(packagePath)} package" - atom.notifications.addFatalError(message, {stack, detail, dismissable: true}) + @handleMetadataError(error, packagePath) return null if metadata.theme @@ -427,3 +423,10 @@ class PackageManager pack.deactivate() delete @activePackages[pack.name] @emitter.emit 'did-deactivate-package', pack + + handleMetadataError: (error, packagePath)-> + metadataPath = path.join(packagePath, 'package.json') + detail = error.message + " in #{metadataPath}" + stack = error.stack + "\n at #{metadataPath}:1:1" + message = "Failed to load the #{path.basename(packagePath)} package" + atom.notifications.addFatalError(message, {stack, detail, dismissable: true}) From 71c138397a8bdb94eec9eeca765b87cbb37d5785 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 17:11:08 -0800 Subject: [PATCH 0050/1783] Remove lint --- src/package-manager.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 58cade753..c663d6064 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -424,7 +424,7 @@ class PackageManager delete @activePackages[pack.name] @emitter.emit 'did-deactivate-package', pack - handleMetadataError: (error, packagePath)-> + handleMetadataError: (error, packagePath) -> metadataPath = path.join(packagePath, 'package.json') detail = error.message + " in #{metadataPath}" stack = error.stack + "\n at #{metadataPath}:1:1" From cec82bd6ca30b20980893981ee2addf058124ea2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 17:26:25 -0800 Subject: [PATCH 0051/1783] Don't use fatal error for package.json errors Notifications can't associate it with a project path since the project never loads --- src/package-manager.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package-manager.coffee b/src/package-manager.coffee index c663d6064..355c65a78 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -429,4 +429,4 @@ class PackageManager detail = error.message + " in #{metadataPath}" stack = error.stack + "\n at #{metadataPath}:1:1" message = "Failed to load the #{path.basename(packagePath)} package" - atom.notifications.addFatalError(message, {stack, detail, dismissable: true}) + atom.notifications.addError(message, {stack, detail, dismissable: true}) From ce33e63532151c28fc0ceecaabc86c52d011e4f8 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Mar 2015 18:07:08 -0800 Subject: [PATCH 0052/1783] selector-parser -> selector-validator --- src/command-registry.coffee | 2 +- src/context-menu-manager.coffee | 2 +- src/{selector-parser.coffee => selector-validator.coffee} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename src/{selector-parser.coffee => selector-validator.coffee} (100%) diff --git a/src/command-registry.coffee b/src/command-registry.coffee index 07ebcd812..ead4415d2 100644 --- a/src/command-registry.coffee +++ b/src/command-registry.coffee @@ -2,7 +2,7 @@ {specificity} = require 'clear-cut' _ = require 'underscore-plus' {$} = require './space-pen-extensions' -{validateSelector} = require './selector-parser' +{validateSelector} = require './selector-validator' SequenceCount = 0 SpecificityCache = {} diff --git a/src/context-menu-manager.coffee b/src/context-menu-manager.coffee index 56f85199f..3f281afb1 100644 --- a/src/context-menu-manager.coffee +++ b/src/context-menu-manager.coffee @@ -8,7 +8,7 @@ fs = require 'fs-plus' {Disposable} = require 'event-kit' Grim = require 'grim' MenuHelpers = require './menu-helpers' -{validateSelector} = require './selector-parser' +{validateSelector} = require './selector-validator' SpecificityCache = {} diff --git a/src/selector-parser.coffee b/src/selector-validator.coffee similarity index 100% rename from src/selector-parser.coffee rename to src/selector-validator.coffee From 2f476b31ecdb21135ca0456be43e68b47cf47883 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 4 Mar 2015 10:10:43 -0800 Subject: [PATCH 0053/1783] Don't return collected array --- src/package.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/package.coffee b/src/package.coffee index 148e5d4e4..73d4708c0 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -229,6 +229,7 @@ class Package for name, {versions} of @metadata.consumedServices for version, methodName of versions @activationDisposables.add atom.packages.serviceHub.consume(name, version, @mainModule[methodName].bind(@mainModule)) + return loadKeymaps: -> if @bundledPackage and packagesCache[@name]? From bf9b51724010486c4f59bddc5784def41ea4c955 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 4 Mar 2015 10:33:45 -0800 Subject: [PATCH 0054/1783] :racehorse: webkitMatchesSelector -> querySelector --- src/selector-validator.coffee | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/selector-validator.coffee b/src/selector-validator.coffee index df8ff0350..f8dcb240a 100644 --- a/src/selector-validator.coffee +++ b/src/selector-validator.coffee @@ -10,7 +10,9 @@ exports.isSelectorValid = (selector) -> testElement ?= document.createElement('div') try - testElement.webkitMatchesSelector(selector) + # querySelector appears to be faster than webkitMatchesSelector + # http://jsperf.com/query-vs-matches + testElement.querySelector(selector) selectorCache[selector] = true true catch selectorError From f10d478c7a035a5f1dc52af3d80af2e4cc5e5c5b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 4 Mar 2015 10:43:40 -0800 Subject: [PATCH 0055/1783] :art: --- src/package-manager.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 355c65a78..9f53d45e2 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -426,7 +426,7 @@ class PackageManager handleMetadataError: (error, packagePath) -> metadataPath = path.join(packagePath, 'package.json') - detail = error.message + " in #{metadataPath}" - stack = error.stack + "\n at #{metadataPath}:1:1" + detail = "#{error.message} in #{metadataPath}" + stack = "#{error.stack}\n at #{metadataPath}:1:1" message = "Failed to load the #{path.basename(packagePath)} package" atom.notifications.addError(message, {stack, detail, dismissable: true}) From 49a26ea326010ed43ef47dbbdb738fa0956a8fd4 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 4 Mar 2015 10:51:03 -0800 Subject: [PATCH 0056/1783] Add notification for package settings errors --- src/package.coffee | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/package.coffee b/src/package.coffee index 73d4708c0..fded24f9b 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -321,7 +321,9 @@ class Package loadSettingsFile = (settingsPath, callback) => ScopedProperties.load settingsPath, (error, settings) => if error? - console.warn("Failed to load package settings: #{settingsPath}", error.stack ? error) + detail = "#{error.message} in #{settingsPath}" + stack += "#{error.stack}\n at #{settingsPath}:1:1" + atom.notifications.addFatalError("Failed to load the #{@name} package settings", {stack, detail, dismissable: true}) else @settings.push(settings) settings.activate() if @settingsActivated From 92754bb9a3560191bb26f4b7e5bda87ee13ce531 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 4 Mar 2015 10:51:49 -0800 Subject: [PATCH 0057/1783] Add notification for package grammar errors --- src/package.coffee | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/package.coffee b/src/package.coffee index fded24f9b..4785a7098 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -302,7 +302,9 @@ class Package loadGrammar = (grammarPath, callback) => atom.grammars.readGrammar grammarPath, (error, grammar) => if error? - console.warn("Failed to load grammar: #{grammarPath}", error.stack ? error) + detail = "#{error.message} in #{grammarPath}" + stack += "#{error.stack}\n at #{grammarPath}:1:1" + atom.notifications.addFatalError("Failed to load a #{@name} package grammar", {stack, detail, dismissable: true}) else grammar.packageName = @name @grammars.push(grammar) From f02fa4a245b25e539a77f8391b67d2839ef00106 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 4 Mar 2015 11:12:09 -0800 Subject: [PATCH 0058/1783] Add spec for invalid grammar notification --- .../grammars/grammar.json | 1 + .../package-with-invalid-grammar/package.json | 4 ++++ spec/package-manager-spec.coffee | 13 +++++++++++++ src/package.coffee | 2 +- 4 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 spec/fixtures/packages/package-with-invalid-grammar/grammars/grammar.json create mode 100644 spec/fixtures/packages/package-with-invalid-grammar/package.json diff --git a/spec/fixtures/packages/package-with-invalid-grammar/grammars/grammar.json b/spec/fixtures/packages/package-with-invalid-grammar/grammars/grammar.json new file mode 100644 index 000000000..41ec4c527 --- /dev/null +++ b/spec/fixtures/packages/package-with-invalid-grammar/grammars/grammar.json @@ -0,0 +1 @@ +>< diff --git a/spec/fixtures/packages/package-with-invalid-grammar/package.json b/spec/fixtures/packages/package-with-invalid-grammar/package.json new file mode 100644 index 000000000..4ed4081f5 --- /dev/null +++ b/spec/fixtures/packages/package-with-invalid-grammar/package.json @@ -0,0 +1,4 @@ +{ + "name": "package-with-invalid-grammar", + "version": "1.0.0" +} diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index a021f979a..76adfe847 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -226,6 +226,19 @@ describe "PackageManager", -> expect(addErrorHandler.callCount).toBe 1 expect(addErrorHandler.argsForCall[0][0].message).toContain("Failed to activate the package-with-invalid-context-menu package") + it "adds a notification when the grammar is invalid", -> + addErrorHandler = jasmine.createSpy() + atom.notifications.onDidAddNotification(addErrorHandler) + + expect(-> atom.packages.activatePackage('package-with-invalid-grammar')).not.toThrow() + + waitsFor -> + addErrorHandler.callCount > 0 + + runs -> + expect(addErrorHandler.callCount).toBe 1 + expect(addErrorHandler.argsForCall[0][0].message).toContain("Failed to load a package-with-invalid-grammar package grammar") + describe "when the package has no main module", -> it "does not throw an exception", -> spyOn(console, "error") diff --git a/src/package.coffee b/src/package.coffee index 4785a7098..0c4f7319d 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -303,7 +303,7 @@ class Package atom.grammars.readGrammar grammarPath, (error, grammar) => if error? detail = "#{error.message} in #{grammarPath}" - stack += "#{error.stack}\n at #{grammarPath}:1:1" + stack = "#{error.stack}\n at #{grammarPath}:1:1" atom.notifications.addFatalError("Failed to load a #{@name} package grammar", {stack, detail, dismissable: true}) else grammar.packageName = @name From 7a3065e0fb1fb27c8bec7e8be2efdae53d18148d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 4 Mar 2015 11:18:10 -0800 Subject: [PATCH 0059/1783] Add spec for invalid settings notification --- .../package-with-invalid-settings/package.json | 4 ++++ .../settings/settings.json | 1 + spec/package-manager-spec.coffee | 13 +++++++++++++ src/package.coffee | 2 +- 4 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 spec/fixtures/packages/package-with-invalid-settings/package.json create mode 100644 spec/fixtures/packages/package-with-invalid-settings/settings/settings.json diff --git a/spec/fixtures/packages/package-with-invalid-settings/package.json b/spec/fixtures/packages/package-with-invalid-settings/package.json new file mode 100644 index 000000000..b09dccb8b --- /dev/null +++ b/spec/fixtures/packages/package-with-invalid-settings/package.json @@ -0,0 +1,4 @@ +{ + "name": "package-with-invalid-settings", + "version": "1.0.0" +} diff --git a/spec/fixtures/packages/package-with-invalid-settings/settings/settings.json b/spec/fixtures/packages/package-with-invalid-settings/settings/settings.json new file mode 100644 index 000000000..41ec4c527 --- /dev/null +++ b/spec/fixtures/packages/package-with-invalid-settings/settings/settings.json @@ -0,0 +1 @@ +>< diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 76adfe847..6efb17a55 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -239,6 +239,19 @@ describe "PackageManager", -> expect(addErrorHandler.callCount).toBe 1 expect(addErrorHandler.argsForCall[0][0].message).toContain("Failed to load a package-with-invalid-grammar package grammar") + it "adds a notification when the settings are invalid", -> + addErrorHandler = jasmine.createSpy() + atom.notifications.onDidAddNotification(addErrorHandler) + + expect(-> atom.packages.activatePackage('package-with-invalid-settings')).not.toThrow() + + waitsFor -> + addErrorHandler.callCount > 0 + + runs -> + expect(addErrorHandler.callCount).toBe 1 + expect(addErrorHandler.argsForCall[0][0].message).toContain("Failed to load the package-with-invalid-settings package settings") + describe "when the package has no main module", -> it "does not throw an exception", -> spyOn(console, "error") diff --git a/src/package.coffee b/src/package.coffee index 0c4f7319d..758894952 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -324,7 +324,7 @@ class Package ScopedProperties.load settingsPath, (error, settings) => if error? detail = "#{error.message} in #{settingsPath}" - stack += "#{error.stack}\n at #{settingsPath}:1:1" + stack = "#{error.stack}\n at #{settingsPath}:1:1" atom.notifications.addFatalError("Failed to load the #{@name} package settings", {stack, detail, dismissable: true}) else @settings.push(settings) From 8796c284bea6fb981f603f714454a2e441fca540 Mon Sep 17 00:00:00 2001 From: Daniel Hengeveld Date: Wed, 4 Mar 2015 12:31:54 -0800 Subject: [PATCH 0060/1783] :arrow_up: settings-view@0.184.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 06f5b2e87..a1df855b5 100644 --- a/package.json +++ b/package.json @@ -108,7 +108,7 @@ "open-on-github": "0.33.0", "package-generator": "0.38.0", "release-notes": "0.51.0", - "settings-view": "0.183.0", + "settings-view": "0.184.0", "snippets": "0.79.0", "spell-check": "0.55.0", "status-bar": "0.60.0", From 0970a3c41138b3e88c04712d3ca394fde2548db3 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 4 Mar 2015 23:54:39 +0100 Subject: [PATCH 0061/1783] :racehorse: Speed up `selectAll` on a buffer with many folds --- src/selection.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/selection.coffee b/src/selection.coffee index 7c7fad10d..1ecd35157 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -251,7 +251,8 @@ class Selection extends Model # Public: Selects all the text in the buffer. selectAll: -> - @setBufferRange(@editor.buffer.getRange(), autoscroll: false) + @editor.unfoldAll() + @setBufferRange(@editor.buffer.getRange(), autoscroll: false, preserveFolds: true) # Public: Selects all the text from the current cursor position to the # beginning of the line. From 2f4801ecefb557c0e5c5116426f6a0b6c82e9ee1 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 4 Mar 2015 15:52:59 -0800 Subject: [PATCH 0062/1783] :arrow_up: language-perl@0.12 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a1df855b5..d8e2eb510 100644 --- a/package.json +++ b/package.json @@ -138,7 +138,7 @@ "language-make": "0.13.0", "language-mustache": "0.11.0", "language-objective-c": "0.15.0", - "language-perl": "0.11.0", + "language-perl": "0.12.0", "language-php": "0.21.0", "language-property-list": "0.8.0", "language-python": "0.32.0", From 2af28fc49c0b0ef5261da624f08a44ea91f11b7a Mon Sep 17 00:00:00 2001 From: Daniel Hengeveld Date: Wed, 4 Mar 2015 16:02:00 -0800 Subject: [PATCH 0063/1783] :arrow_up: markdown-preview @ 0.138.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d8e2eb510..c42c2bfb2 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "incompatible-packages": "0.22.0", "keybinding-resolver": "0.29.0", "link": "0.30.0", - "markdown-preview": "0.137.0", + "markdown-preview": "0.138.0", "metrics": "0.45.0", "notifications": "0.31.0", "open-on-github": "0.33.0", From 9bb4968e6fcfc9367aeea4ef9dc09fbe9ed5fa16 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 4 Mar 2015 16:03:00 -0800 Subject: [PATCH 0064/1783] Store load settings in URL fragment, not query string --- src/atom.coffee | 2 +- src/browser/atom-window.coffee | 2 +- static/index.js | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/atom.coffee b/src/atom.coffee index b59f9252a..ce3774db1 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -118,7 +118,7 @@ class Atom extends Model # Returns the load settings hash associated with the current window. @getLoadSettings: -> - @loadSettings ?= JSON.parse(decodeURIComponent(location.search.substr(14))) + @loadSettings ?= JSON.parse(decodeURIComponent(location.hash.substr(1))) cloned = _.deepClone(@loadSettings) # The loadSettings.windowState could be large, request it only when needed. cloned.__defineGetter__ 'windowState', => diff --git a/src/browser/atom-window.coffee b/src/browser/atom-window.coffee index 785c11147..3f4d1759a 100644 --- a/src/browser/atom-window.coffee +++ b/src/browser/atom-window.coffee @@ -86,7 +86,7 @@ class AtomWindow protocol: 'file' pathname: "#{@resourcePath}/static/index.html" slashes: true - query: {loadSettings: JSON.stringify(loadSettings)} + hash: encodeURIComponent(JSON.stringify(loadSettings)) hasProjectPath: -> @projectPaths?.length > 0 diff --git a/static/index.js b/static/index.js index b502c1b42..e8142a698 100644 --- a/static/index.js +++ b/static/index.js @@ -14,8 +14,7 @@ window.onload = function() { cacheDir = path.join(cacheDir, 'root'); } - // Skip "?loadSettings=". - var rawLoadSettings = decodeURIComponent(location.search.substr(14)); + var rawLoadSettings = decodeURIComponent(location.hash.substr(1)); var loadSettings; try { loadSettings = JSON.parse(rawLoadSettings); From b1f107c8478a82ed4d1bb4886a95590e306b3ed1 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 4 Mar 2015 16:10:04 -0800 Subject: [PATCH 0065/1783] :arrow_up: language-gfm@0.67 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c42c2bfb2..346c11e89 100644 --- a/package.json +++ b/package.json @@ -126,7 +126,7 @@ "language-coffee-script": "0.39.0", "language-csharp": "0.5.0", "language-css": "0.28.0", - "language-gfm": "0.66.0", + "language-gfm": "0.67.0", "language-git": "0.10.0", "language-go": "0.21.0", "language-html": "0.29.0", From 16e4e6b96707993aa309f0ffc8365d6eab5a02f5 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Wed, 4 Mar 2015 16:21:12 -0800 Subject: [PATCH 0066/1783] :arrow_up: status-bar@0.62.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 346c11e89..7472d2f9b 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "settings-view": "0.184.0", "snippets": "0.79.0", "spell-check": "0.55.0", - "status-bar": "0.60.0", + "status-bar": "0.62.0", "styleguide": "0.44.0", "symbols-view": "0.86.0", "tabs": "0.67.0", From 49e92a45ae1361b1614a1c7c4df598624ad97dd3 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 4 Mar 2015 17:40:11 -0800 Subject: [PATCH 0067/1783] Update loadSettings as project paths change This way, reloading the window always preserves your current state. --- src/atom.coffee | 11 +++++++---- src/browser/atom-window.coffee | 17 +++++++++-------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/atom.coffee b/src/atom.coffee index ce3774db1..e03502dee 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -127,6 +127,11 @@ class Atom extends Model @getCurrentWindow().loadSettings.windowState = value cloned + @updateLoadSetting: (key, value) -> + @getLoadSettings() + @loadSettings[key] = value + location.hash = encodeURIComponent(JSON.stringify(@loadSettings)) + @getCurrentWindow: -> remote.getCurrentWindow() @@ -751,10 +756,8 @@ class Atom extends Model # Notify the browser project of the window's current project path watchProjectPath: -> - onProjectPathChanged = => - ipc.send('window-command', 'project-path-changed', @project.getPaths()) - @subscribe @project.onDidChangePaths(onProjectPathChanged) - onProjectPathChanged() + @subscribe @project.onDidChangePaths => + @constructor.updateLoadSetting('initialPaths', @project.getPaths()) exit: (status) -> app = remote.require('app') diff --git a/src/browser/atom-window.coffee b/src/browser/atom-window.coffee index 3f4d1759a..66fad179e 100644 --- a/src/browser/atom-window.coffee +++ b/src/browser/atom-window.coffee @@ -61,34 +61,35 @@ class AtomWindow pathToOpen loadSettings.initialPaths.sort() - @projectPaths = loadSettings.initialPaths @browserWindow.loadSettings = loadSettings @browserWindow.once 'window:loaded', => @emit 'window:loaded' @loaded = true - @browserWindow.on 'project-path-changed', (@projectPaths) => - - @browserWindow.loadUrl @getUrl(loadSettings) + @setLoadSettings(loadSettings) @browserWindow.focusOnWebView() if @isSpec hasPathToOpen = not (locationsToOpen.length is 1 and not locationsToOpen[0].pathToOpen?) @openLocations(locationsToOpen) if hasPathToOpen and not @isSpecWindow() - getUrl: (loadSettingsObj) -> + setLoadSettings: (loadSettingsObj) -> # Ignore the windowState when passing loadSettings via URL, since it could # be quite large. loadSettings = _.clone(loadSettingsObj) delete loadSettings['windowState'] - url.format + @browserWindow.loadUrl url.format protocol: 'file' pathname: "#{@resourcePath}/static/index.html" slashes: true hash: encodeURIComponent(JSON.stringify(loadSettings)) - hasProjectPath: -> @projectPaths?.length > 0 + getLoadSettings: -> + hash = url.parse(@browserWindow.webContents.getUrl()).hash.substr(1) + JSON.parse(decodeURIComponent(hash)) + + hasProjectPath: -> @getLoadSettings().initialPaths?.length > 0 setupContextMenu: -> ContextMenu = null @@ -103,7 +104,7 @@ class AtomWindow true containsPath: (pathToCheck) -> - @projectPaths.some (projectPath) -> + @getLoadSettings().initialPaths?.some (projectPath) -> if not projectPath false else if not pathToCheck From e2dabceb39adc273eeede35079272e90eb9ddc09 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 4 Mar 2015 17:44:30 -0800 Subject: [PATCH 0068/1783] :arrow_up: open-on-github --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7472d2f9b..4752ee8dc 100644 --- a/package.json +++ b/package.json @@ -105,7 +105,7 @@ "markdown-preview": "0.138.0", "metrics": "0.45.0", "notifications": "0.31.0", - "open-on-github": "0.33.0", + "open-on-github": "0.34.0", "package-generator": "0.38.0", "release-notes": "0.51.0", "settings-view": "0.184.0", From 2aa3e5fd8c98a0ef5da13ffa58f355a3fcc882a6 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 5 Mar 2015 09:01:28 +0100 Subject: [PATCH 0069/1783] :racehorse: Speed up `destroyFoldsIntersectingBufferRange` --- 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 b44b6e276..44389db17 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -2776,8 +2776,11 @@ class TextEditor extends Model # Remove any {Fold}s found that intersect the given buffer row. destroyFoldsIntersectingBufferRange: (bufferRange) -> - for row in [bufferRange.start.row..bufferRange.end.row] - @unfoldBufferRow(row) + @unfoldBufferRow(bufferRange.start.row) + @unfoldBufferRow(bufferRange.end.row) + + for row in [bufferRange.end.row..bufferRange.start.row] + fold.destroy() for fold in @displayBuffer.foldsStartingAtBufferRow(row) # {Delegates to: DisplayBuffer.largestFoldContainingBufferRow} largestFoldContainingBufferRow: (bufferRow) -> From b6d6fb40310cd4bd4e1877c1c44fb5576099b975 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 5 Mar 2015 09:12:40 -0800 Subject: [PATCH 0070/1783] :arrow_up: language-perl@0.13 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4752ee8dc..6802fa4e6 100644 --- a/package.json +++ b/package.json @@ -138,7 +138,7 @@ "language-make": "0.13.0", "language-mustache": "0.11.0", "language-objective-c": "0.15.0", - "language-perl": "0.12.0", + "language-perl": "0.13.0", "language-php": "0.21.0", "language-property-list": "0.8.0", "language-python": "0.32.0", From 3c6da56a8b4a5367f4f836044c7ac0c5addc264a Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 5 Mar 2015 10:49:31 -0800 Subject: [PATCH 0071/1783] :arrow_up: status-bar --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6802fa4e6..b9f651edc 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "settings-view": "0.184.0", "snippets": "0.79.0", "spell-check": "0.55.0", - "status-bar": "0.62.0", + "status-bar": "0.63.0", "styleguide": "0.44.0", "symbols-view": "0.86.0", "tabs": "0.67.0", From 30831f7fe731c138d248ee633cb2f91e5e18bf84 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 5 Mar 2015 11:12:31 -0800 Subject: [PATCH 0072/1783] :arrow_up: markdown-preview --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b9f651edc..b4fab0c41 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "incompatible-packages": "0.22.0", "keybinding-resolver": "0.29.0", "link": "0.30.0", - "markdown-preview": "0.138.0", + "markdown-preview": "0.139.0", "metrics": "0.45.0", "notifications": "0.31.0", "open-on-github": "0.34.0", From 8687752f9d74c015369dde463457bca3bacf0a06 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 5 Mar 2015 11:20:56 -0800 Subject: [PATCH 0073/1783] :arrow_up: update-package-dependencies --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b4fab0c41..c706116ff 100644 --- a/package.json +++ b/package.json @@ -117,7 +117,7 @@ "tabs": "0.67.0", "timecop": "0.31.0", "tree-view": "0.164.0", - "update-package-dependencies": "0.8.0", + "update-package-dependencies": "0.9.0", "welcome": "0.25.0", "whitespace": "0.29.0", "wrap-guide": "0.31.0", From ba76a07270eff0cec370bbcfa0b97650eca5332d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 5 Mar 2015 12:30:41 -0800 Subject: [PATCH 0074/1783] :arrow_up: coffee-cash@0.8 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c706116ff..12114220a 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "babel-core": "^4.0.2", "bootstrap": "git+https://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372", "clear-cut": "0.4.0", - "coffee-cash": "0.7.0", + "coffee-cash": "0.8.0", "coffee-script": "1.8.0", "coffeestack": "^1.1.1", "color": "^0.7.3", From 85e87723b038149c0683f0eabf271cda979c2fc2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 5 Mar 2015 12:45:50 -0800 Subject: [PATCH 0075/1783] Mark Project::onDidChangePaths public --- src/project.coffee | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/project.coffee b/src/project.coffee index 8958b6d43..e0d4bfedd 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -109,6 +109,12 @@ class Project extends Model Section: Event Subscription ### + # Public: Invoke the given callback when the project paths change. + # + # * `callback` {Function} to be called after the project paths change. + # * `projectPaths` An {Array} of {String} project paths. + # + # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. onDidChangePaths: (callback) -> @emitter.on 'did-change-paths', callback From d9442b35c3aea4a2c27749a9cdce38204810c4b4 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 5 Mar 2015 13:06:17 -0800 Subject: [PATCH 0076/1783] :arrow_up: pathwatcher@3.3.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 12114220a..ad2950730 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "nslog": "^2.0.0", "oniguruma": "^4.0.0", "optimist": "0.4.0", - "pathwatcher": "^3.3.1", + "pathwatcher": "^3.3.2", "property-accessors": "^1.1.3", "q": "^1.1.2", "random-words": "0.0.1", From ce159a9c0f8c56442f4ca2e6fca7bda59aaccceb Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 5 Mar 2015 13:30:20 -0800 Subject: [PATCH 0077/1783] :arrow_up: pathwatcher@3.3.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ad2950730..6c75dd75e 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "nslog": "^2.0.0", "oniguruma": "^4.0.0", "optimist": "0.4.0", - "pathwatcher": "^3.3.2", + "pathwatcher": "^3.3.3", "property-accessors": "^1.1.3", "q": "^1.1.2", "random-words": "0.0.1", From eae3dab5272fdb1d56ca0f81a4cda2a5452c397b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 5 Mar 2015 13:47:28 -0800 Subject: [PATCH 0078/1783] Use onDid* for file events --- src/theme-manager.coffee | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/theme-manager.coffee b/src/theme-manager.coffee index 9cf3537a1..101c9d252 100644 --- a/src/theme-manager.coffee +++ b/src/theme-manager.coffee @@ -2,7 +2,7 @@ path = require 'path' _ = require 'underscore-plus' EmitterMixin = require('emissary').Emitter -{Emitter, Disposable} = require 'event-kit' +{Emitter, Disposable, CompositeDisposable} = require 'event-kit' {File} = require 'pathwatcher' fs = require 'fs-plus' Q = require 'q' @@ -241,7 +241,8 @@ class ThemeManager throw new Error("Could not find a file at path '#{stylesheetPath}'") unwatchUserStylesheet: -> - @userStylesheetFile?.off() + @userStylsheetSubscriptions?.dispose() + @userStylsheetSubscriptions = null @userStylesheetFile = null @userStyleSheetDisposable?.dispose() @userStyleSheetDisposable = null @@ -254,7 +255,11 @@ class ThemeManager try @userStylesheetFile = new File(userStylesheetPath) - @userStylesheetFile.on 'contents-changed moved removed', => @loadUserStylesheet() + @userStylsheetSubscriptions = new CompositeDisposable() + reloadStylesheet = => @loadUserStylesheet() + @userStylsheetSubscriptions.add(@userStylesheetPath.onDidChange(reloadStylesheet)) + @userStylsheetSubscriptions.add(@userStylesheetPath.onDidRename(reloadStylesheet)) + @userStylsheetSubscriptions.add(@userStylesheetPath.onDidDelete(reloadStylesheet)) catch error message = """ Unable to watch path: `#{path.basename(userStylesheetPath)}`. Make sure From e3fe418b45500e6d4c194697b62a2ab5e767d4be Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 5 Mar 2015 13:49:12 -0800 Subject: [PATCH 0079/1783] Listen on stylesheet file --- src/theme-manager.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/theme-manager.coffee b/src/theme-manager.coffee index 101c9d252..650c1d168 100644 --- a/src/theme-manager.coffee +++ b/src/theme-manager.coffee @@ -257,9 +257,9 @@ class ThemeManager @userStylesheetFile = new File(userStylesheetPath) @userStylsheetSubscriptions = new CompositeDisposable() reloadStylesheet = => @loadUserStylesheet() - @userStylsheetSubscriptions.add(@userStylesheetPath.onDidChange(reloadStylesheet)) - @userStylsheetSubscriptions.add(@userStylesheetPath.onDidRename(reloadStylesheet)) - @userStylsheetSubscriptions.add(@userStylesheetPath.onDidDelete(reloadStylesheet)) + @userStylsheetSubscriptions.add(@userStylesheetFile.onDidChange(reloadStylesheet)) + @userStylsheetSubscriptions.add(@userStylesheetFile.onDidRename(reloadStylesheet)) + @userStylsheetSubscriptions.add(@userStylesheetFile.onDidDelete(reloadStylesheet)) catch error message = """ Unable to watch path: `#{path.basename(userStylesheetPath)}`. Make sure From 384b043cacf587254605462d7165ecbf80c0f096 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 5 Mar 2015 13:57:29 -0800 Subject: [PATCH 0080/1783] :arrow_up: dev-live-reload@0.42 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6c75dd75e..1c2f0a75c 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,7 @@ "bracket-matcher": "0.71.0", "command-palette": "0.34.0", "deprecation-cop": "0.37.0", - "dev-live-reload": "0.41.0", + "dev-live-reload": "0.42.0", "encoding-selector": "0.18.0", "exception-reporting": "0.24.0", "find-and-replace": "0.159.0", From 9e9f70ad252c8f0af98af6fcf42762c456e29149 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 5 Mar 2015 14:03:36 -0800 Subject: [PATCH 0081/1783] :arrow_up: snippets@0.80 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1c2f0a75c..1e3332594 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "package-generator": "0.38.0", "release-notes": "0.51.0", "settings-view": "0.184.0", - "snippets": "0.79.0", + "snippets": "0.80.0", "spell-check": "0.55.0", "status-bar": "0.63.0", "styleguide": "0.44.0", From 0fad8722aa52786da46a0dadd833b4bf41d44ea1 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 5 Mar 2015 14:38:14 -0800 Subject: [PATCH 0082/1783] :arrow_up: fuzzy-finder --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1e3332594..ffae10ed4 100644 --- a/package.json +++ b/package.json @@ -94,7 +94,7 @@ "encoding-selector": "0.18.0", "exception-reporting": "0.24.0", "find-and-replace": "0.159.0", - "fuzzy-finder": "0.69.0", + "fuzzy-finder": "0.70.0", "git-diff": "0.54.0", "go-to-line": "0.30.0", "grammar-selector": "0.45.0", From eb433bf42e56d3877e1b9af8e1f558021f367d3a Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Thu, 5 Mar 2015 14:55:35 -0800 Subject: [PATCH 0083/1783] :arrow_up: atom-shell@0.21.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ffae10ed4..a710a94ef 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "url": "http://github.com/atom/atom/raw/master/LICENSE.md" } ], - "atomShellVersion": "0.21.0", + "atomShellVersion": "0.21.3", "dependencies": { "async": "0.2.6", "atom-keymap": "^3.1.3", From 48d4ea0907e8aba68a8734484ceabdf3f0d02530 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 5 Mar 2015 14:58:03 -0800 Subject: [PATCH 0084/1783] :arrow_up: symbols-view --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ffae10ed4..5003ebe53 100644 --- a/package.json +++ b/package.json @@ -113,7 +113,7 @@ "spell-check": "0.55.0", "status-bar": "0.63.0", "styleguide": "0.44.0", - "symbols-view": "0.86.0", + "symbols-view": "0.87.0", "tabs": "0.67.0", "timecop": "0.31.0", "tree-view": "0.164.0", From 3c0e4511fc73e23a4f226e5298c381130759d52a Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Thu, 5 Mar 2015 15:01:10 -0800 Subject: [PATCH 0085/1783] Built-in modules' code are now in asar archive --- src/module-cache.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/module-cache.coffee b/src/module-cache.coffee index b4d51dd51..e9245cf40 100644 --- a/src/module-cache.coffee +++ b/src/module-cache.coffee @@ -200,7 +200,7 @@ registerBuiltins = (devMode) -> cache.builtins.atom = atomCoffeePath if fs.isFileSync(atomCoffeePath) cache.builtins.atom ?= path.join(cache.resourcePath, 'exports', 'atom.js') - atomShellRoot = path.join(process.resourcesPath, 'atom') + atomShellRoot = path.join(process.resourcesPath, 'atom.asar') commonRoot = path.join(atomShellRoot, 'common', 'api', 'lib') commonBuiltins = ['callbacks-registry', 'clipboard', 'crash-reporter', 'screen', 'shell'] From c286b0d4c9f22fd04405ce5d9641f1bbe0bcbad0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 5 Mar 2015 15:19:18 -0800 Subject: [PATCH 0086/1783] :arrow_up: symbols-view@0.88 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5003ebe53..940faa7da 100644 --- a/package.json +++ b/package.json @@ -113,7 +113,7 @@ "spell-check": "0.55.0", "status-bar": "0.63.0", "styleguide": "0.44.0", - "symbols-view": "0.87.0", + "symbols-view": "0.88.0", "tabs": "0.67.0", "timecop": "0.31.0", "tree-view": "0.164.0", From a6e8f8a08aebcdf968282faf2af8a4c47d7747b2 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 5 Mar 2015 15:05:36 -0800 Subject: [PATCH 0087/1783] Always open all CLI paths in the same window No more 'atom --multi-folder' --- spec/integration/startup-spec.coffee | 27 +-------------------------- src/browser/atom-application.coffee | 7 +------ src/browser/main.coffee | 4 +--- 3 files changed, 3 insertions(+), 35 deletions(-) diff --git a/spec/integration/startup-spec.coffee b/spec/integration/startup-spec.coffee index f3253b81e..e0df3ad9b 100644 --- a/spec/integration/startup-spec.coffee +++ b/spec/integration/startup-spec.coffee @@ -87,7 +87,7 @@ describe "Starting Atom", -> nestedDir = path.join(otherTempDirPath, "nested-dir") fs.mkdirSync(nestedDir) - runAtom [tempDirPath, otherTempDirPath, "--multi-folder"], {ATOM_HOME: AtomHome}, (client) -> + runAtom [tempDirPath, otherTempDirPath], {ATOM_HOME: AtomHome}, (client) -> client .waitForExist("atom-workspace", 5000) .treeViewRootDirectories() @@ -100,31 +100,6 @@ describe "Starting Atom", -> .treeViewRootDirectories() .then ({value}) -> expect(value).toEqual([tempDirPath, otherTempDirPath]) - it "opens each path in its own window unless the --multi-folder flag is passed", -> - runAtom [tempDirPath, otherTempDirPath], {ATOM_HOME: AtomHome}, (client) -> - treeViewDirs = [] - - client - .waitForExist("atom-workspace", 5000) - .waitForWindowCount(2, 10000) - .then ({value: windowHandles}) -> - - @window(windowHandles[0]) - .waitForExist("atom-workspace") - .treeViewRootDirectories() - .then ({value}) -> - expect(value).toHaveLength(1) - treeViewDirs.push(value[0]) - - .window(windowHandles[1]) - .waitForExist("atom-workspace") - .treeViewRootDirectories() - .then ({value}) -> - expect(value).toHaveLength(1) - treeViewDirs.push(value[0]) - .then -> - expect(treeViewDirs.sort()).toEqual([tempDirPath, otherTempDirPath].sort()) - describe "when there is an existing window with no project path", -> describe "opening a directory", -> it "opens the directory in the existing window", -> diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 7324aa460..1ecbe9570 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -60,7 +60,7 @@ class AtomApplication exit: (status) -> app.exit(status) constructor: (options) -> - {@resourcePath, @version, @devMode, @safeMode, @socketPath, @enableMultiFolderProject} = options + {@resourcePath, @version, @devMode, @safeMode, @socketPath} = options # Normalize to make sure drive letter case is consistent on Windows @resourcePath = path.normalize(@resourcePath) if @resourcePath @@ -348,11 +348,6 @@ class AtomApplication # :windowDimensions - Object with height and width keys. # :window - {AtomWindow} to open file paths in. openPaths: ({pathsToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, windowDimensions, window}={}) -> - if pathsToOpen?.length > 1 and not @enableMultiFolderProject - for pathToOpen in pathsToOpen - @openPath({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, windowDimensions, window}) - return - pathsToOpen = (fs.normalize(pathToOpen) for pathToOpen in pathsToOpen) locationsToOpen = (@locationForPathToOpen(pathToOpen) for pathToOpen in pathsToOpen) diff --git a/src/browser/main.coffee b/src/browser/main.coffee index b73556307..09db16357 100644 --- a/src/browser/main.coffee +++ b/src/browser/main.coffee @@ -118,7 +118,6 @@ parseCommandLine = -> options.alias('v', 'version').boolean('v').describe('v', 'Print the version.') options.alias('w', 'wait').boolean('w').describe('w', 'Wait for window to be closed before returning.') options.string('socket-path') - options.boolean('multi-folder') args = options.argv if args.help @@ -140,7 +139,6 @@ parseCommandLine = -> pidToKillWhenClosed = args['pid'] if args['wait'] logFile = args['log-file'] socketPath = args['socket-path'] - enableMultiFolderProject = args['multi-folder'] if args['resource-path'] devMode = true @@ -166,6 +164,6 @@ parseCommandLine = -> process.env.PATH = args['path-environment'] if args['path-environment'] {resourcePath, pathsToOpen, executedFrom, test, version, pidToKillWhenClosed, - devMode, safeMode, newWindow, specDirectory, logFile, socketPath, enableMultiFolderProject} + devMode, safeMode, newWindow, specDirectory, logFile, socketPath} start() From 2e23dd9553e14c20b22d56660ed05c60b80d79d4 Mon Sep 17 00:00:00 2001 From: Basarat Ali Syed Date: Sun, 8 Mar 2015 09:31:13 +1100 Subject: [PATCH 0088/1783] windows build: `$env:GYP_MSVS_VERSION=2013` might still be required closes https://github.com/atom/atom/issues/5888 --- docs/build-instructions/windows.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/build-instructions/windows.md b/docs/build-instructions/windows.md index fddb941c7..3f8c27660 100644 --- a/docs/build-instructions/windows.md +++ b/docs/build-instructions/windows.md @@ -78,6 +78,7 @@ If none of this works, do install Github for Windows and use its Git shell. Make ``` $env:GYP_MSVS_VERSION=2013 ``` + * If you are using Visual Studio 2013 and the build fails with some other error message this environment variable might still be required. * Other `node-gyp` errors on first build attempt, even though the right node and python versions are installed. * Do try the build command one more time, as experience shows it often works on second try in many of these cases. From 722089be4531300e991b92bd384fc31d7ed44579 Mon Sep 17 00:00:00 2001 From: basarat Date: Sun, 8 Mar 2015 14:49:22 +1100 Subject: [PATCH 0089/1783] feat(typescript) initial commit of built in typescript support --- package.json | 1 + src/typescript-transpile.js | 152 ++++++++++++++++++++++++++++++++++++ src/typescript.coffee | 141 +++++++++++++++++++++++++++++++++ static/index.js | 7 ++ 4 files changed, 301 insertions(+) create mode 100644 src/typescript-transpile.js create mode 100644 src/typescript.coffee diff --git a/package.json b/package.json index 2ec0091a3..60f96cb34 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,7 @@ "temp": "0.8.1", "text-buffer": "^4.1.5", "theorist": "^1.0.2", + "typescript": "^1.4.1", "underscore-plus": "^1.6.6" }, "packageDependencies": { diff --git a/src/typescript-transpile.js b/src/typescript-transpile.js new file mode 100644 index 000000000..64d832d1c --- /dev/null +++ b/src/typescript-transpile.js @@ -0,0 +1,152 @@ +// From https://github.com/teppeis/typescript-simple/blob/master/index.js +// with https://github.com/teppeis/typescript-simple/pull/7 + +var fs = require('fs'); +var os = require('os'); +var path = require('path'); +var ts = require('typescript'); +var FILENAME_TS = 'file.ts'; +function tss(code, options) { + if (options) { + return new tss.TypeScriptSimple(options).compile(code); + } + else { + return defaultTss.compile(code); + } +} +var tss; +(function (tss) { + var TypeScriptSimple = (function () { + /** + * @param {ts.CompilerOptions=} options TypeScript compile options (some options are ignored) + */ + function TypeScriptSimple(options, doSemanticChecks) { + if (options === void 0) { options = {}; } + if (doSemanticChecks === void 0) { doSemanticChecks = true; } + this.doSemanticChecks = doSemanticChecks; + this.service = null; + this.outputs = {}; + this.files = {}; + if (options.target == null) { + options.target = ts.ScriptTarget.ES5; + } + if (options.module == null) { + options.module = ts.ModuleKind.None; + } + this.options = options; + } + /** + * @param {string} code TypeScript source code to compile + * @param {string} only needed if you plan to use sourceMaps. Provide the complete filePath relevant to you + * @return {string} The JavaScript with inline sourceMaps if sourceMaps were enabled + */ + TypeScriptSimple.prototype.compile = function (code, filename) { + if (filename === void 0) { filename = FILENAME_TS; } + if (!this.service) { + this.service = this.createService(); + } + var file = this.files[FILENAME_TS]; + file.text = code; + file.version++; + return this.toJavaScript(this.service, filename); + }; + TypeScriptSimple.prototype.createService = function () { + var _this = this; + var defaultLib = this.getDefaultLibFilename(this.options); + var defaultLibPath = path.join(this.getTypeScriptBinDir(), defaultLib); + this.files[defaultLib] = { version: 0, text: fs.readFileSync(defaultLibPath).toString() }; + this.files[FILENAME_TS] = { version: 0, text: '' }; + var servicesHost = { + getScriptFileNames: function () { return [_this.getDefaultLibFilename(_this.options), FILENAME_TS]; }, + getScriptVersion: function (filename) { return _this.files[filename] && _this.files[filename].version.toString(); }, + getScriptSnapshot: function (filename) { + var file = _this.files[filename]; + return { + getText: function (start, end) { return file.text.substring(start, end); }, + getLength: function () { return file.text.length; }, + getLineStartPositions: function () { return []; }, + getChangeRange: function (oldSnapshot) { return undefined; } + }; + }, + getCurrentDirectory: function () { return process.cwd(); }, + getScriptIsOpen: function () { return true; }, + getCompilationSettings: function () { return _this.options; }, + getDefaultLibFilename: function (options) { + return _this.getDefaultLibFilename(options); + }, + log: function (message) { return console.log(message); } + }; + return ts.createLanguageService(servicesHost, ts.createDocumentRegistry()); + }; + TypeScriptSimple.prototype.getTypeScriptBinDir = function () { + return path.dirname(require.resolve('typescript')); + }; + TypeScriptSimple.prototype.getDefaultLibFilename = function (options) { + if (options.target === ts.ScriptTarget.ES6) { + return 'lib.es6.d.ts'; + } + else { + return 'lib.d.ts'; + } + }; + /** + * converts {"version":3,"file":"file.js","sourceRoot":"","sources":["file.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,MAAM,CAAC"} + * to {"version":3,"sources":["foo/test.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,MAAM,CAAC","file":"foo/test.ts","sourcesContent":["var x = 'test';"]} + * derived from : https://github.com/thlorenz/convert-source-map + */ + TypeScriptSimple.prototype.getInlineSourceMap = function (mapText, filename) { + var sourceMap = JSON.parse(mapText); + sourceMap.file = filename; + sourceMap.sources = [filename]; + sourceMap.sourcesContent = [this.files[FILENAME_TS].text]; + delete sourceMap.sourceRoot; + return JSON.stringify(sourceMap); + }; + TypeScriptSimple.prototype.toJavaScript = function (service, filename) { + if (filename === void 0) { filename = FILENAME_TS; } + var output = service.getEmitOutput(FILENAME_TS); + // Meaning of succeeded is driven by whether we need to check for semantic errors or not + var succeeded = output.emitOutputStatus === ts.EmitReturnStatus.Succeeded; + if (!this.doSemanticChecks) { + // We have an output. It implies syntactic success + if (!succeeded) + succeeded = !!output.outputFiles.length; + } + if (succeeded) { + var outputFilename = FILENAME_TS.replace(/ts$/, 'js'); + var file = output.outputFiles.filter(function (file) { return file.name === outputFilename; })[0]; + // Fixed in v1.5 https://github.com/Microsoft/TypeScript/issues/1653 + var text = file.text.replace(/\r\n/g, os.EOL); + // If we have sourceMaps convert them to inline sourceMaps + if (this.options.sourceMap) { + var sourceMapFilename = FILENAME_TS.replace(/ts$/, 'js.map'); + var sourceMapFile = output.outputFiles.filter(function (file) { return file.name === sourceMapFilename; })[0]; + // Transform sourcemap + var sourceMapText = sourceMapFile.text; + sourceMapText = this.getInlineSourceMap(sourceMapText, filename); + var base64SourceMapText = new Buffer(sourceMapText).toString('base64'); + text = text.replace('//# sourceMappingURL=' + sourceMapFilename, '//# sourceMappingURL=data:application/json;base64,' + base64SourceMapText); + } + return text; + } + var allDiagnostics = service.getCompilerOptionsDiagnostics().concat(service.getSyntacticDiagnostics(FILENAME_TS)); + if (this.doSemanticChecks) + allDiagnostics = allDiagnostics.concat(service.getSemanticDiagnostics(FILENAME_TS)); + throw new Error(this.formatDiagnostics(allDiagnostics)); + }; + TypeScriptSimple.prototype.formatDiagnostics = function (diagnostics) { + return diagnostics.map(function (d) { + if (d.file) { + return 'L' + d.file.getLineAndCharacterFromPosition(d.start).line + ': ' + d.messageText; + } + else { + return d.messageText; + } + }).join(os.EOL); + }; + return TypeScriptSimple; + })(); + tss.TypeScriptSimple = TypeScriptSimple; +})(tss || (tss = {})); +var defaultTss = new tss.TypeScriptSimple(); +module.exports = tss; diff --git a/src/typescript.coffee b/src/typescript.coffee new file mode 100644 index 000000000..e47e7b2a1 --- /dev/null +++ b/src/typescript.coffee @@ -0,0 +1,141 @@ +### +Cache for source code transpiled by TypeScript. + +Inspired by https://github.com/atom/atom/blob/7a719d585db96ff7d2977db9067e1d9d4d0adf1a/src/babel.coffee +### + +crypto = require 'crypto' +fs = require 'fs-plus' +path = require 'path' +tss = null # Defer until used + +stats = + hits: 0 + misses: 0 + +defaultOptions = + target: 1 + module: 'commonjs' + sourceMap: true + +### +shasum - Hash with an update() method. +value - Must be a value that could be returned by JSON.parse(). +### +updateDigestForJsonValue = (shasum, value) -> + # Implmentation is similar to that of pretty-printing a JSON object, except: + # * Strings are not escaped. + # * No effort is made to avoid trailing commas. + # These shortcuts should not affect the correctness of this function. + type = typeof value + if type is 'string' + shasum.update('"', 'utf8') + shasum.update(value, 'utf8') + shasum.update('"', 'utf8') + else if type in ['boolean', 'number'] + shasum.update(value.toString(), 'utf8') + else if value is null + shasum.update('null', 'utf8') + else if Array.isArray value + shasum.update('[', 'utf8') + for item in value + updateDigestForJsonValue(shasum, item) + shasum.update(',', 'utf8') + shasum.update(']', 'utf8') + else + # value must be an object: be sure to sort the keys. + keys = Object.keys value + keys.sort() + + shasum.update('{', 'utf8') + for key in keys + updateDigestForJsonValue(shasum, key) + shasum.update(': ', 'utf8') + updateDigestForJsonValue(shasum, value[key]) + shasum.update(',', 'utf8') + shasum.update('}', 'utf8') + +createTypeScriptVersionAndOptionsDigest = (version, options) -> + shasum = crypto.createHash('sha1') + # Include the version of typescript in the hash. + shasum.update('typescript', 'utf8') + shasum.update('\0', 'utf8') + shasum.update(version, 'utf8') + shasum.update('\0', 'utf8') + updateDigestForJsonValue(shasum, options) + shasum.digest('hex') + +cacheDir = null +jsCacheDir = null + +getCachePath = (sourceCode) -> + digest = crypto.createHash('sha1').update(sourceCode, 'utf8').digest('hex') + + unless jsCacheDir? + tsVersion = require('typescript/package.json').version + jsCacheDir = path.join(cacheDir, createTypeScriptVersionAndOptionsDigest(tsVersion, defaultOptions)) + + path.join(jsCacheDir, "#{digest}.js") + +getCachedJavaScript = (cachePath) -> + if fs.isFileSync(cachePath) + try + cachedJavaScript = fs.readFileSync(cachePath, 'utf8') + stats.hits++ + return cachedJavaScript + null + +# Returns the TypeScript options that should be used to transpile filePath. +createOptions = (filePath) -> + options = filename: filePath + for key, value of defaultOptions + options[key] = value + options + +transpile = (sourceCode, filePath, cachePath) -> + options = createOptions(filePath) + tss ?= new (require './typescript-transpile').TypeScriptSimple(options, false) + js = tss.compile(sourceCode, filePath) + stats.misses++ + + try + fs.writeFileSync(cachePath, js) + + js + +# Function that obeys the contract of an entry in the require.extensions map. +# Returns the transpiled version of the JavaScript code at filePath, which is +# either generated on the fly or pulled from cache. +loadFile = (module, filePath) -> + sourceCode = fs.readFileSync(filePath, 'utf8') + cachePath = getCachePath(sourceCode) + js = getCachedJavaScript(cachePath) ? transpile(sourceCode, filePath, cachePath) + module._compile(js, filePath) + +register = -> + Object.defineProperty(require.extensions, '.ts', { + enumerable: true + writable: false + value: loadFile + }) + +setCacheDirectory = (newCacheDir) -> + if cacheDir isnt newCacheDir + cacheDir = newCacheDir + jsCacheDir = null + +module.exports = + register: register + setCacheDirectory: setCacheDirectory + getCacheMisses: -> stats.misses + getCacheHits: -> stats.hits + + # Visible for testing. + createTypeScriptVersionAndOptionsDigest: createTypeScriptVersionAndOptionsDigest + + addPathToCache: (filePath) -> + return if path.extname(filePath) isnt '.ts' + + sourceCode = fs.readFileSync(filePath, 'utf8') + cachePath = getCachePath(sourceCode) + transpile(sourceCode, filePath, cachePath) diff --git a/static/index.js b/static/index.js index e8142a698..d99a9e9e7 100644 --- a/static/index.js +++ b/static/index.js @@ -47,6 +47,7 @@ window.onload = function() { setupCsonCache(cacheDir); setupSourceMapCache(cacheDir); setupBabel(cacheDir); + setupTypeScript(cacheDir); require(loadSettings.bootstrapScript); require('ipc').sendChannel('window-command', 'window:loaded'); @@ -95,6 +96,12 @@ var setupBabel = function(cacheDir) { babel.register(); } +var setupTypeScript = function(cacheDir) { + var typescript = require('../src/typescript'); + typescript.setCacheDirectory(path.join(cacheDir, 'typescript')); + typescript.register(); +} + var setupCsonCache = function(cacheDir) { require('season').setCacheDir(path.join(cacheDir, 'cson')); } From 651139e189d36ff4a41618720ecb91855252ae96 Mon Sep 17 00:00:00 2001 From: liuxiong332 Date: Mon, 9 Mar 2015 13:16:30 +0800 Subject: [PATCH 0090/1783] add pane-resize-handle-view and insert resize view into pane axis element --- src/pane-axis-element.coffee | 25 ++++++++++- src/pane-resize-handle-view.coffee | 69 ++++++++++++++++++++++++++++++ static/panes.less | 14 ++++++ 3 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 src/pane-resize-handle-view.coffee diff --git a/src/pane-axis-element.coffee b/src/pane-axis-element.coffee index ba0cb4b19..00304b65d 100644 --- a/src/pane-axis-element.coffee +++ b/src/pane-axis-element.coffee @@ -1,5 +1,6 @@ {CompositeDisposable} = require 'event-kit' {callAttachHooks} = require './space-pen-extensions' +PaneResizeHandleView = require './pane-resize-handle-view' class PaneAxisElement extends HTMLElement createdCallback: -> @@ -22,13 +23,35 @@ class PaneAxisElement extends HTMLElement @classList.add('vertical', 'pane-column') this + isPaneResizeHandleElement: (element) -> + element?.classList.contains('pane-resize-handle') + childAdded: ({child, index}) -> view = atom.views.getView(child) - @insertBefore(view, @children[index]) + @insertBefore(view, @children[index * 2]) + + prevElement = view.previousSibling + # if previous element is not pane resize element, then insert new resize element + if prevElement? and not @isPaneResizeHandleElement(prevElement) + resizeView = new PaneResizeHandleView() + resizeView.initialize() + @insertBefore(resizeView[0], view) + + nextElement = view.nextSibling + # if next element isnot resize element, then insert new resize element + if nextElement? and not @isPaneResizeHandleElement(nextElement) + resizeView = new PaneResizeHandleView() + resizeView.initialize() + @insertBefore(resizeView[0], nextElement) + callAttachHooks(view) # for backward compatibility with SpacePen views childRemoved: ({child}) -> view = atom.views.getView(child) + siblingView = view.previousSibling + # make sure next sibling view is pane resize view + if siblingView?.classList.contains('pane-resize-handle') + siblingView.remove() view.remove() childReplaced: ({index, oldChild, newChild}) -> diff --git a/src/pane-resize-handle-view.coffee b/src/pane-resize-handle-view.coffee new file mode 100644 index 000000000..111e143d1 --- /dev/null +++ b/src/pane-resize-handle-view.coffee @@ -0,0 +1,69 @@ +{$, View} = require 'atom-space-pen-views' + +module.exports = +class PaneResizeHandleView extends View + @content: -> + @div class: 'pane-resize-handle' + + initialize: -> + @handleEvents() + + attached: -> + @isHorizontal = @parent().hasClass("horizontal") + @prevPane = @prev() + @nextPane = @next() + + detached: -> + + handleEvents: -> + @on 'dblclick', => + @resizeToFitContent() + @on 'mousedown', (e) => + @resizeStarted(e) + + resizeToFitContent: -> + # clear flex-grow css style of both pane + @prevPane.css('flexGrow', '') + @nextPane.css('flexGrow', '') + + resizeStarted: (e)-> + e.stopPropagation() + $(document).on('mousemove', @resizePane) + $(document).on('mouseup', @resizeStopped) + + calcRatio: (ratio1, ratio2, total) -> + allRatio = ratio1 + ratio2 + [total * ratio1 / allRatio, total * ratio2 / allRatio] + + getFlexGrow: (element) -> + parseFloat element.css('flexGrow') + + setFlexGrow: (prevSize, nextSize) -> + flexGrow = @getFlexGrow(@prevPane) + @getFlexGrow(@nextPane) + flexGrows = @calcRatio(prevSize, nextSize, flexGrow) + @prevPane.css('flexGrow', flexGrows[0].toString()) + @nextPane.css('flexGrow', flexGrows[1].toString()) + + fixInRange: (val, minValue, maxValue) -> + Math.min(Math.max(val, minValue), maxValue) + + resizePane: ({pageX, pageY, which}) => + return @resizeStopped() unless which is 1 + + if @isHorizontal + totalWidth = @prevPane.outerWidth() + @nextPane.outerWidth() + #get the left and right width after move the resize view + leftWidth = @fixInRange(pageX - @prevPane.offset().left, 0, totalWidth) + rightWidth = totalWidth - leftWidth + # set the flex grow by the ratio of left width and right width + # to change pane width + @setFlexGrow(leftWidth, rightWidth) + else + totalHeight = @prevPane.outerHeight() + @nextPane.outerHeight() + topHeight = @fixInRange(pageY - @prevPane.offset().top, 0, totalHeight) + bottomHeight = totalHeight - topHeight + @setFlexGrow(topHeight, bottomHeight) + + resizeStopped: => + $(document).off('mousemove', @resizePane) + $(document).off('mouseup', @resizeStopped) diff --git a/static/panes.less b/static/panes.less index cb8bb6565..f48224f61 100644 --- a/static/panes.less +++ b/static/panes.less @@ -11,12 +11,26 @@ atom-pane-container { display: -webkit-flex; -webkit-flex: 1; -webkit-flex-direction: column; + + & > div.pane-resize-handle { + height: 8px; + z-index: 3; + cursor: ns-resize; + border-bottom: none; + } } atom-pane-axis.horizontal { display: -webkit-flex; -webkit-flex: 1; -webkit-flex-direction: row; + + & > div.pane-resize-handle { + width: 8px; + z-index: 3; + cursor: ew-resize; + border-right: none; + } } atom-pane { From 026eb408725ea27e509ee2e9fe9d5a108ccf26ee Mon Sep 17 00:00:00 2001 From: liuxiong332 Date: Mon, 9 Mar 2015 14:28:26 +0800 Subject: [PATCH 0091/1783] fix the bug that when user dynamic add panes, the resizable view's previous and next pane will change. --- src/pane-resize-handle-view.coffee | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/pane-resize-handle-view.coffee b/src/pane-resize-handle-view.coffee index 111e143d1..0f8bfc51b 100644 --- a/src/pane-resize-handle-view.coffee +++ b/src/pane-resize-handle-view.coffee @@ -10,8 +10,6 @@ class PaneResizeHandleView extends View attached: -> @isHorizontal = @parent().hasClass("horizontal") - @prevPane = @prev() - @nextPane = @next() detached: -> @@ -23,8 +21,8 @@ class PaneResizeHandleView extends View resizeToFitContent: -> # clear flex-grow css style of both pane - @prevPane.css('flexGrow', '') - @nextPane.css('flexGrow', '') + @prev().css('flexGrow', '') + @next().css('flexGrow', '') resizeStarted: (e)-> e.stopPropagation() @@ -39,10 +37,10 @@ class PaneResizeHandleView extends View parseFloat element.css('flexGrow') setFlexGrow: (prevSize, nextSize) -> - flexGrow = @getFlexGrow(@prevPane) + @getFlexGrow(@nextPane) + flexGrow = @getFlexGrow(@prev()) + @getFlexGrow(@next()) flexGrows = @calcRatio(prevSize, nextSize, flexGrow) - @prevPane.css('flexGrow', flexGrows[0].toString()) - @nextPane.css('flexGrow', flexGrows[1].toString()) + @prev().css('flexGrow', flexGrows[0].toString()) + @next().css('flexGrow', flexGrows[1].toString()) fixInRange: (val, minValue, maxValue) -> Math.min(Math.max(val, minValue), maxValue) @@ -51,16 +49,16 @@ class PaneResizeHandleView extends View return @resizeStopped() unless which is 1 if @isHorizontal - totalWidth = @prevPane.outerWidth() + @nextPane.outerWidth() + totalWidth = @prev().outerWidth() + @next().outerWidth() #get the left and right width after move the resize view - leftWidth = @fixInRange(pageX - @prevPane.offset().left, 0, totalWidth) + leftWidth = @fixInRange(pageX - @prev().offset().left, 0, totalWidth) rightWidth = totalWidth - leftWidth # set the flex grow by the ratio of left width and right width # to change pane width @setFlexGrow(leftWidth, rightWidth) else - totalHeight = @prevPane.outerHeight() + @nextPane.outerHeight() - topHeight = @fixInRange(pageY - @prevPane.offset().top, 0, totalHeight) + totalHeight = @prev().outerHeight() + @next().outerHeight() + topHeight = @fixInRange(pageY - @prev().offset().top, 0, totalHeight) bottomHeight = totalHeight - topHeight @setFlexGrow(topHeight, bottomHeight) From 0940c9216f4c95099cf6612d6dca5b7279b5e7dd Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 9 Mar 2015 09:11:39 +0100 Subject: [PATCH 0092/1783] Update also @startRow and @endRow on `getState` --- src/text-editor-presenter.coffee | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 70eef98a9..ebcc5a5ca 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -61,6 +61,7 @@ class TextEditorPresenter @[flagName] = true else fn.apply(this) + @[flagName] = false @emitDidUpdateState() @@ -69,6 +70,11 @@ class TextEditorPresenter getState: -> @updating = true + @updateContentDimensions() + @updateScrollbarDimensions() + @updateStartRow() + @updateEndRow() + @updateFocusedState() if @shouldUpdateFocusedState @updateHeightState() if @shouldUpdateHeightState @updateVerticalScrollState() if @shouldUpdateVerticalScrollState @@ -83,20 +89,6 @@ class TextEditorPresenter @updateGutterState() if @shouldUpdateGutterState @updateLineNumbersState() if @shouldUpdateLineNumbersState - @shouldUpdateFocusedState = false - @shouldUpdateHeightState = false - @shouldUpdateVerticalScrollState = false - @shouldUpdateHorizontalScrollState = false - @shouldUpdateScrollbarsState = false - @shouldUpdateHiddenInputState = false - @shouldUpdateContentState = false - @shouldUpdateDecorations = false - @shouldUpdateLinesState = false - @shouldUpdateCursorsState = false - @shouldUpdateOverlaysState = false - @shouldUpdateGutterState = false - @shouldUpdateLineNumbersState = false - @updating = false @state From 8c297ba1fce64b8b824bdc8cf7b060c36513604e Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 9 Mar 2015 13:43:33 +0100 Subject: [PATCH 0093/1783] :white_check_mark: Verify corrupted state graceful handling --- spec/text-editor-component-spec.coffee | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 548c88105..f5c9e7677 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -56,6 +56,17 @@ describe "TextEditorComponent", -> afterEach -> contentNode.style.width = '' + describe "async updates", -> + it "handles corrupted state gracefully", -> + # trigger state updates, e.g. presenter.updateLinesState + editor.insertNewline() + + # simulate state corruption + component.presenter.startRow = -1 + component.presenter.endRow = 9999 + + expect(nextAnimationFrame).not.toThrow() + describe "line rendering", -> it "renders the currently-visible lines plus the overdraw margin", -> wrapperNode.style.height = 4.5 * lineHeightInPixels + 'px' From 71a279745c0736467c616fd5ef7e48a37ebb78d5 Mon Sep 17 00:00:00 2001 From: liuxiong332 Date: Mon, 9 Mar 2015 21:50:17 +0800 Subject: [PATCH 0094/1783] invalidate document's drag and drop event to prevent the browser's default open url link. add listener for pane's drop event to open dragged files. --- src/pane-element.coffee | 14 ++++++++++++++ src/window-event-handler.coffee | 4 +--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/pane-element.coffee b/src/pane-element.coffee index f626e9fad..df4335e4c 100644 --- a/src/pane-element.coffee +++ b/src/pane-element.coffee @@ -1,6 +1,7 @@ {CompositeDisposable} = require 'event-kit' {$, callAttachHooks, callRemoveHooks} = require './space-pen-extensions' PaneView = require './pane-view' +_ = require 'underscore-plus' class PaneElement extends HTMLElement attached: false @@ -37,8 +38,21 @@ class PaneElement extends HTMLElement handleBlur = (event) => @model.blur() unless @contains(event.relatedTarget) + handleDragOver = (event) => + event.preventDefault() + event.stopPropagation() + + handleDrop = (event) => + event.preventDefault() + event.stopPropagation() + @getModel().activate() + pathsToOpen = _.pluck(event.dataTransfer.files, 'path') + atom.open({pathsToOpen}) if pathsToOpen.length > 0 + @addEventListener 'focus', handleFocus, true @addEventListener 'blur', handleBlur, true + @addEventListener 'dragover', handleDragOver + @addEventListener 'drop', handleDrop createSpacePenShim: -> @__spacePenView = new PaneView(this) diff --git a/src/window-event-handler.coffee b/src/window-event-handler.coffee index 1384f0c4a..506fc7d73 100644 --- a/src/window-event-handler.coffee +++ b/src/window-event-handler.coffee @@ -1,6 +1,5 @@ path = require 'path' {$} = require './space-pen-extensions' -_ = require 'underscore-plus' {Disposable} = require 'event-kit' ipc = require 'ipc' shell = require 'shell' @@ -134,12 +133,11 @@ class WindowEventHandler onDrop: (event) -> event.preventDefault() event.stopPropagation() - pathsToOpen = _.pluck(event.dataTransfer.files, 'path') - atom.open({pathsToOpen}) if pathsToOpen.length > 0 onDragOver: (event) -> event.preventDefault() event.stopPropagation() + event.dataTransfer.dropEffect = 'none' openLink: ({target, currentTarget}) -> location = target?.getAttribute('href') or currentTarget?.getAttribute('href') From e476a9a171cab4def51abd0c5ef7bec1f891973b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 9 Mar 2015 09:28:47 -0700 Subject: [PATCH 0095/1783] :arrow_up: language-javascript@0.61 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2ec0091a3..ffbf11eb1 100644 --- a/package.json +++ b/package.json @@ -132,7 +132,7 @@ "language-html": "0.29.0", "language-hyperlink": "0.12.2", "language-java": "0.14.0", - "language-javascript": "0.60.0", + "language-javascript": "0.61.0", "language-json": "0.12.0", "language-less": "0.25.0", "language-make": "0.13.0", From d68ea563c4c958867539f1a50b26d0284ec0fed8 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 9 Mar 2015 09:57:20 -0700 Subject: [PATCH 0096/1783] :arrow_up: language-sass@0.36 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ffbf11eb1..d09c09e7d 100644 --- a/package.json +++ b/package.json @@ -144,7 +144,7 @@ "language-python": "0.32.0", "language-ruby": "0.49.0", "language-ruby-on-rails": "0.20.0", - "language-sass": "0.35.0", + "language-sass": "0.36.0", "language-shellscript": "0.12.0", "language-source": "0.9.0", "language-sql": "0.14.0", From 537f5e0d6f3b83a47bf4ce7f307781850ca36064 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 9 Mar 2015 13:55:51 -0700 Subject: [PATCH 0097/1783] Add feedback package to main distribution --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index d09c09e7d..dc8c8216b 100644 --- a/package.json +++ b/package.json @@ -93,6 +93,7 @@ "dev-live-reload": "0.42.0", "encoding-selector": "0.18.0", "exception-reporting": "0.24.0", + "feedback": "0.34.0", "find-and-replace": "0.159.0", "fuzzy-finder": "0.70.0", "git-diff": "0.54.0", From b05a36d9f0667d68d06fc02fff1620deed9bbb0a Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 9 Mar 2015 17:20:43 -0700 Subject: [PATCH 0098/1783] Prepare 0.188.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dc8c8216b..60d6fe26f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "0.187.0", + "version": "0.188.0", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From f8f42265da2c3c9a8cbd51403ce263e1960740f3 Mon Sep 17 00:00:00 2001 From: liuxiong332 Date: Tue, 10 Mar 2015 17:02:34 +0800 Subject: [PATCH 0099/1783] delete PaneResizeHandleView that use jQuery and View and replaced with PaneResizeHandleElement --- src/pane-axis-element.coffee | 16 +++---- src/pane-resize-handle-element.coffee | 64 +++++++++++++++++++++++++ src/pane-resize-handle-view.coffee | 67 --------------------------- static/panes.less | 4 +- 4 files changed, 73 insertions(+), 78 deletions(-) create mode 100644 src/pane-resize-handle-element.coffee delete mode 100644 src/pane-resize-handle-view.coffee diff --git a/src/pane-axis-element.coffee b/src/pane-axis-element.coffee index 00304b65d..fc6ba2edb 100644 --- a/src/pane-axis-element.coffee +++ b/src/pane-axis-element.coffee @@ -1,6 +1,6 @@ {CompositeDisposable} = require 'event-kit' {callAttachHooks} = require './space-pen-extensions' -PaneResizeHandleView = require './pane-resize-handle-view' +PaneResizeHandleElement = require './pane-resize-handle-element' class PaneAxisElement extends HTMLElement createdCallback: -> @@ -24,7 +24,7 @@ class PaneAxisElement extends HTMLElement this isPaneResizeHandleElement: (element) -> - element?.classList.contains('pane-resize-handle') + element?.nodeName.toLowerCase() is 'atom-pane-resize-handle' childAdded: ({child, index}) -> view = atom.views.getView(child) @@ -33,16 +33,14 @@ class PaneAxisElement extends HTMLElement prevElement = view.previousSibling # if previous element is not pane resize element, then insert new resize element if prevElement? and not @isPaneResizeHandleElement(prevElement) - resizeView = new PaneResizeHandleView() - resizeView.initialize() - @insertBefore(resizeView[0], view) + resizeHandle = document.createElement('atom-pane-resize-handle') + @insertBefore(resizeHandle, view) nextElement = view.nextSibling # if next element isnot resize element, then insert new resize element if nextElement? and not @isPaneResizeHandleElement(nextElement) - resizeView = new PaneResizeHandleView() - resizeView.initialize() - @insertBefore(resizeView[0], nextElement) + resizeHandle = document.createElement('atom-pane-resize-handle') + @insertBefore(resizeHandle, nextElement) callAttachHooks(view) # for backward compatibility with SpacePen views @@ -50,7 +48,7 @@ class PaneAxisElement extends HTMLElement view = atom.views.getView(child) siblingView = view.previousSibling # make sure next sibling view is pane resize view - if siblingView?.classList.contains('pane-resize-handle') + if siblingView? and @isPaneResizeHandleElement(siblingView) siblingView.remove() view.remove() diff --git a/src/pane-resize-handle-element.coffee b/src/pane-resize-handle-element.coffee new file mode 100644 index 000000000..d04e3a93b --- /dev/null +++ b/src/pane-resize-handle-element.coffee @@ -0,0 +1,64 @@ +class PaneResizeHandleElement extends HTMLElement + createdCallback: -> + @resizePane = @resizePane.bind(this) + @resizeStopped = @resizeStopped.bind(this) + @subscribeToDOMEvents() + + subscribeToDOMEvents: -> + @addEventListener 'dblclick', @resizeToFitContent.bind(this) + @addEventListener 'mousedown', @resizeStarted.bind(this) + + attachedCallback: -> + @isHorizontal = @parentElement.classList.contains("horizontal") + + resizeToFitContent: -> + # clear flex-grow css style of both pane + @previousSibling.style.flexGrow = '' + @nextSibling.style.flexGrow = '' + + resizeStarted: (e)-> + e.stopPropagation() + document.addEventListener 'mousemove', @resizePane + document.addEventListener 'mouseup', @resizeStopped + + resizeStopped: -> + document.removeEventListener 'mousemove', @resizePane + document.removeEventListener 'mouseup', @resizeStopped + + calcRatio: (ratio1, ratio2, total) -> + allRatio = ratio1 + ratio2 + [total * ratio1 / allRatio, total * ratio2 / allRatio] + + getFlexGrow: (element) -> + parseFloat window.getComputedStyle(element).flexGrow + + setFlexGrow: (prevSize, nextSize) -> + flexGrow = @getFlexGrow(@previousSibling) + @getFlexGrow(@nextSibling) + flexGrows = @calcRatio(prevSize, nextSize, flexGrow) + @previousSibling.style.flexGrow = flexGrows[0] + @nextSibling.style.flexGrow = flexGrows[1] + + fixInRange: (val, minValue, maxValue) -> + Math.min(Math.max(val, minValue), maxValue) + + resizePane: ({clientX, clientY, which}) -> + return @resizeStopped() unless which is 1 + + if @isHorizontal + totalWidth = @previousSibling.clientWidth + @nextSibling.clientWidth + #get the left and right width after move the resize view + leftWidth = clientX - @previousSibling.getBoundingClientRect().left + leftWidth = @fixInRange(leftWidth, 0, totalWidth) + rightWidth = totalWidth - leftWidth + # set the flex grow by the ratio of left width and right width + # to change pane width + @setFlexGrow(leftWidth, rightWidth) + else + totalHeight = @previousSibling.clientHeight + @nextSibling.clientHeight + topHeight = clientY - @previousSibling.getBoundingClientRect().top + topHeight = @fixInRange(topHeight, 0, totalHeight) + bottomHeight = totalHeight - topHeight + @setFlexGrow(topHeight, bottomHeight) + +module.exports = PaneResizeHandleElement = +document.registerElement 'atom-pane-resize-handle', prototype: PaneResizeHandleElement.prototype diff --git a/src/pane-resize-handle-view.coffee b/src/pane-resize-handle-view.coffee deleted file mode 100644 index 0f8bfc51b..000000000 --- a/src/pane-resize-handle-view.coffee +++ /dev/null @@ -1,67 +0,0 @@ -{$, View} = require 'atom-space-pen-views' - -module.exports = -class PaneResizeHandleView extends View - @content: -> - @div class: 'pane-resize-handle' - - initialize: -> - @handleEvents() - - attached: -> - @isHorizontal = @parent().hasClass("horizontal") - - detached: -> - - handleEvents: -> - @on 'dblclick', => - @resizeToFitContent() - @on 'mousedown', (e) => - @resizeStarted(e) - - resizeToFitContent: -> - # clear flex-grow css style of both pane - @prev().css('flexGrow', '') - @next().css('flexGrow', '') - - resizeStarted: (e)-> - e.stopPropagation() - $(document).on('mousemove', @resizePane) - $(document).on('mouseup', @resizeStopped) - - calcRatio: (ratio1, ratio2, total) -> - allRatio = ratio1 + ratio2 - [total * ratio1 / allRatio, total * ratio2 / allRatio] - - getFlexGrow: (element) -> - parseFloat element.css('flexGrow') - - setFlexGrow: (prevSize, nextSize) -> - flexGrow = @getFlexGrow(@prev()) + @getFlexGrow(@next()) - flexGrows = @calcRatio(prevSize, nextSize, flexGrow) - @prev().css('flexGrow', flexGrows[0].toString()) - @next().css('flexGrow', flexGrows[1].toString()) - - fixInRange: (val, minValue, maxValue) -> - Math.min(Math.max(val, minValue), maxValue) - - resizePane: ({pageX, pageY, which}) => - return @resizeStopped() unless which is 1 - - if @isHorizontal - totalWidth = @prev().outerWidth() + @next().outerWidth() - #get the left and right width after move the resize view - leftWidth = @fixInRange(pageX - @prev().offset().left, 0, totalWidth) - rightWidth = totalWidth - leftWidth - # set the flex grow by the ratio of left width and right width - # to change pane width - @setFlexGrow(leftWidth, rightWidth) - else - totalHeight = @prev().outerHeight() + @next().outerHeight() - topHeight = @fixInRange(pageY - @prev().offset().top, 0, totalHeight) - bottomHeight = totalHeight - topHeight - @setFlexGrow(topHeight, bottomHeight) - - resizeStopped: => - $(document).off('mousemove', @resizePane) - $(document).off('mouseup', @resizeStopped) diff --git a/static/panes.less b/static/panes.less index f48224f61..ee09b8057 100644 --- a/static/panes.less +++ b/static/panes.less @@ -12,7 +12,7 @@ atom-pane-container { -webkit-flex: 1; -webkit-flex-direction: column; - & > div.pane-resize-handle { + & > atom-pane-resize-handle { height: 8px; z-index: 3; cursor: ns-resize; @@ -25,7 +25,7 @@ atom-pane-container { -webkit-flex: 1; -webkit-flex-direction: row; - & > div.pane-resize-handle { + & > atom-pane-resize-handle { width: 8px; z-index: 3; cursor: ew-resize; From 9b77d303a588dcb5dbc4b68e5ee3d453ec023fac Mon Sep 17 00:00:00 2001 From: liuxiong332 Date: Tue, 10 Mar 2015 21:29:16 +0800 Subject: [PATCH 0100/1783] add specs for pane axis element --- spec/pane-axis-element-spec.coffee | 58 ++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) 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..868f2ce11 --- /dev/null +++ b/spec/pane-axis-element-spec.coffee @@ -0,0 +1,58 @@ +PaneAxisElement = require '../src/pane-axis-element' + +describe "PaneResizeHandleElement", -> + describe "add and remove", -> + class TestItemElement extends HTMLElement + createdCallback: -> + @classList.add('test-root') + + TestItemElement = document.registerElement 'atom-test-item-element', prototype: TestItemElement.prototype + + [paneAxis, model, Model] = [] + beforeEach -> + # This is a dummy item to prevent panes from being empty on deserialization + class Model + @newChild: -> document.createElement('atom-test-item-element') + add: (child, index) -> @addCallback({child, index}) + remove: (child) -> @removeCallback {child} + replace: (index, oldChild, newChild) -> + @replaceCallback {index, oldChild, newChild} + onDidAddChild: (@addCallback) -> + onDidRemoveChild: (@removeCallback) -> + onDidReplaceChild: (@replaceCallback) -> + getOrientation: -> 'horizontal' + getChildren: -> [] + + paneAxis = document.createElement('atom-pane-axis') + model = new Model + paneAxis.initialize(model) + document.querySelector('#jasmine-content').appendChild(paneAxis) + + it "should insert the correct postion in one pane axis", -> + expect(paneAxis).toBeTruthy() + modelChildren = (Model.newChild() for i in [1..5]) + model.add(modelChildren[0]) + model.add(modelChildren[1]) + + expect(paneAxis.children[0]).toBe(modelChildren[0]) + expect(paneAxis.children[2]).toBe(modelChildren[1]) + expectTestItemElement = (index) -> + child = paneAxis.children[index] + expect(child.nodeName.toLowerCase()).toBe('atom-test-item-element') + expectResizeElement = (index) -> + expect(paneAxis.isPaneResizeHandleElement(paneAxis.children[index])).toBe(true) + expectResizeElement(1) + + model.add(modelChildren[2]) + model.add(modelChildren[3]) + expectTestItemElement(i) for i in [0, 2, 4, 6] + expectResizeElement(i) for i in [1, 3, 5] + + model.remove(modelChildren[2]) + # modelChildren[3] replace modelChildren[2] + expect(paneAxis.children[4]).toBe(modelChildren[3]) + expectResizeElement(i) for i in [1, 3] + + model.replace(0, modelChildren[0], modelChildren[4]) + expect(paneAxis.children[0]).toBe(modelChildren[4]) + expectResizeElement(i) for i in [1, 3] From 7e9633a2519d65d83002c9ca39df0997626633a6 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 10 Mar 2015 13:15:40 -0700 Subject: [PATCH 0101/1783] :arrow_up: language-javascript@0.62 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 60d6fe26f..1cfac41d4 100644 --- a/package.json +++ b/package.json @@ -133,7 +133,7 @@ "language-html": "0.29.0", "language-hyperlink": "0.12.2", "language-java": "0.14.0", - "language-javascript": "0.61.0", + "language-javascript": "0.62.0", "language-json": "0.12.0", "language-less": "0.25.0", "language-make": "0.13.0", From 914c41125a0f9f4a30fda78749521f77dd923653 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 10 Mar 2015 13:25:36 -0700 Subject: [PATCH 0102/1783] :arrow_up: language-shellscript@0.13 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1cfac41d4..615d748fc 100644 --- a/package.json +++ b/package.json @@ -146,7 +146,7 @@ "language-ruby": "0.49.0", "language-ruby-on-rails": "0.20.0", "language-sass": "0.36.0", - "language-shellscript": "0.12.0", + "language-shellscript": "0.13.0", "language-source": "0.9.0", "language-sql": "0.14.0", "language-text": "0.6.0", From 200b72d2b64b94ca166604e043071773a2e5bf0f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 10 Mar 2015 13:29:35 -0700 Subject: [PATCH 0103/1783] :arrow_up: language-make@0.14 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 615d748fc..07b11f368 100644 --- a/package.json +++ b/package.json @@ -136,7 +136,7 @@ "language-javascript": "0.62.0", "language-json": "0.12.0", "language-less": "0.25.0", - "language-make": "0.13.0", + "language-make": "0.14.0", "language-mustache": "0.11.0", "language-objective-c": "0.15.0", "language-perl": "0.13.0", From 0ec67e3ab6b8e2fcd21abee48eeea2b3723cb931 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Tue, 10 Mar 2015 13:37:46 -0700 Subject: [PATCH 0104/1783] :arrow_up: versions for pkgs using status-bar service api inc-pkgs bumped up 2 because of publish error --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 07b11f368..a36d6c3b9 100644 --- a/package.json +++ b/package.json @@ -91,16 +91,16 @@ "command-palette": "0.34.0", "deprecation-cop": "0.37.0", "dev-live-reload": "0.42.0", - "encoding-selector": "0.18.0", + "encoding-selector": "0.19.0", "exception-reporting": "0.24.0", "feedback": "0.34.0", "find-and-replace": "0.159.0", "fuzzy-finder": "0.70.0", "git-diff": "0.54.0", "go-to-line": "0.30.0", - "grammar-selector": "0.45.0", + "grammar-selector": "0.46.0", "image-view": "0.49.0", - "incompatible-packages": "0.22.0", + "incompatible-packages": "0.24.0", "keybinding-resolver": "0.29.0", "link": "0.30.0", "markdown-preview": "0.139.0", @@ -108,7 +108,7 @@ "notifications": "0.31.0", "open-on-github": "0.34.0", "package-generator": "0.38.0", - "release-notes": "0.51.0", + "release-notes": "0.52.0", "settings-view": "0.184.0", "snippets": "0.80.0", "spell-check": "0.55.0", From ac91c2341ea5a599d54283aa3af6e86ef8cdab3b Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 10 Mar 2015 14:30:20 -0700 Subject: [PATCH 0105/1783] :arrow_up: fuzzy-finder --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 07b11f368..c39889225 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "exception-reporting": "0.24.0", "feedback": "0.34.0", "find-and-replace": "0.159.0", - "fuzzy-finder": "0.70.0", + "fuzzy-finder": "0.71.0", "git-diff": "0.54.0", "go-to-line": "0.30.0", "grammar-selector": "0.45.0", From 589d3f24ac7c3fcd05e71de0a07817627b0fe9c3 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 10 Mar 2015 17:02:11 -0700 Subject: [PATCH 0106/1783] :arrow_up: language-perl@0.14 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ec4354805..cb96983d7 100644 --- a/package.json +++ b/package.json @@ -139,7 +139,7 @@ "language-make": "0.14.0", "language-mustache": "0.11.0", "language-objective-c": "0.15.0", - "language-perl": "0.13.0", + "language-perl": "0.14.0", "language-php": "0.21.0", "language-property-list": "0.8.0", "language-python": "0.32.0", From 8db12c9aa0811493ca9005d0b2fed9303108ab7c Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 10 Mar 2015 22:34:21 -0700 Subject: [PATCH 0107/1783] :arrow_up: fuzzy-finder --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cb96983d7..c6b2c0f9b 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "exception-reporting": "0.24.0", "feedback": "0.34.0", "find-and-replace": "0.159.0", - "fuzzy-finder": "0.71.0", + "fuzzy-finder": "0.72.0", "git-diff": "0.54.0", "go-to-line": "0.30.0", "grammar-selector": "0.46.0", From 2b981922763170fcbbea5fd30c1797a5beba7638 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 11 Mar 2015 16:16:45 +0100 Subject: [PATCH 0108/1783] Destroy only containing folds on selection --- spec/text-editor-spec.coffee | 9 ++++++--- src/selection.coffee | 5 ++--- src/text-editor.coffee | 9 ++++++--- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index c03990bf2..a7ff07df3 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -1505,9 +1505,12 @@ describe "TextEditor", -> editor.setSelectedScreenRanges([[[6, 2], [6, 4]]]) expect(editor.getSelectedScreenRanges()).toEqual [[[6, 2], [6, 4]]] - it "merges intersecting selections and unfolds the fold", -> - editor.setSelectedScreenRanges([[[2, 2], [3, 3]], [[3, 0], [5, 5]]]) - expect(editor.getSelectedScreenRanges()).toEqual [[[2, 2], [8, 5]]] + it "merges intersecting selections and unfolds the fold which contain them", -> + editor.foldBufferRow(0) + + # Use buffer ranges because only the first line is on screen + editor.setSelectedBufferRanges([[[2, 2], [3, 3]], [[3, 0], [5, 5]]]) + expect(editor.getSelectedBufferRanges()).toEqual [[[2, 2], [5, 5]]] it "recyles existing selection instances", -> selection = editor.getLastSelection() diff --git a/src/selection.coffee b/src/selection.coffee index 1ecd35157..2f4a16005 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -100,7 +100,7 @@ class Selection extends Model bufferRange = Range.fromObject(bufferRange) @needsAutoscroll = options.autoscroll options.reversed ?= @isReversed() - @editor.destroyFoldsIntersectingBufferRange(bufferRange) unless options.preserveFolds + @editor.destroyFoldsContainingBufferRange(bufferRange) unless options.preserveFolds @modifySelection => needsFlash = options.flash delete options.flash if options.flash? @@ -251,8 +251,7 @@ class Selection extends Model # Public: Selects all the text in the buffer. selectAll: -> - @editor.unfoldAll() - @setBufferRange(@editor.buffer.getRange(), autoscroll: false, preserveFolds: true) + @setBufferRange(@editor.buffer.getRange(), autoscroll: false) # Public: Selects all the text from the current cursor position to the # beginning of the line. diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 44389db17..44dc13c68 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -2241,7 +2241,7 @@ class TextEditor extends Model # Returns the new {Selection}. addSelection: (marker, options={}) -> unless marker.getProperties().preserveFolds - @destroyFoldsIntersectingBufferRange(marker.getBufferRange()) + @destroyFoldsContainingBufferRange(marker.getBufferRange()) cursor = @addCursor(marker) selection = new Selection(_.extend({editor: this, marker, cursor}, options)) @selections.push(selection) @@ -2776,12 +2776,15 @@ class TextEditor extends Model # Remove any {Fold}s found that intersect the given buffer row. destroyFoldsIntersectingBufferRange: (bufferRange) -> - @unfoldBufferRow(bufferRange.start.row) - @unfoldBufferRow(bufferRange.end.row) + @destroyFoldsContainingBufferRange(bufferRange) for row in [bufferRange.end.row..bufferRange.start.row] fold.destroy() for fold in @displayBuffer.foldsStartingAtBufferRow(row) + destroyFoldsContainingBufferRange: (bufferRange) -> + @unfoldBufferRow(bufferRange.start.row) + @unfoldBufferRow(bufferRange.end.row) + # {Delegates to: DisplayBuffer.largestFoldContainingBufferRow} largestFoldContainingBufferRow: (bufferRow) -> @displayBuffer.largestFoldContainingBufferRow(bufferRow) From 73ee326bb37941c427b20b597b7a15f6d177174e Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 11 Mar 2015 16:17:40 +0100 Subject: [PATCH 0109/1783] :memo: Document `destroyFoldsContainingBufferRange` ...and correct docs for `destroyFoldsIntersectingBufferRange`. --- src/text-editor.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 44dc13c68..b5c8c5290 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -2774,13 +2774,14 @@ class TextEditor extends Model destroyFoldWithId: (id) -> @displayBuffer.destroyFoldWithId(id) - # Remove any {Fold}s found that intersect the given buffer row. + # Remove any {Fold}s found that intersect the given buffer range. destroyFoldsIntersectingBufferRange: (bufferRange) -> @destroyFoldsContainingBufferRange(bufferRange) for row in [bufferRange.end.row..bufferRange.start.row] fold.destroy() for fold in @displayBuffer.foldsStartingAtBufferRow(row) + # Remove any {Fold}s found that contain the given buffer range. destroyFoldsContainingBufferRange: (bufferRange) -> @unfoldBufferRow(bufferRange.start.row) @unfoldBufferRow(bufferRange.end.row) From 093ef6224c1f2b523c04eb2666e7b487134eb4d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=C5=BDu=C5=BEak?= Date: Wed, 11 Mar 2015 14:32:12 -0700 Subject: [PATCH 0110/1783] :arrow_up: notifications@0.32.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c6b2c0f9b..da0d7b191 100644 --- a/package.json +++ b/package.json @@ -105,7 +105,7 @@ "link": "0.30.0", "markdown-preview": "0.139.0", "metrics": "0.45.0", - "notifications": "0.31.0", + "notifications": "0.32.0", "open-on-github": "0.34.0", "package-generator": "0.38.0", "release-notes": "0.52.0", From cdb1f05566fbf932f21ebfd015d8f7ddbe5bbac3 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 11 Mar 2015 14:44:36 -0700 Subject: [PATCH 0111/1783] :arrow_up: language-perl@0.15 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index da0d7b191..e2f2d712e 100644 --- a/package.json +++ b/package.json @@ -139,7 +139,7 @@ "language-make": "0.14.0", "language-mustache": "0.11.0", "language-objective-c": "0.15.0", - "language-perl": "0.14.0", + "language-perl": "0.15.0", "language-php": "0.21.0", "language-property-list": "0.8.0", "language-python": "0.32.0", From f8cbb679de361af3e5c2111b248c73d68cd40bf6 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 11 Mar 2015 14:46:04 -0700 Subject: [PATCH 0112/1783] :arrow_up: language-todo@0.17 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e2f2d712e..0ed133fb2 100644 --- a/package.json +++ b/package.json @@ -150,7 +150,7 @@ "language-source": "0.9.0", "language-sql": "0.14.0", "language-text": "0.6.0", - "language-todo": "0.16.0", + "language-todo": "0.17.0", "language-toml": "0.15.0", "language-xml": "0.28.0", "language-yaml": "0.22.0" From 2b836cae0cd7b39a83ea3e8f8b3aa8105d1023b8 Mon Sep 17 00:00:00 2001 From: Scott Chacon Date: Wed, 11 Mar 2015 15:00:33 -0700 Subject: [PATCH 0113/1783] update README to point to new documentation --- README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7ebdf9252..4049a9aa9 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,13 @@ Visit [atom.io](https://atom.io) to learn more or visit the [Atom forum](https:/ Visit [issue #3684](https://github.com/atom/atom/issues/3684) to learn more about the Atom 1.0 roadmap. +## Documentation + +If you want to read about using Atom or developing packages in Atom, the [Atom Flight Manual](https://atom.io/docs/latest/) is free and available online, along with ePub, PDF and mobi versions. You can find the source to the manual in [atom/docs](https://github.com/atom/docs). + +The [API reference](https://atom.io/docs/api) for developing packages is also documented on Atom.io. + + ## Installing ### OS X @@ -55,7 +62,3 @@ repeat these steps to upgrade to future releases. * [OS X](docs/build-instructions/os-x.md) * [FreeBSD](docs/build-instructions/freebsd.md) * [Windows](docs/build-instructions/windows.md) - -## Developing - -Check out the [guides](https://atom.io/docs/latest) and the [API reference](https://atom.io/docs/api). From c79335d795e057d7d21f93bec8df46b948c28a6b Mon Sep 17 00:00:00 2001 From: Scott Chacon Date: Wed, 11 Mar 2015 15:05:48 -0700 Subject: [PATCH 0114/1783] update debugging url --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 15e42f708..04fa80cf7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,7 +11,7 @@ propose changes to this document in a pull request. ## Submitting Issues -* Check the [debugging guide](https://atom.io/docs/latest/debugging) for tips +* Check the [debugging guide](https://atom.io/docs/latest/hacking-atom-debugging) for tips on debugging. You might be able to find the cause of the problem and fix things yourself. * Include the version of Atom you are using and the OS. From b3325d64b0785d6cece7c3802a76d72f4c2f1051 Mon Sep 17 00:00:00 2001 From: Scott Chacon Date: Wed, 11 Mar 2015 15:11:46 -0700 Subject: [PATCH 0115/1783] update internal docs links --- dot-atom/keymap.cson | 4 ++-- src/config.coffee | 10 +++++----- src/package.coffee | 2 +- src/scope-descriptor.coffee | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/dot-atom/keymap.cson b/dot-atom/keymap.cson index ae63892bf..dea689c12 100644 --- a/dot-atom/keymap.cson +++ b/dot-atom/keymap.cson @@ -17,8 +17,8 @@ # 'ctrl-p': 'core:move-down' # # You can find more information about keymaps in these guides: -# * https://atom.io/docs/latest/customizing-atom#customizing-key-bindings -# * https://atom.io/docs/latest/advanced/keymaps +# * https://atom.io/docs/latest/using-atom-basic-customization#customizing-key-bindings +# * https://atom.io/docs/latest/behind-atom-keymaps-in-depth # # This file uses CoffeeScript Object Notation (CSON). # If you are unfamiliar with CSON, you can read more about it here: diff --git a/src/config.coffee b/src/config.coffee index 937bb1307..331e89af9 100644 --- a/src/config.coffee +++ b/src/config.coffee @@ -78,7 +78,7 @@ ScopeDescriptor = require './scope-descriptor' # # ... # ``` # -# See [Creating a Package](https://atom.io/docs/latest/creating-a-package) for +# See [package docs](https://atom.io/docs/latest/hacking-atom-package-word-count) for # more info. # # ## Config Schemas @@ -360,7 +360,7 @@ class Config # * `scopeDescriptor` (optional) {ScopeDescriptor} describing a path from # the root of the syntax tree to a token. Get one by calling # {editor.getLastCursor().getScopeDescriptor()}. See {::get} for examples. - # See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors) + # See [the scopes docs](https://atom.io/docs/latest/behind-atom-scoped-settings-scopes-and-scope-descriptors) # for more information. # * `callback` {Function} to call when the value of the key changes. # * `value` the new value of the key @@ -403,7 +403,7 @@ class Config # * `scopeDescriptor` (optional) {ScopeDescriptor} describing a path from # the root of the syntax tree to a token. Get one by calling # {editor.getLastCursor().getScopeDescriptor()}. See {::get} for examples. - # See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors) + # See [the scopes docs](https://atom.io/docs/latest/behind-atom-scoped-settings-scopes-and-scope-descriptors) # for more information. # * `callback` {Function} to call when the value of the key changes. # * `event` {Object} @@ -487,7 +487,7 @@ class Config # * `scope` (optional) {ScopeDescriptor} describing a path from # the root of the syntax tree to a token. Get one by calling # {editor.getLastCursor().getScopeDescriptor()} - # See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors) + # See [the scopes docs](https://atom.io/docs/latest/behind-atom-scoped-settings-scopes-and-scope-descriptors) # for more information. # # Returns the value from Atom's default settings, the user's configuration @@ -568,7 +568,7 @@ class Config # setting to the default value. # * `options` (optional) {Object} # * `scopeSelector` (optional) {String}. eg. '.source.ruby' - # See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors) + # See [the scopes docs](https://atom.io/docs/latest/behind-atom-scoped-settings-scopes-and-scope-descriptors) # for more information. # * `source` (optional) {String} The name of a file with which the setting # is associated. Defaults to the user's config file. diff --git a/src/package.coffee b/src/package.coffee index d8ba4a1d8..41d408329 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -174,7 +174,7 @@ class Package atom.config.setSchema @name, {type: 'object', properties: @mainModule.config} else if @mainModule.configDefaults? and typeof @mainModule.configDefaults is 'object' deprecate """Use a config schema instead. See the configuration section - of https://atom.io/docs/latest/creating-a-package and + of https://atom.io/docs/latest/hacking-atom-package-word-count and https://atom.io/docs/api/latest/Config for more details""" atom.config.setDefaults(@name, @mainModule.configDefaults) @mainModule.activateConfig?() diff --git a/src/scope-descriptor.coffee b/src/scope-descriptor.coffee index 5035810d6..d7ec263fd 100644 --- a/src/scope-descriptor.coffee +++ b/src/scope-descriptor.coffee @@ -15,7 +15,7 @@ # specific position in the buffer. # * {Cursor::getScopeDescriptor} to get a cursor's descriptor based on position. # -# See the [scopes and scope descriptor guide](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors) +# See the [scopes and scope descriptor guide](https://atom.io/docs/latest/behind-atom-scoped-settings-scopes-and-scope-descriptors) # for more information. module.exports = class ScopeDescriptor From 55ced560d4a90c1c9a894212d68006f2226c100f Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Wed, 11 Mar 2015 15:36:45 -0700 Subject: [PATCH 0116/1783] :arrow_up: pathwatcher ^4.1.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0ed133fb2..754a5d392 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "nslog": "^2.0.0", "oniguruma": "^4.0.0", "optimist": "0.4.0", - "pathwatcher": "^3.3.3", + "pathwatcher": "^4.1.2", "property-accessors": "^1.1.3", "q": "^1.1.2", "random-words": "0.0.1", From f9bc31d3fbbb18b0a0534866997403f2ffcaa9d4 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 11 Mar 2015 19:21:52 -0700 Subject: [PATCH 0117/1783] :arrow_up: atom-keymap for pathwatcher 4.x upgrade --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0ed133fb2..8babe14b3 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "atomShellVersion": "0.21.3", "dependencies": { "async": "0.2.6", - "atom-keymap": "^3.1.3", + "atom-keymap": "^3.1.4", "atom-space-pen-views": "^2.0.4", "babel-core": "^4.0.2", "bootstrap": "git+https://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372", From bfb633b12265781b87df6a219b458d51acf69324 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 11 Mar 2015 19:37:28 -0700 Subject: [PATCH 0118/1783] :arrow_up: multiple packages for pathwatcher 4.x upgrade --- package.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index aee7a0f92..d62bc3532 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,7 @@ "one-light-ui": "0.4.0", "solarized-dark-syntax": "0.32.0", "solarized-light-syntax": "0.19.0", - "archive-view": "0.50.0", + "archive-view": "0.51.0", "autocomplete": "0.44.0", "autoflow": "0.22.0", "autosave": "0.20.0", @@ -90,7 +90,7 @@ "bracket-matcher": "0.71.0", "command-palette": "0.34.0", "deprecation-cop": "0.37.0", - "dev-live-reload": "0.42.0", + "dev-live-reload": "0.43.0", "encoding-selector": "0.19.0", "exception-reporting": "0.24.0", "feedback": "0.34.0", @@ -99,25 +99,25 @@ "git-diff": "0.54.0", "go-to-line": "0.30.0", "grammar-selector": "0.46.0", - "image-view": "0.49.0", + "image-view": "0.50.0", "incompatible-packages": "0.24.0", "keybinding-resolver": "0.29.0", "link": "0.30.0", - "markdown-preview": "0.139.0", + "markdown-preview": "0.140.0", "metrics": "0.45.0", "notifications": "0.32.0", "open-on-github": "0.34.0", "package-generator": "0.38.0", "release-notes": "0.52.0", "settings-view": "0.184.0", - "snippets": "0.80.0", + "snippets": "0.81.0", "spell-check": "0.55.0", "status-bar": "0.63.0", "styleguide": "0.44.0", - "symbols-view": "0.88.0", + "symbols-view": "0.89.0", "tabs": "0.67.0", "timecop": "0.31.0", - "tree-view": "0.164.0", + "tree-view": "0.165.0", "update-package-dependencies": "0.9.0", "welcome": "0.25.0", "whitespace": "0.29.0", From de73a70725599df8a7b2a9a4048f1e4040c3b1ae Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 11 Mar 2015 19:58:25 -0700 Subject: [PATCH 0119/1783] Revert ":arrow_up: pathwatcher ^4.1.2" --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d62bc3532..7f30c167c 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "nslog": "^2.0.0", "oniguruma": "^4.0.0", "optimist": "0.4.0", - "pathwatcher": "^4.1.2", + "pathwatcher": "^3.3.3", "property-accessors": "^1.1.3", "q": "^1.1.2", "random-words": "0.0.1", From 2dd6c32daa1412b34be6a7aafab207e43f4cd88d Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 11 Mar 2015 20:10:01 -0700 Subject: [PATCH 0120/1783] :arrow_up: packages and atom-keymap to roll back pathwatcher 4.x upgrade MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The upgrade to 4.x on text-buffer had a failing test suite, which I didn’t discover until upgrading everything else. We don’t want to have 2 major versions of pathwatcher shipping with Atom. --- package.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 7f30c167c..0a801ec95 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "atomShellVersion": "0.21.3", "dependencies": { "async": "0.2.6", - "atom-keymap": "^3.1.4", + "atom-keymap": "^3.1.5", "atom-space-pen-views": "^2.0.4", "babel-core": "^4.0.2", "bootstrap": "git+https://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372", @@ -81,7 +81,7 @@ "one-light-ui": "0.4.0", "solarized-dark-syntax": "0.32.0", "solarized-light-syntax": "0.19.0", - "archive-view": "0.51.0", + "archive-view": "0.52.0", "autocomplete": "0.44.0", "autoflow": "0.22.0", "autosave": "0.20.0", @@ -90,7 +90,7 @@ "bracket-matcher": "0.71.0", "command-palette": "0.34.0", "deprecation-cop": "0.37.0", - "dev-live-reload": "0.43.0", + "dev-live-reload": "0.44.0", "encoding-selector": "0.19.0", "exception-reporting": "0.24.0", "feedback": "0.34.0", @@ -99,25 +99,25 @@ "git-diff": "0.54.0", "go-to-line": "0.30.0", "grammar-selector": "0.46.0", - "image-view": "0.50.0", + "image-view": "0.51.0", "incompatible-packages": "0.24.0", "keybinding-resolver": "0.29.0", "link": "0.30.0", - "markdown-preview": "0.140.0", + "markdown-preview": "0.141.0", "metrics": "0.45.0", "notifications": "0.32.0", "open-on-github": "0.34.0", "package-generator": "0.38.0", "release-notes": "0.52.0", "settings-view": "0.184.0", - "snippets": "0.81.0", + "snippets": "0.82.0", "spell-check": "0.55.0", "status-bar": "0.63.0", "styleguide": "0.44.0", - "symbols-view": "0.89.0", + "symbols-view": "0.90.0", "tabs": "0.67.0", "timecop": "0.31.0", - "tree-view": "0.165.0", + "tree-view": "0.166.0", "update-package-dependencies": "0.9.0", "welcome": "0.25.0", "whitespace": "0.29.0", From 9f1bb8245127135903f98c02f3a1204e7a08ad45 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 12 Mar 2015 10:04:05 +0100 Subject: [PATCH 0121/1783] Adjust `DisplayBuffer#getVisibleRowRange` logic This fixes #4596, where the calculation returned a wrong range. * :memo: State clearly that we'll return a closed interval in docs * :white_check_mark: Write tests to ensure a correct behavior --- spec/display-buffer-spec.coffee | 19 +++++++++++++++++++ src/display-buffer.coffee | 5 +++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index 23b658c04..d5f554db7 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -1247,3 +1247,22 @@ describe "DisplayBuffer", -> expect(displayBuffer.getScrollWidth()).toBe 10 * 63 + operatorWidth * 2 + cursorWidth expect(changedSpy.callCount).toBe 1 + + describe "::getVisibleRowRange()", -> + beforeEach -> + displayBuffer.setLineHeightInPixels(10) + displayBuffer.setHeight(100) + + it "returns a closed interval of visible rows", -> + displayBuffer.setScrollTop(0) + + expect(displayBuffer.getVisibleRowRange()).toEqual [0, 9] + + it "includes partially visible rows in the interval", -> + displayBuffer.setScrollTop(5) + expect(displayBuffer.getVisibleRowRange()).toEqual [0, 10] + + it "returns an empty interval when lineHeight is 0", -> + displayBuffer.setLineHeightInPixels(0) + + expect(displayBuffer.getVisibleRowRange()).toEqual [0, 0] diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index e09f1580c..9e5128553 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -348,12 +348,13 @@ class DisplayBuffer extends Model getScrollWidth: -> @scrollWidth + # Returns an {Array} of two numbers representing a closed interval of visible rows. getVisibleRowRange: -> return [0, 0] unless @getLineHeightInPixels() > 0 - heightInLines = Math.ceil(@getHeight() / @getLineHeightInPixels()) + 1 startRow = Math.floor(@getScrollTop() / @getLineHeightInPixels()) - endRow = Math.min(@getLineCount(), startRow + heightInLines) + endRow = Math.ceil((@getScrollTop() + @getHeight()) / @getLineHeightInPixels()) - 1 + endRow = Math.min(@getLineCount(), endRow) [startRow, endRow] From 912dd732a9e1f4d5c26461300752fdb7b3fd68c5 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 12 Mar 2015 10:17:26 +0100 Subject: [PATCH 0122/1783] :art: Uniform new tests structure --- spec/display-buffer-spec.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index d5f554db7..16eb663e4 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -1260,6 +1260,7 @@ describe "DisplayBuffer", -> it "includes partially visible rows in the interval", -> displayBuffer.setScrollTop(5) + expect(displayBuffer.getVisibleRowRange()).toEqual [0, 10] it "returns an empty interval when lineHeight is 0", -> From faa2944232d3b0781ec4155f2a7f2f3424b7e815 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 12 Mar 2015 10:33:19 +0100 Subject: [PATCH 0123/1783] :white_check_mark: Cover edge case scenario ...where buffer rows are less than rows fitting on screen --- spec/display-buffer-spec.coffee | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index 16eb663e4..783c13feb 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -1267,3 +1267,8 @@ describe "DisplayBuffer", -> displayBuffer.setLineHeightInPixels(0) expect(displayBuffer.getVisibleRowRange()).toEqual [0, 0] + + it "ends at last buffer row even if there's more space available", -> + displayBuffer.setScrollTop(60) + + expect(displayBuffer.getVisibleRowRange()).toEqual [6, 13] From 3b5a0b292df3453939d88c8f01cbd56a066afb06 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 12 Mar 2015 12:32:18 +0100 Subject: [PATCH 0124/1783] :memo: Better and consistent naming across specs and docs --- spec/display-buffer-spec.coffee | 6 +++--- src/display-buffer.coffee | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index 783c13feb..df7c13383 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -1253,17 +1253,17 @@ describe "DisplayBuffer", -> displayBuffer.setLineHeightInPixels(10) displayBuffer.setHeight(100) - it "returns a closed interval of visible rows", -> + it "returns the first and the last visible rows", -> displayBuffer.setScrollTop(0) expect(displayBuffer.getVisibleRowRange()).toEqual [0, 9] - it "includes partially visible rows in the interval", -> + it "includes partially visible rows in the range", -> displayBuffer.setScrollTop(5) expect(displayBuffer.getVisibleRowRange()).toEqual [0, 10] - it "returns an empty interval when lineHeight is 0", -> + it "returns an empty range when lineHeight is 0", -> displayBuffer.setLineHeightInPixels(0) expect(displayBuffer.getVisibleRowRange()).toEqual [0, 0] diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index 9e5128553..7845fa365 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -348,7 +348,7 @@ class DisplayBuffer extends Model getScrollWidth: -> @scrollWidth - # Returns an {Array} of two numbers representing a closed interval of visible rows. + # Returns an {Array} of two numbers representing the first and the last visible rows. getVisibleRowRange: -> return [0, 0] unless @getLineHeightInPixels() > 0 From 00122e76cdc884572bd392494ab55456fec591a7 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 12 Mar 2015 08:11:31 -0700 Subject: [PATCH 0125/1783] :arrow_up: language-javascript@0.63 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0a801ec95..10ec091c2 100644 --- a/package.json +++ b/package.json @@ -133,7 +133,7 @@ "language-html": "0.29.0", "language-hyperlink": "0.12.2", "language-java": "0.14.0", - "language-javascript": "0.62.0", + "language-javascript": "0.63.0", "language-json": "0.12.0", "language-less": "0.25.0", "language-make": "0.14.0", From e61b6fca97db5ecd51b6df8ad69cb029d6a79176 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 12 Mar 2015 09:51:44 -0700 Subject: [PATCH 0126/1783] :arrow_up: tree-view --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 10ec091c2..22235aad1 100644 --- a/package.json +++ b/package.json @@ -117,7 +117,7 @@ "symbols-view": "0.90.0", "tabs": "0.67.0", "timecop": "0.31.0", - "tree-view": "0.166.0", + "tree-view": "0.167.0", "update-package-dependencies": "0.9.0", "welcome": "0.25.0", "whitespace": "0.29.0", From 0a0e1e6e2eddd94627f01c84f2635a9e78b0abe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=C5=BDu=C5=BEak?= Date: Thu, 12 Mar 2015 11:24:14 -0700 Subject: [PATCH 0127/1783] Update link to guide for contributing to packages --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 04fa80cf7..32dccf299 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -39,7 +39,7 @@ many packages and themes that are stored in other repos under the [atom-light-ui](https://github.com/atom/atom-light-ui). For more information on how to work with Atom's official packages, see -[Contributing to Atom Packages](https://atom.io/docs/latest/contributing-to-packages.html) +[Contributing to Atom Packages](https://github.com/atom/atom/blob/master/docs/contributing-to-packages.md) ## Pull Requests From f4b791d33bbaa3599601c92a3d96f7960161b64c Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 13 Mar 2015 10:57:45 +0100 Subject: [PATCH 0128/1783] Use screenPosition to select above and below --- src/display-buffer.coffee | 12 ++++++++++++ src/selection.coffee | 20 ++++++++++++-------- src/text-editor.coffee | 8 ++++++++ 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index 7845fa365..5659d38a0 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -859,6 +859,18 @@ class DisplayBuffer extends Model column = screenLine.clipScreenColumn(column, options) new Point(row, column) + # Clip the start and end of the given range to valid positions on screen. + # See {::clipScreenPosition} for more information. + # + # * `range` The {Range} to clip. + # * `options` (optional) See {::clipScreenPosition} `options`. + # Returns a {Range}. + clipScreenRange: (range, options) -> + start = @clipScreenPosition(range.start, options) + end = @clipScreenPosition(range.end, options) + + new Range(start, end) + # Calculates a {Range} representing the start of the {TextBuffer} until the end. # # Returns a {Range}. diff --git a/src/selection.coffee b/src/selection.coffee index 1ecd35157..c094265b9 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -183,7 +183,7 @@ class Selection extends Model # Public: Clears the selection, moving the marker to the head. clear: -> - @marker.setProperties(goalBufferRange: null) + @marker.setProperties(goalBufferRange: null, goalScreenRange: null) @marker.clearTail() unless @retainSelection @finalize() @@ -657,38 +657,38 @@ class Selection extends Model # Public: Moves the selection down one row. addSelectionBelow: -> - range = (@getGoalBufferRange() ? @getBufferRange()).copy() + range = (@getGoalScreenRange() ? @getScreenRange()).copy() nextRow = range.end.row + 1 - for row in [nextRow..@editor.getLastBufferRow()] + for row in [nextRow..@editor.getLastScreenRow()] range.start.row = row range.end.row = row - clippedRange = @editor.clipBufferRange(range) + clippedRange = @editor.clipScreenRange(range) if range.isEmpty() continue if range.end.column > 0 and clippedRange.end.column is 0 else continue if clippedRange.isEmpty() - @editor.addSelectionForBufferRange(range, goalBufferRange: range) + @editor.addSelectionForScreenRange(range, goalScreenRange: range) break # Public: Moves the selection up one row. addSelectionAbove: -> - range = (@getGoalBufferRange() ? @getBufferRange()).copy() + range = (@getGoalScreenRange() ? @getScreenRange()).copy() previousRow = range.end.row - 1 for row in [previousRow..0] range.start.row = row range.end.row = row - clippedRange = @editor.clipBufferRange(range) + clippedRange = @editor.clipScreenRange(range) if range.isEmpty() continue if range.end.column > 0 and clippedRange.end.column is 0 else continue if clippedRange.isEmpty() - @editor.addSelectionForBufferRange(range, goalBufferRange: range) + @editor.addSelectionForScreenRange(range, goalScreenRange: range) break # Public: Combines the given selection into this selection and then destroys @@ -767,3 +767,7 @@ class Selection extends Model getGoalBufferRange: -> if goalBufferRange = @marker.getProperties().goalBufferRange Range.fromObject(goalBufferRange) + + getGoalScreenRange: -> + if goalScreenRange = @marker.getProperties().goalScreenRange + Range.fromObject(goalScreenRange) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 44389db17..d22d84649 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -1275,6 +1275,14 @@ class TextEditor extends Model # Returns a {Point}. clipScreenPosition: (screenPosition, options) -> @displayBuffer.clipScreenPosition(screenPosition, options) + # Extended: Clip the start and end of the given range to valid positions on screen. + # See {::clipScreenPosition} for more information. + # + # * `range` The {Range} to clip. + # * `options` (optional) See {::clipScreenPosition} `options`. + # Returns a {Range}. + clipScreenRange: (range, options) -> @displayBuffer.clipScreenRange(range, options) + ### Section: Decorations ### From 02ad2e8ff7876a25582aa959f0026ac5dd3df167 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 13 Mar 2015 11:32:42 +0100 Subject: [PATCH 0129/1783] :white_check_mark: Write specs for soft-wrapped lines selection --- spec/text-editor-spec.coffee | 48 ++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index c03990bf2..2d7a8e5a9 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -1623,7 +1623,31 @@ describe "TextEditor", -> [[6, 22], [6, 28]] ] + it "selects also soft-wrapped lines", -> + editor.setSoftWrapped(true) + editor.setDefaultCharWidth(10) + editor.setEditorWidthInChars(40) + + editor.setSelectedScreenRange([[6, 20], [6, 25]]) + editor.addSelectionBelow() + expect(editor.getSelectedScreenRanges()).toEqual [ + [[6, 20], [6, 25]] + [[7, 20], [7, 25]] + ] + describe "when the selection is empty", -> + it "does not skip soft-wrapped lines shorter than the current column", -> + editor.setSoftWrapped(true) + editor.setDefaultCharWidth(10) + editor.setEditorWidthInChars(40) + + editor.setCursorScreenPosition([6, 44]) + editor.addSelectionBelow() + expect(editor.getSelectedScreenRanges()).toEqual [ + [[6, 44], [6, 44]] + [[7, 26], [7, 26]] + ] + it "does not skip lines that are shorter than the current column", -> editor.setCursorBufferPosition([3, 36]) editor.addSelectionBelow() @@ -1687,7 +1711,31 @@ describe "TextEditor", -> [[3, 22], [3, 38]] ] + it "selects also soft-wrapped lines", -> + editor.setSoftWrapped(true) + editor.setDefaultCharWidth(10) + editor.setEditorWidthInChars(40) + + editor.setSelectedScreenRange([[7, 20], [7, 25]]) + editor.addSelectionAbove() + expect(editor.getSelectedScreenRanges()).toEqual [ + [[7, 20], [7, 25]] + [[6, 20], [6, 25]] + ] + describe "when the selection is empty", -> + it "does not skip soft-wrapped lines shorter than the current column", -> + editor.setSoftWrapped(true) + editor.setDefaultCharWidth(10) + editor.setEditorWidthInChars(40) + + editor.setCursorScreenPosition([6, 44]) + editor.addSelectionAbove() + expect(editor.getSelectedScreenRanges()).toEqual [ + [[6, 44], [6, 44]] + [[5, 30], [5, 30]] + ] + it "does not skip lines that are shorter than the current column", -> editor.setCursorBufferPosition([6, 36]) editor.addSelectionAbove() From c319b804642869758e6994a82420974debb4e28f Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 13 Mar 2015 11:56:00 +0100 Subject: [PATCH 0130/1783] :white_check_mark: Write specs for atomic tokens --- spec/text-editor-spec.coffee | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 2d7a8e5a9..833128085 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -1635,6 +1635,19 @@ describe "TextEditor", -> [[7, 20], [7, 25]] ] + it "takes atomic tokens into account", -> + waitsForPromise -> + atom.project.open('sample-with-tabs-and-leading-comment.coffee', autoIndent: false).then (o) -> editor = o + + runs -> + editor.setSelectedBufferRange([[2, 1], [2, 3]]) + editor.addSelectionBelow() + + expect(editor.getSelectedBufferRanges()).toEqual [ + [[2, 1], [2, 3]] + [[3, 1], [3, 2]] + ] + describe "when the selection is empty", -> it "does not skip soft-wrapped lines shorter than the current column", -> editor.setSoftWrapped(true) @@ -1723,6 +1736,19 @@ describe "TextEditor", -> [[6, 20], [6, 25]] ] + it "takes atomic tokens into account", -> + waitsForPromise -> + atom.project.open('sample-with-tabs-and-leading-comment.coffee', autoIndent: false).then (o) -> editor = o + + runs -> + editor.setSelectedBufferRange([[3, 1], [3, 2]]) + editor.addSelectionAbove() + + expect(editor.getSelectedBufferRanges()).toEqual [ + [[3, 1], [3, 2]] + [[2, 1], [2, 3]] + ] + describe "when the selection is empty", -> it "does not skip soft-wrapped lines shorter than the current column", -> editor.setSoftWrapped(true) From 8ac4848805f67c6640f8d7fd791caf31306419ca Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 13 Mar 2015 12:05:18 +0100 Subject: [PATCH 0131/1783] Skip soft-wrap indentation tokens while selecting * :art: Restructure specs a bit * :white_check_mark: Write specs for this new behavior --- spec/text-editor-spec.coffee | 64 +++++++++++++++++++++++++----------- src/selection.coffee | 8 ++--- 2 files changed, 48 insertions(+), 24 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 833128085..afbc8aa7d 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -1649,17 +1649,29 @@ describe "TextEditor", -> ] describe "when the selection is empty", -> - it "does not skip soft-wrapped lines shorter than the current column", -> - editor.setSoftWrapped(true) - editor.setDefaultCharWidth(10) - editor.setEditorWidthInChars(40) + describe "when lines are soft-wrapped", -> + beforeEach -> + editor.setSoftWrapped(true) + editor.setDefaultCharWidth(10) + editor.setEditorWidthInChars(40) - editor.setCursorScreenPosition([6, 44]) - editor.addSelectionBelow() - expect(editor.getSelectedScreenRanges()).toEqual [ - [[6, 44], [6, 44]] - [[7, 26], [7, 26]] - ] + it "skips soft-wrap indentation tokens", -> + editor.setCursorScreenPosition([6, 2]) + editor.addSelectionBelow() + + expect(editor.getSelectedScreenRanges()).toEqual [ + [[6, 2], [6, 2]] + [[7, 6], [7, 6]] + ] + + it "does not skip them if they're shorter than the current column", -> + editor.setCursorScreenPosition([6, 44]) + editor.addSelectionBelow() + + expect(editor.getSelectedScreenRanges()).toEqual [ + [[6, 44], [6, 44]] + [[7, 26], [7, 26]] + ] it "does not skip lines that are shorter than the current column", -> editor.setCursorBufferPosition([3, 36]) @@ -1750,17 +1762,29 @@ describe "TextEditor", -> ] describe "when the selection is empty", -> - it "does not skip soft-wrapped lines shorter than the current column", -> - editor.setSoftWrapped(true) - editor.setDefaultCharWidth(10) - editor.setEditorWidthInChars(40) + describe "when lines are soft-wrapped", -> + beforeEach -> + editor.setSoftWrapped(true) + editor.setDefaultCharWidth(10) + editor.setEditorWidthInChars(40) - editor.setCursorScreenPosition([6, 44]) - editor.addSelectionAbove() - expect(editor.getSelectedScreenRanges()).toEqual [ - [[6, 44], [6, 44]] - [[5, 30], [5, 30]] - ] + it "skips soft-wrap indentation tokens", -> + editor.setCursorScreenPosition([8, 0]) + editor.addSelectionAbove() + + expect(editor.getSelectedScreenRanges()).toEqual [ + [[8, 0], [8, 0]] + [[7, 6], [7, 6]] + ] + + it "does not skip them if they're shorter than the current column", -> + editor.setCursorScreenPosition([6, 44]) + editor.addSelectionAbove() + + expect(editor.getSelectedScreenRanges()).toEqual [ + [[6, 44], [6, 44]] + [[5, 30], [5, 30]] + ] it "does not skip lines that are shorter than the current column", -> editor.setCursorBufferPosition([6, 36]) diff --git a/src/selection.coffee b/src/selection.coffee index c094265b9..30a64d873 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -663,14 +663,14 @@ class Selection extends Model for row in [nextRow..@editor.getLastScreenRow()] range.start.row = row range.end.row = row - clippedRange = @editor.clipScreenRange(range) + clippedRange = @editor.clipScreenRange(range, skipSoftWrapIndentation: true) if range.isEmpty() continue if range.end.column > 0 and clippedRange.end.column is 0 else continue if clippedRange.isEmpty() - @editor.addSelectionForScreenRange(range, goalScreenRange: range) + @editor.addSelectionForScreenRange(clippedRange, goalScreenRange: range) break # Public: Moves the selection up one row. @@ -681,14 +681,14 @@ class Selection extends Model for row in [previousRow..0] range.start.row = row range.end.row = row - clippedRange = @editor.clipScreenRange(range) + clippedRange = @editor.clipScreenRange(range, skipSoftWrapIndentation: true) if range.isEmpty() continue if range.end.column > 0 and clippedRange.end.column is 0 else continue if clippedRange.isEmpty() - @editor.addSelectionForScreenRange(range, goalScreenRange: range) + @editor.addSelectionForScreenRange(clippedRange, goalScreenRange: range) break # Public: Combines the given selection into this selection and then destroys From 37f5a3311610ab14c0e393268c41d2cfdb162bef Mon Sep 17 00:00:00 2001 From: Bjoernsen Date: Fri, 13 Mar 2015 13:36:07 +0100 Subject: [PATCH 0132/1783] Enable multiple users Currently, it is not possible to use atom for multiple users on the same linux machine. The socket file '/tmp/atom.sock' belongs to the first user that starts atom. With this small change, a socket file will be created for each user. --- src/browser/atom-application.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 1ecbe9570..52fc08c21 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -18,7 +18,7 @@ DefaultSocketPath = if process.platform is 'win32' '\\\\.\\pipe\\atom-sock' else - path.join(os.tmpdir(), 'atom.sock') + path.join(os.tmpdir(), "atom_#{process.env['USER']}.sock") # The application's singleton class. # From 5067a25f422aa772287097173ddd7867f8003f9f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 13 Mar 2015 10:24:31 -0700 Subject: [PATCH 0133/1783] :arrow_up: language-perl@0.16 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 22235aad1..90863fff3 100644 --- a/package.json +++ b/package.json @@ -139,7 +139,7 @@ "language-make": "0.14.0", "language-mustache": "0.11.0", "language-objective-c": "0.15.0", - "language-perl": "0.15.0", + "language-perl": "0.16.0", "language-php": "0.21.0", "language-property-list": "0.8.0", "language-python": "0.32.0", From 7ec46933bda7bc6396080a1631a3590b8b0bbbc3 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 13 Mar 2015 11:42:30 -0700 Subject: [PATCH 0134/1783] Batch service providers by package --- .../packages/package-with-provided-services/index.coffee | 3 +++ .../packages/package-with-provided-services/package.json | 1 + spec/package-manager-spec.coffee | 1 + src/package.coffee | 4 +++- 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/spec/fixtures/packages/package-with-provided-services/index.coffee b/spec/fixtures/packages/package-with-provided-services/index.coffee index b6413b119..86f319946 100644 --- a/spec/fixtures/packages/package-with-provided-services/index.coffee +++ b/spec/fixtures/packages/package-with-provided-services/index.coffee @@ -3,6 +3,9 @@ module.exports = deactivate: -> + provideFirstServiceV2: -> + 'first-service-v2' + provideFirstServiceV3: -> 'first-service-v3' diff --git a/spec/fixtures/packages/package-with-provided-services/package.json b/spec/fixtures/packages/package-with-provided-services/package.json index 144fc2dac..d95bbf9b7 100644 --- a/spec/fixtures/packages/package-with-provided-services/package.json +++ b/spec/fixtures/packages/package-with-provided-services/package.json @@ -5,6 +5,7 @@ "service-1": { "description": "The first service", "versions": { + "0.2.9": "provideFirstServiceV2", "0.3.1": "provideFirstServiceV3", "0.4.1": "provideFirstServiceV4" } diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 6efb17a55..758d7468f 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -522,6 +522,7 @@ describe "PackageManager", -> atom.packages.activatePackage("package-with-provided-services") runs -> + expect(consumerModule.consumeFirstServiceV3.callCount).toBe(1) expect(consumerModule.consumeFirstServiceV3).toHaveBeenCalledWith('first-service-v3') expect(consumerModule.consumeFirstServiceV4).toHaveBeenCalledWith('first-service-v4') expect(consumerModule.consumeSecondService).toHaveBeenCalledWith('second-service') diff --git a/src/package.coffee b/src/package.coffee index 422077dc9..4d244c50f 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -223,8 +223,10 @@ class Package activateServices: -> for name, {versions} of @metadata.providedServices + servicesByVersion = {} for version, methodName of versions - @activationDisposables.add atom.packages.serviceHub.provide(name, version, @mainModule[methodName]()) + servicesByVersion[version] = @mainModule[methodName]() + @activationDisposables.add atom.packages.serviceHub.provide(name, servicesByVersion) for name, {versions} of @metadata.consumedServices for version, methodName of versions From f476b19a13f9ca282de594e34637caf137551249 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 13 Mar 2015 12:27:56 -0700 Subject: [PATCH 0135/1783] :arrow_up: service-hub --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 22235aad1..770003e92 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "season": "^5.1.4", "semver": "~4.2", "serializable": "^1", - "service-hub": "^0.4.0", + "service-hub": "^0.5.0", "space-pen": "3.8.2", "stacktrace-parser": "0.1.1", "temp": "0.8.1", From 28d617e799c784c7780b7fa1c511b32aff968d7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=C5=BDu=C5=BEak?= Date: Fri, 13 Mar 2015 14:31:17 -0700 Subject: [PATCH 0136/1783] :arrow_up: apm@0.143 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index 7d894d573..b34351f7b 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.142.0" + "atom-package-manager": "0.143.0" } } From 587ebd753840517dca899982d6a4f3931a1f1b39 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 13 Mar 2015 15:07:44 -0700 Subject: [PATCH 0137/1783] Fix Project::relativePath w/ URLs --- spec/project-spec.coffee | 5 +++++ src/project.coffee | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/spec/project-spec.coffee b/spec/project-spec.coffee index 02ea81ff4..a1cdce662 100644 --- a/spec/project-spec.coffee +++ b/spec/project-spec.coffee @@ -486,6 +486,11 @@ describe "Project", -> randomPath = path.join("some", "random", "path") expect(atom.project.relativizePath(randomPath)).toEqual [null, randomPath] + describe "when the given path is a URL", -> + it "returns null for the root path, and the given path unchanged", -> + url = "http://the-path" + expect(atom.project.relativizePath(url)).toEqual [null, url] + describe ".contains(path)", -> it "returns whether or not the given path is in one of the root directories", -> rootPath = atom.project.getPaths()[0] diff --git a/src/project.coffee b/src/project.coffee index e0d4bfedd..69406dbda 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -288,7 +288,6 @@ class Project extends Model # * `relativePath` {String} The relative path from the project directory to # the given path. relativizePath: (fullPath) -> - return fullPath if fullPath?.match(/[A-Za-z0-9+-.]+:\/\//) # leave path alone if it has a scheme for rootDirectory in @rootDirectories relativePath = rootDirectory.relativize(fullPath) return [rootDirectory.getPath(), relativePath] unless relativePath is fullPath From bfe8f7c7406bd42ec3f8429b8bb1c3391fb8e288 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Sat, 14 Mar 2015 09:26:29 +0100 Subject: [PATCH 0138/1783] Fix soft-wrapping specs --- spec/text-editor-spec.coffee | 44 ++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index afbc8aa7d..fddaf573d 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -1623,16 +1623,15 @@ describe "TextEditor", -> [[6, 22], [6, 28]] ] - it "selects also soft-wrapped lines", -> + it "can add selections to soft-wrapped line segments", -> editor.setSoftWrapped(true) - editor.setDefaultCharWidth(10) editor.setEditorWidthInChars(40) - editor.setSelectedScreenRange([[6, 20], [6, 25]]) + editor.setSelectedScreenRange([[3, 10], [3, 15]]) editor.addSelectionBelow() expect(editor.getSelectedScreenRanges()).toEqual [ - [[6, 20], [6, 25]] - [[7, 20], [7, 25]] + [[3, 10], [3, 15]] + [[4, 10], [4, 15]] ] it "takes atomic tokens into account", -> @@ -1652,25 +1651,24 @@ describe "TextEditor", -> describe "when lines are soft-wrapped", -> beforeEach -> editor.setSoftWrapped(true) - editor.setDefaultCharWidth(10) editor.setEditorWidthInChars(40) it "skips soft-wrap indentation tokens", -> - editor.setCursorScreenPosition([6, 2]) + editor.setCursorScreenPosition([3, 0]) editor.addSelectionBelow() expect(editor.getSelectedScreenRanges()).toEqual [ - [[6, 2], [6, 2]] - [[7, 6], [7, 6]] + [[3, 0], [3, 0]] + [[4, 4], [4, 4]] ] it "does not skip them if they're shorter than the current column", -> - editor.setCursorScreenPosition([6, 44]) + editor.setCursorScreenPosition([3, 37]) editor.addSelectionBelow() expect(editor.getSelectedScreenRanges()).toEqual [ - [[6, 44], [6, 44]] - [[7, 26], [7, 26]] + [[3, 37], [3, 37]] + [[4, 26], [4, 26]] ] it "does not skip lines that are shorter than the current column", -> @@ -1736,16 +1734,15 @@ describe "TextEditor", -> [[3, 22], [3, 38]] ] - it "selects also soft-wrapped lines", -> + it "can add selections to soft-wrapped line segments", -> editor.setSoftWrapped(true) - editor.setDefaultCharWidth(10) editor.setEditorWidthInChars(40) - editor.setSelectedScreenRange([[7, 20], [7, 25]]) + editor.setSelectedScreenRange([[4, 10], [4, 15]]) editor.addSelectionAbove() expect(editor.getSelectedScreenRanges()).toEqual [ - [[7, 20], [7, 25]] - [[6, 20], [6, 25]] + [[4, 10], [4, 15]] + [[3, 10], [3, 15]] ] it "takes atomic tokens into account", -> @@ -1765,25 +1762,24 @@ describe "TextEditor", -> describe "when lines are soft-wrapped", -> beforeEach -> editor.setSoftWrapped(true) - editor.setDefaultCharWidth(10) editor.setEditorWidthInChars(40) it "skips soft-wrap indentation tokens", -> - editor.setCursorScreenPosition([8, 0]) + editor.setCursorScreenPosition([5, 0]) editor.addSelectionAbove() expect(editor.getSelectedScreenRanges()).toEqual [ - [[8, 0], [8, 0]] - [[7, 6], [7, 6]] + [[5, 0], [5, 0]] + [[4, 4], [4, 4]] ] it "does not skip them if they're shorter than the current column", -> - editor.setCursorScreenPosition([6, 44]) + editor.setCursorScreenPosition([5, 29]) editor.addSelectionAbove() expect(editor.getSelectedScreenRanges()).toEqual [ - [[6, 44], [6, 44]] - [[5, 30], [5, 30]] + [[5, 29], [5, 29]] + [[4, 26], [4, 26]] ] it "does not skip lines that are shorter than the current column", -> From 0a23a219534327b60736dcaa0eb53f15fae8fbfb Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Sat, 14 Mar 2015 09:48:19 +0100 Subject: [PATCH 0139/1783] :art: Get rid of goalBufferRange --- spec/text-editor-spec.coffee | 4 ++-- src/selection.coffee | 22 ++++++++++------------ 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index fddaf573d..6154af055 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -1456,8 +1456,8 @@ describe "TextEditor", -> expect(editor.getSelectedBufferRanges()).toEqual [[[5, 5], [6, 6]]] it "merges intersecting selections", -> - editor.setSelectedBufferRanges([[[2, 2], [3, 3]], [[3, 0], [5, 5]]]) - expect(editor.getSelectedBufferRanges()).toEqual [[[2, 2], [5, 5]]] + editor.setSelectedBufferRanges([[[2, 2], [3, 3]], [[3, 0], [5, 4]]]) + expect(editor.getSelectedBufferRanges()).toEqual [[[2, 2], [5, 4]]] it "does not merge non-empty adjacent selections", -> editor.setSelectedBufferRanges([[[2, 2], [3, 3]], [[3, 3], [5, 5]]]) diff --git a/src/selection.coffee b/src/selection.coffee index 30a64d873..d4538f9dc 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -183,7 +183,7 @@ class Selection extends Model # Public: Clears the selection, moving the marker to the head. clear: -> - @marker.setProperties(goalBufferRange: null, goalScreenRange: null) + @marker.setProperties(goalScreenRange: null) @marker.clearTail() unless @retainSelection @finalize() @@ -695,15 +695,17 @@ class Selection extends Model # the given selection. # # * `otherSelection` A {Selection} to merge with. - # * `options` (optional) {Object} options matching those found in {::setBufferRange}. + # * `options` (optional) {Object} options matching those found in {::setScreenRange}. merge: (otherSelection, options) -> - myGoalBufferRange = @getGoalBufferRange() - otherGoalBufferRange = otherSelection.getGoalBufferRange() - if myGoalBufferRange? and otherGoalBufferRange? - options.goalBufferRange = myGoalBufferRange.union(otherGoalBufferRange) + myGoalScreenRange = @getGoalScreenRange() + otherGoalScreenRange = otherSelection.getGoalScreenRange() + + if myGoalScreenRange? and otherGoalScreenRange? + options.goalScreenRange = myGoalScreenRange.union(otherGoalScreenRange) else - options.goalBufferRange = myGoalBufferRange ? otherGoalBufferRange - @setBufferRange(@getBufferRange().union(otherSelection.getBufferRange()), options) + options.goalScreenRange = myGoalScreenRange ? otherGoalScreenRange + + @setScreenRange(@getScreenRange().union(otherSelection.getScreenRange()), options) otherSelection.destroy() ### @@ -764,10 +766,6 @@ class Selection extends Model plantTail: -> @marker.plantTail() - getGoalBufferRange: -> - if goalBufferRange = @marker.getProperties().goalBufferRange - Range.fromObject(goalBufferRange) - getGoalScreenRange: -> if goalScreenRange = @marker.getProperties().goalScreenRange Range.fromObject(goalScreenRange) From 6633c90af870c1c361da4ea59e5094b9289e6ae4 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Sat, 14 Mar 2015 10:05:04 +0100 Subject: [PATCH 0140/1783] Use buffer ranges when merging selections --- spec/text-editor-spec.coffee | 4 ++-- src/selection.coffee | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 6154af055..fddaf573d 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -1456,8 +1456,8 @@ describe "TextEditor", -> expect(editor.getSelectedBufferRanges()).toEqual [[[5, 5], [6, 6]]] it "merges intersecting selections", -> - editor.setSelectedBufferRanges([[[2, 2], [3, 3]], [[3, 0], [5, 4]]]) - expect(editor.getSelectedBufferRanges()).toEqual [[[2, 2], [5, 4]]] + editor.setSelectedBufferRanges([[[2, 2], [3, 3]], [[3, 0], [5, 5]]]) + expect(editor.getSelectedBufferRanges()).toEqual [[[2, 2], [5, 5]]] it "does not merge non-empty adjacent selections", -> editor.setSelectedBufferRanges([[[2, 2], [3, 3]], [[3, 3], [5, 5]]]) diff --git a/src/selection.coffee b/src/selection.coffee index d4538f9dc..cada3aa6c 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -695,7 +695,7 @@ class Selection extends Model # the given selection. # # * `otherSelection` A {Selection} to merge with. - # * `options` (optional) {Object} options matching those found in {::setScreenRange}. + # * `options` (optional) {Object} options matching those found in {::setBufferRange}. merge: (otherSelection, options) -> myGoalScreenRange = @getGoalScreenRange() otherGoalScreenRange = otherSelection.getGoalScreenRange() @@ -705,7 +705,7 @@ class Selection extends Model else options.goalScreenRange = myGoalScreenRange ? otherGoalScreenRange - @setScreenRange(@getScreenRange().union(otherSelection.getScreenRange()), options) + @setBufferRange(@getBufferRange().union(otherSelection.getBufferRange()), options) otherSelection.destroy() ### From 66fa86e129a76fa2139ac6bc2f44cb22dcfb3057 Mon Sep 17 00:00:00 2001 From: Bjoernsen Date: Sat, 14 Mar 2015 13:42:54 +0100 Subject: [PATCH 0141/1783] Enable multiple users Enable atom for multiple users on same linux computer. --- src/browser/atom-application.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 52fc08c21..138448f52 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -18,7 +18,7 @@ DefaultSocketPath = if process.platform is 'win32' '\\\\.\\pipe\\atom-sock' else - path.join(os.tmpdir(), "atom_#{process.env['USER']}.sock") + path.join(os.tmpdir(), "atom_#{process.env.USER}.sock") # The application's singleton class. # From 1899e9b8a02642eca9fc378ccc3fe0ffb7358d31 Mon Sep 17 00:00:00 2001 From: "Machiste N. Quintana" Date: Sat, 14 Mar 2015 13:52:50 -0400 Subject: [PATCH 0142/1783] Add pane:close to atom-pane context menu --- menus/darwin.cson | 1 + 1 file changed, 1 insertion(+) diff --git a/menus/darwin.cson b/menus/darwin.cson index 7283ba16f..d1518f8e3 100644 --- a/menus/darwin.cson +++ b/menus/darwin.cson @@ -225,5 +225,6 @@ {label: 'Split Down', command: 'pane:split-down'} {label: 'Split Left', command: 'pane:split-left'} {label: 'Split Right', command: 'pane:split-right'} + {label: 'Close Pane', command: 'pane:close'} {type: 'separator'} ] From 55c5614bd40c9ea5a11ad8d158e25fd854518692 Mon Sep 17 00:00:00 2001 From: "Machiste N. Quintana" Date: Sat, 14 Mar 2015 16:30:17 -0400 Subject: [PATCH 0143/1783] Update darwin.cson Missed a spot --- menus/darwin.cson | 1 + 1 file changed, 1 insertion(+) diff --git a/menus/darwin.cson b/menus/darwin.cson index d1518f8e3..9454a7c34 100644 --- a/menus/darwin.cson +++ b/menus/darwin.cson @@ -217,6 +217,7 @@ {label: 'Split Down', command: 'pane:split-down'} {label: 'Split Left', command: 'pane:split-left'} {label: 'Split Right', command: 'pane:split-right'} + {label: 'Close Pane', command: 'pane:close'} {type: 'separator'} ] 'atom-pane': [ From bd9e48e217116e386600eefc6414b9e98185ba3f Mon Sep 17 00:00:00 2001 From: "Machiste N. Quintana" Date: Sat, 14 Mar 2015 16:30:46 -0400 Subject: [PATCH 0144/1783] Add pane:close to atom-pane context menu (Win) --- menus/win32.cson | 2 ++ 1 file changed, 2 insertions(+) diff --git a/menus/win32.cson b/menus/win32.cson index a3e5c8b8d..af26be7a5 100644 --- a/menus/win32.cson +++ b/menus/win32.cson @@ -196,6 +196,7 @@ {label: 'Split Down', command: 'pane:split-down'} {label: 'Split Left', command: 'pane:split-left'} {label: 'Split Right', command: 'pane:split-right'} + {label: 'Close Pane', command: 'pane:close'} {type: 'separator'} ] 'atom-pane': [ @@ -204,5 +205,6 @@ {label: 'Split Down', command: 'pane:split-down'} {label: 'Split Left', command: 'pane:split-left'} {label: 'Split Right', command: 'pane:split-right'} + {label: 'Close Pane', command: 'pane:close'} {type: 'separator'} ] From 8a6f966d87b24c212c47c25fbb5867994d3ce11c Mon Sep 17 00:00:00 2001 From: "Machiste N. Quintana" Date: Sat, 14 Mar 2015 16:31:23 -0400 Subject: [PATCH 0145/1783] Add pane:close to atom-pane context menu (Linux) --- menus/linux.cson | 2 ++ 1 file changed, 2 insertions(+) diff --git a/menus/linux.cson b/menus/linux.cson index fc1e58785..a3b3875c4 100644 --- a/menus/linux.cson +++ b/menus/linux.cson @@ -174,6 +174,7 @@ {label: 'Split Down', command: 'pane:split-down'} {label: 'Split Left', command: 'pane:split-left'} {label: 'Split Right', command: 'pane:split-right'} + {label: 'Close Pane', command: 'pane:close'} {type: 'separator'} ] 'atom-pane': [ @@ -182,5 +183,6 @@ {label: 'Split Down', command: 'pane:split-down'} {label: 'Split Left', command: 'pane:split-left'} {label: 'Split Right', command: 'pane:split-right'} + {label: 'Close Pane', command: 'pane:close'} {type: 'separator'} ] From d6338b0a2c1beb248f5892c62a56a4f555b09905 Mon Sep 17 00:00:00 2001 From: Bjoernsen Date: Mon, 16 Mar 2015 08:38:01 +0100 Subject: [PATCH 0146/1783] Update start-atom.coffee --- spec/integration/helpers/start-atom.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/integration/helpers/start-atom.coffee b/spec/integration/helpers/start-atom.coffee index b5f5a8c1f..9d57e93ae 100644 --- a/spec/integration/helpers/start-atom.coffee +++ b/spec/integration/helpers/start-atom.coffee @@ -9,7 +9,7 @@ webdriverio = require "../../../build/node_modules/webdriverio" AtomPath = remote.process.argv[0] AtomLauncherPath = path.join(__dirname, "..", "helpers", "atom-launcher.sh") ChromedriverPath = path.resolve(__dirname, '..', '..', '..', 'atom-shell', 'chromedriver', 'chromedriver') -SocketPath = path.join(temp.mkdirSync("socket-dir"), "atom.sock") +SocketPath = path.join(temp.mkdirSync("socket-dir"), "atom_#{process.env['USER']}.sock") ChromedriverPort = 9515 buildAtomClient = (args, env) -> From eaa72fc956e49699d19e1c352ff02206844e099c Mon Sep 17 00:00:00 2001 From: Bjoernsen Date: Mon, 16 Mar 2015 08:38:34 +0100 Subject: [PATCH 0147/1783] Update browser-process-startup.coffee --- benchmark/browser-process-startup.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/browser-process-startup.coffee b/benchmark/browser-process-startup.coffee index 06f2a0d48..53748f5d0 100755 --- a/benchmark/browser-process-startup.coffee +++ b/benchmark/browser-process-startup.coffee @@ -8,7 +8,7 @@ _ = require 'underscore-plus' temp = require 'temp' directoryToOpen = temp.mkdirSync('browser-process-startup-') -socketPath = path.join(os.tmpdir(), 'atom.sock') +socketPath = path.join(os.tmpdir(), "atom_#{process.env['USER']}.sock") numberOfRuns = 10 deleteSocketFile = -> From 823be8ca97b0f9a2907a67358160a331460a81f8 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 16 Mar 2015 09:37:31 -0700 Subject: [PATCH 0148/1783] :arrow_up: language-perl@0.17 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b94303387..cbce46ba8 100644 --- a/package.json +++ b/package.json @@ -139,7 +139,7 @@ "language-make": "0.14.0", "language-mustache": "0.11.0", "language-objective-c": "0.15.0", - "language-perl": "0.16.0", + "language-perl": "0.17.0", "language-php": "0.21.0", "language-property-list": "0.8.0", "language-python": "0.32.0", From 90bb96a23cf57d7971e7a006b4185fc2e1e83c6d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 16 Mar 2015 14:37:38 -0700 Subject: [PATCH 0149/1783] :arrow_up: apm@0.145 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index b34351f7b..a989c7a83 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.143.0" + "atom-package-manager": "0.145.0" } } From 414b82f05ec60562563b9b94fa9cea42ac9a53d9 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 16 Mar 2015 14:49:59 -0700 Subject: [PATCH 0150/1783] Bump license overrides for new jschardet version --- build/tasks/license-overrides.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/tasks/license-overrides.coffee b/build/tasks/license-overrides.coffee index b32ebb545..287d44b63 100644 --- a/build/tasks/license-overrides.coffee +++ b/build/tasks/license-overrides.coffee @@ -65,7 +65,7 @@ module.exports = IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """ - 'jschardet@1.1.0': + 'jschardet@1.1.1': license: 'LGPL' source: 'README.md in the repository' sourceText: """ From d61ceacc26bf4974cf377053cecc277973ccdada Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 16 Mar 2015 14:42:00 -0700 Subject: [PATCH 0151/1783] Make One Dark the default UI/syntax themes --- dot-atom/config.cson | 4 ++-- src/config-schema.coffee | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dot-atom/config.cson b/dot-atom/config.cson index a93b83e66..a3a5984af 100644 --- a/dot-atom/config.cson +++ b/dot-atom/config.cson @@ -2,6 +2,6 @@ 'fontSize': 16 'core': 'themes': [ - 'atom-dark-ui' - 'atom-dark-syntax' + 'one-dark-ui' + 'one-dark-syntax' ] diff --git a/src/config-schema.coffee b/src/config-schema.coffee index 078d7a40b..1f205ecbf 100644 --- a/src/config-schema.coffee +++ b/src/config-schema.coffee @@ -28,7 +28,7 @@ module.exports = type: 'string' themes: type: 'array' - default: ['atom-dark-ui', 'atom-dark-syntax'] + default: ['one-dark-ui', 'one-dark-syntax'] items: type: 'string' projectHome: From 46e881739c81527887392ce36b8553e96e5efb3f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 16 Mar 2015 15:11:12 -0700 Subject: [PATCH 0152/1783] Set themes names at beginning of spec --- spec/theme-manager-spec.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/theme-manager-spec.coffee b/spec/theme-manager-spec.coffee index 94e5fad61..5e65da1fa 100644 --- a/spec/theme-manager-spec.coffee +++ b/spec/theme-manager-spec.coffee @@ -129,6 +129,7 @@ describe "ThemeManager", -> expect(importPaths[0]).toContain 'atom-dark-ui' it 'adds theme-* classes to the workspace for each active theme', -> + atom.config.set('core.themes', ['atom-dark-ui', 'atom-dark-syntax']) workspaceElement = atom.views.getView(atom.workspace) themeManager.onDidChangeActiveThemes didChangeActiveThemesHandler = jasmine.createSpy() From 55a7ef352d16f6fb238f8b74de3c2d488fb1b9c2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 16 Mar 2015 14:54:49 -0700 Subject: [PATCH 0153/1783] Deprecate all TextEditor::on calls --- src/text-editor.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 229335c11..7db2aa810 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -512,6 +512,9 @@ class TextEditor extends Model when 'scroll-left-changed' deprecate("Use TextEditor::onDidChangeScrollLeft instead") + else + deprecate("TextEditor::on is deprecated. Use documented event subscription methods instead.") + EmitterMixin::on.apply(this, arguments) # Retrieves the current {TextBuffer}. From 7c15ec36a35318f1d5e8d09c8da7833636e66171 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 16 Mar 2015 14:56:40 -0700 Subject: [PATCH 0154/1783] Deprecate all Marker::on calls --- src/marker.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/marker.coffee b/src/marker.coffee index 98e3f0265..2224ca1c7 100644 --- a/src/marker.coffee +++ b/src/marker.coffee @@ -124,6 +124,8 @@ class Marker Grim.deprecate("Use Marker::onDidChange instead") when 'destroyed' Grim.deprecate("Use Marker::onDidDestroy instead") + else + Grim.deprecate("Marker::on is deprecated. Use documented event subscription methods instead.") EmitterMixin::on.apply(this, arguments) From 76df65b720dc280809a2eb3f4b0e4f9e871638f0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 16 Mar 2015 14:57:12 -0700 Subject: [PATCH 0155/1783] Deprecate all Project::on calls --- src/project.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/project.coffee b/src/project.coffee index 69406dbda..b15f32615 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -121,6 +121,8 @@ class Project extends Model on: (eventName) -> if eventName is 'path-changed' Grim.deprecate("Use Project::onDidChangePaths instead") + else + Grim.deprecate("Project::on is deprecated. Use documented event subscription methods instead.") super ### From fd614572f168d08309b0f65a6338097ef6a387a1 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 16 Mar 2015 14:57:27 -0700 Subject: [PATCH 0156/1783] Deprecate all Selection::on calls --- src/selection.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/selection.coffee b/src/selection.coffee index c23d106fe..5b0fdae38 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -67,6 +67,8 @@ class Selection extends Model Grim.deprecate("Use Selection::onDidChangeRange instead. Call ::getScreenRange() yourself in your callback if you need the range.") when 'destroyed' Grim.deprecate("Use Selection::onDidDestroy instead.") + else + Grim.deprecate("Selection::on is deprecated. Use documented event subscription methods instead.") super From 03a59c570e30194c871100be36fed7c16a4e3cf0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 16 Mar 2015 15:37:10 -0700 Subject: [PATCH 0157/1783] Subscribe to onDidDestroy when available --- src/pane.coffee | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/pane.coffee b/src/pane.coffee index 5cdc3016a..1aee42715 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -1,6 +1,6 @@ {find, compact, extend, last} = require 'underscore-plus' {Model} = require 'theorist' -{Emitter} = require 'event-kit' +{CompositeDisposable, Emitter} = require 'event-kit' Serializable = require 'serializable' Grim = require 'grim' PaneAxis = require './pane-axis' @@ -34,6 +34,7 @@ class Pane extends Model super @emitter = new Emitter + @subscriptions = new CompositeDisposable @items = [] @addItems(compact(params?.items ? [])) @@ -340,6 +341,8 @@ class Pane extends Model addItem: (item, index=@getActiveItemIndex() + 1) -> return if item in @items + if typeof item.onDidDestroy is 'function' + @subscriptions.add item.onDidDestroy => @removeItem(item, true) if typeof item.on is 'function' @subscribe item, 'destroyed', => @removeItem(item, true) @@ -579,6 +582,7 @@ class Pane extends Model @container.activateNextPane() if @isActive() @emitter.emit 'did-destroy' @emitter.dispose() + @subscriptions.dispose() item.destroy?() for item in @items.slice() @container?.didDestroyPane(pane: this) From 2219abece186d26cf460b7d224342e1aa7db706e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 16 Mar 2015 15:46:44 -0700 Subject: [PATCH 0158/1783] Don't use deprecated buffer events --- src/git-repository.coffee | 3 ++- src/project.coffee | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/git-repository.coffee b/src/git-repository.coffee index d523b562f..c4a9d34f5 100644 --- a/src/git-repository.coffee +++ b/src/git-repository.coffee @@ -96,7 +96,8 @@ class GitRepository @subscriptions.add new Disposable(-> window.removeEventListener 'focus', onWindowFocus) if @project? - @subscriptions.add @project.eachBuffer (buffer) => @subscribeToBuffer(buffer) + @project.getBuffers().forEach (buffer) => @subscribeToBuffer(buffer) + @subscriptions.add @project.onDidAddBuffer (buffer) => @subscribeToBuffer(buffer) # Public: Destroy this {GitRepository} object. # diff --git a/src/project.coffee b/src/project.coffee index b15f32615..a54d5edd1 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -118,6 +118,9 @@ class Project extends Model onDidChangePaths: (callback) -> @emitter.on 'did-change-paths', callback + onDidAddBuffer: (callback) -> + @emitter.on 'did-add-buffer', callback + on: (eventName) -> if eventName is 'path-changed' Grim.deprecate("Use Project::onDidChangePaths instead") @@ -436,6 +439,7 @@ class Project extends Model @buffers.splice(index, 0, buffer) @subscribeToBuffer(buffer) @emit 'buffer-created', buffer + @emitter.emit 'did-add-buffer', buffer buffer # Removes a {TextBuffer} association from the project. From 4d344c16b3ca26c7356bd98b30995716ad5a54fc Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 16 Mar 2015 15:50:13 -0700 Subject: [PATCH 0159/1783] Don't call on when onDidDestroy exists --- src/pane.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pane.coffee b/src/pane.coffee index 1aee42715..6a36bec2b 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -343,7 +343,7 @@ class Pane extends Model if typeof item.onDidDestroy is 'function' @subscriptions.add item.onDidDestroy => @removeItem(item, true) - if typeof item.on is 'function' + else if typeof item.on is 'function' @subscribe item, 'destroyed', => @removeItem(item, true) @items.splice(index, 0, item) From 84f7e6048e69bf605c8e0502b842b3f280a05e85 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 16 Mar 2015 16:22:02 -0700 Subject: [PATCH 0160/1783] :arrow_up: bracket-matcher@0.72 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cbce46ba8..e764aba90 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "autosave": "0.20.0", "background-tips": "0.23.0", "bookmarks": "0.35.0", - "bracket-matcher": "0.71.0", + "bracket-matcher": "0.72.0", "command-palette": "0.34.0", "deprecation-cop": "0.37.0", "dev-live-reload": "0.44.0", From 792a124668d64a27589929eb1914447308db1192 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 16 Mar 2015 16:25:45 -0700 Subject: [PATCH 0161/1783] Add onDidChangeIcon event subscription --- src/text-editor.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 7db2aa810..f731810ae 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -457,6 +457,10 @@ class TextEditor extends Model onDidChangeScrollLeft: (callback) -> @emitter.on 'did-change-scroll-left', callback + # TODO Remove once the tabs package no longer uses .on subscriptions + onDidChangeIcon: (callback) -> + @emitter.on 'did-change-icon', callback + on: (eventName) -> switch eventName when 'title-changed' From 0a1637184591688315b9c909c9e4759f43732fc6 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 16 Mar 2015 16:35:16 -0700 Subject: [PATCH 0162/1783] Dispose of destroyed listener on remove item --- src/pane.coffee | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/pane.coffee b/src/pane.coffee index 6a36bec2b..82f183e30 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -1,6 +1,6 @@ {find, compact, extend, last} = require 'underscore-plus' {Model} = require 'theorist' -{CompositeDisposable, Emitter} = require 'event-kit' +{Emitter} = require 'event-kit' Serializable = require 'serializable' Grim = require 'grim' PaneAxis = require './pane-axis' @@ -34,7 +34,7 @@ class Pane extends Model super @emitter = new Emitter - @subscriptions = new CompositeDisposable + @itemSubscriptions = new WeakMap @items = [] @addItems(compact(params?.items ? [])) @@ -342,7 +342,7 @@ class Pane extends Model return if item in @items if typeof item.onDidDestroy is 'function' - @subscriptions.add item.onDidDestroy => @removeItem(item, true) + @itemSubscriptions.set item, item.onDidDestroy => @removeItem(item, true) else if typeof item.on is 'function' @subscribe item, 'destroyed', => @removeItem(item, true) @@ -373,6 +373,9 @@ class Pane extends Model if typeof item.on is 'function' @unsubscribe item + @itemSubscriptions.get(item)?.dispose() + @itemSubscriptions.delete(item) + if item is @activeItem if @items.length is 1 @setActiveItem(undefined) @@ -582,8 +585,10 @@ class Pane extends Model @container.activateNextPane() if @isActive() @emitter.emit 'did-destroy' @emitter.dispose() - @subscriptions.dispose() - item.destroy?() for item in @items.slice() + for item in @items.slice() + @itemSubscriptions.get(item)?.dispose() + @itemSubscriptions.delete(item) + item.destroy?() @container?.didDestroyPane(pane: this) ### From 05bcebe583adb794cb148bdd44be80d8f359c5c8 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 16 Mar 2015 16:44:46 -0700 Subject: [PATCH 0163/1783] Add unsubscribe from item helper --- src/pane.coffee | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/pane.coffee b/src/pane.coffee index 82f183e30..0f19c40bf 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -250,6 +250,10 @@ class Pane extends Model getPanes: -> [this] + unsubscribeFromItem: (item) -> + @itemSubscriptions.get(item)?.dispose() + @itemSubscriptions.delete(item) + ### Section: Items ### @@ -372,9 +376,7 @@ class Pane extends Model if typeof item.on is 'function' @unsubscribe item - - @itemSubscriptions.get(item)?.dispose() - @itemSubscriptions.delete(item) + @unsubscribeFromItem(item) if item is @activeItem if @items.length is 1 @@ -585,10 +587,7 @@ class Pane extends Model @container.activateNextPane() if @isActive() @emitter.emit 'did-destroy' @emitter.dispose() - for item in @items.slice() - @itemSubscriptions.get(item)?.dispose() - @itemSubscriptions.delete(item) - item.destroy?() + item.destroy?() for item in @items.slice() @container?.didDestroyPane(pane: this) ### From a43333ce234d86973f6d4adc5573afe9727d9d63 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 16 Mar 2015 18:55:11 -0700 Subject: [PATCH 0164/1783] :arrow_up: atom-dark-ui@0.49.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e764aba90..f3a11d19a 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ }, "packageDependencies": { "atom-dark-syntax": "0.26.0", - "atom-dark-ui": "0.47.0", + "atom-dark-ui": "0.49.0", "atom-light-syntax": "0.26.0", "atom-light-ui": "0.41.0", "base16-tomorrow-dark-theme": "0.25.0", From 4980ce30a98615373ca17125a22e168bbb4ef44c Mon Sep 17 00:00:00 2001 From: simurai Date: Tue, 17 Mar 2015 16:02:02 +0900 Subject: [PATCH 0165/1783] Absolute position pane resize-handle - Keeps most themes unaffected - More consistent with the tree-view resizer --- static/panes.less | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/static/panes.less b/static/panes.less index ee09b8057..672878b58 100644 --- a/static/panes.less +++ b/static/panes.less @@ -4,30 +4,39 @@ // settings-view, the archive-view, the image-view. Etc. Basically a non- // editor resource with a tab. atom-pane-container { + position: relative; display: -webkit-flex; -webkit-flex: 1; - atom-pane-axis.vertical { + atom-pane-axis { display: -webkit-flex; -webkit-flex: 1; + + & > atom-pane-resize-handle { + position: absolute; + z-index: 3; + } + } + + atom-pane-axis.vertical { -webkit-flex-direction: column; & > atom-pane-resize-handle { + width: 100%; height: 8px; - z-index: 3; + margin-top: -4px; cursor: ns-resize; border-bottom: none; } } atom-pane-axis.horizontal { - display: -webkit-flex; - -webkit-flex: 1; -webkit-flex-direction: row; & > atom-pane-resize-handle { width: 8px; - z-index: 3; + height: 100%; + margin-left: -4px; cursor: ew-resize; border-right: none; } From c05a410d1185d836abfb3968e67579f217798ffe Mon Sep 17 00:00:00 2001 From: liuxiong332 Date: Tue, 17 Mar 2015 15:35:16 +0800 Subject: [PATCH 0166/1783] add serialization for pane's flex scale when resize the pane --- src/pane-axis-element.coffee | 3 +++ src/pane-axis.coffee | 17 +++++++++++++++- src/pane-element.coffee | 7 +++++-- src/pane-resize-handle-element.coffee | 13 ++++++------ src/pane.coffee | 29 +++++++++++++++++++++++++++ 5 files changed, 59 insertions(+), 10 deletions(-) diff --git a/src/pane-axis-element.coffee b/src/pane-axis-element.coffee index fc6ba2edb..aaa8c6207 100644 --- a/src/pane-axis-element.coffee +++ b/src/pane-axis-element.coffee @@ -13,6 +13,7 @@ class PaneAxisElement extends HTMLElement @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)) @childAdded({child, index}) for child, index in @model.getChildren() @@ -58,6 +59,8 @@ class PaneAxisElement extends HTMLElement @childAdded({child: newChild, index}) focusedElement?.focus() if document.activeElement is document.body + flexScaleChanged: (flexScale) -> @style.flexGrow = flexScale + hasFocus: -> this is document.activeElement or @contains(document.activeElement) diff --git a/src/pane-axis.coffee b/src/pane-axis.coffee index a9eb0757b..3df39c683 100644 --- a/src/pane-axis.coffee +++ b/src/pane-axis.coffee @@ -12,13 +12,14 @@ class PaneAxis extends Model container: null orientation: null - constructor: ({@container, @orientation, children}) -> + constructor: ({@container, @orientation, children, flexScale}) -> @emitter = new Emitter @subscriptionsByChild = new WeakMap @subscriptions = new CompositeDisposable @children = [] if children? @addChild(child) for child in children + @flexScale = flexScale ? 1 deserializeParams: (params) -> {container} = params @@ -28,6 +29,13 @@ class PaneAxis extends Model serializeParams: -> children: @children.map (child) -> child.serialize() orientation: @orientation + flexScale: @flexScale + + getFlexScale: -> @flexScale + + setFlexScale: (@flexScale) -> + @emitter.emit 'did-change-flex-scale', @flexScale + @flexScale getParent: -> @parent @@ -59,6 +67,13 @@ class PaneAxis extends Model onDidDestroy: (fn) -> @emitter.on 'did-destroy', fn + onDidChangeFlexScale: (fn) -> + @emitter.on 'did-change-flex-scale', fn + + observeFlexScale: (fn) -> + fn(@flexScale) + @onDidChangeFlexScale(fn) + addChild: (child, index=@children.length) -> child.setParent(this) child.setContainer(@container) diff --git a/src/pane-element.coffee b/src/pane-element.coffee index df4335e4c..ac49c86ab 100644 --- a/src/pane-element.coffee +++ b/src/pane-element.coffee @@ -1,7 +1,6 @@ {CompositeDisposable} = require 'event-kit' {$, callAttachHooks, callRemoveHooks} = require './space-pen-extensions' PaneView = require './pane-view' -_ = require 'underscore-plus' class PaneElement extends HTMLElement attached: false @@ -46,7 +45,7 @@ class PaneElement extends HTMLElement event.preventDefault() event.stopPropagation() @getModel().activate() - pathsToOpen = _.pluck(event.dataTransfer.files, 'path') + pathsToOpen = Array::map.call event.dataTransfer.files, (file) -> file.path atom.open({pathsToOpen}) if pathsToOpen.length > 0 @addEventListener 'focus', handleFocus, true @@ -63,6 +62,7 @@ class PaneElement extends HTMLElement @subscriptions.add @model.observeActiveItem(@activeItemChanged.bind(this)) @subscriptions.add @model.onDidRemoveItem(@itemRemoved.bind(this)) @subscriptions.add @model.onDidDestroy(@paneDestroyed.bind(this)) + @subscriptions.add @model.observeFlexScale(@flexScaleChanged.bind(this)) @__spacePenView.setModel(@model) this @@ -116,6 +116,9 @@ class PaneElement extends HTMLElement paneDestroyed: -> @subscriptions.dispose() + flexScaleChanged: (flexScale) -> + @style.flexGrow = flexScale + getActiveView: -> atom.views.getView(@model.getActiveItem()) hasFocus: -> diff --git a/src/pane-resize-handle-element.coffee b/src/pane-resize-handle-element.coffee index d04e3a93b..aca900d99 100644 --- a/src/pane-resize-handle-element.coffee +++ b/src/pane-resize-handle-element.coffee @@ -29,14 +29,13 @@ class PaneResizeHandleElement extends HTMLElement allRatio = ratio1 + ratio2 [total * ratio1 / allRatio, total * ratio2 / allRatio] - getFlexGrow: (element) -> - parseFloat window.getComputedStyle(element).flexGrow - setFlexGrow: (prevSize, nextSize) -> - flexGrow = @getFlexGrow(@previousSibling) + @getFlexGrow(@nextSibling) - flexGrows = @calcRatio(prevSize, nextSize, flexGrow) - @previousSibling.style.flexGrow = flexGrows[0] - @nextSibling.style.flexGrow = flexGrows[1] + @prevModel = @previousSibling.getModel() + @nextModel = @nextSibling.getModel() + totalScale = @prevModel.getFlexScale() + @nextModel.getFlexScale() + flexGrows = @calcRatio(prevSize, nextSize, totalScale) + @prevModel.setFlexScale flexGrows[0] + @nextModel.setFlexScale flexGrows[1] fixInRange: (val, minValue, maxValue) -> Math.min(Math.max(val, minValue), maxValue) diff --git a/src/pane.coffee b/src/pane.coffee index 5cdc3016a..2b198c569 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -20,6 +20,7 @@ class Pane extends Model container: undefined activeItem: undefined focused: false + flexScale: 1 # Public: Only one pane is considered *active* at a time. A pane is activated # when it is focused, and when focus returns to the pane container after @@ -38,6 +39,7 @@ class Pane extends Model @addItems(compact(params?.items ? [])) @setActiveItem(@items[0]) unless @getActiveItem()? + @setFlexScale(params?.flexScale ? 1) # Called by the Serializable mixin during serialization. serializeParams: -> @@ -50,6 +52,7 @@ class Pane extends Model items: compact(@items.map((item) -> item.serialize?())) activeItemURI: activeItemURI focused: @focused + flexScale: @flexScale # Called by the Serializable mixin during deserialization. deserializeParams: (params) -> @@ -76,10 +79,36 @@ class Pane extends Model @container = container container.didAddPane({pane: this}) + setFlexScale: (@flexScale) -> + @emitter.emit 'did-change-flex-scale', @flexScale + @flexScale + + getFlexScale: -> @flexScale ### Section: Event Subscription ### + # Public: Invoke the given callback when the pane resize + # + # the callback will be invoked when pane's flexScale property changes + # + # * `callback` {Function} to be called when the pane is resized + # + # Returns a {Disposable} on which '.dispose()' can be called to unsubscribe. + onDidChangeFlexScale: (callback) -> + @emitter.on 'did-change-flex-scale', callback + + # Public: Invoke the given callback with all current and future items. + # + # * `callback` {Function} to be called with current and future items. + # * `item` An item that is present in {::getItems} at the time of + # subscription or that is added at some later time. + # + # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. + observeFlexScale: (callback) -> + callback(@flexScale) + @onDidChangeFlexScale(callback) + # Public: Invoke the given callback when the pane is activated. # # The given callback will be invoked whenever {::activate} is called on the From 86ef14b60085c499eee2eed7ac6f443402ff7a44 Mon Sep 17 00:00:00 2001 From: liuxiong332 Date: Tue, 17 Mar 2015 15:48:32 +0800 Subject: [PATCH 0167/1783] when split panes and replace the pane with new pane axis, switch the flex scale --- src/pane.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pane.coffee b/src/pane.coffee index 2b198c569..7e8374efe 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -661,7 +661,8 @@ class Pane extends Model params.items.push(@copyActiveItem()) if @parent.orientation isnt orientation - @parent.replaceChild(this, new PaneAxis({@container, orientation, children: [this]})) + @parent.replaceChild(this, new PaneAxis({@container, orientation, children: [this], @flexScale})) + @setFlexScale(1) newPane = new @constructor(params) switch side From c9c050d147ab09f9d0f298a335678a7210ea35ee Mon Sep 17 00:00:00 2001 From: liuxiong332 Date: Tue, 17 Mar 2015 17:25:07 +0800 Subject: [PATCH 0168/1783] adjust the flex scale when close pane --- src/pane-axis.coffee | 15 ++++++++++++++- src/pane-resize-handle-element.coffee | 8 ++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/pane-axis.coffee b/src/pane-axis.coffee index 3df39c683..9d946b391 100644 --- a/src/pane-axis.coffee +++ b/src/pane-axis.coffee @@ -83,6 +83,16 @@ class PaneAxis extends Model @children.splice(index, 0, child) @emitter.emit 'did-add-child', {child, index} + adjustFlexScale: -> + # get current total flex scale of children + total = 0 + total += child.getFlexScale() for child in @children + + needTotal = @children.length + # set every child's flex scale by the ratio + for child in @children + child.setFlexScale(needTotal * child.getFlexScale() / total) + removeChild: (child, replacing=false) -> index = @children.indexOf(child) throw new Error("Removing non-existent child") if index is -1 @@ -90,6 +100,7 @@ class PaneAxis extends Model @unsubscribeFromChild(child) @children.splice(index, 1) + @adjustFlexScale() @emitter.emit 'did-remove-child', {child, index} @reparentLastChild() if not replacing and @children.length < 2 @@ -113,7 +124,9 @@ class PaneAxis extends Model @addChild(newChild, index + 1) reparentLastChild: -> - @parent.replaceChild(this, @children[0]) + lastChild = @children[0] + lastChild.setFlexScale(@flexScale) + @parent.replaceChild(this, lastChild) @destroy() subscribeToChild: (child) -> diff --git a/src/pane-resize-handle-element.coffee b/src/pane-resize-handle-element.coffee index aca900d99..74b2a1989 100644 --- a/src/pane-resize-handle-element.coffee +++ b/src/pane-resize-handle-element.coffee @@ -13,8 +13,8 @@ class PaneResizeHandleElement extends HTMLElement resizeToFitContent: -> # clear flex-grow css style of both pane - @previousSibling.style.flexGrow = '' - @nextSibling.style.flexGrow = '' + @previousSibling.model.setFlexScale(1) + @nextSibling.model.setFlexScale(1) resizeStarted: (e)-> e.stopPropagation() @@ -30,8 +30,8 @@ class PaneResizeHandleElement extends HTMLElement [total * ratio1 / allRatio, total * ratio2 / allRatio] setFlexGrow: (prevSize, nextSize) -> - @prevModel = @previousSibling.getModel() - @nextModel = @nextSibling.getModel() + @prevModel = @previousSibling.model + @nextModel = @nextSibling.model totalScale = @prevModel.getFlexScale() + @nextModel.getFlexScale() flexGrows = @calcRatio(prevSize, nextSize, totalScale) @prevModel.setFlexScale flexGrows[0] From 8c5db29035bbd8984c53dae14e56a1bc4edee79b Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 17 Mar 2015 10:46:30 -0700 Subject: [PATCH 0169/1783] :arrow_up: notifications@0.33.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f3a11d19a..964e2ecd8 100644 --- a/package.json +++ b/package.json @@ -105,7 +105,7 @@ "link": "0.30.0", "markdown-preview": "0.141.0", "metrics": "0.45.0", - "notifications": "0.32.0", + "notifications": "0.33.0", "open-on-github": "0.34.0", "package-generator": "0.38.0", "release-notes": "0.52.0", From 916f3c0996053d010e80568ccfb3c1ce3bbf6015 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 17 Mar 2015 11:33:12 -0700 Subject: [PATCH 0170/1783] :arrow_up: language-perl@0.18 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 964e2ecd8..163cffb09 100644 --- a/package.json +++ b/package.json @@ -139,7 +139,7 @@ "language-make": "0.14.0", "language-mustache": "0.11.0", "language-objective-c": "0.15.0", - "language-perl": "0.17.0", + "language-perl": "0.18.0", "language-php": "0.21.0", "language-property-list": "0.8.0", "language-python": "0.32.0", From fec8ea42729278e66f1b212bce38f5a7848275d0 Mon Sep 17 00:00:00 2001 From: vegar Date: Tue, 17 Mar 2015 20:09:37 +0100 Subject: [PATCH 0171/1783] Documentation: workspace.open( ) with no URI I just learned that [calling open on workspace](https://discuss.atom.io/t/how-can-we-help-you-write-packages/4268/67) without specifying an uri is the way to go for getting a new tab with a new document. I can't find anything about this in either the docs or the [api documentation.](https://atom.io/docs/api/v0.187.0/Workspace#instance-open) Should `uri` be marked optional, like the `options` params? And should it be added a line stating that no uri opens a blank editor? (and there's an extra `a` in the title..) --- src/workspace.coffee | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/workspace.coffee b/src/workspace.coffee index 49f84f9b8..c8040f920 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -371,9 +371,11 @@ class Workspace extends Model Section: Opening ### - # Essential: Open a given a URI in Atom asynchronously. - # - # * `uri` A {String} containing a URI. + # Essential: Open a given URI in Atom asynchronously. + # If no URI is given, or URI does not resolve to an existing file, + # a new empty text edtior is created. + # + # * `uri` (optional) A {String} containing a URI. # * `options` (optional) {Object} # * `initialLine` A {Number} indicating which row to move the cursor to # initially. Defaults to `0`. From ddb45566581147385735b7091062152f43c437af Mon Sep 17 00:00:00 2001 From: octref Date: Tue, 17 Mar 2015 15:27:02 -0400 Subject: [PATCH 0172/1783] Don't tokenize on NullGrammar For file format that Atom doesn't recognize as a programming language, such as log files, skip Tokenization since no syntax highlighting should be done. --- src/tokenized-buffer.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 67e4deb87..b068e587b 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -138,6 +138,7 @@ class TokenizedBuffer extends Model tokenizeInBackground: -> return if not @visible or @pendingChunk or not @isAlive() + return if @grammar is @grammar.registry.nullGrammar @pendingChunk = true _.defer => @pendingChunk = false From 7a4ad18f6a324e70ed46d3b230382ddcb94d658a Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 17 Mar 2015 13:51:41 -0600 Subject: [PATCH 0173/1783] :arrow_up: markdown-preview --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 163cffb09..343a0c537 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,7 @@ "incompatible-packages": "0.24.0", "keybinding-resolver": "0.29.0", "link": "0.30.0", - "markdown-preview": "0.141.0", + "markdown-preview": "0.142.0", "metrics": "0.45.0", "notifications": "0.33.0", "open-on-github": "0.34.0", From 67b1d7890b4bd1f5ae78c67eb35c0cdb77812246 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 17 Mar 2015 22:05:43 +0100 Subject: [PATCH 0174/1783] Add soft-wrap hanging indentation spaces --- src/display-buffer.coffee | 10 +++++++++- src/tokenized-line.coffee | 19 ++++++++++++------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index 5659d38a0..ecdd36c6d 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -69,12 +69,17 @@ class DisplayBuffer extends Model scrollPastEnd: atom.config.get('editor.scrollPastEnd', scope: scopeDescriptor) softWrap: atom.config.get('editor.softWrap', scope: scopeDescriptor) softWrapAtPreferredLineLength: atom.config.get('editor.softWrapAtPreferredLineLength', scope: scopeDescriptor) + softWrapHangingIndentationSpaces: atom.config.get('editor.softWrapHangingIndentationSpaces', scope: scopeDescriptor) preferredLineLength: atom.config.get('editor.preferredLineLength', scope: scopeDescriptor) subscriptions.add atom.config.onDidChange 'editor.softWrap', scope: scopeDescriptor, ({newValue}) => @configSettings.softWrap = newValue @updateWrappedScreenLines() + subscriptions.add atom.config.onDidChange 'editor.softWrapHangingIndentationSpaces', scope: scopeDescriptor, ({newValue}) => + @configSettings.softWrapHangingIndentationSpaces = newValue + @updateWrappedScreenLines() + subscriptions.add atom.config.onDidChange 'editor.softWrapAtPreferredLineLength', scope: scopeDescriptor, ({newValue}) => @configSettings.softWrapAtPreferredLineLength = newValue @updateWrappedScreenLines() if @isSoftWrapped() @@ -1157,7 +1162,10 @@ class DisplayBuffer extends Model softWraps = 0 if @isSoftWrapped() while wrapScreenColumn = tokenizedLine.findWrapColumn(@getSoftWrapColumn()) - [wrappedLine, tokenizedLine] = tokenizedLine.softWrapAt(wrapScreenColumn) + [wrappedLine, tokenizedLine] = tokenizedLine.softWrapAt( + wrapScreenColumn, + hangingIndentationSpaces: @configSettings.softWrapHangingIndentationSpaces + ) break if wrappedLine.hasOnlySoftWrapIndentation() screenLines.push(wrappedLine) softWraps++ diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 3560c35a1..ab12d39c3 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -118,18 +118,23 @@ class TokenizedLine oddIndentLevel = @indentLevel - Math.floor(@indentLevel) Math.round(@tabLength * oddIndentLevel) - buildSoftWrapIndentationTokens: (token) -> + buildSoftWrapIndentationTokens: (token, hangingIndentationSpaces) -> indentTokens = [0...Math.floor(@indentLevel)].map => token.buildSoftWrapIndentationToken(@tabLength) if @getOddIndentationSpaces() - indentTokens.concat( - token.buildSoftWrapIndentationToken @getOddIndentationSpaces() + indentTokens.push( + token.buildSoftWrapIndentationToken(@getOddIndentationSpaces()) ) - else - indentTokens - softWrapAt: (column) -> + if hangingIndentationSpaces + indentTokens.push( + token.buildSoftWrapIndentationToken(hangingIndentationSpaces) + ) + + indentTokens + + softWrapAt: (column, {hangingIndentationSpaces}) -> return [new TokenizedLine([], '', [0, 0], [0, 0]), this] if column == 0 rightTokens = new Array(@tokens...) @@ -142,7 +147,7 @@ class TokenizedLine leftTextLength += nextToken.value.length leftTokens.push nextToken - indentationTokens = @buildSoftWrapIndentationTokens(leftTokens[0]) + indentationTokens = @buildSoftWrapIndentationTokens(leftTokens[0], hangingIndentationSpaces) leftFragment = new TokenizedLine( tokens: leftTokens From 6d39bd3657eb64bd1a1f4fb1589768bdf1553b72 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 17 Mar 2015 22:21:07 +0100 Subject: [PATCH 0175/1783] :white_check_mark: Verify that hanging indentation is tokenized --- spec/display-buffer-spec.coffee | 6 ++++++ src/tokenized-line.coffee | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index df7c13383..5a719198d 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -128,6 +128,12 @@ describe "DisplayBuffer", -> expect(displayBuffer.tokenizedLineForScreenRow(4).tokens[0].isSoftWrapIndentation).toBeTruthy() expect(displayBuffer.tokenizedLineForScreenRow(4).tokens[1].isSoftWrapIndentation).toBeTruthy() + it "correctly tokenizes hanging indentation spaces", -> + atom.config.set("editor.softWrapHangingIndentationSpaces", 3) + expect(displayBuffer.tokenizedLineForScreenRow(4).tokens[0].isSoftWrapIndentation).toBeTruthy() + expect(displayBuffer.tokenizedLineForScreenRow(4).tokens[1].isSoftWrapIndentation).toBeTruthy() + expect(displayBuffer.tokenizedLineForScreenRow(4).tokens[2].isSoftWrapIndentation).toBeTruthy() + describe "when the buffer changes", -> describe "when buffer lines are updated", -> describe "when whitespace is added after the max line length", -> diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index ab12d39c3..0437fbdcf 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -134,9 +134,11 @@ class TokenizedLine indentTokens - softWrapAt: (column, {hangingIndentationSpaces}) -> + softWrapAt: (column, options = {}) -> return [new TokenizedLine([], '', [0, 0], [0, 0]), this] if column == 0 + {hangingIndentationSpaces} = options + rightTokens = new Array(@tokens...) leftTokens = [] leftTextLength = 0 From c4d2e0eac8c62e2aafb5784813e7b2ae1a4c28cc Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 17 Mar 2015 22:42:51 +0100 Subject: [PATCH 0176/1783] Add default editor.softWrapHangingIndentationSpaces --- src/config-schema.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/config-schema.coffee b/src/config-schema.coffee index 1f205ecbf..74fc719a4 100644 --- a/src/config-schema.coffee +++ b/src/config-schema.coffee @@ -149,6 +149,9 @@ module.exports = softWrapAtPreferredLineLength: type: 'boolean' default: false + softWrapHangingIndentationSpaces: + type: 'integer' + default: 0 scrollSensitivity: type: 'integer' default: 40 From 6ac8af2a6e7799cbf72e2fc6998f9329159e40d0 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 17 Mar 2015 22:58:14 +0100 Subject: [PATCH 0177/1783] :white_check_mark: Check leading spaces as well --- spec/display-buffer-spec.coffee | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index 5a719198d..1306174aa 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -128,8 +128,15 @@ describe "DisplayBuffer", -> expect(displayBuffer.tokenizedLineForScreenRow(4).tokens[0].isSoftWrapIndentation).toBeTruthy() expect(displayBuffer.tokenizedLineForScreenRow(4).tokens[1].isSoftWrapIndentation).toBeTruthy() + describe "when editor.softWrapHangingIndentationSpaces is set", -> + beforeEach -> + atom.config.set('editor.softWrapHangingIndentationSpaces', 3) + + it "further indents wrapped lines", -> + expect(displayBuffer.tokenizedLineForScreenRow(11).text).toBe " sort(left).concat(pivot).concat(sort(right)" + expect(displayBuffer.tokenizedLineForScreenRow(12).text).toBe " );" + it "correctly tokenizes hanging indentation spaces", -> - atom.config.set("editor.softWrapHangingIndentationSpaces", 3) expect(displayBuffer.tokenizedLineForScreenRow(4).tokens[0].isSoftWrapIndentation).toBeTruthy() expect(displayBuffer.tokenizedLineForScreenRow(4).tokens[1].isSoftWrapIndentation).toBeTruthy() expect(displayBuffer.tokenizedLineForScreenRow(4).tokens[2].isSoftWrapIndentation).toBeTruthy() From 5dc537778f7897a6226d821bcff86f05f6cf45c5 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 17 Mar 2015 14:45:09 -0700 Subject: [PATCH 0178/1783] :arrow_up: pathwatcher@4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 343a0c537..9863433fd 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "nslog": "^2.0.0", "oniguruma": "^4.0.0", "optimist": "0.4.0", - "pathwatcher": "^3.3.3", + "pathwatcher": "^4.2", "property-accessors": "^1.1.3", "q": "^1.1.2", "random-words": "0.0.1", From 408c1d31777704a643e4dec34446073be6f3f456 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 17 Mar 2015 14:46:52 -0700 Subject: [PATCH 0179/1783] :arrow_up: text-buffer@5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9863433fd..42a5ff0de 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "space-pen": "3.8.2", "stacktrace-parser": "0.1.1", "temp": "0.8.1", - "text-buffer": "^4.1.5", + "text-buffer": "^5", "theorist": "^1.0.2", "underscore-plus": "^1.6.6" }, From 782b7fd873f4847a8b44cca9941a6b35d67a29ae Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 17 Mar 2015 14:52:02 -0700 Subject: [PATCH 0180/1783] :arrow_up: atom-keymap@4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 42a5ff0de..f31f725f9 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "atomShellVersion": "0.21.3", "dependencies": { "async": "0.2.6", - "atom-keymap": "^3.1.5", + "atom-keymap": "^4", "atom-space-pen-views": "^2.0.4", "babel-core": "^4.0.2", "bootstrap": "git+https://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372", From db487baaa62ca26313831b54c8591b69c48a5ed5 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 17 Mar 2015 15:00:37 -0700 Subject: [PATCH 0181/1783] :arrow_up: archive-view@0.53 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f31f725f9..c8eb8da22 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,7 @@ "one-light-ui": "0.4.0", "solarized-dark-syntax": "0.32.0", "solarized-light-syntax": "0.19.0", - "archive-view": "0.52.0", + "archive-view": "0.53.0", "autocomplete": "0.44.0", "autoflow": "0.22.0", "autosave": "0.20.0", From 090b47d3501c70db5b8cfd614f3fc648aa60b82e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 17 Mar 2015 15:02:20 -0700 Subject: [PATCH 0182/1783] :arrow_up: dev-live-reload@0.45 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c8eb8da22..9b046a5a9 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,7 @@ "bracket-matcher": "0.72.0", "command-palette": "0.34.0", "deprecation-cop": "0.37.0", - "dev-live-reload": "0.44.0", + "dev-live-reload": "0.45.0", "encoding-selector": "0.19.0", "exception-reporting": "0.24.0", "feedback": "0.34.0", From cb2f9bdf2d110609167fd6e0c3a6f63cfc4b0869 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 17 Mar 2015 15:04:53 -0700 Subject: [PATCH 0183/1783] :arrow_up: image-view@0.52 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9b046a5a9..85278ecc2 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "git-diff": "0.54.0", "go-to-line": "0.30.0", "grammar-selector": "0.46.0", - "image-view": "0.51.0", + "image-view": "0.52.0", "incompatible-packages": "0.24.0", "keybinding-resolver": "0.29.0", "link": "0.30.0", From 5b34ba645c00258f18c139b87c97c050c1bfbd99 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 17 Mar 2015 15:18:44 -0700 Subject: [PATCH 0184/1783] :arrow_up: pathwatcher@4.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 85278ecc2..a4b66bd40 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "nslog": "^2.0.0", "oniguruma": "^4.0.0", "optimist": "0.4.0", - "pathwatcher": "^4.2", + "pathwatcher": "^4.3", "property-accessors": "^1.1.3", "q": "^1.1.2", "random-words": "0.0.1", From 862b990a8088948957140dfc0a63dd9bab2a0bc2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 17 Mar 2015 15:29:52 -0700 Subject: [PATCH 0185/1783] :arrow_up: markdown-preview@0.143 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a4b66bd40..eb078dd26 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,7 @@ "incompatible-packages": "0.24.0", "keybinding-resolver": "0.29.0", "link": "0.30.0", - "markdown-preview": "0.142.0", + "markdown-preview": "0.143.0", "metrics": "0.45.0", "notifications": "0.33.0", "open-on-github": "0.34.0", From e15cde0b2237f13745259a0dc41a1e1925145eee Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 17 Mar 2015 15:41:02 -0700 Subject: [PATCH 0186/1783] :arrow_up: snippets@0.83 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index eb078dd26..b9015e8f3 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "package-generator": "0.38.0", "release-notes": "0.52.0", "settings-view": "0.184.0", - "snippets": "0.82.0", + "snippets": "0.83.0", "spell-check": "0.55.0", "status-bar": "0.63.0", "styleguide": "0.44.0", From 6df9fa85118a0181d8b4254c15b1f9886ce51e43 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 17 Mar 2015 15:42:07 -0700 Subject: [PATCH 0187/1783] :arrow_up: symbols-view@0.91 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b9015e8f3..7e3eafbe8 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "spell-check": "0.55.0", "status-bar": "0.63.0", "styleguide": "0.44.0", - "symbols-view": "0.90.0", + "symbols-view": "0.91.0", "tabs": "0.67.0", "timecop": "0.31.0", "tree-view": "0.167.0", From 2e2b4355e3a28a90e109e15d1d69249b871f8c92 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 17 Mar 2015 15:43:09 -0700 Subject: [PATCH 0188/1783] :arrow_up: tree-view@0.168 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7e3eafbe8..018424cbc 100644 --- a/package.json +++ b/package.json @@ -117,7 +117,7 @@ "symbols-view": "0.91.0", "tabs": "0.67.0", "timecop": "0.31.0", - "tree-view": "0.167.0", + "tree-view": "0.168.0", "update-package-dependencies": "0.9.0", "welcome": "0.25.0", "whitespace": "0.29.0", From 9e28d31054ffcc18735167e92bb47322646195a8 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 17 Mar 2015 16:09:47 -0700 Subject: [PATCH 0189/1783] :arrow_up: pathwatcher@4.3.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 018424cbc..dad0a1b0c 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "nslog": "^2.0.0", "oniguruma": "^4.0.0", "optimist": "0.4.0", - "pathwatcher": "^4.3", + "pathwatcher": "^4.3.1", "property-accessors": "^1.1.3", "q": "^1.1.2", "random-words": "0.0.1", From eb63556b27a347772007ffae389a621b53b6e1b0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 17 Mar 2015 16:51:52 -0700 Subject: [PATCH 0190/1783] Use - in socket file name --- benchmark/browser-process-startup.coffee | 2 +- spec/integration/helpers/start-atom.coffee | 2 +- src/browser/atom-application.coffee | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/benchmark/browser-process-startup.coffee b/benchmark/browser-process-startup.coffee index 53748f5d0..2b06eaaa4 100755 --- a/benchmark/browser-process-startup.coffee +++ b/benchmark/browser-process-startup.coffee @@ -8,7 +8,7 @@ _ = require 'underscore-plus' temp = require 'temp' directoryToOpen = temp.mkdirSync('browser-process-startup-') -socketPath = path.join(os.tmpdir(), "atom_#{process.env['USER']}.sock") +socketPath = path.join(os.tmpdir(), "atom-#{process.env.USER}.sock") numberOfRuns = 10 deleteSocketFile = -> diff --git a/spec/integration/helpers/start-atom.coffee b/spec/integration/helpers/start-atom.coffee index 9d57e93ae..4be2efab8 100644 --- a/spec/integration/helpers/start-atom.coffee +++ b/spec/integration/helpers/start-atom.coffee @@ -9,7 +9,7 @@ webdriverio = require "../../../build/node_modules/webdriverio" AtomPath = remote.process.argv[0] AtomLauncherPath = path.join(__dirname, "..", "helpers", "atom-launcher.sh") ChromedriverPath = path.resolve(__dirname, '..', '..', '..', 'atom-shell', 'chromedriver', 'chromedriver') -SocketPath = path.join(temp.mkdirSync("socket-dir"), "atom_#{process.env['USER']}.sock") +SocketPath = path.join(temp.mkdirSync("socket-dir"), "atom-#{process.env.USER}.sock") ChromedriverPort = 9515 buildAtomClient = (args, env) -> diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 138448f52..8fa888730 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -18,7 +18,7 @@ DefaultSocketPath = if process.platform is 'win32' '\\\\.\\pipe\\atom-sock' else - path.join(os.tmpdir(), "atom_#{process.env.USER}.sock") + path.join(os.tmpdir(), "atom-#{process.env.USER}.sock") # The application's singleton class. # From cd5adb6ab72bdd30168888161972469a77299a52 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 17 Mar 2015 17:41:22 -0700 Subject: [PATCH 0191/1783] Clear invalid rows when short-circuiting for null grammar --- spec/tokenized-buffer-spec.coffee | 22 ++++++++++++++++++++++ src/tokenized-buffer.coffee | 19 ++++++++++++++----- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/spec/tokenized-buffer-spec.coffee b/spec/tokenized-buffer-spec.coffee index 0adcd2756..c1b16ff08 100644 --- a/spec/tokenized-buffer-spec.coffee +++ b/spec/tokenized-buffer-spec.coffee @@ -878,3 +878,25 @@ describe "TokenizedBuffer", -> expect(tokenizedBuffer.tokenizedLineForRow(6).foldable).toBe true expect(tokenizedBuffer.tokenizedLineForRow(7).foldable).toBe false expect(tokenizedBuffer.tokenizedLineForRow(8).foldable).toBe false + + describe "when the buffer is configured with the null grammar", -> + it "uses the placeholder tokens and does not actually tokenize using the grammar", -> + spyOn(atom.grammars.nullGrammar, 'tokenizeLine').andCallThrough() + buffer = atom.project.bufferForPathSync('sample.will-use-the-null-grammar') + buffer.setText('a\nb\nc') + + tokenizedBuffer = new TokenizedBuffer({buffer}) + tokenizeCallback = jasmine.createSpy('onDidTokenize') + tokenizedBuffer.onDidTokenize(tokenizeCallback) + + fullyTokenize(tokenizedBuffer) + + expect(tokenizeCallback.callCount).toBe 1 + expect(atom.grammars.nullGrammar.tokenizeLine.callCount).toBe 0 + + expect(tokenizedBuffer.tokenizedLineForRow(0).tokens.length).toBe 1 + expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[0].value).toBe 'a' + expect(tokenizedBuffer.tokenizedLineForRow(1).tokens.length).toBe 1 + expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[0].value).toBe 'b' + expect(tokenizedBuffer.tokenizedLineForRow(2).tokens.length).toBe 1 + expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[0].value).toBe 'c' diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index b068e587b..b8a9bdab7 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -138,13 +138,19 @@ class TokenizedBuffer extends Model tokenizeInBackground: -> return if not @visible or @pendingChunk or not @isAlive() - return if @grammar is @grammar.registry.nullGrammar + @pendingChunk = true _.defer => @pendingChunk = false @tokenizeNextChunk() if @isAlive() and @buffer.isAlive() tokenizeNextChunk: -> + # Short circuit null grammar which can just use the placeholder tokens + if @grammar is atom.grammars.nullGrammar and @firstInvalidRow()? + @invalidRows = [] + @markTokenizationComplete() + return + rowsRemaining = @chunkSize while @firstInvalidRow()? and rowsRemaining > 0 @@ -178,10 +184,13 @@ class TokenizedBuffer extends Model if @firstInvalidRow()? @tokenizeInBackground() else - unless @fullyTokenized - @emit 'tokenized' - @emitter.emit 'did-tokenize' - @fullyTokenized = true + @markTokenizationComplete() + + markTokenizationComplete: -> + unless @fullyTokenized + @emit 'tokenized' + @emitter.emit 'did-tokenize' + @fullyTokenized = true firstInvalidRow: -> @invalidRows[0] From 67754506953457119896da96d6d462e1ff9f34b6 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 17 Mar 2015 18:00:34 -0700 Subject: [PATCH 0192/1783] :arrow_up: snippets@0.84 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dad0a1b0c..6fea8211a 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "package-generator": "0.38.0", "release-notes": "0.52.0", "settings-view": "0.184.0", - "snippets": "0.83.0", + "snippets": "0.84.0", "spell-check": "0.55.0", "status-bar": "0.63.0", "styleguide": "0.44.0", From 60434b1a7da91fec02474257c2276d221a64324f Mon Sep 17 00:00:00 2001 From: liuxiong332 Date: Wed, 18 Mar 2015 13:32:19 +0800 Subject: [PATCH 0193/1783] simplify the pane-axis-element-spec spec files --- spec/pane-axis-element-spec.coffee | 72 +++++++++++++----------------- 1 file changed, 30 insertions(+), 42 deletions(-) diff --git a/spec/pane-axis-element-spec.coffee b/spec/pane-axis-element-spec.coffee index 868f2ce11..623d3a614 100644 --- a/spec/pane-axis-element-spec.coffee +++ b/spec/pane-axis-element-spec.coffee @@ -1,58 +1,46 @@ PaneAxisElement = require '../src/pane-axis-element' +PaneAxis = require '../src/pane-axis.coffee' -describe "PaneResizeHandleElement", -> +fdescribe "PaneResizeHandleElement", -> describe "add and remove", -> - class TestItemElement extends HTMLElement - createdCallback: -> - @classList.add('test-root') + [paneAxisElement, paneAxis] = [] - TestItemElement = document.registerElement 'atom-test-item-element', prototype: TestItemElement.prototype - - [paneAxis, model, Model] = [] beforeEach -> - # This is a dummy item to prevent panes from being empty on deserialization - class Model - @newChild: -> document.createElement('atom-test-item-element') - add: (child, index) -> @addCallback({child, index}) - remove: (child) -> @removeCallback {child} - replace: (index, oldChild, newChild) -> - @replaceCallback {index, oldChild, newChild} - onDidAddChild: (@addCallback) -> - onDidRemoveChild: (@removeCallback) -> - onDidReplaceChild: (@replaceCallback) -> - getOrientation: -> 'horizontal' - getChildren: -> [] + paneAxisElement = document.createElement('atom-pane-axis') + paneAxis = new PaneAxis({}) + paneAxisElement.initialize(paneAxis) + document.querySelector('#jasmine-content').appendChild(paneAxisElement) - paneAxis = document.createElement('atom-pane-axis') - model = new Model - paneAxis.initialize(model) - document.querySelector('#jasmine-content').appendChild(paneAxis) + it "inserts draggable resize elements between pane axis children", -> + expect(paneAxisElement).toBeTruthy() + modelChildren = (new PaneAxis({}) for i in [1..5]) + paneAxis.addChild(modelChildren[0]) + paneAxis.addChild(modelChildren[1]) - it "should insert the correct postion in one pane axis", -> - expect(paneAxis).toBeTruthy() - modelChildren = (Model.newChild() for i in [1..5]) - model.add(modelChildren[0]) - model.add(modelChildren[1]) + expectPaneAxisElement = (index) -> + child = paneAxisElement.children[index] + expect(child.nodeName.toLowerCase()).toBe('atom-pane-axis') - expect(paneAxis.children[0]).toBe(modelChildren[0]) - expect(paneAxis.children[2]).toBe(modelChildren[1]) - expectTestItemElement = (index) -> - child = paneAxis.children[index] - expect(child.nodeName.toLowerCase()).toBe('atom-test-item-element') expectResizeElement = (index) -> - expect(paneAxis.isPaneResizeHandleElement(paneAxis.children[index])).toBe(true) - expectResizeElement(1) + child = paneAxisElement.children[index] + expect(paneAxisElement.isPaneResizeHandleElement(child)).toBe(true) - model.add(modelChildren[2]) - model.add(modelChildren[3]) - expectTestItemElement(i) for i in [0, 2, 4, 6] + expect(paneAxisElement.children[0].model).toBe(modelChildren[0]) + expectResizeElement(1) + expect(paneAxisElement.children[2].model).toBe(modelChildren[1]) + + paneAxis.addChild(modelChildren[2]) + paneAxis.addChild(modelChildren[3]) + expectPaneAxisElement(i) for i in [0, 2, 4, 6] expectResizeElement(i) for i in [1, 3, 5] - model.remove(modelChildren[2]) + # test removeChild + paneAxis.removeChild(modelChildren[2]) # modelChildren[3] replace modelChildren[2] - expect(paneAxis.children[4]).toBe(modelChildren[3]) + expect(paneAxisElement.children[4].model).toBe(modelChildren[3]) expectResizeElement(i) for i in [1, 3] - model.replace(0, modelChildren[0], modelChildren[4]) - expect(paneAxis.children[0]).toBe(modelChildren[4]) + # test replaceChild + paneAxis.replaceChild(modelChildren[0], modelChildren[4]) + expect(paneAxisElement.children[0].model).toBe(modelChildren[4]) expectResizeElement(i) for i in [1, 3] From 8b137719a0761fc46ab5c557620d3d691f1a9416 Mon Sep 17 00:00:00 2001 From: liuxiong332 Date: Wed, 18 Mar 2015 13:36:23 +0800 Subject: [PATCH 0194/1783] replace 'fdescribe' with 'describe' in pane-axis-element-spec.coffee --- spec/pane-axis-element-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/pane-axis-element-spec.coffee b/spec/pane-axis-element-spec.coffee index 623d3a614..eece34a6e 100644 --- a/spec/pane-axis-element-spec.coffee +++ b/spec/pane-axis-element-spec.coffee @@ -1,7 +1,7 @@ PaneAxisElement = require '../src/pane-axis-element' PaneAxis = require '../src/pane-axis.coffee' -fdescribe "PaneResizeHandleElement", -> +describe "PaneResizeHandleElement", -> describe "add and remove", -> [paneAxisElement, paneAxis] = [] From 9f536c99cf28917eae9ae252c0bd998072789b56 Mon Sep 17 00:00:00 2001 From: Daniel Hengeveld Date: Tue, 17 Mar 2015 23:28:46 -0700 Subject: [PATCH 0195/1783] :arrow_up: settings-view@0.185 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6fea8211a..cb7b27bd5 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "open-on-github": "0.34.0", "package-generator": "0.38.0", "release-notes": "0.52.0", - "settings-view": "0.184.0", + "settings-view": "0.185.0", "snippets": "0.84.0", "spell-check": "0.55.0", "status-bar": "0.63.0", From e7e754eb3068e86d1e19eec7c70dfc2d0d4ab51b Mon Sep 17 00:00:00 2001 From: Basarat Ali Syed Date: Wed, 18 Mar 2015 17:40:49 +1100 Subject: [PATCH 0196/1783] :memo: document where to add the tests and how to run them --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 32dccf299..6be3b8778 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -48,7 +48,7 @@ For more information on how to work with Atom's official packages, see [JavaScript](https://github.com/styleguide/javascript), and [CSS](https://github.com/styleguide/css) styleguides. * Include thoughtfully-worded, well-structured - [Jasmine](http://jasmine.github.io/) specs. + [Jasmine](http://jasmine.github.io/) specs in the `./spec` folder. Run them using `script/grunt run-specs` target with atom closed. * Document new code based on the [Documentation Styleguide](#documentation-styleguide) * End files with a newline. From 8793bebfab542915a7b8fde58228ff86f8d506fc Mon Sep 17 00:00:00 2001 From: Basarat Syed Date: Wed, 18 Mar 2015 17:53:15 +1100 Subject: [PATCH 0197/1783] :white_check_mark: tests for typescript transpiling --- spec/fixtures/typescript/invalid.ts | 1 + spec/fixtures/typescript/valid.ts | 2 ++ spec/typescript-spec.coffee | 36 +++++++++++++++++++++++++++++ src/typescript.coffee | 2 +- 4 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 spec/fixtures/typescript/invalid.ts create mode 100644 spec/fixtures/typescript/valid.ts create mode 100644 spec/typescript-spec.coffee diff --git a/spec/fixtures/typescript/invalid.ts b/spec/fixtures/typescript/invalid.ts new file mode 100644 index 000000000..7a8d0b6d0 --- /dev/null +++ b/spec/fixtures/typescript/invalid.ts @@ -0,0 +1 @@ +var foo = 123 123; // Syntax error diff --git a/spec/fixtures/typescript/valid.ts b/spec/fixtures/typescript/valid.ts new file mode 100644 index 000000000..46cf54693 --- /dev/null +++ b/spec/fixtures/typescript/valid.ts @@ -0,0 +1,2 @@ +var inc = v => v + 1 +export = inc diff --git a/spec/typescript-spec.coffee b/spec/typescript-spec.coffee new file mode 100644 index 000000000..408e9fb77 --- /dev/null +++ b/spec/typescript-spec.coffee @@ -0,0 +1,36 @@ +typescript = require '../src/typescript' +crypto = require 'crypto' + +describe "TypeScript transpiler support", -> + beforeEach -> + jasmine.snapshotDeprecations() + + afterEach -> + jasmine.restoreDeprecationsSnapshot() + + describe "::createTypeScriptVersionAndOptionsDigest", -> + it "returns a digest for the library version and specified options", -> + defaultOptions = + target: 1 # ES5 + module: 'commonjs' + sourceMap: true + version = '1.4.1' + shasum = crypto.createHash('sha1') + shasum.update('typescript', 'utf8') + shasum.update('\0', 'utf8') + shasum.update(version, 'utf8') + shasum.update('\0', 'utf8') + shasum.update('{"target": 1,"module": "commonjs","sourceMap": true,}') + expectedDigest = shasum.digest('hex') + + observedDigest = typescript.createTypeScriptVersionAndOptionsDigest(version, defaultOptions) + expect(observedDigest).toEqual expectedDigest + + describe "when there is a .ts file", -> + it "transpiles it using typescript", -> + transpiled = require('./fixtures/typescript/valid.ts') + expect(transpiled(3)).toBe 4 + + describe "when the .ts file is invalid", -> + it "does not transpile", -> + expect(-> require('./fixtures/typescript/invalid.ts')).toThrow() diff --git a/src/typescript.coffee b/src/typescript.coffee index e47e7b2a1..e336eceff 100644 --- a/src/typescript.coffee +++ b/src/typescript.coffee @@ -14,7 +14,7 @@ stats = misses: 0 defaultOptions = - target: 1 + target: 1 # ES5 module: 'commonjs' sourceMap: true From f0b9bb7ce3e75f716c0d0297bbcacee5fe289f81 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 18 Mar 2015 11:17:34 +0100 Subject: [PATCH 0198/1783] Show indent guides on hanging indentation too --- spec/display-buffer-spec.coffee | 1 + src/tokenized-line.coffee | 28 +++++++++++++--------------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index 1306174aa..1b3ef3c8a 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -140,6 +140,7 @@ describe "DisplayBuffer", -> expect(displayBuffer.tokenizedLineForScreenRow(4).tokens[0].isSoftWrapIndentation).toBeTruthy() expect(displayBuffer.tokenizedLineForScreenRow(4).tokens[1].isSoftWrapIndentation).toBeTruthy() expect(displayBuffer.tokenizedLineForScreenRow(4).tokens[2].isSoftWrapIndentation).toBeTruthy() + expect(displayBuffer.tokenizedLineForScreenRow(4).tokens[3].isSoftWrapIndentation).toBeTruthy() describe "when the buffer changes", -> describe "when buffer lines are updated", -> diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 0437fbdcf..14208e36b 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -111,28 +111,26 @@ class TokenizedLine return maxColumn - # Calculates how many trailing spaces in this line's indentation cannot fit in a single tab. + # For a given `indentLevel`, calculates how many trailing spaces cannot fit in a single tab. # - # Returns a {Number} representing the odd indentation spaces in this line. - getOddIndentationSpaces: -> - oddIndentLevel = @indentLevel - Math.floor(@indentLevel) + # indentLevel - {Number} + # Returns a {Number} representing the odd indentation spaces for `indentLevel`. + oddIndentationSpacesForIndentLevel: (indentLevel) -> + oddIndentLevel = indentLevel - Math.floor(indentLevel) Math.round(@tabLength * oddIndentLevel) buildSoftWrapIndentationTokens: (token, hangingIndentationSpaces) -> - indentTokens = [0...Math.floor(@indentLevel)].map => + hangingIndentLevel = hangingIndentationSpaces / @tabLength + indentLevel = @indentLevel + hangingIndentLevel + indentTokens = [0...Math.floor(indentLevel)].map => token.buildSoftWrapIndentationToken(@tabLength) - if @getOddIndentationSpaces() - indentTokens.push( - token.buildSoftWrapIndentationToken(@getOddIndentationSpaces()) + if oddIndentationSpaces = @oddIndentationSpacesForIndentLevel(indentLevel) + indentTokens.concat( + token.buildSoftWrapIndentationToken(oddIndentationSpaces) ) - - if hangingIndentationSpaces - indentTokens.push( - token.buildSoftWrapIndentationToken(hangingIndentationSpaces) - ) - - indentTokens + else + indentTokens softWrapAt: (column, options = {}) -> return [new TokenizedLine([], '', [0, 0], [0, 0]), this] if column == 0 From ae2c92a1dc15385ee0bf262c3199f8defd0d4c7a Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 18 Mar 2015 11:29:39 +0100 Subject: [PATCH 0199/1783] :memo: --- src/tokenized-line.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 14208e36b..dfc8cac83 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -114,7 +114,7 @@ class TokenizedLine # For a given `indentLevel`, calculates how many trailing spaces cannot fit in a single tab. # # indentLevel - {Number} - # Returns a {Number} representing the odd indentation spaces for `indentLevel`. + # Returns a {Number} representing the odd indentation spaces in `indentLevel`. oddIndentationSpacesForIndentLevel: (indentLevel) -> oddIndentLevel = indentLevel - Math.floor(indentLevel) Math.round(@tabLength * oddIndentLevel) From e5fa44171df82962efb185d6b5d36ab2b8329f86 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 18 Mar 2015 14:15:52 +0100 Subject: [PATCH 0200/1783] :bug: Hanging indent must be a positive value --- src/config-schema.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/config-schema.coffee b/src/config-schema.coffee index 74fc719a4..92d80069f 100644 --- a/src/config-schema.coffee +++ b/src/config-schema.coffee @@ -152,6 +152,7 @@ module.exports = softWrapHangingIndentationSpaces: type: 'integer' default: 0 + minimum: 0 scrollSensitivity: type: 'integer' default: 40 From 7c33b9bf41681f0eb21a1264370e62f6056119a9 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 18 Mar 2015 14:18:27 +0100 Subject: [PATCH 0201/1783] :art: Rename to softWrapHangingIndent --- spec/display-buffer-spec.coffee | 4 ++-- src/config-schema.coffee | 2 +- src/display-buffer.coffee | 8 ++++---- src/tokenized-line.coffee | 8 ++++---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index 1b3ef3c8a..4f2046434 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -128,9 +128,9 @@ describe "DisplayBuffer", -> expect(displayBuffer.tokenizedLineForScreenRow(4).tokens[0].isSoftWrapIndentation).toBeTruthy() expect(displayBuffer.tokenizedLineForScreenRow(4).tokens[1].isSoftWrapIndentation).toBeTruthy() - describe "when editor.softWrapHangingIndentationSpaces is set", -> + describe "when editor.softWrapHangingIndent is set", -> beforeEach -> - atom.config.set('editor.softWrapHangingIndentationSpaces', 3) + atom.config.set('editor.softWrapHangingIndent', 3) it "further indents wrapped lines", -> expect(displayBuffer.tokenizedLineForScreenRow(11).text).toBe " sort(left).concat(pivot).concat(sort(right)" diff --git a/src/config-schema.coffee b/src/config-schema.coffee index 92d80069f..c2944911b 100644 --- a/src/config-schema.coffee +++ b/src/config-schema.coffee @@ -149,7 +149,7 @@ module.exports = softWrapAtPreferredLineLength: type: 'boolean' default: false - softWrapHangingIndentationSpaces: + softWrapHangingIndent: type: 'integer' default: 0 minimum: 0 diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index ecdd36c6d..c8ec23e07 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -69,15 +69,15 @@ class DisplayBuffer extends Model scrollPastEnd: atom.config.get('editor.scrollPastEnd', scope: scopeDescriptor) softWrap: atom.config.get('editor.softWrap', scope: scopeDescriptor) softWrapAtPreferredLineLength: atom.config.get('editor.softWrapAtPreferredLineLength', scope: scopeDescriptor) - softWrapHangingIndentationSpaces: atom.config.get('editor.softWrapHangingIndentationSpaces', scope: scopeDescriptor) + softWrapHangingIndent: atom.config.get('editor.softWrapHangingIndent', scope: scopeDescriptor) preferredLineLength: atom.config.get('editor.preferredLineLength', scope: scopeDescriptor) subscriptions.add atom.config.onDidChange 'editor.softWrap', scope: scopeDescriptor, ({newValue}) => @configSettings.softWrap = newValue @updateWrappedScreenLines() - subscriptions.add atom.config.onDidChange 'editor.softWrapHangingIndentationSpaces', scope: scopeDescriptor, ({newValue}) => - @configSettings.softWrapHangingIndentationSpaces = newValue + subscriptions.add atom.config.onDidChange 'editor.softWrapHangingIndent', scope: scopeDescriptor, ({newValue}) => + @configSettings.softWrapHangingIndent = newValue @updateWrappedScreenLines() subscriptions.add atom.config.onDidChange 'editor.softWrapAtPreferredLineLength', scope: scopeDescriptor, ({newValue}) => @@ -1164,7 +1164,7 @@ class DisplayBuffer extends Model while wrapScreenColumn = tokenizedLine.findWrapColumn(@getSoftWrapColumn()) [wrappedLine, tokenizedLine] = tokenizedLine.softWrapAt( wrapScreenColumn, - hangingIndentationSpaces: @configSettings.softWrapHangingIndentationSpaces + hangingIndent: @configSettings.softWrapHangingIndent ) break if wrappedLine.hasOnlySoftWrapIndentation() screenLines.push(wrappedLine) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index dfc8cac83..a949a6e11 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -119,8 +119,8 @@ class TokenizedLine oddIndentLevel = indentLevel - Math.floor(indentLevel) Math.round(@tabLength * oddIndentLevel) - buildSoftWrapIndentationTokens: (token, hangingIndentationSpaces) -> - hangingIndentLevel = hangingIndentationSpaces / @tabLength + buildSoftWrapIndentationTokens: (token, hangingIndent) -> + hangingIndentLevel = hangingIndent / @tabLength indentLevel = @indentLevel + hangingIndentLevel indentTokens = [0...Math.floor(indentLevel)].map => token.buildSoftWrapIndentationToken(@tabLength) @@ -135,7 +135,7 @@ class TokenizedLine softWrapAt: (column, options = {}) -> return [new TokenizedLine([], '', [0, 0], [0, 0]), this] if column == 0 - {hangingIndentationSpaces} = options + {hangingIndent} = options rightTokens = new Array(@tokens...) leftTokens = [] @@ -147,7 +147,7 @@ class TokenizedLine leftTextLength += nextToken.value.length leftTokens.push nextToken - indentationTokens = @buildSoftWrapIndentationTokens(leftTokens[0], hangingIndentationSpaces) + indentationTokens = @buildSoftWrapIndentationTokens(leftTokens[0], hangingIndent) leftFragment = new TokenizedLine( tokens: leftTokens From f5de75126b7619cc84d4a6bcd5dca1826e5ddfd7 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 18 Mar 2015 09:24:26 -0700 Subject: [PATCH 0202/1783] :arrow_up: language-perl@0.19 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cb7b27bd5..b2a05ad0a 100644 --- a/package.json +++ b/package.json @@ -139,7 +139,7 @@ "language-make": "0.14.0", "language-mustache": "0.11.0", "language-objective-c": "0.15.0", - "language-perl": "0.18.0", + "language-perl": "0.19.0", "language-php": "0.21.0", "language-property-list": "0.8.0", "language-python": "0.32.0", From a79384c6f6da85ef30318be7e2baa4279141a349 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 18 Mar 2015 09:30:23 -0700 Subject: [PATCH 0203/1783] :arrow_up: language-go@0.22 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b2a05ad0a..fd906dd53 100644 --- a/package.json +++ b/package.json @@ -129,7 +129,7 @@ "language-css": "0.28.0", "language-gfm": "0.67.0", "language-git": "0.10.0", - "language-go": "0.21.0", + "language-go": "0.22.0", "language-html": "0.29.0", "language-hyperlink": "0.12.2", "language-java": "0.14.0", From 85595262156bfe30eb2fb3aaf184168f1c4dab05 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 18 Mar 2015 17:42:25 +0100 Subject: [PATCH 0204/1783] :white_check_mark: Write a more comprehensive spec --- spec/display-buffer-spec.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index 4f2046434..c61733836 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -133,6 +133,7 @@ describe "DisplayBuffer", -> atom.config.set('editor.softWrapHangingIndent', 3) it "further indents wrapped lines", -> + expect(displayBuffer.tokenizedLineForScreenRow(10).text).toBe " return " expect(displayBuffer.tokenizedLineForScreenRow(11).text).toBe " sort(left).concat(pivot).concat(sort(right)" expect(displayBuffer.tokenizedLineForScreenRow(12).text).toBe " );" From f5e1e40edd5fcc06734e013e22b9ad87ea43d79d Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 18 Mar 2015 17:44:35 +0100 Subject: [PATCH 0205/1783] Avoid named parameter to save an allocation --- src/display-buffer.coffee | 2 +- src/tokenized-line.coffee | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index c8ec23e07..8e8bd8dcd 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -1164,7 +1164,7 @@ class DisplayBuffer extends Model while wrapScreenColumn = tokenizedLine.findWrapColumn(@getSoftWrapColumn()) [wrappedLine, tokenizedLine] = tokenizedLine.softWrapAt( wrapScreenColumn, - hangingIndent: @configSettings.softWrapHangingIndent + @configSettings.softWrapHangingIndent ) break if wrappedLine.hasOnlySoftWrapIndentation() screenLines.push(wrappedLine) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index a949a6e11..98224e189 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -132,11 +132,9 @@ class TokenizedLine else indentTokens - softWrapAt: (column, options = {}) -> + softWrapAt: (column, hangingIndent) -> return [new TokenizedLine([], '', [0, 0], [0, 0]), this] if column == 0 - {hangingIndent} = options - rightTokens = new Array(@tokens...) leftTokens = [] leftTextLength = 0 From fbfe19825b545d71a29a0309e8da3d68da4325dc Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 18 Mar 2015 18:00:31 +0100 Subject: [PATCH 0206/1783] Even more descriptive specs :sparkles: --- spec/display-buffer-spec.coffee | 34 +++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index c61733836..1703a24d1 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -124,9 +124,16 @@ describe "DisplayBuffer", -> expect(displayBuffer.tokenizedLineForScreenRow(3).tokens[1].isHardTab).toBeTruthy() describe "when a line is wrapped", -> - it "correctly tokenizes soft wrap indentation tokens", -> - expect(displayBuffer.tokenizedLineForScreenRow(4).tokens[0].isSoftWrapIndentation).toBeTruthy() - expect(displayBuffer.tokenizedLineForScreenRow(4).tokens[1].isSoftWrapIndentation).toBeTruthy() + it "breaks soft-wrap indentation into a token for each indentation level to support indent guides", -> + tokenizedLine = displayBuffer.tokenizedLineForScreenRow(4) + + expect(tokenizedLine.tokens[0].value).toBe(" ") + expect(tokenizedLine.tokens[0].isSoftWrapIndentation).toBeTruthy() + + expect(tokenizedLine.tokens[1].value).toBe(" ") + expect(tokenizedLine.tokens[1].isSoftWrapIndentation).toBeTruthy() + + expect(tokenizedLine.tokens[2].isSoftWrapIndentation).toBeFalsy() describe "when editor.softWrapHangingIndent is set", -> beforeEach -> @@ -137,11 +144,22 @@ describe "DisplayBuffer", -> expect(displayBuffer.tokenizedLineForScreenRow(11).text).toBe " sort(left).concat(pivot).concat(sort(right)" expect(displayBuffer.tokenizedLineForScreenRow(12).text).toBe " );" - it "correctly tokenizes hanging indentation spaces", -> - expect(displayBuffer.tokenizedLineForScreenRow(4).tokens[0].isSoftWrapIndentation).toBeTruthy() - expect(displayBuffer.tokenizedLineForScreenRow(4).tokens[1].isSoftWrapIndentation).toBeTruthy() - expect(displayBuffer.tokenizedLineForScreenRow(4).tokens[2].isSoftWrapIndentation).toBeTruthy() - expect(displayBuffer.tokenizedLineForScreenRow(4).tokens[3].isSoftWrapIndentation).toBeTruthy() + it "includes hanging indent when breaking soft-wrap indentation into tokens", -> + tokenizedLine = displayBuffer.tokenizedLineForScreenRow(4) + + expect(tokenizedLine.tokens[0].value).toBe(" ") + expect(tokenizedLine.tokens[0].isSoftWrapIndentation).toBeTruthy() + + expect(tokenizedLine.tokens[1].value).toBe(" ") + expect(tokenizedLine.tokens[1].isSoftWrapIndentation).toBeTruthy() + + expect(tokenizedLine.tokens[2].value).toBe(" ") # hanging indent + expect(tokenizedLine.tokens[2].isSoftWrapIndentation).toBeTruthy() + + expect(tokenizedLine.tokens[3].value).toBe(" ") # odd space + expect(tokenizedLine.tokens[3].isSoftWrapIndentation).toBeTruthy() + + expect(tokenizedLine.tokens[4].isSoftWrapIndentation).toBeFalsy() describe "when the buffer changes", -> describe "when buffer lines are updated", -> From 522e82ebf1eb71370f60af55b6970943677cf0e6 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 18 Mar 2015 18:07:07 +0100 Subject: [PATCH 0207/1783] :art: Refactor buildSoftWrapIndentationTokens ...as suggested by @nathansobo :sparkles: --- src/tokenized-line.coffee | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 98224e189..2a807d84a 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -111,26 +111,16 @@ class TokenizedLine return maxColumn - # For a given `indentLevel`, calculates how many trailing spaces cannot fit in a single tab. - # - # indentLevel - {Number} - # Returns a {Number} representing the odd indentation spaces in `indentLevel`. - oddIndentationSpacesForIndentLevel: (indentLevel) -> - oddIndentLevel = indentLevel - Math.floor(indentLevel) - Math.round(@tabLength * oddIndentLevel) - buildSoftWrapIndentationTokens: (token, hangingIndent) -> - hangingIndentLevel = hangingIndent / @tabLength - indentLevel = @indentLevel + hangingIndentLevel - indentTokens = [0...Math.floor(indentLevel)].map => - token.buildSoftWrapIndentationToken(@tabLength) + totalIndentSpaces = (@indentLevel * @tabLength) + hangingIndent + indentTokens = [] + while totalIndentSpaces > 0 + tokenLength = Math.min(@tabLength, totalIndentSpaces) + indentToken = token.buildSoftWrapIndentationToken(tokenLength) + indentTokens.push(indentToken) + totalIndentSpaces -= tokenLength - if oddIndentationSpaces = @oddIndentationSpacesForIndentLevel(indentLevel) - indentTokens.concat( - token.buildSoftWrapIndentationToken(oddIndentationSpaces) - ) - else - indentTokens + indentTokens softWrapAt: (column, hangingIndent) -> return [new TokenizedLine([], '', [0, 0], [0, 0]), this] if column == 0 From cac361e6dfffe1a17209f68781b9b7bb05b055f0 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Wed, 18 Mar 2015 15:34:28 -0700 Subject: [PATCH 0208/1783] add packages for new spec Signed-off-by: Kevin Sawicki --- .../index.coffee | 4 ++++ .../package.json | 11 +++++++++++ .../index.coffee | 4 ++++ .../package.json | 12 ++++++++++++ 4 files changed, 31 insertions(+) create mode 100644 spec/fixtures/packages/package-with-missing-consumed-services/index.coffee create mode 100644 spec/fixtures/packages/package-with-missing-consumed-services/package.json create mode 100644 spec/fixtures/packages/package-with-missing-provided-services/index.coffee create mode 100644 spec/fixtures/packages/package-with-missing-provided-services/package.json diff --git a/spec/fixtures/packages/package-with-missing-consumed-services/index.coffee b/spec/fixtures/packages/package-with-missing-consumed-services/index.coffee new file mode 100644 index 000000000..0f1fc41e0 --- /dev/null +++ b/spec/fixtures/packages/package-with-missing-consumed-services/index.coffee @@ -0,0 +1,4 @@ +module.exports = + activate: -> + + deactivate: -> diff --git a/spec/fixtures/packages/package-with-missing-consumed-services/package.json b/spec/fixtures/packages/package-with-missing-consumed-services/package.json new file mode 100644 index 000000000..d0e0ddfcb --- /dev/null +++ b/spec/fixtures/packages/package-with-missing-consumed-services/package.json @@ -0,0 +1,11 @@ +{ + "name": "package-with-missing-consumed-services", + + "consumedServices": { + "service-1": { + "versions": { + ">=0.1": "consumeMissingService" + } + } + } +} diff --git a/spec/fixtures/packages/package-with-missing-provided-services/index.coffee b/spec/fixtures/packages/package-with-missing-provided-services/index.coffee new file mode 100644 index 000000000..0f1fc41e0 --- /dev/null +++ b/spec/fixtures/packages/package-with-missing-provided-services/index.coffee @@ -0,0 +1,4 @@ +module.exports = + activate: -> + + deactivate: -> diff --git a/spec/fixtures/packages/package-with-missing-provided-services/package.json b/spec/fixtures/packages/package-with-missing-provided-services/package.json new file mode 100644 index 000000000..a090354a2 --- /dev/null +++ b/spec/fixtures/packages/package-with-missing-provided-services/package.json @@ -0,0 +1,12 @@ +{ + "name": "package-with-missing-provided-services", + + "providedServices": { + "service-1": { + "description": "The first service", + "versions": { + "0.2.9": "provideMissingService" + } + } + } +} From a787242e7a845c9f6d16a3a8f7fa5892007403de Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Wed, 18 Mar 2015 15:37:16 -0700 Subject: [PATCH 0209/1783] check that services method exists Signed-off-by: Kevin Sawicki --- src/package.coffee | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/package.coffee b/src/package.coffee index 4d244c50f..54dc75f2b 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -225,12 +225,14 @@ class Package for name, {versions} of @metadata.providedServices servicesByVersion = {} for version, methodName of versions - servicesByVersion[version] = @mainModule[methodName]() + if typeof @mainModule[methodName] is 'function' + servicesByVersion[version] = @mainModule[methodName]() @activationDisposables.add atom.packages.serviceHub.provide(name, servicesByVersion) for name, {versions} of @metadata.consumedServices for version, methodName of versions - @activationDisposables.add atom.packages.serviceHub.consume(name, version, @mainModule[methodName].bind(@mainModule)) + if typeof @mainModule[methodName] is 'function' + @activationDisposables.add atom.packages.serviceHub.consume(name, version, @mainModule[methodName].bind(@mainModule)) return loadKeymaps: -> From 2c46748307e765bd7796c092535048d5827bd4f2 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Wed, 18 Mar 2015 15:38:13 -0700 Subject: [PATCH 0210/1783] add spec to check missing service methods are skipped Signed-off-by: Kevin Sawicki --- spec/package-manager-spec.coffee | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 758d7468f..2789f36c3 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -547,6 +547,21 @@ describe "PackageManager", -> expect(consumerModule.consumeFirstServiceV4).not.toHaveBeenCalled() expect(consumerModule.consumeSecondService).not.toHaveBeenCalled() + it "ignores provided and consumed services that do not exist", -> + addErrorHandler = jasmine.createSpy() + atom.notifications.onDidAddNotification(addErrorHandler) + + waitsForPromise -> + atom.packages.activatePackage("package-with-missing-consumed-services") + + waitsForPromise -> + atom.packages.activatePackage("package-with-missing-provided-services") + + runs -> + expect(atom.packages.isPackageActive("package-with-missing-consumed-services")).toBe true + expect(atom.packages.isPackageActive("package-with-missing-provided-services")).toBe true + expect(addErrorHandler.callCount).toBe 0 + describe "::deactivatePackage(id)", -> afterEach -> atom.packages.unloadPackages() From 2aa566b7c6eaa81b5650e7e1e7ece6cc68a10eac Mon Sep 17 00:00:00 2001 From: Basarat Ali Syed Date: Thu, 19 Mar 2015 10:56:55 +1100 Subject: [PATCH 0211/1783] :memo: document where to add the tests and how to run them --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6be3b8778..a5ebdd5f5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -48,7 +48,7 @@ For more information on how to work with Atom's official packages, see [JavaScript](https://github.com/styleguide/javascript), and [CSS](https://github.com/styleguide/css) styleguides. * Include thoughtfully-worded, well-structured - [Jasmine](http://jasmine.github.io/) specs in the `./spec` folder. Run them using `script/grunt run-specs` target with atom closed. + [Jasmine](http://jasmine.github.io/) specs in the `./spec` folder. Run them using `apm test`. * Document new code based on the [Documentation Styleguide](#documentation-styleguide) * End files with a newline. From c2f258c679796520493d535ba84dc4b16b22bd3d Mon Sep 17 00:00:00 2001 From: Basarat Syed Date: Thu, 19 Mar 2015 11:45:13 +1100 Subject: [PATCH 0212/1783] Addressed code review --- package.json | 1 + spec/typescript-spec.coffee | 8 +- src/typescript-transpile.js | 152 ------------------------------------ src/typescript.coffee | 45 +---------- 4 files changed, 6 insertions(+), 200 deletions(-) delete mode 100644 src/typescript-transpile.js diff --git a/package.json b/package.json index 60f96cb34..9f12fe358 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "text-buffer": "^4.1.5", "theorist": "^1.0.2", "typescript": "^1.4.1", + "typescript-simple": "^1.0.0", "underscore-plus": "^1.6.6" }, "packageDependencies": { diff --git a/spec/typescript-spec.coffee b/spec/typescript-spec.coffee index 408e9fb77..493715d36 100644 --- a/spec/typescript-spec.coffee +++ b/spec/typescript-spec.coffee @@ -2,12 +2,6 @@ typescript = require '../src/typescript' crypto = require 'crypto' describe "TypeScript transpiler support", -> - beforeEach -> - jasmine.snapshotDeprecations() - - afterEach -> - jasmine.restoreDeprecationsSnapshot() - describe "::createTypeScriptVersionAndOptionsDigest", -> it "returns a digest for the library version and specified options", -> defaultOptions = @@ -20,7 +14,7 @@ describe "TypeScript transpiler support", -> shasum.update('\0', 'utf8') shasum.update(version, 'utf8') shasum.update('\0', 'utf8') - shasum.update('{"target": 1,"module": "commonjs","sourceMap": true,}') + shasum.update(JSON.stringify(defaultOptions)) expectedDigest = shasum.digest('hex') observedDigest = typescript.createTypeScriptVersionAndOptionsDigest(version, defaultOptions) diff --git a/src/typescript-transpile.js b/src/typescript-transpile.js deleted file mode 100644 index 64d832d1c..000000000 --- a/src/typescript-transpile.js +++ /dev/null @@ -1,152 +0,0 @@ -// From https://github.com/teppeis/typescript-simple/blob/master/index.js -// with https://github.com/teppeis/typescript-simple/pull/7 - -var fs = require('fs'); -var os = require('os'); -var path = require('path'); -var ts = require('typescript'); -var FILENAME_TS = 'file.ts'; -function tss(code, options) { - if (options) { - return new tss.TypeScriptSimple(options).compile(code); - } - else { - return defaultTss.compile(code); - } -} -var tss; -(function (tss) { - var TypeScriptSimple = (function () { - /** - * @param {ts.CompilerOptions=} options TypeScript compile options (some options are ignored) - */ - function TypeScriptSimple(options, doSemanticChecks) { - if (options === void 0) { options = {}; } - if (doSemanticChecks === void 0) { doSemanticChecks = true; } - this.doSemanticChecks = doSemanticChecks; - this.service = null; - this.outputs = {}; - this.files = {}; - if (options.target == null) { - options.target = ts.ScriptTarget.ES5; - } - if (options.module == null) { - options.module = ts.ModuleKind.None; - } - this.options = options; - } - /** - * @param {string} code TypeScript source code to compile - * @param {string} only needed if you plan to use sourceMaps. Provide the complete filePath relevant to you - * @return {string} The JavaScript with inline sourceMaps if sourceMaps were enabled - */ - TypeScriptSimple.prototype.compile = function (code, filename) { - if (filename === void 0) { filename = FILENAME_TS; } - if (!this.service) { - this.service = this.createService(); - } - var file = this.files[FILENAME_TS]; - file.text = code; - file.version++; - return this.toJavaScript(this.service, filename); - }; - TypeScriptSimple.prototype.createService = function () { - var _this = this; - var defaultLib = this.getDefaultLibFilename(this.options); - var defaultLibPath = path.join(this.getTypeScriptBinDir(), defaultLib); - this.files[defaultLib] = { version: 0, text: fs.readFileSync(defaultLibPath).toString() }; - this.files[FILENAME_TS] = { version: 0, text: '' }; - var servicesHost = { - getScriptFileNames: function () { return [_this.getDefaultLibFilename(_this.options), FILENAME_TS]; }, - getScriptVersion: function (filename) { return _this.files[filename] && _this.files[filename].version.toString(); }, - getScriptSnapshot: function (filename) { - var file = _this.files[filename]; - return { - getText: function (start, end) { return file.text.substring(start, end); }, - getLength: function () { return file.text.length; }, - getLineStartPositions: function () { return []; }, - getChangeRange: function (oldSnapshot) { return undefined; } - }; - }, - getCurrentDirectory: function () { return process.cwd(); }, - getScriptIsOpen: function () { return true; }, - getCompilationSettings: function () { return _this.options; }, - getDefaultLibFilename: function (options) { - return _this.getDefaultLibFilename(options); - }, - log: function (message) { return console.log(message); } - }; - return ts.createLanguageService(servicesHost, ts.createDocumentRegistry()); - }; - TypeScriptSimple.prototype.getTypeScriptBinDir = function () { - return path.dirname(require.resolve('typescript')); - }; - TypeScriptSimple.prototype.getDefaultLibFilename = function (options) { - if (options.target === ts.ScriptTarget.ES6) { - return 'lib.es6.d.ts'; - } - else { - return 'lib.d.ts'; - } - }; - /** - * converts {"version":3,"file":"file.js","sourceRoot":"","sources":["file.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,MAAM,CAAC"} - * to {"version":3,"sources":["foo/test.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,MAAM,CAAC","file":"foo/test.ts","sourcesContent":["var x = 'test';"]} - * derived from : https://github.com/thlorenz/convert-source-map - */ - TypeScriptSimple.prototype.getInlineSourceMap = function (mapText, filename) { - var sourceMap = JSON.parse(mapText); - sourceMap.file = filename; - sourceMap.sources = [filename]; - sourceMap.sourcesContent = [this.files[FILENAME_TS].text]; - delete sourceMap.sourceRoot; - return JSON.stringify(sourceMap); - }; - TypeScriptSimple.prototype.toJavaScript = function (service, filename) { - if (filename === void 0) { filename = FILENAME_TS; } - var output = service.getEmitOutput(FILENAME_TS); - // Meaning of succeeded is driven by whether we need to check for semantic errors or not - var succeeded = output.emitOutputStatus === ts.EmitReturnStatus.Succeeded; - if (!this.doSemanticChecks) { - // We have an output. It implies syntactic success - if (!succeeded) - succeeded = !!output.outputFiles.length; - } - if (succeeded) { - var outputFilename = FILENAME_TS.replace(/ts$/, 'js'); - var file = output.outputFiles.filter(function (file) { return file.name === outputFilename; })[0]; - // Fixed in v1.5 https://github.com/Microsoft/TypeScript/issues/1653 - var text = file.text.replace(/\r\n/g, os.EOL); - // If we have sourceMaps convert them to inline sourceMaps - if (this.options.sourceMap) { - var sourceMapFilename = FILENAME_TS.replace(/ts$/, 'js.map'); - var sourceMapFile = output.outputFiles.filter(function (file) { return file.name === sourceMapFilename; })[0]; - // Transform sourcemap - var sourceMapText = sourceMapFile.text; - sourceMapText = this.getInlineSourceMap(sourceMapText, filename); - var base64SourceMapText = new Buffer(sourceMapText).toString('base64'); - text = text.replace('//# sourceMappingURL=' + sourceMapFilename, '//# sourceMappingURL=data:application/json;base64,' + base64SourceMapText); - } - return text; - } - var allDiagnostics = service.getCompilerOptionsDiagnostics().concat(service.getSyntacticDiagnostics(FILENAME_TS)); - if (this.doSemanticChecks) - allDiagnostics = allDiagnostics.concat(service.getSemanticDiagnostics(FILENAME_TS)); - throw new Error(this.formatDiagnostics(allDiagnostics)); - }; - TypeScriptSimple.prototype.formatDiagnostics = function (diagnostics) { - return diagnostics.map(function (d) { - if (d.file) { - return 'L' + d.file.getLineAndCharacterFromPosition(d.start).line + ': ' + d.messageText; - } - else { - return d.messageText; - } - }).join(os.EOL); - }; - return TypeScriptSimple; - })(); - tss.TypeScriptSimple = TypeScriptSimple; -})(tss || (tss = {})); -var defaultTss = new tss.TypeScriptSimple(); -module.exports = tss; diff --git a/src/typescript.coffee b/src/typescript.coffee index e336eceff..3814a6c66 100644 --- a/src/typescript.coffee +++ b/src/typescript.coffee @@ -18,43 +18,6 @@ defaultOptions = module: 'commonjs' sourceMap: true -### -shasum - Hash with an update() method. -value - Must be a value that could be returned by JSON.parse(). -### -updateDigestForJsonValue = (shasum, value) -> - # Implmentation is similar to that of pretty-printing a JSON object, except: - # * Strings are not escaped. - # * No effort is made to avoid trailing commas. - # These shortcuts should not affect the correctness of this function. - type = typeof value - if type is 'string' - shasum.update('"', 'utf8') - shasum.update(value, 'utf8') - shasum.update('"', 'utf8') - else if type in ['boolean', 'number'] - shasum.update(value.toString(), 'utf8') - else if value is null - shasum.update('null', 'utf8') - else if Array.isArray value - shasum.update('[', 'utf8') - for item in value - updateDigestForJsonValue(shasum, item) - shasum.update(',', 'utf8') - shasum.update(']', 'utf8') - else - # value must be an object: be sure to sort the keys. - keys = Object.keys value - keys.sort() - - shasum.update('{', 'utf8') - for key in keys - updateDigestForJsonValue(shasum, key) - shasum.update(': ', 'utf8') - updateDigestForJsonValue(shasum, value[key]) - shasum.update(',', 'utf8') - shasum.update('}', 'utf8') - createTypeScriptVersionAndOptionsDigest = (version, options) -> shasum = crypto.createHash('sha1') # Include the version of typescript in the hash. @@ -62,7 +25,7 @@ createTypeScriptVersionAndOptionsDigest = (version, options) -> shasum.update('\0', 'utf8') shasum.update(version, 'utf8') shasum.update('\0', 'utf8') - updateDigestForJsonValue(shasum, options) + shasum.update(JSON.stringify(options)) shasum.digest('hex') cacheDir = null @@ -72,8 +35,8 @@ getCachePath = (sourceCode) -> digest = crypto.createHash('sha1').update(sourceCode, 'utf8').digest('hex') unless jsCacheDir? - tsVersion = require('typescript/package.json').version - jsCacheDir = path.join(cacheDir, createTypeScriptVersionAndOptionsDigest(tsVersion, defaultOptions)) + tssVersion = require('typescript-simple/package.json').version + jsCacheDir = path.join(cacheDir, createTypeScriptVersionAndOptionsDigest(tssVersion, defaultOptions)) path.join(jsCacheDir, "#{digest}.js") @@ -94,7 +57,7 @@ createOptions = (filePath) -> transpile = (sourceCode, filePath, cachePath) -> options = createOptions(filePath) - tss ?= new (require './typescript-transpile').TypeScriptSimple(options, false) + tss ?= new (require 'typescript-simple').TypeScriptSimple(options, false) js = tss.compile(sourceCode, filePath) stats.misses++ From 030dd4c690d339fc938f20b66bee459c2f7c2c2b Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Thu, 19 Mar 2015 09:17:35 +0800 Subject: [PATCH 0213/1783] :arrow_up: atom-shell@0.22.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fd906dd53..11bc09810 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "url": "http://github.com/atom/atom/raw/master/LICENSE.md" } ], - "atomShellVersion": "0.21.3", + "atomShellVersion": "0.22.1", "dependencies": { "async": "0.2.6", "atom-keymap": "^4", From bc00ad3f01b34fa910fb25189daa0d04e7c4737f Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Thu, 19 Mar 2015 09:17:54 +0800 Subject: [PATCH 0214/1783] :arrow_up: apm@0.146.0 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index a989c7a83..6b3001029 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.145.0" + "atom-package-manager": "0.146.0" } } From 56020b11b0e2d1d43c69df54b550995cfab5f2f7 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 19 Mar 2015 11:36:55 +0100 Subject: [PATCH 0215/1783] :bug: Avoid soft-wrapping on indentation --- spec/display-buffer-spec.coffee | 18 ++++++++++++++++++ src/tokenized-line.coffee | 26 +++++++++++++++----------- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index 1703a24d1..95f22acca 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -115,6 +115,24 @@ describe "DisplayBuffer", -> expect(displayBuffer.tokenizedLineForScreenRow(3).text).toBe ' var pivot = items.shift(), current, left = [], ' expect(displayBuffer.tokenizedLineForScreenRow(4).text).toBe ' right = [];' + describe "when the only whitespace characters are at the beginning of the line", -> + beforeEach -> + displayBuffer.setEditorWidthInChars(10) + + it "wraps the line at the max length when indented with tabs", -> + buffer.setTextInRange([[0, 0], [1, 0]], '\t\tabcdefghijklmnopqrstuvwxyz') + + expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe ' abcdef' + expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe ' ghijkl' + expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe ' mnopqr' + + it "wraps the line at the max length when indented with spaces", -> + buffer.setTextInRange([[0, 0], [1, 0]], ' abcdefghijklmnopqrstuvwxyz') + + expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe ' abcdef' + expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe ' ghijkl' + expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe ' mnopqr' + describe "when there are hard tabs", -> beforeEach -> buffer.setText(buffer.getText().replace(new RegExp(' ', 'g'), '\t')) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 2a807d84a..513ad5b4b 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -106,7 +106,7 @@ class TokenizedLine return @text.length else # search backward for the start of the word on the boundary - for column in [maxColumn..0] when @isColumnOutsideSoftWrapIndentation(column) + for column in [maxColumn..0] when @isColumnOutsideIndentation(column) return column + 1 if /\s/.test(@text[column]) return maxColumn @@ -127,12 +127,13 @@ class TokenizedLine rightTokens = new Array(@tokens...) leftTokens = [] - leftTextLength = 0 - while leftTextLength < column - if leftTextLength + rightTokens[0].value.length > column - rightTokens[0..0] = rightTokens[0].splitAt(column - leftTextLength) + leftScreenColumn = 0 + + while leftScreenColumn < column + if leftScreenColumn + rightTokens[0].screenDelta > column + rightTokens[0..0] = rightTokens[0].splitAt(column - leftScreenColumn) nextToken = rightTokens.shift() - leftTextLength += nextToken.value.length + leftScreenColumn += nextToken.screenDelta leftTokens.push nextToken indentationTokens = @buildSoftWrapIndentationTokens(leftTokens[0], hangingIndent) @@ -160,6 +161,9 @@ class TokenizedLine isSoftWrapped: -> @lineEnding is null + isColumnOutsideIndentation: (column) -> + column >= @firstNonWhitespaceIndex and @isColumnOutsideSoftWrapIndentation(column) + isColumnOutsideSoftWrapIndentation: (column) -> return true if @softWrapIndentationTokens.length == 0 @@ -209,15 +213,15 @@ class TokenizedLine outputTokens markLeadingAndTrailingWhitespaceTokens: -> - firstNonWhitespaceIndex = @text.search(NonWhitespaceRegex) - if firstNonWhitespaceIndex > 0 and isPairedCharacter(@text, firstNonWhitespaceIndex - 1) - firstNonWhitespaceIndex-- + @firstNonWhitespaceIndex = @text.search(NonWhitespaceRegex) + if @firstNonWhitespaceIndex > 0 and isPairedCharacter(@text, @firstNonWhitespaceIndex - 1) + @firstNonWhitespaceIndex-- firstTrailingWhitespaceIndex = @text.search(TrailingWhitespaceRegex) @lineIsWhitespaceOnly = firstTrailingWhitespaceIndex is 0 index = 0 for token in @tokens - if index < firstNonWhitespaceIndex - token.firstNonWhitespaceIndex = Math.min(index + token.value.length, firstNonWhitespaceIndex - index) + if index < @firstNonWhitespaceIndex + token.firstNonWhitespaceIndex = Math.min(index + token.value.length, @firstNonWhitespaceIndex - index) # Only the *last* segment of a soft-wrapped line can have trailing whitespace if @lineEnding? and (index + token.value.length > firstTrailingWhitespaceIndex) token.firstTrailingWhitespaceIndex = Math.max(0, firstTrailingWhitespaceIndex - index) From 61cc9b97eabb8f3c7d7e0dd8503768884f076a5d Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 19 Mar 2015 11:45:54 +0100 Subject: [PATCH 0216/1783] :green_heart: Fix failing spec --- spec/text-editor-component-spec.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index f5c9e7677..20ddcdcab 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -1937,14 +1937,14 @@ describe "TextEditorComponent", -> gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(11), metaKey: true)) nextAnimationFrame() gutterNode.dispatchEvent(buildMouseEvent('mouseup', clientCoordinatesForScreenRowInGutter(11), metaKey: true)) - expect(editor.getSelectedScreenRanges()).toEqual [[[7, 4], [7, 6]], [[10, 0], [20, 0]]] + expect(editor.getSelectedScreenRanges()).toEqual [[[7, 4], [7, 6]], [[10, 0], [19, 0]]] it "merges overlapping selections", -> gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(17), metaKey: true)) gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(9), metaKey: true)) nextAnimationFrame() gutterNode.dispatchEvent(buildMouseEvent('mouseup', clientCoordinatesForScreenRowInGutter(9), metaKey: true)) - expect(editor.getSelectedScreenRanges()).toEqual [[[5, 0], [20, 0]]] + expect(editor.getSelectedScreenRanges()).toEqual [[[5, 0], [19, 0]]] describe "when the gutter is shift-clicked and dragged", -> describe "when the shift-click is below the existing selection's tail", -> From 03b526a76b38984be939a9a87f6af3b09ae45761 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 19 Mar 2015 11:48:10 +0100 Subject: [PATCH 0217/1783] :art: Use only @firstNonWhitespaceIndex --- src/tokenized-line.coffee | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 513ad5b4b..489714ae3 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -11,6 +11,7 @@ module.exports = class TokenizedLine endOfLineInvisibles: null lineIsWhitespaceOnly: false + firstNonWhitespaceIndex: 0 foldable: false constructor: ({tokens, @lineEnding, @ruleStack, @startBufferColumn, @fold, @tabLength, @indentLevel, @invisibles}) -> @@ -162,12 +163,7 @@ class TokenizedLine @lineEnding is null isColumnOutsideIndentation: (column) -> - column >= @firstNonWhitespaceIndex and @isColumnOutsideSoftWrapIndentation(column) - - isColumnOutsideSoftWrapIndentation: (column) -> - return true if @softWrapIndentationTokens.length == 0 - - column > @softWrapIndentationDelta + column >= @firstNonWhitespaceIndex isColumnInsideSoftWrapIndentation: (column) -> return false if @softWrapIndentationTokens.length == 0 From 0e0eeb34263fcb3d574614dc17701cec2eeba3b4 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 19 Mar 2015 12:23:10 +0100 Subject: [PATCH 0218/1783] :fire: Delete TokenizedLine#isColumnOutsideIndentation --- src/tokenized-line.coffee | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 489714ae3..b62ab316f 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -97,6 +97,7 @@ class TokenizedLine # Returns a {Number} representing the `line` position where the wrap would take place. # Returns `null` if a wrap wouldn't occur. findWrapColumn: (maxColumn) -> + return unless maxColumn? return unless @text.length > maxColumn if /\s/.test(@text[maxColumn]) @@ -107,7 +108,7 @@ class TokenizedLine return @text.length else # search backward for the start of the word on the boundary - for column in [maxColumn..0] when @isColumnOutsideIndentation(column) + for column in [maxColumn..@firstNonWhitespaceIndex] return column + 1 if /\s/.test(@text[column]) return maxColumn @@ -162,9 +163,6 @@ class TokenizedLine isSoftWrapped: -> @lineEnding is null - isColumnOutsideIndentation: (column) -> - column >= @firstNonWhitespaceIndex - isColumnInsideSoftWrapIndentation: (column) -> return false if @softWrapIndentationTokens.length == 0 From 2863fddff307fcded2736e6edb1ff2b80d95a92d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 19 Mar 2015 09:35:26 -0700 Subject: [PATCH 0219/1783] :arrow_up: language-ruby-on-rails@0.21 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fd906dd53..c50afafb1 100644 --- a/package.json +++ b/package.json @@ -144,7 +144,7 @@ "language-property-list": "0.8.0", "language-python": "0.32.0", "language-ruby": "0.49.0", - "language-ruby-on-rails": "0.20.0", + "language-ruby-on-rails": "0.21.0", "language-sass": "0.36.0", "language-shellscript": "0.13.0", "language-source": "0.9.0", From dccf88063bf9241d83250554a8427ceb4b437389 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 19 Mar 2015 09:37:20 -0700 Subject: [PATCH 0220/1783] :arrow_up: bracket-matcher@0.73 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c50afafb1..801aac11c 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "autosave": "0.20.0", "background-tips": "0.23.0", "bookmarks": "0.35.0", - "bracket-matcher": "0.72.0", + "bracket-matcher": "0.73.0", "command-palette": "0.34.0", "deprecation-cop": "0.37.0", "dev-live-reload": "0.45.0", From 6345799cf3dba3706a8eebb258da6e867c85144c Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 19 Mar 2015 12:47:58 -0600 Subject: [PATCH 0221/1783] Revert "Don't soft-wrap on indentation" --- spec/display-buffer-spec.coffee | 18 ---------------- spec/text-editor-component-spec.coffee | 4 ++-- src/tokenized-line.coffee | 30 ++++++++++++++------------ 3 files changed, 18 insertions(+), 34 deletions(-) diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index 95f22acca..1703a24d1 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -115,24 +115,6 @@ describe "DisplayBuffer", -> expect(displayBuffer.tokenizedLineForScreenRow(3).text).toBe ' var pivot = items.shift(), current, left = [], ' expect(displayBuffer.tokenizedLineForScreenRow(4).text).toBe ' right = [];' - describe "when the only whitespace characters are at the beginning of the line", -> - beforeEach -> - displayBuffer.setEditorWidthInChars(10) - - it "wraps the line at the max length when indented with tabs", -> - buffer.setTextInRange([[0, 0], [1, 0]], '\t\tabcdefghijklmnopqrstuvwxyz') - - expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe ' abcdef' - expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe ' ghijkl' - expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe ' mnopqr' - - it "wraps the line at the max length when indented with spaces", -> - buffer.setTextInRange([[0, 0], [1, 0]], ' abcdefghijklmnopqrstuvwxyz') - - expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe ' abcdef' - expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe ' ghijkl' - expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe ' mnopqr' - describe "when there are hard tabs", -> beforeEach -> buffer.setText(buffer.getText().replace(new RegExp(' ', 'g'), '\t')) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 20ddcdcab..f5c9e7677 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -1937,14 +1937,14 @@ describe "TextEditorComponent", -> gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(11), metaKey: true)) nextAnimationFrame() gutterNode.dispatchEvent(buildMouseEvent('mouseup', clientCoordinatesForScreenRowInGutter(11), metaKey: true)) - expect(editor.getSelectedScreenRanges()).toEqual [[[7, 4], [7, 6]], [[10, 0], [19, 0]]] + expect(editor.getSelectedScreenRanges()).toEqual [[[7, 4], [7, 6]], [[10, 0], [20, 0]]] it "merges overlapping selections", -> gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(17), metaKey: true)) gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(9), metaKey: true)) nextAnimationFrame() gutterNode.dispatchEvent(buildMouseEvent('mouseup', clientCoordinatesForScreenRowInGutter(9), metaKey: true)) - expect(editor.getSelectedScreenRanges()).toEqual [[[5, 0], [19, 0]]] + expect(editor.getSelectedScreenRanges()).toEqual [[[5, 0], [20, 0]]] describe "when the gutter is shift-clicked and dragged", -> describe "when the shift-click is below the existing selection's tail", -> diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index b62ab316f..2a807d84a 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -11,7 +11,6 @@ module.exports = class TokenizedLine endOfLineInvisibles: null lineIsWhitespaceOnly: false - firstNonWhitespaceIndex: 0 foldable: false constructor: ({tokens, @lineEnding, @ruleStack, @startBufferColumn, @fold, @tabLength, @indentLevel, @invisibles}) -> @@ -97,7 +96,6 @@ class TokenizedLine # Returns a {Number} representing the `line` position where the wrap would take place. # Returns `null` if a wrap wouldn't occur. findWrapColumn: (maxColumn) -> - return unless maxColumn? return unless @text.length > maxColumn if /\s/.test(@text[maxColumn]) @@ -108,7 +106,7 @@ class TokenizedLine return @text.length else # search backward for the start of the word on the boundary - for column in [maxColumn..@firstNonWhitespaceIndex] + for column in [maxColumn..0] when @isColumnOutsideSoftWrapIndentation(column) return column + 1 if /\s/.test(@text[column]) return maxColumn @@ -129,13 +127,12 @@ class TokenizedLine rightTokens = new Array(@tokens...) leftTokens = [] - leftScreenColumn = 0 - - while leftScreenColumn < column - if leftScreenColumn + rightTokens[0].screenDelta > column - rightTokens[0..0] = rightTokens[0].splitAt(column - leftScreenColumn) + leftTextLength = 0 + while leftTextLength < column + if leftTextLength + rightTokens[0].value.length > column + rightTokens[0..0] = rightTokens[0].splitAt(column - leftTextLength) nextToken = rightTokens.shift() - leftScreenColumn += nextToken.screenDelta + leftTextLength += nextToken.value.length leftTokens.push nextToken indentationTokens = @buildSoftWrapIndentationTokens(leftTokens[0], hangingIndent) @@ -163,6 +160,11 @@ class TokenizedLine isSoftWrapped: -> @lineEnding is null + isColumnOutsideSoftWrapIndentation: (column) -> + return true if @softWrapIndentationTokens.length == 0 + + column > @softWrapIndentationDelta + isColumnInsideSoftWrapIndentation: (column) -> return false if @softWrapIndentationTokens.length == 0 @@ -207,15 +209,15 @@ class TokenizedLine outputTokens markLeadingAndTrailingWhitespaceTokens: -> - @firstNonWhitespaceIndex = @text.search(NonWhitespaceRegex) - if @firstNonWhitespaceIndex > 0 and isPairedCharacter(@text, @firstNonWhitespaceIndex - 1) - @firstNonWhitespaceIndex-- + firstNonWhitespaceIndex = @text.search(NonWhitespaceRegex) + if firstNonWhitespaceIndex > 0 and isPairedCharacter(@text, firstNonWhitespaceIndex - 1) + firstNonWhitespaceIndex-- firstTrailingWhitespaceIndex = @text.search(TrailingWhitespaceRegex) @lineIsWhitespaceOnly = firstTrailingWhitespaceIndex is 0 index = 0 for token in @tokens - if index < @firstNonWhitespaceIndex - token.firstNonWhitespaceIndex = Math.min(index + token.value.length, @firstNonWhitespaceIndex - index) + if index < firstNonWhitespaceIndex + token.firstNonWhitespaceIndex = Math.min(index + token.value.length, firstNonWhitespaceIndex - index) # Only the *last* segment of a soft-wrapped line can have trailing whitespace if @lineEnding? and (index + token.value.length > firstTrailingWhitespaceIndex) token.firstTrailingWhitespaceIndex = Math.max(0, firstTrailingWhitespaceIndex - index) From b4f911f6d39d263adb9a9f966f8399b5972db265 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 18 Mar 2015 10:28:59 -0700 Subject: [PATCH 0222/1783] Add task to log loop returns --- build/tasks/output-for-loop-returns.coffee | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 build/tasks/output-for-loop-returns.coffee diff --git a/build/tasks/output-for-loop-returns.coffee b/build/tasks/output-for-loop-returns.coffee new file mode 100644 index 000000000..47523aa45 --- /dev/null +++ b/build/tasks/output-for-loop-returns.coffee @@ -0,0 +1,22 @@ +path = require 'path' + +module.exports = (grunt) -> + grunt.registerTask 'output-for-loop-returns', 'Log methods that end with a for loop', -> + appDir = grunt.config.get('atom.appDir') + + jsPaths = [] + grunt.file.recurse path.join(appDir, 'src'), (absolutePath, rootPath, relativePath, fileName) -> + jsPaths.push(absolutePath) if path.extname(fileName) is '.js' + + jsPaths.forEach (jsPath) -> + js = grunt.file.read(jsPath) + method = null + for line, index in js.split('\n') + [match, className, methodName] = /^\s*([a-zA-Z]+)\.prototype\.([a-zA-Z]+)\s*=\s*function\(/.exec(line) ? [] + if className and methodName + method = "#{className}::#{methodName}" + else + [match, ctorName] = /^\s*function\s+([a-zA-Z]+)\(/.exec(line) ? [] + + if /^\s*return\s+_results;\s*$/.test(line) + console.log(method ? "#{path.basename(jsPath)}:#{index}") From f728bc7aec2b9773c8a23e4f23e56f09b12f2bbb Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 18 Mar 2015 14:54:30 -0700 Subject: [PATCH 0223/1783] Add explicit returns to browser process classes --- src/browser/application-menu.coffee | 5 +++-- src/browser/atom-application.coffee | 2 ++ src/browser/auto-update-manager.coffee | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/browser/application-menu.coffee b/src/browser/application-menu.coffee index 5218ff304..4544a963d 100644 --- a/src/browser/application-menu.coffee +++ b/src/browser/application-menu.coffee @@ -82,7 +82,8 @@ class ApplicationMenu # window specific items. enableWindowSpecificItems: (enable) -> for item in @flattenMenuItems(@menu) - item.enabled = enable if item.metadata?['windowSpecific'] + item.enabled = enable if item.metadata?.windowSpecific + return # Replaces VERSION with the current version. substituteVersion: (template) -> @@ -145,7 +146,7 @@ class ApplicationMenu if item.command item.accelerator = @acceleratorForCommand(item.command, keystrokesByCommand) item.click = -> global.atomApplication.sendCommand(item.command) - item.metadata['windowSpecific'] = true unless /^application:/.test(item.command) + item.metadata.windowSpecific = true unless /^application:/.test(item.command) @translateTemplate(item.submenu, keystrokesByCommand) if item.submenu template diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 8fa888730..d79b2bf76 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -388,11 +388,13 @@ class AtomApplication # Kill all processes associated with opened windows. killAllProcesses: -> @killProcess(pid) for pid of @pidsToOpenWindows + return # Kill process associated with the given opened window. killProcessForWindow: (openedWindow) -> for pid, trackedWindow of @pidsToOpenWindows @killProcess(pid) if trackedWindow is openedWindow + return # Kill the process with the given pid. killProcess: (pid) -> diff --git a/src/browser/auto-update-manager.coffee b/src/browser/auto-update-manager.coffee index a0c1f2da8..3ee0fce3d 100644 --- a/src/browser/auto-update-manager.coffee +++ b/src/browser/auto-update-manager.coffee @@ -65,6 +65,7 @@ class AutoUpdateManager return unless @releaseVersion? for atomWindow in windows atomWindow.sendMessage('update-available', {@releaseVersion}) + return setState: (state) -> return if @state is state From 6e464ac35c6e35cd6c2f0283fa74a2c66d325872 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 18 Mar 2015 15:18:55 -0700 Subject: [PATCH 0224/1783] Catch non-protype functions --- build/tasks/output-for-loop-returns.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/tasks/output-for-loop-returns.coffee b/build/tasks/output-for-loop-returns.coffee index 47523aa45..f9b036120 100644 --- a/build/tasks/output-for-loop-returns.coffee +++ b/build/tasks/output-for-loop-returns.coffee @@ -12,7 +12,7 @@ module.exports = (grunt) -> js = grunt.file.read(jsPath) method = null for line, index in js.split('\n') - [match, className, methodName] = /^\s*([a-zA-Z]+)\.prototype\.([a-zA-Z]+)\s*=\s*function\(/.exec(line) ? [] + [match, className, methodName] = /^\s*([a-zA-Z]+)\.(?:prototype\.)?([a-zA-Z]+)\s*=\s*function\(/.exec(line) ? [] if className and methodName method = "#{className}::#{methodName}" else From 590a4b0fd5cccef210e236991ddd4a3a3ee521b9 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 18 Mar 2015 15:19:19 -0700 Subject: [PATCH 0225/1783] Add explicit return after for loop --- src/atom.coffee | 1 + src/command-registry.coffee | 2 ++ src/config.coffee | 3 +++ src/context-menu-manager.coffee | 1 + src/cursors-component.coffee | 2 ++ src/custom-event-mixin.coffee | 2 ++ src/deserializer-manager.coffee | 2 ++ src/display-buffer.coffee | 4 ++++ src/gutter-component.coffee | 2 ++ src/highlights-component.coffee | 4 ++++ src/language-mode.coffee | 4 ++++ src/lines-component.coffee | 3 +++ src/marker.coffee | 1 + src/package-manager.coffee | 2 ++ src/package.coffee | 4 ++++ src/pane-container.coffee | 2 ++ src/pane.coffee | 3 +++ src/project.coffee | 1 + src/row-map.coffee | 1 + src/selection.coffee | 7 +++++++ src/style-manager.coffee | 2 ++ src/styles-element.coffee | 1 + 22 files changed, 54 insertions(+) diff --git a/src/atom.coffee b/src/atom.coffee index e03502dee..188d0b3a6 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -825,6 +825,7 @@ class Atom extends Model delete window[key] else window[key] = value + return onUpdateAvailable: (callback) -> @emitter.on 'update-available', callback diff --git a/src/command-registry.coffee b/src/command-registry.coffee index ead4415d2..479d972fa 100644 --- a/src/command-registry.coffee +++ b/src/command-registry.coffee @@ -50,6 +50,7 @@ class CommandRegistry destroy: -> for commandName of @registeredCommands window.removeEventListener(commandName, @handleCommandEvent, true) + return # Public: Add one or more command listeners associated with a selector. # @@ -187,6 +188,7 @@ class CommandRegistry @selectorBasedListenersByCommandName = {} for commandName, listeners of snapshot @selectorBasedListenersByCommandName[commandName] = listeners.slice() + return handleCommandEvent: (originalEvent) => propagationStopped = false diff --git a/src/config.coffee b/src/config.coffee index 331e89af9..4901f21dc 100644 --- a/src/config.coffee +++ b/src/config.coffee @@ -301,6 +301,7 @@ class Config for typeName, functions of filters for name, enforcerFunction of functions @addSchemaEnforcer(typeName, enforcerFunction) + return @executeSchemaEnforcers: (keyPath, value, schema) -> error = null @@ -898,6 +899,7 @@ class Config @transact => @settings = {} @set(key, value, save: false) for key, value of newSettings + return getRawValue: (keyPath, options) -> unless options?.excludeSources?.indexOf(@getUserConfigPath()) >= 0 @@ -958,6 +960,7 @@ class Config @setRawDefault(keyPath, defaults) catch e console.warn("'#{keyPath}' could not set the default. Attempted default: #{JSON.stringify(defaults)}; Schema: #{JSON.stringify(@getSchema(keyPath))}") + return deepClone: (object) -> if object instanceof Color diff --git a/src/context-menu-manager.coffee b/src/context-menu-manager.coffee index 3f281afb1..ed91f5e6c 100644 --- a/src/context-menu-manager.coffee +++ b/src/context-menu-manager.coffee @@ -132,6 +132,7 @@ class ContextMenuManager new Disposable => for itemSet in addedItemSets @itemSets.splice(@itemSets.indexOf(itemSet), 1) + return templateForElement: (target) -> @templateForEvent({target}) diff --git a/src/cursors-component.coffee b/src/cursors-component.coffee index f4f5d749f..bd530ce2b 100644 --- a/src/cursors-component.coffee +++ b/src/cursors-component.coffee @@ -35,6 +35,8 @@ class CursorsComponent @domNode.appendChild(cursorNode) @updateCursorNode(id, cursorState) + return + updateCursorNode: (id, newCursorState) -> cursorNode = @cursorNodesById[id] oldCursorState = (@oldState.cursors[id] ?= {}) diff --git a/src/custom-event-mixin.coffee b/src/custom-event-mixin.coffee index 1a3bb4d88..12785c89c 100644 --- a/src/custom-event-mixin.coffee +++ b/src/custom-event-mixin.coffee @@ -7,9 +7,11 @@ CustomEventMixin = for name, listeners in @customEventListeners for listener in listeners @getDOMNode().removeEventListener(name, listener) + return addCustomEventListeners: (customEventListeners) -> for name, listener of customEventListeners @customEventListeners[name] ?= [] @customEventListeners[name].push(listener) @getDOMNode().addEventListener(name, listener) + return diff --git a/src/deserializer-manager.coffee b/src/deserializer-manager.coffee index 50becb31a..40c5ea7f3 100644 --- a/src/deserializer-manager.coffee +++ b/src/deserializer-manager.coffee @@ -35,10 +35,12 @@ class DeserializerManager @deserializers[deserializer.name] = deserializer for deserializer in deserializers new Disposable => delete @deserializers[deserializer.name] for deserializer in deserializers + return remove: (classes...) -> Grim.deprecate("Call .dispose() on the Disposable return from ::add instead") delete @deserializers[name] for {name} in classes + return # Public: Deserialize the state and params. # diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index 8e8bd8dcd..4ab65d0f7 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -538,6 +538,7 @@ class DisplayBuffer extends Model # bufferRow - The buffer row {Number} to check against unfoldBufferRow: (bufferRow) -> fold.destroy() for fold in @foldsContainingBufferRow(bufferRow) + return # Given a buffer row, this returns the largest fold that starts there. # @@ -1082,6 +1083,7 @@ class DisplayBuffer extends Model pauseMarkerChangeEvents: -> marker.pauseChangeEvents() for marker in @getMarkers() + return resumeMarkerChangeEvents: -> marker.resumeChangeEvents() for marker in @getMarkers() @@ -1091,6 +1093,7 @@ class DisplayBuffer extends Model refreshMarkerScreenPositions: -> for marker in @getMarkers() marker.notifyObservers(textChanged: false) + return destroyed: -> marker.unsubscribe() for id, marker of @markers @@ -1102,6 +1105,7 @@ class DisplayBuffer extends Model for row in [start..end] line = @tokenizedLineForScreenRow(row).text console.log row, @bufferRowForScreenRow(row), line, line.length + return getRootScopeDescriptor: -> @tokenizedBuffer.rootScopeDescriptor diff --git a/src/gutter-component.coffee b/src/gutter-component.coffee index 6eb11ff1f..072ac99a0 100644 --- a/src/gutter-component.coffee +++ b/src/gutter-component.coffee @@ -84,6 +84,8 @@ class GutterComponent delete @lineNumberNodesById[id] delete @oldState.lineNumbers[id] + return + buildLineNumberHTML: (lineNumberState) -> {screenRow, bufferRow, softWrapped, top, decorationClasses} = lineNumberState if screenRow? diff --git a/src/highlights-component.coffee b/src/highlights-component.coffee index 3bd5197fe..e2c629cb9 100644 --- a/src/highlights-component.coffee +++ b/src/highlights-component.coffee @@ -39,6 +39,8 @@ class HighlightsComponent @domNode.appendChild(highlightNode) @updateHighlightNode(id, highlightState) + return + updateHighlightNode: (id, newHighlightState) -> highlightNode = @highlightNodesById[id] oldHighlightState = (@oldState[id] ?= {regions: [], flashCount: 0}) @@ -92,6 +94,8 @@ class HighlightsComponent else regionNode.style[property] = '' + return + flashHighlightNodeIfRequested: (id, newHighlightState) -> oldHighlightState = @oldState[id] return unless newHighlightState.flashCount > oldHighlightState.flashCount diff --git a/src/language-mode.coffee b/src/language-mode.coffee index b7a52280b..125b15ff6 100644 --- a/src/language-mode.coffee +++ b/src/language-mode.coffee @@ -104,11 +104,13 @@ class LanguageMode [startRow, endRow] = @rowRangeForFoldAtBufferRow(currentRow) ? [] continue unless startRow? @editor.createFold(startRow, endRow) + return # Unfolds all the foldable lines in the buffer. unfoldAll: -> for row in [@buffer.getLastRow()..0] fold.destroy() for fold in @editor.displayBuffer.foldsStartingAtBufferRow(row) + return # Fold all comment and code blocks at a given indentLevel # @@ -122,6 +124,7 @@ class LanguageMode # assumption: startRow will always be the min indent level for the entire range if @editor.indentationForBufferRow(startRow) == indentLevel @editor.createFold(startRow, endRow) + return # Given a buffer row, creates a fold at it. # @@ -276,6 +279,7 @@ class LanguageMode # endRow - The row {Number} to end at autoIndentBufferRows: (startRow, endRow) -> @autoIndentBufferRow(row) for row in [startRow..endRow] + return # Given a buffer row, this indents it. # diff --git a/src/lines-component.coffee b/src/lines-component.coffee index fa4ab23b0..8389a1ae9 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -89,6 +89,7 @@ class LinesComponent removeLineNodes: -> @removeLineNode(id) for id of @oldState.lines + return removeLineNode: (id) -> @lineNodesByLineId[id].remove() @@ -126,6 +127,8 @@ class LinesComponent @lineNodesByLineId[id] = lineNode @domNode.appendChild(lineNode) + return + buildLineHTML: (id) -> {scrollWidth} = @newState {screenRow, tokens, text, top, lineEnding, fold, isSoftWrapped, indentLevel, decorationClasses} = @newState.lines[id] diff --git a/src/marker.coffee b/src/marker.coffee index 2224ca1c7..22460c1f8 100644 --- a/src/marker.coffee +++ b/src/marker.coffee @@ -396,6 +396,7 @@ class Marker for event in deferredChangeEvents @emit 'changed', event @emitter.emit 'did-change', event + return getPixelRange: -> @displayBuffer.pixelRangeForScreenRange(@getScreenRange(), false) diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 9f53d45e2..444497c5b 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -394,6 +394,7 @@ class PackageManager for pack in packages promise = @activatePackage(pack.name) promises.push(promise) unless pack.hasActivationCommands() + return @observeDisabledPackages() promises @@ -413,6 +414,7 @@ class PackageManager deactivatePackages: -> atom.config.transact => @deactivatePackage(pack.name) for pack in @getLoadedPackages() + return @unobserveDisabledPackages() # Deactivate the package with the given name diff --git a/src/package.coffee b/src/package.coffee index 4d244c50f..44516261a 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -238,12 +238,14 @@ class Package @keymaps = (["#{atom.packages.resourcePath}#{path.sep}#{keymapPath}", keymapObject] for keymapPath, keymapObject of packagesCache[@name].keymaps) else @keymaps = @getKeymapPaths().map (keymapPath) -> [keymapPath, CSON.readFileSync(keymapPath) ? {}] + return loadMenus: -> if @bundledPackage and packagesCache[@name]? @menus = (["#{atom.packages.resourcePath}#{path.sep}#{menuPath}", menuObject] for menuPath, menuObject of packagesCache[@name].menus) else @menus = @getMenuPaths().map (menuPath) -> [menuPath, CSON.readFileSync(menuPath) ? {}] + return getKeymapPaths: -> keymapsDirPath = path.join(@path, 'keymaps') @@ -447,6 +449,7 @@ class Package @activateNow() break currentTarget = currentTarget.parentElement + return getActivationCommands: -> return @activationCommands if @activationCommands? @@ -505,6 +508,7 @@ class Package for modulePath in fs.listSync(nodeModulesPath) nativeModulePaths.push(modulePath) if @isNativeModule(modulePath) traversePath(path.join(modulePath, 'node_modules')) + return traversePath(path.join(@path, 'node_modules')) nativeModulePaths diff --git a/src/pane-container.coffee b/src/pane-container.coffee index 14fa25a44..61ff9f207 100644 --- a/src/pane-container.coffee +++ b/src/pane-container.coffee @@ -151,6 +151,7 @@ class PaneContainer extends Model saveAll: -> pane.saveItems() for pane in @getPanes() + return confirmClose: (options) -> allSaved = true @@ -186,6 +187,7 @@ class PaneContainer extends Model destroyEmptyPanes: -> pane.destroy() for pane in @getPanes() when pane.items.length is 0 + return willDestroyPaneItem: (event) -> @emitter.emit 'will-destroy-pane-item', event diff --git a/src/pane.coffee b/src/pane.coffee index 0f19c40bf..a1239acb5 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -440,10 +440,12 @@ class Pane extends Model # Public: Destroy all items. destroyItems: -> @destroyItem(item) for item in @getItems() + return # Public: Destroy all items except for the active item. destroyInactiveItems: -> @destroyItem(item) for item in @getItems() when item isnt @activeItem + return promptToSaveItem: (item, options={}) -> return true unless item.shouldPromptToSave?(options) @@ -518,6 +520,7 @@ class Pane extends Model # Public: Save all items. saveItems: -> @saveItem(item) for item in @getItems() + return # Public: Return the first item that matches the given URI or undefined if # none exists. diff --git a/src/project.coffee b/src/project.coffee index a54d5edd1..299ba920b 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -83,6 +83,7 @@ class Project extends Model destroyUnretainedBuffers: -> buffer.destroy() for buffer in @getBuffers() when not buffer.isRetained() + return ### Section: Serialization diff --git a/src/row-map.coffee b/src/row-map.coffee index fd5dfb2ea..5510c1421 100644 --- a/src/row-map.coffee +++ b/src/row-map.coffee @@ -112,6 +112,7 @@ class RowMap @regions.splice index - 1, 2, bufferRows: leftRegion.bufferRows + rightRegion.bufferRows screenRows: leftRegion.screenRows + rightRegion.screenRows + return # Public: Returns an array of strings describing the map's regions. inspect: -> diff --git a/src/selection.coffee b/src/selection.coffee index 5b0fdae38..375498c41 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -538,6 +538,7 @@ class Selection extends Model for row in [start..end] if matchLength = buffer.lineForRow(row).match(leadingTabRegex)?[0].length buffer.delete [[row, 0], [row, matchLength]] + return # Public: Sets the indentation level of all selected rows to values suggested # by the relevant grammars. @@ -620,6 +621,7 @@ class Selection extends Model currentIndentLevel = @editor.indentLevelForLine(lines[i]) indentLevel = Math.max(0, currentIndentLevel + indentAdjustment) lines[i] = line.replace(/^[\t ]+/, @editor.buildIndentString(indentLevel)) + return # Indent the current line(s). # @@ -651,6 +653,7 @@ class Selection extends Model [start, end] = @getBufferRowRange() for row in [start..end] @editor.buffer.insert([row, 0], @editor.getTabText()) unless @editor.buffer.lineLengthForRow(row) == 0 + return ### Section: Managing multiple selections @@ -674,6 +677,8 @@ class Selection extends Model @editor.addSelectionForScreenRange(clippedRange, goalScreenRange: range) break + return + # Public: Moves the selection up one row. addSelectionAbove: -> range = (@getGoalScreenRange() ? @getScreenRange()).copy() @@ -692,6 +697,8 @@ class Selection extends Model @editor.addSelectionForScreenRange(clippedRange, goalScreenRange: range) break + return + # Public: Combines the given selection into this selection and then destroys # the given selection. # diff --git a/src/style-manager.coffee b/src/style-manager.coffee index c891223b9..cfe86b3fe 100644 --- a/src/style-manager.coffee +++ b/src/style-manager.coffee @@ -152,6 +152,8 @@ class StyleManager for styleElement in styleElementsToRestore @addStyleElement(styleElement) unless styleElement in existingStyleElements + return + ### Section: Paths ### diff --git a/src/styles-element.coffee b/src/styles-element.coffee index d333a2e45..fc3b888cf 100644 --- a/src/styles-element.coffee +++ b/src/styles-element.coffee @@ -46,6 +46,7 @@ class StylesElement extends HTMLElement @styleElementRemoved(child) for child in Array::slice.call(@children) @context = @getAttribute('context') @styleElementAdded(styleElement) for styleElement in atom.styles.getStyleElements() + return styleElementAdded: (styleElement) -> return unless @styleElementMatchesContext(styleElement) From d9a5aff919087133f8f3cd223cf4ec4b391be32e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 18 Mar 2015 15:34:50 -0700 Subject: [PATCH 0226/1783] Add explicit return after for loop --- src/text-editor-presenter.coffee | 11 +++++++++++ src/text-editor.coffee | 20 +++++++++++++++++--- src/tokenized-buffer.coffee | 2 ++ src/tokenized-line.coffee | 3 +++ 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index ebcc5a5ca..babd7725b 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -124,6 +124,7 @@ class TextEditorPresenter @disposables.add @model.onDidChangeScrollLeft(@setScrollLeft.bind(this)) @observeDecoration(decoration) for decoration in @model.getDecorations() @observeCursor(cursor) for cursor in @model.getCursors() + return observeConfig: -> configParams = {scope: @model.getRootScopeDescriptor()} @@ -273,6 +274,7 @@ class TextEditorPresenter for id, line of @state.content.lines unless visibleLineIds.hasOwnProperty(id) delete @state.content.lines[id] + return updateLineState: (row, line) -> lineState = @state.content.lines[line.id] @@ -296,6 +298,7 @@ class TextEditorPresenter updateCursorsState: -> @batch "shouldUpdateCursorsState", -> @state.content.cursors = {} @updateCursorState(cursor) for cursor in @model.cursors # using property directly to avoid allocation + return updateCursorState: (cursor, destroyOnly = false) -> delete @state.content.cursors[cursor.id] @@ -331,6 +334,8 @@ class TextEditorPresenter for id of @state.content.overlays delete @state.content.overlays[id] unless visibleDecorationIds[id] + return + updateGutterState: -> @batch "shouldUpdateGutterState", -> @state.gutter.visible = not @model.isMini() and (@model.isGutterVisible() ? true) and @showLineNumbers @state.gutter.maxLineNumberDigits = @model.getLineCount().toString().length @@ -382,6 +387,8 @@ class TextEditorPresenter for id of @state.gutter.lineNumbers delete @state.gutter.lineNumbers[id] unless visibleLineNumberIds[id] + return + updateStartRow: -> return unless @scrollTop? and @lineHeight? @@ -873,11 +880,13 @@ class TextEditorPresenter unless visibleHighlights[id] delete @state.content.highlights[id] + return removeFromLineDecorationCaches: (decoration, range) -> for row in [range.start.row..range.end.row] by 1 delete @lineDecorationsByScreenRow[row]?[decoration.id] delete @lineNumberDecorationsByScreenRow[row]?[decoration.id] + return addToLineDecorationCaches: (decoration, range) -> marker = decoration.getMarker() @@ -903,6 +912,8 @@ class TextEditorPresenter @lineNumberDecorationsByScreenRow[row] ?= {} @lineNumberDecorationsByScreenRow[row][decoration.id] = decoration + return + updateHighlightState: (decoration) -> return unless @startRow? and @endRow? and @lineHeight? and @hasPixelPositionRequirements() diff --git a/src/text-editor.coffee b/src/text-editor.coffee index f731810ae..d29013280 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -842,7 +842,9 @@ class TextEditor extends Model # {Number} index of that selection. mutateSelectedText: (fn) -> @mergeIntersectingSelections => - @transact => fn(selection, index) for selection, index in @getSelections() + @transact => + fn(selection, index) for selection, index in @getSelections() + return # Move lines intersection the most recent selection up by one row in screen # coordinates. @@ -978,6 +980,7 @@ class TextEditor extends Model selection.setBufferRange(selectedBufferRange.translate([delta, 0])) for [foldStartRow, foldEndRow] in foldedRowRanges @createFold(foldStartRow + delta, foldEndRow + delta) + return # Deprecated: Use {::duplicateLines} instead. duplicateLine: -> @@ -1013,6 +1016,7 @@ class TextEditor extends Model while ++row < end.row @addSelectionForBufferRange([[row, 0], [row, Infinity]]) @addSelectionForBufferRange([[end.row, 0], [end.row, end.column]]) unless end.column is 0 + return # Extended: For each selection, transpose the selected text. # @@ -1779,7 +1783,7 @@ class TextEditor extends Model # Extended: Get an Array of all {Cursor}s. getCursors: -> - cursor for cursor in @cursors + @cursors.slice() # Extended: Get all {Cursors}s, ordered by their position in the buffer # instead of the order in which they were added. @@ -1822,6 +1826,7 @@ class TextEditor extends Model cursor.destroy() else positions[position] = true + return preserveCursorPositionOnBufferReload: -> cursorPosition = null @@ -1886,6 +1891,7 @@ class TextEditor extends Model selections[i].setBufferRange(bufferRange, options) else @addSelectionForBufferRange(bufferRange, options) + return # Essential: Get the {Range} of the most recently added selection in screen # coordinates. @@ -1932,6 +1938,7 @@ class TextEditor extends Model selections[i].setScreenRange(screenRange, options) else @addSelectionForScreenRange(screenRange, options) + return # Essential: Add a selection for the given range in buffer coordinates. # @@ -2159,7 +2166,7 @@ class TextEditor extends Model # # Returns: An {Array} of {Selection}s. getSelections: -> - selection for selection in @selections + @selections.slice() # Extended: Get all {Selection}s, ordered by their position in the buffer # instead of the order in which they were added. @@ -2206,15 +2213,18 @@ class TextEditor extends Model expandSelectionsForward: (fn) -> @mergeIntersectingSelections => fn(selection) for selection in @getSelections() + return # Calls the given function with each selection, then merges selections in the # reversed orientation expandSelectionsBackward: (fn) -> @mergeIntersectingSelections reversed: true, => fn(selection) for selection in @getSelections() + return finalizeSelections: -> selection.finalize() for selection in @getSelections() + return selectionsForScreenRows: (startRow, endRow) -> @getSelections().filter (selection) -> selection.intersectsScreenRowRange(startRow, endRow) @@ -2620,6 +2630,7 @@ class TextEditor extends Model else selection.copy(maintainClipboard, false) maintainClipboard = true + return # Essential: For each selection, cut the selected text. cutSelectedText: -> @@ -2714,6 +2725,7 @@ class TextEditor extends Model # Extended: For each selection, fold the rows it intersects. foldSelectedLines: -> selection.fold() for selection in @getSelections() + return # Extended: Fold all foldable lines. foldAll: -> @@ -2796,6 +2808,8 @@ class TextEditor extends Model for row in [bufferRange.end.row..bufferRange.start.row] fold.destroy() for fold in @displayBuffer.foldsStartingAtBufferRow(row) + return + # Remove any {Fold}s found that contain the given buffer range. destroyFoldsContainingBufferRange: (bufferRange) -> @unfoldBufferRow(bufferRange.start.row) diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index b8a9bdab7..cf7d15c28 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -197,6 +197,7 @@ class TokenizedBuffer extends Model validateRow: (row) -> @invalidRows.shift() while @invalidRows[0] <= row + return invalidateRow: (row) -> @invalidRows.push(row) @@ -468,3 +469,4 @@ class TokenizedBuffer extends Model for row in [start..end] line = @tokenizedLineForRow(row).text console.log row, line, line.length + return diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 2a807d84a..f67d754c8 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -222,6 +222,7 @@ class TokenizedLine if @lineEnding? and (index + token.value.length > firstTrailingWhitespaceIndex) token.firstTrailingWhitespaceIndex = Math.max(0, firstTrailingWhitespaceIndex - index) index += token.value.length + return substituteInvisibleCharacters: -> invisibles = @invisibles @@ -309,6 +310,8 @@ class TokenizedLine for j in [i...desiredScopeDescriptor.length] scopeStack.push(new Scope(desiredScopeDescriptor[j])) + return + class Scope constructor: (@scope) -> @children = [] From a9803d3c4d9fc371edf6f3c600f79a5299284ddf Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 19 Mar 2015 10:53:55 -0700 Subject: [PATCH 0227/1783] Add explicit return after for loop --- src/window-event-handler.coffee | 3 +++ src/workspace-view.coffee | 1 - src/workspace.coffee | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/window-event-handler.coffee b/src/window-event-handler.coffee index 1384f0c4a..593d33476 100644 --- a/src/window-event-handler.coffee +++ b/src/window-event-handler.coffee @@ -32,6 +32,8 @@ class WindowEventHandler unless fs.isDirectorySync(pathToOpen) atom.workspace?.open(pathToOpen, {initialLine, initialColumn}) + return + when 'update-available' atom.updateAvailable(detail) @@ -156,6 +158,7 @@ class WindowEventHandler continue unless tabIndex >= 0 callback(element, tabIndex) + return focusNext: => focusedTabIndex = parseInt($(':focus').attr('tabindex')) or -Infinity diff --git a/src/workspace-view.coffee b/src/workspace-view.coffee index addfe63c5..6a4a685d8 100644 --- a/src/workspace-view.coffee +++ b/src/workspace-view.coffee @@ -222,7 +222,6 @@ class WorkspaceView extends View for editorElement in @panes.element.querySelectorAll('atom-pane > .item-views > atom-text-editor') $(editorElement).view() - ### Section: Deprecated ### diff --git a/src/workspace.coffee b/src/workspace.coffee index 49f84f9b8..4afce1f37 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -110,6 +110,7 @@ class Workspace extends Model packageNames.push(packageName) for scopeName in includedGrammarScopes ? [] addGrammar(atom.grammars.grammarForScopeName(scopeName)) + return editors = @getTextEditors() addGrammar(editor.getGrammar()) for editor in editors From 23eacc1e58201e592167c4db860a0126c0dcfa77 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 19 Mar 2015 10:56:42 -0700 Subject: [PATCH 0228/1783] Add explicit return after for loop --- src/menu-helpers.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/menu-helpers.coffee b/src/menu-helpers.coffee index a91523b82..aa346200c 100644 --- a/src/menu-helpers.coffee +++ b/src/menu-helpers.coffee @@ -17,6 +17,8 @@ merge = (menu, item, itemSpecificity=Infinity) -> else unless item.type is 'separator' and _.last(menu)?.type is 'separator' menu.push(item) + return + unmerge = (menu, item) -> matchingItemIndex = findMatchingItemIndex(menu, item) matchingItem = menu[matchingItemIndex] unless matchingItemIndex is - 1 From 9f31afcbc9ad7d80186e389cd1f39865cbd6764d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 19 Mar 2015 10:57:55 -0700 Subject: [PATCH 0229/1783] Add explicit return after while loop --- src/package.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/package.coffee b/src/package.coffee index 44516261a..c0ab284e9 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -449,6 +449,7 @@ class Package @activateNow() break currentTarget = currentTarget.parentElement + return return getActivationCommands: -> From a72b1ccdf406d95be39f4f7eb3a929c520542b59 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 19 Mar 2015 11:10:15 -0700 Subject: [PATCH 0230/1783] Mention array copying and explicit returns --- CONTRIBUTING.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a5ebdd5f5..d2cf02bef 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -104,6 +104,9 @@ For more information on how to work with Atom's official packages, see should be lower-case: * `getURI` instead of `getUri` * `uriToOpen` instead of `URIToOpen` +* Use `slice()` to copy an array +* Add an explicit `return` when your function ends with a `for`/`while` loop and + you don't want it to return a collected array. ## Documentation Styleguide From 576e00fb9363ffda732b646021fe166e443b0de0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 19 Mar 2015 11:57:16 -0700 Subject: [PATCH 0231/1783] Keep returning array from TextEditor::mutateSelectedText --- src/text-editor.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index d29013280..6ccb97392 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -844,7 +844,6 @@ class TextEditor extends Model @mergeIntersectingSelections => @transact => fn(selection, index) for selection, index in @getSelections() - return # Move lines intersection the most recent selection up by one row in screen # coordinates. From 2bfd30c832d0fea8001b021d697ef43879964db3 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 19 Mar 2015 14:37:39 -0600 Subject: [PATCH 0232/1783] Revert "Revert "Don't soft-wrap on indentation"" --- spec/display-buffer-spec.coffee | 18 ++++++++++++++++ spec/text-editor-component-spec.coffee | 4 ++-- src/tokenized-line.coffee | 30 ++++++++++++-------------- 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index 1703a24d1..95f22acca 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -115,6 +115,24 @@ describe "DisplayBuffer", -> expect(displayBuffer.tokenizedLineForScreenRow(3).text).toBe ' var pivot = items.shift(), current, left = [], ' expect(displayBuffer.tokenizedLineForScreenRow(4).text).toBe ' right = [];' + describe "when the only whitespace characters are at the beginning of the line", -> + beforeEach -> + displayBuffer.setEditorWidthInChars(10) + + it "wraps the line at the max length when indented with tabs", -> + buffer.setTextInRange([[0, 0], [1, 0]], '\t\tabcdefghijklmnopqrstuvwxyz') + + expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe ' abcdef' + expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe ' ghijkl' + expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe ' mnopqr' + + it "wraps the line at the max length when indented with spaces", -> + buffer.setTextInRange([[0, 0], [1, 0]], ' abcdefghijklmnopqrstuvwxyz') + + expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe ' abcdef' + expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe ' ghijkl' + expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe ' mnopqr' + describe "when there are hard tabs", -> beforeEach -> buffer.setText(buffer.getText().replace(new RegExp(' ', 'g'), '\t')) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index f5c9e7677..20ddcdcab 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -1937,14 +1937,14 @@ describe "TextEditorComponent", -> gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(11), metaKey: true)) nextAnimationFrame() gutterNode.dispatchEvent(buildMouseEvent('mouseup', clientCoordinatesForScreenRowInGutter(11), metaKey: true)) - expect(editor.getSelectedScreenRanges()).toEqual [[[7, 4], [7, 6]], [[10, 0], [20, 0]]] + expect(editor.getSelectedScreenRanges()).toEqual [[[7, 4], [7, 6]], [[10, 0], [19, 0]]] it "merges overlapping selections", -> gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(17), metaKey: true)) gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(9), metaKey: true)) nextAnimationFrame() gutterNode.dispatchEvent(buildMouseEvent('mouseup', clientCoordinatesForScreenRowInGutter(9), metaKey: true)) - expect(editor.getSelectedScreenRanges()).toEqual [[[5, 0], [20, 0]]] + expect(editor.getSelectedScreenRanges()).toEqual [[[5, 0], [19, 0]]] describe "when the gutter is shift-clicked and dragged", -> describe "when the shift-click is below the existing selection's tail", -> diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 2a807d84a..b62ab316f 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -11,6 +11,7 @@ module.exports = class TokenizedLine endOfLineInvisibles: null lineIsWhitespaceOnly: false + firstNonWhitespaceIndex: 0 foldable: false constructor: ({tokens, @lineEnding, @ruleStack, @startBufferColumn, @fold, @tabLength, @indentLevel, @invisibles}) -> @@ -96,6 +97,7 @@ class TokenizedLine # Returns a {Number} representing the `line` position where the wrap would take place. # Returns `null` if a wrap wouldn't occur. findWrapColumn: (maxColumn) -> + return unless maxColumn? return unless @text.length > maxColumn if /\s/.test(@text[maxColumn]) @@ -106,7 +108,7 @@ class TokenizedLine return @text.length else # search backward for the start of the word on the boundary - for column in [maxColumn..0] when @isColumnOutsideSoftWrapIndentation(column) + for column in [maxColumn..@firstNonWhitespaceIndex] return column + 1 if /\s/.test(@text[column]) return maxColumn @@ -127,12 +129,13 @@ class TokenizedLine rightTokens = new Array(@tokens...) leftTokens = [] - leftTextLength = 0 - while leftTextLength < column - if leftTextLength + rightTokens[0].value.length > column - rightTokens[0..0] = rightTokens[0].splitAt(column - leftTextLength) + leftScreenColumn = 0 + + while leftScreenColumn < column + if leftScreenColumn + rightTokens[0].screenDelta > column + rightTokens[0..0] = rightTokens[0].splitAt(column - leftScreenColumn) nextToken = rightTokens.shift() - leftTextLength += nextToken.value.length + leftScreenColumn += nextToken.screenDelta leftTokens.push nextToken indentationTokens = @buildSoftWrapIndentationTokens(leftTokens[0], hangingIndent) @@ -160,11 +163,6 @@ class TokenizedLine isSoftWrapped: -> @lineEnding is null - isColumnOutsideSoftWrapIndentation: (column) -> - return true if @softWrapIndentationTokens.length == 0 - - column > @softWrapIndentationDelta - isColumnInsideSoftWrapIndentation: (column) -> return false if @softWrapIndentationTokens.length == 0 @@ -209,15 +207,15 @@ class TokenizedLine outputTokens markLeadingAndTrailingWhitespaceTokens: -> - firstNonWhitespaceIndex = @text.search(NonWhitespaceRegex) - if firstNonWhitespaceIndex > 0 and isPairedCharacter(@text, firstNonWhitespaceIndex - 1) - firstNonWhitespaceIndex-- + @firstNonWhitespaceIndex = @text.search(NonWhitespaceRegex) + if @firstNonWhitespaceIndex > 0 and isPairedCharacter(@text, @firstNonWhitespaceIndex - 1) + @firstNonWhitespaceIndex-- firstTrailingWhitespaceIndex = @text.search(TrailingWhitespaceRegex) @lineIsWhitespaceOnly = firstTrailingWhitespaceIndex is 0 index = 0 for token in @tokens - if index < firstNonWhitespaceIndex - token.firstNonWhitespaceIndex = Math.min(index + token.value.length, firstNonWhitespaceIndex - index) + if index < @firstNonWhitespaceIndex + token.firstNonWhitespaceIndex = Math.min(index + token.value.length, @firstNonWhitespaceIndex - index) # Only the *last* segment of a soft-wrapped line can have trailing whitespace if @lineEnding? and (index + token.value.length > firstTrailingWhitespaceIndex) token.firstTrailingWhitespaceIndex = Math.max(0, firstTrailingWhitespaceIndex - index) From 5f76979fc83367d916e8962a6dd31c12983eff57 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 19 Mar 2015 15:08:36 -0600 Subject: [PATCH 0233/1783] Fix random editor spec now for indented soft-wrap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We previously implemented soft-wrap logic again just for this test. Since the purpose of this test is just to make sure that mutation occurs correctly, we now instead construct a fresh editor for comparison so that changes to soft-wrap logic are reflected. /cc @as-cii Took care of this, so you don’t need to worry about my previous comment on your PR. Sorry for the noise. --- spec/random-editor-spec.coffee | 44 +++++++++------------------------- 1 file changed, 11 insertions(+), 33 deletions(-) diff --git a/spec/random-editor-spec.coffee b/spec/random-editor-spec.coffee index bb5028d9a..d235ebc25 100644 --- a/spec/random-editor-spec.coffee +++ b/spec/random-editor-spec.coffee @@ -4,7 +4,7 @@ TextBuffer = require 'text-buffer' TextEditor = require '../src/text-editor' describe "TextEditor", -> - [editor, tokenizedBuffer, buffer, steps, previousSteps] = [] + [editor, tokenizedBuffer, buffer, steps] = [] softWrapColumn = 80 @@ -13,8 +13,6 @@ describe "TextEditor", -> atom.config.set('editor.preferredLineLength', softWrapColumn) it "properly renders soft-wrapped lines when randomly mutated", -> - previousSteps = JSON.parse(localStorage.steps ? '[]') - times 10, (i) -> buffer = new TextBuffer editor = new TextEditor({buffer}) @@ -47,6 +45,9 @@ describe "TextEditor", -> {bufferRows, screenLines} = getReferenceScreenLines() for bufferRow, screenRow in bufferRows console.log screenRow, bufferRow, screenLines[screenRow].text + console.log "==== steps to reproduce this failure: ===" + for step in steps + console.log 'editor.' + step[0] + '('+ step[1..].map((a) -> JSON.stringify(a)).join(', ') + ')' randomlyMutateEditor = -> if Math.random() < .2 @@ -79,34 +80,11 @@ describe "TextEditor", -> text getReferenceScreenLines = -> - if editor.isSoftWrapped() - screenLines = [] - bufferRows = [] - for bufferRow in [0..tokenizedBuffer.getLastRow()] - for screenLine in softWrapLine(tokenizedBuffer.tokenizedLineForRow(bufferRow)) - screenLines.push(screenLine) - bufferRows.push(bufferRow) - else - screenLines = tokenizedBuffer.tokenizedLines.slice() - bufferRows = [0..tokenizedBuffer.getLastRow()] + referenceEditor = new TextEditor({}) + referenceEditor.setEditorWidthInChars(80) + referenceEditor.setText(editor.getText()) + referenceEditor.setSoftWrapped(editor.isSoftWrapped()) + screenLines = referenceEditor.tokenizedLinesForScreenRows(0, referenceEditor.getLastScreenRow()) + bufferRows = referenceEditor.bufferRowsForScreenRows(0, referenceEditor.getLastScreenRow()) + {screenLines, bufferRows} - - softWrapLine = (tokenizedLine) -> - wrappedLines = [] - while tokenizedLine.text.length > softWrapColumn and wrapScreenColumn = findWrapColumn(tokenizedLine.text) - [wrappedLine, tokenizedLine] = tokenizedLine.softWrapAt(wrapScreenColumn) - wrappedLines.push(wrappedLine) - wrappedLines.push(tokenizedLine) - wrappedLines - - findWrapColumn = (line) -> - if /\s/.test(line[softWrapColumn]) - # search forward for the start of a word past the boundary - for column in [softWrapColumn..line.length] - return column if /\S/.test(line[column]) - return line.length - else - # search backward for the start of the word on the boundary - for column in [softWrapColumn..0] - return column + 1 if /\s/.test(line[column]) - return softWrapColumn From 9c74d1084994f2a20a7188cf6030abbdd742efe5 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 19 Mar 2015 15:34:50 -0700 Subject: [PATCH 0234/1783] :arrow_up: text-buffer@5.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 801aac11c..bf610bb2a 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "space-pen": "3.8.2", "stacktrace-parser": "0.1.1", "temp": "0.8.1", - "text-buffer": "^5", + "text-buffer": "^5.0.1", "theorist": "^1.0.2", "underscore-plus": "^1.6.6" }, From 706222ce8ad67d315dbdab31cce0e2c80946a5df Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 19 Mar 2015 15:51:51 -0700 Subject: [PATCH 0235/1783] :arrow_up: apm@0.147 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index a989c7a83..374a7d98a 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.145.0" + "atom-package-manager": "0.147.0" } } From 2efee4a1a79657d3cebbcf4f927f703d226d4677 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 19 Mar 2015 16:06:55 -0700 Subject: [PATCH 0236/1783] :arrow_down: text-buffer@5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bf610bb2a..801aac11c 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "space-pen": "3.8.2", "stacktrace-parser": "0.1.1", "temp": "0.8.1", - "text-buffer": "^5.0.1", + "text-buffer": "^5", "theorist": "^1.0.2", "underscore-plus": "^1.6.6" }, From 679840cada23adec621b25a085c751ab719ef5d9 Mon Sep 17 00:00:00 2001 From: Basarat Syed Date: Fri, 20 Mar 2015 10:58:52 +1100 Subject: [PATCH 0237/1783] chore: remove unneeded dependency --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 9f12fe358..256df223a 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,6 @@ "temp": "0.8.1", "text-buffer": "^4.1.5", "theorist": "^1.0.2", - "typescript": "^1.4.1", "typescript-simple": "^1.0.0", "underscore-plus": "^1.6.6" }, From c4ae567e8f1644a35ecc9212e5d484dc040c253b Mon Sep 17 00:00:00 2001 From: postcasio Date: Fri, 20 Mar 2015 09:19:06 +0000 Subject: [PATCH 0238/1783] Fix deprecated calls and recommendations in deprecated methods --- src/project.coffee | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/project.coffee b/src/project.coffee index 150e28d9a..752de03cc 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -419,7 +419,7 @@ class Project extends Model # Deprecated: delegate registerOpener: (opener) -> deprecate("Use Workspace::addOpener instead") - atom.workspace.registerOpener(opener) + atom.workspace.addOpener(opener) # Deprecated: delegate unregisterOpener: (opener) -> @@ -428,10 +428,10 @@ class Project extends Model # Deprecated: delegate eachEditor: (callback) -> - deprecate("Use Workspace::eachEditor instead") - atom.workspace.eachEditor(callback) + deprecate("Use Workspace::observeTextEditors instead") + atom.workspace.observeTextEditors(callback) # Deprecated: delegate getEditors: -> - deprecate("Use Workspace::getEditors instead") - atom.workspace.getEditors() + deprecate("Use Workspace::getTextEditors instead") + atom.workspace.getTextEditors() From 895686575248808c2bb159c49c067dff98521c45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=C5=BDu=C5=BEak?= Date: Fri, 20 Mar 2015 15:46:55 +0100 Subject: [PATCH 0239/1783] :arrow_up: language-json@0.13 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 801aac11c..1f3be78ed 100644 --- a/package.json +++ b/package.json @@ -134,7 +134,7 @@ "language-hyperlink": "0.12.2", "language-java": "0.14.0", "language-javascript": "0.63.0", - "language-json": "0.12.0", + "language-json": "0.13.0", "language-less": "0.25.0", "language-make": "0.14.0", "language-mustache": "0.11.0", From 6f17a4dae2758f753e636a1a3d61da24ee2e29d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=C5=BDu=C5=BEak?= Date: Fri, 20 Mar 2015 16:00:03 +0100 Subject: [PATCH 0240/1783] :arrow_down: language-json@0.12 See https://github.com/atom/language-json/pull/16 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1f3be78ed..801aac11c 100644 --- a/package.json +++ b/package.json @@ -134,7 +134,7 @@ "language-hyperlink": "0.12.2", "language-java": "0.14.0", "language-javascript": "0.63.0", - "language-json": "0.13.0", + "language-json": "0.12.0", "language-less": "0.25.0", "language-make": "0.14.0", "language-mustache": "0.11.0", From a47744fd4842b8ff72cbab7b266e1f26554c261b Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 20 Mar 2015 10:49:06 -0600 Subject: [PATCH 0241/1783] :arrow_up: text-buffer to 5.0.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 801aac11c..a9faaa391 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "space-pen": "3.8.2", "stacktrace-parser": "0.1.1", "temp": "0.8.1", - "text-buffer": "^5", + "text-buffer": "^5.0.2", "theorist": "^1.0.2", "underscore-plus": "^1.6.6" }, From 6c38562e96821091b743e31c8a4fadd0aa4cd133 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Fri, 20 Mar 2015 16:31:09 -0700 Subject: [PATCH 0242/1783] :arrow_up: feedback@0.35.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a9faaa391..78560289a 100644 --- a/package.json +++ b/package.json @@ -93,7 +93,7 @@ "dev-live-reload": "0.45.0", "encoding-selector": "0.19.0", "exception-reporting": "0.24.0", - "feedback": "0.34.0", + "feedback": "0.35.0", "find-and-replace": "0.159.0", "fuzzy-finder": "0.72.0", "git-diff": "0.54.0", From a4003f31da2bfae13c54ec7d2fedcc7995c061fe Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 23 Mar 2015 18:03:43 +0800 Subject: [PATCH 0243/1783] :arrow_up: atom-shell@0.22.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 11bc09810..a3078ddc0 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "url": "http://github.com/atom/atom/raw/master/LICENSE.md" } ], - "atomShellVersion": "0.22.1", + "atomShellVersion": "0.22.2", "dependencies": { "async": "0.2.6", "atom-keymap": "^4", From eb6e15790a26f8e68f3073d735510b76bd7e6a34 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 23 Mar 2015 18:24:42 +0800 Subject: [PATCH 0244/1783] :arrow_up: apm@0.148.0 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index 374a7d98a..ccfa1995e 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.147.0" + "atom-package-manager": "0.148.0" } } From 47742768a231cc2a4fc40fe4cb3858bf45ba09f3 Mon Sep 17 00:00:00 2001 From: liuxiong332 Date: Mon, 23 Mar 2015 19:47:05 +0800 Subject: [PATCH 0245/1783] add specs which simulate mouse action in PaneResizeHandleElement to test the resize behavior. --- spec/pane-resize-handle-element-spec.coffee | 98 +++++++++++++++++++++ src/pane-resize-handle-element.coffee | 1 + 2 files changed, 99 insertions(+) create mode 100644 spec/pane-resize-handle-element-spec.coffee diff --git a/spec/pane-resize-handle-element-spec.coffee b/spec/pane-resize-handle-element-spec.coffee new file mode 100644 index 000000000..441be8028 --- /dev/null +++ b/spec/pane-resize-handle-element-spec.coffee @@ -0,0 +1,98 @@ +PaneContainer = require '../src/pane-container' +PaneAxisElement = require '../src/pane-axis-element' +PaneAxis = require '../src/pane-axis.coffee' + +describe "PaneResizeHandleElement", -> + describe "resize", -> + [container, containerElement, resizeElementMove, getElementWidth] = [] + + beforeEach -> + container = new PaneContainer + containerElement = atom.views.getView(container); + containerElement.style.minHeight = 100 + document.querySelector('#jasmine-content').appendChild(containerElement) + + resizeElementMove = (resizeElement, clientX, clientY) -> + mouseDownEvent = new MouseEvent 'mousedown', + { view: window, bubbles: true, button: 0 } + resizeElement.dispatchEvent(mouseDownEvent) + + mouseMoveEvent = new MouseEvent 'mousemove', + { view: window, bubbles: true, clientX: clientX, clientY: clientY} + resizeElement.dispatchEvent(mouseMoveEvent) + + mouseUpEvent = new MouseEvent 'mouseup', + {view: window, bubbles: true, button: 0} + resizeElement.dispatchEvent(mouseUpEvent) + + getElementWidth = (element) -> + element.getBoundingClientRect().width + + it "drag the pane resize handle element, then the panes around it will resize", -> + activePane = container.getActivePane() + rightPane = activePane.splitRight() + + resizeElement = containerElement.querySelector('atom-pane-resize-handle') + expect(resizeElement).toBeTruthy() + + leftWidth = resizeElement.previousSibling.getBoundingClientRect().width + resizeElementMove(resizeElement, leftWidth/2, 0) + expect(activePane.getFlexScale()).toBeCloseTo(0.5, 0.1) + expect(rightPane.getFlexScale()).toBeCloseTo(1.5, 0.1) + + downPane = activePane.splitDown() + # after split down, the horizontal panes retain + expect(rightPane.getFlexScale()).toBeCloseTo(1.5, 0.1) + + it "drag the resize element, the size of other panes in the same direction will not change", -> + leftPane = container.getActivePane() + middlePane = leftPane.splitRight() + rightPane = middlePane.splitRight() + + resizeElements = containerElement.querySelectorAll('atom-pane-resize-handle') + paneElements = containerElement.querySelectorAll('atom-pane') + expect(resizeElements.length).toBe(2) + + expectPaneScale = (leftScale, middleScale, rightScale) -> + expect(leftPane.getFlexScale()).toBeCloseTo(leftScale, 0.1) + expect(middlePane.getFlexScale()).toBeCloseTo(middleScale, 0.1) + expect(rightPane.getFlexScale()).toBeCloseTo(rightScale, 0.1) + + resizeElementMove(resizeElements[0], getElementWidth(paneElements[0]) / 2) + expectPaneScale(0.5, 1.5, 1) + + clientX = getElementWidth(paneElements[0]) + getElementWidth(paneElements[1]) / 2 + resizeElementMove(resizeElements[1], clientX) + expectPaneScale(0.5, 0.75, 1.75) + + it "drag the horizontal element, the size of other vertical pane will not change", -> + upPane = container.getActivePane() + downPane = upPane.splitDown() + + [upRightPane, upLeftPane] = [upPane.splitRight(), upPane] + upPane = upLeftPane.getParent() + + [downRightPane, downLeftPane] = [downPane.splitRight(), downPane] + downPane = downLeftPane.getParent() + + horizontalResizeElements = containerElement.querySelectorAll('atom-pane-resize-handle.horizontal') + verticalResizeElement = containerElement.querySelector('atom-pane-resize-handle.vertical') + expect(horizontalResizeElements.length).toBe(2) + + expectCloseTo = (element, scale) -> + expect(element.getFlexScale()).toBeCloseTo(scale, 0.1) + + expectPaneScale = (up, down, upLeft, upRight, downLeft, downRight) -> + paneScales = [ + [upPane, up], [downPane, down], [upLeftPane, upLeft], + [upRightPane, upRight], [downLeftPane, downLeft], [downRightPane, downRight] + ] + expectCloseTo(e[0], e[1]) for e in paneScales + + newWidth = getElementWidth(horizontalResizeElements[0].previousSibling) / 2 + resizeElementMove(horizontalResizeElements[0], newWidth) + expectPaneScale(1, 1, 0.5, 1.5, 1, 1) + + newWidth = getElementWidth(horizontalResizeElements[1].previousSibling) / 2 + resizeElementMove(horizontalResizeElements[1], newWidth) + expectPaneScale(1, 1, 0.5, 1.5, 0.5, 1.5) diff --git a/src/pane-resize-handle-element.coffee b/src/pane-resize-handle-element.coffee index 74b2a1989..80daecdd8 100644 --- a/src/pane-resize-handle-element.coffee +++ b/src/pane-resize-handle-element.coffee @@ -10,6 +10,7 @@ class PaneResizeHandleElement extends HTMLElement attachedCallback: -> @isHorizontal = @parentElement.classList.contains("horizontal") + @classList.add if @isHorizontal then 'horizontal' else 'vertical' resizeToFitContent: -> # clear flex-grow css style of both pane From e54c5b0cb87a46943ff3598de4e36b773fbca91f Mon Sep 17 00:00:00 2001 From: liuxiong332 Date: Mon, 23 Mar 2015 20:04:35 +0800 Subject: [PATCH 0246/1783] delete some not used statement --- spec/pane-resize-handle-element-spec.coffee | 4 ---- 1 file changed, 4 deletions(-) diff --git a/spec/pane-resize-handle-element-spec.coffee b/spec/pane-resize-handle-element-spec.coffee index 441be8028..40288250d 100644 --- a/spec/pane-resize-handle-element-spec.coffee +++ b/spec/pane-resize-handle-element-spec.coffee @@ -1,6 +1,4 @@ PaneContainer = require '../src/pane-container' -PaneAxisElement = require '../src/pane-axis-element' -PaneAxis = require '../src/pane-axis.coffee' describe "PaneResizeHandleElement", -> describe "resize", -> @@ -9,7 +7,6 @@ describe "PaneResizeHandleElement", -> beforeEach -> container = new PaneContainer containerElement = atom.views.getView(container); - containerElement.style.minHeight = 100 document.querySelector('#jasmine-content').appendChild(containerElement) resizeElementMove = (resizeElement, clientX, clientY) -> @@ -76,7 +73,6 @@ describe "PaneResizeHandleElement", -> downPane = downLeftPane.getParent() horizontalResizeElements = containerElement.querySelectorAll('atom-pane-resize-handle.horizontal') - verticalResizeElement = containerElement.querySelector('atom-pane-resize-handle.vertical') expect(horizontalResizeElements.length).toBe(2) expectCloseTo = (element, scale) -> From 78f760aa08a6af7f3ace450b176721fbf7858e1b Mon Sep 17 00:00:00 2001 From: liuxiong332 Date: Mon, 23 Mar 2015 20:47:20 +0800 Subject: [PATCH 0247/1783] make pane resize behavior be valid when split or close panes dynamically. --- spec/pane-resize-handle-element-spec.coffee | 37 +++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/spec/pane-resize-handle-element-spec.coffee b/spec/pane-resize-handle-element-spec.coffee index 40288250d..f4ad2c166 100644 --- a/spec/pane-resize-handle-element-spec.coffee +++ b/spec/pane-resize-handle-element-spec.coffee @@ -92,3 +92,40 @@ describe "PaneResizeHandleElement", -> newWidth = getElementWidth(horizontalResizeElements[1].previousSibling) / 2 resizeElementMove(horizontalResizeElements[1], newWidth) expectPaneScale(1, 1, 0.5, 1.5, 0.5, 1.5) + + it "transform the flex scale when dynamically split or close panes in the same direction", -> + leftPane = container.getActivePane() + middlePane = leftPane.splitRight() + rightPane = middlePane.splitRight() + + expectPaneScale = (leftScale, middleScale, rightScale) -> + paneScales = [[leftPane, leftScale], [middlePane, middleScale], [rightPane, rightScale]]; + expect(e[0].getFlexScale()).toBeCloseTo(e[1], 0.1) for e in paneScales + + resizeElement = containerElement.querySelector('atom-pane-resize-handle') + resizeElementMove(resizeElement, getElementWidth(atom.views.getView(leftPane)) / 2) + expectPaneScale(0.5, 1.5, 1) + + leftPane.close() + expect(middlePane.getFlexScale()).toBeCloseTo(1.2, 0.1) + expect(rightPane.getFlexScale()).toBeCloseTo(0.8, 0.1) + + rightPane.close() # when close the same direction pane, the flexScale will recorver + expect(middlePane.getFlexScale()).toBeCloseTo(1, 0.1) + + it "change the flex scale when dynamically split or close panes in orthogonal direction", -> + leftPane = container.getActivePane() + rightPane = leftPane.splitRight() + + resizeElement = containerElement.querySelector('atom-pane-resize-handle') + resizeElementMove(resizeElement, getElementWidth(resizeElement.previousSibling) / 2) + expect(leftPane.getFlexScale()).toBeCloseTo(0.5, 0.1) + + downPane = leftPane.splitDown() # dynamically split pane, pane's flexScale will become to 1 + expect(leftPane.getFlexScale()).toBeCloseTo(1, 0.1) + expect(leftPane.getParent().getFlexScale()).toBeCloseTo(0.5, 0.1) + + downPane.close() # dynamically close pane, the pane's flexscale will recorver to origin value + expect(leftPane.getFlexScale()).toBeCloseTo(0.5, 0.1) + + From d50e051c191c48c99cfdb6f68a86d609a9834576 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 23 Mar 2015 09:31:35 -0700 Subject: [PATCH 0248/1783] :arrow_up: language-html@0.30 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 78560289a..2abad0f5e 100644 --- a/package.json +++ b/package.json @@ -130,7 +130,7 @@ "language-gfm": "0.67.0", "language-git": "0.10.0", "language-go": "0.22.0", - "language-html": "0.29.0", + "language-html": "0.30.0", "language-hyperlink": "0.12.2", "language-java": "0.14.0", "language-javascript": "0.63.0", From 5840eacf577eed608552f7b93ea67b13019d33a1 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 23 Mar 2015 09:32:53 -0700 Subject: [PATCH 0249/1783] :arrow_up: language-json@0.14 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2abad0f5e..e9bce42a8 100644 --- a/package.json +++ b/package.json @@ -134,7 +134,7 @@ "language-hyperlink": "0.12.2", "language-java": "0.14.0", "language-javascript": "0.63.0", - "language-json": "0.12.0", + "language-json": "0.14.0", "language-less": "0.25.0", "language-make": "0.14.0", "language-mustache": "0.11.0", From 7bdd456a4d8e815219d9f629703b5a2defcac625 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 23 Mar 2015 09:34:52 -0700 Subject: [PATCH 0250/1783] :arrow_up: status-bar@0.64 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e9bce42a8..a857370ad 100644 --- a/package.json +++ b/package.json @@ -112,7 +112,7 @@ "settings-view": "0.185.0", "snippets": "0.84.0", "spell-check": "0.55.0", - "status-bar": "0.63.0", + "status-bar": "0.64.0", "styleguide": "0.44.0", "symbols-view": "0.91.0", "tabs": "0.67.0", From 9700561fb94c84462a01c3b976f3877f0d3774be Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 23 Mar 2015 09:35:07 -0700 Subject: [PATCH 0251/1783] :arrow_up: fs-plus@2.6 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a857370ad..284b88c29 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "emissary": "^1.3.3", "event-kit": "^1.0.3", "first-mate": "^3.0.0", - "fs-plus": "^2.5", + "fs-plus": "^2.6", "fstream": "0.1.24", "fuzzaldrin": "^2.1", "git-utils": "^3.0.0", From d30f614718ecdc6b9406f2a61cfa05c07691bed6 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 23 Mar 2015 09:35:29 -0700 Subject: [PATCH 0252/1783] :arrow_up: oniguruma@4.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 284b88c29..fc0712886 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "marked": "^0.3", "mixto": "^1", "nslog": "^2.0.0", - "oniguruma": "^4.0.0", + "oniguruma": "^4.1", "optimist": "0.4.0", "pathwatcher": "^4.3.1", "property-accessors": "^1.1.3", From 5b346da58d153be63b61aa21fea28891e421690e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 23 Mar 2015 09:37:15 -0700 Subject: [PATCH 0253/1783] :arrow_up: language-perl@0.20 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fc0712886..73a4f7467 100644 --- a/package.json +++ b/package.json @@ -139,7 +139,7 @@ "language-make": "0.14.0", "language-mustache": "0.11.0", "language-objective-c": "0.15.0", - "language-perl": "0.19.0", + "language-perl": "0.20.0", "language-php": "0.21.0", "language-property-list": "0.8.0", "language-python": "0.32.0", From 6d4ab5087e0eb5cd86db14cb9e7df3d8378005ff Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 23 Mar 2015 10:06:27 -0700 Subject: [PATCH 0254/1783] :arrow_up: language-perl@0.21 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 73a4f7467..f73a58ffc 100644 --- a/package.json +++ b/package.json @@ -139,7 +139,7 @@ "language-make": "0.14.0", "language-mustache": "0.11.0", "language-objective-c": "0.15.0", - "language-perl": "0.20.0", + "language-perl": "0.21.0", "language-php": "0.21.0", "language-property-list": "0.8.0", "language-python": "0.32.0", From f875cdcba54aefae2345fa018de0dab862035922 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Mon, 23 Mar 2015 11:28:52 -0700 Subject: [PATCH 0255/1783] :arrow_up: markdown-preview@0.144.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f73a58ffc..f3b3252b5 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,7 @@ "incompatible-packages": "0.24.0", "keybinding-resolver": "0.29.0", "link": "0.30.0", - "markdown-preview": "0.143.0", + "markdown-preview": "0.144.0", "metrics": "0.45.0", "notifications": "0.33.0", "open-on-github": "0.34.0", From 14316b1cd744f50ecb42bba86096269c26115236 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Mon, 23 Mar 2015 15:38:38 -0700 Subject: [PATCH 0256/1783] Add `Repository::getType()`. For `GitRepository`, this will return `"git"`. --- spec/git-repository-provider-spec.coffee | 1 + src/git-repository.coffee | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/spec/git-repository-provider-spec.coffee b/spec/git-repository-provider-spec.coffee index 59e3f55af..15e1dcc60 100644 --- a/spec/git-repository-provider-spec.coffee +++ b/spec/git-repository-provider-spec.coffee @@ -16,6 +16,7 @@ describe "GitRepositoryProvider", -> expect(result).toBeInstanceOf GitRepository expect(provider.pathToRepository[result.getPath()]).toBeTruthy() expect(result.statusTask).toBeTruthy() + expect(result.getType()).toBe 'git' it "returns the same GitRepository for different Directory objects in the same repo", -> provider = new GitRepositoryProvider atom.project diff --git a/src/git-repository.coffee b/src/git-repository.coffee index c4a9d34f5..ae10e7459 100644 --- a/src/git-repository.coffee +++ b/src/git-repository.coffee @@ -169,6 +169,12 @@ class GitRepository Section: Repository Details ### + # Public: A {String} indicating the type of version control system used by + # this repository. + # + # Returns `"git"`. + getType: -> 'git' + # Public: Returns the {String} path of the repository. getPath: -> @path ?= fs.absolute(@getRepo().getPath()) From 2620c95d86dc98aae2f5730a193f23c7ff46f803 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 24 Mar 2015 12:06:03 +0800 Subject: [PATCH 0257/1783] String.contains is not a standard method in Chrome 41 --- spec/default-directory-provider-spec.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/default-directory-provider-spec.coffee b/spec/default-directory-provider-spec.coffee index 780f2afd5..236283d27 100644 --- a/spec/default-directory-provider-spec.coffee +++ b/spec/default-directory-provider-spec.coffee @@ -15,8 +15,8 @@ describe "DefaultDirectoryProvider", -> provider = new DefaultDirectoryProvider() tmp = temp.mkdirSync() nonNormalizedPath = tmp + path.sep + ".." + path.sep + path.basename(tmp) - expect(tmp.contains("..")).toBe false - expect(nonNormalizedPath.contains("..")).toBe true + expect(tmp.includes("..")).toBe false + expect(nonNormalizedPath.includes("..")).toBe true directory = provider.directoryForURISync(nonNormalizedPath) expect(directory.getPath()).toEqual tmp From 6f1b061dac48210f46335d28769fa03dc103ffa0 Mon Sep 17 00:00:00 2001 From: Basarat Syed Date: Tue, 24 Mar 2015 18:05:30 +1100 Subject: [PATCH 0258/1783] Added TypeScript to the compile-cache --- spec/compile-cache-spec.coffee | 13 ++++++++++++- src/compile-cache.coffee | 4 ++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/spec/compile-cache-spec.coffee b/spec/compile-cache-spec.coffee index 534457157..6eb6556d0 100644 --- a/spec/compile-cache-spec.coffee +++ b/spec/compile-cache-spec.coffee @@ -3,26 +3,37 @@ CSON = require 'season' CoffeeCache = require 'coffee-cash' babel = require '../src/babel' +typescript = require '../src/typescript' CompileCache = require '../src/compile-cache' describe "Compile Cache", -> describe ".addPathToCache(filePath)", -> - it "adds the path to the correct CSON, CoffeeScript, or babel cache", -> + it "adds the path to the correct CSON, CoffeeScript, babel or typescript cache", -> spyOn(CSON, 'readFileSync').andCallThrough() spyOn(CoffeeCache, 'addPathToCache').andCallThrough() spyOn(babel, 'addPathToCache').andCallThrough() + spyOn(typescript, 'addPathToCache').andCallThrough() CompileCache.addPathToCache(path.join(__dirname, 'fixtures', 'cson.cson')) expect(CSON.readFileSync.callCount).toBe 1 expect(CoffeeCache.addPathToCache.callCount).toBe 0 expect(babel.addPathToCache.callCount).toBe 0 + expect(typescript.addPathToCache.callCount).toBe 0 CompileCache.addPathToCache(path.join(__dirname, 'fixtures', 'coffee.coffee')) expect(CSON.readFileSync.callCount).toBe 1 expect(CoffeeCache.addPathToCache.callCount).toBe 1 expect(babel.addPathToCache.callCount).toBe 0 + expect(typescript.addPathToCache.callCount).toBe 0 CompileCache.addPathToCache(path.join(__dirname, 'fixtures', 'babel', 'babel-double-quotes.js')) expect(CSON.readFileSync.callCount).toBe 1 expect(CoffeeCache.addPathToCache.callCount).toBe 1 expect(babel.addPathToCache.callCount).toBe 1 + expect(typescript.addPathToCache.callCount).toBe 0 + + CompileCache.addPathToCache(path.join(__dirname, 'fixtures', 'typescript', 'valid.ts')) + expect(CSON.readFileSync.callCount).toBe 1 + expect(CoffeeCache.addPathToCache.callCount).toBe 1 + expect(babel.addPathToCache.callCount).toBe 1 + expect(typescript.addPathToCache.callCount).toBe 1 diff --git a/src/compile-cache.coffee b/src/compile-cache.coffee index c31f5bdd1..8fe8d6711 100644 --- a/src/compile-cache.coffee +++ b/src/compile-cache.coffee @@ -2,6 +2,7 @@ path = require 'path' CSON = require 'season' CoffeeCache = require 'coffee-cash' babel = require './babel' +typescript = require './typescript' # This file is required directly by apm so that files can be cached during # package install so that the first package load in Atom doesn't have to @@ -16,6 +17,7 @@ exports.addPathToCache = (filePath, atomHome) -> CoffeeCache.setCacheDirectory(path.join(cacheDir, 'coffee')) CSON.setCacheDir(path.join(cacheDir, 'cson')) babel.setCacheDirectory(path.join(cacheDir, 'js', 'babel')) + typescript.setCacheDirectory(path.join(cacheDir, 'ts')) switch path.extname(filePath) when '.coffee' @@ -24,3 +26,5 @@ exports.addPathToCache = (filePath, atomHome) -> CSON.readFileSync(filePath) when '.js' babel.addPathToCache(filePath) + when '.ts' + typescript.addPathToCache(filePath) From 1a73d4cb229f27f96279bf03d3af16e2b2d9fd09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=C5=BDu=C5=BEak?= Date: Tue, 24 Mar 2015 14:22:05 +0100 Subject: [PATCH 0259/1783] :arrow_up: snippets@0.85.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f3b3252b5..4753fe11d 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "package-generator": "0.38.0", "release-notes": "0.52.0", "settings-view": "0.185.0", - "snippets": "0.84.0", + "snippets": "0.85.0", "spell-check": "0.55.0", "status-bar": "0.64.0", "styleguide": "0.44.0", From 37be2e02ec3d3a3052ffc687a5f73cbd38d9522f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 24 Mar 2015 11:12:29 -0700 Subject: [PATCH 0260/1783] :arrow_up: language-javascript@0.64 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4753fe11d..237e487cf 100644 --- a/package.json +++ b/package.json @@ -133,7 +133,7 @@ "language-html": "0.30.0", "language-hyperlink": "0.12.2", "language-java": "0.14.0", - "language-javascript": "0.63.0", + "language-javascript": "0.64.0", "language-json": "0.14.0", "language-less": "0.25.0", "language-make": "0.14.0", From 63e6df8022d6872624751f93c5714eb3feb9bbb5 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 24 Mar 2015 13:12:49 -0700 Subject: [PATCH 0261/1783] Move .npmrc file to build folder apm commands appear to be picking it up as a config file when bootstrapping from the root of the repo causing cache clashes between build modules and core packages. --- .npmrc => build/.npmrc | 0 script/bootstrap | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename .npmrc => build/.npmrc (100%) diff --git a/.npmrc b/build/.npmrc similarity index 100% rename from .npmrc rename to build/.npmrc diff --git a/script/bootstrap b/script/bootstrap index 270abff7c..4c9435852 100755 --- a/script/bootstrap +++ b/script/bootstrap @@ -35,7 +35,7 @@ function bootstrap() { var npmPath = path.resolve(__dirname, '..', 'build', 'node_modules', '.bin', 'npm'); var initialNpmCommand = fs.existsSync(npmPath) ? npmPath : 'npm'; - var npmFlags = ' --userconfig=' + path.resolve('.npmrc') + ' '; + var npmFlags = ' --userconfig=' + path.resolve(__dirname, '..', 'build', '.npmrc') + ' '; var packagesToDedupe = [ 'abbrev', From 40b4e36c0975847748a61400d67d319769f76576 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 23 Mar 2015 14:00:16 -0700 Subject: [PATCH 0262/1783] Add custom formatting for Less errors --- src/package.coffee | 8 ++++++++ src/theme-manager.coffee | 3 +++ 2 files changed, 11 insertions(+) diff --git a/src/package.coffee b/src/package.coffee index 8b63b50a8..aa6afc3ce 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -572,6 +572,14 @@ class Package SyntaxError: #{error.message} at #{location} """ + else if error.type and error.filename and error.column? and error.line? + # Less errors + location = "#{error.filename}:#{error.line}:#{error.column}" + detail = "#{error.message} in #{location}" + stack = """ + Error: #{error.message} + at #{location} + """ else detail = error.message stack = error.stack ? error diff --git a/src/theme-manager.coffee b/src/theme-manager.coffee index 650c1d168..f6025d4d4 100644 --- a/src/theme-manager.coffee +++ b/src/theme-manager.coffee @@ -319,6 +319,9 @@ class ThemeManager @lessCache.read(lessStylesheetPath) catch error if error.line? + # Adjust line numbers for import fallbacks + error.line -= 2 if importFallbackVariables + message = "Error compiling Less stylesheet: `#{lessStylesheetPath}`" detail = """ Line number: #{error.line} From af111651f328cc48633be603d50ea968ad95ba77 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 23 Mar 2015 16:25:56 -0700 Subject: [PATCH 0263/1783] :arrow_up: notifications@0.34 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 237e487cf..1d57689b7 100644 --- a/package.json +++ b/package.json @@ -105,7 +105,7 @@ "link": "0.30.0", "markdown-preview": "0.144.0", "metrics": "0.45.0", - "notifications": "0.33.0", + "notifications": "0.34.0", "open-on-github": "0.34.0", "package-generator": "0.38.0", "release-notes": "0.52.0", From ddae58bd9981ce3028a90615b1df4c8dcd22bb21 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 23 Mar 2015 16:55:47 -0700 Subject: [PATCH 0264/1783] :arrow_up: notifications@0.35 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1d57689b7..fcd9486ee 100644 --- a/package.json +++ b/package.json @@ -105,7 +105,7 @@ "link": "0.30.0", "markdown-preview": "0.144.0", "metrics": "0.45.0", - "notifications": "0.34.0", + "notifications": "0.35.0", "open-on-github": "0.34.0", "package-generator": "0.38.0", "release-notes": "0.52.0", From 27ffac5f1a73dff7914080d5cab7a1179592504e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 24 Mar 2015 08:42:41 -0700 Subject: [PATCH 0265/1783] Set less property on caught error --- src/package.coffee | 4 ++-- src/theme-manager.coffee | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/package.coffee b/src/package.coffee index aa6afc3ce..ebc771123 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -572,12 +572,12 @@ class Package SyntaxError: #{error.message} at #{location} """ - else if error.type and error.filename and error.column? and error.line? + else if error.less and error.filename and error.column? and error.line? # Less errors location = "#{error.filename}:#{error.line}:#{error.column}" detail = "#{error.message} in #{location}" stack = """ - Error: #{error.message} + LessError: #{error.message} at #{location} """ else diff --git a/src/theme-manager.coffee b/src/theme-manager.coffee index f6025d4d4..0ff42c4d2 100644 --- a/src/theme-manager.coffee +++ b/src/theme-manager.coffee @@ -318,6 +318,7 @@ class ThemeManager else @lessCache.read(lessStylesheetPath) catch error + error.less = true if error.line? # Adjust line numbers for import fallbacks error.line -= 2 if importFallbackVariables From 856a6f91f66ecd51a4ba77f41e1bfa9b348f61ae Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 24 Mar 2015 11:06:01 -0700 Subject: [PATCH 0266/1783] :arrow_up: apm@0.149 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index 374a7d98a..544292634 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.147.0" + "atom-package-manager": "0.149.0" } } From c23cfc14a712d58a4504c837cd499163952bba49 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 24 Mar 2015 16:06:31 -0700 Subject: [PATCH 0267/1783] Prepare 0.189 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fcd9486ee..6b0aaaffb 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "0.188.0", + "version": "0.189.0", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From 606ade06b812b99fc8c01d76a5f8458b6789e005 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 24 Mar 2015 16:18:01 -0700 Subject: [PATCH 0268/1783] :arrow_up: open-on-github@0.35 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6b0aaaffb..8ae2b6784 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,7 @@ "markdown-preview": "0.144.0", "metrics": "0.45.0", "notifications": "0.35.0", - "open-on-github": "0.34.0", + "open-on-github": "0.35.0", "package-generator": "0.38.0", "release-notes": "0.52.0", "settings-view": "0.185.0", From 927cdfc14957bfff35bfb899ed56ab2e52fe93c3 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 24 Mar 2015 16:20:00 -0700 Subject: [PATCH 0269/1783] :arrow_up: symbols-view@0.92 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8ae2b6784..7d3382f4f 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "spell-check": "0.55.0", "status-bar": "0.64.0", "styleguide": "0.44.0", - "symbols-view": "0.91.0", + "symbols-view": "0.92.0", "tabs": "0.67.0", "timecop": "0.31.0", "tree-view": "0.168.0", From 869cf2f2006ea1b5e91d581f3c94238a03d24d79 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 24 Mar 2015 16:38:34 -0700 Subject: [PATCH 0270/1783] :arrow_up: open-on-github@0.36 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7d3382f4f..ba6a8a12c 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,7 @@ "markdown-preview": "0.144.0", "metrics": "0.45.0", "notifications": "0.35.0", - "open-on-github": "0.35.0", + "open-on-github": "0.36.0", "package-generator": "0.38.0", "release-notes": "0.52.0", "settings-view": "0.185.0", From 7d66288e1ac3c5db14701fe94db6082fe3e1b608 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Tue, 24 Mar 2015 16:53:58 -0700 Subject: [PATCH 0271/1783] :arrow_up: markdown-preview@0.1450 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ba6a8a12c..5b9cefb8e 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,7 @@ "incompatible-packages": "0.24.0", "keybinding-resolver": "0.29.0", "link": "0.30.0", - "markdown-preview": "0.144.0", + "markdown-preview": "0.145.0", "metrics": "0.45.0", "notifications": "0.35.0", "open-on-github": "0.36.0", From 3e90553180508755037ab74f4a81c3ea7892f1a1 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 25 Mar 2015 09:49:54 +0800 Subject: [PATCH 0272/1783] :arrow_up: apm@0.150.0 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index 544292634..7e4037d74 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.149.0" + "atom-package-manager": "0.150.0" } } From 2421125479e9946e429cd66bf069a966bf9ffdcf Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 16:48:38 -0700 Subject: [PATCH 0273/1783] :arrow_up: welcome@0.26 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ee66a9b42..719e337d1 100644 --- a/package.json +++ b/package.json @@ -119,7 +119,7 @@ "timecop": "0.31.0", "tree-view": "0.168.0", "update-package-dependencies": "0.9.0", - "welcome": "0.25.0", + "welcome": "0.26.0", "whitespace": "0.29.0", "wrap-guide": "0.31.0", "language-c": "0.41.0", From 13f2d9d48149656442e05e217191d98fd6c023cf Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 25 Mar 2015 17:54:42 -0700 Subject: [PATCH 0274/1783] :arrow_up: text-buffer@5.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 719e337d1..47a9a7c29 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "space-pen": "3.8.2", "stacktrace-parser": "0.1.1", "temp": "0.8.1", - "text-buffer": "^5.0.2", + "text-buffer": "^5.1.0", "theorist": "^1.0.2", "underscore-plus": "^1.6.6" }, From c0d4103fef936211236be01dbc1f2849ff39f46c Mon Sep 17 00:00:00 2001 From: "Machiste N. Quintana" Date: Thu, 26 Mar 2015 10:50:12 -0400 Subject: [PATCH 0275/1783] Update set-version-task.coffee Wooo 2015 --- build/tasks/set-version-task.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/tasks/set-version-task.coffee b/build/tasks/set-version-task.coffee index 6f7a68c61..48b6091c4 100644 --- a/build/tasks/set-version-task.coffee +++ b/build/tasks/set-version-task.coffee @@ -46,7 +46,7 @@ module.exports = (grunt) -> strings = CompanyName: 'GitHub, Inc.' FileDescription: 'Atom' - LegalCopyright: 'Copyright (C) 2014 GitHub, Inc. All rights reserved' + LegalCopyright: 'Copyright (C) 2015 GitHub, Inc. All rights reserved' ProductName: 'Atom' ProductVersion: version From 05c53f378e08a24832a6244a166760fb8da5f6a1 Mon Sep 17 00:00:00 2001 From: "Machiste N. Quintana" Date: Thu, 26 Mar 2015 10:52:57 -0400 Subject: [PATCH 0276/1783] Update LICENSE.md :memo: Update copyright --- LICENSE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE.md b/LICENSE.md index 4d231b456..bbb875dc2 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,4 +1,4 @@ -Copyright (c) 2014 GitHub Inc. +Copyright (c) 2015 GitHub Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the From 307e2ad5655139819cd88ac8db64f7ee00c28f3b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Mar 2015 09:04:20 -0700 Subject: [PATCH 0277/1783] :arrow_up: language-sql@0.15 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 47a9a7c29..c67459112 100644 --- a/package.json +++ b/package.json @@ -148,7 +148,7 @@ "language-sass": "0.36.0", "language-shellscript": "0.13.0", "language-source": "0.9.0", - "language-sql": "0.14.0", + "language-sql": "0.15.0", "language-text": "0.6.0", "language-todo": "0.17.0", "language-toml": "0.15.0", From 06da4153e8cb725061f5a9d757d269c9b423f92d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Mar 2015 10:09:15 -0700 Subject: [PATCH 0278/1783] Build on fedora 21 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 76fa18eae..be5624b21 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ # DESCRIPTION: Image to build Atom and create a .rpm file # Base docker image -FROM fedora:20 +FROM fedora:21 # Install dependencies RUN yum install -y \ From dafa40fd4dba56282f82920e7e240711c40fd444 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Mar 2015 10:13:49 -0700 Subject: [PATCH 0279/1783] Try using canonical nodejs npm packages --- Dockerfile | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index be5624b21..c8eca8804 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,11 +12,9 @@ RUN yum install -y \ glibc-devel \ git-core \ libgnome-keyring-devel \ - rpmdevtools - -# Install node -RUN curl -sL https://rpm.nodesource.com/setup | bash - -RUN yum install -y nodejs + rpmdevtools \ + nodejs \ + npm ADD . /atom WORKDIR /atom From ad87ed5c40ef6f9a839575d66179db26a972e559 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Mar 2015 10:23:56 -0700 Subject: [PATCH 0280/1783] Log detected version --- script/utils/verify-requirements.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/utils/verify-requirements.js b/script/utils/verify-requirements.js index 554c27dd0..693af4a2b 100644 --- a/script/utils/verify-requirements.js +++ b/script/utils/verify-requirements.js @@ -57,7 +57,7 @@ function verifyNpm(cb) { var npmMajorVersion = +versionArray[0] || 0; var npmMinorVersion = +versionArray[1] || 0; if (npmMajorVersion === 1 && npmMinorVersion < 4) - cb("npm v1.4+ is required to build Atom."); + cb("npm v1.4+ is required to build Atom. Version " + npmVersion + " was detected"); else cb(null, "npm: v" + npmVersion); }); From a08c939699246472d55c0c30fd13f6baef61f1d5 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Mar 2015 10:25:05 -0700 Subject: [PATCH 0281/1783] Disable npm version check on CI --- script/utils/verify-requirements.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/utils/verify-requirements.js b/script/utils/verify-requirements.js index 693af4a2b..36bf85b21 100644 --- a/script/utils/verify-requirements.js +++ b/script/utils/verify-requirements.js @@ -56,7 +56,7 @@ function verifyNpm(cb) { var versionArray = npmVersion.split('.'); var npmMajorVersion = +versionArray[0] || 0; var npmMinorVersion = +versionArray[1] || 0; - if (npmMajorVersion === 1 && npmMinorVersion < 4) + if (npmMajorVersion === 1 && npmMinorVersion < 4 && !process.env.JANKY_SHA1) cb("npm v1.4+ is required to build Atom. Version " + npmVersion + " was detected"); else cb(null, "npm: v" + npmVersion); From 9bc723f4907dfb16527e9a792753e7fe8609f312 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Mar 2015 10:27:34 -0700 Subject: [PATCH 0282/1783] Upgrade to npm 1.4 on Fedora --- Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Dockerfile b/Dockerfile index c8eca8804..31726e401 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,5 +16,7 @@ RUN yum install -y \ nodejs \ npm +RUN npm install -g npm@1.4.28 + ADD . /atom WORKDIR /atom From 67843c8ebd19f537266e44cfc6af4a923317ebbf Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Mar 2015 10:33:21 -0700 Subject: [PATCH 0283/1783] Remove Janky bypass of npm version check --- script/utils/verify-requirements.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/script/utils/verify-requirements.js b/script/utils/verify-requirements.js index 36bf85b21..890172753 100644 --- a/script/utils/verify-requirements.js +++ b/script/utils/verify-requirements.js @@ -56,8 +56,8 @@ function verifyNpm(cb) { var versionArray = npmVersion.split('.'); var npmMajorVersion = +versionArray[0] || 0; var npmMinorVersion = +versionArray[1] || 0; - if (npmMajorVersion === 1 && npmMinorVersion < 4 && !process.env.JANKY_SHA1) - cb("npm v1.4+ is required to build Atom. Version " + npmVersion + " was detected"); + if (npmMajorVersion === 1 && npmMinorVersion < 4) + cb("npm v1.4+ is required to build Atom. Version " + npmVersion + " was detected."); else cb(null, "npm: v" + npmVersion); }); From 871c32b75dc5aa9cd10610db2e8d1e9995209af7 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Mar 2015 10:38:58 -0700 Subject: [PATCH 0284/1783] Only log install errors --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 31726e401..d792c30c5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,7 +16,7 @@ RUN yum install -y \ nodejs \ npm -RUN npm install -g npm@1.4.28 +RUN npm install -g npm@1.4.28 --loglevel error ADD . /atom WORKDIR /atom From 2f5d97533802ea5f348e2d684d46fe60bf319538 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 26 Mar 2015 11:12:37 -0700 Subject: [PATCH 0285/1783] Remove autoscroll-related legacy editor view support Signed-off-by: Nathan Sobo --- spec/display-buffer-spec.coffee | 10 ++-------- spec/text-editor-spec.coffee | 12 +----------- src/cursor.coffee | 13 ++----------- src/display-buffer.coffee | 14 +++----------- src/selection.coffee | 7 +------ src/text-editor-component.coffee | 1 - src/text-editor.coffee | 8 +++----- 7 files changed, 12 insertions(+), 53 deletions(-) diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index 95f22acca..386cbf062 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -48,7 +48,6 @@ describe "DisplayBuffer", -> expect(displayBuffer.getLineCount()).toBe 100 + originalLineCount it "reassigns the scrollTop if it exceeds the max possible value after lines are removed", -> - displayBuffer.manageScrollPosition = true displayBuffer.setHeight(50) displayBuffer.setLineHeightInPixels(10) displayBuffer.setScrollTop(80) @@ -287,7 +286,6 @@ describe "DisplayBuffer", -> it "sets ::scrollLeft to 0 and keeps it there when soft wrapping is enabled", -> displayBuffer.setDefaultCharWidth(10) displayBuffer.setWidth(85) - displayBuffer.manageScrollPosition = true displayBuffer.setSoftWrapped(false) displayBuffer.setScrollLeft(Infinity) @@ -1174,7 +1172,6 @@ describe "DisplayBuffer", -> describe "::setScrollTop", -> beforeEach -> - displayBuffer.manageScrollPosition = true displayBuffer.setLineHeightInPixels(10) it "disallows negative values", -> @@ -1196,7 +1193,6 @@ describe "DisplayBuffer", -> describe "when editor.scrollPastEnd is false", -> beforeEach -> atom.config.set("editor.scrollPastEnd", false) - displayBuffer.manageScrollPosition = true displayBuffer.setLineHeightInPixels(10) it "does not add the height of the view to the scroll height", -> @@ -1209,7 +1205,6 @@ describe "DisplayBuffer", -> describe "when editor.scrollPastEnd is true", -> beforeEach -> atom.config.set("editor.scrollPastEnd", true) - displayBuffer.manageScrollPosition = true displayBuffer.setLineHeightInPixels(10) it "adds the height of the view to the scroll height", -> @@ -1221,7 +1216,6 @@ describe "DisplayBuffer", -> describe "::setScrollLeft", -> beforeEach -> - displayBuffer.manageScrollPosition = true displayBuffer.setLineHeightInPixels(10) displayBuffer.setDefaultCharWidth(10) @@ -1242,7 +1236,6 @@ describe "DisplayBuffer", -> describe "::scrollToScreenPosition(position, [options])", -> beforeEach -> - displayBuffer.manageScrollPosition = true displayBuffer.setLineHeightInPixels(10) displayBuffer.setDefaultCharWidth(10) displayBuffer.setHorizontalScrollbarHeight(0) @@ -1320,6 +1313,7 @@ describe "DisplayBuffer", -> expect(displayBuffer.getVisibleRowRange()).toEqual [0, 0] it "ends at last buffer row even if there's more space available", -> + displayBuffer.setHeight(150) displayBuffer.setScrollTop(60) - expect(displayBuffer.getVisibleRowRange()).toEqual [6, 13] + expect(displayBuffer.getVisibleRowRange()).toEqual [0, 13] diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index cddb8bdf6..bd412ca98 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -921,7 +921,6 @@ describe "TextEditor", -> describe "autoscroll", -> beforeEach -> - editor.manageScrollPosition = true editor.setVerticalScrollMargin(2) editor.setHorizontalScrollMargin(2) editor.setLineHeightInPixels(10) @@ -1254,7 +1253,6 @@ describe "TextEditor", -> expect(editor.getSelectedBufferRange()).toEqual [[0,0], [2,0]] it "autoscrolls to the selection", -> - editor.manageScrollPosition = true editor.setLineHeightInPixels(10) editor.setDefaultCharWidth(10) editor.setHeight(50) @@ -1523,10 +1521,9 @@ describe "TextEditor", -> describe ".setSelectedBufferRange(range)", -> describe "when the 'autoscroll' option is true", -> it "autoscrolls to the selection", -> - editor.manageScrollPosition = true editor.setLineHeightInPixels(10) editor.setDefaultCharWidth(10) - editor.setHeight(50) + editor.setHeight(70) editor.setWidth(50) editor.setHorizontalScrollbarHeight(0) @@ -1560,8 +1557,6 @@ describe "TextEditor", -> expect(editor.getSelectedBufferRanges()).toEqual [[[0, 0], [0, 0]], [[3, 4], [5, 6]]] it "autoscrolls to the added selection if needed", -> - editor.manageScrollPosition = true - editor.setLineHeightInPixels(10) editor.setDefaultCharWidth(10) editor.setHeight(50) @@ -1922,7 +1917,6 @@ describe "TextEditor", -> expect(cursor2.getBufferPosition()).toEqual [2, 7] it "autoscrolls to the last cursor", -> - editor.manageScrollPosition = true editor.setCursorScreenPosition([1, 2]) editor.addCursorAtScreenPosition([10, 4]) editor.setLineHeightInPixels(10) @@ -4072,8 +4066,6 @@ describe "TextEditor", -> describe ".pageUp/Down()", -> it "scrolls one screen height up or down and moves the cursor one page length", -> - editor.manageScrollPosition = true - editor.setLineHeightInPixels(10) editor.setHeight(50) expect(editor.getScrollHeight()).toBe 130 @@ -4097,8 +4089,6 @@ describe "TextEditor", -> describe ".selectPageUp/Down()", -> it "selects one screen height of text up or down", -> - editor.manageScrollPosition = true - editor.setLineHeightInPixels(10) editor.setHeight(50) expect(editor.getScrollHeight()).toBe 130 diff --git a/src/cursor.coffee b/src/cursor.coffee index 33f50ca9c..2a0665485 100644 --- a/src/cursor.coffee +++ b/src/cursor.coffee @@ -15,7 +15,6 @@ class Cursor extends Model bufferPosition: null goalColumn: null visible: true - needsAutoscroll: null # Instantiated by a {TextEditor} constructor: ({@editor, @marker, id}) -> @@ -30,9 +29,7 @@ class Cursor extends Model {textChanged} = e return if oldHeadScreenPosition.isEqual(newHeadScreenPosition) - # Supports old editor view - @needsAutoscroll ?= @isLastCursor() and !textChanged - @autoscroll() if @editor.manageScrollPosition and @isLastCursor() and textChanged + @autoscroll() if @isLastCursor() and textChanged @goalColumn = null @@ -53,7 +50,6 @@ class Cursor extends Model @emit 'destroyed' @emitter.emit 'did-destroy' @emitter.dispose() - @needsAutoscroll = true destroy: -> @marker.destroy() @@ -600,7 +596,6 @@ class Cursor extends Model setVisible: (visible) -> if @visible != visible @visible = visible - @needsAutoscroll ?= true if @visible and @isLastCursor() @emit 'visibility-changed', @visible @emitter.emit 'did-change-visibility', @visible @@ -628,7 +623,6 @@ class Cursor extends Model # Public: Prevents this cursor from causing scrolling. clearAutoscroll: -> - @needsAutoscroll = null # Public: Deselects the current selection. clearSelection: -> @@ -656,11 +650,8 @@ class Cursor extends Model changePosition: (options, fn) -> @clearSelection() - @needsAutoscroll = options.autoscroll ? @isLastCursor() fn() - if @needsAutoscroll - @emit 'autoscrolled' # Support legacy editor - @autoscroll() if @needsAutoscroll and @editor.manageScrollPosition # Support react editor view + @autoscroll() if options.autoscroll ? @isLastCursor() getPixelRect: -> @editor.pixelRectForScreenRange(@getScreenRange()) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index 4ab65d0f7..059d04909 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -22,7 +22,6 @@ class DisplayBuffer extends Model Serializable.includeInto(this) @properties - manageScrollPosition: false softWrapped: null editorWidthInChars: null lineHeightInPixels: null @@ -268,10 +267,7 @@ class DisplayBuffer extends Model getScrollTop: -> @scrollTop setScrollTop: (scrollTop) -> - if @manageScrollPosition - @scrollTop = Math.round(Math.max(0, Math.min(@getMaxScrollTop(), scrollTop))) - else - @scrollTop = Math.round(scrollTop) + @scrollTop = Math.round(Math.max(0, Math.min(@getMaxScrollTop(), scrollTop))) getMaxScrollTop: -> @getScrollHeight() - @getClientHeight() @@ -283,11 +279,7 @@ class DisplayBuffer extends Model getScrollLeft: -> @scrollLeft setScrollLeft: (scrollLeft) -> - if @manageScrollPosition - @scrollLeft = Math.round(Math.max(0, Math.min(@getScrollWidth() - @getClientWidth(), scrollLeft))) - @scrollLeft - else - @scrollLeft = Math.round(scrollLeft) + @scrollLeft = Math.round(Math.max(0, Math.min(@getScrollWidth() - @getClientWidth(), scrollLeft))) getMaxScrollLeft: -> @getScrollWidth() - @getClientWidth() @@ -1113,7 +1105,7 @@ class DisplayBuffer extends Model handleTokenizedBufferChange: (tokenizedBufferChange) => {start, end, delta, bufferChange} = tokenizedBufferChange @updateScreenLines(start, end + 1, delta, delayChangeEvent: bufferChange?) - @setScrollTop(Math.min(@getScrollTop(), @getMaxScrollTop())) if @manageScrollPosition and delta < 0 + @setScrollTop(Math.min(@getScrollTop(), @getMaxScrollTop())) if delta < 0 updateScreenLines: (startBufferRow, endBufferRow, bufferDelta=0, options={}) -> startBufferRow = @rowMap.bufferRowRangeForBufferRow(startBufferRow)[0] diff --git a/src/selection.coffee b/src/selection.coffee index 375498c41..524f1bd9b 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -14,7 +14,6 @@ class Selection extends Model editor: null initialScreenRange: null wordwise: false - needsAutoscroll: null constructor: ({@cursor, @marker, @editor, id}) -> @emitter = new Emitter @@ -100,15 +99,13 @@ class Selection extends Model # * `autoscroll` if `true`, the {TextEditor} scrolls to the new selection. setBufferRange: (bufferRange, options={}) -> bufferRange = Range.fromObject(bufferRange) - @needsAutoscroll = options.autoscroll options.reversed ?= @isReversed() @editor.destroyFoldsContainingBufferRange(bufferRange) unless options.preserveFolds @modifySelection => needsFlash = options.flash delete options.flash if options.flash? - @cursor.needsAutoscroll = false if @needsAutoscroll? @marker.setBufferRange(bufferRange, options) - @autoscroll() if @needsAutoscroll and @editor.manageScrollPosition + @autoscroll() if options.autoscroll @decoration.flash('flash', @editor.selectionFlashDuration) if needsFlash # Public: Returns the starting and ending buffer rows the selection is @@ -359,7 +356,6 @@ class Selection extends Model @editor.unfoldBufferRow(oldBufferRange.end.row) wasReversed = @isReversed() @clear() - @cursor.needsAutoscroll = @cursor.isLastCursor() autoIndentFirstLine = false precedingText = @editor.getTextInRange([[oldBufferRange.start.row, 0], oldBufferRange.start]) @@ -758,7 +754,6 @@ class Selection extends Model @editor.scrollToScreenRange(@getScreenRange()) clearAutoscroll: -> - @needsAutoscroll = null modifySelection: (fn) -> @retainSelection = true diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 75a9a5136..63a7f9a1c 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -39,7 +39,6 @@ class TextEditorComponent @lineOverdrawMargin = lineOverdrawMargin if lineOverdrawMargin? @disposables = new CompositeDisposable - @editor.manageScrollPosition = true @observeConfig() @setScrollSensitivity(atom.config.get('editor.scrollSensitivity')) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 6ccb97392..114df486a 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -76,7 +76,7 @@ class TextEditor extends Model @delegatesProperties '$lineHeightInPixels', '$defaultCharWidth', '$height', '$width', '$verticalScrollbarWidth', '$horizontalScrollbarHeight', '$scrollTop', '$scrollLeft', - 'manageScrollPosition', toProperty: 'displayBuffer' + toProperty: 'displayBuffer' constructor: ({@softTabs, initialLine, initialColumn, tabLength, softWrapped, @displayBuffer, buffer, registerEditor, suppressCursorCreation, @mini, @placeholderText, @gutterVisible}) -> super @@ -1132,12 +1132,10 @@ class TextEditor extends Model # Essential: Undo the last change. undo: -> - @getLastCursor().needsAutoscroll = true @buffer.undo(this) # Essential: Redo the last change. redo: -> - @getLastCursor().needsAutoscroll = true @buffer.redo(this) # Extended: Batch multiple operations as a single undo/redo step. @@ -1950,7 +1948,7 @@ class TextEditor extends Model addSelectionForBufferRange: (bufferRange, options={}) -> @markBufferRange(bufferRange, _.defaults(@getSelectionMarkerAttributes(), options)) selection = @getLastSelection() - selection.autoscroll() if @manageScrollPosition + selection.autoscroll() selection # Essential: Add a selection for the given range in screen coordinates. @@ -1964,7 +1962,7 @@ class TextEditor extends Model addSelectionForScreenRange: (screenRange, options={}) -> @markScreenRange(screenRange, _.defaults(@getSelectionMarkerAttributes(), options)) selection = @getLastSelection() - selection.autoscroll() if @manageScrollPosition + selection.autoscroll() selection # Essential: Select from the current cursor position to the given position in From e2f3ecf156e5c28453c88dd51c4a19e5e4d3a0fd Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Mar 2015 12:18:08 -0700 Subject: [PATCH 0286/1783] :arrow_up: snippets@0.86 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c67459112..64ee17f6e 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "package-generator": "0.38.0", "release-notes": "0.52.0", "settings-view": "0.185.0", - "snippets": "0.85.0", + "snippets": "0.86.0", "spell-check": "0.55.0", "status-bar": "0.64.0", "styleguide": "0.44.0", From 3deb16b522e63794435a43ba5851daad14524e58 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Mar 2015 12:33:32 -0700 Subject: [PATCH 0287/1783] Set log level to error npm install --- script/cibuild | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/cibuild b/script/cibuild index af5f789e1..c63d5dbf6 100755 --- a/script/cibuild +++ b/script/cibuild @@ -48,7 +48,7 @@ function removeNodeModules() { readEnvironmentVariables(); removeNodeModules(); -cp.safeExec.bind(global, 'npm install npm', {cwd: path.resolve(__dirname, '..', 'build')}, function() { +cp.safeExec.bind(global, 'npm install npm --loglevel error', {cwd: path.resolve(__dirname, '..', 'build')}, function() { cp.safeExec.bind(global, 'node script/bootstrap', function(error) { if (error) process.exit(1); From d9527fd8add798aaf87364d0adee6d5d3123941b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Mar 2015 12:59:38 -0700 Subject: [PATCH 0288/1783] :arrow_up: apm@0.151 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index 7e4037d74..f43d9e024 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.150.0" + "atom-package-manager": "0.151.0" } } From 45afc9eb463613ab2cd70bd46afdfd8adcb44188 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Mar 2015 13:29:30 -0700 Subject: [PATCH 0289/1783] Handle EISDIR save errors Closes #6100 --- src/pane.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pane.coffee b/src/pane.coffee index a1239acb5..a6e456d6a 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -686,7 +686,7 @@ class Pane extends Model true handleSaveError: (error) -> - if error.message.endsWith('is a directory') + if error.code is 'EISDIR' or error.message.endsWith('is a directory') atom.notifications.addWarning("Unable to save file: #{error.message}") else if error.code is 'EACCES' and error.path? atom.notifications.addWarning("Unable to save file: Permission denied '#{error.path}'") From b6d0099242a5f834abbe9fe0eb9c532b031027fd Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Mar 2015 13:46:08 -0700 Subject: [PATCH 0290/1783] :arrow_up: symbols-view@0.93 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 64ee17f6e..ebb5997bd 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "spell-check": "0.55.0", "status-bar": "0.64.0", "styleguide": "0.44.0", - "symbols-view": "0.92.0", + "symbols-view": "0.93.0", "tabs": "0.67.0", "timecop": "0.31.0", "tree-view": "0.168.0", From 6d827f31d0b0cdc227672e32ce3b677ded8b3f0f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Mar 2015 13:55:59 -0700 Subject: [PATCH 0291/1783] :arrow_up: language-ruby@0.50 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ebb5997bd..97b20430a 100644 --- a/package.json +++ b/package.json @@ -143,7 +143,7 @@ "language-php": "0.21.0", "language-property-list": "0.8.0", "language-python": "0.32.0", - "language-ruby": "0.49.0", + "language-ruby": "0.50.0", "language-ruby-on-rails": "0.21.0", "language-sass": "0.36.0", "language-shellscript": "0.13.0", From 10458a5b454b09a54ac9133434ece18beeb13739 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 26 Mar 2015 15:30:53 -0600 Subject: [PATCH 0292/1783] Always autoscroll when the range of the last selection changes Signed-off-by: Max Brunsfeld --- spec/display-buffer-spec.coffee | 6 ++- spec/text-editor-presenter-spec.coffee | 4 +- spec/text-editor-spec.coffee | 46 ++++++++++++--------- src/cursor.coffee | 4 +- src/display-buffer.coffee | 56 ++++++++++++++++++-------- src/selection.coffee | 8 +++- src/text-editor.coffee | 11 +++-- 7 files changed, 85 insertions(+), 50 deletions(-) diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index 386cbf062..2893fd5a4 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -1240,13 +1240,17 @@ describe "DisplayBuffer", -> displayBuffer.setDefaultCharWidth(10) displayBuffer.setHorizontalScrollbarHeight(0) displayBuffer.setHeight(50) - displayBuffer.setWidth(50) + displayBuffer.setWidth(150) it "sets the scroll top and scroll left so the given screen position is in view", -> displayBuffer.scrollToScreenPosition([8, 20]) expect(displayBuffer.getScrollBottom()).toBe (9 + displayBuffer.getVerticalScrollMargin()) * 10 expect(displayBuffer.getScrollRight()).toBe (20 + displayBuffer.getHorizontalScrollMargin()) * 10 + displayBuffer.scrollToScreenPosition([8, 20]) + expect(displayBuffer.getScrollBottom()).toBe (9 + displayBuffer.getVerticalScrollMargin()) * 10 + expect(displayBuffer.getScrollRight()).toBe (20 + displayBuffer.getHorizontalScrollMargin()) * 10 + describe "when the 'center' option is true", -> it "vertically scrolls to center the given position vertically", -> displayBuffer.scrollToScreenPosition([8, 20], center: true) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 4ad319cc1..0cf0c7e53 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -351,11 +351,11 @@ describe "TextEditorPresenter", -> expectValues presenter.getState().hiddenInput, {top: 0, left: 0} expectStateUpdate presenter, -> editor.setCursorBufferPosition([11, 43]) - expectValues presenter.getState().hiddenInput, {top: 50 - 10, left: 300 - 10} + expectValues presenter.getState().hiddenInput, {top: 11 * 10 - editor.getScrollTop(), left: 43 * 10 - editor.getScrollLeft()} newCursor = null expectStateUpdate presenter, -> newCursor = editor.addCursorAtBufferPosition([6, 10]) - expectValues presenter.getState().hiddenInput, {top: (6 * 10) - 40, left: (10 * 10) - 70} + expectValues presenter.getState().hiddenInput, {top: (6 * 10) - editor.getScrollTop(), left: (10 * 10) - editor.getScrollLeft()} expectStateUpdate presenter, -> newCursor.destroy() expectValues presenter.getState().hiddenInput, {top: 50 - 10, left: 300 - 10} diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index bd412ca98..afebf591d 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -1519,23 +1519,28 @@ describe "TextEditor", -> expect(selection1.getScreenRange()).toEqual [[2, 2], [3, 4]] describe ".setSelectedBufferRange(range)", -> - describe "when the 'autoscroll' option is true", -> - it "autoscrolls to the selection", -> - editor.setLineHeightInPixels(10) - editor.setDefaultCharWidth(10) - editor.setHeight(70) - editor.setWidth(50) - editor.setHorizontalScrollbarHeight(0) + it "autoscrolls the selection if it is last unless the 'autoscroll' option is false", -> + editor.setVerticalScrollMargin(2) + editor.setHorizontalScrollMargin(2) + editor.setLineHeightInPixels(10) + editor.setDefaultCharWidth(10) + editor.setHeight(70) + editor.setWidth(100) + editor.setHorizontalScrollbarHeight(0) - expect(editor.getScrollTop()).toBe 0 + expect(editor.getScrollTop()).toBe 0 - editor.setSelectedBufferRange([[5, 6], [6, 8]], autoscroll: true) - expect(editor.getScrollBottom()).toBe (7 + editor.getVerticalScrollMargin()) * 10 - expect(editor.getScrollRight()).toBe 50 + editor.setSelectedBufferRange([[5, 6], [6, 8]]) + expect(editor.getScrollBottom()).toBe (7 + editor.getVerticalScrollMargin()) * 10 + expect(editor.getScrollRight()).toBe (8 + editor.getHorizontalScrollMargin()) * 10 - editor.setSelectedBufferRange([[6, 6], [6, 8]], autoscroll: true) - expect(editor.getScrollBottom()).toBe (7 + editor.getVerticalScrollMargin()) * 10 - expect(editor.getScrollRight()).toBe (8 + editor.getHorizontalScrollMargin()) * 10 + editor.setSelectedBufferRange([[0, 0], [0, 0]]) + expect(editor.getScrollTop()).toBe 0 + expect(editor.getScrollLeft()).toBe 0 + + editor.setSelectedBufferRange([[6, 6], [6, 8]]) + expect(editor.getScrollBottom()).toBe (7 + editor.getVerticalScrollMargin()) * 10 + expect(editor.getScrollRight()).toBe (8 + editor.getHorizontalScrollMargin()) * 10 describe ".selectMarker(marker)", -> describe "if the marker is valid", -> @@ -1557,14 +1562,15 @@ describe "TextEditor", -> expect(editor.getSelectedBufferRanges()).toEqual [[[0, 0], [0, 0]], [[3, 4], [5, 6]]] it "autoscrolls to the added selection if needed", -> + editor.setVerticalScrollMargin(2) + editor.setHorizontalScrollMargin(2) editor.setLineHeightInPixels(10) editor.setDefaultCharWidth(10) - editor.setHeight(50) - editor.setWidth(50) - + editor.setHeight(80) + editor.setWidth(100) editor.addSelectionForBufferRange([[8, 10], [8, 15]]) - expect(editor.getScrollTop()).toBe 75 - expect(editor.getScrollLeft()).toBe 160 + expect(editor.getScrollBottom()).toBe (9 * 10) + (2 * 10) + expect(editor.getScrollRight()).toBe (15 * 10) + (2 * 10) describe ".addSelectionBelow()", -> describe "when the selection is non-empty", -> @@ -4050,7 +4056,7 @@ describe "TextEditor", -> editor.setLineHeightInPixels(10) editor.setDefaultCharWidth(10) editor.setHeight(60) - editor.setWidth(50) + editor.setWidth(130) editor.setHorizontalScrollbarHeight(0) expect(editor.getScrollTop()).toBe 0 expect(editor.getScrollLeft()).toBe 0 diff --git a/src/cursor.coffee b/src/cursor.coffee index 2a0665485..d0602a2f4 100644 --- a/src/cursor.coffee +++ b/src/cursor.coffee @@ -29,8 +29,6 @@ class Cursor extends Model {textChanged} = e return if oldHeadScreenPosition.isEqual(newHeadScreenPosition) - @autoscroll() if @isLastCursor() and textChanged - @goalColumn = null movedEvent = @@ -651,7 +649,7 @@ class Cursor extends Model changePosition: (options, fn) -> @clearSelection() fn() - @autoscroll() if options.autoscroll ? @isLastCursor() + @autoscroll() if options.autoscroll getPixelRect: -> @editor.pixelRectForScreenRange(@getScreenRange()) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index 059d04909..b60113661 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -199,12 +199,22 @@ class DisplayBuffer extends Model # visible - A {Boolean} indicating of the tokenized buffer is shown setVisible: (visible) -> @tokenizedBuffer.setVisible(visible) - getVerticalScrollMargin: -> @verticalScrollMargin + getVerticalScrollMargin: -> Math.min(@verticalScrollMargin, (@getHeight() - @getLineHeightInPixels()) / 2) setVerticalScrollMargin: (@verticalScrollMargin) -> @verticalScrollMargin - getHorizontalScrollMargin: -> @horizontalScrollMargin + getVerticalScrollMarginInPixels: -> + scrollMarginInPixels = @getVerticalScrollMargin() * @getLineHeightInPixels() + maxScrollMarginInPixels = (@getHeight() - @getLineHeightInPixels()) / 2 + Math.min(scrollMarginInPixels, maxScrollMarginInPixels) + + getHorizontalScrollMargin: -> Math.min(@horizontalScrollMargin, (@getWidth() - @getDefaultCharWidth()) / 2) setHorizontalScrollMargin: (@horizontalScrollMargin) -> @horizontalScrollMargin + getHorizontalScrollMarginInPixels: -> + scrollMarginInPixels = @getHorizontalScrollMargin() * @getDefaultCharWidth() + maxScrollMarginInPixels = (@getWidth() - @getDefaultCharWidth()) / 2 + Math.min(scrollMarginInPixels, maxScrollMarginInPixels) + getHorizontalScrollbarHeight: -> @horizontalScrollbarHeight setHorizontalScrollbarHeight: (@horizontalScrollbarHeight) -> @horizontalScrollbarHeight @@ -272,7 +282,7 @@ class DisplayBuffer extends Model getMaxScrollTop: -> @getScrollHeight() - @getClientHeight() - getScrollBottom: -> @scrollTop + @height + getScrollBottom: -> @scrollTop + @getClientHeight() setScrollBottom: (scrollBottom) -> @setScrollTop(scrollBottom - @getClientHeight()) @getScrollBottom() @@ -364,15 +374,16 @@ class DisplayBuffer extends Model @intersectsVisibleRowRange(start.row, end.row + 1) scrollToScreenRange: (screenRange, options) -> - verticalScrollMarginInPixels = @getVerticalScrollMargin() * @getLineHeightInPixels() - horizontalScrollMarginInPixels = @getHorizontalScrollMargin() * @getDefaultCharWidth() + verticalScrollMarginInPixels = @getVerticalScrollMarginInPixels() + horizontalScrollMarginInPixels = @getHorizontalScrollMarginInPixels() - {top, left, height, width} = @pixelRectForScreenRange(screenRange) - bottom = top + height - right = left + width + {top, left} = @pixelRectForScreenRange(new Range(screenRange.start, screenRange.start)) + {top: endTop, left: endLeft, height: endHeight} = @pixelRectForScreenRange(new Range(screenRange.end, screenRange.end)) + bottom = endTop + endHeight + right = endLeft if options?.center - desiredScrollCenter = top + height / 2 + desiredScrollCenter = (top + bottom) / 2 unless @getScrollTop() < desiredScrollCenter < @getScrollBottom() desiredScrollTop = desiredScrollCenter - @getHeight() / 2 desiredScrollBottom = desiredScrollCenter + @getHeight() / 2 @@ -383,15 +394,26 @@ class DisplayBuffer extends Model desiredScrollLeft = left - horizontalScrollMarginInPixels desiredScrollRight = right + horizontalScrollMarginInPixels - if desiredScrollTop < @getScrollTop() - @setScrollTop(desiredScrollTop) - else if desiredScrollBottom > @getScrollBottom() - @setScrollBottom(desiredScrollBottom) + if options?.reversed ? true + if desiredScrollBottom > @getScrollBottom() + @setScrollBottom(desiredScrollBottom) + if desiredScrollTop < @getScrollTop() + @setScrollTop(desiredScrollTop) - if desiredScrollLeft < @getScrollLeft() - @setScrollLeft(desiredScrollLeft) - else if desiredScrollRight > @getScrollRight() - @setScrollRight(desiredScrollRight) + if desiredScrollRight > @getScrollRight() + @setScrollRight(desiredScrollRight) + if desiredScrollLeft < @getScrollLeft() + @setScrollLeft(desiredScrollLeft) + else + if desiredScrollTop < @getScrollTop() + @setScrollTop(desiredScrollTop) + if desiredScrollBottom > @getScrollBottom() + @setScrollBottom(desiredScrollBottom) + + if desiredScrollLeft < @getScrollLeft() + @setScrollLeft(desiredScrollLeft) + if desiredScrollRight > @getScrollRight() + @setScrollRight(desiredScrollRight) scrollToScreenPosition: (screenPosition, options) -> @scrollToScreenRange(new Range(screenPosition, screenPosition), options) diff --git a/src/selection.coffee b/src/selection.coffee index 524f1bd9b..df0e4a5d1 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -733,6 +733,12 @@ class Selection extends Model {oldHeadBufferPosition, oldTailBufferPosition} = e {oldHeadScreenPosition, oldTailScreenPosition} = e + if this is @editor.getLastSelection() + if @marker.hasTail() + @autoscroll() + else + @cursor.autoscroll() + eventObject = oldBufferRange: new Range(oldHeadBufferPosition, oldTailBufferPosition) oldScreenRange: new Range(oldHeadScreenPosition, oldTailScreenPosition) @@ -751,7 +757,7 @@ class Selection extends Model @linewise = false autoscroll: -> - @editor.scrollToScreenRange(@getScreenRange()) + @editor.scrollToScreenRange(@getScreenRange(), reversed: @isReversed()) clearAutoscroll: -> diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 114df486a..820737834 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -1947,9 +1947,7 @@ class TextEditor extends Model # Returns the added {Selection}. addSelectionForBufferRange: (bufferRange, options={}) -> @markBufferRange(bufferRange, _.defaults(@getSelectionMarkerAttributes(), options)) - selection = @getLastSelection() - selection.autoscroll() - selection + @getLastSelection() # Essential: Add a selection for the given range in screen coordinates. # @@ -1961,9 +1959,7 @@ class TextEditor extends Model # Returns the added {Selection}. addSelectionForScreenRange: (screenRange, options={}) -> @markScreenRange(screenRange, _.defaults(@getSelectionMarkerAttributes(), options)) - selection = @getLastSelection() - selection.autoscroll() - selection + @getLastSelection() # Essential: Select from the current cursor position to the given position in # buffer coordinates. @@ -2269,11 +2265,14 @@ class TextEditor extends Model @selections.push(selection) selectionBufferRange = selection.getBufferRange() @mergeIntersectingSelections(preserveFolds: marker.getProperties().preserveFolds) + if selection.destroyed for selection in @getSelections() if selection.intersectsBufferRange(selectionBufferRange) + selection.autoscroll() return selection else + selection.autoscroll() @emit 'selection-added', selection @emitter.emit 'did-add-selection', selection selection From a70be30ee7017b86114592800d9d4bdccff88aa8 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Mar 2015 14:37:30 -0700 Subject: [PATCH 0293/1783] :art: --- src/typescript.coffee | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/typescript.coffee b/src/typescript.coffee index 3814a6c66..3a54941f3 100644 --- a/src/typescript.coffee +++ b/src/typescript.coffee @@ -57,7 +57,9 @@ createOptions = (filePath) -> transpile = (sourceCode, filePath, cachePath) -> options = createOptions(filePath) - tss ?= new (require 'typescript-simple').TypeScriptSimple(options, false) + unless tss? + {TypeScriptSimple} = require 'typescript-simple' + tss = new TypeScriptSimple(options, false) js = tss.compile(sourceCode, filePath) stats.misses++ From 9cdbda5c148c96dc18064b03898960ffdd3b1938 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Mar 2015 14:42:33 -0700 Subject: [PATCH 0294/1783] :arrow_up: language-c@0.42 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ac4c5569b..96db70912 100644 --- a/package.json +++ b/package.json @@ -123,7 +123,7 @@ "welcome": "0.26.0", "whitespace": "0.29.0", "wrap-guide": "0.31.0", - "language-c": "0.41.0", + "language-c": "0.42.0", "language-clojure": "0.13.0", "language-coffee-script": "0.39.0", "language-csharp": "0.5.0", From 99c437ccecff469d2fc4ba70ff3ff9a0f694f9e6 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 26 Mar 2015 16:48:21 -0600 Subject: [PATCH 0295/1783] Allow autoscroll override option in cursor/selection methods Signed-off-by: Max Brunsfeld --- spec/text-editor-component-spec.coffee | 6 +++--- spec/text-editor-presenter-spec.coffee | 12 ++++++------ spec/text-editor-spec.coffee | 24 ++++++++++++++++++++++++ src/cursor.coffee | 16 +++++++++++----- src/selection.coffee | 24 +++++++++++++++++++----- src/text-editor.coffee | 19 ++++++++++++++----- 6 files changed, 77 insertions(+), 24 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 20ddcdcab..135e551a3 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -693,7 +693,7 @@ describe "TextEditorComponent", -> describe "cursor rendering", -> it "renders the currently visible cursors", -> cursor1 = editor.getLastCursor() - cursor1.setScreenPosition([0, 5]) + cursor1.setScreenPosition([0, 5], autoscroll: false) wrapperNode.style.height = 4.5 * lineHeightInPixels + 'px' wrapperNode.style.width = 20 * lineHeightInPixels + 'px' @@ -706,8 +706,8 @@ describe "TextEditorComponent", -> expect(cursorNodes[0].offsetWidth).toBe charWidth expect(cursorNodes[0].style['-webkit-transform']).toBe "translate(#{5 * charWidth}px, #{0 * lineHeightInPixels}px)" - cursor2 = editor.addCursorAtScreenPosition([8, 11]) - cursor3 = editor.addCursorAtScreenPosition([4, 10]) + cursor2 = editor.addCursorAtScreenPosition([8, 11], autoscroll: false) + cursor3 = editor.addCursorAtScreenPosition([4, 10], autoscroll: false) nextAnimationFrame() cursorNodes = componentNode.querySelectorAll('.cursor') diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 0cf0c7e53..b62391db8 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -1417,33 +1417,33 @@ describe "TextEditorPresenter", -> expect(stateForSelection(presenter, 1)).toBeUndefined() # moving into view - expectStateUpdate presenter, -> editor.getSelections()[1].setBufferRange([[2, 4], [2, 6]]) + expectStateUpdate presenter, -> editor.getSelections()[1].setBufferRange([[2, 4], [2, 6]], autoscroll: false) expectValues stateForSelection(presenter, 1), { regions: [{top: 2 * 10, left: 4 * 10, width: 2 * 10, height: 10}] } # becoming empty - expectStateUpdate presenter, -> editor.getSelections()[1].clear() + expectStateUpdate presenter, -> editor.getSelections()[1].clear(autoscroll: false) expect(stateForSelection(presenter, 1)).toBeUndefined() # becoming non-empty - expectStateUpdate presenter, -> editor.getSelections()[1].setBufferRange([[2, 4], [2, 6]]) + expectStateUpdate presenter, -> editor.getSelections()[1].setBufferRange([[2, 4], [2, 6]], autoscroll: false) expectValues stateForSelection(presenter, 1), { regions: [{top: 2 * 10, left: 4 * 10, width: 2 * 10, height: 10}] } # moving out of view - expectStateUpdate presenter, -> editor.getSelections()[1].setBufferRange([[3, 4], [3, 6]]) + expectStateUpdate presenter, -> editor.getSelections()[1].setBufferRange([[3, 4], [3, 6]], autoscroll: false) expect(stateForSelection(presenter, 1)).toBeUndefined() # adding - expectStateUpdate presenter, -> editor.addSelectionForBufferRange([[1, 4], [1, 6]]) + expectStateUpdate presenter, -> editor.addSelectionForBufferRange([[1, 4], [1, 6]], autoscroll: false) expectValues stateForSelection(presenter, 2), { regions: [{top: 1 * 10, left: 4 * 10, width: 2 * 10, height: 10}] } # moving added selection - expectStateUpdate presenter, -> editor.getSelections()[2].setBufferRange([[1, 4], [1, 8]]) + expectStateUpdate presenter, -> editor.getSelections()[2].setBufferRange([[1, 4], [1, 8]], autoscroll: false) expectValues stateForSelection(presenter, 2), { regions: [{top: 1 * 10, left: 4 * 10, width: 4 * 10, height: 10}] } diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index afebf591d..49b75bafd 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -993,6 +993,30 @@ describe "TextEditor", -> editor.undo() expect(editor.getScrollTop()).toBe 0 + it "honors the autoscroll option on cursor and selection manipulation methods", -> + expect(editor.getScrollTop()).toBe 0 + editor.addCursorAtScreenPosition([11, 11], autoscroll: false) + editor.addCursorAtBufferPosition([11, 11], autoscroll: false) + editor.setCursorScreenPosition([11, 11], autoscroll: false) + editor.setCursorBufferPosition([11, 11], autoscroll: false) + editor.addSelectionForBufferRange([[11, 11], [11, 11]], autoscroll: false) + editor.addSelectionForScreenRange([[11, 11], [11, 12]], autoscroll: false) + editor.setSelectedBufferRange([[11, 0], [11, 1]], autoscroll: false) + editor.setSelectedScreenRange([[11, 0], [11, 6]], autoscroll: false) + editor.clearSelections(autoscroll: false) + expect(editor.getScrollTop()).toBe 0 + + editor.addSelectionForScreenRange([[0, 0], [0, 4]]) + + editor.getCursors()[0].setScreenPosition([11, 11], autoscroll: true) + expect(editor.getScrollTop()).toBeGreaterThan 0 + editor.getCursors()[0].setBufferPosition([0, 0], autoscroll: true) + expect(editor.getScrollTop()).toBe 0 + editor.getSelections()[0].setScreenRange([[11, 0], [11, 4]], autoscroll: true) + expect(editor.getScrollTop()).toBeGreaterThan 0 + editor.getSelections()[0].setBufferRange([[0, 0], [0, 4]], autoscroll: true) + expect(editor.getScrollTop()).toBe 0 + describe '.logCursorScope()', -> beforeEach -> spyOn(atom.notifications, 'addInfo') diff --git a/src/cursor.coffee b/src/cursor.coffee index d0602a2f4..2e67ab43b 100644 --- a/src/cursor.coffee +++ b/src/cursor.coffee @@ -122,8 +122,9 @@ class Cursor extends Model # # * `bufferPosition` {Array} of two numbers: the buffer row, and the buffer column. # * `options` (optional) {Object} with the following keys: - # * `autoscroll` A Boolean which, if `true`, scrolls the {TextEditor} to wherever - # the cursor moves to. + # * `autoscroll` {Boolean} indicating whether to autoscroll to the new + # position. Defaults to `true` if this is the most recently added cursor, + # `false` otherwise. setBufferPosition: (bufferPosition, options={}) -> @changePosition options, => @marker.setHeadBufferPosition(bufferPosition, options) @@ -648,8 +649,12 @@ class Cursor extends Model changePosition: (options, fn) -> @clearSelection() - fn() - @autoscroll() if options.autoscroll + @editor.suppressAutoscroll = true if options.autoscroll is false + try + fn() + finally + @editor.suppressAutoscroll = false if options?.autoscroll is false + @autoscroll() if options.autoscroll is true getPixelRect: -> @editor.pixelRectForScreenRange(@getScreenRange()) @@ -659,7 +664,8 @@ class Cursor extends Model new Range(new Point(row, column), new Point(row, column + 1)) autoscroll: (options) -> - @editor.scrollToScreenRange(@getScreenRange(), options) + unless @editor.suppressAutoscroll + @editor.scrollToScreenRange(@getScreenRange(), options) getBeginningOfNextParagraphBufferPosition: -> start = @getBufferPosition() diff --git a/src/selection.coffee b/src/selection.coffee index df0e4a5d1..4987708eb 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -95,8 +95,11 @@ class Selection extends Model # # * `screenRange` The new {Range} to select. # * `options` (optional) {Object} with the keys: - # * `preserveFolds` if `true`, the fold settings are preserved after the selection moves. - # * `autoscroll` if `true`, the {TextEditor} scrolls to the new selection. + # * `preserveFolds` if `true`, the fold settings are preserved after the + # selection moves. + # * `autoscroll` {Boolean} indicating whether to autoscroll to the new + # range. Defaults to `true` if this is the most recently added selection, + # `false` otherwise. setBufferRange: (bufferRange, options={}) -> bufferRange = Range.fromObject(bufferRange) options.reversed ?= @isReversed() @@ -104,8 +107,10 @@ class Selection extends Model @modifySelection => needsFlash = options.flash delete options.flash if options.flash? + @editor.suppressAutoscroll = true if options.autoscroll is false @marker.setBufferRange(bufferRange, options) - @autoscroll() if options.autoscroll + @editor.suppressAutoscroll = false if options.autoscroll is false + @autoscroll() if options?.autoscroll is true @decoration.flash('flash', @editor.selectionFlashDuration) if needsFlash # Public: Returns the starting and ending buffer rows the selection is @@ -181,9 +186,17 @@ class Selection extends Model ### # Public: Clears the selection, moving the marker to the head. - clear: -> + # + # * `options` (optional) {Object} with the following keys: + # * `autoscroll` {Boolean} indicating whether to autoscroll to the new + # range. Defaults to `true` if this is the most recently added selection, + # `false` otherwise. + clear: (options) -> + @editor.suppressAutoscroll = true if options?.autoscroll is false @marker.setProperties(goalScreenRange: null) @marker.clearTail() unless @retainSelection + @editor.suppressAutoscroll = false if options?.autoscroll is false + @autoscroll() if options?.autoscroll is true @finalize() # Public: Selects the text from the current cursor position to a given screen @@ -757,7 +770,8 @@ class Selection extends Model @linewise = false autoscroll: -> - @editor.scrollToScreenRange(@getScreenRange(), reversed: @isReversed()) + unless @editor.suppressAutoscroll + @editor.scrollToScreenRange(@getScreenRange(), reversed: @isReversed()) clearAutoscroll: -> diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 820737834..beaf4aaac 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -69,6 +69,7 @@ class TextEditor extends Model suppressSelectionMerging: false updateBatchDepth: 0 selectionFlashDuration: 500 + suppressAutoscroll: false @delegatesMethods 'suggestedIndentForBufferRow', 'autoIndentBufferRow', 'autoIndentBufferRows', 'autoDecreaseIndentForBufferRow', 'toggleLineCommentForBufferRow', 'toggleLineCommentsForBufferRows', @@ -1606,8 +1607,10 @@ class TextEditor extends Model # * `bufferPosition` A {Point} or {Array} of `[row, column]` # # Returns a {Cursor}. - addCursorAtBufferPosition: (bufferPosition) -> + addCursorAtBufferPosition: (bufferPosition, options) -> + @suppressAutoscroll = true if options?.autoscroll is false @markBufferPosition(bufferPosition, @getSelectionMarkerAttributes()) + @suppressAutoscroll = false if options?.autoscroll is false @getLastSelection().cursor # Essential: Add a cursor at the position in screen coordinates. @@ -1615,8 +1618,10 @@ class TextEditor extends Model # * `screenPosition` A {Point} or {Array} of `[row, column]` # # Returns a {Cursor}. - addCursorAtScreenPosition: (screenPosition) -> + addCursorAtScreenPosition: (screenPosition, options) -> + @suppressAutoscroll = true if options?.autoscroll is false @markScreenPosition(screenPosition, @getSelectionMarkerAttributes()) + @suppressAutoscroll = false if options?.autoscroll is false @getLastSelection().cursor # Essential: Returns {Boolean} indicating whether or not there are multiple cursors. @@ -1946,7 +1951,9 @@ class TextEditor extends Model # # Returns the added {Selection}. addSelectionForBufferRange: (bufferRange, options={}) -> + @suppressAutoscroll = true if options.autoscroll is false @markBufferRange(bufferRange, _.defaults(@getSelectionMarkerAttributes(), options)) + @suppressAutoscroll = false if options.autoscroll is false @getLastSelection() # Essential: Add a selection for the given range in screen coordinates. @@ -1958,7 +1965,9 @@ class TextEditor extends Model # # Returns the added {Selection}. addSelectionForScreenRange: (screenRange, options={}) -> + @suppressAutoscroll = true if options.autoscroll is false @markScreenRange(screenRange, _.defaults(@getSelectionMarkerAttributes(), options)) + @suppressAutoscroll = false if options.autoscroll is false @getLastSelection() # Essential: Select from the current cursor position to the given position in @@ -2272,7 +2281,7 @@ class TextEditor extends Model selection.autoscroll() return selection else - selection.autoscroll() + selection.autoscroll() unless options.autoscroll is false @emit 'selection-added', selection @emitter.emit 'did-add-selection', selection selection @@ -2285,9 +2294,9 @@ class TextEditor extends Model # Reduce one or more selections to a single empty selection based on the most # recently added cursor. - clearSelections: -> + clearSelections: (options) -> @consolidateSelections() - @getLastSelection().clear() + @getLastSelection().clear(options) # Reduce multiple selections to the most recently added selection. consolidateSelections: -> From ae4f7f6170da83c786ba06235f0997e52e806b10 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 26 Mar 2015 16:48:24 -0600 Subject: [PATCH 0296/1783] Explicitly autoscroll when needed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than when the selection’s marker changes. This is simpler than suppressing autoscroll via state when we don’t want it. It also captures the intent to autoscroll when attempting to move the cursor at the beginning or end of the document. Signed-off-by: Max Brunsfeld --- spec/text-editor-component-spec.coffee | 4 ++-- spec/text-editor-spec.coffee | 11 +++++++++-- src/cursor.coffee | 17 ++++++---------- src/selection.coffee | 27 ++++++++++++-------------- src/text-editor.coffee | 19 +++++++----------- 5 files changed, 36 insertions(+), 42 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 135e551a3..656dca0f0 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -1524,7 +1524,7 @@ describe "TextEditorComponent", -> expect(inputNode.offsetLeft).toBe 0 # In bounds, not focused - editor.setCursorBufferPosition([5, 4]) + editor.setCursorBufferPosition([5, 4], autoscroll: false) nextAnimationFrame() expect(inputNode.offsetTop).toBe 0 expect(inputNode.offsetLeft).toBe 0 @@ -1542,7 +1542,7 @@ describe "TextEditorComponent", -> expect(inputNode.offsetLeft).toBe 0 # Out of bounds, not focused - editor.setCursorBufferPosition([1, 2]) + editor.setCursorBufferPosition([1, 2], autoscroll: false) nextAnimationFrame() expect(inputNode.offsetTop).toBe 0 expect(inputNode.offsetLeft).toBe 0 diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 49b75bafd..d87952e85 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -970,9 +970,8 @@ describe "TextEditor", -> it "scrolls left when the last cursor gets closer than ::horizontalScrollMargin to the left of the editor", -> editor.setScrollRight(editor.getScrollWidth()) - editor.setCursorScreenPosition([6, 62]) - expect(editor.getScrollRight()).toBe editor.getScrollWidth() + editor.setCursorScreenPosition([6, 62], autoscroll: false) editor.moveLeft() expect(editor.getScrollLeft()).toBe 59 * 10 @@ -996,13 +995,21 @@ describe "TextEditor", -> it "honors the autoscroll option on cursor and selection manipulation methods", -> expect(editor.getScrollTop()).toBe 0 editor.addCursorAtScreenPosition([11, 11], autoscroll: false) + expect(editor.getScrollTop()).toBe 0 editor.addCursorAtBufferPosition([11, 11], autoscroll: false) + expect(editor.getScrollTop()).toBe 0 editor.setCursorScreenPosition([11, 11], autoscroll: false) + expect(editor.getScrollTop()).toBe 0 editor.setCursorBufferPosition([11, 11], autoscroll: false) + expect(editor.getScrollTop()).toBe 0 editor.addSelectionForBufferRange([[11, 11], [11, 11]], autoscroll: false) + expect(editor.getScrollTop()).toBe 0 editor.addSelectionForScreenRange([[11, 11], [11, 12]], autoscroll: false) + expect(editor.getScrollTop()).toBe 0 editor.setSelectedBufferRange([[11, 0], [11, 1]], autoscroll: false) + expect(editor.getScrollTop()).toBe 0 editor.setSelectedScreenRange([[11, 0], [11, 6]], autoscroll: false) + expect(editor.getScrollTop()).toBe 0 editor.clearSelections(autoscroll: false) expect(editor.getScrollTop()).toBe 0 diff --git a/src/cursor.coffee b/src/cursor.coffee index 2e67ab43b..c96f2eff5 100644 --- a/src/cursor.coffee +++ b/src/cursor.coffee @@ -624,8 +624,8 @@ class Cursor extends Model clearAutoscroll: -> # Public: Deselects the current selection. - clearSelection: -> - @selection?.clear() + clearSelection: (options) -> + @selection?.clear(options) # Public: Get the RegExp used by the cursor to determine what a "word" is. # @@ -648,13 +648,9 @@ class Cursor extends Model ### changePosition: (options, fn) -> - @clearSelection() - @editor.suppressAutoscroll = true if options.autoscroll is false - try - fn() - finally - @editor.suppressAutoscroll = false if options?.autoscroll is false - @autoscroll() if options.autoscroll is true + @clearSelection(options) + fn() + @autoscroll() if options.autoscroll ? @isLastCursor() getPixelRect: -> @editor.pixelRectForScreenRange(@getScreenRange()) @@ -664,8 +660,7 @@ class Cursor extends Model new Range(new Point(row, column), new Point(row, column + 1)) autoscroll: (options) -> - unless @editor.suppressAutoscroll - @editor.scrollToScreenRange(@getScreenRange(), options) + @editor.scrollToScreenRange(@getScreenRange(), options) getBeginningOfNextParagraphBufferPosition: -> start = @getBufferPosition() diff --git a/src/selection.coffee b/src/selection.coffee index 4987708eb..0bee6f7de 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -1,6 +1,6 @@ {Point, Range} = require 'text-buffer' {Model} = require 'theorist' -{pick} = require 'underscore-plus' +{pick} = _ = require 'underscore-plus' {Emitter} = require 'event-kit' Grim = require 'grim' @@ -34,6 +34,9 @@ class Selection extends Model destroy: -> @marker.destroy() + isLastSelection: -> + this is @editor.getLastSelection() + ### Section: Event Subscription ### @@ -107,10 +110,8 @@ class Selection extends Model @modifySelection => needsFlash = options.flash delete options.flash if options.flash? - @editor.suppressAutoscroll = true if options.autoscroll is false @marker.setBufferRange(bufferRange, options) - @editor.suppressAutoscroll = false if options.autoscroll is false - @autoscroll() if options?.autoscroll is true + @autoscroll() if options?.autoscroll ? @isLastSelection() @decoration.flash('flash', @editor.selectionFlashDuration) if needsFlash # Public: Returns the starting and ending buffer rows the selection is @@ -192,11 +193,9 @@ class Selection extends Model # range. Defaults to `true` if this is the most recently added selection, # `false` otherwise. clear: (options) -> - @editor.suppressAutoscroll = true if options?.autoscroll is false @marker.setProperties(goalScreenRange: null) @marker.clearTail() unless @retainSelection - @editor.suppressAutoscroll = false if options?.autoscroll is false - @autoscroll() if options?.autoscroll is true + @autoscroll() if options?.autoscroll ? @isLastSelection() @finalize() # Public: Selects the text from the current cursor position to a given screen @@ -407,6 +406,8 @@ class Selection extends Model else if options.autoDecreaseIndent and NonWhitespaceRegExp.test(text) @editor.autoDecreaseIndentForBufferRow(newBufferRange.start.row) + @autoscroll() if @isLastSelection() + newBufferRange # Public: Removes the first character before the selection if the selection @@ -722,7 +723,7 @@ class Selection extends Model else options.goalScreenRange = myGoalScreenRange ? otherGoalScreenRange - @setBufferRange(@getBufferRange().union(otherSelection.getBufferRange()), options) + @setBufferRange(@getBufferRange().union(otherSelection.getBufferRange()), _.extend(autoscroll: false, options)) otherSelection.destroy() ### @@ -746,12 +747,6 @@ class Selection extends Model {oldHeadBufferPosition, oldTailBufferPosition} = e {oldHeadScreenPosition, oldTailScreenPosition} = e - if this is @editor.getLastSelection() - if @marker.hasTail() - @autoscroll() - else - @cursor.autoscroll() - eventObject = oldBufferRange: new Range(oldHeadBufferPosition, oldTailBufferPosition) oldScreenRange: new Range(oldHeadScreenPosition, oldTailScreenPosition) @@ -770,8 +765,10 @@ class Selection extends Model @linewise = false autoscroll: -> - unless @editor.suppressAutoscroll + if @marker.hasTail() @editor.scrollToScreenRange(@getScreenRange(), reversed: @isReversed()) + else + @cursor.autoscroll() clearAutoscroll: -> diff --git a/src/text-editor.coffee b/src/text-editor.coffee index beaf4aaac..355a644b8 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -69,7 +69,6 @@ class TextEditor extends Model suppressSelectionMerging: false updateBatchDepth: 0 selectionFlashDuration: 500 - suppressAutoscroll: false @delegatesMethods 'suggestedIndentForBufferRow', 'autoIndentBufferRow', 'autoIndentBufferRows', 'autoDecreaseIndentForBufferRow', 'toggleLineCommentForBufferRow', 'toggleLineCommentsForBufferRows', @@ -1133,11 +1132,13 @@ class TextEditor extends Model # Essential: Undo the last change. undo: -> - @buffer.undo(this) + @buffer.undo() + @getLastSelection().autoscroll() # Essential: Redo the last change. redo: -> @buffer.redo(this) + @getLastSelection().autoscroll() # Extended: Batch multiple operations as a single undo/redo step. # @@ -1608,9 +1609,8 @@ class TextEditor extends Model # # Returns a {Cursor}. addCursorAtBufferPosition: (bufferPosition, options) -> - @suppressAutoscroll = true if options?.autoscroll is false @markBufferPosition(bufferPosition, @getSelectionMarkerAttributes()) - @suppressAutoscroll = false if options?.autoscroll is false + @getLastSelection().cursor.autoscroll() unless options?.autoscroll is false @getLastSelection().cursor # Essential: Add a cursor at the position in screen coordinates. @@ -1619,9 +1619,8 @@ class TextEditor extends Model # # Returns a {Cursor}. addCursorAtScreenPosition: (screenPosition, options) -> - @suppressAutoscroll = true if options?.autoscroll is false @markScreenPosition(screenPosition, @getSelectionMarkerAttributes()) - @suppressAutoscroll = false if options?.autoscroll is false + @getLastSelection().cursor.autoscroll() unless options?.autoscroll is false @getLastSelection().cursor # Essential: Returns {Boolean} indicating whether or not there are multiple cursors. @@ -1951,9 +1950,8 @@ class TextEditor extends Model # # Returns the added {Selection}. addSelectionForBufferRange: (bufferRange, options={}) -> - @suppressAutoscroll = true if options.autoscroll is false @markBufferRange(bufferRange, _.defaults(@getSelectionMarkerAttributes(), options)) - @suppressAutoscroll = false if options.autoscroll is false + @getLastSelection().autoscroll() unless options.autoscroll is false @getLastSelection() # Essential: Add a selection for the given range in screen coordinates. @@ -1965,9 +1963,8 @@ class TextEditor extends Model # # Returns the added {Selection}. addSelectionForScreenRange: (screenRange, options={}) -> - @suppressAutoscroll = true if options.autoscroll is false @markScreenRange(screenRange, _.defaults(@getSelectionMarkerAttributes(), options)) - @suppressAutoscroll = false if options.autoscroll is false + @getLastSelection().autoscroll() unless options.autoscroll is false @getLastSelection() # Essential: Select from the current cursor position to the given position in @@ -2278,10 +2275,8 @@ class TextEditor extends Model if selection.destroyed for selection in @getSelections() if selection.intersectsBufferRange(selectionBufferRange) - selection.autoscroll() return selection else - selection.autoscroll() unless options.autoscroll is false @emit 'selection-added', selection @emitter.emit 'did-add-selection', selection selection From 477a9d7002603ca297efd3e07e3af0300b5d7597 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Mar 2015 16:25:12 -0700 Subject: [PATCH 0297/1783] :arrow_up: apm@0.152 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index f43d9e024..e10632417 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.151.0" + "atom-package-manager": "0.152.0" } } From c12f94907dc009395bcdafc746ec8fb689813830 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 10:01:09 -0700 Subject: [PATCH 0298/1783] Remove grim.deprecate override --- src/atom.coffee | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/atom.coffee b/src/atom.coffee index 188d0b3a6..707500479 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -207,12 +207,6 @@ class Atom extends Model # # Call after this instance has been assigned to the `atom` global. initialize: -> - # Disable deprecations unless in dev mode or spec mode so that regular - # editor performance isn't impacted by generating stack traces for - # deprecated calls. - unless @inDevMode() or @inSpecMode() - require('grim').deprecate = -> - sourceMapCache = {} window.onerror = => From c2fecacdbed55e4886b6986c8794aa194b48de93 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 10:47:06 -0700 Subject: [PATCH 0299/1783] Fail CI build when deprecations exist --- spec/jasmine-helper.coffee | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/spec/jasmine-helper.coffee b/spec/jasmine-helper.coffee index 7642de7d7..1efb6ce19 100644 --- a/spec/jasmine-helper.coffee +++ b/spec/jasmine-helper.coffee @@ -27,8 +27,15 @@ module.exports.runSpecSuite = (specSuite, logFile, logErrors=true) -> fs.closeSync(logStream) if logStream? if process.env.JANKY_SHA1 grim = require 'grim' - grim.logDeprecations() if grim.getDeprecationsLength() > 0 - atom.exit(runner.results().failedCount > 0 ? 1 : 0) + + if grim.getDeprecationsLength() > 0 + grim.logDeprecations() + return atom.exit(1) if runner.results().failedCount is 0 + + if runner.results().failedCount > 0 + atom.exit(1) + else + atom.exit(0) else AtomReporter = require './atom-reporter' reporter = new AtomReporter() From ffdf7ac55840c40bd25b79e2bea9998d48c46878 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 12:31:08 -0700 Subject: [PATCH 0300/1783] Remove unneeded failed count check --- spec/jasmine-helper.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/jasmine-helper.coffee b/spec/jasmine-helper.coffee index 1efb6ce19..1e099d897 100644 --- a/spec/jasmine-helper.coffee +++ b/spec/jasmine-helper.coffee @@ -30,7 +30,7 @@ module.exports.runSpecSuite = (specSuite, logFile, logErrors=true) -> if grim.getDeprecationsLength() > 0 grim.logDeprecations() - return atom.exit(1) if runner.results().failedCount is 0 + return atom.exit(1) if runner.results().failedCount > 0 atom.exit(1) From 52e94637a316845dcdf3b8bf2bf27adcd62866fa Mon Sep 17 00:00:00 2001 From: "L. Caputo" Date: Thu, 26 Mar 2015 21:48:07 -0400 Subject: [PATCH 0301/1783] Update CONTRIBUTING.md change spelling: "judgement" to "judgment". --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d2cf02bef..e6073b3ca 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,7 +6,7 @@ The following is a set of guidelines for contributing to Atom and its packages, which are hosted in the [Atom Organization](https://github.com/atom) on GitHub. If you're unsure which package is causing your problem or if you're having an issue with Atom core, please open an issue on the [main atom repository](https://github.com/atom/atom/issues). -These are just guidelines, not rules, use your best judgement and feel free to +These are just guidelines, not rules, use your best judgment and feel free to propose changes to this document in a pull request. ## Submitting Issues From 230eb12a8a4b4fab76bab3ee0ea09aeadfd2288e Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 27 Mar 2015 10:27:24 -0700 Subject: [PATCH 0302/1783] Fix double autoscroll when moving cursor --- spec/text-editor-spec.coffee | 7 +++++++ src/cursor.coffee | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index d87952e85..bdb6b38fc 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -992,6 +992,13 @@ describe "TextEditor", -> editor.undo() expect(editor.getScrollTop()).toBe 0 + it "doesn't scroll when the cursor moves into the visible area", -> + editor.setCursorBufferPosition([0, 0]) + editor.setScrollTop(40) + expect(editor.getVisibleRowRange()).toEqual([4, 9]) + editor.setCursorBufferPosition([6, 0]) + expect(editor.getScrollTop()).toBe 40 + it "honors the autoscroll option on cursor and selection manipulation methods", -> expect(editor.getScrollTop()).toBe 0 editor.addCursorAtScreenPosition([11, 11], autoscroll: false) diff --git a/src/cursor.coffee b/src/cursor.coffee index c96f2eff5..de311358b 100644 --- a/src/cursor.coffee +++ b/src/cursor.coffee @@ -648,7 +648,7 @@ class Cursor extends Model ### changePosition: (options, fn) -> - @clearSelection(options) + @clearSelection(autoscroll: false) fn() @autoscroll() if options.autoscroll ? @isLastCursor() From ba867a14f0ded2f93c7056ae8cf99c8434a44661 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Fri, 27 Mar 2015 12:35:49 -0700 Subject: [PATCH 0303/1783] :arrow_up: settings-view@0.186.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 82b404f89..ad9fc3c80 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "open-on-github": "0.36.0", "package-generator": "0.38.0", "release-notes": "0.52.0", - "settings-view": "0.185.0", + "settings-view": "0.186.0", "snippets": "0.86.0", "spell-check": "0.55.0", "status-bar": "0.64.0", From 14cfefba46781442b178d65846bd6f14fccaae9c Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Fri, 27 Mar 2015 13:37:55 -0700 Subject: [PATCH 0304/1783] :arrow_up: deprecation-cop@0.38.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ad9fc3c80..b37ab89b2 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,7 @@ "bookmarks": "0.35.0", "bracket-matcher": "0.73.0", "command-palette": "0.34.0", - "deprecation-cop": "0.37.0", + "deprecation-cop": "0.38.0", "dev-live-reload": "0.45.0", "encoding-selector": "0.19.0", "exception-reporting": "0.24.0", From 51a7630f7637aa215e41e02ac6b47a32f5a238af Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Fri, 27 Mar 2015 15:36:40 -0700 Subject: [PATCH 0305/1783] :arrow_up: feedback@0.36.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b37ab89b2..f2cda4431 100644 --- a/package.json +++ b/package.json @@ -94,7 +94,7 @@ "dev-live-reload": "0.45.0", "encoding-selector": "0.19.0", "exception-reporting": "0.24.0", - "feedback": "0.35.0", + "feedback": "0.36.0", "find-and-replace": "0.159.0", "fuzzy-finder": "0.72.0", "git-diff": "0.54.0", From 167d9b01525505ca6e8f222c605d63e6435bdb2b Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Fri, 27 Mar 2015 15:55:33 -0700 Subject: [PATCH 0306/1783] :arrow_up: image-view@0.53.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f2cda4431..b74797ebf 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,7 @@ "git-diff": "0.54.0", "go-to-line": "0.30.0", "grammar-selector": "0.46.0", - "image-view": "0.52.0", + "image-view": "0.53.0", "incompatible-packages": "0.24.0", "keybinding-resolver": "0.29.0", "link": "0.30.0", From 3551780cdf953a0f275858663761bc9973015321 Mon Sep 17 00:00:00 2001 From: Nikolaus Wittenstein Date: Tue, 27 Jan 2015 10:34:06 -0500 Subject: [PATCH 0307/1783] Marker::setHead/TailScreenPosition no longer clip unnecessarily DisplayBuffer::bufferPositionForScreenPosition calls clipScreenPosition first thing, meaning that Marker::setHead/TailScreenPosition don't need to call clipScreenPosition before calling bufferPositionForScreenPosition. --- src/marker.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/marker.coffee b/src/marker.coffee index 22460c1f8..962ebb7e7 100644 --- a/src/marker.coffee +++ b/src/marker.coffee @@ -286,7 +286,6 @@ class Marker # * `screenPosition` The new {Point} to use # * `properties` (optional) {Object} properties to associate with the marker. setHeadScreenPosition: (screenPosition, properties) -> - screenPosition = @displayBuffer.clipScreenPosition(screenPosition, properties) @setHeadBufferPosition(@displayBuffer.bufferPositionForScreenPosition(screenPosition, properties)) # Extended: Retrieves the buffer position of the marker's tail. @@ -313,7 +312,6 @@ class Marker # * `screenPosition` The new {Point} to use # * `properties` (optional) {Object} properties to associate with the marker. setTailScreenPosition: (screenPosition, options) -> - screenPosition = @displayBuffer.clipScreenPosition(screenPosition, options) @setTailBufferPosition(@displayBuffer.bufferPositionForScreenPosition(screenPosition, options)) # Extended: Returns a {Boolean} indicating whether the marker has a tail. From 372fb49c88599ccf4e28bb821fa8dd9e2b7f94af Mon Sep 17 00:00:00 2001 From: Nikolaus Wittenstein Date: Tue, 27 Jan 2015 14:42:00 -0500 Subject: [PATCH 0308/1783] TokenizedLine::screenColumnForBufferColumn calculates more accurately screenColumnForBufferColumn used to break only if the current column was strictly greater than the target column. This commit changes it so it breaks when greater or equal, which is how bufferColumnForScreenColumn works. This also adds some unit tests for screenColumnForBufferColumn's interactions with hard tab characters. --- spec/display-buffer-spec.coffee | 8 ++++++++ src/tokenized-line.coffee | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index 2893fd5a4..7635f5074 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -719,6 +719,14 @@ describe "DisplayBuffer", -> expect(displayBuffer.screenPositionForBufferPosition([100000, 0])).toEqual [12, 2] expect(displayBuffer.screenPositionForBufferPosition([100000, 100000])).toEqual [12, 2] + it "clips to the (left or right) edge of an atomic token without simply rounding up", -> + tabLength = 4 + displayBuffer.setTabLength(tabLength) + + buffer.insert([0, 0], '\t') + expect(displayBuffer.screenPositionForBufferPosition([0, 0])).toEqual [0, 0] + expect(displayBuffer.screenPositionForBufferPosition([0, 1])).toEqual [0, tabLength] + describe "position translation in the presence of hard tabs", -> it "correctly translates positions on either side of a tab", -> buffer.setText('\t') diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 11badc859..a6209e210 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -67,7 +67,7 @@ class TokenizedLine screenColumn = 0 currentBufferColumn = 0 for token in @tokens - break if currentBufferColumn > bufferColumn + break if currentBufferColumn + token.bufferDelta > bufferColumn screenColumn += token.screenDelta currentBufferColumn += token.bufferDelta @clipScreenColumn(screenColumn + (bufferColumn - currentBufferColumn)) From 5a3f2035a1f7a7820eb01dc569a5d0ec5fcbcb8f Mon Sep 17 00:00:00 2001 From: Nikolaus Wittenstein Date: Tue, 27 Jan 2015 15:14:15 -0500 Subject: [PATCH 0309/1783] Replace skipAtomicTokens with clip When clipping a screen position, callers used to have to pick between clipping to the left edge or the right edge when the position was in the middle of an atomic token. This change allows them to choose the closest edge, and makes this the default. This makes selecting hard tabs (or any other atomic tokens) work in a similar manner as in other text editors; that is, when clicking near the middle of a tab, the insertion point will move to the closest edge rather than the left edge. --- spec/display-buffer-spec.coffee | 26 +++++++++++++++++++------- src/cursor.coffee | 4 ++-- src/selection.coffee | 2 +- src/tokenized-line.coffee | 21 ++++++++++++++++++--- 4 files changed, 40 insertions(+), 13 deletions(-) diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index 7635f5074..4d46f3da7 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -638,8 +638,11 @@ describe "DisplayBuffer", -> expect(displayBuffer.outermostFoldsInBufferRowRange(3, 18)).toEqual [fold1, fold3, fold5] expect(displayBuffer.outermostFoldsInBufferRowRange(5, 16)).toEqual [fold3] - describe "::clipScreenPosition(screenPosition, wrapBeyondNewlines: false, wrapAtSoftNewlines: false, skipAtomicTokens: false)", -> + describe "::clipScreenPosition(screenPosition, wrapBeyondNewlines: false, wrapAtSoftNewlines: false, clip: 'closest')", -> beforeEach -> + tabLength = 4 + + displayBuffer.setTabLength(tabLength) displayBuffer.setSoftWrapped(true) displayBuffer.setEditorWidthInChars(50) @@ -698,19 +701,28 @@ describe "DisplayBuffer", -> expect(displayBuffer.clipScreenPosition([3, 58], wrapAtSoftNewlines: true)).toEqual [4, 4] expect(displayBuffer.clipScreenPosition([3, 1000], wrapAtSoftNewlines: true)).toEqual [4, 4] - describe "when skipAtomicTokens is false (the default)", -> - it "clips screen positions in the middle of atomic tab characters to the beginning of the character", -> + describe "when clip is 'closest' (the default)", -> + it "clips screen positions in the middle of atomic tab characters to the closest edge of the character", -> buffer.insert([0, 0], '\t') expect(displayBuffer.clipScreenPosition([0, 0])).toEqual [0, 0] expect(displayBuffer.clipScreenPosition([0, 1])).toEqual [0, 0] + expect(displayBuffer.clipScreenPosition([0, 2])).toEqual [0, 0] + expect(displayBuffer.clipScreenPosition([0, tabLength-1])).toEqual [0, tabLength] expect(displayBuffer.clipScreenPosition([0, tabLength])).toEqual [0, tabLength] - describe "when skipAtomicTokens is true", -> + describe "when clip is 'backward'", -> + it "clips screen positions in the middle of atomic tab characters to the beginning of the character", -> + buffer.insert([0, 0], '\t') + expect(displayBuffer.clipScreenPosition([0, 0], clip: 'backward')).toEqual [0, 0] + expect(displayBuffer.clipScreenPosition([0, tabLength-1], clip: 'backward')).toEqual [0, 0] + expect(displayBuffer.clipScreenPosition([0, tabLength], clip: 'backward')).toEqual [0, tabLength] + + describe "when clip is 'forward'", -> it "clips screen positions in the middle of atomic tab characters to the end of the character", -> buffer.insert([0, 0], '\t') - expect(displayBuffer.clipScreenPosition([0, 0], skipAtomicTokens: true)).toEqual [0, 0] - expect(displayBuffer.clipScreenPosition([0, 1], skipAtomicTokens: true)).toEqual [0, tabLength] - expect(displayBuffer.clipScreenPosition([0, tabLength], skipAtomicTokens: true)).toEqual [0, tabLength] + expect(displayBuffer.clipScreenPosition([0, 0], clip: 'forward')).toEqual [0, 0] + expect(displayBuffer.clipScreenPosition([0, 1], clip: 'forward')).toEqual [0, tabLength] + expect(displayBuffer.clipScreenPosition([0, tabLength], clip: 'forward')).toEqual [0, tabLength] describe "::screenPositionForBufferPosition(bufferPosition, options)", -> it "clips the specified buffer position", -> diff --git a/src/cursor.coffee b/src/cursor.coffee index de311358b..c7db4b04a 100644 --- a/src/cursor.coffee +++ b/src/cursor.coffee @@ -305,7 +305,7 @@ class Cursor extends Model columnCount-- # subtract 1 for the row move column = column - columnCount - @setScreenPosition({row, column}) + @setScreenPosition({row, column}, clip: 'backward') # Public: Moves the cursor right one screen column. # @@ -332,7 +332,7 @@ class Cursor extends Model columnsRemainingInLine = rowLength column = column + columnCount - @setScreenPosition({row, column}, skipAtomicTokens: true, wrapBeyondNewlines: true, wrapAtSoftNewlines: true) + @setScreenPosition({row, column}, clip: 'forward', wrapBeyondNewlines: true, wrapAtSoftNewlines: true) # Public: Moves the cursor to the top of the buffer. moveToTop: -> diff --git a/src/selection.coffee b/src/selection.coffee index 0bee6f7de..ea4b54034 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -393,7 +393,7 @@ class Selection extends Model if options.select @setBufferRange(newBufferRange, reversed: wasReversed) else - @cursor.setBufferPosition(newBufferRange.end, skipAtomicTokens: true) if wasReversed + @cursor.setBufferPosition(newBufferRange.end, clip: 'forward') if wasReversed if autoIndentFirstLine @editor.setIndentationForBufferRow(oldBufferRange.start.row, desiredIndentLevel) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index a6209e210..074e7a785 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -41,10 +41,20 @@ class TokenizedLine copy: -> new TokenizedLine({@tokens, @lineEnding, @ruleStack, @startBufferColumn, @fold}) + # This clips a given screen column to a valid column that's within the line + # and not in the middle of any atomic tokens. + # + # column - A {Number} representing the column to clip + # options - A hash with the key clip. Valid values for this key: + # 'closest' (default): clip to the closest edge of an atomic token. + # 'forward': clip to the forward edge. + # 'backward': clip to the backward edge. + # + # Returns a {Number} representing the clipped column. clipScreenColumn: (column, options={}) -> return 0 if @tokens.length == 0 - { skipAtomicTokens } = options + { clip } = options column = Math.min(column, @getMaxScreenColumn()) tokenStartColumn = 0 @@ -55,10 +65,15 @@ class TokenizedLine if @isColumnInsideSoftWrapIndentation(tokenStartColumn) @softWrapIndentationDelta else if token.isAtomic and tokenStartColumn < column - if skipAtomicTokens + if clip == 'forward' tokenStartColumn + token.screenDelta - else + else if clip == 'backward' tokenStartColumn + else #'closest' + if column > tokenStartColumn + (token.screenDelta / 2) + tokenStartColumn + token.screenDelta + else + tokenStartColumn else column From b28ee92896a770504732f3d081e4053e4f93105e Mon Sep 17 00:00:00 2001 From: Nikolaus Wittenstein Date: Mon, 23 Mar 2015 09:42:37 -0400 Subject: [PATCH 0310/1783] Add tests for DisplayBuffer::screenPositionForBufferPosition around soft tabs This makes sure that a buffer position in the middle of a soft tab will correctly clip to the closest edge by default. --- spec/display-buffer-spec.coffee | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index 4d46f3da7..93460f173 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -739,6 +739,17 @@ describe "DisplayBuffer", -> expect(displayBuffer.screenPositionForBufferPosition([0, 0])).toEqual [0, 0] expect(displayBuffer.screenPositionForBufferPosition([0, 1])).toEqual [0, tabLength] + it "clips to the edge closest to the given position when it's inside a soft tab", -> + tabLength = 4 + displayBuffer.setTabLength(tabLength) + + buffer.insert([0, 0], ' ') + expect(displayBuffer.screenPositionForBufferPosition([0, 0])).toEqual [0, 0] + expect(displayBuffer.screenPositionForBufferPosition([0, 1])).toEqual [0, 0] + expect(displayBuffer.screenPositionForBufferPosition([0, 2])).toEqual [0, 0] + expect(displayBuffer.screenPositionForBufferPosition([0, 3])).toEqual [0, 4] + expect(displayBuffer.screenPositionForBufferPosition([0, 4])).toEqual [0, 4] + describe "position translation in the presence of hard tabs", -> it "correctly translates positions on either side of a tab", -> buffer.setText('\t') From 2e10517e1cb5f405617fff8ea17d5b28eb0265bf Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Thu, 29 Jan 2015 11:54:29 -0800 Subject: [PATCH 0311/1783] :arrow_up: asar@0.2.2 --- build/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/build/package.json b/build/package.json index aa3742e40..cb9954147 100644 --- a/build/package.json +++ b/build/package.json @@ -6,6 +6,7 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { + "asar": "^0.2.2", "async": "~0.2.9", "donna": "1.0.7", "formidable": "~1.0.14", From f9e80439d0c9caa40c2bd2070b236af1a13c20f7 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Thu, 29 Jan 2015 11:54:46 -0800 Subject: [PATCH 0312/1783] Add generate-asar task --- build/Gruntfile.coffee | 4 ++-- build/tasks/generate-asar-task.coffee | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 build/tasks/generate-asar-task.coffee diff --git a/build/Gruntfile.coffee b/build/Gruntfile.coffee index 05efaeb38..ed4c7b933 100644 --- a/build/Gruntfile.coffee +++ b/build/Gruntfile.coffee @@ -223,7 +223,7 @@ module.exports = (grunt) -> ciTasks = ['output-disk-space', 'download-atom-shell', 'download-atom-shell-chromedriver', 'build'] ciTasks.push('dump-symbols') if process.platform isnt 'win32' - ciTasks.push('set-version', 'check-licenses', 'lint') + ciTasks.push('set-version', 'check-licenses', 'lint', 'generate-asar') ciTasks.push('mkdeb') if process.platform is 'linux' ciTasks.push('create-windows-installer') if process.platform is 'win32' ciTasks.push('test') if process.platform is 'darwin' @@ -231,6 +231,6 @@ module.exports = (grunt) -> ciTasks.push('publish-build') grunt.registerTask('ci', ciTasks) - defaultTasks = ['download-atom-shell', 'download-atom-shell-chromedriver', 'build', 'set-version'] + defaultTasks = ['download-atom-shell', 'download-atom-shell-chromedriver', 'build', 'set-version', 'generate-asar'] defaultTasks.push 'install' unless process.platform is 'linux' grunt.registerTask('default', defaultTasks) diff --git a/build/tasks/generate-asar-task.coffee b/build/tasks/generate-asar-task.coffee new file mode 100644 index 000000000..266c6bf57 --- /dev/null +++ b/build/tasks/generate-asar-task.coffee @@ -0,0 +1,14 @@ +asar = require 'asar' +path = require 'path' + +module.exports = (grunt) -> + {rm} = require('./task-helpers')(grunt) + + grunt.registerTask 'generate-asar', 'Generate asar archive for the app', -> + done = @async() + + appDir = grunt.config.get('atom.appDir') + asar.createPackage appDir, path.resolve(appDir, '..', 'app.asar'), (err) -> + return done(err) if err? + rm appDir + done() From e79a23f39a4ea47fefcf3a4435f24cdf13ae58e2 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Sun, 1 Feb 2015 17:52:46 -0800 Subject: [PATCH 0313/1783] Do not set "cwd" for tasks The task can be inside an asar archive, which is not allowed to be cwd. --- src/task.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/task.coffee b/src/task.coffee index 9572494b8..cfea0fae5 100644 --- a/src/task.coffee +++ b/src/task.coffee @@ -83,7 +83,7 @@ class Task taskPath = taskPath.replace(/\\/g, "\\\\") env = _.extend({}, process.env, {taskPath, userAgent: navigator.userAgent}) - @childProcess = fork '--eval', [bootstrap], {env, cwd: __dirname} + @childProcess = fork '--eval', [bootstrap], {env} @on "task:log", -> console.log(arguments...) @on "task:warn", -> console.warn(arguments...) From a8b919f0e045b8e8dcfc1b8ff9137edd8b64401e Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 4 Feb 2015 12:17:39 -0800 Subject: [PATCH 0314/1783] Print errors that happened before task-bootstrap --- src/task.coffee | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/task.coffee b/src/task.coffee index cfea0fae5..d752ea11d 100644 --- a/src/task.coffee +++ b/src/task.coffee @@ -83,7 +83,7 @@ class Task taskPath = taskPath.replace(/\\/g, "\\\\") env = _.extend({}, process.env, {taskPath, userAgent: navigator.userAgent}) - @childProcess = fork '--eval', [bootstrap], {env} + @childProcess = fork '--eval', [bootstrap], {env, silent: true} @on "task:log", -> console.log(arguments...) @on "task:warn", -> console.warn(arguments...) @@ -100,6 +100,11 @@ class Task @childProcess.removeAllListeners() @childProcess.on 'message', ({event, args}) => @emit(event, args...) if @childProcess? + # Catch the errors that happened before task-bootstrap. + @childProcess.stdout.on 'data', (data) -> + console.log data.toString() + @childProcess.stderr.on 'data', (data) -> + console.error data.toString() # Public: Starts the task. # From 505754783fbf94d3cfc6c8f882e7721e46571965 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Thu, 5 Feb 2015 14:38:25 -0800 Subject: [PATCH 0315/1783] Warn empty app dir --- build/tasks/generate-asar-task.coffee | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build/tasks/generate-asar-task.coffee b/build/tasks/generate-asar-task.coffee index 266c6bf57..b6b0064ce 100644 --- a/build/tasks/generate-asar-task.coffee +++ b/build/tasks/generate-asar-task.coffee @@ -1,4 +1,5 @@ asar = require 'asar' +fs = require 'fs' path = require 'path' module.exports = (grunt) -> @@ -8,6 +9,10 @@ module.exports = (grunt) -> done = @async() appDir = grunt.config.get('atom.appDir') + unless fs.existsSync(appDir) + grunt.log.error 'The app has to be built before generating asar archive.' + return done(false) + asar.createPackage appDir, path.resolve(appDir, '..', 'app.asar'), (err) -> return done(err) if err? rm appDir From 01130230e4f6d6bd023e663b9e79ed548987b59e Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 25 Mar 2015 10:27:25 +0800 Subject: [PATCH 0316/1783] Copy LICENSE.md to process.resourcesPath The LICENSE file is needed by mkdeb task, we should move it out of asar archive. --- build/tasks/generate-license-task.coffee | 2 +- script/mkdeb | 2 +- src/browser/atom-application.coffee | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build/tasks/generate-license-task.coffee b/build/tasks/generate-license-task.coffee index 6b616f5cb..eaf1a9a66 100644 --- a/build/tasks/generate-license-task.coffee +++ b/build/tasks/generate-license-task.coffee @@ -17,7 +17,7 @@ module.exports = (grunt) -> licenseText = getLicenseText(dependencyLicenses) if mode is 'save' - targetPath = path.join(grunt.config.get('atom.appDir'), 'LICENSE.md') + targetPath = path.resolve(grunt.config.get('atom.appDir'), '..', 'LICENSE.md') fs.writeFileSync(targetPath, licenseText) else console.log licenseText diff --git a/script/mkdeb b/script/mkdeb index 272fe23f3..c39b6d649 100755 --- a/script/mkdeb +++ b/script/mkdeb @@ -33,7 +33,7 @@ cp "$ICON_FILE" "$TARGET/usr/share/pixmaps" # Copy generated LICENSE.md to /usr/share/doc/atom/copyright mkdir -m $FILE_MODE -p "$TARGET/usr/share/doc/atom" -cp "$TARGET/usr/share/atom/resources/app/LICENSE.md" "$TARGET/usr/share/doc/atom/copyright" +cp "$TARGET/usr/share/atom/resources/LICENSE.md" "$TARGET/usr/share/doc/atom/copyright" # Add lintian overrides mkdir -m $FILE_MODE -p "$TARGET/usr/share/lintian/overrides" diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index d79b2bf76..7d88858c5 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -190,7 +190,7 @@ class AtomApplication @openPathOnEvent('application:open-your-keymap', 'atom://.atom/keymap') @openPathOnEvent('application:open-your-snippets', 'atom://.atom/snippets') @openPathOnEvent('application:open-your-stylesheet', 'atom://.atom/stylesheet') - @openPathOnEvent('application:open-license', path.join(@resourcePath, 'LICENSE.md')) + @openPathOnEvent('application:open-license', path.join(process.resourcesPath, 'LICENSE.md')) app.on 'window-all-closed', -> app.quit() if process.platform in ['win32', 'linux'] From 3ce12693e6be43f35f8494bb63fcc0bdf06635c3 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 25 Mar 2015 13:35:03 +0800 Subject: [PATCH 0317/1783] Install apm to process.resourcesPath --- build/tasks/build-task.coffee | 6 +++--- src/command-installer.coffee | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/tasks/build-task.coffee b/build/tasks/build-task.coffee index fcb1eb6a8..74e5d8821 100644 --- a/build/tasks/build-task.coffee +++ b/build/tasks/build-task.coffee @@ -22,7 +22,7 @@ module.exports = (grunt) -> mkdir appDir if process.platform isnt 'win32' - cp 'atom.sh', path.join(appDir, 'atom.sh') + cp 'atom.sh', path.resolve(appDir, '..', 'atom.sh') cp 'package.json', path.join(appDir, 'package.json') @@ -145,9 +145,9 @@ module.exports = (grunt) -> cp 'src', path.join(appDir, 'src'), filter: /.+\.(cson|coffee)$/ cp 'static', path.join(appDir, 'static') - cp path.join('apm', 'node_modules', 'atom-package-manager'), path.join(appDir, 'apm'), filter: filterNodeModule + cp path.join('apm', 'node_modules', 'atom-package-manager'), path.resolve(appDir, '..', 'apm'), filter: filterNodeModule if process.platform isnt 'win32' - fs.symlinkSync(path.join('..', '..', 'bin', 'apm'), path.join(appDir, 'apm', 'node_modules', '.bin', 'apm')) + fs.symlinkSync(path.join('..', '..', 'bin', 'apm'), path.resolve(appDir, '..', 'apm', 'node_modules', '.bin', 'apm')) if process.platform is 'darwin' grunt.file.recurse path.join('resources', 'mac'), (sourcePath, rootDirectory, subDirectory='', filename) -> diff --git a/src/command-installer.coffee b/src/command-installer.coffee index 1d3a16777..b9d40bce0 100644 --- a/src/command-installer.coffee +++ b/src/command-installer.coffee @@ -36,7 +36,7 @@ module.exports = message: "Failed to install shell commands" detailedMessage: error.message - resourcePath = atom.getLoadSettings().resourcePath + resourcePath = process.resourcesPath @installAtomCommand resourcePath, true, (error) => if error? showErrorDialog(error) From 2d9f2091c5631bf43c7932bc92db9820888c80a3 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 25 Mar 2015 16:46:36 +0800 Subject: [PATCH 0318/1783] Unpack native module files It improves performance and makes virus scanners happy --- build/package.json | 2 +- build/tasks/generate-asar-task.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/package.json b/build/package.json index cb9954147..d7323db5c 100644 --- a/build/package.json +++ b/build/package.json @@ -6,7 +6,7 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "asar": "^0.2.2", + "asar": "^0.4.0", "async": "~0.2.9", "donna": "1.0.7", "formidable": "~1.0.14", diff --git a/build/tasks/generate-asar-task.coffee b/build/tasks/generate-asar-task.coffee index b6b0064ce..1f74fbf5d 100644 --- a/build/tasks/generate-asar-task.coffee +++ b/build/tasks/generate-asar-task.coffee @@ -13,7 +13,7 @@ module.exports = (grunt) -> grunt.log.error 'The app has to be built before generating asar archive.' return done(false) - asar.createPackage appDir, path.resolve(appDir, '..', 'app.asar'), (err) -> + asar.createPackageWithOptions appDir, path.resolve(appDir, '..', 'app.asar'), {unpack: '*.node'}, (err) -> return done(err) if err? rm appDir done() From c52058ef12a8b20946ea1be21488d3bedecade6a Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 25 Mar 2015 19:04:19 +0800 Subject: [PATCH 0319/1783] Always install commands from process.resourcesPath --- src/atom.coffee | 4 ++-- src/command-installer.coffee | 13 ++++++------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/atom.coffee b/src/atom.coffee index 707500479..fc4f59ef2 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -581,9 +581,9 @@ class Atom extends Model {resourcePath, safeMode} = @getLoadSettings() CommandInstaller = require './command-installer' - CommandInstaller.installAtomCommand resourcePath, false, (error) -> + CommandInstaller.installAtomCommand false, (error) -> console.warn error.message if error? - CommandInstaller.installApmCommand resourcePath, false, (error) -> + CommandInstaller.installApmCommand false, (error) -> console.warn error.message if error? dimensions = @restoreWindowDimensions() diff --git a/src/command-installer.coffee b/src/command-installer.coffee index b9d40bce0..c7772b4f5 100644 --- a/src/command-installer.coffee +++ b/src/command-installer.coffee @@ -36,12 +36,11 @@ module.exports = message: "Failed to install shell commands" detailedMessage: error.message - resourcePath = process.resourcesPath - @installAtomCommand resourcePath, true, (error) => + @installAtomCommand true, (error) => if error? showErrorDialog(error) else - @installApmCommand resourcePath, true, (error) -> + @installApmCommand true, (error) -> if error? showErrorDialog(error) else @@ -49,12 +48,12 @@ module.exports = message: "Commands installed." detailedMessage: "The shell commands `atom` and `apm` are installed." - installAtomCommand: (resourcePath, askForPrivilege, callback) -> - commandPath = path.join(resourcePath, 'atom.sh') + installAtomCommand: (askForPrivilege, callback) -> + commandPath = path.join(process.resourcesPath, 'atom.sh') @createSymlink commandPath, askForPrivilege, callback - installApmCommand: (resourcePath, askForPrivilege, callback) -> - commandPath = path.join(resourcePath, 'apm', 'node_modules', '.bin', 'apm') + installApmCommand: (askForPrivilege, callback) -> + commandPath = path.join(process.resourcesPath, 'apm', 'node_modules', '.bin', 'apm') @createSymlink commandPath, askForPrivilege, callback createSymlink: (commandPath, askForPrivilege, callback) -> From 685e4ebe960d5cb77bca606fb78fdaa81b96b0ed Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Thu, 26 Mar 2015 17:51:26 +0800 Subject: [PATCH 0320/1783] Update path to apm in squirrel-update and package-manager --- src/browser/squirrel-update.coffee | 2 +- src/package-manager.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/browser/squirrel-update.coffee b/src/browser/squirrel-update.coffee index 1603a7c0a..3bdd84223 100644 --- a/src/browser/squirrel-update.coffee +++ b/src/browser/squirrel-update.coffee @@ -142,7 +142,7 @@ addCommandsToPath = (callback) -> atomShCommand = "#!/bin/sh\r\n\"$0/../#{relativeAtomShPath.replace(/\\/g, '/')}\" \"$@\"" apmCommandPath = path.join(binFolder, 'apm.cmd') - relativeApmPath = path.relative(binFolder, path.join(process.resourcesPath, 'app', 'apm', 'bin', 'apm.cmd')) + relativeApmPath = path.relative(binFolder, path.join(process.resourcesPath, 'apm', 'bin', 'apm.cmd')) apmCommand = "@echo off\r\n\"%~dp0\\#{relativeApmPath}\" %*" apmShCommandPath = path.join(binFolder, 'apm') diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 444497c5b..2bbcf7fe7 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -134,7 +134,7 @@ class PackageManager commandName = 'apm' commandName += '.cmd' if process.platform is 'win32' - apmRoot = path.resolve(__dirname, '..', 'apm') + apmRoot = path.resolve(__dirname, '..', '..', 'apm') @apmPath = path.join(apmRoot, 'bin', commandName) unless fs.isFileSync(@apmPath) @apmPath = path.join(apmRoot, 'node_modules', 'atom-package-manager', 'bin', commandName) From e05bb2290296da549582c657a3fb4f8ec6499f0d Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 30 Mar 2015 15:02:02 +0800 Subject: [PATCH 0321/1783] :arrow_up: apm@0.153.0 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index e10632417..106878360 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.152.0" + "atom-package-manager": "0.153.0" } } From 14ba61f08d1f6ee128c5ae20e31fbec75ba502fc Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 30 Mar 2015 19:10:56 +0800 Subject: [PATCH 0322/1783] :arrow_up: apm@0.154.0 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index 106878360..c43f6e6be 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.153.0" + "atom-package-manager": "0.154.0" } } From 271ad2908badff9eaa74bae9514bd1a8d0402396 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 30 Mar 2015 19:31:38 +0800 Subject: [PATCH 0323/1783] :arrow_up: apm@0.155.0 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index c43f6e6be..318047a78 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.154.0" + "atom-package-manager": "0.155.0" } } From f83f37b53df8fa41e8e59d08e6dfff981dc52deb Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 30 Mar 2015 09:21:37 -0700 Subject: [PATCH 0324/1783] :arrow_up: atom-keymap@5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b74797ebf..308c2c662 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "atomShellVersion": "0.22.2", "dependencies": { "async": "0.2.6", - "atom-keymap": "^4", + "atom-keymap": "^5", "atom-space-pen-views": "^2.0.4", "babel-core": "^4.0.2", "bootstrap": "git+https://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372", From 3b9f829dc6d169c5980bff372ff06db83fe4a5cf Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 30 Mar 2015 09:57:38 -0700 Subject: [PATCH 0325/1783] :arrow_up: language-javascript@0.65 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 308c2c662..73c33cdb7 100644 --- a/package.json +++ b/package.json @@ -134,7 +134,7 @@ "language-html": "0.30.0", "language-hyperlink": "0.12.2", "language-java": "0.14.0", - "language-javascript": "0.64.0", + "language-javascript": "0.65.0", "language-json": "0.14.0", "language-less": "0.25.0", "language-make": "0.14.0", From 5a55c1bba6deb50cf019f1205909f3b65595c188 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Mon, 30 Mar 2015 09:59:33 -0700 Subject: [PATCH 0326/1783] :arrow_up: feedback@0.37.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 308c2c662..a795fcd4b 100644 --- a/package.json +++ b/package.json @@ -94,7 +94,7 @@ "dev-live-reload": "0.45.0", "encoding-selector": "0.19.0", "exception-reporting": "0.24.0", - "feedback": "0.36.0", + "feedback": "0.37.0", "find-and-replace": "0.159.0", "fuzzy-finder": "0.72.0", "git-diff": "0.54.0", From ed8051cb6140a1982b78ff95eb4a50f273a7e539 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 30 Mar 2015 10:01:49 -0700 Subject: [PATCH 0327/1783] :arrow_up: language-php@0.22 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 73c33cdb7..b91f0022c 100644 --- a/package.json +++ b/package.json @@ -141,7 +141,7 @@ "language-mustache": "0.11.0", "language-objective-c": "0.15.0", "language-perl": "0.21.0", - "language-php": "0.21.0", + "language-php": "0.22.0", "language-property-list": "0.8.0", "language-python": "0.32.0", "language-ruby": "0.50.0", From 72dff5b1c10321f7f6cd8554ddb9e11e3e24f0da Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 30 Mar 2015 10:03:41 -0700 Subject: [PATCH 0328/1783] :arrow_up: language-python@0.33 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b91f0022c..c23261aba 100644 --- a/package.json +++ b/package.json @@ -143,7 +143,7 @@ "language-perl": "0.21.0", "language-php": "0.22.0", "language-property-list": "0.8.0", - "language-python": "0.32.0", + "language-python": "0.33.0", "language-ruby": "0.50.0", "language-ruby-on-rails": "0.21.0", "language-sass": "0.36.0", From 4a864e79dca09f911bde74a2daf3bf321cdad0b0 Mon Sep 17 00:00:00 2001 From: Jesse Grosjean Date: Mon, 30 Mar 2015 13:05:45 -0400 Subject: [PATCH 0329/1783] Fix screenPositionForPixelPosition for case above first row. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently screenPositionForPixelPosition special cases pixel positions below the last row so that the column position is always set to the last column of the last line, even if the pixel 'x' position is less then that column. This patch special cases picks above the first row so that the text column position will be in the first column even if the pixel 'x' position is greater then that column. At a higher level, this patch fixes the problem where you can’t select to the start of a text field by just clicking and dragging up. Instead you have to click and drag back (x axis) beyond the start of the text field. --- src/display-buffer.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index b60113661..d79b1bce7 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -692,6 +692,7 @@ class DisplayBuffer extends Model targetLeft = pixelPosition.left defaultCharWidth = @defaultCharWidth row = Math.floor(targetTop / @getLineHeightInPixels()) + targetLeft = -Infinity if row < 0 targetLeft = Infinity if row > @getLastRow() row = Math.min(row, @getLastRow()) row = Math.max(0, row) From 4a05114b6d24dc0fd0c1a2ec87942b1a905b67be Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 30 Mar 2015 10:11:23 -0700 Subject: [PATCH 0330/1783] :arrow_up: markdown-preview@0.146 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c23261aba..5dd88b6ba 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,7 @@ "incompatible-packages": "0.24.0", "keybinding-resolver": "0.29.0", "link": "0.30.0", - "markdown-preview": "0.145.0", + "markdown-preview": "0.146.0", "metrics": "0.45.0", "notifications": "0.35.0", "open-on-github": "0.36.0", From b067a6175fe4f854b47499658f2d4cade4fd065f Mon Sep 17 00:00:00 2001 From: Jesse Grosjean Date: Mon, 30 Mar 2015 13:50:25 -0400 Subject: [PATCH 0331/1783] add screenPositionForPixelPosition spec --- spec/display-buffer-spec.coffee | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index 93460f173..5ece19692 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -724,6 +724,15 @@ describe "DisplayBuffer", -> expect(displayBuffer.clipScreenPosition([0, 1], clip: 'forward')).toEqual [0, tabLength] expect(displayBuffer.clipScreenPosition([0, tabLength], clip: 'forward')).toEqual [0, tabLength] + describe "::screenPositionForPixelPosition(pixelPosition)", -> + it "pixel positions above buffer to map to start", -> + expect(displayBuffer.screenPositionForPixelPosition(top: -Infinity, left: -Infinity)).toEqual [0, 0] + expect(displayBuffer.screenPositionForPixelPosition(top: -Infinity, left: Infinity)).toEqual [0, 0] + + it "pixel positions below buffer map to end", -> + expect(displayBuffer.screenPositionForPixelPosition(top: Infinity, left: -Infinity)).toEqual [12, 2] + expect(displayBuffer.screenPositionForPixelPosition(top: Infinity, left: Infinity)).toEqual [12, 2] + describe "::screenPositionForBufferPosition(bufferPosition, options)", -> it "clips the specified buffer position", -> expect(displayBuffer.screenPositionForBufferPosition([0, 2])).toEqual [0, 2] From 6ba881b9588ba98498924a412a13bfec4661ad03 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 30 Mar 2015 13:07:55 -0700 Subject: [PATCH 0332/1783] :arrow_up: feedback@0.38.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 60ebdb94a..c25004c7a 100644 --- a/package.json +++ b/package.json @@ -94,7 +94,7 @@ "dev-live-reload": "0.45.0", "encoding-selector": "0.19.0", "exception-reporting": "0.24.0", - "feedback": "0.37.0", + "feedback": "0.38.0", "find-and-replace": "0.159.0", "fuzzy-finder": "0.72.0", "git-diff": "0.54.0", From 6a9a824eacd29b8249d82120f3d5b3cc11e4c5f5 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 30 Mar 2015 13:36:40 -0700 Subject: [PATCH 0333/1783] :arrow_up: apm@0.156 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index e10632417..28c393ed5 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.152.0" + "atom-package-manager": "0.156.0" } } From 91710894660018988cfa87c5132333129dd1f0c6 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 30 Mar 2015 13:50:08 -0700 Subject: [PATCH 0334/1783] Add default syntax color vars Will be used by syntax themes, and autocomplete --- static/variables/syntax-variables.less | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/static/variables/syntax-variables.less b/static/variables/syntax-variables.less index 565341f7e..f569773e8 100644 --- a/static/variables/syntax-variables.less +++ b/static/variables/syntax-variables.less @@ -28,3 +28,16 @@ @syntax-color-modified: orange; @syntax-color-removed: red; @syntax-color-renamed: blue; + +// For language entity colors +@syntax-color-variable: #DF6A73; +@syntax-color-constant: #DF6A73; +@syntax-color-property: #DF6A73; +@syntax-color-value: #D29B67; +@syntax-color-function: #61AEEF; +@syntax-color-method: @syntax-color-function; +@syntax-color-class: #E5C17C; +@syntax-color-keyword: #555; +@syntax-color-tag: #555; +@syntax-color-import: #97C378; +@syntax-color-snippet: #97C378; From 2fcfb3416b5f5486b2f6b62fd4e22be3cadb9b59 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 30 Mar 2015 15:24:51 -0700 Subject: [PATCH 0335/1783] :arrow_up: language-javascript@0.66 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c25004c7a..b5cfa450c 100644 --- a/package.json +++ b/package.json @@ -134,7 +134,7 @@ "language-html": "0.30.0", "language-hyperlink": "0.12.2", "language-java": "0.14.0", - "language-javascript": "0.65.0", + "language-javascript": "0.66.0", "language-json": "0.14.0", "language-less": "0.25.0", "language-make": "0.14.0", From ba5ab1056d24307b77e78db6460521e27084f832 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Mon, 30 Mar 2015 15:53:12 -0700 Subject: [PATCH 0336/1783] :arrow_up: status-bar@0.66.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b5cfa450c..072bd5f26 100644 --- a/package.json +++ b/package.json @@ -113,7 +113,7 @@ "settings-view": "0.186.0", "snippets": "0.86.0", "spell-check": "0.55.0", - "status-bar": "0.64.0", + "status-bar": "0.66.0", "styleguide": "0.44.0", "symbols-view": "0.93.0", "tabs": "0.67.0", From d38b9a5b75ef3591aa642adba11a65dc0e73459f Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Mon, 30 Mar 2015 16:17:48 -0700 Subject: [PATCH 0337/1783] :arrow_up: deprecation-cop, image-view --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 072bd5f26..d6a56a02b 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,7 @@ "bookmarks": "0.35.0", "bracket-matcher": "0.73.0", "command-palette": "0.34.0", - "deprecation-cop": "0.38.0", + "deprecation-cop": "0.39.0", "dev-live-reload": "0.45.0", "encoding-selector": "0.19.0", "exception-reporting": "0.24.0", @@ -100,7 +100,7 @@ "git-diff": "0.54.0", "go-to-line": "0.30.0", "grammar-selector": "0.46.0", - "image-view": "0.53.0", + "image-view": "0.54.0", "incompatible-packages": "0.24.0", "keybinding-resolver": "0.29.0", "link": "0.30.0", From a06bf8127a4b3e206dd7fd9ad14b4acc227019ed Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 31 Mar 2015 08:55:47 -0700 Subject: [PATCH 0338/1783] :arrow_up: language-perl@0.22 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d6a56a02b..4315c5077 100644 --- a/package.json +++ b/package.json @@ -140,7 +140,7 @@ "language-make": "0.14.0", "language-mustache": "0.11.0", "language-objective-c": "0.15.0", - "language-perl": "0.21.0", + "language-perl": "0.22.0", "language-php": "0.22.0", "language-property-list": "0.8.0", "language-python": "0.33.0", From 7bd4eebee9effbac2f69261785ca5c33eabe1fcf Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 31 Mar 2015 09:09:23 -0700 Subject: [PATCH 0339/1783] :arrow_up: language-html@0.31 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4315c5077..2d4be5a27 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,7 @@ "language-gfm": "0.67.0", "language-git": "0.10.0", "language-go": "0.22.0", - "language-html": "0.30.0", + "language-html": "0.31.0", "language-hyperlink": "0.12.2", "language-java": "0.14.0", "language-javascript": "0.66.0", From ad0fd817fc890cc60391d752ea2964667f3759bf Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 31 Mar 2015 09:18:40 -0700 Subject: [PATCH 0340/1783] :arrow_up: language-javascript@0.67 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2d4be5a27..c8daa4a4f 100644 --- a/package.json +++ b/package.json @@ -134,7 +134,7 @@ "language-html": "0.31.0", "language-hyperlink": "0.12.2", "language-java": "0.14.0", - "language-javascript": "0.66.0", + "language-javascript": "0.67.0", "language-json": "0.14.0", "language-less": "0.25.0", "language-make": "0.14.0", From 2cc5140e1e024bf120d02b7761f69c6656180119 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 31 Mar 2015 11:06:33 -0700 Subject: [PATCH 0341/1783] :arrow_up: apm@0.157 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index 28c393ed5..84f73451d 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.156.0" + "atom-package-manager": "0.157.0" } } From 4cf34cc1fa96d6ad57edffdd16e8d65cbc830783 Mon Sep 17 00:00:00 2001 From: Vegar Vikan Date: Wed, 1 Apr 2015 00:21:59 +0200 Subject: [PATCH 0342/1783] Documentation: workspace.open( ) refrasing --- src/workspace.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/workspace.coffee b/src/workspace.coffee index c8040f920..6c60cf22a 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -371,8 +371,8 @@ class Workspace extends Model Section: Opening ### - # Essential: Open a given URI in Atom asynchronously. - # If no URI is given, or URI does not resolve to an existing file, + # Essential: Opens the given URI in Atom asynchronously, if it's not already open. + # If no URI is given, or the URI is the path of a file that does not exist, # a new empty text edtior is created. # # * `uri` (optional) A {String} containing a URI. From dc0296851b6a0e6ff66d8576fd546d90ee50b4bb Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 31 Mar 2015 16:04:13 -0700 Subject: [PATCH 0343/1783] :arrow_up: grunt-atom-shell-installer@0.27 --- build/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/package.json b/build/package.json index aa3742e40..941f711d8 100644 --- a/build/package.json +++ b/build/package.json @@ -12,7 +12,7 @@ "fs-plus": "2.x", "github-releases": "~0.2.0", "grunt": "~0.4.1", - "grunt-atom-shell-installer": "^0.25.0", + "grunt-atom-shell-installer": "^0.27.0", "grunt-cli": "~0.1.9", "grunt-coffeelint": "git+https://github.com/atom/grunt-coffeelint.git#cfb99aa99811d52687969532bd5a98011ed95bfe", "grunt-contrib-coffee": "~0.12.0", From e1e34baaea55a687f37e860b80784f1e38bef568 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 31 Mar 2015 16:42:21 -0700 Subject: [PATCH 0344/1783] :arrow_down: grunt-atom-shell-installer@0.25 --- build/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/package.json b/build/package.json index 941f711d8..aa3742e40 100644 --- a/build/package.json +++ b/build/package.json @@ -12,7 +12,7 @@ "fs-plus": "2.x", "github-releases": "~0.2.0", "grunt": "~0.4.1", - "grunt-atom-shell-installer": "^0.27.0", + "grunt-atom-shell-installer": "^0.25.0", "grunt-cli": "~0.1.9", "grunt-coffeelint": "git+https://github.com/atom/grunt-coffeelint.git#cfb99aa99811d52687969532bd5a98011ed95bfe", "grunt-contrib-coffee": "~0.12.0", From 93e4b061fa63ee8b134f6bebaa3a148a3616c71a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mert=20Kahyao=C4=9Flu?= Date: Wed, 1 Apr 2015 14:48:23 +0300 Subject: [PATCH 0345/1783] minor changes in decoration.coffee --- src/decoration.coffee | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/decoration.coffee b/src/decoration.coffee index fdaaa285d..cbf649473 100644 --- a/src/decoration.coffee +++ b/src/decoration.coffee @@ -20,7 +20,7 @@ nextId = -> idCounter++ # decoration = editor.decorateMarker(marker, {type: 'line', class: 'my-line-class'}) # ``` # -# Best practice for destorying the decoration is by destroying the {Marker}. +# Best practice for destroying the decoration is by destroying the {Marker}. # # ```coffee # marker.destroy() @@ -56,7 +56,6 @@ class Decoration @properties.id = @id @flashQueue = null @destroyed = false - @markerDestroyDisposable = @marker.onDidDestroy => @destroy() # Essential: Destroy this marker. From 639fde343cc81a4986246f71d2fa14eb355601bd Mon Sep 17 00:00:00 2001 From: Jesse Grosjean Date: Wed, 11 Feb 2015 10:47:36 -0500 Subject: [PATCH 0346/1783] Export File and Directory through require('atom') Conflicts: exports/atom.coffee --- exports/atom.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/exports/atom.coffee b/exports/atom.coffee index 5afa04022..dab0b007f 100644 --- a/exports/atom.coffee +++ b/exports/atom.coffee @@ -1,5 +1,6 @@ TextBuffer = require 'text-buffer' {Point, Range} = TextBuffer +{File, Directory} = require 'pathwatcher' {Emitter, Disposable, CompositeDisposable} = require 'event-kit' {deprecate} = require 'grim' @@ -11,6 +12,8 @@ module.exports = TextBuffer: TextBuffer Point: Point Range: Range + File: File + Directory: Directory Emitter: Emitter Disposable: Disposable CompositeDisposable: CompositeDisposable From 4612e023ce9a965ad7f47caf048bb5dae2420a31 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 1 Apr 2015 09:15:39 -0700 Subject: [PATCH 0347/1783] Delete temp npm folders at beginning of CI build --- script/cibuild | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/script/cibuild b/script/cibuild index c63d5dbf6..e34feacde 100755 --- a/script/cibuild +++ b/script/cibuild @@ -46,8 +46,39 @@ function removeNodeModules() { } } +function removeTempFolders() { + var fsPlus; + try { + fsPlus = require('fs-plus'); + } catch (error) { + return; + } + + var temp = require('os').tmpdir(); + if (!fsPlus.isDirectorySync(temp)) + return; + + var deletedFolders = 0; + + try { + fsPlus.readdirSync(temp).filter(function(folderName) { + return folderName.indexOf('npm-') === 0; + }).forEach(function(folderName) { + fsPlus.removeSync(path.join(temp, folderName)); + deletedFolders++; + }); + + if (deletedFolders > 0) + console.log("Deleted " + deletedFolder + " npm folders from temp directory"); + } catch (error) { + console.error(error.message); + process.exit(1); + } +} + readEnvironmentVariables(); removeNodeModules(); +removeTempFolders(); cp.safeExec.bind(global, 'npm install npm --loglevel error', {cwd: path.resolve(__dirname, '..', 'build')}, function() { cp.safeExec.bind(global, 'node script/bootstrap', function(error) { if (error) From fead441acf6afdbe402ff0f00e4246eebf71721d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 1 Apr 2015 09:22:47 -0700 Subject: [PATCH 0348/1783] deletedFolder -> deletedFolders --- script/cibuild | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/cibuild b/script/cibuild index e34feacde..682568bb5 100755 --- a/script/cibuild +++ b/script/cibuild @@ -69,7 +69,7 @@ function removeTempFolders() { }); if (deletedFolders > 0) - console.log("Deleted " + deletedFolder + " npm folders from temp directory"); + console.log("Deleted " + deletedFolders + " npm folders from temp directory"); } catch (error) { console.error(error.message); process.exit(1); From 409775b53edaa6081b85cbd5c75e66df13566b8e Mon Sep 17 00:00:00 2001 From: Jesse Grosjean Date: Wed, 1 Apr 2015 12:39:22 -0400 Subject: [PATCH 0349/1783] Improved specs for clipping pixel positions above/below display buffer --- spec/display-buffer-spec.coffee | 10 ++++++++-- spec/text-editor-component-spec.coffee | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index 5ece19692..b5858007e 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -725,13 +725,19 @@ describe "DisplayBuffer", -> expect(displayBuffer.clipScreenPosition([0, tabLength], clip: 'forward')).toEqual [0, tabLength] describe "::screenPositionForPixelPosition(pixelPosition)", -> - it "pixel positions above buffer to map to start", -> + it "clips pixel positions above buffer start", -> + displayBuffer.setLineHeightInPixels(20) expect(displayBuffer.screenPositionForPixelPosition(top: -Infinity, left: -Infinity)).toEqual [0, 0] expect(displayBuffer.screenPositionForPixelPosition(top: -Infinity, left: Infinity)).toEqual [0, 0] + expect(displayBuffer.screenPositionForPixelPosition(top: -1, left: Infinity)).toEqual [0, 0] + expect(displayBuffer.screenPositionForPixelPosition(top: 0, left: Infinity)).toEqual [0, 29] - it "pixel positions below buffer map to end", -> + it "clips pixel positions below buffer end", -> + displayBuffer.setLineHeightInPixels(20) expect(displayBuffer.screenPositionForPixelPosition(top: Infinity, left: -Infinity)).toEqual [12, 2] expect(displayBuffer.screenPositionForPixelPosition(top: Infinity, left: Infinity)).toEqual [12, 2] + expect(displayBuffer.screenPositionForPixelPosition(top: displayBuffer.getHeight() + 1, left: 0)).toEqual [12, 2] + expect(displayBuffer.screenPositionForPixelPosition(top: displayBuffer.getHeight() - 1, left: 0)).toEqual [12, 0] describe "::screenPositionForBufferPosition(bufferPosition, options)", -> it "clips the specified buffer position", -> diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 656dca0f0..df1fbcfbf 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -1559,6 +1559,22 @@ describe "TextEditorComponent", -> beforeEach -> linesNode = componentNode.querySelector('.lines') + describe "when the mouse is single-clicked above the first line", -> + it "moves the cursor to the start of file buffer position", -> + editor.setText('foo') + editor.setCursorBufferPosition([0, 3]) + height = 4.5 * lineHeightInPixels + wrapperNode.style.height = height + 'px' + wrapperNode.style.width = 10 * charWidth + 'px' + component.measureHeightAndWidth() + nextAnimationFrame() + + coordinates = clientCoordinatesForScreenPosition([0, 2]) + coordinates.clientY = -1 + linesNode.dispatchEvent(buildMouseEvent('mousedown', coordinates)) + nextAnimationFrame() + expect(editor.getCursorScreenPosition()).toEqual [0, 0] + describe "when the mouse is single-clicked below the last line", -> it "moves the cursor to the end of file buffer position", -> editor.setText('foo') From 744bc787ce1fbac4e15a131f1bd464bd9209099e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 1 Apr 2015 10:02:41 -0700 Subject: [PATCH 0350/1783] Log delete errors but do not fail build --- script/cibuild | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/script/cibuild b/script/cibuild index 682568bb5..08ff65c6e 100755 --- a/script/cibuild +++ b/script/cibuild @@ -60,20 +60,19 @@ function removeTempFolders() { var deletedFolders = 0; - try { - fsPlus.readdirSync(temp).filter(function(folderName) { - return folderName.indexOf('npm-') === 0; - }).forEach(function(folderName) { + fsPlus.readdirSync(temp).filter(function(folderName) { + return folderName.indexOf('npm-') === 0; + }).forEach(function(folderName) { + try { fsPlus.removeSync(path.join(temp, folderName)); deletedFolders++; - }); + } catch (error) { + console.error("Failed to delete npm temp folder: " + error.message); + } + }); - if (deletedFolders > 0) - console.log("Deleted " + deletedFolders + " npm folders from temp directory"); - } catch (error) { - console.error(error.message); - process.exit(1); - } + if (deletedFolders > 0) + console.log("Deleted " + deletedFolders + " npm folders from temp directory"); } readEnvironmentVariables(); From 33faef249924b97f68ec808752931502000fce19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mert=20Kahyao=C4=9Flu?= Date: Wed, 1 Apr 2015 20:34:59 +0300 Subject: [PATCH 0351/1783] remove duplicate switch case --- src/cursor.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/cursor.coffee b/src/cursor.coffee index c7db4b04a..acfc7fc9e 100644 --- a/src/cursor.coffee +++ b/src/cursor.coffee @@ -94,8 +94,6 @@ class Cursor extends Model Grim.deprecate("Use Cursor::onDidChangePosition instead") when 'destroyed' Grim.deprecate("Use Cursor::onDidDestroy instead") - when 'destroyed' - Grim.deprecate("Use Cursor::onDidDestroy instead") else Grim.deprecate("::on is no longer supported. Use the event subscription methods instead") super From 0f43b246b4ef5c1759c81440e8b0b2abbf9230d3 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Wed, 1 Apr 2015 12:04:11 -0700 Subject: [PATCH 0352/1783] add styleguide for specs --- CONTRIBUTING.md | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d2cf02bef..a6736e11b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -48,7 +48,7 @@ For more information on how to work with Atom's official packages, see [JavaScript](https://github.com/styleguide/javascript), and [CSS](https://github.com/styleguide/css) styleguides. * Include thoughtfully-worded, well-structured - [Jasmine](http://jasmine.github.io/) specs in the `./spec` folder. Run them using `apm test`. + [Jasmine](http://jasmine.github.io/) specs in the `./spec` folder. Run them using `apm test`. See the [Specs Styleguide](#specs-styleguide) below. * Document new code based on the [Documentation Styleguide](#documentation-styleguide) * End files with a newline. @@ -108,6 +108,24 @@ For more information on how to work with Atom's official packages, see * Add an explicit `return` when your function ends with a `for`/`while` loop and you don't want it to return a collected array. +## Specs Styleguide + +- Include thoughtfully-worded, well-structured + [Jasmine](http://jasmine.github.io/) specs in the `./spec` folder. +- treat `describe` as a noun or situation. +- trea `it` as a statement about state or how an operation changes state. + +### Example + +```coffee +describe 'a dog' + it 'barks' + # spec here + describe 'when the dog is happy' + it 'wags its tail' + # spec here +``` + ## Documentation Styleguide * Use [AtomDoc](https://github.com/atom/atomdoc). From 293b34e2a4175f0f964cc796d7259822f97a0dd3 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Wed, 1 Apr 2015 12:10:02 -0700 Subject: [PATCH 0353/1783] typo --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a6736e11b..88c0ffa47 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -113,7 +113,7 @@ For more information on how to work with Atom's official packages, see - Include thoughtfully-worded, well-structured [Jasmine](http://jasmine.github.io/) specs in the `./spec` folder. - treat `describe` as a noun or situation. -- trea `it` as a statement about state or how an operation changes state. +- treat `it` as a statement about state or how an operation changes state. ### Example From 10912da5102df4344108eea0cdc7e66b4f4b0ba2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 1 Apr 2015 12:25:55 -0700 Subject: [PATCH 0354/1783] :arrow_up: settings-view@0.187 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c8daa4a4f..3f55fcece 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "open-on-github": "0.36.0", "package-generator": "0.38.0", "release-notes": "0.52.0", - "settings-view": "0.186.0", + "settings-view": "0.187.0", "snippets": "0.86.0", "spell-check": "0.55.0", "status-bar": "0.66.0", From 691b1255d8e7b790fc4c422839a93ac032821790 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 1 Apr 2015 10:26:08 +0800 Subject: [PATCH 0355/1783] :arrow_up: atom-shell@0.22.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3f55fcece..374f70956 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "url": "http://github.com/atom/atom/raw/master/LICENSE.md" } ], - "atomShellVersion": "0.22.2", + "atomShellVersion": "0.22.3", "dependencies": { "async": "0.2.6", "atom-keymap": "^5", From cfca178eef0c08a8bd36618787b96dedcfcaf0e0 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 1 Apr 2015 16:45:14 +0800 Subject: [PATCH 0356/1783] :arrow_up: grunt-atom-shell-installer@0.28 --- build/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/package.json b/build/package.json index aa3742e40..297ddadfd 100644 --- a/build/package.json +++ b/build/package.json @@ -12,7 +12,7 @@ "fs-plus": "2.x", "github-releases": "~0.2.0", "grunt": "~0.4.1", - "grunt-atom-shell-installer": "^0.25.0", + "grunt-atom-shell-installer": "^0.28.0", "grunt-cli": "~0.1.9", "grunt-coffeelint": "git+https://github.com/atom/grunt-coffeelint.git#cfb99aa99811d52687969532bd5a98011ed95bfe", "grunt-contrib-coffee": "~0.12.0", From bec4b34385d0ed44214bffd5e236202fc120e702 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 1 Apr 2015 10:35:19 -0700 Subject: [PATCH 0357/1783] Log squirrel log on failures --- script/cibuild | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/script/cibuild b/script/cibuild index 08ff65c6e..4f2612ed8 100755 --- a/script/cibuild +++ b/script/cibuild @@ -90,6 +90,12 @@ cp.safeExec.bind(global, 'npm install npm --loglevel error', {cwd: path.resolve( cp.safeExec.bind(global, gruntPath + ' ci --gruntfile build/Gruntfile.coffee --stack --no-color'), ] async.series(tasks, function(error) { + if (error && process.platform === 'win32') { + var fs = require('fs'); + var squirrelLog = path.resolve(__dirname, 'build', 'node_modules', 'grunt-atom-shell-installer', 'vendor', 'SquirrelSetup.log'); + if (fs.existsSync(squirrelLog)) + console.log(fs.readFileSync(squirrelLog)); + } process.exit(error ? 1 : 0); }); })(); From 3d8c19fc79c7e1091db348dba90c4cf4aeea47b5 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 1 Apr 2015 10:35:52 -0700 Subject: [PATCH 0358/1783] Add missing .. --- script/cibuild | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/cibuild b/script/cibuild index 4f2612ed8..41c90f7b3 100755 --- a/script/cibuild +++ b/script/cibuild @@ -92,7 +92,7 @@ cp.safeExec.bind(global, 'npm install npm --loglevel error', {cwd: path.resolve( async.series(tasks, function(error) { if (error && process.platform === 'win32') { var fs = require('fs'); - var squirrelLog = path.resolve(__dirname, 'build', 'node_modules', 'grunt-atom-shell-installer', 'vendor', 'SquirrelSetup.log'); + var squirrelLog = path.resolve(__dirname, '..', 'build', 'node_modules', 'grunt-atom-shell-installer', 'vendor', 'SquirrelSetup.log'); if (fs.existsSync(squirrelLog)) console.log(fs.readFileSync(squirrelLog)); } From d384e0492d89b1d8fedeb633d7c51eed82218573 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 1 Apr 2015 10:40:59 -0700 Subject: [PATCH 0359/1783] Add charset to read call --- script/cibuild | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/cibuild b/script/cibuild index 41c90f7b3..e418d1a15 100755 --- a/script/cibuild +++ b/script/cibuild @@ -94,7 +94,7 @@ cp.safeExec.bind(global, 'npm install npm --loglevel error', {cwd: path.resolve( var fs = require('fs'); var squirrelLog = path.resolve(__dirname, '..', 'build', 'node_modules', 'grunt-atom-shell-installer', 'vendor', 'SquirrelSetup.log'); if (fs.existsSync(squirrelLog)) - console.log(fs.readFileSync(squirrelLog)); + console.log(fs.readFileSync(squirrelLog, 'utf8')); } process.exit(error ? 1 : 0); }); From 631acbd8d487d19173cc376a3d055a036919b782 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 1 Apr 2015 11:02:12 -0700 Subject: [PATCH 0360/1783] Log location --- script/cibuild | 1 + 1 file changed, 1 insertion(+) diff --git a/script/cibuild b/script/cibuild index e418d1a15..e9da6232a 100755 --- a/script/cibuild +++ b/script/cibuild @@ -93,6 +93,7 @@ cp.safeExec.bind(global, 'npm install npm --loglevel error', {cwd: path.resolve( if (error && process.platform === 'win32') { var fs = require('fs'); var squirrelLog = path.resolve(__dirname, '..', 'build', 'node_modules', 'grunt-atom-shell-installer', 'vendor', 'SquirrelSetup.log'); + console.log(squirrelLog, fs.existsSync(squirrelLog)); if (fs.existsSync(squirrelLog)) console.log(fs.readFileSync(squirrelLog, 'utf8')); } From 7027f8619c32a20753fcd15128bb66af3e90083b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 1 Apr 2015 11:18:41 -0700 Subject: [PATCH 0361/1783] Always log squirrel log --- script/cibuild | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/script/cibuild b/script/cibuild index e9da6232a..1e45aa84e 100755 --- a/script/cibuild +++ b/script/cibuild @@ -90,13 +90,13 @@ cp.safeExec.bind(global, 'npm install npm --loglevel error', {cwd: path.resolve( cp.safeExec.bind(global, gruntPath + ' ci --gruntfile build/Gruntfile.coffee --stack --no-color'), ] async.series(tasks, function(error) { - if (error && process.platform === 'win32') { - var fs = require('fs'); - var squirrelLog = path.resolve(__dirname, '..', 'build', 'node_modules', 'grunt-atom-shell-installer', 'vendor', 'SquirrelSetup.log'); - console.log(squirrelLog, fs.existsSync(squirrelLog)); - if (fs.existsSync(squirrelLog)) - console.log(fs.readFileSync(squirrelLog, 'utf8')); - } + console.log('DONE-----'); + var fs = require('fs'); + var squirrelLog = path.resolve(__dirname, '..', 'build', 'node_modules', 'grunt-atom-shell-installer', 'vendor', 'SquirrelSetup.log'); + console.log(squirrelLog, fs.existsSync(squirrelLog)); + if (fs.existsSync(squirrelLog)) + console.log(fs.readFileSync(squirrelLog, 'utf8')); + process.exit(error ? 1 : 0); }); })(); From f24ea101e9ba46206c79ed7529a203c4c0b02599 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 1 Apr 2015 11:21:40 -0700 Subject: [PATCH 0362/1783] Log squirrel log in exit handler --- script/cibuild | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/script/cibuild b/script/cibuild index 1e45aa84e..bb26b8ac9 100755 --- a/script/cibuild +++ b/script/cibuild @@ -90,14 +90,18 @@ cp.safeExec.bind(global, 'npm install npm --loglevel error', {cwd: path.resolve( cp.safeExec.bind(global, gruntPath + ' ci --gruntfile build/Gruntfile.coffee --stack --no-color'), ] async.series(tasks, function(error) { - console.log('DONE-----'); - var fs = require('fs'); - var squirrelLog = path.resolve(__dirname, '..', 'build', 'node_modules', 'grunt-atom-shell-installer', 'vendor', 'SquirrelSetup.log'); - console.log(squirrelLog, fs.existsSync(squirrelLog)); - if (fs.existsSync(squirrelLog)) - console.log(fs.readFileSync(squirrelLog, 'utf8')); - process.exit(error ? 1 : 0); }); })(); })(); + + +process.on('exit', function() { + console.log('DONE-----'); + var fs = require('fs'); + var squirrelLog = path.resolve(__dirname, '..', 'build', 'node_modules', 'grunt-atom-shell-installer', 'vendor', 'SquirrelSetup.log'); + console.log(squirrelLog, fs.existsSync(squirrelLog)); + if (fs.existsSync(squirrelLog)) + console.log(fs.readFileSync(squirrelLog, 'utf8')); + +}); From 4b90926ccf796286d6636950d7335f7cc993ec68 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 1 Apr 2015 11:38:02 -0700 Subject: [PATCH 0363/1783] Log errors --- script/cibuild | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/script/cibuild b/script/cibuild index bb26b8ac9..9358cc09c 100755 --- a/script/cibuild +++ b/script/cibuild @@ -98,10 +98,14 @@ cp.safeExec.bind(global, 'npm install npm --loglevel error', {cwd: path.resolve( process.on('exit', function() { console.log('DONE-----'); - var fs = require('fs'); - var squirrelLog = path.resolve(__dirname, '..', 'build', 'node_modules', 'grunt-atom-shell-installer', 'vendor', 'SquirrelSetup.log'); - console.log(squirrelLog, fs.existsSync(squirrelLog)); - if (fs.existsSync(squirrelLog)) - console.log(fs.readFileSync(squirrelLog, 'utf8')); + try { + var fs = require('fs'); + var squirrelLog = path.resolve(__dirname, '..', 'build', 'node_modules', 'grunt-atom-shell-installer', 'vendor', 'SquirrelSetup.log'); + console.log(squirrelLog, fs.existsSync(squirrelLog)); + if (fs.existsSync(squirrelLog)) + console.log(fs.readFileSync(squirrelLog, 'utf8')); + } catch (error) { + console.error(error.message); + } }); From b44b4a237269e26e73c49522cd8f2d13a310907f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 1 Apr 2015 11:58:22 -0700 Subject: [PATCH 0364/1783] Remove squirrel log output --- script/cibuild | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/script/cibuild b/script/cibuild index 9358cc09c..08ff65c6e 100755 --- a/script/cibuild +++ b/script/cibuild @@ -94,18 +94,3 @@ cp.safeExec.bind(global, 'npm install npm --loglevel error', {cwd: path.resolve( }); })(); })(); - - -process.on('exit', function() { - console.log('DONE-----'); - try { - var fs = require('fs'); - var squirrelLog = path.resolve(__dirname, '..', 'build', 'node_modules', 'grunt-atom-shell-installer', 'vendor', 'SquirrelSetup.log'); - console.log(squirrelLog, fs.existsSync(squirrelLog)); - if (fs.existsSync(squirrelLog)) - console.log(fs.readFileSync(squirrelLog, 'utf8')); - } catch (error) { - console.error(error.message); - } - -}); From 2bfdb5d7770288a627f0242da24b86a6e40056dd Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Wed, 1 Apr 2015 14:37:42 -0700 Subject: [PATCH 0365/1783] add syntax --- CONTRIBUTING.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 88c0ffa47..9041b3fcd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -118,11 +118,11 @@ For more information on how to work with Atom's official packages, see ### Example ```coffee -describe 'a dog' - it 'barks' +describe 'a dog', -> + it 'barks', -> # spec here - describe 'when the dog is happy' - it 'wags its tail' + describe 'when the dog is happy', -> + it 'wags its tail', -> # spec here ``` From 88e65fbbb7e7480fa72158538948128f05304b74 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 1 Apr 2015 14:45:15 -0700 Subject: [PATCH 0366/1783] Prepare 0.190 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 374f70956..cebd145fe 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "0.189.0", + "version": "0.190.0", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From 53445b0e7d3d6efd19f774e8112bad33c2175497 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 1 Apr 2015 17:39:22 -0700 Subject: [PATCH 0367/1783] :arrow_up: snippets@0.87.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cebd145fe..75e2a325d 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "package-generator": "0.38.0", "release-notes": "0.52.0", "settings-view": "0.187.0", - "snippets": "0.86.0", + "snippets": "0.87.0", "spell-check": "0.55.0", "status-bar": "0.66.0", "styleguide": "0.44.0", From db35022d0e88f64f4e98001f37fc58cbdb5ea4db Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 30 Mar 2015 17:17:21 -0700 Subject: [PATCH 0368/1783] Remove OverlayManager from the LinesComponent --- src/lines-component.coffee | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/lines-component.coffee b/src/lines-component.coffee index 8389a1ae9..5004d4060 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -4,7 +4,6 @@ _ = require 'underscore-plus' CursorsComponent = require './cursors-component' HighlightsComponent = require './highlights-component' -OverlayManager = require './overlay-manager' DummyLineNode = $$(-> @div className: 'line', style: 'position: absolute; visibility: hidden;', => @span 'x')[0] AcceptFilter = {acceptNode: -> NodeFilter.FILTER_ACCEPT} @@ -40,13 +39,6 @@ class LinesComponent insertionPoint.setAttribute('select', '.overlayer') @domNode.appendChild(insertionPoint) - insertionPoint = document.createElement('content') - insertionPoint.setAttribute('select', 'atom-overlay') - @overlayManager = new OverlayManager(@presenter, @hostElement) - @domNode.appendChild(insertionPoint) - else - @overlayManager = new OverlayManager(@presenter, @domNode) - updateSync: (state) -> @newState = state.content @oldState ?= {lines: {}} @@ -82,8 +74,6 @@ class LinesComponent @cursorsComponent.updateSync(state) @highlightsComponent.updateSync(state) - @overlayManager?.render(state) - @oldState.indentGuidesVisible = @newState.indentGuidesVisible @oldState.scrollWidth = @newState.scrollWidth From 2338f8e65b92289b088898118d4266e6f6e21a1c Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 30 Mar 2015 17:19:18 -0700 Subject: [PATCH 0369/1783] Make atom-pane `overflow: visible` This allows children of the pane-item to make the decision to overflow or not. --- static/panes.less | 2 +- static/text-editor-shadow.less | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/static/panes.less b/static/panes.less index cb8bb6565..bf275e6da 100644 --- a/static/panes.less +++ b/static/panes.less @@ -24,7 +24,7 @@ atom-pane-container { display: -webkit-flex; -webkit-flex: 1; -webkit-flex-direction: column; - overflow: hidden; + overflow: visible; .item-views { -webkit-flex: 1; diff --git a/static/text-editor-shadow.less b/static/text-editor-shadow.less index 63d27de7f..c67637290 100644 --- a/static/text-editor-shadow.less +++ b/static/text-editor-shadow.less @@ -9,7 +9,6 @@ .editor-contents--private { width: 100%; - overflow: hidden; cursor: text; display: -webkit-flex; -webkit-user-select: none; From 8749db30cf8138a2c75393efc835fd5cfe632721 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 30 Mar 2015 17:20:27 -0700 Subject: [PATCH 0370/1783] Add OverlayManager to the TextEditorComponent --- src/text-editor-component.coffee | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 63a7f9a1c..3bebaea49 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -11,6 +11,7 @@ InputComponent = require './input-component' LinesComponent = require './lines-component' ScrollbarComponent = require './scrollbar-component' ScrollbarCornerComponent = require './scrollbar-corner-component' +OverlayManager = require './overlay-manager' module.exports = class TextEditorComponent @@ -56,8 +57,14 @@ class TextEditorComponent @domNode = document.createElement('div') if @useShadowDOM @domNode.classList.add('editor-contents--private') + + insertionPoint = document.createElement('content') + insertionPoint.setAttribute('select', 'atom-overlay') + @domNode.appendChild(insertionPoint) + @overlayManager = new OverlayManager(@presenter, @hostElement) else @domNode.classList.add('editor-contents') + @overlayManager = new OverlayManager(@presenter, @domNode) @scrollViewNode = document.createElement('div') @scrollViewNode.classList.add('scroll-view') @@ -140,6 +147,8 @@ class TextEditorComponent @verticalScrollbarComponent.updateSync(@newState) @scrollbarCornerComponent.updateSync(@newState) + @overlayManager?.render(@newState) + if @editor.isAlive() @updateParentViewFocusedClassIfNeeded() @updateParentViewMiniClass() From 6b5a74e3b63cfcb0a940c3a03adfbe984d2290b6 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 31 Mar 2015 16:03:05 -0700 Subject: [PATCH 0371/1783] Update specs for overlay rendering --- spec/spec-helper.coffee | 2 +- spec/text-editor-component-spec.coffee | 167 ++++++++++++++----------- src/text-editor-component.coffee | 20 ++- src/text-editor-presenter.coffee | 18 +++ 4 files changed, 128 insertions(+), 79 deletions(-) diff --git a/spec/spec-helper.coffee b/spec/spec-helper.coffee index d34c72b1a..5406ff33a 100644 --- a/spec/spec-helper.coffee +++ b/spec/spec-helper.coffee @@ -370,7 +370,7 @@ window.setEditorWidthInChars = (editorView, widthInChars, charWidth=editorView.c window.setEditorHeightInLines = (editorView, heightInLines, lineHeight=editorView.lineHeight) -> editorView.height(editorView.getEditor().getLineHeightInPixels() * heightInLines) - editorView.component?.measureHeightAndWidth() + editorView.component?.measureDimensions() $.fn.resultOfTrigger = (type) -> event = $.Event(type) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 656dca0f0..9859841fe 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -50,7 +50,7 @@ describe "TextEditorComponent", -> verticalScrollbarNode = componentNode.querySelector('.vertical-scrollbar') horizontalScrollbarNode = componentNode.querySelector('.horizontal-scrollbar') - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() afterEach -> @@ -70,7 +70,7 @@ describe "TextEditorComponent", -> describe "line rendering", -> it "renders the currently-visible lines plus the overdraw margin", -> wrapperNode.style.height = 4.5 * lineHeightInPixels + 'px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() linesNode = componentNode.querySelector('.lines') @@ -113,7 +113,7 @@ describe "TextEditorComponent", -> it "updates the lines when lines are inserted or removed above the rendered row range", -> wrapperNode.style.height = 4.5 * lineHeightInPixels + 'px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() verticalScrollbarNode.scrollTop = 5 * lineHeightInPixels verticalScrollbarNode.dispatchEvent(new UIEvent('scroll')) @@ -163,7 +163,7 @@ describe "TextEditorComponent", -> it "renders the .lines div at the full height of the editor if there aren't enough lines to scroll vertically", -> editor.setText('') wrapperNode.style.height = '300px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() linesNode = componentNode.querySelector('.lines') @@ -175,7 +175,7 @@ describe "TextEditorComponent", -> lineNodes = componentNode.querySelectorAll('.line') componentNode.style.width = gutterWidth + (30 * charWidth) + 'px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() expect(editor.getScrollWidth()).toBeGreaterThan scrollViewNode.offsetWidth @@ -187,7 +187,7 @@ describe "TextEditorComponent", -> expect(lineNode.style.width).toBe editor.getScrollWidth() + 'px' componentNode.style.width = gutterWidth + editor.getScrollWidth() + 100 + 'px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() scrollViewWidth = scrollViewNode.offsetWidth @@ -339,7 +339,7 @@ describe "TextEditorComponent", -> editor.setSoftWrapped(true) nextAnimationFrame() componentNode.style.width = 16 * charWidth + editor.getVerticalScrollbarWidth() + 'px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() it "doesn't show end of line invisibles at the end of wrapped lines", -> @@ -480,7 +480,7 @@ describe "TextEditorComponent", -> describe "gutter rendering", -> it "renders the currently-visible line numbers", -> wrapperNode.style.height = 4.5 * lineHeightInPixels + 'px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() expect(componentNode.querySelectorAll('.line-number').length).toBe 6 + 2 + 1 # line overdraw margin below + dummy line number @@ -524,7 +524,7 @@ describe "TextEditorComponent", -> editor.setSoftWrapped(true) wrapperNode.style.height = 4.5 * lineHeightInPixels + 'px' wrapperNode.style.width = 30 * charWidth + 'px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() expect(componentNode.querySelectorAll('.line-number').length).toBe 6 + lineOverdrawMargin + 1 # 1 dummy line componentNode @@ -562,7 +562,7 @@ describe "TextEditorComponent", -> it "renders the .line-numbers div at the full height of the editor even if it's taller than its content", -> wrapperNode.style.height = componentNode.offsetHeight + 100 + 'px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() expect(componentNode.querySelector('.line-numbers').offsetHeight).toBe componentNode.offsetHeight @@ -653,7 +653,7 @@ describe "TextEditorComponent", -> editor.setSoftWrapped(true) nextAnimationFrame() componentNode.style.width = 16 * charWidth + editor.getVerticalScrollbarWidth() + 'px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() it "doesn't add the foldable class for soft-wrapped lines", -> @@ -697,7 +697,7 @@ describe "TextEditorComponent", -> wrapperNode.style.height = 4.5 * lineHeightInPixels + 'px' wrapperNode.style.width = 20 * lineHeightInPixels + 'px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() cursorNodes = componentNode.querySelectorAll('.cursor') @@ -992,7 +992,7 @@ describe "TextEditorComponent", -> # Shrink editor vertically wrapperNode.style.height = 4.5 * lineHeightInPixels + 'px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() # Add decorations that are out of range @@ -1016,7 +1016,7 @@ describe "TextEditorComponent", -> editor.setText("a line that wraps, ok") editor.setSoftWrapped(true) componentNode.style.width = 16 * charWidth + 'px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() marker.destroy() @@ -1132,7 +1132,7 @@ describe "TextEditorComponent", -> it "does not render highlights for off-screen lines until they come on-screen", -> wrapperNode.style.height = 2.5 * lineHeightInPixels + 'px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() marker = editor.displayBuffer.markBufferRange([[9, 2], [9, 4]], invalidate: 'inside') @@ -1279,10 +1279,13 @@ describe "TextEditorComponent", -> expect(componentNode.querySelector('.new-test-highlight')).toBeTruthy() describe "overlay decoration rendering", -> - [item] = [] + [item, gutterWidth] = [] beforeEach -> item = document.createElement('div') item.classList.add 'overlay-test' + item.style.background = 'red' + + gutterWidth = componentNode.querySelector('.gutter').offsetWidth describe "when the marker is empty", -> it "renders an overlay decoration when added and removes the overlay when the decoration is destroyed", -> @@ -1309,7 +1312,7 @@ describe "TextEditorComponent", -> position = wrapperNode.pixelPositionForBufferPosition([2, 5]) overlay = component.getTopmostDOMNode().querySelector('atom-overlay') - expect(overlay.style.left).toBe position.left + 'px' + expect(overlay.style.left).toBe position.left + gutterWidth + 'px' expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' editor.moveRight() @@ -1318,7 +1321,7 @@ describe "TextEditorComponent", -> position = wrapperNode.pixelPositionForBufferPosition([2, 7]) - expect(overlay.style.left).toBe position.left + 'px' + expect(overlay.style.left).toBe position.left + gutterWidth + 'px' expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' describe "when the marker is not empty", -> @@ -1330,7 +1333,7 @@ describe "TextEditorComponent", -> position = wrapperNode.pixelPositionForBufferPosition([2, 10]) overlay = component.getTopmostDOMNode().querySelector('atom-overlay') - expect(overlay.style.left).toBe position.left + 'px' + expect(overlay.style.left).toBe position.left + gutterWidth + 'px' expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' it "renders at the head of the marker when the marker is reversed", -> @@ -1341,7 +1344,7 @@ describe "TextEditorComponent", -> position = wrapperNode.pixelPositionForBufferPosition([2, 5]) overlay = component.getTopmostDOMNode().querySelector('atom-overlay') - expect(overlay.style.left).toBe position.left + 'px' + expect(overlay.style.left).toBe position.left + gutterWidth + 'px' expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' it "renders at the tail of the marker when the 'position' option is 'tail'", -> @@ -1352,18 +1355,19 @@ describe "TextEditorComponent", -> position = wrapperNode.pixelPositionForBufferPosition([2, 5]) overlay = component.getTopmostDOMNode().querySelector('atom-overlay') - expect(overlay.style.left).toBe position.left + 'px' + expect(overlay.style.left).toBe position.left + gutterWidth + 'px' expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' describe "positioning the overlay when near the edge of the editor", -> - [itemWidth, itemHeight] = [] + [itemWidth, itemHeight, windowWidth, windowHeight] = [] beforeEach -> + atom.storeWindowDimensions() + itemWidth = 4 * editor.getDefaultCharWidth() itemHeight = 4 * editor.getLineHeightInPixels() - gutterWidth = componentNode.querySelector('.gutter').offsetWidth windowWidth = gutterWidth + 30 * editor.getDefaultCharWidth() - windowHeight = 9 * editor.getLineHeightInPixels() + windowHeight = 10 * editor.getLineHeightInPixels() item.style.width = itemWidth + 'px' item.style.height = itemHeight + 'px' @@ -1371,10 +1375,16 @@ describe "TextEditorComponent", -> wrapperNode.style.width = windowWidth + 'px' wrapperNode.style.height = windowHeight + 'px' - component.measureHeightAndWidth() + atom.setWindowDimensions({width: windowWidth, height: windowHeight}) + + component.measureDimensions() + component.measureWindowSize() nextAnimationFrame() - it "flips horizontally when near the right edge", -> + afterEach -> + atom.restoreWindowDimensions() + + it "slides horizontally when near the right edge", -> marker = editor.displayBuffer.markBufferRange([[0, 26], [0, 26]], invalidate: 'never') decoration = editor.decorateMarker(marker, {type: 'overlay', item}) nextAnimationFrame() @@ -1382,17 +1392,24 @@ describe "TextEditorComponent", -> position = wrapperNode.pixelPositionForBufferPosition([0, 26]) overlay = component.getTopmostDOMNode().querySelector('atom-overlay') - expect(overlay.style.left).toBe position.left + 'px' + expect(overlay.style.left).toBe position.left + gutterWidth + 'px' expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' editor.insertText('a') nextAnimationFrame() - position = wrapperNode.pixelPositionForBufferPosition([0, 27]) - - expect(overlay.style.left).toBe position.left - itemWidth + 'px' + expect(overlay.style.left).toBe windowWidth - itemWidth + 'px' expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' + editor.insertText('b') + nextAnimationFrame() + + expect(overlay.style.left).toBe windowWidth - itemWidth + 'px' + expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' + + it "slides horizontally right when near the left edge with margin", -> + # TODO: + it "flips vertically when near the bottom edge", -> marker = editor.displayBuffer.markBufferRange([[4, 0], [4, 0]], invalidate: 'never') decoration = editor.decorateMarker(marker, {type: 'overlay', item}) @@ -1401,7 +1418,7 @@ describe "TextEditorComponent", -> position = wrapperNode.pixelPositionForBufferPosition([4, 0]) overlay = component.getTopmostDOMNode().querySelector('atom-overlay') - expect(overlay.style.left).toBe position.left + 'px' + expect(overlay.style.left).toBe position.left + gutterWidth + 'px' expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' editor.insertNewline() @@ -1409,7 +1426,7 @@ describe "TextEditorComponent", -> position = wrapperNode.pixelPositionForBufferPosition([5, 0]) - expect(overlay.style.left).toBe position.left + 'px' + expect(overlay.style.left).toBe position.left + gutterWidth + 'px' expect(overlay.style.top).toBe position.top - itemHeight + 'px' describe "when the editor is very small", -> @@ -1421,7 +1438,7 @@ describe "TextEditorComponent", -> wrapperNode.style.width = windowWidth + 'px' wrapperNode.style.height = windowHeight + 'px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() it "does not flip horizontally and force the overlay to have a negative left", -> @@ -1432,7 +1449,7 @@ describe "TextEditorComponent", -> position = wrapperNode.pixelPositionForBufferPosition([0, 2]) overlay = component.getTopmostDOMNode().querySelector('atom-overlay') - expect(overlay.style.left).toBe position.left + 'px' + expect(overlay.style.left).toBe position.left + gutterWidth + 'px' expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' editor.insertText('a') @@ -1440,7 +1457,7 @@ describe "TextEditorComponent", -> position = wrapperNode.pixelPositionForBufferPosition([0, 3]) - expect(overlay.style.left).toBe position.left + 'px' + expect(overlay.style.left).toBe position.left + gutterWidth + 'px' expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' it "does not flip vertically and force the overlay to have a negative top", -> @@ -1451,7 +1468,7 @@ describe "TextEditorComponent", -> position = wrapperNode.pixelPositionForBufferPosition([1, 0]) overlay = component.getTopmostDOMNode().querySelector('atom-overlay') - expect(overlay.style.left).toBe position.left + 'px' + expect(overlay.style.left).toBe position.left + gutterWidth + 'px' expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' editor.insertNewline() @@ -1459,33 +1476,35 @@ describe "TextEditorComponent", -> position = wrapperNode.pixelPositionForBufferPosition([2, 0]) - expect(overlay.style.left).toBe position.left + 'px' + expect(overlay.style.left).toBe position.left + gutterWidth + 'px' expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' - describe "when editor scroll position is not 0", -> it "flips horizontally when near the right edge", -> - editor.setScrollLeft(2 * editor.getDefaultCharWidth()) - marker = editor.displayBuffer.markBufferRange([[0, 28], [0, 28]], invalidate: 'never') + scrollLeft = 3 * editor.getDefaultCharWidth() + editor.setScrollLeft(scrollLeft) + editor.setCursorBufferPosition([1, 20]) + marker = editor.displayBuffer.markBufferRange([[1, 29], [1, 29]], invalidate: 'never') decoration = editor.decorateMarker(marker, {type: 'overlay', item}) nextAnimationFrame() - position = wrapperNode.pixelPositionForBufferPosition([0, 28]) + position = wrapperNode.pixelPositionForBufferPosition([1, 29]) overlay = component.getTopmostDOMNode().querySelector('atom-overlay') - expect(overlay.style.left).toBe position.left + 'px' + expect(overlay.style.left).toBe position.left + gutterWidth - scrollLeft + 'px' expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' editor.insertText('a') nextAnimationFrame() - position = wrapperNode.pixelPositionForBufferPosition([0, 29]) - - expect(overlay.style.left).toBe position.left - itemWidth + 'px' + expect(overlay.style.left).toBe windowWidth - itemWidth + 'px' expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' it "flips vertically when near the bottom edge", -> - editor.setScrollTop(2 * editor.getLineHeightInPixels()) + scrollTop = 2 * editor.getLineHeightInPixels() + editor.setScrollTop(scrollTop) + editor.setCursorBufferPosition([5, 0]) + marker = editor.displayBuffer.markBufferRange([[6, 0], [6, 0]], invalidate: 'never') decoration = editor.decorateMarker(marker, {type: 'overlay', item}) nextAnimationFrame() @@ -1493,16 +1512,16 @@ describe "TextEditorComponent", -> position = wrapperNode.pixelPositionForBufferPosition([6, 0]) overlay = component.getTopmostDOMNode().querySelector('atom-overlay') - expect(overlay.style.left).toBe position.left + 'px' - expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' + expect(overlay.style.left).toBe position.left + gutterWidth + 'px' + expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() - scrollTop + 'px' editor.insertNewline() nextAnimationFrame() position = wrapperNode.pixelPositionForBufferPosition([7, 0]) - expect(overlay.style.left).toBe position.left + 'px' - expect(overlay.style.top).toBe position.top - itemHeight + 'px' + expect(overlay.style.left).toBe position.left + gutterWidth + 'px' + expect(overlay.style.top).toBe position.top - itemHeight - scrollTop + 'px' describe "hidden input field", -> it "renders the hidden input field at the position of the last cursor if the cursor is on screen and the editor is focused", -> @@ -1512,7 +1531,7 @@ describe "TextEditorComponent", -> inputNode = componentNode.querySelector('.hidden-input') wrapperNode.style.height = 5 * lineHeightInPixels + 'px' wrapperNode.style.width = 10 * charWidth + 'px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() expect(editor.getCursorScreenPosition()).toEqual [0, 0] @@ -1566,7 +1585,7 @@ describe "TextEditorComponent", -> height = 4.5 * lineHeightInPixels wrapperNode.style.height = height + 'px' wrapperNode.style.width = 10 * charWidth + 'px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() coordinates = clientCoordinatesForScreenPosition([0, 2]) @@ -1580,7 +1599,7 @@ describe "TextEditorComponent", -> it "moves the cursor to the nearest screen position", -> wrapperNode.style.height = 4.5 * lineHeightInPixels + 'px' wrapperNode.style.width = 10 * charWidth + 'px' - component.measureHeightAndWidth() + component.measureDimensions() editor.setScrollTop(3.5 * lineHeightInPixels) editor.setScrollLeft(2 * charWidth) nextAnimationFrame() @@ -1863,7 +1882,7 @@ describe "TextEditorComponent", -> editor.setSoftWrapped(true) nextAnimationFrame() componentNode.style.width = 21 * charWidth + editor.getVerticalScrollbarWidth() + 'px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() describe "when the gutter is clicked", -> @@ -2029,7 +2048,7 @@ describe "TextEditorComponent", -> describe "scrolling", -> it "updates the vertical scrollbar when the scrollTop is changed in the model", -> wrapperNode.style.height = 4.5 * lineHeightInPixels + 'px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() expect(verticalScrollbarNode.scrollTop).toBe 0 @@ -2040,7 +2059,7 @@ describe "TextEditorComponent", -> it "updates the horizontal scrollbar and the x transform of the lines based on the scrollLeft of the model", -> componentNode.style.width = 30 * charWidth + 'px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() linesNode = componentNode.querySelector('.lines') @@ -2054,7 +2073,7 @@ describe "TextEditorComponent", -> it "updates the scrollLeft of the model when the scrollLeft of the horizontal scrollbar changes", -> componentNode.style.width = 30 * charWidth + 'px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() expect(editor.getScrollLeft()).toBe 0 @@ -2067,7 +2086,7 @@ describe "TextEditorComponent", -> it "does not obscure the last line with the horizontal scrollbar", -> wrapperNode.style.height = 4.5 * lineHeightInPixels + 'px' wrapperNode.style.width = 10 * charWidth + 'px' - component.measureHeightAndWidth() + component.measureDimensions() editor.setScrollBottom(editor.getScrollHeight()) nextAnimationFrame() lastLineNode = component.lineNodeForScreenRow(editor.getLastScreenRow()) @@ -2077,7 +2096,7 @@ describe "TextEditorComponent", -> # Scroll so there's no space below the last line when the horizontal scrollbar disappears wrapperNode.style.width = 100 * charWidth + 'px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() bottomOfLastLine = lastLineNode.getBoundingClientRect().bottom bottomOfEditor = componentNode.getBoundingClientRect().bottom @@ -2086,7 +2105,7 @@ describe "TextEditorComponent", -> it "does not obscure the last character of the longest line with the vertical scrollbar", -> wrapperNode.style.height = 7 * lineHeightInPixels + 'px' wrapperNode.style.width = 10 * charWidth + 'px' - component.measureHeightAndWidth() + component.measureDimensions() editor.setScrollLeft(Infinity) nextAnimationFrame() @@ -2100,21 +2119,21 @@ describe "TextEditorComponent", -> wrapperNode.style.height = 4.5 * lineHeightInPixels + 'px' wrapperNode.style.width = '1000px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() expect(verticalScrollbarNode.style.display).toBe '' expect(horizontalScrollbarNode.style.display).toBe 'none' componentNode.style.width = 10 * charWidth + 'px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() expect(verticalScrollbarNode.style.display).toBe '' expect(horizontalScrollbarNode.style.display).toBe '' wrapperNode.style.height = 20 * lineHeightInPixels + 'px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() expect(verticalScrollbarNode.style.display).toBe 'none' @@ -2123,7 +2142,7 @@ describe "TextEditorComponent", -> it "makes the dummy scrollbar divs only as tall/wide as the actual scrollbars", -> wrapperNode.style.height = 4 * lineHeightInPixels + 'px' wrapperNode.style.width = 10 * charWidth + 'px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() atom.styles.addStyleSheet """ @@ -2152,21 +2171,21 @@ describe "TextEditorComponent", -> wrapperNode.style.height = 4.5 * lineHeightInPixels + 'px' wrapperNode.style.width = '1000px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() expect(verticalScrollbarNode.style.bottom).toBe '0px' expect(horizontalScrollbarNode.style.right).toBe verticalScrollbarNode.offsetWidth + 'px' expect(scrollbarCornerNode.style.display).toBe 'none' componentNode.style.width = 10 * charWidth + 'px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() expect(verticalScrollbarNode.style.bottom).toBe horizontalScrollbarNode.offsetHeight + 'px' expect(horizontalScrollbarNode.style.right).toBe verticalScrollbarNode.offsetWidth + 'px' expect(scrollbarCornerNode.style.display).toBe '' wrapperNode.style.height = 20 * lineHeightInPixels + 'px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() expect(verticalScrollbarNode.style.bottom).toBe horizontalScrollbarNode.offsetHeight + 'px' expect(horizontalScrollbarNode.style.right).toBe '0px' @@ -2175,7 +2194,7 @@ describe "TextEditorComponent", -> it "accounts for the width of the gutter in the scrollWidth of the horizontal scrollbar", -> gutterNode = componentNode.querySelector('.gutter') componentNode.style.width = 10 * charWidth + 'px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() expect(horizontalScrollbarNode.scrollWidth).toBe editor.getScrollWidth() @@ -2189,7 +2208,7 @@ describe "TextEditorComponent", -> beforeEach -> wrapperNode.style.height = 4.5 * lineHeightInPixels + 'px' wrapperNode.style.width = 20 * charWidth + 'px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() it "updates the scrollLeft or scrollTop on mousewheel events depending on which delta is greater (x or y)", -> @@ -2233,7 +2252,7 @@ describe "TextEditorComponent", -> it "keeps the line on the DOM if it is scrolled off-screen", -> wrapperNode.style.height = 4.5 * lineHeightInPixels + 'px' wrapperNode.style.width = 20 * charWidth + 'px' - component.measureHeightAndWidth() + component.measureDimensions() lineNode = componentNode.querySelector('.line') wheelEvent = new WheelEvent('mousewheel', wheelDeltaX: 0, wheelDeltaY: -500) @@ -2246,7 +2265,7 @@ describe "TextEditorComponent", -> it "does not set the mouseWheelScreenRow if scrolling horizontally", -> wrapperNode.style.height = 4.5 * lineHeightInPixels + 'px' wrapperNode.style.width = 20 * charWidth + 'px' - component.measureHeightAndWidth() + component.measureDimensions() lineNode = componentNode.querySelector('.line') wheelEvent = new WheelEvent('mousewheel', wheelDeltaX: 10, wheelDeltaY: 0) @@ -2289,7 +2308,7 @@ describe "TextEditorComponent", -> it "keeps the line number on the DOM if it is scrolled off-screen", -> wrapperNode.style.height = 4.5 * lineHeightInPixels + 'px' wrapperNode.style.width = 20 * charWidth + 'px' - component.measureHeightAndWidth() + component.measureDimensions() lineNumberNode = componentNode.querySelectorAll('.line-number')[1] wheelEvent = new WheelEvent('mousewheel', wheelDeltaX: 0, wheelDeltaY: -500) @@ -2304,7 +2323,7 @@ describe "TextEditorComponent", -> wrapperNode.style.height = 4.5 * lineHeightInPixels + 'px' wrapperNode.style.width = 20 * charWidth + 'px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() # try to scroll past the top, which is impossible @@ -2700,7 +2719,7 @@ describe "TextEditorComponent", -> describe "when the wrapper view has an explicit height", -> it "does not assign a height on the component node", -> wrapperNode.style.height = '200px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() expect(componentNode.style.height).toBe '' diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 3bebaea49..0de081d85 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -168,7 +168,8 @@ class TextEditorComponent @measureScrollbars() if @measureScrollbarsWhenShown @sampleFontStyling() @sampleBackgroundColors() - @measureHeightAndWidth() + @measureWindowSize() + @measureDimensions() @measureLineHeightAndDefaultCharWidth() if @measureLineHeightAndDefaultCharWidthWhenShown @remeasureCharacterWidths() if @remeasureCharacterWidthsWhenShown @editor.setVisible(true) @@ -565,7 +566,7 @@ class TextEditorComponent pollDOM: => unless @checkForVisibilityChange() @sampleBackgroundColors() - @measureHeightAndWidth() + @measureDimensions() @sampleFontStyling() checkForVisibilityChange: -> @@ -584,13 +585,14 @@ class TextEditorComponent @heightAndWidthMeasurementRequested = true requestAnimationFrame => @heightAndWidthMeasurementRequested = false - @measureHeightAndWidth() + @measureDimensions() + @measureWindowSize() # Measure explicitly-styled height and width and relay them to the model. If # these values aren't explicitly styled, we assume the editor is unconstrained # and use the scrollHeight / scrollWidth as its height and width in # calculations. - measureHeightAndWidth: -> + measureDimensions: -> return unless @mounted {position} = getComputedStyle(@hostElement) @@ -611,6 +613,16 @@ class TextEditorComponent if clientWidth > 0 @presenter.setContentFrameWidth(clientWidth) + @presenter.setBoundingClientRect(@hostElement.getBoundingClientRect()) + + measureWindowSize: -> + return unless @mounted + + width = window.innerWidth + height = window.innerHeight + + @presenter.setWindowSize(width, height) + sampleFontStyling: => oldFontSize = @fontSize oldFontFamily = @fontFamily diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index babd7725b..81eb93a5b 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -657,6 +657,24 @@ class TextEditorPresenter @updateLinesState() @updateCursorsState() unless oldContentFrameWidth? + setBoundingClientRect: (boundingClientRect) -> + unless @clientRectsEqual(@boundingClientRect, boundingClientRect) + @boundingClientRect = boundingClientRect + @updateOverlaysState() + + clientRectsEqual: (clientRectA, clientRectB) -> + clientRectA? and clientRectB? and + clientRectA.top is clientRectB.top and + clientRectA.left is clientRectB.left and + clientRectA.width is clientRectB.width and + clientRectA.height is clientRectB.height + + setWindowSize: (width, height) -> + if @windowWidth isnt width or @windowHeight isnt height + @windowWidth = width + @windowHeight = height + @updateOverlaysState() + setBackgroundColor: (backgroundColor) -> unless @backgroundColor is backgroundColor @backgroundColor = backgroundColor From 0fa03f15b6dac00694a80463e7552f4bbf954e41 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 31 Mar 2015 16:04:01 -0700 Subject: [PATCH 0372/1783] Update overlay rendering --- src/overlay-manager.coffee | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/overlay-manager.coffee b/src/overlay-manager.coffee index c8b5da0e8..0babb45ae 100644 --- a/src/overlay-manager.coffee +++ b/src/overlay-manager.coffee @@ -23,16 +23,23 @@ class OverlayManager itemWidth = item.offsetWidth itemHeight = item.offsetHeight - + contentMargin = parseInt(getComputedStyle(item)['margin-left']) ? 0 {scrollTop, scrollLeft} = state.content - left = pixelPosition.left - if left + itemWidth - scrollLeft > @presenter.contentFrameWidth and left - itemWidth >= scrollLeft - left -= itemWidth + editorBounds = @presenter.boundingClientRect + gutterWidth = editorBounds.width - @presenter.contentFrameWidth - top = pixelPosition.top + @presenter.lineHeight - if top + itemHeight - scrollTop > @presenter.height and top - itemHeight - @presenter.lineHeight >= scrollTop + left = pixelPosition.left - scrollLeft + gutterWidth + top = pixelPosition.top + @presenter.lineHeight - scrollTop + + rightDiff = left + editorBounds.left + itemWidth + contentMargin - @presenter.windowWidth + left -= rightDiff if rightDiff > 0 + + leftDiff = left + editorBounds.left + contentMargin + left -= leftDiff if leftDiff < 0 + + if top + editorBounds.top + itemHeight > @presenter.windowHeight top -= itemHeight + @presenter.lineHeight overlayNode.style.top = top + 'px' From 01905ae55b4ca3b467cd9ecaf5cde95730f51733 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 31 Mar 2015 16:20:58 -0700 Subject: [PATCH 0373/1783] Add specs for margin handling --- spec/text-editor-component-spec.coffee | 38 +++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 9859841fe..df5b9cd48 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -1384,7 +1384,7 @@ describe "TextEditorComponent", -> afterEach -> atom.restoreWindowDimensions() - it "slides horizontally when near the right edge", -> + it "slides horizontally left when near the right edge", -> marker = editor.displayBuffer.markBufferRange([[0, 26], [0, 26]], invalidate: 'never') decoration = editor.decorateMarker(marker, {type: 'overlay', item}) nextAnimationFrame() @@ -1407,9 +1407,6 @@ describe "TextEditorComponent", -> expect(overlay.style.left).toBe windowWidth - itemWidth + 'px' expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' - it "slides horizontally right when near the left edge with margin", -> - # TODO: - it "flips vertically when near the bottom edge", -> marker = editor.displayBuffer.markBufferRange([[4, 0], [4, 0]], invalidate: 'never') decoration = editor.decorateMarker(marker, {type: 'overlay', item}) @@ -1429,6 +1426,39 @@ describe "TextEditorComponent", -> expect(overlay.style.left).toBe position.left + gutterWidth + 'px' expect(overlay.style.top).toBe position.top - itemHeight + 'px' + describe "when the overlay item has a margin", -> + itemMargin = null + beforeEach -> + itemWidth = 12 * editor.getDefaultCharWidth() + itemMargin = gutterWidth + 2 * editor.getDefaultCharWidth() + item.style.width = itemWidth + 'px' + item.style['margin-left'] = "-#{itemMargin}px" + + it "slides horizontally right when near the left edge with margin", -> + editor.setCursorBufferPosition([0, 3]) + cursor = editor.getLastCursor() + marker = cursor.marker + decoration = editor.decorateMarker(marker, {type: 'overlay', item}) + nextAnimationFrame() + + position = wrapperNode.pixelPositionForBufferPosition([0, 3]) + + overlay = component.getTopmostDOMNode().querySelector('atom-overlay') + expect(overlay.style.left).toBe position.left + gutterWidth + 'px' + expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' + + cursor.moveLeft() + nextAnimationFrame() + + expect(overlay.style.left).toBe itemMargin + 'px' + expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' + + cursor.moveLeft() + nextAnimationFrame() + + expect(overlay.style.left).toBe itemMargin + 'px' + expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' + describe "when the editor is very small", -> beforeEach -> gutterWidth = componentNode.querySelector('.gutter').offsetWidth From c62f06af9d8434904593d2d2c486a14a9b84c19b Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 31 Mar 2015 19:11:56 -0700 Subject: [PATCH 0374/1783] Cache the overlay dimensions in the presenter --- src/overlay-manager.coffee | 80 +++++++++++++++++++++++++++----- src/text-editor-component.coffee | 10 ++-- src/text-editor-presenter.coffee | 14 ++++++ 3 files changed, 87 insertions(+), 17 deletions(-) diff --git a/src/overlay-manager.coffee b/src/overlay-manager.coffee index 0babb45ae..2ab7123ab 100644 --- a/src/overlay-manager.coffee +++ b/src/overlay-manager.coffee @@ -1,30 +1,86 @@ module.exports = class OverlayManager constructor: (@presenter, @container) -> - @overlayNodesById = {} + @overlaysById = {} render: (state) -> - for decorationId, {pixelPosition, item} of state.content.overlays - @renderOverlay(state, decorationId, item, pixelPosition) + editorDimensionsHaveChanged = !@editorDimensionsAreEqual(state) - for id, overlayNode of @overlayNodesById + for decorationId, overlay of state.content.overlays + overlayHasChanged = not @overlayStateIsEqual(decorationId, overlay) + if editorDimensionsHaveChanged or overlayHasChanged + @renderOverlay(state, decorationId, overlay) + @cacheOverlayState(decorationId, overlay) + + for id, {overlayNode} of @overlaysById unless state.content.overlays.hasOwnProperty(id) - delete @overlayNodesById[id] + delete @overlaysById[id] overlayNode.remove() - return + @cacheEditorDimensions(state) - renderOverlay: (state, decorationId, item, pixelPosition) -> + overlayStateIsEqual: (decorationId, overlay) -> + return false unless @overlaysById[decorationId]? + @overlaysById[decorationId].itemWidth is overlay.itemWidth and + @overlaysById[decorationId].itemHeight is overlay.itemHeight and + @overlaysById[decorationId].contentMargin is overlay.contentMargin and + @overlaysById[decorationId].pixelPosition?.top is overlay.pixelPosition?.top and + @overlaysById[decorationId].pixelPosition?.left is overlay.pixelPosition?.left + + cacheOverlayState: (decorationId, overlay) -> + return unless @overlaysById[decorationId]? + @overlaysById[decorationId].itemWidth = overlay.itemWidth + @overlaysById[decorationId].itemHeight = overlay.itemHeight + @overlaysById[decorationId].contentMargin = overlay.contentMargin + @overlaysById[decorationId].pixelPosition = overlay.pixelPosition + + cacheEditorDimensions: (state) -> + @cachedEditorDimensions = + lineHeight: @presenter.lineHeight + contentFrameWidth: @presenter.contentFrameWidth + editorTop: @presenter.boundingClientRect?.top + editorLeft: @presenter.boundingClientRect?.left + editorWidth: @presenter.boundingClientRect?.width + windowWidth: @presenter.windowWidth + windowHeight: @presenter.windowHeight + scrollTop: state.content.scrollTop + scrollLeft: state.content.scrollLeft + + editorDimensionsAreEqual: (state) -> + return false unless @cachedEditorDimensions? + @cachedEditorDimensions.lineHeight is @presenter.lineHeight and + @cachedEditorDimensions.contentFrameWidth is @presenter.contentFrameWidth and + @cachedEditorDimensions.editorTop is @presenter.boundingClientRect?.top and + @cachedEditorDimensions.editorLeft is @presenter.boundingClientRect?.left and + @cachedEditorDimensions.editorWidth is @presenter.boundingClientRect?.width and + @cachedEditorDimensions.windowWidth is @presenter.windowWidth and + @cachedEditorDimensions.windowHeight is @presenter.windowHeight and + @cachedEditorDimensions.scrollTop is state.content.scrollTop and + @cachedEditorDimensions.scrollLeft is state.content.scrollLeft + + measureOverlays: -> + for decorationId, {item} of @overlaysById + @measureOverlay(decorationId, item) + + measureOverlay: (decorationId, item) -> + contentMargin = parseInt(getComputedStyle(item)['margin-left']) ? 0 + @presenter.setOverlayDimensions(decorationId, item.offsetWidth, item.offsetHeight, contentMargin) + + renderOverlay: (state, decorationId, {item, pixelPosition}) -> item = atom.views.getView(item) - unless overlayNode = @overlayNodesById[decorationId] - overlayNode = @overlayNodesById[decorationId] = document.createElement('atom-overlay') + overlay = @overlaysById[decorationId] + unless overlayNode = overlay?.overlayNode + overlayNode = document.createElement('atom-overlay') overlayNode.appendChild(item) @container.appendChild(overlayNode) + @overlaysById[decorationId] = overlay = {overlayNode, item} - itemWidth = item.offsetWidth - itemHeight = item.offsetHeight - contentMargin = parseInt(getComputedStyle(item)['margin-left']) ? 0 + overlayDimensions = @presenter.getOverlayDimensions(decorationId) + unless overlayDimensions?.itemWidth? + @measureOverlay(decorationId, item) + overlayDimensions = @presenter.getOverlayDimensions(decorationId) + {itemWidth, itemHeight, contentMargin} = overlayDimensions {scrollTop, scrollLeft} = state.content editorBounds = @presenter.boundingClientRect diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 0de081d85..459d4368b 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -158,6 +158,7 @@ class TextEditorComponent readAfterUpdateSync: => @linesComponent.measureCharactersInNewLines() if @isVisible() and not @newState.content.scrollingVertically + @overlayManager?.measureOverlays() mountGutterComponent: -> @gutterComponent = new GutterComponent({@editor, onMouseDown: @onGutterMouseDown}) @@ -189,6 +190,8 @@ class TextEditorComponent else unless @updateRequested @updateRequested = true atom.views.updateDocument => + @editor.horribleUpdateMethod?() + @editor.horribleUpdateMethod = null @updateRequested = false @updateSync() if @editor.isAlive() atom.views.readDocument(@readAfterUpdateSync) @@ -568,6 +571,7 @@ class TextEditorComponent @sampleBackgroundColors() @measureDimensions() @sampleFontStyling() + @overlayManager?.measureOverlays() checkForVisibilityChange: -> if @isVisible() @@ -617,11 +621,7 @@ class TextEditorComponent measureWindowSize: -> return unless @mounted - - width = window.innerWidth - height = window.innerHeight - - @presenter.setWindowSize(width, height) + @presenter.setWindowSize(window.innerWidth, window.innerHeight) sampleFontStyling: => oldFontSize = @fontSize diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 81eb93a5b..649e8f290 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -1012,6 +1012,20 @@ class TextEditorPresenter regions + setOverlayDimensions: (decorationId, itemWidth, itemHeight, contentMargin) -> + if overlayState = @state.content.overlays[decorationId] + dimensionsAreEqual = overlayState.itemWidth is itemWidth and + overlayState.itemHeight is itemHeight and + overlayState.contentMargin is contentMargin + unless dimensionsAreEqual + overlayState.itemWidth = itemWidth + overlayState.itemHeight = itemHeight + overlayState.contentMargin = contentMargin + @updateOverlaysState() + + getOverlayDimensions: (decorationId) -> + @state.content.overlays[decorationId] + observeCursor: (cursor) -> didChangePositionDisposable = cursor.onDidChangePosition => @updateHiddenInputState() if cursor.isLastCursor() From b0794bbb681b66e8e837ad599198cbe6d1ff2931 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 1 Apr 2015 13:05:52 -0700 Subject: [PATCH 0375/1783] Move the overlay calculation into the presenter. --- spec/text-editor-component-spec.coffee | 11 +++ src/overlay-manager.coffee | 99 +++++--------------------- src/text-editor-presenter.coffee | 52 +++++++++++--- 3 files changed, 71 insertions(+), 91 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index df5b9cd48..3f5d4f7fd 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -1308,6 +1308,7 @@ describe "TextEditorComponent", -> marker = editor.getLastCursor().getMarker() decoration = editor.decorateMarker(marker, {type: 'overlay', item}) nextAnimationFrame() + nextAnimationFrame() position = wrapperNode.pixelPositionForBufferPosition([2, 5]) @@ -1329,6 +1330,7 @@ describe "TextEditorComponent", -> marker = editor.displayBuffer.markBufferRange([[2, 5], [2, 10]], invalidate: 'never') decoration = editor.decorateMarker(marker, {type: 'overlay', item}) nextAnimationFrame() + nextAnimationFrame() position = wrapperNode.pixelPositionForBufferPosition([2, 10]) @@ -1340,6 +1342,7 @@ describe "TextEditorComponent", -> marker = editor.displayBuffer.markBufferRange([[2, 5], [2, 10]], invalidate: 'never', reversed: true) decoration = editor.decorateMarker(marker, {type: 'overlay', item}) nextAnimationFrame() + nextAnimationFrame() position = wrapperNode.pixelPositionForBufferPosition([2, 5]) @@ -1351,6 +1354,7 @@ describe "TextEditorComponent", -> marker = editor.displayBuffer.markBufferRange([[2, 5], [2, 10]], invalidate: 'never') decoration = editor.decorateMarker(marker, {type: 'overlay', position: 'tail', item}) nextAnimationFrame() + nextAnimationFrame() position = wrapperNode.pixelPositionForBufferPosition([2, 5]) @@ -1388,6 +1392,7 @@ describe "TextEditorComponent", -> marker = editor.displayBuffer.markBufferRange([[0, 26], [0, 26]], invalidate: 'never') decoration = editor.decorateMarker(marker, {type: 'overlay', item}) nextAnimationFrame() + nextAnimationFrame() position = wrapperNode.pixelPositionForBufferPosition([0, 26]) @@ -1411,6 +1416,7 @@ describe "TextEditorComponent", -> marker = editor.displayBuffer.markBufferRange([[4, 0], [4, 0]], invalidate: 'never') decoration = editor.decorateMarker(marker, {type: 'overlay', item}) nextAnimationFrame() + nextAnimationFrame() position = wrapperNode.pixelPositionForBufferPosition([4, 0]) @@ -1440,6 +1446,7 @@ describe "TextEditorComponent", -> marker = cursor.marker decoration = editor.decorateMarker(marker, {type: 'overlay', item}) nextAnimationFrame() + nextAnimationFrame() position = wrapperNode.pixelPositionForBufferPosition([0, 3]) @@ -1475,6 +1482,7 @@ describe "TextEditorComponent", -> marker = editor.displayBuffer.markBufferRange([[0, 2], [0, 2]], invalidate: 'never') decoration = editor.decorateMarker(marker, {type: 'overlay', item}) nextAnimationFrame() + nextAnimationFrame() position = wrapperNode.pixelPositionForBufferPosition([0, 2]) @@ -1494,6 +1502,7 @@ describe "TextEditorComponent", -> marker = editor.displayBuffer.markBufferRange([[1, 0], [1, 0]], invalidate: 'never') decoration = editor.decorateMarker(marker, {type: 'overlay', item}) nextAnimationFrame() + nextAnimationFrame() position = wrapperNode.pixelPositionForBufferPosition([1, 0]) @@ -1517,6 +1526,7 @@ describe "TextEditorComponent", -> marker = editor.displayBuffer.markBufferRange([[1, 29], [1, 29]], invalidate: 'never') decoration = editor.decorateMarker(marker, {type: 'overlay', item}) nextAnimationFrame() + nextAnimationFrame() position = wrapperNode.pixelPositionForBufferPosition([1, 29]) @@ -1538,6 +1548,7 @@ describe "TextEditorComponent", -> marker = editor.displayBuffer.markBufferRange([[6, 0], [6, 0]], invalidate: 'never') decoration = editor.decorateMarker(marker, {type: 'overlay', item}) nextAnimationFrame() + nextAnimationFrame() position = wrapperNode.pixelPositionForBufferPosition([6, 0]) diff --git a/src/overlay-manager.coffee b/src/overlay-manager.coffee index 2ab7123ab..8d0db365d 100644 --- a/src/overlay-manager.coffee +++ b/src/overlay-manager.coffee @@ -4,99 +4,38 @@ class OverlayManager @overlaysById = {} render: (state) -> - editorDimensionsHaveChanged = !@editorDimensionsAreEqual(state) - for decorationId, overlay of state.content.overlays - overlayHasChanged = not @overlayStateIsEqual(decorationId, overlay) - if editorDimensionsHaveChanged or overlayHasChanged + if @shouldUpdateOverlay(decorationId, overlay) @renderOverlay(state, decorationId, overlay) - @cacheOverlayState(decorationId, overlay) for id, {overlayNode} of @overlaysById unless state.content.overlays.hasOwnProperty(id) delete @overlaysById[id] overlayNode.remove() - @cacheEditorDimensions(state) - - overlayStateIsEqual: (decorationId, overlay) -> - return false unless @overlaysById[decorationId]? - @overlaysById[decorationId].itemWidth is overlay.itemWidth and - @overlaysById[decorationId].itemHeight is overlay.itemHeight and - @overlaysById[decorationId].contentMargin is overlay.contentMargin and - @overlaysById[decorationId].pixelPosition?.top is overlay.pixelPosition?.top and - @overlaysById[decorationId].pixelPosition?.left is overlay.pixelPosition?.left - - cacheOverlayState: (decorationId, overlay) -> - return unless @overlaysById[decorationId]? - @overlaysById[decorationId].itemWidth = overlay.itemWidth - @overlaysById[decorationId].itemHeight = overlay.itemHeight - @overlaysById[decorationId].contentMargin = overlay.contentMargin - @overlaysById[decorationId].pixelPosition = overlay.pixelPosition - - cacheEditorDimensions: (state) -> - @cachedEditorDimensions = - lineHeight: @presenter.lineHeight - contentFrameWidth: @presenter.contentFrameWidth - editorTop: @presenter.boundingClientRect?.top - editorLeft: @presenter.boundingClientRect?.left - editorWidth: @presenter.boundingClientRect?.width - windowWidth: @presenter.windowWidth - windowHeight: @presenter.windowHeight - scrollTop: state.content.scrollTop - scrollLeft: state.content.scrollLeft - - editorDimensionsAreEqual: (state) -> - return false unless @cachedEditorDimensions? - @cachedEditorDimensions.lineHeight is @presenter.lineHeight and - @cachedEditorDimensions.contentFrameWidth is @presenter.contentFrameWidth and - @cachedEditorDimensions.editorTop is @presenter.boundingClientRect?.top and - @cachedEditorDimensions.editorLeft is @presenter.boundingClientRect?.left and - @cachedEditorDimensions.editorWidth is @presenter.boundingClientRect?.width and - @cachedEditorDimensions.windowWidth is @presenter.windowWidth and - @cachedEditorDimensions.windowHeight is @presenter.windowHeight and - @cachedEditorDimensions.scrollTop is state.content.scrollTop and - @cachedEditorDimensions.scrollLeft is state.content.scrollLeft + shouldUpdateOverlay: (decorationId, overlay) -> + cachedOverlay = @overlaysById[decorationId] + return true unless cachedOverlay? + cachedOverlay.pixelPosition?.top isnt overlay.pixelPosition?.top or + cachedOverlay.pixelPosition?.left isnt overlay.pixelPosition?.left measureOverlays: -> - for decorationId, {item} of @overlaysById - @measureOverlay(decorationId, item) + for decorationId, {itemView} of @overlaysById + @measureOverlay(decorationId, itemView) - measureOverlay: (decorationId, item) -> - contentMargin = parseInt(getComputedStyle(item)['margin-left']) ? 0 - @presenter.setOverlayDimensions(decorationId, item.offsetWidth, item.offsetHeight, contentMargin) + measureOverlay: (decorationId, itemView) -> + contentMargin = parseInt(getComputedStyle(itemView)['margin-left']) ? 0 + @presenter.setOverlayDimensions(decorationId, itemView.offsetWidth, itemView.offsetHeight, contentMargin) renderOverlay: (state, decorationId, {item, pixelPosition}) -> - item = atom.views.getView(item) - overlay = @overlaysById[decorationId] - unless overlayNode = overlay?.overlayNode + itemView = atom.views.getView(item) + cachedOverlay = @overlaysById[decorationId] + unless overlayNode = cachedOverlay?.overlayNode overlayNode = document.createElement('atom-overlay') - overlayNode.appendChild(item) + overlayNode.appendChild(itemView) @container.appendChild(overlayNode) - @overlaysById[decorationId] = overlay = {overlayNode, item} + @overlaysById[decorationId] = cachedOverlay = {overlayNode, itemView} - overlayDimensions = @presenter.getOverlayDimensions(decorationId) - unless overlayDimensions?.itemWidth? - @measureOverlay(decorationId, item) - overlayDimensions = @presenter.getOverlayDimensions(decorationId) - - {itemWidth, itemHeight, contentMargin} = overlayDimensions - {scrollTop, scrollLeft} = state.content - - editorBounds = @presenter.boundingClientRect - gutterWidth = editorBounds.width - @presenter.contentFrameWidth - - left = pixelPosition.left - scrollLeft + gutterWidth - top = pixelPosition.top + @presenter.lineHeight - scrollTop - - rightDiff = left + editorBounds.left + itemWidth + contentMargin - @presenter.windowWidth - left -= rightDiff if rightDiff > 0 - - leftDiff = left + editorBounds.left + contentMargin - left -= leftDiff if leftDiff < 0 - - if top + editorBounds.top + itemHeight > @presenter.windowHeight - top -= itemHeight + @presenter.lineHeight - - overlayNode.style.top = top + 'px' - overlayNode.style.left = left + 'px' + cachedOverlay.pixelPosition = pixelPosition + overlayNode.style.top = pixelPosition.top + 'px' + overlayNode.style.left = pixelPosition.left + 'px' diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 649e8f290..c35032e72 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -9,6 +9,7 @@ class TextEditorPresenter stoppedScrollingTimeoutId: null mouseWheelScreenRow: null scopedCharacterWidthsChangeCount: 0 + overlayDimensions: {} constructor: (params) -> {@model, @autoHeight, @explicitHeight, @contentFrameWidth, @scrollTop, @scrollLeft} = params @@ -327,13 +328,39 @@ class TextEditorPresenter else screenPosition = decoration.getMarker().getHeadScreenPosition() + pixelPosition = @pixelPositionForScreenPosition(screenPosition) + + if overlayDimensions = @overlayDimensions[decoration.id] + {itemWidth, itemHeight, contentMargin} = overlayDimensions + {scrollTop, scrollLeft} = @state.content + + gutterWidth = @boundingClientRect.width - @contentFrameWidth + + left = pixelPosition.left - scrollLeft + gutterWidth + top = pixelPosition.top + @lineHeight - scrollTop + + rightDiff = left + @boundingClientRect.left + itemWidth + contentMargin - @windowWidth + left -= rightDiff if rightDiff > 0 + + leftDiff = left + @boundingClientRect.left + contentMargin + left -= leftDiff if leftDiff < 0 + + if top + @boundingClientRect.top + itemHeight > @windowHeight + top -= itemHeight + @lineHeight + + pixelPosition.top = top + pixelPosition.left = left + @state.content.overlays[decoration.id] ?= {item} - @state.content.overlays[decoration.id].pixelPosition = @pixelPositionForScreenPosition(screenPosition) + @state.content.overlays[decoration.id].pixelPosition = pixelPosition visibleDecorationIds[decoration.id] = true for id of @state.content.overlays delete @state.content.overlays[id] unless visibleDecorationIds[id] + for id of @overlayDimensions + delete @overlayDimensions[id] unless visibleDecorationIds[id] + return updateGutterState: -> @batch "shouldUpdateGutterState", -> @@ -566,6 +593,7 @@ class TextEditorPresenter @updateLinesState() @updateCursorsState() @updateLineNumbersState() + @updateOverlaysState() didStartScrolling: -> if @stoppedScrollingTimeoutId? @@ -593,6 +621,7 @@ class TextEditorPresenter @updateHorizontalScrollState() @updateHiddenInputState() @updateCursorsState() unless oldScrollLeft? + @updateOverlaysState() setHorizontalScrollbarHeight: (horizontalScrollbarHeight) -> unless @measuredHorizontalScrollbarHeight is horizontalScrollbarHeight @@ -1013,18 +1042,19 @@ class TextEditorPresenter regions setOverlayDimensions: (decorationId, itemWidth, itemHeight, contentMargin) -> - if overlayState = @state.content.overlays[decorationId] - dimensionsAreEqual = overlayState.itemWidth is itemWidth and - overlayState.itemHeight is itemHeight and - overlayState.contentMargin is contentMargin - unless dimensionsAreEqual - overlayState.itemWidth = itemWidth - overlayState.itemHeight = itemHeight - overlayState.contentMargin = contentMargin - @updateOverlaysState() + @overlayDimensions[decorationId] ?= {} + overlayState = @overlayDimensions[decorationId] + dimensionsAreEqual = overlayState.itemWidth is itemWidth and + overlayState.itemHeight is itemHeight and + overlayState.contentMargin is contentMargin + unless dimensionsAreEqual + overlayState.itemWidth = itemWidth + overlayState.itemHeight = itemHeight + overlayState.contentMargin = contentMargin + @updateOverlaysState() getOverlayDimensions: (decorationId) -> - @state.content.overlays[decorationId] + @overlayDimensions[decorationId] observeCursor: (cursor) -> didChangePositionDisposable = cursor.onDidChangePosition => From 32572c010670529d73d3dcca0f54bab287e8c0bc Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 1 Apr 2015 14:01:00 -0700 Subject: [PATCH 0376/1783] Add ViewRegistry::pollAfterNextUpdate Closes #6196 --- spec/view-registry-spec.coffee | 15 +++++++++++++++ src/view-registry.coffee | 5 ++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/spec/view-registry-spec.coffee b/spec/view-registry-spec.coffee index 4d0d72abc..239f2e878 100644 --- a/spec/view-registry-spec.coffee +++ b/spec/view-registry-spec.coffee @@ -137,6 +137,21 @@ describe "ViewRegistry", -> advanceClock(registry.documentPollingInterval) expect(events).toEqual ['write', 'read', 'poll', 'poll'] + it "polls the document after updating when ::pollAfterNextUpdate() has been called", -> + events = [] + registry.pollDocument -> events.push('poll') + registry.updateDocument -> events.push('write') + registry.readDocument -> events.push('read') + frameRequests.shift()() + expect(events).toEqual ['write', 'read'] + + events = [] + registry.pollAfterNextUpdate() + registry.updateDocument -> events.push('write') + registry.readDocument -> events.push('read') + frameRequests.shift()() + expect(events).toEqual ['write', 'read', 'poll'] + describe "::pollDocument(fn)", -> it "calls all registered reader functions on an interval until they are disabled via a returned disposable", -> spyOn(window, 'setInterval').andCallFake(fakeSetInterval) diff --git a/src/view-registry.coffee b/src/view-registry.coffee index 4dbb5594e..050444ff0 100644 --- a/src/view-registry.coffee +++ b/src/view-registry.coffee @@ -178,6 +178,9 @@ class ViewRegistry @documentPollers = @documentPollers.filter (poller) -> poller isnt fn @stopPollingDocument() if @documentPollers.length is 0 + pollAfterNextUpdate: -> + @performDocumentPollAfterUpdate = true + clearDocumentRequests: -> @documentReaders = [] @documentWriters = [] @@ -194,6 +197,7 @@ class ViewRegistry writer() while writer = @documentWriters.shift() reader() while reader = @documentReaders.shift() @performDocumentPoll() if @performDocumentPollAfterUpdate + @performDocumentPollAfterUpdate = false startPollingDocument: -> @pollIntervalHandle = window.setInterval(@performDocumentPoll, @documentPollingInterval) @@ -205,6 +209,5 @@ class ViewRegistry if @documentUpdateRequested @performDocumentPollAfterUpdate = true else - @performDocumentPollAfterUpdate = false poller() for poller in @documentPollers return From 3adc646a7902acab1bf7590819d4f0bdcddd3df7 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 1 Apr 2015 14:01:24 -0700 Subject: [PATCH 0377/1783] Remove the horribleUpdateMethod --- src/text-editor-component.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 459d4368b..43f8184db 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -190,8 +190,6 @@ class TextEditorComponent else unless @updateRequested @updateRequested = true atom.views.updateDocument => - @editor.horribleUpdateMethod?() - @editor.horribleUpdateMethod = null @updateRequested = false @updateSync() if @editor.isAlive() atom.views.readDocument(@readAfterUpdateSync) From 77139104fd6e8062aa62a351c905610c37f943cd Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 1 Apr 2015 14:02:05 -0700 Subject: [PATCH 0378/1783] Remove getOverlayDimensions No longer needed --- src/text-editor-presenter.coffee | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index c35032e72..4546c7893 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -1053,9 +1053,6 @@ class TextEditorPresenter overlayState.contentMargin = contentMargin @updateOverlaysState() - getOverlayDimensions: (decorationId) -> - @overlayDimensions[decorationId] - observeCursor: (cursor) -> didChangePositionDisposable = cursor.onDidChangePosition => @updateHiddenInputState() if cursor.isLastCursor() From bed09cf0efb3afc65f2ce05f5332fe1da82b0fd4 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 1 Apr 2015 14:44:38 -0700 Subject: [PATCH 0379/1783] =?UTF-8?q?Presenter=20positions=20overlays=20wh?= =?UTF-8?q?en=20the=20overlay=20doesn=E2=80=99t=20have=20a=20size?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix presenter specs --- spec/text-editor-presenter-spec.coffee | 40 +++++++++++++++++--------- src/text-editor-presenter.coffee | 23 ++++++++------- 2 files changed, 39 insertions(+), 24 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index b62391db8..445ec6bf1 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -29,6 +29,9 @@ describe "TextEditorPresenter", -> model: editor explicitHeight: 130 contentFrameWidth: 500 + windowWidth: 500 + windowHeight: 130 + boundingClientRect: {left: 0, top: 0, width: 500, height: 130} lineHeight: 10 baseCharacterWidth: 10 horizontalScrollbarHeight: 10 @@ -1497,14 +1500,14 @@ describe "TextEditorPresenter", -> # Initial state expectValues stateForOverlay(presenter, decoration), { item: item - pixelPosition: {top: 2 * 10, left: 13 * 10} + pixelPosition: {top: 3 * 10 - presenter.state.content.scrollTop, left: 13 * 10} } # Change range expectStateUpdate presenter, -> marker.setBufferRange([[2, 13], [4, 6]]) expectValues stateForOverlay(presenter, decoration), { item: item - pixelPosition: {top: 4 * 10, left: 6 * 10} + pixelPosition: {top: 5 * 10 - presenter.state.content.scrollTop, left: 6 * 10} } # Valid -> invalid @@ -1515,14 +1518,14 @@ describe "TextEditorPresenter", -> expectStateUpdate presenter, -> editor.undo() expectValues stateForOverlay(presenter, decoration), { item: item - pixelPosition: {top: 4 * 10, left: 6 * 10} + pixelPosition: {top: 5 * 10 - presenter.state.content.scrollTop, left: 6 * 10} } # Reverse direction expectStateUpdate presenter, -> marker.setBufferRange([[2, 13], [4, 6]], reversed: true) expectValues stateForOverlay(presenter, decoration), { item: item - pixelPosition: {top: 2 * 10, left: 13 * 10} + pixelPosition: {top: 3 * 10 - presenter.state.content.scrollTop, left: 13 * 10} } # Destroy @@ -1533,53 +1536,56 @@ describe "TextEditorPresenter", -> decoration2 = editor.decorateMarker(marker, {type: 'overlay', item}) expectValues stateForOverlay(presenter, decoration2), { item: item - pixelPosition: {top: 2 * 10, left: 13 * 10} + pixelPosition: {top: 3 * 10 - presenter.state.content.scrollTop, left: 13 * 10} } it "updates when ::baseCharacterWidth changes", -> item = {} + scrollTop = 20 marker = editor.markBufferPosition([2, 13], invalidate: 'touch') decoration = editor.decorateMarker(marker, {type: 'overlay', item}) - presenter = buildPresenter(explicitHeight: 30, scrollTop: 20) + presenter = buildPresenter({explicitHeight: 30, scrollTop}) expectValues stateForOverlay(presenter, decoration), { item: item - pixelPosition: {top: 2 * 10, left: 13 * 10} + pixelPosition: {top: 3 * 10 - scrollTop, left: 13 * 10} } expectStateUpdate presenter, -> presenter.setBaseCharacterWidth(5) expectValues stateForOverlay(presenter, decoration), { item: item - pixelPosition: {top: 2 * 10, left: 13 * 5} + pixelPosition: {top: 3 * 10 - scrollTop, left: 13 * 5} } it "updates when ::lineHeight changes", -> item = {} + scrollTop = 20 marker = editor.markBufferPosition([2, 13], invalidate: 'touch') decoration = editor.decorateMarker(marker, {type: 'overlay', item}) - presenter = buildPresenter(explicitHeight: 30, scrollTop: 20) + presenter = buildPresenter({explicitHeight: 30, scrollTop}) expectValues stateForOverlay(presenter, decoration), { item: item - pixelPosition: {top: 2 * 10, left: 13 * 10} + pixelPosition: {top: 3 * 10 - scrollTop, left: 13 * 10} } expectStateUpdate presenter, -> presenter.setLineHeight(5) expectValues stateForOverlay(presenter, decoration), { item: item - pixelPosition: {top: 2 * 5, left: 13 * 10} + pixelPosition: {top: 3 * 5 - scrollTop, left: 13 * 10} } it "honors the 'position' option on overlay decorations", -> item = {} + scrollTop = 20 marker = editor.markBufferRange([[2, 13], [4, 14]], invalidate: 'touch') decoration = editor.decorateMarker(marker, {type: 'overlay', position: 'tail', item}) - presenter = buildPresenter(explicitHeight: 30, scrollTop: 20) + presenter = buildPresenter({explicitHeight: 30, scrollTop}) expectValues stateForOverlay(presenter, decoration), { item: item - pixelPosition: {top: 2 * 10, left: 13 * 10} + pixelPosition: {top: 3 * 10 - scrollTop, left: 13 * 10} } it "is empty until all of the required measurements are assigned", -> @@ -1587,13 +1593,19 @@ describe "TextEditorPresenter", -> marker = editor.markBufferRange([[2, 13], [4, 14]], invalidate: 'touch') decoration = editor.decorateMarker(marker, {type: 'overlay', position: 'tail', item}) - presenter = buildPresenter(baseCharacterWidth: null, lineHeight: null) + presenter = buildPresenter(baseCharacterWidth: null, lineHeight: null, windowWidth: null, windowHeight: null, boundingClientRect: null) expect(presenter.getState().content.overlays).toEqual({}) presenter.setBaseCharacterWidth(10) expect(presenter.getState().content.overlays).toEqual({}) presenter.setLineHeight(10) + expect(presenter.getState().content.overlays).toEqual({}) + + presenter.setWindowSize(500, 100) + expect(presenter.getState().content.overlays).toEqual({}) + + presenter.setBoundingClientRect({top: 0, left: 0, height: 100, width: 500}) expect(presenter.getState().content.overlays).not.toEqual({}) describe ".gutter", -> diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 4546c7893..f8703c085 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -12,7 +12,7 @@ class TextEditorPresenter overlayDimensions: {} constructor: (params) -> - {@model, @autoHeight, @explicitHeight, @contentFrameWidth, @scrollTop, @scrollLeft} = params + {@model, @autoHeight, @explicitHeight, @contentFrameWidth, @scrollTop, @scrollLeft, @boundingClientRect, @windowWidth, @windowHeight} = params {horizontalScrollbarHeight, verticalScrollbarWidth} = params {@lineHeight, @baseCharacterWidth, @lineOverdrawMargin, @backgroundColor, @gutterBackgroundColor} = params {@cursorBlinkPeriod, @cursorBlinkResumeDelay, @stoppedScrollingDelay, @focused} = params @@ -315,7 +315,7 @@ class TextEditorPresenter @emitDidUpdateState() updateOverlaysState: -> @batch "shouldUpdateOverlaysState", -> - return unless @hasPixelRectRequirements() + return unless @hasOverlayPositionRequirements() visibleDecorationIds = {} @@ -330,14 +330,14 @@ class TextEditorPresenter pixelPosition = @pixelPositionForScreenPosition(screenPosition) + {scrollTop, scrollLeft} = @state.content + gutterWidth = @boundingClientRect.width - @contentFrameWidth + + left = pixelPosition.left - scrollLeft + gutterWidth + top = pixelPosition.top + @lineHeight - scrollTop + if overlayDimensions = @overlayDimensions[decoration.id] {itemWidth, itemHeight, contentMargin} = overlayDimensions - {scrollTop, scrollLeft} = @state.content - - gutterWidth = @boundingClientRect.width - @contentFrameWidth - - left = pixelPosition.left - scrollLeft + gutterWidth - top = pixelPosition.top + @lineHeight - scrollTop rightDiff = left + @boundingClientRect.left + itemWidth + contentMargin - @windowWidth left -= rightDiff if rightDiff > 0 @@ -348,8 +348,8 @@ class TextEditorPresenter if top + @boundingClientRect.top + itemHeight > @windowHeight top -= itemHeight + @lineHeight - pixelPosition.top = top - pixelPosition.left = left + pixelPosition.top = top + pixelPosition.left = left @state.content.overlays[decoration.id] ?= {item} @state.content.overlays[decoration.id].pixelPosition = pixelPosition @@ -824,6 +824,9 @@ class TextEditorPresenter hasPixelRectRequirements: -> @hasPixelPositionRequirements() and @scrollWidth? + hasOverlayPositionRequirements: -> + @hasPixelRectRequirements() and @boundingClientRect? and @windowWidth and @windowHeight + pixelRectForScreenRange: (screenRange) -> if screenRange.end.row > screenRange.start.row top = @pixelPositionForScreenPosition(screenRange.start).top From 48a06868c89e491641ba73e68bc69cad27a4cd6c Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 1 Apr 2015 16:17:22 -0700 Subject: [PATCH 0380/1783] Add specs from the text-editor-component --- spec/text-editor-presenter-spec.coffee | 169 ++++++++++++++++++++++++- 1 file changed, 164 insertions(+), 5 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 445ec6bf1..577c87401 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -1488,11 +1488,11 @@ describe "TextEditorPresenter", -> } describe ".overlays", -> + [item] = [] stateForOverlay = (presenter, decoration) -> presenter.getState().content.overlays[decoration.id] it "contains state for overlay decorations both initially and when their markers move", -> - item = {} marker = editor.markBufferPosition([2, 13], invalidate: 'touch') decoration = editor.decorateMarker(marker, {type: 'overlay', item}) presenter = buildPresenter(explicitHeight: 30, scrollTop: 20) @@ -1540,7 +1540,6 @@ describe "TextEditorPresenter", -> } it "updates when ::baseCharacterWidth changes", -> - item = {} scrollTop = 20 marker = editor.markBufferPosition([2, 13], invalidate: 'touch') decoration = editor.decorateMarker(marker, {type: 'overlay', item}) @@ -1559,7 +1558,6 @@ describe "TextEditorPresenter", -> } it "updates when ::lineHeight changes", -> - item = {} scrollTop = 20 marker = editor.markBufferPosition([2, 13], invalidate: 'touch') decoration = editor.decorateMarker(marker, {type: 'overlay', item}) @@ -1578,7 +1576,6 @@ describe "TextEditorPresenter", -> } it "honors the 'position' option on overlay decorations", -> - item = {} scrollTop = 20 marker = editor.markBufferRange([[2, 13], [4, 14]], invalidate: 'touch') decoration = editor.decorateMarker(marker, {type: 'overlay', position: 'tail', item}) @@ -1589,7 +1586,6 @@ describe "TextEditorPresenter", -> } it "is empty until all of the required measurements are assigned", -> - item = {} marker = editor.markBufferRange([[2, 13], [4, 14]], invalidate: 'touch') decoration = editor.decorateMarker(marker, {type: 'overlay', position: 'tail', item}) @@ -1608,6 +1604,169 @@ describe "TextEditorPresenter", -> presenter.setBoundingClientRect({top: 0, left: 0, height: 100, width: 500}) expect(presenter.getState().content.overlays).not.toEqual({}) + describe "when the overlay has been measured", -> + [gutterWidth, windowWidth, windowHeight, itemWidth, itemHeight, contentMargin, boundingClientRect, contentFrameWidth] = [] + beforeEach -> + item = {} + gutterWidth = 5 * 10 # 5 chars wide + contentFrameWidth = 30 * 10 + windowWidth = gutterWidth + contentFrameWidth + windowHeight = 9 * 10 + + itemWidth = 4 * 10 + itemHeight = 4 * 10 + contentMargin = 0 + + boundingClientRect = + top: 0 + left: 0, + width: windowWidth + height: windowHeight + + it "slides horizontally left when near the right edge", -> + scrollLeft = 20 + marker = editor.markBufferPosition([0, 26], invalidate: 'never') + decoration = editor.decorateMarker(marker, {type: 'overlay', item}) + + presenter = buildPresenter({scrollLeft, windowWidth, windowHeight, contentFrameWidth, boundingClientRect}) + expectStateUpdate presenter, -> + presenter.setOverlayDimensions(decoration.id, itemWidth, itemHeight, contentMargin) + + expectValues stateForOverlay(presenter, decoration), { + item: item + pixelPosition: {top: 1 * 10, left: 26 * 10 + gutterWidth - scrollLeft} + } + + expectStateUpdate presenter, -> editor.insertText('a') + expectValues stateForOverlay(presenter, decoration), { + item: item + pixelPosition: {top: 1 * 10, left: windowWidth - itemWidth} + } + + expectStateUpdate presenter, -> editor.insertText('b') + expectValues stateForOverlay(presenter, decoration), { + item: item + pixelPosition: {top: 1 * 10, left: windowWidth - itemWidth} + } + + it "flips vertically when near the bottom edge", -> + scrollTop = 10 + marker = editor.markBufferPosition([5, 0], invalidate: 'never') + decoration = editor.decorateMarker(marker, {type: 'overlay', item}) + + presenter = buildPresenter({scrollTop, windowWidth, windowHeight, contentFrameWidth, boundingClientRect}) + expectStateUpdate presenter, -> + presenter.setOverlayDimensions(decoration.id, itemWidth, itemHeight, contentMargin) + + expectValues stateForOverlay(presenter, decoration), { + item: item + pixelPosition: {top: 6 * 10 - scrollTop, left: gutterWidth} + } + + expectStateUpdate presenter, -> + editor.insertNewline() + editor.setScrollTop(scrollTop) # I'm fighting the editor + expectValues stateForOverlay(presenter, decoration), { + item: item + pixelPosition: {top: 6 * 10 - scrollTop - itemHeight, left: gutterWidth} + } + + describe "when the overlay item has a margin", -> + beforeEach -> + itemWidth = 12 * 10 + contentMargin = -(gutterWidth + 2 * 10) + + it "slides horizontally right when near the left edge with margin", -> + editor.setCursorBufferPosition([0, 3]) + cursor = editor.getLastCursor() + marker = cursor.marker + decoration = editor.decorateMarker(marker, {type: 'overlay', item}) + + presenter = buildPresenter({windowWidth, windowHeight, contentFrameWidth, boundingClientRect}) + expectStateUpdate presenter, -> + presenter.setOverlayDimensions(decoration.id, itemWidth, itemHeight, contentMargin) + + expectValues stateForOverlay(presenter, decoration), { + item: item + pixelPosition: {top: 1 * 10, left: 3 * 10 + gutterWidth} + } + + expectStateUpdate presenter, -> cursor.moveLeft() + expectValues stateForOverlay(presenter, decoration), { + item: item + pixelPosition: {top: 1 * 10, left: -contentMargin} + } + + expectStateUpdate presenter, -> cursor.moveLeft() + expectValues stateForOverlay(presenter, decoration), { + item: item + pixelPosition: {top: 1 * 10, left: -contentMargin} + } + + describe "when the editor is very small", -> + beforeEach -> + windowWidth = gutterWidth + 6 * 10 + windowHeight = 6 * 10 + contentFrameWidth = windowWidth - gutterWidth + boundingClientRect.width = windowWidth + boundingClientRect.height = windowHeight + + it "does not flip vertically and force the overlay to have a negative top", -> + marker = editor.markBufferPosition([1, 0], invalidate: 'never') + decoration = editor.decorateMarker(marker, {type: 'overlay', item}) + + presenter = buildPresenter({windowWidth, windowHeight, contentFrameWidth, boundingClientRect}) + expectStateUpdate presenter, -> + presenter.setOverlayDimensions(decoration.id, itemWidth, itemHeight, contentMargin) + + expectValues stateForOverlay(presenter, decoration), { + item: item + pixelPosition: {top: 2 * 10, left: 0 * 10 + gutterWidth} + } + + expectStateUpdate presenter, -> editor.insertNewline() + expectValues stateForOverlay(presenter, decoration), { + item: item + pixelPosition: {top: 3 * 10, left: gutterWidth} + } + + it "does not adjust horizontally and force the overlay to have a negative left", -> + itemWidth = 6 * 10 + + marker = editor.markBufferPosition([0, 0], invalidate: 'never') + decoration = editor.decorateMarker(marker, {type: 'overlay', item}) + + presenter = buildPresenter({windowWidth, windowHeight, contentFrameWidth, boundingClientRect}) + expectStateUpdate presenter, -> + presenter.setOverlayDimensions(decoration.id, itemWidth, itemHeight, contentMargin) + + expectValues stateForOverlay(presenter, decoration), { + item: item + pixelPosition: {top: 10, left: gutterWidth} + } + + windowWidth = gutterWidth + 5 * 10 + expectStateUpdate presenter, -> presenter.setWindowSize(windowWidth, windowHeight) + expectValues stateForOverlay(presenter, decoration), { + item: item + pixelPosition: {top: 10, left: windowWidth - itemWidth} + } + + windowWidth = gutterWidth + 1 * 10 + expectStateUpdate presenter, -> presenter.setWindowSize(windowWidth, windowHeight) + expectValues stateForOverlay(presenter, decoration), { + item: item + pixelPosition: {top: 10, left: 0} + } + + windowWidth = gutterWidth + expectStateUpdate presenter, -> presenter.setWindowSize(windowWidth, windowHeight) + expectValues stateForOverlay(presenter, decoration), { + item: item + pixelPosition: {top: 10, left: 0} + } + + describe ".gutter", -> describe ".scrollHeight", -> it "is initialized based on ::lineHeight, the number of lines, and ::explicitHeight", -> From 48c05210fa636627f2d931a6e970a545aa2b6785 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 1 Apr 2015 16:19:36 -0700 Subject: [PATCH 0381/1783] Remove specs from text-editor-component --- spec/text-editor-component-spec.coffee | 168 ------------------------- src/text-editor-presenter.coffee | 4 +- 2 files changed, 2 insertions(+), 170 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 3f5d4f7fd..cc4d8e37d 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -1338,30 +1338,6 @@ describe "TextEditorComponent", -> expect(overlay.style.left).toBe position.left + gutterWidth + 'px' expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' - it "renders at the head of the marker when the marker is reversed", -> - marker = editor.displayBuffer.markBufferRange([[2, 5], [2, 10]], invalidate: 'never', reversed: true) - decoration = editor.decorateMarker(marker, {type: 'overlay', item}) - nextAnimationFrame() - nextAnimationFrame() - - position = wrapperNode.pixelPositionForBufferPosition([2, 5]) - - overlay = component.getTopmostDOMNode().querySelector('atom-overlay') - expect(overlay.style.left).toBe position.left + gutterWidth + 'px' - expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' - - it "renders at the tail of the marker when the 'position' option is 'tail'", -> - marker = editor.displayBuffer.markBufferRange([[2, 5], [2, 10]], invalidate: 'never') - decoration = editor.decorateMarker(marker, {type: 'overlay', position: 'tail', item}) - nextAnimationFrame() - nextAnimationFrame() - - position = wrapperNode.pixelPositionForBufferPosition([2, 5]) - - overlay = component.getTopmostDOMNode().querySelector('atom-overlay') - expect(overlay.style.left).toBe position.left + gutterWidth + 'px' - expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' - describe "positioning the overlay when near the edge of the editor", -> [itemWidth, itemHeight, windowWidth, windowHeight] = [] beforeEach -> @@ -1411,19 +1387,6 @@ describe "TextEditorComponent", -> expect(overlay.style.left).toBe windowWidth - itemWidth + 'px' expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' - - it "flips vertically when near the bottom edge", -> - marker = editor.displayBuffer.markBufferRange([[4, 0], [4, 0]], invalidate: 'never') - decoration = editor.decorateMarker(marker, {type: 'overlay', item}) - nextAnimationFrame() - nextAnimationFrame() - - position = wrapperNode.pixelPositionForBufferPosition([4, 0]) - - overlay = component.getTopmostDOMNode().querySelector('atom-overlay') - expect(overlay.style.left).toBe position.left + gutterWidth + 'px' - expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' - editor.insertNewline() nextAnimationFrame() @@ -1432,137 +1395,6 @@ describe "TextEditorComponent", -> expect(overlay.style.left).toBe position.left + gutterWidth + 'px' expect(overlay.style.top).toBe position.top - itemHeight + 'px' - describe "when the overlay item has a margin", -> - itemMargin = null - beforeEach -> - itemWidth = 12 * editor.getDefaultCharWidth() - itemMargin = gutterWidth + 2 * editor.getDefaultCharWidth() - item.style.width = itemWidth + 'px' - item.style['margin-left'] = "-#{itemMargin}px" - - it "slides horizontally right when near the left edge with margin", -> - editor.setCursorBufferPosition([0, 3]) - cursor = editor.getLastCursor() - marker = cursor.marker - decoration = editor.decorateMarker(marker, {type: 'overlay', item}) - nextAnimationFrame() - nextAnimationFrame() - - position = wrapperNode.pixelPositionForBufferPosition([0, 3]) - - overlay = component.getTopmostDOMNode().querySelector('atom-overlay') - expect(overlay.style.left).toBe position.left + gutterWidth + 'px' - expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' - - cursor.moveLeft() - nextAnimationFrame() - - expect(overlay.style.left).toBe itemMargin + 'px' - expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' - - cursor.moveLeft() - nextAnimationFrame() - - expect(overlay.style.left).toBe itemMargin + 'px' - expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' - - describe "when the editor is very small", -> - beforeEach -> - gutterWidth = componentNode.querySelector('.gutter').offsetWidth - windowWidth = gutterWidth + 6 * editor.getDefaultCharWidth() - windowHeight = 6 * editor.getLineHeightInPixels() - - wrapperNode.style.width = windowWidth + 'px' - wrapperNode.style.height = windowHeight + 'px' - - component.measureDimensions() - nextAnimationFrame() - - it "does not flip horizontally and force the overlay to have a negative left", -> - marker = editor.displayBuffer.markBufferRange([[0, 2], [0, 2]], invalidate: 'never') - decoration = editor.decorateMarker(marker, {type: 'overlay', item}) - nextAnimationFrame() - nextAnimationFrame() - - position = wrapperNode.pixelPositionForBufferPosition([0, 2]) - - overlay = component.getTopmostDOMNode().querySelector('atom-overlay') - expect(overlay.style.left).toBe position.left + gutterWidth + 'px' - expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' - - editor.insertText('a') - nextAnimationFrame() - - position = wrapperNode.pixelPositionForBufferPosition([0, 3]) - - expect(overlay.style.left).toBe position.left + gutterWidth + 'px' - expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' - - it "does not flip vertically and force the overlay to have a negative top", -> - marker = editor.displayBuffer.markBufferRange([[1, 0], [1, 0]], invalidate: 'never') - decoration = editor.decorateMarker(marker, {type: 'overlay', item}) - nextAnimationFrame() - nextAnimationFrame() - - position = wrapperNode.pixelPositionForBufferPosition([1, 0]) - - overlay = component.getTopmostDOMNode().querySelector('atom-overlay') - expect(overlay.style.left).toBe position.left + gutterWidth + 'px' - expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' - - editor.insertNewline() - nextAnimationFrame() - - position = wrapperNode.pixelPositionForBufferPosition([2, 0]) - - expect(overlay.style.left).toBe position.left + gutterWidth + 'px' - expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' - - describe "when editor scroll position is not 0", -> - it "flips horizontally when near the right edge", -> - scrollLeft = 3 * editor.getDefaultCharWidth() - editor.setScrollLeft(scrollLeft) - editor.setCursorBufferPosition([1, 20]) - marker = editor.displayBuffer.markBufferRange([[1, 29], [1, 29]], invalidate: 'never') - decoration = editor.decorateMarker(marker, {type: 'overlay', item}) - nextAnimationFrame() - nextAnimationFrame() - - position = wrapperNode.pixelPositionForBufferPosition([1, 29]) - - overlay = component.getTopmostDOMNode().querySelector('atom-overlay') - expect(overlay.style.left).toBe position.left + gutterWidth - scrollLeft + 'px' - expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' - - editor.insertText('a') - nextAnimationFrame() - - expect(overlay.style.left).toBe windowWidth - itemWidth + 'px' - expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' - - it "flips vertically when near the bottom edge", -> - scrollTop = 2 * editor.getLineHeightInPixels() - editor.setScrollTop(scrollTop) - editor.setCursorBufferPosition([5, 0]) - - marker = editor.displayBuffer.markBufferRange([[6, 0], [6, 0]], invalidate: 'never') - decoration = editor.decorateMarker(marker, {type: 'overlay', item}) - nextAnimationFrame() - nextAnimationFrame() - - position = wrapperNode.pixelPositionForBufferPosition([6, 0]) - - overlay = component.getTopmostDOMNode().querySelector('atom-overlay') - expect(overlay.style.left).toBe position.left + gutterWidth + 'px' - expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() - scrollTop + 'px' - - editor.insertNewline() - nextAnimationFrame() - - position = wrapperNode.pixelPositionForBufferPosition([7, 0]) - - expect(overlay.style.left).toBe position.left + gutterWidth + 'px' - expect(overlay.style.top).toBe position.top - itemHeight - scrollTop + 'px' describe "hidden input field", -> it "renders the hidden input field at the position of the last cursor if the cursor is on screen and the editor is focused", -> diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index f8703c085..5b30178d6 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -333,8 +333,8 @@ class TextEditorPresenter {scrollTop, scrollLeft} = @state.content gutterWidth = @boundingClientRect.width - @contentFrameWidth - left = pixelPosition.left - scrollLeft + gutterWidth top = pixelPosition.top + @lineHeight - scrollTop + left = pixelPosition.left + gutterWidth - scrollLeft if overlayDimensions = @overlayDimensions[decoration.id] {itemWidth, itemHeight, contentMargin} = overlayDimensions @@ -345,7 +345,7 @@ class TextEditorPresenter leftDiff = left + @boundingClientRect.left + contentMargin left -= leftDiff if leftDiff < 0 - if top + @boundingClientRect.top + itemHeight > @windowHeight + if top + @boundingClientRect.top + itemHeight > @windowHeight and top - (itemHeight + @lineHeight) >= 0 top -= itemHeight + @lineHeight pixelPosition.top = top From 44d130240248dbc1530518a6ff425ffe38c0b15a Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 1 Apr 2015 16:22:24 -0700 Subject: [PATCH 0382/1783] Fix text-editor-component spec --- spec/text-editor-component-spec.coffee | 32 -------------------------- 1 file changed, 32 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index cc4d8e37d..1699a0f9b 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -1284,7 +1284,6 @@ describe "TextEditorComponent", -> item = document.createElement('div') item.classList.add 'overlay-test' item.style.background = 'red' - gutterWidth = componentNode.querySelector('.gutter').offsetWidth describe "when the marker is empty", -> @@ -1302,29 +1301,6 @@ describe "TextEditorComponent", -> overlay = component.getTopmostDOMNode().querySelector('atom-overlay .overlay-test') expect(overlay).toBe null - it "renders in the correct position on initial display and when the marker moves", -> - editor.setCursorBufferPosition([2, 5]) - - marker = editor.getLastCursor().getMarker() - decoration = editor.decorateMarker(marker, {type: 'overlay', item}) - nextAnimationFrame() - nextAnimationFrame() - - position = wrapperNode.pixelPositionForBufferPosition([2, 5]) - - overlay = component.getTopmostDOMNode().querySelector('atom-overlay') - expect(overlay.style.left).toBe position.left + gutterWidth + 'px' - expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' - - editor.moveRight() - editor.moveRight() - nextAnimationFrame() - - position = wrapperNode.pixelPositionForBufferPosition([2, 7]) - - expect(overlay.style.left).toBe position.left + gutterWidth + 'px' - expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' - describe "when the marker is not empty", -> it "renders at the head of the marker by default", -> marker = editor.displayBuffer.markBufferRange([[2, 5], [2, 10]], invalidate: 'never') @@ -1387,14 +1363,6 @@ describe "TextEditorComponent", -> expect(overlay.style.left).toBe windowWidth - itemWidth + 'px' expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' - editor.insertNewline() - nextAnimationFrame() - - position = wrapperNode.pixelPositionForBufferPosition([5, 0]) - - expect(overlay.style.left).toBe position.left + gutterWidth + 'px' - expect(overlay.style.top).toBe position.top - itemHeight + 'px' - describe "hidden input field", -> it "renders the hidden input field at the position of the last cursor if the cursor is on screen and the editor is focused", -> From e29b8416a1c6bd7cbccf94790a915bac2aba5788 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 1 Apr 2015 17:36:13 -0700 Subject: [PATCH 0383/1783] Always add the item to the parent. --- src/overlay-manager.coffee | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/overlay-manager.coffee b/src/overlay-manager.coffee index 8d0db365d..6dc36b998 100644 --- a/src/overlay-manager.coffee +++ b/src/overlay-manager.coffee @@ -32,10 +32,13 @@ class OverlayManager cachedOverlay = @overlaysById[decorationId] unless overlayNode = cachedOverlay?.overlayNode overlayNode = document.createElement('atom-overlay') - overlayNode.appendChild(itemView) @container.appendChild(overlayNode) @overlaysById[decorationId] = cachedOverlay = {overlayNode, itemView} + # The same node may be used in more than one overlay. This steals the node + # back if it has been displayed in another overlay. + overlayNode.appendChild(itemView) if overlayNode.childNodes.length == 0 + cachedOverlay.pixelPosition = pixelPosition overlayNode.style.top = pixelPosition.top + 'px' overlayNode.style.left = pixelPosition.left + 'px' From dff2453b65a28e362a1902e6aab13b5c55190b93 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 1 Apr 2015 18:05:17 -0700 Subject: [PATCH 0384/1783] Attempt to fix spec --- spec/text-editor-component-spec.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 1699a0f9b..5f9d2af2f 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -2234,6 +2234,7 @@ describe "TextEditorComponent", -> expect(editor.lineTextForBufferRow(0)).toBe 'üvar quicksort = function () {' it "does not handle input events when input is disabled", -> + nextAnimationFrame = noAnimationFrame # This spec is flaky on the build machine, so this. component.setInputEnabled(false) componentNode.dispatchEvent(buildTextInputEvent(data: 'x', target: inputNode)) expect(nextAnimationFrame).toBe noAnimationFrame From 89d1bc9a716009791d186f21251b0c8573002733 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Thu, 2 Apr 2015 10:08:55 +0800 Subject: [PATCH 0385/1783] :arrow_up: apm@0.158.0 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index 84f73451d..e7a0c8fdc 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.157.0" + "atom-package-manager": "0.158.0" } } From 44d88e082c6771f68804cf9e762b46664877b0e0 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 2 Apr 2015 16:28:22 +0200 Subject: [PATCH 0386/1783] :bug: Always copy selections in order --- spec/text-editor-spec.coffee | 14 ++++++++++++++ src/text-editor.coffee | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index bdb6b38fc..0caf62ada 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -2792,6 +2792,20 @@ describe "TextEditor", -> [[5, 8], [5, 8]] ]) + describe "when many selections get added in shuffle order", -> + it "copies them in order", -> + editor.setSelectedBufferRanges([ + [[2,8], [2, 13]] + [[0,4], [0,13]], + [[1,6], [1, 10]], + ]) + editor.copySelectedText() + expect(atom.clipboard.read()).toEqual """ + quicksort + sort + items + """ + describe ".pasteText()", -> copyText = (text, {startColumn, textEditor}={}) -> startColumn ?= 0 diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 355a644b8..d3b8200ab 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -2621,7 +2621,7 @@ class TextEditor extends Model # Essential: For each selection, copy the selected text. copySelectedText: -> maintainClipboard = false - for selection in @getSelections() + for selection in @getSelectionsOrderedByBufferPosition() if selection.isEmpty() previousRange = selection.getBufferRange() selection.selectLine() From b3bdad084f400eb4ab010b7e138c417e9b57e705 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 2 Apr 2015 16:35:26 +0200 Subject: [PATCH 0387/1783] Always mutate selections in order --- spec/text-editor-spec.coffee | 22 ++++++++++++++++++++-- src/text-editor.coffee | 2 +- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 0caf62ada..51226a22b 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -2730,6 +2730,20 @@ describe "TextEditor", -> """ + describe "when many selections get added in shuffle order", -> + it "cuts them in order", -> + editor.setSelectedBufferRanges([ + [[2,8], [2, 13]] + [[0,4], [0,13]], + [[1,6], [1, 10]], + ]) + editor.cutSelectedText() + expect(atom.clipboard.read()).toEqual """ + quicksort + sort + items + """ + describe ".cutToEndOfLine()", -> describe "when soft wrap is on", -> it "cuts up to the end of the line", -> @@ -2900,8 +2914,12 @@ describe "TextEditor", -> editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[1, 6], [1, 10]]]) editor.copySelectedText() - it "pastes each selection separately into the buffer", -> - editor.copySelectedText() + it "pastes each selection in order separately into the buffer", -> + editor.setSelectedBufferRanges([ + [[1, 6], [1, 10]] + [[0, 4], [0, 13]], + ]) + editor.moveRight() editor.insertText("_") editor.pasteText() diff --git a/src/text-editor.coffee b/src/text-editor.coffee index d3b8200ab..548725cf6 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -843,7 +843,7 @@ class TextEditor extends Model mutateSelectedText: (fn) -> @mergeIntersectingSelections => @transact => - fn(selection, index) for selection, index in @getSelections() + fn(selection, index) for selection, index in @getSelectionsOrderedByBufferPosition() # Move lines intersection the most recent selection up by one row in screen # coordinates. From 0fe1ea1af3c93a19affc9a35ad2a169849d72fd8 Mon Sep 17 00:00:00 2001 From: Jesse Grosjean Date: Thu, 2 Apr 2015 12:25:16 -0400 Subject: [PATCH 0388/1783] Target 0 instead of -Infinity to make the code a bit clearer. --- src/display-buffer.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index d79b1bce7..6ec4ce859 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -692,7 +692,7 @@ class DisplayBuffer extends Model targetLeft = pixelPosition.left defaultCharWidth = @defaultCharWidth row = Math.floor(targetTop / @getLineHeightInPixels()) - targetLeft = -Infinity if row < 0 + targetLeft = 0 if row < 0 targetLeft = Infinity if row > @getLastRow() row = Math.min(row, @getLastRow()) row = Math.max(0, row) From cd8536d8a0d44df4574bad8ed5c3e2d99f9f5513 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 2 Apr 2015 09:42:49 -0700 Subject: [PATCH 0389/1783] Listen for error event before any other calls --- src/browser/auto-update-manager.coffee | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/browser/auto-update-manager.coffee b/src/browser/auto-update-manager.coffee index 3ee0fce3d..358390889 100644 --- a/src/browser/auto-update-manager.coffee +++ b/src/browser/auto-update-manager.coffee @@ -33,6 +33,10 @@ class AutoUpdateManager else autoUpdater = require 'auto-updater' + autoUpdater.on 'error', (event, message) => + @setState(ErrorState) + console.error "Error Downloading Update: #{message}" + autoUpdater.setFeedUrl @feedUrl autoUpdater.on 'checking-for-update', => @@ -44,10 +48,6 @@ class AutoUpdateManager autoUpdater.on 'update-available', => @setState(DownladingState) - autoUpdater.on 'error', (event, message) => - @setState(ErrorState) - console.error "Error Downloading Update: #{message}" - autoUpdater.on 'update-downloaded', (event, releaseNotes, @releaseVersion) => @setState(UpdateAvailableState) @emitUpdateAvailableEvent(@getWindows()...) From 1b8337e79f3cf9837f401209b648b6f702963177 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 2 Apr 2015 09:47:20 -0700 Subject: [PATCH 0390/1783] Project::getPath -> Project::getPaths Closes atom/autocomplete-css#4 --- src/atom.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/atom.coffee b/src/atom.coffee index 707500479..a71adeeeb 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -768,7 +768,7 @@ class Atom extends Model callback(showSaveDialogSync()) showSaveDialogSync: (defaultPath) -> - defaultPath ?= @project?.getPath() + defaultPath ?= @project?.getPaths()[0] currentWindow = @getCurrentWindow() dialog = remote.require('dialog') dialog.showSaveDialog currentWindow, {title: 'Save File', defaultPath} From bc4ed8a874e160e3691a63296152ad34203cbe3e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 2 Apr 2015 10:01:49 -0700 Subject: [PATCH 0391/1783] :arrow_up: first-mate@3.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 75e2a325d..e53f93ea6 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "delegato": "^1", "emissary": "^1.3.3", "event-kit": "^1.0.3", - "first-mate": "^3.0.0", + "first-mate": "^3.0.1", "fs-plus": "^2.6", "fstream": "0.1.24", "fuzzaldrin": "^2.1", From 21df0d0401a33a3589ddacd4c2d6c2f067315ef0 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 2 Apr 2015 19:06:41 +0200 Subject: [PATCH 0392/1783] :white_check_mark: Use component.measureDimensions() --- spec/text-editor-component-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 4b5a503bc..a5ca4c309 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -1426,7 +1426,7 @@ describe "TextEditorComponent", -> height = 4.5 * lineHeightInPixels wrapperNode.style.height = height + 'px' wrapperNode.style.width = 10 * charWidth + 'px' - component.measureHeightAndWidth() + component.measureDimensions() nextAnimationFrame() coordinates = clientCoordinatesForScreenPosition([0, 2]) From 15091c716db2e279e8b6434d799556f69de9cd87 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 2 Apr 2015 10:16:18 -0700 Subject: [PATCH 0393/1783] Pin to typescript-simple@1.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e53f93ea6..2b15919e9 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ "temp": "0.8.1", "text-buffer": "^5.1.0", "theorist": "^1.0.2", - "typescript-simple": "^1.0.0", + "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6" }, "packageDependencies": { From ede6dbb581044e5e6e53ec9eedd912c6ec80ea0b Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 2 Apr 2015 13:56:45 -0600 Subject: [PATCH 0394/1783] :arrow_up: text-buffer to fix marker restoration (fixes #6223) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2b15919e9..371720500 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "space-pen": "3.8.2", "stacktrace-parser": "0.1.1", "temp": "0.8.1", - "text-buffer": "^5.1.0", + "text-buffer": "^5.1.1", "theorist": "^1.0.2", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6" From 89f082602b5b17c8b7a60a0573d8038358087f4b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 2 Apr 2015 14:44:40 -0700 Subject: [PATCH 0395/1783] :arrow_up: grim@1.2.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 371720500..4b130c3a2 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "fstream": "0.1.24", "fuzzaldrin": "^2.1", "git-utils": "^3.0.0", - "grim": "1.2", + "grim": "1.2.1", "jasmine-json": "~0.0", "jasmine-tagged": "^1.1.4", "jquery": "^2.1.1", From 14e75aacf921cd32d9b58263e4131ed8659d852a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 2 Apr 2015 15:17:16 -0700 Subject: [PATCH 0396/1783] :arrow_up: archive-view@0.55 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4b130c3a2..311d1c8f1 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ "one-light-ui": "0.4.0", "solarized-dark-syntax": "0.32.0", "solarized-light-syntax": "0.19.0", - "archive-view": "0.53.0", + "archive-view": "0.55.0", "autocomplete": "0.44.0", "autoflow": "0.22.0", "autosave": "0.20.0", From 4c7fe0414b6f5784a83162c30fa76d7ff7418ece Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 2 Apr 2015 15:18:19 -0700 Subject: [PATCH 0397/1783] :arrow_up: language-c@0.43 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 311d1c8f1..683d0badc 100644 --- a/package.json +++ b/package.json @@ -123,7 +123,7 @@ "welcome": "0.26.0", "whitespace": "0.29.0", "wrap-guide": "0.31.0", - "language-c": "0.42.0", + "language-c": "0.43.0", "language-clojure": "0.13.0", "language-coffee-script": "0.39.0", "language-csharp": "0.5.0", From aa4d294c19c4fcdcd30a95d94cdb525684d318d2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 2 Apr 2015 17:19:20 -0700 Subject: [PATCH 0398/1783] Implement clearObservers in GrammarRegistry --- src/grammar-registry.coffee | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/grammar-registry.coffee b/src/grammar-registry.coffee index acdc863bc..911ffafbe 100644 --- a/src/grammar-registry.coffee +++ b/src/grammar-registry.coffee @@ -2,6 +2,7 @@ _ = require 'underscore-plus' {deprecate} = require 'grim' {specificity} = require 'clear-cut' {Subscriber} = require 'emissary' +{Emitter} = require 'event-kit' FirstMate = require 'first-mate' {ScopeSelector} = FirstMate ScopedPropertyStore = require 'scoped-property-store' @@ -69,3 +70,7 @@ class GrammarRegistry extends FirstMate.GrammarRegistry propertiesForScope: (scope, keyPath) -> deprecate 'Use atom.config.getAll instead.' atom.config.settingsForScopeDescriptor(scope, keyPath) + + clearObservers: -> + @off() + @emitter = new Emitter From 2d5f848b4f49ebd507b3a8b18831aba682f0db7e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 2 Apr 2015 17:29:03 -0700 Subject: [PATCH 0399/1783] :arrow_up: keybinding-resolver@0.30 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 683d0badc..795ee2bc6 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "grammar-selector": "0.46.0", "image-view": "0.54.0", "incompatible-packages": "0.24.0", - "keybinding-resolver": "0.29.0", + "keybinding-resolver": "0.30.0", "link": "0.30.0", "markdown-preview": "0.146.0", "metrics": "0.45.0", From 33d5a2b3fc3e493773d8f1bfc078a7f13533b637 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Fri, 3 Apr 2015 18:21:39 +0800 Subject: [PATCH 0400/1783] InspectorFrontendAPI changed to DevToolsAPI --- src/atom.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/atom.coffee b/src/atom.coffee index fc4f59ef2..95ed0d4c9 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -226,7 +226,7 @@ class Atom extends Model if openDevTools @openDevTools() - @executeJavaScriptInDevTools('InspectorFrontendAPI.showConsole()') + @executeJavaScriptInDevTools('DevToolsAPI.showConsole()') @emit 'uncaught-error', arguments... @emitter.emit 'did-throw-error', {message, url, line, column, originalError} From 6910c81b4636bc16f0cdbc47875fe92d21e7a97c Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Fri, 3 Apr 2015 18:25:45 +0800 Subject: [PATCH 0401/1783] Fix error when running apm in packages --- src/package-manager.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 2bbcf7fe7..c00087084 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -134,7 +134,7 @@ class PackageManager commandName = 'apm' commandName += '.cmd' if process.platform is 'win32' - apmRoot = path.resolve(__dirname, '..', '..', 'apm') + apmRoot = path.join(process.resourcesPath, 'apm') @apmPath = path.join(apmRoot, 'bin', commandName) unless fs.isFileSync(@apmPath) @apmPath = path.join(apmRoot, 'node_modules', 'atom-package-manager', 'bin', commandName) From 1cf5822d20ffef09d2b446e79b75ef59c64b6c6e Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 3 Apr 2015 18:06:28 +0200 Subject: [PATCH 0402/1783] Merge intersecting selections by row before deleting lines --- spec/text-editor-spec.coffee | 15 +++++++++++++++ src/selection.coffee | 7 +++++++ src/text-editor.coffee | 17 +++++++++++++---- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 51226a22b..f2945977a 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -3376,6 +3376,21 @@ describe "TextEditor", -> expect(buffer.lineForRow(0)).toBe(line2) expect(buffer.getLineCount()).toBe(count - 2) + it "deletes only the first line when it has multiple selections", -> + line1 = buffer.lineForRow(1) + count = buffer.getLineCount() + editor.getLastCursor().moveToTop() + editor.setSelectedBufferRanges([ + [[0, 1], [0, 2]], + [[0, 4], [0, 5]] + ]) + expect(buffer.lineForRow(0)).not.toBe(line1) + + editor.deleteLine() + + expect(buffer.lineForRow(0)).toBe(line1) + expect(buffer.getLineCount()).toBe(count - 1) + it "only deletes first line if only newline is selected on second line", -> editor.setSelectedBufferRange([[0, 2], [1, 0]]) line1 = buffer.lineForRow(1) diff --git a/src/selection.coffee b/src/selection.coffee index ea4b54034..971ddbdd9 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -174,6 +174,13 @@ class Selection extends Model intersectsScreenRow: (screenRow) -> @getScreenRange().intersectsRow(screenRow) + intersectsByRowWith: (otherSelection) -> + otherScreenRange = otherSelection.getScreenRange() + + @getScreenRange().intersectsRowRange( + otherScreenRange.start.row, otherScreenRange.end.row + ) + # Public: Identifies if a selection intersects with another selection. # # * `otherSelection` A {Selection} to check against. diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 548725cf6..23a612ee4 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -1114,6 +1114,7 @@ class TextEditor extends Model # Extended: Delete all lines intersecting selections. deleteLine: -> + @mergeIntersectingSelectionsByRow() @mutateSelectedText (selection) -> selection.deleteLine() # Deprecated: Use {::deleteToBeginningOfWord} instead. @@ -2232,6 +2233,17 @@ class TextEditor extends Model # the function with merging suppressed, then merges intersecting selections # afterward. mergeIntersectingSelections: (args...) -> + @mergeSelections args..., (previousSelection, currentSelection) -> + exclusive = not currentSelection.isEmpty() and not previousSelection.isEmpty() + + previousSelection.intersectsWith(currentSelection, exclusive) + + mergeIntersectingSelectionsByRow: (args...) -> + @mergeSelections args..., (previousSelection, currentSelection) -> + previousSelection.intersectsByRowWith(currentSelection) + + mergeSelections: (args...) -> + mergePredicate = args.pop() fn = args.pop() if _.isFunction(_.last(args)) options = args.pop() ? {} @@ -2244,10 +2256,7 @@ class TextEditor extends Model reducer = (disjointSelections, selection) -> adjacentSelection = _.last(disjointSelections) - exclusive = not selection.isEmpty() and not adjacentSelection.isEmpty() - intersects = adjacentSelection.intersectsWith(selection, exclusive) - - if intersects + if mergePredicate(adjacentSelection, selection) adjacentSelection.merge(selection, options) disjointSelections else From 42521900e8248ab95bd8a986e91934d01ecae822 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 3 Apr 2015 18:10:43 +0200 Subject: [PATCH 0403/1783] :memo: Improve naming --- spec/text-editor-spec.coffee | 2 +- src/selection.coffee | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index f2945977a..3be0c8b0e 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -3376,7 +3376,7 @@ describe "TextEditor", -> expect(buffer.lineForRow(0)).toBe(line2) expect(buffer.getLineCount()).toBe(count - 2) - it "deletes only the first line when it has multiple selections", -> + it "deletes a line only once when multiple selections are on the same line", -> line1 = buffer.lineForRow(1) count = buffer.getLineCount() editor.getLastCursor().moveToTop() diff --git a/src/selection.coffee b/src/selection.coffee index 971ddbdd9..c6d6933c0 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -174,6 +174,11 @@ class Selection extends Model intersectsScreenRow: (screenRow) -> @getScreenRange().intersectsRow(screenRow) + # Public: Identifies if this selection's rows intersects with another selection's rows. + # + # * `otherSelection` A {Selection} to check against. + # + # Returns a {Boolean} intersectsByRowWith: (otherSelection) -> otherScreenRange = otherSelection.getScreenRange() From decab183b7ddef217ed0ecd58875915f81c31c79 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 3 Apr 2015 10:34:21 -0700 Subject: [PATCH 0404/1783] Fix screen/buffer range error in paragraph cursor motions --- spec/text-editor-spec.coffee | 26 ++++++++++---------------- src/cursor.coffee | 4 ++-- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 51226a22b..439a1ddb6 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -831,35 +831,29 @@ describe "TextEditor", -> describe ".moveToBeginningOfNextParagraph()", -> it "moves the cursor before the first line of the next paragraph", -> - editor.setCursorBufferPosition [0,6] - cursor = editor.getLastCursor() + editor.setCursorBufferPosition [0, 6] + editor.foldBufferRow(4) editor.moveToBeginningOfNextParagraph() - - expect(cursor.getBufferPosition()).toEqual { row : 10, column : 0 } + expect(editor.getCursorBufferPosition()).toEqual [10, 0] editor.setText("") - editor.setCursorBufferPosition [0,0] - cursor = editor.getLastCursor() + editor.setCursorBufferPosition [0, 0] editor.moveToBeginningOfNextParagraph() - - expect(cursor.getBufferPosition()).toEqual [0, 0] + expect(editor.getCursorBufferPosition()).toEqual [0, 0] describe ".moveToBeginningOfPreviousParagraph()", -> it "moves the cursor before the first line of the pevious paragraph", -> - editor.setCursorBufferPosition [10,0] - cursor = editor.getLastCursor() + editor.setCursorBufferPosition [10, 0] + editor.foldBufferRow(4) editor.moveToBeginningOfPreviousParagraph() - - expect(cursor.getBufferPosition()).toEqual { row : 0, column : 0 } + expect(editor.getCursorBufferPosition()).toEqual [0, 0] editor.setText("") - editor.setCursorBufferPosition [0,0] - cursor = editor.getLastCursor() + editor.setCursorBufferPosition [0, 0] editor.moveToBeginningOfPreviousParagraph() - - expect(cursor.getBufferPosition()).toEqual [0, 0] + expect(editor.getCursorBufferPosition()).toEqual [0, 0] describe ".getCurrentParagraphBufferRange()", -> it "returns the buffer range of the current paragraph, delimited by blank lines or the beginning / end of the file", -> diff --git a/src/cursor.coffee b/src/cursor.coffee index acfc7fc9e..1656b9dc2 100644 --- a/src/cursor.coffee +++ b/src/cursor.coffee @@ -672,7 +672,7 @@ class Cursor extends Model if !range.start.isEqual(start) position = range.start stop() - @editor.screenPositionForBufferPosition(position) + position getBeginningOfPreviousParagraphBufferPosition: -> start = @getBufferPosition() @@ -685,4 +685,4 @@ class Cursor extends Model if !range.start.isEqual(zero) position = range.start stop() - @editor.screenPositionForBufferPosition(position) + position From 3de83f6860d9086d5366a80ce8f5516851d3865c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 3 Apr 2015 11:03:43 -0700 Subject: [PATCH 0405/1783] Revert "Add asar support in Atom" --- apm/package.json | 2 +- build/Gruntfile.coffee | 4 ++-- build/package.json | 1 - build/tasks/build-task.coffee | 6 +++--- build/tasks/generate-asar-task.coffee | 19 ------------------- build/tasks/generate-license-task.coffee | 2 +- script/mkdeb | 2 +- src/atom.coffee | 6 +++--- src/browser/atom-application.coffee | 2 +- src/browser/squirrel-update.coffee | 2 +- src/command-installer.coffee | 13 +++++++------ src/package-manager.coffee | 2 +- src/task.coffee | 7 +------ 13 files changed, 22 insertions(+), 46 deletions(-) delete mode 100644 build/tasks/generate-asar-task.coffee diff --git a/apm/package.json b/apm/package.json index e7a0c8fdc..84f73451d 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.158.0" + "atom-package-manager": "0.157.0" } } diff --git a/build/Gruntfile.coffee b/build/Gruntfile.coffee index ed4c7b933..05efaeb38 100644 --- a/build/Gruntfile.coffee +++ b/build/Gruntfile.coffee @@ -223,7 +223,7 @@ module.exports = (grunt) -> ciTasks = ['output-disk-space', 'download-atom-shell', 'download-atom-shell-chromedriver', 'build'] ciTasks.push('dump-symbols') if process.platform isnt 'win32' - ciTasks.push('set-version', 'check-licenses', 'lint', 'generate-asar') + ciTasks.push('set-version', 'check-licenses', 'lint') ciTasks.push('mkdeb') if process.platform is 'linux' ciTasks.push('create-windows-installer') if process.platform is 'win32' ciTasks.push('test') if process.platform is 'darwin' @@ -231,6 +231,6 @@ module.exports = (grunt) -> ciTasks.push('publish-build') grunt.registerTask('ci', ciTasks) - defaultTasks = ['download-atom-shell', 'download-atom-shell-chromedriver', 'build', 'set-version', 'generate-asar'] + defaultTasks = ['download-atom-shell', 'download-atom-shell-chromedriver', 'build', 'set-version'] defaultTasks.push 'install' unless process.platform is 'linux' grunt.registerTask('default', defaultTasks) diff --git a/build/package.json b/build/package.json index ef5b314a0..297ddadfd 100644 --- a/build/package.json +++ b/build/package.json @@ -6,7 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "asar": "^0.4.0", "async": "~0.2.9", "donna": "1.0.7", "formidable": "~1.0.14", diff --git a/build/tasks/build-task.coffee b/build/tasks/build-task.coffee index 74e5d8821..fcb1eb6a8 100644 --- a/build/tasks/build-task.coffee +++ b/build/tasks/build-task.coffee @@ -22,7 +22,7 @@ module.exports = (grunt) -> mkdir appDir if process.platform isnt 'win32' - cp 'atom.sh', path.resolve(appDir, '..', 'atom.sh') + cp 'atom.sh', path.join(appDir, 'atom.sh') cp 'package.json', path.join(appDir, 'package.json') @@ -145,9 +145,9 @@ module.exports = (grunt) -> cp 'src', path.join(appDir, 'src'), filter: /.+\.(cson|coffee)$/ cp 'static', path.join(appDir, 'static') - cp path.join('apm', 'node_modules', 'atom-package-manager'), path.resolve(appDir, '..', 'apm'), filter: filterNodeModule + cp path.join('apm', 'node_modules', 'atom-package-manager'), path.join(appDir, 'apm'), filter: filterNodeModule if process.platform isnt 'win32' - fs.symlinkSync(path.join('..', '..', 'bin', 'apm'), path.resolve(appDir, '..', 'apm', 'node_modules', '.bin', 'apm')) + fs.symlinkSync(path.join('..', '..', 'bin', 'apm'), path.join(appDir, 'apm', 'node_modules', '.bin', 'apm')) if process.platform is 'darwin' grunt.file.recurse path.join('resources', 'mac'), (sourcePath, rootDirectory, subDirectory='', filename) -> diff --git a/build/tasks/generate-asar-task.coffee b/build/tasks/generate-asar-task.coffee deleted file mode 100644 index 1f74fbf5d..000000000 --- a/build/tasks/generate-asar-task.coffee +++ /dev/null @@ -1,19 +0,0 @@ -asar = require 'asar' -fs = require 'fs' -path = require 'path' - -module.exports = (grunt) -> - {rm} = require('./task-helpers')(grunt) - - grunt.registerTask 'generate-asar', 'Generate asar archive for the app', -> - done = @async() - - appDir = grunt.config.get('atom.appDir') - unless fs.existsSync(appDir) - grunt.log.error 'The app has to be built before generating asar archive.' - return done(false) - - asar.createPackageWithOptions appDir, path.resolve(appDir, '..', 'app.asar'), {unpack: '*.node'}, (err) -> - return done(err) if err? - rm appDir - done() diff --git a/build/tasks/generate-license-task.coffee b/build/tasks/generate-license-task.coffee index eaf1a9a66..6b616f5cb 100644 --- a/build/tasks/generate-license-task.coffee +++ b/build/tasks/generate-license-task.coffee @@ -17,7 +17,7 @@ module.exports = (grunt) -> licenseText = getLicenseText(dependencyLicenses) if mode is 'save' - targetPath = path.resolve(grunt.config.get('atom.appDir'), '..', 'LICENSE.md') + targetPath = path.join(grunt.config.get('atom.appDir'), 'LICENSE.md') fs.writeFileSync(targetPath, licenseText) else console.log licenseText diff --git a/script/mkdeb b/script/mkdeb index c39b6d649..272fe23f3 100755 --- a/script/mkdeb +++ b/script/mkdeb @@ -33,7 +33,7 @@ cp "$ICON_FILE" "$TARGET/usr/share/pixmaps" # Copy generated LICENSE.md to /usr/share/doc/atom/copyright mkdir -m $FILE_MODE -p "$TARGET/usr/share/doc/atom" -cp "$TARGET/usr/share/atom/resources/LICENSE.md" "$TARGET/usr/share/doc/atom/copyright" +cp "$TARGET/usr/share/atom/resources/app/LICENSE.md" "$TARGET/usr/share/doc/atom/copyright" # Add lintian overrides mkdir -m $FILE_MODE -p "$TARGET/usr/share/lintian/overrides" diff --git a/src/atom.coffee b/src/atom.coffee index f05ce11f6..a71adeeeb 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -226,7 +226,7 @@ class Atom extends Model if openDevTools @openDevTools() - @executeJavaScriptInDevTools('DevToolsAPI.showConsole()') + @executeJavaScriptInDevTools('InspectorFrontendAPI.showConsole()') @emit 'uncaught-error', arguments... @emitter.emit 'did-throw-error', {message, url, line, column, originalError} @@ -581,9 +581,9 @@ class Atom extends Model {resourcePath, safeMode} = @getLoadSettings() CommandInstaller = require './command-installer' - CommandInstaller.installAtomCommand false, (error) -> + CommandInstaller.installAtomCommand resourcePath, false, (error) -> console.warn error.message if error? - CommandInstaller.installApmCommand false, (error) -> + CommandInstaller.installApmCommand resourcePath, false, (error) -> console.warn error.message if error? dimensions = @restoreWindowDimensions() diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 7d88858c5..d79b2bf76 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -190,7 +190,7 @@ class AtomApplication @openPathOnEvent('application:open-your-keymap', 'atom://.atom/keymap') @openPathOnEvent('application:open-your-snippets', 'atom://.atom/snippets') @openPathOnEvent('application:open-your-stylesheet', 'atom://.atom/stylesheet') - @openPathOnEvent('application:open-license', path.join(process.resourcesPath, 'LICENSE.md')) + @openPathOnEvent('application:open-license', path.join(@resourcePath, 'LICENSE.md')) app.on 'window-all-closed', -> app.quit() if process.platform in ['win32', 'linux'] diff --git a/src/browser/squirrel-update.coffee b/src/browser/squirrel-update.coffee index 3bdd84223..1603a7c0a 100644 --- a/src/browser/squirrel-update.coffee +++ b/src/browser/squirrel-update.coffee @@ -142,7 +142,7 @@ addCommandsToPath = (callback) -> atomShCommand = "#!/bin/sh\r\n\"$0/../#{relativeAtomShPath.replace(/\\/g, '/')}\" \"$@\"" apmCommandPath = path.join(binFolder, 'apm.cmd') - relativeApmPath = path.relative(binFolder, path.join(process.resourcesPath, 'apm', 'bin', 'apm.cmd')) + relativeApmPath = path.relative(binFolder, path.join(process.resourcesPath, 'app', 'apm', 'bin', 'apm.cmd')) apmCommand = "@echo off\r\n\"%~dp0\\#{relativeApmPath}\" %*" apmShCommandPath = path.join(binFolder, 'apm') diff --git a/src/command-installer.coffee b/src/command-installer.coffee index c7772b4f5..1d3a16777 100644 --- a/src/command-installer.coffee +++ b/src/command-installer.coffee @@ -36,11 +36,12 @@ module.exports = message: "Failed to install shell commands" detailedMessage: error.message - @installAtomCommand true, (error) => + resourcePath = atom.getLoadSettings().resourcePath + @installAtomCommand resourcePath, true, (error) => if error? showErrorDialog(error) else - @installApmCommand true, (error) -> + @installApmCommand resourcePath, true, (error) -> if error? showErrorDialog(error) else @@ -48,12 +49,12 @@ module.exports = message: "Commands installed." detailedMessage: "The shell commands `atom` and `apm` are installed." - installAtomCommand: (askForPrivilege, callback) -> - commandPath = path.join(process.resourcesPath, 'atom.sh') + installAtomCommand: (resourcePath, askForPrivilege, callback) -> + commandPath = path.join(resourcePath, 'atom.sh') @createSymlink commandPath, askForPrivilege, callback - installApmCommand: (askForPrivilege, callback) -> - commandPath = path.join(process.resourcesPath, 'apm', 'node_modules', '.bin', 'apm') + installApmCommand: (resourcePath, askForPrivilege, callback) -> + commandPath = path.join(resourcePath, 'apm', 'node_modules', '.bin', 'apm') @createSymlink commandPath, askForPrivilege, callback createSymlink: (commandPath, askForPrivilege, callback) -> diff --git a/src/package-manager.coffee b/src/package-manager.coffee index c00087084..444497c5b 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -134,7 +134,7 @@ class PackageManager commandName = 'apm' commandName += '.cmd' if process.platform is 'win32' - apmRoot = path.join(process.resourcesPath, 'apm') + apmRoot = path.resolve(__dirname, '..', 'apm') @apmPath = path.join(apmRoot, 'bin', commandName) unless fs.isFileSync(@apmPath) @apmPath = path.join(apmRoot, 'node_modules', 'atom-package-manager', 'bin', commandName) diff --git a/src/task.coffee b/src/task.coffee index d752ea11d..9572494b8 100644 --- a/src/task.coffee +++ b/src/task.coffee @@ -83,7 +83,7 @@ class Task taskPath = taskPath.replace(/\\/g, "\\\\") env = _.extend({}, process.env, {taskPath, userAgent: navigator.userAgent}) - @childProcess = fork '--eval', [bootstrap], {env, silent: true} + @childProcess = fork '--eval', [bootstrap], {env, cwd: __dirname} @on "task:log", -> console.log(arguments...) @on "task:warn", -> console.warn(arguments...) @@ -100,11 +100,6 @@ class Task @childProcess.removeAllListeners() @childProcess.on 'message', ({event, args}) => @emit(event, args...) if @childProcess? - # Catch the errors that happened before task-bootstrap. - @childProcess.stdout.on 'data', (data) -> - console.log data.toString() - @childProcess.stderr.on 'data', (data) -> - console.error data.toString() # Public: Starts the task. # From f79c2669fc95992499858592bbee9910345b14c6 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 09:46:23 -0700 Subject: [PATCH 0406/1783] Add 1.0 API preview command line option --- src/atom.coffee | 10 +++++++--- src/browser/atom-application.coffee | 24 ++++++++++++++---------- src/browser/atom-window.coffee | 3 ++- src/browser/main.coffee | 5 ++++- 4 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/atom.coffee b/src/atom.coffee index a71adeeeb..c45744408 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -342,15 +342,19 @@ class Atom extends Model # Public: Is the current window in development mode? inDevMode: -> - @getLoadSettings().devMode + @devMode ?= @getLoadSettings().devMode # Public: Is the current window in safe mode? inSafeMode: -> - @getLoadSettings().safeMode + @safeMode ?= @getLoadSettings().safeMode # Public: Is the current window running specs? inSpecMode: -> - @getLoadSettings().isSpec + @specMode ?= @getLoadSettings().isSpec + + # Is the current window in 1.0 API preview mode? + inApiPreviewMode: -> + @apiPreviewMode ?= @getLoadSettings().apiPreviewMode # Public: Get the version of the Atom application. # diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index d79b2bf76..fb9085416 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -60,7 +60,7 @@ class AtomApplication exit: (status) -> app.exit(status) constructor: (options) -> - {@resourcePath, @version, @devMode, @safeMode, @socketPath} = options + {@resourcePath, @version, @devMode, @safeMode, @apiPreviewMode, @socketPath} = options # Normalize to make sure drive letter case is consistent on Windows @resourcePath = path.normalize(@resourcePath) if @resourcePath @@ -82,15 +82,15 @@ class AtomApplication @openWithOptions(options) # Opens a new window based on the options provided. - openWithOptions: ({pathsToOpen, urlsToOpen, test, pidToKillWhenClosed, devMode, safeMode, newWindow, specDirectory, logFile}) -> + openWithOptions: ({pathsToOpen, urlsToOpen, test, pidToKillWhenClosed, devMode, safeMode, apiPreviewMode, newWindow, specDirectory, logFile}) -> if test @runSpecs({exitWhenDone: true, @resourcePath, specDirectory, logFile}) else if pathsToOpen.length > 0 - @openPaths({pathsToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode}) + @openPaths({pathsToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, apiPreviewMode}) else if urlsToOpen.length > 0 - @openUrl({urlToOpen, devMode, safeMode}) for urlToOpen in urlsToOpen + @openUrl({urlToOpen, devMode, safeMode, apiPreviewMode}) for urlToOpen in urlsToOpen else - @openPath({pidToKillWhenClosed, newWindow, devMode, safeMode}) # Always open a editor window if this is the first instance of Atom. + @openPath({pidToKillWhenClosed, newWindow, devMode, safeMode, apiPreviewMode}) # Always open a editor window if this is the first instance of Atom. # Public: Removes the {AtomWindow} from the global window list. removeWindow: (window) -> @@ -146,6 +146,7 @@ class AtomApplication getLoadSettings = => devMode: @focusedWindow()?.devMode safeMode: @focusedWindow()?.safeMode + apiPreviewMode: @focusedWindow()?.apiPreviewMode @on 'application:run-all-specs', -> @runSpecs(exitWhenDone: false, resourcePath: global.devResourcePath, safeMode: @focusedWindow()?.safeMode) @on 'application:run-benchmarks', -> @runBenchmarks() @@ -157,6 +158,7 @@ class AtomApplication @on 'application:open-folder', -> @promptForPathToOpen('folder', getLoadSettings()) @on 'application:open-dev', -> @promptForPathToOpen('all', devMode: true) @on 'application:open-safe', -> @promptForPathToOpen('all', safeMode: true) + @on 'application:open-api-preview', -> @promptForPathToOpen('all', apiPreviewMode: true) @on 'application:inspect', ({x,y, atomWindow}) -> atomWindow ?= @focusedWindow() atomWindow?.browserWindow.inspectElement(x, y) @@ -209,7 +211,7 @@ class AtomApplication app.on 'open-url', (event, urlToOpen) => event.preventDefault() - @openUrl({urlToOpen, @devMode, @safeMode}) + @openUrl({urlToOpen, @devMode, @safeMode, @apiPreviewMode}) app.on 'activate-with-no-open-windows', (event) => event.preventDefault() @@ -333,9 +335,10 @@ class AtomApplication # :newWindow - Boolean of whether this should be opened in a new window. # :devMode - Boolean to control the opened window's dev mode. # :safeMode - Boolean to control the opened window's safe mode. + # :apiPreviewMode - Boolean to control the opened window's 1.0 API preview mode. # :window - {AtomWindow} to open file paths in. - openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, window}) -> - @openPaths({pathsToOpen: [pathToOpen], pidToKillWhenClosed, newWindow, devMode, safeMode, window}) + openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, apiPreviewMode, window}) -> + @openPaths({pathsToOpen: [pathToOpen], pidToKillWhenClosed, newWindow, devMode, safeMode, apiPreviewMode, window}) # Public: Opens a single path, in an existing window if possible. # @@ -345,9 +348,10 @@ class AtomApplication # :newWindow - Boolean of whether this should be opened in a new window. # :devMode - Boolean to control the opened window's dev mode. # :safeMode - Boolean to control the opened window's safe mode. + # :apiPreviewMode - Boolean to control the opened window's 1.0 API preview mode. # :windowDimensions - Object with height and width keys. # :window - {AtomWindow} to open file paths in. - openPaths: ({pathsToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, windowDimensions, window}={}) -> + openPaths: ({pathsToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, apiPreviewMode, windowDimensions, window}={}) -> pathsToOpen = (fs.normalize(pathToOpen) for pathToOpen in pathsToOpen) locationsToOpen = (@locationForPathToOpen(pathToOpen) for pathToOpen in pathsToOpen) @@ -377,7 +381,7 @@ class AtomApplication bootstrapScript ?= require.resolve('../window-bootstrap') resourcePath ?= @resourcePath - openedWindow = new AtomWindow({locationsToOpen, bootstrapScript, resourcePath, devMode, safeMode, windowDimensions}) + openedWindow = new AtomWindow({locationsToOpen, bootstrapScript, resourcePath, devMode, safeMode, apiPreviewMode, windowDimensions}) if pidToKillWhenClosed? @pidsToOpenWindows[pidToKillWhenClosed] = openedWindow diff --git a/src/browser/atom-window.coffee b/src/browser/atom-window.coffee index 66fad179e..fff98799c 100644 --- a/src/browser/atom-window.coffee +++ b/src/browser/atom-window.coffee @@ -18,7 +18,7 @@ class AtomWindow isSpec: null constructor: (settings={}) -> - {@resourcePath, pathToOpen, locationsToOpen, @isSpec, @exitWhenDone, @safeMode, @devMode} = settings + {@resourcePath, pathToOpen, locationsToOpen, @isSpec, @exitWhenDone, @safeMode, @devMode, @apiPreviewMode} = settings locationsToOpen ?= [{pathToOpen}] if pathToOpen locationsToOpen ?= [] @@ -47,6 +47,7 @@ class AtomWindow loadSettings.resourcePath = @resourcePath loadSettings.devMode ?= false loadSettings.safeMode ?= false + loadSettings.apiPreviewMode ?= false # Only send to the first non-spec window created if @constructor.includeShellLoadTime and not @isSpec diff --git a/src/browser/main.coffee b/src/browser/main.coffee index 09db16357..812771e9a 100644 --- a/src/browser/main.coffee +++ b/src/browser/main.coffee @@ -106,6 +106,7 @@ parseCommandLine = -> ATOM_HOME The root path for all configuration files and folders. Defaults to `~/.atom`. """ + options.alias('1', 'one').boolean('1').describe('1', 'Run in 1.0 API preview mode.') options.alias('d', 'dev').boolean('d').describe('d', 'Run in development mode.') options.alias('f', 'foreground').boolean('f').describe('f', 'Keep the browser process in the foreground.') options.alias('h', 'help').boolean('h').describe('h', 'Print this usage message.') @@ -131,6 +132,7 @@ parseCommandLine = -> executedFrom = args['executed-from'] devMode = args['dev'] safeMode = args['safe'] + apiPreviewMode = args['one'] pathsToOpen = args._ pathsToOpen = [executedFrom] if executedFrom and pathsToOpen.length is 0 test = args['test'] @@ -164,6 +166,7 @@ parseCommandLine = -> process.env.PATH = args['path-environment'] if args['path-environment'] {resourcePath, pathsToOpen, executedFrom, test, version, pidToKillWhenClosed, - devMode, safeMode, newWindow, specDirectory, logFile, socketPath} + devMode, apiPreviewMode, safeMode, newWindow, specDirectory, logFile, + socketPath} start() From 80cb757cfec8f2da6385fb7be6a9d6e390c131d5 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 09:47:44 -0700 Subject: [PATCH 0407/1783] Add api preview open ipc event proxy --- src/workspace-element.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/workspace-element.coffee b/src/workspace-element.coffee index 425d920d8..5afe2cf0e 100644 --- a/src/workspace-element.coffee +++ b/src/workspace-element.coffee @@ -136,6 +136,7 @@ atom.commands.add 'atom-workspace', 'application:open-folder': -> ipc.send('command', 'application:open-folder') 'application:open-dev': -> ipc.send('command', 'application:open-dev') 'application:open-safe': -> ipc.send('command', 'application:open-safe') + 'application:open-api-preview': -> ipc.send('command', 'application:open-api-preview') 'application:minimize': -> ipc.send('command', 'application:minimize') 'application:zoom': -> ipc.send('command', 'application:zoom') 'application:bring-all-windows-to-front': -> ipc.send('command', 'application:bring-all-windows-to-front') From 5a7d746eaeec84d4bea4304808f295676304809b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 12:18:11 -0700 Subject: [PATCH 0408/1783] Conditionally include deprecations in Atom --- src/atom.coffee | 88 +++++++++++++++++++++++++------------------------ static/index.js | 2 ++ 2 files changed, 47 insertions(+), 43 deletions(-) diff --git a/src/atom.coffee b/src/atom.coffee index c45744408..49a76481b 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -6,7 +6,7 @@ remote = require 'remote' shell = require 'shell' _ = require 'underscore-plus' -{deprecate} = require 'grim' +{deprecate, includeDeprecations} = require 'grim' {Emitter} = require 'event-kit' {Model} = require 'theorist' fs = require 'fs-plus' @@ -34,35 +34,36 @@ class Atom extends Model atom = @deserialize(@loadState(mode)) ? new this({mode, @version}) atom.deserializeTimings.atom = Date.now() - startTime - workspaceViewDeprecationMessage = """ - atom.workspaceView is no longer available. - In most cases you will not need the view. See the Workspace docs for - alternatives: https://atom.io/docs/api/latest/Workspace. - If you do need the view, please use `atom.views.getView(atom.workspace)`, - which returns an HTMLElement. - """ + if includeDeprecations + workspaceViewDeprecationMessage = """ + atom.workspaceView is no longer available. + In most cases you will not need the view. See the Workspace docs for + alternatives: https://atom.io/docs/api/latest/Workspace. + If you do need the view, please use `atom.views.getView(atom.workspace)`, + which returns an HTMLElement. + """ - serviceHubDeprecationMessage = """ - atom.services is no longer available. To register service providers and - consumers, use the `providedServices` and `consumedServices` fields in - your package's package.json. - """ + serviceHubDeprecationMessage = """ + atom.services is no longer available. To register service providers and + consumers, use the `providedServices` and `consumedServices` fields in + your package's package.json. + """ - Object.defineProperty atom, 'workspaceView', - get: -> - deprecate(workspaceViewDeprecationMessage) - atom.__workspaceView - set: (newValue) -> - deprecate(workspaceViewDeprecationMessage) - atom.__workspaceView = newValue + Object.defineProperty atom, 'workspaceView', + get: -> + deprecate(workspaceViewDeprecationMessage) + atom.__workspaceView + set: (newValue) -> + deprecate(workspaceViewDeprecationMessage) + atom.__workspaceView = newValue - Object.defineProperty atom, 'services', - get: -> - deprecate(serviceHubDeprecationMessage) - atom.packages.serviceHub - set: (newValue) -> - deprecate(serviceHubDeprecationMessage) - atom.packages.serviceHub = newValue + Object.defineProperty atom, 'services', + get: -> + deprecate(serviceHubDeprecationMessage) + atom.packages.serviceHub + set: (newValue) -> + deprecate(serviceHubDeprecationMessage) + atom.packages.serviceHub = newValue atom @@ -263,7 +264,10 @@ class Atom extends Model @config = new Config({configDirPath, resourcePath}) @keymaps = new KeymapManager({configDirPath, resourcePath}) - @keymap = @keymaps # Deprecated + + if includeDeprecations + @keymap = @keymaps # Deprecated + @keymaps.subscribeToFileReadFailure() @tooltips = new TooltipManager @notifications = new NotificationManager @@ -279,9 +283,10 @@ class Atom extends Model @grammars = @deserializers.deserialize(@state.grammars ? @state.syntax) ? new GrammarRegistry() - Object.defineProperty this, 'syntax', get: -> - deprecate "The atom.syntax global is deprecated. Use atom.grammars instead." - @grammars + if includeDeprecations + Object.defineProperty this, 'syntax', get: -> + deprecate "The atom.syntax global is deprecated. Use atom.grammars instead." + @grammars @subscribe @packages.onDidActivateInitialPackages => @watchThemes() @@ -352,10 +357,6 @@ class Atom extends Model inSpecMode: -> @specMode ?= @getLoadSettings().isSpec - # Is the current window in 1.0 API preview mode? - inApiPreviewMode: -> - @apiPreviewMode ?= @getLoadSettings().apiPreviewMode - # Public: Get the version of the Atom application. # # Returns the version text {String}. @@ -831,17 +832,18 @@ class Atom extends Model updateAvailable: (details) -> @emitter.emit 'update-available', details - # Deprecated: Callers should be converted to use atom.deserializers - registerRepresentationClass: -> - deprecate("Callers should be converted to use atom.deserializers") - - # Deprecated: Callers should be converted to use atom.deserializers - registerRepresentationClasses: -> - deprecate("Callers should be converted to use atom.deserializers") - setBodyPlatformClass: -> document.body.classList.add("platform-#{process.platform}") setAutoHideMenuBar: (autoHide) -> ipc.send('call-window-method', 'setAutoHideMenuBar', autoHide) ipc.send('call-window-method', 'setMenuBarVisibility', !autoHide) + +if includeDeprecations + # Deprecated: Callers should be converted to use atom.deserializers + Atom::registerRepresentationClass = -> + deprecate("Callers should be converted to use atom.deserializers") + + # Deprecated: Callers should be converted to use atom.deserializers + Atom::registerRepresentationClasses = -> + deprecate("Callers should be converted to use atom.deserializers") diff --git a/static/index.js b/static/index.js index d99a9e9e7..7c8e92571 100644 --- a/static/index.js +++ b/static/index.js @@ -34,6 +34,8 @@ window.onload = function() { ModuleCache.register(loadSettings); ModuleCache.add(loadSettings.resourcePath); + require('grim').includeDeprecations = !loadSettings.apiPreviewMode; + // Start the crash reporter before anything else. require('crash-reporter').start({ productName: 'Atom', From 69b0d90e6449842ef3eec8da6324bb37019f3379 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 12:23:41 -0700 Subject: [PATCH 0409/1783] Remove unused require --- src/token.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/token.coffee b/src/token.coffee index 778ea16e6..941daf032 100644 --- a/src/token.coffee +++ b/src/token.coffee @@ -1,5 +1,4 @@ _ = require 'underscore-plus' -{deprecate} = require 'grim' textUtils = require './text-utils' WhitespaceRegexesByTabLength = {} From 87fca98bab08173dda5f360442f45a618a16e02c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 12:24:48 -0700 Subject: [PATCH 0410/1783] Deprecate TextEditorComponent::setShowInvisibles --- src/text-editor-component.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 43f8184db..071d39271 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -754,6 +754,7 @@ class TextEditorComponent # Deprecated setShowInvisibles: (showInvisibles) -> + grim.deprecate "Use config.set('editor.showInvisibles', showInvisibles) instead" atom.config.set('editor.showInvisibles', showInvisibles) setScrollSensitivity: (scrollSensitivity) => From 94d42197eb32702ba4b067b50fe36a3420c224f0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 12:29:13 -0700 Subject: [PATCH 0411/1783] Conditionally include deprecations --- exports/atom.coffee | 190 +++++++++++++++++++------------------- src/styles-element.coffee | 5 +- 2 files changed, 99 insertions(+), 96 deletions(-) diff --git a/exports/atom.coffee b/exports/atom.coffee index 5afa04022..6b9243098 100644 --- a/exports/atom.coffee +++ b/exports/atom.coffee @@ -1,7 +1,7 @@ TextBuffer = require 'text-buffer' {Point, Range} = TextBuffer {Emitter, Disposable, CompositeDisposable} = require 'event-kit' -{deprecate} = require 'grim' +{includeDeprecations, deprecate} = require 'grim' module.exports = BufferedNodeProcess: require '../src/buffered-node-process' @@ -21,109 +21,111 @@ unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE module.exports.Task = require '../src/task' module.exports.TextEditor = require '../src/text-editor' - {$, $$, $$$, View} = require '../src/space-pen-extensions' + if includeDeprecations + {$, $$, $$$, View} = require '../src/space-pen-extensions' - Object.defineProperty module.exports, 'Workspace', get: -> - deprecate """ - Requiring `Workspace` from `atom` is no longer supported. - If you need this, please open an issue on - https://github.com/atom/atom/issues/new - And let us know what you are using it for. - """ - require '../src/workspace' + Object.defineProperty module.exports, 'Workspace', get: -> + deprecate """ + Requiring `Workspace` from `atom` is no longer supported. + If you need this, please open an issue on + https://github.com/atom/atom/issues/new + And let us know what you are using it for. + """ + require '../src/workspace' - Object.defineProperty module.exports, 'WorkspaceView', get: -> - deprecate """ - Requiring `WorkspaceView` from `atom` is no longer supported. - Use `atom.views.getView(atom.workspace)` instead. - """ - require '../src/workspace-view' + Object.defineProperty module.exports, 'WorkspaceView', get: -> + deprecate """ + Requiring `WorkspaceView` from `atom` is no longer supported. + Use `atom.views.getView(atom.workspace)` instead. + """ + require '../src/workspace-view' - Object.defineProperty module.exports, '$', get: -> - deprecate """ - Requiring `$` from `atom` is no longer supported. - If you are using `space-pen`, please require `$` from `atom-space-pen-views`. Otherwise require `jquery` instead: - `{$} = require 'atom-space-pen-views'` - or - `$ = require 'jquery'` - Add `"atom-space-pen-views": "^2.0.3"` to your package dependencies. - Or add `"jquery": "^2"` to your package dependencies. - """ - $ + Object.defineProperty module.exports, '$', get: -> + deprecate """ + Requiring `$` from `atom` is no longer supported. + If you are using `space-pen`, please require `$` from `atom-space-pen-views`. Otherwise require `jquery` instead: + `{$} = require 'atom-space-pen-views'` + or + `$ = require 'jquery'` + Add `"atom-space-pen-views": "^2.0.3"` to your package dependencies. + Or add `"jquery": "^2"` to your package dependencies. + """ + $ - Object.defineProperty module.exports, '$$', get: -> - deprecate """ - Requiring `$$` from `atom` is no longer supported. - Please require `atom-space-pen-views` instead: - `{$$} = require 'atom-space-pen-views'` - Add `"atom-space-pen-views": "^2.0.3"` to your package dependencies. - """ - $$ + Object.defineProperty module.exports, '$$', get: -> + deprecate """ + Requiring `$$` from `atom` is no longer supported. + Please require `atom-space-pen-views` instead: + `{$$} = require 'atom-space-pen-views'` + Add `"atom-space-pen-views": "^2.0.3"` to your package dependencies. + """ + $$ - Object.defineProperty module.exports, '$$$', get: -> - deprecate """ - Requiring `$$$` from `atom` is no longer supported. - Please require `atom-space-pen-views` instead: - `{$$$} = require 'atom-space-pen-views'` - Add `"atom-space-pen-views": "^2.0.3"` to your package dependencies. - """ - $$$ + Object.defineProperty module.exports, '$$$', get: -> + deprecate """ + Requiring `$$$` from `atom` is no longer supported. + Please require `atom-space-pen-views` instead: + `{$$$} = require 'atom-space-pen-views'` + Add `"atom-space-pen-views": "^2.0.3"` to your package dependencies. + """ + $$$ - Object.defineProperty module.exports, 'View', get: -> - deprecate """ - Requiring `View` from `atom` is no longer supported. - Please require `atom-space-pen-views` instead: - `{View} = require 'atom-space-pen-views'` - Add `"atom-space-pen-views": "^2.0.3"` to your package dependencies. - """ - View + Object.defineProperty module.exports, 'View', get: -> + deprecate """ + Requiring `View` from `atom` is no longer supported. + Please require `atom-space-pen-views` instead: + `{View} = require 'atom-space-pen-views'` + Add `"atom-space-pen-views": "^2.0.3"` to your package dependencies. + """ + View - Object.defineProperty module.exports, 'EditorView', get: -> - deprecate """ - Requiring `EditorView` from `atom` is no longer supported. - Please require `TextEditorView` from `atom-space-pen-view` instead: - `{TextEditorView} = require 'atom-space-pen-views'` - Add `"atom-space-pen-views": "^2.0.3"` to your package dependencies. - """ - require '../src/text-editor-view' + Object.defineProperty module.exports, 'EditorView', get: -> + deprecate """ + Requiring `EditorView` from `atom` is no longer supported. + Please require `TextEditorView` from `atom-space-pen-view` instead: + `{TextEditorView} = require 'atom-space-pen-views'` + Add `"atom-space-pen-views": "^2.0.3"` to your package dependencies. + """ + require '../src/text-editor-view' - Object.defineProperty module.exports, 'TextEditorView', get: -> - deprecate """ - Requiring `TextEditorView` from `atom` is no longer supported. - Please require `TextEditorView` from `atom-space-pen-view` instead: - `{TextEditorView} = require 'atom-space-pen-views'` - Add `"atom-space-pen-views": "^2.0.3"` to your package dependencies. - """ - require '../src/text-editor-view' + Object.defineProperty module.exports, 'TextEditorView', get: -> + deprecate """ + Requiring `TextEditorView` from `atom` is no longer supported. + Please require `TextEditorView` from `atom-space-pen-view` instead: + `{TextEditorView} = require 'atom-space-pen-views'` + Add `"atom-space-pen-views": "^2.0.3"` to your package dependencies. + """ + require '../src/text-editor-view' - Object.defineProperty module.exports, 'ScrollView', get: -> - deprecate """ - Requiring `ScrollView` from `atom` is no longer supported. - Please require `ScrollView` from `atom-space-pen-view` instead: - `{ScrollView} = require 'atom-space-pen-views'` - Note that the API has changed slightly! Please read the docs at https://github.com/atom/atom-space-pen-views - Add `"atom-space-pen-views": "^2.0.3"` to your package dependencies. - """ - require '../src/scroll-view' + Object.defineProperty module.exports, 'ScrollView', get: -> + deprecate """ + Requiring `ScrollView` from `atom` is no longer supported. + Please require `ScrollView` from `atom-space-pen-view` instead: + `{ScrollView} = require 'atom-space-pen-views'` + Note that the API has changed slightly! Please read the docs at https://github.com/atom/atom-space-pen-views + Add `"atom-space-pen-views": "^2.0.3"` to your package dependencies. + """ + require '../src/scroll-view' - Object.defineProperty module.exports, 'SelectListView', get: -> - deprecate """ - Requiring `SelectListView` from `atom` is no longer supported. - Please require `SelectListView` from `atom-space-pen-view` instead: - `{SelectListView} = require 'atom-space-pen-views'` - Note that the API has changed slightly! Please read the docs at https://github.com/atom/atom-space-pen-views - Add `"atom-space-pen-views": "^2.0.3"` to your package dependencies. - """ - require '../src/select-list-view' + Object.defineProperty module.exports, 'SelectListView', get: -> + deprecate """ + Requiring `SelectListView` from `atom` is no longer supported. + Please require `SelectListView` from `atom-space-pen-view` instead: + `{SelectListView} = require 'atom-space-pen-views'` + Note that the API has changed slightly! Please read the docs at https://github.com/atom/atom-space-pen-views + Add `"atom-space-pen-views": "^2.0.3"` to your package dependencies. + """ + require '../src/select-list-view' - Object.defineProperty module.exports, 'React', get: -> - deprecate "Please require `react-atom-fork` instead: `React = require 'react-atom-fork'`. Add `\"react-atom-fork\": \"^0.11\"` to your package dependencies." - require 'react-atom-fork' + Object.defineProperty module.exports, 'React', get: -> + deprecate "Please require `react-atom-fork` instead: `React = require 'react-atom-fork'`. Add `\"react-atom-fork\": \"^0.11\"` to your package dependencies." + require 'react-atom-fork' - Object.defineProperty module.exports, 'Reactionary', get: -> - deprecate "Please require `reactionary-atom-fork` instead: `Reactionary = require 'reactionary-atom-fork'`. Add `\"reactionary-atom-fork\": \"^0.9\"` to your package dependencies." - require 'reactionary-atom-fork' + Object.defineProperty module.exports, 'Reactionary', get: -> + deprecate "Please require `reactionary-atom-fork` instead: `Reactionary = require 'reactionary-atom-fork'`. Add `\"reactionary-atom-fork\": \"^0.9\"` to your package dependencies." + require 'reactionary-atom-fork' -Object.defineProperty module.exports, 'Git', get: -> - deprecate "Please require `GitRepository` instead of `Git`: `{GitRepository} = require 'atom'`" - module.exports.GitRepository +if includeDeprecations + Object.defineProperty module.exports, 'Git', get: -> + deprecate "Please require `GitRepository` instead of `Git`: `{GitRepository} = require 'atom'`" + module.exports.GitRepository diff --git a/src/styles-element.coffee b/src/styles-element.coffee index fc3b888cf..eaf7c53c8 100644 --- a/src/styles-element.coffee +++ b/src/styles-element.coffee @@ -1,4 +1,5 @@ {Emitter, CompositeDisposable} = require 'event-kit' +{includeDeprecations} = require 'grim' class StylesElement extends HTMLElement subscriptions: null @@ -18,7 +19,7 @@ class StylesElement extends HTMLElement @styleElementClonesByOriginalElement = new WeakMap attachedCallback: -> - if @context is 'atom-text-editor' + if includeDeprecations and @context is 'atom-text-editor' for styleElement in @children @upgradeDeprecatedSelectors(styleElement) @initialize() @@ -66,7 +67,7 @@ class StylesElement extends HTMLElement @insertBefore(styleElementClone, insertBefore) - if @context is 'atom-text-editor' + if includeDeprecations and @context is 'atom-text-editor' @upgradeDeprecatedSelectors(styleElementClone) @emitter.emit 'did-add-style-element', styleElementClone From bc58574238a377493fa9ebe2c7456d7f388dbeb6 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 12:41:27 -0700 Subject: [PATCH 0412/1783] Conditionally include deprecations in Cursor --- src/cursor.coffee | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/cursor.coffee b/src/cursor.coffee index 1656b9dc2..a930666c3 100644 --- a/src/cursor.coffee +++ b/src/cursor.coffee @@ -39,13 +39,13 @@ class Cursor extends Model textChanged: textChanged cursor: this - @emit 'moved', movedEvent + @emit 'moved', movedEvent if Grim.includeDeprecations @emitter.emit 'did-change-position', movedEvent @editor.cursorMoved(movedEvent) @marker.onDidDestroy => @destroyed = true @editor.removeCursor(this) - @emit 'destroyed' + @emit 'destroyed' if Grim.includeDeprecations @emitter.emit 'did-destroy' @emitter.dispose() @@ -89,6 +89,8 @@ class Cursor extends Model @emitter.on 'did-change-visibility', callback on: (eventName) -> + return unless Grim.includeDeprecations + switch eventName when 'moved' Grim.deprecate("Use Cursor::onDidChangePosition instead") @@ -222,9 +224,6 @@ class Cursor extends Model # Returns a {ScopeDescriptor} getScopeDescriptor: -> @editor.scopeDescriptorForBufferPosition(@getBufferPosition()) - getScopes: -> - Grim.deprecate 'Use Cursor::getScopeDescriptor() instead' - @getScopeDescriptor().getScopesArray() # Public: Returns true if this cursor has no non-whitespace characters before # its current position. @@ -476,10 +475,6 @@ class Cursor extends Model endOfWordPosition or currentBufferPosition - getMoveNextWordBoundaryBufferPosition: (options) -> - Grim.deprecate 'Use `::getNextWordBoundaryBufferPosition(options)` instead' - @getNextWordBoundaryBufferPosition(options) - # Public: Retrieves the buffer position of where the current word starts. # # * `options` (optional) An {Object} with the following keys: @@ -593,7 +588,7 @@ class Cursor extends Model setVisible: (visible) -> if @visible != visible @visible = visible - @emit 'visibility-changed', @visible + @emit 'visibility-changed', @visible if Grim.includeDeprecations @emitter.emit 'did-change-visibility', @visible # Public: Returns the visibility of the cursor. @@ -686,3 +681,12 @@ class Cursor extends Model position = range.start stop() position + +if Grim.includeDeprecations + Cursor::getScopes = -> + Grim.deprecate 'Use Cursor::getScopeDescriptor() instead' + @getScopeDescriptor().getScopesArray() + + Cursor::getMoveNextWordBoundaryBufferPosition = (options) -> + Grim.deprecate 'Use `::getNextWordBoundaryBufferPosition(options)` instead' + @getNextWordBoundaryBufferPosition(options) From 4884e32a3df1261296aa276ac12764e530628664 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 12:41:40 -0700 Subject: [PATCH 0413/1783] Conditionally include deprecations in ContextMenuManager --- src/context-menu-manager.coffee | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/context-menu-manager.coffee b/src/context-menu-manager.coffee index ed91f5e6c..69caa5d6d 100644 --- a/src/context-menu-manager.coffee +++ b/src/context-menu-manager.coffee @@ -101,25 +101,26 @@ class ContextMenuManager # with the following argument: # * `event` The click event that deployed the context menu. add: (itemsBySelector) -> - # Detect deprecated file path as first argument - if itemsBySelector? and typeof itemsBySelector isnt 'object' - Grim.deprecate """ - ContextMenuManager::add has changed to take a single object as its - argument. Please see - https://atom.io/docs/api/latest/ContextMenuManager for more info. - """ - itemsBySelector = arguments[1] - devMode = arguments[2]?.devMode - - # Detect deprecated format for items object - for key, value of itemsBySelector - unless _.isArray(value) + if Grim.includeDeprecations + # Detect deprecated file path as first argument + if itemsBySelector? and typeof itemsBySelector isnt 'object' Grim.deprecate """ ContextMenuManager::add has changed to take a single object as its argument. Please see https://atom.io/docs/api/latest/ContextMenuManager for more info. """ - itemsBySelector = @convertLegacyItemsBySelector(itemsBySelector, devMode) + itemsBySelector = arguments[1] + devMode = arguments[2]?.devMode + + # Detect deprecated format for items object + for key, value of itemsBySelector + unless _.isArray(value) + Grim.deprecate """ + ContextMenuManager::add has changed to take a single object as its + argument. Please see + https://atom.io/docs/api/latest/ContextMenuManager for more info. + """ + itemsBySelector = @convertLegacyItemsBySelector(itemsBySelector, devMode) addedItemSets = [] From 2d9eaa5c7529210c575189421e15621d961b2fe0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 12:45:18 -0700 Subject: [PATCH 0414/1783] Conditionally include deprecations in Decoration --- src/decoration.coffee | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/decoration.coffee b/src/decoration.coffee index cbf649473..92316042c 100644 --- a/src/decoration.coffee +++ b/src/decoration.coffee @@ -30,7 +30,6 @@ nextId = -> idCounter++ # the marker. module.exports = class Decoration - EmitterMixin.includeInto(this) # Private: Check if the `decorationProperties.type` matches `type` # @@ -123,9 +122,6 @@ class Decoration # Essential: Returns the {Decoration}'s properties. getProperties: -> @properties - getParams: -> - Grim.deprecate 'Use Decoration::getProperties instead' - @getProperties() # Essential: Update the marker with new Properties. Allows you to change the decoration's class. # @@ -143,9 +139,6 @@ class Decoration @properties.id = @id @emit 'updated', {oldParams: oldProperties, newParams: newProperties} @emitter.emit 'did-change-properties', {oldProperties, newProperties} - update: (newProperties) -> - Grim.deprecate 'Use Decoration::setProperties instead' - @setProperties(newProperties) ### Section: Private methods @@ -171,7 +164,10 @@ class Decoration return @flashQueue.shift() if @flashQueue?.length > 0 null - on: (eventName) -> +if Grim.includeDeprecations + EmitterMixin.includeInto(Decoration) + + Decoration::on = (eventName) -> switch eventName when 'updated' Grim.deprecate 'Use Decoration::onDidChangeProperties instead' @@ -183,3 +179,11 @@ class Decoration Grim.deprecate 'Decoration::on is deprecated. Use event subscription methods instead.' EmitterMixin::on.apply(this, arguments) + + Decoration::getParams = -> + Grim.deprecate 'Use Decoration::getProperties instead' + @getProperties() + + Decoration::update = -> (newProperties) -> + Grim.deprecate 'Use Decoration::setProperties instead' + @setProperties(newProperties) From 1fdbd4db3fc9788466d844432958beb50c8018c3 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 12:46:00 -0700 Subject: [PATCH 0415/1783] Conditionally include deprecations in DeserializerManager --- src/deserializer-manager.coffee | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/deserializer-manager.coffee b/src/deserializer-manager.coffee index 40c5ea7f3..4efc71ec5 100644 --- a/src/deserializer-manager.coffee +++ b/src/deserializer-manager.coffee @@ -37,11 +37,6 @@ class DeserializerManager delete @deserializers[deserializer.name] for deserializer in deserializers return - remove: (classes...) -> - Grim.deprecate("Call .dispose() on the Disposable return from ::add instead") - delete @deserializers[name] for {name} in classes - return - # Public: Deserialize the state and params. # # * `state` The state {Object} to deserialize. @@ -65,3 +60,9 @@ class DeserializerManager name = state.get?('deserializer') ? state.deserializer @deserializers[name] + +if Grim.includeDeprecations + DeserializerManager::remove = (classes...) -> + Grim.deprecate("Call .dispose() on the Disposable return from ::add instead") + delete @deserializers[name] for {name} in classes + return From 15c48c5388a5e7ecfb0ed6a40693873d3a88eb67 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 12:49:44 -0700 Subject: [PATCH 0416/1783] Conditionally include deprecations in DisplayBuffer --- src/display-buffer.coffee | 69 ++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index 6ec4ce859..aef36fc99 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -151,38 +151,11 @@ class DisplayBuffer extends Model onDidUpdateMarkers: (callback) -> @emitter.on 'did-update-markers', callback - on: (eventName) -> - switch eventName - when 'changed' - Grim.deprecate("Use DisplayBuffer::onDidChange instead") - when 'grammar-changed' - Grim.deprecate("Use DisplayBuffer::onDidChangeGrammar instead") - when 'soft-wrap-changed' - Grim.deprecate("Use DisplayBuffer::onDidChangeSoftWrap instead") - when 'character-widths-changed' - Grim.deprecate("Use DisplayBuffer::onDidChangeCharacterWidths instead") - when 'decoration-added' - Grim.deprecate("Use DisplayBuffer::onDidAddDecoration instead") - when 'decoration-removed' - Grim.deprecate("Use DisplayBuffer::onDidRemoveDecoration instead") - when 'decoration-changed' - Grim.deprecate("Use decoration.getMarker().onDidChange() instead") - when 'decoration-updated' - Grim.deprecate("Use Decoration::onDidChangeProperties instead") - when 'marker-created' - Grim.deprecate("Use Decoration::onDidCreateMarker instead") - when 'markers-updated' - Grim.deprecate("Use Decoration::onDidUpdateMarkers instead") - else - Grim.deprecate("DisplayBuffer::on is deprecated. Use event subscription methods instead.") - - EmitterMixin::on.apply(this, arguments) - emitDidChange: (eventProperties, refreshMarkers=true) -> if refreshMarkers @pauseMarkerChangeEvents() @refreshMarkerScreenPositions() - @emit 'changed', eventProperties + @emit 'changed', eventProperties if Grim.includeDeprecations @emitter.emit 'did-change', eventProperties @resumeMarkerChangeEvents() @@ -336,7 +309,7 @@ class DisplayBuffer extends Model characterWidthsChanged: -> @computeScrollWidth() - @emit 'character-widths-changed', @scopedCharacterWidthsChangeCount + @emit 'character-widths-changed', @scopedCharacterWidthsChangeCount if Grim.includeDeprecations @emitter.emit 'did-change-character-widths', @scopedCharacterWidthsChangeCount clearScopedCharWidths: -> @@ -454,7 +427,7 @@ class DisplayBuffer extends Model @softWrapped = softWrapped @updateWrappedScreenLines() softWrapped = @isSoftWrapped() - @emit 'soft-wrap-changed', softWrapped + @emit 'soft-wrap-changed', softWrapped if Grim.includeDeprecations @emitter.emit 'did-change-soft-wrapped', softWrapped softWrapped else @@ -938,7 +911,7 @@ class DisplayBuffer extends Model @decorationsByMarkerId[marker.id] ?= [] @decorationsByMarkerId[marker.id].push(decoration) @decorationsById[decoration.id] = decoration - @emit 'decoration-added', decoration + @emit 'decoration-added', decoration if Grim.includeDeprecations @emitter.emit 'did-add-decoration', decoration decoration @@ -950,7 +923,7 @@ class DisplayBuffer extends Model if index > -1 decorations.splice(index, 1) delete @decorationsById[decoration.id] - @emit 'decoration-removed', decoration + @emit 'decoration-removed', decoration if Grim.includeDeprecations @emitter.emit 'did-remove-decoration', decoration delete @decorationsByMarkerId[marker.id] if decorations.length is 0 @@ -1102,7 +1075,7 @@ class DisplayBuffer extends Model resumeMarkerChangeEvents: -> marker.resumeChangeEvents() for marker in @getMarkers() - @emit 'markers-updated' + @emit 'markers-updated' if Grim.includeDeprecations @emitter.emit 'did-update-markers' refreshMarkerScreenPositions: -> @@ -1244,7 +1217,7 @@ class DisplayBuffer extends Model if marker = @getMarker(textBufferMarker.id) # The marker might have been removed in some other handler called before # this one. Only emit when the marker still exists. - @emit 'marker-created', marker + @emit 'marker-created', marker if Grim.includeDeprecations @emitter.emit 'did-create-marker', marker createFoldForMarker: (marker) -> @@ -1253,3 +1226,31 @@ class DisplayBuffer extends Model foldForMarker: (marker) -> @foldsByMarkerId[marker.id] + +if Grim.includeDeprecations + DisplayBuffer::on = (eventName) -> + switch eventName + when 'changed' + Grim.deprecate("Use DisplayBuffer::onDidChange instead") + when 'grammar-changed' + Grim.deprecate("Use DisplayBuffer::onDidChangeGrammar instead") + when 'soft-wrap-changed' + Grim.deprecate("Use DisplayBuffer::onDidChangeSoftWrap instead") + when 'character-widths-changed' + Grim.deprecate("Use DisplayBuffer::onDidChangeCharacterWidths instead") + when 'decoration-added' + Grim.deprecate("Use DisplayBuffer::onDidAddDecoration instead") + when 'decoration-removed' + Grim.deprecate("Use DisplayBuffer::onDidRemoveDecoration instead") + when 'decoration-changed' + Grim.deprecate("Use decoration.getMarker().onDidChange() instead") + when 'decoration-updated' + Grim.deprecate("Use Decoration::onDidChangeProperties instead") + when 'marker-created' + Grim.deprecate("Use Decoration::onDidCreateMarker instead") + when 'markers-updated' + Grim.deprecate("Use Decoration::onDidUpdateMarkers instead") + else + Grim.deprecate("DisplayBuffer::on is deprecated. Use event subscription methods instead.") + + EmitterMixin::on.apply(this, arguments) From efcfcc73a4c414ad899ec2d621604aceb8c27702 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 12:54:13 -0700 Subject: [PATCH 0417/1783] Conditionally include deprecations in GitRepository --- src/git-repository.coffee | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/git-repository.coffee b/src/git-repository.coffee index ae10e7459..2fb61bdff 100644 --- a/src/git-repository.coffee +++ b/src/git-repository.coffee @@ -5,7 +5,7 @@ EmitterMixin = require('emissary').Emitter {Emitter, Disposable, CompositeDisposable} = require 'event-kit' fs = require 'fs-plus' GitUtils = require 'git-utils' -{deprecate} = require 'grim' +{includeDeprecations, deprecate} = require 'grim' Task = require './task' @@ -155,16 +155,6 @@ class GitRepository onDidChangeStatuses: (callback) -> @emitter.on 'did-change-statuses', callback - on: (eventName) -> - switch eventName - when 'status-changed' - deprecate 'Use GitRepository::onDidChangeStatus instead' - when 'statuses-changed' - deprecate 'Use GitRepository::onDidChangeStatuses instead' - else - deprecate 'GitRepository::on is deprecated. Use event subscription methods instead.' - EmitterMixin::on.apply(this, arguments) - ### Section: Repository Details ### @@ -252,9 +242,6 @@ class GitRepository # * `path` (optional) {String} path in the repository to get this information # for, only needed if the repository has submodules. getOriginURL: (path) -> @getConfigValue('remote.origin.url', path) - getOriginUrl: (path) -> - deprecate 'Use ::getOriginURL instead.' - @getOriginURL(path) # Public: Returns the upstream branch for the current HEAD, or null if there # is no upstream branch for the current HEAD. @@ -492,3 +479,18 @@ class GitRepository unless statusesUnchanged @emit 'statuses-changed' @emitter.emit 'did-change-statuses' + +if includeDeprecations + GitRepository::on = (eventName) -> + switch eventName + when 'status-changed' + deprecate 'Use GitRepository::onDidChangeStatus instead' + when 'statuses-changed' + deprecate 'Use GitRepository::onDidChangeStatuses instead' + else + deprecate 'GitRepository::on is deprecated. Use event subscription methods instead.' + EmitterMixin::on.apply(this, arguments) + + GitRepository::getOriginUrl = (path) -> + deprecate 'Use ::getOriginURL instead.' + @getOriginURL(path) From 00b31c5c6e1cab3ae55fd7c21a325cc3c320712a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 12:54:54 -0700 Subject: [PATCH 0418/1783] Conditionally include Emitter mixin --- 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 2fb61bdff..a14869655 100644 --- a/src/git-repository.coffee +++ b/src/git-repository.coffee @@ -1,7 +1,6 @@ {basename, join} = require 'path' _ = require 'underscore-plus' -EmitterMixin = require('emissary').Emitter {Emitter, Disposable, CompositeDisposable} = require 'event-kit' fs = require 'fs-plus' GitUtils = require 'git-utils' @@ -43,8 +42,6 @@ Task = require './task' # ``` module.exports = class GitRepository - EmitterMixin.includeInto(this) - @exists: (path) -> if git = @open(path) git.destroy() @@ -481,6 +478,9 @@ class GitRepository @emitter.emit 'did-change-statuses' if includeDeprecations + EmitterMixin = require('emissary').Emitter + EmitterMixin.includeInto(GitRepository) + GitRepository::on = (eventName) -> switch eventName when 'status-changed' From d799254cbbfee658d842a0d560d7c42e5692e231 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 12:59:27 -0700 Subject: [PATCH 0419/1783] Conditionally include deprecations in Marker --- src/marker.coffee | 60 +++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/src/marker.coffee b/src/marker.coffee index 962ebb7e7..798dcc12d 100644 --- a/src/marker.coffee +++ b/src/marker.coffee @@ -1,7 +1,5 @@ {Range} = require 'text-buffer' _ = require 'underscore-plus' -{Subscriber} = require 'emissary' -EmitterMixin = require('emissary').Emitter {Emitter} = require 'event-kit' Grim = require 'grim' @@ -45,9 +43,6 @@ Grim = require 'grim' # See {TextEditor::markBufferRange} for usage. module.exports = class Marker - EmitterMixin.includeInto(this) - Subscriber.includeInto(this) - bufferMarkerSubscription: null oldHeadBufferPosition: null oldHeadScreenPosition: null @@ -118,17 +113,6 @@ class Marker onDidDestroy: (callback) -> @emitter.on 'did-destroy', callback - on: (eventName) -> - switch eventName - when 'changed' - Grim.deprecate("Use Marker::onDidChange instead") - when 'destroyed' - Grim.deprecate("Use Marker::onDidDestroy instead") - else - Grim.deprecate("Marker::on is deprecated. Use documented event subscription methods instead.") - - EmitterMixin::on.apply(this, arguments) - ### Section: Marker Details ### @@ -161,9 +145,6 @@ class Marker # the marker. getProperties: -> @bufferMarker.getProperties() - getAttributes: -> - Grim.deprecate 'Use Marker::getProperties instead' - @getProperties() # Essential: Merges an {Object} containing new properties into the marker's # existing properties. @@ -171,16 +152,10 @@ class Marker # * `properties` {Object} setProperties: (properties) -> @bufferMarker.setProperties(properties) - setAttributes: (properties) -> - Grim.deprecate 'Use Marker::getProperties instead' - @setProperties(properties) matchesProperties: (attributes) -> attributes = @displayBuffer.translateToBufferMarkerParams(attributes) @bufferMarker.matchesParams(attributes) - matchesAttributes: (attributes) -> - Grim.deprecate 'Use Marker::matchesProperties instead' - @matchesProperties(attributes) ### Section: Comparing to other markers @@ -344,7 +319,7 @@ class Marker destroyed: -> delete @displayBuffer.markers[@id] - @emit 'destroyed' + @emit 'destroyed' if Grim.includeDeprecations @emitter.emit 'did-destroy' @emitter.dispose() @@ -375,7 +350,7 @@ class Marker if @deferredChangeEvents? @deferredChangeEvents.push(changeEvent) else - @emit 'changed', changeEvent + @emit 'changed', changeEvent if Grim.includeDeprecations @emitter.emit 'did-change', changeEvent @oldHeadBufferPosition = newHeadBufferPosition @@ -392,9 +367,38 @@ class Marker @deferredChangeEvents = null for event in deferredChangeEvents - @emit 'changed', event + @emit 'changed', event if Grim.includeDeprecations @emitter.emit 'did-change', event return getPixelRange: -> @displayBuffer.pixelRangeForScreenRange(@getScreenRange(), false) + +if Grim.includeDeprecations + {Subscriber} = require 'emissary' + EmitterMixin = require('emissary').Emitter + EmitterMixin.includeInto(Marker) + Subscriber.includeInto(Marker) + + Marker::on = (eventName) -> + switch eventName + when 'changed' + Grim.deprecate("Use Marker::onDidChange instead") + when 'destroyed' + Grim.deprecate("Use Marker::onDidDestroy instead") + else + Grim.deprecate("Marker::on is deprecated. Use documented event subscription methods instead.") + + EmitterMixin::on.apply(this, arguments) + + Marker::getAttributes = -> + Grim.deprecate 'Use Marker::getProperties instead' + @getProperties() + + Marker::setAttributes = (properties) -> + Grim.deprecate 'Use Marker::setProperties instead' + @setProperties(properties) + + Marker::matchesAttributes = (attributes) -> + Grim.deprecate 'Use Marker::matchesProperties instead' + @matchesProperties(attributes) From 729fe91e36837c228fa104a5aec9a6e8d5afeca1 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 13:02:11 -0700 Subject: [PATCH 0420/1783] Conditionally include deprecations in Selection --- src/selection.coffee | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/selection.coffee b/src/selection.coffee index ea4b54034..2a2d1c98c 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -63,18 +63,6 @@ class Selection extends Model onDidDestroy: (callback) -> @emitter.on 'did-destroy', callback - on: (eventName) -> - switch eventName - when 'screen-range-changed' - Grim.deprecate("Use Selection::onDidChangeRange instead. Call ::getScreenRange() yourself in your callback if you need the range.") - when 'destroyed' - Grim.deprecate("Use Selection::onDidDestroy instead.") - else - Grim.deprecate("Selection::on is deprecated. Use documented event subscription methods instead.") - - super - - ### Section: Managing the selection range ### @@ -416,16 +404,6 @@ class Selection extends Model @selectLeft() if @isEmpty() and not @editor.isFoldedAtScreenRow(@cursor.getScreenRow()) @deleteSelectedText() - # Deprecated: Use {::deleteToBeginningOfWord} instead. - backspaceToBeginningOfWord: -> - deprecate("Use Selection::deleteToBeginningOfWord() instead") - @deleteToBeginningOfWord() - - # Deprecated: Use {::deleteToBeginningOfLine} instead. - backspaceToBeginningOfLine: -> - deprecate("Use Selection::deleteToBeginningOfLine() instead") - @deleteToBeginningOfLine() - # Public: Removes from the start of the selection to the beginning of the # current word if the selection is empty otherwise it deletes the selection. deleteToBeginningOfWord: -> @@ -789,3 +767,25 @@ class Selection extends Model getGoalScreenRange: -> if goalScreenRange = @marker.getProperties().goalScreenRange Range.fromObject(goalScreenRange) + +if Grim.includeDeprecations + Selection::on = (eventName) -> + switch eventName + when 'screen-range-changed' + Grim.deprecate("Use Selection::onDidChangeRange instead. Call ::getScreenRange() yourself in your callback if you need the range.") + when 'destroyed' + Grim.deprecate("Use Selection::onDidDestroy instead.") + else + Grim.deprecate("Selection::on is deprecated. Use documented event subscription methods instead.") + + super + + # Deprecated: Use {::deleteToBeginningOfWord} instead. + Selection::backspaceToBeginningOfWord = -> + deprecate("Use Selection::deleteToBeginningOfWord() instead") + @deleteToBeginningOfWord() + + # Deprecated: Use {::deleteToBeginningOfLine} instead. + Selection::backspaceToBeginningOfLine = -> + deprecate("Use Selection::deleteToBeginningOfLine() instead") + @deleteToBeginningOfLine() From baca3284f4be42cead249ba381bfa4118baa830f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 13:03:10 -0700 Subject: [PATCH 0421/1783] Conditionally include deprecations in TextEditorComponent --- src/text-editor-component.coffee | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 071d39271..c2babdca4 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -747,16 +747,6 @@ class TextEditorComponent setShowIndentGuide: (showIndentGuide) -> atom.config.set("editor.showIndentGuide", showIndentGuide) - # Deprecated - setInvisibles: (invisibles={}) -> - grim.deprecate "Use config.set('editor.invisibles', invisibles) instead" - atom.config.set('editor.invisibles', invisibles) - - # Deprecated - setShowInvisibles: (showInvisibles) -> - grim.deprecate "Use config.set('editor.showInvisibles', showInvisibles) instead" - atom.config.set('editor.showInvisibles', showInvisibles) - setScrollSensitivity: (scrollSensitivity) => if scrollSensitivity = parseInt(scrollSensitivity) @scrollSensitivity = Math.abs(scrollSensitivity) / 100 @@ -789,3 +779,14 @@ class TextEditorComponent updateParentViewMiniClass: -> @hostElement.classList.toggle('mini', @editor.isMini()) @rootElement.classList.toggle('mini', @editor.isMini()) + +if grim.includeDeprecations + # Deprecated + TextEditorComponent::setInvisibles = (invisibles={}) -> + grim.deprecate "Use config.set('editor.invisibles', invisibles) instead" + atom.config.set('editor.invisibles', invisibles) + + # Deprecated + TextEditorComponent::setShowInvisibles = (showInvisibles) -> + grim.deprecate "Use config.set('editor.showInvisibles', showInvisibles) instead" + atom.config.set('editor.showInvisibles', showInvisibles) From f91630553870b576ddf261217d29a95dada0ee0f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 13:06:54 -0700 Subject: [PATCH 0422/1783] Conditionally include deprecations in TokenizedBuffer --- src/tokenized-buffer.coffee | 40 +++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index cf7d15c28..303906ada 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -1,6 +1,5 @@ _ = require 'underscore-plus' {Model} = require 'theorist' -EmitterMixin = require('emissary').Emitter {Emitter} = require 'event-kit' {Point, Range} = require 'text-buffer' Serializable = require 'serializable' @@ -56,19 +55,6 @@ class TokenizedBuffer extends Model onDidTokenize: (callback) -> @emitter.on 'did-tokenize', callback - on: (eventName) -> - switch eventName - when 'changed' - Grim.deprecate("Use TokenizedBuffer::onDidChange instead") - when 'grammar-changed' - Grim.deprecate("Use TokenizedBuffer::onDidChangeGrammar instead") - when 'tokenized' - Grim.deprecate("Use TokenizedBuffer::onDidTokenize instead") - else - Grim.deprecate("TokenizedBuffer::on is deprecated. Use event subscription methods instead.") - - EmitterMixin::on.apply(this, arguments) - grammarAddedOrUpdated: (grammar) => if grammar.injectionSelector? @retokenizeLines() if @hasTokenForSelector(grammar.injectionSelector) @@ -94,7 +80,7 @@ class TokenizedBuffer extends Model @retokenizeLines() - @emit 'grammar-changed', grammar + @emit 'grammar-changed', grammar if Grim.includeDeprecations @emitter.emit 'did-change-grammar', grammar reloadGrammar: -> @@ -116,7 +102,7 @@ class TokenizedBuffer extends Model @invalidateRow(0) @fullyTokenized = false event = {start: 0, end: lastRow, delta: 0} - @emit 'changed', event + @emit 'changed', event if Grim.includeDeprecations @emitter.emit 'did-change', event setVisible: (@visible) -> @@ -178,7 +164,7 @@ class TokenizedBuffer extends Model [startRow, endRow] = @updateFoldableStatus(startRow, endRow) event = {start: startRow, end: endRow, delta: 0} - @emit 'changed', event + @emit 'changed', event if Grim.includeDeprecations @emitter.emit 'did-change', event if @firstInvalidRow()? @@ -188,7 +174,7 @@ class TokenizedBuffer extends Model markTokenizationComplete: -> unless @fullyTokenized - @emit 'tokenized' + @emit 'tokenized' if Grim.includeDeprecations @emitter.emit 'did-tokenize' @fullyTokenized = true @@ -235,7 +221,7 @@ class TokenizedBuffer extends Model end -= delta event = { start, end, delta, bufferChange: e } - @emit 'changed', event + @emit 'changed', event if Grim.includeDeprecations @emitter.emit 'did-change', event retokenizeWhitespaceRowsIfIndentLevelChanged: (row, increment) -> @@ -470,3 +456,19 @@ class TokenizedBuffer extends Model line = @tokenizedLineForRow(row).text console.log row, line, line.length return + +if Grim.includeDeprecations + EmitterMixin = require('emissary').Emitter + + TokenizedBuffer::on = (eventName) -> + switch eventName + when 'changed' + Grim.deprecate("Use TokenizedBuffer::onDidChange instead") + when 'grammar-changed' + Grim.deprecate("Use TokenizedBuffer::onDidChangeGrammar instead") + when 'tokenized' + Grim.deprecate("Use TokenizedBuffer::onDidTokenize instead") + else + Grim.deprecate("TokenizedBuffer::on is deprecated. Use event subscription methods instead.") + + EmitterMixin::on.apply(this, arguments) From 8375526ca658aa76e58f522c5cd91fac0b062760 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 13:23:08 -0700 Subject: [PATCH 0423/1783] Use CompositeDisposable instead of Subscriber mixin --- src/marker.coffee | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/marker.coffee b/src/marker.coffee index 798dcc12d..bd48eb48c 100644 --- a/src/marker.coffee +++ b/src/marker.coffee @@ -1,6 +1,6 @@ {Range} = require 'text-buffer' _ = require 'underscore-plus' -{Emitter} = require 'event-kit' +{CompositeDisposable, Emitter} = require 'event-kit' Grim = require 'grim' # Essential: Represents a buffer annotation that remains logically stationary @@ -57,6 +57,7 @@ class Marker constructor: ({@bufferMarker, @displayBuffer}) -> @emitter = new Emitter + @disposables = new CompositeDisposable @id = @bufferMarker.id @oldHeadBufferPosition = @getHeadBufferPosition() @oldHeadScreenPosition = @getHeadScreenPosition() @@ -64,14 +65,14 @@ class Marker @oldTailScreenPosition = @getTailScreenPosition() @wasValid = @isValid() - @subscribe @bufferMarker.onDidDestroy => @destroyed() - @subscribe @bufferMarker.onDidChange (event) => @notifyObservers(event) + @disposables.add @bufferMarker.onDidDestroy => @destroyed() + @disposables.add @bufferMarker.onDidChange (event) => @notifyObservers(event) # Essential: Destroys the marker, causing it to emit the 'destroyed' event. Once # destroyed, a marker cannot be restored by undo/redo operations. destroy: -> @bufferMarker.destroy() - @unsubscribe() + @disposables.dispose() # Essential: Creates and returns a new {Marker} with the same properties as this # marker. @@ -375,10 +376,8 @@ class Marker @displayBuffer.pixelRangeForScreenRange(@getScreenRange(), false) if Grim.includeDeprecations - {Subscriber} = require 'emissary' EmitterMixin = require('emissary').Emitter EmitterMixin.includeInto(Marker) - Subscriber.includeInto(Marker) Marker::on = (eventName) -> switch eventName From f7c4fa4bccdc5ae1f9d67de5d31f240591b14243 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 13:24:28 -0700 Subject: [PATCH 0424/1783] Only do legacy emits when deprecations are included --- src/git-repository.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/git-repository.coffee b/src/git-repository.coffee index a14869655..0ae4abf3a 100644 --- a/src/git-repository.coffee +++ b/src/git-repository.coffee @@ -313,7 +313,7 @@ class GitRepository else delete @statuses[relativePath] if currentPathStatus isnt pathStatus - @emit 'status-changed', path, pathStatus + @emit 'status-changed', path, pathStatus if includeDeprecations @emitter.emit 'did-change-status', {path, pathStatus} pathStatus @@ -474,7 +474,7 @@ class GitRepository submoduleRepo.upstream = submodules[submodulePath]?.upstream ? {ahead: 0, behind: 0} unless statusesUnchanged - @emit 'statuses-changed' + @emit 'statuses-changed' if includeDeprecations @emitter.emit 'did-change-statuses' if includeDeprecations From 6a6036db580722b24faf437ff7b785035121f801 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 13:25:51 -0700 Subject: [PATCH 0425/1783] Add command for open dev and api preview modes --- src/browser/atom-application.coffee | 1 + src/workspace-element.coffee | 1 + 2 files changed, 2 insertions(+) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index fb9085416..ec4fe650a 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -159,6 +159,7 @@ class AtomApplication @on 'application:open-dev', -> @promptForPathToOpen('all', devMode: true) @on 'application:open-safe', -> @promptForPathToOpen('all', safeMode: true) @on 'application:open-api-preview', -> @promptForPathToOpen('all', apiPreviewMode: true) + @on 'application:open-dev-api-preview', -> @promptForPathToOpen('all', {apiPreviewMode: true, devMode: true}) @on 'application:inspect', ({x,y, atomWindow}) -> atomWindow ?= @focusedWindow() atomWindow?.browserWindow.inspectElement(x, y) diff --git a/src/workspace-element.coffee b/src/workspace-element.coffee index 5afe2cf0e..f2805ff08 100644 --- a/src/workspace-element.coffee +++ b/src/workspace-element.coffee @@ -137,6 +137,7 @@ atom.commands.add 'atom-workspace', 'application:open-dev': -> ipc.send('command', 'application:open-dev') 'application:open-safe': -> ipc.send('command', 'application:open-safe') 'application:open-api-preview': -> ipc.send('command', 'application:open-api-preview') + 'application:open-dev-api-preview': -> ipc.send('command', 'application:open-dev-api-preview') 'application:minimize': -> ipc.send('command', 'application:minimize') 'application:zoom': -> ipc.send('command', 'application:zoom') 'application:bring-all-windows-to-front': -> ipc.send('command', 'application:bring-all-windows-to-front') From 914c1b55e51d8b411b86a06a85d15b953eecb520 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 13:28:56 -0700 Subject: [PATCH 0426/1783] Pass through apiPreviewMode flag --- src/browser/atom-application.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index ec4fe650a..45c0c8b5c 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -503,9 +503,9 @@ class AtomApplication # :safeMode - A Boolean which controls whether any newly opened windows # should be in safe mode or not. # :window - An {AtomWindow} to use for opening a selected file path. - promptForPathToOpen: (type, {devMode, safeMode, window}) -> + promptForPathToOpen: (type, {devMode, safeMode, apiPreviewMode, window}) -> @promptForPath type, (pathsToOpen) => - @openPaths({pathsToOpen, devMode, safeMode, window}) + @openPaths({pathsToOpen, devMode, safeMode, apiPreviewMode, window}) promptForPath: (type, callback) -> properties = From f34b6c9e95f8d778dc7b2f1258293ff8831da200 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 14:25:37 -0700 Subject: [PATCH 0427/1783] Conditionally include deprecations in GrammarRegistry --- src/grammar-registry.coffee | 42 ++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/src/grammar-registry.coffee b/src/grammar-registry.coffee index 911ffafbe..b95b561da 100644 --- a/src/grammar-registry.coffee +++ b/src/grammar-registry.coffee @@ -1,14 +1,6 @@ -_ = require 'underscore-plus' -{deprecate} = require 'grim' -{specificity} = require 'clear-cut' -{Subscriber} = require 'emissary' {Emitter} = require 'event-kit' +{includeDeprecations, deprecate} = require 'grim' FirstMate = require 'first-mate' -{ScopeSelector} = FirstMate -ScopedPropertyStore = require 'scoped-property-store' -PropertyAccessors = require 'property-accessors' - -{$, $$} = require './space-pen-extensions' Token = require './token' # Extended: Syntax class holding the grammars used for tokenizing. @@ -19,16 +11,12 @@ Token = require './token' # language-specific comment regexes. See {::getProperty} for more details. module.exports = class GrammarRegistry extends FirstMate.GrammarRegistry - PropertyAccessors.includeInto(this) - Subscriber.includeInto(this) - @deserialize: ({grammarOverridesByPath}) -> grammarRegistry = new GrammarRegistry() grammarRegistry.grammarOverridesByPath = grammarOverridesByPath grammarRegistry atom.deserializers.add(this) - atom.deserializers.add(name: 'Syntax', deserialize: @deserialize) # Support old serialization constructor: -> super(maxTokensPerLine: 100) @@ -49,28 +37,38 @@ class GrammarRegistry extends FirstMate.GrammarRegistry # Returns a {Grammar}, never null. selectGrammar: (filePath, fileContents) -> super + clearObservers: -> + @off() if includeDeprecations + @emitter = new Emitter + +if includeDeprecations + PropertyAccessors = require 'property-accessors' + PropertyAccessors.includeInto(GrammarRegistry) + + {Subscriber} = require 'emissary' + Subscriber.includeInto(GrammarRegistry) + + # Support old serialization + atom.deserializers.add(name: 'Syntax', deserialize: GrammarRegistry.deserialize) + # Deprecated: Used by settings-view to display snippets for packages - @::accessor 'propertyStore', -> + GrammarRegistry::accessor 'propertyStore', -> deprecate("Do not use this. Use a public method on Config") atom.config.scopedSettingsStore - addProperties: (args...) -> + GrammarRegistry::addProperties = (args...) -> args.unshift(null) if args.length == 2 deprecate 'Consider using atom.config.set() instead. A direct (but private) replacement is available at atom.config.addScopedSettings().' atom.config.addScopedSettings(args...) - removeProperties: (name) -> + GrammarRegistry::removeProperties = (name) -> deprecate 'atom.config.addScopedSettings() now returns a disposable you can call .dispose() on' atom.config.scopedSettingsStore.removeProperties(name) - getProperty: (scope, keyPath) -> + GrammarRegistry::getProperty = (scope, keyPath) -> deprecate 'A direct (but private) replacement is available at atom.config.getRawScopedValue().' atom.config.getRawScopedValue(scope, keyPath) - propertiesForScope: (scope, keyPath) -> + GrammarRegistry::propertiesForScope = (scope, keyPath) -> deprecate 'Use atom.config.getAll instead.' atom.config.settingsForScopeDescriptor(scope, keyPath) - - clearObservers: -> - @off() - @emitter = new Emitter From b9570be338eda576cede3b1d1987b3d5b58e74c3 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 14:36:12 -0700 Subject: [PATCH 0428/1783] Conditionally include deprecations in PackageManager --- src/package-manager.coffee | 48 ++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 444497c5b..7399eaab1 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -1,7 +1,6 @@ path = require 'path' _ = require 'underscore-plus' -EmitterMixin = require('emissary').Emitter {Emitter} = require 'event-kit' fs = require 'fs-plus' Q = require 'q' @@ -28,8 +27,6 @@ ThemePackage = require './theme-package' # settings and also by calling `enablePackage()/disablePackage()`. module.exports = class PackageManager - EmitterMixin.includeInto(this) - constructor: ({configDirPath, @devMode, safeMode, @resourcePath}) -> @emitter = new Emitter @packageDirPaths = [] @@ -57,11 +54,6 @@ class PackageManager # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. onDidLoadInitialPackages: (callback) -> @emitter.on 'did-load-initial-packages', callback - @emitter.on 'did-load-all', callback # TODO: Remove once deprecated pre-1.0 APIs are gone - - onDidLoadAll: (callback) -> - Grim.deprecate("Use `::onDidLoadInitialPackages` instead.") - @onDidLoadInitialPackages(callback) # Public: Invoke the given callback when all packages have been activated. # @@ -70,11 +62,6 @@ class PackageManager # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. onDidActivateInitialPackages: (callback) -> @emitter.on 'did-activate-initial-packages', callback - @emitter.on 'did-activate-all', callback # TODO: Remove once deprecated pre-1.0 APIs are gone - - onDidActivateAll: (callback) -> - Grim.deprecate("Use `::onDidActivateInitialPackages` instead.") - @onDidActivateInitialPackages(callback) # Public: Invoke the given callback when a package is activated. # @@ -112,16 +99,6 @@ class PackageManager onDidUnloadPackage: (callback) -> @emitter.on 'did-unload-package', callback - on: (eventName) -> - switch eventName - when 'loaded' - Grim.deprecate 'Use PackageManager::onDidLoadInitialPackages instead' - when 'activated' - Grim.deprecate 'Use PackageManager::onDidActivateInitialPackages instead' - else - Grim.deprecate 'PackageManager::on is deprecated. Use event subscription methods instead.' - EmitterMixin::on.apply(this, arguments) - ### Section: Package system data ### @@ -331,7 +308,7 @@ class PackageManager packagePaths = packagePaths.filter (packagePath) => not @isPackageDisabled(path.basename(packagePath)) packagePaths = _.uniq packagePaths, (packagePath) -> path.basename(packagePath) @loadPackage(packagePath) for packagePath in packagePaths - @emit 'loaded' + @emit 'loaded' if Grim.includeDeprecations @emitter.emit 'did-load-initial-packages' loadPackage: (nameOrPath) -> @@ -380,7 +357,7 @@ class PackageManager packages = @getLoadedPackagesForTypes(types) promises = promises.concat(activator.activatePackages(packages)) Q.all(promises).then => - @emit 'activated' + @emit 'activated' if Grim.includeDeprecations @emitter.emit 'did-activate-initial-packages' # another type of package manager can handle other package types. @@ -432,3 +409,24 @@ class PackageManager stack = "#{error.stack}\n at #{metadataPath}:1:1" message = "Failed to load the #{path.basename(packagePath)} package" atom.notifications.addError(message, {stack, detail, dismissable: true}) + +if Grim.includeDeprecations + PackageManager::onDidLoadAll = (callback) -> + Grim.deprecate("Use `::onDidLoadInitialPackages` instead.") + @onDidLoadInitialPackages(callback) + + PackageManager::onDidActivateAll = (callback) -> + Grim.deprecate("Use `::onDidActivateInitialPackages` instead.") + @onDidActivateInitialPackages(callback) + + EmitterMixin = require('emissary').Emitter + EmitterMixin.includeInto(PackageManager) + PackageManager::on = (eventName) -> + switch eventName + when 'loaded' + Grim.deprecate 'Use PackageManager::onDidLoadInitialPackages instead' + when 'activated' + Grim.deprecate 'Use PackageManager::onDidActivateInitialPackages instead' + else + Grim.deprecate 'PackageManager::on is deprecated. Use event subscription methods instead.' + EmitterMixin::on.apply(this, arguments) From 484e78f09605c161c5f756fe66c460afcf0dec50 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 14:39:26 -0700 Subject: [PATCH 0429/1783] Conditionally include deprecations in Package --- src/package.coffee | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/package.coffee b/src/package.coffee index ebc771123..7b590aab4 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -4,10 +4,9 @@ _ = require 'underscore-plus' async = require 'async' CSON = require 'season' fs = require 'fs-plus' -EmitterMixin = require('emissary').Emitter {Emitter, CompositeDisposable} = require 'event-kit' Q = require 'q' -{deprecate} = require 'grim' +{includeDeprecations, deprecate} = require 'grim' ModuleCache = require './module-cache' ScopedProperties = require './scoped-properties' @@ -21,8 +20,6 @@ catch error # stylesheets, keymaps, grammar, editor properties, and menus. module.exports = class Package - EmitterMixin.includeInto(this) - @isBundledPackagePath: (packagePath) -> if atom.packages.devMode return false unless atom.packages.resourcePath.startsWith("#{process.resourcesPath}#{path.sep}") @@ -43,11 +40,11 @@ class Package metadata ?= {} metadata.name = packageName - if metadata.stylesheetMain? + if includeDeprecations and metadata.stylesheetMain? deprecate("Use the `mainStyleSheet` key instead of `stylesheetMain` in the `package.json` of `#{packageName}`", {packageName}) metadata.mainStyleSheet = metadata.stylesheetMain - if metadata.stylesheets? + if includeDeprecations and metadata.stylesheets? deprecate("Use the `styleSheets` key instead of `stylesheets` in the `package.json` of `#{packageName}`", {packageName}) metadata.styleSheets = metadata.stylesheets @@ -87,14 +84,6 @@ class Package onDidDeactivate: (callback) -> @emitter.on 'did-deactivate', callback - on: (eventName) -> - switch eventName - when 'deactivated' - deprecate 'Use Package::onDidDeactivate instead' - else - deprecate 'Package::on is deprecated. Use event subscription methods instead.' - EmitterMixin::on.apply(this, arguments) - ### Section: Instance Methods ### @@ -174,7 +163,7 @@ class Package if @mainModule? if @mainModule.config? and typeof @mainModule.config is 'object' atom.config.setSchema @name, {type: 'object', properties: @mainModule.config} - else if @mainModule.configDefaults? and typeof @mainModule.configDefaults is 'object' + else if includeDeprecations and @mainModule.configDefaults? and typeof @mainModule.configDefaults is 'object' deprecate """Use a config schema instead. See the configuration section of https://atom.io/docs/latest/hacking-atom-package-word-count and https://atom.io/docs/api/latest/Config for more details""" @@ -268,7 +257,7 @@ class Package [stylesheetPath, atom.themes.loadStylesheet(stylesheetPath, true)] getStylesheetsPath: -> - if fs.isDirectorySync(path.join(@path, 'stylesheets')) + if includeDeprecations and fs.isDirectorySync(path.join(@path, 'stylesheets')) deprecate("Store package style sheets in the `styles/` directory instead of `stylesheets/` in the `#{@name}` package", packageName: @name) path.join(@path, 'stylesheets') else @@ -339,7 +328,7 @@ class Package deferred = Q.defer() - if fs.isDirectorySync(path.join(@path, 'scoped-properties')) + if includeDeprecations and fs.isDirectorySync(path.join(@path, 'scoped-properties')) settingsDirPath = path.join(@path, 'scoped-properties') deprecate("Store package settings files in the `settings/` directory instead of `scoped-properties/`", packageName: @name) else @@ -467,7 +456,7 @@ class Package else if _.isArray(commands) @activationCommands[selector].push(commands...) - if @metadata.activationEvents? + if includeDeprecations and @metadata.activationEvents? deprecate """ Use `activationCommands` instead of `activationEvents` in your package.json Commands should be grouped by selector as follows: @@ -585,3 +574,15 @@ class Package stack = error.stack ? error atom.notifications.addFatalError(message, {stack, detail, dismissable: true}) + +if includeDeprecations + EmitterMixin = require('emissary').Emitter + EmitterMixin.includeInto(Package) + + Package::on = (eventName) -> + switch eventName + when 'deactivated' + deprecate 'Use Package::onDidDeactivate instead' + else + deprecate 'Package::on is deprecated. Use event subscription methods instead.' + EmitterMixin::on.apply(this, arguments) From 193ab71aca7ad131e00ba6d47640c48140502315 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 14:43:15 -0700 Subject: [PATCH 0430/1783] Call dispose instead of unsubscribe on marker --- src/display-buffer.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index aef36fc99..27e2ae936 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -1084,7 +1084,7 @@ class DisplayBuffer extends Model return destroyed: -> - marker.unsubscribe() for id, marker of @markers + marker.disposables.dispose() for id, marker of @markers @scopedConfigSubscriptions.dispose() @unsubscribe() @tokenizedBuffer.destroy() From 7a52ef7d0a0a5f5fa9f17e8f2329654398fdc899 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 14:50:55 -0700 Subject: [PATCH 0431/1783] Use disposables in Atom --- src/atom.coffee | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/atom.coffee b/src/atom.coffee index 49a76481b..ace3245ef 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -7,7 +7,7 @@ shell = require 'shell' _ = require 'underscore-plus' {deprecate, includeDeprecations} = require 'grim' -{Emitter} = require 'event-kit' +{CompositeDisposable, Emitter} = require 'event-kit' {Model} = require 'theorist' fs = require 'fs-plus' {convertStackTrace, convertLine} = require 'coffeestack' @@ -198,6 +198,7 @@ class Atom extends Model # Call .loadOrCreate instead constructor: (@state) -> @emitter = new Emitter + @disposables = new CompositeDisposable {@mode} = @state DeserializerManager = require './deserializer-manager' @deserializers = new DeserializerManager() @@ -232,7 +233,9 @@ class Atom extends Model @emit 'uncaught-error', arguments... @emitter.emit 'did-throw-error', {message, url, line, column, originalError} - @unsubscribe() + @disposables?.dispose() + @disposables = new CompositeDisposable + @setBodyPlatformClass() @loadTime = null @@ -288,7 +291,7 @@ class Atom extends Model deprecate "The atom.syntax global is deprecated. Use atom.grammars instead." @grammars - @subscribe @packages.onDidActivateInitialPackages => @watchThemes() + @disposables.add @packages.onDidActivateInitialPackages => @watchThemes() Project = require './project' TextBuffer = require 'text-buffer' @@ -605,7 +608,7 @@ class Atom extends Model @requireUserInitScript() unless safeMode @menu.update() - @subscribe @config.onDidChange 'core.autoHideMenuBar', ({newValue}) => + @disposables.add @config.onDidChange 'core.autoHideMenuBar', ({newValue}) => @setAutoHideMenuBar(newValue) @setAutoHideMenuBar(true) if @config.get('core.autoHideMenuBar') @@ -755,7 +758,7 @@ class Atom extends Model # Notify the browser project of the window's current project path watchProjectPath: -> - @subscribe @project.onDidChangePaths => + @disposables.add @project.onDidChangePaths => @constructor.updateLoadSetting('initialPaths', @project.getPaths()) exit: (status) -> From 8eded9f9bdf5c3ae753cb3e62fc97e1943c781eb Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 14:52:12 -0700 Subject: [PATCH 0432/1783] Use disposables in DisplayBuffer --- src/display-buffer.coffee | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index 27e2ae936..277a79200 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -42,6 +42,7 @@ class DisplayBuffer extends Model super @emitter = new Emitter + @disposables = new CompositeDisposable @tokenizedBuffer ?= new TokenizedBuffer({tabLength, buffer, @invisibles}) @buffer = @tokenizedBuffer.buffer @@ -50,10 +51,10 @@ class DisplayBuffer extends Model @foldsByMarkerId = {} @decorationsById = {} @decorationsByMarkerId = {} - @subscribe @tokenizedBuffer.observeGrammar @subscribeToScopedConfigSettings - @subscribe @tokenizedBuffer.onDidChange @handleTokenizedBufferChange - @subscribe @buffer.onDidUpdateMarkers @handleBufferMarkersUpdated - @subscribe @buffer.onDidCreateMarker @handleBufferMarkerCreated + @disposables.add @tokenizedBuffer.observeGrammar @subscribeToScopedConfigSettings + @disposables.add @tokenizedBuffer.onDidChange @handleTokenizedBufferChange + @disposables.add @buffer.onDidUpdateMarkers @handleBufferMarkersUpdated + @disposables.add @buffer.onDidCreateMarker @handleBufferMarkerCreated @updateAllScreenLines() @createFoldForMarker(marker) for marker in @buffer.findMarkers(@getFoldMarkerAttributes()) @@ -907,7 +908,7 @@ class DisplayBuffer extends Model decorateMarker: (marker, decorationParams) -> marker = @getMarker(marker.id) decoration = new Decoration(marker, this, decorationParams) - @subscribe decoration.onDidDestroy => @removeDecoration(decoration) + @disposables.add decoration.onDidDestroy => @removeDecoration(decoration) @decorationsByMarkerId[marker.id] ?= [] @decorationsByMarkerId[marker.id].push(decoration) @decorationsById[decoration.id] = decoration @@ -1086,7 +1087,7 @@ class DisplayBuffer extends Model destroyed: -> marker.disposables.dispose() for id, marker of @markers @scopedConfigSubscriptions.dispose() - @unsubscribe() + @disposables.dispose() @tokenizedBuffer.destroy() logLines: (start=0, end=@getLastRow()) -> From 382974412fa4151a5e7ea9e900d1363cd4884a21 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 15:01:53 -0700 Subject: [PATCH 0433/1783] Conditionally include deprecations in Workspace --- src/workspace.coffee | 143 ++++++++++++++++++++++--------------------- 1 file changed, 73 insertions(+), 70 deletions(-) diff --git a/src/workspace.coffee b/src/workspace.coffee index 4afce1f37..a5a4e5e30 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -1,4 +1,4 @@ -{deprecate} = require 'grim' +{includeDeprecations, deprecate} = require 'grim' _ = require 'underscore-plus' path = require 'path' {join} = path @@ -33,16 +33,6 @@ class Workspace extends Model atom.deserializers.add(this) Serializable.includeInto(this) - Object.defineProperty @::, 'activePaneItem', - get: -> - Grim.deprecate "Use ::getActivePaneItem() instead of the ::activePaneItem property" - @getActivePaneItem() - - Object.defineProperty @::, 'activePane', - get: -> - Grim.deprecate "Use ::getActivePane() instead of the ::activePane property" - @getActivePane() - @properties paneContainer: null fullScreen: false @@ -342,32 +332,6 @@ class Workspace extends Model @onDidAddPaneItem ({item, pane, index}) -> callback({textEditor: item, pane, index}) if item instanceof TextEditor - eachEditor: (callback) -> - deprecate("Use Workspace::observeTextEditors instead") - - callback(editor) for editor in @getEditors() - @subscribe this, 'editor-created', (editor) -> callback(editor) - - getEditors: -> - deprecate("Use Workspace::getTextEditors instead") - - editors = [] - for pane in @paneContainer.getPanes() - editors.push(item) for item in pane.getItems() when item instanceof TextEditor - - editors - - on: (eventName) -> - switch eventName - when 'editor-created' - deprecate("Use Workspace::onDidAddTextEditor or Workspace::observeTextEditors instead.") - when 'uri-opened' - deprecate("Use Workspace::onDidOpen or Workspace::onDidAddPaneItem instead. https://atom.io/docs/api/latest/Workspace#instance-onDidOpen") - else - deprecate("Subscribing via ::on is deprecated. Use documented event subscription methods instead.") - - super - ### Section: Opening ### @@ -425,7 +389,7 @@ class Workspace extends Model # the containing pane. Defaults to `true`. openSync: (uri='', options={}) -> # TODO: Remove deprecated changeFocus option - if options.changeFocus? + if includeDeprecations and options.changeFocus? deprecate("The `changeFocus` option has been renamed to `activatePane`") options.activatePane = options.changeFocus delete options.changeFocus @@ -446,7 +410,7 @@ class Workspace extends Model openURIInPane: (uri, pane, options={}) -> # TODO: Remove deprecated changeFocus option - if options.changeFocus? + if includeDeprecations and options.changeFocus? deprecate("The `changeFocus` option has been renamed to `activatePane`") options.activatePane = options.changeFocus delete options.changeFocus @@ -496,12 +460,6 @@ class Workspace extends Model else Q() - # Deprecated - reopenItemSync: -> - deprecate("Use Workspace::reopenItem instead") - if uri = @destroyedItemURIs.pop() - @openSync(uri) - # Public: Register an opener for a uri. # # An {TextEditor} will be used if no openers return a value. @@ -519,24 +477,20 @@ class Workspace extends Model # Returns a {Disposable} on which `.dispose()` can be called to remove the # opener. addOpener: (opener) -> - packageName = @getCallingPackageName() + if includeDeprecations + packageName = @getCallingPackageName() - wrappedOpener = (uri, options) -> - item = opener(uri, options) - if item? and typeof item.getUri is 'function' and typeof item.getURI isnt 'function' - Grim.deprecate("Pane item with class `#{item.constructor.name}` should implement `::getURI` instead of `::getUri`.", {packageName}) - item + wrappedOpener = (uri, options) -> + item = opener(uri, options) + if item? and typeof item.getUri is 'function' and typeof item.getURI isnt 'function' + Grim.deprecate("Pane item with class `#{item.constructor.name}` should implement `::getURI` instead of `::getUri`.", {packageName}) + item - @openers.push(wrappedOpener) - new Disposable => _.remove(@openers, wrappedOpener) - - registerOpener: (opener) -> - Grim.deprecate("Call Workspace::addOpener instead") - @addOpener(opener) - - unregisterOpener: (opener) -> - Grim.deprecate("Call .dispose() on the Disposable returned from ::addOpener instead") - _.remove(@openers, opener) + @openers.push(wrappedOpener) + new Disposable => _.remove(@openers, wrappedOpener) + else + @openers.push(opener) + new Disposable => _.remove(@openers, opener) getOpeners: -> @openers @@ -599,11 +553,6 @@ class Workspace extends Model activeItem = @getActivePaneItem() activeItem if activeItem instanceof TextEditor - # Deprecated - getActiveEditor: -> - Grim.deprecate "Call ::getActiveTextEditor instead" - @getActivePane()?.getActiveEditor() - # Save all pane items. saveAll: -> @paneContainer.saveAll() @@ -667,10 +616,6 @@ class Workspace extends Model paneForURI: (uri) -> @paneContainer.paneForURI(uri) - paneForUri: (uri) -> - deprecate("Use ::paneForURI instead.") - @paneForURI(uri) - # Extended: Get the {Pane} containing the given item. # # * `item` Item the returned pane contains. @@ -945,3 +890,61 @@ class Workspace extends Model checkFinished() deferred.promise + +if includeDeprecations + Object.defineProperty Workspace::, 'activePaneItem', + get: -> + Grim.deprecate "Use ::getActivePaneItem() instead of the ::activePaneItem property" + @getActivePaneItem() + + Object.defineProperty Workspace::, 'activePane', + get: -> + Grim.deprecate "Use ::getActivePane() instead of the ::activePane property" + @getActivePane() + + Workspace::eachEditor = (callback) -> + deprecate("Use Workspace::observeTextEditors instead") + + callback(editor) for editor in @getEditors() + @subscribe this, 'editor-created', (editor) -> callback(editor) + + Workspace::getEditors = -> + deprecate("Use Workspace::getTextEditors instead") + + editors = [] + for pane in @paneContainer.getPanes() + editors.push(item) for item in pane.getItems() when item instanceof TextEditor + + editors + + Workspace::on = (eventName) -> + switch eventName + when 'editor-created' + deprecate("Use Workspace::onDidAddTextEditor or Workspace::observeTextEditors instead.") + when 'uri-opened' + deprecate("Use Workspace::onDidOpen or Workspace::onDidAddPaneItem instead. https://atom.io/docs/api/latest/Workspace#instance-onDidOpen") + else + deprecate("Subscribing via ::on is deprecated. Use documented event subscription methods instead.") + + super + + Workspace::reopenItemSync = -> + deprecate("Use Workspace::reopenItem instead") + if uri = @destroyedItemURIs.pop() + @openSync(uri) + + Workspace::registerOpener = (opener) -> + Grim.deprecate("Call Workspace::addOpener instead") + @addOpener(opener) + + Workspace::unregisterOpener = (opener) -> + Grim.deprecate("Call .dispose() on the Disposable returned from ::addOpener instead") + _.remove(@openers, opener) + + Workspace::getActiveEditor = -> + Grim.deprecate "Call ::getActiveTextEditor instead" + @getActivePane()?.getActiveEditor() + + Workspace::paneForUri = (uri) -> + deprecate("Use ::paneForURI instead.") + @paneForURI(uri) From 8e56a252e014121a147e6386635547d8a99f4447 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 15:02:56 -0700 Subject: [PATCH 0434/1783] Only call emit when deprecations are included --- src/decoration.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/decoration.coffee b/src/decoration.coffee index 92316042c..b3ad4b7ff 100644 --- a/src/decoration.coffee +++ b/src/decoration.coffee @@ -66,7 +66,7 @@ class Decoration @markerDestroyDisposable.dispose() @markerDestroyDisposable = null @destroyed = true - @emit 'destroyed' + @emit 'destroyed' if Grim.includeDeprecations @emitter.emit 'did-destroy' @emitter.dispose() @@ -137,7 +137,7 @@ class Decoration oldProperties = @properties @properties = newProperties @properties.id = @id - @emit 'updated', {oldParams: oldProperties, newParams: newProperties} + @emit 'updated', {oldParams: oldProperties, newParams: newProperties} if Grim.includeDeprecations @emitter.emit 'did-change-properties', {oldProperties, newProperties} ### @@ -157,7 +157,7 @@ class Decoration flashObject = {class: klass, duration} @flashQueue ?= [] @flashQueue.push(flashObject) - @emit 'flash' + @emit 'flash' if Grim.includeDeprecations @emitter.emit 'did-flash' consumeNextFlash: -> From b0b9172154d523f9a1e04af62f65138a27401f4d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 15:24:40 -0700 Subject: [PATCH 0435/1783] Conditionally include deprecations in TextEditor --- src/text-editor.coffee | 437 +++++++++++++++++++++-------------------- 1 file changed, 226 insertions(+), 211 deletions(-) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 548725cf6..1821a8a52 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -2,7 +2,7 @@ _ = require 'underscore-plus' path = require 'path' Serializable = require 'serializable' Delegator = require 'delegato' -{deprecate} = require 'grim' +{includeDeprecations, deprecate} = require 'grim' {Model} = require 'theorist' EmitterMixin = require('emissary').Emitter {CompositeDisposable, Emitter} = require 'event-kit' @@ -174,9 +174,6 @@ class TextEditor extends Model subscriptions.add atom.config.onDidChange 'editor.showInvisibles', scope: scopeDescriptor, => @updateInvisibles() subscriptions.add atom.config.onDidChange 'editor.invisibles', scope: scopeDescriptor, => @updateInvisibles() - getViewClass: -> - require './text-editor-view' - destroyed: -> @unsubscribe() @scopedConfigSubscriptions.dispose() @@ -461,76 +458,12 @@ class TextEditor extends Model onDidChangeIcon: (callback) -> @emitter.on 'did-change-icon', callback - on: (eventName) -> - switch eventName - when 'title-changed' - deprecate("Use TextEditor::onDidChangeTitle instead") - when 'path-changed' - deprecate("Use TextEditor::onDidChangePath instead") - when 'modified-status-changed' - deprecate("Use TextEditor::onDidChangeModified instead") - when 'soft-wrap-changed' - deprecate("Use TextEditor::onDidChangeSoftWrapped instead") - when 'grammar-changed' - deprecate("Use TextEditor::onDidChangeGrammar instead") - when 'character-widths-changed' - deprecate("Use TextEditor::onDidChangeCharacterWidths instead") - when 'contents-modified' - deprecate("Use TextEditor::onDidStopChanging instead") - when 'contents-conflicted' - deprecate("Use TextEditor::onDidConflict instead") - - when 'will-insert-text' - deprecate("Use TextEditor::onWillInsertText instead") - when 'did-insert-text' - deprecate("Use TextEditor::onDidInsertText instead") - - when 'cursor-added' - deprecate("Use TextEditor::onDidAddCursor instead") - when 'cursor-removed' - deprecate("Use TextEditor::onDidRemoveCursor instead") - when 'cursor-moved' - deprecate("Use TextEditor::onDidChangeCursorPosition instead") - - when 'selection-added' - deprecate("Use TextEditor::onDidAddSelection instead") - when 'selection-removed' - deprecate("Use TextEditor::onDidRemoveSelection instead") - when 'selection-screen-range-changed' - deprecate("Use TextEditor::onDidChangeSelectionRange instead") - - when 'decoration-added' - deprecate("Use TextEditor::onDidAddDecoration instead") - when 'decoration-removed' - deprecate("Use TextEditor::onDidRemoveDecoration instead") - when 'decoration-updated' - deprecate("Use Decoration::onDidChangeProperties instead. You will get the decoration back from `TextEditor::decorateMarker()`") - when 'decoration-changed' - deprecate("Use Marker::onDidChange instead. e.g. `editor::decorateMarker(...).getMarker().onDidChange()`") - - when 'screen-lines-changed' - deprecate("Use TextEditor::onDidChange instead") - - when 'scroll-top-changed' - deprecate("Use TextEditor::onDidChangeScrollTop instead") - when 'scroll-left-changed' - deprecate("Use TextEditor::onDidChangeScrollLeft instead") - - else - deprecate("TextEditor::on is deprecated. Use documented event subscription methods instead.") - - EmitterMixin::on.apply(this, arguments) - # Retrieves the current {TextBuffer}. getBuffer: -> @buffer # Retrieves the current buffer's URI. getURI: -> @buffer.getUri() - getUri: -> - deprecate("Use `::getURI` instead") - @getURI() - # Create an {TextEditor} with its initial state based on this object copy: -> displayBuffer = @displayBuffer.copy() @@ -698,9 +631,6 @@ class TextEditor extends Model # # * `bufferRow` A {Number} representing a zero-indexed buffer row. lineTextForBufferRow: (bufferRow) -> @buffer.lineForRow(bufferRow) - lineForBufferRow: (bufferRow) -> - deprecate 'Use TextEditor::lineTextForBufferRow(bufferRow) instead' - @lineTextForBufferRow(bufferRow) # Essential: Returns a {String} representing the contents of the line at the # given screen row. @@ -714,23 +644,9 @@ class TextEditor extends Model # # Returns {TokenizedLine} tokenizedLineForScreenRow: (screenRow) -> @displayBuffer.tokenizedLineForScreenRow(screenRow) - lineForScreenRow: (screenRow) -> - deprecate "TextEditor::tokenizedLineForScreenRow(bufferRow) is the new name. But it's private. Try to use TextEditor::lineTextForScreenRow instead" - @tokenizedLineForScreenRow(screenRow) # {Delegates to: DisplayBuffer.tokenizedLinesForScreenRows} tokenizedLinesForScreenRows: (start, end) -> @displayBuffer.tokenizedLinesForScreenRows(start, end) - linesForScreenRows: (start, end) -> - deprecate "Use TextEditor::tokenizedLinesForScreenRows instead" - @tokenizedLinesForScreenRows(start, end) - - # Returns a {Number} representing the line length for the given - # buffer row, exclusive of its line-ending character(s). - # - # * `row` A {Number} indicating the buffer row. - lineLengthForBufferRow: (row) -> - deprecate "Use editor.lineTextForBufferRow(row).length instead" - @lineTextForBufferRow(row).length bufferRowForScreenRow: (row) -> @displayBuffer.bufferRowForScreenRow(row) @@ -981,11 +897,6 @@ class TextEditor extends Model @createFold(foldStartRow + delta, foldEndRow + delta) return - # Deprecated: Use {::duplicateLines} instead. - duplicateLine: -> - deprecate("Use TextEditor::duplicateLines() instead") - @duplicateLines() - replaceSelectedText: (options={}, fn) -> {selectWordIfEmpty} = options @mutateSelectedText (selection) -> @@ -1116,16 +1027,6 @@ class TextEditor extends Model deleteLine: -> @mutateSelectedText (selection) -> selection.deleteLine() - # Deprecated: Use {::deleteToBeginningOfWord} instead. - backspaceToBeginningOfWord: -> - deprecate("Use TextEditor::deleteToBeginningOfWord() instead") - @deleteToBeginningOfWord() - - # Deprecated: Use {::deleteToBeginningOfLine} instead. - backspaceToBeginningOfLine: -> - deprecate("Use TextEditor::deleteToBeginningOfLine() instead") - @deleteToBeginningOfLine() - ### Section: History ### @@ -1351,7 +1252,7 @@ class TextEditor extends Model # # Returns a {Decoration} object decorateMarker: (marker, decorationParams) -> - if decorationParams.type is 'gutter' + if includeDeprecations and decorationParams.type is 'gutter' deprecate("Decorations of `type: 'gutter'` have been renamed to `type: 'line-number'`.") decorationParams.type = 'line-number' @displayBuffer.decorateMarker(marker, decorationParams) @@ -1387,11 +1288,6 @@ class TextEditor extends Model getLineDecorations: (propertyFilter) -> @displayBuffer.getLineDecorations(propertyFilter) - # Soft-deprecated (forgot to deprecated this pre 1.0) - getGutterDecorations: (propertyFilter) -> - deprecate("Use ::getLineNumberDecorations instead") - @getLineNumberDecorations(propertyFilter) - # Extended: Get all decorations of type 'line-number'. # # * `propertyFilter` (optional) An {Object} containing key value pairs that @@ -1585,13 +1481,6 @@ class TextEditor extends Model getCursorScreenPositions: -> cursor.getScreenPosition() for cursor in @getCursors() - # Get the row of the most recently added cursor in screen coordinates. - # - # Returns the screen row {Number}. - getCursorScreenRow: -> - deprecate('Use `editor.getCursorScreenPosition().row` instead') - @getCursorScreenPosition().row - # Essential: Move the cursor to the given position in screen coordinates. # # If there are multiple cursors, they will be consolidated to a single cursor. @@ -1632,85 +1521,52 @@ class TextEditor extends Model # * `lineCount` (optional) {Number} number of lines to move moveUp: (lineCount) -> @moveCursors (cursor) -> cursor.moveUp(lineCount, moveToEndOfSelection: true) - moveCursorUp: (lineCount) -> - deprecate("Use TextEditor::moveUp() instead") - @moveUp(lineCount) # Essential: Move every cursor down one row in screen coordinates. # # * `lineCount` (optional) {Number} number of lines to move moveDown: (lineCount) -> @moveCursors (cursor) -> cursor.moveDown(lineCount, moveToEndOfSelection: true) - moveCursorDown: (lineCount) -> - deprecate("Use TextEditor::moveDown() instead") - @moveDown(lineCount) # Essential: Move every cursor left one column. # # * `columnCount` (optional) {Number} number of columns to move (default: 1) moveLeft: (columnCount) -> @moveCursors (cursor) -> cursor.moveLeft(columnCount, moveToEndOfSelection: true) - moveCursorLeft: -> - deprecate("Use TextEditor::moveLeft() instead") - @moveLeft() # Essential: Move every cursor right one column. # # * `columnCount` (optional) {Number} number of columns to move (default: 1) moveRight: (columnCount) -> @moveCursors (cursor) -> cursor.moveRight(columnCount, moveToEndOfSelection: true) - moveCursorRight: -> - deprecate("Use TextEditor::moveRight() instead") - @moveRight() # Essential: Move every cursor to the beginning of its line in buffer coordinates. moveToBeginningOfLine: -> @moveCursors (cursor) -> cursor.moveToBeginningOfLine() - moveCursorToBeginningOfLine: -> - deprecate("Use TextEditor::moveToBeginningOfLine() instead") - @moveToBeginningOfLine() # Essential: Move every cursor to the beginning of its line in screen coordinates. moveToBeginningOfScreenLine: -> @moveCursors (cursor) -> cursor.moveToBeginningOfScreenLine() - moveCursorToBeginningOfScreenLine: -> - deprecate("Use TextEditor::moveToBeginningOfScreenLine() instead") - @moveToBeginningOfScreenLine() # Essential: Move every cursor to the first non-whitespace character of its line. moveToFirstCharacterOfLine: -> @moveCursors (cursor) -> cursor.moveToFirstCharacterOfLine() - moveCursorToFirstCharacterOfLine: -> - deprecate("Use TextEditor::moveToFirstCharacterOfLine() instead") - @moveToFirstCharacterOfLine() # Essential: Move every cursor to the end of its line in buffer coordinates. moveToEndOfLine: -> @moveCursors (cursor) -> cursor.moveToEndOfLine() - moveCursorToEndOfLine: -> - deprecate("Use TextEditor::moveToEndOfLine() instead") - @moveToEndOfLine() # Essential: Move every cursor to the end of its line in screen coordinates. moveToEndOfScreenLine: -> @moveCursors (cursor) -> cursor.moveToEndOfScreenLine() - moveCursorToEndOfScreenLine: -> - deprecate("Use TextEditor::moveToEndOfScreenLine() instead") - @moveToEndOfScreenLine() # Essential: Move every cursor to the beginning of its surrounding word. moveToBeginningOfWord: -> @moveCursors (cursor) -> cursor.moveToBeginningOfWord() - moveCursorToBeginningOfWord: -> - deprecate("Use TextEditor::moveToBeginningOfWord() instead") - @moveToBeginningOfWord() # Essential: Move every cursor to the end of its surrounding word. moveToEndOfWord: -> @moveCursors (cursor) -> cursor.moveToEndOfWord() - moveCursorToEndOfWord: -> - deprecate("Use TextEditor::moveToEndOfWord() instead") - @moveToEndOfWord() # Cursor Extended @@ -1719,63 +1575,37 @@ class TextEditor extends Model # If there are multiple cursors, they will be merged into a single cursor. moveToTop: -> @moveCursors (cursor) -> cursor.moveToTop() - moveCursorToTop: -> - deprecate("Use TextEditor::moveToTop() instead") - @moveToTop() # Extended: Move every cursor to the bottom of the buffer. # # If there are multiple cursors, they will be merged into a single cursor. moveToBottom: -> @moveCursors (cursor) -> cursor.moveToBottom() - moveCursorToBottom: -> - deprecate("Use TextEditor::moveToBottom() instead") - @moveToBottom() # Extended: Move every cursor to the beginning of the next word. moveToBeginningOfNextWord: -> @moveCursors (cursor) -> cursor.moveToBeginningOfNextWord() - moveCursorToBeginningOfNextWord: -> - deprecate("Use TextEditor::moveToBeginningOfNextWord() instead") - @moveToBeginningOfNextWord() # Extended: Move every cursor to the previous word boundary. moveToPreviousWordBoundary: -> @moveCursors (cursor) -> cursor.moveToPreviousWordBoundary() - moveCursorToPreviousWordBoundary: -> - deprecate("Use TextEditor::moveToPreviousWordBoundary() instead") - @moveToPreviousWordBoundary() # Extended: Move every cursor to the next word boundary. moveToNextWordBoundary: -> @moveCursors (cursor) -> cursor.moveToNextWordBoundary() - moveCursorToNextWordBoundary: -> - deprecate("Use TextEditor::moveToNextWordBoundary() instead") - @moveToNextWordBoundary() # Extended: Move every cursor to the beginning of the next paragraph. moveToBeginningOfNextParagraph: -> @moveCursors (cursor) -> cursor.moveToBeginningOfNextParagraph() - moveCursorToBeginningOfNextParagraph: -> - deprecate("Use TextEditor::moveToBeginningOfNextParagraph() instead") - @moveToBeginningOfNextParagraph() # Extended: Move every cursor to the beginning of the previous paragraph. moveToBeginningOfPreviousParagraph: -> @moveCursors (cursor) -> cursor.moveToBeginningOfPreviousParagraph() - moveCursorToBeginningOfPreviousParagraph: -> - deprecate("Use TextEditor::moveToBeginningOfPreviousParagraph() instead") - @moveToBeginningOfPreviousParagraph() # Extended: Returns the most recently added {Cursor} getLastCursor: -> _.last(@cursors) - # Deprecated: - getCursor: -> - deprecate("Use TextEditor::getLastCursor() instead") - @getLastCursor() - # Extended: Returns the word surrounding the most recently added cursor. # # * `options` (optional) See {Cursor::getBeginningOfCurrentWordBufferPosition}. @@ -2087,16 +1917,10 @@ class TextEditor extends Model # This method merges selections on successive lines. selectLinesContainingCursors: -> @expandSelectionsForward (selection) -> selection.selectLine() - selectLine: -> - deprecate('Use TextEditor::selectLinesContainingCursors instead') - @selectLinesContainingCursors() # Essential: Select the word surrounding each cursor. selectWordsContainingCursors: -> @expandSelectionsForward (selection) -> selection.selectWord() - selectWord: -> - deprecate('Use TextEditor::selectWordsContainingCursors instead') - @selectWordsContainingCursors() # Selection Extended @@ -2152,15 +1976,6 @@ class TextEditor extends Model getLastSelection: -> _.last(@selections) - # Deprecated: - getSelection: (index) -> - if index? - deprecate("Use TextEditor::getSelections()[index] instead when getting a specific selection") - @getSelections()[index] - else - deprecate("Use TextEditor::getLastSelection() instead") - @getLastSelection() - # Extended: Get current {Selection}s. # # Returns: An {Array} of {Selection}s. @@ -2428,9 +2243,6 @@ class TextEditor extends Model # # Returns a {Boolean}. isSoftWrapped: (softWrapped) -> @displayBuffer.isSoftWrapped() - getSoftWrapped: -> - deprecate("Use TextEditor::isSoftWrapped instead") - @displayBuffer.isSoftWrapped() # Essential: Enable or disable soft wrapping for this editor. # @@ -2438,17 +2250,11 @@ class TextEditor extends Model # # Returns a {Boolean}. setSoftWrapped: (softWrapped) -> @displayBuffer.setSoftWrapped(softWrapped) - setSoftWrap: (softWrapped) -> - deprecate("Use TextEditor::setSoftWrapped instead") - @setSoftWrapped(softWrapped) # Essential: Toggle soft wrapping for this editor # # Returns a {Boolean}. toggleSoftWrapped: -> @setSoftWrapped(not @isSoftWrapped()) - toggleSoftWrap: -> - deprecate("Use TextEditor::toggleSoftWrapped instead") - @toggleSoftWrapped() # Public: Gets the column at which column will soft wrap getSoftWrapColumn: -> @displayBuffer.getSoftWrapColumn() @@ -2573,9 +2379,6 @@ class TextEditor extends Model # Returns a {ScopeDescriptor}. scopeDescriptorForBufferPosition: (bufferPosition) -> @displayBuffer.scopeDescriptorForBufferPosition(bufferPosition) - scopesForBufferPosition: (bufferPosition) -> - deprecate 'Use ::scopeDescriptorForBufferPosition instead. The return value has changed! It now returns a `ScopeDescriptor`' - @scopeDescriptorForBufferPosition(bufferPosition).getScopesArray() # Extended: Get the range in buffer coordinates of all tokens surrounding the # cursor that match the given scope selector. @@ -2607,13 +2410,6 @@ class TextEditor extends Model # {Delegates to: DisplayBuffer.tokenForBufferPosition} tokenForBufferPosition: (bufferPosition) -> @displayBuffer.tokenForBufferPosition(bufferPosition) - scopesAtCursor: -> - deprecate 'Use editor.getLastCursor().getScopeDescriptor() instead' - @getLastCursor().getScopeDescriptor().getScopesArray() - getCursorScopes: -> - deprecate 'Use editor.getLastCursor().getScopeDescriptor() instead' - @scopesAtCursor() - ### Section: Clipboard Operations ### @@ -3030,11 +2826,6 @@ class TextEditor extends Model pixelRectForScreenRange: (screenRange) -> @displayBuffer.pixelRectForScreenRange(screenRange) - # Deprecated: Call {::joinLines} instead. - joinLine: -> - deprecate("Use TextEditor::joinLines() instead") - @joinLines() - ### Section: Utility ### @@ -3043,3 +2834,227 @@ class TextEditor extends Model "" logScreenLines: (start, end) -> @displayBuffer.logLines(start, end) + +if includeDeprecations + TextEditor::getViewClass = -> + require './text-editor-view' + + TextEditor::joinLine = -> + deprecate("Use TextEditor::joinLines() instead") + @joinLines() + + TextEditor::scopesAtCursor = -> + deprecate 'Use editor.getLastCursor().getScopeDescriptor() instead' + @getLastCursor().getScopeDescriptor().getScopesArray() + + TextEditor::getCursorScopes = -> + deprecate 'Use editor.getLastCursor().getScopeDescriptor() instead' + @scopesAtCursor() + + TextEditor::getUri = -> + deprecate("Use `::getURI` instead") + @getURI() + + TextEditor::lineForBufferRow = (bufferRow) -> + deprecate 'Use TextEditor::lineTextForBufferRow(bufferRow) instead' + @lineTextForBufferRow(bufferRow) + + TextEditor::lineForScreenRow = (screenRow) -> + deprecate "TextEditor::tokenizedLineForScreenRow(bufferRow) is the new name. But it's private. Try to use TextEditor::lineTextForScreenRow instead" + @tokenizedLineForScreenRow(screenRow) + + TextEditor::linesForScreenRows = (start, end) -> + deprecate "Use TextEditor::tokenizedLinesForScreenRows instead" + @tokenizedLinesForScreenRows(start, end) + + TextEditor::lineLengthForBufferRow = (row) -> + deprecate "Use editor.lineTextForBufferRow(row).length instead" + @lineTextForBufferRow(row).length + + TextEditor::duplicateLine = -> + deprecate("Use TextEditor::duplicateLines() instead") + @duplicateLines() + + TextEditor::scopesForBufferPosition = (bufferPosition) -> + deprecate 'Use ::scopeDescriptorForBufferPosition instead. The return value has changed! It now returns a `ScopeDescriptor`' + @scopeDescriptorForBufferPosition(bufferPosition).getScopesArray() + + TextEditor::toggleSoftWrap = -> + deprecate("Use TextEditor::toggleSoftWrapped instead") + @toggleSoftWrapped() + + TextEditor::setSoftWrap = (softWrapped) -> + deprecate("Use TextEditor::setSoftWrapped instead") + @setSoftWrapped(softWrapped) + + TextEditor::backspaceToBeginningOfWord = -> + deprecate("Use TextEditor::deleteToBeginningOfWord() instead") + @deleteToBeginningOfWord() + + TextEditor::backspaceToBeginningOfLine = -> + deprecate("Use TextEditor::deleteToBeginningOfLine() instead") + @deleteToBeginningOfLine() + + TextEditor::getGutterDecorations = (propertyFilter) -> + deprecate("Use ::getLineNumberDecorations instead") + @getLineNumberDecorations(propertyFilter) + + TextEditor::getCursorScreenRow = -> + deprecate('Use `editor.getCursorScreenPosition().row` instead') + @getCursorScreenPosition().row + + TextEditor::moveCursorUp = (lineCount) -> + deprecate("Use TextEditor::moveUp() instead") + @moveUp(lineCount) + + TextEditor::moveCursorDown = (lineCount) -> + deprecate("Use TextEditor::moveDown() instead") + @moveDown(lineCount) + + TextEditor::moveCursorLeft = -> + deprecate("Use TextEditor::moveLeft() instead") + @moveLeft() + + TextEditor::moveCursorRight = -> + deprecate("Use TextEditor::moveRight() instead") + @moveRight() + + TextEditor::moveCursorToBeginningOfLine = -> + deprecate("Use TextEditor::moveToBeginningOfLine() instead") + @moveToBeginningOfLine() + + TextEditor::moveCursorToBeginningOfScreenLine = -> + deprecate("Use TextEditor::moveToBeginningOfScreenLine() instead") + @moveToBeginningOfScreenLine() + + TextEditor::moveCursorToFirstCharacterOfLine = -> + deprecate("Use TextEditor::moveToFirstCharacterOfLine() instead") + @moveToFirstCharacterOfLine() + + TextEditor::moveCursorToEndOfLine = -> + deprecate("Use TextEditor::moveToEndOfLine() instead") + @moveToEndOfLine() + + TextEditor::moveCursorToEndOfScreenLine = -> + deprecate("Use TextEditor::moveToEndOfScreenLine() instead") + @moveToEndOfScreenLine() + + TextEditor::moveCursorToBeginningOfWord = -> + deprecate("Use TextEditor::moveToBeginningOfWord() instead") + @moveToBeginningOfWord() + + TextEditor::moveCursorToEndOfWord = -> + deprecate("Use TextEditor::moveToEndOfWord() instead") + @moveToEndOfWord() + + TextEditor::moveCursorToTop = -> + deprecate("Use TextEditor::moveToTop() instead") + @moveToTop() + + TextEditor::moveCursorToBottom = -> + deprecate("Use TextEditor::moveToBottom() instead") + @moveToBottom() + + TextEditor::moveCursorToBeginningOfNextWord = -> + deprecate("Use TextEditor::moveToBeginningOfNextWord() instead") + @moveToBeginningOfNextWord() + + TextEditor::moveCursorToPreviousWordBoundary = -> + deprecate("Use TextEditor::moveToPreviousWordBoundary() instead") + @moveToPreviousWordBoundary() + + TextEditor::moveCursorToNextWordBoundary = -> + deprecate("Use TextEditor::moveToNextWordBoundary() instead") + @moveToNextWordBoundary() + + TextEditor::moveCursorToBeginningOfNextParagraph = -> + deprecate("Use TextEditor::moveToBeginningOfNextParagraph() instead") + @moveToBeginningOfNextParagraph() + + TextEditor::moveCursorToBeginningOfPreviousParagraph = -> + deprecate("Use TextEditor::moveToBeginningOfPreviousParagraph() instead") + @moveToBeginningOfPreviousParagraph() + + TextEditor::getCursor = -> + deprecate("Use TextEditor::getLastCursor() instead") + @getLastCursor() + + TextEditor::selectLine = -> + deprecate('Use TextEditor::selectLinesContainingCursors instead') + @selectLinesContainingCursors() + + TextEditor::selectWord = -> + deprecate('Use TextEditor::selectWordsContainingCursors instead') + @selectWordsContainingCursors() + + TextEditor::getSelection = (index) -> + if index? + deprecate("Use TextEditor::getSelections()[index] instead when getting a specific selection") + @getSelections()[index] + else + deprecate("Use TextEditor::getLastSelection() instead") + @getLastSelection() + + TextEditor::getSoftWrapped = -> + deprecate("Use TextEditor::isSoftWrapped instead") + @displayBuffer.isSoftWrapped() + + TextEditor::on = (eventName) -> + switch eventName + when 'title-changed' + deprecate("Use TextEditor::onDidChangeTitle instead") + when 'path-changed' + deprecate("Use TextEditor::onDidChangePath instead") + when 'modified-status-changed' + deprecate("Use TextEditor::onDidChangeModified instead") + when 'soft-wrap-changed' + deprecate("Use TextEditor::onDidChangeSoftWrapped instead") + when 'grammar-changed' + deprecate("Use TextEditor::onDidChangeGrammar instead") + when 'character-widths-changed' + deprecate("Use TextEditor::onDidChangeCharacterWidths instead") + when 'contents-modified' + deprecate("Use TextEditor::onDidStopChanging instead") + when 'contents-conflicted' + deprecate("Use TextEditor::onDidConflict instead") + + when 'will-insert-text' + deprecate("Use TextEditor::onWillInsertText instead") + when 'did-insert-text' + deprecate("Use TextEditor::onDidInsertText instead") + + when 'cursor-added' + deprecate("Use TextEditor::onDidAddCursor instead") + when 'cursor-removed' + deprecate("Use TextEditor::onDidRemoveCursor instead") + when 'cursor-moved' + deprecate("Use TextEditor::onDidChangeCursorPosition instead") + + when 'selection-added' + deprecate("Use TextEditor::onDidAddSelection instead") + when 'selection-removed' + deprecate("Use TextEditor::onDidRemoveSelection instead") + when 'selection-screen-range-changed' + deprecate("Use TextEditor::onDidChangeSelectionRange instead") + + when 'decoration-added' + deprecate("Use TextEditor::onDidAddDecoration instead") + when 'decoration-removed' + deprecate("Use TextEditor::onDidRemoveDecoration instead") + when 'decoration-updated' + deprecate("Use Decoration::onDidChangeProperties instead. You will get the decoration back from `TextEditor::decorateMarker()`") + when 'decoration-changed' + deprecate("Use Marker::onDidChange instead. e.g. `editor::decorateMarker(...).getMarker().onDidChange()`") + + when 'screen-lines-changed' + deprecate("Use TextEditor::onDidChange instead") + + when 'scroll-top-changed' + deprecate("Use TextEditor::onDidChangeScrollTop instead") + when 'scroll-left-changed' + deprecate("Use TextEditor::onDidChangeScrollLeft instead") + + else + deprecate("TextEditor::on is deprecated. Use documented event subscription methods instead.") + + EmitterMixin::on.apply(this, arguments) From 164d5e46b0552cf5012bce20958f61e3d9467ac3 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 15:29:58 -0700 Subject: [PATCH 0436/1783] Only call emit when including deprecations --- src/package.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package.coffee b/src/package.coffee index 7b590aab4..f9d3ac576 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -356,7 +356,7 @@ class Package @mainModule?.deactivate?() catch e console.error "Error deactivating package '#{@name}'", e.stack - @emit 'deactivated' + @emit 'deactivated' if includeDeprecations @emitter.emit 'did-deactivate' deactivateConfig: -> From 97bf4fb4d18f739cd385f6e3678f11ce3ae028de Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 15:56:29 -0700 Subject: [PATCH 0437/1783] :arrow_up: command-palette@0.35 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 795ee2bc6..02b3c9669 100644 --- a/package.json +++ b/package.json @@ -89,7 +89,7 @@ "background-tips": "0.23.0", "bookmarks": "0.35.0", "bracket-matcher": "0.73.0", - "command-palette": "0.34.0", + "command-palette": "0.35.0", "deprecation-cop": "0.39.0", "dev-live-reload": "0.45.0", "encoding-selector": "0.19.0", From c24948ebccb2c510d3963ec0c624052f8d201ff5 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 16:15:09 -0700 Subject: [PATCH 0438/1783] Conditionally include deprecations in Pane --- src/pane.coffee | 85 +++++++++++++++++++++++++------------------------ 1 file changed, 43 insertions(+), 42 deletions(-) diff --git a/src/pane.coffee b/src/pane.coffee index a6e456d6a..d1e83c609 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -42,7 +42,7 @@ class Pane extends Model # Called by the Serializable mixin during serialization. serializeParams: -> - if typeof @activeItem?.getURI is 'function' + if Grim.includeDeprecations and typeof @activeItem?.getURI is 'function' activeItemURI = @activeItem.getURI() else if typeof @activeItem?.getUri is 'function' activeItemURI = @activeItem.getUri() @@ -203,39 +203,6 @@ class Pane extends Model onWillDestroyItem: (callback) -> @emitter.on 'will-destroy-item', callback - on: (eventName) -> - switch eventName - when 'activated' - Grim.deprecate("Use Pane::onDidActivate instead") - when 'destroyed' - Grim.deprecate("Use Pane::onDidDestroy instead") - when 'item-added' - Grim.deprecate("Use Pane::onDidAddItem instead") - when 'item-removed' - Grim.deprecate("Use Pane::onDidRemoveItem instead") - when 'item-moved' - Grim.deprecate("Use Pane::onDidMoveItem instead") - when 'before-item-destroyed' - Grim.deprecate("Use Pane::onWillDestroyItem instead") - else - Grim.deprecate("Subscribing via ::on is deprecated. Use documented event subscription methods instead.") - super - - behavior: (behaviorName) -> - switch behaviorName - when 'active' - Grim.deprecate("The $active behavior property is deprecated. Use ::observeActive or ::onDidChangeActive instead.") - when 'container' - Grim.deprecate("The $container behavior property is deprecated.") - when 'activeItem' - Grim.deprecate("The $activeItem behavior property is deprecated. Use ::observeActiveItem or ::onDidChangeActiveItem instead.") - when 'focused' - Grim.deprecate("The $focused behavior property is deprecated.") - else - Grim.deprecate("Pane::behavior is deprecated. Use event subscription methods instead.") - - super - # Called by the view layer to indicate that the pane has gained focus. focus: -> @focused = true @@ -535,10 +502,6 @@ class Pane extends Model itemUri is uri - itemForUri: (uri) -> - Grim.deprecate("Use `::itemForURI` instead.") - @itemForURI(uri) - # Public: Activate the first item that matches the given URI. # # Returns a {Boolean} indicating whether an item matching the URI was found. @@ -549,10 +512,6 @@ class Pane extends Model else false - activateItemForUri: (uri) -> - Grim.deprecate("Use `::activateItemForURI` instead.") - @activateItemForURI(uri) - copyActiveItem: -> if @activeItem? @activeItem.copy?() ? atom.deserializers.deserialize(@activeItem.serialize()) @@ -701,3 +660,45 @@ class Pane extends Model atom.notifications.addWarning("Unable to save file: A directory in the path '#{fileName}' could not be written to") else throw error + +if Grim.includeDeprecations + Pane::on = (eventName) -> + switch eventName + when 'activated' + Grim.deprecate("Use Pane::onDidActivate instead") + when 'destroyed' + Grim.deprecate("Use Pane::onDidDestroy instead") + when 'item-added' + Grim.deprecate("Use Pane::onDidAddItem instead") + when 'item-removed' + Grim.deprecate("Use Pane::onDidRemoveItem instead") + when 'item-moved' + Grim.deprecate("Use Pane::onDidMoveItem instead") + when 'before-item-destroyed' + Grim.deprecate("Use Pane::onWillDestroyItem instead") + else + Grim.deprecate("Subscribing via ::on is deprecated. Use documented event subscription methods instead.") + super + + Pane::behavior = (behaviorName) -> + switch behaviorName + when 'active' + Grim.deprecate("The $active behavior property is deprecated. Use ::observeActive or ::onDidChangeActive instead.") + when 'container' + Grim.deprecate("The $container behavior property is deprecated.") + when 'activeItem' + Grim.deprecate("The $activeItem behavior property is deprecated. Use ::observeActiveItem or ::onDidChangeActiveItem instead.") + when 'focused' + Grim.deprecate("The $focused behavior property is deprecated.") + else + Grim.deprecate("Pane::behavior is deprecated. Use event subscription methods instead.") + + super + + Pane::itemForUri = (uri) -> + Grim.deprecate("Use `::itemForURI` instead.") + @itemForURI(uri) + + Pane::activateItemForUri = (uri) -> + Grim.deprecate("Use `::activateItemForURI` instead.") + @activateItemForURI(uri) From edf17f1fdbaeb4ea1a6a46a2501f8c94e1fc9d81 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 16:19:53 -0700 Subject: [PATCH 0439/1783] Conditionally include deprecations in Project --- src/project.coffee | 115 ++++++++++++++++++++++----------------------- 1 file changed, 56 insertions(+), 59 deletions(-) diff --git a/src/project.coffee b/src/project.coffee index f0d368531..02be678fe 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -4,7 +4,7 @@ url = require 'url' _ = require 'underscore-plus' fs = require 'fs-plus' Q = require 'q' -{deprecate} = require 'grim' +{includeDeprecations, deprecate} = require 'grim' {Model} = require 'theorist' {Subscriber} = require 'emissary' {Emitter} = require 'event-kit' @@ -25,12 +25,6 @@ class Project extends Model atom.deserializers.add(this) Serializable.includeInto(this) - @pathForRepositoryUrl: (repoUrl) -> - deprecate '::pathForRepositoryUrl will be removed. Please remove from your code.' - [repoName] = url.parse(repoUrl).path.split('/')[-1..] - repoName = repoName.replace(/\.git$/, '') - path.join(atom.config.get('core.projectHome'), repoName) - ### Section: Construction and Destruction ### @@ -73,8 +67,10 @@ class Project extends Model @subscribeToBuffer(buffer) for buffer in @buffers - Grim.deprecate("Pass 'paths' array instead of 'path' to project constructor") if path? - paths ?= _.compact([path]) + if Grim.includeDeprecations and path? + Grim.deprecate("Pass 'paths' array instead of 'path' to project constructor") + paths ?= _.compact([path]) + @setPaths(paths) destroyed: -> @@ -122,13 +118,6 @@ class Project extends Model onDidAddBuffer: (callback) -> @emitter.on 'did-add-buffer', callback - on: (eventName) -> - if eventName is 'path-changed' - Grim.deprecate("Use Project::onDidChangePaths instead") - else - Grim.deprecate("Project::on is deprecated. Use documented event subscription methods instead.") - super - ### Section: Accessing the git repository ### @@ -144,9 +133,6 @@ class Project extends Model # project.repositoryForDirectory.bind(project))) # ``` getRepositories: -> @repositories - getRepo: -> - Grim.deprecate("Use ::getRepositories instead") - @getRepositories()[0] # Public: Get the repository for a given directory asynchronously. # @@ -180,9 +166,6 @@ class Project extends Model # Public: Get an {Array} of {String}s containing the paths of the project's # directories. getPaths: -> rootDirectory.getPath() for rootDirectory in @rootDirectories - getPath: -> - Grim.deprecate("Use ::getPaths instead") - @getPaths()[0] # Public: Set the paths of the project's directories. # @@ -198,10 +181,6 @@ class Project extends Model @emit "path-changed" @emitter.emit 'did-change-paths', projectPaths - setPath: (path) -> - Grim.deprecate("Use ::setPaths instead") - @setPaths([path]) - # Public: Add a path to the project's list of root paths # # * `projectPath` {String} The path to the directory to add. @@ -257,13 +236,6 @@ class Project extends Model # Public: Get an {Array} of {Directory}s associated with this project. getDirectories: -> @rootDirectories - getRootDirectory: -> - Grim.deprecate("Use ::getDirectories instead") - @getDirectories()[0] - - resolve: (uri) -> - Grim.deprecate("Use `Project::getDirectories()[0]?.resolve()` instead") - @resolvePath(uri) resolvePath: (uri) -> return unless uri @@ -329,18 +301,6 @@ class Project extends Model contains: (pathToCheck) -> @rootDirectories.some (dir) -> dir.contains(pathToCheck) - ### - Section: Searching and Replacing - ### - - scan: (regex, options={}, iterator) -> - Grim.deprecate("Use atom.workspace.scan instead of atom.project.scan") - atom.workspace.scan(regex, options, iterator) - - replace: (regex, replacementText, filePaths, iterator) -> - Grim.deprecate("Use atom.workspace.replace instead of atom.project.replace") - atom.workspace.replace(regex, replacementText, filePaths, iterator) - ### Section: Private ### @@ -365,12 +325,6 @@ class Project extends Model @bufferForPath(filePath).then (buffer) => @buildEditorForBuffer(buffer, options) - # Deprecated - openSync: (filePath, options={}) -> - deprecate("Use Project::open instead") - filePath = @resolvePath(filePath) - @buildEditorForBuffer(@bufferForPathSync(filePath), options) - # Retrieves all the {TextBuffer}s in the project; that is, the # buffers for all open files. # @@ -479,22 +433,65 @@ class Project extends Model detail: error.message dismissable: true - # Deprecated: delegate - registerOpener: (opener) -> +if includeDeprecations + Project.pathForRepositoryUrl = (repoUrl) -> + deprecate '::pathForRepositoryUrl will be removed. Please remove from your code.' + [repoName] = url.parse(repoUrl).path.split('/')[-1..] + repoName = repoName.replace(/\.git$/, '') + path.join(atom.config.get('core.projectHome'), repoName) + + Project::registerOpener = (opener) -> deprecate("Use Workspace::addOpener instead") atom.workspace.addOpener(opener) - # Deprecated: delegate - unregisterOpener: (opener) -> + Project::unregisterOpener = (opener) -> deprecate("Call .dispose() on the Disposable returned from ::addOpener instead") atom.workspace.unregisterOpener(opener) - # Deprecated: delegate - eachEditor: (callback) -> + Project::eachEditor = (callback) -> deprecate("Use Workspace::observeTextEditors instead") atom.workspace.observeTextEditors(callback) - # Deprecated: delegate - getEditors: -> + Project::getEditors = -> deprecate("Use Workspace::getTextEditors instead") atom.workspace.getTextEditors() + + Project::on = (eventName) -> + if eventName is 'path-changed' + Grim.deprecate("Use Project::onDidChangePaths instead") + else + Grim.deprecate("Project::on is deprecated. Use documented event subscription methods instead.") + super + + Project::getRepo = -> + Grim.deprecate("Use ::getRepositories instead") + @getRepositories()[0] + + Project::getPath = -> + Grim.deprecate("Use ::getPaths instead") + @getPaths()[0] + + Project::setPath = (path) -> + Grim.deprecate("Use ::setPaths instead") + @setPaths([path]) + + Project::getRootDirectory = -> + Grim.deprecate("Use ::getDirectories instead") + @getDirectories()[0] + + Project::resolve = (uri) -> + Grim.deprecate("Use `Project::getDirectories()[0]?.resolve()` instead") + @resolvePath(uri) + + Project::scan = (regex, options={}, iterator) -> + Grim.deprecate("Use atom.workspace.scan instead of atom.project.scan") + atom.workspace.scan(regex, options, iterator) + + Project::replace = (regex, replacementText, filePaths, iterator) -> + Grim.deprecate("Use atom.workspace.replace instead of atom.project.replace") + atom.workspace.replace(regex, replacementText, filePaths, iterator) + + Project::openSync = (filePath, options={}) -> + deprecate("Use Project::open instead") + filePath = @resolvePath(filePath) + @buildEditorForBuffer(@bufferForPathSync(filePath), options) From 9e904268411b0b955823371cee7a79102f01726e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 16:42:20 -0700 Subject: [PATCH 0440/1783] Only do legacy emit when including deprecations --- src/workspace.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/workspace.coffee b/src/workspace.coffee index a5a4e5e30..858ae063f 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -112,7 +112,7 @@ class Workspace extends Model _.uniq(packageNames) editorAdded: (editor) -> - @emit 'editor-created', editor + @emit 'editor-created', editor if includeDeprecations installShellCommands: -> require('./command-installer').installShellCommandsInteractively() @@ -446,7 +446,7 @@ class Workspace extends Model if options.initialLine? or options.initialColumn? item.setCursorBufferPosition?([options.initialLine, options.initialColumn]) index = pane.getActiveItemIndex() - @emit "uri-opened" + @emit "uri-opened" if includeDeprecations @emitter.emit 'did-open', {uri, pane, item, index} item From 23d1c72a5f3945aa1b8f76c884ee95bfe613f05a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 17:06:10 -0700 Subject: [PATCH 0441/1783] Remove unused imports --- src/context-menu-manager.coffee | 4 +--- src/decoration.coffee | 2 +- src/display-buffer.coffee | 3 ++- src/marker.coffee | 1 - src/pane.coffee | 1 - 5 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/context-menu-manager.coffee b/src/context-menu-manager.coffee index 69caa5d6d..4565c8b55 100644 --- a/src/context-menu-manager.coffee +++ b/src/context-menu-manager.coffee @@ -1,6 +1,4 @@ -{$} = require './space-pen-extensions' _ = require 'underscore-plus' -remote = require 'remote' path = require 'path' CSON = require 'season' fs = require 'fs-plus' @@ -189,7 +187,7 @@ class ContextMenuManager menuTemplate = @templateForEvent(event) return unless menuTemplate?.length > 0 - remote.getCurrentWindow().emit('context-menu', menuTemplate) + atom.getCurrentWindow().emit('context-menu', menuTemplate) return clear: -> diff --git a/src/decoration.coffee b/src/decoration.coffee index b3ad4b7ff..a556a3a3c 100644 --- a/src/decoration.coffee +++ b/src/decoration.coffee @@ -1,5 +1,4 @@ _ = require 'underscore-plus' -EmitterMixin = require('emissary').Emitter {Emitter} = require 'event-kit' Grim = require 'grim' @@ -165,6 +164,7 @@ class Decoration null if Grim.includeDeprecations + EmitterMixin = require('emissary').Emitter EmitterMixin.includeInto(Decoration) Decoration::on = (eventName) -> diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index 277a79200..12b839143 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -1,5 +1,4 @@ _ = require 'underscore-plus' -EmitterMixin = require('emissary').Emitter Serializable = require 'serializable' {Model} = require 'theorist' {CompositeDisposable, Emitter} = require 'event-kit' @@ -1229,6 +1228,8 @@ class DisplayBuffer extends Model @foldsByMarkerId[marker.id] if Grim.includeDeprecations + EmitterMixin = require('emissary').Emitter + DisplayBuffer::on = (eventName) -> switch eventName when 'changed' diff --git a/src/marker.coffee b/src/marker.coffee index bd48eb48c..c177b792e 100644 --- a/src/marker.coffee +++ b/src/marker.coffee @@ -1,4 +1,3 @@ -{Range} = require 'text-buffer' _ = require 'underscore-plus' {CompositeDisposable, Emitter} = require 'event-kit' Grim = require 'grim' diff --git a/src/pane.coffee b/src/pane.coffee index d1e83c609..07e621e46 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -5,7 +5,6 @@ Serializable = require 'serializable' Grim = require 'grim' PaneAxis = require './pane-axis' TextEditor = require './text-editor' -PaneView = null # Extended: A container for presenting content in the center of the workspace. # Panes can contain multiple items, one of which is *active* at a given time. From 63072bf8aee0909ab69585f4e5109d649855a3e2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 17:11:42 -0700 Subject: [PATCH 0442/1783] Check deprecations flag for space pen shim inclusion --- src/atom.coffee | 4 +++- src/text-editor-component.coffee | 7 ++++--- src/text-editor-element.coffee | 5 +++-- src/workspace-element.coffee | 6 +++--- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/atom.coffee b/src/atom.coffee index ace3245ef..b787764be 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -721,7 +721,9 @@ class Atom extends Model deserializeWorkspaceView: -> Workspace = require './workspace' - WorkspaceView = require './workspace-view' + + if includeDeprecations + WorkspaceView = require './workspace-view' startTime = Date.now() @workspace = Workspace.deserialize(@state.workspace) ? new Workspace diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index c2babdca4..b57920952 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -152,9 +152,10 @@ class TextEditorComponent if @editor.isAlive() @updateParentViewFocusedClassIfNeeded() @updateParentViewMiniClass() - @hostElement.__spacePenView.trigger 'cursor:moved' if cursorMoved - @hostElement.__spacePenView.trigger 'selection:changed' if selectionChanged - @hostElement.__spacePenView.trigger 'editor:display-updated' + if grim.includeDeprecations + @hostElement.__spacePenView.trigger 'cursor:moved' if cursorMoved + @hostElement.__spacePenView.trigger 'selection:changed' if selectionChanged + @hostElement.__spacePenView.trigger 'editor:display-updated' readAfterUpdateSync: => @linesComponent.measureCharactersInNewLines() if @isVisible() and not @newState.content.scrollingVertically diff --git a/src/text-editor-element.coffee b/src/text-editor-element.coffee index ccd69dca8..5822f533c 100644 --- a/src/text-editor-element.coffee +++ b/src/text-editor-element.coffee @@ -3,6 +3,7 @@ Path = require 'path' {defaults} = require 'underscore-plus' TextBuffer = require 'text-buffer' +Grim = require 'grim' TextEditor = require './text-editor' TextEditorComponent = require './text-editor-component' TextEditorView = null @@ -20,7 +21,7 @@ class TextEditorElement extends HTMLElement createdCallback: -> @emitter = new Emitter @initializeContent() - @createSpacePenShim() + @createSpacePenShim() if Grim.includeDeprecations @addEventListener 'focus', @focused.bind(this) @addEventListener 'blur', @blurred.bind(this) @@ -86,7 +87,7 @@ class TextEditorElement extends HTMLElement @model.onDidChangeGrammar => @addGrammarScopeAttribute() @model.onDidChangeEncoding => @addEncodingAttribute() @model.onDidDestroy => @unmountComponent() - @__spacePenView.setModel(@model) + @__spacePenView.setModel(@model) if Grim.includeDeprecations @model getModel: -> diff --git a/src/workspace-element.coffee b/src/workspace-element.coffee index f2805ff08..66ded0084 100644 --- a/src/workspace-element.coffee +++ b/src/workspace-element.coffee @@ -16,10 +16,10 @@ class WorkspaceElement extends HTMLElement @initializeContent() @observeScrollbarStyle() @observeTextEditorFontConfig() - @createSpacePenShim() + @createSpacePenShim() if Grim.includeDeprecations attachedCallback: -> - callAttachHooks(this) + callAttachHooks(this) if Grim.includeDeprecations @focus() detachedCallback: -> @@ -82,7 +82,7 @@ class WorkspaceElement extends HTMLElement @appendChild(@panelContainers.modal) - @__spacePenView.setModel(@model) + @__spacePenView.setModel(@model) if Grim.includeDeprecations this getModel: -> @model From dd72bbe0ef1eae13eff908f006ae4181aae3756f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 17:19:44 -0700 Subject: [PATCH 0443/1783] Conditionally include deprecations in Config --- src/config.coffee | 163 ++++++++++++++++++++-------------------------- 1 file changed, 70 insertions(+), 93 deletions(-) diff --git a/src/config.coffee b/src/config.coffee index 4901f21dc..b48d69ca0 100644 --- a/src/config.coffee +++ b/src/config.coffee @@ -371,13 +371,13 @@ class Config observe: -> if arguments.length is 2 [keyPath, callback] = arguments - else if arguments.length is 3 and (_.isArray(arguments[0]) or arguments[0] instanceof ScopeDescriptor) + else if Grim.includeDeprecations and arguments.length is 3 and (_.isArray(arguments[0]) or arguments[0] instanceof ScopeDescriptor) Grim.deprecate """ Passing a scope descriptor as the first argument to Config::observe is deprecated. Pass a `scope` in an options hash as the third argument instead. """ [scopeDescriptor, keyPath, callback] = arguments - else if arguments.length is 3 and (_.isString(arguments[0]) and _.isObject(arguments[1])) + else if Grim.includeDeprecations and arguments.length is 3 and (_.isString(arguments[0]) and _.isObject(arguments[1])) [keyPath, options, callback] = arguments scopeDescriptor = options.scope if options.callNow? @@ -419,7 +419,7 @@ class Config [callback] = arguments else if arguments.length is 2 [keyPath, callback] = arguments - else if _.isArray(arguments[0]) or arguments[0] instanceof ScopeDescriptor + else if Grim.includeDeprecations and _.isArray(arguments[0]) or arguments[0] instanceof ScopeDescriptor Grim.deprecate """ Passing a scope descriptor as the first argument to Config::onDidChange is deprecated. Pass a `scope` in an options hash as the third argument instead. @@ -498,7 +498,7 @@ class Config if typeof arguments[0] is 'string' or not arguments[0]? [keyPath, options] = arguments {scope} = options - else + else if Grim.includeDeprecations Grim.deprecate """ Passing a scope descriptor as the first argument to Config::get is deprecated. Pass a `scope` in an options hash as the final argument instead. @@ -578,7 +578,7 @@ class Config # * `true` if the value was set. # * `false` if the value was not able to be coerced to the type specified in the setting's schema. set: -> - if arguments[0]?[0] is '.' + if Grim.includeDeprecations and arguments[0]?[0] is '.' Grim.deprecate """ Passing a scope selector as the first argument to Config::set is deprecated. Pass a `scopeSelector` in an options hash as the final argument instead. @@ -617,7 +617,7 @@ class Config # * `scopeSelector` (optional) {String}. See {::set} # * `source` (optional) {String}. See {::set} unset: (keyPath, options) -> - if typeof options is 'string' + if Grim.includeDeprecations and typeof options is 'string' Grim.deprecate """ Passing a scope selector as the first argument to Config::unset is deprecated. Pass a `scopeSelector` in an options hash as the second argument instead. @@ -652,47 +652,6 @@ class Config getSources: -> _.uniq(_.pluck(@scopedSettingsStore.propertySets, 'source')).sort() - # Deprecated: Restore the global setting at `keyPath` to its default value. - # - # Returns the new value. - restoreDefault: (scopeSelector, keyPath) -> - Grim.deprecate("Use ::unset instead.") - @unset(scopeSelector, keyPath) - @get(keyPath) - - # Deprecated: Get the global default value of the key path. _Please note_ that in most - # cases calling this is not necessary! {::get} returns the default value when - # a custom value is not specified. - # - # * `scopeSelector` (optional) {String}. eg. '.source.ruby' - # * `keyPath` The {String} name of the key. - # - # Returns the default value. - getDefault: -> - Grim.deprecate("Use `::get(keyPath, {scope, excludeSources: [atom.config.getUserConfigPath()]})` instead") - if arguments.length is 1 - [keyPath] = arguments - else - [scopeSelector, keyPath] = arguments - scope = [scopeSelector] - @get(keyPath, {scope, excludeSources: [@getUserConfigPath()]}) - - # Deprecated: Is the value at `keyPath` its default value? - # - # * `scopeSelector` (optional) {String}. eg. '.source.ruby' - # * `keyPath` The {String} name of the key. - # - # Returns a {Boolean}, `true` if the current value is the default, `false` - # otherwise. - isDefault: -> - Grim.deprecate("Use `not ::get(keyPath, {scope, sources: [atom.config.getUserConfigPath()]})?` instead") - if arguments.length is 1 - [keyPath] = arguments - else - [scopeSelector, keyPath] = arguments - scope = [scopeSelector] - not @get(keyPath, {scope, sources: [@getUserConfigPath()]})? - # Extended: Retrieve the schema for a specific key path. The schema will tell # you what type the keyPath expects, and other metadata about the config # option. @@ -709,12 +668,6 @@ class Config schema = schema.properties?[key] schema - # Deprecated: Returns a new {Object} containing all of the global settings and - # defaults. Returns the scoped settings when a `scopeSelector` is specified. - getSettings: -> - Grim.deprecate "Use ::get(keyPath) instead" - _.deepExtend({}, @settings, @defaultSettings) - # Extended: Get the {String} path to the config file being used. getUserConfigPath: -> @configFilePath @@ -732,31 +685,6 @@ class Config @transactDepth-- @emitChangeEvent() - ### - Section: Deprecated - ### - - getInt: (keyPath) -> - Grim.deprecate '''Config::getInt is no longer necessary. Use ::get instead. - Make sure the config option you are accessing has specified an `integer` - schema. See the schema section of - https://atom.io/docs/api/latest/Config for more info.''' - parseInt(@get(keyPath)) - - getPositiveInt: (keyPath, defaultValue=0) -> - Grim.deprecate '''Config::getPositiveInt is no longer necessary. Use ::get instead. - Make sure the config option you are accessing has specified an `integer` - schema with `minimum: 1`. See the schema section of - https://atom.io/docs/api/latest/Config for more info.''' - Math.max(@getInt(keyPath), 0) or defaultValue - - toggle: (keyPath) -> - Grim.deprecate 'Config::toggle is no longer supported. Please remove from your code.' - @set(keyPath, !@get(keyPath)) - - unobserve: (keyPath) -> - Grim.deprecate 'Config::unobserve no longer does anything. Call `.dispose()` on the object returned by Config::observe instead.' - ### Section: Internal methods used by core ### @@ -1056,16 +984,6 @@ class Config @emitChangeEvent() - addScopedSettings: (source, selector, value, options) -> - Grim.deprecate("Use ::set instead") - settingsBySelector = {} - settingsBySelector[selector] = value - disposable = @scopedSettingsStore.addProperties(source, settingsBySelector, options) - @emitChangeEvent() - new Disposable => - disposable.dispose() - @emitChangeEvent() - setRawScopedValue: (keyPath, value, source, selector, options) -> if keyPath? newValue = {} @@ -1094,11 +1012,6 @@ class Config oldValue = newValue callback(event) - settingsForScopeDescriptor: (scopeDescriptor, keyPath) -> - Grim.deprecate("Use Config::getAll instead") - entries = @getAll(null, scope: scopeDescriptor) - value for {value} in entries when _.valueForKeyPath(value, keyPath)? - # Base schema enforcers. These will coerce raw input into the specified type, # and will throw an error when the value cannot be coerced. Throwing the error # will indicate that the value should not be set. @@ -1232,3 +1145,67 @@ withoutEmptyObjects = (object) -> else resultObject = object resultObject + +if Grim.includeDeprecations + Config::restoreDefault = (scopeSelector, keyPath) -> + Grim.deprecate("Use ::unset instead.") + @unset(scopeSelector, keyPath) + @get(keyPath) + + Config::getDefault = -> + Grim.deprecate("Use `::get(keyPath, {scope, excludeSources: [atom.config.getUserConfigPath()]})` instead") + if arguments.length is 1 + [keyPath] = arguments + else + [scopeSelector, keyPath] = arguments + scope = [scopeSelector] + @get(keyPath, {scope, excludeSources: [@getUserConfigPath()]}) + + Config::isDefault = -> + Grim.deprecate("Use `not ::get(keyPath, {scope, sources: [atom.config.getUserConfigPath()]})?` instead") + if arguments.length is 1 + [keyPath] = arguments + else + [scopeSelector, keyPath] = arguments + scope = [scopeSelector] + not @get(keyPath, {scope, sources: [@getUserConfigPath()]})? + + Config::getSettings = -> + Grim.deprecate "Use ::get(keyPath) instead" + _.deepExtend({}, @settings, @defaultSettings) + + Config::getInt = (keyPath) -> + Grim.deprecate '''Config::getInt is no longer necessary. Use ::get instead. + Make sure the config option you are accessing has specified an `integer` + schema. See the schema section of + https://atom.io/docs/api/latest/Config for more info.''' + parseInt(@get(keyPath)) + + Config::getPositiveInt = (keyPath, defaultValue=0) -> + Grim.deprecate '''Config::getPositiveInt is no longer necessary. Use ::get instead. + Make sure the config option you are accessing has specified an `integer` + schema with `minimum: 1`. See the schema section of + https://atom.io/docs/api/latest/Config for more info.''' + Math.max(@getInt(keyPath), 0) or defaultValue + + Config::toggle = (keyPath) -> + Grim.deprecate 'Config::toggle is no longer supported. Please remove from your code.' + @set(keyPath, !@get(keyPath)) + + Config::unobserve = (keyPath) -> + Grim.deprecate 'Config::unobserve no longer does anything. Call `.dispose()` on the object returned by Config::observe instead.' + + Config::addScopedSettings = (source, selector, value, options) -> + Grim.deprecate("Use ::set instead") + settingsBySelector = {} + settingsBySelector[selector] = value + disposable = @scopedSettingsStore.addProperties(source, settingsBySelector, options) + @emitChangeEvent() + new Disposable => + disposable.dispose() + @emitChangeEvent() + + Config::settingsForScopeDescriptor = (scopeDescriptor, keyPath) -> + Grim.deprecate("Use Config::getAll instead") + entries = @getAll(null, scope: scopeDescriptor) + value for {value} in entries when _.valueForKeyPath(value, keyPath)? From 0c06c69cd91c0bca31c547893b2b4c272fa2fc55 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 17:31:28 -0700 Subject: [PATCH 0444/1783] Check deprecations flag for space pen shim inclusion --- src/pane-container-element.coffee | 9 ++++++--- src/pane-element.coffee | 8 +++++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/pane-container-element.coffee b/src/pane-container-element.coffee index 65ee9ecea..55d527971 100644 --- a/src/pane-container-element.coffee +++ b/src/pane-container-element.coffee @@ -1,4 +1,5 @@ {CompositeDisposable} = require 'event-kit' +Grim = require 'grim' {callAttachHooks} = require './space-pen-extensions' PaneContainerView = null _ = require 'underscore-plus' @@ -8,12 +9,14 @@ class PaneContainerElement extends HTMLElement createdCallback: -> @subscriptions = new CompositeDisposable @classList.add 'panes' - PaneContainerView ?= require './pane-container-view' - @__spacePenView = new PaneContainerView(this) + + if Grim.includeDeprecations + PaneContainerView ?= require './pane-container-view' + @__spacePenView = new PaneContainerView(this) initialize: (@model) -> @subscriptions.add @model.observeRoot(@rootChanged.bind(this)) - @__spacePenView.setModel(@model) + @__spacePenView.setModel(@model) if Grim.includeDeprecations this rootChanged: (root) -> diff --git a/src/pane-element.coffee b/src/pane-element.coffee index f626e9fad..f050567b2 100644 --- a/src/pane-element.coffee +++ b/src/pane-element.coffee @@ -1,6 +1,7 @@ {CompositeDisposable} = require 'event-kit' +Grim = require 'grim' {$, callAttachHooks, callRemoveHooks} = require './space-pen-extensions' -PaneView = require './pane-view' +PaneView = null class PaneElement extends HTMLElement attached: false @@ -12,7 +13,7 @@ class PaneElement extends HTMLElement @initializeContent() @subscribeToDOMEvents() - @createSpacePenShim() + @createSpacePenShim() if Grim.includeDeprecations attachedCallback: -> @attached = true @@ -41,6 +42,7 @@ class PaneElement extends HTMLElement @addEventListener 'blur', handleBlur, true createSpacePenShim: -> + PaneView ?= require './pane-view' @__spacePenView = new PaneView(this) initialize: (@model) -> @@ -49,7 +51,7 @@ class PaneElement extends HTMLElement @subscriptions.add @model.observeActiveItem(@activeItemChanged.bind(this)) @subscriptions.add @model.onDidRemoveItem(@itemRemoved.bind(this)) @subscriptions.add @model.onDidDestroy(@paneDestroyed.bind(this)) - @__spacePenView.setModel(@model) + @__spacePenView.setModel(@model) if Grim.includeDeprecations this getModel: -> @model From bb53548ba02b96cf45cbe7d1caa5766e65ec96de Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 17:35:29 -0700 Subject: [PATCH 0445/1783] Only check deprecation flag for callNow usage --- src/config.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config.coffee b/src/config.coffee index b48d69ca0..3d0e363ad 100644 --- a/src/config.coffee +++ b/src/config.coffee @@ -377,10 +377,10 @@ class Config Pass a `scope` in an options hash as the third argument instead. """ [scopeDescriptor, keyPath, callback] = arguments - else if Grim.includeDeprecations and arguments.length is 3 and (_.isString(arguments[0]) and _.isObject(arguments[1])) + else if arguments.length is 3 and (_.isString(arguments[0]) and _.isObject(arguments[1])) [keyPath, options, callback] = arguments scopeDescriptor = options.scope - if options.callNow? + if Grim.includeDeprecations and options.callNow? Grim.deprecate """ Config::observe no longer takes a `callNow` option. Use ::onDidChange instead. Note that ::onDidChange passes its callback different arguments. From 8ceb2e2028edddb84017479371ee80bd64f85e2f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 18:09:00 -0700 Subject: [PATCH 0446/1783] Don't extend Model in 1.0 mode --- src/atom.coffee | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/atom.coffee b/src/atom.coffee index b787764be..463f5a7bf 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -16,11 +16,13 @@ fs = require 'fs-plus' WindowEventHandler = require './window-event-handler' StylesElement = require './styles-element' +SuperClass = if includeDeprecations then Model else Object + # Essential: Atom global for dealing with packages, themes, menus, and the window. # # An instance of this class is always available as the `atom` global. module.exports = -class Atom extends Model +class Atom extends SuperClass @version: 1 # Increment this when the serialization format changes # Load or create the Atom environment in the given mode. @@ -230,7 +232,7 @@ class Atom extends Model @openDevTools() @executeJavaScriptInDevTools('InspectorFrontendAPI.showConsole()') - @emit 'uncaught-error', arguments... + @emit 'uncaught-error', arguments... if includeDeprecations @emitter.emit 'did-throw-error', {message, url, line, column, originalError} @disposables?.dispose() From 488e40e635fc7b86946c518d4b97ea278c196a83 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 18:17:03 -0700 Subject: [PATCH 0447/1783] Add 1.0 preview mode bridge Model class --- src/atom.coffee | 8 +++++--- src/model.coffee | 27 +++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 src/model.coffee diff --git a/src/atom.coffee b/src/atom.coffee index 463f5a7bf..427811162 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -8,7 +8,6 @@ shell = require 'shell' _ = require 'underscore-plus' {deprecate, includeDeprecations} = require 'grim' {CompositeDisposable, Emitter} = require 'event-kit' -{Model} = require 'theorist' fs = require 'fs-plus' {convertStackTrace, convertLine} = require 'coffeestack' @@ -16,13 +15,16 @@ fs = require 'fs-plus' WindowEventHandler = require './window-event-handler' StylesElement = require './styles-element' -SuperClass = if includeDeprecations then Model else Object +if includeDeprecations + {Model} = require 'theorist' +else + Model = require './model' # Essential: Atom global for dealing with packages, themes, menus, and the window. # # An instance of this class is always available as the `atom` global. module.exports = -class Atom extends SuperClass +class Atom extends Model @version: 1 # Increment this when the serialization format changes # Load or create the Atom environment in the given mode. diff --git a/src/model.coffee b/src/model.coffee new file mode 100644 index 000000000..b590082a5 --- /dev/null +++ b/src/model.coffee @@ -0,0 +1,27 @@ +PropertyAccessors = require 'property-accessors' + +nextInstanceId = 1 + +module.exports = +class Model + PropertyAccessors.includeInto(this) + + @resetNextInstanceId: -> nextInstanceId = 1 + + constructor: (params) -> + @assignId(params?.id) + + assignId: (id) -> + @id ?= id ? nextInstanceId++ + + @::advisedAccessor 'id', + set: (id) -> nextInstanceId = id + 1 if id >= nextInstanceId + + destroy: -> + return unless @isAlive() + @alive = false + @destroyed?() + + isAlive: -> @alive + + isDestroyed: -> not @isAlive() From e41a366e081f4db1fac881137207e12aa8d36d2e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 18:19:41 -0700 Subject: [PATCH 0448/1783] Using single Model class require --- src/atom.coffee | 7 +------ src/model.coffee | 5 +++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/atom.coffee b/src/atom.coffee index 427811162..55cb7ee59 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -10,16 +10,11 @@ _ = require 'underscore-plus' {CompositeDisposable, Emitter} = require 'event-kit' fs = require 'fs-plus' {convertStackTrace, convertLine} = require 'coffeestack' - +Model = require './model' {$} = require './space-pen-extensions' WindowEventHandler = require './window-event-handler' StylesElement = require './styles-element' -if includeDeprecations - {Model} = require 'theorist' -else - Model = require './model' - # Essential: Atom global for dealing with packages, themes, menus, and the window. # # An instance of this class is always available as the `atom` global. diff --git a/src/model.coffee b/src/model.coffee index b590082a5..20128b0d2 100644 --- a/src/model.coffee +++ b/src/model.coffee @@ -1,3 +1,8 @@ +Grim = require 'grim' +if Grim.includeDeprecations + module.exports = require('theorist').Model + return + PropertyAccessors = require 'property-accessors' nextInstanceId = 1 From 82c39a5af9e0e6371ba3c8c0e499ecb518d540c9 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 18:28:51 -0700 Subject: [PATCH 0449/1783] Use lighter Model in cursor, selection, and project --- src/cursor.coffee | 2 +- src/project.coffee | 10 +++++----- src/selection.coffee | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/cursor.coffee b/src/cursor.coffee index a930666c3..6bb3f4bae 100644 --- a/src/cursor.coffee +++ b/src/cursor.coffee @@ -1,8 +1,8 @@ {Point, Range} = require 'text-buffer' -{Model} = require 'theorist' {Emitter} = require 'event-kit' _ = require 'underscore-plus' Grim = require 'grim' +Model = require './model' # Extended: The `Cursor` class represents the little blinking line identifying # where text can be inserted. diff --git a/src/project.coffee b/src/project.coffee index 02be678fe..0392bd7ce 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -5,7 +5,6 @@ _ = require 'underscore-plus' fs = require 'fs-plus' Q = require 'q' {includeDeprecations, deprecate} = require 'grim' -{Model} = require 'theorist' {Subscriber} = require 'emissary' {Emitter} = require 'event-kit' DefaultDirectoryProvider = require './default-directory-provider' @@ -13,6 +12,7 @@ Serializable = require 'serializable' TextBuffer = require 'text-buffer' Grim = require 'grim' +Model = require './model' TextEditor = require './text-editor' Task = require './task' GitRepositoryProvider = require './git-repository-provider' @@ -178,7 +178,7 @@ class Project extends Model @addPath(projectPath, emitEvent: false) for projectPath in projectPaths - @emit "path-changed" + @emit "path-changed" if includeDeprecations @emitter.emit 'did-change-paths', projectPaths # Public: Add a path to the project's list of root paths @@ -205,7 +205,7 @@ class Project extends Model @repositories.push(repo ? null) unless options?.emitEvent is false - @emit "path-changed" + @emit "path-changed" if includeDeprecations @emitter.emit 'did-change-paths', @getPaths() # Public: remove a path from the project's list of root paths. @@ -227,7 +227,7 @@ class Project extends Model [removedRepository] = @repositories.splice(indexToRemove, 1) removedDirectory.off() removedRepository?.destroy() unless removedRepository in @repositories - @emit "path-changed" + @emit "path-changed" if includeDeprecations @emitter.emit "did-change-paths", @getPaths() true else @@ -393,7 +393,7 @@ class Project extends Model addBufferAtIndex: (buffer, index, options={}) -> @buffers.splice(index, 0, buffer) @subscribeToBuffer(buffer) - @emit 'buffer-created', buffer + @emit 'buffer-created', buffer if includeDeprecations @emitter.emit 'did-add-buffer', buffer buffer diff --git a/src/selection.coffee b/src/selection.coffee index 2a2d1c98c..af70e234c 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -1,8 +1,8 @@ {Point, Range} = require 'text-buffer' -{Model} = require 'theorist' {pick} = _ = require 'underscore-plus' {Emitter} = require 'event-kit' Grim = require 'grim' +Model = require './model' NonWhitespaceRegExp = /\S/ @@ -27,7 +27,7 @@ class Selection extends Model unless @editor.isDestroyed() @destroyed = true @editor.removeSelection(this) - @emit 'destroyed' + @emit 'destroyed' if Grim.includeDeprecations @emitter.emit 'did-destroy' @emitter.dispose() @@ -732,7 +732,7 @@ class Selection extends Model newScreenRange: @getScreenRange() selection: this - @emit 'screen-range-changed', @getScreenRange() # old event + @emit 'screen-range-changed', @getScreenRange() if Grim.includeDeprecations @emitter.emit 'did-change-range' @editor.selectionRangeChanged(eventObject) From 578bce1aaf8a98ca3121b37c68ecd388c23ce797 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Mar 2015 18:30:36 -0700 Subject: [PATCH 0450/1783] :art: --- src/project.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/project.coffee b/src/project.coffee index 0392bd7ce..63e5576de 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -7,11 +7,11 @@ Q = require 'q' {includeDeprecations, deprecate} = require 'grim' {Subscriber} = require 'emissary' {Emitter} = require 'event-kit' -DefaultDirectoryProvider = require './default-directory-provider' Serializable = require 'serializable' TextBuffer = require 'text-buffer' Grim = require 'grim' +DefaultDirectoryProvider = require './default-directory-provider' Model = require './model' TextEditor = require './text-editor' Task = require './task' From 83b679dcc2f273fba146ecd6990be1fd5e00aff1 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Mar 2015 15:58:38 -0700 Subject: [PATCH 0451/1783] ::subscribe -> CompositeDisposable --- src/tokenized-buffer.coffee | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 303906ada..ff06c66e6 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -1,6 +1,6 @@ _ = require 'underscore-plus' {Model} = require 'theorist' -{Emitter} = require 'event-kit' +{CompositeDisposable, Emitter} = require 'event-kit' {Point, Range} = require 'text-buffer' Serializable = require 'serializable' TokenizedLine = require './tokenized-line' @@ -24,15 +24,19 @@ class TokenizedBuffer extends Model constructor: ({@buffer, @tabLength, @invisibles}) -> @emitter = new Emitter + @disposables = new CompositeDisposable - @subscribe atom.grammars.onDidAddGrammar(@grammarAddedOrUpdated) - @subscribe atom.grammars.onDidUpdateGrammar(@grammarAddedOrUpdated) + @disposables.add atom.grammars.onDidAddGrammar(@grammarAddedOrUpdated) + @disposables.add atom.grammars.onDidUpdateGrammar(@grammarAddedOrUpdated) - @subscribe @buffer.preemptDidChange (e) => @handleBufferChange(e) - @subscribe @buffer.onDidChangePath (@bufferPath) => @reloadGrammar() + @disposables.add @buffer.preemptDidChange (e) => @handleBufferChange(e) + @disposables.add @buffer.onDidChangePath (@bufferPath) => @reloadGrammar() @reloadGrammar() + destroyed: -> + @disposables.dispose() + serializeParams: -> bufferPath: @buffer.getPath() tabLength: @tabLength @@ -64,11 +68,14 @@ class TokenizedBuffer extends Model setGrammar: (grammar, score) -> return if grammar is @grammar - @unsubscribe(@grammar) if @grammar + @grammar = grammar @rootScopeDescriptor = new ScopeDescriptor(scopes: [@grammar.scopeName]) @currentGrammarScore = score ? grammar.getScore(@buffer.getPath(), @buffer.getText()) - @subscribe @grammar.onDidUpdate => @retokenizeLines() + + @grammarUpdateDisposable?.dispose() + @grammarUpdateDisposable = @grammar.onDidUpdate => @retokenizeLines() + @disposables.add(@grammarUpdateDisposable) @configSettings = tabLength: atom.config.get('editor.tabLength', scope: @rootScopeDescriptor) @@ -76,7 +83,7 @@ class TokenizedBuffer extends Model @grammarTabLengthSubscription = atom.config.onDidChange 'editor.tabLength', scope: @rootScopeDescriptor, ({newValue}) => @configSettings.tabLength = newValue @retokenizeLines() - @subscribe @grammarTabLengthSubscription + @disposables.add(@grammarTabLengthSubscription) @retokenizeLines() From 7861e462bece67e4965c996b65d8b879ebd34f70 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Mar 2015 15:59:24 -0700 Subject: [PATCH 0452/1783] Add alive ivar to light Model --- src/model.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/model.coffee b/src/model.coffee index 20128b0d2..bfb854320 100644 --- a/src/model.coffee +++ b/src/model.coffee @@ -13,6 +13,8 @@ class Model @resetNextInstanceId: -> nextInstanceId = 1 + alive: true + constructor: (params) -> @assignId(params?.id) From 3a94376c46706187b90505d7b065d15e32881611 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 2 Apr 2015 15:00:43 -0700 Subject: [PATCH 0453/1783] :arrow_up: event-kit@1.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 02b3c9669..b36c35b0a 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "color": "^0.7.3", "delegato": "^1", "emissary": "^1.3.3", - "event-kit": "^1.0.3", + "event-kit": "^1.1", "first-mate": "^3.0.1", "fs-plus": "^2.6", "fstream": "0.1.24", From fe1bb240753cee00acb7fa792f115b2747eb206f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 2 Apr 2015 15:31:31 -0700 Subject: [PATCH 0454/1783] :arrow_up: pathwatcher@4.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b36c35b0a..b6abacc20 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "nslog": "^2.0.0", "oniguruma": "^4.1", "optimist": "0.4.0", - "pathwatcher": "^4.3.1", + "pathwatcher": "^4.4", "property-accessors": "^1.1.3", "q": "^1.1.2", "random-words": "0.0.1", From ccd57bd66689db897a97353bf1b220f5aa78f1fb Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 2 Apr 2015 15:35:40 -0700 Subject: [PATCH 0455/1783] :arrow_up: atom-keymap@5.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b6abacc20..2e4b6c9d2 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "atomShellVersion": "0.22.3", "dependencies": { "async": "0.2.6", - "atom-keymap": "^5", + "atom-keymap": "^5.1", "atom-space-pen-views": "^2.0.4", "babel-core": "^4.0.2", "bootstrap": "git+https://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372", From 5e090669f91d4617e08dd55bcb86e7b3777a3e46 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 2 Apr 2015 15:38:49 -0700 Subject: [PATCH 0456/1783] :arrow_up: scoped-property-store@0.17 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2e4b6c9d2..0e700271c 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "reactionary-atom-fork": "^1.0.0", "runas": "2.0.0", "scandal": "2.0.0", - "scoped-property-store": "^0.16.2", + "scoped-property-store": "^0.17.0", "scrollbar-style": "^2.0.0", "season": "^5.1.4", "semver": "~4.2", From 1f8d7a05af90668d097bd245e05cb11820f4a054 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 2 Apr 2015 15:50:48 -0700 Subject: [PATCH 0457/1783] :arrow_up: first-mate@3.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0e700271c..093afa9a5 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "delegato": "^1", "emissary": "^1.3.3", "event-kit": "^1.1", - "first-mate": "^3.0.1", + "first-mate": "^3.1", "fs-plus": "^2.6", "fstream": "0.1.24", "fuzzaldrin": "^2.1", From 2a2cf17fc1ac81c95d8a44651135c32c87099c8c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 2 Apr 2015 17:04:16 -0700 Subject: [PATCH 0458/1783] :arrow_up: text-buffer@5.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 093afa9a5..8b575680c 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "space-pen": "3.8.2", "stacktrace-parser": "0.1.1", "temp": "0.8.1", - "text-buffer": "^5.1.1", + "text-buffer": "^5.2", "theorist": "^1.0.2", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6" From 7d592c8b7851b4e94a79d941b37e893a494d1161 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 2 Apr 2015 17:08:28 -0700 Subject: [PATCH 0459/1783] includeDeprecations -> includeDeprecatedAPIs --- exports/atom.coffee | 6 +++--- src/atom.coffee | 14 +++++++------- src/config.coffee | 14 +++++++------- src/context-menu-manager.coffee | 2 +- src/cursor.coffee | 10 +++++----- src/decoration.coffee | 8 ++++---- src/deserializer-manager.coffee | 2 +- src/display-buffer.coffee | 16 ++++++++-------- src/git-repository.coffee | 8 ++++---- src/grammar-registry.coffee | 4 ++-- src/marker.coffee | 8 ++++---- src/model.coffee | 2 +- src/package-manager.coffee | 6 +++--- src/package.coffee | 18 +++++++++--------- src/pane-container-element.coffee | 4 ++-- src/pane-element.coffee | 4 ++-- src/pane.coffee | 4 ++-- src/project.coffee | 14 +++++++------- src/selection.coffee | 6 +++--- src/styles-element.coffee | 6 +++--- src/text-editor-component.coffee | 4 ++-- src/text-editor-element.coffee | 4 ++-- src/text-editor.coffee | 6 +++--- src/tokenized-buffer.coffee | 12 ++++++------ src/workspace-element.coffee | 6 +++--- src/workspace.coffee | 14 +++++++------- static/index.js | 2 +- 27 files changed, 102 insertions(+), 102 deletions(-) diff --git a/exports/atom.coffee b/exports/atom.coffee index 6b9243098..0d4583c5d 100644 --- a/exports/atom.coffee +++ b/exports/atom.coffee @@ -1,7 +1,7 @@ TextBuffer = require 'text-buffer' {Point, Range} = TextBuffer {Emitter, Disposable, CompositeDisposable} = require 'event-kit' -{includeDeprecations, deprecate} = require 'grim' +{includeDeprecatedAPIs, deprecate} = require 'grim' module.exports = BufferedNodeProcess: require '../src/buffered-node-process' @@ -21,7 +21,7 @@ unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE module.exports.Task = require '../src/task' module.exports.TextEditor = require '../src/text-editor' - if includeDeprecations + if includeDeprecatedAPIs {$, $$, $$$, View} = require '../src/space-pen-extensions' Object.defineProperty module.exports, 'Workspace', get: -> @@ -125,7 +125,7 @@ unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE deprecate "Please require `reactionary-atom-fork` instead: `Reactionary = require 'reactionary-atom-fork'`. Add `\"reactionary-atom-fork\": \"^0.9\"` to your package dependencies." require 'reactionary-atom-fork' -if includeDeprecations +if includeDeprecatedAPIs Object.defineProperty module.exports, 'Git', get: -> deprecate "Please require `GitRepository` instead of `Git`: `{GitRepository} = require 'atom'`" module.exports.GitRepository diff --git a/src/atom.coffee b/src/atom.coffee index 55cb7ee59..1710edd98 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -6,7 +6,7 @@ remote = require 'remote' shell = require 'shell' _ = require 'underscore-plus' -{deprecate, includeDeprecations} = require 'grim' +{deprecate, includeDeprecatedAPIs} = require 'grim' {CompositeDisposable, Emitter} = require 'event-kit' fs = require 'fs-plus' {convertStackTrace, convertLine} = require 'coffeestack' @@ -33,7 +33,7 @@ class Atom extends Model atom = @deserialize(@loadState(mode)) ? new this({mode, @version}) atom.deserializeTimings.atom = Date.now() - startTime - if includeDeprecations + if includeDeprecatedAPIs workspaceViewDeprecationMessage = """ atom.workspaceView is no longer available. In most cases you will not need the view. See the Workspace docs for @@ -229,7 +229,7 @@ class Atom extends Model @openDevTools() @executeJavaScriptInDevTools('InspectorFrontendAPI.showConsole()') - @emit 'uncaught-error', arguments... if includeDeprecations + @emit 'uncaught-error', arguments... if includeDeprecatedAPIs @emitter.emit 'did-throw-error', {message, url, line, column, originalError} @disposables?.dispose() @@ -267,7 +267,7 @@ class Atom extends Model @config = new Config({configDirPath, resourcePath}) @keymaps = new KeymapManager({configDirPath, resourcePath}) - if includeDeprecations + if includeDeprecatedAPIs @keymap = @keymaps # Deprecated @keymaps.subscribeToFileReadFailure() @@ -285,7 +285,7 @@ class Atom extends Model @grammars = @deserializers.deserialize(@state.grammars ? @state.syntax) ? new GrammarRegistry() - if includeDeprecations + if includeDeprecatedAPIs Object.defineProperty this, 'syntax', get: -> deprecate "The atom.syntax global is deprecated. Use atom.grammars instead." @grammars @@ -721,7 +721,7 @@ class Atom extends Model deserializeWorkspaceView: -> Workspace = require './workspace' - if includeDeprecations + if includeDeprecatedAPIs WorkspaceView = require './workspace-view' startTime = Date.now() @@ -843,7 +843,7 @@ class Atom extends Model ipc.send('call-window-method', 'setAutoHideMenuBar', autoHide) ipc.send('call-window-method', 'setMenuBarVisibility', !autoHide) -if includeDeprecations +if includeDeprecatedAPIs # Deprecated: Callers should be converted to use atom.deserializers Atom::registerRepresentationClass = -> deprecate("Callers should be converted to use atom.deserializers") diff --git a/src/config.coffee b/src/config.coffee index 3d0e363ad..f7db867ed 100644 --- a/src/config.coffee +++ b/src/config.coffee @@ -371,7 +371,7 @@ class Config observe: -> if arguments.length is 2 [keyPath, callback] = arguments - else if Grim.includeDeprecations and arguments.length is 3 and (_.isArray(arguments[0]) or arguments[0] instanceof ScopeDescriptor) + else if Grim.includeDeprecatedAPIs and arguments.length is 3 and (_.isArray(arguments[0]) or arguments[0] instanceof ScopeDescriptor) Grim.deprecate """ Passing a scope descriptor as the first argument to Config::observe is deprecated. Pass a `scope` in an options hash as the third argument instead. @@ -380,7 +380,7 @@ class Config else if arguments.length is 3 and (_.isString(arguments[0]) and _.isObject(arguments[1])) [keyPath, options, callback] = arguments scopeDescriptor = options.scope - if Grim.includeDeprecations and options.callNow? + if Grim.includeDeprecatedAPIs and options.callNow? Grim.deprecate """ Config::observe no longer takes a `callNow` option. Use ::onDidChange instead. Note that ::onDidChange passes its callback different arguments. @@ -419,7 +419,7 @@ class Config [callback] = arguments else if arguments.length is 2 [keyPath, callback] = arguments - else if Grim.includeDeprecations and _.isArray(arguments[0]) or arguments[0] instanceof ScopeDescriptor + else if Grim.includeDeprecatedAPIs and _.isArray(arguments[0]) or arguments[0] instanceof ScopeDescriptor Grim.deprecate """ Passing a scope descriptor as the first argument to Config::onDidChange is deprecated. Pass a `scope` in an options hash as the third argument instead. @@ -498,7 +498,7 @@ class Config if typeof arguments[0] is 'string' or not arguments[0]? [keyPath, options] = arguments {scope} = options - else if Grim.includeDeprecations + else if Grim.includeDeprecatedAPIs Grim.deprecate """ Passing a scope descriptor as the first argument to Config::get is deprecated. Pass a `scope` in an options hash as the final argument instead. @@ -578,7 +578,7 @@ class Config # * `true` if the value was set. # * `false` if the value was not able to be coerced to the type specified in the setting's schema. set: -> - if Grim.includeDeprecations and arguments[0]?[0] is '.' + if Grim.includeDeprecatedAPIs and arguments[0]?[0] is '.' Grim.deprecate """ Passing a scope selector as the first argument to Config::set is deprecated. Pass a `scopeSelector` in an options hash as the final argument instead. @@ -617,7 +617,7 @@ class Config # * `scopeSelector` (optional) {String}. See {::set} # * `source` (optional) {String}. See {::set} unset: (keyPath, options) -> - if Grim.includeDeprecations and typeof options is 'string' + if Grim.includeDeprecatedAPIs and typeof options is 'string' Grim.deprecate """ Passing a scope selector as the first argument to Config::unset is deprecated. Pass a `scopeSelector` in an options hash as the second argument instead. @@ -1146,7 +1146,7 @@ withoutEmptyObjects = (object) -> resultObject = object resultObject -if Grim.includeDeprecations +if Grim.includeDeprecatedAPIs Config::restoreDefault = (scopeSelector, keyPath) -> Grim.deprecate("Use ::unset instead.") @unset(scopeSelector, keyPath) diff --git a/src/context-menu-manager.coffee b/src/context-menu-manager.coffee index 4565c8b55..00b635251 100644 --- a/src/context-menu-manager.coffee +++ b/src/context-menu-manager.coffee @@ -99,7 +99,7 @@ class ContextMenuManager # with the following argument: # * `event` The click event that deployed the context menu. add: (itemsBySelector) -> - if Grim.includeDeprecations + if Grim.includeDeprecatedAPIs # Detect deprecated file path as first argument if itemsBySelector? and typeof itemsBySelector isnt 'object' Grim.deprecate """ diff --git a/src/cursor.coffee b/src/cursor.coffee index 6bb3f4bae..3ed9939ad 100644 --- a/src/cursor.coffee +++ b/src/cursor.coffee @@ -39,13 +39,13 @@ class Cursor extends Model textChanged: textChanged cursor: this - @emit 'moved', movedEvent if Grim.includeDeprecations + @emit 'moved', movedEvent if Grim.includeDeprecatedAPIs @emitter.emit 'did-change-position', movedEvent @editor.cursorMoved(movedEvent) @marker.onDidDestroy => @destroyed = true @editor.removeCursor(this) - @emit 'destroyed' if Grim.includeDeprecations + @emit 'destroyed' if Grim.includeDeprecatedAPIs @emitter.emit 'did-destroy' @emitter.dispose() @@ -89,7 +89,7 @@ class Cursor extends Model @emitter.on 'did-change-visibility', callback on: (eventName) -> - return unless Grim.includeDeprecations + return unless Grim.includeDeprecatedAPIs switch eventName when 'moved' @@ -588,7 +588,7 @@ class Cursor extends Model setVisible: (visible) -> if @visible != visible @visible = visible - @emit 'visibility-changed', @visible if Grim.includeDeprecations + @emit 'visibility-changed', @visible if Grim.includeDeprecatedAPIs @emitter.emit 'did-change-visibility', @visible # Public: Returns the visibility of the cursor. @@ -682,7 +682,7 @@ class Cursor extends Model stop() position -if Grim.includeDeprecations +if Grim.includeDeprecatedAPIs Cursor::getScopes = -> Grim.deprecate 'Use Cursor::getScopeDescriptor() instead' @getScopeDescriptor().getScopesArray() diff --git a/src/decoration.coffee b/src/decoration.coffee index a556a3a3c..8654cf39a 100644 --- a/src/decoration.coffee +++ b/src/decoration.coffee @@ -65,7 +65,7 @@ class Decoration @markerDestroyDisposable.dispose() @markerDestroyDisposable = null @destroyed = true - @emit 'destroyed' if Grim.includeDeprecations + @emit 'destroyed' if Grim.includeDeprecatedAPIs @emitter.emit 'did-destroy' @emitter.dispose() @@ -136,7 +136,7 @@ class Decoration oldProperties = @properties @properties = newProperties @properties.id = @id - @emit 'updated', {oldParams: oldProperties, newParams: newProperties} if Grim.includeDeprecations + @emit 'updated', {oldParams: oldProperties, newParams: newProperties} if Grim.includeDeprecatedAPIs @emitter.emit 'did-change-properties', {oldProperties, newProperties} ### @@ -156,14 +156,14 @@ class Decoration flashObject = {class: klass, duration} @flashQueue ?= [] @flashQueue.push(flashObject) - @emit 'flash' if Grim.includeDeprecations + @emit 'flash' if Grim.includeDeprecatedAPIs @emitter.emit 'did-flash' consumeNextFlash: -> return @flashQueue.shift() if @flashQueue?.length > 0 null -if Grim.includeDeprecations +if Grim.includeDeprecatedAPIs EmitterMixin = require('emissary').Emitter EmitterMixin.includeInto(Decoration) diff --git a/src/deserializer-manager.coffee b/src/deserializer-manager.coffee index 4efc71ec5..fab84539c 100644 --- a/src/deserializer-manager.coffee +++ b/src/deserializer-manager.coffee @@ -61,7 +61,7 @@ class DeserializerManager name = state.get?('deserializer') ? state.deserializer @deserializers[name] -if Grim.includeDeprecations +if Grim.includeDeprecatedAPIs DeserializerManager::remove = (classes...) -> Grim.deprecate("Call .dispose() on the Disposable return from ::add instead") delete @deserializers[name] for {name} in classes diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index 12b839143..a8b24086a 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -155,7 +155,7 @@ class DisplayBuffer extends Model if refreshMarkers @pauseMarkerChangeEvents() @refreshMarkerScreenPositions() - @emit 'changed', eventProperties if Grim.includeDeprecations + @emit 'changed', eventProperties if Grim.includeDeprecatedAPIs @emitter.emit 'did-change', eventProperties @resumeMarkerChangeEvents() @@ -309,7 +309,7 @@ class DisplayBuffer extends Model characterWidthsChanged: -> @computeScrollWidth() - @emit 'character-widths-changed', @scopedCharacterWidthsChangeCount if Grim.includeDeprecations + @emit 'character-widths-changed', @scopedCharacterWidthsChangeCount if Grim.includeDeprecatedAPIs @emitter.emit 'did-change-character-widths', @scopedCharacterWidthsChangeCount clearScopedCharWidths: -> @@ -427,7 +427,7 @@ class DisplayBuffer extends Model @softWrapped = softWrapped @updateWrappedScreenLines() softWrapped = @isSoftWrapped() - @emit 'soft-wrap-changed', softWrapped if Grim.includeDeprecations + @emit 'soft-wrap-changed', softWrapped if Grim.includeDeprecatedAPIs @emitter.emit 'did-change-soft-wrapped', softWrapped softWrapped else @@ -911,7 +911,7 @@ class DisplayBuffer extends Model @decorationsByMarkerId[marker.id] ?= [] @decorationsByMarkerId[marker.id].push(decoration) @decorationsById[decoration.id] = decoration - @emit 'decoration-added', decoration if Grim.includeDeprecations + @emit 'decoration-added', decoration if Grim.includeDeprecatedAPIs @emitter.emit 'did-add-decoration', decoration decoration @@ -923,7 +923,7 @@ class DisplayBuffer extends Model if index > -1 decorations.splice(index, 1) delete @decorationsById[decoration.id] - @emit 'decoration-removed', decoration if Grim.includeDeprecations + @emit 'decoration-removed', decoration if Grim.includeDeprecatedAPIs @emitter.emit 'did-remove-decoration', decoration delete @decorationsByMarkerId[marker.id] if decorations.length is 0 @@ -1075,7 +1075,7 @@ class DisplayBuffer extends Model resumeMarkerChangeEvents: -> marker.resumeChangeEvents() for marker in @getMarkers() - @emit 'markers-updated' if Grim.includeDeprecations + @emit 'markers-updated' if Grim.includeDeprecatedAPIs @emitter.emit 'did-update-markers' refreshMarkerScreenPositions: -> @@ -1217,7 +1217,7 @@ class DisplayBuffer extends Model if marker = @getMarker(textBufferMarker.id) # The marker might have been removed in some other handler called before # this one. Only emit when the marker still exists. - @emit 'marker-created', marker if Grim.includeDeprecations + @emit 'marker-created', marker if Grim.includeDeprecatedAPIs @emitter.emit 'did-create-marker', marker createFoldForMarker: (marker) -> @@ -1227,7 +1227,7 @@ class DisplayBuffer extends Model foldForMarker: (marker) -> @foldsByMarkerId[marker.id] -if Grim.includeDeprecations +if Grim.includeDeprecatedAPIs EmitterMixin = require('emissary').Emitter DisplayBuffer::on = (eventName) -> diff --git a/src/git-repository.coffee b/src/git-repository.coffee index 0ae4abf3a..145b2bf96 100644 --- a/src/git-repository.coffee +++ b/src/git-repository.coffee @@ -4,7 +4,7 @@ _ = require 'underscore-plus' {Emitter, Disposable, CompositeDisposable} = require 'event-kit' fs = require 'fs-plus' GitUtils = require 'git-utils' -{includeDeprecations, deprecate} = require 'grim' +{includeDeprecatedAPIs, deprecate} = require 'grim' Task = require './task' @@ -313,7 +313,7 @@ class GitRepository else delete @statuses[relativePath] if currentPathStatus isnt pathStatus - @emit 'status-changed', path, pathStatus if includeDeprecations + @emit 'status-changed', path, pathStatus if includeDeprecatedAPIs @emitter.emit 'did-change-status', {path, pathStatus} pathStatus @@ -474,10 +474,10 @@ class GitRepository submoduleRepo.upstream = submodules[submodulePath]?.upstream ? {ahead: 0, behind: 0} unless statusesUnchanged - @emit 'statuses-changed' if includeDeprecations + @emit 'statuses-changed' if includeDeprecatedAPIs @emitter.emit 'did-change-statuses' -if includeDeprecations +if includeDeprecatedAPIs EmitterMixin = require('emissary').Emitter EmitterMixin.includeInto(GitRepository) diff --git a/src/grammar-registry.coffee b/src/grammar-registry.coffee index b95b561da..b43e095d9 100644 --- a/src/grammar-registry.coffee +++ b/src/grammar-registry.coffee @@ -1,5 +1,5 @@ {Emitter} = require 'event-kit' -{includeDeprecations, deprecate} = require 'grim' +{includeDeprecatedAPIs, deprecate} = require 'grim' FirstMate = require 'first-mate' Token = require './token' @@ -41,7 +41,7 @@ class GrammarRegistry extends FirstMate.GrammarRegistry @off() if includeDeprecations @emitter = new Emitter -if includeDeprecations +if includeDeprecatedAPIs PropertyAccessors = require 'property-accessors' PropertyAccessors.includeInto(GrammarRegistry) diff --git a/src/marker.coffee b/src/marker.coffee index c177b792e..5d1e35570 100644 --- a/src/marker.coffee +++ b/src/marker.coffee @@ -319,7 +319,7 @@ class Marker destroyed: -> delete @displayBuffer.markers[@id] - @emit 'destroyed' if Grim.includeDeprecations + @emit 'destroyed' if Grim.includeDeprecatedAPIs @emitter.emit 'did-destroy' @emitter.dispose() @@ -350,7 +350,7 @@ class Marker if @deferredChangeEvents? @deferredChangeEvents.push(changeEvent) else - @emit 'changed', changeEvent if Grim.includeDeprecations + @emit 'changed', changeEvent if Grim.includeDeprecatedAPIs @emitter.emit 'did-change', changeEvent @oldHeadBufferPosition = newHeadBufferPosition @@ -367,14 +367,14 @@ class Marker @deferredChangeEvents = null for event in deferredChangeEvents - @emit 'changed', event if Grim.includeDeprecations + @emit 'changed', event if Grim.includeDeprecatedAPIs @emitter.emit 'did-change', event return getPixelRange: -> @displayBuffer.pixelRangeForScreenRange(@getScreenRange(), false) -if Grim.includeDeprecations +if Grim.includeDeprecatedAPIs EmitterMixin = require('emissary').Emitter EmitterMixin.includeInto(Marker) diff --git a/src/model.coffee b/src/model.coffee index bfb854320..7b38c0eef 100644 --- a/src/model.coffee +++ b/src/model.coffee @@ -1,5 +1,5 @@ Grim = require 'grim' -if Grim.includeDeprecations +if Grim.includeDeprecatedAPIs module.exports = require('theorist').Model return diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 7399eaab1..bc4443418 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -308,7 +308,7 @@ class PackageManager packagePaths = packagePaths.filter (packagePath) => not @isPackageDisabled(path.basename(packagePath)) packagePaths = _.uniq packagePaths, (packagePath) -> path.basename(packagePath) @loadPackage(packagePath) for packagePath in packagePaths - @emit 'loaded' if Grim.includeDeprecations + @emit 'loaded' if Grim.includeDeprecatedAPIs @emitter.emit 'did-load-initial-packages' loadPackage: (nameOrPath) -> @@ -357,7 +357,7 @@ class PackageManager packages = @getLoadedPackagesForTypes(types) promises = promises.concat(activator.activatePackages(packages)) Q.all(promises).then => - @emit 'activated' if Grim.includeDeprecations + @emit 'activated' if Grim.includeDeprecatedAPIs @emitter.emit 'did-activate-initial-packages' # another type of package manager can handle other package types. @@ -410,7 +410,7 @@ class PackageManager message = "Failed to load the #{path.basename(packagePath)} package" atom.notifications.addError(message, {stack, detail, dismissable: true}) -if Grim.includeDeprecations +if Grim.includeDeprecatedAPIs PackageManager::onDidLoadAll = (callback) -> Grim.deprecate("Use `::onDidLoadInitialPackages` instead.") @onDidLoadInitialPackages(callback) diff --git a/src/package.coffee b/src/package.coffee index f9d3ac576..dd6701527 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -6,7 +6,7 @@ CSON = require 'season' fs = require 'fs-plus' {Emitter, CompositeDisposable} = require 'event-kit' Q = require 'q' -{includeDeprecations, deprecate} = require 'grim' +{includeDeprecatedAPIs, deprecate} = require 'grim' ModuleCache = require './module-cache' ScopedProperties = require './scoped-properties' @@ -40,11 +40,11 @@ class Package metadata ?= {} metadata.name = packageName - if includeDeprecations and metadata.stylesheetMain? + if includeDeprecatedAPIs and metadata.stylesheetMain? deprecate("Use the `mainStyleSheet` key instead of `stylesheetMain` in the `package.json` of `#{packageName}`", {packageName}) metadata.mainStyleSheet = metadata.stylesheetMain - if includeDeprecations and metadata.stylesheets? + if includeDeprecatedAPIs and metadata.stylesheets? deprecate("Use the `styleSheets` key instead of `stylesheets` in the `package.json` of `#{packageName}`", {packageName}) metadata.styleSheets = metadata.stylesheets @@ -163,7 +163,7 @@ class Package if @mainModule? if @mainModule.config? and typeof @mainModule.config is 'object' atom.config.setSchema @name, {type: 'object', properties: @mainModule.config} - else if includeDeprecations and @mainModule.configDefaults? and typeof @mainModule.configDefaults is 'object' + else if includeDeprecatedAPIs and @mainModule.configDefaults? and typeof @mainModule.configDefaults is 'object' deprecate """Use a config schema instead. See the configuration section of https://atom.io/docs/latest/hacking-atom-package-word-count and https://atom.io/docs/api/latest/Config for more details""" @@ -257,7 +257,7 @@ class Package [stylesheetPath, atom.themes.loadStylesheet(stylesheetPath, true)] getStylesheetsPath: -> - if includeDeprecations and fs.isDirectorySync(path.join(@path, 'stylesheets')) + if includeDeprecatedAPIs and fs.isDirectorySync(path.join(@path, 'stylesheets')) deprecate("Store package style sheets in the `styles/` directory instead of `stylesheets/` in the `#{@name}` package", packageName: @name) path.join(@path, 'stylesheets') else @@ -328,7 +328,7 @@ class Package deferred = Q.defer() - if includeDeprecations and fs.isDirectorySync(path.join(@path, 'scoped-properties')) + if includeDeprecatedAPIs and fs.isDirectorySync(path.join(@path, 'scoped-properties')) settingsDirPath = path.join(@path, 'scoped-properties') deprecate("Store package settings files in the `settings/` directory instead of `scoped-properties/`", packageName: @name) else @@ -356,7 +356,7 @@ class Package @mainModule?.deactivate?() catch e console.error "Error deactivating package '#{@name}'", e.stack - @emit 'deactivated' if includeDeprecations + @emit 'deactivated' if includeDeprecatedAPIs @emitter.emit 'did-deactivate' deactivateConfig: -> @@ -456,7 +456,7 @@ class Package else if _.isArray(commands) @activationCommands[selector].push(commands...) - if includeDeprecations and @metadata.activationEvents? + if includeDeprecatedAPIs and @metadata.activationEvents? deprecate """ Use `activationCommands` instead of `activationEvents` in your package.json Commands should be grouped by selector as follows: @@ -575,7 +575,7 @@ class Package atom.notifications.addFatalError(message, {stack, detail, dismissable: true}) -if includeDeprecations +if includeDeprecatedAPIs EmitterMixin = require('emissary').Emitter EmitterMixin.includeInto(Package) diff --git a/src/pane-container-element.coffee b/src/pane-container-element.coffee index 55d527971..94b008255 100644 --- a/src/pane-container-element.coffee +++ b/src/pane-container-element.coffee @@ -10,13 +10,13 @@ class PaneContainerElement extends HTMLElement @subscriptions = new CompositeDisposable @classList.add 'panes' - if Grim.includeDeprecations + if Grim.includeDeprecatedAPIs PaneContainerView ?= require './pane-container-view' @__spacePenView = new PaneContainerView(this) initialize: (@model) -> @subscriptions.add @model.observeRoot(@rootChanged.bind(this)) - @__spacePenView.setModel(@model) if Grim.includeDeprecations + @__spacePenView.setModel(@model) if Grim.includeDeprecatedAPIs this rootChanged: (root) -> diff --git a/src/pane-element.coffee b/src/pane-element.coffee index f050567b2..f5bfc18bd 100644 --- a/src/pane-element.coffee +++ b/src/pane-element.coffee @@ -13,7 +13,7 @@ class PaneElement extends HTMLElement @initializeContent() @subscribeToDOMEvents() - @createSpacePenShim() if Grim.includeDeprecations + @createSpacePenShim() if Grim.includeDeprecatedAPIs attachedCallback: -> @attached = true @@ -51,7 +51,7 @@ class PaneElement extends HTMLElement @subscriptions.add @model.observeActiveItem(@activeItemChanged.bind(this)) @subscriptions.add @model.onDidRemoveItem(@itemRemoved.bind(this)) @subscriptions.add @model.onDidDestroy(@paneDestroyed.bind(this)) - @__spacePenView.setModel(@model) if Grim.includeDeprecations + @__spacePenView.setModel(@model) if Grim.includeDeprecatedAPIs this getModel: -> @model diff --git a/src/pane.coffee b/src/pane.coffee index 07e621e46..6d2aa5154 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -41,7 +41,7 @@ class Pane extends Model # Called by the Serializable mixin during serialization. serializeParams: -> - if Grim.includeDeprecations and typeof @activeItem?.getURI is 'function' + if Grim.includeDeprecatedAPIs and typeof @activeItem?.getURI is 'function' activeItemURI = @activeItem.getURI() else if typeof @activeItem?.getUri is 'function' activeItemURI = @activeItem.getUri() @@ -660,7 +660,7 @@ class Pane extends Model else throw error -if Grim.includeDeprecations +if Grim.includeDeprecatedAPIs Pane::on = (eventName) -> switch eventName when 'activated' diff --git a/src/project.coffee b/src/project.coffee index 63e5576de..b34d301b6 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -4,7 +4,7 @@ url = require 'url' _ = require 'underscore-plus' fs = require 'fs-plus' Q = require 'q' -{includeDeprecations, deprecate} = require 'grim' +{includeDeprecatedAPIs, deprecate} = require 'grim' {Subscriber} = require 'emissary' {Emitter} = require 'event-kit' Serializable = require 'serializable' @@ -67,7 +67,7 @@ class Project extends Model @subscribeToBuffer(buffer) for buffer in @buffers - if Grim.includeDeprecations and path? + if Grim.includeDeprecatedAPIs and path? Grim.deprecate("Pass 'paths' array instead of 'path' to project constructor") paths ?= _.compact([path]) @@ -178,7 +178,7 @@ class Project extends Model @addPath(projectPath, emitEvent: false) for projectPath in projectPaths - @emit "path-changed" if includeDeprecations + @emit "path-changed" if includeDeprecatedAPIs @emitter.emit 'did-change-paths', projectPaths # Public: Add a path to the project's list of root paths @@ -205,7 +205,7 @@ class Project extends Model @repositories.push(repo ? null) unless options?.emitEvent is false - @emit "path-changed" if includeDeprecations + @emit "path-changed" if includeDeprecatedAPIs @emitter.emit 'did-change-paths', @getPaths() # Public: remove a path from the project's list of root paths. @@ -227,7 +227,7 @@ class Project extends Model [removedRepository] = @repositories.splice(indexToRemove, 1) removedDirectory.off() removedRepository?.destroy() unless removedRepository in @repositories - @emit "path-changed" if includeDeprecations + @emit "path-changed" if includeDeprecatedAPIs @emitter.emit "did-change-paths", @getPaths() true else @@ -393,7 +393,7 @@ class Project extends Model addBufferAtIndex: (buffer, index, options={}) -> @buffers.splice(index, 0, buffer) @subscribeToBuffer(buffer) - @emit 'buffer-created', buffer if includeDeprecations + @emit 'buffer-created', buffer if includeDeprecatedAPIs @emitter.emit 'did-add-buffer', buffer buffer @@ -433,7 +433,7 @@ class Project extends Model detail: error.message dismissable: true -if includeDeprecations +if includeDeprecatedAPIs Project.pathForRepositoryUrl = (repoUrl) -> deprecate '::pathForRepositoryUrl will be removed. Please remove from your code.' [repoName] = url.parse(repoUrl).path.split('/')[-1..] diff --git a/src/selection.coffee b/src/selection.coffee index af70e234c..91f942524 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -27,7 +27,7 @@ class Selection extends Model unless @editor.isDestroyed() @destroyed = true @editor.removeSelection(this) - @emit 'destroyed' if Grim.includeDeprecations + @emit 'destroyed' if Grim.includeDeprecatedAPIs @emitter.emit 'did-destroy' @emitter.dispose() @@ -732,7 +732,7 @@ class Selection extends Model newScreenRange: @getScreenRange() selection: this - @emit 'screen-range-changed', @getScreenRange() if Grim.includeDeprecations + @emit 'screen-range-changed', @getScreenRange() if Grim.includeDeprecatedAPIs @emitter.emit 'did-change-range' @editor.selectionRangeChanged(eventObject) @@ -768,7 +768,7 @@ class Selection extends Model if goalScreenRange = @marker.getProperties().goalScreenRange Range.fromObject(goalScreenRange) -if Grim.includeDeprecations +if Grim.includeDeprecatedAPIs Selection::on = (eventName) -> switch eventName when 'screen-range-changed' diff --git a/src/styles-element.coffee b/src/styles-element.coffee index eaf7c53c8..74ebd23ba 100644 --- a/src/styles-element.coffee +++ b/src/styles-element.coffee @@ -1,5 +1,5 @@ {Emitter, CompositeDisposable} = require 'event-kit' -{includeDeprecations} = require 'grim' +{includeDeprecatedAPIs} = require 'grim' class StylesElement extends HTMLElement subscriptions: null @@ -19,7 +19,7 @@ class StylesElement extends HTMLElement @styleElementClonesByOriginalElement = new WeakMap attachedCallback: -> - if includeDeprecations and @context is 'atom-text-editor' + if includeDeprecatedAPIs and @context is 'atom-text-editor' for styleElement in @children @upgradeDeprecatedSelectors(styleElement) @initialize() @@ -67,7 +67,7 @@ class StylesElement extends HTMLElement @insertBefore(styleElementClone, insertBefore) - if includeDeprecations and @context is 'atom-text-editor' + if includeDeprecatedAPIs and @context is 'atom-text-editor' @upgradeDeprecatedSelectors(styleElementClone) @emitter.emit 'did-add-style-element', styleElementClone diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index b57920952..c001c2252 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -152,7 +152,7 @@ class TextEditorComponent if @editor.isAlive() @updateParentViewFocusedClassIfNeeded() @updateParentViewMiniClass() - if grim.includeDeprecations + if grim.includeDeprecatedAPIs @hostElement.__spacePenView.trigger 'cursor:moved' if cursorMoved @hostElement.__spacePenView.trigger 'selection:changed' if selectionChanged @hostElement.__spacePenView.trigger 'editor:display-updated' @@ -781,7 +781,7 @@ class TextEditorComponent @hostElement.classList.toggle('mini', @editor.isMini()) @rootElement.classList.toggle('mini', @editor.isMini()) -if grim.includeDeprecations +if grim.includeDeprecatedAPIs # Deprecated TextEditorComponent::setInvisibles = (invisibles={}) -> grim.deprecate "Use config.set('editor.invisibles', invisibles) instead" diff --git a/src/text-editor-element.coffee b/src/text-editor-element.coffee index 5822f533c..4a7a11147 100644 --- a/src/text-editor-element.coffee +++ b/src/text-editor-element.coffee @@ -21,7 +21,7 @@ class TextEditorElement extends HTMLElement createdCallback: -> @emitter = new Emitter @initializeContent() - @createSpacePenShim() if Grim.includeDeprecations + @createSpacePenShim() if Grim.includeDeprecatedAPIs @addEventListener 'focus', @focused.bind(this) @addEventListener 'blur', @blurred.bind(this) @@ -87,7 +87,7 @@ class TextEditorElement extends HTMLElement @model.onDidChangeGrammar => @addGrammarScopeAttribute() @model.onDidChangeEncoding => @addEncodingAttribute() @model.onDidDestroy => @unmountComponent() - @__spacePenView.setModel(@model) if Grim.includeDeprecations + @__spacePenView.setModel(@model) if Grim.includeDeprecatedAPIs @model getModel: -> diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 1821a8a52..1f917b6a2 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -2,7 +2,7 @@ _ = require 'underscore-plus' path = require 'path' Serializable = require 'serializable' Delegator = require 'delegato' -{includeDeprecations, deprecate} = require 'grim' +{includeDeprecatedAPIs, deprecate} = require 'grim' {Model} = require 'theorist' EmitterMixin = require('emissary').Emitter {CompositeDisposable, Emitter} = require 'event-kit' @@ -1252,7 +1252,7 @@ class TextEditor extends Model # # Returns a {Decoration} object decorateMarker: (marker, decorationParams) -> - if includeDeprecations and decorationParams.type is 'gutter' + if includeDeprecatedAPIs and decorationParams.type is 'gutter' deprecate("Decorations of `type: 'gutter'` have been renamed to `type: 'line-number'`.") decorationParams.type = 'line-number' @displayBuffer.decorateMarker(marker, decorationParams) @@ -2835,7 +2835,7 @@ class TextEditor extends Model logScreenLines: (start, end) -> @displayBuffer.logLines(start, end) -if includeDeprecations +if includeDeprecatedAPIs TextEditor::getViewClass = -> require './text-editor-view' diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index ff06c66e6..bfc563d93 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -87,7 +87,7 @@ class TokenizedBuffer extends Model @retokenizeLines() - @emit 'grammar-changed', grammar if Grim.includeDeprecations + @emit 'grammar-changed', grammar if Grim.includeDeprecatedAPIs @emitter.emit 'did-change-grammar', grammar reloadGrammar: -> @@ -109,7 +109,7 @@ class TokenizedBuffer extends Model @invalidateRow(0) @fullyTokenized = false event = {start: 0, end: lastRow, delta: 0} - @emit 'changed', event if Grim.includeDeprecations + @emit 'changed', event if Grim.includeDeprecatedAPIs @emitter.emit 'did-change', event setVisible: (@visible) -> @@ -171,7 +171,7 @@ class TokenizedBuffer extends Model [startRow, endRow] = @updateFoldableStatus(startRow, endRow) event = {start: startRow, end: endRow, delta: 0} - @emit 'changed', event if Grim.includeDeprecations + @emit 'changed', event if Grim.includeDeprecatedAPIs @emitter.emit 'did-change', event if @firstInvalidRow()? @@ -181,7 +181,7 @@ class TokenizedBuffer extends Model markTokenizationComplete: -> unless @fullyTokenized - @emit 'tokenized' if Grim.includeDeprecations + @emit 'tokenized' if Grim.includeDeprecatedAPIs @emitter.emit 'did-tokenize' @fullyTokenized = true @@ -228,7 +228,7 @@ class TokenizedBuffer extends Model end -= delta event = { start, end, delta, bufferChange: e } - @emit 'changed', event if Grim.includeDeprecations + @emit 'changed', event if Grim.includeDeprecatedAPIs @emitter.emit 'did-change', event retokenizeWhitespaceRowsIfIndentLevelChanged: (row, increment) -> @@ -464,7 +464,7 @@ class TokenizedBuffer extends Model console.log row, line, line.length return -if Grim.includeDeprecations +if Grim.includeDeprecatedAPIs EmitterMixin = require('emissary').Emitter TokenizedBuffer::on = (eventName) -> diff --git a/src/workspace-element.coffee b/src/workspace-element.coffee index 66ded0084..33ea14093 100644 --- a/src/workspace-element.coffee +++ b/src/workspace-element.coffee @@ -16,10 +16,10 @@ class WorkspaceElement extends HTMLElement @initializeContent() @observeScrollbarStyle() @observeTextEditorFontConfig() - @createSpacePenShim() if Grim.includeDeprecations + @createSpacePenShim() if Grim.includeDeprecatedAPIs attachedCallback: -> - callAttachHooks(this) if Grim.includeDeprecations + callAttachHooks(this) if Grim.includeDeprecatedAPIs @focus() detachedCallback: -> @@ -82,7 +82,7 @@ class WorkspaceElement extends HTMLElement @appendChild(@panelContainers.modal) - @__spacePenView.setModel(@model) if Grim.includeDeprecations + @__spacePenView.setModel(@model) if Grim.includeDeprecatedAPIs this getModel: -> @model diff --git a/src/workspace.coffee b/src/workspace.coffee index 858ae063f..722a45f21 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -1,4 +1,4 @@ -{includeDeprecations, deprecate} = require 'grim' +{includeDeprecatedAPIs, deprecate} = require 'grim' _ = require 'underscore-plus' path = require 'path' {join} = path @@ -112,7 +112,7 @@ class Workspace extends Model _.uniq(packageNames) editorAdded: (editor) -> - @emit 'editor-created', editor if includeDeprecations + @emit 'editor-created', editor if includeDeprecatedAPIs installShellCommands: -> require('./command-installer').installShellCommandsInteractively() @@ -389,7 +389,7 @@ class Workspace extends Model # the containing pane. Defaults to `true`. openSync: (uri='', options={}) -> # TODO: Remove deprecated changeFocus option - if includeDeprecations and options.changeFocus? + if includeDeprecatedAPIs and options.changeFocus? deprecate("The `changeFocus` option has been renamed to `activatePane`") options.activatePane = options.changeFocus delete options.changeFocus @@ -410,7 +410,7 @@ class Workspace extends Model openURIInPane: (uri, pane, options={}) -> # TODO: Remove deprecated changeFocus option - if includeDeprecations and options.changeFocus? + if includeDeprecatedAPIs and options.changeFocus? deprecate("The `changeFocus` option has been renamed to `activatePane`") options.activatePane = options.changeFocus delete options.changeFocus @@ -446,7 +446,7 @@ class Workspace extends Model if options.initialLine? or options.initialColumn? item.setCursorBufferPosition?([options.initialLine, options.initialColumn]) index = pane.getActiveItemIndex() - @emit "uri-opened" if includeDeprecations + @emit "uri-opened" if includeDeprecatedAPIs @emitter.emit 'did-open', {uri, pane, item, index} item @@ -477,7 +477,7 @@ class Workspace extends Model # Returns a {Disposable} on which `.dispose()` can be called to remove the # opener. addOpener: (opener) -> - if includeDeprecations + if includeDeprecatedAPIs packageName = @getCallingPackageName() wrappedOpener = (uri, options) -> @@ -891,7 +891,7 @@ class Workspace extends Model deferred.promise -if includeDeprecations +if includeDeprecatedAPIs Object.defineProperty Workspace::, 'activePaneItem', get: -> Grim.deprecate "Use ::getActivePaneItem() instead of the ::activePaneItem property" diff --git a/static/index.js b/static/index.js index 7c8e92571..aa582f845 100644 --- a/static/index.js +++ b/static/index.js @@ -34,7 +34,7 @@ window.onload = function() { ModuleCache.register(loadSettings); ModuleCache.add(loadSettings.resourcePath); - require('grim').includeDeprecations = !loadSettings.apiPreviewMode; + require('grim').includeDeprecatedAPIs = !loadSettings.apiPreviewMode; // Start the crash reporter before anything else. require('crash-reporter').start({ From 183ac788a1e48e6c50e3f0359e8baae1dee5dbc2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 3 Apr 2015 09:22:36 -0700 Subject: [PATCH 0460/1783] Check Grim.includeDeprecatedAPIs in keymap-extensions --- src/keymap-extensions.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/keymap-extensions.coffee b/src/keymap-extensions.coffee index 821abbc0c..551c6580d 100644 --- a/src/keymap-extensions.coffee +++ b/src/keymap-extensions.coffee @@ -3,13 +3,14 @@ path = require 'path' KeymapManager = require 'atom-keymap' CSON = require 'season' {jQuery} = require 'space-pen' +Grim = require 'grim' KeymapManager::onDidLoadBundledKeymaps = (callback) -> @emitter.on 'did-load-bundled-keymaps', callback KeymapManager::loadBundledKeymaps = -> @loadKeymap(path.join(@resourcePath, 'keymaps')) - @emit 'bundled-keymaps-loaded' + @emit 'bundled-keymaps-loaded' if Grim.includeDeprecatedAPIs @emitter.emit 'did-load-bundled-keymaps' KeymapManager::getUserKeymapPath = -> From ec5cd753508a61b2dbaf03425c726492548b19ef Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 3 Apr 2015 09:40:17 -0700 Subject: [PATCH 0461/1783] includeDeprecations -> includeDeprecatedAPIs --- src/grammar-registry.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/grammar-registry.coffee b/src/grammar-registry.coffee index b43e095d9..8272dce47 100644 --- a/src/grammar-registry.coffee +++ b/src/grammar-registry.coffee @@ -38,7 +38,7 @@ class GrammarRegistry extends FirstMate.GrammarRegistry selectGrammar: (filePath, fileContents) -> super clearObservers: -> - @off() if includeDeprecations + @off() if includeDeprecatedAPIs @emitter = new Emitter if includeDeprecatedAPIs From 50d7825200d9fc0eeb2b7f1568363eacc44bfc98 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 3 Apr 2015 09:45:13 -0700 Subject: [PATCH 0462/1783] Always assign paths --- src/project.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/project.coffee b/src/project.coffee index b34d301b6..f7f1eb498 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -69,7 +69,7 @@ class Project extends Model if Grim.includeDeprecatedAPIs and path? Grim.deprecate("Pass 'paths' array instead of 'path' to project constructor") - paths ?= _.compact([path]) + paths ?= _.compact([path]) @setPaths(paths) From d1289be584bb98358414c597c78f5ec0f4958357 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 3 Apr 2015 09:51:11 -0700 Subject: [PATCH 0463/1783] :arrow_up: markdown-preview@0.147 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8b575680c..e1f0b075a 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,7 @@ "incompatible-packages": "0.24.0", "keybinding-resolver": "0.30.0", "link": "0.30.0", - "markdown-preview": "0.146.0", + "markdown-preview": "0.147.0", "metrics": "0.45.0", "notifications": "0.35.0", "open-on-github": "0.36.0", From 8be59f7433ecc6b51b3f398742a05673088c51a0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 3 Apr 2015 09:53:18 -0700 Subject: [PATCH 0464/1783] :arrow_up: wrap-guide@0.32 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e1f0b075a..531f8f093 100644 --- a/package.json +++ b/package.json @@ -122,7 +122,7 @@ "update-package-dependencies": "0.9.0", "welcome": "0.26.0", "whitespace": "0.29.0", - "wrap-guide": "0.31.0", + "wrap-guide": "0.32.0", "language-c": "0.43.0", "language-clojure": "0.13.0", "language-coffee-script": "0.39.0", From 2cf1a926889cee018ace189253370abdbb2ac116 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 3 Apr 2015 11:11:25 -0700 Subject: [PATCH 0465/1783] :arrow_up: donna@1.0.9 --- build/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/package.json b/build/package.json index 297ddadfd..18bef4d1e 100644 --- a/build/package.json +++ b/build/package.json @@ -7,7 +7,7 @@ }, "dependencies": { "async": "~0.2.9", - "donna": "1.0.7", + "donna": "1.0.9", "formidable": "~1.0.14", "fs-plus": "2.x", "github-releases": "~0.2.0", From f5aab3547659759a016f43f8306e76036d2e8864 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 3 Apr 2015 11:21:54 -0700 Subject: [PATCH 0466/1783] Check Grim.includeDeprecatedAPIs before emitting --- src/pane.coffee | 10 +++++----- src/text-editor.coffee | 29 +++++++++++++++-------------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/pane.coffee b/src/pane.coffee index 6d2aa5154..c69c74180 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -317,7 +317,7 @@ class Pane extends Model @subscribe item, 'destroyed', => @removeItem(item, true) @items.splice(index, 0, item) - @emit 'item-added', item, index + @emit 'item-added', item, index if Grim.includeDeprecatedAPIs @emitter.emit 'did-add-item', {item, index} @setActiveItem(item) unless @getActiveItem()? item @@ -352,7 +352,7 @@ class Pane extends Model else @activatePreviousItem() @items.splice(index, 1) - @emit 'item-removed', item, index, destroyed + @emit 'item-removed', item, index, destroyed if Grim.includeDeprecatedAPIs @emitter.emit 'did-remove-item', {item, index, destroyed} @container?.didDestroyPaneItem({item, index, pane: this}) if destroyed @destroy() if @items.length is 0 and atom.config.get('core.destroyEmptyPanes') @@ -365,7 +365,7 @@ class Pane extends Model oldIndex = @items.indexOf(item) @items.splice(oldIndex, 1) @items.splice(newIndex, 0, item) - @emit 'item-moved', item, newIndex + @emit 'item-moved', item, newIndex if Grim.includeDeprecatedAPIs @emitter.emit 'did-move-item', {item, oldIndex, newIndex} # Public: Move the given item to the given index on another pane. @@ -393,7 +393,7 @@ class Pane extends Model destroyItem: (item) -> index = @items.indexOf(item) if index isnt -1 - @emit 'before-item-destroyed', item + @emit 'before-item-destroyed', item if Grim.includeDeprecatedAPIs @emitter.emit 'will-destroy-item', {item, index} @container?.willDestroyPaneItem({item, index, pane: this}) if @promptToSaveItem(item) @@ -530,7 +530,7 @@ class Pane extends Model throw new Error("Pane has been destroyed") if @isDestroyed() @container?.setActivePane(this) - @emit 'activated' + @emit 'activated' if Grim.includeDeprecatedAPIs @emitter.emit 'did-activate' # Public: Close the pane and destroy all its items. diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 1f917b6a2..cbf1136a2 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -109,10 +109,10 @@ class TextEditor extends Model @setEncoding(atom.config.get('core.fileEncoding', scope: @getRootScopeDescriptor())) @subscribe @$scrollTop, (scrollTop) => - @emit 'scroll-top-changed', scrollTop + @emit 'scroll-top-changed', scrollTop if includeDeprecatedAPIs @emitter.emit 'did-change-scroll-top', scrollTop @subscribe @$scrollLeft, (scrollLeft) => - @emit 'scroll-left-changed', scrollLeft + @emit 'scroll-left-changed', scrollLeft if includeDeprecatedAPIs @emitter.emit 'did-change-scroll-left', scrollLeft atom.workspace?.editorAdded(this) if registerEditor @@ -134,18 +134,19 @@ class TextEditor extends Model @subscribe @buffer.onDidChangePath => unless atom.project.getPaths().length > 0 atom.project.setPaths([path.dirname(@getPath())]) - @emit "title-changed" + @emit "title-changed" if includeDeprecatedAPIs @emitter.emit 'did-change-title', @getTitle() - @emit "path-changed" + @emit "path-changed" if includeDeprecatedAPIs @emitter.emit 'did-change-path', @getPath() @subscribe @buffer.onDidChangeEncoding => @emitter.emit 'did-change-encoding', @getEncoding() @subscribe @buffer.onDidDestroy => @destroy() # TODO: remove these when we remove the deprecations. They are old events. - @subscribe @buffer.onDidStopChanging => @emit "contents-modified" - @subscribe @buffer.onDidConflict => @emit "contents-conflicted" - @subscribe @buffer.onDidChangeModified => @emit "modified-status-changed" + if includeDeprecatedAPIs + @subscribe @buffer.onDidStopChanging => @emit "contents-modified" + @subscribe @buffer.onDidConflict => @emit "contents-conflicted" + @subscribe @buffer.onDidChangeModified => @emit "modified-status-changed" @preserveCursorPositionOnBufferReload() @@ -1630,14 +1631,14 @@ class TextEditor extends Model @decorateMarker(marker, type: 'line-number', class: 'cursor-line') @decorateMarker(marker, type: 'line-number', class: 'cursor-line-no-selection', onlyHead: true, onlyEmpty: true) @decorateMarker(marker, type: 'line', class: 'cursor-line', onlyEmpty: true) - @emit 'cursor-added', cursor + @emit 'cursor-added', cursor if includeDeprecatedAPIs @emitter.emit 'did-add-cursor', cursor cursor # Remove the given cursor from this editor. removeCursor: (cursor) -> _.remove(@cursors, cursor) - @emit 'cursor-removed', cursor + @emit 'cursor-removed', cursor if includeDeprecatedAPIs @emitter.emit 'did-remove-cursor', cursor moveCursors: (fn) -> @@ -1645,7 +1646,7 @@ class TextEditor extends Model @mergeCursors() cursorMoved: (event) -> - @emit 'cursor-moved', event + @emit 'cursor-moved', event if includeDeprecatedAPIs @emitter.emit 'did-change-cursor-position', event # Merge cursors that have the same screen position @@ -2092,14 +2093,14 @@ class TextEditor extends Model if selection.intersectsBufferRange(selectionBufferRange) return selection else - @emit 'selection-added', selection + @emit 'selection-added', selection if includeDeprecatedAPIs @emitter.emit 'did-add-selection', selection selection # Remove the given selection. removeSelection: (selection) -> _.remove(@selections, selection) - @emit 'selection-removed', selection + @emit 'selection-removed', selection if includeDeprecatedAPIs @emitter.emit 'did-remove-selection', selection # Reduce one or more selections to a single empty selection based on the most @@ -2119,7 +2120,7 @@ class TextEditor extends Model # Called by the selection selectionRangeChanged: (event) -> - @emit 'selection-screen-range-changed', event + @emit 'selection-screen-range-changed', event if includeDeprecatedAPIs @emitter.emit 'did-change-selection-range', event ### @@ -2723,7 +2724,7 @@ class TextEditor extends Model @updateInvisibles() @subscribeToScopedConfigSettings() @unfoldAll() - @emit 'grammar-changed' + @emit 'grammar-changed' if includeDeprecatedAPIs @emitter.emit 'did-change-grammar', @getGrammar() handleMarkerCreated: (marker) => From e39df0e40d44feb0e142e5327af8582dc1de0d92 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 3 Apr 2015 11:26:36 -0700 Subject: [PATCH 0467/1783] Conditionally include deprecations in ThemeManager --- src/theme-manager.coffee | 157 ++++++++++++++++----------------------- 1 file changed, 64 insertions(+), 93 deletions(-) diff --git a/src/theme-manager.coffee b/src/theme-manager.coffee index 0ff42c4d2..01bb9652a 100644 --- a/src/theme-manager.coffee +++ b/src/theme-manager.coffee @@ -1,22 +1,16 @@ path = require 'path' - _ = require 'underscore-plus' -EmitterMixin = require('emissary').Emitter {Emitter, Disposable, CompositeDisposable} = require 'event-kit' {File} = require 'pathwatcher' fs = require 'fs-plus' Q = require 'q' Grim = require 'grim' -Package = require './package' - # Extended: Handles loading and activating available themes. # # An instance of this class is always available as the `atom.themes` global. module.exports = class ThemeManager - EmitterMixin.includeInto(this) - constructor: ({@packageManager, @resourcePath, @configDirPath, @safeMode}) -> @emitter = new Emitter @styleSheetDisposablesBySourcePath = {} @@ -33,24 +27,24 @@ class ThemeManager styleElementAdded: (styleElement) -> {sheet} = styleElement @sheetsByStyleElement.set(styleElement, sheet) - @emit 'stylesheet-added', sheet + @emit 'stylesheet-added', sheet if Grim.includeDeprecatedAPIs @emitter.emit 'did-add-stylesheet', sheet - @emit 'stylesheets-changed' + @emit 'stylesheets-changed' if Grim.includeDeprecatedAPIs @emitter.emit 'did-change-stylesheets' styleElementRemoved: (styleElement) -> sheet = @sheetsByStyleElement.get(styleElement) - @emit 'stylesheet-removed', sheet + @emit 'stylesheet-removed', sheet if Grim.includeDeprecatedAPIs @emitter.emit 'did-remove-stylesheet', sheet - @emit 'stylesheets-changed' + @emit 'stylesheets-changed' if Grim.includeDeprecatedAPIs @emitter.emit 'did-change-stylesheets' styleElementUpdated: ({sheet}) -> - @emit 'stylesheet-removed', sheet + @emit 'stylesheet-removed', sheet if Grim.includeDeprecatedAPIs @emitter.emit 'did-remove-stylesheet', sheet - @emit 'stylesheet-added', sheet + @emit 'stylesheet-added', sheet if Grim.includeDeprecatedAPIs @emitter.emit 'did-add-stylesheet', sheet - @emit 'stylesheets-changed' + @emit 'stylesheets-changed' if Grim.includeDeprecatedAPIs @emitter.emit 'did-change-stylesheets' ### @@ -65,65 +59,6 @@ class ThemeManager @emitter.on 'did-change-active-themes', callback @emitter.on 'did-reload-all', callback # TODO: Remove once deprecated pre-1.0 APIs are gone - onDidReloadAll: (callback) -> - Grim.deprecate("Use `::onDidChangeActiveThemes` instead.") - @onDidChangeActiveThemes(callback) - - # Deprecated: Invoke `callback` when a stylesheet has been added to the dom. - # - # * `callback` {Function} - # * `stylesheet` {StyleSheet} the style node - # - # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. - onDidAddStylesheet: (callback) -> - Grim.deprecate("Use atom.styles.onDidAddStyleElement instead") - @emitter.on 'did-add-stylesheet', callback - - # Deprecated: Invoke `callback` when a stylesheet has been removed from the dom. - # - # * `callback` {Function} - # * `stylesheet` {StyleSheet} the style node - # - # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. - onDidRemoveStylesheet: (callback) -> - Grim.deprecate("Use atom.styles.onDidRemoveStyleElement instead") - @emitter.on 'did-remove-stylesheet', callback - - # Deprecated: Invoke `callback` when a stylesheet has been updated. - # - # * `callback` {Function} - # * `stylesheet` {StyleSheet} the style node - # - # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. - onDidUpdateStylesheet: (callback) -> - Grim.deprecate("Use atom.styles.onDidUpdateStyleElement instead") - @emitter.on 'did-update-stylesheet', callback - - # Deprecated: Invoke `callback` when any stylesheet has been updated, added, or removed. - # - # * `callback` {Function} - # - # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. - onDidChangeStylesheets: (callback) -> - Grim.deprecate("Use atom.styles.onDidAdd/RemoveStyleElement instead") - @emitter.on 'did-change-stylesheets', callback - - on: (eventName) -> - switch eventName - when 'reloaded' - Grim.deprecate 'Use ThemeManager::onDidChangeActiveThemes instead' - when 'stylesheet-added' - Grim.deprecate 'Use ThemeManager::onDidAddStylesheet instead' - when 'stylesheet-removed' - Grim.deprecate 'Use ThemeManager::onDidRemoveStylesheet instead' - when 'stylesheet-updated' - Grim.deprecate 'Use ThemeManager::onDidUpdateStylesheet instead' - when 'stylesheets-changed' - Grim.deprecate 'Use ThemeManager::onDidChangeStylesheets instead' - else - Grim.deprecate 'ThemeManager::on is deprecated. Use event subscription methods instead.' - EmitterMixin::on.apply(this, arguments) - ### Section: Accessing Available Themes ### @@ -140,10 +75,6 @@ class ThemeManager getLoadedThemeNames: -> theme.name for theme in @getLoadedThemes() - getLoadedNames: -> - Grim.deprecate("Use `::getLoadedThemeNames` instead.") - @getLoadedThemeNames() - # Public: Get an array of all the loaded themes. getLoadedThemes: -> pack for pack in @packageManager.getLoadedPackages() when pack.isTheme() @@ -156,10 +87,6 @@ class ThemeManager getActiveThemeNames: -> theme.name for theme in @getActiveThemes() - getActiveNames: -> - Grim.deprecate("Use `::getActiveThemeNames` instead.") - @getActiveThemeNames() - # Public: Get an array of all the active themes. getActiveThemes: -> pack for pack in @packageManager.getActivePackages() when pack.isTheme() @@ -208,22 +135,10 @@ class ThemeManager # the first/top theme to override later themes in the stack. themeNames.reverse() - # Set the list of enabled themes. - # - # * `enabledThemeNames` An {Array} of {String} theme names. - setEnabledThemes: (enabledThemeNames) -> - Grim.deprecate("Use `atom.config.set('core.themes', arrayOfThemeNames)` instead") - atom.config.set('core.themes', enabledThemeNames) - ### Section: Private ### - # Returns the {String} path to the user's stylesheet under ~/.atom - getUserStylesheetPath: -> - Grim.deprecate("Call atom.styles.getUserStyleSheetPath() instead") - atom.styles.getUserStyleSheetPath() - # Resolve and apply the stylesheet specified by the path. # # This supports both CSS and Less stylsheets. @@ -366,7 +281,7 @@ class ThemeManager @loadUserStylesheet() @reloadBaseStylesheets() @initialLoadComplete = true - @emit 'reloaded' + @emit 'reloaded' if Grim.includeDeprecatedAPIs @emitter.emit 'did-change-active-themes' deferred.resolve() @@ -410,3 +325,59 @@ class ThemeManager themePaths.push(path.join(themePath, 'styles')) themePaths.filter (themePath) -> fs.isDirectorySync(themePath) + +if Grim.includeDeprecatedAPIs + EmitterMixin = require('emissary').Emitter + EmitterMixin.includeInto(ThemeManager) + + ThemeManager::on = (eventName) -> + switch eventName + when 'reloaded' + Grim.deprecate 'Use ThemeManager::onDidChangeActiveThemes instead' + when 'stylesheet-added' + Grim.deprecate 'Use ThemeManager::onDidAddStylesheet instead' + when 'stylesheet-removed' + Grim.deprecate 'Use ThemeManager::onDidRemoveStylesheet instead' + when 'stylesheet-updated' + Grim.deprecate 'Use ThemeManager::onDidUpdateStylesheet instead' + when 'stylesheets-changed' + Grim.deprecate 'Use ThemeManager::onDidChangeStylesheets instead' + else + Grim.deprecate 'ThemeManager::on is deprecated. Use event subscription methods instead.' + EmitterMixin::on.apply(this, arguments) + + ThemeManager::onDidReloadAll = (callback) -> + Grim.deprecate("Use `::onDidChangeActiveThemes` instead.") + @onDidChangeActiveThemes(callback) + + ThemeManager::onDidAddStylesheet = (callback) -> + Grim.deprecate("Use atom.styles.onDidAddStyleElement instead") + @emitter.on 'did-add-stylesheet', callback + + ThemeManager::onDidRemoveStylesheet = (callback) -> + Grim.deprecate("Use atom.styles.onDidRemoveStyleElement instead") + @emitter.on 'did-remove-stylesheet', callback + + ThemeManager::onDidUpdateStylesheet = (callback) -> + Grim.deprecate("Use atom.styles.onDidUpdateStyleElement instead") + @emitter.on 'did-update-stylesheet', callback + + ThemeManager::onDidChangeStylesheets = (callback) -> + Grim.deprecate("Use atom.styles.onDidAdd/RemoveStyleElement instead") + @emitter.on 'did-change-stylesheets', callback + + ThemeManager::getUserStylesheetPath = -> + Grim.deprecate("Call atom.styles.getUserStyleSheetPath() instead") + atom.styles.getUserStyleSheetPath() + + ThemeManager::getLoadedNames = -> + Grim.deprecate("Use `::getLoadedThemeNames` instead.") + @getLoadedThemeNames() + + ThemeManager::getActiveNames = -> + Grim.deprecate("Use `::getActiveThemeNames` instead.") + @getActiveThemeNames() + + ThemeManager::setEnabledThemes = (enabledThemeNames) -> + Grim.deprecate("Use `atom.config.set('core.themes', arrayOfThemeNames)` instead") + atom.config.set('core.themes', enabledThemeNames) From 73707ce57c8a1349ce6e19295dadb5f28b8c5354 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 3 Apr 2015 11:35:04 -0700 Subject: [PATCH 0468/1783] :art: --- src/package-manager.coffee | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/package-manager.coffee b/src/package-manager.coffee index bc4443418..16142cda4 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -411,16 +411,9 @@ class PackageManager atom.notifications.addError(message, {stack, detail, dismissable: true}) if Grim.includeDeprecatedAPIs - PackageManager::onDidLoadAll = (callback) -> - Grim.deprecate("Use `::onDidLoadInitialPackages` instead.") - @onDidLoadInitialPackages(callback) - - PackageManager::onDidActivateAll = (callback) -> - Grim.deprecate("Use `::onDidActivateInitialPackages` instead.") - @onDidActivateInitialPackages(callback) - EmitterMixin = require('emissary').Emitter EmitterMixin.includeInto(PackageManager) + PackageManager::on = (eventName) -> switch eventName when 'loaded' @@ -430,3 +423,11 @@ if Grim.includeDeprecatedAPIs else Grim.deprecate 'PackageManager::on is deprecated. Use event subscription methods instead.' EmitterMixin::on.apply(this, arguments) + + PackageManager::onDidLoadAll = (callback) -> + Grim.deprecate("Use `::onDidLoadInitialPackages` instead.") + @onDidLoadInitialPackages(callback) + + PackageManager::onDidActivateAll = (callback) -> + Grim.deprecate("Use `::onDidActivateInitialPackages` instead.") + @onDidActivateInitialPackages(callback) From 5aeffd49ab597a0545de3b5bfe4e508408a4e3e6 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 3 Apr 2015 11:36:10 -0700 Subject: [PATCH 0469/1783] :art: --- src/project.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/project.coffee b/src/project.coffee index f7f1eb498..b1c939905 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -69,8 +69,8 @@ class Project extends Model if Grim.includeDeprecatedAPIs and path? Grim.deprecate("Pass 'paths' array instead of 'path' to project constructor") - paths ?= _.compact([path]) + paths ?= _.compact([path]) @setPaths(paths) destroyed: -> From 60913cd9bfa9794a0b4a0f5c659eb8d766824f18 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 3 Apr 2015 11:37:34 -0700 Subject: [PATCH 0470/1783] :memo: Remove empty deprecated comments --- src/text-editor-component.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index c001c2252..bd0e0ee86 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -782,12 +782,10 @@ class TextEditorComponent @rootElement.classList.toggle('mini', @editor.isMini()) if grim.includeDeprecatedAPIs - # Deprecated TextEditorComponent::setInvisibles = (invisibles={}) -> grim.deprecate "Use config.set('editor.invisibles', invisibles) instead" atom.config.set('editor.invisibles', invisibles) - # Deprecated TextEditorComponent::setShowInvisibles = (showInvisibles) -> grim.deprecate "Use config.set('editor.showInvisibles', showInvisibles) instead" atom.config.set('editor.showInvisibles', showInvisibles) From 9944e660edd45ed3b1a80b16ea210572603adfde Mon Sep 17 00:00:00 2001 From: Jussi Kalliokoski Date: Sat, 4 Apr 2015 01:11:06 +0300 Subject: [PATCH 0471/1783] :art: :green_heart: Fixed the test script. Also removed duplicated logic to run grunt. --- script/build | 7 +++---- script/grunt | 19 ++++--------------- script/test | 4 ++-- script/utils/run-grunt.js | 17 +++++++++++++++++ 4 files changed, 26 insertions(+), 21 deletions(-) create mode 100644 script/utils/run-grunt.js diff --git a/script/build b/script/build index 1f0f123ce..a40a02e13 100755 --- a/script/build +++ b/script/build @@ -1,13 +1,12 @@ #!/usr/bin/env node var cp = require('./utils/child-process-wrapper.js'); +var runGrunt = require('./utils/run-grunt.js'); var path = require('path'); process.chdir(path.dirname(__dirname)); cp.safeExec('node script/bootstrap', function() { // build/node_modules/.bin/grunt "$@" - var gruntPath = path.join('build', 'node_modules', '.bin', 'grunt') + (process.platform === 'win32' ? '.cmd' : ''); - var args = ['--gruntfile', path.resolve('build', 'Gruntfile.coffee')]; - args = args.concat(process.argv.slice(2)); - cp.safeSpawn(gruntPath, args, process.exit); + var args = process.argv.slice(2); + runGrunt(args, process.exit); }); diff --git a/script/grunt b/script/grunt index 23b12cf85..99f6860d2 100755 --- a/script/grunt +++ b/script/grunt @@ -1,17 +1,6 @@ #!/usr/bin/env node -var cp = require('./utils/child-process-wrapper.js'); -var fs = require('fs'); -var path = require('path'); +var runGrunt = require('./utils/run-grunt.js'); -// node build/node_modules/.bin/grunt "$@" -var gruntPath = path.resolve(__dirname, '..', 'build', 'node_modules', '.bin', 'grunt') + (process.platform === 'win32' ? '.cmd' : ''); - -if (!fs.existsSync(gruntPath)) { - console.error('Grunt command does not exist at: ' + gruntPath); - console.error('Run script/bootstrap to install Grunt'); - process.exit(1); -} - -var args = ['--gruntfile', path.resolve('build', 'Gruntfile.coffee')]; -args = args.concat(process.argv.slice(2)); -cp.safeSpawn(gruntPath, args, process.exit); +// build/node_modules/.bin/grunt "$@" +var args = process.argv.slice(2); +runGrunt(args, process.exit); diff --git a/script/test b/script/test index 2c3b37147..e8cb53006 100755 --- a/script/test +++ b/script/test @@ -1,10 +1,10 @@ #!/usr/bin/env node var safeExec = require('./utils/child-process-wrapper.js').safeExec; +var runGrunt = require('./utils/run-grunt.js'); var path = require('path'); process.chdir(path.dirname(__dirname)); safeExec('node script/bootstrap', function() { - var gruntPath = path.join('node_modules', '.bin', 'grunt') + (process.platform === 'win32' ? '.cmd' : ''); - safeExec(gruntPath + ' ci --stack --no-color', process.exit); + runGrunt(["ci", "--stack", "--no-color"], process.exit); }); diff --git a/script/utils/run-grunt.js b/script/utils/run-grunt.js new file mode 100644 index 000000000..f63d1009a --- /dev/null +++ b/script/utils/run-grunt.js @@ -0,0 +1,17 @@ +var cp = require('./child-process-wrapper.js'); +var fs = require('fs'); +var path = require('path'); + +module.exports = function(additionalArgs, callback) { + var gruntPath = path.join('build', 'node_modules', '.bin', 'grunt') + (process.platform === 'win32' ? '.cmd' : ''); + + if (!fs.existsSync(gruntPath)) { + console.error('Grunt command does not exist at: ' + gruntPath); + console.error('Run script/bootstrap to install Grunt'); + process.exit(1); + } + + var args = ['--gruntfile', path.resolve('build', 'Gruntfile.coffee')]; + args = args.concat(additionalArgs); + cp.safeSpawn(gruntPath, args, callback); +}; From 42092ce41563b1c475d562ee2ab43fef2abd6790 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 3 Apr 2015 09:32:23 +0200 Subject: [PATCH 0472/1783] Initial .travis.yml configuration --- .travis.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..e86ff77c1 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,14 @@ +language: objective-c + +install: script/build + +script: ./apm/node_modules/.bin/apm test --path ./atom.sh + +notifications: + email: + on_success: never + on_failure: change + +cache: + directories: + - node_modules From dbd5850c5b6d3ae7ba5c2d8cb94caef6e5fcc151 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Sat, 4 Apr 2015 17:50:36 +0200 Subject: [PATCH 0473/1783] Add AppVeyor configuration --- appveyor.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 appveyor.yml diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 000000000..77865dfb7 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,9 @@ +version: "{build}" +os: Windows Server 2012 R2 + +test: off +deploy: off + +build_script: + - cd %APPVEYOR_BUILD_FOLDER% + - script/cibuild From 22d034057ccc2dbb947bfac3eb2cd59521811574 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Sat, 4 Apr 2015 17:59:07 +0200 Subject: [PATCH 0474/1783] Use script/build on AppVeyor :rainbow: --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 77865dfb7..95bf9556a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,4 +6,4 @@ deploy: off build_script: - cd %APPVEYOR_BUILD_FOLDER% - - script/cibuild + - "script/build" From 4ec5f2b4adc2dac91b942c15b008e0ac8dd4e0ea Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Apr 2015 09:15:08 -0700 Subject: [PATCH 0475/1783] :arrow_up: language-c@0.44 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 531f8f093..7fe621085 100644 --- a/package.json +++ b/package.json @@ -123,7 +123,7 @@ "welcome": "0.26.0", "whitespace": "0.29.0", "wrap-guide": "0.32.0", - "language-c": "0.43.0", + "language-c": "0.44.0", "language-clojure": "0.13.0", "language-coffee-script": "0.39.0", "language-csharp": "0.5.0", From a470ab9dd39d1552204d4fb3f478ea800d67ec74 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Apr 2015 09:20:11 -0700 Subject: [PATCH 0476/1783] :arrow_up: language-javascript@0.68 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7fe621085..2567e164d 100644 --- a/package.json +++ b/package.json @@ -134,7 +134,7 @@ "language-html": "0.31.0", "language-hyperlink": "0.12.2", "language-java": "0.14.0", - "language-javascript": "0.67.0", + "language-javascript": "0.68.0", "language-json": "0.14.0", "language-less": "0.25.0", "language-make": "0.14.0", From e0f316e53c38a6bfc70bce5d98dd4482e81f3122 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Apr 2015 09:26:08 -0700 Subject: [PATCH 0477/1783] :arrow_up: language-clojure@0.14 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2567e164d..5024e41b2 100644 --- a/package.json +++ b/package.json @@ -124,7 +124,7 @@ "whitespace": "0.29.0", "wrap-guide": "0.32.0", "language-c": "0.44.0", - "language-clojure": "0.13.0", + "language-clojure": "0.14.0", "language-coffee-script": "0.39.0", "language-csharp": "0.5.0", "language-css": "0.28.0", From 4b46a5218e2270965e6cd06160ba68d2e7c82d20 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Apr 2015 09:33:21 -0700 Subject: [PATCH 0478/1783] :arrow_up: language-ruby@0.51 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5024e41b2..8ca00c56c 100644 --- a/package.json +++ b/package.json @@ -144,7 +144,7 @@ "language-php": "0.22.0", "language-property-list": "0.8.0", "language-python": "0.33.0", - "language-ruby": "0.50.0", + "language-ruby": "0.51.0", "language-ruby-on-rails": "0.21.0", "language-sass": "0.36.0", "language-shellscript": "0.13.0", From af80bc54197e616aab2170eee008bf5fb5ed6abe Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Thu, 2 Apr 2015 13:32:39 -0700 Subject: [PATCH 0479/1783] :memo: Make TextEditor::getBuffer public --- 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 cbf1136a2..8d54fadb1 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -459,7 +459,7 @@ class TextEditor extends Model onDidChangeIcon: (callback) -> @emitter.on 'did-change-icon', callback - # Retrieves the current {TextBuffer}. + # Public: Retrieves the current {TextBuffer}. getBuffer: -> @buffer # Retrieves the current buffer's URI. From cf0a18e0f1b9b5e12ecfce47a60c3d61c3dd80b1 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Apr 2015 09:45:31 -0700 Subject: [PATCH 0480/1783] :arrow_up: markdown-preview@0.148 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8ca00c56c..f280f18bc 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,7 @@ "incompatible-packages": "0.24.0", "keybinding-resolver": "0.30.0", "link": "0.30.0", - "markdown-preview": "0.147.0", + "markdown-preview": "0.148.0", "metrics": "0.45.0", "notifications": "0.35.0", "open-on-github": "0.36.0", From 361732ce8119a189a67cca24f8922f85a1a384c2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Apr 2015 09:50:59 -0700 Subject: [PATCH 0481/1783] :arrow_up: snippets@0.88 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f280f18bc..55762cec0 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "package-generator": "0.38.0", "release-notes": "0.52.0", "settings-view": "0.187.0", - "snippets": "0.87.0", + "snippets": "0.88.0", "spell-check": "0.55.0", "status-bar": "0.66.0", "styleguide": "0.44.0", From 39a1d6b788de9537566dd779f71c465b05c36d6d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Apr 2015 10:59:06 -0700 Subject: [PATCH 0482/1783] Wrap getUri in deprecated API check --- src/pane.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pane.coffee b/src/pane.coffee index c69c74180..b24d5b7e2 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -41,9 +41,9 @@ class Pane extends Model # Called by the Serializable mixin during serialization. serializeParams: -> - if Grim.includeDeprecatedAPIs and typeof @activeItem?.getURI is 'function' + if typeof @activeItem?.getURI is 'function' activeItemURI = @activeItem.getURI() - else if typeof @activeItem?.getUri is 'function' + else if Grim.includeDeprecatedAPIs and typeof @activeItem?.getUri is 'function' activeItemURI = @activeItem.getUri() id: @id From b98c2a8fbb0a100946afae4fd323ae7da895f1f5 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Apr 2015 11:02:14 -0700 Subject: [PATCH 0483/1783] Only call Directory::off when including deprecated APIs --- src/project.coffee | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/project.coffee b/src/project.coffee index b1c939905..5094ef8ce 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -171,7 +171,9 @@ class Project extends Model # # * `projectPaths` {Array} of {String} paths. setPaths: (projectPaths) -> - rootDirectory.off() for rootDirectory in @rootDirectories + if includeDeprecatedAPIs + rootDirectory.off() for rootDirectory in @rootDirectories + repository?.destroy() for repository in @repositories @rootDirectories = [] @repositories = [] @@ -225,7 +227,7 @@ class Project extends Model if indexToRemove? [removedDirectory] = @rootDirectories.splice(indexToRemove, 1) [removedRepository] = @repositories.splice(indexToRemove, 1) - removedDirectory.off() + removedDirectory.off() if includeDeprecatedAPIs removedRepository?.destroy() unless removedRepository in @repositories @emit "path-changed" if includeDeprecatedAPIs @emitter.emit "did-change-paths", @getPaths() From 661b2124b2b1a10ce40ef96694dbbcfd4e2a2b64 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Apr 2015 09:56:40 -0700 Subject: [PATCH 0484/1783] Use new Model in PaneAxis --- src/pane-axis.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pane-axis.coffee b/src/pane-axis.coffee index a9eb0757b..ec77b17d2 100644 --- a/src/pane-axis.coffee +++ b/src/pane-axis.coffee @@ -1,7 +1,7 @@ -{Model} = require 'theorist' {Emitter, CompositeDisposable} = require 'event-kit' {flatten} = require 'underscore-plus' Serializable = require 'serializable' +Model = require './model' module.exports = class PaneAxis extends Model From 312c03e6d20f6cf8aaeb0bc38c3864a3f2bb29a7 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Apr 2015 10:02:02 -0700 Subject: [PATCH 0485/1783] Conditionally include activePane/activePaneItem properties --- src/pane-container.coffee | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/pane-container.coffee b/src/pane-container.coffee index 61ff9f207..7bc7c37e0 100644 --- a/src/pane-container.coffee +++ b/src/pane-container.coffee @@ -1,7 +1,8 @@ {find, flatten} = require 'underscore-plus' -{Model} = require 'theorist' +Grim = require 'grim' {Emitter, CompositeDisposable} = require 'event-kit' Serializable = require 'serializable' +Model = require './model' Pane = require './pane' PaneElement = require './pane-element' PaneContainerElement = require './pane-container-element' @@ -18,16 +19,8 @@ class PaneContainer extends Model @version: 1 - @properties - activePane: null - root: null - @behavior 'activePaneItem', -> - @$activePane - .switch((activePane) -> activePane?.$activeItem) - .distinctUntilChanged() - constructor: (params) -> super @@ -236,3 +229,15 @@ class PaneContainer extends Model removedPaneItem: (item) -> @itemRegistry.removeItem(item) + +if Grim.includeDeprecatedAPIs + PaneContainer.properties + activePane: null + + PaneContainer.behavior 'activePaneItem', -> + @$activePane + .switch((activePane) -> activePane?.$activeItem) + .distinctUntilChanged() + +else + PaneContainer::activePane = null From 96b95b74e9efae29781276bfd66718d22526c932 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Apr 2015 10:56:33 -0700 Subject: [PATCH 0486/1783] Conditionally include Pane model properties and behaviors --- src/pane-container.coffee | 4 +++- src/pane.coffee | 38 ++++++++++++++++++++++---------------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/src/pane-container.coffee b/src/pane-container.coffee index 7bc7c37e0..58da39872 100644 --- a/src/pane-container.coffee +++ b/src/pane-container.coffee @@ -24,6 +24,9 @@ class PaneContainer extends Model constructor: (params) -> super + unless Grim.includeDeprecatedAPIs + @activePane = params?.activePane + @emitter = new Emitter @subscriptions = new CompositeDisposable @@ -238,6 +241,5 @@ if Grim.includeDeprecatedAPIs @$activePane .switch((activePane) -> activePane?.$activeItem) .distinctUntilChanged() - else PaneContainer::activePane = null diff --git a/src/pane.coffee b/src/pane.coffee index b24d5b7e2..dec0789c5 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -15,23 +15,13 @@ class Pane extends Model atom.deserializers.add(this) Serializable.includeInto(this) - @properties - container: undefined - activeItem: undefined - focused: false - - # Public: Only one pane is considered *active* at a time. A pane is activated - # when it is focused, and when focus returns to the pane container after - # moving to another element such as a panel, it returns to the active pane. - @behavior 'active', -> - @$container - .switch((container) -> container?.$activePane) - .map((activePane) => activePane is this) - .distinctUntilChanged() - constructor: (params) -> super + unless Grim.includeDeprecatedAPIs + @container = params?.container + @activeItem = params?.activeItem + @emitter = new Emitter @itemSubscriptions = new WeakMap @items = [] @@ -313,7 +303,8 @@ class Pane extends Model if typeof item.onDidDestroy is 'function' @itemSubscriptions.set item, item.onDidDestroy => @removeItem(item, true) - else if typeof item.on is 'function' + else if Grim.includeDeprecations and typeof item.on is 'function' + deprecate 'If you would like your pane item to support removal when destroyed behavior, please implement a ::onDidDestroy() method. ::on methods for items are no longer supported. If not, ignore this message.' @subscribe item, 'destroyed', => @removeItem(item, true) @items.splice(index, 0, item) @@ -340,7 +331,7 @@ class Pane extends Model index = @items.indexOf(item) return if index is -1 - if typeof item.on is 'function' + if Grim.includeDeprecations and typeof item.on is 'function' @unsubscribe item @unsubscribeFromItem(item) @@ -661,6 +652,17 @@ class Pane extends Model throw error if Grim.includeDeprecatedAPIs + Pane.properties + container: undefined + activeItem: undefined + focused: false + + Pane.behavior 'active', -> + @$container + .switch((container) -> container?.$activePane) + .map((activePane) => activePane is this) + .distinctUntilChanged() + Pane::on = (eventName) -> switch eventName when 'activated' @@ -701,3 +703,7 @@ if Grim.includeDeprecatedAPIs Pane::activateItemForUri = (uri) -> Grim.deprecate("Use `::activateItemForURI` instead.") @activateItemForURI(uri) +else + Pane::container = undefined + Pane::activeItem = undefined + Pane::focused = undefined From 383523677e41fec017c12c40924fd44a71f1f92f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Apr 2015 11:07:17 -0700 Subject: [PATCH 0487/1783] Use new Model superclass in Pane --- src/pane.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pane.coffee b/src/pane.coffee index dec0789c5..892a42a0c 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -1,8 +1,8 @@ {find, compact, extend, last} = require 'underscore-plus' -{Model} = require 'theorist' {Emitter} = require 'event-kit' Serializable = require 'serializable' Grim = require 'grim' +Model = require './model' PaneAxis = require './pane-axis' TextEditor = require './text-editor' From fcefe55e0d634d0953f4209d6973da2c03b1091b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Apr 2015 11:08:01 -0700 Subject: [PATCH 0488/1783] Add deprecated check for item.getUri --- src/pane.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pane.coffee b/src/pane.coffee index 892a42a0c..04dbab1f3 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -49,7 +49,7 @@ class Pane extends Model params.activeItem = find params.items, (item) -> if typeof item.getURI is 'function' itemURI = item.getURI() - else if typeof item.getUri is 'function' + else if Grim.includeDeprecatedAPIs and typeof item.getUri is 'function' itemURI = item.getUri() itemURI is activeItemURI From e8e1500d119f00f67d25ce0ce7c1e26e021ab3b5 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Apr 2015 11:22:51 -0700 Subject: [PATCH 0489/1783] Use new Model superclass in Workspace --- src/workspace.coffee | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/workspace.coffee b/src/workspace.coffee index 722a45f21..646ab0a98 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -9,6 +9,7 @@ Serializable = require 'serializable' Grim = require 'grim' fs = require 'fs-plus' StackTraceParser = require 'stacktrace-parser' +Model = require './model' TextEditor = require './text-editor' PaneContainer = require './pane-container' Pane = require './pane' @@ -33,14 +34,14 @@ class Workspace extends Model atom.deserializers.add(this) Serializable.includeInto(this) - @properties - paneContainer: null - fullScreen: false - destroyedItemURIs: -> [] - constructor: (params) -> super + unless Grim.includeDeprecatedAPIs + @paneContainer = params?.paneContainer + @fullScreen = params?.fullScreen ? false + @destroyedItemURIs = params?.destroyedItemURIs ? [] + @emitter = new Emitter @openers = [] @@ -892,6 +893,11 @@ class Workspace extends Model deferred.promise if includeDeprecatedAPIs + Workspace.properties + paneContainer: null + fullScreen: false + destroyedItemURIs: -> [] + Object.defineProperty Workspace::, 'activePaneItem', get: -> Grim.deprecate "Use ::getActivePaneItem() instead of the ::activePaneItem property" From 39a7af1f24764feb2b4723c5e6f3f16ab6d38184 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Apr 2015 11:23:09 -0700 Subject: [PATCH 0490/1783] Remove theorist require --- src/workspace.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/workspace.coffee b/src/workspace.coffee index 646ab0a98..6a7a40a0c 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -2,7 +2,6 @@ _ = require 'underscore-plus' path = require 'path' {join} = path -{Model} = require 'theorist' Q = require 'q' Serializable = require 'serializable' {Emitter, Disposable, CompositeDisposable} = require 'event-kit' From 0691b837a1ff36de858176264dfc56c5da8595bd Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Apr 2015 11:25:35 -0700 Subject: [PATCH 0491/1783] Use new Model superclass in TokenizedBuffer --- src/tokenized-buffer.coffee | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index bfc563d93..b9d1d01f6 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -1,8 +1,8 @@ _ = require 'underscore-plus' -{Model} = require 'theorist' {CompositeDisposable, Emitter} = require 'event-kit' {Point, Range} = require 'text-buffer' Serializable = require 'serializable' +Model = require './model' TokenizedLine = require './tokenized-line' Token = require './token' ScopeDescriptor = require './scope-descriptor' @@ -12,11 +12,10 @@ module.exports = class TokenizedBuffer extends Model Serializable.includeInto(this) - @property 'tabLength' - grammar: null currentGrammarScore: null buffer: null + tabLength: null tokenizedLines: null chunkSize: 50 invalidRows: null From 265bc94eb3addee3be4e51c410644e56aef3fa6d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Apr 2015 13:10:37 -0700 Subject: [PATCH 0492/1783] Bind TextEditor behaviors to deprecated API flag --- src/text-editor.coffee | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 8d54fadb1..82781c8ec 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -74,10 +74,6 @@ class TextEditor extends Model 'autoDecreaseIndentForBufferRow', 'toggleLineCommentForBufferRow', 'toggleLineCommentsForBufferRows', toProperty: 'languageMode' - @delegatesProperties '$lineHeightInPixels', '$defaultCharWidth', '$height', '$width', - '$verticalScrollbarWidth', '$horizontalScrollbarHeight', '$scrollTop', '$scrollLeft', - toProperty: 'displayBuffer' - constructor: ({@softTabs, initialLine, initialColumn, tabLength, softWrapped, @displayBuffer, buffer, registerEditor, suppressCursorCreation, @mini, @placeholderText, @gutterVisible}) -> super @@ -108,10 +104,10 @@ class TextEditor extends Model @setEncoding(atom.config.get('core.fileEncoding', scope: @getRootScopeDescriptor())) - @subscribe @$scrollTop, (scrollTop) => + @subscribe @displayBuffer.$scrollTop, (scrollTop) => @emit 'scroll-top-changed', scrollTop if includeDeprecatedAPIs @emitter.emit 'did-change-scroll-top', scrollTop - @subscribe @$scrollLeft, (scrollLeft) => + @subscribe @displayBuffer.$scrollLeft, (scrollLeft) => @emit 'scroll-left-changed', scrollLeft if includeDeprecatedAPIs @emitter.emit 'did-change-scroll-left', scrollLeft @@ -2837,6 +2833,10 @@ class TextEditor extends Model logScreenLines: (start, end) -> @displayBuffer.logLines(start, end) if includeDeprecatedAPIs + TextEditor.delegatesProperties '$lineHeightInPixels', '$defaultCharWidth', '$height', '$width', + '$verticalScrollbarWidth', '$horizontalScrollbarHeight', '$scrollTop', '$scrollLeft', + toProperty: 'displayBuffer' + TextEditor::getViewClass = -> require './text-editor-view' From 72678df7fc91912409e7c7fc33c5c2d647b6f592 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Apr 2015 13:25:55 -0700 Subject: [PATCH 0493/1783] Use new Model superclass in DisplayBuffer --- src/display-buffer.coffee | 66 +++++++++++++++++++++++++++++---------- src/text-editor.coffee | 7 +++-- 2 files changed, 55 insertions(+), 18 deletions(-) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index a8b24086a..e5cba3506 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -1,11 +1,11 @@ _ = require 'underscore-plus' Serializable = require 'serializable' -{Model} = require 'theorist' {CompositeDisposable, Emitter} = require 'event-kit' {Point, Range} = require 'text-buffer' TokenizedBuffer = require './tokenized-buffer' RowMap = require './row-map' Fold = require './fold' +Model = require './model' Token = require './token' Decoration = require './decoration' Marker = require './marker' @@ -20,19 +20,6 @@ module.exports = class DisplayBuffer extends Model Serializable.includeInto(this) - @properties - softWrapped: null - editorWidthInChars: null - lineHeightInPixels: null - defaultCharWidth: null - height: null - width: null - scrollTop: 0 - scrollLeft: 0 - scrollWidth: 0 - verticalScrollbarWidth: 15 - horizontalScrollbarHeight: 15 - verticalScrollMargin: 2 horizontalScrollMargin: 6 scopedCharacterWidthsChangeCount: 0 @@ -135,6 +122,20 @@ class DisplayBuffer extends Model onDidChangeCharacterWidths: (callback) -> @emitter.on 'did-change-character-widths', callback + onDidChangeScrollTop: (callback) -> + @emitter.on 'did-change-scroll-top', callback + + onDidChangeScrollLeft: (callback) -> + @emitter.on 'did-change-scroll-left', callback + + observeScrollTop: (callback) -> + callback(@scrollTop) + @onDidChangeScrollTop(callback) + + observeScrollLeft: (callback) -> + callback(@scrollLeft) + @onDidChangeScrollLeft(callback) + observeDecorations: (callback) -> callback(decoration) for decoration in @getDecorations() @onDidAddDecoration(callback) @@ -250,7 +251,11 @@ class DisplayBuffer extends Model getScrollTop: -> @scrollTop setScrollTop: (scrollTop) -> - @scrollTop = Math.round(Math.max(0, Math.min(@getMaxScrollTop(), scrollTop))) + scrollTop = Math.round(Math.max(0, Math.min(@getMaxScrollTop(), scrollTop))) + return if scrollTop is @scrollTop + + @scrollTop = scrollTop + @emitter.emit 'did-change-scroll-top', @scrollTop getMaxScrollTop: -> @getScrollHeight() - @getClientHeight() @@ -262,7 +267,11 @@ class DisplayBuffer extends Model getScrollLeft: -> @scrollLeft setScrollLeft: (scrollLeft) -> - @scrollLeft = Math.round(Math.max(0, Math.min(@getScrollWidth() - @getClientWidth(), scrollLeft))) + scrollLeft = Math.round(Math.max(0, Math.min(@getScrollWidth() - @getClientWidth(), scrollLeft))) + return if scrollLeft is @scrollLeft + + @scrollLeft = scrollLeft + @emitter.emit 'did-change-scroll-left', @scrollLeft getMaxScrollLeft: -> @getScrollWidth() - @getClientWidth() @@ -1228,6 +1237,19 @@ class DisplayBuffer extends Model @foldsByMarkerId[marker.id] if Grim.includeDeprecatedAPIs + DisplayBuffer.properties + softWrapped: null + editorWidthInChars: null + lineHeightInPixels: null + defaultCharWidth: null + height: null + width: null + scrollTop: 0 + scrollLeft: 0 + scrollWidth: 0 + verticalScrollbarWidth: 15 + horizontalScrollbarHeight: 15 + EmitterMixin = require('emissary').Emitter DisplayBuffer::on = (eventName) -> @@ -1256,3 +1278,15 @@ if Grim.includeDeprecatedAPIs Grim.deprecate("DisplayBuffer::on is deprecated. Use event subscription methods instead.") EmitterMixin::on.apply(this, arguments) +else + DisplayBuffer::softWrapped = null + DisplayBuffer::editorWidthInChars = null + DisplayBuffer::lineHeightInPixels = null + DisplayBuffer::defaultCharWidth = null + DisplayBuffer::height = null + DisplayBuffer::width = null + DisplayBuffer::scrollTop = 0 + DisplayBuffer::scrollLeft = 0 + DisplayBuffer::scrollWidth = 0 + DisplayBuffer::verticalScrollbarWidth = 15 + DisplayBuffer::horizontalScrollbarHeight = 15 diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 82781c8ec..a9bf86b33 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -78,6 +78,7 @@ class TextEditor extends Model super @emitter = new Emitter + @disposables = new CompositeDisposable @cursors = [] @selections = [] @@ -104,10 +105,11 @@ class TextEditor extends Model @setEncoding(atom.config.get('core.fileEncoding', scope: @getRootScopeDescriptor())) - @subscribe @displayBuffer.$scrollTop, (scrollTop) => + @disposables.add @displayBuffer.onDidChangeScrollTop (scrollTop) => @emit 'scroll-top-changed', scrollTop if includeDeprecatedAPIs @emitter.emit 'did-change-scroll-top', scrollTop - @subscribe @displayBuffer.$scrollLeft, (scrollLeft) => + + @disposables.add @displayBuffer.onDidChangeScrollLeft (scrollLeft) => @emit 'scroll-left-changed', scrollLeft if includeDeprecatedAPIs @emitter.emit 'did-change-scroll-left', scrollLeft @@ -173,6 +175,7 @@ class TextEditor extends Model destroyed: -> @unsubscribe() + @disposables.dispose() @scopedConfigSubscriptions.dispose() selection.destroy() for selection in @getSelections() @buffer.release() From f36f8ba5eb2992a748bec6f9d7c0c8b65c9d0e8f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Apr 2015 13:32:22 -0700 Subject: [PATCH 0494/1783] Use new Model superclass in TextEditor --- src/text-editor.coffee | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index a9bf86b33..2ca7d74bb 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -3,13 +3,13 @@ path = require 'path' Serializable = require 'serializable' Delegator = require 'delegato' {includeDeprecatedAPIs, deprecate} = require 'grim' -{Model} = require 'theorist' EmitterMixin = require('emissary').Emitter {CompositeDisposable, Emitter} = require 'event-kit' {Point, Range} = TextBuffer = require 'text-buffer' LanguageMode = require './language-mode' DisplayBuffer = require './display-buffer' Cursor = require './cursor' +Model = require './model' Selection = require './selection' TextMateScopeSelector = require('first-mate').ScopeSelector {Directory} = require "pathwatcher" @@ -129,16 +129,16 @@ class TextEditor extends Model subscribeToBuffer: -> @buffer.retain() - @subscribe @buffer.onDidChangePath => + @disposables.add @buffer.onDidChangePath => unless atom.project.getPaths().length > 0 atom.project.setPaths([path.dirname(@getPath())]) @emit "title-changed" if includeDeprecatedAPIs @emitter.emit 'did-change-title', @getTitle() @emit "path-changed" if includeDeprecatedAPIs @emitter.emit 'did-change-path', @getPath() - @subscribe @buffer.onDidChangeEncoding => + @disposables.add @buffer.onDidChangeEncoding => @emitter.emit 'did-change-encoding', @getEncoding() - @subscribe @buffer.onDidDestroy => @destroy() + @disposables.add @buffer.onDidDestroy => @destroy() # TODO: remove these when we remove the deprecations. They are old events. if includeDeprecatedAPIs @@ -149,18 +149,19 @@ class TextEditor extends Model @preserveCursorPositionOnBufferReload() subscribeToDisplayBuffer: -> - @subscribe @displayBuffer.onDidCreateMarker @handleMarkerCreated - @subscribe @displayBuffer.onDidUpdateMarkers => @mergeIntersectingSelections() - @subscribe @displayBuffer.onDidChangeGrammar => @handleGrammarChange() - @subscribe @displayBuffer.onDidTokenize => @handleTokenization() - @subscribe @displayBuffer.onDidChange (e) => - @emit 'screen-lines-changed', e + @disposables.add @displayBuffer.onDidCreateMarker @handleMarkerCreated + @disposables.add @displayBuffer.onDidUpdateMarkers => @mergeIntersectingSelections() + @disposables.add @displayBuffer.onDidChangeGrammar => @handleGrammarChange() + @disposables.add @displayBuffer.onDidTokenize => @handleTokenization() + @disposables.add @displayBuffer.onDidChange (e) => + @emit 'screen-lines-changed', e if includeDeprecatedAPIs @emitter.emit 'did-change', e # TODO: remove these when we remove the deprecations. Though, no one is likely using them - @subscribe @displayBuffer.onDidChangeSoftWrapped (softWrapped) => @emit 'soft-wrap-changed', softWrapped - @subscribe @displayBuffer.onDidAddDecoration (decoration) => @emit 'decoration-added', decoration - @subscribe @displayBuffer.onDidRemoveDecoration (decoration) => @emit 'decoration-removed', decoration + if includeDeprecatedAPIs + @subscribe @displayBuffer.onDidChangeSoftWrapped (softWrapped) => @emit 'soft-wrap-changed', softWrapped + @subscribe @displayBuffer.onDidAddDecoration (decoration) => @emit 'decoration-added', decoration + @subscribe @displayBuffer.onDidRemoveDecoration (decoration) => @emit 'decoration-removed', decoration @subscribeToScopedConfigSettings() @@ -174,7 +175,7 @@ class TextEditor extends Model subscriptions.add atom.config.onDidChange 'editor.invisibles', scope: scopeDescriptor, => @updateInvisibles() destroyed: -> - @unsubscribe() + @unsubscribe() if includeDeprecatedAPIs @disposables.dispose() @scopedConfigSubscriptions.dispose() selection.destroy() for selection in @getSelections() @@ -719,7 +720,7 @@ class TextEditor extends Model willInsert = true cancel = -> willInsert = false willInsertEvent = {cancel, text} - @emit('will-insert-text', willInsertEvent) + @emit('will-insert-text', willInsertEvent) if includeDeprecatedAPIs @emitter.emit 'will-insert-text', willInsertEvent if willInsert @@ -728,7 +729,7 @@ class TextEditor extends Model @mutateSelectedText (selection) => range = selection.insertText(text, options) didInsertEvent = {text, range} - @emit('did-insert-text', didInsertEvent) + @emit('did-insert-text', didInsertEvent) if includeDeprecatedAPIs @emitter.emit 'did-insert-text', didInsertEvent range else @@ -1661,9 +1662,9 @@ class TextEditor extends Model preserveCursorPositionOnBufferReload: -> cursorPosition = null - @subscribe @buffer.onWillReload => + @disposables.add @buffer.onWillReload => cursorPosition = @getCursorBufferPosition() - @subscribe @buffer.onDidReload => + @disposables.add @buffer.onDidReload => @setCursorBufferPosition(cursorPosition) if cursorPosition cursorPosition = null From 6e3bdd2daf54b9aab1e23cc7d194289e0ff513c1 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Apr 2015 13:38:34 -0700 Subject: [PATCH 0495/1783] Return value from scroll top/left setters --- src/display-buffer.coffee | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index e5cba3506..ec95d0619 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -252,10 +252,10 @@ class DisplayBuffer extends Model getScrollTop: -> @scrollTop setScrollTop: (scrollTop) -> scrollTop = Math.round(Math.max(0, Math.min(@getMaxScrollTop(), scrollTop))) - return if scrollTop is @scrollTop - - @scrollTop = scrollTop - @emitter.emit 'did-change-scroll-top', @scrollTop + unless scrollTop is @scrollTop + @scrollTop = scrollTop + @emitter.emit 'did-change-scroll-top', @scrollTop + @scrollTop getMaxScrollTop: -> @getScrollHeight() - @getClientHeight() @@ -268,10 +268,10 @@ class DisplayBuffer extends Model getScrollLeft: -> @scrollLeft setScrollLeft: (scrollLeft) -> scrollLeft = Math.round(Math.max(0, Math.min(@getScrollWidth() - @getClientWidth(), scrollLeft))) - return if scrollLeft is @scrollLeft - - @scrollLeft = scrollLeft - @emitter.emit 'did-change-scroll-left', @scrollLeft + unless scrollLeft is @scrollLeft + @scrollLeft = scrollLeft + @emitter.emit 'did-change-scroll-left', @scrollLeft + @scrollLeft getMaxScrollLeft: -> @getScrollWidth() - @getClientWidth() From b45aa8c51f7763309d3375767e05d973924f5cbc Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Apr 2015 13:44:17 -0700 Subject: [PATCH 0496/1783] includeDeprecations -> includeDeprecatedAPIs --- src/pane.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pane.coffee b/src/pane.coffee index 04dbab1f3..75daa782c 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -303,8 +303,8 @@ class Pane extends Model if typeof item.onDidDestroy is 'function' @itemSubscriptions.set item, item.onDidDestroy => @removeItem(item, true) - else if Grim.includeDeprecations and typeof item.on is 'function' - deprecate 'If you would like your pane item to support removal when destroyed behavior, please implement a ::onDidDestroy() method. ::on methods for items are no longer supported. If not, ignore this message.' + else if Grim.includeDeprecatedAPIs and typeof item.on is 'function' + Grim.deprecate 'If you would like your pane item to support removal when destroyed behavior, please implement a ::onDidDestroy() method. ::on methods for items are no longer supported. If not, ignore this message.' @subscribe item, 'destroyed', => @removeItem(item, true) @items.splice(index, 0, item) @@ -331,7 +331,7 @@ class Pane extends Model index = @items.indexOf(item) return if index is -1 - if Grim.includeDeprecations and typeof item.on is 'function' + if Grim.includeDeprecatedAPIs and typeof item.on is 'function' @unsubscribe item @unsubscribeFromItem(item) From c4062d8fea0e34341e22acd9b27e4a7d505ecab2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Apr 2015 13:57:52 -0700 Subject: [PATCH 0497/1783] Remove destroyed event deprecation --- src/pane.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pane.coffee b/src/pane.coffee index 75daa782c..8b12fcf7f 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -304,7 +304,6 @@ class Pane extends Model if typeof item.onDidDestroy is 'function' @itemSubscriptions.set item, item.onDidDestroy => @removeItem(item, true) else if Grim.includeDeprecatedAPIs and typeof item.on is 'function' - Grim.deprecate 'If you would like your pane item to support removal when destroyed behavior, please implement a ::onDidDestroy() method. ::on methods for items are no longer supported. If not, ignore this message.' @subscribe item, 'destroyed', => @removeItem(item, true) @items.splice(index, 0, item) From c7071f15b52123e02d8c082704b9efca53bab3fe Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Apr 2015 14:43:49 -0700 Subject: [PATCH 0498/1783] :arrow_up: donna@1.0.10 --- build/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/package.json b/build/package.json index 18bef4d1e..212f9c3ed 100644 --- a/build/package.json +++ b/build/package.json @@ -7,7 +7,7 @@ }, "dependencies": { "async": "~0.2.9", - "donna": "1.0.9", + "donna": "1.0.10", "formidable": "~1.0.14", "fs-plus": "2.x", "github-releases": "~0.2.0", From b54177eb5eb4797f48057f3d7a1057cc6dedc7e0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Apr 2015 15:14:26 -0700 Subject: [PATCH 0499/1783] Remove property always set in constructor --- src/pane-container.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/pane-container.coffee b/src/pane-container.coffee index 58da39872..e6eb97075 100644 --- a/src/pane-container.coffee +++ b/src/pane-container.coffee @@ -241,5 +241,3 @@ if Grim.includeDeprecatedAPIs @$activePane .switch((activePane) -> activePane?.$activeItem) .distinctUntilChanged() -else - PaneContainer::activePane = null From 5df56fc50ae2f5442ad82d1f9bd48ac31762de60 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 6 Apr 2015 12:30:12 -0700 Subject: [PATCH 0500/1783] Add workspace element command for 'add root folder' --- spec/atom-spec.coffee | 16 ++++++++++++++++ src/atom.coffee | 11 ++++++++--- src/workspace-element.coffee | 1 + 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/spec/atom-spec.coffee b/spec/atom-spec.coffee index 1fca9cf28..f888c433f 100644 --- a/spec/atom-spec.coffee +++ b/spec/atom-spec.coffee @@ -180,3 +180,19 @@ describe "the `atom` global", -> it "does not open an empty buffer", -> atom.openInitialEmptyEditorIfNecessary() expect(atom.workspace.open).not.toHaveBeenCalled() + + describe "adding a root folder", -> + it "adds a second path to the project", -> + initialPaths = atom.project.getPaths() + tempDirectory = temp.mkdirSync("a-new-directory") + spyOn(atom, "pickFolder").andCallFake (callback) -> + callback([tempDirectory]) + atom.addRootFolder() + expect(atom.project.getPaths()).toEqual(initialPaths.concat([tempDirectory])) + + it "does nothing if the user dismisses the file picker", -> + initialPaths = atom.project.getPaths() + tempDirectory = temp.mkdirSync("a-new-directory") + spyOn(atom, "pickFolder").andCallFake (callback) -> callback(null) + atom.addRootFolder() + expect(atom.project.getPaths()).toEqual(initialPaths) diff --git a/src/atom.coffee b/src/atom.coffee index 1710edd98..701f2e91e 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -412,10 +412,11 @@ class Atom extends Model open: (options) -> ipc.send('open', options) - # Extended: Show the native dialog to prompt the user to select a folder. + # Extended: Prompt the user to select one or more folders. # - # * `callback` A {Function} to call once the user has selected a folder. - # * `path` {String} the path to the folder the user selected. + # * `callback` A {Function} to call once the user has confirmed the selection. + # * `paths` An {Array} of {String} paths that the user selected, or `null` + # if the user dismissed the dialog. pickFolder: (callback) -> responseChannel = "atom-pick-folder-response" ipc.on responseChannel, (path) -> @@ -773,6 +774,10 @@ class Atom extends Model setRepresentedFilename: (filename) -> ipc.send('call-window-method', 'setRepresentedFilename', filename) + addRootFolder: -> + @pickFolder (selectedPaths = []) => + @project.addPath(selectedPath) for selectedPath in selectedPaths + showSaveDialog: (callback) -> callback(showSaveDialogSync()) diff --git a/src/workspace-element.coffee b/src/workspace-element.coffee index 33ea14093..ccf165439 100644 --- a/src/workspace-element.coffee +++ b/src/workspace-element.coffee @@ -138,6 +138,7 @@ atom.commands.add 'atom-workspace', 'application:open-safe': -> ipc.send('command', 'application:open-safe') 'application:open-api-preview': -> ipc.send('command', 'application:open-api-preview') 'application:open-dev-api-preview': -> ipc.send('command', 'application:open-dev-api-preview') + 'application:add-root-folder': -> atom.addRootFolder() 'application:minimize': -> ipc.send('command', 'application:minimize') 'application:zoom': -> ipc.send('command', 'application:zoom') 'application:bring-all-windows-to-front': -> ipc.send('command', 'application:bring-all-windows-to-front') From 4560be9eaeddbb2680bef1097a3169e1c574a3ae Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Apr 2015 15:53:25 -0700 Subject: [PATCH 0501/1783] Don't use deprecated atom.config.toggle --- src/workspace-element.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/workspace-element.coffee b/src/workspace-element.coffee index ccf165439..5f127d970 100644 --- a/src/workspace-element.coffee +++ b/src/workspace-element.coffee @@ -156,9 +156,9 @@ atom.commands.add 'atom-workspace', 'window:focus-pane-on-left': -> @focusPaneViewOnLeft() 'window:focus-pane-on-right': -> @focusPaneViewOnRight() 'window:save-all': -> @getModel().saveAll() - 'window:toggle-invisibles': -> atom.config.toggle("editor.showInvisibles") + 'window:toggle-invisibles': -> atom.config.set("editor.showInvisibles", !atom.config.get("editor.showInvisibles")) 'window:log-deprecation-warnings': -> Grim.logDeprecations() - 'window:toggle-auto-indent': -> atom.config.toggle("editor.autoIndent") + 'window:toggle-auto-indent': -> atom.config.set("editor.autoIndent", !atom.config.get("editor.autoIndent")) 'pane:reopen-closed-item': -> @getModel().reopenItem() 'core:close': -> @getModel().destroyActivePaneItemOrEmptyPane() 'core:save': -> @getModel().saveActivePaneItem() From 188b2e5a74e87ae98c1ce70986848d74d637ce03 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Apr 2015 15:55:51 -0700 Subject: [PATCH 0502/1783] Report core deprecations in specs --- spec/spec-helper.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/spec-helper.coffee b/spec/spec-helper.coffee index 5406ff33a..70fb4fb58 100644 --- a/spec/spec-helper.coffee +++ b/spec/spec-helper.coffee @@ -72,7 +72,6 @@ if specDirectory isCoreSpec = specDirectory == fs.realpathSync(__dirname) beforeEach -> - Grim.clearDeprecations() if isCoreSpec $.fx.off = true documentTitle = null projectPath = specProjectPath ? path.join(@specDirectory, 'fixtures') From 50d9fee0d3ce00b6a1bbfe8a2f7a4249956d14f7 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Apr 2015 16:21:09 -0700 Subject: [PATCH 0503/1783] Use Project::onDidAddBuffer --- 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 a1cdce662..703b3d4f8 100644 --- a/spec/project-spec.coffee +++ b/spec/project-spec.coffee @@ -221,7 +221,7 @@ describe "Project", -> beforeEach -> absolutePath = require.resolve('./fixtures/dir/a') newBufferHandler = jasmine.createSpy('newBufferHandler') - atom.project.on 'buffer-created', newBufferHandler + atom.project.onDidAddBuffer(newBufferHandler) describe "when given an absolute path that isn't currently open", -> it "returns a new edit session for the given path and emits 'buffer-created'", -> From 9b7870d5032607b6bd357c49cdf3feaa5cdb4154 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Apr 2015 16:22:31 -0700 Subject: [PATCH 0504/1783] Snapshot deprecations around calls to Project::eachBuffer --- spec/project-spec.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spec/project-spec.coffee b/spec/project-spec.coffee index 703b3d4f8..d89802243 100644 --- a/spec/project-spec.coffee +++ b/spec/project-spec.coffee @@ -502,8 +502,12 @@ describe "Project", -> describe ".eachBuffer(callback)", -> beforeEach -> + jasmine.snapshotDeprecations() atom.project.bufferForPathSync('a') + afterEach -> + jasmine.restoreDeprecationsSnapshot() + it "invokes the callback for existing buffer", -> count = 0 count = 0 From e02e8c91a6ce97b9a9d348ef297b27256203a700 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Apr 2015 16:29:12 -0700 Subject: [PATCH 0505/1783] Use TextEditor::onDidChangeCursorPosition in spec --- spec/text-editor-component-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index a5ca4c309..b2ef2ec51 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -728,7 +728,7 @@ describe "TextEditorComponent", -> expect(cursorNodes[0].style['-webkit-transform']).toBe "translate(#{10 * charWidth}px, #{4 * lineHeightInPixels}px)" expect(cursorNodes[1].style['-webkit-transform']).toBe "translate(#{11 * charWidth}px, #{8 * lineHeightInPixels}px)" - wrapperView.on 'cursor:moved', cursorMovedListener = jasmine.createSpy('cursorMovedListener') + editor.onDidChangeCursorPosition cursorMovedListener = jasmine.createSpy('cursorMovedListener') cursor3.setScreenPosition([4, 11], autoscroll: false) nextAnimationFrame() expect(cursorNodes[0].style['-webkit-transform']).toBe "translate(#{11 * charWidth}px, #{4 * lineHeightInPixels}px)" From fdba094aa6b1bd987e6085989367a18c69eae68b Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 6 Apr 2015 17:12:50 -0700 Subject: [PATCH 0506/1783] :arrow_up: tree-view --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 55762cec0..ce1d886c4 100644 --- a/package.json +++ b/package.json @@ -118,7 +118,7 @@ "symbols-view": "0.93.0", "tabs": "0.67.0", "timecop": "0.31.0", - "tree-view": "0.168.0", + "tree-view": "0.169.0", "update-package-dependencies": "0.9.0", "welcome": "0.26.0", "whitespace": "0.29.0", From a80256155344a7d175d14b80afddf258fbedafb3 Mon Sep 17 00:00:00 2001 From: simurai Date: Tue, 7 Apr 2015 09:20:27 +0900 Subject: [PATCH 0507/1783] :arrow_up: one-dark-ui@0.6.0 one-light-ui@0.5.0 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index ce1d886c4..48f8a591c 100644 --- a/package.json +++ b/package.json @@ -76,10 +76,10 @@ "atom-light-ui": "0.41.0", "base16-tomorrow-dark-theme": "0.25.0", "base16-tomorrow-light-theme": "0.8.0", - "one-dark-ui": "0.5.0", + "one-dark-ui": "0.6.0", "one-dark-syntax": "0.3.0", "one-light-syntax": "0.4.0", - "one-light-ui": "0.4.0", + "one-light-ui": "0.5.0", "solarized-dark-syntax": "0.32.0", "solarized-light-syntax": "0.19.0", "archive-view": "0.55.0", From aed17cda9b43e96c6b31dd1f70199d3742b904ff Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 6 Apr 2015 17:51:18 -0700 Subject: [PATCH 0508/1783] :arrow_up: language-javascript@0.69 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 48f8a591c..d6abef9c6 100644 --- a/package.json +++ b/package.json @@ -134,7 +134,7 @@ "language-html": "0.31.0", "language-hyperlink": "0.12.2", "language-java": "0.14.0", - "language-javascript": "0.68.0", + "language-javascript": "0.69.0", "language-json": "0.14.0", "language-less": "0.25.0", "language-make": "0.14.0", From a6d47d403fc68ef9e0c29635a5427dff4d5ecfe9 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 7 Apr 2015 11:01:54 +0800 Subject: [PATCH 0509/1783] :penguin: Don't use clipboard in renderer process, fixes #6221 --- src/clipboard.coffee | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/clipboard.coffee b/src/clipboard.coffee index 3fba6f4e8..bc0926521 100644 --- a/src/clipboard.coffee +++ b/src/clipboard.coffee @@ -1,6 +1,12 @@ -clipboard = require 'clipboard' crypto = require 'crypto' +# Using clipboard in renderer process is not safe on Linux. +clipboard = + if process.platform is 'linux' + require('remote').require 'clipboard' + else + require 'clipboard' + # Extended: Represents the clipboard used for copying and pasting in Atom. # # An instance of this class is always available as the `atom.clipboard` global. From 099c8eda77763d0c38b0c67ef947c7a228e0a1f7 Mon Sep 17 00:00:00 2001 From: simurai Date: Tue, 7 Apr 2015 12:33:44 +0900 Subject: [PATCH 0510/1783] :arrow_up: status-bar@v0.67.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d6abef9c6..f8ebc304d 100644 --- a/package.json +++ b/package.json @@ -113,7 +113,7 @@ "settings-view": "0.187.0", "snippets": "0.88.0", "spell-check": "0.55.0", - "status-bar": "0.66.0", + "status-bar": "0.67.0", "styleguide": "0.44.0", "symbols-view": "0.93.0", "tabs": "0.67.0", From 9b8d7d46fe8e72f7fe6e31b419de7407f50f6ca2 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Thu, 2 Apr 2015 23:03:29 -0400 Subject: [PATCH 0511/1783] Lint for more styleguide errors - Add more coffeelint rules to cover code style requirements from CONTRIBUTING.md --- coffeelint.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/coffeelint.json b/coffeelint.json index d8e19fc46..f3caf09cc 100644 --- a/coffeelint.json +++ b/coffeelint.json @@ -13,5 +13,19 @@ }, "no_debugger": { "level": "error" + }, + "prefer_english_operator": { + "level": "error" + }, + "colon_assignment_spacing": { + "spacing": { + "left": 0, + "right": 1 + }, + "level": "error" + }, + "braces_spacing": { + "spaces": 0, + "level": "error" } } From 5d2392ea674e9ccefe567e35ef625314a81a91f7 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Mon, 6 Apr 2015 23:45:02 -0400 Subject: [PATCH 0512/1783] :shirt: Fix new coffeelint errors --- benchmark/benchmark-helper.coffee | 6 ++-- benchmark/benchmark-suite.coffee | 4 +-- benchmark/fixtures/medium.coffee | 14 ++++----- .../translate-crash-log-addresses.coffee | 9 +++--- spec/config-spec.coffee | 6 ++-- spec/fixtures/coffee.coffee | 3 +- .../package-with-config-defaults/index.coffee | 2 +- ...ample-with-tabs-and-leading-comment.coffee | 6 ++-- spec/fixtures/sample-with-tabs.coffee | 2 ++ spec/package-manager-spec.coffee | 24 +++++++-------- spec/pane-container-view-spec.coffee | 2 +- spec/pane-view-spec.coffee | 6 ++-- spec/spec-helper.coffee | 10 +++---- spec/text-editor-spec.coffee | 2 +- spec/theme-manager-spec.coffee | 10 +++---- spec/tokenized-buffer-spec.coffee | 6 ++-- spec/workspace-spec.coffee | 14 ++++----- src/atom.coffee | 2 +- src/browser/application-menu.coffee | 20 ++++++------- src/browser/atom-application.coffee | 2 +- src/command-installer.coffee | 8 ++--- src/config.coffee | 2 +- src/cursor.coffee | 22 +++++++------- src/decoration.coffee | 2 +- src/default-directory-provider.coffee | 2 +- src/display-buffer.coffee | 10 +++---- src/language-mode.coffee | 8 ++--- src/menu-manager.coffee | 2 +- src/notification.coffee | 6 ++-- src/overlay-manager.coffee | 2 +- src/pane-axis-element.coffee | 2 +- src/project.coffee | 2 +- src/scan-handler.coffee | 2 +- src/selection.coffee | 12 ++++---- src/text-editor-component.coffee | 2 +- src/text-editor.coffee | 6 ++-- src/token.coffee | 2 +- src/tokenized-buffer.coffee | 30 +++++++++---------- src/tokenized-line.coffee | 14 ++++----- src/window-event-handler.coffee | 2 +- src/workspace.coffee | 8 ++--- 41 files changed, 150 insertions(+), 146 deletions(-) diff --git a/benchmark/benchmark-helper.coffee b/benchmark/benchmark-helper.coffee index ae6bab740..d831572c5 100644 --- a/benchmark/benchmark-helper.coffee +++ b/benchmark/benchmark-helper.coffee @@ -29,7 +29,7 @@ window.benchmark = (args...) -> else count = defaultCount [fn, options] = args - { profile, focused } = (options ? {}) + {profile, focused} = (options ? {}) method = if focused then fit else it method description, -> @@ -69,7 +69,7 @@ window.keyIdentifierForKey = (key) -> "U+00" + charCode.toString(16) window.keydownEvent = (key, properties={}) -> - $.Event "keydown", _.extend({originalEvent: { keyIdentifier: keyIdentifierForKey(key) }}, properties) + $.Event "keydown", _.extend({originalEvent: {keyIdentifier: keyIdentifierForKey(key)}}, properties) window.clickEvent = (properties={}) -> $.Event "click", properties @@ -93,7 +93,7 @@ window.pagePixelPositionForPoint = (editorView, point) -> point = Point.fromObject point top = editorView.lines.offset().top + point.row * editorView.lineHeight left = editorView.lines.offset().left + point.column * editorView.charWidth - editorView.lines.scrollLeft() - { top, left } + {top, left} window.seteditorViewWidthInChars = (editorView, widthInChars, charWidth=editorView.charWidth) -> editorView.width(charWidth * widthInChars + editorView.lines.position().left) diff --git a/benchmark/benchmark-suite.coffee b/benchmark/benchmark-suite.coffee index 7a17f22c2..7b06d9758 100644 --- a/benchmark/benchmark-suite.coffee +++ b/benchmark/benchmark-suite.coffee @@ -213,7 +213,7 @@ describe "TokenizedBuffer.", -> beforeEach -> editor = benchmarkFixturesProject.openSync('medium.coffee') - { languageMode, buffer } = editor + {languageMode, buffer} = editor benchmark "construction", 20, -> - new TokenizedBuffer(buffer, { languageMode, tabLength: 2}) + new TokenizedBuffer(buffer, {languageMode, tabLength: 2}) diff --git a/benchmark/fixtures/medium.coffee b/benchmark/fixtures/medium.coffee index 2bdb8c6f7..28ec156b0 100644 --- a/benchmark/fixtures/medium.coffee +++ b/benchmark/fixtures/medium.coffee @@ -209,13 +209,13 @@ template = (str) -> 'var p=[],print=function(){p.push.apply(p,arguments);};' + 'with(obj){p.push(\'' + str.replace(/[\r\t\n]/g, " ") - .replace(/'(?=[^<]*%>)/g,"\t") - .split("'").join("\\'") - .split("\t").join("'") - .replace(/<%=(.+?)%>/g, "',$1,'") - .split('<%').join("');") - .split('%>').join("p.push('") + - "');}return p.join('');" + .replace(/'(?=[^<]*%>)/g,"\t") + .split("'").join("\\'") + .split("\t").join("'") + .replace(/<%=(.+?)%>/g, "',$1,'") + .split('<%').join("');") + .split('%>').join("p.push('") + + "');}return p.join('');" # Create the template that we will use to generate the Docco HTML page. docco_template = template fs.readFileSync(__dirname + '/../resources/docco.jst').toString() diff --git a/script/utils/translate-crash-log-addresses.coffee b/script/utils/translate-crash-log-addresses.coffee index 7fb01532b..fdb540d64 100755 --- a/script/utils/translate-crash-log-addresses.coffee +++ b/script/utils/translate-crash-log-addresses.coffee @@ -17,7 +17,7 @@ parse_stack_trace = (raw) -> addresses = [] for line in raw columns = line.split /\ +/ - if columns[1] == 'libcef.dylib' and /0x[a-f0-9]+/.test columns[3] + if columns[1] is 'libcef.dylib' and /0x[a-f0-9]+/.test columns[3] lines[columns[0]] = addresses.length addresses.push '0x' + parseInt(columns[5]).toString(16) + ' ' @@ -36,12 +36,12 @@ parse_log_file = (content) -> lines = content.split /\r?\n/ for line in lines - if state == 'start' + if state is 'start' if /Thread \d+ Crashed::/.test line console.log line state = 'parse' - else if state == 'parse' - break if line == '' + else if state is 'parse' + break if line is '' stack_trace.push line parse_stack_trace stack_trace @@ -53,4 +53,3 @@ process.stdin.on 'data', (chunk) -> input += chunk process.stdin.on 'end', -> parse_log_file input - diff --git a/spec/config-spec.coffee b/spec/config-spec.coffee index 4abd3b0db..a7e1c6f39 100644 --- a/spec/config-spec.coffee +++ b/spec/config-spec.coffee @@ -251,9 +251,9 @@ describe "Config", -> it "removes all scoped and unscoped properties for that key-path", -> atom.config.setDefaults("foo.bar", baz: 100) - atom.config.set("foo.bar", { baz: 1, ok: 2 }, scopeSelector: ".a") - atom.config.set("foo.bar", { baz: 11, ok: 12 }, scopeSelector: ".b") - atom.config.set("foo.bar", { baz: 21, ok: 22 }) + atom.config.set("foo.bar", {baz: 1, ok: 2}, scopeSelector: ".a") + atom.config.set("foo.bar", {baz: 11, ok: 12}, scopeSelector: ".b") + atom.config.set("foo.bar", {baz: 21, ok: 22}) atom.config.unset("foo.bar.baz") diff --git a/spec/fixtures/coffee.coffee b/spec/fixtures/coffee.coffee index b8367ca59..d68b84267 100644 --- a/spec/fixtures/coffee.coffee +++ b/spec/fixtures/coffee.coffee @@ -1,4 +1,4 @@ -class quicksort +class Quicksort sort: (items) -> return items if items.length <= 1 @@ -13,6 +13,7 @@ class quicksort if current < pivot left.push(current) else + # coffeelint: disable=no_trailing_semicolons right.push(current); sort(left).concat(pivot).concat(sort(right)) diff --git a/spec/fixtures/packages/package-with-config-defaults/index.coffee b/spec/fixtures/packages/package-with-config-defaults/index.coffee index 554c6c5eb..6c48b2af4 100644 --- a/spec/fixtures/packages/package-with-config-defaults/index.coffee +++ b/spec/fixtures/packages/package-with-config-defaults/index.coffee @@ -1,5 +1,5 @@ module.exports = configDefaults: - numbers: { one: 1, two: 2 } + numbers: {one: 1, two: 2} activate: -> # no-op diff --git a/spec/fixtures/sample-with-tabs-and-leading-comment.coffee b/spec/fixtures/sample-with-tabs-and-leading-comment.coffee index 0f81f6fe8..08e81aa68 100644 --- a/spec/fixtures/sample-with-tabs-and-leading-comment.coffee +++ b/spec/fixtures/sample-with-tabs-and-leading-comment.coffee @@ -1,4 +1,6 @@ # This is a comment + # coffeelint: disable=no_tabs + # coffeelint: disable=indentation if this.studyingEconomics - buy() while supply > demand - sell() until supply > demand + buy() while supply > demand + sell() until supply > demand diff --git a/spec/fixtures/sample-with-tabs.coffee b/spec/fixtures/sample-with-tabs.coffee index 1b937ea33..5e7595a7d 100644 --- a/spec/fixtures/sample-with-tabs.coffee +++ b/spec/fixtures/sample-with-tabs.coffee @@ -1,3 +1,5 @@ +# coffeelint: disable=no_tabs +# coffeelint: disable=no_trailing_whitespace # Econ 101 if this.studyingEconomics buy() while supply > demand diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 2789f36c3..db2a76135 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -330,32 +330,32 @@ describe "PackageManager", -> element2 = $$ -> @div class: 'test-2' element3 = $$ -> @div class: 'test-3' - expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element1[0])).toHaveLength 0 - expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element2[0])).toHaveLength 0 - expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element3[0])).toHaveLength 0 + expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element1[0])).toHaveLength 0 + expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element2[0])).toHaveLength 0 + expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element3[0])).toHaveLength 0 waitsForPromise -> atom.packages.activatePackage("package-with-keymaps") runs -> - expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element1[0])[0].command).toBe "test-1" - expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element2[0])[0].command).toBe "test-2" - expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element3[0])).toHaveLength 0 + expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element1[0])[0].command).toBe "test-1" + expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element2[0])[0].command).toBe "test-2" + expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element3[0])).toHaveLength 0 describe "when the metadata contains a 'keymaps' manifest", -> it "loads only the keymaps specified by the manifest, in the specified order", -> element1 = $$ -> @div class: 'test-1' element3 = $$ -> @div class: 'test-3' - expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element1[0])).toHaveLength 0 + expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element1[0])).toHaveLength 0 waitsForPromise -> atom.packages.activatePackage("package-with-keymaps-manifest") runs -> - expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element1[0])[0].command).toBe 'keymap-1' - expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-n', target:element1[0])[0].command).toBe 'keymap-2' - expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-y', target:element3[0])).toHaveLength 0 + expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element1[0])[0].command).toBe 'keymap-1' + expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-n', target: element1[0])[0].command).toBe 'keymap-2' + expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-y', target: element3[0])).toHaveLength 0 describe "when the keymap file is empty", -> it "does not throw an error on activation", -> @@ -645,8 +645,8 @@ describe "PackageManager", -> runs -> atom.packages.deactivatePackage('package-with-keymaps') - expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target: ($$ -> @div class: 'test-1')[0])).toHaveLength 0 - expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target: ($$ -> @div class: 'test-2')[0])).toHaveLength 0 + expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: ($$ -> @div class: 'test-1')[0])).toHaveLength 0 + expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: ($$ -> @div class: 'test-2')[0])).toHaveLength 0 it "removes the package's stylesheets", -> waitsForPromise -> diff --git a/spec/pane-container-view-spec.coffee b/spec/pane-container-view-spec.coffee index 6c088c343..1b9cf9813 100644 --- a/spec/pane-container-view-spec.coffee +++ b/spec/pane-container-view-spec.coffee @@ -15,7 +15,7 @@ describe "PaneContainerView", -> @deserialize: ({name}) -> new TestView(name) @content: -> @div tabindex: -1 initialize: (@name) -> @text(@name) - serialize: -> { deserializer: 'TestView', @name } + serialize: -> {deserializer: 'TestView', @name} getURI: -> path.join(temp.dir, @name) save: -> @saved = true isEqual: (other) -> @name is other?.name diff --git a/spec/pane-view-spec.coffee b/spec/pane-view-spec.coffee index 763cc9ab4..2df5aa68c 100644 --- a/spec/pane-view-spec.coffee +++ b/spec/pane-view-spec.coffee @@ -14,9 +14,9 @@ describe "PaneView", -> @content: ({id, text}) -> @div class: 'test-view', id: id, tabindex: -1, text initialize: ({@id, @text}) -> @emitter = new Emitter - serialize: -> { deserializer: 'TestView', @id, @text } + serialize: -> {deserializer: 'TestView', @id, @text} getURI: -> @id - isEqual: (other) -> other? and @id == other.id and @text == other.text + isEqual: (other) -> other? and @id is other.id and @text is other.text changeTitle: -> @emitter.emit 'did-change-title', 'title' onDidChangeTitle: (callback) -> @@ -222,7 +222,7 @@ describe "PaneView", -> fs.removeSync(filePath) waitsFor -> - pane.items.length == 4 + pane.items.length is 4 describe "when a pane is destroyed", -> [pane2, pane2Model] = [] diff --git a/spec/spec-helper.coffee b/spec/spec-helper.coffee index 70fb4fb58..1c9e6fb6b 100644 --- a/spec/spec-helper.coffee +++ b/spec/spec-helper.coffee @@ -69,7 +69,7 @@ if specDirectory specPackageName = JSON.parse(fs.readFileSync(path.join(specPackagePath, 'package.json')))?.name specProjectPath = path.join(specDirectory, 'fixtures') -isCoreSpec = specDirectory == fs.realpathSync(__dirname) +isCoreSpec = specDirectory is fs.realpathSync(__dirname) beforeEach -> $.fx.off = true @@ -234,7 +234,7 @@ addCustomMatchers = (spec) -> else notText = if @isNot then " not" else "" this.message = => "Expected object with length #{@actual.length} to#{notText} have length #{expected}" - @actual.length == expected + @actual.length is expected toExistOnDisk: (expected) -> notText = this.isNot and " not" or "" @@ -297,7 +297,7 @@ window.mousemoveEvent = (properties={}) -> window.waitsForPromise = (args...) -> if args.length > 1 - { shouldReject, timeout } = args[0] + {shouldReject, timeout} = args[0] else shouldReject = false fn = _.last(args) @@ -328,7 +328,7 @@ window.fakeSetTimeout = (callback, ms) -> id window.fakeClearTimeout = (idToClear) -> - window.timeouts = window.timeouts.filter ([id]) -> id != idToClear + window.timeouts = window.timeouts.filter ([id]) -> id isnt idToClear window.fakeSetInterval = (callback, ms) -> id = ++window.intervalCount @@ -358,7 +358,7 @@ window.pagePixelPositionForPoint = (editorView, point) -> point = Point.fromObject point top = editorView.renderedLines.offset().top + point.row * editorView.lineHeight left = editorView.renderedLines.offset().left + point.column * editorView.charWidth - editorView.renderedLines.scrollLeft() - { top, left } + {top, left} window.tokensText = (tokens) -> _.pluck(tokens, 'value').join('') diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 439a1ddb6..ecb176ad5 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -547,7 +547,7 @@ describe "TextEditor", -> lastLine = buffer.lineForRow(lastLineIndex) expect(lastLine.length).toBeGreaterThan(0) - lastPosition = { row: lastLineIndex, column: lastLine.length } + lastPosition = {row: lastLineIndex, column: lastLine.length} editor.setCursorScreenPosition(lastPosition) editor.moveRight() diff --git a/spec/theme-manager-spec.coffee b/spec/theme-manager-spec.coffee index 5e65da1fa..c39e4994b 100644 --- a/spec/theme-manager-spec.coffee +++ b/spec/theme-manager-spec.coffee @@ -84,7 +84,7 @@ describe "ThemeManager", -> atom.config.set('core.themes', []) waitsFor -> - didChangeActiveThemesHandler.callCount == 1 + didChangeActiveThemesHandler.callCount is 1 runs -> didChangeActiveThemesHandler.reset() @@ -92,7 +92,7 @@ describe "ThemeManager", -> atom.config.set('core.themes', ['atom-dark-ui']) waitsFor -> - didChangeActiveThemesHandler.callCount == 1 + didChangeActiveThemesHandler.callCount is 1 runs -> didChangeActiveThemesHandler.reset() @@ -101,7 +101,7 @@ describe "ThemeManager", -> atom.config.set('core.themes', ['atom-light-ui', 'atom-dark-ui']) waitsFor -> - didChangeActiveThemesHandler.callCount == 1 + didChangeActiveThemesHandler.callCount is 1 runs -> didChangeActiveThemesHandler.reset() @@ -111,7 +111,7 @@ describe "ThemeManager", -> atom.config.set('core.themes', []) waitsFor -> - didChangeActiveThemesHandler.callCount == 1 + didChangeActiveThemesHandler.callCount is 1 runs -> didChangeActiveThemesHandler.reset() @@ -120,7 +120,7 @@ describe "ThemeManager", -> atom.config.set('core.themes', ['theme-with-index-less', 'atom-dark-ui']) waitsFor -> - didChangeActiveThemesHandler.callCount == 1 + didChangeActiveThemesHandler.callCount is 1 runs -> expect($('style[priority=1]')).toHaveLength 2 diff --git a/spec/tokenized-buffer-spec.coffee b/spec/tokenized-buffer-spec.coffee index c1b16ff08..3cd776c2b 100644 --- a/spec/tokenized-buffer-spec.coffee +++ b/spec/tokenized-buffer-spec.coffee @@ -352,7 +352,7 @@ describe "TokenizedBuffer", -> tabAsSpaces = _.multiplyString(' ', tokenizedBuffer.getTabLength()) screenLine0 = tokenizedBuffer.tokenizedLineForRow(0) expect(screenLine0.text).toBe "# Econ 101#{tabAsSpaces}" - { tokens } = screenLine0 + {tokens} = screenLine0 expect(tokens.length).toBe 4 expect(tokens[0].value).toBe "#" @@ -452,7 +452,7 @@ describe "TokenizedBuffer", -> it "renders each UTF-8 surrogate pair as its own atomic token", -> screenLine0 = tokenizedBuffer.tokenizedLineForRow(0) expect(screenLine0.text).toBe "'abc\uD835\uDF97def'" - { tokens } = screenLine0 + {tokens} = screenLine0 expect(tokens.length).toBe 5 expect(tokens[0].value).toBe "'" @@ -464,7 +464,7 @@ describe "TokenizedBuffer", -> screenLine1 = tokenizedBuffer.tokenizedLineForRow(1) expect(screenLine1.text).toBe "//\uD835\uDF97xyz" - { tokens } = screenLine1 + {tokens} = screenLine1 expect(tokens.length).toBe 4 expect(tokens[0].value).toBe '//' diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index e40ef1925..dac2849c0 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -189,7 +189,7 @@ describe "Workspace", -> workspace.open('a', split: 'right').then (o) -> editor = o runs -> - pane2 = workspace.getPanes().filter((p) -> p != pane1)[0] + pane2 = workspace.getPanes().filter((p) -> p isnt pane1)[0] expect(workspace.getActivePane()).toBe pane2 expect(pane1.items).toEqual [] expect(pane2.items).toEqual [editor] @@ -218,7 +218,7 @@ describe "Workspace", -> workspace.open('a', split: 'right').then (o) -> editor = o runs -> - pane4 = workspace.getPanes().filter((p) -> p != pane1)[0] + pane4 = workspace.getPanes().filter((p) -> p isnt pane1)[0] expect(workspace.getActivePane()).toBe pane4 expect(pane4.items).toEqual [editor] expect(workspace.paneContainer.root.children[0]).toBe pane1 @@ -226,19 +226,19 @@ describe "Workspace", -> describe "when passed a path that matches a custom opener", -> it "returns the resource returned by the custom opener", -> - fooOpener = (pathToOpen, options) -> { foo: pathToOpen, options } if pathToOpen?.match(/\.foo/) - barOpener = (pathToOpen) -> { bar: pathToOpen } if pathToOpen?.match(/^bar:\/\//) + fooOpener = (pathToOpen, options) -> {foo: pathToOpen, options} if pathToOpen?.match(/\.foo/) + barOpener = (pathToOpen) -> {bar: pathToOpen} if pathToOpen?.match(/^bar:\/\//) workspace.addOpener(fooOpener) workspace.addOpener(barOpener) waitsForPromise -> pathToOpen = atom.project.getDirectories()[0]?.resolve('a.foo') workspace.open(pathToOpen, hey: "there").then (item) -> - expect(item).toEqual { foo: pathToOpen, options: {hey: "there"} } + expect(item).toEqual {foo: pathToOpen, options: {hey: "there"}} waitsForPromise -> workspace.open("bar://baz").then (item) -> - expect(item).toEqual { bar: "bar://baz" } + expect(item).toEqual {bar: "bar://baz"} it "notifies ::onDidAddTextEditor observers", -> absolutePath = require.resolve('./fixtures/dir/a') @@ -835,7 +835,7 @@ describe "Workspace", -> runs -> expect(results).toHaveLength 3 - resultForA = _.find results, ({filePath}) -> path.basename(filePath) == 'a' + resultForA = _.find results, ({filePath}) -> path.basename(filePath) is 'a' expect(resultForA.matches).toHaveLength 1 expect(resultForA.matches[0].matchText).toBe 'Elephant' diff --git a/src/atom.coffee b/src/atom.coffee index 701f2e91e..88c8257e1 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -499,7 +499,7 @@ class Atom extends Model # Extended: Toggle the full screen state of the current window. toggleFullScreen: -> - @setFullScreen(!@isFullScreen()) + @setFullScreen(not @isFullScreen()) # Schedule the window to be shown and focused on the next tick. # diff --git a/src/browser/application-menu.coffee b/src/browser/application-menu.coffee index 4544a963d..d88314c89 100644 --- a/src/browser/application-menu.coffee +++ b/src/browser/application-menu.coffee @@ -87,15 +87,15 @@ class ApplicationMenu # Replaces VERSION with the current version. substituteVersion: (template) -> - if (item = _.find(@flattenMenuTemplate(template), ({label}) -> label == 'VERSION')) + if (item = _.find(@flattenMenuTemplate(template), ({label}) -> label is 'VERSION')) item.label = "Version #{@version}" # Sets the proper visible state the update menu items showUpdateMenuItem: (state) -> - checkForUpdateItem = _.find(@flattenMenuItems(@menu), ({label}) -> label == 'Check for Update') - checkingForUpdateItem = _.find(@flattenMenuItems(@menu), ({label}) -> label == 'Checking for Update') - downloadingUpdateItem = _.find(@flattenMenuItems(@menu), ({label}) -> label == 'Downloading Update') - installUpdateItem = _.find(@flattenMenuItems(@menu), ({label}) -> label == 'Restart and Install Update') + checkForUpdateItem = _.find(@flattenMenuItems(@menu), ({label}) -> label is 'Check for Update') + checkingForUpdateItem = _.find(@flattenMenuItems(@menu), ({label}) -> label is 'Checking for Update') + downloadingUpdateItem = _.find(@flattenMenuItems(@menu), ({label}) -> label is 'Downloading Update') + installUpdateItem = _.find(@flattenMenuItems(@menu), ({label}) -> label is 'Restart and Install Update') return unless checkForUpdateItem? and checkingForUpdateItem? and downloadingUpdateItem? and installUpdateItem? @@ -121,11 +121,11 @@ class ApplicationMenu [ label: "Atom" submenu: [ - { label: "Check for Update", metadata: {autoUpdate: true}} - { label: 'Reload', accelerator: 'Command+R', click: => @focusedWindow()?.reload() } - { label: 'Close Window', accelerator: 'Command+Shift+W', click: => @focusedWindow()?.close() } - { label: 'Toggle Dev Tools', accelerator: 'Command+Alt+I', click: => @focusedWindow()?.toggleDevTools() } - { label: 'Quit', accelerator: 'Command+Q', click: -> app.quit() } + {label: "Check for Update", metadata: {autoUpdate: true}} + {label: 'Reload', accelerator: 'Command+R', click: => @focusedWindow()?.reload()} + {label: 'Close Window', accelerator: 'Command+Shift+W', click: => @focusedWindow()?.close()} + {label: 'Toggle Dev Tools', accelerator: 'Command+Alt+I', click: => @focusedWindow()?.toggleDevTools()} + {label: 'Quit', accelerator: 'Command+Q', click: -> app.quit()} ] ] diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 45c0c8b5c..609d26d9f 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -95,7 +95,7 @@ class AtomApplication # Public: Removes the {AtomWindow} from the global window list. removeWindow: (window) -> @windows.splice @windows.indexOf(window), 1 - @applicationMenu?.enableWindowSpecificItems(false) if @windows.length == 0 + @applicationMenu?.enableWindowSpecificItems(false) if @windows.length is 0 # Public: Adds the {AtomWindow} to the global window list. addWindow: (window) -> diff --git a/src/command-installer.coffee b/src/command-installer.coffee index 1d3a16777..c0ed22482 100644 --- a/src/command-installer.coffee +++ b/src/command-installer.coffee @@ -6,7 +6,7 @@ runas = null # defer until used symlinkCommand = (sourcePath, destinationPath, callback) -> fs.unlink destinationPath, (error) -> - if error? and error?.code != 'ENOENT' + if error? and error?.code isnt 'ENOENT' callback(error) else fs.makeTree path.dirname(destinationPath), (error) -> @@ -17,13 +17,13 @@ symlinkCommand = (sourcePath, destinationPath, callback) -> symlinkCommandWithPrivilegeSync = (sourcePath, destinationPath) -> runas ?= require 'runas' - if runas('/bin/rm', ['-f', destinationPath], admin: true) != 0 + if runas('/bin/rm', ['-f', destinationPath], admin: true) isnt 0 throw new Error("Failed to remove '#{destinationPath}'") - if runas('/bin/mkdir', ['-p', path.dirname(destinationPath)], admin: true) != 0 + if runas('/bin/mkdir', ['-p', path.dirname(destinationPath)], admin: true) isnt 0 throw new Error("Failed to create directory '#{destinationPath}'") - if runas('/bin/ln', ['-s', sourcePath, destinationPath], admin: true) != 0 + if runas('/bin/ln', ['-s', sourcePath, destinationPath], admin: true) isnt 0 throw new Error("Failed to symlink '#{sourcePath}' to '#{destinationPath}'") module.exports = diff --git a/src/config.coffee b/src/config.coffee index f7db867ed..50d8caba3 100644 --- a/src/config.coffee +++ b/src/config.coffee @@ -1128,7 +1128,7 @@ splitKeyPath = (keyPath) -> startIndex = 0 keyPathArray = [] for char, i in keyPath - if char is '.' and (i is 0 or keyPath[i-1] != '\\') + if char is '.' and (i is 0 or keyPath[i-1] isnt '\\') keyPathArray.push keyPath.substring(startIndex, i) startIndex = i + 1 keyPathArray.push keyPath.substr(startIndex, keyPath.length) diff --git a/src/cursor.coffee b/src/cursor.coffee index 3ed9939ad..b54cc6bcd 100644 --- a/src/cursor.coffee +++ b/src/cursor.coffee @@ -156,7 +156,7 @@ class Cursor extends Model # Public: Returns whether the cursor is at the start of a line. isAtBeginningOfLine: -> - @getBufferPosition().column == 0 + @getBufferPosition().column is 0 # Public: Returns whether the cursor is on the line return character. isAtEndOfLine: -> @@ -210,7 +210,7 @@ class Cursor extends Model isInsideWord: (options) -> {row, column} = @getBufferPosition() range = [[row, column], [row, Infinity]] - @editor.getTextInBufferRange(range).search(options?.wordRegex ? @wordRegExp()) == 0 + @editor.getTextInBufferRange(range).search(options?.wordRegex ? @wordRegExp()) is 0 # Public: Returns the indentation level of the current line. getIndentLevel: -> @@ -243,7 +243,7 @@ class Cursor extends Model # # Returns a {Boolean}. isLastCursor: -> - this == @editor.getLastCursor() + this is @editor.getLastCursor() ### Section: Moving the Cursor @@ -258,9 +258,9 @@ class Cursor extends Model moveUp: (rowCount=1, {moveToEndOfSelection}={}) -> range = @marker.getScreenRange() if moveToEndOfSelection and not range.isEmpty() - { row, column } = range.start + {row, column} = range.start else - { row, column } = @getScreenPosition() + {row, column} = @getScreenPosition() column = @goalColumn if @goalColumn? @setScreenPosition({row: row - rowCount, column: column}, skipSoftWrapIndentation: true) @@ -275,9 +275,9 @@ class Cursor extends Model moveDown: (rowCount=1, {moveToEndOfSelection}={}) -> range = @marker.getScreenRange() if moveToEndOfSelection and not range.isEmpty() - { row, column } = range.end + {row, column} = range.end else - { row, column } = @getScreenPosition() + {row, column} = @getScreenPosition() column = @goalColumn if @goalColumn? @setScreenPosition({row: row + rowCount, column: column}, skipSoftWrapIndentation: true) @@ -315,7 +315,7 @@ class Cursor extends Model if moveToEndOfSelection and not range.isEmpty() @setScreenPosition(range.end) else - { row, column } = @getScreenPosition() + {row, column} = @getScreenPosition() maxLines = @editor.getScreenLineCount() rowLength = @editor.lineTextForScreenRow(row).length columnsRemainingInLine = rowLength - column @@ -586,7 +586,7 @@ class Cursor extends Model # Public: Sets whether the cursor is visible. setVisible: (visible) -> - if @visible != visible + if @visible isnt visible @visible = visible @emit 'visibility-changed', @visible if Grim.includeDeprecatedAPIs @emitter.emit 'did-change-visibility', @visible @@ -664,7 +664,7 @@ class Cursor extends Model position = new Point(row, column - 1) @editor.scanInBufferRange /^\n*$/g, scanRange, ({range, stop}) -> - if !range.start.isEqual(start) + unless range.start.isEqual(start) position = range.start stop() position @@ -677,7 +677,7 @@ class Cursor extends Model position = new Point(0, 0) zero = new Point(0,0) @editor.backwardsScanInBufferRange /^\n*$/g, scanRange, ({range, stop}) -> - if !range.start.isEqual(zero) + unless range.start.isEqual(zero) position = range.start stop() position diff --git a/src/decoration.coffee b/src/decoration.coffee index 8654cf39a..48b26e81f 100644 --- a/src/decoration.coffee +++ b/src/decoration.coffee @@ -146,7 +146,7 @@ class Decoration matchesPattern: (decorationPattern) -> return false unless decorationPattern? for key, value of decorationPattern - return false if @properties[key] != value + return false if @properties[key] isnt value true onDidFlash: (callback) -> diff --git a/src/default-directory-provider.coffee b/src/default-directory-provider.coffee index a05c532a9..9e25e097b 100644 --- a/src/default-directory-provider.coffee +++ b/src/default-directory-provider.coffee @@ -16,7 +16,7 @@ class DefaultDirectoryProvider directoryForURISync: (uri) -> projectPath = path.normalize(uri) - directoryPath = if !fs.isDirectorySync(projectPath) and fs.isDirectorySync(path.dirname(projectPath)) + directoryPath = if not fs.isDirectorySync(projectPath) and fs.isDirectorySync(path.dirname(projectPath)) path.dirname(projectPath) else projectPath diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index ec95d0619..d86fd13be 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -166,7 +166,7 @@ class DisplayBuffer extends Model @updateAllScreenLines() screenDelta = @getLastRow() - end bufferDelta = 0 - @emitDidChange({ start, end, screenDelta, bufferDelta }) + @emitDidChange({start, end, screenDelta, bufferDelta}) # Sets the visibility of the tokenized buffer. # @@ -740,7 +740,7 @@ class DisplayBuffer extends Model screenPositionForBufferPosition: (bufferPosition, options) -> throw new Error("This TextEditor has been destroyed") if @isDestroyed() - { row, column } = @buffer.clipPosition(bufferPosition) + {row, column} = @buffer.clipPosition(bufferPosition) [startScreenRow, endScreenRow] = @rowMap.screenRowRangeForBufferRow(row) for screenRow in [startScreenRow...endScreenRow] screenLine = @screenLines[screenRow] @@ -774,7 +774,7 @@ class DisplayBuffer extends Model # # Returns a {Point}. bufferPositionForScreenPosition: (screenPosition, options) -> - { row, column } = @clipScreenPosition(Point.fromObject(screenPosition), options) + {row, column} = @clipScreenPosition(Point.fromObject(screenPosition), options) [bufferRow] = @rowMap.bufferRowRangeForScreenRow(row) new Point(bufferRow, @screenLines[row].bufferColumnForScreenColumn(column)) @@ -828,8 +828,8 @@ class DisplayBuffer extends Model # # Returns the new, clipped {Point}. Note that this could be the same as `position` if no clipping was performed. clipScreenPosition: (screenPosition, options={}) -> - { wrapBeyondNewlines, wrapAtSoftNewlines, skipSoftWrapIndentation } = options - { row, column } = Point.fromObject(screenPosition) + {wrapBeyondNewlines, wrapAtSoftNewlines, skipSoftWrapIndentation} = options + {row, column} = Point.fromObject(screenPosition) if row < 0 row = 0 diff --git a/src/language-mode.coffee b/src/language-mode.coffee index 125b15ff6..3cbb8ce49 100644 --- a/src/language-mode.coffee +++ b/src/language-mode.coffee @@ -122,7 +122,7 @@ class LanguageMode continue unless startRow? # assumption: startRow will always be the min indent level for the entire range - if @editor.indentationForBufferRow(startRow) == indentLevel + if @editor.indentationForBufferRow(startRow) is indentLevel @editor.createFold(startRow, endRow) return @@ -178,7 +178,7 @@ class LanguageMode continue if @editor.isBufferRowBlank(row) indentation = @editor.indentationForBufferRow(row) if indentation <= startIndentLevel - includeRowInFold = indentation == startIndentLevel and @foldEndRegexForScopeDescriptor(scopeDescriptor)?.searchSync(@editor.lineTextForBufferRow(row)) + includeRowInFold = indentation is startIndentLevel and @foldEndRegexForScopeDescriptor(scopeDescriptor)?.searchSync(@editor.lineTextForBufferRow(row)) foldEndRow = row if includeRowInFold break @@ -211,14 +211,14 @@ class LanguageMode startRow = bufferRow while startRow > firstRow - break if @isLineCommentedAtBufferRow(startRow - 1) != isOriginalRowComment + break if @isLineCommentedAtBufferRow(startRow - 1) isnt isOriginalRowComment break unless /\w/.test(@editor.lineTextForBufferRow(startRow - 1)) startRow-- endRow = bufferRow lastRow = @editor.getLastBufferRow() while endRow < lastRow - break if @isLineCommentedAtBufferRow(endRow + 1) != isOriginalRowComment + break if @isLineCommentedAtBufferRow(endRow + 1) isnt isOriginalRowComment break unless /\w/.test(@editor.lineTextForBufferRow(endRow + 1)) endRow++ diff --git a/src/menu-manager.coffee b/src/menu-manager.coffee index 1991cba95..568d726a4 100644 --- a/src/menu-manager.coffee +++ b/src/menu-manager.coffee @@ -164,7 +164,7 @@ class MenuManager filtered = {} for key, bindings of keystrokesByCommand for binding in bindings - continue if binding.indexOf(' ') != -1 + continue if binding.indexOf(' ') isnt -1 filtered[key] ?= [] filtered[key].push(binding) diff --git a/src/notification.coffee b/src/notification.coffee index 0ca82e724..43044c182 100644 --- a/src/notification.coffee +++ b/src/notification.coffee @@ -27,9 +27,9 @@ class Notification getDetail: -> @options.detail isEqual: (other) -> - @getMessage() == other.getMessage() \ - and @getType() == other.getType() \ - and @getDetail() == other.getDetail() + @getMessage() is other.getMessage() \ + and @getType() is other.getType() \ + and @getDetail() is other.getDetail() dismiss: -> return unless @isDismissable() and not @isDismissed() diff --git a/src/overlay-manager.coffee b/src/overlay-manager.coffee index 6dc36b998..21a484fbe 100644 --- a/src/overlay-manager.coffee +++ b/src/overlay-manager.coffee @@ -37,7 +37,7 @@ class OverlayManager # The same node may be used in more than one overlay. This steals the node # back if it has been displayed in another overlay. - overlayNode.appendChild(itemView) if overlayNode.childNodes.length == 0 + overlayNode.appendChild(itemView) if overlayNode.childNodes.length is 0 cachedOverlay.pixelPosition = pixelPosition overlayNode.style.top = pixelPosition.top + 'px' diff --git a/src/pane-axis-element.coffee b/src/pane-axis-element.coffee index ba0cb4b19..569c36534 100644 --- a/src/pane-axis-element.coffee +++ b/src/pane-axis-element.coffee @@ -31,7 +31,7 @@ class PaneAxisElement extends HTMLElement view = atom.views.getView(child) view.remove() - childReplaced: ({index, oldChild, newChild}) -> + childReplaced: ({index, oldChild, newChild}) -> focusedElement = document.activeElement if @hasFocus() @childRemoved({child: oldChild, index}) @childAdded({child: newChild, index}) diff --git a/src/project.coffee b/src/project.coffee index 5094ef8ce..a02c7d747 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -339,7 +339,7 @@ class Project extends Model @findBufferForPath(@resolvePath(filePath))?.isModified() findBufferForPath: (filePath) -> - _.find @buffers, (buffer) -> buffer.getPath() == filePath + _.find @buffers, (buffer) -> buffer.getPath() is filePath # Only to be used in specs bufferForPathSync: (filePath) -> diff --git a/src/scan-handler.coffee b/src/scan-handler.coffee index 71917cc6e..74e15d930 100644 --- a/src/scan-handler.coffee +++ b/src/scan-handler.coffee @@ -34,7 +34,7 @@ module.exports = (rootPaths, regexSource, options) -> scanner.on 'path-found', -> pathsSearched++ - if pathsSearched % PATHS_COUNTER_SEARCHED_CHUNK == 0 + if pathsSearched % PATHS_COUNTER_SEARCHED_CHUNK is 0 emit('scan:paths-searched', pathsSearched) search regex, scanner, searcher, -> diff --git a/src/selection.coffee b/src/selection.coffee index 91f942524..f806acf43 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -110,7 +110,7 @@ class Selection extends Model range = @getBufferRange() start = range.start.row end = range.end.row - end = Math.max(start, end - 1) if range.end.column == 0 + end = Math.max(start, end - 1) if range.end.column is 0 [start, end] getTailScreenPosition: -> @@ -386,7 +386,7 @@ class Selection extends Model if autoIndentFirstLine @editor.setIndentationForBufferRow(oldBufferRange.start.row, desiredIndentLevel) - if options.autoIndentNewline and text == '\n' + if options.autoIndentNewline and text is '\n' currentIndentation = @editor.indentationForBufferRow(newBufferRange.start.row) @editor.autoIndentBufferRow(newBufferRange.end.row, preserveLeadingWhitespace: true, skipBlankLines: false) if @editor.indentationForBufferRow(newBufferRange.end.row) < currentIndentation @@ -601,7 +601,7 @@ class Selection extends Model # of levels. Leaves the first line unchanged. adjustIndent: (lines, indentAdjustment) -> for line, i in lines - if indentAdjustment == 0 or line is '' + if indentAdjustment is 0 or line is '' continue else if indentAdjustment > 0 lines[i] = @editor.buildIndentString(indentAdjustment) + line @@ -620,8 +620,8 @@ class Selection extends Model # * `options` (optional) {Object} with the keys: # * `autoIndent` If `true`, the line is indented to an automatically-inferred # level. Otherwise, {TextEditor::getTabText} is inserted. - indent: ({ autoIndent }={}) -> - { row, column } = @cursor.getBufferPosition() + indent: ({autoIndent}={}) -> + {row, column} = @cursor.getBufferPosition() if @isEmpty() @cursor.skipLeadingWhitespace() @@ -640,7 +640,7 @@ class Selection extends Model indentSelectedRows: -> [start, end] = @getBufferRowRange() for row in [start..end] - @editor.buffer.insert([row, 0], @editor.getTabText()) unless @editor.buffer.lineLengthForRow(row) == 0 + @editor.buffer.insert([row, 0], @editor.getTabText()) unless @editor.buffer.lineLengthForRow(row) is 0 return ### diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index bd0e0ee86..4d04dc98f 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -117,7 +117,7 @@ class TextEditorComponent @cursorMoved = false @selectionChanged = false - if @editor.getLastSelection()? and !@editor.getLastSelection().isEmpty() + if @editor.getLastSelection()? and not @editor.getLastSelection().isEmpty() @domNode.classList.add('has-selection') else @domNode.classList.remove('has-selection') diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 2ca7d74bb..be8376ccb 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -949,14 +949,14 @@ class TextEditor extends Model # For each selection, if the selection is empty, converts the containing word # to upper case. Otherwise convert the selected text to upper case. upperCase: -> - @replaceSelectedText selectWordIfEmpty:true, (text) -> text.toUpperCase() + @replaceSelectedText selectWordIfEmpty: true, (text) -> text.toUpperCase() # Extended: Convert the selected text to lower case. # # For each selection, if the selection is empty, converts the containing word # to upper case. Otherwise convert the selected text to upper case. lowerCase: -> - @replaceSelectedText selectWordIfEmpty:true, (text) -> text.toLowerCase() + @replaceSelectedText selectWordIfEmpty: true, (text) -> text.toLowerCase() # Extended: Toggle line comments for rows intersecting selections. # @@ -2464,7 +2464,7 @@ class TextEditor extends Model {cursor} = selection if indentBasis? containsNewlines = text.indexOf('\n') isnt -1 - if containsNewlines or !cursor.hasPrecedingCharactersOnLine() + if containsNewlines or not cursor.hasPrecedingCharactersOnLine() options.indentBasis ?= indentBasis if fullLine and selection.isEmpty() diff --git a/src/token.coffee b/src/token.coffee index 941daf032..8aa4a8706 100644 --- a/src/token.coffee +++ b/src/token.coffee @@ -27,7 +27,7 @@ class Token isEqual: (other) -> # TODO: scopes is deprecated. This is here for the sake of lang package tests - @value == other.value and _.isEqual(@scopes, other.scopes) and !!@isAtomic == !!other.isAtomic + @value is other.value and _.isEqual(@scopes, other.scopes) and !!@isAtomic is !!other.isAtomic isBracket: -> /^meta\.brace\b/.test(_.last(@scopes)) diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index b9d1d01f6..521cdb204 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -154,11 +154,11 @@ class TokenizedBuffer extends Model loop previousStack = @stackForRow(row) @tokenizedLines[row] = @buildTokenizedLineForRow(row, @stackForRow(row - 1)) - if --rowsRemaining == 0 + if --rowsRemaining is 0 filledRegion = false endRow = row break - if row == lastRow or _.isEqual(@stackForRow(row), previousStack) + if row is lastRow or _.isEqual(@stackForRow(row), previousStack) filledRegion = true endRow = row break @@ -280,7 +280,7 @@ class TokenizedBuffer extends Model ruleStack = startingStack stopTokenizingAt = startRow + @chunkSize tokenizedLines = for row in [startRow..endRow] - if (ruleStack or row == 0) and row < stopTokenizingAt + if (ruleStack or row is 0) and row < stopTokenizingAt screenLine = @buildTokenizedLineForRow(row, ruleStack) ruleStack = screenLine.ruleStack else @@ -390,7 +390,7 @@ class TokenizedBuffer extends Model iterateTokensInBufferRange: (bufferRange, iterator) -> bufferRange = Range.fromObject(bufferRange) - { start, end } = bufferRange + {start, end} = bufferRange keepLooping = true stop = -> keepLooping = false @@ -399,13 +399,13 @@ class TokenizedBuffer extends Model bufferColumn = 0 for token in @tokenizedLines[bufferRow].tokens startOfToken = new Point(bufferRow, bufferColumn) - iterator(token, startOfToken, { stop }) if bufferRange.containsPoint(startOfToken) + iterator(token, startOfToken, {stop}) if bufferRange.containsPoint(startOfToken) return unless keepLooping bufferColumn += token.bufferDelta backwardsIterateTokensInBufferRange: (bufferRange, iterator) -> bufferRange = Range.fromObject(bufferRange) - { start, end } = bufferRange + {start, end} = bufferRange keepLooping = true stop = -> keepLooping = false @@ -415,20 +415,20 @@ class TokenizedBuffer extends Model for token in new Array(@tokenizedLines[bufferRow].tokens...).reverse() bufferColumn -= token.bufferDelta startOfToken = new Point(bufferRow, bufferColumn) - iterator(token, startOfToken, { stop }) if bufferRange.containsPoint(startOfToken) + iterator(token, startOfToken, {stop}) if bufferRange.containsPoint(startOfToken) return unless keepLooping findOpeningBracket: (startBufferPosition) -> range = [[0,0], startBufferPosition] position = null depth = 0 - @backwardsIterateTokensInBufferRange range, (token, startPosition, { stop }) -> + @backwardsIterateTokensInBufferRange range, (token, startPosition, {stop}) -> if token.isBracket() - if token.value == '}' + if token.value is '}' depth++ - else if token.value == '{' + else if token.value is '{' depth-- - if depth == 0 + if depth is 0 position = startPosition stop() position @@ -437,13 +437,13 @@ class TokenizedBuffer extends Model range = [startBufferPosition, @buffer.getEndPosition()] position = null depth = 0 - @iterateTokensInBufferRange range, (token, startPosition, { stop }) -> + @iterateTokensInBufferRange range, (token, startPosition, {stop}) -> if token.isBracket() - if token.value == '{' + if token.value is '{' depth++ - else if token.value == '}' + else if token.value is '}' depth-- - if depth == 0 + if depth is 0 position = startPosition stop() position diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 074e7a785..b81d972a0 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -52,9 +52,9 @@ class TokenizedLine # # Returns a {Number} representing the clipped column. clipScreenColumn: (column, options={}) -> - return 0 if @tokens.length == 0 + return 0 if @tokens.length is 0 - { clip } = options + {clip} = options column = Math.min(column, @getMaxScreenColumn()) tokenStartColumn = 0 @@ -65,9 +65,9 @@ class TokenizedLine if @isColumnInsideSoftWrapIndentation(tokenStartColumn) @softWrapIndentationDelta else if token.isAtomic and tokenStartColumn < column - if clip == 'forward' + if clip is 'forward' tokenStartColumn + token.screenDelta - else if clip == 'backward' + else if clip is 'backward' tokenStartColumn else #'closest' if column > tokenStartColumn + (token.screenDelta / 2) @@ -140,7 +140,7 @@ class TokenizedLine indentTokens softWrapAt: (column, hangingIndent) -> - return [new TokenizedLine([], '', [0, 0], [0, 0]), this] if column == 0 + return [new TokenizedLine([], '', [0, 0], [0, 0]), this] if column is 0 rightTokens = new Array(@tokens...) leftTokens = [] @@ -179,7 +179,7 @@ class TokenizedLine @lineEnding is null isColumnInsideSoftWrapIndentation: (column) -> - return false if @softWrapIndentationTokens.length == 0 + return false if @softWrapIndentationTokens.length is 0 column < @softWrapIndentationDelta @@ -190,7 +190,7 @@ class TokenizedLine _.reduce @softWrapIndentationTokens, ((acc, token) -> acc + token.screenDelta), 0 hasOnlySoftWrapIndentation: -> - @tokens.length == @softWrapIndentationTokens.length + @tokens.length is @softWrapIndentationTokens.length tokenAtBufferColumn: (bufferColumn) -> @tokens[@tokenIndexAtBufferColumn(bufferColumn)] diff --git a/src/window-event-handler.coffee b/src/window-event-handler.coffee index 593d33476..96518c446 100644 --- a/src/window-event-handler.coffee +++ b/src/window-event-handler.coffee @@ -85,7 +85,7 @@ class WindowEventHandler if process.platform in ['win32', 'linux'] @subscribeToCommand $(window), 'window:toggle-menu-bar', -> - atom.config.set('core.autoHideMenuBar', !atom.config.get('core.autoHideMenuBar')) + atom.config.set('core.autoHideMenuBar', not atom.config.get('core.autoHideMenuBar')) @subscribeToCommand $(document), 'core:focus-next', @focusNext diff --git a/src/workspace.coffee b/src/workspace.coffee index 6a7a40a0c..b18799160 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -400,7 +400,7 @@ class Workspace extends Model uri = atom.project.resolvePath(uri) item = @getActivePane().itemForURI(uri) if uri - item ?= opener(uri, options) for opener in @getOpeners() when !item + item ?= opener(uri, options) for opener in @getOpeners() when not item item ?= atom.project.openSync(uri, {initialLine, initialColumn}) @getActivePane().activateItem(item) @@ -419,7 +419,7 @@ class Workspace extends Model if uri? item = pane.itemForURI(uri) - item ?= opener(uri, options) for opener in @getOpeners() when !item + item ?= opener(uri, options) for opener in @getOpeners() when not item try item ?= atom.project.open(uri, options) @@ -865,8 +865,8 @@ class Workspace extends Model openPaths = (buffer.getPath() for buffer in atom.project.getBuffers()) outOfProcessPaths = _.difference(filePaths, openPaths) - inProcessFinished = !openPaths.length - outOfProcessFinished = !outOfProcessPaths.length + inProcessFinished = not openPaths.length + outOfProcessFinished = not outOfProcessPaths.length checkFinished = -> deferred.resolve() if outOfProcessFinished and inProcessFinished From 2bb2022b5be282982812fe4c851a5c8f1b6a7372 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Tue, 7 Apr 2015 00:05:19 -0400 Subject: [PATCH 0513/1783] :shirt: --- build/tasks/spec-task.coffee | 2 +- build/tasks/task-helpers.coffee | 4 ++-- src/atom.coffee | 2 +- src/config.coffee | 2 +- src/grammar-registry.coffee | 2 +- src/tokenized-buffer.coffee | 2 +- src/workspace-element.coffee | 4 ++-- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/build/tasks/spec-task.coffee b/build/tasks/spec-task.coffee index 73bb63f70..b5547fe64 100644 --- a/build/tasks/spec-task.coffee +++ b/build/tasks/spec-task.coffee @@ -138,4 +138,4 @@ module.exports = (grunt) -> if process.platform is 'win32' and process.env.JANKY_SHA1 done() else - done(!coreSpecFailed and failedPackages.length == 0) + done(not coreSpecFailed and failedPackages.length is 0) diff --git a/build/tasks/task-helpers.coffee b/build/tasks/task-helpers.coffee index a862f291f..2819c952a 100644 --- a/build/tasks/task-helpers.coffee +++ b/build/tasks/task-helpers.coffee @@ -55,9 +55,9 @@ module.exports = (grunt) -> proc.stderr.on 'data', (data) -> stderr.push(data.toString()) proc.on 'error', (processError) -> error ?= processError proc.on 'close', (exitCode, signal) -> - error ?= new Error(signal) if exitCode != 0 + error ?= new Error(signal) if exitCode isnt 0 results = {stderr: stderr.join(''), stdout: stdout.join(''), code: exitCode} - grunt.log.error results.stderr if exitCode != 0 + grunt.log.error results.stderr if exitCode isnt 0 callback(error, results, exitCode) isAtomPackage: (packagePath) -> diff --git a/src/atom.coffee b/src/atom.coffee index 88c8257e1..b02d04d5c 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -846,7 +846,7 @@ class Atom extends Model setAutoHideMenuBar: (autoHide) -> ipc.send('call-window-method', 'setAutoHideMenuBar', autoHide) - ipc.send('call-window-method', 'setMenuBarVisibility', !autoHide) + ipc.send('call-window-method', 'setMenuBarVisibility', not autoHide) if includeDeprecatedAPIs # Deprecated: Callers should be converted to use atom.deserializers diff --git a/src/config.coffee b/src/config.coffee index 50d8caba3..cb2d8ab76 100644 --- a/src/config.coffee +++ b/src/config.coffee @@ -1190,7 +1190,7 @@ if Grim.includeDeprecatedAPIs Config::toggle = (keyPath) -> Grim.deprecate 'Config::toggle is no longer supported. Please remove from your code.' - @set(keyPath, !@get(keyPath)) + @set(keyPath, not @get(keyPath)) Config::unobserve = (keyPath) -> Grim.deprecate 'Config::unobserve no longer does anything. Call `.dispose()` on the object returned by Config::observe instead.' diff --git a/src/grammar-registry.coffee b/src/grammar-registry.coffee index 8272dce47..568de483a 100644 --- a/src/grammar-registry.coffee +++ b/src/grammar-registry.coffee @@ -57,7 +57,7 @@ if includeDeprecatedAPIs atom.config.scopedSettingsStore GrammarRegistry::addProperties = (args...) -> - args.unshift(null) if args.length == 2 + args.unshift(null) if args.length is 2 deprecate 'Consider using atom.config.set() instead. A direct (but private) replacement is available at atom.config.addScopedSettings().' atom.config.addScopedSettings(args...) diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 521cdb204..d9f1bcba7 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -226,7 +226,7 @@ class TokenizedBuffer extends Model [start, end] = @updateFoldableStatus(start, end + delta) end -= delta - event = { start, end, delta, bufferChange: e } + event = {start, end, delta, bufferChange: e} @emit 'changed', event if Grim.includeDeprecatedAPIs @emitter.emit 'did-change', event diff --git a/src/workspace-element.coffee b/src/workspace-element.coffee index 5f127d970..5768b2dbb 100644 --- a/src/workspace-element.coffee +++ b/src/workspace-element.coffee @@ -156,9 +156,9 @@ atom.commands.add 'atom-workspace', 'window:focus-pane-on-left': -> @focusPaneViewOnLeft() 'window:focus-pane-on-right': -> @focusPaneViewOnRight() 'window:save-all': -> @getModel().saveAll() - 'window:toggle-invisibles': -> atom.config.set("editor.showInvisibles", !atom.config.get("editor.showInvisibles")) + 'window:toggle-invisibles': -> atom.config.set("editor.showInvisibles", not atom.config.get("editor.showInvisibles")) 'window:log-deprecation-warnings': -> Grim.logDeprecations() - 'window:toggle-auto-indent': -> atom.config.set("editor.autoIndent", !atom.config.get("editor.autoIndent")) + 'window:toggle-auto-indent': -> atom.config.set("editor.autoIndent", not atom.config.get("editor.autoIndent")) 'pane:reopen-closed-item': -> @getModel().reopenItem() 'core:close': -> @getModel().destroyActivePaneItemOrEmptyPane() 'core:save': -> @getModel().saveActivePaneItem() From ef19b6ab223e7a9488cd8fa194f507d5f4bbc284 Mon Sep 17 00:00:00 2001 From: simurai Date: Tue, 7 Apr 2015 15:20:29 +0900 Subject: [PATCH 0514/1783] :arrow_up: find-and-replace@v0.160.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f8ebc304d..8f75a4a85 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "encoding-selector": "0.19.0", "exception-reporting": "0.24.0", "feedback": "0.38.0", - "find-and-replace": "0.159.0", + "find-and-replace": "0.160.0", "fuzzy-finder": "0.72.0", "git-diff": "0.54.0", "go-to-line": "0.30.0", From 2e86e22d46fb22ab1a4acd8e011155ccf41b35ff Mon Sep 17 00:00:00 2001 From: simurai Date: Tue, 7 Apr 2015 16:42:50 +0900 Subject: [PATCH 0515/1783] :arrrow_up: one-dark-ui@v0.6.1 one-light-ui@v0.5.1 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 8f75a4a85..9dc9ad061 100644 --- a/package.json +++ b/package.json @@ -76,10 +76,10 @@ "atom-light-ui": "0.41.0", "base16-tomorrow-dark-theme": "0.25.0", "base16-tomorrow-light-theme": "0.8.0", - "one-dark-ui": "0.6.0", + "one-dark-ui": "0.6.1", "one-dark-syntax": "0.3.0", "one-light-syntax": "0.4.0", - "one-light-ui": "0.5.0", + "one-light-ui": "0.5.1", "solarized-dark-syntax": "0.32.0", "solarized-light-syntax": "0.19.0", "archive-view": "0.55.0", From 859a6dcf6867b4b930b7c96215987b1200cc62e8 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 7 Apr 2015 10:48:18 +0200 Subject: [PATCH 0516/1783] Use script/cibuild --- .travis.yml | 8 +------- build/tasks/spec-task.coffee | 2 +- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index e86ff77c1..535414f56 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,8 @@ language: objective-c -install: script/build - -script: ./apm/node_modules/.bin/apm test --path ./atom.sh +script: script/cibuild notifications: email: on_success: never on_failure: change - -cache: - directories: - - node_modules diff --git a/build/tasks/spec-task.coffee b/build/tasks/spec-task.coffee index 73bb63f70..49c9f8592 100644 --- a/build/tasks/spec-task.coffee +++ b/build/tasks/spec-task.coffee @@ -4,7 +4,7 @@ path = require 'path' _ = require 'underscore-plus' async = require 'async' -concurrency = 2 +concurrency = 1 module.exports = (grunt) -> {isAtomPackage, spawn} = require('./task-helpers')(grunt) From f3a7cc1b9de9a662696094024d0d1493017b3c47 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 7 Apr 2015 11:24:12 +0200 Subject: [PATCH 0517/1783] wip: focus on integration specs only --- spec/integration/startup-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/integration/startup-spec.coffee b/spec/integration/startup-spec.coffee index e0df3ad9b..4529e5f0b 100644 --- a/spec/integration/startup-spec.coffee +++ b/spec/integration/startup-spec.coffee @@ -10,7 +10,7 @@ AtomHome = temp.mkdirSync('atom-home') fs.writeFileSync(path.join(AtomHome, 'config.cson'), fs.readFileSync(path.join(__dirname, 'fixtures', 'atom-home', 'config.cson'))) runAtom = require("./helpers/start-atom") -describe "Starting Atom", -> +fdescribe "Starting Atom", -> [tempDirPath, otherTempDirPath] = [] beforeEach -> From a090a81767229c4c8b9ffd8f6e57f934c890090d Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 7 Apr 2015 11:46:42 +0200 Subject: [PATCH 0518/1783] Bump chromedriver wait timeout --- spec/integration/helpers/start-atom.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/integration/helpers/start-atom.coffee b/spec/integration/helpers/start-atom.coffee index 4be2efab8..09ba2296a 100644 --- a/spec/integration/helpers/start-atom.coffee +++ b/spec/integration/helpers/start-atom.coffee @@ -114,7 +114,7 @@ module.exports = (args, env, fn) -> chromedriver.stderr.on "close", -> resolve(errorCode) - waits(100) + waits(5000) waitsFor("webdriver to finish", (done) -> finish = once -> @@ -137,4 +137,4 @@ module.exports = (args, env, fn) -> finish() fn(client.init()).then(finish) - , 30000) + , 60000) From 5e5acb7432ff6cfe0f67468c5d0ab66e85caa0d7 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 7 Apr 2015 12:24:41 +0200 Subject: [PATCH 0519/1783] :art: Rename to `TextEditor#mergeSelectionsOnSameRows` * :fire: Delete `Selection#intersectsByRowWith` --- src/selection.coffee | 12 ------------ src/text-editor.coffee | 6 +++--- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/selection.coffee b/src/selection.coffee index 49aa2c6b1..91f942524 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -162,18 +162,6 @@ class Selection extends Model intersectsScreenRow: (screenRow) -> @getScreenRange().intersectsRow(screenRow) - # Public: Identifies if this selection's rows intersects with another selection's rows. - # - # * `otherSelection` A {Selection} to check against. - # - # Returns a {Boolean} - intersectsByRowWith: (otherSelection) -> - otherScreenRange = otherSelection.getScreenRange() - - @getScreenRange().intersectsRowRange( - otherScreenRange.start.row, otherScreenRange.end.row - ) - # Public: Identifies if a selection intersects with another selection. # # * `otherSelection` A {Selection} to check against. diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 6395ccc32..8936e125a 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -1026,7 +1026,7 @@ class TextEditor extends Model # Extended: Delete all lines intersecting selections. deleteLine: -> - @mergeIntersectingSelectionsByRow() + @mergeSelectionsOnSameRows() @mutateSelectedText (selection) -> selection.deleteLine() ### @@ -2054,9 +2054,9 @@ class TextEditor extends Model previousSelection.intersectsWith(currentSelection, exclusive) - mergeIntersectingSelectionsByRow: (args...) -> + mergeSelectionsOnSameRows: (args...) -> @mergeSelections args..., (previousSelection, currentSelection) -> - previousSelection.intersectsByRowWith(currentSelection) + previousSelection.intersectsScreenRowRange(currentSelection.getBufferRowRange()...) mergeSelections: (args...) -> mergePredicate = args.pop() From a244c0fa072bbd36122849268e58766f402672ef Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 7 Apr 2015 12:30:51 +0200 Subject: [PATCH 0520/1783] :fire: Delete useless line in spec --- spec/text-editor-spec.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 05cc666c3..3dfbce82e 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -3373,7 +3373,6 @@ describe "TextEditor", -> it "deletes a line only once when multiple selections are on the same line", -> line1 = buffer.lineForRow(1) count = buffer.getLineCount() - editor.getLastCursor().moveToTop() editor.setSelectedBufferRanges([ [[0, 1], [0, 2]], [[0, 4], [0, 5]] From 9dddce495e19dfffb7cb494218dbd41ff867d1b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=C5=BDu=C5=BEak?= Date: Tue, 7 Apr 2015 12:41:06 +0200 Subject: [PATCH 0521/1783] :arrow_up: notifications@0.36.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9dc9ad061..9d71a3dc4 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,7 @@ "link": "0.30.0", "markdown-preview": "0.148.0", "metrics": "0.45.0", - "notifications": "0.35.0", + "notifications": "0.36.0", "open-on-github": "0.36.0", "package-generator": "0.38.0", "release-notes": "0.52.0", From 662efb3d6ec8b9ea5b7abfbfccd254c15e90b45a Mon Sep 17 00:00:00 2001 From: simurai Date: Tue, 7 Apr 2015 19:57:24 +0900 Subject: [PATCH 0522/1783] :arrrow_up: one-dark-ui@v0.6.2 one-light-ui@v0.5.2 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 9d71a3dc4..cf2ae12b4 100644 --- a/package.json +++ b/package.json @@ -76,10 +76,10 @@ "atom-light-ui": "0.41.0", "base16-tomorrow-dark-theme": "0.25.0", "base16-tomorrow-light-theme": "0.8.0", - "one-dark-ui": "0.6.1", + "one-dark-ui": "0.6.2", "one-dark-syntax": "0.3.0", "one-light-syntax": "0.4.0", - "one-light-ui": "0.5.1", + "one-light-ui": "0.5.2", "solarized-dark-syntax": "0.32.0", "solarized-light-syntax": "0.19.0", "archive-view": "0.55.0", From 36641884f904f6ae1f8744ab77612e8599653bed Mon Sep 17 00:00:00 2001 From: Ivan Zuzak Date: Tue, 7 Apr 2015 13:37:30 +0200 Subject: [PATCH 0523/1783] Point in-app link for reporting issues to CONTRIBUTING guide --- src/browser/atom-application.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 45c0c8b5c..9922a1380 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -169,7 +169,7 @@ class AtomApplication @on 'application:open-roadmap', -> require('shell').openExternal('https://atom.io/roadmap?app') @on 'application:open-faq', -> require('shell').openExternal('https://atom.io/faq') @on 'application:open-terms-of-use', -> require('shell').openExternal('https://atom.io/terms') - @on 'application:report-issue', -> require('shell').openExternal('https://github.com/atom/atom/issues/new') + @on 'application:report-issue', -> require('shell').openExternal('https://github.com/atom/atom/blob/master/CONTRIBUTING.md#submitting-issues') @on 'application:search-issues', -> require('shell').openExternal('https://github.com/issues?q=+is%3Aissue+user%3Aatom') @on 'application:install-update', -> @autoUpdateManager.install() From 4a95dd1234a5bbabed09583d387e8de6601ae7fd Mon Sep 17 00:00:00 2001 From: Ivan Zuzak Date: Tue, 7 Apr 2015 13:38:57 +0200 Subject: [PATCH 0524/1783] Update CONTRIBUTING guide section on reporting issues --- CONTRIBUTING.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2a5ba9945..66080c614 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,13 +4,14 @@ The following is a set of guidelines for contributing to Atom and its packages, which are hosted in the [Atom Organization](https://github.com/atom) on GitHub. -If you're unsure which package is causing your problem or if you're having an -issue with Atom core, please open an issue on the [main atom repository](https://github.com/atom/atom/issues). These are just guidelines, not rules, use your best judgment and feel free to propose changes to this document in a pull request. ## Submitting Issues +* You can create an issue [here](https://github.com/atom/atom/issues/new), but + before doing that please read the notes below on debugging and submitting issues, + and include as many details as possible with your report. * Check the [debugging guide](https://atom.io/docs/latest/hacking-atom-debugging) for tips on debugging. You might be able to find the cause of the problem and fix things yourself. @@ -24,7 +25,8 @@ propose changes to this document in a pull request. will be logged. If you can reproduce the error, use this approach to get the full stack trace and include it in the issue. * On Mac, check Console.app for stack traces to include if reporting a crash. -* Perform a cursory search to see if a similar issue has already been submitted. +* Perform a [cursory search](https://github.com/issues?q=+is%3Aissue+user%3Aatom) + to see if a similar issue has already been submitted. * Please setup a [profile picture](https://help.github.com/articles/how-do-i-set-up-my-profile-picture) to make yourself recognizable and so we can all get to know each other better. @@ -38,6 +40,10 @@ many packages and themes that are stored in other repos under the [language-javascript](https://github.com/atom/language-javascript), and [atom-light-ui](https://github.com/atom/atom-light-ui). +If your issue is related to a specific package, open an issue on that package's +issue tracker. If you're unsure which package is causing your problem or if +you're having an issue with Atom core, open an issue on this repository. + For more information on how to work with Atom's official packages, see [Contributing to Atom Packages](https://github.com/atom/atom/blob/master/docs/contributing-to-packages.md) From 32ae7945ff5a9e579a62d1d10cf05056b17c675c Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 7 Apr 2015 13:48:50 +0200 Subject: [PATCH 0525/1783] Fine tune waiting time --- spec/integration/helpers/start-atom.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/integration/helpers/start-atom.coffee b/spec/integration/helpers/start-atom.coffee index 09ba2296a..c4e4fb28e 100644 --- a/spec/integration/helpers/start-atom.coffee +++ b/spec/integration/helpers/start-atom.coffee @@ -114,7 +114,7 @@ module.exports = (args, env, fn) -> chromedriver.stderr.on "close", -> resolve(errorCode) - waits(5000) + waits(1000) waitsFor("webdriver to finish", (done) -> finish = once -> @@ -137,4 +137,4 @@ module.exports = (args, env, fn) -> finish() fn(client.init()).then(finish) - , 60000) + , 30000) From 722705bb4cf5b7ce3194b304a3da636322315c3d Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 7 Apr 2015 14:40:36 +0200 Subject: [PATCH 0526/1783] Reduce chromedriver waiting time to 500ms --- spec/integration/helpers/start-atom.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/integration/helpers/start-atom.coffee b/spec/integration/helpers/start-atom.coffee index c4e4fb28e..1ac122726 100644 --- a/spec/integration/helpers/start-atom.coffee +++ b/spec/integration/helpers/start-atom.coffee @@ -114,7 +114,7 @@ module.exports = (args, env, fn) -> chromedriver.stderr.on "close", -> resolve(errorCode) - waits(1000) + waits(500) waitsFor("webdriver to finish", (done) -> finish = once -> From 127253bea38079294e9940934789eb7cb1beebcc Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 7 Apr 2015 15:01:46 +0200 Subject: [PATCH 0527/1783] Revert "Reduce chromedriver waiting time to 500ms" This reverts commit 722705bb4cf5b7ce3194b304a3da636322315c3d. --- spec/integration/helpers/start-atom.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/integration/helpers/start-atom.coffee b/spec/integration/helpers/start-atom.coffee index 1ac122726..c4e4fb28e 100644 --- a/spec/integration/helpers/start-atom.coffee +++ b/spec/integration/helpers/start-atom.coffee @@ -114,7 +114,7 @@ module.exports = (args, env, fn) -> chromedriver.stderr.on "close", -> resolve(errorCode) - waits(500) + waits(1000) waitsFor("webdriver to finish", (done) -> finish = once -> From efa2a34fd673d161770ca0e64009613858527549 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 7 Apr 2015 15:36:54 +0200 Subject: [PATCH 0528/1783] Use a large value in `waits` ...to confirm that it is the culprit of Travis build errors. --- spec/integration/helpers/start-atom.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/integration/helpers/start-atom.coffee b/spec/integration/helpers/start-atom.coffee index c4e4fb28e..1fa3db599 100644 --- a/spec/integration/helpers/start-atom.coffee +++ b/spec/integration/helpers/start-atom.coffee @@ -114,7 +114,7 @@ module.exports = (args, env, fn) -> chromedriver.stderr.on "close", -> resolve(errorCode) - waits(1000) + waits(5000) waitsFor("webdriver to finish", (done) -> finish = once -> From 1c7b473243748f6e3be47d2e7843cfd578bdb127 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 7 Apr 2015 17:46:44 +0200 Subject: [PATCH 0529/1783] Wait for chromedriver to initialize Via a polling mechanism inspired by https://github.com/SeleniumHQ/selenium/blob/master/dotnet/src/webdriver/DriverService.cs#L173-205 --- spec/integration/helpers/start-atom.coffee | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/spec/integration/helpers/start-atom.coffee b/spec/integration/helpers/start-atom.coffee index 1fa3db599..8c5e45d15 100644 --- a/spec/integration/helpers/start-atom.coffee +++ b/spec/integration/helpers/start-atom.coffee @@ -1,4 +1,5 @@ path = require "path" +http = require "http" temp = require("temp").track() remote = require "remote" async = require "async" @@ -11,6 +12,16 @@ AtomLauncherPath = path.join(__dirname, "..", "helpers", "atom-launcher.sh") ChromedriverPath = path.resolve(__dirname, '..', '..', '..', 'atom-shell', 'chromedriver', 'chromedriver') SocketPath = path.join(temp.mkdirSync("socket-dir"), "atom-#{process.env.USER}.sock") ChromedriverPort = 9515 +ChromedriverURLBase = "/wd/hub" +ChromedriverStatusURL = "http://localhost:#{ChromedriverPort}#{ChromedriverURLBase}/status" + +pollChromeDriver = (done) -> + http.get(ChromedriverStatusURL, (response) -> + if response.statusCode is 200 + done() + else + pollChromeDriver(done) + ) buildAtomClient = (args, env) -> client = webdriverio.remote( @@ -101,7 +112,7 @@ module.exports = (args, env, fn) -> chromedriver = spawn(ChromedriverPath, [ "--verbose", "--port=#{ChromedriverPort}", - "--url-base=/wd/hub" + "--url-base=#{ChromedriverURLBase}" ]) chromedriverLogs = [] @@ -114,7 +125,7 @@ module.exports = (args, env, fn) -> chromedriver.stderr.on "close", -> resolve(errorCode) - waits(5000) + waitsFor("webdriver to start", pollChromeDriver, 5000) waitsFor("webdriver to finish", (done) -> finish = once -> From d4949667597d4464bd350e84fe7c74859d220018 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 7 Apr 2015 17:53:05 +0200 Subject: [PATCH 0530/1783] Relax polling to check only every 100ms --- spec/integration/helpers/start-atom.coffee | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/spec/integration/helpers/start-atom.coffee b/spec/integration/helpers/start-atom.coffee index 8c5e45d15..9993181a8 100644 --- a/spec/integration/helpers/start-atom.coffee +++ b/spec/integration/helpers/start-atom.coffee @@ -16,12 +16,15 @@ ChromedriverURLBase = "/wd/hub" ChromedriverStatusURL = "http://localhost:#{ChromedriverPort}#{ChromedriverURLBase}/status" pollChromeDriver = (done) -> - http.get(ChromedriverStatusURL, (response) -> - if response.statusCode is 200 - done() - else - pollChromeDriver(done) - ) + checkStatus = -> + http.get(ChromedriverStatusURL, (response) -> + if response.statusCode is 200 + done() + else + pollChromeDriver(done) + ) + + setTimeout(checkStatus, 100) buildAtomClient = (args, env) -> client = webdriverio.remote( From 4c12b6767e6fea52a5898e2dc2061319d6abb5ee Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 7 Apr 2015 17:55:01 +0200 Subject: [PATCH 0531/1783] Stop focusing on integration specs --- spec/integration/startup-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/integration/startup-spec.coffee b/spec/integration/startup-spec.coffee index 4529e5f0b..e0df3ad9b 100644 --- a/spec/integration/startup-spec.coffee +++ b/spec/integration/startup-spec.coffee @@ -10,7 +10,7 @@ AtomHome = temp.mkdirSync('atom-home') fs.writeFileSync(path.join(AtomHome, 'config.cson'), fs.readFileSync(path.join(__dirname, 'fixtures', 'atom-home', 'config.cson'))) runAtom = require("./helpers/start-atom") -fdescribe "Starting Atom", -> +describe "Starting Atom", -> [tempDirPath, otherTempDirPath] = [] beforeEach -> From cbf499243e0787b33ca486ec6c9a396d4cd74f31 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 7 Apr 2015 18:08:51 +0200 Subject: [PATCH 0532/1783] Use screen ranges consistently --- src/text-editor.coffee | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 8936e125a..7606cea7e 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -2056,7 +2056,9 @@ class TextEditor extends Model mergeSelectionsOnSameRows: (args...) -> @mergeSelections args..., (previousSelection, currentSelection) -> - previousSelection.intersectsScreenRowRange(currentSelection.getBufferRowRange()...) + screenRange = currentSelection.getScreenRange() + + previousSelection.intersectsScreenRowRange(screenRange.start.row, screenRange.end.row) mergeSelections: (args...) -> mergePredicate = args.pop() From 0a9902b918053b42729f324414806681b0cec781 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 7 Apr 2015 18:45:05 +0200 Subject: [PATCH 0533/1783] Use script/cibuild on AppVeyor --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 95bf9556a..081341af3 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,4 +6,4 @@ deploy: off build_script: - cd %APPVEYOR_BUILD_FOLDER% - - "script/build" + - "script/cibuild" From c0b685dd970ca8d72f4197c7f999ad2224fcb1e3 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 09:48:10 -0700 Subject: [PATCH 0534/1783] :arrow_up: language-go@0.23 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cf2ae12b4..50bd77e28 100644 --- a/package.json +++ b/package.json @@ -130,7 +130,7 @@ "language-css": "0.28.0", "language-gfm": "0.67.0", "language-git": "0.10.0", - "language-go": "0.22.0", + "language-go": "0.23.0", "language-html": "0.31.0", "language-hyperlink": "0.12.2", "language-java": "0.14.0", From 2aaf1fffe6eece195db41c3ea344b9195a054823 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 09:51:16 -0700 Subject: [PATCH 0535/1783] Move stack trace helpers into deprecation block --- src/workspace.coffee | 59 ++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/src/workspace.coffee b/src/workspace.coffee index 6a7a40a0c..2e433d6b9 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -7,7 +7,6 @@ Serializable = require 'serializable' {Emitter, Disposable, CompositeDisposable} = require 'event-kit' Grim = require 'grim' fs = require 'fs-plus' -StackTraceParser = require 'stacktrace-parser' Model = require './model' TextEditor = require './text-editor' PaneContainer = require './pane-container' @@ -495,34 +494,6 @@ class Workspace extends Model getOpeners: -> @openers - getCallingPackageName: -> - error = new Error - Error.captureStackTrace(error) - stack = StackTraceParser.parse(error.stack) - - packagePaths = @getPackagePathsByPackageName() - - for i in [0...stack.length] - stackFramePath = stack[i].file - - # Empty when it was run from the dev console - return unless stackFramePath - - for packageName, packagePath of packagePaths - continue if stackFramePath is 'node.js' - relativePath = path.relative(packagePath, stackFramePath) - return packageName unless /^\.\./.test(relativePath) - return - - getPackagePathsByPackageName: -> - packagePathsByPackageName = {} - for pack in atom.packages.getLoadedPackages() - packagePath = pack.path - if packagePath.indexOf('.atom/dev/packages') > -1 or packagePath.indexOf('.atom/packages') > -1 - packagePath = fs.realpathSync(packagePath) - packagePathsByPackageName[pack.name] = packagePath - packagePathsByPackageName - ### Section: Pane Items ### @@ -907,6 +878,36 @@ if includeDeprecatedAPIs Grim.deprecate "Use ::getActivePane() instead of the ::activePane property" @getActivePane() + StackTraceParser = require 'stacktrace-parser' + + Workspace::getCallingPackageName = -> + error = new Error + Error.captureStackTrace(error) + stack = StackTraceParser.parse(error.stack) + + packagePaths = @getPackagePathsByPackageName() + + for i in [0...stack.length] + stackFramePath = stack[i].file + + # Empty when it was run from the dev console + return unless stackFramePath + + for packageName, packagePath of packagePaths + continue if stackFramePath is 'node.js' + relativePath = path.relative(packagePath, stackFramePath) + return packageName unless /^\.\./.test(relativePath) + return + + Workspace::getPackagePathsByPackageName = -> + packagePathsByPackageName = {} + for pack in atom.packages.getLoadedPackages() + packagePath = pack.path + if packagePath.indexOf('.atom/dev/packages') > -1 or packagePath.indexOf('.atom/packages') > -1 + packagePath = fs.realpathSync(packagePath) + packagePathsByPackageName[pack.name] = packagePath + packagePathsByPackageName + Workspace::eachEditor = (callback) -> deprecate("Use Workspace::observeTextEditors instead") From 5a8f37bdfd57c6f5db7c095885d29d81807bb814 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 7 Apr 2015 18:48:24 +0200 Subject: [PATCH 0536/1783] Copy AppVeyor configuration from atom/keyboard-layout --- appveyor.yml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 081341af3..706763363 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,9 +1,10 @@ -version: "{build}" -os: Windows Server 2012 R2 +environment: + nodejs_version: "0.10" -test: off -deploy: off +install: + - ps: Install-Product node $env:nodejs_version -build_script: - - cd %APPVEYOR_BUILD_FOLDER% +test_script: - "script/cibuild" + +build: off From d90b6937f408a07672b0169ba4c483cfe320ad64 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 7 Apr 2015 19:13:31 +0200 Subject: [PATCH 0537/1783] Explicitly use node in test_script --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 706763363..19d49846e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,6 +5,6 @@ install: - ps: Install-Product node $env:nodejs_version test_script: - - "script/cibuild" + - node "script\cibuild" build: off From 73fb36590d2efb16cd477778c9d43bb5fd43933d Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 7 Apr 2015 19:28:10 +0200 Subject: [PATCH 0538/1783] Use a 15s timeout for webdriver startup --- spec/integration/helpers/start-atom.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/integration/helpers/start-atom.coffee b/spec/integration/helpers/start-atom.coffee index 9993181a8..9775de8c7 100644 --- a/spec/integration/helpers/start-atom.coffee +++ b/spec/integration/helpers/start-atom.coffee @@ -128,7 +128,7 @@ module.exports = (args, env, fn) -> chromedriver.stderr.on "close", -> resolve(errorCode) - waitsFor("webdriver to start", pollChromeDriver, 5000) + waitsFor("webdriver to start", pollChromeDriver, 15000) waitsFor("webdriver to finish", (done) -> finish = once -> From 9a647309167973a0d0bb76e455406229fec28e21 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 7 Apr 2015 11:23:22 -0700 Subject: [PATCH 0539/1783] :arrow_up: background-tips --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 50bd77e28..0360f085e 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,7 @@ "autocomplete": "0.44.0", "autoflow": "0.22.0", "autosave": "0.20.0", - "background-tips": "0.23.0", + "background-tips": "0.24.0", "bookmarks": "0.35.0", "bracket-matcher": "0.73.0", "command-palette": "0.35.0", From 06b8195fb8de1fe21755f1469004d11498280aec Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 11:43:35 -0700 Subject: [PATCH 0540/1783] Remove template config.cson file This old template file had several problems: * The entries in this file are already the schema defaults so they would get unset anyway when initially loaded * The file was in the old format that didn't have scope selectors * A race condition could occur when the file was copied, inited, and written to all during the very first run of Atom. Closes #6226 --- dot-atom/config.cson | 7 ------- spec/config-spec.coffee | 1 - 2 files changed, 8 deletions(-) delete mode 100644 dot-atom/config.cson diff --git a/dot-atom/config.cson b/dot-atom/config.cson deleted file mode 100644 index a3a5984af..000000000 --- a/dot-atom/config.cson +++ /dev/null @@ -1,7 +0,0 @@ -'editor': - 'fontSize': 16 -'core': - 'themes': [ - 'one-dark-ui' - 'one-dark-syntax' - ] diff --git a/spec/config-spec.coffee b/spec/config-spec.coffee index 4abd3b0db..b8cfc67d0 100644 --- a/spec/config-spec.coffee +++ b/spec/config-spec.coffee @@ -987,7 +987,6 @@ describe "Config", -> expect(fs.existsSync(atom.config.configDirPath)).toBeTruthy() expect(fs.existsSync(path.join(atom.config.configDirPath, 'packages'))).toBeTruthy() expect(fs.isFileSync(path.join(atom.config.configDirPath, 'snippets.cson'))).toBeTruthy() - expect(fs.isFileSync(path.join(atom.config.configDirPath, 'config.cson'))).toBeTruthy() expect(fs.isFileSync(path.join(atom.config.configDirPath, 'init.coffee'))).toBeTruthy() expect(fs.isFileSync(path.join(atom.config.configDirPath, 'styles.less'))).toBeTruthy() From 4421d929a74d5fa867b8d88190947f26bee093fa Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 11:54:58 -0700 Subject: [PATCH 0541/1783] :arrow_up: language-javascript@0.70 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0360f085e..92a133ad6 100644 --- a/package.json +++ b/package.json @@ -134,7 +134,7 @@ "language-html": "0.31.0", "language-hyperlink": "0.12.2", "language-java": "0.14.0", - "language-javascript": "0.69.0", + "language-javascript": "0.70.0", "language-json": "0.14.0", "language-less": "0.25.0", "language-make": "0.14.0", From f39c67411aabb0c6dbb1ccd3dc68f051aa3bb0d7 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 7 Apr 2015 11:59:14 -0700 Subject: [PATCH 0542/1783] Rename 'add-root-folder' -> 'add-project-folder' --- spec/atom-spec.coffee | 6 +++--- src/atom.coffee | 2 +- src/workspace-element.coffee | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/atom-spec.coffee b/spec/atom-spec.coffee index f888c433f..19a2cca5c 100644 --- a/spec/atom-spec.coffee +++ b/spec/atom-spec.coffee @@ -181,18 +181,18 @@ describe "the `atom` global", -> atom.openInitialEmptyEditorIfNecessary() expect(atom.workspace.open).not.toHaveBeenCalled() - describe "adding a root folder", -> + describe "adding a project folder", -> it "adds a second path to the project", -> initialPaths = atom.project.getPaths() tempDirectory = temp.mkdirSync("a-new-directory") spyOn(atom, "pickFolder").andCallFake (callback) -> callback([tempDirectory]) - atom.addRootFolder() + atom.addProjectFolder() expect(atom.project.getPaths()).toEqual(initialPaths.concat([tempDirectory])) it "does nothing if the user dismisses the file picker", -> initialPaths = atom.project.getPaths() tempDirectory = temp.mkdirSync("a-new-directory") spyOn(atom, "pickFolder").andCallFake (callback) -> callback(null) - atom.addRootFolder() + atom.addProjectFolder() expect(atom.project.getPaths()).toEqual(initialPaths) diff --git a/src/atom.coffee b/src/atom.coffee index 701f2e91e..f5e229962 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -774,7 +774,7 @@ class Atom extends Model setRepresentedFilename: (filename) -> ipc.send('call-window-method', 'setRepresentedFilename', filename) - addRootFolder: -> + addProjectFolder: -> @pickFolder (selectedPaths = []) => @project.addPath(selectedPath) for selectedPath in selectedPaths diff --git a/src/workspace-element.coffee b/src/workspace-element.coffee index 5f127d970..46a005af0 100644 --- a/src/workspace-element.coffee +++ b/src/workspace-element.coffee @@ -138,7 +138,7 @@ atom.commands.add 'atom-workspace', 'application:open-safe': -> ipc.send('command', 'application:open-safe') 'application:open-api-preview': -> ipc.send('command', 'application:open-api-preview') 'application:open-dev-api-preview': -> ipc.send('command', 'application:open-dev-api-preview') - 'application:add-root-folder': -> atom.addRootFolder() + 'application:add-project-folder': -> atom.addProjectFolder() 'application:minimize': -> ipc.send('command', 'application:minimize') 'application:zoom': -> ipc.send('command', 'application:zoom') 'application:bring-all-windows-to-front': -> ipc.send('command', 'application:bring-all-windows-to-front') From ceaa86942673d583b6b9867182d27c6d97ecf740 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 12:33:41 -0700 Subject: [PATCH 0543/1783] Add application:add-project-folder keybinding --- keymaps/darwin.cson | 1 + keymaps/linux.cson | 1 + keymaps/win32.cson | 1 + 3 files changed, 3 insertions(+) diff --git a/keymaps/darwin.cson b/keymaps/darwin.cson index 5226bb5e6..46f949317 100644 --- a/keymaps/darwin.cson +++ b/keymaps/darwin.cson @@ -37,6 +37,7 @@ 'cmd-N': 'application:new-window' 'cmd-W': 'window:close' 'cmd-o': 'application:open' + 'cmd-alt-o': 'application:add-project-folder' 'cmd-T': 'pane:reopen-closed-item' 'cmd-n': 'application:new-file' 'cmd-s': 'core:save' diff --git a/keymaps/linux.cson b/keymaps/linux.cson index 59803d193..cea470635 100644 --- a/keymaps/linux.cson +++ b/keymaps/linux.cson @@ -21,6 +21,7 @@ 'ctrl-N': 'application:new-window' 'ctrl-W': 'window:close' 'ctrl-o': 'application:open-file' + 'ctrl-alt-o': 'application:add-project-folder' 'ctrl-q': 'application:quit' 'ctrl-T': 'pane:reopen-closed-item' 'ctrl-n': 'application:new-file' diff --git a/keymaps/win32.cson b/keymaps/win32.cson index da43ac364..382b280a8 100644 --- a/keymaps/win32.cson +++ b/keymaps/win32.cson @@ -25,6 +25,7 @@ 'ctrl-N': 'application:new-window' 'ctrl-W': 'window:close' 'ctrl-o': 'application:open-file' + 'ctrl-alt-o': 'application:add-project-folder' 'ctrl-T': 'pane:reopen-closed-item' 'ctrl-n': 'application:new-file' 'ctrl-s': 'core:save' From 54c238ba2d02c60884041df5236172c760274396 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 7 Apr 2015 12:34:08 -0700 Subject: [PATCH 0544/1783] :arrow_up: tree-view --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 92a133ad6..26dc284a1 100644 --- a/package.json +++ b/package.json @@ -118,7 +118,7 @@ "symbols-view": "0.93.0", "tabs": "0.67.0", "timecop": "0.31.0", - "tree-view": "0.169.0", + "tree-view": "0.170.0", "update-package-dependencies": "0.9.0", "welcome": "0.26.0", "whitespace": "0.29.0", From 8e0efb184480a9be5bd184634741970f29e97bea Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 12:34:36 -0700 Subject: [PATCH 0545/1783] Add Add Project Folder system menu --- menus/darwin.cson | 1 + menus/linux.cson | 1 + menus/win32.cson | 1 + 3 files changed, 3 insertions(+) diff --git a/menus/darwin.cson b/menus/darwin.cson index 9454a7c34..effd19197 100644 --- a/menus/darwin.cson +++ b/menus/darwin.cson @@ -34,6 +34,7 @@ { label: 'New Window', command: 'application:new-window' } { label: 'New File', command: 'application:new-file' } { label: 'Open...', command: 'application:open' } + { label: 'Add Project Folder...', command: 'application:add-project-folder' } { label: 'Reopen Last Item', command: 'pane:reopen-closed-item' } { type: 'separator' } { label: 'Save', command: 'core:save' } diff --git a/menus/linux.cson b/menus/linux.cson index a3b3875c4..c92017de9 100644 --- a/menus/linux.cson +++ b/menus/linux.cson @@ -6,6 +6,7 @@ { label: '&New File', command: 'application:new-file' } { label: '&Open File...', command: 'application:open-file' } { label: 'Open Folder...', command: 'application:open-folder' } + { label: 'Add Project Folder...', command: 'application:add-project-folder' } { label: 'Reopen Last &Item', command: 'pane:reopen-closed-item' } { type: 'separator' } { label: '&Save', command: 'core:save' } diff --git a/menus/win32.cson b/menus/win32.cson index af26be7a5..2bd013ce3 100644 --- a/menus/win32.cson +++ b/menus/win32.cson @@ -6,6 +6,7 @@ { label: '&New File', command: 'application:new-file' } { label: '&Open File...', command: 'application:open-file' } { label: 'Open Folder...', command: 'application:open-folder' } + { label: 'Add Project Folder...', command: 'application:add-project-folder' } { label: 'Reopen Last &Item', command: 'pane:reopen-closed-item' } { type: 'separator' } { label: 'Se&ttings', command: 'application:show-settings' } From 1acc3a835673c7df91330ef482e800506c030647 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 12:41:59 -0700 Subject: [PATCH 0546/1783] Don't clash with existing linux/windows keybindings --- keymaps/linux.cson | 2 +- keymaps/win32.cson | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/keymaps/linux.cson b/keymaps/linux.cson index cea470635..fed3bdc49 100644 --- a/keymaps/linux.cson +++ b/keymaps/linux.cson @@ -21,7 +21,7 @@ 'ctrl-N': 'application:new-window' 'ctrl-W': 'window:close' 'ctrl-o': 'application:open-file' - 'ctrl-alt-o': 'application:add-project-folder' + 'ctrl-alt-O': 'application:add-project-folder' 'ctrl-q': 'application:quit' 'ctrl-T': 'pane:reopen-closed-item' 'ctrl-n': 'application:new-file' diff --git a/keymaps/win32.cson b/keymaps/win32.cson index 382b280a8..d5e331f0c 100644 --- a/keymaps/win32.cson +++ b/keymaps/win32.cson @@ -25,7 +25,7 @@ 'ctrl-N': 'application:new-window' 'ctrl-W': 'window:close' 'ctrl-o': 'application:open-file' - 'ctrl-alt-o': 'application:add-project-folder' + 'ctrl-alt-O': 'application:add-project-folder' 'ctrl-T': 'pane:reopen-closed-item' 'ctrl-n': 'application:new-file' 'ctrl-s': 'core:save' From d41296b121bf2d2ed97992285aef3d9c6e136e61 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 13:02:11 -0700 Subject: [PATCH 0547/1783] Swap open-dev and add-project-folder keybindings --- keymaps/darwin.cson | 4 ++-- keymaps/linux.cson | 4 ++-- keymaps/win32.cson | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/keymaps/darwin.cson b/keymaps/darwin.cson index 46f949317..8f023427e 100644 --- a/keymaps/darwin.cson +++ b/keymaps/darwin.cson @@ -18,7 +18,7 @@ 'ctrl-d': 'core:delete' # Atom Specific - 'cmd-O': 'application:open-dev' + 'cmd-alt-o': 'application:open-dev' 'cmd-alt-ctrl-s': 'application:run-all-specs' 'enter': 'core:confirm' 'escape': 'core:cancel' @@ -37,7 +37,7 @@ 'cmd-N': 'application:new-window' 'cmd-W': 'window:close' 'cmd-o': 'application:open' - 'cmd-alt-o': 'application:add-project-folder' + 'cmd-O': 'application:add-project-folder' 'cmd-T': 'pane:reopen-closed-item' 'cmd-n': 'application:new-file' 'cmd-s': 'core:save' diff --git a/keymaps/linux.cson b/keymaps/linux.cson index fed3bdc49..6fef9f482 100644 --- a/keymaps/linux.cson +++ b/keymaps/linux.cson @@ -10,7 +10,7 @@ 'ctrl-shift-i': 'window:toggle-dev-tools' 'ctrl-alt-p': 'window:run-package-specs' 'ctrl-alt-s': 'application:run-all-specs' - 'ctrl-alt-o': 'application:open-dev' + 'ctrl-alt-shift-o': 'application:open-dev' 'ctrl-shift-o': 'application:open-folder' 'ctrl-shift-pageup': 'pane:move-item-left' 'ctrl-shift-pagedown': 'pane:move-item-right' @@ -21,7 +21,7 @@ 'ctrl-N': 'application:new-window' 'ctrl-W': 'window:close' 'ctrl-o': 'application:open-file' - 'ctrl-alt-O': 'application:add-project-folder' + 'ctrl-alt-o': 'application:add-project-folder' 'ctrl-q': 'application:quit' 'ctrl-T': 'pane:reopen-closed-item' 'ctrl-n': 'application:new-file' diff --git a/keymaps/win32.cson b/keymaps/win32.cson index d5e331f0c..968adb0a8 100644 --- a/keymaps/win32.cson +++ b/keymaps/win32.cson @@ -14,7 +14,7 @@ 'ctrl-alt-i': 'window:toggle-dev-tools' 'ctrl-alt-p': 'window:run-package-specs' 'ctrl-alt-s': 'application:run-all-specs' - 'ctrl-alt-o': 'application:open-dev' + 'ctrl-alt-shift-o': 'application:open-dev' 'ctrl-shift-o': 'application:open-folder' 'ctrl-shift-left': 'pane:move-item-left' 'ctrl-shift-right': 'pane:move-item-right' @@ -25,7 +25,7 @@ 'ctrl-N': 'application:new-window' 'ctrl-W': 'window:close' 'ctrl-o': 'application:open-file' - 'ctrl-alt-O': 'application:add-project-folder' + 'ctrl-alt-o': 'application:add-project-folder' 'ctrl-T': 'pane:reopen-closed-item' 'ctrl-n': 'application:new-file' 'ctrl-s': 'core:save' From b9db13ae064facbb9dc27650ffec254d7e08fe4e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 13:05:28 -0700 Subject: [PATCH 0548/1783] Group add-project-folder with open-folder --- keymaps/linux.cson | 2 +- keymaps/win32.cson | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/keymaps/linux.cson b/keymaps/linux.cson index 6fef9f482..d8877d77c 100644 --- a/keymaps/linux.cson +++ b/keymaps/linux.cson @@ -12,6 +12,7 @@ 'ctrl-alt-s': 'application:run-all-specs' 'ctrl-alt-shift-o': 'application:open-dev' 'ctrl-shift-o': 'application:open-folder' + 'ctrl-alt-o': 'application:add-project-folder' 'ctrl-shift-pageup': 'pane:move-item-left' 'ctrl-shift-pagedown': 'pane:move-item-right' 'F11': 'window:toggle-full-screen' @@ -21,7 +22,6 @@ 'ctrl-N': 'application:new-window' 'ctrl-W': 'window:close' 'ctrl-o': 'application:open-file' - 'ctrl-alt-o': 'application:add-project-folder' 'ctrl-q': 'application:quit' 'ctrl-T': 'pane:reopen-closed-item' 'ctrl-n': 'application:new-file' diff --git a/keymaps/win32.cson b/keymaps/win32.cson index 968adb0a8..4d5bb5159 100644 --- a/keymaps/win32.cson +++ b/keymaps/win32.cson @@ -16,6 +16,7 @@ 'ctrl-alt-s': 'application:run-all-specs' 'ctrl-alt-shift-o': 'application:open-dev' 'ctrl-shift-o': 'application:open-folder' + 'ctrl-alt-o': 'application:add-project-folder' 'ctrl-shift-left': 'pane:move-item-left' 'ctrl-shift-right': 'pane:move-item-right' 'F11': 'window:toggle-full-screen' @@ -25,7 +26,6 @@ 'ctrl-N': 'application:new-window' 'ctrl-W': 'window:close' 'ctrl-o': 'application:open-file' - 'ctrl-alt-o': 'application:add-project-folder' 'ctrl-T': 'pane:reopen-closed-item' 'ctrl-n': 'application:new-file' 'ctrl-s': 'core:save' From a49f635fc0ba1d952320d6710d75731e7a106717 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 13:10:01 -0700 Subject: [PATCH 0549/1783] Remove application:open-dev keybindings --- keymaps/darwin.cson | 1 - keymaps/linux.cson | 1 - keymaps/win32.cson | 1 - 3 files changed, 3 deletions(-) diff --git a/keymaps/darwin.cson b/keymaps/darwin.cson index 8f023427e..34d18e159 100644 --- a/keymaps/darwin.cson +++ b/keymaps/darwin.cson @@ -18,7 +18,6 @@ 'ctrl-d': 'core:delete' # Atom Specific - 'cmd-alt-o': 'application:open-dev' 'cmd-alt-ctrl-s': 'application:run-all-specs' 'enter': 'core:confirm' 'escape': 'core:cancel' diff --git a/keymaps/linux.cson b/keymaps/linux.cson index d8877d77c..cd71d99e7 100644 --- a/keymaps/linux.cson +++ b/keymaps/linux.cson @@ -10,7 +10,6 @@ 'ctrl-shift-i': 'window:toggle-dev-tools' 'ctrl-alt-p': 'window:run-package-specs' 'ctrl-alt-s': 'application:run-all-specs' - 'ctrl-alt-shift-o': 'application:open-dev' 'ctrl-shift-o': 'application:open-folder' 'ctrl-alt-o': 'application:add-project-folder' 'ctrl-shift-pageup': 'pane:move-item-left' diff --git a/keymaps/win32.cson b/keymaps/win32.cson index 4d5bb5159..656d9ec8e 100644 --- a/keymaps/win32.cson +++ b/keymaps/win32.cson @@ -14,7 +14,6 @@ 'ctrl-alt-i': 'window:toggle-dev-tools' 'ctrl-alt-p': 'window:run-package-specs' 'ctrl-alt-s': 'application:run-all-specs' - 'ctrl-alt-shift-o': 'application:open-dev' 'ctrl-shift-o': 'application:open-folder' 'ctrl-alt-o': 'application:add-project-folder' 'ctrl-shift-left': 'pane:move-item-left' From debe192d9eb34bba10769b8c61b62cbcb7863a33 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 14:14:46 -0700 Subject: [PATCH 0550/1783] Prepare 0.191 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 26dc284a1..9b30cb63f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "0.190.0", + "version": "0.191.0", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From ff86712a22e3def0b2014095dd06de0eef60d53d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 14:15:30 -0700 Subject: [PATCH 0551/1783] Add missing View > Panes menu on Linux Closes #1897 --- menus/linux.cson | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/menus/linux.cson b/menus/linux.cson index c92017de9..2cfb17871 100644 --- a/menus/linux.cson +++ b/menus/linux.cson @@ -96,6 +96,25 @@ { label: '&Reload', command: 'window:reload' } { label: 'Toggle &Full Screen', command: 'window:toggle-full-screen' } { label: 'Toggle Menu Bar', command: 'window:toggle-menu-bar' } + { + label: 'Panes' + submenu: [ + { label: 'Split Up', command: 'pane:split-up' } + { label: 'Split Down', command: 'pane:split-down' } + { label: 'Split Left', command: 'pane:split-left' } + { label: 'Split Right', command: 'pane:split-right' } + { type: 'separator' } + { label: 'Focus Next Pane', command: 'window:focus-next-pane' } + { label: 'Focus Previous Pane', command: 'window:focus-previous-pane' } + { type: 'separator' } + { label: 'Focus Pane Above', command: 'window:focus-pane-above' } + { label: 'Focus Pane Below', command: 'window:focus-pane-below' } + { label: 'Focus Pane On Left', command: 'window:focus-pane-on-left' } + { label: 'Focus Pane On Right', command: 'window:focus-pane-on-right' } + { type: 'separator' } + { label: 'Close Pane', command: 'pane:close' } + ] + } { label: 'Developer' submenu: [ From 2a95b18ffd6548cca99cfc66cceb4f7f2729786f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 14:38:26 -0700 Subject: [PATCH 0552/1783] :arrow_up: deprecation-cop@0.40 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9b30cb63f..9e9b716d5 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,7 @@ "bookmarks": "0.35.0", "bracket-matcher": "0.73.0", "command-palette": "0.35.0", - "deprecation-cop": "0.39.0", + "deprecation-cop": "0.40.0", "dev-live-reload": "0.45.0", "encoding-selector": "0.19.0", "exception-reporting": "0.24.0", From baae0c0ac680a717be6033474baa2e3eee111172 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 14:40:27 -0700 Subject: [PATCH 0553/1783] Only include emissary Emitter in deprecation mode --- src/config.coffee | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/config.coffee b/src/config.coffee index f7db867ed..918a18848 100644 --- a/src/config.coffee +++ b/src/config.coffee @@ -1,6 +1,5 @@ _ = require 'underscore-plus' fs = require 'fs-plus' -EmitterMixin = require('emissary').Emitter {CompositeDisposable, Disposable, Emitter} = require 'event-kit' CSON = require 'season' path = require 'path' @@ -290,7 +289,6 @@ ScopeDescriptor = require './scope-descriptor' # module.exports = class Config - EmitterMixin.includeInto(this) @schemaEnforcers = {} @addSchemaEnforcer: (typeName, enforcerFunction) -> @@ -1147,6 +1145,9 @@ withoutEmptyObjects = (object) -> resultObject if Grim.includeDeprecatedAPIs + EmitterMixin = require('emissary').Emitter + EmitterMixin.includeInto(Config) + Config::restoreDefault = (scopeSelector, keyPath) -> Grim.deprecate("Use ::unset instead.") @unset(scopeSelector, keyPath) From e71c6b10611de175b1414842079464a74b4a9ffa Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 14:41:45 -0700 Subject: [PATCH 0554/1783] Remove unused require --- src/project.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/project.coffee b/src/project.coffee index 5094ef8ce..49d7fe295 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -5,7 +5,6 @@ _ = require 'underscore-plus' fs = require 'fs-plus' Q = require 'q' {includeDeprecatedAPIs, deprecate} = require 'grim' -{Subscriber} = require 'emissary' {Emitter} = require 'event-kit' Serializable = require 'serializable' TextBuffer = require 'text-buffer' From 4b764f4a59a131d3775ac93b40c17f36b620923b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 14:43:27 -0700 Subject: [PATCH 0555/1783] Move emissary require to deprecation block --- 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 7606cea7e..02e7b9ba6 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -3,7 +3,6 @@ path = require 'path' Serializable = require 'serializable' Delegator = require 'delegato' {includeDeprecatedAPIs, deprecate} = require 'grim' -EmitterMixin = require('emissary').Emitter {CompositeDisposable, Emitter} = require 'event-kit' {Point, Range} = TextBuffer = require 'text-buffer' LanguageMode = require './language-mode' @@ -3015,6 +3014,7 @@ if includeDeprecatedAPIs deprecate("Use TextEditor::isSoftWrapped instead") @displayBuffer.isSoftWrapped() + EmitterMixin = require('emissary').Emitter TextEditor::on = (eventName) -> switch eventName when 'title-changed' From 7b952e3f33d2a85c92ead87537800062af93df6d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 14:44:46 -0700 Subject: [PATCH 0556/1783] Remove unused emissary mixins --- src/language-mode.coffee | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/language-mode.coffee b/src/language-mode.coffee index 125b15ff6..54638965a 100644 --- a/src/language-mode.coffee +++ b/src/language-mode.coffee @@ -1,14 +1,10 @@ {Range} = require 'text-buffer' _ = require 'underscore-plus' {OnigRegExp} = require 'oniguruma' -{Emitter, Subscriber} = require 'emissary' ScopeDescriptor = require './scope-descriptor' module.exports = class LanguageMode - Emitter.includeInto(this) - Subscriber.includeInto(this) - # Sets up a `LanguageMode` for the given {TextEditor}. # # editor - The {TextEditor} to associate with @@ -16,7 +12,6 @@ class LanguageMode {@buffer} = @editor destroy: -> - @unsubscribe() toggleLineCommentForBufferRow: (row) -> @toggleLineCommentsForBufferRows(row, row) From 018fe0e8b8473bcc459e503742bdec193e7939ab Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 15:11:53 -0700 Subject: [PATCH 0557/1783] Only set atom.__workspaceView in deprecated mode --- src/atom.coffee | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/atom.coffee b/src/atom.coffee index f5e229962..dd86b382c 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -729,7 +729,10 @@ class Atom extends Model @workspace = Workspace.deserialize(@state.workspace) ? new Workspace workspaceElement = @views.getView(@workspace) - @__workspaceView = workspaceElement.__spacePenView + + if includeDeprecatedAPIs + @__workspaceView = workspaceElement.__spacePenView + @deserializeTimings.workspace = Date.now() - startTime @keymaps.defaultTarget = workspaceElement From 2fc132c97b51ee2f612cb5f55f1fc5879c7bd60c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 15:23:25 -0700 Subject: [PATCH 0558/1783] :racehorse: Use require to read/parse package.json This file is really large and should be read via require so it is cached --- src/package-manager.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 16142cda4..9d085e27f 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -276,9 +276,9 @@ class PackageManager getPackageDependencies: -> unless @packageDependencies? try - metadataPath = path.join(@resourcePath, 'package.json') - {@packageDependencies} = JSON.parse(fs.readFileSync(metadataPath)) ? {} - @packageDependencies ?= {} + @packageDependencies = require('../package.json')?.packageDependencies ? {} + catch error + @packageDependencies = {} @packageDependencies From 658629f45ec1101efbb6756cce132bc7217e4967 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 15:29:34 -0700 Subject: [PATCH 0559/1783] :art: --- src/package-manager.coffee | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 9d085e27f..386a65e68 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -276,9 +276,8 @@ class PackageManager getPackageDependencies: -> unless @packageDependencies? try - @packageDependencies = require('../package.json')?.packageDependencies ? {} - catch error - @packageDependencies = {} + @packageDependencies = require('../package.json')?.packageDependencies + @packageDependencies ?= {} @packageDependencies From ec11c89a7440f257de4a4f64bf4a6e449e58e56f Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Tue, 7 Apr 2015 19:24:29 -0400 Subject: [PATCH 0560/1783] Revert :shirt: for spec fixtures --- spec/fixtures/coffee.coffee | 3 +-- spec/fixtures/sample-with-tabs-and-leading-comment.coffee | 6 ++---- spec/fixtures/sample-with-tabs.coffee | 2 -- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/spec/fixtures/coffee.coffee b/spec/fixtures/coffee.coffee index d68b84267..b8367ca59 100644 --- a/spec/fixtures/coffee.coffee +++ b/spec/fixtures/coffee.coffee @@ -1,4 +1,4 @@ -class Quicksort +class quicksort sort: (items) -> return items if items.length <= 1 @@ -13,7 +13,6 @@ class Quicksort if current < pivot left.push(current) else - # coffeelint: disable=no_trailing_semicolons right.push(current); sort(left).concat(pivot).concat(sort(right)) diff --git a/spec/fixtures/sample-with-tabs-and-leading-comment.coffee b/spec/fixtures/sample-with-tabs-and-leading-comment.coffee index 08e81aa68..0f81f6fe8 100644 --- a/spec/fixtures/sample-with-tabs-and-leading-comment.coffee +++ b/spec/fixtures/sample-with-tabs-and-leading-comment.coffee @@ -1,6 +1,4 @@ # This is a comment - # coffeelint: disable=no_tabs - # coffeelint: disable=indentation if this.studyingEconomics - buy() while supply > demand - sell() until supply > demand + buy() while supply > demand + sell() until supply > demand diff --git a/spec/fixtures/sample-with-tabs.coffee b/spec/fixtures/sample-with-tabs.coffee index 5e7595a7d..1b937ea33 100644 --- a/spec/fixtures/sample-with-tabs.coffee +++ b/spec/fixtures/sample-with-tabs.coffee @@ -1,5 +1,3 @@ -# coffeelint: disable=no_tabs -# coffeelint: disable=no_trailing_whitespace # Econ 101 if this.studyingEconomics buy() while supply > demand From dee626ab69388c2ff83fb91845003c5aa118ed80 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 8 Apr 2015 08:36:46 +0200 Subject: [PATCH 0561/1783] Investigate timeouts issues (again) --- spec/integration/helpers/start-atom.coffee | 2 ++ spec/integration/startup-spec.coffee | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/spec/integration/helpers/start-atom.coffee b/spec/integration/helpers/start-atom.coffee index 9775de8c7..826d8c17e 100644 --- a/spec/integration/helpers/start-atom.coffee +++ b/spec/integration/helpers/start-atom.coffee @@ -18,6 +18,8 @@ ChromedriverStatusURL = "http://localhost:#{ChromedriverPort}#{ChromedriverURLBa pollChromeDriver = (done) -> checkStatus = -> http.get(ChromedriverStatusURL, (response) -> + console.log response.statusCode + if response.statusCode is 200 done() else diff --git a/spec/integration/startup-spec.coffee b/spec/integration/startup-spec.coffee index e0df3ad9b..b7f6425a3 100644 --- a/spec/integration/startup-spec.coffee +++ b/spec/integration/startup-spec.coffee @@ -19,7 +19,7 @@ describe "Starting Atom", -> tempDirPath = temp.mkdirSync("empty-dir") otherTempDirPath = temp.mkdirSync("another-temp-dir") - describe "opening a new file", -> + fdescribe "opening a new file", -> it "opens the parent directory and creates an empty text editor", -> runAtom [path.join(tempDirPath, "new-file")], {ATOM_HOME: AtomHome}, (client) -> client From f9f5213cdf04ae6e9a44521cb52f271061e6d769 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 8 Apr 2015 08:57:03 +0200 Subject: [PATCH 0562/1783] Handle http.on('error') for webdriver polling --- spec/integration/helpers/start-atom.coffee | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/spec/integration/helpers/start-atom.coffee b/spec/integration/helpers/start-atom.coffee index 826d8c17e..08d3659c3 100644 --- a/spec/integration/helpers/start-atom.coffee +++ b/spec/integration/helpers/start-atom.coffee @@ -18,13 +18,11 @@ ChromedriverStatusURL = "http://localhost:#{ChromedriverPort}#{ChromedriverURLBa pollChromeDriver = (done) -> checkStatus = -> http.get(ChromedriverStatusURL, (response) -> - console.log response.statusCode - if response.statusCode is 200 done() else pollChromeDriver(done) - ) + ).on("error", -> pollChromeDriver(done)) setTimeout(checkStatus, 100) From 8e2c5a34e4fef4a7db3054d444aeb2f056f97ed1 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 8 Apr 2015 10:08:20 +0200 Subject: [PATCH 0563/1783] Avoid setting --arch=ia32 --- script/bootstrap | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/script/bootstrap b/script/bootstrap index 4c9435852..58255749b 100755 --- a/script/bootstrap +++ b/script/bootstrap @@ -80,8 +80,8 @@ function bootstrap() { // apm ships with 32-bit node so make sure its native modules are compiled // for a 32-bit target architecture - if (process.env.JANKY_SHA1 && process.platform === 'win32') - apmInstallCommand += ' --arch=ia32'; + // if (process.env.JANKY_SHA1 && process.platform === 'win32') + // apmInstallCommand += ' --arch=ia32'; var commands = [ { From 32909efd7e2dcf0dcad5a366026894b20f4cc18c Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 8 Apr 2015 10:23:54 +0200 Subject: [PATCH 0564/1783] Revert "Avoid setting --arch=ia32" This reverts commit 8e2c5a34e4fef4a7db3054d444aeb2f056f97ed1. --- script/bootstrap | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/script/bootstrap b/script/bootstrap index 58255749b..4c9435852 100755 --- a/script/bootstrap +++ b/script/bootstrap @@ -80,8 +80,8 @@ function bootstrap() { // apm ships with 32-bit node so make sure its native modules are compiled // for a 32-bit target architecture - // if (process.env.JANKY_SHA1 && process.platform === 'win32') - // apmInstallCommand += ' --arch=ia32'; + if (process.env.JANKY_SHA1 && process.platform === 'win32') + apmInstallCommand += ' --arch=ia32'; var commands = [ { From b08bd79e0237ac18a740f2b053732d0f34ce6ba0 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 8 Apr 2015 10:27:03 +0200 Subject: [PATCH 0565/1783] Disable focus methods on CI --- spec/integration/startup-spec.coffee | 2 +- spec/jasmine-helper.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/integration/startup-spec.coffee b/spec/integration/startup-spec.coffee index b7f6425a3..e0df3ad9b 100644 --- a/spec/integration/startup-spec.coffee +++ b/spec/integration/startup-spec.coffee @@ -19,7 +19,7 @@ describe "Starting Atom", -> tempDirPath = temp.mkdirSync("empty-dir") otherTempDirPath = temp.mkdirSync("another-temp-dir") - fdescribe "opening a new file", -> + describe "opening a new file", -> it "opens the parent directory and creates an empty text editor", -> runAtom [path.join(tempDirPath, "new-file")], {ATOM_HOME: AtomHome}, (client) -> client diff --git a/spec/jasmine-helper.coffee b/spec/jasmine-helper.coffee index 1e099d897..31f65167b 100644 --- a/spec/jasmine-helper.coffee +++ b/spec/jasmine-helper.coffee @@ -7,7 +7,7 @@ module.exports.runSpecSuite = (specSuite, logFile, logErrors=true) -> {TerminalReporter} = require 'jasmine-tagged' - disableFocusMethods() if process.env.JANKY_SHA1 + disableFocusMethods() if process.env.JANKY_SHA1 or process.env.CI TimeReporter = require './time-reporter' timeReporter = new TimeReporter() From 6d132a9a24f1a0ba79a63277fc816efd9b9c85d9 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 8 Apr 2015 10:35:58 +0200 Subject: [PATCH 0566/1783] Use GYP_MSVS_VERSION=2013 as suggested on #5894 --- appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/appveyor.yml b/appveyor.yml index 19d49846e..ba817084b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,6 @@ environment: nodejs_version: "0.10" + GYP_MSVS_VERSION: 2013 install: - ps: Install-Product node $env:nodejs_version From 79989a59a96cc646c0d0908b1c2a51cbdb0e9982 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 8 Apr 2015 09:03:17 -0700 Subject: [PATCH 0567/1783] :arrow_up: settings-view@0.189 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9e9b716d5..e5d3eac3e 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "open-on-github": "0.36.0", "package-generator": "0.38.0", "release-notes": "0.52.0", - "settings-view": "0.187.0", + "settings-view": "0.189.0", "snippets": "0.88.0", "spell-check": "0.55.0", "status-bar": "0.67.0", From 937fc27f6e3deb4827c87e748b2828be86902059 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 8 Apr 2015 09:04:43 -0700 Subject: [PATCH 0568/1783] :arrow_up: keybinding-resolver@0.31 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e5d3eac3e..20bbb5043 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "grammar-selector": "0.46.0", "image-view": "0.54.0", "incompatible-packages": "0.24.0", - "keybinding-resolver": "0.30.0", + "keybinding-resolver": "0.31.0", "link": "0.30.0", "markdown-preview": "0.148.0", "metrics": "0.45.0", From fe927280ff1983b4b0869ca4fdb2db64d6851c46 Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 9 Apr 2015 01:12:41 +0900 Subject: [PATCH 0569/1783] :arrrow_up: one-dark-ui@v0.6.3 one-light-ui@v0.5.3 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 20bbb5043..7d7a2ba9a 100644 --- a/package.json +++ b/package.json @@ -76,10 +76,10 @@ "atom-light-ui": "0.41.0", "base16-tomorrow-dark-theme": "0.25.0", "base16-tomorrow-light-theme": "0.8.0", - "one-dark-ui": "0.6.2", + "one-dark-ui": "0.6.3", "one-dark-syntax": "0.3.0", "one-light-syntax": "0.4.0", - "one-light-ui": "0.5.2", + "one-light-ui": "0.5.3", "solarized-dark-syntax": "0.32.0", "solarized-light-syntax": "0.19.0", "archive-view": "0.55.0", From d0bd76072b6ed529b25ea6002f2a2183bb639db9 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 15:58:44 -0700 Subject: [PATCH 0570/1783] Inline platform system menu --- build/tasks/compile-packages-slug-task.coffee | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/build/tasks/compile-packages-slug-task.coffee b/build/tasks/compile-packages-slug-task.coffee index 4e24f948e..ed9c2e9e4 100644 --- a/build/tasks/compile-packages-slug-task.coffee +++ b/build/tasks/compile-packages-slug-task.coffee @@ -6,6 +6,13 @@ _ = require 'underscore-plus' module.exports = (grunt) -> {spawn, rm} = require('./task-helpers')(grunt) + getMenu = (appDir) -> + menusPath = path.join(appDir, 'menus') + menuPath = path.join(menusPath, process.platform) + menu = CSON.readFileSync(menuPath) if fs.isFileSync(menuPath) + rm menusPath + menu ? {} + grunt.registerTask 'compile-packages-slug', 'Add bundled package metadata information to the main package.json file', -> appDir = fs.realpathSync(grunt.config.get('atom.appDir')) @@ -50,5 +57,6 @@ module.exports = (grunt) -> metadata = grunt.file.readJSON(path.join(appDir, 'package.json')) metadata._atomPackages = packages + metadata._menu = getMenu(appDir) grunt.file.write(path.join(appDir, 'package.json'), JSON.stringify(metadata)) From f36584903ff9d579962978d67e2e275008df9101 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 16:51:57 -0700 Subject: [PATCH 0571/1783] Inline all keymaps into package.json --- build/tasks/compile-packages-slug-task.coffee | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build/tasks/compile-packages-slug-task.coffee b/build/tasks/compile-packages-slug-task.coffee index ed9c2e9e4..574ce89d4 100644 --- a/build/tasks/compile-packages-slug-task.coffee +++ b/build/tasks/compile-packages-slug-task.coffee @@ -13,6 +13,12 @@ module.exports = (grunt) -> rm menusPath menu ? {} + getKeymaps = (appDir) -> + keymapsPath = path.join(appDir, 'keymaps') + keymaps = fs.listSync(keymapsPath, ['.cson', '.json']).map (keymapPath) -> CSON.readFileSync(keymapPath) + rm keymapsPath + keymaps ? [] + grunt.registerTask 'compile-packages-slug', 'Add bundled package metadata information to the main package.json file', -> appDir = fs.realpathSync(grunt.config.get('atom.appDir')) @@ -58,5 +64,6 @@ module.exports = (grunt) -> metadata = grunt.file.readJSON(path.join(appDir, 'package.json')) metadata._atomPackages = packages metadata._menu = getMenu(appDir) + metadata._keymaps = getKeymaps(appDir) grunt.file.write(path.join(appDir, 'package.json'), JSON.stringify(metadata)) From bdca781fb8edfa9f4cbcac63c489a8cc0ab7dd0a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 16:52:22 -0700 Subject: [PATCH 0572/1783] Add atom prefix to keys --- build/tasks/compile-packages-slug-task.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/tasks/compile-packages-slug-task.coffee b/build/tasks/compile-packages-slug-task.coffee index 574ce89d4..c5af73911 100644 --- a/build/tasks/compile-packages-slug-task.coffee +++ b/build/tasks/compile-packages-slug-task.coffee @@ -63,7 +63,7 @@ module.exports = (grunt) -> metadata = grunt.file.readJSON(path.join(appDir, 'package.json')) metadata._atomPackages = packages - metadata._menu = getMenu(appDir) - metadata._keymaps = getKeymaps(appDir) + metadata._atomMenu = getMenu(appDir) + metadata._atomKeymaps = getKeymaps(appDir) grunt.file.write(path.join(appDir, 'package.json'), JSON.stringify(metadata)) From 0560687e966449e71652240c1f306ee7a5216d5f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 16:52:39 -0700 Subject: [PATCH 0573/1783] Remove unneeded default --- build/tasks/compile-packages-slug-task.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/tasks/compile-packages-slug-task.coffee b/build/tasks/compile-packages-slug-task.coffee index c5af73911..0d95f3e89 100644 --- a/build/tasks/compile-packages-slug-task.coffee +++ b/build/tasks/compile-packages-slug-task.coffee @@ -17,7 +17,7 @@ module.exports = (grunt) -> keymapsPath = path.join(appDir, 'keymaps') keymaps = fs.listSync(keymapsPath, ['.cson', '.json']).map (keymapPath) -> CSON.readFileSync(keymapPath) rm keymapsPath - keymaps ? [] + keymaps grunt.registerTask 'compile-packages-slug', 'Add bundled package metadata information to the main package.json file', -> appDir = fs.realpathSync(grunt.config.get('atom.appDir')) From d30b61f7c9a5a1046311a53d275319271a1bf476 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 16:54:55 -0700 Subject: [PATCH 0574/1783] Load platform menu from package.json --- src/menu-manager.coffee | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/menu-manager.coffee b/src/menu-manager.coffee index 1991cba95..29fdbce25 100644 --- a/src/menu-manager.coffee +++ b/src/menu-manager.coffee @@ -8,6 +8,11 @@ fs = require 'fs-plus' MenuHelpers = require './menu-helpers' +try + platformMenu = require('../package.json')?._atomMenu +catch error + platformMenu = null + # Extended: Provides a registry for menu items that you'd like to appear in the # application menu. # @@ -144,10 +149,13 @@ class MenuManager @sendToBrowserProcess(@template, keystrokesByCommand) loadPlatformItems: -> - menusDirPath = path.join(@resourcePath, 'menus') - platformMenuPath = fs.resolve(menusDirPath, process.platform, ['cson', 'json']) - {menu} = CSON.readFileSync(platformMenuPath) - @add(menu) + if platformMenuPath + @add(menu) + else + menusDirPath = path.join(@resourcePath, 'menus') + platformMenuPath = fs.resolve(menusDirPath, process.platform, ['cson', 'json']) + {menu} = CSON.readFileSync(platformMenuPath) + @add(menu) # Merges an item in a submenu aware way such that new items are always # appended to the bottom of existing menus where possible. From 0d3d72c18114a5e5a63602ab94a3606a665a0f59 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 17:24:38 -0700 Subject: [PATCH 0575/1783] Add missing extension --- build/tasks/compile-packages-slug-task.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/tasks/compile-packages-slug-task.coffee b/build/tasks/compile-packages-slug-task.coffee index 0d95f3e89..3deed46c0 100644 --- a/build/tasks/compile-packages-slug-task.coffee +++ b/build/tasks/compile-packages-slug-task.coffee @@ -8,7 +8,7 @@ module.exports = (grunt) -> getMenu = (appDir) -> menusPath = path.join(appDir, 'menus') - menuPath = path.join(menusPath, process.platform) + menuPath = path.join(menusPath, "#{process.platform}.cson") menu = CSON.readFileSync(menuPath) if fs.isFileSync(menuPath) rm menusPath menu ? {} From 50688973e65416b17866d2d2f3cbddf9aa6c5c5f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 17:25:02 -0700 Subject: [PATCH 0576/1783] Load keymaps from package.json --- build/tasks/compile-packages-slug-task.coffee | 10 +++++++++- src/keymap-extensions.coffee | 14 +++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/build/tasks/compile-packages-slug-task.coffee b/build/tasks/compile-packages-slug-task.coffee index 3deed46c0..e9db9b8fa 100644 --- a/build/tasks/compile-packages-slug-task.coffee +++ b/build/tasks/compile-packages-slug-task.coffee @@ -3,6 +3,8 @@ CSON = require 'season' fs = require 'fs-plus' _ = require 'underscore-plus' +OtherPlatforms = ['darwin', 'freebsd', 'linux', 'sunos', 'win32'].filter (platform) -> platform isnt process.platform + module.exports = (grunt) -> {spawn, rm} = require('./task-helpers')(grunt) @@ -15,7 +17,13 @@ module.exports = (grunt) -> getKeymaps = (appDir) -> keymapsPath = path.join(appDir, 'keymaps') - keymaps = fs.listSync(keymapsPath, ['.cson', '.json']).map (keymapPath) -> CSON.readFileSync(keymapPath) + keymaps = {} + for keymapPath in fs.listSync(keymapsPath, ['.cson', '.json']) + name = path.basename(keymapPath, path.extname(keymapPath)) + continue unless OtherPlatforms.indexOf(name) is -1 + + keymap = CSON.readFileSync(keymapPath) + keymaps[path.basename(keymapPath)] = keymap rm keymapsPath keymaps diff --git a/src/keymap-extensions.coffee b/src/keymap-extensions.coffee index 551c6580d..3d1ca3547 100644 --- a/src/keymap-extensions.coffee +++ b/src/keymap-extensions.coffee @@ -5,11 +5,23 @@ CSON = require 'season' {jQuery} = require 'space-pen' Grim = require 'grim' +try + bundledKeymaps = require('../package.json')?._atomKeymaps +catch error + bundledKeymaps = null + KeymapManager::onDidLoadBundledKeymaps = (callback) -> @emitter.on 'did-load-bundled-keymaps', callback KeymapManager::loadBundledKeymaps = -> - @loadKeymap(path.join(@resourcePath, 'keymaps')) + keymapsPath = path.join(@resourcePath, 'keymaps') + if bundledKeymaps? + for keymapName, keymap of bundledKeymaps + keymapPath = path.join(keymapsPath, keymapName) + @add(keymapPath, keymap) + else + @loadKeymap(keymapsPath) + @emit 'bundled-keymaps-loaded' if Grim.includeDeprecatedAPIs @emitter.emit 'did-load-bundled-keymaps' From ab79f2cf50d9089af441cc7f9003f6bd08fed2ad Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 17:28:02 -0700 Subject: [PATCH 0577/1783] :art: Drop unneeded detail: --- src/keymap-extensions.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keymap-extensions.coffee b/src/keymap-extensions.coffee index 3d1ca3547..06ff95cea 100644 --- a/src/keymap-extensions.coffee +++ b/src/keymap-extensions.coffee @@ -63,7 +63,7 @@ KeymapManager::subscribeToFileReadFailure = -> else error.message - atom.notifications.addError(message, {detail: detail, dismissable: true}) + atom.notifications.addError(message, {detail, dismissable: true}) # This enables command handlers registered via jQuery to call # `.abortKeyBinding()` on the `jQuery.Event` object passed to the handler. From 3954a5fd84d791f66704137bcfdac7711e20747b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 17:32:00 -0700 Subject: [PATCH 0578/1783] .cson -> .json --- build/tasks/compile-packages-slug-task.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/tasks/compile-packages-slug-task.coffee b/build/tasks/compile-packages-slug-task.coffee index e9db9b8fa..e31dc52e2 100644 --- a/build/tasks/compile-packages-slug-task.coffee +++ b/build/tasks/compile-packages-slug-task.coffee @@ -10,7 +10,7 @@ module.exports = (grunt) -> getMenu = (appDir) -> menusPath = path.join(appDir, 'menus') - menuPath = path.join(menusPath, "#{process.platform}.cson") + menuPath = path.join(menusPath, "#{process.platform}.json") menu = CSON.readFileSync(menuPath) if fs.isFileSync(menuPath) rm menusPath menu ? {} From c69af727cf5b9889e6a634310afac14e71b0cd51 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 17:34:48 -0700 Subject: [PATCH 0579/1783] Don't default menu value --- build/tasks/compile-packages-slug-task.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/tasks/compile-packages-slug-task.coffee b/build/tasks/compile-packages-slug-task.coffee index e31dc52e2..f3b04683e 100644 --- a/build/tasks/compile-packages-slug-task.coffee +++ b/build/tasks/compile-packages-slug-task.coffee @@ -13,7 +13,7 @@ module.exports = (grunt) -> menuPath = path.join(menusPath, "#{process.platform}.json") menu = CSON.readFileSync(menuPath) if fs.isFileSync(menuPath) rm menusPath - menu ? {} + menu getKeymaps = (appDir) -> keymapsPath = path.join(appDir, 'keymaps') From 4b8bb9e1d9fe927d0dd7566d068616608c463a92 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 17:39:50 -0700 Subject: [PATCH 0580/1783] platformMenuPath -> platformMenu --- src/menu-manager.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/menu-manager.coffee b/src/menu-manager.coffee index 29fdbce25..d0a95dd1f 100644 --- a/src/menu-manager.coffee +++ b/src/menu-manager.coffee @@ -149,8 +149,8 @@ class MenuManager @sendToBrowserProcess(@template, keystrokesByCommand) loadPlatformItems: -> - if platformMenuPath - @add(menu) + if platformMenu? + @add(platformMenu) else menusDirPath = path.join(@resourcePath, 'menus') platformMenuPath = fs.resolve(menusDirPath, process.platform, ['cson', 'json']) From 83541c01b59e0d8374e25e2460c1e6e61943cebf Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 18:00:08 -0700 Subject: [PATCH 0581/1783] Pull out menu property from _atomMenu --- src/menu-manager.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/menu-manager.coffee b/src/menu-manager.coffee index d0a95dd1f..6d4e4c77c 100644 --- a/src/menu-manager.coffee +++ b/src/menu-manager.coffee @@ -9,7 +9,7 @@ fs = require 'fs-plus' MenuHelpers = require './menu-helpers' try - platformMenu = require('../package.json')?._atomMenu + platformMenu = require('../package.json')?._atomMenu?.menu catch error platformMenu = null From ca67d33ebef514cdc4d879907809adf12bb979f5 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 7 Apr 2015 18:00:23 -0700 Subject: [PATCH 0582/1783] Use inlined context menu from package.json when available --- src/context-menu-manager.coffee | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/context-menu-manager.coffee b/src/context-menu-manager.coffee index 00b635251..7446c6ac0 100644 --- a/src/context-menu-manager.coffee +++ b/src/context-menu-manager.coffee @@ -8,6 +8,11 @@ Grim = require 'grim' MenuHelpers = require './menu-helpers' {validateSelector} = require './selector-validator' +try + platformContextMenu = require('../package.json')?._atomMenu?['context-menu'] +catch error + platformContextMenu = null + SpecificityCache = {} # Extended: Provides a registry for commands that you'd like to appear in the @@ -49,10 +54,13 @@ class ContextMenuManager atom.keymaps.onDidLoadBundledKeymaps => @loadPlatformItems() loadPlatformItems: -> - menusDirPath = path.join(@resourcePath, 'menus') - platformMenuPath = fs.resolve(menusDirPath, process.platform, ['cson', 'json']) - map = CSON.readFileSync(platformMenuPath) - atom.contextMenu.add(map['context-menu']) + if platformContextMenu? + @add(platformContextMenu) + else + menusDirPath = path.join(@resourcePath, 'menus') + platformMenuPath = fs.resolve(menusDirPath, process.platform, ['cson', 'json']) + map = CSON.readFileSync(platformMenuPath) + @add(map['context-menu']) # Public: Add context menu items scoped by CSS selectors. # From 80787ef1e20c1dbadd76fe45e90050e40966c0d8 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 8 Apr 2015 09:29:04 -0700 Subject: [PATCH 0583/1783] Remove try/catch around package.json requiring No other requires are ever guarded against and the package.json should be assumed to be valid JSON. --- src/context-menu-manager.coffee | 6 +----- src/keymap-extensions.coffee | 5 +---- src/menu-manager.coffee | 5 +---- src/package.coffee | 5 +---- 4 files changed, 4 insertions(+), 17 deletions(-) diff --git a/src/context-menu-manager.coffee b/src/context-menu-manager.coffee index 7446c6ac0..8397da33d 100644 --- a/src/context-menu-manager.coffee +++ b/src/context-menu-manager.coffee @@ -8,11 +8,7 @@ Grim = require 'grim' MenuHelpers = require './menu-helpers' {validateSelector} = require './selector-validator' -try - platformContextMenu = require('../package.json')?._atomMenu?['context-menu'] -catch error - platformContextMenu = null - +platformContextMenu = require('../package.json')?._atomMenu?['context-menu'] SpecificityCache = {} # Extended: Provides a registry for commands that you'd like to appear in the diff --git a/src/keymap-extensions.coffee b/src/keymap-extensions.coffee index 06ff95cea..7ffd3d7ef 100644 --- a/src/keymap-extensions.coffee +++ b/src/keymap-extensions.coffee @@ -5,10 +5,7 @@ CSON = require 'season' {jQuery} = require 'space-pen' Grim = require 'grim' -try - bundledKeymaps = require('../package.json')?._atomKeymaps -catch error - bundledKeymaps = null +bundledKeymaps = require('../package.json')?._atomKeymaps KeymapManager::onDidLoadBundledKeymaps = (callback) -> @emitter.on 'did-load-bundled-keymaps', callback diff --git a/src/menu-manager.coffee b/src/menu-manager.coffee index 6d4e4c77c..bd42dddb9 100644 --- a/src/menu-manager.coffee +++ b/src/menu-manager.coffee @@ -8,10 +8,7 @@ fs = require 'fs-plus' MenuHelpers = require './menu-helpers' -try - platformMenu = require('../package.json')?._atomMenu?.menu -catch error - platformMenu = null +platformMenu = require('../package.json')?._atomMenu?.menu # Extended: Provides a registry for menu items that you'd like to appear in the # application menu. diff --git a/src/package.coffee b/src/package.coffee index dd6701527..74c4f0eb8 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -11,10 +11,7 @@ Q = require 'q' ModuleCache = require './module-cache' ScopedProperties = require './scoped-properties' -try - packagesCache = require('../package.json')?._atomPackages ? {} -catch error - packagesCache = {} +packagesCache = require('../package.json')?._atomPackages ? {} # Loads and activates a package's main module and resources such as # stylesheets, keymaps, grammar, editor properties, and menus. From 6d61588467c529e99f5bcac7368d66f0ca9e2583 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 8 Apr 2015 09:40:23 -0700 Subject: [PATCH 0584/1783] Only look for JSON keymaps --- build/tasks/compile-packages-slug-task.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/tasks/compile-packages-slug-task.coffee b/build/tasks/compile-packages-slug-task.coffee index f3b04683e..613a4a380 100644 --- a/build/tasks/compile-packages-slug-task.coffee +++ b/build/tasks/compile-packages-slug-task.coffee @@ -18,7 +18,7 @@ module.exports = (grunt) -> getKeymaps = (appDir) -> keymapsPath = path.join(appDir, 'keymaps') keymaps = {} - for keymapPath in fs.listSync(keymapsPath, ['.cson', '.json']) + for keymapPath in fs.listSync(keymapsPath, ['.json']) name = path.basename(keymapPath, path.extname(keymapPath)) continue unless OtherPlatforms.indexOf(name) is -1 From adbd539302b0a979e3e136d3a4122bf6861bb803 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Wed, 8 Apr 2015 14:36:00 -0400 Subject: [PATCH 0585/1783] Revert :shirt: --- benchmark/fixtures/medium.coffee | 14 +++++++------- .../package-with-config-defaults/index.coffee | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/benchmark/fixtures/medium.coffee b/benchmark/fixtures/medium.coffee index 28ec156b0..2bdb8c6f7 100644 --- a/benchmark/fixtures/medium.coffee +++ b/benchmark/fixtures/medium.coffee @@ -209,13 +209,13 @@ template = (str) -> 'var p=[],print=function(){p.push.apply(p,arguments);};' + 'with(obj){p.push(\'' + str.replace(/[\r\t\n]/g, " ") - .replace(/'(?=[^<]*%>)/g,"\t") - .split("'").join("\\'") - .split("\t").join("'") - .replace(/<%=(.+?)%>/g, "',$1,'") - .split('<%').join("');") - .split('%>').join("p.push('") + - "');}return p.join('');" + .replace(/'(?=[^<]*%>)/g,"\t") + .split("'").join("\\'") + .split("\t").join("'") + .replace(/<%=(.+?)%>/g, "',$1,'") + .split('<%').join("');") + .split('%>').join("p.push('") + + "');}return p.join('');" # Create the template that we will use to generate the Docco HTML page. docco_template = template fs.readFileSync(__dirname + '/../resources/docco.jst').toString() diff --git a/spec/fixtures/packages/package-with-config-defaults/index.coffee b/spec/fixtures/packages/package-with-config-defaults/index.coffee index 6c48b2af4..554c6c5eb 100644 --- a/spec/fixtures/packages/package-with-config-defaults/index.coffee +++ b/spec/fixtures/packages/package-with-config-defaults/index.coffee @@ -1,5 +1,5 @@ module.exports = configDefaults: - numbers: {one: 1, two: 2} + numbers: { one: 1, two: 2 } activate: -> # no-op From 7fb6e79c8dcb9f189409f317145ee891764fae55 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 8 Apr 2015 17:03:50 -0700 Subject: [PATCH 0586/1783] :arrow_up: language-javascript@0.71 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7d7a2ba9a..45b92bc33 100644 --- a/package.json +++ b/package.json @@ -134,7 +134,7 @@ "language-html": "0.31.0", "language-hyperlink": "0.12.2", "language-java": "0.14.0", - "language-javascript": "0.70.0", + "language-javascript": "0.71.0", "language-json": "0.14.0", "language-less": "0.25.0", "language-make": "0.14.0", From 5fd767b9d8a7f3c43b7aa9accc7771b76556f0cb Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 8 Apr 2015 17:46:06 -0700 Subject: [PATCH 0587/1783] :arrow_up: symbols-view@0.94 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 45b92bc33..56bb2fa56 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,7 @@ "spell-check": "0.55.0", "status-bar": "0.67.0", "styleguide": "0.44.0", - "symbols-view": "0.93.0", + "symbols-view": "0.94.0", "tabs": "0.67.0", "timecop": "0.31.0", "tree-view": "0.170.0", From 821f60924fdd11bdea04fb5ad3f8eae23659b1c0 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 9 Apr 2015 10:29:36 +0200 Subject: [PATCH 0588/1783] Enable Multi-OS support --- .travis.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 535414f56..364794759 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,9 @@ -language: objective-c +os: + - linux + - osx + +install: + - test "$TRAVIS_OS_NAME" = "linux" && sudo apt-get install build-essential git libgnome-keyring-dev fakeroot script: script/cibuild From 3d6c6d0cc12d9baf2d2b9c45ab9586d88ee5c432 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 9 Apr 2015 10:40:50 +0200 Subject: [PATCH 0589/1783] :apple: Don't fail on Mac OS X build --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 364794759..eeefbfa84 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ os: - osx install: - - test "$TRAVIS_OS_NAME" = "linux" && sudo apt-get install build-essential git libgnome-keyring-dev fakeroot + - test "$TRAVIS_OS_NAME" = "linux" && sudo apt-get install build-essential git libgnome-keyring-dev fakeroot || true script: script/cibuild From f78dec2574eafab1de6343b5f8b8a9c23180d90d Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 9 Apr 2015 10:58:14 +0200 Subject: [PATCH 0590/1783] Run against multiple nodejs versions --- .travis.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index eeefbfa84..398a2c141 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,20 @@ +env: + - NODE_VERSION=0.10 + - NODE_VERSION=0.12 + - NODE_VERSION=iojs + os: - linux - osx install: - - test "$TRAVIS_OS_NAME" = "linux" && sudo apt-get install build-essential git libgnome-keyring-dev fakeroot || true + - git clone https://github.com/creationix/nvm.git ./.nvm + - source ./.nvm/nvm.sh + - nvm install $NODE_VERSION + - nvm use $NODE_VERSION + - if [ $TRAVIS_OS_NAME == "linux" ]; then + sudo apt-get install build-essential git libgnome-keyring-dev fakeroot; + fi script: script/cibuild From c8d30d929cebdef756995d21d9928ec7b099dc16 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 9 Apr 2015 11:09:23 +0200 Subject: [PATCH 0591/1783] Remove iojs from build matrix --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 398a2c141..7c0bde467 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ env: - NODE_VERSION=0.10 - NODE_VERSION=0.12 - - NODE_VERSION=iojs os: - linux From 31d1f587e3f1f34c80bd1e6d2ced92cd09f0e5f1 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 9 Apr 2015 11:36:26 +0200 Subject: [PATCH 0592/1783] :penguin: Run tests also on Linux --- build/Gruntfile.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/Gruntfile.coffee b/build/Gruntfile.coffee index 05efaeb38..24ad88b7e 100644 --- a/build/Gruntfile.coffee +++ b/build/Gruntfile.coffee @@ -226,7 +226,7 @@ module.exports = (grunt) -> ciTasks.push('set-version', 'check-licenses', 'lint') ciTasks.push('mkdeb') if process.platform is 'linux' ciTasks.push('create-windows-installer') if process.platform is 'win32' - ciTasks.push('test') if process.platform is 'darwin' + ciTasks.push('test') if process.platform in ['darwin', 'linux'] ciTasks.push('codesign') ciTasks.push('publish-build') grunt.registerTask('ci', ciTasks) From b8fb2f4d11cd6bdf2bd8b5ec2d01702d42c3cafb Mon Sep 17 00:00:00 2001 From: Ivan Zuzak Date: Thu, 9 Apr 2015 15:38:48 +0200 Subject: [PATCH 0593/1783] Clarify that URIs don't need to be files --- src/workspace.coffee | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/workspace.coffee b/src/workspace.coffee index 6c60cf22a..e864e2af2 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -371,11 +371,12 @@ class Workspace extends Model Section: Opening ### - # Essential: Opens the given URI in Atom asynchronously, if it's not already open. - # If no URI is given, or the URI is the path of a file that does not exist, - # a new empty text edtior is created. - # - # * `uri` (optional) A {String} containing a URI. + # Essential: Opens the given URI in Atom asynchronously. + # If the URI is already open, the existing item for that URI will be + # activated. If no URI is given, or no registered opener can open + # the URI, a new empty {TextEditor} will be created. + # + # * `uri` (optional) A {String} containing a URI. # * `options` (optional) {Object} # * `initialLine` A {Number} indicating which row to move the cursor to # initially. Defaults to `0`. From 5068bd530e50cdcd4e0353b8be0bf99325e13077 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 9 Apr 2015 19:05:33 +0200 Subject: [PATCH 0594/1783] Revert ":penguin: Run tests also on Linux" This reverts commit 31d1f587e3f1f34c80bd1e6d2ced92cd09f0e5f1. --- build/Gruntfile.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/Gruntfile.coffee b/build/Gruntfile.coffee index 24ad88b7e..05efaeb38 100644 --- a/build/Gruntfile.coffee +++ b/build/Gruntfile.coffee @@ -226,7 +226,7 @@ module.exports = (grunt) -> ciTasks.push('set-version', 'check-licenses', 'lint') ciTasks.push('mkdeb') if process.platform is 'linux' ciTasks.push('create-windows-installer') if process.platform is 'win32' - ciTasks.push('test') if process.platform in ['darwin', 'linux'] + ciTasks.push('test') if process.platform is 'darwin' ciTasks.push('codesign') ciTasks.push('publish-build') grunt.registerTask('ci', ciTasks) From ffd4ab8aff517365465334a47a81a4f540460b64 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 9 Apr 2015 19:42:23 +0200 Subject: [PATCH 0595/1783] Clone .nvm into tmp directory --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7c0bde467..7e47d0660 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,8 +7,8 @@ os: - osx install: - - git clone https://github.com/creationix/nvm.git ./.nvm - - source ./.nvm/nvm.sh + - git clone https://github.com/creationix/nvm.git /tmp/.nvm + - source /tmp/.nvm/nvm.sh - nvm install $NODE_VERSION - nvm use $NODE_VERSION - if [ $TRAVIS_OS_NAME == "linux" ]; then From 1f9d8b129f13cca8249b115c0f791de858353b21 Mon Sep 17 00:00:00 2001 From: subesokun Date: Thu, 9 Apr 2015 20:32:06 +0200 Subject: [PATCH 0596/1783] :memo: Fix doc on getting the home directory --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 66080c614..fe9a742b4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -66,7 +66,7 @@ For more information on how to work with Atom's official packages, see * Class methods and properties (methods starting with a `@`) * Instance methods and properties * Avoid platform-dependent code: - * Use `require('atom').fs.getHomeDirectory()` to get the home directory. + * Use `require('fs-plus').getHomeDirectory()` to get the home directory. * Use `path.join()` to concatenate filenames. * Use `os.tmpdir()` rather than `/tmp` when you need to reference the temporary directory. From 09be369544b9c7fe738e5a4b83c3d9b100c41266 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 9 Apr 2015 13:06:11 -0700 Subject: [PATCH 0597/1783] Update help message to reflect changes to multi-path handling --- src/browser/main.coffee | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/browser/main.coffee b/src/browser/main.coffee index 812771e9a..469d53fae 100644 --- a/src/browser/main.coffee +++ b/src/browser/main.coffee @@ -91,12 +91,10 @@ parseCommandLine = -> Usage: atom [options] [path ...] - One or more paths to files or folders to open may be specified. - - File paths will open in the current window. - - Folder paths will open in an existing window if that folder has already been - opened or a new window if it hasn't. + One or more paths to files or folders may be specified. If there is an + existing Atom window that contains all of the given folders, the paths + will be opened in that window. Otherwise, they will be opened in a new + window. Environment Variables: From f35187e8c343aa329fa151c8f8d6ad3622dd9e00 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Thu, 9 Apr 2015 14:21:03 -0700 Subject: [PATCH 0598/1783] Allow editor.completions to be an array or an object. --- src/config-schema.coffee | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/config-schema.coffee b/src/config-schema.coffee index c2944911b..87e1040bc 100644 --- a/src/config-schema.coffee +++ b/src/config-schema.coffee @@ -99,9 +99,7 @@ module.exports = # These can be used as globals or scoped, thus defaults. completions: - type: "array" - items: - type: "string" + type: ['array', 'object'] default: [] fontFamily: type: 'string' From d9d319c4066744cd1edcf2a868f17e13dc5f127c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 9 Apr 2015 16:33:12 -0700 Subject: [PATCH 0599/1783] :arrow_up: settings-view@0.190 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 56bb2fa56..5339f582c 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "open-on-github": "0.36.0", "package-generator": "0.38.0", "release-notes": "0.52.0", - "settings-view": "0.189.0", + "settings-view": "0.190.0", "snippets": "0.88.0", "spell-check": "0.55.0", "status-bar": "0.67.0", From 94ebbccc9f8dee5c0861c454c45c4ef1c58ddf8b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 9 Apr 2015 16:36:56 -0700 Subject: [PATCH 0600/1783] :arrow_up: language-python@0.34 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5339f582c..8e071aaf0 100644 --- a/package.json +++ b/package.json @@ -143,7 +143,7 @@ "language-perl": "0.22.0", "language-php": "0.22.0", "language-property-list": "0.8.0", - "language-python": "0.33.0", + "language-python": "0.34.0", "language-ruby": "0.51.0", "language-ruby-on-rails": "0.21.0", "language-sass": "0.36.0", From 43a807c6301665cbf4308576c913ad249b367955 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 10 Apr 2015 10:17:17 +0200 Subject: [PATCH 0601/1783] Fix cibuild returning 0 as status code --- build/tasks/spec-task.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/tasks/spec-task.coffee b/build/tasks/spec-task.coffee index 49c9f8592..1126e2541 100644 --- a/build/tasks/spec-task.coffee +++ b/build/tasks/spec-task.coffee @@ -4,7 +4,7 @@ path = require 'path' _ = require 'underscore-plus' async = require 'async' -concurrency = 1 +concurrency = 2 module.exports = (grunt) -> {isAtomPackage, spawn} = require('./task-helpers')(grunt) @@ -78,7 +78,7 @@ module.exports = (grunt) -> continue unless isAtomPackage(packagePath) packageSpecQueue.push(packagePath) - packageSpecQueue.concurrency = concurrency - 1 + packageSpecQueue.concurrency = Math.min(1, concurrency - 1) packageSpecQueue.drain = -> callback(null, failedPackages) runCoreSpecs = (callback) -> @@ -110,7 +110,7 @@ module.exports = (grunt) -> fs.unlinkSync('ci.log') else # TODO: Restore concurrency on Windows - packageSpecQueue.concurrency = concurrency + packageSpecQueue?.concurrency = concurrency logDeprecations('Core Specs', results) callback(null, error) From 01504cfde56c85530dd328a95721768458b9aee6 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 10 Apr 2015 10:20:02 +0200 Subject: [PATCH 0602/1783] Use Math.max instead of Math.min --- build/tasks/spec-task.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/tasks/spec-task.coffee b/build/tasks/spec-task.coffee index 1126e2541..1151974b2 100644 --- a/build/tasks/spec-task.coffee +++ b/build/tasks/spec-task.coffee @@ -78,7 +78,7 @@ module.exports = (grunt) -> continue unless isAtomPackage(packagePath) packageSpecQueue.push(packagePath) - packageSpecQueue.concurrency = Math.min(1, concurrency - 1) + packageSpecQueue.concurrency = Math.max(1, concurrency - 1) packageSpecQueue.drain = -> callback(null, failedPackages) runCoreSpecs = (callback) -> From f790cda5caff682cf23d8f3f72cc56ad98ab7dd7 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 10 Apr 2015 11:45:03 +0200 Subject: [PATCH 0603/1783] Run CI tests verbosely --- build/tasks/spec-task.coffee | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/build/tasks/spec-task.coffee b/build/tasks/spec-task.coffee index 1151974b2..449c8e93c 100644 --- a/build/tasks/spec-task.coffee +++ b/build/tasks/spec-task.coffee @@ -12,7 +12,7 @@ module.exports = (grunt) -> packageSpecQueue = null logDeprecations = (label, {stderr}={}) -> - return unless process.env.JANKY_SHA1 + return unless process.env.JANKY_SHA1 or process.env.CI stderr ?= '' deprecatedStart = stderr.indexOf('Calls to deprecated functions') return if deprecatedStart is -1 @@ -60,7 +60,7 @@ module.exports = (grunt) -> cwd: packagePath env: _.extend({}, process.env, ATOM_PATH: rootDir) - grunt.verbose.writeln "Launching #{path.basename(packagePath)} specs." + grunt.log.ok "Launching #{path.basename(packagePath)} specs." spawn options, (error, results, code) -> if process.platform is 'win32' if error @@ -78,7 +78,7 @@ module.exports = (grunt) -> continue unless isAtomPackage(packagePath) packageSpecQueue.push(packagePath) - packageSpecQueue.concurrency = Math.max(1, concurrency - 1) + packageSpecQueue.concurrency = concurrency - 1 packageSpecQueue.drain = -> callback(null, failedPackages) runCoreSpecs = (callback) -> @@ -104,6 +104,7 @@ module.exports = (grunt) -> ATOM_INTEGRATION_TESTS_ENABLED: true ) + grunt.log.ok "Launching core specs." spawn options, (error, results, code) -> if process.platform is 'win32' process.stderr.write(fs.readFileSync('ci.log')) if error From 4d20e17b2b4631acfbc884d706a07c34d24d119b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 10 Apr 2015 09:08:41 -0700 Subject: [PATCH 0604/1783] :arrow_up: language-javascript@0.72 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8e071aaf0..9f0d43e57 100644 --- a/package.json +++ b/package.json @@ -134,7 +134,7 @@ "language-html": "0.31.0", "language-hyperlink": "0.12.2", "language-java": "0.14.0", - "language-javascript": "0.71.0", + "language-javascript": "0.72.0", "language-json": "0.14.0", "language-less": "0.25.0", "language-make": "0.14.0", From 6dfcc582b39ea2b46866c609bd80d00d519eb9a6 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 10 Apr 2015 21:07:14 +0200 Subject: [PATCH 0605/1783] Increase defaultTimeoutInterval for Travis --- spec/spec-helper.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/spec-helper.coffee b/spec/spec-helper.coffee index 1c9e6fb6b..6b4a8ff3d 100644 --- a/spec/spec-helper.coffee +++ b/spec/spec-helper.coffee @@ -51,7 +51,7 @@ Object.defineProperty document, 'title', jasmine.getEnv().addEqualityTester(_.isEqual) # Use underscore's definition of equality for toEqual assertions -if process.env.JANKY_SHA1 and process.platform is 'win32' +if (process.env.JANKY_SHA1 and process.platform is 'win32') or process.env.CI jasmine.getEnv().defaultTimeoutInterval = 60000 else jasmine.getEnv().defaultTimeoutInterval = 5000 From 3bbf337d648a951f5046dad36a745f8f1c18e8d1 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 10 Apr 2015 14:59:17 -0700 Subject: [PATCH 0606/1783] :arrow_up: notifications@0.37 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9f0d43e57..127f5fb46 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,7 @@ "link": "0.30.0", "markdown-preview": "0.148.0", "metrics": "0.45.0", - "notifications": "0.36.0", + "notifications": "0.37.0", "open-on-github": "0.36.0", "package-generator": "0.38.0", "release-notes": "0.52.0", From 27e2a04ba9c8ebdd366e6d49de8ff70becc176f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=C5=BDu=C5=BEak?= Date: Sat, 11 Apr 2015 10:30:32 +0200 Subject: [PATCH 0607/1783] :arrow_up: language-todo@0.18.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 127f5fb46..bc8f83188 100644 --- a/package.json +++ b/package.json @@ -151,7 +151,7 @@ "language-source": "0.9.0", "language-sql": "0.15.0", "language-text": "0.6.0", - "language-todo": "0.17.0", + "language-todo": "0.18.0", "language-toml": "0.15.0", "language-xml": "0.28.0", "language-yaml": "0.22.0" From 2dda990533c144b7c39c5284ded5d5e378912930 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Sat, 11 Apr 2015 11:46:20 +0200 Subject: [PATCH 0608/1783] Try again to run specs on :penguin: --- .travis.yml | 2 ++ build/Gruntfile.coffee | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7e47d0660..2372e62b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,8 @@ install: - nvm use $NODE_VERSION - if [ $TRAVIS_OS_NAME == "linux" ]; then sudo apt-get install build-essential git libgnome-keyring-dev fakeroot; + export DISPLAY=:99.0; + sh -e /etc/init.d/xvfb start; fi script: script/cibuild diff --git a/build/Gruntfile.coffee b/build/Gruntfile.coffee index 05efaeb38..24ad88b7e 100644 --- a/build/Gruntfile.coffee +++ b/build/Gruntfile.coffee @@ -226,7 +226,7 @@ module.exports = (grunt) -> ciTasks.push('set-version', 'check-licenses', 'lint') ciTasks.push('mkdeb') if process.platform is 'linux' ciTasks.push('create-windows-installer') if process.platform is 'win32' - ciTasks.push('test') if process.platform is 'darwin' + ciTasks.push('test') if process.platform in ['darwin', 'linux'] ciTasks.push('codesign') ciTasks.push('publish-build') grunt.registerTask('ci', ciTasks) From 756ce8cea65c75f4a6f2dc0a33f7c80108df3828 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Sat, 11 Apr 2015 12:13:17 +0200 Subject: [PATCH 0609/1783] Avoid specs to trip up on each other ...because of possible race conditions. --- build/tasks/spec-task.coffee | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build/tasks/spec-task.coffee b/build/tasks/spec-task.coffee index da5b24685..da3c67df4 100644 --- a/build/tasks/spec-task.coffee +++ b/build/tasks/spec-task.coffee @@ -4,7 +4,7 @@ path = require 'path' _ = require 'underscore-plus' async = require 'async' -concurrency = 2 +concurrency = 1 module.exports = (grunt) -> {isAtomPackage, spawn} = require('./task-helpers')(grunt) @@ -78,7 +78,7 @@ module.exports = (grunt) -> continue unless isAtomPackage(packagePath) packageSpecQueue.push(packagePath) - packageSpecQueue.concurrency = concurrency - 1 + packageSpecQueue.concurrency = concurrency packageSpecQueue.drain = -> callback(null, failedPackages) runCoreSpecs = (callback) -> @@ -122,9 +122,9 @@ module.exports = (grunt) -> # TODO: This should really be parallel on both platforms, however our # fixtures step on each others toes currently. - if process.platform in ['darwin', 'linux'] + if process.platform is 'darwin' method = async.parallel - else if process.platform is 'win32' + else if process.platform in ['win32', 'linux'] method = async.series method [runCoreSpecs, runPackageSpecs], (error, results) -> From b9c98bced45b539df53eb84c389a25ccc3433ed7 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Sat, 11 Apr 2015 12:33:35 +0200 Subject: [PATCH 0610/1783] Enable RANDR extension for xvfb --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2372e62b4..9deccde61 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ install: - if [ $TRAVIS_OS_NAME == "linux" ]; then sudo apt-get install build-essential git libgnome-keyring-dev fakeroot; export DISPLAY=:99.0; - sh -e /etc/init.d/xvfb start; + sh -e /etc/init.d/xvfb start -- :99 -screen 0 1024x768x24 -ac +extension GLX +extension RANDR +render -noreset; fi script: script/cibuild From 458cd0bf2f4cc3c2f7f9981bf8c1ee57e306947e Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Sat, 11 Apr 2015 15:05:49 +0200 Subject: [PATCH 0611/1783] Revert "Avoid specs to trip up on each other" This reverts commit 756ce8cea65c75f4a6f2dc0a33f7c80108df3828. --- .travis.yml | 2 +- build/tasks/spec-task.coffee | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9deccde61..2372e62b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ install: - if [ $TRAVIS_OS_NAME == "linux" ]; then sudo apt-get install build-essential git libgnome-keyring-dev fakeroot; export DISPLAY=:99.0; - sh -e /etc/init.d/xvfb start -- :99 -screen 0 1024x768x24 -ac +extension GLX +extension RANDR +render -noreset; + sh -e /etc/init.d/xvfb start; fi script: script/cibuild diff --git a/build/tasks/spec-task.coffee b/build/tasks/spec-task.coffee index da3c67df4..da5b24685 100644 --- a/build/tasks/spec-task.coffee +++ b/build/tasks/spec-task.coffee @@ -4,7 +4,7 @@ path = require 'path' _ = require 'underscore-plus' async = require 'async' -concurrency = 1 +concurrency = 2 module.exports = (grunt) -> {isAtomPackage, spawn} = require('./task-helpers')(grunt) @@ -78,7 +78,7 @@ module.exports = (grunt) -> continue unless isAtomPackage(packagePath) packageSpecQueue.push(packagePath) - packageSpecQueue.concurrency = concurrency + packageSpecQueue.concurrency = concurrency - 1 packageSpecQueue.drain = -> callback(null, failedPackages) runCoreSpecs = (callback) -> @@ -122,9 +122,9 @@ module.exports = (grunt) -> # TODO: This should really be parallel on both platforms, however our # fixtures step on each others toes currently. - if process.platform is 'darwin' + if process.platform in ['darwin', 'linux'] method = async.parallel - else if process.platform in ['win32', 'linux'] + else if process.platform is 'win32' method = async.series method [runCoreSpecs, runPackageSpecs], (error, results) -> From fe4fff4dc80ad4745606cd23bcaa7ea0e953f1b6 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Sat, 11 Apr 2015 16:07:30 +0200 Subject: [PATCH 0612/1783] Run script/cibuild with sudo --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2372e62b4..4ecf6125a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ install: sh -e /etc/init.d/xvfb start; fi -script: script/cibuild +script: sudo script/cibuild notifications: email: From 8aba0f721855f7152b0c428dfa0a1abae718983b Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 13 Apr 2015 13:21:07 +1200 Subject: [PATCH 0613/1783] :arrow_up: settings-view to load config for inactive packages --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bc8f83188..88019a403 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "open-on-github": "0.36.0", "package-generator": "0.38.0", "release-notes": "0.52.0", - "settings-view": "0.190.0", + "settings-view": "0.191.0", "snippets": "0.88.0", "spell-check": "0.55.0", "status-bar": "0.67.0", From 379ec598e87b7d84158184b909b42d8076354a33 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 13 Apr 2015 10:04:06 +0200 Subject: [PATCH 0614/1783] Revert "Run script/cibuild with sudo" This reverts commit fe4fff4dc80ad4745606cd23bcaa7ea0e953f1b6. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4ecf6125a..2372e62b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ install: sh -e /etc/init.d/xvfb start; fi -script: sudo script/cibuild +script: script/cibuild notifications: email: From 16dbb7d0bb1edb1bf2fe542e5dfe122bc5273fa7 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 13 Apr 2015 12:02:06 +0200 Subject: [PATCH 0615/1783] :penguin: :green_heart: Mock native clipboard appropriately --- spec/spec-helper.coffee | 2 +- spec/text-editor-spec.coffee | 2 +- src/clipboard.coffee | 8 +------- src/native-clipboard.coffee | 6 ++++++ 4 files changed, 9 insertions(+), 9 deletions(-) create mode 100644 src/native-clipboard.coffee diff --git a/spec/spec-helper.coffee b/spec/spec-helper.coffee index 1c9e6fb6b..33ec8c521 100644 --- a/spec/spec-helper.coffee +++ b/spec/spec-helper.coffee @@ -24,7 +24,7 @@ TextEditorElement = require '../src/text-editor-element' TokenizedBuffer = require '../src/tokenized-buffer' TextEditorComponent = require '../src/text-editor-component' pathwatcher = require 'pathwatcher' -clipboard = require 'clipboard' +clipboard = require "../src/native-clipboard" atom.themes.loadBaseStylesheets() atom.themes.requireStylesheet '../static/jasmine' diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 06f285fd0..38f17072d 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -1,4 +1,4 @@ -clipboard = require 'clipboard' +clipboard = require '../src/native-clipboard' TextEditor = require '../src/text-editor' describe "TextEditor", -> diff --git a/src/clipboard.coffee b/src/clipboard.coffee index bc0926521..80ec464e7 100644 --- a/src/clipboard.coffee +++ b/src/clipboard.coffee @@ -1,11 +1,5 @@ crypto = require 'crypto' - -# Using clipboard in renderer process is not safe on Linux. -clipboard = - if process.platform is 'linux' - require('remote').require 'clipboard' - else - require 'clipboard' +clipboard = require "./native-clipboard" # Extended: Represents the clipboard used for copying and pasting in Atom. # diff --git a/src/native-clipboard.coffee b/src/native-clipboard.coffee new file mode 100644 index 000000000..f66d44646 --- /dev/null +++ b/src/native-clipboard.coffee @@ -0,0 +1,6 @@ +# Using clipboard in renderer process is not safe on Linux. +module.exports = + if process.platform is 'linux' + require('remote').require 'clipboard' + else + require 'clipboard' From 8daca6a63b76f484898fa751f4cac620a5f43e48 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 13 Apr 2015 12:24:25 +0200 Subject: [PATCH 0616/1783] :penguin: :green_heart: Humanize keystrokes in specs --- spec/tooltip-manager-spec.coffee | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/spec/tooltip-manager-spec.coffee b/spec/tooltip-manager-spec.coffee index 74b875658..88d235398 100644 --- a/spec/tooltip-manager-spec.coffee +++ b/spec/tooltip-manager-spec.coffee @@ -1,9 +1,13 @@ TooltipManager = require '../src/tooltip-manager' {$} = require '../src/space-pen-extensions' +_ = require "underscore-plus" describe "TooltipManager", -> [manager, element] = [] + ctrlX = _.humanizeKeystroke("ctrl-x") + ctrlY = _.humanizeKeystroke("ctrl-y") + beforeEach -> manager = new TooltipManager element = document.createElement('div') @@ -35,7 +39,7 @@ describe "TooltipManager", -> hover element, -> tooltipElement = document.body.querySelector(".tooltip") - expect(tooltipElement).toHaveText "Title ⌃X ⌃Y" + expect(tooltipElement).toHaveText "Title #{ctrlX} #{ctrlY}" describe "when no title is specified", -> it "shows the key binding corresponding to the command alone", -> @@ -45,7 +49,7 @@ describe "TooltipManager", -> hover element, -> tooltipElement = document.body.querySelector(".tooltip") - expect(tooltipElement).toHaveText "⌃X ⌃Y" + expect(tooltipElement).toHaveText "#{ctrlX} #{ctrlY}" describe "when a keyBindingTarget is specified", -> it "looks up the key binding relative to the target", -> @@ -57,7 +61,7 @@ describe "TooltipManager", -> hover element, -> tooltipElement = document.body.querySelector(".tooltip") - expect(tooltipElement).toHaveText "⌃X ⌃Y" + expect(tooltipElement).toHaveText "#{ctrlX} #{ctrlY}" it "does not display the keybinding if there is nothing mapped to the specified keyBindingCommand", -> manager.add element, title: 'A Title', keyBindingCommand: 'test-command', keyBindingTarget: element From 106f9fdf2e122acfecca759c53549f8f6fb5d5d3 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 13 Apr 2015 12:28:20 +0200 Subject: [PATCH 0617/1783] Use src/native-clipboard in atom-application --- spec/text-editor-component-spec.coffee | 2 +- src/browser/atom-application.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index b2ef2ec51..ad1f50d74 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -2815,7 +2815,7 @@ describe "TextEditorComponent", -> clipboardWrittenTo = false spyOn(require('ipc'), 'send').andCallFake (eventName, selectedText) -> if eventName is 'write-text-to-selection-clipboard' - require('clipboard').writeText(selectedText, 'selection') + require('../src/native-clipboard').writeText(selectedText, 'selection') clipboardWrittenTo = true atom.clipboard.write('') diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 7c15d0f2a..950cb6b78 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -256,7 +256,7 @@ class AtomApplication clipboard = null ipc.on 'write-text-to-selection-clipboard', (event, selectedText) -> - clipboard ?= require 'clipboard' + clipboard ?= require '../native-clipboard' clipboard.writeText(selectedText, 'selection') # Public: Executes the given command. From f633a4f771b3f25728bd97ad057906dd06d2bf91 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 13 Apr 2015 14:20:17 +0200 Subject: [PATCH 0618/1783] Use src/native-clipboard in TextEditorComponent --- src/text-editor-component.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 4d04dc98f..fb6f42a21 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -556,7 +556,7 @@ class TextEditorComponent pasteSelectionClipboard = (event) => if event?.which is 2 and process.platform is 'linux' - if selection = require('clipboard').readText('selection') + if selection = require('./native-clipboard').readText('selection') @editor.insertText(selection) window.addEventListener('mousemove', onMouseMove) From c4205e36a628ac1544344afeb760e0ee713abaab Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 13 Apr 2015 14:32:40 +0200 Subject: [PATCH 0619/1783] :green_heart: Use a serif font to make sure char widths change --- spec/text-editor-component-spec.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index ad1f50d74..d21b36118 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -2444,7 +2444,7 @@ describe "TextEditorComponent", -> initialLineHeightInPixels = editor.getLineHeightInPixels() initialCharWidth = editor.getDefaultCharWidth() - component.setFontFamily('sans-serif') + component.setFontFamily('serif') expect(editor.getDefaultCharWidth()).toBe initialCharWidth wrapperView.show() @@ -2453,7 +2453,7 @@ describe "TextEditorComponent", -> it "does not re-measure character widths until the editor is shown again", -> wrapperView.hide() - component.setFontFamily('sans-serif') + component.setFontFamily('serif') wrapperView.show() editor.setCursorBufferPosition([0, Infinity]) From 87972caf1e85d01a99b08264856027f307ccabde Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 13 Apr 2015 16:24:22 +0200 Subject: [PATCH 0620/1783] :penguin: Disable failing spec --- spec/text-editor-component-spec.coffee | 17 +++++++++-------- src/text-editor-component.coffee | 4 ++++ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index d21b36118..2ed17ab9f 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -1352,17 +1352,18 @@ describe "TextEditorComponent", -> expect(overlay.style.left).toBe position.left + gutterWidth + 'px' expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' - editor.insertText('a') - nextAnimationFrame() + if process.platform isnt "linux" # see TextEditorComponent#measureWindowSize + editor.insertText('a') + nextAnimationFrame() - expect(overlay.style.left).toBe windowWidth - itemWidth + 'px' - expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' + expect(overlay.style.left).toBe windowWidth - itemWidth + 'px' + expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' - editor.insertText('b') - nextAnimationFrame() + editor.insertText('b') + nextAnimationFrame() - expect(overlay.style.left).toBe windowWidth - itemWidth + 'px' - expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' + expect(overlay.style.left).toBe windowWidth - itemWidth + 'px' + expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' describe "hidden input field", -> it "renders the hidden input field at the position of the last cursor if the cursor is on screen and the editor is focused", -> diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index fb6f42a21..4348279de 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -620,6 +620,10 @@ class TextEditorComponent measureWindowSize: -> return unless @mounted + + # FIXME: on Ubuntu (via xvfb) `window.innerWidth` reports an incorrect value + # when window gets resized through `atom.setWindowDimensions({width: + # windowWidth, height: windowHeight})`. @presenter.setWindowSize(window.innerWidth, window.innerHeight) sampleFontStyling: => From 4cb7bde4a6cc794cf1b57d2f59ac37b7f986936b Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 13 Apr 2015 16:59:29 +0200 Subject: [PATCH 0621/1783] :green_heart: Fix race condition on window-spec ...caused by an afterEach block which was called before the SUT. --- spec/window-spec.coffee | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/spec/window-spec.coffee b/spec/window-spec.coffee index 883474e85..3c1a5b4ae 100644 --- a/spec/window-spec.coffee +++ b/spec/window-spec.coffee @@ -285,19 +285,35 @@ describe "Window", -> it "adds it to the project's paths", -> pathToOpen = __filename atom.getCurrentWindow().send 'message', 'open-locations', [{pathToOpen}] - expect(atom.project.getPaths()[0]).toBe __dirname + + waitsFor -> + atom.project.getPaths().length is 1 + + runs -> + expect(atom.project.getPaths()[0]).toBe __dirname describe "when the opened path does not exist but its parent directory does", -> it "adds the parent directory to the project paths", -> pathToOpen = path.join(__dirname, 'this-path-does-not-exist.txt') atom.getCurrentWindow().send 'message', 'open-locations', [{pathToOpen}] - expect(atom.project.getPaths()[0]).toBe __dirname + + waitsFor -> + atom.project.getPaths().length is 1 + + runs -> + expect(atom.project.getPaths()[0]).toBe __dirname describe "when the opened path is a file", -> it "opens it in the workspace", -> pathToOpen = __filename atom.getCurrentWindow().send 'message', 'open-locations', [{pathToOpen}] - expect(atom.workspace.open.mostRecentCall.args[0]).toBe __filename + + waitsFor -> + atom.workspace.open.callCount is 1 + + runs -> + expect(atom.workspace.open.mostRecentCall.args[0]).toBe __filename + describe "when the opened path is a directory", -> it "does not open it in the workspace", -> From aae4a4b016d86e189495834cdd4e1e1c2f312987 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 13 Apr 2015 11:01:54 -0700 Subject: [PATCH 0622/1783] :arrow_up: language-html --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 88019a403..e65f94ff3 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,7 @@ "language-gfm": "0.67.0", "language-git": "0.10.0", "language-go": "0.23.0", - "language-html": "0.31.0", + "language-html": "0.32.0", "language-hyperlink": "0.12.2", "language-java": "0.14.0", "language-javascript": "0.72.0", From 2fcf5d6248107e4bbe59481b5c32962451844bd7 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 10 Apr 2015 13:45:03 -0700 Subject: [PATCH 0623/1783] Precompile bootstrap.less --- build/tasks/prebuild-less-task.coffee | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/build/tasks/prebuild-less-task.coffee b/build/tasks/prebuild-less-task.coffee index bcaa0467f..58f5138a1 100644 --- a/build/tasks/prebuild-less-task.coffee +++ b/build/tasks/prebuild-less-task.coffee @@ -1,9 +1,24 @@ path = require 'path' fs = require 'fs' - +temp = require('temp').track() LessCache = require 'less-cache' module.exports = (grunt) -> + {rm} = require('./task-helpers')(grunt) + + compileBootstrap = -> + appDir = grunt.config.get('atom.appDir') + bootstrapLessPath = path.join(appDir, 'static', 'bootstrap.less') + bootstrapCssPath = path.join(appDir, 'static', 'bootstrap.css') + + lessCache = new LessCache + cacheDir: temp.mkdirSync('atom-less-cache') + resourcePath: path.resolve('.') + + bootstrapCss = lessCache.readFileSync(bootstrapLessPath) + grunt.file.write(bootstrapCssPath, bootstrapCss) + rm(bootstrapLessPath) + grunt.registerMultiTask 'prebuild-less', 'Prebuild cached of compiled LESS files', -> prebuiltConfigurations = [ ['atom-dark-ui', 'atom-dark-syntax'] @@ -78,3 +93,5 @@ module.exports = (grunt) -> for file in themeMains grunt.verbose.writeln("File #{file.cyan} created in cache.") cssForFile(file) + + compileBootstrap() From bc325c36c56a16afae8850cbb2d76195cefe4006 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 10 Apr 2015 14:02:24 -0700 Subject: [PATCH 0624/1783] Exclude bootstrap/less from build --- build/tasks/prebuild-less-task.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/build/tasks/prebuild-less-task.coffee b/build/tasks/prebuild-less-task.coffee index 58f5138a1..2fa5f16db 100644 --- a/build/tasks/prebuild-less-task.coffee +++ b/build/tasks/prebuild-less-task.coffee @@ -18,6 +18,7 @@ module.exports = (grunt) -> bootstrapCss = lessCache.readFileSync(bootstrapLessPath) grunt.file.write(bootstrapCssPath, bootstrapCss) rm(bootstrapLessPath) + rm(path.join(appDir, 'node_modules', 'bootstrap', 'less')) grunt.registerMultiTask 'prebuild-less', 'Prebuild cached of compiled LESS files', -> prebuiltConfigurations = [ From e7030ba4b38a42fc2d5db2befea9bb20d5e2fad0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 10 Apr 2015 14:03:24 -0700 Subject: [PATCH 0625/1783] Compile bootstrap before prebuilding cache --- build/tasks/prebuild-less-task.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/tasks/prebuild-less-task.coffee b/build/tasks/prebuild-less-task.coffee index 2fa5f16db..31adccc0a 100644 --- a/build/tasks/prebuild-less-task.coffee +++ b/build/tasks/prebuild-less-task.coffee @@ -21,6 +21,8 @@ module.exports = (grunt) -> rm(path.join(appDir, 'node_modules', 'bootstrap', 'less')) grunt.registerMultiTask 'prebuild-less', 'Prebuild cached of compiled LESS files', -> + compileBootstrap() + prebuiltConfigurations = [ ['atom-dark-ui', 'atom-dark-syntax'] ['atom-dark-ui', 'atom-light-syntax'] @@ -94,5 +96,3 @@ module.exports = (grunt) -> for file in themeMains grunt.verbose.writeln("File #{file.cyan} created in cache.") cssForFile(file) - - compileBootstrap() From 168c0d0dd71e536dc8717ff202b19e8a2b8841e9 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 10 Apr 2015 14:49:53 -0700 Subject: [PATCH 0626/1783] LESS -> Less --- build/tasks/prebuild-less-task.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/tasks/prebuild-less-task.coffee b/build/tasks/prebuild-less-task.coffee index 31adccc0a..36bdd2bdd 100644 --- a/build/tasks/prebuild-less-task.coffee +++ b/build/tasks/prebuild-less-task.coffee @@ -75,7 +75,7 @@ module.exports = (grunt) -> themeMains.push(mainPath) if grunt.file.isFile(mainPath) importPaths.unshift(stylesheetsDir) if grunt.file.isDir(stylesheetsDir) - grunt.verbose.writeln("Building LESS cache for #{configuration.join(', ').yellow}") + grunt.verbose.writeln("Building Less cache for #{configuration.join(', ').yellow}") lessCache = new LessCache cacheDir: directory resourcePath: path.resolve('.') From 9d6248cabb86af672609e984c9e50fa8c8f3fa13 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 10 Apr 2015 14:50:03 -0700 Subject: [PATCH 0627/1783] Don't ship bootstrap dist and fonts folders --- build/tasks/build-task.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build/tasks/build-task.coffee b/build/tasks/build-task.coffee index fcb1eb6a8..a94b38f75 100644 --- a/build/tasks/build-task.coffee +++ b/build/tasks/build-task.coffee @@ -49,6 +49,8 @@ module.exports = (grunt) -> path.join('oniguruma', 'deps') path.join('less', 'dist') path.join('bootstrap', 'docs') + path.join('bootstrap', 'dist') + path.join('bootstrap', 'fonts') path.join('bootstrap', '_config.yml') path.join('bootstrap', '_includes') path.join('bootstrap', '_layouts') From 932e7d4ad7d238849296bc1a04fb8b2ca311a5a2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 10 Apr 2015 15:09:05 -0700 Subject: [PATCH 0628/1783] LESS -> Less --- build/tasks/prebuild-less-task.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/tasks/prebuild-less-task.coffee b/build/tasks/prebuild-less-task.coffee index 36bdd2bdd..18a323403 100644 --- a/build/tasks/prebuild-less-task.coffee +++ b/build/tasks/prebuild-less-task.coffee @@ -20,7 +20,7 @@ module.exports = (grunt) -> rm(bootstrapLessPath) rm(path.join(appDir, 'node_modules', 'bootstrap', 'less')) - grunt.registerMultiTask 'prebuild-less', 'Prebuild cached of compiled LESS files', -> + grunt.registerMultiTask 'prebuild-less', 'Prebuild cached of compiled Less files', -> compileBootstrap() prebuiltConfigurations = [ From 838c3c1b5e0a27c6b5f4b4259d78236112409341 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 13 Apr 2015 13:59:25 -0700 Subject: [PATCH 0629/1783] Remove bootstrap from prebuildLessConfig --- build/Gruntfile.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/build/Gruntfile.coffee b/build/Gruntfile.coffee index 05efaeb38..e4ebf3e9a 100644 --- a/build/Gruntfile.coffee +++ b/build/Gruntfile.coffee @@ -92,7 +92,6 @@ module.exports = (grunt) -> prebuildLessConfig = src: [ 'static/**/*.less' - 'node_modules/bootstrap/less/bootstrap.less' ] csonConfig = From 74caf89dd1a74103796e798bf74f1a4c4741e427 Mon Sep 17 00:00:00 2001 From: Sean Lee Date: Fri, 20 Mar 2015 14:23:37 +0800 Subject: [PATCH 0630/1783] :bug: fix rowRangeForParagraphAtBufferRow using \S --- spec/language-mode-spec.coffee | 8 ++++++++ src/language-mode.coffee | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/spec/language-mode-spec.coffee b/spec/language-mode-spec.coffee index 07b875a91..d23bd5506 100644 --- a/spec/language-mode-spec.coffee +++ b/spec/language-mode-spec.coffee @@ -124,6 +124,11 @@ describe "LanguageMode", -> // lines var sort = function(items) {}; // comment line after fn + + var nosort = function(items) { + return item; + } + }; ''' @@ -144,6 +149,9 @@ describe "LanguageMode", -> range = languageMode.rowRangeForParagraphAtBufferRow(15) expect(range).toEqual [[15,0], [15,26]] + range = languageMode.rowRangeForParagraphAtBufferRow(18) + expect(range).toEqual [[17,0], [19,1]] + describe "coffeescript", -> beforeEach -> waitsForPromise -> diff --git a/src/language-mode.coffee b/src/language-mode.coffee index 96c1073c1..267383ff4 100644 --- a/src/language-mode.coffee +++ b/src/language-mode.coffee @@ -194,7 +194,7 @@ class LanguageMode # Right now, a paragraph is a block of text bounded by and empty line or a # block of text that is not the same type (comments next to source code). rowRangeForParagraphAtBufferRow: (bufferRow) -> - return unless /\w/.test(@editor.lineTextForBufferRow(bufferRow)) + return unless /\S/.test(@editor.lineTextForBufferRow(bufferRow)) if @isLineCommentedAtBufferRow(bufferRow) isOriginalRowComment = true @@ -207,14 +207,14 @@ class LanguageMode startRow = bufferRow while startRow > firstRow break if @isLineCommentedAtBufferRow(startRow - 1) isnt isOriginalRowComment - break unless /\w/.test(@editor.lineTextForBufferRow(startRow - 1)) + break unless /\S/.test(@editor.lineTextForBufferRow(startRow - 1)) startRow-- endRow = bufferRow lastRow = @editor.getLastBufferRow() while endRow < lastRow break if @isLineCommentedAtBufferRow(endRow + 1) isnt isOriginalRowComment - break unless /\w/.test(@editor.lineTextForBufferRow(endRow + 1)) + break unless /\S/.test(@editor.lineTextForBufferRow(endRow + 1)) endRow++ new Range([startRow, 0], [endRow, @editor.lineTextForBufferRow(endRow).length]) From 2872000d13279b09c1624b526fb822875cccb3f3 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 13 Apr 2015 16:26:24 -0700 Subject: [PATCH 0631/1783] Fix paragraph computation in blocks of single line comments. Closes #6050 Closes #5963 --- spec/language-mode-spec.coffee | 4 ++-- src/language-mode.coffee | 43 +++++++++++++++++++++++----------- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/spec/language-mode-spec.coffee b/spec/language-mode-spec.coffee index d23bd5506..47fa30bdf 100644 --- a/spec/language-mode-spec.coffee +++ b/spec/language-mode-spec.coffee @@ -126,7 +126,7 @@ describe "LanguageMode", -> // comment line after fn var nosort = function(items) { - return item; + return item; } }; @@ -150,7 +150,7 @@ describe "LanguageMode", -> expect(range).toEqual [[15,0], [15,26]] range = languageMode.rowRangeForParagraphAtBufferRow(18) - expect(range).toEqual [[17,0], [19,1]] + expect(range).toEqual [[17,0], [19,3]] describe "coffeescript", -> beforeEach -> diff --git a/src/language-mode.coffee b/src/language-mode.coffee index 267383ff4..bff2c55a0 100644 --- a/src/language-mode.coffee +++ b/src/language-mode.coffee @@ -24,14 +24,8 @@ class LanguageMode # endRow - The row {Number} to end at toggleLineCommentsForBufferRows: (start, end) -> scope = @editor.scopeDescriptorForBufferPosition([start, 0]) - commentStartEntry = atom.config.getAll('editor.commentStart', {scope})[0] - - return unless commentStartEntry? - - commentEndEntry = _.find atom.config.getAll('editor.commentEnd', {scope}), (entry) -> - entry.scopeSelector is commentStartEntry.scopeSelector - commentStartString = commentStartEntry?.value - commentEndString = commentEndEntry?.value + {commentStartString, commentEndString} = @getCommentStartAndEndStrings(scope) + return unless commentStartString? buffer = @editor.buffer commentStartRegexString = _.escapeRegExp(commentStartString).replace(/(\s+)$/, '(?:$1)?') @@ -190,11 +184,24 @@ class LanguageMode return false unless 0 <= bufferRow <= @editor.getLastBufferRow() @editor.displayBuffer.tokenizedBuffer.tokenizedLineForRow(bufferRow).isComment() - # Find a row range for a 'paragraph' around specified bufferRow. - # Right now, a paragraph is a block of text bounded by and empty line or a - # block of text that is not the same type (comments next to source code). + # Find a row range for a 'paragraph' around specified bufferRow. A paragraph + # is a block of text bounded by and empty line or a block of text that is not + # the same type (comments next to source code). rowRangeForParagraphAtBufferRow: (bufferRow) -> - return unless /\S/.test(@editor.lineTextForBufferRow(bufferRow)) + scope = @editor.scopeDescriptorForBufferPosition([bufferRow, 0]) + {commentStartString, commentEndString} = @getCommentStartAndEndStrings(scope) + commentStartRegex = null + if commentStartString? and not commentEndString? + commentStartRegexString = _.escapeRegExp(commentStartString).replace(/(\s+)$/, '(?:$1)?') + commentStartRegex = new OnigRegExp("^(\\s*)(#{commentStartRegexString})") + + filterLineComments = (line) -> + if commentStartRegex? + matches = commentStartRegex.searchSync(line) + line = line.substring(matches[0].end) if matches?.length + line + + return unless /\S/.test(filterLineComments(@editor.lineTextForBufferRow(bufferRow))) if @isLineCommentedAtBufferRow(bufferRow) isOriginalRowComment = true @@ -207,14 +214,14 @@ class LanguageMode startRow = bufferRow while startRow > firstRow break if @isLineCommentedAtBufferRow(startRow - 1) isnt isOriginalRowComment - break unless /\S/.test(@editor.lineTextForBufferRow(startRow - 1)) + break unless /\S/.test(filterLineComments(@editor.lineTextForBufferRow(startRow - 1))) startRow-- endRow = bufferRow lastRow = @editor.getLastBufferRow() while endRow < lastRow break if @isLineCommentedAtBufferRow(endRow + 1) isnt isOriginalRowComment - break unless /\S/.test(@editor.lineTextForBufferRow(endRow + 1)) + break unless /\S/.test(filterLineComments(@editor.lineTextForBufferRow(endRow + 1))) endRow++ new Range([startRow, 0], [endRow, @editor.lineTextForBufferRow(endRow).length]) @@ -319,3 +326,11 @@ class LanguageMode foldEndRegexForScopeDescriptor: (scopeDescriptor) -> @getRegexForProperty(scopeDescriptor, 'editor.foldEndPattern') + + getCommentStartAndEndStrings: (scope) -> + commentStartEntry = atom.config.getAll('editor.commentStart', {scope})[0] + commentEndEntry = _.find atom.config.getAll('editor.commentEnd', {scope}), (entry) -> + entry.scopeSelector is commentStartEntry.scopeSelector + commentStartString = commentStartEntry?.value + commentEndString = commentEndEntry?.value + {commentStartString, commentEndString} From d38f6bb1d38871b71c4905ba7c4c0661d3cf62c8 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 13 Apr 2015 16:26:50 -0700 Subject: [PATCH 0632/1783] Add toString to `ScopeDescriptor` --- src/scope-descriptor.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/scope-descriptor.coffee b/src/scope-descriptor.coffee index d7ec263fd..7940cc630 100644 --- a/src/scope-descriptor.coffee +++ b/src/scope-descriptor.coffee @@ -44,3 +44,6 @@ class ScopeDescriptor scope = ".#{scope}" unless scope[0] is '.' scope .join(' ') + + toString: -> + @getScopeChain() From 8f2fbbfd9d329ab264004d40961e5b7fc04d1ff9 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 13 Apr 2015 16:29:10 -0700 Subject: [PATCH 0633/1783] Rename method to be more consistent --- src/language-mode.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/language-mode.coffee b/src/language-mode.coffee index bff2c55a0..d48c68d58 100644 --- a/src/language-mode.coffee +++ b/src/language-mode.coffee @@ -24,7 +24,7 @@ class LanguageMode # endRow - The row {Number} to end at toggleLineCommentsForBufferRows: (start, end) -> scope = @editor.scopeDescriptorForBufferPosition([start, 0]) - {commentStartString, commentEndString} = @getCommentStartAndEndStrings(scope) + {commentStartString, commentEndString} = @commentStartAndEndStringsForScope(scope) return unless commentStartString? buffer = @editor.buffer @@ -189,7 +189,7 @@ class LanguageMode # the same type (comments next to source code). rowRangeForParagraphAtBufferRow: (bufferRow) -> scope = @editor.scopeDescriptorForBufferPosition([bufferRow, 0]) - {commentStartString, commentEndString} = @getCommentStartAndEndStrings(scope) + {commentStartString, commentEndString} = @commentStartAndEndStringsForScope(scope) commentStartRegex = null if commentStartString? and not commentEndString? commentStartRegexString = _.escapeRegExp(commentStartString).replace(/(\s+)$/, '(?:$1)?') @@ -327,7 +327,7 @@ class LanguageMode foldEndRegexForScopeDescriptor: (scopeDescriptor) -> @getRegexForProperty(scopeDescriptor, 'editor.foldEndPattern') - getCommentStartAndEndStrings: (scope) -> + commentStartAndEndStringsForScope: (scope) -> commentStartEntry = atom.config.getAll('editor.commentStart', {scope})[0] commentEndEntry = _.find atom.config.getAll('editor.commentEnd', {scope}), (entry) -> entry.scopeSelector is commentStartEntry.scopeSelector From f6c1f95b65e8a8831b7d02b90849801b63cd9dc3 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 13 Apr 2015 16:32:26 -0700 Subject: [PATCH 0634/1783] Rename method for clarity --- src/language-mode.coffee | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/language-mode.coffee b/src/language-mode.coffee index d48c68d58..b5529a05e 100644 --- a/src/language-mode.coffee +++ b/src/language-mode.coffee @@ -195,13 +195,13 @@ class LanguageMode commentStartRegexString = _.escapeRegExp(commentStartString).replace(/(\s+)$/, '(?:$1)?') commentStartRegex = new OnigRegExp("^(\\s*)(#{commentStartRegexString})") - filterLineComments = (line) -> + filterCommentStart = (line) -> if commentStartRegex? matches = commentStartRegex.searchSync(line) line = line.substring(matches[0].end) if matches?.length line - return unless /\S/.test(filterLineComments(@editor.lineTextForBufferRow(bufferRow))) + return unless /\S/.test(filterCommentStart(@editor.lineTextForBufferRow(bufferRow))) if @isLineCommentedAtBufferRow(bufferRow) isOriginalRowComment = true @@ -214,14 +214,14 @@ class LanguageMode startRow = bufferRow while startRow > firstRow break if @isLineCommentedAtBufferRow(startRow - 1) isnt isOriginalRowComment - break unless /\S/.test(filterLineComments(@editor.lineTextForBufferRow(startRow - 1))) + break unless /\S/.test(filterCommentStart(@editor.lineTextForBufferRow(startRow - 1))) startRow-- endRow = bufferRow lastRow = @editor.getLastBufferRow() while endRow < lastRow break if @isLineCommentedAtBufferRow(endRow + 1) isnt isOriginalRowComment - break unless /\S/.test(filterLineComments(@editor.lineTextForBufferRow(endRow + 1))) + break unless /\S/.test(filterCommentStart(@editor.lineTextForBufferRow(endRow + 1))) endRow++ new Range([startRow, 0], [endRow, @editor.lineTextForBufferRow(endRow).length]) From 626afe4e0dd06e814dd3471493f2c0f4647b896a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 13 Apr 2015 16:23:26 -0700 Subject: [PATCH 0635/1783] Don't include fallback imports for static files --- build/tasks/prebuild-less-task.coffee | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/build/tasks/prebuild-less-task.coffee b/build/tasks/prebuild-less-task.coffee index 18a323403..755003455 100644 --- a/build/tasks/prebuild-less-task.coffee +++ b/build/tasks/prebuild-less-task.coffee @@ -20,6 +20,9 @@ module.exports = (grunt) -> rm(bootstrapLessPath) rm(path.join(appDir, 'node_modules', 'bootstrap', 'less')) + importFallbackVariables = (lessFilePath) -> + lessFilePath.indexOf('static') isnt 0 + grunt.registerMultiTask 'prebuild-less', 'Prebuild cached of compiled Less files', -> compileBootstrap() @@ -82,12 +85,14 @@ module.exports = (grunt) -> importPaths: importPaths cssForFile = (file) -> - baseVarImports = """ - @import "variables/ui-variables"; - @import "variables/syntax-variables"; - """ less = fs.readFileSync(file, 'utf8') - lessCache.cssForFile(file, [baseVarImports, less].join('\n')) + if importFallbackVariables(file) + baseVarImports = """ + @import "variables/ui-variables"; + @import "variables/syntax-variables"; + """ + less = [baseVarImports, less].join('\n') + lessCache.cssForFile(file, less) for file in @filesSrc grunt.verbose.writeln("File #{file.cyan} created in cache.") From 930f30647631c07ec4c47b02d374c18a3706c170 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 13 Apr 2015 16:45:48 -0700 Subject: [PATCH 0636/1783] Precompile atom-space-pen-views stylesheets --- build/Gruntfile.coffee | 1 + build/tasks/prebuild-less-task.coffee | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/build/Gruntfile.coffee b/build/Gruntfile.coffee index e4ebf3e9a..dac5c8f1f 100644 --- a/build/Gruntfile.coffee +++ b/build/Gruntfile.coffee @@ -92,6 +92,7 @@ module.exports = (grunt) -> prebuildLessConfig = src: [ 'static/**/*.less' + 'node_modules/atom-space-pen-views/stylesheets/**/*.less' ] csonConfig = diff --git a/build/tasks/prebuild-less-task.coffee b/build/tasks/prebuild-less-task.coffee index 755003455..5e3bd274e 100644 --- a/build/tasks/prebuild-less-task.coffee +++ b/build/tasks/prebuild-less-task.coffee @@ -21,7 +21,12 @@ module.exports = (grunt) -> rm(path.join(appDir, 'node_modules', 'bootstrap', 'less')) importFallbackVariables = (lessFilePath) -> - lessFilePath.indexOf('static') isnt 0 + if lessFilePath.indexOf('static') is 0 + false + else if lessFilePath.indexOf('atom-space-pen-views') isnt -1 + false + else + true grunt.registerMultiTask 'prebuild-less', 'Prebuild cached of compiled Less files', -> compileBootstrap() From c2998900fd8ef965cec429f1d123952c7588b90f Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 13 Apr 2015 17:26:03 -0700 Subject: [PATCH 0637/1783] :arrow_up: scandal@2.0.1 Fixes duplication when following symlinks --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e65f94ff3..69c32e2f9 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "react-atom-fork": "^0.11.5", "reactionary-atom-fork": "^1.0.0", "runas": "2.0.0", - "scandal": "2.0.0", + "scandal": "2.0.1", "scoped-property-store": "^0.17.0", "scrollbar-style": "^2.0.0", "season": "^5.1.4", From 7cd263dfb75dd12349b95875b5d0e9fc935cb549 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 13 Apr 2015 17:46:53 -0700 Subject: [PATCH 0638/1783] :arrow_up: clear-cut@1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e65f94ff3..5e00878fe 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "atom-space-pen-views": "^2.0.4", "babel-core": "^4.0.2", "bootstrap": "git+https://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372", - "clear-cut": "0.4.0", + "clear-cut": "^1", "coffee-cash": "0.8.0", "coffee-script": "1.8.0", "coffeestack": "^1.1.1", From 54496580118b2054647616cbc1c7900f5b5107ff Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 13 Apr 2015 17:47:25 -0700 Subject: [PATCH 0639/1783] Remove specificity caching now handled by clear-cut --- src/command-registry.coffee | 3 +-- src/context-menu-manager.coffee | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/command-registry.coffee b/src/command-registry.coffee index 479d972fa..b3cacff0e 100644 --- a/src/command-registry.coffee +++ b/src/command-registry.coffee @@ -5,7 +5,6 @@ _ = require 'underscore-plus' {validateSelector} = require './selector-validator' SequenceCount = 0 -SpecificityCache = {} # Public: Associates listener functions with commands in a # context-sensitive way using CSS selectors. You can access a global instance of @@ -241,7 +240,7 @@ class CommandRegistry class SelectorBasedListener constructor: (@selector, @callback) -> - @specificity = (SpecificityCache[@selector] ?= specificity(@selector)) + @specificity = specificity(@selector) @sequenceNumber = SequenceCount++ compare: (other) -> diff --git a/src/context-menu-manager.coffee b/src/context-menu-manager.coffee index 8397da33d..344173579 100644 --- a/src/context-menu-manager.coffee +++ b/src/context-menu-manager.coffee @@ -9,7 +9,6 @@ MenuHelpers = require './menu-helpers' {validateSelector} = require './selector-validator' platformContextMenu = require('../package.json')?._atomMenu?['context-menu'] -SpecificityCache = {} # Extended: Provides a registry for commands that you'd like to appear in the # context menu. @@ -208,4 +207,4 @@ class ContextMenuManager class ContextMenuItemSet constructor: (@selector, @items) -> - @specificity = (SpecificityCache[@selector] ?= specificity(@selector)) + @specificity = specificity(@selector) From 2538191449073eead67a2eb0b11513e5c3a95ff9 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 13 Apr 2015 17:47:25 -0700 Subject: [PATCH 0640/1783] Default `core.followSymlinks` to true --- src/config-schema.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config-schema.coffee b/src/config-schema.coffee index 87e1040bc..ba8150a26 100644 --- a/src/config-schema.coffee +++ b/src/config-schema.coffee @@ -18,7 +18,7 @@ module.exports = title: 'Exclude VCS Ignored Paths' followSymlinks: type: 'boolean' - default: false + default: true title: 'Follow symlinks' description: 'Used when searching and when opening files with the fuzzy finder.' disabledPackages: From 4c6722832b97f6795d6b1d2b1859a95f090d74b5 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 13 Apr 2015 18:01:40 -0700 Subject: [PATCH 0641/1783] :arrow_up: clear-cut@2.0 --- package.json | 2 +- src/command-registry.coffee | 4 ++-- src/context-menu-manager.coffee | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 5e00878fe..66a2821c0 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "atom-space-pen-views": "^2.0.4", "babel-core": "^4.0.2", "bootstrap": "git+https://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372", - "clear-cut": "^1", + "clear-cut": "^2", "coffee-cash": "0.8.0", "coffee-script": "1.8.0", "coffeestack": "^1.1.1", diff --git a/src/command-registry.coffee b/src/command-registry.coffee index b3cacff0e..89357268e 100644 --- a/src/command-registry.coffee +++ b/src/command-registry.coffee @@ -1,5 +1,5 @@ {Emitter, Disposable, CompositeDisposable} = require 'event-kit' -{specificity} = require 'clear-cut' +{calculateSpecificity} = require 'clear-cut' _ = require 'underscore-plus' {$} = require './space-pen-extensions' {validateSelector} = require './selector-validator' @@ -240,7 +240,7 @@ class CommandRegistry class SelectorBasedListener constructor: (@selector, @callback) -> - @specificity = specificity(@selector) + @specificity = calculateSpecificity(@selector) @sequenceNumber = SequenceCount++ compare: (other) -> diff --git a/src/context-menu-manager.coffee b/src/context-menu-manager.coffee index 344173579..a9b3449e0 100644 --- a/src/context-menu-manager.coffee +++ b/src/context-menu-manager.coffee @@ -2,7 +2,7 @@ _ = require 'underscore-plus' path = require 'path' CSON = require 'season' fs = require 'fs-plus' -{specificity} = require 'clear-cut' +{calculateSpecificity} = require 'clear-cut' {Disposable} = require 'event-kit' Grim = require 'grim' MenuHelpers = require './menu-helpers' @@ -207,4 +207,4 @@ class ContextMenuManager class ContextMenuItemSet constructor: (@selector, @items) -> - @specificity = specificity(@selector) + @specificity = calculateSpecificity(@selector) From b789a898cd28f9c89e1d01071cc53b31e7c4bae4 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 13 Apr 2015 18:01:55 -0700 Subject: [PATCH 0642/1783] :arrow_up: atom-keymap@5.1.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 66a2821c0..847c02299 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "atomShellVersion": "0.22.3", "dependencies": { "async": "0.2.6", - "atom-keymap": "^5.1", + "atom-keymap": "^5.1.2", "atom-space-pen-views": "^2.0.4", "babel-core": "^4.0.2", "bootstrap": "git+https://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372", From 84bab1c67badc4ae9fcf1db0f004a1d7c3b05174 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 13 Apr 2015 18:03:14 -0700 Subject: [PATCH 0643/1783] Use selector validator provided by clear-cut --- src/command-registry.coffee | 3 +-- src/context-menu-manager.coffee | 3 +-- src/selector-validator.coffee | 28 ---------------------------- 3 files changed, 2 insertions(+), 32 deletions(-) delete mode 100644 src/selector-validator.coffee diff --git a/src/command-registry.coffee b/src/command-registry.coffee index 89357268e..3969dc283 100644 --- a/src/command-registry.coffee +++ b/src/command-registry.coffee @@ -1,8 +1,7 @@ {Emitter, Disposable, CompositeDisposable} = require 'event-kit' -{calculateSpecificity} = require 'clear-cut' +{calculateSpecificity, validateSelector} = require 'clear-cut' _ = require 'underscore-plus' {$} = require './space-pen-extensions' -{validateSelector} = require './selector-validator' SequenceCount = 0 diff --git a/src/context-menu-manager.coffee b/src/context-menu-manager.coffee index a9b3449e0..bd5ff943e 100644 --- a/src/context-menu-manager.coffee +++ b/src/context-menu-manager.coffee @@ -2,11 +2,10 @@ _ = require 'underscore-plus' path = require 'path' CSON = require 'season' fs = require 'fs-plus' -{calculateSpecificity} = require 'clear-cut' +{calculateSpecificity, validateSelector} = require 'clear-cut' {Disposable} = require 'event-kit' Grim = require 'grim' MenuHelpers = require './menu-helpers' -{validateSelector} = require './selector-validator' platformContextMenu = require('../package.json')?._atomMenu?['context-menu'] diff --git a/src/selector-validator.coffee b/src/selector-validator.coffee deleted file mode 100644 index f8dcb240a..000000000 --- a/src/selector-validator.coffee +++ /dev/null @@ -1,28 +0,0 @@ -selectorCache = null -testElement = null - -# Parses CSS selectors and memoizes their validity so each selector will only -# be parsed once. -exports.isSelectorValid = (selector) -> - selectorCache ?= {} - cachedValue = selectorCache[selector] - return cachedValue if cachedValue? - - testElement ?= document.createElement('div') - try - # querySelector appears to be faster than webkitMatchesSelector - # http://jsperf.com/query-vs-matches - testElement.querySelector(selector) - selectorCache[selector] = true - true - catch selectorError - selectorCache[selector] = false - false - -# Parse the given CSS selector and throw an error if it is invalid. -exports.validateSelector = (selector) -> - return if exports.isSelectorValid(selector) - - error = new Error("'#{selector}' is not a valid selector") - error.code = 'EBADSELECTOR' - throw error From c13dce2d8f6374933af21ab37256018a3dfbe867 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 13 Apr 2015 18:32:01 -0700 Subject: [PATCH 0644/1783] Fix spec --- spec/atom-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/atom-spec.coffee b/spec/atom-spec.coffee index 19a2cca5c..a293edccd 100644 --- a/spec/atom-spec.coffee +++ b/spec/atom-spec.coffee @@ -55,7 +55,7 @@ describe "the `atom` global", -> describe "loading default config", -> it 'loads the default core config', -> expect(atom.config.get('core.excludeVcsIgnoredPaths')).toBe true - expect(atom.config.get('core.followSymlinks')).toBe false + expect(atom.config.get('core.followSymlinks')).toBe true expect(atom.config.get('editor.showInvisibles')).toBe false describe "window onerror handler", -> From 1c8cf4390c3cc08cdb8f5256c281d9356bcb47bb Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 14 Apr 2015 10:50:09 +0200 Subject: [PATCH 0645/1783] Rename to safe-clipboard ...and use remote only on Linux renderer processes. --- spec/spec-helper.coffee | 2 +- spec/text-editor-component-spec.coffee | 2 +- spec/text-editor-spec.coffee | 2 +- src/browser/atom-application.coffee | 2 +- src/clipboard.coffee | 2 +- src/native-clipboard.coffee | 6 ------ src/safe-clipboard.coffee | 6 ++++++ src/text-editor-component.coffee | 2 +- 8 files changed, 12 insertions(+), 12 deletions(-) delete mode 100644 src/native-clipboard.coffee create mode 100644 src/safe-clipboard.coffee diff --git a/spec/spec-helper.coffee b/spec/spec-helper.coffee index 33ec8c521..0daf6586e 100644 --- a/spec/spec-helper.coffee +++ b/spec/spec-helper.coffee @@ -24,7 +24,7 @@ TextEditorElement = require '../src/text-editor-element' TokenizedBuffer = require '../src/tokenized-buffer' TextEditorComponent = require '../src/text-editor-component' pathwatcher = require 'pathwatcher' -clipboard = require "../src/native-clipboard" +clipboard = require "../src/safe-clipboard" atom.themes.loadBaseStylesheets() atom.themes.requireStylesheet '../static/jasmine' diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 2ed17ab9f..0b8282e43 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -2816,7 +2816,7 @@ describe "TextEditorComponent", -> clipboardWrittenTo = false spyOn(require('ipc'), 'send').andCallFake (eventName, selectedText) -> if eventName is 'write-text-to-selection-clipboard' - require('../src/native-clipboard').writeText(selectedText, 'selection') + require('../src/safe-clipboard').writeText(selectedText, 'selection') clipboardWrittenTo = true atom.clipboard.write('') diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 38f17072d..5e0fef9e6 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -1,4 +1,4 @@ -clipboard = require '../src/native-clipboard' +clipboard = require '../src/safe-clipboard' TextEditor = require '../src/text-editor' describe "TextEditor", -> diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 950cb6b78..2fee79f0b 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -256,7 +256,7 @@ class AtomApplication clipboard = null ipc.on 'write-text-to-selection-clipboard', (event, selectedText) -> - clipboard ?= require '../native-clipboard' + clipboard ?= require '../safe-clipboard' clipboard.writeText(selectedText, 'selection') # Public: Executes the given command. diff --git a/src/clipboard.coffee b/src/clipboard.coffee index 80ec464e7..000eb70e3 100644 --- a/src/clipboard.coffee +++ b/src/clipboard.coffee @@ -1,5 +1,5 @@ crypto = require 'crypto' -clipboard = require "./native-clipboard" +clipboard = require "./safe-clipboard" # Extended: Represents the clipboard used for copying and pasting in Atom. # diff --git a/src/native-clipboard.coffee b/src/native-clipboard.coffee deleted file mode 100644 index f66d44646..000000000 --- a/src/native-clipboard.coffee +++ /dev/null @@ -1,6 +0,0 @@ -# Using clipboard in renderer process is not safe on Linux. -module.exports = - if process.platform is 'linux' - require('remote').require 'clipboard' - else - require 'clipboard' diff --git a/src/safe-clipboard.coffee b/src/safe-clipboard.coffee new file mode 100644 index 000000000..571ff4578 --- /dev/null +++ b/src/safe-clipboard.coffee @@ -0,0 +1,6 @@ +# Using clipboard in renderer process is not safe on Linux. +module.exports = + if process.platform is "linux" and process.type is "renderer" + require("remote").require("clipboard") + else + require("clipboard") diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 4348279de..4c8e567f0 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -556,7 +556,7 @@ class TextEditorComponent pasteSelectionClipboard = (event) => if event?.which is 2 and process.platform is 'linux' - if selection = require('./native-clipboard').readText('selection') + if selection = require('./safe-clipboard').readText('selection') @editor.insertText(selection) window.addEventListener('mousemove', onMouseMove) From 769beadcf3efdbb88b4809fe0072e6dde4c026b8 Mon Sep 17 00:00:00 2001 From: liuxiong332 Date: Tue, 14 Apr 2015 21:10:05 +0800 Subject: [PATCH 0646/1783] integration test in pane-axis-element-spec into pane-resize-handle-element-spec --- spec/pane-axis-element-spec.coffee | 46 --------------- spec/pane-resize-handle-element-spec.coffee | 65 ++++++++++++++++----- spec/spec-helper.coffee | 1 - 3 files changed, 50 insertions(+), 62 deletions(-) delete mode 100644 spec/pane-axis-element-spec.coffee diff --git a/spec/pane-axis-element-spec.coffee b/spec/pane-axis-element-spec.coffee deleted file mode 100644 index eece34a6e..000000000 --- a/spec/pane-axis-element-spec.coffee +++ /dev/null @@ -1,46 +0,0 @@ -PaneAxisElement = require '../src/pane-axis-element' -PaneAxis = require '../src/pane-axis.coffee' - -describe "PaneResizeHandleElement", -> - describe "add and remove", -> - [paneAxisElement, paneAxis] = [] - - beforeEach -> - paneAxisElement = document.createElement('atom-pane-axis') - paneAxis = new PaneAxis({}) - paneAxisElement.initialize(paneAxis) - document.querySelector('#jasmine-content').appendChild(paneAxisElement) - - it "inserts draggable resize elements between pane axis children", -> - expect(paneAxisElement).toBeTruthy() - modelChildren = (new PaneAxis({}) for i in [1..5]) - paneAxis.addChild(modelChildren[0]) - paneAxis.addChild(modelChildren[1]) - - expectPaneAxisElement = (index) -> - child = paneAxisElement.children[index] - expect(child.nodeName.toLowerCase()).toBe('atom-pane-axis') - - expectResizeElement = (index) -> - child = paneAxisElement.children[index] - expect(paneAxisElement.isPaneResizeHandleElement(child)).toBe(true) - - expect(paneAxisElement.children[0].model).toBe(modelChildren[0]) - expectResizeElement(1) - expect(paneAxisElement.children[2].model).toBe(modelChildren[1]) - - paneAxis.addChild(modelChildren[2]) - paneAxis.addChild(modelChildren[3]) - expectPaneAxisElement(i) for i in [0, 2, 4, 6] - expectResizeElement(i) for i in [1, 3, 5] - - # test removeChild - paneAxis.removeChild(modelChildren[2]) - # modelChildren[3] replace modelChildren[2] - expect(paneAxisElement.children[4].model).toBe(modelChildren[3]) - expectResizeElement(i) for i in [1, 3] - - # test replaceChild - paneAxis.replaceChild(modelChildren[0], modelChildren[4]) - expect(paneAxisElement.children[0].model).toBe(modelChildren[4]) - expectResizeElement(i) for i in [1, 3] diff --git a/spec/pane-resize-handle-element-spec.coffee b/spec/pane-resize-handle-element-spec.coffee index f4ad2c166..d97368a0b 100644 --- a/spec/pane-resize-handle-element-spec.coffee +++ b/spec/pane-resize-handle-element-spec.coffee @@ -1,7 +1,45 @@ PaneContainer = require '../src/pane-container' +PaneAxisElement = require '../src/pane-axis-element' +PaneAxis = require '../src/pane-axis' -describe "PaneResizeHandleElement", -> - describe "resize", -> +fdescribe "PaneResizeHandleElement", -> + describe "as children of PaneAxisElement", -> + [paneAxisElement, paneAxis] = [] + + beforeEach -> + paneAxisElement = document.createElement('atom-pane-axis') + paneAxis = new PaneAxis({}) + paneAxisElement.initialize(paneAxis) + document.querySelector('#jasmine-content').appendChild(paneAxisElement) + + it "inserts or remove resize elements when pane axis added or removed", -> + modelChildren = (new PaneAxis({}) for i in [1..5]) + paneAxis.addChild(modelChildren[0]) + paneAxis.addChild(modelChildren[1]) + + expectPaneAxisElement = (index) -> + child = paneAxisElement.children[index] + expect(child.nodeName.toLowerCase()).toBe('atom-pane-axis') + + expectResizeElement = (index) -> + child = paneAxisElement.children[index] + expect(paneAxisElement.isPaneResizeHandleElement(child)).toBe(true) + expectResizeElement(1) + + paneAxis.addChild(modelChildren[2]) + paneAxis.addChild(modelChildren[3]) + expectPaneAxisElement(i) for i in [0, 2, 4, 6] + expectResizeElement(i) for i in [1, 3, 5] + + # test removeChild + paneAxis.removeChild(modelChildren[2]) + expectResizeElement(i) for i in [1, 3] + + # test replaceChild + paneAxis.replaceChild(modelChildren[0], modelChildren[4]) + expectResizeElement(i) for i in [1, 3] + + describe "when mouse drag the resize element", -> [container, containerElement, resizeElementMove, getElementWidth] = [] beforeEach -> @@ -32,15 +70,11 @@ describe "PaneResizeHandleElement", -> resizeElement = containerElement.querySelector('atom-pane-resize-handle') expect(resizeElement).toBeTruthy() - leftWidth = resizeElement.previousSibling.getBoundingClientRect().width + leftWidth = getElementWidth(resizeElement.previousSibling) resizeElementMove(resizeElement, leftWidth/2, 0) expect(activePane.getFlexScale()).toBeCloseTo(0.5, 0.1) expect(rightPane.getFlexScale()).toBeCloseTo(1.5, 0.1) - downPane = activePane.splitDown() - # after split down, the horizontal panes retain - expect(rightPane.getFlexScale()).toBeCloseTo(1.5, 0.1) - it "drag the resize element, the size of other panes in the same direction will not change", -> leftPane = container.getActivePane() middlePane = leftPane.splitRight() @@ -63,11 +97,11 @@ describe "PaneResizeHandleElement", -> expectPaneScale(0.5, 0.75, 1.75) it "drag the horizontal element, the size of other vertical pane will not change", -> - upPane = container.getActivePane() - downPane = upPane.splitDown() + upperPane = container.getActivePane() + downPane = upperPane.splitDown() - [upRightPane, upLeftPane] = [upPane.splitRight(), upPane] - upPane = upLeftPane.getParent() + [upperRightPane, upperLeftPane] = [upperPane.splitRight(), upperPane] + upperPane = upperLeftPane.getParent() [downRightPane, downLeftPane] = [downPane.splitRight(), downPane] downPane = downLeftPane.getParent() @@ -78,10 +112,11 @@ describe "PaneResizeHandleElement", -> expectCloseTo = (element, scale) -> expect(element.getFlexScale()).toBeCloseTo(scale, 0.1) - expectPaneScale = (up, down, upLeft, upRight, downLeft, downRight) -> + expectPaneScale = (upper, down, upperLeft, upperRight, downLeft, downRight) -> paneScales = [ - [upPane, up], [downPane, down], [upLeftPane, upLeft], - [upRightPane, upRight], [downLeftPane, downLeft], [downRightPane, downRight] + [upperPane, upper], [downPane, down], [upperLeftPane, upperLeft], + [upperRightPane, upperRight], [downLeftPane, downLeft], + [downRightPane, downRight] ] expectCloseTo(e[0], e[1]) for e in paneScales @@ -113,7 +148,7 @@ describe "PaneResizeHandleElement", -> rightPane.close() # when close the same direction pane, the flexScale will recorver expect(middlePane.getFlexScale()).toBeCloseTo(1, 0.1) - it "change the flex scale when dynamically split or close panes in orthogonal direction", -> + it "retain the flex scale when dynamically split or close panes in orthogonal direction", -> leftPane = container.getActivePane() rightPane = leftPane.splitRight() diff --git a/spec/spec-helper.coffee b/spec/spec-helper.coffee index d34c72b1a..b96eb2ce9 100644 --- a/spec/spec-helper.coffee +++ b/spec/spec-helper.coffee @@ -164,7 +164,6 @@ afterEach -> jasmine.unspy(atom, 'saveSync') ensureNoPathSubscriptions() - atom.grammars.clearObservers() waits(0) # yield to ui thread to make screen update more frequently ensureNoPathSubscriptions = -> From 1c6583994ab3236501965ef2fe5c889a09c4e27e Mon Sep 17 00:00:00 2001 From: liuxiong332 Date: Tue, 14 Apr 2015 21:17:40 +0800 Subject: [PATCH 0647/1783] replace 'downPane' to 'lowerPane' --- spec/pane-resize-handle-element-spec.coffee | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/spec/pane-resize-handle-element-spec.coffee b/spec/pane-resize-handle-element-spec.coffee index d97368a0b..f2e75ba1c 100644 --- a/spec/pane-resize-handle-element-spec.coffee +++ b/spec/pane-resize-handle-element-spec.coffee @@ -98,13 +98,13 @@ fdescribe "PaneResizeHandleElement", -> it "drag the horizontal element, the size of other vertical pane will not change", -> upperPane = container.getActivePane() - downPane = upperPane.splitDown() + lowerPane = upperPane.splitDown() [upperRightPane, upperLeftPane] = [upperPane.splitRight(), upperPane] upperPane = upperLeftPane.getParent() - [downRightPane, downLeftPane] = [downPane.splitRight(), downPane] - downPane = downLeftPane.getParent() + [lowerRightPane, lowerLeftPane] = [lowerPane.splitRight(), lowerPane] + lowerPane = lowerLeftPane.getParent() horizontalResizeElements = containerElement.querySelectorAll('atom-pane-resize-handle.horizontal') expect(horizontalResizeElements.length).toBe(2) @@ -112,11 +112,11 @@ fdescribe "PaneResizeHandleElement", -> expectCloseTo = (element, scale) -> expect(element.getFlexScale()).toBeCloseTo(scale, 0.1) - expectPaneScale = (upper, down, upperLeft, upperRight, downLeft, downRight) -> + expectPaneScale = (upper, lower, upperLeft, upperRight, lowerLeft, lowerRight) -> paneScales = [ - [upperPane, upper], [downPane, down], [upperLeftPane, upperLeft], - [upperRightPane, upperRight], [downLeftPane, downLeft], - [downRightPane, downRight] + [upperPane, upper], [lowerPane, lower], [upperLeftPane, upperLeft], + [upperRightPane, upperRight], [lowerLeftPane, lowerLeft], + [lowerRightPane, lowerRight] ] expectCloseTo(e[0], e[1]) for e in paneScales @@ -156,11 +156,11 @@ fdescribe "PaneResizeHandleElement", -> resizeElementMove(resizeElement, getElementWidth(resizeElement.previousSibling) / 2) expect(leftPane.getFlexScale()).toBeCloseTo(0.5, 0.1) - downPane = leftPane.splitDown() # dynamically split pane, pane's flexScale will become to 1 + lowerPane = leftPane.splitDown() # dynamically split pane, pane's flexScale will become to 1 expect(leftPane.getFlexScale()).toBeCloseTo(1, 0.1) expect(leftPane.getParent().getFlexScale()).toBeCloseTo(0.5, 0.1) - downPane.close() # dynamically close pane, the pane's flexscale will recorver to origin value + lowerPane.close() # dynamically close pane, the pane's flexscale will recorver to origin value expect(leftPane.getFlexScale()).toBeCloseTo(0.5, 0.1) From 412fbdef543d80da5b42b97ff7c73b4632fc1c3c Mon Sep 17 00:00:00 2001 From: liuxiong332 Date: Tue, 14 Apr 2015 21:31:59 +0800 Subject: [PATCH 0648/1783] add specs for pane's serialization --- spec/pane-resize-handle-element-spec.coffee | 2 +- spec/pane-spec.coffee | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/spec/pane-resize-handle-element-spec.coffee b/spec/pane-resize-handle-element-spec.coffee index f2e75ba1c..7a24100dd 100644 --- a/spec/pane-resize-handle-element-spec.coffee +++ b/spec/pane-resize-handle-element-spec.coffee @@ -2,7 +2,7 @@ PaneContainer = require '../src/pane-container' PaneAxisElement = require '../src/pane-axis-element' PaneAxis = require '../src/pane-axis' -fdescribe "PaneResizeHandleElement", -> +describe "PaneResizeHandleElement", -> describe "as children of PaneAxisElement", -> [paneAxisElement, paneAxis] = [] diff --git a/spec/pane-spec.coffee b/spec/pane-spec.coffee index ac6e1d26f..7d6410048 100644 --- a/spec/pane-spec.coffee +++ b/spec/pane-spec.coffee @@ -696,7 +696,10 @@ describe "Pane", -> pane = null beforeEach -> - pane = new Pane(items: [new Item("A", "a"), new Item("B", "b"), new Item("C", "c")]) + params = + items: [new Item("A", "a"), new Item("B", "b"), new Item("C", "c")] + flexScale: 2 + pane = new Pane(params) it "can serialize and deserialize the pane and all its items", -> newPane = pane.testSerialization() From 1e07cd0e5339953a1a60b5dd91f1e096cd48207e Mon Sep 17 00:00:00 2001 From: Daniel Hengeveld Date: Tue, 14 Apr 2015 08:54:49 -0700 Subject: [PATCH 0649/1783] :arrow_up: settings-view@0.192.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 69c32e2f9..7b11ebd5b 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "open-on-github": "0.36.0", "package-generator": "0.38.0", "release-notes": "0.52.0", - "settings-view": "0.191.0", + "settings-view": "0.192.0", "snippets": "0.88.0", "spell-check": "0.55.0", "status-bar": "0.67.0", From acb236417a0ba06740c20c2ef2da7f184a2498ac Mon Sep 17 00:00:00 2001 From: liuxiong332 Date: Wed, 15 Apr 2015 00:23:48 +0800 Subject: [PATCH 0650/1783] simplify the PaneResizeHandleElement specs --- spec/pane-resize-handle-element-spec.coffee | 125 +++++--------------- 1 file changed, 32 insertions(+), 93 deletions(-) diff --git a/spec/pane-resize-handle-element-spec.coffee b/spec/pane-resize-handle-element-spec.coffee index 7a24100dd..1b569b63d 100644 --- a/spec/pane-resize-handle-element-spec.coffee +++ b/spec/pane-resize-handle-element-spec.coffee @@ -3,7 +3,7 @@ PaneAxisElement = require '../src/pane-axis-element' PaneAxis = require '../src/pane-axis' describe "PaneResizeHandleElement", -> - describe "as children of PaneAxisElement", -> + describe "when add or remove panes in PaneAxisElement", -> [paneAxisElement, paneAxis] = [] beforeEach -> @@ -12,11 +12,7 @@ describe "PaneResizeHandleElement", -> paneAxisElement.initialize(paneAxis) document.querySelector('#jasmine-content').appendChild(paneAxisElement) - it "inserts or remove resize elements when pane axis added or removed", -> - modelChildren = (new PaneAxis({}) for i in [1..5]) - paneAxis.addChild(modelChildren[0]) - paneAxis.addChild(modelChildren[1]) - + it "inserts or remove resize elements", -> expectPaneAxisElement = (index) -> child = paneAxisElement.children[index] expect(child.nodeName.toLowerCase()).toBe('atom-pane-axis') @@ -24,23 +20,23 @@ describe "PaneResizeHandleElement", -> expectResizeElement = (index) -> child = paneAxisElement.children[index] expect(paneAxisElement.isPaneResizeHandleElement(child)).toBe(true) + + models = (new PaneAxis({}) for i in [0..2]) + paneAxis.addChild(models[0]) + paneAxis.addChild(models[1]) expectResizeElement(1) - paneAxis.addChild(modelChildren[2]) - paneAxis.addChild(modelChildren[3]) - expectPaneAxisElement(i) for i in [0, 2, 4, 6] - expectResizeElement(i) for i in [1, 3, 5] + paneAxis.addChild(models[2]) + expectPaneAxisElement(i) for i in [0, 2, 4] + expectResizeElement(i) for i in [1, 3] # test removeChild - paneAxis.removeChild(modelChildren[2]) + paneAxis.removeChild(models[2]) expectResizeElement(i) for i in [1, 3] - # test replaceChild - paneAxis.replaceChild(modelChildren[0], modelChildren[4]) - expectResizeElement(i) for i in [1, 3] - - describe "when mouse drag the resize element", -> - [container, containerElement, resizeElementMove, getElementWidth] = [] + describe "when user drag the resize element", -> + [container, containerElement] = [] + [resizeElementMove, getElementWidth, expectFlexScale] = [] beforeEach -> container = new PaneContainer @@ -63,104 +59,47 @@ describe "PaneResizeHandleElement", -> getElementWidth = (element) -> element.getBoundingClientRect().width - it "drag the pane resize handle element, then the panes around it will resize", -> - activePane = container.getActivePane() - rightPane = activePane.splitRight() + # assert the pane's flex scale. arguments is list of pane-scale pair + expectFlexScale = -> + args = Array::slice.apply(arguments, 0) + for paneScale in args + expect(paneScale[0].getFlexScale()).toBeCloseTo(paneScale[1], 0.1) - resizeElement = containerElement.querySelector('atom-pane-resize-handle') - expect(resizeElement).toBeTruthy() - - leftWidth = getElementWidth(resizeElement.previousSibling) - resizeElementMove(resizeElement, leftWidth/2, 0) - expect(activePane.getFlexScale()).toBeCloseTo(0.5, 0.1) - expect(rightPane.getFlexScale()).toBeCloseTo(1.5, 0.1) - - it "drag the resize element, the size of other panes in the same direction will not change", -> + it "add and remove panes in the same direction", -> leftPane = container.getActivePane() middlePane = leftPane.splitRight() - rightPane = middlePane.splitRight() resizeElements = containerElement.querySelectorAll('atom-pane-resize-handle') paneElements = containerElement.querySelectorAll('atom-pane') expect(resizeElements.length).toBe(2) - expectPaneScale = (leftScale, middleScale, rightScale) -> - expect(leftPane.getFlexScale()).toBeCloseTo(leftScale, 0.1) - expect(middlePane.getFlexScale()).toBeCloseTo(middleScale, 0.1) - expect(rightPane.getFlexScale()).toBeCloseTo(rightScale, 0.1) - resizeElementMove(resizeElements[0], getElementWidth(paneElements[0]) / 2) - expectPaneScale(0.5, 1.5, 1) + expectPaneScale [leftPane, 0.5], [middlePane, 1.5] + rightPane = middlePane.splitRight() clientX = getElementWidth(paneElements[0]) + getElementWidth(paneElements[1]) / 2 resizeElementMove(resizeElements[1], clientX) - expectPaneScale(0.5, 0.75, 1.75) + expectPaneScale [leftPane, 0.5], [middlePane, 0.75], [rightPane, 1.75] - it "drag the horizontal element, the size of other vertical pane will not change", -> - upperPane = container.getActivePane() - lowerPane = upperPane.splitDown() - - [upperRightPane, upperLeftPane] = [upperPane.splitRight(), upperPane] - upperPane = upperLeftPane.getParent() - - [lowerRightPane, lowerLeftPane] = [lowerPane.splitRight(), lowerPane] - lowerPane = lowerLeftPane.getParent() - - horizontalResizeElements = containerElement.querySelectorAll('atom-pane-resize-handle.horizontal') - expect(horizontalResizeElements.length).toBe(2) - - expectCloseTo = (element, scale) -> - expect(element.getFlexScale()).toBeCloseTo(scale, 0.1) - - expectPaneScale = (upper, lower, upperLeft, upperRight, lowerLeft, lowerRight) -> - paneScales = [ - [upperPane, upper], [lowerPane, lower], [upperLeftPane, upperLeft], - [upperRightPane, upperRight], [lowerLeftPane, lowerLeft], - [lowerRightPane, lowerRight] - ] - expectCloseTo(e[0], e[1]) for e in paneScales - - newWidth = getElementWidth(horizontalResizeElements[0].previousSibling) / 2 - resizeElementMove(horizontalResizeElements[0], newWidth) - expectPaneScale(1, 1, 0.5, 1.5, 1, 1) - - newWidth = getElementWidth(horizontalResizeElements[1].previousSibling) / 2 - resizeElementMove(horizontalResizeElements[1], newWidth) - expectPaneScale(1, 1, 0.5, 1.5, 0.5, 1.5) - - it "transform the flex scale when dynamically split or close panes in the same direction", -> - leftPane = container.getActivePane() - middlePane = leftPane.splitRight() - rightPane = middlePane.splitRight() - - expectPaneScale = (leftScale, middleScale, rightScale) -> - paneScales = [[leftPane, leftScale], [middlePane, middleScale], [rightPane, rightScale]]; - expect(e[0].getFlexScale()).toBeCloseTo(e[1], 0.1) for e in paneScales - - resizeElement = containerElement.querySelector('atom-pane-resize-handle') - resizeElementMove(resizeElement, getElementWidth(atom.views.getView(leftPane)) / 2) - expectPaneScale(0.5, 1.5, 1) + middlePane.close() + expectPaneScale [leftPane, 0.44], [rightPane, 1.55] leftPane.close() - expect(middlePane.getFlexScale()).toBeCloseTo(1.2, 0.1) - expect(rightPane.getFlexScale()).toBeCloseTo(0.8, 0.1) + expectPaneScale [rightPane, 1] - rightPane.close() # when close the same direction pane, the flexScale will recorver - expect(middlePane.getFlexScale()).toBeCloseTo(1, 0.1) - - it "retain the flex scale when dynamically split or close panes in orthogonal direction", -> + it "split or close panes in orthogonal direction", -> leftPane = container.getActivePane() rightPane = leftPane.splitRight() resizeElement = containerElement.querySelector('atom-pane-resize-handle') resizeElementMove(resizeElement, getElementWidth(resizeElement.previousSibling) / 2) - expect(leftPane.getFlexScale()).toBeCloseTo(0.5, 0.1) - lowerPane = leftPane.splitDown() # dynamically split pane, pane's flexScale will become to 1 - expect(leftPane.getFlexScale()).toBeCloseTo(1, 0.1) - expect(leftPane.getParent().getFlexScale()).toBeCloseTo(0.5, 0.1) + # dynamically split pane, pane's flexScale will become to 1 + lowerPane = leftPane.splitDown() + expectPaneScale [lowerPane, 1], [leftPane, 1], [leftPane.getParent(), 0.5] - lowerPane.close() # dynamically close pane, the pane's flexscale will recorver to origin value - expect(leftPane.getFlexScale()).toBeCloseTo(0.5, 0.1) + # dynamically close pane, the pane's flexscale will recorver to origin value + lowerPane.close() + expectPaneScale [leftPane, 0.5], [rightPane, 1.5] From 888261eb747ca7842cf94a85ade8af2e4c2eae89 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 14 Apr 2015 09:31:50 -0700 Subject: [PATCH 0651/1783] :arrow_up: language-ruby@0.52 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7b11ebd5b..1fdaf3e5e 100644 --- a/package.json +++ b/package.json @@ -144,7 +144,7 @@ "language-php": "0.22.0", "language-property-list": "0.8.0", "language-python": "0.34.0", - "language-ruby": "0.51.0", + "language-ruby": "0.52.0", "language-ruby-on-rails": "0.21.0", "language-sass": "0.36.0", "language-shellscript": "0.13.0", From 97865c688829a6f21367bb6a510893861a32e700 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 14 Apr 2015 09:41:36 -0700 Subject: [PATCH 0652/1783] :arrow_up: clear-cut@2.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 847c02299..4f9a27320 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "atom-space-pen-views": "^2.0.4", "babel-core": "^4.0.2", "bootstrap": "git+https://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372", - "clear-cut": "^2", + "clear-cut": "^2.0.1", "coffee-cash": "0.8.0", "coffee-script": "1.8.0", "coffeestack": "^1.1.1", From b106dadb1b4e97964b4149141d0353843d372d0e Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 14 Apr 2015 10:22:20 -0700 Subject: [PATCH 0653/1783] :arrow_up: language-javascript --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e39ca1f14..0df4bab60 100644 --- a/package.json +++ b/package.json @@ -134,7 +134,7 @@ "language-html": "0.32.0", "language-hyperlink": "0.12.2", "language-java": "0.14.0", - "language-javascript": "0.72.0", + "language-javascript": "0.73.0", "language-json": "0.14.0", "language-less": "0.25.0", "language-make": "0.14.0", From 4022d477aaaadf5a30381b61bfc5ffd37cd38120 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 14 Apr 2015 10:33:29 -0700 Subject: [PATCH 0654/1783] :arrow_up: fuzzy-finder@0.73.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0df4bab60..99ab51eb7 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,7 @@ "exception-reporting": "0.24.0", "feedback": "0.38.0", "find-and-replace": "0.160.0", - "fuzzy-finder": "0.72.0", + "fuzzy-finder": "0.73.0", "git-diff": "0.54.0", "go-to-line": "0.30.0", "grammar-selector": "0.46.0", From 304b959ca83d51e3670a6917862e9f603c24f701 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 14 Apr 2015 19:34:04 +0200 Subject: [PATCH 0655/1783] :art: Use tags to exclude spec on Linux --- spec/text-editor-component-spec.coffee | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 0b8282e43..769ce424f 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -1340,7 +1340,8 @@ describe "TextEditorComponent", -> afterEach -> atom.restoreWindowDimensions() - it "slides horizontally left when near the right edge", -> + # This spec should actually run on Linux as well, see TextEditorComponent#measureWindowSize for further information. + it "slides horizontally left when near the right edge on #win32 and #darwin", -> marker = editor.displayBuffer.markBufferRange([[0, 26], [0, 26]], invalidate: 'never') decoration = editor.decorateMarker(marker, {type: 'overlay', item}) nextAnimationFrame() @@ -1352,18 +1353,17 @@ describe "TextEditorComponent", -> expect(overlay.style.left).toBe position.left + gutterWidth + 'px' expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' - if process.platform isnt "linux" # see TextEditorComponent#measureWindowSize - editor.insertText('a') - nextAnimationFrame() + editor.insertText('a') + nextAnimationFrame() - expect(overlay.style.left).toBe windowWidth - itemWidth + 'px' - expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' + expect(overlay.style.left).toBe windowWidth - itemWidth + 'px' + expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' - editor.insertText('b') - nextAnimationFrame() + editor.insertText('b') + nextAnimationFrame() - expect(overlay.style.left).toBe windowWidth - itemWidth + 'px' - expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' + expect(overlay.style.left).toBe windowWidth - itemWidth + 'px' + expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' describe "hidden input field", -> it "renders the hidden input field at the position of the last cursor if the cursor is on screen and the editor is focused", -> From 6190fe00d7861387a4fb98c093b68a40cf3d411f Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 14 Apr 2015 19:34:43 +0200 Subject: [PATCH 0656/1783] :art: Avoid string interpolation in require --- spec/spec-helper.coffee | 2 +- src/clipboard.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/spec-helper.coffee b/spec/spec-helper.coffee index 0daf6586e..af0b03eb1 100644 --- a/spec/spec-helper.coffee +++ b/spec/spec-helper.coffee @@ -24,7 +24,7 @@ TextEditorElement = require '../src/text-editor-element' TokenizedBuffer = require '../src/tokenized-buffer' TextEditorComponent = require '../src/text-editor-component' pathwatcher = require 'pathwatcher' -clipboard = require "../src/safe-clipboard" +clipboard = require '../src/safe-clipboard' atom.themes.loadBaseStylesheets() atom.themes.requireStylesheet '../static/jasmine' diff --git a/src/clipboard.coffee b/src/clipboard.coffee index 000eb70e3..2412394a6 100644 --- a/src/clipboard.coffee +++ b/src/clipboard.coffee @@ -1,5 +1,5 @@ crypto = require 'crypto' -clipboard = require "./safe-clipboard" +clipboard = require './safe-clipboard' # Extended: Represents the clipboard used for copying and pasting in Atom. # From ae6b5e54ef9777acda7cea24f00cc1f0fa163f06 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 14 Apr 2015 11:08:26 -0700 Subject: [PATCH 0657/1783] :art: " -> ' --- src/safe-clipboard.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/safe-clipboard.coffee b/src/safe-clipboard.coffee index 571ff4578..8301f9d54 100644 --- a/src/safe-clipboard.coffee +++ b/src/safe-clipboard.coffee @@ -1,6 +1,6 @@ # Using clipboard in renderer process is not safe on Linux. module.exports = - if process.platform is "linux" and process.type is "renderer" - require("remote").require("clipboard") + if process.platform is 'linux' and process.type is 'renderer' + require('remote').require('clipboard') else - require("clipboard") + require('clipboard') From 7b8cea2662bc75b2491c20c0ccd2def82c3aa22f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 14 Apr 2015 11:21:20 -0700 Subject: [PATCH 0658/1783] :arrow_up: language-gfm@0.68 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 99ab51eb7..2f7bb54c2 100644 --- a/package.json +++ b/package.json @@ -128,7 +128,7 @@ "language-coffee-script": "0.39.0", "language-csharp": "0.5.0", "language-css": "0.28.0", - "language-gfm": "0.67.0", + "language-gfm": "0.68.0", "language-git": "0.10.0", "language-go": "0.23.0", "language-html": "0.32.0", From 8875746f771765c52b75d9e22532c35758cfaae8 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 14 Apr 2015 11:36:12 -0700 Subject: [PATCH 0659/1783] :arrow_up: status-bar@0.68 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2f7bb54c2..acca77a2f 100644 --- a/package.json +++ b/package.json @@ -113,7 +113,7 @@ "settings-view": "0.192.0", "snippets": "0.88.0", "spell-check": "0.55.0", - "status-bar": "0.67.0", + "status-bar": "0.68.0", "styleguide": "0.44.0", "symbols-view": "0.94.0", "tabs": "0.67.0", From d5ff7f26bf7201c72470b92f887585f3d133ac66 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 14 Apr 2015 14:14:15 -0700 Subject: [PATCH 0660/1783] Create a new ATOM_HOME dir for each integration spec --- spec/integration/startup-spec.coffee | 32 ++++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/spec/integration/startup-spec.coffee b/spec/integration/startup-spec.coffee index e0df3ad9b..5c18255a8 100644 --- a/spec/integration/startup-spec.coffee +++ b/spec/integration/startup-spec.coffee @@ -6,22 +6,22 @@ return unless process.env.ATOM_INTEGRATION_TESTS_ENABLED fs = require "fs" path = require "path" temp = require("temp").track() -AtomHome = temp.mkdirSync('atom-home') -fs.writeFileSync(path.join(AtomHome, 'config.cson'), fs.readFileSync(path.join(__dirname, 'fixtures', 'atom-home', 'config.cson'))) runAtom = require("./helpers/start-atom") describe "Starting Atom", -> - [tempDirPath, otherTempDirPath] = [] + [tempDirPath, otherTempDirPath, atomHome] = [] beforeEach -> jasmine.useRealClock() + atomHome = temp.mkdirSync('atom-home') + fs.writeFileSync(path.join(atomHome, 'config.cson'), fs.readFileSync(path.join(__dirname, 'fixtures', 'atom-home', 'config.cson'))) tempDirPath = temp.mkdirSync("empty-dir") otherTempDirPath = temp.mkdirSync("another-temp-dir") describe "opening a new file", -> it "opens the parent directory and creates an empty text editor", -> - runAtom [path.join(tempDirPath, "new-file")], {ATOM_HOME: AtomHome}, (client) -> + runAtom [path.join(tempDirPath, "new-file")], {ATOM_HOME: atomHome}, (client) -> client .waitForWindowCount(1, 1000) .waitForExist("atom-workspace", 5000) @@ -42,7 +42,7 @@ describe "Starting Atom", -> tempFilePath = path.join(temp.mkdirSync("a-third-dir"), "a-file") fs.writeFileSync(tempFilePath, "This file was already here.") - runAtom [path.join(tempDirPath, "new-file")], {ATOM_HOME: AtomHome}, (client) -> + runAtom [path.join(tempDirPath, "new-file")], {ATOM_HOME: atomHome}, (client) -> client .waitForWindowCount(1, 1000) .waitForExist("atom-workspace", 5000) @@ -50,7 +50,7 @@ describe "Starting Atom", -> # Opening another file reuses the same window and does not change the # project paths. - .startAnotherAtom([tempFilePath], ATOM_HOME: AtomHome) + .startAnotherAtom([tempFilePath], ATOM_HOME: atomHome) .waitForPaneItemCount(2, 5000) .waitForWindowCount(1, 1000) .treeViewRootDirectories() @@ -60,7 +60,7 @@ describe "Starting Atom", -> # Opening another directory creates a second window. .waitForNewWindow(-> - @startAnotherAtom([otherTempDirPath], ATOM_HOME: AtomHome) + @startAnotherAtom([otherTempDirPath], ATOM_HOME: atomHome) , 5000) .waitForExist("atom-workspace", 5000) .waitForPaneItemCount(0, 1000) @@ -69,7 +69,7 @@ describe "Starting Atom", -> describe "reopening a directory that was previously opened", -> it "remembers the state of the window", -> - runAtom [tempDirPath], {ATOM_HOME: AtomHome}, (client) -> + runAtom [tempDirPath], {ATOM_HOME: atomHome}, (client) -> client .waitForExist("atom-workspace", 5000) .waitForPaneItemCount(0, 3000) @@ -77,7 +77,7 @@ describe "Starting Atom", -> .waitForPaneItemCount(1, 3000) .execute -> atom.unloadEditorWindow() - runAtom [tempDirPath], {ATOM_HOME: AtomHome}, (client) -> + runAtom [tempDirPath], {ATOM_HOME: atomHome}, (client) -> client .waitForExist("atom-workspace", 5000) .waitForPaneItemCount(1, 5000) @@ -87,7 +87,7 @@ describe "Starting Atom", -> nestedDir = path.join(otherTempDirPath, "nested-dir") fs.mkdirSync(nestedDir) - runAtom [tempDirPath, otherTempDirPath], {ATOM_HOME: AtomHome}, (client) -> + runAtom [tempDirPath, otherTempDirPath], {ATOM_HOME: atomHome}, (client) -> client .waitForExist("atom-workspace", 5000) .treeViewRootDirectories() @@ -95,7 +95,7 @@ describe "Starting Atom", -> # Opening one of those directories again reuses the same window and # does not change the project paths. - .startAnotherAtom([nestedDir], ATOM_HOME: AtomHome) + .startAnotherAtom([nestedDir], ATOM_HOME: atomHome) .waitForExist("atom-workspace", 5000) .treeViewRootDirectories() .then ({value}) -> expect(value).toEqual([tempDirPath, otherTempDirPath]) @@ -103,13 +103,13 @@ describe "Starting Atom", -> describe "when there is an existing window with no project path", -> describe "opening a directory", -> it "opens the directory in the existing window", -> - runAtom [], {ATOM_HOME: AtomHome}, (client) -> + runAtom [], {ATOM_HOME: atomHome}, (client) -> client .waitForExist("atom-workspace") .treeViewRootDirectories() .then ({value}) -> expect(value).toEqual([]) - .startAnotherAtom([tempDirPath], ATOM_HOME: AtomHome) + .startAnotherAtom([tempDirPath], ATOM_HOME: atomHome) .waitUntil(-> @treeViewRootDirectories() .then ({value}) -> value[0] is tempDirPath @@ -119,12 +119,12 @@ describe "Starting Atom", -> describe "launching with no path", -> it "always opens a new window with a single untitled buffer", -> - runAtom [], {ATOM_HOME: AtomHome}, (client) -> + runAtom [], {ATOM_HOME: atomHome}, (client) -> client .waitForExist("atom-workspace") .waitForPaneItemCount(1, 5000) - runAtom [], {ATOM_HOME: AtomHome}, (client) -> + runAtom [], {ATOM_HOME: atomHome}, (client) -> client .waitForExist("atom-workspace") .waitForPaneItemCount(1, 5000) @@ -132,5 +132,5 @@ describe "Starting Atom", -> # Opening with no file paths always creates a new window, even if # existing windows have no project paths. .waitForNewWindow(-> - @startAnotherAtom([], ATOM_HOME: AtomHome) + @startAnotherAtom([], ATOM_HOME: atomHome) , 5000) From ce7d0c161db57263ff5ee768a1f628afabc20f96 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 14 Apr 2015 14:16:39 -0700 Subject: [PATCH 0661/1783] Always quit Atom realistically in integration specs --- spec/integration/helpers/start-atom.coffee | 12 +++++++++++- spec/integration/startup-spec.coffee | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/spec/integration/helpers/start-atom.coffee b/spec/integration/helpers/start-atom.coffee index 4be2efab8..798853eab 100644 --- a/spec/integration/helpers/start-atom.coffee +++ b/spec/integration/helpers/start-atom.coffee @@ -94,6 +94,15 @@ buildAtomClient = (args, env) -> ]), env: extend({}, process.env, env)) done() + .addCommand "dispatchCommand", (command, done) -> + @execute "atom.commands.dispatch(document.activeElement, '#{command}')" + .call(done) + + .addCommand "simulateQuit", (done) -> + @execute -> atom.unloadEditorWindow() + .execute -> require("remote").require("app").emit("before-quit") + .call(done) + module.exports = (args, env, fn) -> [chromedriver, chromedriverLogs, chromedriverExit] = [] @@ -119,6 +128,7 @@ module.exports = (args, env, fn) -> waitsFor("webdriver to finish", (done) -> finish = once -> client + .simulateQuit() .end() .then(-> chromedriver.kill()) .then(chromedriverExit.then( @@ -133,7 +143,7 @@ module.exports = (args, env, fn) -> client = buildAtomClient(args, env) client.on "error", (err) -> - jasmine.getEnv().currentSpec.fail(JSON.stringify(err)) + jasmine.getEnv().currentSpec.fail(new Error(err.response?.body?.value?.message)) finish() fn(client.init()).then(finish) diff --git a/spec/integration/startup-spec.coffee b/spec/integration/startup-spec.coffee index 5c18255a8..d34330b9e 100644 --- a/spec/integration/startup-spec.coffee +++ b/spec/integration/startup-spec.coffee @@ -36,6 +36,7 @@ describe "Starting Atom", -> .keys("Hello!") .execute -> atom.workspace.getActiveTextEditor().getText() .then ({value}) -> expect(value).toBe "Hello!" + .dispatchCommand("editor:delete-line") describe "when there is already a window open", -> it "reuses that window when opening files, but not when opening directories", -> @@ -75,7 +76,6 @@ describe "Starting Atom", -> .waitForPaneItemCount(0, 3000) .execute -> atom.workspace.open() .waitForPaneItemCount(1, 3000) - .execute -> atom.unloadEditorWindow() runAtom [tempDirPath], {ATOM_HOME: atomHome}, (client) -> client From e7f64c5ec1e055ebc3a6de1c52531589f9a11ff4 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 14 Apr 2015 14:17:40 -0700 Subject: [PATCH 0662/1783] Fix docs for AtomApplication::openPaths --- src/browser/atom-application.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 7c15d0f2a..101bfb330 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -328,7 +328,7 @@ class AtomApplication focusedWindow: -> _.find @windows, (atomWindow) -> atomWindow.isFocused() - # Public: Opens multiple paths, in existing windows if possible. + # Public: Opens a single path, in an existing window if possible. # # options - # :pathToOpen - The file path to open @@ -341,7 +341,7 @@ class AtomApplication openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, apiPreviewMode, window}) -> @openPaths({pathsToOpen: [pathToOpen], pidToKillWhenClosed, newWindow, devMode, safeMode, apiPreviewMode, window}) - # Public: Opens a single path, in an existing window if possible. + # Public: Opens multiple paths, in existing windows if possible. # # options - # :pathsToOpen - The array of file paths to open From 3d05ae02ba8b0327f51737c1dbb87b2403c52bc1 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 14 Apr 2015 14:18:44 -0700 Subject: [PATCH 0663/1783] Reopen windows when launching w/ no arguments --- spec/integration/startup-spec.coffee | 85 ++++++++++++++++++---------- src/browser/atom-application.coffee | 45 ++++++++++++++- src/browser/atom-window.coffee | 7 ++- 3 files changed, 101 insertions(+), 36 deletions(-) diff --git a/spec/integration/startup-spec.coffee b/spec/integration/startup-spec.coffee index d34330b9e..2dcf6ba38 100644 --- a/spec/integration/startup-spec.coffee +++ b/spec/integration/startup-spec.coffee @@ -101,36 +101,61 @@ describe "Starting Atom", -> .then ({value}) -> expect(value).toEqual([tempDirPath, otherTempDirPath]) describe "when there is an existing window with no project path", -> - describe "opening a directory", -> - it "opens the directory in the existing window", -> - runAtom [], {ATOM_HOME: atomHome}, (client) -> - client - .waitForExist("atom-workspace") + it "reuses that window to open a directory", -> + runAtom [], {ATOM_HOME: atomHome}, (client) -> + client + .waitForExist("atom-workspace") + .treeViewRootDirectories() + .then ({value}) -> expect(value).toEqual([]) + + .startAnotherAtom([tempDirPath], ATOM_HOME: atomHome) + .waitUntil(-> + @treeViewRootDirectories() + .then ({value}) -> value[0] is tempDirPath + , 5000) + .then (result) -> expect(result).toBe(true) + .waitForWindowCount(1, 5000) + + describe "launching with no path", -> + it "opens a new window with a single untitled buffer", -> + runAtom [], {ATOM_HOME: atomHome}, (client) -> + client + .waitForExist("atom-workspace") + .waitForPaneItemCount(1, 5000) + + # Opening with no file paths always creates a new window, even if + # existing windows have no project paths. + .waitForNewWindow(-> + @startAnotherAtom([], ATOM_HOME: atomHome) + , 5000) + .waitForExist("atom-workspace") + .waitForPaneItemCount(1, 5000) + + it "reopens any previously opened windows", -> + runAtom [tempDirPath], {ATOM_HOME: atomHome}, (client) -> + client + .waitForExist("atom-workspace") + .waitForNewWindow(-> + @startAnotherAtom([otherTempDirPath], ATOM_HOME: atomHome) + , 5000) + .waitForExist("atom-workspace") + + runAtom [], {ATOM_HOME: atomHome}, (client) -> + windowProjectPaths = [] + + client + .waitForWindowCount(2, 10000) + .then ({value: windowHandles}) -> + @window(windowHandles[0]) .treeViewRootDirectories() - .then ({value}) -> expect(value).toEqual([]) + .then ({value: directories}) -> windowProjectPaths.push(directories) - .startAnotherAtom([tempDirPath], ATOM_HOME: atomHome) - .waitUntil(-> - @treeViewRootDirectories() - .then ({value}) -> value[0] is tempDirPath - , 5000) - .then (result) -> expect(result).toBe(true) - .waitForWindowCount(1, 5000) + .window(windowHandles[1]) + .treeViewRootDirectories() + .then ({value: directories}) -> windowProjectPaths.push(directories) - describe "launching with no path", -> - it "always opens a new window with a single untitled buffer", -> - runAtom [], {ATOM_HOME: atomHome}, (client) -> - client - .waitForExist("atom-workspace") - .waitForPaneItemCount(1, 5000) - - runAtom [], {ATOM_HOME: atomHome}, (client) -> - client - .waitForExist("atom-workspace") - .waitForPaneItemCount(1, 5000) - - # Opening with no file paths always creates a new window, even if - # existing windows have no project paths. - .waitForNewWindow(-> - @startAnotherAtom([], ATOM_HOME: atomHome) - , 5000) + .call -> + expect(windowProjectPaths.sort()).toEqual [ + [tempDirPath] + [otherTempDirPath] + ].sort() diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 101bfb330..ead7756ee 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -43,7 +43,6 @@ class AtomApplication createAtomApplication() return - client = net.connect {path: options.socketPath}, -> client.write JSON.stringify(options), -> client.end() @@ -79,9 +78,11 @@ class AtomApplication @setupJavaScriptArguments() @handleEvents() - @openWithOptions(options) + if options.pathsToOpen?.length > 0 or options.urlsToOpen?.length > 0 or options.test + @openWithOptions(options) + else + @loadState() or @openPath(options) - # Opens a new window based on the options provided. openWithOptions: ({pathsToOpen, urlsToOpen, test, pidToKillWhenClosed, devMode, safeMode, apiPreviewMode, newWindow, specDirectory, logFile}) -> if test @runSpecs({exitWhenDone: true, @resourcePath, specDirectory, logFile}) @@ -198,6 +199,9 @@ class AtomApplication app.on 'window-all-closed', -> app.quit() if process.platform in ['win32', 'linux'] + app.on 'before-quit', => + @saveState() + app.on 'will-quit', => @killAllProcesses() @deleteSocketFile() @@ -411,6 +415,41 @@ class AtomApplication console.log("Killing process #{pid} failed: #{error.code ? error.message}") delete @pidsToOpenWindows[pid] + saveState: -> + states = [] + for window in @windows + if loadSettings = window.getLoadSettings() + states.push(_.pick(loadSettings, + 'initialPaths' + 'isSpec' + 'devMode' + 'safeMode' + 'apiPreviewMode' + )) + fs.writeFileSync(@getStatePath(), JSON.stringify(states)) + + loadState: -> + try + stateString = fs.readFileSync(@getStatePath(), 'utf8') + catch error + if error.code is 'ENOENT' + return false + else + throw error + + states = JSON.parse(fs.readFileSync(@getStatePath())) + for state in states + @openWithOptions({ + pathsToOpen: state.initialPaths + urlsToOpen: [] + devMode: state.devMode + safeMode: state.safeMode + apiPreviewMode: state.apiPreviewMode + }) + + getStatePath: -> + path.join(process.env.ATOM_HOME, "storage", "application.json") + # Open an atom:// url. # # The host of the URL being opened is assumed to be the package name diff --git a/src/browser/atom-window.coffee b/src/browser/atom-window.coffee index fff98799c..6a6abb4b9 100644 --- a/src/browser/atom-window.coffee +++ b/src/browser/atom-window.coffee @@ -87,8 +87,9 @@ class AtomWindow hash: encodeURIComponent(JSON.stringify(loadSettings)) getLoadSettings: -> - hash = url.parse(@browserWindow.webContents.getUrl()).hash.substr(1) - JSON.parse(decodeURIComponent(hash)) + if @browserWindow.webContents.loaded + hash = url.parse(@browserWindow.webContents.getUrl()).hash.substr(1) + JSON.parse(decodeURIComponent(hash)) hasProjectPath: -> @getLoadSettings().initialPaths?.length > 0 @@ -105,7 +106,7 @@ class AtomWindow true containsPath: (pathToCheck) -> - @getLoadSettings().initialPaths?.some (projectPath) -> + @getLoadSettings()?.initialPaths?.some (projectPath) -> if not projectPath false else if not pathToCheck From 7ea71deb96f264448676385f17279659846a324d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 14 Apr 2015 14:24:15 -0700 Subject: [PATCH 0664/1783] Prepare 0.192 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index acca77a2f..157165272 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "0.191.0", + "version": "0.192.0", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From 55b6499b7d932f4baa845c786d16e8da4d484547 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 14 Apr 2015 15:25:36 -0700 Subject: [PATCH 0665/1783] Add notification for ENXIO save error Closes #5576 --- src/pane.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pane.coffee b/src/pane.coffee index 8b12fcf7f..0d8c68066 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -644,6 +644,8 @@ class Pane extends Model atom.notifications.addWarning("Unable to save file: Read-only file system '#{error.path}'") else if error.code is 'ENOSPC' and error.path? atom.notifications.addWarning("Unable to save file: No space left on device '#{error.path}'") + else if error.code is 'ENXIO' and error.path? + atom.notifications.addWarning("Unable to save file: No such device or address '#{error.path}'") else if errorMatch = /ENOTDIR, not a directory '([^']+)'/.exec(error.message) fileName = errorMatch[1] atom.notifications.addWarning("Unable to save file: A directory in the path '#{fileName}' could not be written to") From 3091ac83316795bb1e32b1110e280044d5837616 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 14 Apr 2015 15:29:04 -0700 Subject: [PATCH 0666/1783] Don't try to reopen spec windows on launch --- src/browser/atom-application.coffee | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index ead7756ee..3d1b3b92e 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -419,13 +419,13 @@ class AtomApplication states = [] for window in @windows if loadSettings = window.getLoadSettings() - states.push(_.pick(loadSettings, - 'initialPaths' - 'isSpec' - 'devMode' - 'safeMode' - 'apiPreviewMode' - )) + unless loadSettings.isSpec + states.push(_.pick(loadSettings, + 'initialPaths' + 'devMode' + 'safeMode' + 'apiPreviewMode' + )) fs.writeFileSync(@getStatePath(), JSON.stringify(states)) loadState: -> From 078c6a80cf0304c8de1c06eeae14aff729a1ce81 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Tue, 14 Apr 2015 18:35:32 -0400 Subject: [PATCH 0667/1783] Add .has-file-path if active buffer has a file path --- spec/pane-view-spec.coffee | 5 +++++ src/pane-element.coffee | 2 ++ 2 files changed, 7 insertions(+) diff --git a/spec/pane-view-spec.coffee b/spec/pane-view-spec.coffee index 2df5aa68c..4f240cf66 100644 --- a/spec/pane-view-spec.coffee +++ b/spec/pane-view-spec.coffee @@ -118,6 +118,11 @@ describe "PaneView", -> paneModel.activateItem(view2) expect(pane.itemViews.find('#view-2').length).toBe 1 + describe "when the active item implements ::getPath", -> + fit "adds .has-file-path to the active item element", -> + paneModel.activateItem(editor1) + expect(pane.itemViews.find('atom-text-editor')).toHaveClass('has-file-path') + describe "when an item is destroyed", -> it "triggers the 'pane:item-removed' event with the item and its former index", -> itemRemovedHandler = jasmine.createSpy("itemRemovedHandler") diff --git a/src/pane-element.coffee b/src/pane-element.coffee index f5bfc18bd..69d41f1ef 100644 --- a/src/pane-element.coffee +++ b/src/pane-element.coffee @@ -71,6 +71,8 @@ class PaneElement extends HTMLElement hasFocus = @hasFocus() itemView = atom.views.getView(item) + if item.getPath? then $(itemView).addClass('has-file-path') + unless @itemViews.contains(itemView) @itemViews.appendChild(itemView) callAttachHooks(itemView) From a24e76fb60f9f50f250e4dbc84c2c744ce1ea88b Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 14 Apr 2015 15:35:27 -0700 Subject: [PATCH 0668/1783] :arrow_up: fuzzy-finder@0.74.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 157165272..ef863920d 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,7 @@ "exception-reporting": "0.24.0", "feedback": "0.38.0", "find-and-replace": "0.160.0", - "fuzzy-finder": "0.73.0", + "fuzzy-finder": "0.74.0", "git-diff": "0.54.0", "go-to-line": "0.30.0", "grammar-selector": "0.46.0", From e6d1e167399b24a1a2a8bb102ce32962b5bffc17 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Tue, 14 Apr 2015 18:51:19 -0400 Subject: [PATCH 0669/1783] Add image and archive fixtures --- spec/fixtures/sample.png | Bin 0 -> 1701085 bytes spec/fixtures/sample.zip | Bin 0 -> 1212 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 spec/fixtures/sample.png create mode 100644 spec/fixtures/sample.zip diff --git a/spec/fixtures/sample.png b/spec/fixtures/sample.png new file mode 100644 index 0000000000000000000000000000000000000000..c5c4547bf38dd3dc35d5c1168d82354009372ef0 GIT binary patch literal 1701085 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ⅅLCf6O}`v)BfQZ?dZ# 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

~Di>82VIOIjEL-g<>xh<2D@4@cWzh6jl( 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�<2H$fbv_#Noji=_A>Zyhqf>6-`Jemf24Qs{?0vz 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≠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

XqTA2!!0~e) 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

eVx(9)PdC^@x^ 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

d*vk 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�ypk!cir=HUP`Y`A~V z33}L}<1?cWjyJhJ4T%(L6A4sfDU~550)t}?*OwwNgaf{}G0RBb&WI#z7;1u_K)|

LV$ow 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%0AcV=+Lb#kd*z!+zH0`=-Yb}(|=$%%m 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�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

0~>E@SLsv8^4ot^IC;nLZI)r-rGt4EuUZnke8 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­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

ypcT#f(|xoAUXm1IVm7bTFA~ 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

+;UXw%GU6`Z6K}p9Df!8@O*Cu01*J=adiX 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 z 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�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 P00000NkvXXu0mjfy)g(J literal 0 HcmV?d00001 diff --git a/spec/fixtures/sample.zip b/spec/fixtures/sample.zip new file mode 100644 index 0000000000000000000000000000000000000000..4bead6aad82f53c499636ba3a74f2ebc7566b50e GIT binary patch literal 1212 zcmWIWW@Zs#-~d9QS?z8NNPw3?fFU_QEiE-w4?=}T@Gz|I(hUtxRSEsdD8i5%c-rr< zfxw>U+HS9o+6f%ox@GSN$qwf!Ia$r}2eX;y`|t7V(kk3k{(R%(uP@lrYQ(JT3Ve1l zzbb6mG}9*ACgz&h1dZt;3cfdX##XsMoW<*xZd2+M{U-d3MZSTwb^21)LX+?ZU)SEe zx%#HpO8$z@d%-6*Fy0i{Ggr->_mA1Ni+_)B%ds*Yn-p~Queq@4OFxUP1=1IozIrDv zHaoUX@pwtH=Y{H9#onRUm#pf1cUK(70%f3haoWzpbrC&C$ z$$3{hr%O3b{_}Um{Q=(W9M2!UmA?)Qi-n8~3<2;Ey0)eOC4@LZAyk~7rw1Znp|hlw z9UMB|TY?N8G68k7bLhMcna2(^jTMLyrU`qOV3<~%m|KvOs+Uy^GL3VZZs;_59Cc7C-J>$=2aY>>8xk;_c+`%B{I+OFbx5Y8v=-&I3ba2Hr5{28J;-RB}>_!Qs*f3>R1^7kivLe^P%_P=HzC zMiZmr&CebMo%8VZ@zf1k@hm8y!ON;4GkaasIv(XUkHAr}LS=rD4$x9i$RnZxJz}{K zmX=hMz~TaCC-=GYzM&ePYc(!DhQ#mU-MQ_&Km)nKhB7jVG9z*na!TT5-~p-t1BWGz zAQ~-yalrFefH%Szkn50>5GRT;O2FVlN`w$2Ku$$A0+iN}!yDCz0-zB{DUSo5@{o-H zxdJ)#xKUiu#soJ45=|TouxLUz1Ua<0Pz?EvFa#Xz5Qjkg!pa5;FIFH71Em*c5Dx%b C(S=h0 literal 0 HcmV?d00001 From 1a783963e303b0f40487aafccf072dbd9a16fbf0 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Tue, 14 Apr 2015 19:26:17 -0400 Subject: [PATCH 0670/1783] :white_check_mark: Add tests for images and archives --- spec/pane-view-spec.coffee | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/spec/pane-view-spec.coffee b/spec/pane-view-spec.coffee index 4f240cf66..8b58eca09 100644 --- a/spec/pane-view-spec.coffee +++ b/spec/pane-view-spec.coffee @@ -7,7 +7,7 @@ path = require 'path' temp = require 'temp' describe "PaneView", -> - [container, containerModel, view1, view2, editor1, editor2, pane, paneModel, deserializerDisposable] = [] + [container, containerModel, view1, view2, editor1, editor2, image, archive, pane, paneModel, deserializerDisposable] = [] class TestView extends View @deserialize: ({id, text}) -> new TestView({id, text}) @@ -37,10 +37,16 @@ describe "PaneView", -> waitsForPromise -> atom.workspace.open('sample.txt').then (o) -> editor2 = o + waitsForPromise -> + atom.workspace.open('sample.png').then (o) -> image = o + + waitsForPromise -> + atom.workspace.open('sample.zip').then (o) -> archive = o + runs -> pane = container.getRoot() paneModel = pane.getModel() - paneModel.addItems([view1, editor1, view2, editor2]) + paneModel.addItems([view1, editor1, view2, editor2, image, archive]) afterEach -> deserializerDisposable.dispose() @@ -118,10 +124,14 @@ describe "PaneView", -> paneModel.activateItem(view2) expect(pane.itemViews.find('#view-2').length).toBe 1 - describe "when the active item implements ::getPath", -> + describe "when the new activeItem implements ::getPath", -> fit "adds .has-file-path to the active item element", -> paneModel.activateItem(editor1) expect(pane.itemViews.find('atom-text-editor')).toHaveClass('has-file-path') + paneModel.activateItem(image) + expect(pane.itemViews.find('.image-view')).toHaveClass('has-file-path') + paneModel.activateItem(archive) + expect(pane.itemViews.find('.archive-editor')).toHaveClass('has-file-path') describe "when an item is destroyed", -> it "triggers the 'pane:item-removed' event with the item and its former index", -> From bf852160da21254b0f74e778e0556d0f5a1b7f43 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Tue, 14 Apr 2015 19:52:07 -0400 Subject: [PATCH 0671/1783] Revert "Add image and archive fixtures" This reverts commit e6d1e167399b24a1a2a8bb102ce32962b5bffc17. --- spec/fixtures/sample.png | Bin 1701085 -> 0 bytes spec/fixtures/sample.zip | Bin 1212 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 spec/fixtures/sample.png delete mode 100644 spec/fixtures/sample.zip diff --git a/spec/fixtures/sample.png b/spec/fixtures/sample.png deleted file mode 100644 index c5c4547bf38dd3dc35d5c1168d82354009372ef0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1701085 zcmV)RK(oJzP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02y>eSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+&q*x_f7Kme}lX8_X@DLYew~{4eYm9*4u@wB!8}r`P55E%VcseZr#Ow6A9X^K>akwy-4|n^K zRX5`COT5fVBCATQCeRv9se}?FGNoWPCkFx^mT|E(!ZJRV^N1p%XsBiqMu;`Tyb+Ru zAw8W<)a&)>bXqFp7!r4`-uJrhBc2t%%kduz=5=FU7v^!HcX2x*ez*N0(&Hsv9>V<) z_56u<^*-`Y!yTs6@fCvHQv!Ig78}fJrB=#Et^D%WnymDjqw)IjY~y&kelXZOn-Awr zAwZzGlVB@82?1}st4SusHK zGQkKa$#_xHgOCVH`24sBLET=&3mH4nPRPE(l{sAkxem3|c_e!;tc!9hH~ z5RqRg_(PR)sFah(T{N;v<31AgVkm-P7*3FWjPfG5%SU+pl+TACUXRb~@qYQ|`#C<3 z*XQy0y&l5nqWvBLbHQI#CEXh74p6Xn7?Gj{lHzcJ#c;-tLTJPfVf`3`pp4H?dlA}m z7eC{LpahQm92`S1)ayswKCjE`arnGW#OH#*76jsRW2lcJQH~|!VWnSB?5($MFE-vh zJ^b+U* zjqIeB9+VTkQhZQJ_N(bhD?jg**N3&mpf>51N1fuRQ-YQ8s5+U{X4Cq7)__bWwZWj& z>1LbFRIL_+G+W7DKQ|l|`-6O=nJ5&@ctSKyN|yW_=OM{8f>@&{H_Q1r-p>gb%VR7@ zP_!Sz5kCe;k{_oCilteB7i1}<1!9(&3|n!_G!&5|Q4IbRt`)y~l|UR2%nK`P9O=;& zDxb1?t-|`WwGBUZEz?c~vl<)W{1)pA^JqlGqB0Sd;B>$(5i>0yNMd2@>r2pno^sleNfBPu;w~x|)c9wp-6}#%li?X&=GpE&P zIVz0{^3#pji=E_~{mh5s;@79;PbcM%$EA-)#rFsKce}Z_yV)jmW4SeQa{w^Pn%I^y7P#=PM{BYgHU4G2zN1Z6d@4{e-J7EigI(&%3>vehDa3aA$OA;tU_!%5waW9X# zIn>1?YXa&t7=K)4!Wt7$a7jRT*2~gvj`0aB!ZUuJK{*;_NtD8UG>(c4tqOv|^CH9Y z6eH18N=7Roev}VxH`7P`!f`*h+lVdl>M+5MW9W8)zv}7V9OVC(AJ_lK|LW=g^MCvG z|K_{dQPFuYO1-$+x;~$7Y?Mw;```ceYHPnV9$BA0Z2b@ayTACK{`KC`)8YHk9HnC-rLyj zWOGWp6W`mZU7YsMj#^vu?5GnOb%N{T#KwAlIEXbGMz0rHEOOi1mBYi<<>j>1jucB; zxnfkR!D7kCWYv5@Z?@u{Zo1xxwdz)mi^sjU&&Qu$Z+v*Uc>iJ@^7h%{<<0c< z?fm1*-6t2L)7{4Te(QLrvA8d-GoKd6!|bG=+@9tx_8K?4<%^B{^=A2a zlxn5qQbZ_3l!zv3JP`}>VVyA*A|Ut`)~j;9ph6^qd?BG{BT70fr7R()Ga;EUc)ua| zBPx|NxRl1mWhxAJ4IT}NcobfmLPY0-0X7)mEDcsTOXb4>F=41FQ%jqA+R&2reNBjI zLdul#5v>%{iV-y*lJb^N3`-@8%Nuk?K~s`1Dkm<0i*QFMUy{f33R}|nQh?9POkQD90uiPW z9dpXQ6~X&}_uOZ__gT+<4)?-o1-Dc`+%H^EN3CIqhaympAvuO-8H%P!ih?E0F8?ts zOEV13z_pg(7>eU)USJ>`Pjei_vLr+j8ChZj5~s<$A@Qcf83JqYjLy+<8clITPNK>h z*RaHXLR~LKjt1H5_1eXHWp9ugR*hr$$ zW_or#KE51m9n@Qch#5t__@BU~4#PcAM39u9VF^VQlgVhaRh`X8qj7sMY<7Eoe zJvqCcZk-O+k2>S+`f#&4*>0{M^w;+X)6GtIQf>Du#ab$!4C=7k1PUh*xN(vsDvDgT zY?ND}Mk`V-X_aE&aI^O6@z(iaFKVKi<}Fps-NV7&=`iSD?Rsf1nF zy?YOWMsV7l&Or$4N0Y_=VCQ67@8&7N=ku?Tl#gc#9?oY16DbNJ{XW105_kXyLx4g4 z2nlc*T_WMm37`Uu{ICLnPY5e?B)~^C39hGUOV5VQT*S(TgJ~<63>x4BKtjq4 zCUh$nFe9oS6cvpTB%EfUoI_9>3Em|VJU+ke1h3EKgTPLMI2}HS!{&kCx#R)FW0P;q z?^(lqP6~DNghyul29E?qG#(%_CRGU0)hN@5bKTT3Nv4~i+i|89CigpLNz8#azr5(X}Kw~tHV1C5@=SP7D9v|jIX^iB746q&b+vn=thoL5d*h27n0S~qiyiN*nbAAU@ zITGejAcR+0MF z!1kX5JXnGOkl-Z=zd$3Vgk~Z_rxMv1mrr(kkIxscpX`2kdGz+#{^Rq>;Z}XziPejN zY>bK+zL4gL1(AH5>E|QELUdY7Z*_`0{mN#yG;3ssmDHe|?3R;*T4vlXOuOZ2uQKVD z$6eq-Wj3e|`=vp@G#r#iqsn+({VA2vxI7pXdc9n?o9%Qnkaj2CYNwh_z;>)$4ren) zEGh*81kZaJ#!J&4iuMo`Tu;3q1ct>(8Yk=!1Wn?U9gKv!fj4X?s1ZX8>w%yu1q4=P zaE^e=bQN(u@Hy`xuKSpGg&|y;L`E$s9oO6W$h4B2Ra4_qqMHpBLsC+uV=@_qC}dc+ z6H=&^!ZU4o))?dGC{)^Y8-@PpSt7jR=zkHJW``i5A-jsfGQTe!+ zIUA+-JCTi6s$UFmw?Z$rldpEuZx6EXj|xzr+dNnb;ln}U{a*gvUJjf9B=|Y+ck+;z z+nHC8r4ZiyWP`iBJ17DSzO3&T-XB24U%Cr?<)4LMBVoCOmwh(jbETMEI?Q5a1i zAOwzr%OJ&(BuhZ-D`AxLBqe`2$n-P%W-Y$oPVF`08%1rDbXcZ+?%yQ2%87fy_5Bm z%dNe`akrnV)~v~-u)kB^-Ks!2KJG;({mAAtxxZQH_ag1KH5|sL)AZ(M>FB6^ble#X zQ_WVmRMG(nrLqA+C=~T_#cDL;kZLVbub3bN;K8UJ9=5}<0x$1u0D<+{AaSr&Io_@B zZIrfVIS>LYch-yBTg9F2((ZO?YqPMqp5I*LHs;y&X=X7_O?t82^&;@#=5+A%V)F9Q z;`QT=*Ej3WE+(&^^xwT0LS8@ZKfi82yY9SxGI;ZJ{POYe&C}_t+sU)5;qyo17uS=g zm*d;>(bZ9Rf4#Ih&h4*PFAn=Rmy69swbxFx8_{7WcDPx7eldD+(z@I%fDle6nNCIp zA(Uc)bXZSXYTUAgV8}SwK%(6;<1r*GX0Vxvl8MNGgiKgYSz=sg!wMOcu#k*L6fyyo zx4#mX)R%VVdFRS#hH%L*{vLoM!tmvT31p6RBuuNkNJdniu>T z4oT6z1m%r!XqfheDQ}cUzyqLyVt^|JxPrnK0$f(2<2)9keFouDF^BA5<&lS+_W^^t zDYzr}J-E+}`dohdJvcY!_u{CJ!2BeEGjPgq9MAKxWSFHGXb=MlLSPw^5imWEG24pD&NR&jDNWiipQBcUL!F1!wq8!}sB#$TggHdL^8|~MO zMnNv*#7v5fCul%IFi7bdtp#XJqjlKtCTj#aJ;(-vOu(cKi;X6fYBe^WH;(p3hdaah zuu{*55<$igRzr#_V-dBK*vhK)q?otJxatdwuDF4A%I3~S<@|Jbbu~S|o&gfJPP)Ub z65NamxggjeXflzo7>}tzlM@7troA8puWuDfQ zSOd?H%$jZz#i}veC>~u5Pi{B%ucqsVT|mNUvp(HvFZO!#o&I>E-5)oa-BP)lNoS%~ zC?JXqN!sthktAkDsZ>!Zl(krtGBsbLpdD`3k9L~51Q(4`rHV1%tZg3jlLdq1+@ZJ< z2dig7sa!amHq4k3uvjC^L)jdSNtu)$4@&mQ>4x#Ph9~*jS3(h? z-bprknP4Jt-}S3CS2&s38gFfZ5N7+s#eQ$=Xp|}heZ-0nS;27^OG8CSa3sbPxIo|{ zNr)tA#}es=MA1w^mKj!}8G)oZoMccOw1E4d z(DtJqC}Qn+T!?$wjO27eQGqyJeiy{)bUD`CcYE2jhI-a;pOf~lF{neKJwSz!1XRE> z22~0(wK(5Q3hk8GPRi}LomNb2MuldSYsdIrQW$2$NnTm6Xq#1ix1k?)tkXgGd=xn! zMotITaWA;lPK-)MJuYN)EFyYM))k=EMBKrn4i0lOs0*&G6y~Q1jKm2X#h{qMF<9~A zej5)c>PPKU6}6FoKvncJ61;ZXks;ZT(I`&k46U)POzUA7b85|4N=zXuEe*LTR04fYn;4j;8)>~SDor!5MQr~B8W z@196G!Wvmfs-0SVa|(Cs@r#?C_b-n=ygGUFeE<4vvbRwibrO}l5)a`)#ghby8FVQs zb#lQ`Eir3l7MNkD6)7u$dY(QvF7<-$)JHnQ5=EfDiQxgI<2n&ky^B(V#dU zm1oo1VqRZgG#88dY*rnOioIU8(@8_Ry-a_Q8xHfsA>g6Vs3&u|AY56@Ag8JnFJctq zBPcJ;qBMh&EN+*3EJ-pXP7^4B0h)LUhd-diQgDkhRVi$!VKZRqvZ?SAhqEL?qAt|C z;&a{iI`8>C4{&6S!ki|LWevU_*N4T#qE&zl%c({>RE(%eoe#@YSfRoy4GAeUAi8H-C9SVBjVhBqHZnptMnQg$cd>x10$i|U7) z#`n+LfBw4nyEpB>d)xk3uj~KnRqgMeSO3Mc>c4o=`rWJ1Uq0-Y|Q$ z$iCjsyxGsbJ;=Q~gyi3U2~_s^_xsE2Ewh{duxIDvUg5)D;q^}D^=|gf-m>Xnf0>_z z0Bm>zsMrT86hH{}irtb>{B&$fz!n0O{&&p?OCi`~>{r1W1 z^W*i$o7HhSl+h`LaKUxV{qUX}PH8Wk>NuSDew^^4nA`7PHgfr$2W!`sv?&bM&wO`u6|w@Bi-q@ZbO4fBA1eTs>V+S5nn(<@oAg?`(U0Z@hQ1*xDa; z2l;X}G8krdc3L2W$tcxnn7yVs8^(7Q8Az!lce~+@jl%A3_3*HDdfMCEEa!4kwQ7J6 z3WY$v5C9=mYoTT{)@a5m)o`h7)ysOX5gd1;kZ#>Y9*vx64Y_b+bdFK-sl zucps0C$Dc7pI+?#_|5LO?-y^L^`Bk0o?JDbJ!(U4FIqQejc1Sg&mRq+T=t({4sS2| zH>bTP7q$>K$C;g3;p(V=zTZ9AX%FCzRt-V=t;pVb;rZq0#O2;LMeYh(rJn zmf)u#AcSy$3F}Y8 zwUIO`VW}FCsv*8?vE?9L3DVUdUDENK>;s&HWYUs|5PWNej0dQc!RCTo-r`dMJPy^8 z;E8gs81Kp`zFL?aWYl@Z+OCJUtL7rFjMLmC&94`wt%|x?R@RH+B*XS%L^nos!c^13 zYdT(5{RIih@xBb_O>n+A>rJrUB!^@~4C?QaN|#iosL*ANE2?Z(p;HnW7w|CWHz}`* zJ4OF0gE%R_dl?Tnfq;6~c7hXeJN#ZZ$ebo|mIVNCEX&f%1_irKfg%~;0c#6^O*yMr+YwEP7Q@TOxK}NS&-C|UolmnP=kym zdP^q^HpZ1=N{Hx)&aZ_OPcBT?({dxDl;eChNQlI}u<9*lq(L{nwOKtr9b8<`&K}Q> zu13d4^(!i{1sxK??5t4@y{7ihunMoAYdy0st~ zOUt>ES*(VNwNSonr1DBEBPMfFy%U{omUj-@$Csna+xgY);`nN~wO=ok5@t|hI1DGf z81BLBi=T(2{ffe+(&1_?*X>tEllpK{?GN+4VZJ{GC*;P9+-RQa4&$wEqTNsS2IWR8 zm(IjZGa!f@MG+{5_)!m6%*GiDxl-hxR8iRAcT<4%FAYiY@C_&k{k2z z`DyO;tH$kE)jL`&b0?P=1!yo?P03ijPU{fPagczPb4ah z!^QsI;%GYE?X4elHxK(pgma@`q1Y;htnIx za9q-;!k{XH*V_aT`^B@%)E5I$Ms$e_eU0#d@%01258 zP$8JIf@#Z2heFwKBo~Q7vf*et6pk52RM$hQYKW4`@q&F-u{-M!K0oF|Q7?jcpzif~ zoIbbH3vs!8ZWlPg>u^GW;d0pj*6iL$HWi@MTOpv-Mx7k)k|~eI`NJ}vFqmwJFGQqD zRB1-lRxHqo2ilOB)QUm`a6$*D5M%psZj@qYIdQA3?l;YoZs@!pxfsUIX2s)iZoi-2 zY{e(#P%EY8Oe)BEC3KBLRyhBvfVts!R~TGk2&g$IzmM>FaKsLVcmWBJrREVI;`c%T z3CqC$eO{m6F`Lw#2)#kJ6Y+4zQ zOW*`h0oY(L$N?Do{oG&xawxPrxkfWpsU~uTa4eylmZSt2R={Zv178w$0Gb2|PGCub z0W6?2;iqwgA^aSTNj#+~d{CFerWy|$5i4K>1c@VPs7}3WUgrak^Pbyr4|ROSxbBO7 zhsEQ?ur{h@*E^MYr#!Cbn%PJ;tfnnFVF=Lx8wMfB6vU>2Oxf=gN<>hmEtLrexM;xc zlMvU$gf1mCK4nOmppXgjX@f~>I3#1@Ig1>?UB4STo+qE|7vEpDe!Ok}+4KJ2zU=<) zRrhaRwEyOL`**Jg|Kk1Z&z^Q4ttSt9#?d%-y>oGk>qp}@|v8R3sw5+LyM zk8JRJ9@M_QsC~Yw{czL#;mP>B$HSMWy`yQqmDNlUCq1j)wH3eHf%<@QplS?7@0#4~ zc;JQx_g)_YarxjH0H+X!;W$nbc2z=>1cB3V)nZvy6l9(gSw>)Jf%c2EOJ+SPj~Fr@ z3M@N-8C+E7UnKdPe*Sr`cU0|`+oml|L)cA{{HpbZw}Y@nw3sz^Kfx?b98vIdvdkA zb2RIX%B5O3a6`ZbL7Zl=(cnyIVUw>7AYRx3{aU zW~f}!012g%RxAbp3FWfcXhhrX1T4!Ht5gcMYSyqF1|Ez$5ugItpji$;fCsRBd!FB2 zF9Hb`qm=zQ?eMf82Q%z#mbbUcyF1mL&C>eZ76N2rmfc?DcQ=Zc$DPOL!xuNRw@)|U zKHYeEJ$vzJ^8VT8Z$6#=>F51#-p$`WAH2Nn+Iif&y=Yt=*DjALH)m}S!i($ilZ(O4 zS@*@G>67!}*8KJ5@>YO0Wl%btfS4g-x`3Jz9#W{7&ZR?AE~@5Z0a&Ij zF=_HqK)#4WB1!kEfN^8cIT9_}HbWTN6f+rE6;{iIR!uKL#3XxFBltu%U zvj&sVh_s3&B_zhXBa9=$tR+QHQOE0Hc9c;z%f@B}qOF(IS)QNfI9P%Z)=Sc&D9#J~ zB*P67R3}U{On)WdE6JXMQC6EJJl<|^GlvT2#v5=C+6*Mj%VACoS z7l|N)XrxC#-K^im*m2W{i$Ywa&xQM3cJGF}dxzf#PA3QqPC&-)Uqn+hgko4bEQF&O z2-rY?Ycj(K@G*i0JTN53Qh)@Bqh+81YbV4}VF*iv7|f!O5akIo-lXKq1h9Hs=;i{W zsx@gwAicWPENSJuTFNQ;l$wnxX(-miKn2z`C_^U$I-%->Zc?Vj1PoFMU;&MYM#V}w zG96cr_D2_|^TVB1yB>}js3tls#gh(^m6X)X1zLG1Q790CCORz5m(Pg9Vd~(pef4;L z`+V#1_15L-e1E$)9u%vka5`Z-Ar_IN5!nn1ib}H_T)A8x??b0|1>*2LTy;HIb$#XX z{TidzL=_Fiq;%dWRKmq-IA5{S1uc@~GX<^E47UfV*=FV7w10WKe*J9o>URC$Xx<-I z;z@%SF^q76Kq$sX(mp@xWLUp$2>1-nP`w(b`kWY zBJ{8wUrZw>N4aOu>QA5LMk7Wb9Z5@w8LXucri}fZ#`g6mEQ z4yYx6-$Mn2;9Oh2T=6)+2!X&HzylInb2=XUB!o4e!|8W`2Hjq_kD=H=FsR2s2)Y=S z0&z863T7%6{QexjN>dJ&@$;Ntln_}#RUOrXxEW@xm=ul&5~)b7X$t{Pq_v0lfh)M( zx9_3fv+{>^|9_Y-HdylDE+gBjC1WFO`*9`s5i;v;P%B5 zzxe8xoLuM(FE)=3=7$py!sbzLvDX$hMFM+^S0AWzXMgoTNODFII z#*=nL61j^+LHrVJYXJZNQ5k%x1zh7vQ(`Qcg{8fs*ekj~!be5Y$KzfBM^uI|McWB+ zBak$WWbm#r!ODiikW46?wn89;Tr8H2MpB^=m^U2I3`vF~T7)YMNz*tfMCWiHYqf-;U6bPL%A$s9}p z`MmZB6B46vl*EuP7+B^`1$LA1QY`Qx+bzp2exHj(T{PyveGmQauYAs5d)I#HS^Fh` zfk5taq(hVZ`BY#!C>-we?x^tHryI!oSEn~e3KiB7-S%`etOi7_iCYLN$@}*zK9u>#;Y-rQh5%{_;il zuU_>2=2idi-cA1c_4w6ZdcDf;w3PE%^4VeS^>O9(e&$Q|(sy~YmwB_BdApYd9=!hp zAuN#qJSc(?>=p)C9{!x)BLR2-U%@7XEeG2SOD*K>(FIEb{GJLn2JYGlelLW(ri0HH z_0LNl*e@@t-#w~+Jk7s9t9^ev_|2=GZ=Y^HKI|{L#d6Z1{T|G-=2=^HuB+BUzy=VwN&4*;1RDuUAy5RY5Cjw?vLMK!s7R73%c@8zoKNArunh2i zC>Db%8P*usFHk8)ROW7H={y#o5tZ~oU?sr#?>a2mA-r%R%eY%5JO zzxc~%pI>aAE^@aAjkhm0&yQO3&0KpFZI83-`?I6V{hi~D>lYU{&rYYC-Fhd}9po1q zjh&t5d|n##;@wtw*ojOB@#!GeYZ_&!4yT#j-RkjC=lpE2yIXIyLWP3d>m@Q70fbPg znAK{qR<-K&aJ><&*CVx>oqjt8Ht094ej^A=5JIgW!xB6IJUHC0f)Lin=`Wwtv|#&u znB1J@cD5>ud2T*Qug`Lj#U!&n&F*iNFHgEpu0~HEO<&&5fd}uNZGjCwyx98ucK^5E zo_}~XefMJc{^j`N>*>c=(>G6tPp?`xXU)gw&6~5>}vGpcKtDwM~CgF zmy;(K6X3yOm>G7Hy=JuEP4qj7Q8%`?D7?5DfBSTPvsZbtSHD=~n<+VOah0TANQN^J zqmVXp2|W`Jq@!voq9j661PT|KR5`e3c@)O0^C&nWVe;9qQi$uNgq>_qOsF&nA;_a} z^}cIE03PU~-4bXj32&}S z7|h2Jez^M(sMqIlIGw9*w*yW@8wecBunfaOl}xj+Tsnc~?n2Z2G91a+-Hq(B6QZgaW!6nqvr1S;RAEh(9F~O^i|TZdKffBEpG+TLZasUv56gp{{-9eZ z6|7iPHgzTx60MLF&{$r;Ny_8HoNiqg|O!SmCN@Pf6R#JI@xVGd$US@7c=o)oSjZCXiUqkl zBt&%PKVJy$wFh433e;GL$GPm40yemd)9V5u*l#c|8yOy=zEuKs0unG}#j$qJ?S`@v zcyKoo*6mw!y4_xqq*co_;t@4!h!I&&>A6}YRSN1R20~z1C&&2(5t9_ZqT%2q-6Dcf zE|idBX(N+MRO`iZsRZ{h_`y(sIO0TH_fXHn-&gZp3=icrvefF!oRGJN0OBxHw)v+MXSb7YF^_lkR9yAn5xp?=MJl z6+<5o=qiJ|NxzduJdEGNq6oJ{0*BjS2|I8_utVD6?Vth$vD@?|h7cKCpzRffqg0+= zE-6i9LIFOa@!&XgurKn|b^5QYy&{a_)JhN~f;(bP)Bs>edjM7Wi(+KFH%VS*OyB;;;f>c;qP zl>Rp4t;fnbj09udpo@?#bKKFeRb1EW{jA`9g;b3?A z?Dq8Q_fLNJ7jORTho>Lk9ABSLHm8MpQHz=2$$NzF7rM9-GrXk~J7}1jbl8lIT8VKdHSMLRgY0aOn+@~RVSX~qk6}3~%qHcK`b{c5$5OXp*un64TkC({({Y1;26;Y9Ya@K+K^ zNu&jyWEqU25SsEcG_0U3OGqNCYjViaBVjXS8K$AaOW0GmXN|J^t+`2`6LW$Y9uV#o z+UE$Xe5aHd){Bc?eRI&9wJV)sG9S^xGHr5LRK>$G8j`SxLc~-irm_*44RW+b;Za!* zi(*)iBBC5u0%_gM1;d31wJgG$;IlRBG(>cM2oabZ{uA5Jn?JGD1ggYRFi|M|PE z@16{H+Daq3cFE!pr62JyO3juiW z-JKAYZ42L?7k{`;e>#i2Jx+W&&wP8``24v0?c>qckJsN{%_h}EB`TSWpLX8&-~XlW z-Y=1Rzw+PzH7uQL_g!lb+|CuKOEA<+lQ_pfodG2Y!?OHxfH6QLkSI)~_-4|Yn@U=uo%2#|4=NGNz*#v%e@u^x?ba}>$LQA5)# zMKT0V<8Uh3{nKO?4i=Z+`GEGX@q{xJAV=-=`N6Q3*ODP>(TcpgoIX44k6XcwQQ{x| z?RS6sSI_n~i$8pG_IH2r^277plkLXS%f)x^FP=U-m`uy@yjJWawohm0kB>GFW=9v> zFW=v6><;Sf%y?cqy;vNcj6n#kRqg2qF^+>Oi?6wobZhY7dck5=Ss<*2;@BlJs zg#ZR8dkql6<}?c`02{!kO?t7}AhAqxKFN*xN%+raqx6yoxo!AQ_8U(gO`hLOUfj-J z-cDaVnZ0|y{>|H+A3h!a`1Rqp?{;23?!9?7`1E@A^_%&Jmyu-aeZ`UR)2a zj_Rj-<;Ul}SGTiA$DPM#Jut?{mpiv-!_84<*a-ESkzpr38)v5@xF#g`?OsNMuWzR( z^VIcL>G4i=P&5l+J{uCFhOEnU%#speB@@#MsbD!9hU61a0!ks332=Ue@yWComO6)q zWC}c=4XXhAO2R0`v`kQps&r6*dlPC;JRno>Ux5}t_+gcc+5H1$P<>L95&;l}7*zxl zz_0RgQ%+fdY*^1mv}`z#4Jj#8j7S7fp%hl?3B8#zS}DDm)Y>V%n>Cjsn6Z@PhvWi8 zDacepoZZ3@z@v;SOgmznJ0<$S5+I6#Mr0K zmX}QmMTIH_m?Ahq7jl}A4R8qwignze5CwG!zE#Gv!g^O(#L1y<26YoYr{C^{0XKye zpU;h9K7zzZ3a9N62(}O?mVyv03Be&8Mc5}51LqZO4`iloODu;sgDfC2%cwl339K%# zhQQo)TGna%WHcGK#d#tkk}=47N*ULp8{N#jof_9;gL1f=4>r!sb)$Rmdu7x*u+Bc7P9zEJvUsMa(fG&GQ>Y+eA$jAA5 zF3_n28wEJ235mH+qrVJlo=!b@xY>MsHh+1u`|5W8$)m0FqsjJqv(-qX5=t=07$$9n zcq=R#L5`JBKk0D$A2@vXT;2z8@mO@(&1R4Ar(L!oJU`7R{{gVMw4 zzVC8Bpco_;H~PcI!SUwB^}*TI-of$uc+ncp8pC;gvfi3)b>=(W$wsq1Di#~DL?)I< z$72yQY$$LJW-PUmw2~GVlu?0OL(pF%_*Z%aYYh^57!4G~R^5(=UZ|u!PX8YX!S0&^Jov{#z|l3o_W|68yq-1qe8lPSt*s#rmv7AlLcnoS z3t3hwuEm3LR5deZz8;HYR8ev<>47GzVi%Yw{^szVuD$Zq=NZ@TGpb|@nG~77tb&?^{FtP6Bn& zxCizlzodf1VlszGEG;sWNRt9hLUF^vRhq|dxG++E<6azD{<3P&9IY>wL44iOp9BS;`%T*>!nBS z#Gn};G-Lf%d;nVLXF&+#es0*y4*S{BurL{yX4CR~R-Mo5i}mIVE?Cp*a8&9KN?m)j zR;k;!h0q<;Ae}+I)vH#Ug={GmPFSib11@=mnr6#~xUwR^66zjWXK6^l5c0j`-(fDkqZ zjg5YN-l+_#>0CrenM^D|MHTW+2r-q5NPI{DCvYaq23an|i%TH{GlrGYOjxfZtXeWy zjs@}|5rmM^@w9>GEq^hLjY{I)AauT-I-f^daZe?9|7sBd9z5SmJ=;m%@c?Y_{g{g&-ER61k?l_gT(d1S|IZMfS@-Y(uDhdv1?U03m#Rmj8Si|K=k0@hlB_cUpXRR{e0<{pNP# z`{%nqzP^0-X!p_X{BYXc=+s7)LL(JR8>$8M1PLdD8!qXN)%&X}_Z({v;bQ9Z`M}jU zL6Uao29Dt+K?(@64nm-La6&+q_@F|CH8y5I87D+ECMbgw`~k+R(H@iY1$iVa`eO=_ z)|tG;=Yw2YqoOh{3p__tG!8a^>l-OD4D5UsXzllrJ_qJrA$=<>wkA=|Z~$vpBI~1E zyAtf=cxWAZpB6eIFB;j zMyOLWKnSgJpp@pySpj&kHOqkw_BYELlgzXqAGSh(g!OTHd!C06!OEl;?*Qhz@j)ln zYek0L*w&(Odf2``A3Qo6yu6*ida`(RJAeHI7_jl(hyCAtbNt==z1L4BU%y#={dV#G z#rV~2@A-B6^^@T@?>4^wxcBY5?GG>4-#nc?zaHIQ^si6ax95X5Pu3w%E{4~~y^H*$L(*Q&9{5j#d_h*`Cy}yEJXOIN@^ml^02480TByn zY$~Dx5-Qm+q?ES63F)v3$G~0hGMVy<%lB&n3~&)m=v*-xsHK7p`23`q42mIz0wIKf zmn!g*iP%CA<96pjDZb7i~M$3+^I-gC1In$P1E!& z!_G6@G{p>~WH*Slbblj&Ldr5$lKgoQ%ZYeirt$$6kWes0NLCZlDwmL%h(HDzRKdNR zZ_S=T(QzMf+($jDH0EV#j3)dZuhZpPb$c9$A1Wo3q6i2<6ZQbGJ0ARTNQNR=ind!D z;DXGGJSPdfNKrCF2RH_VU0Cl#))urJL1sTn(Udz#lMh!=i&BMmH%y0xx+v(Pc%LMkBVp z-F|ejxV~8IZ8jT4(^3)A`wN+R7&oy>R&JGza#o6(ewlv&zd%60$Wgz}#Q1J4x;ZJI z?hmfd=8vzoZm+g3P8WxJ!%jP!PU}{fS2g$+Pz3TST;F93A)Rhy1$Y29aJe5kT@M`2 zub>u3{HrwMRRdHqtpgHTolK=3Pv?wSLV{%SdZixO*l9p^5Bld<>$lGiZl3J#9*j!W zxF};3Gia7U%?uW~M*+8B*Dj*g}W zv+3b*_hPzx)JkSKANmUf{RM`8g`@Xqe2pXBEbd}aj~xtzfWQ*MUZGeLz7YeLMB z!vS6wD3L_q`*N5^r2GLMM8PEtxZrAO%gBYzeALQEL-~lcoC?Xx$HMt&I2Q>4A(BBO zrUyc*9Fzo|=XeIbKa|1X8X83iyWI7l9yjcKzuN`-e|ZSlM*(Qz=fHvB@c``Cz=2M` zJv|gK$uCp5&QW2RPn$|Uq*Y>CJz+GHMk{5sGe$RS_OfOxLfHwEkWQ2yCi!_@-Kv`V z&B%7eJZOf``pK(N_R%;8xg2JW+tJ;s*$mS;#cntbGftCus9-BH`cQ;A19u99hbMd- z;e$Uih5HE{#qFV({-y8{1oPUlr*^VMXb;`AM{h3kr2~>1^Lq$;cr<(kgeCnPg{my0 za*V<FwG3S4YpU*Ut~S z^M10D79s(+#@*NX2XWm~h!LY&c-~GeI*>FhXYJ$|kgy!C08|)tlA|spHSVX!gUo1< z9`usEPGZnYkH@9Sv@%~b*4LX$Ei}fn+GtXRi(s>zYjq3VLAf`oK{|tKqf;u?v$=92 zku;54V$TWI1#Zl ziDTf?00}-P?sZ_U7600OWc4e|`9Q?IQI)TzBI9~#tKZljlxNLMI~&f2q?kg51Uw{= zQ8>s0VoDFhR4FV9HWfH7$O$1)ipXkI4OkKzQMkAvr^8w-<+qvy~uofQTq0x^7VP`!%5@a zQT@B?+4nc|AD?Xf_W9nQzdZQu^Mmhhw%(nLpY61crqzvhrjrZif?P=O%Y>8l*}cDf ztG~j1PN-6FI8bq%Wm!Q~cv0p>l?N>doXnG&%)vg3m`cQy?0IPvZ~~#2H@Th#TBxAXt{Uw-(9fA!HGdV4wg>py$({PD)lM*a9;`0C}!?d{Rw(Y(?rR=cIc z>%-fR&#qrTI=|k#x;;ERT@z1q=c>0nVfS}&dMw-2_eTZ__S zlG~W1Pj@SCZ|C2?Tt8i;UmSPdKN`=P(R7fG1V~+GBo-4{MBy=ArYwz%2E`;4>v1EW z43^R%NHJyQVtOJd+f52ADiU4+cSFDlVVO!>QYmTHGNDQ;n2V@MQ;g|+L}kJX9aY(c z#@kW(IMmH5msI(bE~P?RI;=xL2ysJ7m~twpq=ItNl!`Gu7m_nUaTy_N@{mGEs>QWo zMjxgFy@b+^3U!OE7-TVk=M@xEGN_74mkqk4Q-uJLSMhv+C}?EKpevS8w&c9VB?QzW zT^6wdkf>YqBp2AOhxVJ+ZauhFR@U>vJj*Py%w~bxEsF;=<)|SZH^ig5v|kan^Xz(( zoJ6r<2pgFGwuUuSe^s_y5=s(Ql*y6`-#pag~EcSwNxfVVq$qHx-<6vj|+{tzrpaSY9~ zoWS#In?4&i$j8}*P=Z!5iJI}R#F=k!m~B#E+oWpJ9)I#dUQH{aPI4|b@%jBekJs&XJHS!P=}GfW|03^&`E-k>nFMUKZ$qfS|6^2OL>);_u1I=$RJIGbGq-QV=UtIULcPhE8q^Z7Gkgt`ZxuhNs3DFRlh|{f>ae7{T@oJt; z1!U0|H0XF#OvYsp!m_#G_tpQhvRme75ByUBPT0edmm@yyg2rw-u=A4;pf>y>gq5Wb z?DtB&z&qD{pWlHYP*=j&|5*rL)Q>4a-AqOU@t_n{jkF0u(4suatT5afFZx8g0fEvj z$_Oz=gbc>$NJ>oPv|=sM8#FuJI-Cn21i#0Lc_FK~_aWrxW`Tbk`>6=-KbY+3Zo3!a zCK1^3!0&Y9E*f`3HGJRg{1t(b*-W83DwH|_UPFKVfc9a*;pWE9*~#>9Iz1ZgUCwq6 z>Y*4;()T!Fg=1D(YL&s)NCbYE6%O+*vlN0oxyKhF*z=vCOC;ca+P*cS%$*Qudzw^O z0W;WafGYq)3U=cm0f7~X!DPk{Hc(kiJS5_8wKps={g-~k%f zSu!ZH5mk)q_SAA2%gBU`(}miTM7e37heN$G;nNvBB2y`y z&jp22M6SgHt+dh21;-hAlokg`z87af2%QMki!s9_H%W{0th8Cu_G-bSX85ENz33+% zjndbn^yMIV(ogTT5{t6cP0A&cjERUzITYL>VGfCK1E_#Wa0#`mPg@9xeVw%jDcJM+ zBM{Uc!o2K;{rlX_Ub>u>$c+LOd~hU#8r`_x&EY7J0AK(-kQqv0zKjV2Fvv96jNl0j zJ_o1(D-du3jrhprC~5>wXD@tN1bAQ%7hQJBve(fsazK1;ugB?et+@f)ZpU&qq+j9K z131hT35iGeRxP@-(Y!vNzqsA~_T3re)9b@mkJr!lTZ?|YmK73)*AiF4k~^tmrI^qy z27w2g!~E8$u;^!}-PEuZhoYnhX+`_(_^_8657Ogd2BAX zTZ@hMXi^`Hsvv}RztrxRK?vO;P@&!%*E`*Ey^+foJ8jVF| zww~07<@iRowAHIj8@YBaT8wB=Si}_G64DK}ZzsNf2ZObQ)3ls4m4# zC2py)P#_-G;!!mj52RvJ*dXI3-pNaYvbxjMo@^JMERwIbGH>>CulBPq_A)Pa)6aKO zFLqKdchj%;V7onb`KMtCKM7$!{eH;V2%h+R@ms@h*oJPODOn!Hn{pKw7=_CtZ_S^I7 zw->Fi&sv|(dS9OpzP*}$e?9-<@y3t0o4ZEaeR#C>`h4-^aD1`Z-5u3N z)nqQJMFOnM;xy*<+hlbEsA-1d1xb)pK@Lcwpookn^JYK{21FCCHVV7!R&KvH99HS5 z#zq5FP=pf1X9-AD#^Nd-3s9D!Tc#c~3`5lvK>{Jbu|U`jd?=g<3`qzarOI5;lw;8V z+#NF+vtCQJv(m{V{ny`|{lnkC|Mtc9#X;+DfBW?PtHa&R+Wt=G_GahV)1$-VMYW!; z^(y-pdsnY-E?+;sd2{{Z?bXS}W~mmdG!ol;{iDaTdd-^8iW~Fdpd0J8 z!W+}v#Yykk&HTyLSeQC4-YztQ7;9{ zUJDBSaJ#Bk^HOEW12DkBRt1Cr5}5Vv4oDz`X+OR`N^MRucheb7y3rAsVVE7Z6E+X} zsqIDaXt!~3+`T>@++K~I-He}Jk3a|?-)w&SVdvA^O|Zf1=i{&6ZF~eLJR7}!I{f%* z{{6?DA3p7Ue6@J}Wc=!O^x@^kr`JFQ0K?Ar9}hpjKY06W{mI4P;-GQ5Q$63UUG6on zP6o%jjqUZ)e4H6~BkRNX^-=SOSDP=-+TXv}dVe))=K@g`jT@|`2~e$?0mf7rL!mT@ z)IMnFzo;ri+F^Dl{Tfz5t8ZvBikOAyJI$^=!D3vI-z` zLyRbNEMN;E9^m5&8&lZ0$|eH<2D@vM-G*QVl9rkT8-xOBh@~V9F=NRo)8;`wtP~?k zJ|t!A2QM&?T95%73{vVStqqcDD*l4ST^abf~6%tBqiY~ zg~{oB(cm)*6=hr@axKm}bBeca5u+5hD5wVw^ROA*tE$^2ajU@Z6orGTd^0kyhsL9x zanTN()a3o5u$gA&ae5LV20^lG;7yIFsdz=fiwaqgiL69qM7*%nLMcF(G^VIA*#MK0 z2>X!{tUo|`1t?vJA~Fdm8bAJtZnl+vA>Tif1U9XLMT#jLu;Oi^BJ{Sj1v{AcQdMiwpj= zLKIE58B<1u(0U`a)y|G;@pe8~&1j{xT1YFIl$1;ekvMCH?VcS03$qi#RSTC*QnhHs zAY={GO)`~HyWPy*cIWbJez?^dwBnfvV+c--U5%>VLX>G{l~ztI#`u_y8lu~hz4^E> z>1ECi2G&x}ai^a*w1Ww!0v|Oo2qbb=8Gav*b!s$Ul6nVIh_J(KXp{{_SUpTBCdP>#Uh+o5 zd^WAuTGnVQKHtlfT6`$wskfE0%hvuuqg>L0I+lv5)na7%rWou*5rmM=(4C&Py_>I; z!Xoc6G$IxeY#}V$3Y;JWJIiK-r53&j;g4Gw{)0fpZ}%^O!VvYr{lo2rYR0+ZT@L-U zCo*zAgn$tIJ_qJ^q6mEEs{J4d6kfXh-esGE!{vj$>GpcP2p>@NctlTzm4vP(jd;P5 zLr@VrIMF4mn5r`Y6AlQ<1hdAdP?C*j)oj^nbaJC{r&vl;1h%&F0E&JRaTDG(%zY34 zXU8G@kr3=H%Ml1R65Id`zx%%5<;7e);bq+JU#+hEi6HQ`daXAurz46(QW)T*E`c4Wqo zXgeaMbCkxC0fvCUiow&C$c7am8j#YK4phj6gN3M7jD-rZP(EtqBESYSVOeoA7&Yv{ z%|Th!1W{qQyD3vCdypdvB?RiZn>x|wb9ucEj|YldID%ZTlkG#yo(jp~gt*|iT8?W+ z+^e|H#b9oMLV!A^L`HQ!ZI5r$S~0$p5PC^zkX8n1d61I&@G{PJW6U7Ij#I)cBQA2% zW>MX%>c_3nMK5;Qk3AZtKnoXx@~gM*YDiF9t zEuFy9D$6XLKuO>PinJRRmQ+}_B*6Z~NF2xQd1U+qiV~Q;0!V=^IA)he@Y0@$$!9;n z0j_vHk9!%H$9>=HdEkYm`#$Dh5m;Zy;PNS>QH~#N_aB`?S#a>pn~U$>U443S{N!xD zH>*rq@lsq!n?zE>5;~R*QPs5EuZAYA#H^cM46^e?VcQd|@{!OlFPIv^E@9`=e@aSOG9}`lVjKVs}I8SK8gu9Tj2; zLpMZGqB)-AID+NKFS#3OXHVh>PC!Z0Pg8J%BSe8#W!})FkfBB`Eo`c$!s`;NG6Wc# zaId0{2maN2{*`-#^MQi9Egs8SN-G;3*K_k$Y1%9fs+o2nkqSz2`yEO)q%dKHiP$q8 zaS@e+mr(VFRN9_LMP)3FvrH)zl*3^q8V$t4a?}#CQMnJGYQzsavCB#RdYF1LNk7}j zKHtea+sQoN&AKy`{APW`K<7b z{j&J^wDR3~Zuy=grR-Edax}7tPO?t?#cpKR)jM=C=2n+xc&97eC%Eet5k8 z`DXF)YVrDHbiLC%UvKWf{w>E-K~bc9xMv0PIT;)g7!vAwMdDRigebD0$h<0X0h!Ze zZ~||t_AHiRU5FUV;ZpDim&u?^nD*>9gsF&@1{e$c^xO<3Ao3DaG9*D`h(HsDJ+xg4 z2c>jU&*wtXh*&Cy#&z>{zy3F$FaFhUpT51Be|~fH+pjNo)@!?)jmI~;&t9A!94}hK zYQC1QWW9@Hvkw;gNMtZGTG6atNk31`h> zoSQ>^4?<`}y7eFkp;gg<2a8e4=D}upa|$O~Y_y!?Xwr+p_N{4l*}3S;#@Qe_?ZeB| z`Z%}0Sv}itUmo|aPI`|{d)MdvM`!KlkH_y`Ej9+&5P;l=aaWDryt(T-#i_? zdNO?beDd|1br8aLA9g;zT7Ua&`tJGc<>S$^8`AcVUmySQ>FC4D&3Dh%Up}7RoOZ4b zn@`VruO3a#_FG%i+|gcReVT1o1A~TsbKLryZ%hzQb3|Z zhG6Nie`!@DWDbP{1Om>Zm?@fuWH>8ll8Uij;ULJFBm_wnx zA(>2?LN2V7;yR=l3FO0S#uO7O8-=@oL?u)vqw^V4iWzcDm!fv7xR|okY(&pR^raAl zqybkpF&9#b(Jv2E%UM#!6d=U_UNNX$DX*@4($h zz3K<92gc37yzZG7E&aGE@8!j1h6VNLB)zPR*?K987)H;tgI4c zjV$Tl1S+S|nE(|Naf3l*`w5|Ir01bMF*oX_F%OM<3AoEHXT13G3?skCParsh+rxT9 zhTxgI#sokDZa+7{76N4pf&1y=Yri)`-;Gb;7?GvynWw|hU6QXr?EkLiNbgY?GyQN?`3A-EB1(zwh<3X}f zG}ou4K5@B3P|uyZvIPS7`UrkWN3{A7#h05+I?|&$c?b z?w|-a#CE4xsb;dNm}LZjZ-4}!Z_Vpn@%mOgz6U=4imZ|8yw#spwvR>!=d)dVI@Hd1 zvkp#}Z#IV0Qoon6y99SL*$``R?ren1Mfp@r2rXwa4Fnl0Dw>uktCXn;aH^(rN`DdF zIx4h>nw4;ss@%bG<@luCX-6U7SMpq;xXpr%k zm`*CcSW4h0B;1w$|9=SqAOSpZyB!Y1 zm1H7mK2^|*^=Nlgo=m%us18+~Ed9P~>|71&`Rn8MjnAv_LOa7`q2i85rUifjy65(h8mCs|+hq zG>?;vAE$gM;YBdF4|RDE*t0J0s>i?LMpj(jhfdFm(*=REb`6x^a^6kUV2?}jIp7E( zaSxo}szjLqHlv~igRF(vR$S_()nP^*0u@psIAM_B261)}XNGZloM2{Yb|WwDmeu{L zc3jubn#N@}bTf=Uou+SRxyychw{Fb~YA4PW4Ll|Lf{aVW9*Wqigs(}YJwq$hJ@#K7 zUm^|u?5LmcBLwnu06%vBBRlY`*>l3)O$+PCJz!Bc>GhC4pn^S76-dB-anBz$Q}z&X2{=ud?)h7%ZuqZnbY02{D7E!@TLLw;UI5#;VU&2Vq<*}ab*dR-6w zo>dBUa+EJ>2)TsOuV?la-P^P656{lNef{X$*Owok+cO{?%qru0w2}~$1{Tx&X^Skz zg=$9WRzjmzV$w-X`pTR0yl_M}bUtiK zrL;A!CO0~TqfX|upTFv7ult$naq4D0@pvQkWGnr2JM(Ni4Y851n|ZaDwfh|b67Gbs zpSDLWA7t*D5$@U$>_&rSzK{Sguv7tP!EROfsVCB>6PpL$oY?~pY#!WYDFhn~cQYp0 zy^MZ8K4A%iB^B(^%%yLR@}EzN-<_5rpHE8P9+y5Jm%cl#e1BH`?yU0TMeT>n%J&!L z&lkn-E(_mZmA-#e_9R zS0UYgtAaKpCa7@XfEdx0sIG=JC8&zJ$SE8d(&a=%j|AmNP|T%`axoGO^TmAdaFM?~ zY<#?3{Q1YzKmT<8XJ0=$*{sjUrR$50m#;3)9_{rejY7LP-kE?69=&;b{`~Rz^V|K4 zy-q)qFPXhT_Vj#qcr>(m0JrmYywi%!r-eZ;*{GW1e(Gqi_4Io2`uWbQr&~aUPA6V( zgsatHwQAPvX^Vo@irJ`Hoo1w3)PM)IlHRF@p{!rn!+g`jR;*VKHOqDvqhUJ?0NCFs z9d1{57KPa$F<8!A1SGI$E}CY)3`kf$Rm~PcKQZpaH^%wHt@_1b_tEL#=4^ObJ)eH_cJuT5?Qh?0ef?$=^6B-) z`xkQ%!n`>==9}YBueV;_j3KWcPhk1xcJ}e<`kR~S(ROuvmOI?3O^3;DUEdtX z-`-CC_VdZ(gUaK*>dUk4plU?|s41aPc0fXg7}PjjrWGjqK?p1gHyXIb!2QJnjca_= zkW%45F&V1mV)c9ioKQ$uaZ@y9Lgf&N@<3$Ltx%pIk0mrV7m~{{t(Gt#g^*%DSWP72 zGMU!7Y*0!rI~T=tF}|G6C}j^tP% zEs#kLO)=gKhm;k6+hV3kX}26aYsYU!*(bByqe0-ZZzJJRUw=FZ-VUsrUhuMMoL1HS zyu6j>=W%uvqIyB1Z4gZzuLZD*;;+cQvg9pGzLE@I76l|!bh2pwFmy(x;t~p>Dg&AL528%f1o7(r>pXAfz9qv1OI8?4Zms#PZ?HHVIgk;y9FH zFqS2N3Oq+cDZOl106{P`Au*)NQ5r{@903Wjc!sf(@v=SW4_PCc?QD<2>9uP$cS z*Bh6Y^ZkR~Y+kOnV(FY3jVa-fX_>mNDU!&sa689*J`jRy1>*JEeVsk-hhEPLiaJ>q zHGr4NV6m9Ul>+I!lE{ehw2;h5`I6D>CZ>z(?m_?Ld~xw;>+EuCcYoX)l+)QzKx1eI z0U<0O6=UDGDVk7KDU%JiJEi`}p3$f~$aDv(-pF>sV3He5@`G`{H_CSh`7S7;St%DX z(Xg({EJGvM@^N4w1h@CT8@Weuo?uj{wo|k1_U_4K?{vC#G+5v7PSy+Kd9K@y4mz=E zKiSL$Ox^*1pL$NqB;`n$HSNb!2v$@Hg*8nVHCYTuVkpAYdMXHEydH_AeYq07xsyFP z?Tm)0M2wAw#Bx3Y_r4Sm9k5pofsukyBoZf5NyXHOP>_yCg=9kh=Y{Z7+rmE)r^n^? zxjoJ7zsr%DMoOE5TpRE=rlOVjI!aR2t0^o#Z1|#wBmjH>98%`5dB`aYi$LD z0L3?)PK5g&>HW_X0`6PIeek7xeg}`aS(obY7*Nc-w$%5f-hG|5r~U7#ffX9*vHI8pDa z&%HvS2#x(T0s&$p0U=Qz;rCL@dF7YSG_~6hAn*xyieL$ZhmdxJKhlCN1eGVi1|S5R z3a|nZ2%8Fm-M=U(aUq3=STYy18yTqpgDVuO(rAFjbe0J6R7B?DnwSo%xsVP>$cK!4 z*eph@QZ!VIh6@oZ8!{7y77M6RRShe$DT)D>lSrD!2*!_6K7{aq<`IVvUGw_amb2Od z2$tQB+zyZ1>2^7Rly0ZT11GS34tqVT2x9AzB0NFL8D{MZQ+7EMMLi5&;I>v4fZ?eQU~kG2CVej4>-UN7$R;lAZK1^a=tcTPYF zKMqF={!?r!_&hXXHz|Cf!m{^~L{rP99U08PEk|Th6ayhi`+3BK-J6tz01{9X1r;o( zTUxI8F$Bf^7zu2ut}+z)x&ZOL>oX-+!D)1Ard zo1<@DU;pW+n;+j_et3HD_;|82DRs(LF3QFYJQDE7bSxca%4wxri!27&t!a64S^_GJ z0ST={uay{dQlnmWGRRMd_Jb70!@_8gAO1dt(Wp2EGt8>g!>xqLnmPXHAZSz!f{<^_`HDPExMbrGmQ*bic(5RybF5}}vj z;CSXKL*-*ZEfq17mJS7_Df0oImPm|pt&z@EeCRG>d zHYh$Cy>8i& zff7Iq61Nlr4*?+n4E9v_c8CG+BB_U7f;<@Mfh(XMm~ z{mtR^o5!~wUtYd?eERg!{?+MdqhG89o9)E*Zu|ITv{;9OGudv%`n}X-lv~V-m6AT_ z#CNx9m#4!QPqtn^+c`aGR|-nA8Libr)vDEKgj=m>yA^FVLiK8}UNK8K1(49LS%X$| z)QOMUu|YG^tA#r7jmlcLX3YBW-Sy(}PVHc;vNg@#VPMb-fe?TPTeBRjz{|Ta39uZr z!t+6DcTqaqZ#_Bz7}&WvAKYFJo?ee%J)OOHGI@SGdiHqm?Dj7Gr?=fFH=S3v!%wf* zfB3Zb~Z{O{_d%n0m?>;(dJi8ive7W)C zhr{n)?c5wS&-R;_hwb?&)o+KlW*PXLPcJvVf3<$Pp1Rs9f)FOnNWvto0AZPusS6+k zLuKp+1m3>01VmDkD7dr0jpmCMc*2zFh%ThT38_#$7jKo)m24!J&{JVKs&he!&{zbJ zAmc6tcNvT?rci~D+)P=mOsE>ua;A`m+C^hhI=6iKA&@|Yq9CCQF>U!s1WV3E0(KW8 zOU{O5FvfC5W66H#a!3X$RD*m4s(+n^R86)S5qrr1*kF>g=B4Pg5E-P6W<)9(bY3O$ zs$G{?f?Ux68z>n?&L~nw7PE?wQ-r+27gR2<&^Zy$@Mwm0=LKI~!$xrdkZ{pU-A)TH zH{-W6>(Rit>}ijB#^Zr?I}G3UBRAdfX;nWe1@`mmRz{j9xM73=C$tQ_siRfJSCKp= z(OnWfCCOU?B&b*+K-i-rG&&2vzDh+TdoZy=`s_|eh=cO3k=`}J>x3eQL_H+x#qG9x zx7P|!hBJw*HiJBWg3dENg+!M znyM($1l+TI4v2p_?+Ea~<-G57-1B%Il7v^0=}<^XW|Uk}FIKF4$xLOHSW--+|*25&ECb;&hGxS1HX1uWqChAVgycs5SFtcdU%mYrmb2d)$V0`!(4Ba zZTFJRP7J6pniVFC(r{V?Ikej8ZmZJo)LN}lJ{J#~KpBvR!;h_Dgv0H-=k)yAi#-rj zER{FA-xdoywKzY=K^ErcY11^I0L2lAmhpl3yizK}`>PA4o4u{X>a(TVL1X~EHSTGldi-8yoXmN!%XjbruG9s#&s1X5+ zu@YP~E5~v|qA2IOD&1$`VjTdmQbNQ@a*NQ!_uy>X6-2cxO0@UsVvgUXDeQO+W z!|D1Hl3XiPgVW7QxtU>P_94&+3)VV&r!P*oFSn*A-R;Mt&67?JpzZ%P;lIz*PRhSR z`&UK63&pq2kp|CL5+4poF++(MvZV={OiMh*GYDLkz!D- z+MfWiCrc*%cQc>DDRB2Vg}ZrCMH+`l3uJXv5jJtIP35$4Av*$u7N99gN?`Dl&M(btNURvp;q)t-oB)E2*8^x(< zf|w=AMVj8u^M_USq5~K1*v%+$GfrJk($|yB^U3-`+XWp;n^=;DeQ^q?AXmg%c&k|45iRzFx>Wl{h;eF!>1wmvem+7 z33>+!4DLTO z<8FG=&rS!q*{A@Sj`GVCW|PulT3*a68;ja}(E=n)CXMm9Zs*HNV>qhK=bh=aJs4D* z&3v&KPbSS^P?SW1g;Rj>QH+I_!py`;oIz z>|&a@oF*R4lQ)ah?MC|9R`%si?$ur%knrXpZ$EU|e(rMKp0nuCp34YUzD!|ccRGS( z-a_^>AC^-a{Xy~{j|-npinb6=zVssk4E)^P=#B(;8@~wQ%Xnpb$ntVVquSR;wND4t zPX`sqH;3iVN0rY?uV1y zcgOkfj`E+6^4}bRF^XTGR3RUZ8y`;dp!H$$>PK1M@W-cp*#-|&#K?E zhWVTn?iEbD&tdWMCY-H z%BCzCbk`_E%W0#MH5yQSq~%PM-B~X`yIDWlsdZ}l{(9-pzrFs;@18)7vOOw4zdgFW zIT%cv`Bt{O(cOP?^7!lLk3T%WdH?L}_I$iKskE}~PHcCtb#XD7&x`e%Rjr!cPHZyH zPRF@UE83_A&yM<6=i{e0>o1?~oE`Rx8L60+OXXm>5(FUt6}sJIzXz_cKe<{mss*iC zF?)?Lz@Xm<_o~5e#q5;yRx!}42f+hi0I&gMd!C;S65xSJHwxPqqtsmk0>Gf(1Ym?f z4tFbi^TO$F{raT$7;JFXzdr5VocEtT8oqood;4Jz zJbBz(wiwv?{C@X0-yFgcYyg2RfA-z!Z$F=a6W%&K%{PsT^H_@kZj+egFoeli#3qb6fnvZirCjaMa7 zOGwJ#(|`w4TrP!d&?bSMpm>*@ zCFMg(F%oD*wR%LYSW-DCKq{743(Jj&{rJv)IylOQ$NBIm7wV>;@3Kaf8Y0Tt=m%A{nHS0Ol5kW8;7~V&#yo`I<@c_+-S*gAKjwuy zhkc)*aFQnN0S63y_Yb29h&{5I`O^D{!RXgfiBDJy@@TL7kx45k#$#GIB#Q!6rE5O#iqEs+ zaXoN3?m1S!a<1Kj>J)=N9f{~BA4}-@Vx(A(W%E`np@gDBBo0ncEA?n^SlHa@o?UL- zK0SEy?D*_rb2zT%i(y3-m(PbG2>3sVfzS}YTa<`I(x}#x;DqiV*B@md-C?{li1$W` z!8A3TgofU?wT2<6<((C;oXM z{4?>o>^FaX9>kv1a@mFeNI($}2mxXX!Mg@4cS2Yq0Rq(^fXP8JPz0bP;X}O6pM~IX zyJ=O@Z6PEAX-kgjMpBh5j+cC*;=dDu7Ggt5KAuzJ1u0ch%B^T`TAXgQn(Y!!cwB1_ z{ZQq*R&e(!>4960AOI({S3~NHWj`&0kxg5^aJ`&3Bis?!-tm53lw5M z^px>~6F>-ejR`UUgCSM85O9>n(}u`evfZQ*QN^&rg(TJz8L)xD;W~?f6Lbc&fJOu& zCQ(V1&FEr2s1(CmIcij5-~_82vr5rmF%m3h_7s?e z2hK}-Jc`{u>h!wd&{?j45SDXexmNGuaIK(gzlLCIzs4P3QSSRZvZCM)gLZ{DUq-`= zL8cz%yJ=-u(5EG1S~SM_z%Z+f6ZANWErUYlNpdsGZWqM8vT{(fhbx@-<5$!C?MCH# zqkc9m?e;Q@dbFF>GddraD4q1dC7AWBu%1-`amhFmpfHuD6p9oHiiPUj2P!~tub)J4 z8lz}?N>haN`-tV!50pF>W>KGXQrpuCWNTX41OSW*lU`=fN_OGTRgX>vx#@6egE2V4&Uly~4RXVN zb~35YX063~XLGZ+xz%4^?}8Tk{YtBq?{td2UU@jIjmJ%(0xa9@QmK?or$dG*2ok~a zD9zeh-~>#RND0agk>q)Tp;4Oh6POoAJtXeq8A6qyQc+?dGZ&9%qtQgrFeUgzAK_g= z-S=?sSET>G-~9{J^9$1dOPO1Z2JvbkFzzL{7v+QP#<&o413-d3P~nexuoS`_5(-~02N?XJ z5P$?{G?z#ye|-QpsD6J^`~IZ*-Ej$!07Cfjy!69m z{`-sU=Zo}rSLq)ffe_N4A0_|vy!hLT(w|39Bi>_J}_v;UO(FbA&fc^ zsHbmEho9e^JiC}Ly15_TJ-WHt?RSf*e7H8O9^W2czI%M|^z{1elSglEHx9STt#YN2 z+1qPBe!OvVGN@LA`JB>hhKGZ6A8xTFJ(rO#&&TH{!`CnN-oHLN+HIBdY9S*v%0@P) z7K(bM5^OXg?N+SQj<=f8W-ZjHTK#sc*Nk*(RvTadJg5fSHV?FRNm~q)dmAOl-Gh_u zrh}#hJb>-nvmAf{HUbrZ4e;x9Y6b*&0A@JfZ#_Eh-JTC2kI(uyXT8TuA-s5Ow;nvd z9Y4DrJ-GqNG>;EUM+b$=i~6e9BsUOJi6Gg9L>{LyOs0(`r&5r>a_dr<@Tr7+t050k58Jv zdAoJJSA2Qa`S$tx?zB)!DT$B}vXnr84ak(lV*=}kr6$vs&O;1^mN^uJzylAK^Jf4O zfC?hz(|E#C*?36Kr-Jojyjx9os;N#fUQGql|3A|Hv&nHJTh|5e?&=bmA*i7xL4qI& z5TMptYaI+NNQM>}skN-C?%qe|;w_x};D=4^dLEZp3y_k#0w! z7dy!pv&8){eBBOQHB^9vr~L>(!hJV<*9l!U_0y{VDDU2ibE7cXGsw1vH++t&$5wU& z9@riTA>*>6vP&|VQRuXf&-jFdSB$z>MNv6iq3jZF5gn#gpS5+;2DZv3=`a(76=boQ ztaj7N&27g?d{w5HS+z9bNL1a320VDs_ax?(`%e%!f#*byLG3{q6npGp2_O5N5C9K! zC$5W_m$7(Y7pBb`Z!?^ZsE5i0rDi5DZYH-nnO-eg&1?CTCzEhz6LLD`PbQQ|#1+ta zfCN;h-bblA7mP^pxJT7km(%Lx%|02=#=YZC{^D@-;_7g|+pOm`pVLCy{zW8zi5pzI z5^7aKrL;G!QZ9a-BY$!U8<~V_ds18+bl1SN2tA3}U z%bF^2EJosHtND?6^Jk0ck>0qXwtIEJK}?9#M?h<6~k;rCg8n z$JxO+TWf`iRkd8#TD|aKoaqnBzy_6SqTWciJNZU43uL0{PEN29_ruFs2ipbX@)q5`twDmAtoD?37`4fYc2R^=)Zwt97qy}eTX0ts;pF9TKuv{}q%OzQKvMODTuu)Tcp!O6x5{{f zd>}4_((Z6pN|cmxCpz3Nk7l(@He$1bVfhPYMa|9#(<9RKGiCZKiJGSUGXVTg`uFk> zENhr;9cbKP;wSEn2 z#yU1}6KWa-s{rTN6mW|Z>{rSr5>^f~G4@Ty0n7k)A#er8;y6bj0XFc+5+z(5xk3e) zBU<1o+k->~lSSTzVqIutup+3S+&t|SSwIE&HmNR7lU9vsB~&t5gH=f&{XF5OEH26- z(>5=MsUm5(VX+nynw-|X$$*m7l$7qx7-}vQ$cOc8NK5IyxL*nTJi1rb6t_9Qqv!NIcz?vwddZ}iKv`DD+^(vVJw^Mct zN8!vLJ(Wq!hI%KjGM-^{SWT$Rm(}#pT=_w`-2!*xNV}7U9TazQgv?VOfdB`#b2!1{Bo9}XgVk4lqKsnf|+ zs*!Y7HG-mB#u?5`F(!t!u)G~;0Tw=9Bw2xCc?wP-8W0Ng*`g^1HbBB9IgOw{9uLLi zMhLb2;{?u55gVIp|A*D|gWd9z-Tb57^doM0B%*{3S1}bHw`;RrYrEH+b}F56DjSk@ z7amryeArouI@@V^TG0>N(RnYi>?Te@?f9}4TePE#Zfx00oPjadPn`Cm%WmYf7Y3d8 z!xw|_)hK#9iQdoRPq!1#caxwOdq~f>V=s2%FZU9!_LHyoQ*RDdJ(X8No`LWBBcSNd zAfgo>{7;0i@)&$CY`PNMe7M7(Y0Yr+)1rvb;wbasI0IJx*LeYHMF?N!xnGyXuV=+C zr})lwyRQCrRsD8Z{&ZUW0PJyETGdM}ygtgm zI?TO1%D*`&zCW#gyl6Z-Y0M|3Q8ky4lTgjWVtxqqn?$7rIy-FNbfOdX%zH|I^e*9uNe|0v0a?;*z7OP3% z((UcWV%|DDs1Ew^S~bvVMF#yuyBW%7J(-kidzxRKbS{?t7x#N72hD0x1N)=Xh@@i9 zbjFu2Xyvj2DwXtNUM&^WdRcGR!=r9u)wWz~71cJ3d0!>vYUY%2BXlsy9?tS8vZw{d zjoK{x0RTp@ybKcCqZEuVAGAUM39H~D)EEJ_-1BB$xjiZ!^uz6v=WM_D+o#3nw@0_9&C`SYi|fvR z`+EH1y#Ds4|Le=0yAs0<0|ncOW(-%TL_Kzqsr_ z8-gvTi}i%RnF_ShMm?eCbSdJd0)pKT9Wf7+(VPh%pY-!7RZMHntnSVS9Qu)!EOu7jgYIV3q?PjRj`zME$1~ig7{Y6b=CoTl*iAS} z_(bVysJp+z20H>vQ9Q%&0>SYF!;>^eP#j6Y5{j6C1)=uKJO{MEa)1*I58Dt&OFUTQ zv>SFPC*yO0ZNPd3%Ew|p7WXrDFNy@VMx8|5P31MAo7T2!vE5d3T8*@`{&LKfi@1w% zrI7SxVxDNoscWncwN#^IFX`2IUqAr6-0h)6C+2kGejlGr8Qo^#VmXEH^~rvx+ekzL zEJyszU_a_!qLlI1a)DCHn=p8<2=>ok6n>+U_U(^LSI7O^^Xb*q^z3}JTn_j5o6Tk{ z5_WpMr0QqGAy*`%s6JlcFx0=_vSu|uwwfMW&1*LE+WI;&VC@bY&$FuPi6@L~E}AU_ zQ<;Df5{$4IiMx^+rBKm3gY@2E>+EuRb-QzYw|BA}c6zx`M5Z~j&9R1)CYrHRw4J1E z42#JgJ`(d)YN*|EZWxyJK>}{po6%|`TB(EL)q1jAjVoSWa1s<{$1qf2 z-DW{@SZySRMPgFBpFG&BUoHoCXXC}Jk`D_JpQBy$qqw79bg^t7E!z3A>XI#)oUhf0 zC!#LDpH@`H1EU}Js-#D;CX&){klmVAD&H>|p$@+x{Q~T;ycHpLE2R4l0R&kq-Ex9=DHjDTJ&tiXr&Jq8=B+89ADBr>p*Y zKRMY)9VLQcuf_VvvhfHAfiMFhJSH}OA~t@Y%>O|`u$dk^tZTRpbC`MS2C=^JqY?B@ z_T$67pceLS+ITB2h0~4w<|D6P3U166F002qQ^r{NI-Zcd`@0*;)C-0GSEU<1qr z!r~;YsB|Xa0U`vXeI~n zbuvH*x(hgg39LB5%VP@X@UV6dgQT#I2UGxxct}@BXr8q012!l`jC@4T1_2WMNkdD7 z^ms53)zzTt)fCx_91DUZa3TlG5zUYU1|)8?Syw*~bO1kaQXo875rP?=Z^*}BUjN0k z_A_RFjH4QGj~Q%TAWbrFQ{7ZV<>R_k3_I&lsg-c|QgT173{$Rt!r6}t{TSbiFx@ac zh;gHo1SBvk`gbe(ej|L?iZ8l}>p|jXn7kQhF8ayiW^}8dwxUwb&%|7Ih1zuEYa+HO z;wE_8os{EGLO_+KD2ygi5vo5S0e4t{1Ymps26V)3K~<1}89?wAu$yQAJj}!qR`^g5 zDzGGc3h)s;R6s&v7?i+3Gfs*Ii6D{!rbcaxfeKJw1Zb5YVF%f190j1#B#sCHl}|;5 zm>f2X1C8r;>m#fAC-cT%%^N@B)<+%*Pe+wjCAL4U-z+Du?hd}aJ^RP!n{Tfd&(6n3 zlYGCT=ObcR#zL|q?7?DwDi;N!fCt-Kjot0mY+4_W%KdJx(@p~Y}VLP8R`$ z!0|ZC12&Mby)gpK2n@|5LZCTDl0=4~0G?K>!Ic&{;on4gyo47etUS3|)`Ichks|EkK3X)9u)^?b!33 z*o$362nY{Qs&NMNCn13T7d-fW@cYg0raw#`2mv_?Rxw2&m?J_!clfha0_wyJ4+KI0 zeLT*7J_a^Gc<}i+^W`M>ZBh7&(iL(a7TFKW+{d#5;KAD^ph)uLBK_qw_w52f!tXb= z->$3QuBu-zDqqekAD5-KC;3-Lx!1?}cZ)LU)luQue&+dc?Q(+|?@fMQ) zT0RJbkcmm1s&RhOyuTV9ZfCbg@#R^6GAkDHYO5A~{q*G9+q-@(olFGE<>cOSws?Me zaCdz2>TLPuqO;vhRAc2vdTZ8REXF5CjZQ0EF8TVs*mRufcVn%3u-ynvN15x3(fp_d zc(6As6|>%4O0E>tOk9F_sbo~Dp=vD*gpkjxxvaNXP@C0Yw;Am>qd*9~TCiUWb}M=_ z=LJF-RQ01tZhw+}C{hI0f4iyy20R28!NCVAfDr`0?bdZTez;vYJE~tTTDQyQ)k*E* zxB`%Hd)B(Y>^{Bj-CuVB60XmimuL0UMP+_m1VXsFXg<3izIZXdzwg6+UfvEsPp>*p zF4`*+IQaT@A12RldcX!RZhLQ^jlaIz13h>f?k`)<&YO3~<>OK8aGHAmbnE?#-Niv^ z+6x|TC0^b3{`LLdv(xIkoBr45v+Z6o5flP`#;>`65PTla@8wmm023etw@5fShsfGN z$W6Vkqlot0Q0VeIj39#bnJCFd8DVE22Nf+{p3N-wDmQ0S4roAQ8Kak&-} zfe>gE!5NIBiM53H5>EuX>Bi%gd5h$=y zWE6LV2SmycNqF@DYu8z;&RD~uE#qVBanGP&OsbJdH9V|@nt7v<(~D_;E}^92o_I_S zMCfhaiL`emC6;tY5>g`L zsno;ctaSUb59qG}?(;GhS;X8m&yTohy_Qp|IEO=2;de3HT$eKnSLd&5g%vcI;=T z+nP$cx5s%Pgxix|E9Z{~2q1)N(bsAQ_x8)ni++Ec_NiF8s?Vn7e8y)Od>|yLI`7j+ ze}I-1tE%DYl#6=l4W141x-L?pl@LP9Dm{s%La z!ES>GSuG9|0t7RTJ7}692s1T(rC_sV`o_R&g!^M{>UL^6`jNY;}mDY-_VIZRLY>#afF?P1N< zU#y#t9p()n1QH-&MF@=bmw&SU|5yDxgkU$XVb*mN>TO}In*^{;DwWt-#5yyV%kNw> zxd=9pZwyYZo{bmN?Tg)`=acDGIa&774wJ+5h;vvOFdwZJ5p#$R2WPP|W;1OzaW)HV zmSAF{1(dOJl$j#daqKbg0G8Nv;$|0RRd`I3n6Ot&1msN67uVb{54aeG!zI#!x&_Jh*oMiz z0poYsHcXcFP4oK3`r7)Mbye^f#jT+$0go{|EQ=PA$6QV-Ak$Glm(rbuu&WaDG~(`N zLhdA7-Q+5>Il^_Kd?zY&VnQeG?5E^W&bL+4_p92n>N;V*xGNW+gD!`M-VpIM9$yzJlf>F(VTA`21|#w$P^eWfiKG7j26%wmD8L5Pn#~S# z%x+$ls58U=4Y#fnmS0HABg(qQz(Tqe;we-*h-Oaomh!CcACj zYWfLifyURIti|ufUEGsgr z6P+Rf4^W&IY9C0zc?0Ai06Y*t5xhV+;me{3s_Kda{QvFmUUSc_sWLfxpHXY_) zHc6A6wP0?N4!K>qpjM9fN+G44bZ=FRgJ$rkWgNBiqlS7=_Z>IYMaNingY&k248Ll| zP5>3UiDfUj?8QL<3Fn{zjFF2$-ezB>Y&KKFhln8U$0D~bSf{|`MRA$(6f__Qc|{(}&Z8v#H9AmPC;ag=&D zPrRQeKFpJ-8Nx~G(@E;{N#^rO7VzNnN%8BV{Ap4BFfYG5DZiap-!AH}7mb%EwO1$E z*YoV#W&ZtH@#97L^HufBb^Y5-W z+N*i%)x3STSDz0u<5I95m$Molc2gQ}b7CgO{D?NM@piM!5SkalDyKAu*O4tghtot;^}TJ~2;zR@r-?8Vy6 z;Gi2j*eze44X)2e&+c~ShplQ!OUIp=gbS322<5!LTnSaG;YuY~EC%v9709GoHd?h% zrx9rbCjcJQL%pieDQlgge^@j22C3zCX?u`-a1H<-00WFV5x@Y@Ls-!RGd$b@jvUPL zfI!!$-Rouh?zC~ctY0r`x2N?d=RgRZdocR1+P4?2n~Ub@N%{C7e|%UtKdn8v>%VwD zeg1rWch`UUWV9lL;hU$EPp@`9zutZOZ1Nn?;dD~4%dO9Ec7PL}UbXMe z8~2yZ`?LD}N#(^^^TV^**VlU&^ZKBrx67WLLFmb8?enwY?Q#As5W6oR~gLGYQN(dtH@d<*5>9N zsEU!7F9elVDmchThxzCr7w)72#efuc+P%b@%l?yO`_Y3x(m4xCko7X=)@ z(n?`DqY8iuDV0z8K|)#+GXW_ZkYI#)+E8Kl$-p*bs43m|Knpp;TMYRdalIbX%0W+F zb7uVl5JD*+RdkTEop6o{5@?unbyGqu%$5zhtg{uJuZ5hgsN9ISYeBfDSkk$Y&Z1u# zY$eE5f;5s&6#Vvr*HZOc`w{A>;JWGrUr%GN#?j{k{b|>C*YeypU3YEw)1Lf%pj@^6 zr*+>+*|VQ>%~HZB#`S_^QzL6WysY3Q52}lrbCFqz$T+F2MCV*=-p%J_KIh@GGM8{O z5s?UR4h1*?+XTaawyv?bnL)*l%p`0yHrQ)G77$^xQly!t%rtGI83)bc6idO%Nvw*Z z;w+5FnLu$2%`pt>S3`3g#UqgdM@a(X;%O&KC@i6gOwh@MfD<@Orz}Cn7UnEb!Jc$u z1(j_@-J^V9R*j5nv0*vV$m`{lFPHRYQ@(WC7f*V_QMX6slmPDyI6;akdcbyvb4lT0 z-B#Rq#1Lzx@b;v#IP5PE`&)xzF7EM3cE8hVc<^|DDf73Lbv zz-*RXo^~!S2IuF)#iF~rQ|oopU=VA5E}-$cCc$~D$ea^43ler@R4K<|Cd?)rOx+DI zX~F2VnZOW{6~+hxCn%|`Kb`Z%)9z4I(8EkDDHW@MRyRJ~%^u84^Rw3Z_2}$sJlpML zb3qxbBGQgwHk2kvpaSp=OMsypj(YQ@aI=$c_fo}%ztq%folvtMZ4ZDPQjJcs+DMdZ z@lK~wE~k?5h_3ovqCjDU-E6aNSRH1^+WHS0rXQS~wUE?yhn4xX)+>hdV8fKub|cVk z1-5rGXV>kW!<-SZmusG#opiMp{Oe5_2IhC8v#KNh>3V05etN) zeg$AVs|LcnsF*`3cCwcT01J9?L%||`DyGr@J|X;ZTN5VMu^5 zV1tJ!BftY-DVu%MV%g`it#gdz_i<*Q@Om!`aQ&pKY6K012c8z9;L1>1QAW z&i?qHtpER2{|+Hw){T|GoTF_f0>iL!xqNVusE--W&8}@KoRnyew@;tE7#>e{F85Df zPW#J@p5zJ324-3p35>N{8H+`503l$!)yCUavfDTe^-bdl3rCt+%EZu{Aas5D4><{w z8#sY;_~FYh(P2ec6@GTY7*crMh1wswNQ;1Nunw>kaRwtE1gL;$fgo0%ga=_L*BKFl zW92#kLco9!P=E$S0wkf{<BCiwH3Hy`k=)7ZWtac7nR11@N&EI{CxQ7>E3Uz7Qeqd`*?f!=$E7dx@~3(I{c-ipQSJ3{Gf&x z)v^G3y)3*vD}A`EegQ(bYyEcL{q0HnPe^!kl6!TWeRY(1d6<5-o4((MG52D>`1+{& z^0@K*uzt5&yF__Dg}qjGT#i*@THGtDJSCHMCuS8LHW9N490psp3=5hE^`i*so>D!{kL<_XuDJfDBY=FUhG_5>`r^tY)sqR8{OP4 zmrv%$Pv`TO%gNO&HOOY_kzg^ZF*$$$sxxRg!0VO}Wepj=+fX8k}26~Kc=wA+jVBs9x&D}|6aZm+9xLlyTw{Uv}$^X9B}f7bYTH~iQ4 z2fx2Rety|I-pLKydavf4^^J?e{Ohac<$n78-SGFf}YiG;fyms>G+BjTzC#j?Q_b*2!Y3jqpL4zbmU zP>*mGgDUuJdG}^f-e~#FgCMpjI_g_w<)V99#$iq63s)ywPS za%5PIb&A1C4!+lFF5^#SwPf0F#1u8;QUXr5D!BcE$M5uNF2CmXt8OoBuWn5BlCiL> zQHdUI!&hT+IBWD9iB!lLa5+?`H6&xXu+&KVOHp^iN9m$P5!ZcwQ!35%`jNxK^66>! z?5w|B^pB4^+gsIIC6-S4gStxtxLsB3^~!?CQ50@-*m$d%Hf=iA*DUL6zzFMBn+Yd3 zXvU)W$xu{EWtB|co6N|Ogb6b5H-3qe>2t95N-^C!}=uDa+<*xN`4nrXe3k=sSJ*EYIceQP^$dfhmf=VK|X zSQTfpXshYT<$bk!VS8sd+v!wlNniuF+u`$4x+cI|5sRv!pb{`-r$oln-cUjULhywh zv%^xq76C9YWJgHB!#?7l2?6B|Bdu=!A)tl-8(B~gh|O%a0Up?Fc7niYngBuoL(O7c z16$33n;e+=fe_4=O{>*x2Xh6-8Q$Vn2*00`T_i=Atft2{^BTa?x@nV?M1LY4F6Ojs z+!IGWgh0}-XpA>Nt06uRa~cULl5wR<-b!1qc7ubh+-$d2EQK)pn$`TX9bjW~4QzDE zx~;KBa{34i7xSnU>@12x!%KitZ(%y7^@I8PM2ILQlZ8*y2! zk4|=$&#p!%!@aBB#q+K9UQ*FX%)9~5z~K(sZl$bN*5TkW3?$&VlOzP-D9lRR&6H!4 z!b~(_W+)3sTb-n1CA&!21p*Ml!ebT=GjR@+ld{Pi?w1%t5m84;O^*0o2JERW7R+%M zLpf>Gjf=zWC@leX@3L{YjVBx;g^Lsh0vZ)a#~-r8&4;E6tM&^I%@#0z1qsgYBH%ee z5>2=nQsyXyXHfG5kjQ!^U;{yQi>fU8f#_VkPvR7j0XzV@a4`hP!&5#dtGNY0g^GE)*M6(Qqd?Dx!Lz%z? zeAjG94$y|lgnB8U*rN@UqhQ%sow#f3a3Z1R8ymR8!~jGwc7?ZVE-LC}QW{?fI%`pP zE8*#-y@RZ;msUCnxgB#gqf#fzPh!MYoZ3!tdpYr-C?8jSCk<`hGM1h2`7m`c%AAjL zi$Qw785#PTC?;W)Vi(CZell@P4j3S|DK*@zC)AHABNOn35E7 z0wB*j?bx7f8>DTMfHT$#Bho{XI*;3(6b|pd2i|`UHM#S0w3~$^*u$GFtrF8k8ZjOV zuL5rqZh!DvASNM^;{w>gZa3is;DHq<0OQRBVJ2b3O@w0|HVoYM2)F)>S$@LJKatj- zB*ql>ag}sn)XXe)JFjjJ-#=Y^d3FBj<=N}IgKJbQHQy`*vJq!o0|3M00jda~RqzjL z!ErM(ZO3-{$!VuBZsvxKOuv@y)l&U>df3d4I{9g@IO!I~-TbJR15}s{3$saSHYsn7 zOE8~K%adt&FwA$l>2@d8>E*ipe79fh^a`jQTd!1W<@1$PA`>=Z0k7_n6cNCH7D!HF zkVJ|RNSecG7DIx?mBrzG;26>+ihhrx`?a9oFhIUg$RGB*6%jDmYNgDZtYw2Y{luGp zPPlEuoO)0Xp0q-Xc4&!Q2gYenKkLCHaMDtbnt{V+_^25QW%Mu}XFi-DNIsj{e zY4+*;@4&I<8krRy!3HieScDUb6k0KRDE?^dwE=caa4PET7J7My`C3d&GRt6 zT^8S;RX$zRK3~?q-Lybot{R`==0)wxW&P7x<=vwA>L~l-AoF}LbHAOs+e+R|llMEh z7l-B7C(XCZ&f8`0d8(@P5W3Mxxt$LO5!HFZA0KO)#o$!5; zF|Cjd7jofTS_4AZ8Wk^>!|Su*;;{PccJlxIf4_hKa(6PVZ0)ueXWR3|Y%r)5i-~5d zc>V0+=Ec?gesOqzvU9yx->$`Kk#bfZmQBgUoUfEu3jhNdFN~RloX`7HDLEdOl1XyZC|5pYZ7kq^H{{gru@!az+H{_`uWIKEjcO2+vz|tD8*$`V>Z3SW0(CW#0k`j z6Z~8~=I!N-WpPVIXj<@f6V7%_Y(@EI z7{oO~Y|Wr60kWi$WkV{hybx8xS=0HN#+1Ey!EMTlYjvM_6rqlbuG?PV#WeDAEA(`v zUw7p5hV#1Ry=|*^oxojJzwHDr8tS|x?`5Q|gfIxRZJloT$+AKg-B?Z{Kv^e10+o@- zteeQnMAk#)6gsW2DTRr7n6R7Hoj7U+>e%2M8>}65Q9y!;9d2$qtdH#0M>g9Uaw!v5 zk|AiYl3|HN-IrHYP*EXN=E04y@+8nmzzaMpio7IpBF{K!9Hla|1Q@U?PllX~A&>@Z z570K9wgg#gn6pI%d%{Ij40ksb7?)$yYJ5GQHK7cNPd-^YMuKj;;X_PeL^5iAHm8qomj6*d)qBcrp8w6~E2O5{R{ zU2$!ATA3ybs?Y&T7dWZ7?+!%DF(-I z8(4X!P1EMO$@CbsY5IB7^b(rmS@*|9Z(Hu0j}?I8mpAz$;Ant@s;T93OUp^L3N2diP;>486(XsYlrWeMQ=jwKAcfXoS%ZktL^%J@wgu?LVdq8Ty zDLS!m+#O5Gvd^w)w%J~B){kc*Ovq;ih5few!@6nuf0E5){(q7cxelz4AFrFuX0ZDS zzf;P zmiI+d(NaarWZaQpBp(cA0zMsA4P1{hMnVXs#6(`oRy@67q}>bd?Ur}9E9tn$y7pK5 z#!uMhCT=oercESdsjuPI^?&1m|BDa|SWJKijz0wRhl41c0TwZv8FTz#wfy9hUGu~J z?UQi2W_3`$jm?1`JJ`D)9X_9KEqe#o)6=_Iy&reFF}vA}S*@f4#fATq95AvZzG}z? zzgmevBTy{qu>O+=fZ|cS5E8eF6rwR3z3RR!&<+<*DiRy;O5uPf7WBme?ucIu!jkQx z6ajNmU{-E&*e18iRS*f=DsW}R9smruLjYlRFg+R4%2GCtMwR9T78h7zbv2d}*;QO3 zs;fhBU~W+~k3zmVk>w>$kU9QA9)2a^K`cmh37RabZowzPP1?=j66K_KOSbi~EADOLd7R!d!YPVYfLq(Q!i>Osx*ek?UXWo#i zQEw;V?IwJ^gtwPadT~!L=I%tKPFMu>qs~c6-p%`uD}hBLcv=sfHuS4j@U|DeA4H!H zB2Rk3tET^~;;Dw{jL#NwuKVeqJ;YBQ^0AlM@Ny0i*!PIsND7u-8dwY$2~5N>2?>=U zS{0zcEFb~}CfQJTG`kgLZCf^NR=`wLo`PNFoJf?_O%G|iC&oHnH00?$BUD;^+BBx$B73%Ytl*+`%T%z^v9 zM$9|T1!e_fzY?4`!sp$@%_wm_OkDOO=iShv6Fh1K51Yn8(>Q8}=Dp~mA72dO^M354 z7d`I9=Kc75kX(+^i&1($Oq~pp$G!LwP((kuQUbIbB+iD3i%IHwn!cT7pYG+J9~535 z6<)3M@-X-EAp7zl0|GYqc$`K}kxw!o5gw%8AEw?Pr9T{}Kb)W}&blKHyGeOu;NUDAqQmc`GD;-^L7-7z3U@x!9@eqMTeTzm~LdI+yud~;HU zBkxX%51<0`kITxZ(<+Sb7v&G2W#!|t`suXx`K=}rRWXYZxq z?|*%Wu;%GzqNFSWGPzqp4IN zpVj-F9Gqt7C%wa2`N?Vj|NQ&?|L4EHc(Q1p?2nhndxwYHjZQTfHxjk%(e3i++4M58T2>!b~dREEf?W)GI~}*q|P6SB%CA55~2? z@hEvc%bZUVXZ;{(s~zez!@X8y)Jsf<>2WX7ZG<{Cy<0arRlQmCcdI(E^cf(^L2bEH zT5cDw4(m@&yH}@mK!WSD`t3#Y?y_}z*}4YHeu?nla5ud?DcxMQp56_fJsI8Kjh@^N zpWcn1-%sDX7=3)R_3gv%?;rPneYgGb+359k`^{DR-F4?TAcyCZmuL0!-PFk>ax{$| zPQvGh**Ew7Z|@F2znQ;%e(>`7!JAhn_xHQU$F0dQ(P^lYUhw&O{r!{vyPMwE=hMAG zBB4{df=5HL0XCfKRAf}ATZC1P#{du966JDIB8Sn01vVFkv{5*$Y-W~nxJ25?Qw(Xh zV`i(v42w7NXA-uDZYSKTc!oe(U9`<75;3n(jQZP|(4ZI_mExmfyq^nIBJQM@(%4Ne z`PhU10-T`Wj{>YI=Ef^w_plJ!t|iCCNF(meYeL4yf^sUK3b>O2cPb!*(z+*Wc=IS< zSuI7hyy45~-n{NB8vbHXEr+y9IPjoSK+Aj8g3n*lltwr($^siikD8HrCw$!0w~Nv= zD~u9!KS~ZF^dQ3YLrl+L+B#d+^^#vLc$JdhTQmI4u-Xjys{v=;%cR}bjK@||u}+NJ zt$5D{q1##NZaZ-`jb7K>cNOVbQ+eIf-VF7Z{lJr!a#nGj)FxaKW2pId;{za@9Ejm;q%b&^*HkC~cYLI2J~pK}~!Z z5|&erqXeFIt*#h)B~BArRbT=v6=28!Md%bBq=~eXDJsr($T!V|_e$~oN_tJ!tEmzIJ;Dr?034nyx^ue7cQ%Owip~vt0#-$$w_ZK z$QDv=O}2QMpF?hQUMK4@p^=meQCG-=x#`CWw~+{P-CAgGt294qoh`d(=l!$u-tJ+g z*$pRhPAx+Cf(~EE;SXVoLWrV;qSqacUu?EtES5)R^DidT+Q#N1lW7BXWH@(S9w`vi zqRDU~6N{xnp|}pVJ_b}GD60XvKlWD4Zd#Y9%GwbIRAc08*s&L&6mL9H2yCEbH@t~X5A+e)*`PIr8l zchx7)+k;6ond6NpqlGxX!Kp!KBH)^*bqxB+?U7zc;Zc1Z6f-vd z!-QZqnUG%wY&8ei{+OL49TbfLo0=_a7!C^osu7C_!MtHIp`>Qafm0OicH2}x5z@JU zk8-jmyXhy}=3gx~D-eQ>=Dd+aq*&H6X*n8-0o)qc^D_AhA1-IEKY?U^OgC6j}LE#Qy zLDGSEfC8hR05jdeQWyv(jN_lfgdQS=Kp0D490__zC$RG<)!5-gEe>!OPXs(%Op}s9 zPbTckguPMCrMegwV+TTD?WkC?fLjC{I03mP5Fudp2SNZm03kd;B7hKhhIsHQJP-m{ zR{x|`tYiT_YQ?#f@4SW1Sw^wtzJ)G!-b!$}v z6mwv3%Gp*QkJ)b9u%otfk3gtGf%UP~{utmLl^=s2v(0WL>|iKcc*5eMtqNy1oQ}A{ z6f~|HlA2L>C+_Jdy`z+GnDP#jNg%nhRaQPB%JDJjdU|DvJYwDsGr zfv)fDvc`N99vdEGbH8M(ODroMTm%N+V3WCU*l zPar}NC`^K2z(RAH~-`WlC%OL5V#dz1twt*l(&F6Y&I)U7y4G)tZ>s| zN8j8ZC~Cv2P^qNaYiH+2gBSP5Uq9ab{p-`;K3u(fc6@o<-RdSQDR*4O4YygBHiK?c zQFrw+!TnbLbkaQE>dZ%ty-pGEU|3BJ8`)7aJ8b3p4+2i;m4FboCiNk*{!4>Vc{r|) zrhp2y=~iQFyS2UB24(<4c+hvRLO1`==)O`*#ZzHD?03T{D8k8#Q4C7O<9JGRGHzKE zMcCb7*CQDkgszkcJR`fLd_EZpt8R&L38d;l^%H|KoAq(cxUZY=4wBw!#=l!o4=eh- z5m>f^7yZcfD0VT7opd9>1`m*M+zHQnF(8EHFtHpa&&KH`P(d$#*ohvrBQOFR9QPCR zesbPRtP}?=da>moemYE?kKz~O#NBoVAmQ0Qa6;|{Xg>o+_Vc~ebCj-tkl@3L6Mzr^ z4AA5x`)Qs-7_i8FoTIL4KntikDiFd0B*1Tv5g~k;=e{oTUzhnW%fgpM;eim|pA7Gu)&)nF!XaU!W{q!KA+XTT{eHaZvTGM zg~_MW3LwY3)pMd}I4QmX@PPlzUiSHJ<^d8w?~W^&<+ID}>*JFbmpeB{^__O6oh`M~v*W?pVlJWUz8Weh2#C~C1Ar<8}Q)y zJy5~;*^}|pyAcq=vnP{ZKOg-1Y47vf+56|CmpAPvi}D=+-jn`+{e1M_z8rsgGPpY` z-W-DpI|F^On|yQM`|xu7=IP|c?d-*qofppzp55=ApAGi*D%;b{?liSLD89Mryu0hY zzG#1YzI8OoWFvgYPsPF>T@yVnN|s2slLRnWu>t86aGrHAq=hCe51R{3SOF4Xi*Y*{ zfCP?qfH44egVkT8;H` zdO7R@PSAO?2Y=+W{2-eDB3b_msF3iGjks@8iUKE0%CSy5P%@;1OvZd-GT_P>9#B$s zMHMmP5mKtV5cJg(!FmF~BTx+ba{(o*dh!7;&;o*lpi$L>wP2_o(rO{K9+X;9&p4~> zR@IX>V!zX_anew?bJ8%zbb>_Jpax-X6mzvA;ksdzHGjb?=M(?~v8=h9VNWmNZv^?W zO65G3w0k4(H8;cftmwWNg`e$Z-%Vq0`T-z>+p2V3ao*PD`?mKa@WIE@@({6LhWlFisX}2XUJ2DRavVP~ll zn$0Tb%i;Cua5l)qe0DeSlb`uHE?bIWp_cYnl1e%(`kfY$`q?9Fq@v=mmpDFb93IsH z5-zTXC(HI^Cs*qjse((7Q;J~^Mv9!YjM zh+nLZpK)@7Vm2}IM?u=uLqa;ImaDNk*!S&Rvklu>u3AsGyRgTVkw2lCDpw<=O1NAL z15O0vn#(6LPJ)$404Leca}v(GFfAnMVOKok?~hAYw|h5F_D5UAcuH>fQ~gn<)%7|i3FoMvyIHV+r&!8BH?>(P|#H&{gjP7sZd6pXkN@V=#ehQax~Sfd_1*pB8Bj`~8kJgR906%PQZdxhU6O4unr9d|0iH5>CJ)AStFs+6NJ;sJoVk|4= zDoVEEX?KIW`-R24-D}4cm&3aDqkZFN++-##76M)f41GihkFftZA%F!+J5Y?#zfi=Z zaxr>+x!>E0=n1=xl1Z+YZ=4=IJJ`P7+P&y4p3V+V`_YsKFcG&~NenDAu=^j1U?Mg^ z;UBmim9;_EDoQN{Lin?TGT7xbn2ac+0AFPugL(H*o(POQltq9NjtM)6C2TBV{ZkCe za5aI+s7g%8=ZpuGWYCui`O_ga>~kqR>7p?a9%45!Hedz-2Af1VTwuA16flNB!4p~- z44JANX%i^S$-t}I;dMD2L&*#TA&?|koT!iv%}6wfw8~g;G1RJ~0vM^Q3Op!*;UNiu z@uPaFJd8dki*7m@&B^$9(!*db(&nPQ6;-Rb}iFt0-2HrA0#!3IL*j;)r55=g6W z`!A-=pRAid+08$b)}J|IU1rUigoV9SLgTVQXC=+#00SK$fucxQh(QENVgyQkvBM8AgVnq$ zg0zX-O#JE-7YVBq-bs|JK%ra(f%l1``yrwE`)5SBSlq>6PTD4r=&By<+#rgukhqz| zEV#pj+s&BWL}0Lyqmz?d6`#dyHoL`QTXi_MSvKvq$EZ@OchBe7i_zYw*enF%I;#ujkYtPd$b3j_X8hxNY_Fd?+N#XA zYr`h0eT0gl_S55jde}|&+wnm!IU1yg{mh`3?RT^NUUt~eqY|j&@)$HKPsWwWq&gl~ zhNE(SQ0xtgeP9W=IjIiD)mE=uX=F2nSR|ooK@ZAlcF`P<(~OC2P=W(rTC z&?DLba!L#@kdjCln!A*Z4(r)oCEd*iI~g5Tlod33MkyIIOp04s_kP6(AM{y2dNzo` zcYWClFS?;c7sl`$IH3~)ox-mM@v|Xv5u6U=%Ry}3ivm#`!*BcXm12wUih`E?$Z`-p z?T62Y(W^=Pb}Ml9(=p#e7)?wx!QVpK0X;229;p9Wb~`yZY5O9snx9i_H^{@YPLJfjGE!w zMfZRF?e5FVgEu$huP^t{&-c5-b}Su@Wn#0V*^~Frmru?Y_h$!J$Bk(-RZAAznbE8^ zKc5{Rw%W~Tt>AB$1EWrC(2Z7#-eS%(KWYFTJip()xtt7p$xPA}4e{BOr;zglBowkL z5JIB{co1*YV!4#msAypBcUzH0)j))h_ZPE1Fl*8gp;6TKN7<{x#b=P@% zUb{c7zPfIGeKGmh5BndV4#Cz3-ONk#o#gF#6+q(4`|YsU;`HR7s??5uG1Ld03%@&1s>Q;Hai#wu;SS$5}*Qb!Y+%nCi5;9 zqpgo^kN<*i{NThlgEEr~Da~wXQqOF+^PoXFQA=nkRnSGdj6dehKe!z~yB)u%^k&jS z)uYNVAKa=$x608;F`V-82``uO3)z6H7*Z-xe>vjM>vGyJWi>gkd-A$cFucW}uN3ry zkUzojm2`h4s5PQSCmHG_gUy()9`Q6HzzNP_M%k|!$F0a&FTU(V53Bkt>lwzyeuVFV z5g+$-Vsb0ust3hNfGep?$xl~QrlxbPkk~Nzil54R92u82>#|n-z`#>-LY z)j0Hgr~?(8*QC>`c-fMl^!@k4z-?bUZ+VYOuB{~1HL#XuYxr$V)lu`=QN1I#B`aAn zPD@6zWnJ*hc*;el-BixIDt6=%qAnEwfp1=YIaIC;H9QQy71njd6y>cn6jteY^6&PM*1(9`%h!Z>lqlm0u zU^S7`1U) zBa*5LJ|E{-c{Lzvx~K+tSs?|<#))R9%W4GqW;4Dx?%v<-UM~mZPBLY%F6tN7_JhKk zvJt6Qi!=&)NF`nDnv;Fx_gK>jX)?;}?vxgb_SMzs=5}&+(c9X|m#Y3?gmSwrfdCbW zIDYwWE17K@6pMQ`cO((a7Q)$r5l?xIu&C;6AjGD! zO1%{sO>;-{_T}x?&6Az0+wJYWTCoxe1bM+}#mUDQ{+MB{Hpe5AMo6tlkdS+o5{LsI~QcH4)E-w6NmQM7N(;G{I*`UU+BxjMIaA z{B$Di>kab<$K9R%X1N~j3^F~`#W_%KIy-%3_aJq7(>%ZF9iP^xyM=l;nklJ?oX=-4 zz$&q%ClYhTVs3Z`0vb~;>X-9IDea8uSSn0qfXT`# zMb-Tkf%ZCCpTq$qfHW7UySRYFsv-@X;N=J)1ewO%lmjHwgqNdqml#&uan+j)AP2&O zvPLLl1k-vD5kf$Z2LiD`AQI3(K9AeumLy3O1dai~LcJC277V42Y&zh~bD$pUcH4%{ zy1DAbwrN5Ycuku>TQ+~RZURjH1vCGZvi_BG{Olwixv6y@XO6gtxQ8z2&RSIIr2KS;i*{3eU?N1I)HUHChoUH;*8J2V0r8GZbv$fTmUw z1pruxl~$)BB3K{<5KZ6|4%<0~+2DwsW9<}aCa?`41k2_Rn`?iunSNx+4aG$SRjyM@ zoF5Hd-yi?>@#eq&{^Gy=?d5OpFJIp5?)P%Nyq*bgy3^w4H-m0_4p1Sl4Qi47N%3gA zdN`}>ZIx!D9N1^wX0+XibefTVCpGBhK!696QE6*h1py=s2gMQG+^QqZ8q;ZgG^qk1 zbo)qWSQv2@ITlFNH3)<%XE{jP#xi!< zNd;9`A*MBQ(P<^I)6C4u(P_chDg?H2J|KjCj025Q!Za)Gmc0jc?Wn2GJ3-(Cpasyf zADwr@Cx8LnFwDi>J5Z*sr^*=7WI?TO2&I2m^5oLrTkpK*U1VCW)0||UNuK^OkO+W<% z6-T*O2ibS?;^*_~my6ohOF#wWSorm-_4T6p8F518^(xTl)d4&wJk`p9aN2x#Qhjw) zd3!zkaJT#RX6N1UmR3N zod|G3tD=to$W#VG*cqix4{B#e_4C8}Vy|+#UwwdttCQB{N%MNyxLVdP=GEn4@nkP| zw3|8E%Px1Dq=) z5(p=cyPb?Iu`ZEbfq?_8e~yCX#fsTB9|*x}GXo*m9mso$$~nLigqcMKQ=F(oo&wLn z*d@~BBsKvOBw|xxtZ^S#iL1j(a;uq}wQ|#Xx|a`^Bc8az1UR$H_LE@xi|qJ0C|I(7 zrW$tlGTN*Xn^cpXY`7HhrZs2MC!|#=Z+I$EwHng^5)z7-_PYQQ$|1EH(Lt54hUVcw zJz~@&dNURPLKtL>emVfwe?7$4f^0j=_mk3g!F$pSo%a&w-S|m8xRdja5>hvzG$XD? z$k~iYotPWc2#F;>m3G;RKB5+2ffG6rsT~q)0j8*6S;?AqntK7uVVb^adEabB-tWX; zOpNQc=e*$pU3I)b2-jWpyrnMd%3;y7ofbziwi_gy0lelX%8H{P+jA~!MzW*0BMD1N z1d^Lgd$_b$OnaU1-;B69L!|sH=B4bEeS@%~&}+iBNrOePGEp30qOGl)%_y7H?r>lL z3KRuMKy!!$K=eaq0uOVJ;W?V8QS=cIgun^{Bl5J9|9+v+$1^I=1b9~GS%YW80v+P1 zAdBfVaDpYo*%B_IpmFuEdsGUI%i%#K)G6vU!19!mOL+1be<>e`MigC_{3_~}p!is? zpY^G%SEapv%A??t%PL8hfS;(9^vjdp)2rF(USn7bNByLL|Kw)YbdMt+mum&BlJ&=e ztXte*sUN)_OFHQs3=&62_0zNN>3R2f(cC+%%ytWzj1q|mDm=fJ@c9_v6R(eBIBa9{ zC$nW86-Gfd6cHzEm=Pp6NDIYbK23-wlypwZ6$7cPKNJ-LAtoFXQdzm)j!d_U2gl9D z+35Ugx;&rm?6=Cbs9)mjnU3Keg@mMAr{#d;=Li0DzT-;j)$Hx&1(L8mXk$v#T*V2YoFzogYoR_bBEgUNQK zH;gn|Qg7e`LO8!}EH0XR$EEFq^7divVA0v1_mVjuYG8*NM-Zw;10jS%VlLzBH}y!s zuE`rAzcs2m{&xrg40{w4zOk`kv1|e%NG_h`NR#=o&A#ct%pj}n;R^0!D=H&Jy4{i% zAOkuX3bG-cQQUUY{>Zukgn)7tOc>$x>!EBuRLJ|2@nBYu6~mFVWW?D}N{AOc*{Z+V z(Lw!D?Ci38bks=3T)6E=+xpMg<|D#vAuU#vwvT)WYnbI1%<>;31dGY+uw$^OS*<_% zywu))WwGoe3z{H12tf(N$D@P0gS*A}ba(z_bpB%29Ty}w5XvuL@q^vZk|=fv*)bEOCsp;d6};$0ullj`Ui_>ZyBws>ddZ`Dc$)LI!hB9~ zMA&r=|H)_n(PjTd#MUHY!$n)%tj)>c0^?x5a{>s5Wg4X>U=Ea>u)+pl1`Nkg`%I8^ z6GXum%5G&HHV$*}1n%KkH$pfPhjC`C%?Tr|M>j){(N$@Rqj=Txu_WNw>?fy`q5!0)^CC(7wa|RgI01f$Zn1DTcg5sSU`EqioyuDT1nKibz8(Uko z@uWILnF*!-xYAqYCxE)ca;INvb_(@ou3AgQ6Pgi{6(27+ahkP}w1uKAG-HD~kOR#+ zIMxBiO~5B+BfeTL(kp<%(@Jc+7T>N$w#&v=Nt@=qY%&|DEb5# zu*`l1oo2tCW`6}Ov)>lEZ;R}=6({_mRm2erIx51WJ{)I3A5Y*(kXPaTNe(y!EdDpg zh!Y;%2uSlHavC7l0Ro1P%krnQ%IC8xj3}%KIUL~5`FHRP@Fy)xpU)}?6)x)EE}IXW z@aeSn?xg(Y5Fn)VVNnA-_;lKU2|&X8dF9WAdOC=`}+D7`)V5;9yoc+Ntdfb3-^@ zP&;|wtR21DtG>AyeR;Y6>E+(@>%qlw^=OtIw}PFjf7CMer|Gl9>g7q}?5K8nSUo>( zT+UmUfCr2A^`djVY+oGLE>S;(>T!`_Hc*nj3WAJRN>` zIsN>0`|G=%FYmTLzM8yyHh6X0d2!WzecSo`a`M~T?KgM5>*K=pN#X1ub9#_@^|bfj z{`LI7{HL?uz8-%4vj6$h?#Fj~Z=TLB7tO74y4wzohKar1;_-g*a63KUO~1ZsK3$fd z&MW`=cJKPA4ulZ!I5aN{grI9KAOuBbQPVUxIB%=>lkl@y^llWm?0Qcd(xN89c+rw?y58HK z|Dq`$6}VXf8-*NwooZ`%U2#-oYtd!POSY`jo)#S`!4VgTq?1g#__QphJ+74EPRg#h z+ZA(3szAC)3u{>;H+~^EAJY~S2W!6FL7~R{Hf&Xz#g0J1j`kXgLKq-&u(_gsY63^0 zXj$}e!bVH-4E={Q0VMKBE{<`dOH_=9V-yb2f+n&7f!26bYDwc9hJZ(0L{ee$y4Z*- zgFzYL;;aA0Q)LX45nw<=o_>Fd~+B7N+t=7_;J-yuz*1Ne9%V+7m2yT5ofs?n(fr4vqGmE8VqB52gS>q{^Go~wU-<3 zWcKH^>!(|HFLtY)kQSu%5UY4GczZ)3XUK3yLQ*Os>OR~r+fc?KnRmbF5su^<{umzzu>0F zKnNg|hp-|997P%ZM+w1T%_*E%YR81ALfax!iHV;n(WFh2}qM95FctEIgv*tED zf+CPk3hYbNi;V}~AnhnFg+%oQjIg5&<=7XsKWz8PXq=2nAw6Eu#BFnpgLGRK?|!or+r!VWHwUieXS88)!Pn0!{fq}RiZSCDGfi;YX>l*_J}P?`bq!GAyc0g}MlO1>>tXU{ zl)f4y7p?GC*3%BrWuGJBw0c>yOmB+B2Jd)GW1B2tW@!h{kt|CQs~?051a2n?JN{jO z4m4(_9cDP=Nt=nZnJJs)55b4-;82nY`e*>*WDbYV*CPNq;4YqY@szacedA;a5mi9K z1!^T!3JHgE3=x9Oiq1m}or2!;=MkZH?L}Gq5Ajt|VN(9ThA^mmLFa`s+#JcAC5%$1esE)I0&eps9gi0y=0LhaKan69iN^>4oQj3Mj+~MHwyo zk<)(UY!F52M^Ag=PPRrFEf$#&`)DtwfAb%-o-AcPO|{6m8B$CLCIfB^u5 zv)pfIx!=#x_}eo7>oWH%;)L(|jt7hUx6|U6MgG$~|LFwi0tGC6LUBj=_s4(-D|7#W z4gR$L5hoNL$N@NE1qoGvgpa2cpn~srJIMjJyhrH`58+AW&*#7i4S!V3ggE`{XNjmVeZ4c3JCFRzwqp^{PAk|ukRNB<dbC%vOtWviD05^m;{1}q3w{a}zf z-7P*jYrlUs`}A`6`Bi^!l$f-Gdt+dp+V!FZY_QlXEf1=I1h?nC>(lP4)G5;0Vdea= za&}l=?iJ^|dBB64Mg8T?;QjO2i<=%0!i$^kt0(<;&qhE6pWkeKem(v8YW)8B@bz8y z(=eEe7h)J&r4T};?wKqub=k*`+vUt_Vw`nyRFZkcfb95_~Gr& z-Ff$Tw>Tcer=#T2VRgA^9q$(=z2Kx1c)Bdzo#gLN%Kvz~cZGZiE&F}Qe zti0;144mLo1h0p8J87PA2rMdn0aU=z*y?(O1176nJ3F@Wi8{Xj*Z~jz457qPI~O}F zfG95xo`JE8tV7~(w+IUt{%`^7p{8HZBjlr6yO5YPa$C*(ZaY6H#p-cy#?KnO+2i<8 zH2sU)`d5{F6c((7fB>AZQ%iz|xllc#6f|c}6-$O(4z376bLCW5P6KA})}k5^LNgg? zru>bhuNL!GBc4iFsYQIvnA%C`-IU%r&62WS^=))R_MIGi z*7n^Dw7YTOcHqD2dM?`Ti>7qhcHeY7*KPTtAuTKXVUF913F9!^3(ze;UQ_V0>?lZ% ztkaPe>~S7X@OWHg5)zkmJ5#bNCCe#~C#5K1H>ZoFLff5o6JuT{H`giC2AFFA3A6)8 z&3pk6ELN~%!1zJVY>J>+ie5EXCIyb*SzrSPLxJD}et?AU{sff2K#MHxWNFl4iA7a3 zU^n*(D@cG%U!(%CrSh20+d*NcBk83}A*r2KN2SQL79Url-MrCA`O9g4Ddo>6z3Hes z8WfBG8&GM#O8I;w;DN_S_*B}bF&-c3mN8XhbGg6(l_lt&9`&ZZTt2DzT@E+Dp*YP! zl>|a4q&%spsCsNp_7_FkOoZ81&DfddQLTcL*7;fQblKV8t9IJ4Oj6-6S;5r4T-i)kC7HbF!C!QSlLOk0Ts))?pj%C%fH9 zzaO9N4RuQ*LB<2R2a^-nIPe@oq(hAS-T)7?KwcIQ30lY4-0fGv`0Yu@VNjF1#SklAc z9u`UA2*e4(iW6MCCUHK2hDF3La;g*l3=Z%BXu(YrE(#T0_6e*e@rEpgeR53mCUk!? zsHH-IbVyH!^>hR&6$W6?;)XvO@P;)-^Lo6p+vAd4qJVlf(3Z7G3V zMYTEXe~Px-C}0MMowTpq3&@`Uuf7VCL$406YsT#+0_8JoI#!9|xP8MZ5W41WltZI# zX1?EkcC+{S?fGw?Z@#|2c>Q$$_I$iO%5-XaDeX#xs0UQYCAdb((`#t6esXV^+ZklP zcWZ7XhOPLpl^C=V<6e5@Oh5%v$AkQMSVS&`X?1&6-`=iIx9gKxZM0P#O)Eptq%s(n z`#=kW;uwV_)%wG7tCOqL64`tx8u$4$ffMZ%ZH3iY;4z=VC!<=koE)`_<7TE`N%V^0 zela*K2FE31S_y8~g4=Z%^;rct!M9zKw~O+u;NHqhAeir0y+8uXP7v7OyZYhtUg)eF zJniVqc3{y4LeLL7E4B4MQDMG9g_BP3q=Ql#mR&%L$Y~d~R=5}@uEweJVf<_uyO<=d zx01KB^va)*eRY^!ney2;t3s&%6Cs=&U zJ_9GL^!^070#I<#q6oG=nEvR6PLPWLjVlH~?u#WbKndZ&{NWBcn7m(rfF;n~;QsI= zpH3^E&uU-J8{aOQzu)x!e%Jr)y8Gq4`RTO&`KVHayT$LXk3YYjFLtZldKhf+gWcNcyuUjuAMDlh8KpIA?OvZ8-JKraEPxOW7JHde zs$S1cC++#sGTCF{3sskxJH6%X=FowOP^{MWjwGv^~n79(7I++h<1| z&|0pN&7goP2pb z`TT19;l<$H)6Sc_?yH;5+xz~P*IU26-~I4>bh9X(ALZ`Os<&sAH_rxt|913`-%mb$ z*!l2b=lzG-+jrAG&dQ$$| z>+OsEN+sz+?UO=sDB$#a1&@nyIZ2Q#(H=J|yBH@=vXo8a2$-xY;~_T!5CW>hfqJ(5 zK?wiG2w;t_Ai-t^p+1tRhm4JU2!q5e3}xe43_T%B!e&PUML5g?Y4eJ73~c(i-Y&!^ z_4HOVx82H2D)CmzpH+bqEQ;f2$^3tK?0?mnjkH45Bk~}lPYU62KGaL=t+>A$@{|lW zDsKu3zzD#gR3rX+R4Yg1Qp8zH$gQ*rs8EagD`9UftTv*0D`vD~Mkf*MB?Il4zZr2g zBT_dGNZ{QrYX=SAaVIc`uXZ!ATlS9AQZLSTqhdei?8oGGP^|m8io#SBw&8cS0`9J^ zbabT|1J5aAWp7W;bqVBwGO4lv-ZCk!< z$R~OEAS3O>g-Mw18&pTd>s}0Tg3Fe1Vj0nq6v+h037o(uB_Zi@rrc7@#l&4qRAPfX z<)a*u-NKnSXtSBISXjFQIDxdGzzGKsf(1Sllw1nXfC_X260kIm90&k>NI(ei0iyzl zJOe^SQF#Oj{L0^eP~pLuAh2E$g%YSJaDevngrBwh7^}|Nblw(`u#AtbMLdI?u~mu9 zs_|(#+RSNr#0^chCc}KIqVG;}%SH3*qJMcY zI6kZo2kCNIPbKA0(24p6z^U%zC5dEM8;)q97p;!S2V5x zB&0HdSkf1YxGfK;+fN*wv@ULkM~nJ+Cq3Fp?w*uRE?Tq0LOdgm_qt03>LPp;G@FnaV3RK>wJ{7K@oAabXpjMv{()vZprt1A9FJ z2%{Oh%gw5qI~Zk+2$e{Rxs05QNs1Ft;;)+>U&jjw`98izXh~HvdYXR?3@%*@l~}mvVbhc6>0ADS(24hL(uGd2tBu<Z zB!C3U;i6HKF9|G85_b}qNTB8q5=FWw3YGL>v6XNbA2>nbNF<(8xYcC_iPzm?z$I#u z0Gyz3w9Kr2%YVO{Poy;$XL!Vj&mGg0r0z=@{!B>AMf7~s0A(Y94JsUrYid+gBYt1V z>(yo1?~*(MFL8{>Q1CwE4l8E2*x$dH#!1jKyAQ%$L@d~lXmXF2~Y=iAD9Cuw<{a*dMGI3-R}&fS80zvMYA zdycEhvgtqXs5gV)lS$;+R`hNweKE?ObmFtJ-j2J{ek$aⅅLCf6O}`v)BfQZ?dZ# zJ{omfbKtn$u_}kUDl7bNKNyC%0fSA~27fI4!4}+ZBY;9zMm##rfGSY}I_c(UkPHB} zs!j_NH^;bHIEW?^Lpv!_BvE4x9!@G8;1j6Tj@#^%0|yZ{2Vn<7AQ*yV2!g@@TkIsz z0*TRpF__f`Ul!Av#k^*>nOJH=60L^H7PEoLuml|a`uXDPhpXQ{-+q06{^r@?)v~`k z&NNH@Y>bN=M8Y6aA+nNkb&J}l9^URI4@SBDQGOR_p`V#{Qxi}xJ?^GQ-SiOD%Z>)Q z@1aN2($=gp1#N?>4;pV(hT~FySb%Z7Rh?|r#?va017Jg|lg*dI;ke>*)1pW?SA`nA zGOPQ9c*s-D8og?ASWAp*@o_CSsYS-s@VKmx%KD^YY}JrI;h?S_f*R^U&A(gr?385C zUfFX{^&ZuH#|{4iXrUcA>l)`h<3{y>IV;d#$nfZfP@E5c9bMtbd)@wq%NoFtF816;)K-wPV(7a>LtogNWVMEd^kycMud<7{dV@C z6(O7ze?Kq%?Ysmd%vX?5K!mUaU?~1}R{HgL7vy&_ibP=d=26*PXxL4gPl9|MjW^ z`t7p)`?C07Z2ZfwJn^w|EISF6AgpB$gBt3u!)uK_z_%m@ioA8u#TC)=F)MKTT ztCmx0Id3K7DW~N|K^?c_hqKD*VQYU{gvorbu{>x2EnF`K_ZQQ%!}hG7?pL%<-rdSd z?YwKNrC%Rc-`{&KI@Qlgjd_3?@6^!SO5$ zgmANHzPKK~y`KUhyt)~_z8$=MGWzs<^7ZxX*SDbQ=a<9xPus6=Yp-rv@9zg+UQNHf znE^b!ylLMq%QvUxCztg%&xe2ecJyEV_3XD_k6ynXfB3ZX@$>HUSHtTkt+Qo$xt~8j zF5g^spFNpeU3Pc3Gu@`YRuG0w@4K7k>&x1UMdkOGTW7n)YSNtuu&JmwVz^YF(<^f> zC*|aEkwbFw55YyaB+w6X@|4Ju+^SOF>XHX6Q>zG;RS?SqBdmVVvbMSyw`q4+3Dn5N zf#FuW0|g*}WkA4whiYt6JWX;mi8evZDv)-cNQM1UF6?dPBU_EkUbnE<$<6ACPDabA zjKQ0N%(_NA@?$@1#N!BWE%@0^+&d{owyTLj#%L$N==asaN+l>ixD*fxM0};NREV(U zxY$T}n`vJ&X*3dndeo?egY|H*84b7N(OxPH>L%58TxrJK&8XOliQ}xeTTzZ%`Vzj& z?a*N@uwC$uQ5KW4A9Zy@&W_=1>maG4yW6_ErMl`qv8oHzpiniqa)8cxv5b2&=P}nc zTQ5rP7p04~dff{=8E8)i>P^di)o@-noVP9MuI;&Ls+TqIX-PhY*G=(TQF;(0+X1}c zca#;ZBs+3$A|v4`Cz%wfgh<5&HX*WUH=S`a8JSPZe8RwO9e~C}I^{#I9n(x1QZxl22nteKnbYQ5ht)bG6Fe} zB=927!saXSj4UvUz<323Y!5GotE}BmTQ%AeTqP$IRiPdAPO`!6Qgl=f4a!Eh7-(kw zm84uq$a%yG=xQ=brPXtBR@sv`k zh8pcey%j4|j7lq6ZYJxUOrwkTuTV@*WYk>I&~!eQ@T9Y9B<|L9HWGCK8-P3>hudxQ zDn!VT(kZo6Hio18;=H>!@9Z2EMmvegUTSwn@}gpHN{>4b4&hpGESs7mu0+?beLa;t| zU_eNiN8y2-A_+beV^V3UT=W;RUR4GY`UgY^8*A$p8|U^SLa0?yNIBitKIY?Y1sr3CM&*a`GXK1|Nl=2e?r2agn(mK6ufSE zarx}3mM+k!`=2YAtk!m~7H6-XZk?TOpPxQ?zq55x@OZ&6drUYsNX!I~@SxQd zRuka>WG*A*&bRGh!m`?79KZowha+8%QWg#V7U3H&jpZ>4XU|t zAmnkv5mjUqmRO;JMR1se6)FHBh~$G1A*|d8$diDa38ejx#tYcL5dulBgh`amO*;@C ztegolgTYM~<#5v&Y6ONd7EnjF2TuZUf-Xyj2PCQzhth2scm{wF2Rzm%(3->rWijk? z#Wf{u_~CCZM1d3ZY*@>L)Qq904I`}^DP2!!T152+6^|yn5h^$ZiDv~kJ!t}LXa_1V zYO&hQ7MlrOGqGW28>+ZrLWO)#_Z0Z@n>HSq)*m^{k1*>RWe3}RT_iVU)}l&y*h>Q{ zG{VkK)ICUg#u?u<=bz?ane$FEu5sGckFot2GfHu@thiTlAJ>#+OFi#s7u~?sFm^M| z-OY+mb}P5r<&%DPT-0H6ih4+ux4LMvL~X(c#}a0mu+lj4L6Iu~Agr_k1(HONfa9>u z!oKT(W!>Qbs~v<=7;I)(;sJ-?QMAL#VyKCplO})@&~+WB;FCnZ%jp$)4-de=$!KKV zEYJewq)8EVVZ&jwMm;eohQ?4kdANzTZ}eJLh9pP~c73Y@_7b}V^@_Hm?g|#zQ8s_D zS$@Q9KU4T)CvVYJwwyP1r`4PD+54A^Uq4>`dJ zZSOU9_M1CU`J6tl;BhkoYa<=7T>Rn@Y|(&N z&*{Tje9}m4HRIDpY+MNrA0VM>%&LLis_(F&owSWPs$vv8ZUqkO{{5;KAYr#8?-t!V zMHgtlEFaf>r=7snAbc~9EymILFmf^oANNB?y_FvDpcg(HB|xXc#OWXoY%uRcPFi8m zyd7ELLHc5v212+1PME|mr-_?s>~<^mY&Y?0)o%I2aq81N^JSU-x&%l_|9YDF^)&k% zVu0fB7v;aL^amsqzaf7D!h_#0D!-qX(UCu}0S+QUI4gfXuY5+3P(nU|mFob^{Rg}M z^-=cKVfxiU8pbzAS@;$5HY@-J3V;XjSP($MiYSmT0$}6oMFR-o?Q!wbX$>IZ_nY2t z*WGWI?Qa*&zn@qB+gy!WU_q%Z~lTCWIrq!$K{lk-C zJfk|OwLsW)_2l^C&CLTL>|Y#~dzDB`8%|owqv_G^U^b|rK7IAnsFU96=jt`1RPc6t z(W80e^n7r9+`YZofsG}RaAh;zOj=3AT&cLbm{W^cwN^5K3Ni@~5CTlvwP>#qZ&f0V zoKnvz<+M8=cNUYbPDS4tW)Ej2I5W40*=Y~q>-I1=->u)C4xe4mo?J|>7yYxn@@_ZO z%1Nad)yg>!MzNcd>YKaK*SGus>D%dl|HsvT{oCcYkH_~{owJiN=zLK1F@z{nq=Zv)8xdrx)Efx5E$5rho^(zuW!&{m!p%C!b#o-aTmoA-uou z{|eafW*a!+$yxPgQF?yWe0AS@^R)k8{(kyj{&D*G!_KFVJHP#U{OR-Fn|ISE&wD4Q zg@gUn>0$o%tnuQ0^89|hIH`_?k#^nNt9uTo(XY=3?{8Z#PiudBxplrhNp5-4%i==@I!3<+i=PlF8!%aR>X0O=1%z|aqjsP!zm zT#eg-5HP}ymSLO8284iWrlXaOz%h|yT_TSzKibWhd5yBJJ1MK?Bx9;rj3}+FF{vi@ zJGsMNVXv7Q6@q15NV>5Ax#l+iRowU&kM*w+-ck*@2N``~b8-(lx2(+6B-1l2})3Ft+ke>XjK~&9n z9RY%%FcLUtKiJA$i+StOKqcg_1pW1J5SG=TyAknr5@I*$X~iAYkg@2~RsCcm$n@gI zY0eHO?_LAtCu|hFleD89G_?YTmfzI!o7;YK%V%kbrm9n4vgtAclZN5Ztt*OL*~gbf zI%~(0rsat4(~Nnk?bEKO^=A#o?I>_N5HFg-NyT_r;7-b>%cgkIaGzD3zzMrK^JdC0 ziE_OF(-O&wlPEdxoQ+Id@PrYM>hTDNhd6))GHqoOW-4Z+V0Q^EniWhA|ETO3b_JUj=)eqHJ$|lCjcR6S>#NB9~c0RLJ0{B z%dsLiTZ(wa}rx|N`l2Hwbo%~4V3v8b)OWfT3x>%j^+>v$O7 z-KiWMv=8^&JKMGKu+XSQ{9brF-s3U2-3F(Fw^~`A2g_EW21rn#^8E@FV!yfqhU@ZY z3grsTsLd9}>$67VE`Wqc+#ZhEd_lc8z=z|OT*=$+r6z0jt)1@P;dp0vFq%|Lm8d^x z<_v0;_EVMSGd1>^7Jovqt0oI3`VEP+yI2WVn~6d-n#g)Hg#bW8p%RJ29l@B8&Uxc0 z7jQx*=Zz&D{-7}&u{vFp%gqRO++R$^nOd$SXd0#r=O?u*$SgPs`rY)h2DOIr- z8lGI$K3q@k?$-vRxI+L-{+F2IGg2uhKynob2h$(5OM9wSeyUY`_TN##f0YdM0SQ2; zO_h8h0!)Ub&lSq0V9>Um~LOsr$-0Vs zAOYC;-#Hdg01}c`%V@NW7GnVqP-Rk_Cy7NnWH1L&-*vT|*2rkBoWbNQF4qAbfN%w; zmg}`j1EwM=EQhsD`Bb(drjJj<;s~#xA03Tkt#A#P~Tn5q;sD~Fw zkBTWNrLGG~PK%_|ETl%g!Ek^C+(=<2Mq>sx(BURVt0z?`NNG{8lh#@}3ibbDk*rd3 zvt6%q7&w;+B~?3(tjnZxn{}{s7#JHzSQxF5R0G}sy}$?aTKI_5n)Eu-epkltPWxOL zw=3gBN;{oNyFDrhF~J^lIO8sN*x~eAtZt*p#_P>2i#ipM2xf69Yfi3S046{!N?8DI zkSox!jT~eM6_#YnpUam&Q?7olRVQQ~ZnIPS(aE53Tf zly;I1dYM!Fl9K(LQT$4eJ+;ts3#+CW4kKs{Mo1x|G|4bHMZw315gY?xph%Q`fnzE# z*i}jpJfsDnP{?tGj8rLTwTjWGSxf`RiJ3*5fW+%0U_k3u9#8=w0SE!(ffHcBr&)Au zh@=^uB()fhoEd5m>YomyC2T>`g1`a*a**89C}05B0zAl+vZwNu&(w+~4yFVPS4f3M zo$~44?A^opAHI9_=ik2l^_RD=ZuYMZXX`LnMXg@5+JJp(#6K0y>NHHN1@Ekz+8!6S z#)XYxcG^n~+i}UC0JIQp*Mgl!cs$IE`l&%LIqav#u+OA0n-r&$;&_xF!*W~za_IKb z-F~J&LhglHGZstQGwEO|8Hh$aKCjg-a7H~wldD?gC(6~I6Y5Wmtjuet^KnPN9^V|~ zHhS4nJ=!VwI$2jg=NRPd!@Ofw@ouAbY2oc=V52Iom0as3=UUM*&D+LV%P4Icr%ltW z?!K8u-!n-*Y?_x-Bx(3=HD!Px2nE* zJ2LM^=iSI|H@u5zA$&ZFosXjz)7Zr%axo5GO+wFS!MpYF!)Ey9cI54D{LB61mj~%D z_Of5>=f3Ijv`t@1!?OyTA!^*=>@!fIr{q^LV`<-9EJ^t$L`ObPh6m?V^>4RsxTSuFrY*@_` z29Gu0tF4{Prze}+*L!Qn>xDMVknU1BzPZ`koYcqde5(*{<%6R}a?(ll>d|ycsMiA9 z^ZMRV=is=1csQ!pV}XDX6ph+qQCl=(jYn;nq_dRs=F{#})Rv4`GjV%4E7psFTHcpW zIJ+fpIbqF)^u?H|Q}oQ*(X~#jSB8z2R^HVu`-YA1q!XKV6XSM#(oJkni^ucU-C6hc zxOTLj-0TNH`?L7@JpXXn`TEtyKmO+QZ-0LNkH0zl=H1SVtM2h$ad$Jlx0ODa=k~TU z!?t&Q968x7-JEw`Tn_He`!^?@=O>-J^WMX=-rL*B*N?NWAE#g3^gogG!j{Xo0v9`yX{5TsT?6DUHGhFOflc!o6SXcNzZj2ug17})wB+z5-L<&QUw z7KSubWI{`5Ra&)7B}dT~l)BY^IfdE1M14 zo0-6G3_QPFr_ zvt6|8&lk z&1BBTW^H`Rq6-^Xzm9Y>q=UrGTD49oqhw3?>Qhp&%&28LOsQ3_uCAbRl&i93jYbJD z!0J&T5m+Qr*aH|Y6v0VxMJT6PiaTOxR1FF70mDi+R0)Zp42!rUy-qZ7C^><}9hBNZ zD%~VNf;z-$V+JDWpi4nhC*v7c!jnp*llNERj%-B8gl(CaBN?#=yhg#!n#_dJMw#ub z#l>6Qdb^8rIat9)8ucoRNt=k;$Nj?LZvSL|I2{xNE}dB?qgB5&QcD2`osSBogd^$G zyG^+V7@I1z#v&vfC)DnQ%HduV@l%I-b+Q z1gBCdKnjISillkEDqE5(mQ?B$hSdlT-XF9l(;_GkHoH-KHJvYLh$U^6hPOXXtZ$dL zcB?Qh?H~8nHY@p(-v-};`ct*`b1lA#5ppdi$8Z(LQ=->hEavL%T(KHU=K}xtx9 z4yUueXu^RM7qU6AR0$S}-dxUIDtVJh!Q-Lqf)>69tBH0BoXMp1`3$*|r`ik-W~u3R zZoHWRD|+v=S+4tIDN8)*07A&5eF2{k4LdVAOR?-|bpnG?Y&ecfJ_N~iAldzZ2P?3$ z@Fe^gh4DWKRhdUcPLYEUPI8q>37EhDA(-?!j?!r0k5s5NtElg^W|^cEMlYO`&o=zAf<2nIW^1lW z$6slCM;qzA!$z&?GaBR?bH48%Ev?>sNQA(FU5%SBc?PHYP*i~ znfb8YoN_vHZg)Wxi#{JH>-DDHo`lOCbGi~9G2!(_-0pzWDcS@V>aJii^Ljm_V@O6z zuz-L{4WUqDN@N3rP~4HOX){Rel4kAPa8LLmff=Bu<1YTgn$sv zhN+8b{&J&wJj~DPu~yoh3s`~zZDZw(>Ql|iuaq#8(k!FnNt#u|(WyY?1GNOM)AK+D zzy`1ms36r##ngc87}`RpRg_AJq*jqCC80#g&9p`ZhYCkvdWtYIC;-XI>wpuG5IN|~ z9AX2M^o^607R47a1k4UF3+OlojxWtZxJFCjz$U03NvnCrdcT0iwZhE_$+>#oi0Uiu;j&9mE%-Pqg;(j-B)Q@ddJ)q4Bpn_v9 zkGu+?wY+t$U>lZ%Y1O&W6nDCTy+Pz)7(?nu_j-}-R$#N{U9X56RquAqzf%u@_FCbi zUL5sbYlS4CVyXMx;L#v*I*K4jm_)Cp;hS0Hb}a`?M?o&pkB z>;U9&yAcCCkdhFPUP_N5y4cGCA-vhozd0zv%A$Y5%X$70HD${_?&MK#=G_A5{b~EV z>(Q_8w|?{b;OmFov%}G#o$3zC>)ZY9qmAac>58~%fltTM7?qu}&ov^Xmuw)al7^d$)0XJ~%uXRI3pH1Gk&;`Sg*n z1=t`F6EaCxKI6$IUD2Q^9x@lw?pncL&HGAePdVdh6oUW;=>S)ZnTNID?j*N2&5s+Q zYFa2Kt%aDWl&~}l?qM^$-cJL;jyv&QJ=CcNXPw}|GUiY6rYu{dUP7lf_`=!&v%HeK)dp&V9FC6a{&kt+Yr!Dw%pP%)B z4IZyX@9x&$-><*A8os>jynWvP;;#SZy7_ofefPZahp*PYd$o3d)_8tYd2!abJ*}PY z=H9*-{=@H2zx{ISYtZ|x_g`*)`Q;`M!p-yc!BKwi00^OYec60@)4P4vJl-#DOk<-# z5VSFg>~AJ64~t*j_1;~#-ac#p>D@Mb-^B=OSnIa2W=><|39E?(LV%@U;jAX01=?a{ zQQ0CX>p;pqK#;)E1Q?CToz_t2^KyMW7Q9y1h@e-C{#cJFqWx6N?2klHLli> zS}g%ly_1~>~(Vc-TY27Gbw~? zAt7SMfenm`Um9e;aNtW`og!)>OMc5R7uarP=AGO|EeWVl2pZxZZ855EW?a>TkaQWt zRyJWb7yTj-0^mVC67D3zjcA}8aOAzP-CT>Rb z<|JgL%-6y5zIuy+Y1yN!j%=D;qNrNh?!wbIpLcE^;M1 zmNhBT{1Z^!A)iIrld9ux7`ht-POH|_isiUsI;&YP+s>Q5`=aAKsF*i1%s57M1Dd)= z1CUU5YRgW%AZXJjb&QuM^~waVh;yn0uSpp2q?t)ubt#)MC77aCW5B?FQVAVcO9(jMKHy0Ioi*D6KFFEvzkdsaajJb#<5}>WdC5HHgp8YJ~B^y=W&PMsTCGv7t}ZVxKb0$105#Man2ndg;sq<8(P?aU zIux-dGagVRZu16shnsYGG>MG4*^LY)>9wu$9BAaAyRqHukMgmE%W9_yQm#}zh1bC_ zB}Hi&04^OJj5>3rNV%TKm&5V2C!TZ_N}+N!k}deaxKCx=xty5Exbk_i-%k$)nPO3l zMoeDOAi7L$r`}*tah%*_Q@VXrs$gplLX)lR{J4JkV$vNZ<7sO+V#(+IrD7x=6(b>g zrRHw7{o`qJbGxv!TSkO{d<7o}0SQ*%?vLC5p5!Yi4g)ci43+%>RDg4sVHk_Wq}S^- zS_S-tV8duJK%!Mvr?l88x5)cL=3qh>OfcDkwc8E0n?b*e)yjURQ7mf|h*B|HCwTqA zY$ljZ`!c>{J(+KZlT}ZmWY0IHNjo&h6&pcx~_Q z=;)#+MkuZN6HNXIrG0{HpJJLPxaKKEtWboE#8(OJiWGf>+z5mg)wb6Hgs2p_Mnz~f zB+CBOk{UUPLe0yR45kJ`(2-gWUB_KC#|0h$Fj(k^h6%`Zfbtg5iu8~c^-ox6@gj>p zYaku5kOssN8XlLzffhLf9|{(!cpL=_k;-LSwW`y~4S)(d9E@_G%@6`k@CpgPBkr|_ zU1qP9cjzfI4OAebl}n`T38Px&v$D6Nel z1Rd$+*^ogWHJg%xE$wt<+^(GH$$Py8pFijGrA2QFIKeF@T%MTI6LGjgg2QhW+-95A zWHa$5j^$~RAyIC#R+_jF0e`rPrI4%9wXIc^Y(=@ctXx@w16CnhRmxUjJEl~?LBP|v zMbEmdyw_oh`|a7NyOi?6(AF-6d*x847-;6iddAgBmb_ z-1MEcgQwl_vwrMylD(eg&&Sz$Gty5x3O-%fsx@*njj1%K*T)J4KN(BtIT(%A7=S1y z$1&-o(XjhaB2%?ey8$5nEa*$k)vvjT+~VR``WGO(zT zzENj2au$Q$j6$|Ow;5fW8rPcoU`dTfe)er<=3XWs&C1MC3 z;6uPik*~^@fUnR=2WKduk^#Y5bY$G`88$0NTWhbbkAMB{`5(W1{KGf*?;lT}?T}Lku)UcNxkMh%TaWu@g+sSe{kj=W$0Fw!4v!P5Tm`(>0DQ`6HfdM@jvWXtO zU?ugOlER;8RllM&pPE>i$4Z1eTp{l0S0mGQa;u-)9_H8DiBT=wFZugL@1W!zSA1*r z;8rud)e3I{MU=%+-qFigJ1KJ~YwhQSQOP;0c{f{uola=C7uoB__WQBDZUn6V?Pd_Q zXKn@Ou+j*?a<3BxFxYJRw(lDTd70BLT~1&cSremM}?2dzdg*q z-UmZJ14jS-cKm)T{`kRBkbS+6Ha=`8UckmVyd8i65CR}X0<@rrh1+4_Pmmg}Nrh9T zw#_d#(|4PhhyBL&X7SzS^qUtu-@QJ1|MK|iY^~GHx7xY=XS>_STlsd$myL#ssZ6(C zT^p`l9F3262V1>DD;3N6a^>)Nt$uVk8V!rJLZF)SwJYI4Bi1ShvvHwYkM3+Y5B7WK z&(`)1daX_hCg4y+2!^bYs68HY#N&=c+?h_gK(UY|>^G(&wrbwrEQe}&Uoq(_CY_DE zKOZ(!leTd^csMIu%xk9`#f^4&P;~Z-j$zr=EeOqwrJgo7v$l58)hW3vx;)-)(&PZvEYx*{g@q?RERvY32N+e0|Zl zzwN!eg^y9)--u26{;jp>!EWwwzi>Fu9Bw7f0Shl`?{8XPUUq)>a_w-EN&8s0QRTKW zRvxuUmV5{_uz_IVZD!7-XRIbp&yqj|lB*n*>4POhU@VC*glc253|NX_J<=pt=LID=326;i%S{w;wVo96;8`P*oIH6VPX&f~Y)uPJXFuxcn zm5swaW+vz~*5ck_F}~R@><+3s-O{KOuSQ)dCl|3&qE2bmd~T5c(xUz>Xizt!!g@I} zZzlKJ>CI-Wm-iHc`ly|Z*~y&GR0;|u1Oo!76mV5SVnb@CRtvkTA!jw@s7IWQsJj{R zb)vz3BG`=wnqhaLT zNxeF0BvU3TZR3+xK5Etl^puCi?4-)9S=B3-IK>l2xk9Vtv|2%`Ai6 zt&!uDmgXo*N0BUm0Za)5!IE$gP$+R(YN4=bvZiBEOJ>QRz;m3Q=gpkX!s`T{vGcTp zqg*<|rNcd}7HGjiuDTeR-=K{NOx|a%$K2g)U{H(>%kg@~UyQr+F;^<;h=*)`pV95o z*#ydD!Hg!Y$%NZ%w9CcW?TkUM)-f`(LE{(og{*JfFYIl1VelAtGBLl&$gHy3&#b&0 z4e3dHGGy>ONx>*Lu}{tXvd=|Ui{gBb1KL^R=Po&J-MQHu9-avS~rf}35jl089hc9Swdexo)<`2{Hw6WUs zP1bXJhwbCD@!{!cZL?i%B>h1rZ=h6a`O3=j%E}6y57M`(a<~ksY_M8Sm#c|*$`c4# z6G>O48ckrmzzRw5?I?wZti7%_R;A7(LeA}Kk~r; zC?Ev50U<16jTYGmz*SbO*<{j7J_IF(%W*GP#CiEN)LAlMWYh{;WS)OBTD)Ov9I|ItxvAa~vLSBscd<$7kJ8 zl*6>2DrLXKRZj_p9O);7fGeM1DntlB82x`oKZX_kxN#ABB$utqPM*BPaFSmAIY^|MboV+~WI;a}$GL`)2nw4MRs!stAw5rcRxOR!cfeKLE z5s4vx0!^q$48TBvt3gTv5rWjI3Wfd2NR5orqGpE-1{T}LbYxVn{wIV0Jb(nlA`n0FvszLvSKjB#d3|Y*nDK~dk2mA>WxW2h=u3LMakm(DiC&l2 zWp~-kzzIe@tAmr0!VxEERZ_OX2SSh_K@N}rV1PIQ`50v~`RWQtxw@i(V^6JMa3x2o zZ3fb9)%l%#%xlVo?d7Dami4yszIMSs$l50OzCP3*Z}Y~(gZl!e8SN7j zz3R2%F_9}J9K(8StDgl<*yyIFjp(4{>tvn%f@dmm!g@WhUh}V2eQOo(T16aJ+@rE< zSaOX@u5sBlt$5bzzO7~ewNXPo)FOM`=s`brG>9JpGjzg>X3X2oz*Z};{ZT*&yPd#( zH*nYs91ntLqtLT)_;MP$nuUQ7p09`RHltw2-)|?R_Gf7@#~1z1UL)lYBp|^`?(J^& z?QZ6+RLJ1~kpM6QEI&ZPLO=*FcYz`@i`qvo zrP@c2QlDnjZh1TNd?R(WS-RV+e|5X{?ZfVy=R4LimXcLb;);Yy}FskA4Rawn7S6x@wF;!zh4%-(y)%{UoR`+eRgR=&Zp|hPAnptZ-YpZ9h^_;z3 za!uR*y=nYxp1(e--W*k*pVS^NJFlPjK`(E*4_7VF!B%{05;)mSAJ3D=yQ!DA?Z5u{ z+5h&xzWeuod-0Edy!igx{r7LTUq7rp-cBB_$M;vG7tea{?$*AL2;t#b}RLU(LUHzxD3T+T;D;>RJ70KX-hP z2RwMZ>%Vy%KiqWA_p?ALvti(PFMo5{zP@Ok9~OZSj<*x9&MRMDH{YE%fAcUsnr1S7 z9T0-Y#yZU?xJa-76(GNX&BR#@tbwD<2INEF7y=-HCbWw}-W2{Jm=;7LcczvCT3{r9 zf{tMribU5BFchS$R;mCAB*|4^OneaP76R=;-C6o9*KMum;+0=htefM$8o#7$>=6kpIFU|CIxO8Zl`q ze&aABuGhlrjmW4RXs6xfuqEp?W<_J(Yc2RtrK3vFT@JWFwXmld6I*dFs2OwDBd$i! z+X(sE5q~cZoDk|I{Ozcx9n!iusrmMr{+*gQ$yz#5T^%)8u$8>l zl4vb^Z56MrqkZ{_v9afFoIc^%K20^Uj)wV@-MNpNjio98oHOSI>c}lNJ z^2!*mjdGfViB4K{DVsiJHzou_*sK#dTp$!i^)ie62`hvG_2HqVy0jDy^NSqS15_@n zFr|i2Ybh<@0cxhk(KM12RD?o{7Hyb+fCN^j({UUJGl-r+%{^^83K0TFx;fGVkf6hy zjKWFFoV47{Dt!iRRA6#G3ku)O2K%L0rx>ZGec6~Z8L~ygws6qm_Z!_FPO#HvGXaob zwUADy&gIbAZM4;lTTPhVLik*|QqI3QsUB>1Hpi7lF%vd*jKXB0++I@%s3zr1WQ~C+?G)8+pEexl^JQ1NAD?cNxA)rn zN7LTCqj3iYKw{Cg?>gDNE)WhgQRJgFpd(2Ny<3Om{Ad=f_+}`95jQ+-RMa_ zaWY6A4^lhb(oVOy(aH{r(Mrr2b8&8i+DtF&@y}V!6IT0##glEig}YNZfO=3w-hKh8Z8wxpdFwBN5b3>L?T%9sN;l@v*=k9 z$Cy|O_K@E!x;Tf0wCVvBlsqlx8HJfwdmXxT)LttD zd$stenHn{d{c3nni;Suvq)KpH35=_OX)QFXhu0dxY0W>bc!wp=py(bJ-QzN_gt%7o zt<}7n4gb6yLN$wq@#A6QXb{`)0XCqnYP+2fEax4-gTQXbzb9$G>p$rFkNW=OVeoVm zI-i6urs1o#=<|*E-FEVBJNQm%F)#oy_fK`ed!}_3h?&FAv||Y@P0Q2JKX(5a{%Z7gu}zwT>?i1Rt!9nzN(L z$c%MtwRh*K46-L2Na`gKnZ(4VLqsRz18is~qk3FV5Ew z_6O}|Dw7tYQAaQ=0RAP@-eg)#r9A1BmOS9Z-tN~Qj@u81^^48i*;?vo9NX=OHk#t7Y;R^v)db(jnEPet?lf_> zTRPhB4lHSRB}x98>4-T3J|_Ud`#FMmAzfBmm7 z|NTGi{`POr|Mg#Q|MHicfBy6JpMHPw>u-;~dOLsfu>N>GesM8)xahvRK{bos-w)nC zZ$CUM-Jay`PirrZYp*Wa-@aP=)3*oz@av=Bf3vs9QU2!3t#_}c54XLG)5`H)?&7%o zaNT`*)4O}tcy^FG+K!#>rkyMw)-Se7 z<%rR1R*M4b6*wvVfHU$G$fRcg4`84$=qQHJ@GQyE1WQW2L6H{KIHcaaD!EE2(`u9? zp=DqnR6!rbt5XOPw5T~G%1%H|TS+L$Tfzq93{`@pGJXi@AwPIHM+$j5% z3tx(wRCy2AO1jtUiT!?Iy%ulAfd?!_pQ+$86@BKC-&zUUszFCB?5u}f^{~4h_B0}5 zGwSWcgN?AS9zu6Jaeprr0CnQ-M%Z2tno(&~pS~V4_L9O{QQWEpwyOU1k~m5`yD@7c zV61rc6_mqZsRt}&(Uf!W85^4s*u0Z3d5mSzSafq)2b~s(q!mk9G)1eXB{J(N>v7$G zH3;5}f>#6Yv#$N5X*sC!Cr#6{w(X)LoHcBRWz$ZETaPi*Fwt_W8ctnCalJNaB+?cZ_$2Q%X6%N9g$?qUmsZ(f64xkoiWN%sl$I}pRluTnX_(`d z6!NFQ2};$9N-NhAYJ$cnmSA)g%c1l&ilrIgKu))CBcNiaEKBR)E-(beFf`9li!w*3 zR0&FAra*3~ZGuxOc4Vg%E?N~ZkV%I=@3Xd2zFt1u$psr3UnSwrMs3NUDH&f>vr+L2{sF1GH9$Ot;0q}L)K<3wmGZqZndX_LLu$(IvJjLYGLIb zD-jX-M8FjB@uD5K8RaH!Ip}5cX(vn^^Udbz(fIsiZGS!(bPMHt2yAYbsI%HhgIUWP zG`t>TIWq_l`?o)wPppwWvotPwXwc{HJS3JGh#C7ibTw* zl)YT`HW~p?zaQD$$jxTScFUK`*`pD2G-4^00?Cxa;ikTwMw z7^%0}fe=#lDiA`f5-;}?g-$rv5Q}Y3a}=8GWREYq8`~wTpil!^to}kR`|JloK>7(G z;QteZAeRW?Ljcn9(-j<}V+r4Et2o;%1!GQ}kr{+krG32l?09~^v2!=uyPsWub2yk} z9Uk24#6m8@W!3UJ1uENRuBY1IG>PjSr>rdigimofD!61wam5dtbLuR-P-m`YlN z2a!h;1NP*T?NhXe*Gnh2#X{0Iq%AJ9^I?uR&#h0xP+V)23> zA4L^c!D5qoX=yo9qXS65fmIX?paKTyBIi)Lf)b?1P$mPQg2%)K?WTy^mhd{_qCM=i z_^iCsKv@~BiBuYJIgiPB95rNMQ48l)T7ydTNVSy!8-No~F9p=P0Wpab{zRfyYXAu! z2;nD^H~}?~w&+MJhsqxT55TY@=vljgbr?CPiF24xy22u3!44pSnzi8;8ne>4z>*$= zE?_lC|GSteB45Gf8Ky6wIXjnN%PLoRE(cim`k#n$3q3*+4w) zi>JM@lo(BVq6v32?n=ZYMI7<4-7lJLR@SH|SXxODGM-fm7Ah#3(ott68|cp5M%|0N1f3AD0T9B`FnTyZ zsmTYu@O}?Aq9laeaTKkNqp5>7@T;DobDq{ZE=ga<$i00St{ z2zGvR0L%d7fE)`SIRU@`)}~@3oE2 z-r+Qy4tT=OQnxfaSlc++8qO#Eol&Nh7gPRh&Nt|$w>E0)vr@epN~dhqvai#QH0r@( z!QE_xHa9AJ^Umq<`0QkD*e~WY{zTLji#S6OM>LM`57;k}^rTWEkV7Wr$s|41Vz89; z6;tkf!igF-MQquKH6Im zcQ%Xfbi9L-wVg2x%ECs+ceI%~-7OvO6pnZDC-cJ5b_R5LSbTZi`TEuL>sRBu^YXj9 z)>kk4S4XMq-k^)cKL7rarf{4dH)~(@%Zn5d;IG^zxeYX zZhrs$`FCIJzq*}0UiIJJjlX)FzPsz)ot3W+(|2cuH&>lESKV(PXaDfc!JofB`t_IF zzx`_dr{A9Z=Ih-rUe8{=7(P7j-d!|rpEX|H^xobM?@sH-o2lJt=wv4bl=AAn|8U#A zxolpZ*Dg;>mq+>MCq=-6ub#JF9asPOdgJb(*~&PA0`7NkA-8eiJXKiWZ~QetW)N=_h9%@5?6m+Fa=%2i6a%BW>}TqSU1&~7M1 z#8D-+)h(aQS|`)SUN64}hg{5_5-=yeY*qf!s{Dmr`y`;pN`Big7o3%2vvPE;5*g-v zji{~YGk{8dW7%&l`z>X^Q1;uaLEr=+1YbK5XvO@Es0f76h<@-eNcD~Y9$byEQ1P3} zfB`;3Gi>gsoU@{DqY~UIdp8Qsamv<4K=^H3N+#|=3op2R6ydgZa(MH zXFWV9<6tr-94z}haDrF2o-rTR-Ism;?F8gIZJJIRrn83WylJ^?3zseXdEItgH1B2j zNrV~%u#TwtzzH^0$*L?^u)G-{L6g*LQ$`|Vrn6QiYh|-GHf5ocW;$%3MV7P^8lzgq z$(Km^Q%e4nP%h)DWvyyir9@IHSCsI}YEX4riozI{WOWq9kTimXMWB(6(&7;99f9(gX^n$WIw_Tp(}s*>+Nm!Gg=WIj&H4Lz-~@Lm zE@V+fRAW4B354vT&m!1$dIM%OVm2G?aIkiPMv*o)(qz<_3~JHM!bHogI;B^j;{jtbWDa^5hgrolPXv=963|zR{@JK-Fz=llj`z0v>yuimoyZhi z{;=L^#|>tc2{^<;a6C>@O0{+skO`y!D_Oq0Dg%f@?bQfU&Fcx5$oWI&c*+@1IRasm zOJtoQ?F;D>X-BmY>kadp+nxQx>A~UJ`bNK6%XobbhSdUcXfQcWDse)N6Tk^7z#+hc zT+WwDJ2DwZvFNVXyseghFbHpN@K&q7Lc!f?$7}U)BqoSHy~R%H%@}XS z^k%|fA;VE;A|<9X-h4h#E`^JEe>iN4=hmA6RuM^(5+T^Mm{O}%;-s8m)x1$_wh<0D;|=Pg2_c%}@=akljgBX= zO3CSWQ9Sjz?CB>!2wS?Wa#ZC|+~w#MQ0-Tbq=QL7Wy z@k?seFIDni{zwQi8yZS;mkr#5Q(Hy-`YV88BKd zh=um}a{Kah>uzo9c5?iB{n`6@qZ19sjODzuS#;+TLNH+Vc?}MM(eo;r0#sNALeQ$7 zs+CUw4^Y-7yoE}J1~t^P7ImS5CD`8!Eg<28V5HLkDtz!ENX9)57V1v~Pn1~VL-^2w z7GQs{@1AE;j0S4wHD?PNRmGpr(7I_OKNW~H$B||8Uq}B*? z02sR(1qvn7$n}`gOlhnPwkVkzcA8_NHSQIn9!o&byG^vfVJ2qbLr_SNAY)MQ5-@{` zC#9Cm6i@+jS?F+;4p;vG2?pQ+6nBJ#(h?-0y9`QKFta3Bs7M@bg^@+i*bJ;-VC_bo z1MtAYxvV@0Rvbpg#(nIoz~DB9uo;BbjHhr?*G@CE~`;{X*1ipIzv2mw}Ru0*(aFtb0eehIoMLlz2489%{%Y!=l}TK&7Z%!{Pmmt$7h4n zt-?kpQjOZOUOsHYgJx~iLBaRg$@|vYsrjh1Juc0s)tzZ|*2^_Yp-kKk6G=AdY*fOT zlrNR=rINl>%Ad{z(z#$JAI=mb*-|832qkiW3f@KBQ8MmHCBac?;62?QK& zm&s@#X-ZDvt2#<<;x#UTNrY_qgu7J?4(jo7GdXU=2enAA6zmlI!;*JY20ZWsD$HuZ zSuHTF`X`7JJd?5;2w|-Xa)UPO;%+B^*g(=@Z?O_Og!KU|7YZ(PGzcCIVHtvzbHdR zp>8L=J*#ZZ%Dr~HkagyBj&?Hy6Ja`SgXL^i*x&D*9FI;f3Ml=+RfyR^^{jW&O1-?8JwNO{+eR4(r)&AM zwaoc?=4LzhuwQw7Tm?NImhbiomz$}Bad^AqoezSCv-tj6YIiNYzX4#7Kb{x%HqO_Wts37ytSn*Z=mPxBvR@ zxBvRL7ytIRhyVE7tN;AhH~;?ESO4L6k_yl^YONSch!D;-h2CE^yTB^>z6Yigqy?i{xrHj z3tt{)UR+e}uA5iqm8F&^ z)HH>0I!e!>$W9n8NL&l%K8zSzHOfa&DddZ?YzpL7kV>VZ6laiH^Pw>_VhM>5Fc{DP zL{I>dT0yGhlv+-yWQ1awkS{UHB{QXtISi$Uds0p8_KL^j>iM*KJSuM2!;P>xZdSVR zCnotP2H7W8^;40RXI=VH-oM+)>~>OXgs`_B602cX z6ObSk=%oD3xLAw0YGK&l)rpH;uxJyWcHGsB*lPhx*=Gb=Xhnox(zRJ~&8zNt)w5M{ z&oV+UW@!ZUHNUAIFiU%y^KL`R&L!+@%Ee_xL(Xf=`HV%;RCXA17A9p>gNlNx?I+hW zhSRq5ZW?@8^I!FyXASd7&3In7T(ulG9oKcsby0I1lq@@0{WQk*{CLx?soABtBO6w- zVmT9*F=8o$HlasK8im&SNos%-NErMPBrpI8KM(?`zwL&s-gNYEm#&8r>B9h9X8r?pf%gY9%=5*fE zY^P@HjlF~M;qlte?y%c0XL2F4nFE`HVl)J)079T>nO={HA|H#}vsqU*>&WHo<+7{U z^bH50t$2=Hv|)n5xxQfpvKd;joZM z!0UJmd0#wki{_YkUe_3U*7wu%(;^T8DsKu%@T14z10k#+Lin$Z(tgkngs{503McKt z0M9@$zbXPkuv)ExU;~uIFcnEDSWaUw<5oNA^00xhA(6Jni-vO7HQh)~XYoqO5%Mr* z-Lm}Yue9(DDphiomNA-u5c2J2xD<(3yzoy9iyi#Lz6WZI(Eex_1> zs#Sfakw3v?N)Rqn;W9O@kP*ri;v*p}7~t;<#bKkA%^wM2(HKFtvbv-&8635GZgXC& zwSt^chtXP3q&D2V-F<$sb+^8GJ3jw%cJQ*F$~obW8g?RUy=boys@G!G3Ubzj0v4y8 zwVDZ|9^+XJODh=?uoFF|Hei~CU|p|O0xF+NvB>h(`uKI3OS7luQllxl73sl zXAL+FPBR$pV8PQS76UNQ;R{-jvzP+z0v>$S!jqr{NZ?7#1W15HfQ+CYvlIy62Na2< zqs*MtEm+T*dB&_~VCpg&D5Ht8SXrw8=PfVTIKis3TUduhXXQyFtuZs0jm1%ER}N5t zK^2f}#)QL?bqYC`J@0Xqe4diuSM>X`UNPx*$6c1Hi;&qC;hz4hCMMVKhcpGO;RX15QhmEr(ym^_2^&)qeu-& zNOgw@r6dJO{vbI)tl;=EhLZ1}V(O=aW{JjDSzOMOO4RmFhXZaodD^XKJv{5?7$-y7 z;n&eqdY%OF9Kq>umceLBL*PnGD_1F&)#z_m(45f2ooELWe(b8dU)YRf?N8`>7YFz3*S`{^QrD|NPzgKYerl+lS-({n4xv z$%?$+sP^iWVH=qXm>Vh2q?wwJ%X@2$jX|MV45cHssLz-TSqn+`f)EmMF&0A@5KW4S zj6YorXUow{IhqDeD2CJdP%0Y$en=+0iI^uAafKtEU^EbkhhoWaDCYNg?KZ)HQr38k z*J<=RwarWgMPnxBs^$W%abQxC)E&&J1T<^DoiT=S=F~z^RL%^8x8+P z-3xdyEjwlv$41?~)$nZAUGuhA3MdL3_7Daf55q{K$WIgn9gQM~gYW_H!!UA$?nY4y zg;D%$ntHaLxdKkuF5K^yUma9mAJ!gsi;sIi3x!vEh1W-g*r`3cSYKPOMML&v%$zHb7j-sQX$kRM@ktV92KRMr<`(E)1G!Au+ht%&wJPV zoo73Zi|yLYUgQ3-b$?L1-pZd(A}533n{!BdH3cS3`zqu(soTu;4QeQsS z|M<@b|Ma)hfBCnofBNgiKmE(qzx?I)U;p*tKmP6QfBxIs|M<)6|M=_cfBM7K`&XOK z&l(p8`J0pS!)5jUqVmnd{{hN(Hes>6j@alH(>TYl+bwvO?_~!Nc zx34$e-;G|Lw_Y4pp6`|JPRfs0)!Xyp>0$O{KlA*u@%mx-_`Gwzm!402m)p_Dll<*G z`|B5@yTj(7VvkbQm-t!(kfvnP_1ZDD`f>k!RfQ8lZl=VPl5dj004ztB}erVf4E6_fNoL^Bn=F+ zFxbLfRFZ*2BOGjmEpXGSl(^)mgehJtU(v2U0aP#%a=T6&7T97)7#4!No%G4Lcrh)W z46_?0Z#!&=n{c~EZe0Cbzw!&ab}3@g6uo>uW8ZED_qwt5st?v{A#>Sps0M@vP(c`_ zAJhV#Lcmmw3aylbCJi~0!~N`vLVU$^f!oZDshBxC6SCjN&8sG22pcVqv}K)micFI&Q8L%3?#ubYnBmiw+PUiUobE&D;)vX$Yd zQKlcD+8(U#z$-RQ#YU8@L>@T7piS}WlwO-L;&}^Iv@uzWE@k3UW{?Sr<7`$#^j_HHP@GF)~&$su2HRm5dM)`3T7F}jX(nhavZ6HDM3&227-g>K~JKM z@DRfy9|P<{avWu$2^&p1Sjx@OBG34F+Q(5oMk7)x4=EQ(nV(feO`3wpbyD_G!8aVJu~Xj}wH2!)*<1s z?^h=4Ij|2SaRJ5fSZR}mHkcS*&(MIyaAYe`B~-Y{02U;H!K_j#DOzi`=zV^BEP-5_ zfw0->VO?I@AJ)f`)_lp+?8c@WrQL(h!O39nsMqT?B9VZ>z>t($$Kf^`D+rv~tObR` z#(3Nmj~nuNYop=mbUc%BczrE48v5I9u~K#B3$|K4Fk3Hn`}uM$Uao;{9dmgFFa&W* zZL#SrR-M~p5Ji0;U`!?e6|C{1K2b8XCV{Qv;{HYbXNv|19|=LeXpaC}U^^m&pZE=a zs-F@9oT6|}!hJYJ7lc5P2&70_$?+KcPJ)wmd$~}|oXWXU6?1JMu5D+gYl%w98S(0D zdb#}RCzupvw5m|U0pw4m3Y}K89F12KjcK+%N!Nyv#wgg|NNgXL?_O_syu|YAuhh!V z3GGv@a_Rqw5D3j@i(JgVD=Aa+?-PQ2MP;*iTAkA7Zn0PsNgWJzcre+S&L0l%Z{`nM z+jo;^@7LC^tKI+?OWH==C=kM+73p_#!+xRL&Q?m1ObQGOHy9R?pwll}Ek=e1^Bh-e zRWh{#AVI2Vq(<2Yz~YinHo_tyL6Q;)1#K_lwlz{RsFqY|36%z{*hK-;EW(FAgcAM4^8lP+)bSh*CL;NaRRV`0kDB3fe`c*{vjp`<|mc}NU$1o zCL^4p6bLv0mS!VmH8Tz?=N1fJyU}MidTj>L%sF_>UrJ%nQ3giQUtluB^coSYP>JNu~p`aKHxcxSp(`*s+MzfALP&9ng zsNFD}4(Li3OlWXcz$vn_Dw7}_P8pcKfFYE!r?Qn_DdnGH%1=r4=X&f@8?zFCQOQXZ zeM~LDwxaq`+5(WUQF5&pooji=G-sctt?MCb>c_@@Y&}BlW(_Ab`?I!q-tnF^-TMvk zv=_RXW$$)sFLqm38;yB8)l9h3E)E8kg#%xsQlqYFxK@G$5I}+!K?12JN!5Z7B*BTS z!0}ZrumQG2V9O-FLSZYUcA3;HQ|e_>wM45{bQ+nFP}vyV&9hzu=QHv?125`zRtx$S z^e`8&IIklB6%aFU6sJQSIawM9gMcD5xK;`F0lM0UYZ%njA3h9nIA9upt0hdm#F7df zu}Z2w!xg`vls~6cKj$<*6WAwFm!_Q)4yNgc)6Vw~JAe85?r+~c{Po-W-@iV8IGS#? z(mB7;&aN`@pYhsH<09WFho_y)ppmE-0>zXkpK#^k&Qx3kLP#$h2-#pV7mR28k(4(C zwqwQ@&jk{>01!g97%7!vg<>?H3un`TR5~0>$D+wdG!crWBFS_lkqkv59-q(Vahbes zqsz_-CfsV!+D(|x!KOmiYS!1Q#pnI(Mk@}G(9etAtgD-K4vHcW!e%oxt9pSDwp#wJ zrf;L}S+BW(5Y{S=anZV2bM3agdmSG@!cjkTGK!pzV`mdE{eMsbbUKY6kE5WIN$g}2 zKba&@KEpV1GD)6JlV{W9v$gcqM&@=qcRw$@J}AFFsJuBSy*((uJ18L?B7JdK0?U38 zHMH;>+;7M3cNSg+q{S9M1rTfpRCsrkdw*K|;yC~IP~rrH3Wy&T*$ZEu6hUtea;RIv zcIxe65g_4yD+%jgo!0*NIQ!;dubp#siXvG2d+W8WX{8NTeaI3Bm<~_Yb`K{zhm-m7 zbg)(rCY%nRp*=3PMupiR3s6x`*>iDoqa+Udv0TQM&RVDIxy_x*&VF+rCe(g5n-kLs zF&wbPL#})>RLDkB8Tk49X+XYgAfE6G7!X`ml1hlf9URk9y)>+j-dYTy4Z&o|M11Y`%Hc zczIgAJ#Ac_wl7awX9v~2&Fp+FKA*)mhyG#HK5pB$$Kuw=vpsYiZTg=dC+^SFwtgO7x; z7-C@wTTu5ksfa4vUo6zoHe=W8 z)w`|w^;+q$Tj;~tZDcKq&-mq^bIU)|ul~$KKPmdC^{V%5nme6j_d4lG!Cw#A3m$Xc zZLRn`&4|Aqca+1{V!&JqS!yu{Ktea;>!$tfq!$RG7Ip#^G{PPrgkdHEYDaxlzpEyy zo8HxKSTjv?yH)#1Hv-zO1}9l}J0{e^wrW_YMC|3TJr}fQeCC8lA93k`5Xw#$5JK5$ zskkgfI|YQ0GAw6|pA~ISJKojZ0{>#@eX|~ZISxE;yPj377Zuxe-Elke-3+`}UGKA& z=NQJ8f_)=t8V2=kk!iS?nuD&|>5`2uSgD+u1VR8#00ALnZN{XTi<)$xuuUH@>+CvQ zPbh#8Fy#`VUP0}iC^bc>ajgO%LB9G_E_;d-8n7@VLSPnzKuKUg=?xm1#aNgRP!U`f zwO3;~p5=L(=O`;nSt-IoXsv|SLE}Ch6*RCRo(SkLAFcAzavvl2v8z6vENGOcT~sY* z9+t#GGf}RlA~BEXvqa+_ILD)Lx99^-U;q;ICap!FoF2|C@(vek6G)R;YXDR*s$y=T zTg)77j4ls0_SQPptlw?M811h})z4j4O)RL-By91p$!XQn_-7RMsoPFx60YGmxwTiE zAJ%pcTibh$;iOb32mL|8DsVsuMiXZ;^G1__WobARk)aGGrCbI!^2+M6T)wIVj?&7( zHg>uUVHk)~&S=8!3vnJF;}l7^kB%lS)n*7FVZPs)A9VKjw>CDW^?E4~bnC&;pcOoi z*=&ShBb*N0>Ck$;L^^G(Rh{LswbgRZW|7U!#Aq0*0wLtB`J#I~&9yq2QZ?4>6zi>$ z+iU;q>95q7!sE5t9R|CDH5xT$v)b!rBN1aL!-TVJtuLmM zwSH_citZiMuWr`&_S-rZ#)e<16i>A(ISd4gP!CM0khF>^S1=_yb|u034}ymlLWPV- zwGv=JD_g;(Qb_o!jF8J|g;Kk;EXU>Ugtxnu9qoAn8B(dR>-ku@)7U!QnO{BIy1d@M zJHC8Z@9(-(;h)cX_-@I5nDOuAeS?B~RP>C>Vi&kJZpsC9*&tVf$t>q+6x`*s5b@D& zLFKS2tfp0-{fyB54A=aOmOs@z`31iGl$6P6xk{%bcnw9$HLMC}G+;mzv_^$1WgLl9 z8f^9RryOCRkpDnSs(}ZzV3|tMM5K-Y20-;{XiUp~$Z7t&S|lo9Iuf4v6H&lH9}*G} zW}uGFXd^6P9f69J>x{I>entrrNbpiWeI2-q0+ytGbcDvlVh$4qYA2_ira z18zcX8Bm*N3u*_!_$AP8QnMGHiSI;+SOsQDmrDyU!y1I3C;^;E0=T&?(2vHDBd(kJq#pDUMF zHLJk5IIYs_37bV1c9~NFXF2R?#C+XkaFh;Dv*DexW3ynJWlW>ys$-41Ro6B~_);D%Bd8jZsHul30WUz`Rat zRe*L@9qlyfeR_@Gp!FLuzY+HtaE~5$>NGY+W2RJAmayqigqT@J8&SwI>bMEk1A=5+ z_0e~sq(~)6s3=mk@NWQ407Yn2fLp7wm1Wrqm=p?%Ak0QnIN+TQvim#Dm$y5={qE*3 z|M2>s|M>X*muD|7Ci|PELc$PoYwY}|R^2Z}>vA?sbxOjlEv|KZ&8(*qcNQW-He^W$ zOsSwb11nJ>9kpkr*z`oq6_0sRNpCJ6E0hw2QnFA=6^iLXE}comR7MXx9iS>uJ3FV{7~m~76IMN zLZI7O@K##h&4M>G0EyJ`FmZ_bF~?6v014^yS?1Xkl)l-_-)73Cv`nc^Zcv5^cP2k7dzRrQTWUA z&cFZq;;Wlkx0(Ru;yUL7s%ki(@j{frd z{cpaRzyEp%mfwH3_x-oKU%gvyKG(WW)CKzgK_ZoxbVgE&ecKj?M?q=vsj22 z1$ISXltBU2Id#~KqRS>atu8^T63sIl1qPuKCJQO36?J5XISBRYK~*sbjvzH!jRMYL zty+nJp`cY^Y7}>A!~wMq-m zggy3ZHa=*S)_TpuQS)-rI3Lw^YRQV%Jzj4=f>5a*_59|49cqCu+xa1j`GKY z%oYHDQm6*Fg2Pta$H|g4_M)q3CgHC#{5!)>KM+ryE$5&l+-91Ai@JuW zFM7-wJD;#n8M_XZOY)k^9(~3}#tf>EZaHR2iw=36^%yBz>RwOU0 z^leN3(6>Aegcm*gb<=!OHtuKHwFoot5-kT-wc=$nUa|0HGndozDTayhs;GG-Zk4A6 zZO%y)99-7MB#mrTM+Hd2rNJz#a`wqG^JJNoDR`xtQ>tmX0$W*m`uXQzI^tU7!KSGX zH=3qc9YfNK6a|JsgupVWoHi1xXLULx4#WX7um+wnq8I_%qGzl+(#qm?7I!gP2c>os zN*|+580fssPz&0+c@g<(YvFpzo(UO}em)T}#Dm6Iz!>tGTz1-MAPff5V%6InR)@=O zv)hdpGh@J6BQCfN*-~tMtABd7J>Q!Y3SqrogR4IywNI>iO)OxkWc|g2TeJ`c;wi`` z;PI@xKP~PZ4-QU;y9b@E-R5YVEm!@)kltce@!Trv$zUU0R>sJxN!5~O^>dZ%=>mwC zWUz)~FU?LotWN!DLI}ay2w`FLe`J9FX+n@K zPCzAwt2qPh@K|{hLFrVCPRRqBSP4O(JZ>%ukev^7TEfm&6bPZ!^kmZJNW?4%xI+1K zRrc9a`ID!LC9pBYxG&!>#;Vb1C0ZQi>Km2TBt4oY_759Z*Xz?+0mqhr5R~#KT9pjf zd7fi4b@iGvX}I%r(DgXrJ1yXYB5tG#AgF+KCG{%Z0(|_ zRTkT2Z?)hm=N!eHBa^fQ{fx_@@i;Lfu3(kRW)injG#r`asv1PdR5~@mVOmP9Bvo=` zYU>z|qyZ9igdREfNHCh9s`+lS|9`-C<5UDYGZ6- zaSKOVH~<3*2mv@jPZ4?&2Rwikl+Y~U!4HHWK>}vua2t;addvr1k!D$ zTt?Kk*^XlCDM3e}_!*9I>vf`$k2~!tk2~k{76XA&FbE)DmQ)FbG9C{=0w@ir;PJ#< zuAt54Hk%!Ky+x-p&g2DkI2nv-k$Iu@pH84VTb#=IgCr}QFlajd^ zxtmpqoJQ1RqJa?ggiBAk^rV1>c$9{&rwK4Aba2R_Had&}CIkipFj$Brz#v$pMgY1f z0S{2OXf*#zt`OveL4^=8jh3M>6Sv|LwCR|o--;g28xJ=dU%x&2{WlkX`u^(6hpqjM zd@;d04NnZjFRbh*e%o>;h?f((a$Kk-U5$)b&xqxOD;u!^B%~t(axX+3iKrtPcPA5G zP(0yBN(K|DP%0J8rV`n7BAbb2Gto>Ym_n6O-BNo?dpre8AsDrILk4$%cltPo7sNY6 z&Sj%T2N(1h7P$(we4ty6jho3?H#2J|rmgs-5gFHlqpE*W^-XL3^+s^B6`oaH)3N|~ zuvvHQv^;xlajzrpcRc%T_t`M;d_8uz5x?JzKWruLH=}p!;pcz{W8c*{^lUA6KFyp> z(x;R3*)#*|&k!M`LDw63fQ08;g}d$2J>rDwtAqLi6<(jzUZ2)JaKb_9eisqK%|_~a zJ^5lgyC{eRknjS)U^4@R@VJ$Ixt)87vY&Hr4+>u%A-z9LgT6XUesi4q`Y83~VG{JX zlYDoWzgbUwbJ_c+ce`I*jdt4MP9+J1Fr74Zwg-)FF_7|klivKW0)#L<-R$j8vhAFh z@OYz+LMhUR?Y%<3mC0wtbjn#Q_{*gLumR9Qzn1~+@AdX}yOU9|S_vf+_Gm<6gM=dy zx5I9UxHFmbMk6R?Ih7Fe8Gj)gC}sVXoWEWO)^px`++K{^T6u9)3r!kf&{`|9-B0b$ zvPT<*vz_YYe)IaEb+zAowp%;iDDKa4zyqh-NayqF#aQmbSMN8*9~_U@$k_2b|#zuWu6*X!SX zxA*P$`(J;(^ToUMSC6B|yUycX_lt-ASFc9jy_0yzKwxvG?_D@9jnN{5|Z!vIa%$Ft?7%$Ld^udFT1plc}14Xr5qe8XbP~&98 z1`5rhQJPYzRY>I?WJ--pgDEjW1;Y%@Vg^0V^O%m+(v%9u1WYSatH8=ycpgv~l2)ZA zF&tGz!YEvgYn6yUfDq*Wl@LH$4Gd~%IHNFl2bo3&&1;J?iQt zeeHy|9(GoM69Pgl?11%F)YDD)`Y8knowx{i0G!Z^`^K5@Am{I8y`7Z18F$nowrbGa zh}ilG=Qt~Fl|#Gr=x!}CF9p`pu0hDu_HqCTEe{KXP!i1rw<+(`XYE|puFE^Ql83MP z44}M&$l39{U0ZbGH7`Agn|8|L#V~olReCwF-FJ=8Tl(iM!(G>M-?xLVTlUk6X(we^ zi|9rHUDv}k9c*1NR&DyC(EyN;G-+d&)tE&VH!BksRmMsKA!M!kti_Nt8Nxc=OHdZ2 zhF_8ERuwv#l9ekNg_2gP2rZ^kC|8$Pz`|64l|m26GfC0wj0{rAVqmj5f}bNgJKjdE|}~(y_GgtX@G=K%w4J^`h&{) zT5EHolSz0y4xN!z@Z^f1*TlU>fP{q4qGwKOD1h3iRHW}>(y}+9t28Y)o z1}xs7H4?X{b7HpS%~ixwBT(xEdz0i~8V5Eg)m^ogSgw0SKg}7IJRYN0G)o1|El!&g zsNZ3Ane8-h(mF+hH)Qokg#Sx~0Oz_KMI3z~1TC)C=_w!tiyiDEjOA5&lh$e@olexr zG7%HXrQl%b+1`n+twri}M>=gxrR|BNU;^_HTajy46qt-L(Y}N)-^|7<;dnJto#cBv z^}$AAx}G^WZe3olS8GAJ>=UKpQ-$maj5dT8MSp|-X9+>VgH>EE!(^aUTqYv{72r?% z>~r2`$agA}{YGu5&EOQR1$a=QM!9O# zE_WeXqXxl9{V`Kn>Y0GXYiaD(qU-v|(Esmj{e@+ZAOSt)!^V$-ol$NB+70cAmOng% zB!R?#MFq5*^bm(CnQBnJ0j|{HN}f;|X|0tb02SO8F6_2OMIjY%rh?9d&mMM}JZ2W< zH&d{)jKk#|A?FE&fr4kLji}oil99noAR3iJl^Q8X>C31kvs7J&{veCA1%$3WNVciO z3 ziUEH)6e@-Sg^<4x^yh=VY`~WWBS&;cJ+6q$=@SIE#o{m;Exg{y>Uf4_5G|ly1P^5%J2IBvSnyS``r(8Vx%IZj+p(^u2<**GF)49{0MQhDcpP;((nwv701iMHnCz%55=LSe zC3R0DwHn=r9vARS;T9c^%BX{N*aF*8xhe)Xq2g39^aCg0EUjTFB!<+` zAXIo838hnORV1dSrO*Wu(`r>pjY5u2d6itN_!X)CoFiAPdTqeP7m}WFH+Qnze<4*s zdU3gVwB4NbQtgtzn6SmXwA(B*ke_>u>YzZyMSU(JRMVo=v(uMPxBwF3AzLD1Psd&9 zq?iGv{V2XD>5oM{iMT(Pj%Cx)Y$lvZhtp|45JEELNu=G0v@4Nz#*&V3TnNUjfvC+N zvH2pf6ntTu%dT?>j8mXpcE;=C!aidvW=CCnVLWU^ht2r76`O+Eu#8L^AwY#;#kbWA z?6v~)7T6-bdBeNg5JCG*&jSChMxmQ=_--1xpT!>5q7Spk{WNqx3Bs0}jqLLcFz%7A z*V0#OsjHc!wbade=4K;vvz~swp1Ix3zSzz^%!@B~ORx7Uua7EkjzLurtiRkZ0wmmR zq22`#^W5WZ9th!XGkv?B1ijcu10(<*yxhq?Zl@o&Q!lrZuXa-J_EYZ;2z=ya{DF-*!Yg?NQz=P2+Un=^6 z3L+uoJpho%q}{LtU`QsMiMS`=w}ykZeAZve2eT)@zE(M0OgccVf;eu%_aE(* zytR~2O<3DG*P!N~b)&n}?8$cJe7EszuW>rB9c`8m)(eO0#pA8=*}QhK-?}>LTpxEY z5880|c(c4cEAMW#4|cm7)56ADVZNE2jiS4=*x_32VkiCfyz%{u(I4M#{^oJ|^0ISt zQoA~>Kfmt1yc@o~YJBrz@cu>p@jQEX8hgASg_l`^wc(c7G#uxRty(EZ;tB zKHPM_cscp?*PGwH-+2Fi`>SvEzWRFp_VwEBP50)!c7M}(|2X>Q&Fq`k(=YD_FK?QU z*9~BX@4lRU_r>gsm;Hy^#_Q+R@9yird(->f>+x65TW_8oD^!tHEV6xvWN;firQ8o+eow zqcmz#3XVmnfO4QP6$ZvS815>W3QPtV^cHQ=P#b1`vXZL`~mG3Wg$}0Q5X~2_?J{yd8>dfTdI`6_rTRs1`L? zNsS6@0QKs!W_1asR3k$;Onky)YbAWsN@~AfIhi(3C-vPd#(6EC$-f`jSHbx%vA~6DgkRf>}W<^wUE6anxu>cM?2=}r~IRA zc#?~ZGNEqVi~I>O*CKVHmjO=jG-LK!$XX9s8euDN!dl)puSSkqNzhI)FiF_EL1W9y z)kL=BWh-D1`}wk0S8&mJCs}k+6%SkUauqiVDY^aI570&c3B(dCiwYp|I#SP32oj{uNG_goa)gW0 zI7zjKRQqVHpVfqTbxL4Lep4grXlKNJA<)kI%1LKBY>9;|@sKqX6ue%O;NZd9)SDT- zl{4A&HWzPkuqG?Tn=rizw>x#QguBzp?aqhm(?+M2fr-FjA$8=kfnN1G*hJ6@^1F35 zquQWbwVIUCkg?s2tW68^o%+#XcW<{fnG`ymM4{jh223^^Z7^u{ddy^^3}E_@S{1H> z8Gl*6{B(6`34j4iYNZ^`0-V$sOq^S^hQh8;1R%lU_UfG;#woJVls;Fs)jEOUT6X)O zwRbj}?KDcQbhZ{t6hfY`U~=kAcGl+BTOEwWPJ4X%V8jwh*y9;brU+CJ>5lTlX}-~k zmFs~v~!cnu)tOx|mv6xfzn4EUKQ!oJe>vg2vMF)Z=yNmI7d0)`4cGeI`ePsM8=aqrE1IMOqFV& zH%KSa0nUI?9LDHLi^~+w1oMqdyb=P{#<{_~G2Sk3Y!{DCy3a0V(U^JZ=`Yl(Ckol; zYUS$xX+lt~ENNvc014XF6%ZkplM01)WmWm)iOu7vjXSf0PQD{x`p=#`F-N1Lt>crk z7dHpbpYLAZ9p9ZF-IQY`s+N(@I^2H6H%|s8aX8_HYSdf^@EI?ga8ofC5%NKOZTqxkuM?_oH3wUKRGmN0uI{|Z9z<^a;`GinE z!PQTcE5BNO@=LAaDXCWL2okkYmiikkTBN}W4QHU#i;7Y!f6_YbgMQfa2NPei?>~49 z7G+g`YW@Gz;{SmqK0F2J;)iF!Yf8NF;}d__4ehh2Q-rL>MTJwK1>gh#20f{==?E~^ zeKvjAWsZ3TfCP|K4GBn=74)Q;)dC*q2|x=Z4p(rP+(4nWYf`HO3^i5*LsMFpilP!` zn)*?w9H&%>6OjWvM8FErg22&sJ>$@`4lrH~tkhaT??$Z^3?LDfaM#4U4V+WY0wjPO zEbY`WZeHgz=tEX>++hb)05JHeazTGK=*tBC>3~1(6(b&Z$nEkwogP7OT5UF?(ZuOd zJ2sM{F#^#7ikyW>5@j?il&cEm3aX>5SW+mLRPxW2aCpl;!xT?Q)e@^+)e~|-r|_7t zu$@l%^o6jw78hD+XFuy0=3SGVFwP0ntYwlh0whdRFe~V{^2T}5yjOAT*W5=0$bJ`-kRm1at2AXfGGik?vENt!1}l%s;-1Pu3> z)G8VN;W(;|B&7xdCE(f*f_a*RJ+)xdqiX03914>yQNa-Abw;Y9NNF`7R7(-lptD2ulu$mw6`#YB zBV=|X5%HSx3D2aH-5iwUI5O(#6DkPr>qlW|Wv=}n^41%DcK(Pzh3iggX+F{-M8EDAGG{Oo#1INc-{{^>jf`*{>z^Ky6?Xk z1n!1``*HAb5_&leKdi-`Z=~`fnP$30Nxcg!&dk>tj zlYiLFKkO9%3|<|SULTf0u<~-R__$YiwU3gUA9iwgTkzb(%~}FM!e;tm8}K0Wu$8*s zNZfD49ya4|=7}%%5G1@m%6xg0eRr7s^0@E@*yE`3r#JKWSL35`dJ2D9E4DsqO$W7B zyO1x$VwqsFl4wkt)8mbeXFKh!u9)#T01trNy18CI-|1%C)o3bWE96ALfNaK-&A6M5 z*l>{F+^8QPjb_twrHs4>k+3-!Fh(O5U<23(lu5f%Nmo4PibfoXm@A(R6mx-GTFfS0 zs7qQ_%*AZYqJP?sZ}if@XNiWYOJJft)hF_2(I_zTch-Rn%i3|9B!6RcB;S$ z$J^Dj-NyM|^Vxpu;-C#Wo7dsdjY)ZPtv%oBu1`wyt;Xd^=U}^ZKF{Bu)V{wT|Mjc+ zzkPe~fB%Pz|My>C{Ova<@1OUt4+_ur^S5WU*H^8#*PXY|Yj2-d-#jnAzRkb9$=_e) zo}Z_V=ZWXfD)-mjS9jwtUao)rZtKf8>#rULU%Z*#-;eGeCy$SlhZm!}o8J9(=k@*Q z{o@4m>bmoI0Wi?{>T&d&FE)Pje&d@rlP?|yZ|=L_yz2ky%h4a+4Zpqby*{tJJgvPv zYup}`j@M#)qrmNP;rrK7!qYl z)v89jidwIdN|I93w3eYUhQ^U790LPXsX$RiYAu2K)o3(wm0G4$BlmyL)y-9$Y*C;KR$^aplh^&dun%Jy`%h?QBt3F}nA|}SmV-8wr##eal6P^0W!VaNfIshZm?huH|r909=|aVu}2c_RLgWY8o12&V50Yc!78mmCSJB7lgOxjtihBme%KnVSjSSXvb1#`O>-<~&W&5YSb zo9vv;Z4yI{L_VCarxN7=s4__Pw<^=^%Fb@}^n7r9GO|1Ir%!*5X_u7pCu+qCp^;pa z|MP^PTz(38fXQVVLXj9c81{G8N8{aYylhoapRLLq#nSHnv&-Y>*9X@( zhqo_IU!3opX2qDYnpTbK+`Q!5Nd~7$l!jQ3+X_Kr*2g8>bi_e~?0DEoM%;ABP5A`O zW5c38E}IZQiHJEFwbV-fOx$JSRAvsdn;5~U6AXOF()kRtY%8gz`F2N2zd1WoC*{YIJ z8U=y`63l(fKx3#;8UdW3Hjqe0Qf*n>hfwpmA z-)neW!D?1fBQ|&zr8XgHJ_@$L692)6@DUP_01~9TXrqOtZ92xLV?T&Pvg>tr1DLJ6 z%ZxYyAVIVmy%r;^xM4f6gpLMIu+fA-6HXoF(X)QDAtaci4r{_~Py5`tpf?{56e59K zIG76u5GMrvsenHb@W*_k$uKi-#b+gdD=vny6&g~wE!7En_Oza2|zSW?T7T8h-dbWhO)O_MZD0Vbffs6Yr9M&cw5NQ>bb z;03S<;7`LaKnse%S%6H6FtQYIf&fTn=G+$EW9D2&;51SIJA(s?U?icAY+zyN84^Vz zk?2^0LsV-2hgKFjFmRZmpl1q4N4ORaaybd-wfw18_5?ANdWpqkf&mY>jD@6c*vie< z+oyY@^MlFB-tcgzJE+AgNl)Bs^q6s*PGRGeqLqyLjG2f%8*>&?VkH+WW&P=xGZL`I z!$K zXCF}hKpIKvnD$~Lb+?&EE|@q8nByP19gM*lnqZ1Cow1eX2VY|)a$+U<1V~Z`t@<+pT6At zd!~xgK4B3al{;fw5QU^j@Ih^ ze!f%+mNFhttrAWpow2C3QVy=KRX5h_Tbqr|jYh2+1|)#(;gC5LG{s{!$%o(q0VJf8 zu0-6GP5TPDKtAg)WW1n!%AJV`sfe|lb`6`c^?n*4VNeZrN@BaNl&zAn*YnO+ z$jm)t?`g@6HOZZ|ZMf)Lz~co}Z^LPm))s>5G%{s~5d*-|znJ*QdYz{`A|g_rH9% z{p!{D_O^3***rb1o}5%J&g=KLgZHo3zJ9y$?#1Zws(pP_LXkpugWtT{_}%-h@7~P5 zc{Ta&&Ggq_tpEP~`X9a+fBVpReNlTjDZM;vf^PPT`{VFV-}n3|4}<`8@zulV?zFYh zjntC1e9)Tq8@&SOGQoh18EI6;n!^=(7>8Nh%2RHe(Sw``CWqNzGw>!}XJBa#Y(Z3I zNUa2uU5fTmY1C4sQdH0sHI;$?Yg8xjS2#F4WH*$f;;5RQ_bZ2!=JB+7G^%bk(#?oHYQ~+~6^r~6oAMJ6u^iEB>mlo` z7~1b-4}1CTdUBZY!EW`i(2lxVQD+kof*sTdJKIqYaKbPh9A!iOT(F(?HWF^I@mfhw zKj$CjgM*B>lW?}8_Ey-|3|l)9+c4?cDg<|{(YuTN8voo_ZyNku{0*fUUhdU6s18LylXdr1u@<5u=j5MPe$=~=J{|`QIWcBO-N8FiV znfC3sJv=-kDkI$A_xbpv^wXNSogrsYYcGhm{A9x*YHmlxWv@6LCBxVSa9LOL0(satTkmjPC8lfn-Bw?wf zr`1fa%^Evf0G~i$zrFQYvtEq{eWD`TM9v)6>0D6Ghn19{4>;`#^SMi0js=-Y!7~|V z_x3tRNBx7N;e4~%8T>8_&L7r-5mzMPEmjikZlTf2)Ede5YOd4GrL!KVYL7&udOZr0WFqbihXk*O zK*$nI}sX;ADmr1J-xa=V1~Gs>~dpu+QZpIeCpG~LPg+_cvP2G)`)W8;4I>cLJXp*t*}VJn{y z=G&BYnYOKf7|hJ!7T#e+x9V@|Hee>$$=W{(p8Zi)ganIw{~tGgZyQ4cH50^oEShds22vi1>@qKrt39MuX*e7=WRYj8&8I zN-|!GMe~tRHW)|;d}*&Q?eZp6JtR8~PHe zF5fn-+<~bCu06|&-ELwinuFaCVSyVR*+GfE8 z+A6xXi~3HXE8I`z2)vE;3&N)!) z3?$Nykl0ReILR->p<2Lp%4WN%O9oduja%XE+^P@_dMbs)xZgO~nLWIFaB;fv;AnQV z*_(BX)r>#vW_7{l5^P?@;n&ExUo5AMP9+Me7Xql&ZpK?o0n)ou32!=OfVr8^1{SS( z(U{Nsb4URgQ9ov+a5e{uWOLC>E)q+5;{Y4L2^n89VTYv?_&)w4O6qv zLx%ipI2u$MhpP49P7$KB-FAaj3|y_n`7uN9uH7oM%SS-#Itey*(myS7|T(3o+ZYExAr(f-6k@m8$_j7L!3U3dKFL$#@d$}7eau_nt zw$e|xQkUz=g;H1Z^yAI!vz@}LgYui>+WWI65W<_2I%wfcsJu8VKie-o-77xbD?HoD zz1+^d+R4A(E4Tj|MYT+cdV;E$mDi z^Z78JkB8$v_yR`r{>IUKx;JgFb(+(r7FMFAP_3KmPphL@b5*K5&i#tnFIqnrGMLf&_ihmgy9@>!#p57sKtW-VSTM=Hf&r4T6R zjC{(KPifO$de+ZQI*DF2*ajphc?W!(Tt{etEa{^j`n+q1sI4_(ZB~SKacTcj9FB`94u7iI0%ZtDGi?_e|?UN5*9>4u?@cyg)^9SvR4_8l) zD+hb|^V8akC*!Z*?RiiGKX~{fFqTBev*FiCZvq>%@#<7Q5Yo<2IB51xpO->jFy>iIVQX zn1ngVX2VS;kj=UbvRaUAR#Yg-zNnlAkbq-WJ91s12qny7#%(a`;vffRcVJe+ZX!{s zaT7~eT>=^NY4vP$)W~lS8|U-hz0JYBwa)HpVURZRF3L|VIhQ{XKmUox{%J-f1}V>8 zD|I?39ruen&D5+I9)a~A(^unefP`Ms=q8O`($`P<2btg~7hbEUruEdI6z%4MtJ%P! z0#alIzf}m0LHPi1LMN)VBkCaOUN3}p>xrXw_HZ@6({#-%@;J+P<76j-v>IW$5pFfi zHM~sSOE=tH%PV#aW!0yx8fx3)Y`EmSVlArnra?`T%0WHwXqjtA3mnC>3!%zZEKmcmgUE^k>aZsBC@#RoGajBX1TMre35twUWSGDL zc8i}h#{@^#&6UGSBjxE7PNT@oHo6>bk zRUNW|0VKHHOfu4a`y|;e;kUfxorLNr1*K|KP5BtVY;g%ony?h| zlhulUGAZmI4^HpS_Rc12yQ|G%K3NKQ!jkMHof@sWSlLPO0zuNS+ylx2A>08THd~g> z=4A_7+^q~tIKkfVyQ4AG#2}W?eL=zFqm3XNPAln>r#s6Y-XA@Ce{%F-+!!P>6>qxe z34{ez$5q`S$W}$A+=kO_C@_YiM!t|N6jOy_vRcbFTZK|7>UIN%P=x|KrKi$TGR3FT zY%pZ^d-2IA<8fKMZd=Gt{O1#bMe!+cIu5;WqPs9wC6hETb^6C(M9zAk*#7S8m;s7^XGoY@Y14 zXH6x*eqz4O3d#A_lY38JoLxUYxw?G#;@QLJ4|&(72{wE{4Q> zfCo0n2Zd~aPZ>6gQ%iNfH2sQ|0)d@d}$892k$t13zQbITof&iQY(~5Oj zz)UKQ2b@C6?=HndwRE(Wij)(LueWu9*pU+$D&?UrBel&-g`N0a)b8qfMAoiXwDTP${qCzd4E zCb1Zan^_tYct%A2VU}Gu6DU;Sh_un7jS_7nZzWk9!C(Y!M~&LxIrz&k)F{nvVHY&3 zP&OCm@Jb|t1WgXOTsQK&G@t4OPH+kQ4JQB_!02QtU`tdLmv)GN2Pg?1t^!sdXkY`@ z?tpQT9Eo!A0k6V_ZMm8(*DoJ%4oY`2Oz6&amG| zCxcGINoc%P<1HT99(2>0h_hbscPf!~CEO?mDu4t421x#V77WmZazCmNSSXYQ0U_ig z3oQsCZ7c}k?;s(W@g~!rWXhdLXpxBQGZ=abUi zN%_IF{BTyjm=!N(h09s~dX{^#mV3UQeKF6yT+2M4B>@ti43R(K@j5DP^lU5nat9zG z^Lh{PAP;x|y2%!JeUJxW0KqnJ0y5}#(f|fm>#57NAYe+0I;VX8{l1-|PM6%ez+x z?RMVN%zCDs%b1ypQrX>J-P`SMZ*^8XsfFtR6)#F9wHrJrmjXZ$nY25Z&|p8H z0^mWV6snd&^-82#3YKz433e8I{Z`_1Z*^^u>s0*Jj8;x5)s(Z9*GG-u)-XNkrN+JF zuoLe!!tH9HSvG(ZI@Lh85ndZ)cGfFr`>Pjsr`HeGADxZ&x9S_?{Ms-(=$2>G;l+c~ zAHIJ1;_B?X=O_Q@m#=>LeE0jy=`SBofAeJYXD_CI^TpP``Lm0E|Igq5pZ~>||J`3c z{wH5;|8UiP_jv8qqw(XraB^n0Cf;#Znhw;1o#@r0>bGAX{_+=h|KXp%{Hwou|0jR) z?5l6iUcK3V_HymvRqyJ$|L|e^;r-V2Meq6J(UV8LvxCyvPX5tx^^0e-Kl-ru%MW|s zzux!);Nki7kH6ag)9;P}625&oef_BU3aR`0VejdA=h1%k?soosEBElA^!lRnM<2Fc zU#x!fa`xhW|6rOP)%=5UXjF~#%ZYYATub{)F;6<+47oTLhjI8aW%(T4w6ZPpq)p)| zT^0Zje7b7rs@LU|B>|=hl5~LOzbK84S{VQhpkyYy9l-!fW&Bvi^!I+SoBV{El5ke* z3W{t-zE%rvx1sXfq(fvGRT5pYSm0SW#$>ZCTLBd;%b3mdkq|J;qJg6g zL-}6_66{tC*Z?>Iv!F6dG)!O)8$beXT_!AdV8zsVM_A*F5zn-q+38gtZT6q+&#t!z zC;jp$wbOSe)w6N+uv=IwMTd*HqYjEVGKRng*-$U# zNBIfa0N}y68lTpZlWGF+08pWy_4jjuQ9d{+gphK9LCU)tQ9*-*dy@5SRs)AU-%-zh z*bVG7+-n8rAjNlMY%j|9qQYuWTnz~wpVaaS4IQcFk-L6<7&6*HzUrY0PHRqHDZ9+Q zFtJ;9UCkoz_6x7JV$bKnr!y}Q!u8PkWGFuwfh5qqw!UBSZsyc!Oza1!j+8(aDB8~tOZUpQA;zdrBcvx{Ho|ZTYMHF*j0{|qj0hW$Y zWP+jN92I380m|y9EPmD!6m3zB$VH@D#@()md#zZj5vh~|xtu$Z(qaj8k0u!44KJhX zgtq7~0I1-0(_VuWC7USPfCqHogp_A6tQ?=L@9j_e!%8ls_!*Oif99c=G6vUz2`BCh z>bSyw&JaHp`P+%O)Enk@54yX@qn+c?#=&5=+g%-3k}01*sDSM*$^aoKGlAm?+yVCW zZIfwf5ox@#Vp>{SzP-G18?#$@f$?~>SkjYBd*dlR5_bk7q9;VF1|G@Eok{BclZ~^> z*>tDcn`S$sOtBga$0U!BQ8Zj~5{iq{+=5f%Rb2>$y@_Nfor&ZNiAptHD#s0KT%I9)gyB%Cx%WoYg*Y~5XpiN`N_&T^4<2qle6(GzL~q~z13Pvbvw=Om;(*D*YWk57ZaN#>U;yyI z5@fa#Ej~Zma&x z?%Ct}&!3-OU!Go{U%a}1|M70Mp@_;Kgq%N%XrBh@PomWAxM&SKaZpqv6CNh+VPbAN zs?#wKn=tsWPDk8KP^Y6_J{5AN!)iPrM+_l>&KL(yd`=K1hr^87mMx|w3}!RLK(~a0grv(P^01?7Rp?=H@THr|gBDe@p0f%iAeY7|XPyt}zh6<1nBrM7w{g@B^ zqqpIAPKJ-1fO4a82j?I}ik4Z{$#DwHDh#7As6MGoks{&X>=;ZOoZTi7xXMs&fiq;m z%~BfWka4SsnI*f$MdLw*Py1cfM6j8SHZze*!k-K2agP*GNR2l0wp+CMXM$rzrfdt{ z1RbGt1(bonB9{f~zlH*h{?4%gY_JgRgc*mU)!*yW?3P%M%(`V(rZG(*y$Ta>2_d%> z@R**_#hDZgST->dseXe}aTaNgvv0yD0Y9zv~WVD@% zHxsd1GzzN5VpZf@2xkKRnBfh1+&-74t4>vxV6mfVlpc%|4isJsYoo=oVzZkt+>D`U zTbNhTG7IcrTC$m!v6WlE!yLZiWNcoUjObh@pp;|oM%oXH%~~n4S&Q#95}>VWXqNX* zGR|>Q-pH$a7572SbK3OWTlHTK0@tI^<5BQ>=zlVcKLbwKEIgQHPWsV#-PcJ7Nte|{ zekNLf;$oInYDpqZGG&%&;8m1iBA^q->R>nr4PqBU34}2BQ#4I2C<06b0`*L_IqX&f zFcnTY8W&i?#S31^=~J|TQx9pLkV_A0u7IinJHhz?U)&-#jJe4>*9BVV;d^vQBrd>v zU<6^Y5oQ}{wKH}&{b+$krSk|>L=~qh9jthewZ2HcxlPYrS$gX&927Hvh!2^anEWN!VqtB%Q;0s0XV{(N``Qg`6j!(X(ki zmvQH_-h9r;=X_ZN42ud#IZ!y4i-5AZC@575CySwEA(+Sq;#prT9`Y1M}kp* zd)V4P-Q74?ZwzYLS}I*lgtPwEpxEpe29rv6kS`Q{$(Yn`MCPM>CMLoszcFtd9t?N3 zS9i8MlW`dUppf^alP-V(K!t3^eUpIzQ~(cen4w(sH)@e`!B@^3wNjv*_ZBjGqY~Jd z6d#^VUS99qJ?d{w@}qXFTlII!UQn;*AGN~WR&1f@%|@>s>vs}^ZgSL1O$M2@aejBJ zaegvs!k7rNr zuHN0L9IfXL*V4xunR|Q1mk(RN_^|ci$>3LC?tJldcD9)x*Ns8RH>w0ybG~lQKP*S4 z^~9u}TrGt2AvNHnG{&q@7J*n{>`SEW4v2P`WsdN;q@bZ0x>Hv~Cm4Aw#lj_t8mrp~ zI|c%1SR^3WevC81aSVsuH_t2zIiSo0D`r8tj&_uL40zyxgHS^uD=aiJ$7muCQdk<5 zwnI&wfgj8cY#CN{o8``roxIGL)dVAsS#f|9JHAMuf`0Ze9Ld;Ut z&u=%9*E_wdt={pVJS#=oF})sgHX~XuWsGy-Ng+~?x$6l}Hy@f*lWUF4td<&vajdzxXb5ps4D>b&gQYx+<7DD3d08{4h>*K*n*CU(Po zKOzld@-XTggaHhMwwG&pxVD#H^@#;Ts05V;>dGvZyi`%gDh4r5a(guo%=Rz0QZF}S zFV+H2M((SwblsC)jMTSl?&nkg#lQ!ga9ojhvdlb2&cgU8U?2FfuE*MRS!$}O;9SYc zOBv@%)@9CnFyMrepDKB!vLWZ)Vq7BK4wGoQ#Vvm(SeBi*mABhCo0YQKaFZ2VfsY(DT_|6c$gKxU`l$(deYf1`^Pn)++erhZKSnoLN26TxulkkJ7Xci@1@)t zt|>OBf@w}WaDvCnYC6SBHkvbwPDdi^pKbQe9_(G7Z|n?8*?=J7pRkrc^av}d0GE#` z#iSYwFq&kN*xLesClcbjz4ZP;@9cbbd^*`X=xuJcTCI3EECP_YT$J0*Y8oSo1W8(K zK)+~_H=9hR<>i&-Ws})t!E6qafCCt>M~%k3sZ1c5G5k?pP|Z%CDOr;D?zWE~b=UTa z!+B=Bk)Lf;R|n}rDG-aRzzMpK_D5uIKvGe3dg-3AE$dMub&D>xGW-s z(0pFpJOo0BGzYFyOX zc#BW41SBlv1dG-lkgW)Gd_u&-g>)wD;UZoh#xT%ASXEsl&8|?im7;7k zg|W1Qp>V7DmSyELyX|Kycm9xe+)l;h@gO(p6;ctW!eStw3NPY}`P7(Ciy3OrCAvil zHA=9r(6%Mi?+}D7!$SZA!C^)sEGXaiKLh}jDu7u?)J4uj*)0ed7O1drAYcd&02^or z3LIKE6K?c7Bmg}4hziWddZ_>pu>U3!NgzpJ0}yO1%HE+y0lWj}9S(s23y%QF)Iy{K z2mvHI>>`fIcB|sRoP=F**ks%y+08II39E~?dj%q_@tJ^DP5L|eXr~aZrTp2T8uth; z4wp!)MBWer_K^@!r6bfT0p3EPfD>pS1Pw(TA*l@KWZ0Y53O9s+V&cI7D0A`K@KatUF#6!R(xpBgvRs9O#=SvUL^g{dUwW*mNzjyQ#++nMpY zib10q4K@)ZB-^P}GnuR>5&#LMg^G!IA(_a;W07DW;Ptp%E=iJj5w)hLS%#!3J3%a2 zY|AjCqQ-*gx&%P5T2S#ohuwl(ZZDdPe@2)-rOcmlwp$9h;^l22Cs{DKdPrVPxJFs; zS}`y$`8O-Uor-U-=HDsnn|WoP73OJXBhBs?`IDOSLC1aB_g#)74`-=IYnjW<;?v#g zlfCA}cI|Xp+*(ZyU;={KlQ(nNZOZZ)gDr`q&B>xh*D`9qClIVavOLM4np-zQgaA`N z=>S5YU?~7mI78Y|sUldBQJ^Zu*&HGcNY1%=*{3)Isut8fD&$f@epS+e-xi7HZlE{> z38V}YIK>Gh%{wT-1KRGOFr2{bq#fs&n<5z$e10fZlCa^h?mMgm38(!M=U5VHlS{;d zZoZK44cmpI&B4X#){}d?S7)2&yThGvwO5ITUATzNHUD1Rq64ydeXCN&3L!wV34GHrKR-b4MtBztw99JW!lk)X`@AcW_ z-TCE>1X@@?!t1>> z2%*A3?)_o@i{s*#r{xbv)elFtcZZd?2W4dI@8q9v=bmh301__N6OYys7xUyL0K-o1 z>3-okpu%zG)oJy^Y2&Mt#=C>cO8^Yee)+{->3X~PV4l6+uYLV==ermCfCmX5)2_s( z{mS~dx!Np7LT+!+vpQ&R?5(fwuAyMBRsj_}&G^#Q`0BXQ8JFvwRIw5)mf)ifb{dgp z$tb4O&Gq_xy}mhb?(g;h55W4*Wj!|`Mz8^Fkk5I64PZZz126;f9#q54dbC~%)ylzY z$zRNRG6`ofqfdI7i@URLK0NsOmk)pb<)aTTj;`)bPIsCI^UBV&FzG~_c~_?qZr4NY zdKmrz-F9r)OHGH_wMk(!+KS z2aOjGTL0jO)4%(Sc}oA1Bee(_@P@&qvD-+a0I z*T25|SATT!>-Y1o9(UhfblzMKfDm3h9GveI4`%7ZwcPPW?s%R#o~Iuil2{SD_Y-YxR{M9l`yF}hl6^SPR5(wO6w=UU`yLAb(qWf+( z3o==3Xxd!7`ofoBF!sBmg0BsP!ht;4BRz+R380 zR+eQ@9|fKRLJ%3oNi!aj@lvdhp#vNn;Hdyl1_V4H+JiC(tg;oKupHCv<(Skf8Iwk2 z+Ki6sp<>3JPr0%SNJz$%SXc`9Shr3nvQ5<-sz&G@#_)??zW{{bpqFJAoyZ0@MwN$q zgGUFW-Ep}PmL=j-g}UX}?8zWkOlgI*7W9%p2n_w1s@ak$b+wz`-d#O8og5tv4-W_P zd8-L_KvZ*SH2kura$b+3C;|lw;ersXK+ASG@9~vo%O^j(Wj5Wx?Piw4bPpecRi@|; z#06K->Q9mzhvnV#=IS(FZW--iZ2!1_d_JDcs?~Zdne`-d-f|EULe z+I2Pu?u~=|$%Afx7WajyK!k}V|bkp*4y4rk}Dfn&f`dU*sx0YB+QT40RJebBj6;0Diw0kAr}*Nu@Mg+ z^$Ibs2xG)6P?QCCtYD~4v>E0_+ClL&>f24(F^;m3_B*PCr(;?!;qfZ8L|a&xww91f zmvfjD#_o~npe_O}ggr_?mwX!UQNYY4WX8_nz(Qa+-g204QPw-GeT8$F7XW|(Bnb4! ze$23k!L5J?6pBHz&_9ZCSXsgb2Z)SgVfrs3ixw^d#0kGg2shD3=&2tAjczs;%^6S| z2cD!*Q)k?DumK2hf=b~Ug@fhoByB2X zQ)!#V*xWqsm#L_m&xW*W%HPUG%1I*=0b~;W8s!pgGHnvcWspR!$h28utWFkFSzO~l z1ZtariXh=C3l={MMyE>vFd&?)Lt$}+S%}4*9Io;XRd8q`;gU#QBHc3OR%nkx2V6o> z7lJU}NE3h=LMjgm%4|TQ{Q_lhgqOvAEFKc+geqn{&OBV7$#5wZtz_brOafF+B}$-V zqL@hJWAR)xmWjkup=jJ63VRGg)pgOS@{-Jh(T$Us#co+N|6ZK-HZxp+%P_Glgt!3- zwHp2CwigLZXB`2BO?c#dNUz4+t#n|J4@}G9c{RLQ3vE^dTNUqS*}YkGg0@P|owDkt^bUn{qt>-V-3y;>zhu!!v=PCKwsBHDpcQpJn+4iYq{Y0iL z3Io7k2T3%>lU4>dQMiS2SYU={S(2tn5-5R$$%4X33L{`8hyOWvj1X{AB4~wVVaC^3 z&c*R=LGUT^4IzYFPE?duLltQ~sDaL+UMdfC$AD!Z0i7}woQE7mpbAKYouceKM~V`P zYh_snMcY9%i?ckz(H5RI^OTt*ObosZ*O4j^alckhg-5O8{#y6`{_OH({o&#CWV1PI zC);^xwMI)!?!rPG0A z(g?%;f&X>&l)5Tz>7y?d+raY0PCz^Ce67EP`4})T^a7+)yT*08?Hw44Y zdUVRI61rmdIPr+VWTQ&27Cu<3T$~KwU2VR-+!d_~N(*Q^14Tll9E&gW8+J`jg$t;3iS`)3E$w5BU~qa2-%TGMg6SuZ3Kkw`4q9<+PY-gIj+-Wb(Z%du=Q5O-%v z;nh*KJ1o@Osa(OxWc6~{->ip=d3PzNuaEOv8_ms)=K5NFG%VJuk!;!xV6Z>}H?Tpm zfQlCZC*(4K4FC)%O&L@v`Riq0wP;ido@&9D=zNkt+HE~NpS*s$`^Br{uiu`1 z_2%Tm%fmNMcAq?$o$a+Y$C>_WqFOS_MQ^hf>~-SEd(cnMXQl1U+Wv0)V7GmCGQ59x zdbGa^NA|mk-L1y{PHQ$yZ;Ubz4?1tohwtu!tAZ?9Lsdp-G+Z+HLn+wJdP4ZnG|`rXUk*DpqIo=jdpnLK?k zymweX+pV2!mG@_v%|T>y5W2gU`Rc_K2;tk8voD{_fDooNV_5R7)x(oga9j?KOTkeo zI4A~s1*C2%Jg7w5g-|VRWFuNohpW;|T0gU!enwbtv5sYlhS?a^pwmS<?vBjN*d zMTAv@1R$`Oanx_#wnzrR7yTPCD_BZqK>CFlzbI{FvssW20cAMDEVp8}0$u#L^xMqv zIy8=P1gg~Ra&oG|$O6eTcABs{?69!j;K8zek+N(<5f3Qb3EkhkaZX?kD^9Es#EQd# zDk$CbS;H}h!%jI+3k4c8(>4=pSrY9g4}+)N%4#OM-Kn0h^&f3_FZTxbH#*y$Oe^k+ zD|WZzbEoB}viYZ8;&#EqP72|pJ`hFo?zC~(E3K8Ht8u*%b2k&-PTJqi2D{n7Y6do7 zW)6=_F@S_gDK;)dM)@!ZHYUaBbfH->vX&2x)4oAmAH?0$jCZRXK5V7V`?>q0!bvBw zRWe3#u@`3h5q1>k#|eHAWx7G49FhtFq2Oan0lpEDR^!f2OlkP2qGqe8mWCS}h3Ngf zcGZu6u~q(Nul`}4e=&?-^z?^)>?{}w&vxlUa_e2DTNAhxQ8$+m{~9{QOkG8-v zvy)~FL;Wz9z}Cd!0|yM?S(*nbpi#^H1s>c8l}6<`Uf_{9)M9~WIf)l#FylpD75POJ z0PT@TLvr{;+|OJ5oGHjGh1r#aXenq!!!HbC+B9QK+o?_|SWfAvy;?-h##9vk9g+fG zMwYCyWK&g#%R}o1tGXG01YW^KF!20rv0zLmrK5xX-p*>P9t{ULO|pp0ZC$p;141_D zEGD$5mvJ(;CE`{y1%o!z1f_MO7&_q5p{XooKqnrkx~_uW#Is0 z)MAF^8^;}1i~ZA2KEHGO*2>att96N_EwYnv2be%i45isvUYu;_ch8#LX*`zUvlVS~ zx4E<5-rntuC*|HaHQz7ZyBh7Etkyf>Kv?7@3&U9juwmR%By5C2-cUe`$GnwNw2%vg zf?_bpu6E)N&Q@PN-5B@6=_nO8tp8(#@FNoZM}+W^85V@_)gj7b#=9SfMV0W*)bDAB@eLx89v9WzzJi6Cu4?;$e2*1fm`I5I% z57gU{PA@i^X4bcgJNvb}_hyeC?XRu1InH|L&L7yUw+V;oBO!pf{QrXxRuCZo7+@<4 zLO{TP2*I`>1XQ&EOlLD91Pl>^-3C?_iU1>7vfXX(olPd&RbSk_>~LT_*O(3OzIc3e zb?@Nv{L!n!2hYZnjd&qP%-2GjUH`_aZ&Fr=Ie9gsRuk@QP>y@psE*=`!WtP=i5o%) zX*58BUm=lHDhQ~cb740RqAAo124zs$tag|sZ8&KsXdKm8pzswEyQ3>)CZ=bix=SD= z3JAf1FW<2*-@=jU|2YY!KfVIi7z&1QasihZ)Fl{wn&5S^x=1-$T%@dU42=OM-GPq< z2nt|;bs+11!3h8WD7c8mEg+x;V1xfiF!O@N4-5eFFVao!^1_pV+y#rqYRJ#9NJ#j- zBPqZGB$D9>iYLe$2_%RR00us~5y+dMqZ_XRK!THWC=NSt0*p=)5dz3bVzR^HB&`cs zRLZj81iMcrfxBWJAsbN(2_2M=yE0KV5tKu2#&8n4Xa`#09ZLeL;|Zu>Q(60h6C5D; zd~Vzhzy=ymx&#mfAEw3=AeTsf)B+D+{3wxtkJmtA42AJIS-+DFYJ6A|A}%rN5@Rr` zLPX($5*^@4KSu;OA_yA_>vzi$pDPvd<&%-}M@~ppGwBK_g;Yvpit$uFn#hErNq;zQ zgd!ea(Czd(MNI&M81Wc<;Be|<7C3X4VNL-mK%qw#n+eHovf5XyxXJ1O5~eImyxpu& zn42ep3YGLq<*>7vaQCyuq~u?(1h(seoknoC=H0I7n(_0+?^EmI>}MNR}BeqC+1_8B>c8QEGguQlQJu`8BSM` zvIsOlCb|v80RB=0L6HPSIcNr_7#qo037WiXF^FVC9;&TSW_4Z2m!8LAOxBhDHQqywgPKs zcn1p?5pS1yyToAv4d?a>Wm}>#AW18n42Dc6e9n3{G-{+a2W23Hv#s{soz|nH-uDjz`G86%cnDCLbNJ-`Vega>*s>hcFFdqZHQ>Qk`eGw- zxtV;tlX<$Gf3aPBwOf9=U3|G$d2!TyvR8Y4+I@eu@#4X3t)I!qX`CfCt0X z`1&}vIV)~X3mcRC?!0_<(7C=peR;k0{>8ypuaCcY1)Q)AoUpgu91k+RRm29vUh4M= z;c&lmemZ)1e+>i+|JtN5=%t4J6pW)zWOtgmJZir=?SA!W`j6fo{N{T0)oJ6~d#&%T zdfz-B{O0TJZ@=7n^J4V$s(<~c`}kr1@@(~FGk-jc9QH%!>*3e;s(<{&^soPT|F8e} z;J4qdfBS0n&we=k$G^Sz*MEBXXTLcA^5yK&S^0Q7al9M7cbvX{RCxBd{OVc#?aTI; z@A^Ogdj6~Lw}1F*^Q$+LZ{AFQ`~AV+{Mo~Q@+bGcdp*89OkN%(Uq38;^`!aXY5&Fb z@X5pO(}%;CSF`7jW|wFElkL)aFEnnsPd4K~2=5>FKRg+{deA*tOOGncpO zLeolUQV!ifLLVTZ6dIHx{Ytc3jQObRI(+o9)ABPH_E~^7<#eW>_U*6c0TND!mEBfmR0y|IzIsfrMl={ZXScqg zX+MmkLS$Twf`AbEnZO_$9Oolz<@iQ5wN**Yi}5MUQ7Qj8WlXcac_Fw}4(-)r=e-o@ zq!Zn(8f#g35Tm%Q@@rJt0Q?X<8KrMo_|soSbLUez6C zohZ79f{GVpTOOp~MU^PI=%UURbS~rKQ!2X0?bj6vvXN5Gu={o(YQ|9%w-n1aVP16(E68B^nlMujnv< z5I74!LWo%o(aTY4DZ#AdL|auOTVB4I^>&JZZaD;;P|F(mxRwsfiLjiEDqt~t-L&Gg z3$jgA?23zWd0ExNC@Aj8tf+|~lUT-!jm-D`Wmv-_i3bSN5?I}NBh&od~ zF6gv-d6U7Lqi(WR_QC9Nc04*g8t(6Q=d*gZlg(#?LBFi2h-sZNFH1bj&=`iTz|S%Y zG_sn(#$GX7?pSTNabk%PR}>xhgmHg@8gFJ#9`>f&`FKtU#;Ix}*y$(c8}<1{bF!Y> zJj_3OI)3?C4I)$QdJC!>H_=#mUCEGynv)X3*TuwX^Q&TvR>wYJwAa72?rBBNyTda3HGx5MpTygy1#P>4}!@34OV!N%RY zJI!Vmx8GS_{wZd?joX(o>yq8JNJaQNLb%cI2w@rU0JAOQRwNWf^P>ZSG=sTpMIF-? z)sc|{!MwC$UKUhoygoU&J6@e8WkbAUr+K$;c({J|&E?_M`O)>=%h!8%uUmtuQO=RG zp|RZyueE&Bnrm8B2PJnS<159qOi)Vug_Ms^c)6&DjkuYJ4q`(Zbl#tqp48v!R3 z0Bq3U62M_bTa;b1lbGFMvEycpwAvUuPFR;5md{llkNK5EK=sP3$`L$nN6plLjx4wB zrq6B5pIMha#a3>?!K}lK3QF*VTV}l~@7JY}#~EQNaN|Q* z@B_h-6n`U%78VjITB1?h(Z}jW4qW^(;z%Tc861cZXhH!?@s8g~yV*d%fTRfoNd27>rvbSY@4v4A@nHgeHWDG{rtlZ{NKo=(?O*;*=7 zO{6QaR5_L^MU%xyEECXEJ}u^ThIQHJ6m^kPSc(H<8^!IyLWVr&7AtPHI##U2vXxx6 zQXp*EgfA~SmX`?AGHqVrY+$=%hDd}|Cg~OOA*GhkyLn?=4X-tjX7%8#9$2sFTSb1m zB<@xe&|XD7tm~&8|NTMqVw}93WgpKAPq(U1w`$iL)d$nUaX-1!49_dRyq8M5@Q7qF zm?anSxzq8vlepugEvRQUiwg{Dh=!a8BPS;*&QrqXEBVk+j%%K z7WAkvNKO_$YTz+3=u*NSHR5%_=+#7*%*s3|v4n)0Di9)EAaFr37zbd?lcGrSyn_KY zU@(@mb36{CB-mvEmw8-dfso;phP5AN2AChflvxrSW}U}_8l4I#&Ac&cCJxrCPwvg$ zKHYiqV(azu%?IbbQ8&`68J$L;RSOm}dNL{%vYvd#Q^*-n=8Z#v~hzJ;Pc zne)cedMu^KGwx*8o6Mr-_K~C>Uz9mYq%m(Su>l7j*hU&QR19PkNIX zUo5U0KHjA{oC+q37KvX5xg>Ke$hE7%t!e3OfA!Jn=*ju$?RodrY5Vz6$yrgmJTGd!D=JZ8n|}Wwl~ftrpzc-~d?EYrubieiReDL&Q z?e&xGchC3UKHI&%*gQWO9_@Gbwi}!4<=Hp~f{l&!^1*KF{`vUfz3KVM01g0PfTx=E zKnJdZVf=h2|M#pqxE^3gy4>iCxz-S6%-fBt0f+n?|MtG|8qFaFinfBu(` zKYVp?`FMQ)UhjCnu`y0u2YR~Q!u8va=j&kS670}iF{`0HZ^}W&M`QYMo_3nP< zaGpNjNxy$Gd~>n-_Nw>te)nuWJE?g4Iq$IG8yEePQUC~HRt-<9;Yl?-ssJ8@2F2hi z7+a-auM+81qpRg`qYx-2Trs~8)G3KrVy(Aia>XkVF|V8o=?T9U_Bw-Z#qUylE>t5` zmt~G176lrtV9XPk1Gi!3l_kt(CJ8$Tw}WMGT7(Ii>^2Kww}D{!Mg^m>8(Of~t!5-x z-EcDliyBYL5{nG4Ma_K+roD`#zLIgA`#OKA#dNI9LNY3){X)Zj;1V<@jlyZ;Lo}F6oq?^1yPTw0Q z58Hu_qH~;L2XS&3Cs)&IC#|-V&PGhC2D!4qfEs?G6PCLnc{L!my=+4xs*1g?*e5~x zv=VtbEWg@JzuXQ!T{o`A?neXds;@sDdY+AgFQ@Qq_(97!skpY%$|THm{dC))8XmId zCMzySQ8pJOQ%*GJB}>6+FKJ}i&6KtQn<-67ZFn zm(9z!%`3O9Rue(mX_jUM%n{NQqs%GVn&IqegRRE3ZZSBlMtkK5>aU-0<>RhGQqLyzcu4kn z8BN836P&6;(@B?`cDX6ph4W4erX}{qS6q#0J)~TTQVhRA+ zZg-$^=qRSnV!mxQ-?CV5*&Lq|%pF#_BkHEwYH0hYHQOp>ikd%6CQ?eF>>UiU<4LhM zj*T|L#}De)FV@d5diy7<sDPPC)fnRp{h(U-~z>C-gMHRh*)Td-0>2k;|?Zz6Zx&n-SfBi53Wy7p5DKFvvqb+=#RBlnV)t&yMx5E?wizI zqnf;0RI4dZA*yDAVmc_onDPrrkPj*5;leKDMhK`Ruz_D8eKOF3!;l;ji*uwE-Fipi zHw0}X2(z8C+697UFf(DfBa&8+Oc_9a0;6&yhvBTv&e*|rH-QKY{@x|Kx*vS>5-j42P!hs|78XeGBP!ffH*(+%L9hgH0{M{; zXdna%Bv2#|FG8S%gc~sUC<1^1Ulc;cWe_S)gu0=DU|S-92T_8jsZzsb(_WN@ZH9EU1~xHWR5@ z)LV^uN?}hv;7S=<)U5i1?O5d@vw=E22!W=6W)UteO z#lEy`U%KO1S*9$@@C3SR4il(KM+_kob(OP5y%=m)quoY)QV(ub)Sa4ZukPNf>APhO zv{!Z=R^2BJ<6bxXpdWoSN?uPhPuBBKH;d1<%g=WzFLtVDz4%_;KhCI)Af3}}QE|o3 z-gZ$-8hP8vSY+BFP*#@07|Kr5B+XDHgFFiiNeTqe_5;?oTU@*#pLly~1aEM_2qis?Y2%fXEEXKhxJPtD>Yzwf>VFGLC z89PtIc@AeR%E4=} z)wkA)-BzTO({J)$i#boF=r0%j#k@D4br%cXY6WcHXtrP^0VFbdD(gvSy@|9N6+8v| zDdCPMJ-`5olmUt-jA+~&iF(3OcPQow0xiTn;e;oWG@?mwAPU$Z8-CI4VPVDMMGH;c zCdpf(Xb$*UFpF0^sjaoj_2KH%)BdZwBhbsU-m|0jEg^`0}jz z)mih)(*_{H`@_S#6?&Ig4?KAsIn z)4_B;T&X2jyM=BySFS|TDOaTol!e$Jmvc9p(ZL`GYu@Hov)9d*ih)I2G#L)Nfq{I^ zxM`ofC~|7t1Q!7wH0rT>Em|puN_kH)qf`s7ZX+-qB)8V`yYmugYpt*`&CVy8tyvy+ zf_CP`gYD|sLHogJ|MK4W#nZi~*ISP-Hy+)eo*s4gw(Glq7CVR*VEgR2e|pq|hr3&K zcy@EW)NMy5!}RfH_Tn)A_@MA=C;P+0)qnRV*Z-S8ef+my?frunlRx`n^Kbt0^1uCG zeE0AE`@i~M{~!PIFaGHlkKgR<9k(~Os+((tlS%a6Jaw^`d~%$7c`x_=s`TB9)-T@= ze)IM8+vkICp7+0bKKknE=*^?n#X;s^>f0JR_a?6SNZOn04^NYCp0&RJa`uaFw!i(b z{?*&{FW=6;ez*DTvU|FhIonHrcrpH~-<QH_vw>J8OaM&E(NR@$N}$f4evz zrw%sDS9g1_uV*hWMpviRR~Oyq_gn9-`tL6%4|ghS^}uRM?`1qgU}oS1V75wdtsYr# z#AfyAxEdao0;>h1TlDoS!C^fzX~rh4_^1)>lmm^NC*|YA8X0y`5uJ&;*`UT4GU1ge zpOf_}oY%>RJZi}6_Bg?wXJH~+v{=JX*=Mwf!zyn9;Wkv51Y0yTz+j=rZ8wF9K=_T( zZ?)J^tNKOdB0G`;w~%mY(+)5!6JJY{fEuoWIqI-s4h(?Aj_%IkgyrKs zI#hNVIT#j&8c`gz)dKHA;WpZVeN5g1`_-~cT9+ka#Vz0oLvCcl>#L>X_3pi$(Y>wy z(X_QzOEzM9LctC4wvK(`v40X`mTP`~RtOyROJ|e%@vySn$*omly|mGe>#Ip`AMhX> z80LbbdyIlf*^u2&MXMcmOi7n|g=(_D6z&n%Rf=3?V)Xp}ZaY40ebtrv~mhX14& zy*rAX4Z?>VW3wVpvdn5)LQ2W)gw%?O&9K-A39X>g4k@c4*J{w!@vBX@R8_gMMAucm z@7LDi{DPVZ`8f1)8hbH`KOIINtwvAEp3RhV9Ok<| zy5*soZlb1Ht4?!S0a?mUTSddmE~2Et%-T?u zb{aF2wiUbij%DSx#dI6a1A@RvnxI&UMjaA3Snl8lu>o)b%@8oTO9Czlq{M?*iQy#R z1yVux@*Hjs^9Xo|LkiRO2x$vDtPvb3=5(ZVx)6}+34Jve=$9g(b}>}X7{CeHxR#Eo zv9KKQvAPT0no$(YsoFIkt@tQb#VFCl$QG}U&lN+%etCPdw>@7SHnX{i%gb9;aw#NY zX*W~w2}K{D&`Br1VqPNtz}K zA`5`DIOkWamL-ejbF<|$ll5m->{E>T#KGS3Mc8UP+~~&Ac`Y30(^;)h^0eBqW;0T0 z>WzVOeLw#A)%5cD=tB1cM1h_^qhmE8iu(s9Pg>2CmiOaDhUnn~}UH`^b^5Cd+ za8~L~eXB!bV>f$rx3RXBOJ;e`f)KI=y;w1-&0xD1>y1*wNqRQV@9fu4@Aa=AAM9*T zbQgd7^FOp%Zvz`x&A08y?l*z{2ZVqi;f4?Z4?v3}QAL8^Cj<`1D4UhQY&gsl)|K0) zJ7&8%m<(?n?;YM7rOUE~G@Bi+WVLtr;`H?O-Gi&M^XHE)UvC}X&kn}gsOcKD^qpR6 zS`VzXjB!J47o6p!o{uQ$01$!zW75wj3@%~tNgp5cuo0bx`4Lbd?%^Xk8*q|_gnI?M z%z({p0*fCkW(llkf<{%|?O+ho0vPD_6_K*2yj=wYh=v0&%3@`$sLuc@;|K?U9ZzAv z0~Br{Z19IKVdmS`mCr3Jx2(&z02@fViKlT@V!bXo;MGEg7VtO?m*kQ;g$EPg4h#Tn z0FZzj3+RJdp)eC-48qEjn8@Hj8ox_3079S;oS>jj>^(x3nrC#&8RaPvV14DeBS^9zEv| zlp~RPBH08;NM{!UU4jyrWm03nn zV;Cy+W3f8S7Ka%{)?rI`Y)iMSOP}GU&nepygD(rDN#SfBClU4vsfb!gdE0rzNF z%lF3FgHCK#@--u3Om(>FJ5F**CYMFZB+xdAu`iO)7MTeQ!NS?%SQN=cZNlvwzQ9Wy ztahXyQ|b|>0xF=Ixg=^4h*~Siw8Y~qWdQ*s$gm{9M=H~RUQQS#8X!U79UwpjS)wG7 z0bg!D3(&`Y^>R?u5C<*(|&i-F`{10 zkfP~8t(ooiOYKgsQVFNhI=cN|31u^SBCZsR#$;03+HOy#mEpKlECv#BH4>IU$%J;3 zdvL=Bi*F+R-#Z&Vx<9$TSigF-e*b)QdbE0W+&w?;?QPW$cAH20?Sq}h z4*cT0ybC7&dTDd5c(m7gbX>nUEIisyzueCL>U#Kp_=^|+kAL}#|I^>T|5v}d`;Wgr z`0Ic0@L&G(xBuP${vZBd|6l+0fAequ^yL=^Tf5cuwc^1}_4=^-_^9^er11Q1`Q26R z+ZXL0-t@kI-TUT6`}M=d`|Hk^PljJS9=^R;eSWWcb)37u7d_hw9?ZS>4x`U6D(_$P zzIZi!{d917ue!gPob-)x&*;?Ea+YqE_~Y&LufEy+%irAp;meID_bbOc$;18p-7{dG ze6=W7a>@j3%7gl=tLca5^Ve7X*O$FF7u~O(O~1IBJ=m^HtG-UsHO%`4dGFxHnNSX_ z)xzt|=z23Yt%paIz^ED=Rs#L9A2g^0hV}5I6`gewYpcm=D>fdPzU*1n-R#52nfUVfdi!9Tl~HPFYP!orJiWkh@8>n^0GyS}UZqgU)t9?F6*d zfYuGVx_+(Yktu}Hr)Xu4a2R#b_~Y|U_1*VKmvnqGEokOS=|2N z2$0AzBF%~vk9fhM@D3M;dL{WeM}Q~791&rNFpY;vJVe+dl0C49K>}1L1m$+tKdQus z^+dNEDJ9*dl&6&O=F^^J)EO{Xmx?pM;u;`Jk9PydL-U)iiQpP=8P48~D&QHd>+uhB1 ztKTaX3t`{{fCNRRMH&85_zQ8Gzz7^p_+_j0bF=kREA|;i-g2;aC}GKEkin=BjBwGU zRI2)FjbO7CDVKejf{>|Dow4W9)8WPQ(c_mJ*U#tUwOlge3`K=dL~*LPB9ofRXh7+1 zIUMvPqW(nG*Q^I3VS003ZUG^r<-ZppEPM!yXHijGE4spPLXBqdOJ(Is zUF!{l8(Z<6z4YE;p*!>sCXxN)>gm1CXqJk^X(LD^GE%69M7gbj>T`^`iUJ|0a;9+-w*;SWM%;dSoseL!Gv27Bw*Oe?+D>0$_PP% z)l8X9$o{a~NF4bxEmk-O@7O3TQO<50@9v)VBPkZx0%OwE{>ky%yZbLs4z3>Dd-?3* z<>vlrq}vq-6?Y>o_VZ!TS|>d17+u(tH!3N;5OZe3QYs+CymVM6LoOnsQ&Be^a*<&d zc~kr}?%^UXI;4_ejdJr=g<29FD++1V7>7nv3gHlNtB6{OEz6Y2uTpWp6!vf`hqLx& zeEAM-wZQZQlOT@DJewW3l_tUBA!U(O6#+(g=zuBGytI7hv!&agt}NZMnC@WK6%x0~ z9HA>5KtjZ?$ATUhVcYHGodU%;EH|8hTke2h12};rZ3q%>>J(7~f&_=1hL3L1Z|--Z zkcR;=1AkN9h@s$Dc$x$}K=vQN1NC<`jutKmTwy60g!*9tEi8I1BLqU?2o&jr5+oSn zMiNU(H^;Lyygo1nychgSZr)L18HHn=ti#D-P6ljxB$>8|q)8-K1P8hw>=NvLjZOrV zQp#7)hnvMnJs+xOgSm(nlrf)Rf$Lc%?w4l-JcM0ID<=gx-x#YCi%Nz`(QRyy3tL_677I}>ZBqqStD z5)T(+;bJtD4Tn;}K+Nz5b+1R!R6&wh9+}?+gBDJk*=9w;Y$$#gTh#AB#Xzhk!7^YP*@(YsU9miQ{%`w;Gs(RgvT; zNp7B#4(jfEgYflw>d8F+e6#p!xAyk1_2#hse7EsvmfLGbrv-P}PbXDdP*`?Tx19E$ z$@WiF;+D>=czFO|Tx5Y0?2FPyX3}nf4Ro*00Tw*INIrHj#3EmCk)H$0Gb&$ZGqbdf zCd~xCLJ?+;!4#2nIayuhbyd(6-lcGw#5x5Uq)D7x5nK`nrw|+_OQa-_JnLX6)TM#2 z+ZYF&pA1i-7O?1~TClOm04FbbR7WN6-fNKp$$tIpuyyYQ z8IFg$O|Ta?)(YccVznJ?)V-~Sx4RnbG$XaLuTt=W%6V9F^iKs;KkmOd?Y}$gzdKodd)Rz) zP=9++dv{oWcT#zGT!!)eN#%>P+L!0`FVE^9PAUKfH_a2?9hTl7m4PCFCB8hVE`pIN zFZU~tcdM7%<DRSE`ZWs8Xq?8}0mX+Ubv4{ZV^ubF#U+ zR%zv3e#PyVa;4~M4|xx&l}I7u$);SrPBIl&5-}N2q1(+2C*{qZ)wQiox)?|!ak(dVW4m^_u>AQLC3+ zt99RKH8SbP*2k%BSZg-RyBnpgwfy=dJsl>dgT&f6y*&q`zj1chIXP$@?>FzC_8;9F zogTFBo^;_MJO%p?wrkTtaz4qPAFVz(8(f~XAM6+IZ>B#SRQ}?-|Cj&!KmXVNt6zWk`tbCqaj;oB-K$-kc0iZs zwP%kyA6^W;dq4T+?dbJ&Pxqf!9y zU{LT4i~dO^IID$b_0Y5y9G86?t?0ZJnKgprnr~3{^h^4%;+ZuA8=dg+tavmlZLB5- zkP!ad3b=GDYzBfD13u2r(La(Y@$&C1EO3MjE&iO;K` z$gC8c+V zdcfHVYpXGLC!$w;V%|lkC2LkTS3QnNLOyDSU(SnfcWQ4p^Uo)V>t67(K+tl`p{5(na1CE~0-tpR6ZfnD3t!dVZYAGq!ykySHSV6IuG^*<1>V{M| zkXSuzo!Ds?JwWWDO>9Mxa@q;&@V6_!VSSg9O%S)-4JiQ3QDf$-@hN(&VSi0ooE`ZBY?V zxtMau*~$7R)dT=-rx2{B-1(?81Lj;Uk(JFh9RpeBZ-6v z9O9K5<;-W^PCQbfe;%4l*Z4 z{iB2K{@&_*UTb$!@q|m&9IRjwB%7|Xs!R(UPLUQAU2k7@kQSQ9d6}Ykj1ldk)8TYE zd_f_b(@Pb9vl(i&!`Y%7PB}^~?d(zK{`KJE$@uB(jl=Wics(^*OO2+PNSsww%;O<- z7p1AR*DZ$pddTleWnft$YK>4jtA(Tgqdk>j`#(ttaKMTQgf;*VELOzXr~?W{&<-P@ zHaf*}J(AArnS!(0(EG#C=5}K5AiK4fT^$(HdHm#V>*Q{`-3Ax26hu71PdI4 z(sOTW837?6NU&LW2hNZ<;lSXpy<=ITMW)gbhxG@l1nMW=4OBDCYSx3HRH!~5qmMt)^lD&2ytgVs$@c9!pFwEOw>c8 z(arc3yH~XN6+EPofCn)*n}UlltR@U0?4o=!SXw6SoXtd-K2=$3DQQf* z#cnMX)I|nca;z+|sN@k~r4?1W#6Fh1qzF_g6*xf>P|C~4;7g7I2ECyL;DqJdpPFv} z46Zkr$ao3^D)6X+->rnePW9_yp9{8uA0*bn5>_|{IKghd4RTmk00S5t<4F8>NeC>m z*ldIiuHgkFEUHO-j4!&$Mj#yk2|Nv`KnX~&jhd`|?9K*S+zb{-y9i*gXoe*-4uyr+ zcStNDbHD=t2EZEx(8A({yZTWeL_T!lJ-uMLRT> z0yc2*00SHdW*iqt{80jGxTYbm0xFcG0f`AD;DLc4fdokKhz=N0H6+v{jE{Jfgx{6+ z>q$dPc+`a38FR^Drx=uZLts5T?Gag@B7}5j)X)2s?rb%5z8bpQi#`}7FW2%Z?Zn-muk(I%h*X~!HWt>1)WcW`X!h7fqh zE(@flFhB?%l%K#MNRR;%IG44uP73A8&VG?X^5uihu{ld#&Sx_VIq}V6VQr zUD@6&ZEob}>)B>4*r@pHWq+*%oM05PZm@%MDR(L7%V+$#w2@AD;!!;s(jq}E8UkAI zBw|K9?u#e=H;N?|+X-Jd>H$13{7#==HGEFk2n1a~3&F5%_*LB_DhesmCJ9b;dPN|X zoXm1qCtEq=Xj*=8zV=5ikA8T5@ZHt?{rTYKe*M{2>G=-W{f%$$^%kK-Wx#_Er`0d- zHom#n`ubk;i__}6qte^M;_ukt3mA_pU!LBiE0lo{p6=J59yA_omA`ww{mtv6LERtm z5viEeX~tH&*=jA8$%hdkOxokM-gG`(-P(J4?7r>ei z6f*8iQY{sXUN^nAUYpGu-9bKIjf4|gWD#6+<1zRcYm`KNl;bfam2~B@-eSR5E(L4V zaHSl)$yx?rSZ&9)XW8BL{O-K4HOm4jOnTALYIq3hgu2ZDsNW8ay3t8LJ{u<2$7$dM z0EYERW{M!%PzkWUhLipRiy874u_K*H||Nbxk>3{jv^Vb_k z2i4>4%H4y;y@UGIdH2O-@7=TUSFgw4z8in>viJ01`R;z~(NXbeBep+{9<3+u?qnbC z=P!2GO$Nkv( zVf`Th!1egM5BuMLbM*Gz#^Wc0t<_I=p8x=eEa`PQ zW1&DU8OtZa*;p{@ce@pyBkXqbvSs;m%gP;_dD)64u|@C#GClwlZt{)oATZ*=lm`nQ zgrbK~Pc}6Bp#UVSnXubnN|8BQlXzVbHIb8Of`j!GB_|-=K!OcH!s5jjKd7ENsxpIY z9hBP)w1C-6@QT(&ER(}V6E@0WC2h-unGjEy~4w_=H*7`q+i;s#;1kQFyrs1yub;t0jSVT zc>3wUqzGV;S+8a{>bZ?NY@}!9_@o$~7QTHJr5|A1}XFUL%puh&8LObeehoqX9Dyp`exRjTd z2SLX{+5L2!_-e26)ou~M;Bnu7(eXSRh2Cr=-*0DLti>L7y~kDOUQydfiK8&xG3*T; z2*FZOtz{LfXjs8%2S~`tc)>}Qb++miYlc*Ii+PQUDU6>ZT!dAyF3~Hu2-7Xfe4DbH z7>5P7tzcHv)MC-j0%Rv01WPj_FK~hYgaBF;I|6z@cY0W!1VZ2e4|ob7Vd3zH<(qZ! zoX+!ZPS80%K$*j=Ey7_T&gN$>HtKu3s|Wjo?Va9WSW0CKNwF&;Aqx&51fIhM zShFNbRu~DGL}g@+R$Pozr(GV(>*xGICK{KDMR%tYDOA)*nkY5Z{j=)Xqt&yAtB;rv&JH2Qy#HZ4(SPa!u(p1LlmJN>-2r-7A3`KZffCg0fdl3Q{>WgXs z3zmi-)I{6vpm5PimFt;mGg_$liWR-y()**p?tbe0UUh3H*Bb=po7wYw-NWN%sR9cd zmPkw4yjH6DfDr2K@aiBrn&qeS;^uDc%Ft{jZ7+PHr+O@d~P+P1}GNO?VAvz z-y?*T{{bPa;0`lpM|Dwc<~z7~iL|UxRx@L>uwc|$Od{C06ybnV&$0~0k?c`>o0E-` zz4jn0Yj7q??%>w^@av;D_ctFOoj!a1=~b-w&HCAXGZEBTSoK-EiFa7RW-Nswhx6nP%lnx!bx?y!Ot___JcCo7--6h^TAnMG?Gm&^hugbej2 z2FdN@Rgpp^Xb6<>@Ucw9kIBklqXQuzUja?t^hdk#41gGva*aF;gw0IhHn8x1CmyVP zu=Rg*3!r>x5`^)DO&~E5Y%;_NI6wl}Z6XKs57#yY3&x`88Nq?w#!xH?-x|qLG*2@E zYShlb2;ynZ$+8;DstoO9 z(@85DqiSqGRYICG=5b{LzEUhwPbXTrR6CbyWs-m;n}3v;ICYp+*W6!B7*F&l)(z0hGZgM@4S6});vC}to2i% zNjEWQMpvt$Ryoip`l>l!DeWm|{l&DAPa2t+Clzrg!wW@V+nf4vjECG2zZMO;Q&C?! z9!$jo@rW-PHliUT95Vcd?$({UOVQmc~9-q(c^|&;Z7kP@KtUPH^7^_#rB04=R z1@;DoC;Q#69&P;M$<7Z~^DoW@FSaZ2b-X?Zr#o!sO37?FT4`lh2c`CEu3Qf1GM-}2Xq1EXQXm@OTD5S$ zn;8yr<7s)cRxeZ|dQgnze9@RQ5mx~Z!1Q0#Eb^pNsPzG$LME->R67MEfDutd##1T= zTFu1TIDfEN+*!|VjFaob`1&ZZF-gwH$=NVI8^q_6%%~e~*NtY?)2ew_oBqLS_{Mv1 z0GPL)-(JgsHfPz*X=ZPuc)VNN-zp#P*6$v*AKe{X-XA?Y@83UJy?!`(cD0Tko^&1^ zx1ODJzC7%_+iiR^%l&e<`rGsNpWN^K=5g;=AEv+lYW}NVAO6kXJpSWf96vlO?~g-g zT=`ttF1S$w_d-Ry?ilx{;dD_vi;y*_Pkc_uJpU-2TOzefaP{Jl?vy(`*&|e$}o?n4tk_gL#3uT~yG|$0AB1BIeVsaX)!} z+C#6hF zs2T7u6P#4SlWOE9M|oTc-VnmL;+t0eqmn)@duBCbqaE1oMGi*s<4NLZ96ubzHsK>} z2G&|Y3$g8fa;u-2HlzJYxKj)i6MEPK^C!&z7KOEQqz$*+v8~)DF|#Vt3BR5Vdvmcs zD&!5i6;+^F0wXYs9Th{hzLd3k1}nW8!_9Vw87ENR6Wn0|RIu5AA#QGAq9zM= zn`LFmynGu-gSJ})3U~69OJp>GQaMtF^@Sig+(Fwg!fM6M7P}d>YXA$!Vzw-sR*(gR zdeC4N!eJo^GvQdq?MtZBl^IY0v)fQPM*?$TV3yp*O`nqHTRLryx|l{>U$4baN0rNs z){~vp$D7SZv&v>U*bYl6(W0Aw%6;+^;j^E`*rjev-D@T;=k3Sa-IIQCy%Yv==qEkH zv@y>5M_GSA>s!qk{Q`XK;k9~fy^&a}CuV>X<>;goot7f7u~v@HtI3UOYQ3D8=A(mD zpcC_MmDGcV_p}?iH%i_crj9%D?W%vAb@vnMYQot`sGX$RN;sQwxfI*a`p- zs0$m)W(NCOp+%4!=ZPqbhZ!tLTR|b#1`2Z40Bgw@Ts5k8a=t+&GOR^cOM!aEU5YD( zsFaSl;z3u?3kD;nNfex=U_0qf!L5ldm6s)0x$L}P3x=Gn)y&3rXJfZBm=*H{!^K#5 z?3T(brvhR*<;p}vL$gTSrvmdcmiZ)=;QPJU`dVRgv%0;gTe`LZ(`F(VklZdt1v5Ya zv6?39x>M6Nr{>f>n%i(00X-OY`2vc^OZWq9EY79UVmu|r(n_frnD3U)9u80LcTVoN z56-IVJE`r%{NoqX*+wE?bhbLddLtBz$sS+~4`+Bex1TmboHxjN{EXYr{Cx<)Y%_s* zv2ey=7!E%Kj*~dS5Kf(Ib<6!xq1{b3I)P@#+ZzUU_EQfpT0jW>L2zq3fA?N@Z@-$& z%O1m;$*F}B3NZpgXs$;46%Fzj6L(^8D@L{^2AP^e!)b29RJzkgx=t0G0tF z1mqw1PZENIfa`Wa2&UV1(;dRR41@r9z@b7$Ce(b921~=XY+hQ%OnShxcC@{9eo$&e zS zfTK2*sDzsx9Rqt{KO6&`fU>nD8hGF)QyJ!Bpasly%eHb0HUJ)2!lLkmN9BPN!af%$ z=v9$pK^C3xE&wE`5w*o(G5zRL_%ZR|_fio67~rWzW-|sP^ED6Jg}rjvP=bENXUHC}sCjrz=YSAABJUPhkH7_0 zIcd1_zyPsuH68&l=wuSBnM5~>w3?2!laXdD*ogXb@jxo(PegpNkT(+a1pRK0t|$`E zGZan0iso?OxE-zmD`rN`6@VHR6+SHX6(ER33@-c-RuhX^6vFCdu&_iH+)TyCuSSGX z8mPdvQ}gV%jKhv`wCdZb`L=7uR>iwfa&MIMt+IQ+;Xmue9!)dX>$xZM{L{_C^R3d0 z?edGQ($jhVa*}*7Ky@VIF`vgHgVpZ9O%B}5&~`}#K;jjNyD49Ry5*n?mPRd_QA-5^ zPIIeeiNGyj<)i+a91W5VEn_y^v!YU z#X;`bZU*#XKlkRa`1Tli4_@!*-yf9#557J_gz(|8^x>fRB{0Kb>HS{edNX&iQ~7W) z`}LRSS4Zt^luJjLdc{8;=O>d=y_GDK!<|8;KWPl7t=_0nu4m)vP%;~?wzIWPzTGV} z+u2GbQp)?w1%IvRD`wn4#jT6Hii7HiQ&){F2UYos%P1TH{=R8qSMD@vkP z%BbKefI+1cT;M?a>4f^?`z0TtYqX#GLqwVtcT4r;a-kN2$*Rnh7x$X7b z#w;`GM+cn{XxNPmyHOZNz1Vb^06bV5CD#G`W?94u>vfYe--Tt$a)mK}U_j}EMdOiQASMxuA*#GlKy+6M0eR17< zb5XmzsJwkUeD{2Kd0u(Ao4ejFT<%p*PY2i6TQ6U3K6|!yb=AALXkCIHH6PxuAMWIj zcZ&y``Rz$+dy+ieDL%d5efMPa`l|orr1SKob8*l*nC2(VaJL#6x01b9wpNTrgQ~95 zs*J0$-Eh;qnD6`tII8`m-0m`T4yE zhoyAT4Wj z0%k1UXc-U#MQ6g=i7(sjcQD&+U<1N|x-FPjELOAKZiN|%u$w5`Z3bIn&7bhrPj%vU z!ihJ+@+|K==%g;!Yj2K*FZOzmX0_dVtR0f#9O4Ac^b;R`E6T1kgVI(tb~Y?sZLD6* z+k36dG#?zKyub;AtgoB%_VUKC7#NpB(`sZ^i>=k->$SvMEio;{rsddLIWe!MHfrh3 zT4tk?UN5C)g~T|;P14+YPT8q?PP)c1yin0!r4kFpk_*LB*k)+ z&IcW3pIY|?oBm+i?`?SXno3ojWXomidTeVE;o~iYA$=t<*2AQ5JFzWKt;t-(daTF1SzMB zDHT>m+Q$RMWdS1 ziZETr{V+er0|YjLFOJ)|!(?~h4vLUH&RjL$nWihfK&2CGbrZc&d}lv=d0m@r=KACK z!D;LKVSlooiX@3Z#GcHG`Lb57BSL6(1+y{p-i*L$jK~yAI!2AV-Kq*bQ^)tKeQ-}2q ziGqu)H0EG1huutZgv|0bg1xn3U0OCvv2=6yVQ=SQHYO*Sptu z??1nP@#^93L8a5;+Er$!>pmI><~3uK*Xl8*7_=wdHlJX1(<>^uq*2Q*)}nJ(k7zd( zGN3Ubo%2Wzw}b~=Y|IejJ}K(q!)`VT+$Q5b#Q~#>GYk0VtnCx8XdX8sZy)bGI_gZ@ z!EwVkta;OZTxUKDNXr4q>}KvL#EMMV6cSS?J1Xh(v41e3A%_|PrZz{|7{?-y3dkG9 zcAF_2wM<60@WDXmX_;rh_~vMwbXXT%4VM7GET%hF>k@{U2*Sp4q^$6|+v)Y`ena

~Di>82VIOIjEL-g<>xh<2D@4@cWzh6jl( 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�<2H$fbv_#Noji=_A>Zyhqf>6-`Jemf24Qs{?0vz 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≠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

XqTA2!!0~e) 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

eVx(9)PdC^@x^ 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

CRB8PA}VNCX1zTI^&DR98RZ3spRqb z6b1uBAi_|n86*+{hmS2Sk0V#6@Pv652O*W=jV4aWZ%9UM<$R!BkFRwz8*BNkjnd9$ zd3Uo6d`Y_zDHq(SgbBnXuUlfb^2|ntUQ5;M@ESEnr9`P!XoHSmv(f=Dc-=gYi|h9S zs|UDC76}8xr%omG`K-BIbkwV!R?F904fNL|+dJu_lhWP$-DjTLdij;3kG^sH%}+i2 z>{~Cq_4bQj`0{IC{`wnV`TEDd_|-Q)`-NBE{Pc^jee9VRUVZrRx%1;&+iP3RQX>;f z2V8!O&a9NE1SC2hLt0rzEzZJbAhQz_(|{JnE@}zioSd7UhRs5k7v_;mOBf`QfWgyA zWDcD!V6(-1o?IkS%j9~s+HBC-%zB5#;Ix@sc8kYp^SOcSK9|$)@q~Q-NFWpoMH1my zGLlL~)9F|`6-gz-$ygv3_Cx}%u+I_l*{vqALCe=`fcfC492ZWJH^0E3IwvNr%2K&Bqo92h1Mnwkc7e|&0cVg@=j zKR*kDEiA)faQHF;0bf}`E-x=VPJ#NH8G{MH0OR8~A&_B#v&Wf;Adu0?$(!R7BjXb{ z#>THtL9W6U#&MW=CLJvjP&6v8!=?-dfb+0MBbH#m;BqQVM!s6bl*z~hz8!K67E#s*qorRb!9Wur| zYOh&rQL}YYs*H;jG7v&0Qp5sU5ik&3DvUv#qhO|qNC*}-iI}~)0J*X_brmr`ibG73 zvGY_Sj1Fu!3k}3!p@7)Hf3sGYzY&*%;q!1JAz3!ugi2$x@L24^<5YEkv2i$gY$MlBAz%w!TeoHDCLWH4~dCZ5ACb~uD?x5Q*-DODtk zg$)QH7?gXxVvk20aLNEAXrvUajG~rM1WXhOH3R;gYzmTsTcF|>SyVU}>bXoLi?+mN zB7AQ7-CL{s`;~m&?r;ii4q>6>e&OZgx4!uDXWoAKvtRh|*Z<&CfAVKv`qMxA(s#b| zwSV{T{_xqSPHkqnO3HGW6fTQW1+F*x3YUW5(U1TMfB+uwY2XOxBk1@AAp;E%f=Pf` zHT=DP<<@>rDIlpuWPk@62~`cQTRuTJEQ_|nqYj@dVPgOxfV*NA8eoG)Ox4Tis*A^K zMMSfllJF{fRiE3;kqVIp4asWeU6g}xgu<>sz;3bX)EcSXuC3P7FT8mB&%gWCAO85S z|L%YM-SaO$uhuKodQ~(L>UQf#M?3fLoz|+^RwKKyR;!oeiLgEB)&*T!pIzlPOKp0g zQ9;m4F$Ou-tRz@9WB?3S4b@}eMZI#5g>Tg|EE?tz12jyFj$_iW^h$8Npkvv}vU*RF;AE`>?YHR*WCjdy}G)Zg@ zgUe$9C&C?$c_Zm?s#L9pGD+zDgh+;T}rP*;jznt9%U@3 zjfb=$pCaUw#)7I;T$4@dvngFBp~)mQ`HZeoGOx8G>z&woF9-->Yv6nEApiT{eDJ;h z@rOV8$ps<2`{UteFPDpPN(D0-wRbkV)zw;iYp}YvyLGs?d$7~(R$W#B0X;6H%{#SpDGQEY z8bQupMb3?`%#UFZi-^V9rNxE$*|}LL7#bG=AzZsLIRTmH3goe5q1tIAYcXrkC{%Ny z2*{1`OOw!%Dd?~FE6+@gT?ll5fM0(M3B#$|Spauo%;FG; zrH}JkAaS@wIAUsc;U;AI>e$2wN5EH`RZk$D}WFH8-UJ* zhQ}`im|>`Em!7zJ^@F3=J~%P*#Ps-;`I#H=g$Xob29KU6<6$iNiik&0$>;_R7hr?K zBJnttL7z4jHpSwWc+v`nr%cY3D|iYeZ?WVnmc2lwiuYo%&9Hz2Xv;Nl#9b`A3T0=h zY%f==m8$KrKz~^CxMr`_9gU`|)%J9{zSXth`bK195WA>u^rhT%4@)}-#m(J9e>2lrivtH-sCYAZXCh+_hAkeS(eBikt#Z9ltkw$T zDvnr67l1YKC1g3e7$&x}q^U7vtlo0z;h z@oQkX0-3%x4ZSvGhPmr=3nPn5WAK$p6lMmGU%=t!fk1~yTqIMLsMKZJ#r6gU6VB$W z2!vRvjHpsmwK}HB%(Xj2E|1g~P=+F!Si+FXSh9J0zT^OuRjIp&`$mRy4uBRs^_HvN z9;(#?*x>7}`_~4c{!VmbKe2U`-Z{zcp62(@3WvAK$9HPO6-Rd)CwH5-9`ugyG!M_~ z2WPd-18_kGi*-+XE!x{iG`rzuH?qE!-8-u79#+fskXTLvL6kyYX7ey2DOn&U;zn>{ zPOLx3o!%)u^K$#abJdMKU!`T(+|C>vR~|fEzkR2>wG*o~^qHKjP*SJTlC44U?(L1i zMyk{H?(b#q-f4H*0k=!!^Gd^EjY>sfv6d`W{?T#sfen4> z)zgoB@}<{5^UBK~dlu-8&wTiePrv-)M;<*OeQc9PiJ3GQqK@7^h#9A|cSqJxd#(P3to zl<6q9-VcReW~*7x?;ef^El)^2)hFVpNrEKa`7BL%X!BxZ-$;uPCmQjcF1ju{du zOR*fR)#HsuqSZ>bJK1(SS8t@s`^&Gs{gpSq__dFH zVaN<0dGj+bedJ?LKlk#TyN?bJ&j-DYTBVtZX97;2S!0w5q#P=Xh{P_+$ww@Oa4BLVy9pp#%gmA1@P=RWh1VMw5w10xpJ4N6^VI z3UMAwm?BbUsZ1D)hvbVeQaM4Tp&Csrn_UnLDI*beJf=-04Y{m2pECoJ%%t?mgtq9> z70v3TM(mfc9bAfmh1bx~QYunJhV#fvY%+{ZS)$WmWYQcO2U%Vjom;*(y?A+Q;VJ|+ zF|{-~hn!xYi3IL#TDUC*fUdOdq zgeDVTr)TT+Y_o;$bcsD)nN~-YNU=r}(;tvUW12`*6^^Ll0d3GJ1NKxcAxpS8CTWR` zo@Ef1$(SJ|&Ex_?`_9JM+1mN(+VNp0>Nkmb1i66hG)mnjnSxK`Q4t*SvVgV%Pyz6OgpHGO z@M0EL$|ZnS0{Y+xml$^Icl*_DHOZwSrCb~^{R#n5DJ05xH~}3Acz_RDHbx~R$$5An zrH}-qkx&33$oT{S5?UeACZ|X3vP#lokl-cUWdrc;Mz+f?a@wUPqeP?P2?Z1m8-H;T za`SoTg9mG0`pQSX{;jV+`_i*^w^gN6INg?FDZRJ1asS>)y_U;oLd{ybkoHIXCZ9v? zvC17riOVFh8-ykW(ICSP=MdB+yO!$E(d|0A$IJ^kC2kYXs%6@AY@417WYKX=8n!{j z(kU1k1w$!k0rRO-(DX{WNkuiQsE-LjH6#SGTu$5FZFD-RXh59~t2bK#fCpQ3*Fh_G z-p|!zrieulF!Fpxo?FLG2X)7rrNgaCvm6ZjbxxbyZk6eDe8ojp3E+IpT7gq10`G;x zqI6hPCcDY%vO0oMZzAW87Q&hK_Q}&9d-IF^!HL)DbXm=IgVd(sxQs%-Q|YnEeGa+T zF8A7`L6;&H&_w+zzf%(SNt0o9E~zV|4TZEmpVsEnnqp30Etz`F&{{j%@A~_zZa@ei z7=8K6=l}h`fAc3l`M2-9^Y`z*`=kFq2m#!F{_~%|^X@GPAbv;Pwz{00(+gfKmaL{YeWci5e;XY;jazUpiCVuS5$ zvlA+neVMEy5;41+D!raBky4l}6oEL0!a$anr(uiJ3-gd!==c=m=J@!vk&#Q+uRU?~ z$`jYFK6&lxC7`QUp1g7y2ps$n&^6FrdjI7Q{oa)i{od6l-*f%adv9EM-^kSqT^s7= z_4iFrTmta}L=iLsf(z1=*$-2m;$t>*DrRbbI+mD_yR}a)m%V=?aD~Hby&DW~dC2@%X4!hb8|O9 zyRbOAv^;@8Kvq_!QK+dE)D#vsgD1=qN%LgNaCVzQU8K=r4AwH6i{$Z9LNQLJAZc|B zvxVnyiTwd(B&JQIjG3GzSFq+v)&e*);6&9N)rPaybX@?0r`Gkx`rFCfzCJ`=iSx_qRI-dSdF-VhZzeC(g|t3VgMt~df&I& z18o2}+Dh4Mvr-Luyk3Vl8VPPUJ(E%7GRka9zOxZX$0ceR%wfXsZUol5&O%z@bU1&dwX>x0*+%+07kK zt7`(BkjjX6wu%q$4bIQ%dwalzm!EpHc5+- zle6aWY2(hl-h)T|dyfXMy!qlQpLhvy!YAH-{fpoH>^J`Si{AwLqqqOyPrmf6KmNj> z{@btq(I3D4XW#kCx4-?RZ+_!bU;o-CzWk*(-hA`fS6{vL@Zr|kS?B1ezOj+XX3VWt zpx+Ot(i)SA=y1~F2}wF5-QEd4^-T5dz1-8!RL;)h{WWW^Z8+TXKl7+~_f~Rq-Lbpv zy>*s6KTQEb*xd=;xt%}Qk8iB|IvwZscI5mF&_!l*GgPnX+bz@Her$Uuvbi1EJ;)rK z6v5@RI!Jcc(~WMdSo0?`Hh)Cx^h#|`p~cR#*myR(*lL$rZ4#SZ=5nb*A#*z8EtjK> zMylP;cDwm*H`nQ;o6Q6m9O4PH+aoucIWifUK|zsm%c$kKr8&sL%m{3D1imdC8OId;*ejLN!rT=Z@V4^w6L>T+TKiT4q_YNvhVuqHAg;YjK`Egzu4y$I&5sK znfV*BY!N9+cxUaFF@_#7OWu!MroE`c$6YIJJi#>CB=knz#!$q~r- zjma^<4->O9Gq8nu1RRE1fuWI$X!tU2Wrc`Ak+3TS3=)SzVpot@Boc#wBbVR^7#zO1 zyga`In}aPvVGH1?Kv3i|1dp936PAfMzyL5Fhv2lSl5tnSYgEYrf}qhz=-9*f=u0N7Ua!Jx5opwOsRYmGqnOMkDs>JB5CV$@<8YRFT$F%|=L2zYpd;cDq(ZVn zN>j-hKmZSTDefDNdm1sVm$;=*~t6|oGbP*W}zg7VxRNid{}Ck&a4 zC7ZQmL7TB;Ql?~F8xAPkPJzwBa!BYlCP`05%P>nqEfT1SgL^zs;rf`Wg0fo*d(RoA$kHF>=I06Edy2NB6`CPO_ zh?9%)N-kJxQA*0Q&wYgPJr_$k2SgaC@MQpQ6jV8WE%hYHYCNt0Nm3h2!t&T2N5Ue)t5DXH! zU|8WDe*3HSJEcZ7Qzaqs7)T;|7QZshAR(xDn2=2X9WDbc;^FyhG=(^eMvnPC^1uA^ zFaFW*zkYgD0T2ZUDiTsuD(+$t7!s{Npa=%lKCi-V6XT}=6$CK(M66EIe!Je=&; z7(kSAhMN`u9)Kf&5R?LsMc%IZZ(>V+x;%J%c1hRbr!2asp2R#0)d#Wl(B4j ziQlCU1?>T!#p1MB-8N?^8c5~ckz6QQ-#dBwjgNhPV{q(s+Pw~I$ZZJNWp1+wfPvF2 zc9}(Pi`ZwAM7*kGNEi33d^TYssLaN+g_OROF%~oWLPlH6>M8|8qiX4ZklKn238ClS z-0W_08Qzy;-X@s?}PhQZ1KXLa~A!?fUOryY_q6FMr_L<@aB|@`1-4psSbOclFYHuRQslOCS2(YnR`9oe0Mv(VASg-HY)io?RFR1}9p6pQF`8C$CrnoKggUFGrUgF#C) z>PRNs>9jYK@ukz&blQ;1nTsWW0gh_bb&*rmU9WpUJG@(URVu@&hJ3-2&6yr6S1=W; zrc%vZX;^Dbd%fjscHEs+-|Bj>KZtB>#W#17+k5G~!`$IX@#MUEej7ye_T2}aJNMRa z-`%)%d;RRz+Ufb~(Mf0ju(`ck9c-1ly>z`9tyDw#qBoUs#Nw7fNayx|aY3p#isVYZ zOu>`NI3S)0L^Lj+!se1#90Hw*B@XvCEMssBj~6K|!66H%N_iWR?Y+#wad~IIP^x%T8VVl- zQ7KNNqZ>?Yg^JALEGtx`O5K;vT15gP20lw8z}a*-lM2J4ZU{Jw$*8*9@J9m*25DBn zg3}3ebo?v@Gf6^?Q81$dCe)-R$b=XMd3Jg3g8&kQta+=B7;zq+ z!Br`-8Z}<4A(&0HU_hKoYO*P9DR0_dk0!%1t$f92XC7?Ex^;UYtq%Kn#k_WBCvxvW z_5P#U{zyTI}qketuRvJj@>*74F?@pPf~Yk1KcXw2x1!AO_2a1(oQ9qQl`5bXTJro2k`) z478iu>E3#B`(&_twsq&3^A}!w_9Jh;{O0FA`h~B3<`4e#tKa_ax4!%D|Mb87&A_WM8jo4@<}|M(yO)3?9;wNLCGv}H=F z$ttkBg?clS$(a*Kmdtjl1Mp8l-QVbdPZ4_1%P>f3v{?pmZ;cNI$3Si;~7DD6(M!NdhuuTnLX zM#ItScm|`;Vv#zXsz5-W$+)YvP^**Zt)^G|nf3MJR=>U4suVNPkk@9`$;CVx84nCF zWN!M#%;eP>U}PsQ%|I?M&fUPGrnxMPUc>Xbw5f!?Qns(HhWB=J$4BMk!}9)aerG$o zy_s2GOLSVHYT2DhnL`1U+bOnLcorkaY-H0Ktp@^~$Ng;9SgC<)AhqPFxfO5 z0S#YSnp>QmoSC>WcH_#8D_2IYULU(LGBJ8{a_lB#^v2Z4D0FOceiE_(8EPIfwJE&)T!Ku&Hkc%CuRfl1 z7t4`uFW&Dbfm*FlE@$`q6$S%CAXs70=ZORe0Y6D5UzD<8FAMl9LLo{dLJNgxv4|iQ zGh`Bm97xKPN$3(0O)Mmf1SEhBY$l39Ly(CJ1l%kh2L*({Vj@IByh2X3*tm8l-{lc| z{jy+48I5X_DPt~YD-~UpvS(PzBV~?;G#;netY^x_ST=ouN}OgRp@QXk0enHY0u!T` z1(+r7$^s2OLxN4B=SG&MuK+DTuPn}9U0xbNqah^n!f>sr08bS$>0&lh!lH{96dsAh z!IL>SIuFMZ64(L^UqX<`2y!J!sUoS>M2(uLRTF@8a=b-N_1neiu%Vc8BqLUrRi;%7 zbs7<0K$pt62D8#+*Q$+jsZOM|sf=!&!L7Bp)J~V$?a?@#N~=v~wMh*|fmX-S8@Lvm z$my2(gBp)d4irxsLF@pn!zI*cso>*a)HAgzxF9bT zg-c)L(-xI{tXhC`YB@oh%&g)7`ws9x&LhZqM5TcIm=L5qqD(+$lHoiCM$9Er@JnnO z+GSNm{1z4!HOzu~K?o`_SuLT+_;>&SLM948f|Pr4Tto&xdi)rJlBtnWfz*IH*m%8w zY>`t1HRWBz4X=G&OaLW)`A^{%ZP+PJ`Q^EYx{%P8Qo2$~TTE+8SzWbg zY*sDZAt6Nj-N5>)XLH?ib{752XLkSkufOz@pZwW7@BFuS-~GY6!^}kh27YrJ62iay zD?$Jr00aNegz(E>{p9cd_7|_c`p1LKha1~_s~g+RMyFnH*J{mbwNa_me`hrzTuTc3 z$=?t{RJcAQ1n~tS2!2fnHeTAyjt&Wd4hX>^r+JOyTp_-Hu<^{p_TBSxyX16e8Gu1O z4r8O1s}Jh+joRwr*80i*=E2_T>S{6;&`Xd4>J$faQ-GiF=ol^?gF~D}&Rs_>-duo= zBA2ESOY?|j7#MT`AzbVun7@AQ=G4?Ihb{2O1L<}$Sn%1yW|o{jwKxVKVR~+K8agZ; zKQl8VgyB|%e?QL#Zm%`gP=2)NaR@zb`rJ($l;0c ziTBgD$U4LRZZ2X2l$0YcIBYwy2$<$XY)Gdl92$%)I;Q`hF_N0(p|NW?V2DKZJpVqqm> znpVR%fe7K227|J2L>Y^#lf$@c$Yj7sZ3aA$&KToyEx21O+J4Opbzmc0l_5nq8||S0 z9+Yd=eA$#O=reg;I;YDN^uvrm7wW7Ax@)0cA9&wre-K;WjPLH(4h~yK$DPx&9^iy~ z_ctFr+9=5Yv8*G-=)^qh{GMkU2v!Qs>7YsYx zUX#V9)*Gd2tx%@m@C3sZN{_`Cf<7Pz9F@L8qQEH>1d+Ie1@M4^F2g~Ty*WK|b$sH9 z8zb+Vn0#Uq@+1&s>dC3;OEb_bbMx01VKw5JOMDnJe9h{V8B^y zB%QuQrp(dk3ryA$4@624S|SCb7*3|ZtF;uHi|-CdB1v63Z!J_@<%YM`3IH%@bV7g- zn%xNK1401G6dc}w(qb0?Lg;TsyZrz-R{#hG& z7J15PqOCQ3YweidB_*P75>O*b5yJ0aCj#P3SZr3IYgujF$Mf45As5GEWh%r-sQ@nF zBe;xt7G+W{glQG1As7e&7+{rBgordPzrTh)`((#~GE*9Qhso-c^w2{s^v{oTU;UT%9E z`04cNX=QUW(d&h`w$mGfl-DOwYe>L|G#Y-JgE!d9Y;2`Ey%2ze{vh67jjio;n*C~T zs}0&@AsWku8mr~o5077Z?U@h1_RQN~{^Xy2=No_ZH~;Q?|M*}2@%w-EvtRtEzpnt`S1SXFTc5W*bzwxMho9$W|_=|bPaO20ox4!P(-ie%?70+%Dr|e#Qb^q1Z&p-0Ut=B$w>!TmP{ra1CUjO*5 zkGy{R(uen+dtvL|gZ|lh_u#Oxu~}%fWBGzF6gJo$3V;VX9bcp2%H?#v0MF*2xjeK; zOi-$5Is@BolScf`RMcN7Bzw)$#%g`A*64Su-DbXCP9~yGmrbpdGJ$15Bd6w}S0`?M z;M%3%{m}b=cVg_{%+J0LgSy6~&nRSQhmDg;=vI4?gZY+l;5{tYxKvrH{xa2O~& zdI7#L35DDkzj=N9#tq1gYm?WnPF%Y-aSimxX2vGxCLa^R^xV|U{PgU?^a5-awlu%I zJhbvlKuZfq#OxAmdI>hQFh4mxbz^+=(%9&b1i*+rK6)84aTSom%=8GL2+*GxyF4*| z693JGj!4-lL6;&P&__{FT`<#L?V}hXOplDEDl(04uJvwoic_<$&{#B8Y34-Z)5=( zO)QIrZMSn>F22_*N{2OtxT#U_^y-mLHJpyx4Jrw#6D#>51y88r zsVxeVS8wqf>|UMMrw@fJ!Jx_Q)_~8N$t*G$`DUxg;gorNis9P7inrDXc2^VYgLHQ_ zmM=MiVHF?*0T0O=mNrAP7ziS69*>@-laW9)5(0;sqY{@G6gZ6pqY!5CXoyNq{M4Hd zpT589v2lzVVm@U6s+1g!sym;xWYeZ(Oc(Mi+;)N8$k8dtRyD(Z1P07&kae6u4s-;?V zbhk|q@+w0vO5xHksWla+*aEzpjvSxUFK3iS0HpT?U5R$nsgZL5C>h5czFFuZ3^du`L>= zRm-;Oh7$-DE!U`K>y=EMoS~G_q*5TNQbJP8C|VgwCnc&SB)N$A|6%Mupc_lmGfgl{ zDw8G*y@w&Z_uhN&z4zV_07;M_0fGcU?->j-yvdBrh>VDIm6hdHrINa&9<`tDX+P85 zqir*1x}|NIQn}2?{Si@8Yj)@CF3%hPxx4@o7Z>+_-}~Si%X|B0&dg=!|rrGR;XmEi?zAs`CO&ui=`a?SSVhq&aF0^-EwI@7V*AKlmGVlx4!vLc6RQsZ|$}_n=7rgX0yG#)LLpZ0Vlk+UQl#CSv@)5d*?yp`boZCu=@-ghgO)4$2u#^ zjqQb{oyE12-R|`xKnShnl{g?-;gp^?X5>S~#D1d?8FL8yW)1^CiiKW6zy@)sF)Rjx z!%d^n@K@j8^a}6{4ULbEGN?3X(4JmMCT3&4tXpCdLb2n+(7q|e2plyIn+CCX6bJ_C zE%f#h4|<&mkRBvVPQg$x1XgcS7s|k-`rKZzPEUEYo}j#c@X!sig17GX!|7u_VS1(<9?e*7R`^Gn3d*hAQ-g@gRmoNX; z<;!1r>#f)Nuf8$Z|JLx}rP1LlVdY%N)<#AixTu%}e; zmkRcol54i=ouBnD%m)|ip{2#}@=~O=99x(Nd;AM^-$EU<{>24%^si3U%%eCxL5|dakF*ncKhzV&ix17p6;*Tf4Ft;?cF;M zwr}3uxOUOrKVIC}sjhSijaGWT5ii$**`hm=F!_QSmse?b$*c~E*(NlYc|r+ZD8-9p zM6sMCRZwI~s#Hl4%gI71k;y?)888xc3P&76VTTZ?0T`kW0>3&1yF4=bjiJG>zS8jU z*T=`+fIu$8VOJ4|eiCtl#YC`}y|l;Spm;pAK!6nr0d(PoLIRJ6=ko~y0Z}L-Nu*Sz zlBL%RtTrjg5Rs_4Pz+S6k!m$kt3`8pkI$!ZIAyJs0x-2}oy5ygUXf-q)@&x)?etP3 zQJL`-^3HV1nn;)u31cj#1KG>#l{6aBeBR=)3iTiy8~A1eL#L(~v{;v&zA)!(HT>zA z%I6T2Gd7EwA?Kmlq){M)9A7Uv-n+N)&b{r0Y5)L(lm`pD1&b9&w;A5+#Mc}C&Y~~m zWW{~L`I5buGAczFJ`*An;Mi0Mmp-ADu0n#B ziE&~9nob!P@=+=|Ng~3q888L~Mkhn5gb4;2q7)JMbU2R&F{^2rh&~xoC4$OSR5equ zbk-8*7Yldpwf2w8i%s8pclP9T?ct;KC(pWf9xQC^L|Uuf_1aPW=&*WlG;?-dzjeF0-c8jPyz2l^*AiYIU!%pvzPz1!Qhlau94+6I_^wOzPz zvHtG6$IqW#eDAxDe(?SGe)7A||HZ%l{r}}({p4T#o8SM=58kQF1*LMF-6bqn-Pydw z@0Sz`mTot@(akI`hw?dnFd$6C<F7EM8g(^oW$i!lZYcQ=o>?WU%7hawZ5yb z4G(=~eC%r!@+9zW8a2z~Qe`u4@F#majqBICw{Pw~ynp!U;nBl;`*&_`ot?CIHfLK) znc7S+pK&Cj#-LZ>vh}`5R>=rJdNswYXV}dgmyPH52!cLQI3S4xrLl-ImC$C=`gB?! zkE?w?aUdWKMU>IFCXqH|3%1Ivud$L?+sN?G zLC~W^Q&%q!z5ZtZ*9Ry1`^T>Kja=;??He2)8U;3edUC3_UIy%Cm%=0(GYzl-2Ak~f zzx<8Yzxw8zU%!0i&HjNaL&N=}ql06;m9l$F;f;(AOiYeIpc5Djiby1oNJKK3M4^z# zWFmopL!*(?)3C|O@sZJ?@$peW2yi$A2xK}y2osZ|;6?fedn@dXj$NIC452Vn3>IFl z=GJ-1STthl`NP z2}(7^XkocL;&4=*%9;vgTe<42%(_cOH;8Yu)zEA$R4MzjX-Ckfu^NRc8I3`PQSg%_ z%s2@RG(p8e7=&py8O5cbu|yaQHwi(HO(KRTdj0=HDC`7@1Y^*UJQfz1T7`h36Vdcy zxL6h6A)Tw!V4v~PFghPfAuu(h?#^sRJDuK}m7+a*)aP~ zTIqb*t=7||N`l=jjl|7Pk6I|EU~%9wm|`*UQZbXm0yiU3#3u>3cs2u$LH1EeBP+|P z`D(zVWyC_7>!;0w-MK{EpwrS+Dze$k1&O0v^2B2XqmHRnQJrQ!aJ?RjAm#;jS?jgR zOe!{T{J_~8lx&llYu55j8opM+mI|pZn@T2Ts1;nXfToml6LD{SzQAPQG*YTg&HyrN zI2HiwKoq|nPp4o2S^x~7SAd-WEhs%65D)|`lw3ftf+xu702RPatCkyZDxv|k$1XDH zX;ur{Y~fmM0=r#mx2wEfgU_S)y7iHuF&;5R0;+&V6!3`S5kttYj)nC;x7_2DMuOT* z!V>m_jKhlr)VZWJo3zA2S`Z@QA#J@H+E^{*Q`U$}614FHHbKxXjJl;szbX~ffOj2o z%Dh&QySG%4$YYTJtL?H#UUeW?bbOql=Z}0xv#@5Q(db7E- z)SHH|u(()XSe$=tz4(72gl=pw;hyg+{3S$;&A?jG|HqLJy zzI|`;ct2f98NGV8&n%nCWjEK_jh)5i-NxFtMgJu;g`^m5f0>Z`>h6%c;Xs z>WI(4O!*XY9)>X8hky=Xk)s&Y6cz&mgaDt0g3yVaMof&2O^lA=&=|d4n_5WbmviA# zP+^y%$gshwDuHOk^OQa0Y@VyF+C#h*T=BRLbD-h;%v%kB6dAW7E^a zQ0TzK#Fe3;H?Cay>gBh-26P4J($}x{MkRft|H|uqS6+Wb4u1^^Zw_32qc_#z(yOO^ zV`$(Tqa&}6jlMBH_U6RcTa)9Lpi@_;VFM_{Fo^(RvoL%fK?ZIEHP2#_dR&@Nz?_IV zvuSs^=&Y1o)fqQXrR*#h?WKaPRInBc)+%733V;XK+^nZQ?*oLe)Ce}0!>wkd(RekA z>3?W>IRda@Z7sFdNq0Kw^_S$Zvr{@as2(5BpPbf#&d!@R?yTRu+r4#f6L3OL_j|ex zbg$Q*-|8M+Ywa8?bT+Ha)k1wKRhy5NtD$l=m?^lzag*DpwAe*D6IZQgDK!j*nr<)) zbVi<9$CfE+LJ5f{#Iw0*dT$CHoI-_>h*NmnI0`j9Jv{(}UWG!gOif*yoP29y;tin5 zi8rRE-h=`uMO?*T2J!e&5^0=HhjBPq4j0GaVtX4eXGQb*c#()C7L)mWoK#9tshJuL zOQ+{*v~0P8rZ;dKOPPbiN_Qi@v5^JudS|!1y*;zFHPc?nE-$B=%jxB%UfWzw&CUiw zA*IVDTv!Yhi?(o3<9BNU9<|pc@;F72pfDN|wVT2AaxfKDyd(sxL(kEH1kXpwIMWV2 zeYxg+c%yx^JC}(YIn)ug1f2@WmuKBOYl$02GxyHs9$qYz63To`wNQ4XLP|DyjEwGM zk|&Xnw+N`q9NL(G4dF2-g=~mQij(lBIrK@X5N$EAO**DrjMJ-WIyFteMQD^16FAQ@ zB9Dz=GY}Nw6c*8sfLtOV`cYGFl2H9J9?GN!nFeoEksKDL&&|ta^{tg~cQZY^;EE)q z$&_QIUB0-r^zc#Z?4sOkyXpvzX?xiJTy{^4}vT)<9 zd3pjanAw}RmmfUr?CciW?byM=%*JNM=>lgP8HvhDB{Lv|y}d%K6WS?a$q~v3C1*_vmPGd%JpYP(MFkJv&?3+N#y-v1%o-un=EbN&$7&O6_)GZ@1oF zFSOT-XE#>QZ>=@k>1@HCNSo&71NovY5R~O|=Jsj=APP8)rA2?OVxOxyW=f`9TAhl@ z02tU!WQ_u;Q6P+3tkp=g7>E`l(c@wzqOwRx91V+OQE6qy(rSWxCs3bv&E&KI5)QU= zM|;K7quRy!((T*rYiG+Jd~^=<9O%RA&z@g<^7Qz<$NTTTyZiXPoyU)NpFTf$`oZD* z&kvtGJ9_`w5x@hW_n)2vJ$-iL+4EaZpWS@?4a^z66&;z z`#bgHgQe4>=Cz~clY_?o_UzVrX=N!nUk#S?j#Nw^^vWC-u31mFTNqXo&8Q>kH3XxM zY_l-jPM+5zbi4V%pez`Y`-5_?UjpK--6a5Wdc~fA%mWOBSCNPq3K_@jOkjC237F*k z+UkRQdv8BDdgq;!_us$x_~QrP`Of1X{LTkI{PBlB{LzPC<9omJ!MA?+{Q0*YJ$(Px z^}C0Ar`?r}#mYhcbIdCKoDI;?>!7 zxf&~!!D3gqI>pC1i!1 zp;dFi=WfsmHENzh#*&KZLIIh}!?QV9fCnrVn#;$ErDQcQSSFs`Ar6F8k(e%>vy>|C z+Ptqe@2|{yiZk|H(UQ+OlfAwIrPab$D`_GD7Pww2agvA~#UY09$PqvYG(3bsgfj?m z3T6re8J-^Rn*jL^IReK|Vky%U7M9H;@`Mzzh$XZjP!| z9#OBbJrBobAZcV689zn9PGM2w1T2h7LQzOa4x1#CvQ;XcOvV%lNfIedsbQ&g9J5X4 z^&3MGTQF?(_>FF#-r-hT>@u@W;&3a&F>|>Z?rc`px-<2qWOY7Vt_5->5cCXzh&qum zw^s98yY+>otlgz1k>QgQeFQv=goh*GBUtn}lZF&&vUKJ&|HY|*h?W`5MGintXXv&gO&7!*tZ33k2E zrWacEz$FWe8lGCll!<5x2}8&w33+6ZfNIoB!$G^#p`+6`>N3Tb?Pl|P`1 z#hjs#)oxXqjZ&{m6%Oda0cF4|_PfPim(1^0L_<2CTj8=x0v-jRg^*7L2qEB+=To*U zpgX_H>yU(f%1XiAT!^QlhM+^}xAOef9wdYuy-LOjpEBZ61nd&GS>Q4O30-Cpki#Ul z^(G$h%^IFw%~7e?0E2ZZx?asNspv)(U8kU{WpuTiZ7?YLe7Z^{0g&K#8m(H1LCV(i ziE;)~M4jg1Ct27@26}>xhXF$1k}*^)f=459faqif70+RlRcfKdrc`T%YQ3Nb2@VZ_ z41-OrHi+dKzR4m37fd!CEMz0OL^vCb6qB)PI$keivO!DIXQ-sCm6RdwlSRCWuty$s z_mmE(XEV0ujBg?5$odtPgnl+{0(ej_SnEaWT*)$9G*^ozpw>dHwGeMEf^g?*HJv-V zf#=U#|MFjb`d|OsAO7MOfBeN4fAZps|2IPT6@Y~Q?}X5M+KU&j2;pac`T6gB|DWye zKUnQ8iIiI-fmXuuLv|R!SA!Zh* z9Lh@CyRp~4xPA2C&g|Y+xD?g+^qjC=J71pJTJJ3FE-vpawvV?vXNMd6`}4I0yHO)1 zyl&tQJ7p*%4+2={L;K zf8`CJfve!5OTz<~!S>Zl-{`vxb^>?+0w8gDWbo?PaQ`cfj}Ab_hru~P!l!WPX$k?u zq!RgTidsh1DH#?$*J%;^T=IxtlZqO1DQhw7s1#k*lDk%R&sIEhRquSwTmNg#&%5e% z_rijwr@FgdcY$_s(Yw6l2Tln1HlX%Ocy%?pzMklIlN;S+uiegU9~O3xN_(#sP`ch* zKei zSV`6v!-c9RU9g7}#y~{t391}knZ+eG+J!nZSEXagH8kMkRZ50bLJn7ls4AOtF3G??@cFd<$|w1 z8(UeGKM6 zIb&(Y>J17M8ni(#&ZGmK_3Zv(vAr6~=2fYTV!e|;*qc8+UOe2J-QUgbY=_!yXMJ8j zKc~BKwtVMe?b@~aaj#-@DmXJ9 z7aw?EtrQjU2y+SDY{{`)4{xj$4)^9eozm%P^X|Q!NAI3Idw%}OC$~TS^v^WeG^Y@>fKY1UZ!Ucc?fC|r^ z-vqxtdiV7HgM-_5b}r60&(7A54p+7|>np9&>}))j^~R!Bzh7rIi-3$qfmX{_D(P}L zO{HQQ4Sa`P=5Z_iK5ZmoN~c}ra%g@&wYZpFT*%hz>1rib$On^gm(Oc58)Y&ni_OG> zy90-vLc&L;r-qQQ5gclQPC`of6r)Dub7~VITR9hKE#%f)Gy5C$lfC8B{pG{$h3!sd zZ8_JRPgD!`QpTK&r~_`1%gS+BSPl!@ZedwX46}*R8&Ga#+w5GsgXeS!++L9{0Mf7` z>=Q+Ng0N2z^6-OhUck+Z2E>_!rj#>-7`4)jZ+7!XNAtICw%>kx_x<;eKm6$8({J7R z?7MG&`*+^|&X1pd_jf<|!S8+a{onieyFdQ$TR(XA(Rbc|_Dz5d_b%?AZ69wfbsELF zQX~^|1YBC1QKnN;=~O(4fIuPO$Y~mb=5#xkTg$8KYq4aUNG3wyP!O`gLuf3TKqiu? zWCDqZ#bYs83>uA^o}Pw4rY0tOWsiG5_WFs5sYY}Nqs77DpnlDs|?C}|o_MWJYD43&(fGH`Sjfyp7VxFi;b&=VKD z7b0Is7WLM&pa{iagCdpF)LOR5B67GDzJNL$RwWYpm+K=rXUd*x#b2L`E;rKcR(_$L zoUO&mrBEj22?fn|t3oMfb6DULgW`#BEFOx*LGc7Qk%S}?kvJS2i-Le83nDy=hLs6v z8W~e1r71)Nt(%}h25$2_;t~QEtzo_Kq}8U z!!ctVWXy`c#|g8+)<$7rHMO!)?(WTR?ltO51)EcY#lsNDF*s~wYH|P$9V8Q=Yz8=K zlVrkJB&fc5zS>={Bonq;EqeFv-u?UgfskG#Au2Ttw@)=w4KFlO>5Ri-7AO=Hor+;I z3w%zw%ObMsc@CrKWj_GlX#yr*VAAjmYOYSjQGs_PXLA8)NtkjOo6jT5LB*2t@c<7vR2X0blZInZva~X~1|WotX4dxVz5zS{8+t9vXyjOJ ze50AA(NpCb;`~zd`mOHyo$Z5@PIqf%cE05Id(38o+hq>;Yylr=bpfx&=M+Z#@wjl8GBaUYQplfk&E%X!9vcz$5kB_<#@sFS`+d!cGZ* zgs@BQw~1UvzQe$C_SQ2MI*dZQQDl9I2Syb~t7IvZ426QBR#1D>))h3J9GE()LQIp2 z=wdOC&89IJR1SwFLxvXDlQQ87F`ltCroum}PUO~7JE1U!ub?sysji)Yf992S$s zpp!{B2A!zYN&-Q%$E&kBz$GEJxiyY}*%dIlygh)lnfY#~IN{e8B9>~xRf~HHesjjD zE&9!Qzq%MuSE8zXP!x4?!X9bRB@Wt!0Df{I%~IL3xfolm`O6V)Eoq!fndUO4xvXh6 zXR75*vjtPF*NtESc+hSnSDWE>)7x5hb~jw_yfgPt|Jeus=YRd_&wu_OKL7l`zWCxV z{)P}<{`~68|9e9CvzIlMdp}=%0Umqts~3O%#g{+(tDk-TJ3shmyL)m!|y}7cm z+^jd2d&LlX^$=bW!UlkZ|2slxgypkd5x|3@Qg6E5dlUb zPLs(98V${2;<;QBpHC5q$xV5;Nr~WJ-K2aUkYRk z{&dcp%6L*4Zwe&uusi6tyB$WeQK?o6r6M+;OXV<0OgaINg`*Ku2-rAeVi=fyzyO1N zJrWomxYB?5t*dXn*?0L;|CP&wSFa5GwFdjHf<0F+z17>_cXg=0Zy0Exe{^tQe0XSb zbOALxTgqs1V^ba*E3;@H)ic1_n2CI;JnA%`8`+d07YY|T15Ynz+1&(Awv3G823a4j`FOG{p$M#Ix+`j*!M%}#J-J+itP zTi;G?>}59hb6W@b?Ze{UN#*ct_S%ic^;=Cq3m11*05IITw+5Ku*2B)t`)e2XR?qLY zuisfYyVW|mSUx;!?48s%_iLT4a%(-mxRRP}#L9D_T-h7X*g}ck+-SE;X}3vDMuA?( z)u>rY1zjp3i-ZKg3_yGymcvHTX)p?Tibxp8VMhQtppnDi3?pD;Kyb(iY-$KPIS8E^ zgh2+Up+i{oI1Dm?MvmYx;Q3=1^au(uh{KG^r8JX)E|;Q>dRovYPsNStgf$w{X#k># z2r4-utNuai9AF9Je%d}rlg zJ+-}(T&;&EC!Ws|g-Bz*Bp-2JSVUsJwWTk`> z@M!#QHIIc73-D?M9UQ!fN2HT6I3xrEAHzBobh1BpcGNgIo;y0Np5IsigaA+hu)+R8vAYrXcv)5}sa7@5)-0K{{Mu=GtsUIm zPVH_dfzD1!x2}~=_fpsP(xBb#Mz+?1`x~)q2l?~k(pD$hTyS+-!M)A&?nY{3Exx;% z>8wPK_lld_iJiUl`bKPHGjV!WJ-?X0c2?W$rb`7=HmRMjy1VVv=4!UPl3rgmF8H!uTkX)0zaW}ObZ*ka}fgSt${IX@TetQGfn=dYbKZeFaueSh=GyZg^S z*#F=Ypu-QpdHnIGr{Db6jgLP)|M26B=O3Iueb(zq095e!$tzB{0Z;+7V7sUHFW!6a z?45T`9zHyN@Zb>mj~h2OPfl0&_8M!QnPxLTHy1CK{K=F(95#BrYKK#1vx!Y6p+Vo9 z?Wfgp4F-YLD)V@>(TFXXaOHBrQZZ7QiPx$rpmHgmPWdBYhtF%anbbOkSSjI&xO5g3 zPsJlh7#I;f1w_Tec?`T<2<(@@?@-5srb5y+Uk7u)aR z1igZ2NSaQl3prC|rbqA13}AO7h3zxRW0{@`1WKYn`W(f!lg=k2w%xrKTp z9@85161mJ|wWM>|R3@WPtMDWu8i&OZ3B+EP0U2zduowgi1xF%aa2ON{otgr8@V9<` zQ{$|sSB281r=d6;nog&P#R9EPWwjaH9%CSA19H0cCW~CF7pb&7g_oynm0X34D-p2-TpEW(VKd1* zHbcl`3wazNmm?N2^?Fr>29Y{^lWaTY3$T-lt=>mw<-FD!6)83r3c zp+gAe6KugSl{87lj{`OU0&GCWO_8uuB-9ihF+oH^3DXcf9D;{IiPO_G6o!Q(@JKWP zh0$9jf!WcLt-#1&Em5}HWCkf}K;qrm8p+x!}D%oNTz5+!f8>YJH! zRqLMl#o$saw$e_mwA0JW$%Xk?btagO+k;-M%^*=rm?9RDLq;=j(^NE!gqXtM;YchL ziGiX47!VLRJQ9t8qY#ro1Pqi*$Em~&lM2{krcO#UC@5A9)vlvCtrC~pV0UWuMu}1l zJh9B~RQKdkxqZ4&#OwQbWK&aUq+Z0=T-V!01!<-fiuuBWkySLWcE5&5eIXj!Ub9eu}Cl}!L1!9s+ z#c+6(wR&QymCxkdk*KLRfY89TS%eO&$Y~Y1EMfo#fDnLvx9E6!C0h$nP{lQB1$s44 zA!W*?Oog1IP;g(`5~@}wQESBv7J+ls1Hq)`8kB6c zoFSFbq%x{fN>a(l8YvK|_XY(NAuw_rI$yx1GpINmmQKQRCkm|41Y}okq~8#esmysQm0F1_W(jLc_Wr!#OMoZ zJr04#E=YLfrHG*#v&;ldIhQ(ZlcjC)tV>+*O7nhU%FT?}89|o_DAb#1Ax!xc^_;yk z7iw3$fDkG%T_vh5$28@*rkv2ur1jOD5#T|+VsFfboAo##gq3A)W5K%IG+ta}|LE^M z`p^I6cmL|I{@v%l{y$%Q@#p_nLilwL5?*}q|BDd5{MCy;`{K*L1cdOz@Bh!++jp9) zYpvDQrRCYiQf;9zQ(r6ty|z(MZ1&V6g!P=FlLM`)lU1&!6|J~zIU;F1=i? z#hg(k;$tr5HKhZw*j$FRsLY;Uo-X#^aKfI{Jr z-h{5Pp+N+0TJ6%!tW@Va^Mytskn*x5bQorQ9NHs<-asSR2oy2~>EXf4vdR+^z0#9o zQ=_9uIE+LhQH@6P;$rRA&4YIzU4M9g_rd+$+c#D(uD4E)7Y=r-o9l(uR-&;Onya}% zc1b3!p|H{IQCqAMtq$C5G?AFd<6}8o6q5y~(IF(t1c5k;!w=)|LpZ`Po;XY(jS$J> zWGaM0gHq`rh{Ks|6qk<`iii>!MXqFMbX+qCKpwR}Xb6T)k*GDEbYybgLMd3t`-+7? zsTcrlKIcuRT#2|n7PUr!hjVM}Ho4ItR4G|vA%GSPl>#T?CxKN(BF11)@Rmm=#s|kn z`-g|F4h~%I?|bX&l{cf8BgYX?oS_8nH`&AB)+~Jnn zd)42BS_4O}qDd5Fk(9s_;W&IWi;DmsD}xE6(5CRjF*I%%i5^6t1`sIF4nkm8Cn1+% z@c!xP0XV!5GIe=;{Ef-+H%WvE3S}IP>ce3N88nEHkCRC#A_0L+fRON$pyeCJ>1T&Ec&8; zkxGVDNYG+FO2|c+w3M(;fT8Xvg_(IiR&RUBZYjZKSI2%sIjIofmxtLs8N}CNF zy@p}XvD6BRfP-L?#%P3LI&oYL5Q~H9l?W9OB0j*LH*qZ{rcp-)gitKlYE@4l zAk%8dcDp>E_cvD(>znDNRxn@EXA8P&&6m&HvpGj71cI#4YGYdMOoxjdj>zWc!!tAf z3W$S?o}KON`SpdhwM26{+Fj2qErlHpw$Vh+WHqU@GMQGKoX&LCV|xdMz5T-Oe)0T# z{^s@S#kH9mXVtUg;@);*yBj^&NnbxLgZ;`qx0`D>gZYf6kku{MJ=^Q4y^ZX_R_h)rSQ3Cc@EDDE1?e!TW5qm1-1K3a~go}l6DIY54g1NLW9<_U2 zS`+ZKa;8`S%n*)3gj0wRGGU5@n;_#S85FpHgHy@qW}P7DQKw_pO3}YK8*eVASDU%c zN@2ZSTwg7&uN6A0g?2j&ykNZ^sZ_kVygixf&F6`Q=%W6LZF~e81M?bZob>W zb=cTIP6x;3a=n; zizeW+d0aLQizX8BWD*gi76O5Q!C7v0si{c-22+rUDafmW2EFA<$Hs>yCWd>( zJz--o_&5SNi6?@9Ly|~2I=#%{)CYq0Xxtl%dwf2V1K3l&SR!SxId~c!MWrFBbR>J zfXrs8Mk}z`W~}FB9m3@aLEA}*qma$k)zQu>`q}Qq76s14wuO2;`-yNc)^yQ zaV>QUM;D#ri|#_JJTsqKYFE2E%L_}zc+zDsiG(78%dI>+TfKdItKBZgV)jxwa{JEV zN1wct&iI)utU|$byEUEFnbX5&qn;>cU4DWB0*^RnG^6U;}5PSBZ>gu?n0nz)m0taOG;s=I-q8{lT~X(LekB zzw>v0@ckcs_Te|5K79A#{kQL*-#ptt+S%OctgbKB7fZ#GKbQCVgIbqcVFRD9UF`R( z!(qKv%ka3R>69fF(FJ^ppkEORD7|ip$0hQ*#Q}>TXyFGee7~9JGjRh}LBuHu*~K0c z-=X8!v}~J>YuESiz^vw()I6h_uUBwYQicTF5h9XIL{vz~N(osGe3yVA;NrO)9GguN ziI{9Q6^}2x6_2r9S z0uK26i!Xou;#a@^@>gHH`1K2b0smvB^3Ps;`Ile3_~jR006cg#4*_t)&p-d-7k~EO zfAQI;f6(n-Yp$%fRyvJFwO*f@ua{owwe6f7Xe+PWD5$yx)mlN*&a2v4MLQ#J#>CBt za5XMp@X2OuyrM&&G%6zoW5FNoES67i6>dJLonO@F>n=AyD*#OCV6(N?jE7GaD+RLIJ%CJk)jI1c(220DzNp2SVV z(J&+s7J)@T5EG+gqeH`RBtmY~7VFj8@_eS6_eR|e0c{F7Ix^Ka4jY8PN2XxIQ&VFg zC{KalJOO>VtkLx3==A6a8U`g}Ff@hSST5C0PEPOLyL0Q#>79FLckb@pzO#GlPWR^R zwTqjr>*tH7XZ4fQ+R<@kXRo@kHM82uEw_^M3*k!5o6TFI33VVOb9#7Y8(n84DKu!Y z94?Sda)o0o-Y}g#Kx2#nBBhX#L?RrIhvIM$AUqyIAV7#jD47gnFi;#WmMb$Kw4_ZsDZk=n`7n{!Iws)oDU+o50HxldH>CL^u?os&wd?;u2(~G6+ zH`^C?)^6P1ymfc$_PxEk4-W4=Jihnv^xlJ$yZ2A-+&ezMyLIi(`swY?(aqJpv*qr= zTyvwiu$G-)NmUxr{H#AwbOe$HcSP+BDeVEd*(=dI1sW?uWkM?rD48BD(IN#ZBu|cD zOQxA31f37Z(u!ND&RoR@>nlH|ks4IgJ*_VhscW+;T~~yyV#1jUVhquN|juoEHxF zW80hIxmjZ*%yYSzCKExcBWSdEpNE->i56yoSB|W;f~_UrQr%U`=~r9foz3jxytj}w z9qv`{-RaaSo|&Svly`)KDwB?&77rT~lLjTanm72IA~tF@#1; z5wLJ3jVj^`Gzx{?VhZ{^*;Hh{R_b;Zj}AIFZ|pvJIqd$)lar@U&z?RzdG`F|gAY$X z{OI(fkIz2%=-RUn02>@VdH?Xq`$z9TJ$~|jPmiA*KYe=b{hqErdv*@U;n_3564wEE zJbZX~apU;(+Wy|bMt7stTA2sAp;%7FlfGcc;dJYbX1Pkk6G>=10ZAYt%M?tlo^LdZ zt#+}?BMFAp$&{r~0+A|EsrAY})@GwKl~5|}3P;Q~yF#gC^Z7(76@kM|B9WtT_%H?- zWeki$M6wuov5>CQh}=$HBIYdSL#^fF+G=HUV|I6^zQ4Dyw>!VHJ-e|nv%X$hS;;Il z;&XGsa@n2B*-|MJz=m*G9SA7AUa89^aySH5E7xM-SS(ztg=;o*OeU7a!f?2#PB-1_ z;!3m9ZdF%TYHRJ;jrIEW=F;Bg+z?oBO-7@cmVTFn!QsBAWlMnh642r_vZh(bZq zXlQ|e1}wgSPm_pQav2XuD&a`P9J!pYQS;R*u0qa~h^YcTu{XMsg=8>b3_6U-fO9!0 zF|bVvx<<{`sJU7-Pp=i3j38f2{cf?(DfBu-9=p(O6FSU1i;iPZF;o%~pNV3SAOzGX z7CwZ54dW4GMARe+Jw?Vq$v83rO~4|tm}xX-8ihro2xtruizVanOd6RBE zbA6_HBBgaQ_gg2Q3pNcbeUQ!q#f4h_R&rU}?-JP-y5 zjzPn*m{)=U;Q&J5U?3O2oCi2cBtf`5oLo**DCrU@>E%*jbe*1UHVSPfsof&8S!BJL z8%6*L5{-^6RZ!$As#-_an>ir9$rN~*9BZ+#LLq>lD!)%0Nvk4hwLh-#M&;#&z|qb2 zy(dTAqeiOYfB5Xiw}1D8d+%LeXqR0fgV8RlHw(``x_9f|!FqQ-61D;`xN+;~vu{72 zoh{I4IGvIobQ?BX<%_+gRy7*)D9uW$M#J`cwef5qQI1El0Z+(cv@2CQ5s*eFQE5af zwMeUx81!s}^FcC5?MlB>5WK^e~?==b#RpPLSoK~^dDG&K|ZigIPMUBPmH$QpjM?e1NcfR+* zXW#qq({Dff^n0KD;CH|K?9*qDKYa4RXCFQL)`vIWzH@r_+RoYTY^zpUD8}+(Z`9$B zIl?KILdSQwm5H=795s3UDvwX$^C{dOsn^rHe* z?UpCpijZC6G;nPuk=w2?X}NBj%xMwZjC{XKk&Rm-K6NQ$ujE||Grs10xU-blXr(ur zsnvx@qv~BMCN~#ro6GUl1$%4Gwz}Y7TMRsUJNv)?yLbQMPyfxY|LV_QeE#R3zxZ!2 zzWlRaeg5SyKmYQtUi|8>zWn8{UI0k=Rd24rm%jvh@#QbR=v7h!+rNJC;`1*)fANc7 z0EGDR*T4GmPyXxAKKnR81jc7D-mNE%f!lW8WL*lgCW-7a3-s~jEAl*%TjUF>sf%EfrQ z-CXUoTb<6%(c$L)=FZXf(sCu>(Wxa=n}RB$OlcX@4l&6oBU(gglL+b7k&6+v+sMO0 z-b7CJ<6z@>1ROVw0)&8qqo$|elVcO(Bco$elN27?n+WG?B@nGW5jR)Lf}+L&Axyvq zp@`Am%BRo?AQ%J+n}Wk8r=b%FAUKQ!g%TkU42LU;#Zv8+_BsHV)@*mPd2rY~JZc@C zET5b%UpreqyT0_YqSMj^aH8icXXmTeFILZQtexLjJv(n59WQL}Rl1wS?p9%aBe$}a zSXd5LXI;6XF_u#K!y=cLYcjKCGL}e0<8g^B7LLip(CHx1!->Qx9Bv$k8^aSO2*hzb zz#+mY4nKk?fKW9?rc97212p;wn=>I4!DVu^T0<}xsQ?=sPOd*7iA0sjls;duR;sSK zd4FRm-0bzYCKi`cv-7E$YOGKUrL(?h+~EtD>`slrEK{iXd;yKgB9cfb6lw|vpO~B) z9v$l+9J8-E!U43J4;PUWLUr&Po4~9mDhJl6$hld7+ z2KxpF`anC>-}mO=z+1z^mq$mhOpNzUP4y$DNAdV6koCdsCzVnaN`_9)0gk~R)Fe|j zfCrUYaHi@l&DdvZuG+kNuI>fxOwCc6u@=fEpmNPxs#=N_V`0XSFYEJVUB0Y+DP6u| zDglJ3yXKa>3(eqCJKF3d+TG0BW`6IeesIz_I&Gd@Up>26zqq+|^Ult#yZd+U9o)FT zb@SoYop<*hJUM*(>G8w&kM6#^fBT)Cn{RJlzq@{Xv%PRxjJ^;ToMBt(B!PGNf9nRKt*Im{KKOs-TG_WEKmB!;T{0eR%9B z5;Y8k^}%5MAnO1Qq>vFkk&t8}oJvBn=y(B_CK0gsEDDW?p_6bxI3x@O8^<9h$apA) zI6);&aM=)#OPER+EG9OO4VO!ZS{2=ClLR~}k4tPdv(hQ;;bG~){guO`s#=2+i6+u1 zWqsbZ(()Ycr%n!2*H5#zZR7k^sP1n zot1E_;Vooz&4z!YldP6)$(ZV3w{qv!>SniadbDuuq_Nh{)XJ9Gg1nlOrz5h}Mj#qc zh`0!?ikgg@3wdXIHGOfhGCSwBTA3O((d`h#Lt2+b1nh;=Ey@=i^+vGWNvy2LTb=0s z$;|Z|>C;=eIWYj$141vkT3c`f>?m%DJU{rtGzOWIX<)h(GGE(mYN+jWj?fPwF*H zorXasjbU+pd=X46LzwK;$~=GyO`&S5EO-~&iQOZ>{MA+~yt|h_KcC;&J)rcFT9L+jI6u`93{q&K&c>z(lKPWo^!bG)B9-pg!v!Yhl; z&DGG}Mr^$uT3PbWR&4p4K9y1hf?@z^ayj1N;5!^5tA%eca1Fp)8-xNLNu}V(C2S#| z#-bBQ1Oyrh!qy0MatJcfKQ-Pz*mtS_@};5vtK-81kckoG^f;M-;eG>+~ zib0Ps=mGj~ESCZ+t^EGp;@P#;+qXCF-0t4Iv3C8eb$ry=-JM-uFSeTL z#$tSC#+y!CVllnnuW;CfCKFqyqpOr8nG7!$BLt!`E+53$Q6LUyipiX$P{wfBVH9!z zhaJbD#=v19;6tD#;HFp%j9khv=tNot9hjte$eavY?IszQfhXZ$1oSipV8O%~bbJgp zIRTrR>dh>em;{6{J~}cwJTx?PWoY=)*hC)`K7vF~k|+o^mnc)P^+t)qr3r>D@svAT z@MrSASkmDQ=nQ6oNJ?U`5F`@p)z?WB>NK5>1{s9K!m`-}E|(+}(nUgs@TJ5emQ2P| zDg<&FUo2vaga8akzy`5^t*0ZHjA;%BB@|#Ky>Uk*m6F!`2HGlhIhAgw+UZa^9iY`X zY*L$vV=*v|8oEYKmWgnDCY(kX!y)=n&?^}D03JC^!c0(bQxqJOgqgx4Cou3)6m$gL z0|N{Wg(YBcBpjYXAW(@!DiIGvBjKoIAPkL+p;NI;I*!XGi3K#7gv}LU*pg|02MQzA z;N-a@s#MuAyBuHHEUj+Ov^L7^&6(A$+Uj<#y-{6SE7e=M+F~kO3c1`CgHa_Aff$Oz z;}94$426WC5L3wMNh}JAL&09+0UY1~p*Ns>nt($9&j+4Kz#|EG1Rf7Irtx@y2R%Z- z;ijgihj91_4i_ttkbwXmfV5?@2+S6N$tW~xg?de|E`)$j5QzaiQ29a}SAY>na8d

d*vk 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�ypk!cir=HUP`Y`A~V z33}L}<1?cWjyJhJ4T%(L6A4sfDU~550)t}?*OwwNgaf{}G0RBb&WI#z7;1u_K)|

LV$ow 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%0AcV=+Lb#kd*z!+zH0`=-Yb}(|=$%%m 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�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

0~>E@SLsv8^4ot^IC;nLZI)r-rGt4EuUZnke8 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­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

ypcT#f(|xoAUXm1IVm7bTFA~ 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

+;UXw%GU6`Z6K}p9Df!8@O*Cu01*J=adiX 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 z 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�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 P00000NkvXXu0mjfy)g(J diff --git a/spec/fixtures/sample.zip b/spec/fixtures/sample.zip deleted file mode 100644 index 4bead6aad82f53c499636ba3a74f2ebc7566b50e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1212 zcmWIWW@Zs#-~d9QS?z8NNPw3?fFU_QEiE-w4?=}T@Gz|I(hUtxRSEsdD8i5%c-rr< zfxw>U+HS9o+6f%ox@GSN$qwf!Ia$r}2eX;y`|t7V(kk3k{(R%(uP@lrYQ(JT3Ve1l zzbb6mG}9*ACgz&h1dZt;3cfdX##XsMoW<*xZd2+M{U-d3MZSTwb^21)LX+?ZU)SEe zx%#HpO8$z@d%-6*Fy0i{Ggr->_mA1Ni+_)B%ds*Yn-p~Queq@4OFxUP1=1IozIrDv zHaoUX@pwtH=Y{H9#onRUm#pf1cUK(70%f3haoWzpbrC&C$ z$$3{hr%O3b{_}Um{Q=(W9M2!UmA?)Qi-n8~3<2;Ey0)eOC4@LZAyk~7rw1Znp|hlw z9UMB|TY?N8G68k7bLhMcna2(^jTMLyrU`qOV3<~%m|KvOs+Uy^GL3VZZs;_59Cc7C-J>$=2aY>>8xk;_c+`%B{I+OFbx5Y8v=-&I3ba2Hr5{28J;-RB}>_!Qs*f3>R1^7kivLe^P%_P=HzC zMiZmr&CebMo%8VZ@zf1k@hm8y!ON;4GkaasIv(XUkHAr}LS=rD4$x9i$RnZxJz}{K zmX=hMz~TaCC-=GYzM&ePYc(!DhQ#mU-MQ_&Km)nKhB7jVG9z*na!TT5-~p-t1BWGz zAQ~-yalrFefH%Szkn50>5GRT;O2FVlN`w$2Ku$$A0+iN}!yDCz0-zB{DUSo5@{o-H zxdJ)#xKUiu#soJ45=|TouxLUz1Ua<0Pz?EvFa#Xz5Qjkg!pa5;FIFH71Em*c5Dx%b C(S=h0 From 5c9cb6d90254077b4a86d5af04193f913a0f35e6 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Tue, 14 Apr 2015 19:53:21 -0400 Subject: [PATCH 0672/1783] Revert ":white_check_mark: Add tests for images and archives" This reverts commit 1a783963e303b0f40487aafccf072dbd9a16fbf0. --- spec/pane-view-spec.coffee | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/spec/pane-view-spec.coffee b/spec/pane-view-spec.coffee index 8b58eca09..4f240cf66 100644 --- a/spec/pane-view-spec.coffee +++ b/spec/pane-view-spec.coffee @@ -7,7 +7,7 @@ path = require 'path' temp = require 'temp' describe "PaneView", -> - [container, containerModel, view1, view2, editor1, editor2, image, archive, pane, paneModel, deserializerDisposable] = [] + [container, containerModel, view1, view2, editor1, editor2, pane, paneModel, deserializerDisposable] = [] class TestView extends View @deserialize: ({id, text}) -> new TestView({id, text}) @@ -37,16 +37,10 @@ describe "PaneView", -> waitsForPromise -> atom.workspace.open('sample.txt').then (o) -> editor2 = o - waitsForPromise -> - atom.workspace.open('sample.png').then (o) -> image = o - - waitsForPromise -> - atom.workspace.open('sample.zip').then (o) -> archive = o - runs -> pane = container.getRoot() paneModel = pane.getModel() - paneModel.addItems([view1, editor1, view2, editor2, image, archive]) + paneModel.addItems([view1, editor1, view2, editor2]) afterEach -> deserializerDisposable.dispose() @@ -124,14 +118,10 @@ describe "PaneView", -> paneModel.activateItem(view2) expect(pane.itemViews.find('#view-2').length).toBe 1 - describe "when the new activeItem implements ::getPath", -> + describe "when the active item implements ::getPath", -> fit "adds .has-file-path to the active item element", -> paneModel.activateItem(editor1) expect(pane.itemViews.find('atom-text-editor')).toHaveClass('has-file-path') - paneModel.activateItem(image) - expect(pane.itemViews.find('.image-view')).toHaveClass('has-file-path') - paneModel.activateItem(archive) - expect(pane.itemViews.find('.archive-editor')).toHaveClass('has-file-path') describe "when an item is destroyed", -> it "triggers the 'pane:item-removed' event with the item and its former index", -> From 0c69ecdd7fded4f60c06a509e86ab75dc402c52e Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Tue, 14 Apr 2015 19:57:29 -0400 Subject: [PATCH 0673/1783] Unfocus spec --- spec/pane-view-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/pane-view-spec.coffee b/spec/pane-view-spec.coffee index 4f240cf66..286cf2e4e 100644 --- a/spec/pane-view-spec.coffee +++ b/spec/pane-view-spec.coffee @@ -119,7 +119,7 @@ describe "PaneView", -> expect(pane.itemViews.find('#view-2').length).toBe 1 describe "when the active item implements ::getPath", -> - fit "adds .has-file-path to the active item element", -> + it "adds .has-file-path to the active item element", -> paneModel.activateItem(editor1) expect(pane.itemViews.find('atom-text-editor')).toHaveClass('has-file-path') From 94c5de0aeb9f52c75a02d706af056e38237a8bfc Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Tue, 14 Apr 2015 20:00:06 -0400 Subject: [PATCH 0674/1783] :art: Change wording in spec --- spec/pane-view-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/pane-view-spec.coffee b/spec/pane-view-spec.coffee index 286cf2e4e..68ce63a6f 100644 --- a/spec/pane-view-spec.coffee +++ b/spec/pane-view-spec.coffee @@ -118,7 +118,7 @@ describe "PaneView", -> paneModel.activateItem(view2) expect(pane.itemViews.find('#view-2').length).toBe 1 - describe "when the active item implements ::getPath", -> + describe "when the new activeItem implements ::getPath", -> it "adds .has-file-path to the active item element", -> paneModel.activateItem(editor1) expect(pane.itemViews.find('atom-text-editor')).toHaveClass('has-file-path') From ca99ff4ce8cdd7e16f048152d8650a6807795531 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 14 Apr 2015 17:08:43 -0700 Subject: [PATCH 0675/1783] :arrow_up: scandal@2.0.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ef863920d..a66753883 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "react-atom-fork": "^0.11.5", "reactionary-atom-fork": "^1.0.0", "runas": "2.0.0", - "scandal": "2.0.1", + "scandal": "2.0.2", "scoped-property-store": "^0.17.0", "scrollbar-style": "^2.0.0", "season": "^5.1.4", From 06c7ed98f92120e255a6ba3e5c1782c22b907820 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Tue, 14 Apr 2015 20:20:39 -0400 Subject: [PATCH 0676/1783] :art: Refactor class add --- src/pane-element.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pane-element.coffee b/src/pane-element.coffee index 69d41f1ef..642e614cb 100644 --- a/src/pane-element.coffee +++ b/src/pane-element.coffee @@ -71,7 +71,7 @@ class PaneElement extends HTMLElement hasFocus = @hasFocus() itemView = atom.views.getView(item) - if item.getPath? then $(itemView).addClass('has-file-path') + itemView.classList.add('has-file-path') if item.getPath? unless @itemViews.contains(itemView) @itemViews.appendChild(itemView) From 2b43f7d163191d740389cf214b1559cf07820e88 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Tue, 14 Apr 2015 20:52:26 -0400 Subject: [PATCH 0677/1783] Add active path and file name to atom-pane --- spec/pane-view-spec.coffee | 7 +++++-- src/pane-element.coffee | 8 +++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/spec/pane-view-spec.coffee b/spec/pane-view-spec.coffee index 68ce63a6f..3ab43847d 100644 --- a/spec/pane-view-spec.coffee +++ b/spec/pane-view-spec.coffee @@ -119,9 +119,12 @@ describe "PaneView", -> expect(pane.itemViews.find('#view-2').length).toBe 1 describe "when the new activeItem implements ::getPath", -> - it "adds .has-file-path to the active item element", -> + it "adds its file path to the active pane", -> paneModel.activateItem(editor1) - expect(pane.itemViews.find('atom-text-editor')).toHaveClass('has-file-path') + expect(pane).toHaveAttr('data-active-path') + it "adds its file name to the active pane", -> + paneModel.activateItem(editor1) + expect(pane).toHaveAttr('data-active-name') describe "when an item is destroyed", -> it "triggers the 'pane:item-removed' event with the item and its former index", -> diff --git a/src/pane-element.coffee b/src/pane-element.coffee index 642e614cb..7769e7cdc 100644 --- a/src/pane-element.coffee +++ b/src/pane-element.coffee @@ -71,7 +71,13 @@ class PaneElement extends HTMLElement hasFocus = @hasFocus() itemView = atom.views.getView(item) - itemView.classList.add('has-file-path') if item.getPath? + if itemPath = item.getPath?() + path = require 'path' + @dataset.activeName = path.basename(itemPath) + @dataset.activePath = itemPath + else + delete @dataset.activeName + delete @dataset.activePath unless @itemViews.contains(itemView) @itemViews.appendChild(itemView) From 4ab06aa627e9e5a40bb07784cbd42b8035fcb5e6 Mon Sep 17 00:00:00 2001 From: liuxiong332 Date: Wed, 15 Apr 2015 09:32:51 +0800 Subject: [PATCH 0678/1783] fix some error in specs --- spec/pane-resize-handle-element-spec.coffee | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/spec/pane-resize-handle-element-spec.coffee b/spec/pane-resize-handle-element-spec.coffee index 1b569b63d..74bf84853 100644 --- a/spec/pane-resize-handle-element-spec.coffee +++ b/spec/pane-resize-handle-element-spec.coffee @@ -32,11 +32,11 @@ describe "PaneResizeHandleElement", -> # test removeChild paneAxis.removeChild(models[2]) - expectResizeElement(i) for i in [1, 3] + expectResizeElement(i) for i in [1] describe "when user drag the resize element", -> [container, containerElement] = [] - [resizeElementMove, getElementWidth, expectFlexScale] = [] + [resizeElementMove, getElementWidth, expectPaneScale] = [] beforeEach -> container = new PaneContainer @@ -60,8 +60,8 @@ describe "PaneResizeHandleElement", -> element.getBoundingClientRect().width # assert the pane's flex scale. arguments is list of pane-scale pair - expectFlexScale = -> - args = Array::slice.apply(arguments, 0) + expectPaneScale = -> + args = Array::slice.call(arguments, 0) for paneScale in args expect(paneScale[0].getFlexScale()).toBeCloseTo(paneScale[1], 0.1) @@ -69,14 +69,19 @@ describe "PaneResizeHandleElement", -> leftPane = container.getActivePane() middlePane = leftPane.splitRight() - resizeElements = containerElement.querySelectorAll('atom-pane-resize-handle') - paneElements = containerElement.querySelectorAll('atom-pane') - expect(resizeElements.length).toBe(2) + [resizeElements, paneElements] = [] + reloadElements = -> + resizeElements = containerElement.querySelectorAll('atom-pane-resize-handle') + paneElements = containerElement.querySelectorAll('atom-pane') + reloadElements() + expect(resizeElements.length).toBe(1) resizeElementMove(resizeElements[0], getElementWidth(paneElements[0]) / 2) expectPaneScale [leftPane, 0.5], [middlePane, 1.5] + # add a new pane rightPane = middlePane.splitRight() + reloadElements() clientX = getElementWidth(paneElements[0]) + getElementWidth(paneElements[1]) / 2 resizeElementMove(resizeElements[1], clientX) expectPaneScale [leftPane, 0.5], [middlePane, 0.75], [rightPane, 1.75] From 0cb00a8de8ef8ec7e063eae18409d754a90a5d08 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Tue, 14 Apr 2015 23:23:26 -0400 Subject: [PATCH 0679/1783] :white_check_mark: Add converse specs --- spec/pane-view-spec.coffee | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/spec/pane-view-spec.coffee b/spec/pane-view-spec.coffee index 3ab43847d..114fbf2bf 100644 --- a/spec/pane-view-spec.coffee +++ b/spec/pane-view-spec.coffee @@ -119,13 +119,22 @@ describe "PaneView", -> expect(pane.itemViews.find('#view-2').length).toBe 1 describe "when the new activeItem implements ::getPath", -> - it "adds its file path to the active pane", -> + beforeEach -> paneModel.activateItem(editor1) + it "adds its file path to the active pane", -> expect(pane).toHaveAttr('data-active-path') it "adds its file name to the active pane", -> - paneModel.activateItem(editor1) expect(pane).toHaveAttr('data-active-name') + describe "when the new activeItem does not implement ::getPath", -> + beforeEach -> + paneModel.activateItem(editor1) + paneModel.activateItem(document.createElement('div')) + it "removes its file path from the active pane", -> + expect(pane).not.toHaveAttr('data-active-path') + it "removes its file name from the active pane", -> + expect(pane).not.toHaveAttr('data-active-name') + describe "when an item is destroyed", -> it "triggers the 'pane:item-removed' event with the item and its former index", -> itemRemovedHandler = jasmine.createSpy("itemRemovedHandler") From 86a004dc8ce58cf34848f518a24a4ec7c24f32c9 Mon Sep 17 00:00:00 2001 From: liuxiong332 Date: Wed, 15 Apr 2015 12:44:13 +0800 Subject: [PATCH 0680/1783] add observer to watch flex scale change event in pane-element.coffee --- src/pane-element.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pane-element.coffee b/src/pane-element.coffee index 0efcc5528..7b3b1add5 100644 --- a/src/pane-element.coffee +++ b/src/pane-element.coffee @@ -64,6 +64,8 @@ class PaneElement extends HTMLElement @subscriptions.add @model.observeActiveItem(@activeItemChanged.bind(this)) @subscriptions.add @model.onDidRemoveItem(@itemRemoved.bind(this)) @subscriptions.add @model.onDidDestroy(@paneDestroyed.bind(this)) + @subscriptions.add @model.observeFlexScale(@flexScaleChanged.bind(this)) + @__spacePenView.setModel(@model) if Grim.includeDeprecatedAPIs this From 47c106256196f425ddbcd6c51013d9b5c8da010d Mon Sep 17 00:00:00 2001 From: liuxiong332 Date: Wed, 15 Apr 2015 12:55:45 +0800 Subject: [PATCH 0681/1783] rename the spec file name to 'pane-container-element-spec' --- ...dle-element-spec.coffee => pane-container-element-spec.coffee} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename spec/{pane-resize-handle-element-spec.coffee => pane-container-element-spec.coffee} (100%) diff --git a/spec/pane-resize-handle-element-spec.coffee b/spec/pane-container-element-spec.coffee similarity index 100% rename from spec/pane-resize-handle-element-spec.coffee rename to spec/pane-container-element-spec.coffee From 3c47cc7964abe90c18331b940d5923cdbdb79a97 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 15 Apr 2015 12:15:51 +0200 Subject: [PATCH 0682/1783] Stop polling document when clearing document requests --- src/view-registry.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/view-registry.coffee b/src/view-registry.coffee index 050444ff0..e4b413f00 100644 --- a/src/view-registry.coffee +++ b/src/view-registry.coffee @@ -186,6 +186,7 @@ class ViewRegistry @documentWriters = [] @documentPollers = [] @documentUpdateRequested = false + @stopPollingDocument() requestDocumentUpdate: -> unless @documentUpdateRequested From 6087587864dc04098432997aa0eda486769226ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=C5=BDu=C5=BEak?= Date: Wed, 15 Apr 2015 13:00:49 +0200 Subject: [PATCH 0683/1783] :arrow_up: notifications@0.38.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a66753883..8fd36d5bd 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,7 @@ "link": "0.30.0", "markdown-preview": "0.148.0", "metrics": "0.45.0", - "notifications": "0.37.0", + "notifications": "0.38.0", "open-on-github": "0.36.0", "package-generator": "0.38.0", "release-notes": "0.52.0", From 4daadfc4c0751378b9eec81b9c01e053cff7e8b4 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 15 Apr 2015 14:43:33 +0200 Subject: [PATCH 0684/1783] Avoid codesign and publish-build on Travis --- build/Gruntfile.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/Gruntfile.coffee b/build/Gruntfile.coffee index a66d47ebe..3655e91e9 100644 --- a/build/Gruntfile.coffee +++ b/build/Gruntfile.coffee @@ -227,8 +227,8 @@ module.exports = (grunt) -> ciTasks.push('mkdeb') if process.platform is 'linux' ciTasks.push('create-windows-installer') if process.platform is 'win32' ciTasks.push('test') if process.platform in ['darwin', 'linux'] - ciTasks.push('codesign') - ciTasks.push('publish-build') + ciTasks.push('codesign') unless process.env.TRAVIS + ciTasks.push('publish-build') unless process.env.TRAVIS grunt.registerTask('ci', ciTasks) defaultTasks = ['download-atom-shell', 'download-atom-shell-chromedriver', 'build', 'set-version'] From bc2747ead7690d09bbb6e43fd91a73d582db9e75 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 15 Apr 2015 15:20:54 +0200 Subject: [PATCH 0685/1783] Run spec on darwin only ...as we're not ready yet to use Linux. --- build/Gruntfile.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/Gruntfile.coffee b/build/Gruntfile.coffee index 3655e91e9..071dd1295 100644 --- a/build/Gruntfile.coffee +++ b/build/Gruntfile.coffee @@ -226,7 +226,7 @@ module.exports = (grunt) -> ciTasks.push('set-version', 'check-licenses', 'lint') ciTasks.push('mkdeb') if process.platform is 'linux' ciTasks.push('create-windows-installer') if process.platform is 'win32' - ciTasks.push('test') if process.platform in ['darwin', 'linux'] + ciTasks.push('test') if process.platform is 'darwin' ciTasks.push('codesign') unless process.env.TRAVIS ciTasks.push('publish-build') unless process.env.TRAVIS grunt.registerTask('ci', ciTasks) From 1331cfad4b5a076bb0e053d2b60f84c6d2f5c297 Mon Sep 17 00:00:00 2001 From: liuxiong332 Date: Wed, 15 Apr 2015 22:20:17 +0800 Subject: [PATCH 0686/1783] change the spec description to make it clear --- spec/pane-container-element-spec.coffee | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/pane-container-element-spec.coffee b/spec/pane-container-element-spec.coffee index 74bf84853..ef7392d84 100644 --- a/spec/pane-container-element-spec.coffee +++ b/spec/pane-container-element-spec.coffee @@ -3,7 +3,7 @@ PaneAxisElement = require '../src/pane-axis-element' PaneAxis = require '../src/pane-axis' describe "PaneResizeHandleElement", -> - describe "when add or remove panes in PaneAxisElement", -> + describe "when panes are added or removed in PaneAxisElement", -> [paneAxisElement, paneAxis] = [] beforeEach -> @@ -12,7 +12,7 @@ describe "PaneResizeHandleElement", -> paneAxisElement.initialize(paneAxis) document.querySelector('#jasmine-content').appendChild(paneAxisElement) - it "inserts or remove resize elements", -> + it "inserts or removes resize elements", -> expectPaneAxisElement = (index) -> child = paneAxisElement.children[index] expect(child.nodeName.toLowerCase()).toBe('atom-pane-axis') @@ -34,7 +34,7 @@ describe "PaneResizeHandleElement", -> paneAxis.removeChild(models[2]) expectResizeElement(i) for i in [1] - describe "when user drag the resize element", -> + describe "when the resize element is dragged ", -> [container, containerElement] = [] [resizeElementMove, getElementWidth, expectPaneScale] = [] @@ -65,7 +65,7 @@ describe "PaneResizeHandleElement", -> for paneScale in args expect(paneScale[0].getFlexScale()).toBeCloseTo(paneScale[1], 0.1) - it "add and remove panes in the same direction", -> + it "adds and removes panes in the direction that the pane is being dragged", -> leftPane = container.getActivePane() middlePane = leftPane.splitRight() @@ -92,7 +92,7 @@ describe "PaneResizeHandleElement", -> leftPane.close() expectPaneScale [rightPane, 1] - it "split or close panes in orthogonal direction", -> + it "splits or closes panes in orthogonal direction that the pane is being dragged", -> leftPane = container.getActivePane() rightPane = leftPane.splitRight() From 04fb61002ca9d56b7abfbea63b7f1b7d73a8c8f0 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 15 Apr 2015 16:51:11 +0200 Subject: [PATCH 0687/1783] Goodbye AppVeyor :wave: --- appveyor.yml | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 appveyor.yml diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index ba817084b..000000000 --- a/appveyor.yml +++ /dev/null @@ -1,11 +0,0 @@ -environment: - nodejs_version: "0.10" - GYP_MSVS_VERSION: 2013 - -install: - - ps: Install-Product node $env:nodejs_version - -test_script: - - node "script\cibuild" - -build: off From bf9f0f45976d8a4acfed523d41cdab417367b487 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 14 Apr 2015 15:36:27 -0700 Subject: [PATCH 0688/1783] Show notifications for theme activate errors --- src/theme-package.coffee | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/theme-package.coffee b/src/theme-package.coffee index e1b87e783..89e6bf91e 100644 --- a/src/theme-package.coffee +++ b/src/theme-package.coffee @@ -26,7 +26,10 @@ class ThemePackage extends Package @activationDeferred = Q.defer() @measure 'activateTime', => - @loadStylesheets() - @activateNow() + try + @loadStylesheets() + @activateNow() + catch error + @handleError("Failed to activate the #{@name} theme", error) @activationDeferred.promise From f8e940fdc03a5dffcb5cacde51e52f5af4439c31 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 14 Apr 2015 15:51:56 -0700 Subject: [PATCH 0689/1783] Add spec for invalid theme stylesheet notification --- .../fixtures/packages/theme-with-invalid-styles/index.less | 1 + .../packages/theme-with-invalid-styles/package.json | 4 ++++ spec/theme-manager-spec.coffee | 7 +++++++ 3 files changed, 12 insertions(+) create mode 100644 spec/fixtures/packages/theme-with-invalid-styles/index.less create mode 100644 spec/fixtures/packages/theme-with-invalid-styles/package.json diff --git a/spec/fixtures/packages/theme-with-invalid-styles/index.less b/spec/fixtures/packages/theme-with-invalid-styles/index.less new file mode 100644 index 000000000..b554d9e46 --- /dev/null +++ b/spec/fixtures/packages/theme-with-invalid-styles/index.less @@ -0,0 +1 @@ +<> diff --git a/spec/fixtures/packages/theme-with-invalid-styles/package.json b/spec/fixtures/packages/theme-with-invalid-styles/package.json new file mode 100644 index 000000000..1dd1ee48b --- /dev/null +++ b/spec/fixtures/packages/theme-with-invalid-styles/package.json @@ -0,0 +1,4 @@ +{ + "name": "theme-with-invalid-styles", + "theme": "ui" +} diff --git a/spec/theme-manager-spec.coffee b/spec/theme-manager-spec.coffee index c39e4994b..98a85f389 100644 --- a/spec/theme-manager-spec.coffee +++ b/spec/theme-manager-spec.coffee @@ -390,6 +390,13 @@ describe "ThemeManager", -> expect(note.getType()).toBe 'error' expect(note.getMessage()).toContain 'Unable to watch path' + it "adds a notification when a theme's stylesheet is invalid", -> + addErrorHandler = jasmine.createSpy() + atom.notifications.onDidAddNotification(addErrorHandler) + expect(-> atom.packages.activatePackage('theme-with-invalid-styles')).not.toThrow() + expect(addErrorHandler.callCount).toBe 2 + expect(addErrorHandler.argsForCall[1][0].message).toContain("Failed to activate the theme-with-invalid-styles theme") + describe "when a non-existent theme is present in the config", -> beforeEach -> spyOn(console, 'warn') From 63af011b3826fc85ecc60018336f37429529b1bb Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 14 Apr 2015 15:57:17 -0700 Subject: [PATCH 0690/1783] Remove unneeded metadata loading This is handled by the super class constructor and by the package manager. --- src/theme-package.coffee | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/theme-package.coffee b/src/theme-package.coffee index 89e6bf91e..eff0d200c 100644 --- a/src/theme-package.coffee +++ b/src/theme-package.coffee @@ -14,11 +14,6 @@ class ThemePackage extends Package atom.config.removeAtKeyPath('core.themes', @name) load: -> - @measure 'loadTime', => - try - @metadata ?= Package.loadMetadata(@path) - catch error - console.warn "Failed to load theme named '#{@name}'", error.stack ? error this activate: -> From fda6bb36248625ac2065c497be19be6083600dd1 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 14 Apr 2015 16:10:56 -0700 Subject: [PATCH 0691/1783] Add notification when reloading stylesheets fails --- spec/package-manager-spec.coffee | 6 ++++++ src/package.coffee | 7 ++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index db2a76135..8dcc6bc37 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -28,6 +28,12 @@ describe "PackageManager", -> expect(pack.metadata.name).toBe "package-with-invalid-styles" expect(pack.stylesheets.length).toBe 0 + addErrorHandler = jasmine.createSpy() + atom.notifications.onDidAddNotification(addErrorHandler) + expect(-> pack.reloadStylesheets()).not.toThrow() + expect(addErrorHandler.callCount).toBe 2 + expect(addErrorHandler.argsForCall[1][0].message).toContain("Failed to reload the package-with-invalid-styles package stylesheets") + it "returns null if the package has an invalid package.json", -> addErrorHandler = jasmine.createSpy() atom.notifications.onDidAddNotification(addErrorHandler) diff --git a/src/package.coffee b/src/package.coffee index 74c4f0eb8..de90c6cb4 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -371,7 +371,12 @@ class Package reloadStylesheets: -> oldSheets = _.clone(@stylesheets) - @loadStylesheets() + + try + @loadStylesheets() + catch error + @handleError("Failed to reload the #{@name} package stylesheets", error) + @stylesheetDisposables?.dispose() @stylesheetDisposables = new CompositeDisposable @stylesheetsActivated = false From ff88cd649812a1422ddb186a02299dab589c698c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 15 Apr 2015 09:27:53 -0700 Subject: [PATCH 0692/1783] Add 0 load time for no-op ThemePackage::load --- src/theme-package.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/theme-package.coffee b/src/theme-package.coffee index eff0d200c..f14750d2f 100644 --- a/src/theme-package.coffee +++ b/src/theme-package.coffee @@ -14,6 +14,7 @@ class ThemePackage extends Package atom.config.removeAtKeyPath('core.themes', @name) load: -> + @loadTime = 0 this activate: -> From 0ee462afe094db8dc14d9a5de1331153a66bf8bf Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 15 Apr 2015 09:51:36 -0700 Subject: [PATCH 0693/1783] :arrow_up: language-go@0.24 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8fd36d5bd..62d0cba1b 100644 --- a/package.json +++ b/package.json @@ -130,7 +130,7 @@ "language-css": "0.28.0", "language-gfm": "0.68.0", "language-git": "0.10.0", - "language-go": "0.23.0", + "language-go": "0.24.0", "language-html": "0.32.0", "language-hyperlink": "0.12.2", "language-java": "0.14.0", From e1f2bc132a43a43b0172e41a99f90c927b2f2adf Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 15 Apr 2015 09:57:22 -0700 Subject: [PATCH 0694/1783] :arrow_up: language-gfm@0.69 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 62d0cba1b..6fa477f61 100644 --- a/package.json +++ b/package.json @@ -128,7 +128,7 @@ "language-coffee-script": "0.39.0", "language-csharp": "0.5.0", "language-css": "0.28.0", - "language-gfm": "0.68.0", + "language-gfm": "0.69.0", "language-git": "0.10.0", "language-go": "0.24.0", "language-html": "0.32.0", From ad42af9d389516290fab86c92b192d8e64061f82 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 15 Apr 2015 10:06:08 -0700 Subject: [PATCH 0695/1783] :arrow_up: status-bar --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6fa477f61..9f01c0c16 100644 --- a/package.json +++ b/package.json @@ -113,7 +113,7 @@ "settings-view": "0.192.0", "snippets": "0.88.0", "spell-check": "0.55.0", - "status-bar": "0.68.0", + "status-bar": "0.69.0", "styleguide": "0.44.0", "symbols-view": "0.94.0", "tabs": "0.67.0", From 8d0168a520b0e37068e4c93c9c838c0e7971a031 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Wed, 15 Apr 2015 13:12:38 -0400 Subject: [PATCH 0696/1783] :art: --- spec/pane-view-spec.coffee | 12 ++++++++---- src/pane-element.coffee | 4 ++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/spec/pane-view-spec.coffee b/spec/pane-view-spec.coffee index 114fbf2bf..e8311b482 100644 --- a/spec/pane-view-spec.coffee +++ b/spec/pane-view-spec.coffee @@ -121,19 +121,23 @@ describe "PaneView", -> describe "when the new activeItem implements ::getPath", -> beforeEach -> paneModel.activateItem(editor1) + it "adds its file path to the active pane", -> - expect(pane).toHaveAttr('data-active-path') + expect(pane).toHaveAttr('data-active-item-path') + it "adds its file name to the active pane", -> - expect(pane).toHaveAttr('data-active-name') + expect(pane).toHaveAttr('data-active-item-name') describe "when the new activeItem does not implement ::getPath", -> beforeEach -> paneModel.activateItem(editor1) paneModel.activateItem(document.createElement('div')) + it "removes its file path from the active pane", -> - expect(pane).not.toHaveAttr('data-active-path') + expect(pane).not.toHaveAttr('data-active-item-path') + it "removes its file name from the active pane", -> - expect(pane).not.toHaveAttr('data-active-name') + expect(pane).not.toHaveAttr('data-active-item-name') describe "when an item is destroyed", -> it "triggers the 'pane:item-removed' event with the item and its former index", -> diff --git a/src/pane-element.coffee b/src/pane-element.coffee index 7769e7cdc..7dcb96157 100644 --- a/src/pane-element.coffee +++ b/src/pane-element.coffee @@ -73,8 +73,8 @@ class PaneElement extends HTMLElement if itemPath = item.getPath?() path = require 'path' - @dataset.activeName = path.basename(itemPath) - @dataset.activePath = itemPath + @dataset.activeItemName = path.basename(itemPath) + @dataset.activeItemPath = itemPath else delete @dataset.activeName delete @dataset.activePath From 7b02720d06dcacf06efde8bd1b5e7123cbe268e1 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Wed, 15 Apr 2015 13:16:31 -0400 Subject: [PATCH 0697/1783] :art: Finish rename --- src/pane-element.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pane-element.coffee b/src/pane-element.coffee index 7dcb96157..2f0481829 100644 --- a/src/pane-element.coffee +++ b/src/pane-element.coffee @@ -76,8 +76,8 @@ class PaneElement extends HTMLElement @dataset.activeItemName = path.basename(itemPath) @dataset.activeItemPath = itemPath else - delete @dataset.activeName - delete @dataset.activePath + delete @dataset.activeItemName + delete @dataset.activeItemPath unless @itemViews.contains(itemView) @itemViews.appendChild(itemView) From 476cf4152c990e4cb064483fc22c51ec756214ae Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 15 Apr 2015 10:24:30 -0700 Subject: [PATCH 0698/1783] :art: --- spec/pane-view-spec.coffee | 8 ++++---- src/pane-element.coffee | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/pane-view-spec.coffee b/spec/pane-view-spec.coffee index e8311b482..2bff010e7 100644 --- a/spec/pane-view-spec.coffee +++ b/spec/pane-view-spec.coffee @@ -122,10 +122,10 @@ describe "PaneView", -> beforeEach -> paneModel.activateItem(editor1) - it "adds its file path to the active pane", -> + it "adds the file path as a data attribute to the pane", -> expect(pane).toHaveAttr('data-active-item-path') - it "adds its file name to the active pane", -> + it "adds the file name as a data attribute to the pane", -> expect(pane).toHaveAttr('data-active-item-name') describe "when the new activeItem does not implement ::getPath", -> @@ -133,10 +133,10 @@ describe "PaneView", -> paneModel.activateItem(editor1) paneModel.activateItem(document.createElement('div')) - it "removes its file path from the active pane", -> + it "does not add the file path as a data attribute to the pane", -> expect(pane).not.toHaveAttr('data-active-item-path') - it "removes its file name from the active pane", -> + it "does not add the file name as data attribute to the pane", -> expect(pane).not.toHaveAttr('data-active-item-name') describe "when an item is destroyed", -> diff --git a/src/pane-element.coffee b/src/pane-element.coffee index 2f0481829..fec8904fb 100644 --- a/src/pane-element.coffee +++ b/src/pane-element.coffee @@ -1,3 +1,4 @@ +path = require 'path' {CompositeDisposable} = require 'event-kit' Grim = require 'grim' {$, callAttachHooks, callRemoveHooks} = require './space-pen-extensions' @@ -72,7 +73,6 @@ class PaneElement extends HTMLElement itemView = atom.views.getView(item) if itemPath = item.getPath?() - path = require 'path' @dataset.activeItemName = path.basename(itemPath) @dataset.activeItemPath = itemPath else From 9a0c3f94a9c455a7f84af2d0955cb0ade89c618c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 15 Apr 2015 10:32:22 -0700 Subject: [PATCH 0699/1783] Remove path data attributes when no active item --- spec/pane-view-spec.coffee | 6 ++++++ src/pane-element.coffee | 6 +++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/spec/pane-view-spec.coffee b/spec/pane-view-spec.coffee index 2bff010e7..ecb8b259d 100644 --- a/spec/pane-view-spec.coffee +++ b/spec/pane-view-spec.coffee @@ -128,6 +128,12 @@ describe "PaneView", -> it "adds the file name as a data attribute to the pane", -> expect(pane).toHaveAttr('data-active-item-name') + describe "when the activeItem is destroyed", -> + it "removes the data attributes", -> + pane.destroyItems() + expect(pane).not.toHaveAttr('data-active-item-path') + expect(pane).not.toHaveAttr('data-active-item-name') + describe "when the new activeItem does not implement ::getPath", -> beforeEach -> paneModel.activateItem(editor1) diff --git a/src/pane-element.coffee b/src/pane-element.coffee index fec8904fb..2f2e2e8cc 100644 --- a/src/pane-element.coffee +++ b/src/pane-element.coffee @@ -67,6 +67,9 @@ class PaneElement extends HTMLElement @classList.remove('active') activeItemChanged: (item) -> + delete @dataset.activeItemName + delete @dataset.activeItemPath + return unless item? hasFocus = @hasFocus() @@ -75,9 +78,6 @@ class PaneElement extends HTMLElement if itemPath = item.getPath?() @dataset.activeItemName = path.basename(itemPath) @dataset.activeItemPath = itemPath - else - delete @dataset.activeItemName - delete @dataset.activeItemPath unless @itemViews.contains(itemView) @itemViews.appendChild(itemView) From 960a5a45f9b7ce44796e947085c7959b0d93b527 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 15 Apr 2015 11:10:01 -0700 Subject: [PATCH 0700/1783] :arrow_up: tello@1.0.5 --- build/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/package.json b/build/package.json index 212f9c3ed..565d7edb7 100644 --- a/build/package.json +++ b/build/package.json @@ -31,7 +31,7 @@ "request": "~2.27.0", "rimraf": "~2.2.2", "runas": "^2", - "tello": "1.0.4", + "tello": "1.0.5", "temp": "~0.8.1", "underscore-plus": "1.x", "unzip": "~0.1.9", From 37e7a734cf20ab9293df6a3cb1d97c2fc5f8887e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 15 Apr 2015 11:15:37 -0700 Subject: [PATCH 0701/1783] Prepare 0.193 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9f01c0c16..805866a29 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "0.192.0", + "version": "0.193.0", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From 1602b8cf45c8fb3c355691387fc4423750210f2c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 15 Apr 2015 14:01:49 -0700 Subject: [PATCH 0702/1783] :shirt: remove some coffee lint --- src/pane-element.coffee | 2 +- src/pane-resize-handle-element.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pane-element.coffee b/src/pane-element.coffee index ca3c35b31..15990bcc2 100644 --- a/src/pane-element.coffee +++ b/src/pane-element.coffee @@ -39,7 +39,7 @@ class PaneElement extends HTMLElement handleBlur = (event) => @model.blur() unless @contains(event.relatedTarget) - handleDragOver = (event) => + handleDragOver = (event) -> event.preventDefault() event.stopPropagation() diff --git a/src/pane-resize-handle-element.coffee b/src/pane-resize-handle-element.coffee index 80daecdd8..47548bc60 100644 --- a/src/pane-resize-handle-element.coffee +++ b/src/pane-resize-handle-element.coffee @@ -17,7 +17,7 @@ class PaneResizeHandleElement extends HTMLElement @previousSibling.model.setFlexScale(1) @nextSibling.model.setFlexScale(1) - resizeStarted: (e)-> + resizeStarted: (e) -> e.stopPropagation() document.addEventListener 'mousemove', @resizePane document.addEventListener 'mouseup', @resizeStopped From 1c67912ab68db4f034e396d18a35438c3b62658a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 15 Apr 2015 14:04:10 -0700 Subject: [PATCH 0703/1783] :shirt: remove a ; --- spec/pane-container-element-spec.coffee | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/spec/pane-container-element-spec.coffee b/spec/pane-container-element-spec.coffee index ef7392d84..ee0cb2d5b 100644 --- a/spec/pane-container-element-spec.coffee +++ b/spec/pane-container-element-spec.coffee @@ -40,7 +40,7 @@ describe "PaneResizeHandleElement", -> beforeEach -> container = new PaneContainer - containerElement = atom.views.getView(container); + containerElement = atom.views.getView(container) document.querySelector('#jasmine-content').appendChild(containerElement) resizeElementMove = (resizeElement, clientX, clientY) -> @@ -106,5 +106,3 @@ describe "PaneResizeHandleElement", -> # dynamically close pane, the pane's flexscale will recorver to origin value lowerPane.close() expectPaneScale [leftPane, 0.5], [rightPane, 1.5] - - From e4984d68cc48bb0d957db6621ac36ccdaf0e538a Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 15 Apr 2015 14:09:11 -0700 Subject: [PATCH 0704/1783] :art: Tidy up pane container resize element spec --- spec/pane-container-element-spec.coffee | 136 ++++++++++++++---------- src/pane-axis.coffee | 2 +- 2 files changed, 82 insertions(+), 56 deletions(-) diff --git a/spec/pane-container-element-spec.coffee b/spec/pane-container-element-spec.coffee index ee0cb2d5b..0a5b11b39 100644 --- a/spec/pane-container-element-spec.coffee +++ b/spec/pane-container-element-spec.coffee @@ -2,88 +2,108 @@ PaneContainer = require '../src/pane-container' PaneAxisElement = require '../src/pane-axis-element' PaneAxis = require '../src/pane-axis' -describe "PaneResizeHandleElement", -> - describe "when panes are added or removed in PaneAxisElement", -> +describe "PaneContainerElement", -> + describe "when panes are added or removed", -> [paneAxisElement, paneAxis] = [] beforeEach -> - paneAxisElement = document.createElement('atom-pane-axis') - paneAxis = new PaneAxis({}) - paneAxisElement.initialize(paneAxis) - document.querySelector('#jasmine-content').appendChild(paneAxisElement) + paneAxis = new PaneAxis + paneAxisElement = new PaneAxisElement().initialize(paneAxis) + + childTagNames = -> + child.nodeName.toLowerCase() for child in paneAxisElement.children it "inserts or removes resize elements", -> - expectPaneAxisElement = (index) -> - child = paneAxisElement.children[index] - expect(child.nodeName.toLowerCase()).toBe('atom-pane-axis') + expect(childTagNames()).toEqual [] - expectResizeElement = (index) -> - child = paneAxisElement.children[index] - expect(paneAxisElement.isPaneResizeHandleElement(child)).toBe(true) + paneAxis.addChild(new PaneAxis) + expect(childTagNames()).toEqual [ + 'atom-pane-axis' + ] - models = (new PaneAxis({}) for i in [0..2]) - paneAxis.addChild(models[0]) - paneAxis.addChild(models[1]) - expectResizeElement(1) + paneAxis.addChild(new PaneAxis) + expect(childTagNames()).toEqual [ + 'atom-pane-axis' + 'atom-pane-resize-handle' + 'atom-pane-axis' + ] - paneAxis.addChild(models[2]) - expectPaneAxisElement(i) for i in [0, 2, 4] - expectResizeElement(i) for i in [1, 3] + paneAxis.addChild(new PaneAxis) + expect(childTagNames()).toEqual [ + 'atom-pane-axis' + 'atom-pane-resize-handle' + 'atom-pane-axis' + 'atom-pane-resize-handle' + 'atom-pane-axis' + ] - # test removeChild - paneAxis.removeChild(models[2]) - expectResizeElement(i) for i in [1] + paneAxis.removeChild(paneAxis.getChildren()[2]) + expect(childTagNames()).toEqual [ + 'atom-pane-axis' + 'atom-pane-resize-handle' + 'atom-pane-axis' + ] describe "when the resize element is dragged ", -> [container, containerElement] = [] - [resizeElementMove, getElementWidth, expectPaneScale] = [] beforeEach -> container = new PaneContainer containerElement = atom.views.getView(container) document.querySelector('#jasmine-content').appendChild(containerElement) - resizeElementMove = (resizeElement, clientX, clientY) -> - mouseDownEvent = new MouseEvent 'mousedown', - { view: window, bubbles: true, button: 0 } - resizeElement.dispatchEvent(mouseDownEvent) + dragElementToPosition = (element, clientX) -> + element.dispatchEvent(new MouseEvent('mousedown', + view: window + bubbles: true + button: 0 + )) - mouseMoveEvent = new MouseEvent 'mousemove', - { view: window, bubbles: true, clientX: clientX, clientY: clientY} - resizeElement.dispatchEvent(mouseMoveEvent) + element.dispatchEvent(new MouseEvent 'mousemove', + view: window + bubbles: true + clientX: clientX + ) - mouseUpEvent = new MouseEvent 'mouseup', - {view: window, bubbles: true, button: 0} - resizeElement.dispatchEvent(mouseUpEvent) + element.dispatchEvent(new MouseEvent 'mouseup', + iew: window + bubbles: true + button: 0 + ) - getElementWidth = (element) -> - element.getBoundingClientRect().width + getElementWidth = (element) -> + element.getBoundingClientRect().width - # assert the pane's flex scale. arguments is list of pane-scale pair - expectPaneScale = -> - args = Array::slice.call(arguments, 0) - for paneScale in args - expect(paneScale[0].getFlexScale()).toBeCloseTo(paneScale[1], 0.1) + expectPaneScale = (pairs...) -> + for [pane, expectedFlexScale] in pairs + expect(pane.getFlexScale()).toBeCloseTo(expectedFlexScale, 0.1) + + getResizeElement = (i) -> + containerElement.querySelectorAll('atom-pane-resize-handle')[i] + + getPaneElement = (i) -> + containerElement.querySelectorAll('atom-pane')[i] it "adds and removes panes in the direction that the pane is being dragged", -> leftPane = container.getActivePane() + expectPaneScale [leftPane, 1] + middlePane = leftPane.splitRight() + expectPaneScale [leftPane, 1], [middlePane, 1] - [resizeElements, paneElements] = [] - reloadElements = -> - resizeElements = containerElement.querySelectorAll('atom-pane-resize-handle') - paneElements = containerElement.querySelectorAll('atom-pane') - reloadElements() - expect(resizeElements.length).toBe(1) - - resizeElementMove(resizeElements[0], getElementWidth(paneElements[0]) / 2) + dragElementToPosition( + getResizeElement(0), + getElementWidth(getPaneElement(0)) / 2 + ) expectPaneScale [leftPane, 0.5], [middlePane, 1.5] - # add a new pane rightPane = middlePane.splitRight() - reloadElements() - clientX = getElementWidth(paneElements[0]) + getElementWidth(paneElements[1]) / 2 - resizeElementMove(resizeElements[1], clientX) + expectPaneScale [leftPane, 0.5], [middlePane, 1.5], [rightPane, 1] + + dragElementToPosition( + getResizeElement(1), + getElementWidth(getPaneElement(0)) + getElementWidth(getPaneElement(1)) / 2 + ) expectPaneScale [leftPane, 0.5], [middlePane, 0.75], [rightPane, 1.75] middlePane.close() @@ -94,10 +114,16 @@ describe "PaneResizeHandleElement", -> it "splits or closes panes in orthogonal direction that the pane is being dragged", -> leftPane = container.getActivePane() - rightPane = leftPane.splitRight() + expectPaneScale [leftPane, 1] - resizeElement = containerElement.querySelector('atom-pane-resize-handle') - resizeElementMove(resizeElement, getElementWidth(resizeElement.previousSibling) / 2) + rightPane = leftPane.splitRight() + expectPaneScale [leftPane, 1], [rightPane, 1] + + dragElementToPosition( + getResizeElement(0), + getElementWidth(getPaneElement(0)) / 2 + ) + expectPaneScale [leftPane, 0.5], [rightPane, 1.5] # dynamically split pane, pane's flexScale will become to 1 lowerPane = leftPane.splitDown() diff --git a/src/pane-axis.coffee b/src/pane-axis.coffee index 9489d3222..1fba48d37 100644 --- a/src/pane-axis.coffee +++ b/src/pane-axis.coffee @@ -12,7 +12,7 @@ class PaneAxis extends Model container: null orientation: null - constructor: ({@container, @orientation, children, flexScale}) -> + constructor: ({@container, @orientation, children, flexScale}={}) -> @emitter = new Emitter @subscriptionsByChild = new WeakMap @subscriptions = new CompositeDisposable From 4545671dcfc8580470afb6924f99f05a15632881 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 15 Apr 2015 14:20:16 -0700 Subject: [PATCH 0705/1783] Move file drag and drop specs to pane-view-spec --- spec/pane-view-spec.coffee | 27 +++++++++++++++++++++++++++ spec/window-spec.coffee | 27 --------------------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/spec/pane-view-spec.coffee b/spec/pane-view-spec.coffee index ecb8b259d..19fa247e0 100644 --- a/spec/pane-view-spec.coffee +++ b/spec/pane-view-spec.coffee @@ -360,3 +360,30 @@ describe "PaneView", -> pane3 = container3.getRoot() container3.attachToDom() expect(pane3).not.toMatchSelector(':has(:focus)') + + describe "drag and drop", -> + buildDragEvent = (type, files) -> + dataTransfer = + files: files + data: {} + setData: (key, value) -> @data[key] = value + getData: (key) -> @data[key] + + event = new CustomEvent("drop") + event.dataTransfer = dataTransfer + event + + describe "when a file is dragged to window", -> + it "opens it", -> + spyOn(atom, "open") + event = buildDragEvent("drop", [ {path: "/fake1"}, {path: "/fake2"} ]) + pane[0].dispatchEvent(event) + expect(atom.open.callCount).toBe 1 + expect(atom.open.argsForCall[0][0]).toEqual pathsToOpen: ['/fake1', '/fake2'] + + describe "when a non-file is dragged to window", -> + it "does nothing", -> + spyOn(atom, "open") + event = buildDragEvent("drop", []) + pane[0].dispatchEvent(event) + expect(atom.open).not.toHaveBeenCalled() diff --git a/spec/window-spec.coffee b/spec/window-spec.coffee index 3c1a5b4ae..376a71ab3 100644 --- a/spec/window-spec.coffee +++ b/spec/window-spec.coffee @@ -141,33 +141,6 @@ describe "Window", -> expect(buffer.getSubscriptionCount()).toBe 0 - describe "drag and drop", -> - buildDragEvent = (type, files) -> - dataTransfer = - files: files - data: {} - setData: (key, value) -> @data[key] = value - getData: (key) -> @data[key] - - event = new CustomEvent("drop") - event.dataTransfer = dataTransfer - event - - describe "when a file is dragged to window", -> - it "opens it", -> - spyOn(atom, "open") - event = buildDragEvent("drop", [ {path: "/fake1"}, {path: "/fake2"} ]) - document.dispatchEvent(event) - expect(atom.open.callCount).toBe 1 - expect(atom.open.argsForCall[0][0]).toEqual pathsToOpen: ['/fake1', '/fake2'] - - describe "when a non-file is dragged to window", -> - it "does nothing", -> - spyOn(atom, "open") - event = buildDragEvent("drop", []) - document.dispatchEvent(event) - expect(atom.open).not.toHaveBeenCalled() - describe "when a link is clicked", -> it "opens the http/https links in an external application", -> shell = require 'shell' From c8f590dfec22b6eb8f438b63877ff70c7fce9543 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 15 Apr 2015 14:28:22 -0700 Subject: [PATCH 0706/1783] Don't bundle specs and fixtures --- build/tasks/build-task.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/tasks/build-task.coffee b/build/tasks/build-task.coffee index a94b38f75..57d9f7964 100644 --- a/build/tasks/build-task.coffee +++ b/build/tasks/build-task.coffee @@ -143,7 +143,7 @@ module.exports = (grunt) -> for directory in packageDirectories cp directory, path.join(appDir, directory), filter: filterPackage - cp 'spec', path.join(appDir, 'spec') + cp 'spec', path.join(appDir, 'spec'), filter: /fixtures|integration|.+-spec\.coffee/ cp 'src', path.join(appDir, 'src'), filter: /.+\.(cson|coffee)$/ cp 'static', path.join(appDir, 'static') From da3012b643bd0a10c5daad3b006b63ae2c1f1691 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 15 Apr 2015 15:06:08 -0700 Subject: [PATCH 0707/1783] :arrow_up: language-go@0.25 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 805866a29..744994a8f 100644 --- a/package.json +++ b/package.json @@ -130,7 +130,7 @@ "language-css": "0.28.0", "language-gfm": "0.69.0", "language-git": "0.10.0", - "language-go": "0.24.0", + "language-go": "0.25.0", "language-html": "0.32.0", "language-hyperlink": "0.12.2", "language-java": "0.14.0", From b8c7f655f92f2e78a4668b4bc92fcc7762619ca3 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 14 Apr 2015 17:11:52 -0700 Subject: [PATCH 0708/1783] :art: Extract logic for storage folder into separate class --- spec/atom-spec.coffee | 2 +- src/atom.coffee | 49 +++++++++++------------------ src/browser/atom-application.coffee | 33 +++++++------------ src/storage-folder.coffee | 27 ++++++++++++++++ 4 files changed, 58 insertions(+), 53 deletions(-) create mode 100644 src/storage-folder.coffee diff --git a/spec/atom-spec.coffee b/spec/atom-spec.coffee index a293edccd..99a7f432e 100644 --- a/spec/atom-spec.coffee +++ b/spec/atom-spec.coffee @@ -139,7 +139,7 @@ describe "the `atom` global", -> windowState: null spyOn(Atom, 'getLoadSettings').andCallFake -> loadSettings - spyOn(Atom, 'getStorageDirPath').andReturn(temp.mkdirSync("storage-dir-")) + spyOn(Atom.getStorageFolder(), 'getPath').andReturn(temp.mkdirSync("storage-dir-")) atom.mode = "editor" atom.state.stuff = "cool" diff --git a/src/atom.coffee b/src/atom.coffee index 595dc7930..8016d0971 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -14,6 +14,7 @@ Model = require './model' {$} = require './space-pen-extensions' WindowEventHandler = require './window-event-handler' StylesElement = require './styles-element' +StorageFolder = require './storage-folder' # Essential: Atom global for dealing with packages, themes, menus, and the window. # @@ -73,34 +74,24 @@ class Atom extends Model # Loads and returns the serialized state corresponding to this window # if it exists; otherwise returns undefined. @loadState: (mode) -> - statePath = @getStatePath(@getLoadSettings().initialPaths, mode) + if stateKey = @getStateKey(@getLoadSettings().initialPaths, mode) + if state = @getStorageFolder().load(stateKey) + return state - if fs.existsSync(statePath) + if windowState = @getLoadSettings().windowState try - stateString = fs.readFileSync(statePath, 'utf8') + JSON.parse(@getLoadSettings().windowState) catch error - console.warn "Error reading window state: #{statePath}", error.stack, error - else - stateString = @getLoadSettings().windowState - - try - JSON.parse(stateString) if stateString? - catch error - console.warn "Error parsing window state: #{statePath} #{error.stack}", error + console.warn "Error parsing window state: #{statePath} #{error.stack}", error # Returns the path where the state for the current window will be # located if it exists. - @getStatePath: (paths, mode) -> - switch mode - when 'spec' - filename = 'spec' - when 'editor' - if paths?.length > 0 - sha1 = crypto.createHash('sha1').update(paths.slice().sort().join("\n")).digest('hex') - filename = "editor-#{sha1}" - - if filename - path.join(@getStorageDirPath(), filename) + @getStateKey: (paths, mode) -> + if mode is 'spec' + 'spec' + else if mode is 'editor' and paths?.length > 0 + sha1 = crypto.createHash('sha1').update(paths.slice().sort().join("\n")).digest('hex') + "editor-#{sha1}" else null @@ -110,11 +101,8 @@ class Atom extends Model @getConfigDirPath: -> @configDirPath ?= process.env.ATOM_HOME - # Get the path to Atom's storage directory. - # - # Returns the absolute path to ~/.atom/storage - @getStorageDirPath: -> - @storageDirPath ?= path.join(@getConfigDirPath(), 'storage') + @getStorageFolder: -> + @storageFolder ?= new StorageFolder(@getConfigDirPath()) # Returns the load settings hash associated with the current window. @getLoadSettings: -> @@ -791,11 +779,10 @@ class Atom extends Model dialog.showSaveDialog currentWindow, {title: 'Save File', defaultPath} saveSync: -> - stateString = JSON.stringify(@state) - if statePath = @constructor.getStatePath(@project?.getPaths(), @mode) - fs.writeFileSync(statePath, stateString, 'utf8') + if storageKey = @constructor.getStateKey(@project?.getPaths(), @mode) + @constructor.getStorageFolder().store(storageKey, @state) else - @getCurrentWindow().loadSettings.windowState = stateString + @getCurrentWindow().loadSettings.windowState = JSON.stringify(@state) crashMainProcess: -> remote.process.crash() diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 3d1b3b92e..6db4629bb 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -3,6 +3,7 @@ ApplicationMenu = require './application-menu' AtomProtocolHandler = require './atom-protocol-handler' AutoUpdateManager = require './auto-update-manager' BrowserWindow = require 'browser-window' +StorageFolder = require '../storage-folder' Menu = require 'menu' app = require 'app' fs = require 'fs-plus' @@ -77,6 +78,7 @@ class AtomApplication @listenForArgumentsFromNewProcess() @setupJavaScriptArguments() @handleEvents() + @storageFolder = new StorageFolder(process.env.ATOM_HOME) if options.pathsToOpen?.length > 0 or options.urlsToOpen?.length > 0 or options.test @openWithOptions(options) @@ -426,29 +428,18 @@ class AtomApplication 'safeMode' 'apiPreviewMode' )) - fs.writeFileSync(@getStatePath(), JSON.stringify(states)) + @storageFolder.store('application.json', states) loadState: -> - try - stateString = fs.readFileSync(@getStatePath(), 'utf8') - catch error - if error.code is 'ENOENT' - return false - else - throw error - - states = JSON.parse(fs.readFileSync(@getStatePath())) - for state in states - @openWithOptions({ - pathsToOpen: state.initialPaths - urlsToOpen: [] - devMode: state.devMode - safeMode: state.safeMode - apiPreviewMode: state.apiPreviewMode - }) - - getStatePath: -> - path.join(process.env.ATOM_HOME, "storage", "application.json") + if states = @storageFolder.load('application.json') + for state in states + @openWithOptions({ + pathsToOpen: state.initialPaths + urlsToOpen: [] + devMode: state.devMode + safeMode: state.safeMode + apiPreviewMode: state.apiPreviewMode + }) # Open an atom:// url. # diff --git a/src/storage-folder.coffee b/src/storage-folder.coffee new file mode 100644 index 000000000..12139d197 --- /dev/null +++ b/src/storage-folder.coffee @@ -0,0 +1,27 @@ +path = require "path" +fs = require "fs-plus" + +module.exports = +class StorageFolder + constructor: (containingPath) -> + @path = path.join(containingPath, "storage") + + store: (name, object) -> + fs.writeFileSync(@pathForKey(name), JSON.stringify(object), 'utf8') + + load: (name) -> + try + stateString = fs.readFileSync(@pathForKey(name), 'utf8') + catch error + if error.code is 'ENOENT' + return undefined + else + throw error + + try + JSON.parse(stateString) + catch error + console.warn "Error reading state file: #{statePath}", error.stack, error + + pathForKey: (name) -> path.join(@getPath(), name) + getPath: -> @path From 8f063018803ecd230c8cb1c6830ef88fdfe63c5e Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 15 Apr 2015 10:15:02 -0700 Subject: [PATCH 0709/1783] Open window if Atom was previously quit w/ no open windows --- src/browser/atom-application.coffee | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 6db4629bb..8a56b8cf0 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -431,7 +431,7 @@ class AtomApplication @storageFolder.store('application.json', states) loadState: -> - if states = @storageFolder.load('application.json') + if (states = @storageFolder.load('application.json'))?.length > 0 for state in states @openWithOptions({ pathsToOpen: state.initialPaths @@ -440,6 +440,9 @@ class AtomApplication safeMode: state.safeMode apiPreviewMode: state.apiPreviewMode }) + true + else + false # Open an atom:// url. # From 5a8885aeed7a278ef1878492186e39284e9673ff Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 8 Apr 2015 14:04:50 -0700 Subject: [PATCH 0710/1783] Revert "Revert "Add asar support in Atom"" --- apm/package.json | 2 +- build/Gruntfile.coffee | 4 ++-- build/package.json | 1 + build/tasks/build-task.coffee | 6 +++--- build/tasks/generate-asar-task.coffee | 19 +++++++++++++++++++ build/tasks/generate-license-task.coffee | 2 +- script/mkdeb | 2 +- src/atom.coffee | 6 +++--- src/browser/atom-application.coffee | 2 +- src/browser/squirrel-update.coffee | 2 +- src/command-installer.coffee | 13 ++++++------- src/package-manager.coffee | 2 +- src/task.coffee | 7 ++++++- 13 files changed, 46 insertions(+), 22 deletions(-) create mode 100644 build/tasks/generate-asar-task.coffee diff --git a/apm/package.json b/apm/package.json index 84f73451d..e7a0c8fdc 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.157.0" + "atom-package-manager": "0.158.0" } } diff --git a/build/Gruntfile.coffee b/build/Gruntfile.coffee index dac5c8f1f..e2ca43e07 100644 --- a/build/Gruntfile.coffee +++ b/build/Gruntfile.coffee @@ -223,7 +223,7 @@ module.exports = (grunt) -> ciTasks = ['output-disk-space', 'download-atom-shell', 'download-atom-shell-chromedriver', 'build'] ciTasks.push('dump-symbols') if process.platform isnt 'win32' - ciTasks.push('set-version', 'check-licenses', 'lint') + ciTasks.push('set-version', 'check-licenses', 'lint', 'generate-asar') ciTasks.push('mkdeb') if process.platform is 'linux' ciTasks.push('create-windows-installer') if process.platform is 'win32' ciTasks.push('test') if process.platform is 'darwin' @@ -231,6 +231,6 @@ module.exports = (grunt) -> ciTasks.push('publish-build') grunt.registerTask('ci', ciTasks) - defaultTasks = ['download-atom-shell', 'download-atom-shell-chromedriver', 'build', 'set-version'] + defaultTasks = ['download-atom-shell', 'download-atom-shell-chromedriver', 'build', 'set-version', 'generate-asar'] defaultTasks.push 'install' unless process.platform is 'linux' grunt.registerTask('default', defaultTasks) diff --git a/build/package.json b/build/package.json index 565d7edb7..f9829f4b5 100644 --- a/build/package.json +++ b/build/package.json @@ -6,6 +6,7 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { + "asar": "^0.4.0", "async": "~0.2.9", "donna": "1.0.10", "formidable": "~1.0.14", diff --git a/build/tasks/build-task.coffee b/build/tasks/build-task.coffee index 57d9f7964..81ec1e17f 100644 --- a/build/tasks/build-task.coffee +++ b/build/tasks/build-task.coffee @@ -22,7 +22,7 @@ module.exports = (grunt) -> mkdir appDir if process.platform isnt 'win32' - cp 'atom.sh', path.join(appDir, 'atom.sh') + cp 'atom.sh', path.resolve(appDir, '..', 'atom.sh') cp 'package.json', path.join(appDir, 'package.json') @@ -147,9 +147,9 @@ module.exports = (grunt) -> cp 'src', path.join(appDir, 'src'), filter: /.+\.(cson|coffee)$/ cp 'static', path.join(appDir, 'static') - cp path.join('apm', 'node_modules', 'atom-package-manager'), path.join(appDir, 'apm'), filter: filterNodeModule + cp path.join('apm', 'node_modules', 'atom-package-manager'), path.resolve(appDir, '..', 'apm'), filter: filterNodeModule if process.platform isnt 'win32' - fs.symlinkSync(path.join('..', '..', 'bin', 'apm'), path.join(appDir, 'apm', 'node_modules', '.bin', 'apm')) + fs.symlinkSync(path.join('..', '..', 'bin', 'apm'), path.resolve(appDir, '..', 'apm', 'node_modules', '.bin', 'apm')) if process.platform is 'darwin' grunt.file.recurse path.join('resources', 'mac'), (sourcePath, rootDirectory, subDirectory='', filename) -> diff --git a/build/tasks/generate-asar-task.coffee b/build/tasks/generate-asar-task.coffee new file mode 100644 index 000000000..1f74fbf5d --- /dev/null +++ b/build/tasks/generate-asar-task.coffee @@ -0,0 +1,19 @@ +asar = require 'asar' +fs = require 'fs' +path = require 'path' + +module.exports = (grunt) -> + {rm} = require('./task-helpers')(grunt) + + grunt.registerTask 'generate-asar', 'Generate asar archive for the app', -> + done = @async() + + appDir = grunt.config.get('atom.appDir') + unless fs.existsSync(appDir) + grunt.log.error 'The app has to be built before generating asar archive.' + return done(false) + + asar.createPackageWithOptions appDir, path.resolve(appDir, '..', 'app.asar'), {unpack: '*.node'}, (err) -> + return done(err) if err? + rm appDir + done() diff --git a/build/tasks/generate-license-task.coffee b/build/tasks/generate-license-task.coffee index 6b616f5cb..eaf1a9a66 100644 --- a/build/tasks/generate-license-task.coffee +++ b/build/tasks/generate-license-task.coffee @@ -17,7 +17,7 @@ module.exports = (grunt) -> licenseText = getLicenseText(dependencyLicenses) if mode is 'save' - targetPath = path.join(grunt.config.get('atom.appDir'), 'LICENSE.md') + targetPath = path.resolve(grunt.config.get('atom.appDir'), '..', 'LICENSE.md') fs.writeFileSync(targetPath, licenseText) else console.log licenseText diff --git a/script/mkdeb b/script/mkdeb index 272fe23f3..c39b6d649 100755 --- a/script/mkdeb +++ b/script/mkdeb @@ -33,7 +33,7 @@ cp "$ICON_FILE" "$TARGET/usr/share/pixmaps" # Copy generated LICENSE.md to /usr/share/doc/atom/copyright mkdir -m $FILE_MODE -p "$TARGET/usr/share/doc/atom" -cp "$TARGET/usr/share/atom/resources/app/LICENSE.md" "$TARGET/usr/share/doc/atom/copyright" +cp "$TARGET/usr/share/atom/resources/LICENSE.md" "$TARGET/usr/share/doc/atom/copyright" # Add lintian overrides mkdir -m $FILE_MODE -p "$TARGET/usr/share/lintian/overrides" diff --git a/src/atom.coffee b/src/atom.coffee index 8016d0971..58f940548 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -215,7 +215,7 @@ class Atom extends Model if openDevTools @openDevTools() - @executeJavaScriptInDevTools('InspectorFrontendAPI.showConsole()') + @executeJavaScriptInDevTools('DevToolsAPI.showConsole()') @emit 'uncaught-error', arguments... if includeDeprecatedAPIs @emitter.emit 'did-throw-error', {message, url, line, column, originalError} @@ -577,9 +577,9 @@ class Atom extends Model {resourcePath, safeMode} = @getLoadSettings() CommandInstaller = require './command-installer' - CommandInstaller.installAtomCommand resourcePath, false, (error) -> + CommandInstaller.installAtomCommand false, (error) -> console.warn error.message if error? - CommandInstaller.installApmCommand resourcePath, false, (error) -> + CommandInstaller.installApmCommand false, (error) -> console.warn error.message if error? dimensions = @restoreWindowDimensions() diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index b7a2ca5c0..dbe29caab 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -196,7 +196,7 @@ class AtomApplication @openPathOnEvent('application:open-your-keymap', 'atom://.atom/keymap') @openPathOnEvent('application:open-your-snippets', 'atom://.atom/snippets') @openPathOnEvent('application:open-your-stylesheet', 'atom://.atom/stylesheet') - @openPathOnEvent('application:open-license', path.join(@resourcePath, 'LICENSE.md')) + @openPathOnEvent('application:open-license', path.join(process.resourcesPath, 'LICENSE.md')) app.on 'window-all-closed', -> app.quit() if process.platform in ['win32', 'linux'] diff --git a/src/browser/squirrel-update.coffee b/src/browser/squirrel-update.coffee index 1603a7c0a..3bdd84223 100644 --- a/src/browser/squirrel-update.coffee +++ b/src/browser/squirrel-update.coffee @@ -142,7 +142,7 @@ addCommandsToPath = (callback) -> atomShCommand = "#!/bin/sh\r\n\"$0/../#{relativeAtomShPath.replace(/\\/g, '/')}\" \"$@\"" apmCommandPath = path.join(binFolder, 'apm.cmd') - relativeApmPath = path.relative(binFolder, path.join(process.resourcesPath, 'app', 'apm', 'bin', 'apm.cmd')) + relativeApmPath = path.relative(binFolder, path.join(process.resourcesPath, 'apm', 'bin', 'apm.cmd')) apmCommand = "@echo off\r\n\"%~dp0\\#{relativeApmPath}\" %*" apmShCommandPath = path.join(binFolder, 'apm') diff --git a/src/command-installer.coffee b/src/command-installer.coffee index c0ed22482..f18a05199 100644 --- a/src/command-installer.coffee +++ b/src/command-installer.coffee @@ -36,12 +36,11 @@ module.exports = message: "Failed to install shell commands" detailedMessage: error.message - resourcePath = atom.getLoadSettings().resourcePath - @installAtomCommand resourcePath, true, (error) => + @installAtomCommand true, (error) => if error? showErrorDialog(error) else - @installApmCommand resourcePath, true, (error) -> + @installApmCommand true, (error) -> if error? showErrorDialog(error) else @@ -49,12 +48,12 @@ module.exports = message: "Commands installed." detailedMessage: "The shell commands `atom` and `apm` are installed." - installAtomCommand: (resourcePath, askForPrivilege, callback) -> - commandPath = path.join(resourcePath, 'atom.sh') + installAtomCommand: (askForPrivilege, callback) -> + commandPath = path.join(process.resourcesPath, 'atom.sh') @createSymlink commandPath, askForPrivilege, callback - installApmCommand: (resourcePath, askForPrivilege, callback) -> - commandPath = path.join(resourcePath, 'apm', 'node_modules', '.bin', 'apm') + installApmCommand: (askForPrivilege, callback) -> + commandPath = path.join(process.resourcesPath, 'apm', 'node_modules', '.bin', 'apm') @createSymlink commandPath, askForPrivilege, callback createSymlink: (commandPath, askForPrivilege, callback) -> diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 386a65e68..829cae804 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -111,7 +111,7 @@ class PackageManager commandName = 'apm' commandName += '.cmd' if process.platform is 'win32' - apmRoot = path.resolve(__dirname, '..', 'apm') + apmRoot = path.join(process.resourcesPath, 'apm') @apmPath = path.join(apmRoot, 'bin', commandName) unless fs.isFileSync(@apmPath) @apmPath = path.join(apmRoot, 'node_modules', 'atom-package-manager', 'bin', commandName) diff --git a/src/task.coffee b/src/task.coffee index 9572494b8..d752ea11d 100644 --- a/src/task.coffee +++ b/src/task.coffee @@ -83,7 +83,7 @@ class Task taskPath = taskPath.replace(/\\/g, "\\\\") env = _.extend({}, process.env, {taskPath, userAgent: navigator.userAgent}) - @childProcess = fork '--eval', [bootstrap], {env, cwd: __dirname} + @childProcess = fork '--eval', [bootstrap], {env, silent: true} @on "task:log", -> console.log(arguments...) @on "task:warn", -> console.warn(arguments...) @@ -100,6 +100,11 @@ class Task @childProcess.removeAllListeners() @childProcess.on 'message', ({event, args}) => @emit(event, args...) if @childProcess? + # Catch the errors that happened before task-bootstrap. + @childProcess.stdout.on 'data', (data) -> + console.log data.toString() + @childProcess.stderr.on 'data', (data) -> + console.error data.toString() # Public: Starts the task. # From a61f732cf808558b272d18ad9a2ee3ff5786dbe7 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 8 Apr 2015 14:30:32 -0700 Subject: [PATCH 0711/1783] Keep apm and atom.sh in app folder --- build/tasks/build-task.coffee | 6 +++--- build/tasks/generate-asar-task.coffee | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/build/tasks/build-task.coffee b/build/tasks/build-task.coffee index 81ec1e17f..f49079d19 100644 --- a/build/tasks/build-task.coffee +++ b/build/tasks/build-task.coffee @@ -22,7 +22,7 @@ module.exports = (grunt) -> mkdir appDir if process.platform isnt 'win32' - cp 'atom.sh', path.resolve(appDir, '..', 'atom.sh') + cp 'atom.sh', path.resolve(appDir, '..', 'new-app', 'atom.sh') cp 'package.json', path.join(appDir, 'package.json') @@ -147,9 +147,9 @@ module.exports = (grunt) -> cp 'src', path.join(appDir, 'src'), filter: /.+\.(cson|coffee)$/ cp 'static', path.join(appDir, 'static') - cp path.join('apm', 'node_modules', 'atom-package-manager'), path.resolve(appDir, '..', 'apm'), filter: filterNodeModule + cp path.join('apm', 'node_modules', 'atom-package-manager'), path.resolve(appDir, '..', 'new-app', 'apm'), filter: filterNodeModule if process.platform isnt 'win32' - fs.symlinkSync(path.join('..', '..', 'bin', 'apm'), path.resolve(appDir, '..', 'apm', 'node_modules', '.bin', 'apm')) + fs.symlinkSync(path.join('..', '..', 'bin', 'apm'), path.resolve(appDir, '..', 'new-app', 'apm', 'node_modules', '.bin', 'apm')) if process.platform is 'darwin' grunt.file.recurse path.join('resources', 'mac'), (sourcePath, rootDirectory, subDirectory='', filename) -> diff --git a/build/tasks/generate-asar-task.coffee b/build/tasks/generate-asar-task.coffee index 1f74fbf5d..d08c169e2 100644 --- a/build/tasks/generate-asar-task.coffee +++ b/build/tasks/generate-asar-task.coffee @@ -3,7 +3,7 @@ fs = require 'fs' path = require 'path' module.exports = (grunt) -> - {rm} = require('./task-helpers')(grunt) + {cp, rm} = require('./task-helpers')(grunt) grunt.registerTask 'generate-asar', 'Generate asar archive for the app', -> done = @async() @@ -15,5 +15,7 @@ module.exports = (grunt) -> asar.createPackageWithOptions appDir, path.resolve(appDir, '..', 'app.asar'), {unpack: '*.node'}, (err) -> return done(err) if err? + rm appDir + fs.renameSync path.resolve(appDir, '..', 'new-app'), appDir done() From 00e91dc9df1e361b43373a8351b28990d27d96db Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 8 Apr 2015 14:31:37 -0700 Subject: [PATCH 0712/1783] Look for apm in app folder --- src/package-manager.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 829cae804..8527188d3 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -111,7 +111,7 @@ class PackageManager commandName = 'apm' commandName += '.cmd' if process.platform is 'win32' - apmRoot = path.join(process.resourcesPath, 'apm') + apmRoot = path.join(process.resourcesPath, 'app', 'apm') @apmPath = path.join(apmRoot, 'bin', commandName) unless fs.isFileSync(@apmPath) @apmPath = path.join(apmRoot, 'node_modules', 'atom-package-manager', 'bin', commandName) From df28212bdfdead32b9025091c15c2d2ff3fbafeb Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 8 Apr 2015 14:33:39 -0700 Subject: [PATCH 0713/1783] Expect atom.sh and apm in app folder --- src/command-installer.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/command-installer.coffee b/src/command-installer.coffee index f18a05199..2f3f78b17 100644 --- a/src/command-installer.coffee +++ b/src/command-installer.coffee @@ -49,11 +49,11 @@ module.exports = detailedMessage: "The shell commands `atom` and `apm` are installed." installAtomCommand: (askForPrivilege, callback) -> - commandPath = path.join(process.resourcesPath, 'atom.sh') + commandPath = path.join(process.resourcesPath, 'app', 'atom.sh') @createSymlink commandPath, askForPrivilege, callback installApmCommand: (askForPrivilege, callback) -> - commandPath = path.join(process.resourcesPath, 'apm', 'node_modules', '.bin', 'apm') + commandPath = path.join(process.resourcesPath, 'app', 'apm', 'node_modules', '.bin', 'apm') @createSymlink commandPath, askForPrivilege, callback createSymlink: (commandPath, askForPrivilege, callback) -> From 245f4585cd9fbe8eff568e031197a4146370aee4 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 8 Apr 2015 14:52:34 -0700 Subject: [PATCH 0714/1783] Unpack ctags --- build/tasks/generate-asar-task.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/tasks/generate-asar-task.coffee b/build/tasks/generate-asar-task.coffee index d08c169e2..764fccb02 100644 --- a/build/tasks/generate-asar-task.coffee +++ b/build/tasks/generate-asar-task.coffee @@ -13,7 +13,7 @@ module.exports = (grunt) -> grunt.log.error 'The app has to be built before generating asar archive.' return done(false) - asar.createPackageWithOptions appDir, path.resolve(appDir, '..', 'app.asar'), {unpack: '*.node'}, (err) -> + asar.createPackageWithOptions appDir, path.resolve(appDir, '..', 'app.asar'), {unpack: '{*.node,ctags-darwin,ctags-linux,ctags-win32.exe}'}, (err) -> return done(err) if err? rm appDir From 8e5323d154bd41d9eff3760ce8a979c46405ae68 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 8 Apr 2015 14:53:49 -0700 Subject: [PATCH 0715/1783] apm is back in app folder --- src/browser/squirrel-update.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/browser/squirrel-update.coffee b/src/browser/squirrel-update.coffee index 3bdd84223..1603a7c0a 100644 --- a/src/browser/squirrel-update.coffee +++ b/src/browser/squirrel-update.coffee @@ -142,7 +142,7 @@ addCommandsToPath = (callback) -> atomShCommand = "#!/bin/sh\r\n\"$0/../#{relativeAtomShPath.replace(/\\/g, '/')}\" \"$@\"" apmCommandPath = path.join(binFolder, 'apm.cmd') - relativeApmPath = path.relative(binFolder, path.join(process.resourcesPath, 'apm', 'bin', 'apm.cmd')) + relativeApmPath = path.relative(binFolder, path.join(process.resourcesPath, 'app', 'apm', 'bin', 'apm.cmd')) apmCommand = "@echo off\r\n\"%~dp0\\#{relativeApmPath}\" %*" apmShCommandPath = path.join(binFolder, 'apm') From d534f2a867b1ab7f74dc16a38a7b2cc9ce4ca711 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 8 Apr 2015 17:39:36 -0700 Subject: [PATCH 0716/1783] Make ctags executable --- build/tasks/generate-asar-task.coffee | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build/tasks/generate-asar-task.coffee b/build/tasks/generate-asar-task.coffee index 764fccb02..1c4e2456e 100644 --- a/build/tasks/generate-asar-task.coffee +++ b/build/tasks/generate-asar-task.coffee @@ -18,4 +18,9 @@ module.exports = (grunt) -> rm appDir fs.renameSync path.resolve(appDir, '..', 'new-app'), appDir + + ctagsFolder = path.join("#{appDir}.asar.unpacked", 'node_modules', 'symbols-view', 'vendor') + for ctagsFile in fs.readdirSync(ctagsFolder) + fs.chmodSync(path.join(ctagsFolder, ctagsFile), "755") + done() From 6fcca86ede55c527ed280fdd298074883815575d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 8 Apr 2015 17:41:56 -0700 Subject: [PATCH 0717/1783] Unpack .ctags file --- build/tasks/generate-asar-task.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/tasks/generate-asar-task.coffee b/build/tasks/generate-asar-task.coffee index 1c4e2456e..775a7c92f 100644 --- a/build/tasks/generate-asar-task.coffee +++ b/build/tasks/generate-asar-task.coffee @@ -13,7 +13,7 @@ module.exports = (grunt) -> grunt.log.error 'The app has to be built before generating asar archive.' return done(false) - asar.createPackageWithOptions appDir, path.resolve(appDir, '..', 'app.asar'), {unpack: '{*.node,ctags-darwin,ctags-linux,ctags-win32.exe}'}, (err) -> + asar.createPackageWithOptions appDir, path.resolve(appDir, '..', 'app.asar'), {unpack: '{*.node,ctags-darwin,ctags-linux,ctags-win32.exe,\\.ctags}'}, (err) -> return done(err) if err? rm appDir From 1c6ee82c6d68e0b01d879d5f2aca36be86ccde56 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 13 Apr 2015 10:11:28 -0700 Subject: [PATCH 0718/1783] Don't bundle native-mate It makes the apm paths long and is only used during the build --- build/tasks/build-task.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/build/tasks/build-task.coffee b/build/tasks/build-task.coffee index f49079d19..3411f4dae 100644 --- a/build/tasks/build-task.coffee +++ b/build/tasks/build-task.coffee @@ -65,6 +65,7 @@ module.exports = (grunt) -> path.join('jasmine-node', 'node_modules', 'gaze') path.join('jasmine-node', 'spec') path.join('node_modules', 'nan') + path.join('node_modules', 'native-mate') path.join('build', 'binding.Makefile') path.join('build', 'config.gypi') path.join('build', 'gyp-mac-tool') From 1c5726b60c7d288437b9800cca7fb0bae141230f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 13 Apr 2015 10:13:45 -0700 Subject: [PATCH 0719/1783] :arrow_up: grunt-atom-shell-installer@0.29 --- build/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/package.json b/build/package.json index f9829f4b5..0403d04e0 100644 --- a/build/package.json +++ b/build/package.json @@ -13,7 +13,7 @@ "fs-plus": "2.x", "github-releases": "~0.2.0", "grunt": "~0.4.1", - "grunt-atom-shell-installer": "^0.28.0", + "grunt-atom-shell-installer": "^0.29.0", "grunt-cli": "~0.1.9", "grunt-coffeelint": "git+https://github.com/atom/grunt-coffeelint.git#cfb99aa99811d52687969532bd5a98011ed95bfe", "grunt-contrib-coffee": "~0.12.0", From 9f3ee0842e5984c917e75b185799c9dc9f73bd8a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 13 Apr 2015 10:30:47 -0700 Subject: [PATCH 0720/1783] :art: --- build/tasks/generate-asar-task.coffee | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/build/tasks/generate-asar-task.coffee b/build/tasks/generate-asar-task.coffee index 775a7c92f..81c3aae0b 100644 --- a/build/tasks/generate-asar-task.coffee +++ b/build/tasks/generate-asar-task.coffee @@ -8,12 +8,21 @@ module.exports = (grunt) -> grunt.registerTask 'generate-asar', 'Generate asar archive for the app', -> done = @async() + unpack = [ + '*.node' + 'ctags-darwin' + 'ctags-linux' + 'ctags-win32.exe' + '\\.ctags' + ] + unpack = "{#{unpack.join(',')}}" + appDir = grunt.config.get('atom.appDir') unless fs.existsSync(appDir) grunt.log.error 'The app has to be built before generating asar archive.' return done(false) - asar.createPackageWithOptions appDir, path.resolve(appDir, '..', 'app.asar'), {unpack: '{*.node,ctags-darwin,ctags-linux,ctags-win32.exe,\\.ctags}'}, (err) -> + asar.createPackageWithOptions appDir, path.resolve(appDir, '..', 'app.asar'), {unpack}, (err) -> return done(err) if err? rm appDir From 19b6043e92198181e6b003d0b40e3d052bfa7406 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 13 Apr 2015 12:17:54 -0700 Subject: [PATCH 0721/1783] Update .ctags pattern for unpacking --- build/tasks/generate-asar-task.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/tasks/generate-asar-task.coffee b/build/tasks/generate-asar-task.coffee index 81c3aae0b..ea09af862 100644 --- a/build/tasks/generate-asar-task.coffee +++ b/build/tasks/generate-asar-task.coffee @@ -10,10 +10,10 @@ module.exports = (grunt) -> unpack = [ '*.node' + '*.ctags' 'ctags-darwin' 'ctags-linux' 'ctags-win32.exe' - '\\.ctags' ] unpack = "{#{unpack.join(',')}}" From 324b68c79594b38cafa3b37c3c9aabf8b49821c6 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 13 Apr 2015 12:39:01 -0700 Subject: [PATCH 0722/1783] Remove unneeded * --- build/tasks/generate-asar-task.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/tasks/generate-asar-task.coffee b/build/tasks/generate-asar-task.coffee index ea09af862..a71d88dfe 100644 --- a/build/tasks/generate-asar-task.coffee +++ b/build/tasks/generate-asar-task.coffee @@ -10,7 +10,7 @@ module.exports = (grunt) -> unpack = [ '*.node' - '*.ctags' + '.ctags' 'ctags-darwin' 'ctags-linux' 'ctags-win32.exe' From e6a49c45316902f5ffcca2e998800727966dc827 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 13 Apr 2015 13:32:00 -0700 Subject: [PATCH 0723/1783] Remove unused resource path --- src/atom.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/atom.coffee b/src/atom.coffee index 58f940548..e2544640d 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -574,7 +574,7 @@ class Atom extends Model # Call this method when establishing a real application window. startEditorWindow: -> - {resourcePath, safeMode} = @getLoadSettings() + {safeMode} = @getLoadSettings() CommandInstaller = require './command-installer' CommandInstaller.installAtomCommand false, (error) -> From 2c5655b7d2ea26523ba5617588915dc96d319679 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 13 Apr 2015 13:33:12 -0700 Subject: [PATCH 0724/1783] Remove unused requires --- src/command-installer.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/command-installer.coffee b/src/command-installer.coffee index 2f3f78b17..afd5000c1 100644 --- a/src/command-installer.coffee +++ b/src/command-installer.coffee @@ -1,6 +1,4 @@ path = require 'path' -_ = require 'underscore-plus' -async = require 'async' fs = require 'fs-plus' runas = null # defer until used From 65420bd6cea22b046bb3e5134b9ab329b724d3ef Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 15 Apr 2015 11:28:36 -0700 Subject: [PATCH 0725/1783] Ensure latest asar is used --- build/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/package.json b/build/package.json index 0403d04e0..3f0a3caef 100644 --- a/build/package.json +++ b/build/package.json @@ -6,7 +6,7 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "asar": "^0.4.0", + "asar": "^0.4.4", "async": "~0.2.9", "donna": "1.0.10", "formidable": "~1.0.14", From 356bb7ce0f0e1293eadc683d687ea701f16f5863 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 15 Apr 2015 16:53:45 -0700 Subject: [PATCH 0726/1783] Don't rethrow exceptions from reading state files They block startup. --- src/storage-folder.coffee | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/storage-folder.coffee b/src/storage-folder.coffee index 12139d197..bf969dee2 100644 --- a/src/storage-folder.coffee +++ b/src/storage-folder.coffee @@ -10,18 +10,18 @@ class StorageFolder fs.writeFileSync(@pathForKey(name), JSON.stringify(object), 'utf8') load: (name) -> + statePath = @pathForKey(name) try - stateString = fs.readFileSync(@pathForKey(name), 'utf8') + stateString = fs.readFileSync(statePath, 'utf8') catch error - if error.code is 'ENOENT' - return undefined - else - throw error + unless error.code is 'ENOENT' + console.warn "Error reading state file: #{statePath}", error.stack, error + return undefined try JSON.parse(stateString) catch error - console.warn "Error reading state file: #{statePath}", error.stack, error + console.warn "Error parsing state file: #{statePath}", error.stack, error pathForKey: (name) -> path.join(@getPath(), name) getPath: -> @path From 77d73f92f76996f9953b2762d71fec560c421de2 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 16 Apr 2015 09:04:32 +0200 Subject: [PATCH 0727/1783] :penguin: Avoid starting xvfb on Linux ...since we don't run tests anymore in there. --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2372e62b4..7e47d0660 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,8 +13,6 @@ install: - nvm use $NODE_VERSION - if [ $TRAVIS_OS_NAME == "linux" ]; then sudo apt-get install build-essential git libgnome-keyring-dev fakeroot; - export DISPLAY=:99.0; - sh -e /etc/init.d/xvfb start; fi script: script/cibuild From b984a48456f0b6cc98c54bbb600e5a4f1e8d218e Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 16 Apr 2015 09:13:14 +0200 Subject: [PATCH 0728/1783] Don't run integration tests on Travis --- build/tasks/spec-task.coffee | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/build/tasks/spec-task.coffee b/build/tasks/spec-task.coffee index da5b24685..09a062ac9 100644 --- a/build/tasks/spec-task.coffee +++ b/build/tasks/spec-task.coffee @@ -86,23 +86,25 @@ module.exports = (grunt) -> resourcePath = process.cwd() coreSpecsPath = path.resolve('spec') + # Integration tests require a fast machine and, for now, we cannot afford to + # run them on Travis. + env = _.extend({}, process.env, + ATOM_INTEGRATION_TESTS_ENABLED: not process.env.TRAVIS + ) + if process.platform in ['darwin', 'linux'] options = cmd: appPath args: ['--test', "--resource-path=#{resourcePath}", "--spec-directory=#{coreSpecsPath}"] opts: - env: _.extend({}, process.env, - ATOM_INTEGRATION_TESTS_ENABLED: true - ) + env: env else if process.platform is 'win32' options = cmd: process.env.comspec args: ['/c', appPath, '--test', "--resource-path=#{resourcePath}", "--spec-directory=#{coreSpecsPath}", "--log-file=ci.log"] opts: - env: _.extend({}, process.env, - ATOM_INTEGRATION_TESTS_ENABLED: true - ) + env: env grunt.log.ok "Launching core specs." spawn options, (error, results, code) -> From 17894fd36b08f5dd96c3a463cd46ef6960be6ad4 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 16 Apr 2015 09:15:46 +0200 Subject: [PATCH 0729/1783] :art: --- .travis.yml | 3 +++ spec/spec-helper.coffee | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7e47d0660..de5a94718 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,6 @@ +git: + depth: 10 + env: - NODE_VERSION=0.10 - NODE_VERSION=0.12 diff --git a/spec/spec-helper.coffee b/spec/spec-helper.coffee index a0905ddf7..0112042e2 100644 --- a/spec/spec-helper.coffee +++ b/spec/spec-helper.coffee @@ -51,7 +51,7 @@ Object.defineProperty document, 'title', jasmine.getEnv().addEqualityTester(_.isEqual) # Use underscore's definition of equality for toEqual assertions -if (process.env.JANKY_SHA1 and process.platform is 'win32') or process.env.CI +if process.env.CI jasmine.getEnv().defaultTimeoutInterval = 60000 else jasmine.getEnv().defaultTimeoutInterval = 5000 From 50010a55b94ce4d13da905f5ff03b54ca17dbfa9 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 16 Apr 2015 09:52:41 +0200 Subject: [PATCH 0730/1783] Use a guard clause to disable integration specs --- build/tasks/spec-task.coffee | 14 ++++++-------- spec/integration/startup-spec.coffee | 3 +++ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/build/tasks/spec-task.coffee b/build/tasks/spec-task.coffee index 09a062ac9..da5b24685 100644 --- a/build/tasks/spec-task.coffee +++ b/build/tasks/spec-task.coffee @@ -86,25 +86,23 @@ module.exports = (grunt) -> resourcePath = process.cwd() coreSpecsPath = path.resolve('spec') - # Integration tests require a fast machine and, for now, we cannot afford to - # run them on Travis. - env = _.extend({}, process.env, - ATOM_INTEGRATION_TESTS_ENABLED: not process.env.TRAVIS - ) - if process.platform in ['darwin', 'linux'] options = cmd: appPath args: ['--test', "--resource-path=#{resourcePath}", "--spec-directory=#{coreSpecsPath}"] opts: - env: env + env: _.extend({}, process.env, + ATOM_INTEGRATION_TESTS_ENABLED: true + ) else if process.platform is 'win32' options = cmd: process.env.comspec args: ['/c', appPath, '--test', "--resource-path=#{resourcePath}", "--spec-directory=#{coreSpecsPath}", "--log-file=ci.log"] opts: - env: env + env: _.extend({}, process.env, + ATOM_INTEGRATION_TESTS_ENABLED: true + ) grunt.log.ok "Launching core specs." spawn options, (error, results, code) -> diff --git a/spec/integration/startup-spec.coffee b/spec/integration/startup-spec.coffee index 2dcf6ba38..b20427954 100644 --- a/spec/integration/startup-spec.coffee +++ b/spec/integration/startup-spec.coffee @@ -2,6 +2,9 @@ # # ATOM_INTEGRATION_TESTS_ENABLED=true apm test return unless process.env.ATOM_INTEGRATION_TESTS_ENABLED +# Integration tests require a fast machine and, for now, we cannot afford to +# run them on Travis. +return if process.env.TRAVIS fs = require "fs" path = require "path" From f33db6b7d0749dca3f3478758952e7590ee28a00 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 16 Apr 2015 09:55:23 -0700 Subject: [PATCH 0731/1783] Add Travis badge to README --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4049a9aa9..137f0433e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ ![Atom](https://cloud.githubusercontent.com/assets/72919/2874231/3af1db48-d3dd-11e3-98dc-6066f8bc766f.png) +[![Build Status](https://travis-ci.org/atom/atom.svg?branch=master)](https://travis-ci.org/atom/atom) + Atom is a hackable text editor for the 21st century, built on [atom-shell](https://github.com/atom/atom-shell), and based on everything we love about our favorite editors. We designed it to be deeply customizable, but still approachable using the default configuration. Visit [atom.io](https://atom.io) to learn more or visit the [Atom forum](https://discuss.atom.io). @@ -13,7 +15,6 @@ If you want to read about using Atom or developing packages in Atom, the [Atom F The [API reference](https://atom.io/docs/api) for developing packages is also documented on Atom.io. - ## Installing ### OS X From abb72a39ca3cb5ea6fbf8a6ba72792514ed7d96f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 16 Apr 2015 10:16:29 -0700 Subject: [PATCH 0732/1783] :arrow_up: apm@0.159 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index e7a0c8fdc..211884e84 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.158.0" + "atom-package-manager": "0.159.0" } } From 019356be32dde6e62ba0dd38891f00b1f6d123ad Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 16 Apr 2015 14:31:11 -0700 Subject: [PATCH 0733/1783] :arrow_up: fuzzy-finder --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 744994a8f..4b4f800ec 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,7 @@ "exception-reporting": "0.24.0", "feedback": "0.38.0", "find-and-replace": "0.160.0", - "fuzzy-finder": "0.74.0", + "fuzzy-finder": "0.75.0", "git-diff": "0.54.0", "go-to-line": "0.30.0", "grammar-selector": "0.46.0", From f1d90570b685d338b937068833124e61892e3487 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 16 Apr 2015 13:35:44 -0700 Subject: [PATCH 0734/1783] Check grammars/settings paths before reading asar seems to create and throw errors synchronously when these do not exist and fs.readdir is called. --- src/package.coffee | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/package.coffee b/src/package.coffee index de90c6cb4..9e7715754 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -305,8 +305,11 @@ class Package deferred = Q.defer() grammarsDirPath = path.join(@path, 'grammars') - fs.list grammarsDirPath, ['json', 'cson'], (error, grammarPaths=[]) -> - async.each grammarPaths, loadGrammar, -> deferred.resolve() + fs.exists grammarsDirPath, (grammarsDirExists) -> + return deferred.resolve() unless grammarsDirExists + + fs.list grammarsDirPath, ['json', 'cson'], (error, grammarPaths=[]) -> + async.each grammarPaths, loadGrammar, -> deferred.promise loadSettings: -> @@ -331,8 +334,11 @@ class Package else settingsDirPath = path.join(@path, 'settings') - fs.list settingsDirPath, ['json', 'cson'], (error, settingsPaths=[]) -> - async.each settingsPaths, loadSettingsFile, -> deferred.resolve() + fs.exists settingsDirPath, (settingsDirExists) -> + return deferred.resolve() unless settingsDirExists + + fs.list settingsDirPath, ['json', 'cson'], (error, settingsPaths=[]) -> + async.each settingsPaths, loadSettingsFile, -> deferred.resolve() deferred.promise serialize: -> From edbcf4023ee4420e0e9fd5407b97dab0b4902860 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 16 Apr 2015 14:37:52 -0700 Subject: [PATCH 0735/1783] Add back accidentally deleted resolve call --- src/package.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package.coffee b/src/package.coffee index 9e7715754..8003d2d8d 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -309,7 +309,7 @@ class Package return deferred.resolve() unless grammarsDirExists fs.list grammarsDirPath, ['json', 'cson'], (error, grammarPaths=[]) -> - async.each grammarPaths, loadGrammar, -> + async.each grammarPaths, loadGrammar, -> deferred.resolve() deferred.promise loadSettings: -> From 917c9e8d04791c6cc00b25ffdcd466c5e5d465fc Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 16 Apr 2015 15:40:40 -0700 Subject: [PATCH 0736/1783] :arrow_up: scandal --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4b4f800ec..ea7481fd7 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "react-atom-fork": "^0.11.5", "reactionary-atom-fork": "^1.0.0", "runas": "2.0.0", - "scandal": "2.0.2", + "scandal": "2.0.3", "scoped-property-store": "^0.17.0", "scrollbar-style": "^2.0.0", "season": "^5.1.4", From 05ab1bc60a292a3af3222f413c4d8aa6e4835652 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 16 Apr 2015 16:09:49 -0700 Subject: [PATCH 0737/1783] :arrow_up: fuzzy-finder@0.76 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ea7481fd7..4e889e3d0 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,7 @@ "exception-reporting": "0.24.0", "feedback": "0.38.0", "find-and-replace": "0.160.0", - "fuzzy-finder": "0.75.0", + "fuzzy-finder": "0.76.0", "git-diff": "0.54.0", "go-to-line": "0.30.0", "grammar-selector": "0.46.0", From 759f32afa0429dc7a1c39a9cea320c50f5dc413f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 16 Apr 2015 16:42:09 -0700 Subject: [PATCH 0738/1783] :arrow_up: fuzzy-finder@0.77 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4e889e3d0..b9332bb27 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,7 @@ "exception-reporting": "0.24.0", "feedback": "0.38.0", "find-and-replace": "0.160.0", - "fuzzy-finder": "0.76.0", + "fuzzy-finder": "0.77.0", "git-diff": "0.54.0", "go-to-line": "0.30.0", "grammar-selector": "0.46.0", From 168aa4f42647d88f81d7665383179ce5264e8da9 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 16 Apr 2015 17:30:45 -0700 Subject: [PATCH 0739/1783] :arrow_up: fuzzy-finder@0.78 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b9332bb27..ddbb90e9e 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,7 @@ "exception-reporting": "0.24.0", "feedback": "0.38.0", "find-and-replace": "0.160.0", - "fuzzy-finder": "0.77.0", + "fuzzy-finder": "0.78.0", "git-diff": "0.54.0", "go-to-line": "0.30.0", "grammar-selector": "0.46.0", From ca0948114ecaa7372ed09e3776f2809dda12865e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 16 Apr 2015 17:32:49 -0700 Subject: [PATCH 0740/1783] :arrow_up: fuzzy-finder@0.79 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ddbb90e9e..604ab8ae1 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,7 @@ "exception-reporting": "0.24.0", "feedback": "0.38.0", "find-and-replace": "0.160.0", - "fuzzy-finder": "0.78.0", + "fuzzy-finder": "0.79.0", "git-diff": "0.54.0", "go-to-line": "0.30.0", "grammar-selector": "0.46.0", From c0522d2d26a8702d09106037c1e59934fdeb09ca Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 16 Apr 2015 17:46:48 -0700 Subject: [PATCH 0741/1783] :arrow_up: fuzzy-finder@0.80 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 604ab8ae1..b600b6409 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,7 @@ "exception-reporting": "0.24.0", "feedback": "0.38.0", "find-and-replace": "0.160.0", - "fuzzy-finder": "0.79.0", + "fuzzy-finder": "0.80.0", "git-diff": "0.54.0", "go-to-line": "0.30.0", "grammar-selector": "0.46.0", From bcb8ca4549828d7766ac8fbaec3f087be06c3922 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 16 Apr 2015 19:56:14 -0700 Subject: [PATCH 0742/1783] :arrow_up: fuzzy-finder@0.81 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b600b6409..1fcb6c185 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,7 @@ "exception-reporting": "0.24.0", "feedback": "0.38.0", "find-and-replace": "0.160.0", - "fuzzy-finder": "0.80.0", + "fuzzy-finder": "0.81.0", "git-diff": "0.54.0", "go-to-line": "0.30.0", "grammar-selector": "0.46.0", From e8ca2e8a18948b8cc9dc305f4b185029f5808f70 Mon Sep 17 00:00:00 2001 From: Suyash Date: Sat, 18 Apr 2015 00:58:13 +0530 Subject: [PATCH 0743/1783] :memo: atom-shell is now electron --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 137f0433e..bc159cd43 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Build Status](https://travis-ci.org/atom/atom.svg?branch=master)](https://travis-ci.org/atom/atom) -Atom is a hackable text editor for the 21st century, built on [atom-shell](https://github.com/atom/atom-shell), and based on everything we love about our favorite editors. We designed it to be deeply customizable, but still approachable using the default configuration. +Atom is a hackable text editor for the 21st century, built on [electron](https://github.com/atom/electron), and based on everything we love about our favorite editors. We designed it to be deeply customizable, but still approachable using the default configuration. Visit [atom.io](https://atom.io) to learn more or visit the [Atom forum](https://discuss.atom.io). From 294df98f83fef02f23bd6c6a550aa1842340321b Mon Sep 17 00:00:00 2001 From: Suyash Date: Sat, 18 Apr 2015 01:07:22 +0530 Subject: [PATCH 0744/1783] :memo: capitalize `electron` --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bc159cd43..d06cc7405 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Build Status](https://travis-ci.org/atom/atom.svg?branch=master)](https://travis-ci.org/atom/atom) -Atom is a hackable text editor for the 21st century, built on [electron](https://github.com/atom/electron), and based on everything we love about our favorite editors. We designed it to be deeply customizable, but still approachable using the default configuration. +Atom is a hackable text editor for the 21st century, built on [Electron](https://github.com/atom/electron), and based on everything we love about our favorite editors. We designed it to be deeply customizable, but still approachable using the default configuration. Visit [atom.io](https://atom.io) to learn more or visit the [Atom forum](https://discuss.atom.io). From d02a67f5bb8ed360c232c06ea092ebb6f1775f13 Mon Sep 17 00:00:00 2001 From: vvakame Date: Sun, 19 Apr 2015 11:39:19 +0900 Subject: [PATCH 0745/1783] :memo: improves document consistency --- 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 aa0cd8c26..454abbabf 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -714,7 +714,7 @@ class TextEditor extends Model # * `options` (optional) See {Selection::insertText}. # # Returns a {Range} when the text has been inserted - # Returns a {Bool} false when the text has not been inserted + # Returns a {Boolean} false when the text has not been inserted insertText: (text, options={}) -> willInsert = true cancel = -> willInsert = false From 0e851cd1f461593f584e1ae0fbbc7241970a2927 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 20 Apr 2015 12:05:12 +0200 Subject: [PATCH 0746/1783] Switch to containerized infrastructure --- .travis.yml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index de5a94718..4d991c345 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,14 +9,13 @@ os: - linux - osx +sudo: false + install: - git clone https://github.com/creationix/nvm.git /tmp/.nvm - source /tmp/.nvm/nvm.sh - nvm install $NODE_VERSION - nvm use $NODE_VERSION - - if [ $TRAVIS_OS_NAME == "linux" ]; then - sudo apt-get install build-essential git libgnome-keyring-dev fakeroot; - fi script: script/cibuild @@ -24,3 +23,11 @@ notifications: email: on_success: never on_failure: change + +addons: + apt: + packages: + - build-essential + - git + - libgnome-keyring-dev + - fakeroot From 46f90f09841e220b28a81a5c207421c63c9bc573 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 20 Apr 2015 10:39:54 -0700 Subject: [PATCH 0747/1783] :arrow_up: grunt-download-atom-shell@0.14 --- build/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/package.json b/build/package.json index 3f0a3caef..e4612eb6f 100644 --- a/build/package.json +++ b/build/package.json @@ -20,7 +20,7 @@ "grunt-contrib-csslint": "~0.1.2", "grunt-contrib-less": "~0.8.0", "grunt-cson": "0.14.0", - "grunt-download-atom-shell": "~0.12.0", + "grunt-download-atom-shell": "~0.14.0", "grunt-lesslint": "0.13.0", "grunt-peg": "~1.1.0", "grunt-shell": "~0.3.1", From 96b0938c7cf9a78caeef29c256c015cd04e3e9df Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sat, 18 Apr 2015 12:21:46 +1200 Subject: [PATCH 0748/1783] :art: --- spec/config-spec.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/config-spec.coffee b/spec/config-spec.coffee index 4aeb46c68..b3af6f931 100644 --- a/spec/config-spec.coffee +++ b/spec/config-spec.coffee @@ -854,7 +854,7 @@ describe "Config", -> expect(atom.config.get('foo.bar')).toBe 'baz' expect(atom.config.get('foo.baz')).toBe 'ok' - describe 'when the default value is a complex value', -> + describe "when the default value is a complex value", -> beforeEach -> atom.config.setSchema 'foo.bar', type: 'array' @@ -877,7 +877,7 @@ describe "Config", -> expect(atom.config.get('foo.bar')).toEqual ['baz', 'ok'] expect(atom.config.get('foo.baz')).toBe 'another' - describe 'when scoped settings are used', -> + describe "when scoped settings are used", -> it "fires a change event for scoped settings that are removed", -> scopedSpy = jasmine.createSpy() atom.config.onDidChange('foo.scoped', scope: ['.source.ruby'], scopedSpy) From d1c44dcb54994eb733eff0bfde69c8454aeff22c Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sat, 18 Apr 2015 12:39:20 +1200 Subject: [PATCH 0749/1783] Never load config settings from disk when a save is pending MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #5771 We load the user’s settings from disk when we detect a change to their config.cson file. However, if there’s a save pending, doing this will end up blowing away the values we intend to save. --- spec/config-spec.coffee | 17 +++++++++++++++++ src/config.coffee | 24 ++++++++++++++++-------- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/spec/config-spec.coffee b/spec/config-spec.coffee index b3af6f931..2c5ba2fc2 100644 --- a/spec/config-spec.coffee +++ b/spec/config-spec.coffee @@ -486,6 +486,7 @@ describe "Config", -> atom.config.set('foo.bar.baz', "value 1") expect(observeHandler).toHaveBeenCalledWith("value 1") + advanceClock(100) # complete pending save that was requested in ::set observeHandler.reset() atom.config.loadUserConfig() @@ -789,6 +790,22 @@ describe "Config", -> expect(warnSpy).toHaveBeenCalled() expect(warnSpy.mostRecentCall.args[0]).toContain "foo.int" + describe "when there is a pending save", -> + it "does not change the config settings", -> + fs.writeFileSync atom.config.configFilePath, "'*': foo: bar: 'baz'" + + atom.config.set("foo.bar", "quux") + atom.config.loadUserConfig() + expect(atom.config.get("foo.bar")).toBe "quux" + + advanceClock(100) + expect(atom.config.save.callCount).toBe 1 + + expect(atom.config.get("foo.bar")).toBe "quux" + atom.config.loadUserConfig() + expect(atom.config.get("foo.bar")).toBe "baz" + + describe ".observeUserConfig()", -> updatedHandler = null diff --git a/src/config.coffee b/src/config.coffee index 6c440f219..b97ce99ec 100644 --- a/src/config.coffee +++ b/src/config.coffee @@ -332,9 +332,16 @@ class Config @configFilePath = fs.resolve(@configDirPath, 'config', ['json', 'cson']) @configFilePath ?= path.join(@configDirPath, 'config.cson') @transactDepth = 0 + @savePending = false - @debouncedSave = _.debounce(@save, 100) - @debouncedLoad = _.debounce(@loadUserConfig, 100) + @requestLoad = _.debounce(@loadUserConfig, 100) + @requestSave = => + @savePending = true + debouncedSave.call(this) + save = => + @savePending = false + @save() + debouncedSave = _.debounce(save, 100) ### Section: Config Subscription @@ -605,7 +612,7 @@ class Config else @setRawValue(keyPath, value) - @debouncedSave() if source is @getUserConfigPath() and shouldSave and not @configFileHasErrors + @requestSave() if source is @getUserConfigPath() and shouldSave and not @configFileHasErrors true # Essential: Restore the setting at `keyPath` to its default value. @@ -635,7 +642,7 @@ class Config _.setValueForKeyPath(settings, keyPath, undefined) settings = withoutEmptyObjects(settings) @set(null, settings, {scopeSelector, source, priority: @priorityForSource(source)}) if settings? - @debouncedSave() + @requestSave() else @scopedSettingsStore.removePropertiesForSourceAndSelector(source, scopeSelector) @emitChangeEvent() @@ -757,9 +764,10 @@ class Config CSON.writeFileSync(@configFilePath, {}) try - userConfig = CSON.readFileSync(@configFilePath) - @resetUserSettings(userConfig) - @configFileHasErrors = false + unless @savePending + userConfig = CSON.readFileSync(@configFilePath) + @resetUserSettings(userConfig) + @configFileHasErrors = false catch error @configFileHasErrors = true message = "Failed to load `#{path.basename(@configFilePath)}`" @@ -776,7 +784,7 @@ class Config observeUserConfig: -> try @watchSubscription ?= pathWatcher.watch @configFilePath, (eventType) => - @debouncedLoad() if eventType is 'change' and @watchSubscription? + @requestLoad() if eventType is 'change' and @watchSubscription? catch error @notifyFailure """ Unable to watch path: `#{path.basename(@configFilePath)}`. Make sure you have permissions to From 7a9b1674c8f28718cec3f1bd81691f3ec1ad03e3 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 20 Apr 2015 15:47:17 -0700 Subject: [PATCH 0750/1783] :arrow_up: fs-plus@2.7.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1fcb6c185..d616f739e 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "emissary": "^1.3.3", "event-kit": "^1.1", "first-mate": "^3.1", - "fs-plus": "^2.6", + "fs-plus": "^2.7.1", "fstream": "0.1.24", "fuzzaldrin": "^2.1", "git-utils": "^3.0.0", From 88b6db8ac73a6620d31f34b0f722980dea573e09 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Mon, 20 Apr 2015 13:24:27 -0700 Subject: [PATCH 0751/1783] Bump babel-core from 4.0.2 to 5.1.11. Notable new features from the [https://github.com/babel/babel/blob/master/CHANGELOG.md](changelog): * Add [trailing function comma proposal](https://github.com/jeffmo/es-trailing-function-commas). * Decorators based on [@wycat's stage 1 proposal](https://github.com/wycats). There is a number of bug fixes and performance improvements, as well. --- package.json | 2 +- src/babel.coffee | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 1fcb6c185..47828f61a 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "async": "0.2.6", "atom-keymap": "^5.1.2", "atom-space-pen-views": "^2.0.4", - "babel-core": "^4.0.2", + "babel-core": "^5.1.11", "bootstrap": "git+https://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372", "clear-cut": "^2.0.1", "coffee-cash": "0.8.0", diff --git a/src/babel.coffee b/src/babel.coffee index c93112e78..286ee45ef 100644 --- a/src/babel.coffee +++ b/src/babel.coffee @@ -28,10 +28,6 @@ defaultOptions = 'useStrict' ] - # Includes support for es7 features listed at: - # http://babeljs.io/docs/usage/transformers/#es7-experimental-. - experimental: true - optional: [ # Target a version of the regenerator runtime that # supports yield so the transpiled code is cleaner/smaller. @@ -43,6 +39,11 @@ defaultOptions = 'reactCompat' ] + # Includes support for es7 features listed at: + # http://babeljs.io/docs/usage/experimental/. + stage: 0 + + ### shasum - Hash with an update() method. value - Must be a value that could be returned by JSON.parse(). From d39fa88ae558384a6297031e088566e521033bd4 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 20 Apr 2015 16:09:09 -0700 Subject: [PATCH 0752/1783] :arrow_up: settings-view@0.193 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d616f739e..7d7f070ba 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "open-on-github": "0.36.0", "package-generator": "0.38.0", "release-notes": "0.52.0", - "settings-view": "0.192.0", + "settings-view": "0.193.0", "snippets": "0.88.0", "spell-check": "0.55.0", "status-bar": "0.69.0", From 1530d68a08e29decabc8f2b49d4c207e5296bada Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 20 Apr 2015 13:24:36 -0700 Subject: [PATCH 0753/1783] Only compile .pegjs files in lib/ --- build/Gruntfile.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/Gruntfile.coffee b/build/Gruntfile.coffee index 7c687ac92..1a34b70f2 100644 --- a/build/Gruntfile.coffee +++ b/build/Gruntfile.coffee @@ -128,7 +128,7 @@ module.exports = (grunt) -> lessConfig.glob_to_multiple.src.push("#{directory}/**/*.less") prebuildLessConfig.src.push("#{directory}/**/*.less") unless theme csonConfig.glob_to_multiple.src.push("#{directory}/**/*.cson") - pegConfig.glob_to_multiple.src.push("#{directory}/**/*.pegjs") + pegConfig.glob_to_multiple.src.push("#{directory}/lib/*.pegjs") grunt.initConfig pkg: grunt.file.readJSON('package.json') From f12eb04339dcc015075677bce0c512c7d2a43d13 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 20 Apr 2015 13:25:05 -0700 Subject: [PATCH 0754/1783] Don't compile package specs --- build/Gruntfile.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build/Gruntfile.coffee b/build/Gruntfile.coffee index 1a34b70f2..c3261ad90 100644 --- a/build/Gruntfile.coffee +++ b/build/Gruntfile.coffee @@ -125,9 +125,13 @@ module.exports = (grunt) -> {engines, theme} = grunt.file.readJSON(metadataPath) if engines?.atom? coffeeConfig.glob_to_multiple.src.push("#{directory}/**/*.coffee") + coffeeConfig.glob_to_multiple.src.push("!#{directory}/spec/**/*.coffee") + lessConfig.glob_to_multiple.src.push("#{directory}/**/*.less") prebuildLessConfig.src.push("#{directory}/**/*.less") unless theme + csonConfig.glob_to_multiple.src.push("#{directory}/**/*.cson") + pegConfig.glob_to_multiple.src.push("#{directory}/lib/*.pegjs") grunt.initConfig From 931ea2f198b54482f28a8e79e947e5e670fa0c25 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 20 Apr 2015 13:28:17 -0700 Subject: [PATCH 0755/1783] Ignore package spec folder --- build/tasks/build-task.coffee | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build/tasks/build-task.coffee b/build/tasks/build-task.coffee index 3411f4dae..2530aab79 100644 --- a/build/tasks/build-task.coffee +++ b/build/tasks/build-task.coffee @@ -26,6 +26,7 @@ module.exports = (grunt) -> cp 'package.json', path.join(appDir, 'package.json') + packageNames = [] packageDirectories = [] nonPackageDirectories = [ 'benchmark' @@ -39,6 +40,7 @@ module.exports = (grunt) -> directory = path.join('node_modules', child) if isAtomPackage(directory) packageDirectories.push(directory) + packageNames.push(child) else nonPackageDirectories.push(directory) @@ -92,6 +94,9 @@ module.exports = (grunt) -> '.pairs' '.travis.yml' ] + + packageNames.forEach (packageName) -> ignoredPaths.push(path.join(packageName, 'spec')) + ignoredPaths = ignoredPaths.map (ignoredPath) -> _.escapeRegExp(ignoredPath) # Add .* to avoid matching hunspell_dictionaries. From 91eb0b3b9ff53aff90d3f63a7e26f62ab3a02320 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 20 Apr 2015 13:28:39 -0700 Subject: [PATCH 0756/1783] Remove unneeded atom-keymap ignores --- build/tasks/build-task.coffee | 3 --- 1 file changed, 3 deletions(-) diff --git a/build/tasks/build-task.coffee b/build/tasks/build-task.coffee index 2530aab79..43b1b81ee 100644 --- a/build/tasks/build-task.coffee +++ b/build/tasks/build-task.coffee @@ -81,9 +81,6 @@ module.exports = (grunt) -> path.join('resources', 'win') # These are only require in dev mode when the grammar isn't precompiled - path.join('atom-keymap', 'node_modules', 'loophole') - path.join('atom-keymap', 'node_modules', 'pegjs') - path.join('atom-keymap', 'node_modules', '.bin', 'pegjs') path.join('snippets', 'node_modules', 'loophole') path.join('snippets', 'node_modules', 'pegjs') path.join('snippets', 'node_modules', '.bin', 'pegjs') From 32a475a5a2453224cd7b33290bc90b6d00524661 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 20 Apr 2015 13:32:27 -0700 Subject: [PATCH 0757/1783] Don't compile spec .less/.cson files --- build/Gruntfile.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build/Gruntfile.coffee b/build/Gruntfile.coffee index c3261ad90..55a465e40 100644 --- a/build/Gruntfile.coffee +++ b/build/Gruntfile.coffee @@ -128,9 +128,11 @@ module.exports = (grunt) -> coffeeConfig.glob_to_multiple.src.push("!#{directory}/spec/**/*.coffee") lessConfig.glob_to_multiple.src.push("#{directory}/**/*.less") + lessConfig.glob_to_multiple.src.push("!#{directory}/spec/**/*.less") prebuildLessConfig.src.push("#{directory}/**/*.less") unless theme csonConfig.glob_to_multiple.src.push("#{directory}/**/*.cson") + csonConfig.glob_to_multiple.src.push("!#{directory}/spec/**/*.cson") pegConfig.glob_to_multiple.src.push("#{directory}/lib/*.pegjs") From e633e5d8de82367ed2cf79f5901b23e0e9c4b343 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 20 Apr 2015 13:36:37 -0700 Subject: [PATCH 0758/1783] Remove empty keymaps/menus folders --- build/tasks/compile-packages-slug-task.coffee | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/build/tasks/compile-packages-slug-task.coffee b/build/tasks/compile-packages-slug-task.coffee index 613a4a380..a56ed6e18 100644 --- a/build/tasks/compile-packages-slug-task.coffee +++ b/build/tasks/compile-packages-slug-task.coffee @@ -54,15 +54,19 @@ module.exports = (grunt) -> mainPath = require.resolve(path.resolve(moduleDirectory, metadata.main)) pack.main = path.relative(appDir, mainPath) - for keymapPath in fs.listSync(path.join(moduleDirectory, 'keymaps'), ['.cson', '.json']) + keymapsPath = path.join(moduleDirectory, 'keymaps') + for keymapPath in fs.listSync(keymapsPath, ['.cson', '.json']) relativePath = path.relative(appDir, keymapPath) pack.keymaps[relativePath] = CSON.readFileSync(keymapPath) rm keymapPath + rm keymapsPath if fs.listSync(keymapsPath).length is 0 - for menuPath in fs.listSync(path.join(moduleDirectory, 'menus'), ['.cson', '.json']) + menusPath = path.join(moduleDirectory, 'menus') + for menuPath in fs.listSync(menusPath, ['.cson', '.json']) relativePath = path.relative(appDir, menuPath) pack.menus[relativePath] = CSON.readFileSync(menuPath) rm menuPath + rm menusPath if fs.listSync(menusPath).length is 0 packages[metadata.name] = pack From bc0acf47a3674b371d98202e39a2b97d24d1c9d6 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 20 Apr 2015 13:46:02 -0700 Subject: [PATCH 0759/1783] Ignore bundle testla from get-parameter-names This should have been a dev dependency --- build/tasks/build-task.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build/tasks/build-task.coffee b/build/tasks/build-task.coffee index 43b1b81ee..67791af2d 100644 --- a/build/tasks/build-task.coffee +++ b/build/tasks/build-task.coffee @@ -63,6 +63,8 @@ module.exports = (grunt) -> path.join('npm', 'node_modules', '.bin', 'clear') path.join('npm', 'node_modules', '.bin', 'starwars') path.join('pegjs', 'examples') + path.join('get-parameter-names', 'node_modules', 'testla') + path.join('get-parameter-names', '.bin', 'testla') path.join('jasmine-reporters', 'ext') path.join('jasmine-node', 'node_modules', 'gaze') path.join('jasmine-node', 'spec') From f4b8d88143a128b1087b6f85f18a50fe64af9a90 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 20 Apr 2015 13:46:18 -0700 Subject: [PATCH 0760/1783] Don't bundle appveyor.yml files --- build/tasks/build-task.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/build/tasks/build-task.coffee b/build/tasks/build-task.coffee index 67791af2d..af9d26144 100644 --- a/build/tasks/build-task.coffee +++ b/build/tasks/build-task.coffee @@ -92,6 +92,7 @@ module.exports = (grunt) -> '.npmignore' '.pairs' '.travis.yml' + 'appveyor.yml' ] packageNames.forEach (packageName) -> ignoredPaths.push(path.join(packageName, 'spec')) From 5703aeff2c3c8b67250f11ee82b1311eb9d92709 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 20 Apr 2015 13:46:28 -0700 Subject: [PATCH 0761/1783] Don't bundle .idea folders --- build/tasks/build-task.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/build/tasks/build-task.coffee b/build/tasks/build-task.coffee index af9d26144..fd9d296f9 100644 --- a/build/tasks/build-task.coffee +++ b/build/tasks/build-task.coffee @@ -93,6 +93,7 @@ module.exports = (grunt) -> '.pairs' '.travis.yml' 'appveyor.yml' + '.idea' ] packageNames.forEach (packageName) -> ignoredPaths.push(path.join(packageName, 'spec')) From 592641801c618083d5cf4a4b31921567a4187a48 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 20 Apr 2015 13:46:42 -0700 Subject: [PATCH 0762/1783] Add _ prefix/suffix to test folder pattern --- build/tasks/build-task.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/tasks/build-task.coffee b/build/tasks/build-task.coffee index fd9d296f9..302e53a70 100644 --- a/build/tasks/build-task.coffee +++ b/build/tasks/build-task.coffee @@ -126,7 +126,7 @@ module.exports = (grunt) -> ignoredPaths.push path.join('spellchecker', 'vendor', 'hunspell_dictionaries') ignoredPaths = ignoredPaths.map (ignoredPath) -> "(#{ignoredPath})" - testFolderPattern = new RegExp("#{_.escapeRegExp(path.sep)}te?sts?#{_.escapeRegExp(path.sep)}") + testFolderPattern = new RegExp("#{_.escapeRegExp(path.sep)}_*te?sts?_*#{_.escapeRegExp(path.sep)}") exampleFolderPattern = new RegExp("#{_.escapeRegExp(path.sep)}examples?#{_.escapeRegExp(path.sep)}") benchmarkFolderPattern = new RegExp("#{_.escapeRegExp(path.sep)}benchmarks?#{_.escapeRegExp(path.sep)}") From d5f7151096e558272fcd4dfb6429fe0ef8a53a4c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 20 Apr 2015 13:47:15 -0700 Subject: [PATCH 0763/1783] Add missing node_modules segment --- build/tasks/build-task.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/tasks/build-task.coffee b/build/tasks/build-task.coffee index 302e53a70..6a9ed7e35 100644 --- a/build/tasks/build-task.coffee +++ b/build/tasks/build-task.coffee @@ -64,7 +64,7 @@ module.exports = (grunt) -> path.join('npm', 'node_modules', '.bin', 'starwars') path.join('pegjs', 'examples') path.join('get-parameter-names', 'node_modules', 'testla') - path.join('get-parameter-names', '.bin', 'testla') + path.join('get-parameter-names', 'node_modules', '.bin', 'testla') path.join('jasmine-reporters', 'ext') path.join('jasmine-node', 'node_modules', 'gaze') path.join('jasmine-node', 'spec') From 2a8d08db4224025aacb2b7e14e33384f3f0cbe85 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 20 Apr 2015 13:51:24 -0700 Subject: [PATCH 0764/1783] Don't bundle config files --- build/tasks/build-task.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build/tasks/build-task.coffee b/build/tasks/build-task.coffee index 6a9ed7e35..e053678aa 100644 --- a/build/tasks/build-task.coffee +++ b/build/tasks/build-task.coffee @@ -94,6 +94,10 @@ module.exports = (grunt) -> '.travis.yml' 'appveyor.yml' '.idea' + '.editorconfig' + '.lint' + '.lintignore' + '.eslintrc' ] packageNames.forEach (packageName) -> ignoredPaths.push(path.join(packageName, 'spec')) From 426a2e5e6b620857b6544daade3f72d94f38f954 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 20 Apr 2015 13:54:05 -0700 Subject: [PATCH 0765/1783] Don't bundle .jshintignore files --- build/tasks/build-task.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/build/tasks/build-task.coffee b/build/tasks/build-task.coffee index e053678aa..066ee3481 100644 --- a/build/tasks/build-task.coffee +++ b/build/tasks/build-task.coffee @@ -98,6 +98,7 @@ module.exports = (grunt) -> '.lint' '.lintignore' '.eslintrc' + '.jshintignore' ] packageNames.forEach (packageName) -> ignoredPaths.push(path.join(packageName, 'spec')) From cb47dde7b00a43a1bab40c79fcf8f881bdc11f40 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 20 Apr 2015 13:54:14 -0700 Subject: [PATCH 0766/1783] Don't bundle .git* files --- build/tasks/build-task.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build/tasks/build-task.coffee b/build/tasks/build-task.coffee index 066ee3481..0b71a7a36 100644 --- a/build/tasks/build-task.coffee +++ b/build/tasks/build-task.coffee @@ -99,6 +99,8 @@ module.exports = (grunt) -> '.lintignore' '.eslintrc' '.jshintignore' + '.gitattributes' + '.gitkeep' ] packageNames.forEach (packageName) -> ignoredPaths.push(path.join(packageName, 'spec')) From 175d717d8c6bcbd7143669e70e8a41b6f9d31bc7 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 20 Apr 2015 14:08:54 -0700 Subject: [PATCH 0767/1783] Don't bundle es6-weak-map --- build/tasks/build-task.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build/tasks/build-task.coffee b/build/tasks/build-task.coffee index 0b71a7a36..a6f74bffd 100644 --- a/build/tasks/build-task.coffee +++ b/build/tasks/build-task.coffee @@ -87,6 +87,10 @@ module.exports = (grunt) -> path.join('snippets', 'node_modules', 'pegjs') path.join('snippets', 'node_modules', '.bin', 'pegjs') + # These aren't needed since WeakMap is built-in + path.join('emissary', 'node_modules', 'es6-weak-map') + path.join('property-accessors', 'node_modules', 'es6-weak-map') + '.DS_Store' '.jshintrc' '.npmignore' From 0cd8a300f8322eb0bdaef2885e88727ee783e27b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 20 Apr 2015 14:09:31 -0700 Subject: [PATCH 0768/1783] Don't bundle spec .less files in cache --- build/Gruntfile.coffee | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/build/Gruntfile.coffee b/build/Gruntfile.coffee index 55a465e40..14fbd6e5d 100644 --- a/build/Gruntfile.coffee +++ b/build/Gruntfile.coffee @@ -129,7 +129,10 @@ module.exports = (grunt) -> lessConfig.glob_to_multiple.src.push("#{directory}/**/*.less") lessConfig.glob_to_multiple.src.push("!#{directory}/spec/**/*.less") - prebuildLessConfig.src.push("#{directory}/**/*.less") unless theme + + unless theme + prebuildLessConfig.src.push("#{directory}/**/*.less") + prebuildLessConfig.src.push("!#{directory}/spec/**/*.less") csonConfig.glob_to_multiple.src.push("#{directory}/**/*.cson") csonConfig.glob_to_multiple.src.push("!#{directory}/spec/**/*.cson") From 65cc9486474afa8f9db5cf7d6b6800d573e2d83b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 20 Apr 2015 15:10:27 -0700 Subject: [PATCH 0769/1783] Don't bundle native source files --- build/tasks/build-task.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/build/tasks/build-task.coffee b/build/tasks/build-task.coffee index a6f74bffd..0fb967019 100644 --- a/build/tasks/build-task.coffee +++ b/build/tasks/build-task.coffee @@ -125,6 +125,7 @@ module.exports = (grunt) -> ignoredPaths.push "#{_.escapeRegExp(path.join('runas', 'src') + path.sep)}.*\\.(cc|h)*" ignoredPaths.push "#{_.escapeRegExp(path.join('scrollbar-style', 'src') + path.sep)}.*\\.(cc|h)*" ignoredPaths.push "#{_.escapeRegExp(path.join('spellchecker', 'src') + path.sep)}.*\\.(cc|h)*" + ignoredPaths.push "#{_.escapeRegExp(path.join('keyboard-layout', 'src') + path.sep)}.*\\.(cc|h|mm)*" # Ignore build files ignoredPaths.push "#{_.escapeRegExp(path.sep)}binding\\.gyp$" From e4007f7c8f87ee4110cc1eb40c2081c1f1bc2ba2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 20 Apr 2015 15:28:26 -0700 Subject: [PATCH 0770/1783] Precompile spec/ CoffeeScript files --- build/Gruntfile.coffee | 2 ++ build/tasks/build-task.coffee | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/build/Gruntfile.coffee b/build/Gruntfile.coffee index 14fbd6e5d..b48c7a773 100644 --- a/build/Gruntfile.coffee +++ b/build/Gruntfile.coffee @@ -69,6 +69,8 @@ module.exports = (grunt) -> expand: true src: [ 'src/**/*.coffee' + 'spec/*.coffee' + '!spec/*-spec.coffee' 'exports/**/*.coffee' 'static/**/*.coffee' ] diff --git a/build/tasks/build-task.coffee b/build/tasks/build-task.coffee index 0fb967019..343960f61 100644 --- a/build/tasks/build-task.coffee +++ b/build/tasks/build-task.coffee @@ -162,7 +162,6 @@ module.exports = (grunt) -> for directory in packageDirectories cp directory, path.join(appDir, directory), filter: filterPackage - cp 'spec', path.join(appDir, 'spec'), filter: /fixtures|integration|.+-spec\.coffee/ cp 'src', path.join(appDir, 'src'), filter: /.+\.(cson|coffee)$/ cp 'static', path.join(appDir, 'static') From dfc30830ffce970ca829a68860761f191b230c95 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 20 Apr 2015 16:23:41 -0700 Subject: [PATCH 0771/1783] Recurse into .asar files --- build/tasks/output-build-filetypes.coffee | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/build/tasks/output-build-filetypes.coffee b/build/tasks/output-build-filetypes.coffee index 64b952bbe..9d51ca30c 100644 --- a/build/tasks/output-build-filetypes.coffee +++ b/build/tasks/output-build-filetypes.coffee @@ -1,3 +1,4 @@ +asar = require 'asar' path = require 'path' module.exports = (grunt) -> @@ -5,11 +6,19 @@ module.exports = (grunt) -> shellAppDir = grunt.config.get('atom.shellAppDir') types = {} - grunt.file.recurse shellAppDir, (absolutePath, rootPath, relativePath, fileName) -> - extension = path.extname(fileName) or fileName + registerFile = (filePath) -> + extension = path.extname(filePath) or path.basename(filePath) types[extension] ?= 0 types[extension]++ + if extension is '.asar' + asar.listPackage(filePath).forEach (archivePath) -> + archivePath = archivePath.substring(1) + unless asar.statFile(filePath, archivePath, true).files + registerFile(archivePath) + + grunt.file.recurse shellAppDir, (absolutePath, rootPath, relativePath, fileName) -> registerFile(absolutePath) + extensions = Object.keys(types).sort (extension1, extension2) -> diff = types[extension2] - types[extension1] if diff is 0 From 2d575808817782a71a75f71949a12e894e5b5dc8 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 20 Apr 2015 16:31:28 -0700 Subject: [PATCH 0772/1783] Add --extension option to log out all found paths --- build/tasks/output-build-filetypes.coffee | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/build/tasks/output-build-filetypes.coffee b/build/tasks/output-build-filetypes.coffee index 9d51ca30c..2d7b292f6 100644 --- a/build/tasks/output-build-filetypes.coffee +++ b/build/tasks/output-build-filetypes.coffee @@ -8,8 +8,8 @@ module.exports = (grunt) -> types = {} registerFile = (filePath) -> extension = path.extname(filePath) or path.basename(filePath) - types[extension] ?= 0 - types[extension]++ + types[extension] ?= [] + types[extension].push(filePath) if extension is '.asar' asar.listPackage(filePath).forEach (archivePath) -> @@ -20,11 +20,15 @@ module.exports = (grunt) -> grunt.file.recurse shellAppDir, (absolutePath, rootPath, relativePath, fileName) -> registerFile(absolutePath) extensions = Object.keys(types).sort (extension1, extension2) -> - diff = types[extension2] - types[extension1] + diff = types[extension2].length - types[extension1].length if diff is 0 extension1.toLowerCase().localeCompare(extension2.toLowerCase()) else diff - extensions.forEach (extension) -> - grunt.log.error "#{extension}: #{types[extension]}" + if extension = grunt.option('extension') + types[extension]?.sort().forEach (filePath) -> + console.log filePath + else + extensions.forEach (extension) -> + grunt.log.error "#{extension}: #{types[extension].length}" From ab9a6c12b34eae94434134ba8869c364bc0b9607 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 20 Apr 2015 16:34:55 -0700 Subject: [PATCH 0773/1783] Only log out top 25 file types --- build/tasks/output-build-filetypes.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/tasks/output-build-filetypes.coffee b/build/tasks/output-build-filetypes.coffee index 2d7b292f6..1b8aeb330 100644 --- a/build/tasks/output-build-filetypes.coffee +++ b/build/tasks/output-build-filetypes.coffee @@ -28,7 +28,7 @@ module.exports = (grunt) -> if extension = grunt.option('extension') types[extension]?.sort().forEach (filePath) -> - console.log filePath + grunt.log.error filePath else - extensions.forEach (extension) -> + extensions[0...25].forEach (extension) -> grunt.log.error "#{extension}: #{types[extension].length}" From 1cc5c83af7ad3a5579bcbafc7981910b46cf082a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 20 Apr 2015 17:56:17 -0700 Subject: [PATCH 0774/1783] :arrow_up: notifications@0.39 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7d7f070ba..29be99f96 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,7 @@ "link": "0.30.0", "markdown-preview": "0.148.0", "metrics": "0.45.0", - "notifications": "0.38.0", + "notifications": "0.39.0", "open-on-github": "0.36.0", "package-generator": "0.38.0", "release-notes": "0.52.0", From 4fb59af3cc5205de3f3a20416d83d102dcfe1cb1 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 20 Apr 2015 18:33:51 -0700 Subject: [PATCH 0775/1783] Add fallback syntax var for attributes --- static/variables/syntax-variables.less | 1 + 1 file changed, 1 insertion(+) diff --git a/static/variables/syntax-variables.less b/static/variables/syntax-variables.less index f569773e8..608943cf4 100644 --- a/static/variables/syntax-variables.less +++ b/static/variables/syntax-variables.less @@ -39,5 +39,6 @@ @syntax-color-class: #E5C17C; @syntax-color-keyword: #555; @syntax-color-tag: #555; +@syntax-color-attribute: #87400d; @syntax-color-import: #97C378; @syntax-color-snippet: #97C378; From 76a919f8b4e40f0ad2a0c2e5c849f24650b3d33c Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 20 Apr 2015 21:59:13 -0600 Subject: [PATCH 0776/1783] Perform document updates in same frame when requested from reads A common pattern is to put something on the DOM, measure it, then update the DOM again based on that measurement. This change ensures that any updates requested as a result of reading from the DOM get scheduled for the end of the current frame. If you want to read *again* after these follow-on updates, you will need to wait for the next frame. But at least this way we ensure instant feedback with minimal thrashing (1 reflow) when we have no choice but to read the DOM before updating. /cc @benogle --- spec/view-registry-spec.coffee | 30 ++++++++++++++++++++++++++++++ src/view-registry.coffee | 9 ++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/spec/view-registry-spec.coffee b/spec/view-registry-spec.coffee index 239f2e878..df822309e 100644 --- a/spec/view-registry-spec.coffee +++ b/spec/view-registry-spec.coffee @@ -119,6 +119,36 @@ describe "ViewRegistry", -> frameRequests[0]() expect(events).toEqual ['write 4', 'read 3'] + it "performs writes requested from read callbacks in the same animation frame", -> + spyOn(window, 'setInterval').andCallFake(fakeSetInterval) + spyOn(window, 'clearInterval').andCallFake(fakeClearInterval) + events = [] + + registry.pollDocument -> events.push('poll') + registry.pollAfterNextUpdate() + registry.updateDocument -> events.push('write 1') + registry.readDocument -> + registry.updateDocument -> events.push('write from read 1') + events.push('read 1') + registry.readDocument -> + registry.updateDocument -> events.push('write from read 2') + events.push('read 2') + registry.updateDocument -> events.push('write 2') + + expect(frameRequests.length).toBe 1 + frameRequests[0]() + expect(frameRequests.length).toBe 1 + + expect(events).toEqual [ + 'write 1' + 'write 2' + 'read 1' + 'read 2' + 'poll' + 'write from read 1' + 'write from read 2' + ] + it "pauses DOM polling when reads or writes are pending", -> spyOn(window, 'setInterval').andCallFake(fakeSetInterval) spyOn(window, 'clearInterval').andCallFake(fakeClearInterval) diff --git a/src/view-registry.coffee b/src/view-registry.coffee index e4b413f00..24c53bd57 100644 --- a/src/view-registry.coffee +++ b/src/view-registry.coffee @@ -44,6 +44,7 @@ module.exports = class ViewRegistry documentPollingInterval: 200 documentUpdateRequested: false + documentReadInProgress: false performDocumentPollAfterUpdate: false pollIntervalHandle: null @@ -161,7 +162,7 @@ class ViewRegistry updateDocument: (fn) -> @documentWriters.push(fn) - @requestDocumentUpdate() + @requestDocumentUpdate() unless @documentReadInProgress new Disposable => @documentWriters = @documentWriters.filter (writer) -> writer isnt fn @@ -196,9 +197,15 @@ class ViewRegistry performDocumentUpdate: => @documentUpdateRequested = false writer() while writer = @documentWriters.shift() + + @documentReadInProgress = true reader() while reader = @documentReaders.shift() @performDocumentPoll() if @performDocumentPollAfterUpdate @performDocumentPollAfterUpdate = false + @documentReadInProgress = false + + # process updates requested as a result of reads + writer() while writer = @documentWriters.shift() startPollingDocument: -> @pollIntervalHandle = window.setInterval(@performDocumentPoll, @documentPollingInterval) From b2d7a203e79cd762d3c508527b444e79e6272a8b Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 21 Apr 2015 12:50:55 +0200 Subject: [PATCH 0777/1783] Run specs in series when concurrency is 1 We need to run specs in series on the Travis Build, because workers have less than 2 cores: trying to parallelize jobs on such machines increases context-switching, thus making specs slower and, as a result, flakier. --- build/tasks/spec-task.coffee | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/build/tasks/spec-task.coffee b/build/tasks/spec-task.coffee index da5b24685..fe1db4dc0 100644 --- a/build/tasks/spec-task.coffee +++ b/build/tasks/spec-task.coffee @@ -4,7 +4,10 @@ path = require 'path' _ = require 'underscore-plus' async = require 'async' -concurrency = 2 +if process.env.TRAVIS + concurrency = 1 +else + concurrency = 2 module.exports = (grunt) -> {isAtomPackage, spawn} = require('./task-helpers')(grunt) @@ -78,7 +81,7 @@ module.exports = (grunt) -> continue unless isAtomPackage(packagePath) packageSpecQueue.push(packagePath) - packageSpecQueue.concurrency = concurrency - 1 + packageSpecQueue.concurrency = Math.max(1, concurrency - 1) packageSpecQueue.drain = -> callback(null, failedPackages) runCoreSpecs = (callback) -> @@ -122,10 +125,10 @@ module.exports = (grunt) -> # TODO: This should really be parallel on both platforms, however our # fixtures step on each others toes currently. - if process.platform in ['darwin', 'linux'] - method = async.parallel - else if process.platform is 'win32' + if concurrency is 1 or process.platform is 'win32' method = async.series + else if process.platform in ['darwin', 'linux'] + method = async.parallel method [runCoreSpecs, runPackageSpecs], (error, results) -> [coreSpecFailed, failedPackages] = results From 9823f4ce09824dd1508d45944d64d18decabfcbd Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 21 Apr 2015 08:09:07 -0600 Subject: [PATCH 0778/1783] Fix legacy event spec for scheduler change --- spec/text-editor-component-spec.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 769ce424f..955504319 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -2624,7 +2624,7 @@ describe "TextEditorComponent", -> expect(componentNode.querySelector('.placeholder-text')).toBeNull() describe "legacy editor compatibility", -> - it "triggers the screen-lines-changed event before the editor:display-update event", -> + it "triggers the screen-lines-changed event before the editor:display-updated event", -> editor.setSoftWrapped(true) callingOrder = [] @@ -2633,7 +2633,7 @@ describe "TextEditorComponent", -> editor.insertText("HELLO! HELLO!\n HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! ") nextAnimationFrame() - expect(callingOrder).toEqual ['screen-lines-changed', 'editor:display-updated'] + expect(callingOrder).toEqual ['screen-lines-changed', 'editor:display-updated', 'editor:display-updated'] it "works with the ::setEditorHeightInLines and ::setEditorWidthInChars helpers", -> setEditorHeightInLines(wrapperView, 7) From b2ac9be211992c2a17a6396d8bcc82828388159a Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 21 Apr 2015 16:15:00 +0200 Subject: [PATCH 0779/1783] Use `concurrency` variable only to configure async/parallel stuff --- build/tasks/spec-task.coffee | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/build/tasks/spec-task.coffee b/build/tasks/spec-task.coffee index fe1db4dc0..2367c9a5f 100644 --- a/build/tasks/spec-task.coffee +++ b/build/tasks/spec-task.coffee @@ -4,7 +4,10 @@ path = require 'path' _ = require 'underscore-plus' async = require 'async' -if process.env.TRAVIS +# TODO: This should really be parallel on every platform, however: +# - On Windows, our fixtures step on each others toes. +# - On Travis, Mac workers haven't enough horsepower. +if process.env.TRAVIS or process.platform is 'win32' concurrency = 1 else concurrency = 2 @@ -122,13 +125,11 @@ module.exports = (grunt) -> grunt.registerTask 'run-specs', 'Run the specs', -> done = @async() startTime = Date.now() - - # TODO: This should really be parallel on both platforms, however our - # fixtures step on each others toes currently. - if concurrency is 1 or process.platform is 'win32' - method = async.series - else if process.platform in ['darwin', 'linux'] - method = async.parallel + method = + if concurrency is 1 + async.series + else + async.parallel method [runCoreSpecs, runPackageSpecs], (error, results) -> [coreSpecFailed, failedPackages] = results From 7c0e33225f0f495627a180a42dc25f93d7215bb6 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 21 Apr 2015 11:14:23 -0700 Subject: [PATCH 0780/1783] :arrow_up: notifications@0.40 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 29be99f96..34e944fef 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,7 @@ "link": "0.30.0", "markdown-preview": "0.148.0", "metrics": "0.45.0", - "notifications": "0.39.0", + "notifications": "0.40.0", "open-on-github": "0.36.0", "package-generator": "0.38.0", "release-notes": "0.52.0", From c795879e0c2632ecb5d0f0a0aea39fd8736c9072 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 21 Apr 2015 11:43:38 -0700 Subject: [PATCH 0781/1783] Update colors in syntax fallback vars --- static/variables/syntax-variables.less | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/static/variables/syntax-variables.less b/static/variables/syntax-variables.less index 608943cf4..23b8d994e 100644 --- a/static/variables/syntax-variables.less +++ b/static/variables/syntax-variables.less @@ -37,8 +37,8 @@ @syntax-color-function: #61AEEF; @syntax-color-method: @syntax-color-function; @syntax-color-class: #E5C17C; -@syntax-color-keyword: #555; -@syntax-color-tag: #555; +@syntax-color-keyword: #a431c4; +@syntax-color-tag: #b72424; @syntax-color-attribute: #87400d; @syntax-color-import: #97C378; @syntax-color-snippet: #97C378; From bf9999d07a9b93f29081cfbe2359ffeb16db0339 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Tue, 21 Apr 2015 12:49:55 -0700 Subject: [PATCH 0782/1783] core:select-up/down should work in mini editor as well as main editor. Fixes #6445. --- src/text-editor-element.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/text-editor-element.coffee b/src/text-editor-element.coffee index 4a7a11147..99ae8ca17 100644 --- a/src/text-editor-element.coffee +++ b/src/text-editor-element.coffee @@ -244,6 +244,8 @@ atom.commands.add 'atom-text-editor', stopEventPropagation( 'core:move-right': -> @moveRight() 'core:select-left': -> @selectLeft() 'core:select-right': -> @selectRight() + 'core:select-up': -> @selectUp() + 'core:select-down': -> @selectDown() 'core:select-all': -> @selectAll() 'editor:move-to-previous-word': -> @moveToPreviousWord() 'editor:select-word': -> @selectWordsContainingCursors() @@ -297,8 +299,6 @@ atom.commands.add 'atom-text-editor:not([mini])', stopEventPropagation( 'core:move-to-bottom': -> @moveToBottom() 'core:page-up': -> @pageUp() 'core:page-down': -> @pageDown() - 'core:select-up': -> @selectUp() - 'core:select-down': -> @selectDown() 'core:select-to-top': -> @selectToTop() 'core:select-to-bottom': -> @selectToBottom() 'core:select-page-up': -> @selectPageUp() From c826d799fa4c9717859b0b8b64ff6656c006efe3 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 21 Apr 2015 22:22:03 +0200 Subject: [PATCH 0783/1783] Remove nodejs 0.10 from build matrix --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4d991c345..993787aee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ git: depth: 10 env: - - NODE_VERSION=0.10 - NODE_VERSION=0.12 os: From c2d9e8973e68924bc37ce270addcce46f23b5a56 Mon Sep 17 00:00:00 2001 From: "Machiste N. Quintana" Date: Tue, 21 Apr 2015 17:11:24 -0400 Subject: [PATCH 0784/1783] Add david-dm dependency status badge to Readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d06cc7405..cafeca707 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ ![Atom](https://cloud.githubusercontent.com/assets/72919/2874231/3af1db48-d3dd-11e3-98dc-6066f8bc766f.png) [![Build Status](https://travis-ci.org/atom/atom.svg?branch=master)](https://travis-ci.org/atom/atom) +[![Dependency Status](https://david-dm.org/atom/atom.svg)](https://david-dm.org/atom/atom) Atom is a hackable text editor for the 21st century, built on [Electron](https://github.com/atom/electron), and based on everything we love about our favorite editors. We designed it to be deeply customizable, but still approachable using the default configuration. From 1e893b0c0a02904f4fc6859c683c908f94906312 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 21 Apr 2015 15:27:13 -0700 Subject: [PATCH 0785/1783] Prepare 0.194 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e742dd114..5620157c7 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "0.193.0", + "version": "0.194.0", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From 34f664611948f7c60047f4e6e6b37431406d42a8 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 21 Apr 2015 15:48:44 -0700 Subject: [PATCH 0786/1783] :arrow_up: language-less@0.26 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5620157c7..881ae8602 100644 --- a/package.json +++ b/package.json @@ -136,7 +136,7 @@ "language-java": "0.14.0", "language-javascript": "0.73.0", "language-json": "0.14.0", - "language-less": "0.25.0", + "language-less": "0.26.0", "language-make": "0.14.0", "language-mustache": "0.11.0", "language-objective-c": "0.15.0", From a1670371d4ec72c83ea9248cbe2e04a01b479b27 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 21 Apr 2015 16:01:06 -0700 Subject: [PATCH 0787/1783] :arrow_up: marked@0.3.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 881ae8602..ee43dc58b 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "jasmine-tagged": "^1.1.4", "jquery": "^2.1.1", "less-cache": "0.22", - "marked": "^0.3", + "marked": "^0.3.3", "mixto": "^1", "nslog": "^2.0.0", "oniguruma": "^4.1", From 07085a7cfe016b98d38e45e10b4e6d2f2bc34fd9 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 21 Apr 2015 16:03:52 -0700 Subject: [PATCH 0788/1783] :arrow_up: semver@4.3.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ee43dc58b..e8779c254 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "scoped-property-store": "^0.17.0", "scrollbar-style": "^2.0.0", "season": "^5.1.4", - "semver": "~4.2", + "semver": "^4.3.3", "serializable": "^1", "service-hub": "^0.5.0", "space-pen": "3.8.2", From 1cb8f27ee0eeca4983c4d5797ad38de225a0421a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 21 Apr 2015 16:05:04 -0700 Subject: [PATCH 0789/1783] :arrow_up: settings-view@0.194 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e8779c254..8f0f1cd48 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "open-on-github": "0.36.0", "package-generator": "0.38.0", "release-notes": "0.52.0", - "settings-view": "0.193.0", + "settings-view": "0.194.0", "snippets": "0.88.0", "spell-check": "0.55.0", "status-bar": "0.69.0", From 2d34726b90a3795b93884081e653f2108c62f2ac Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 21 Apr 2015 16:24:34 -0700 Subject: [PATCH 0790/1783] :arrow_up: grim@1.2.2 Closes atom/deprecation-cop#36 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8f0f1cd48..97b44afd1 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "fstream": "0.1.24", "fuzzaldrin": "^2.1", "git-utils": "^3.0.0", - "grim": "1.2.1", + "grim": "1.2.2", "jasmine-json": "~0.0", "jasmine-tagged": "^1.1.4", "jquery": "^2.1.1", From 78a25e7dedd6ae1a35b66e316b364f3bb1b148c9 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 21 Apr 2015 18:27:17 -0700 Subject: [PATCH 0791/1783] :arrow_up: apm@0.160 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index 211884e84..029b2b129 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.159.0" + "atom-package-manager": "0.160.0" } } From 5c8872c24edc52463c5932efcb38fca8734699e5 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 21 Apr 2015 18:43:19 -0700 Subject: [PATCH 0792/1783] :arrow_up: apm@0.161 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index 029b2b129..3cd607758 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.160.0" + "atom-package-manager": "0.161.0" } } From c2fc850e315620c0cad6d65838f7f5a94f378c79 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 21 Apr 2015 18:56:56 -0700 Subject: [PATCH 0793/1783] :arrow_up: settings-view@0.195 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 97b44afd1..17d0946d5 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "open-on-github": "0.36.0", "package-generator": "0.38.0", "release-notes": "0.52.0", - "settings-view": "0.194.0", + "settings-view": "0.195.0", "snippets": "0.88.0", "spell-check": "0.55.0", "status-bar": "0.69.0", From ecd04446434e47c505d7f1d3d8cb0fb76e91aa64 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 21 Apr 2015 19:13:54 -0700 Subject: [PATCH 0794/1783] Prepare 0.195 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 17d0946d5..d9debf674 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "0.194.0", + "version": "0.195.0", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From e96376121dd1bdbee86384b147106e712d6213fa Mon Sep 17 00:00:00 2001 From: Dean Brettle Date: Wed, 22 Apr 2015 00:55:17 -0700 Subject: [PATCH 0795/1783] Fix issue #6466 by using full path to atom --- build/tasks/mkrpm-task.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/tasks/mkrpm-task.coffee b/build/tasks/mkrpm-task.coffee index 8436fea7a..5744343a5 100644 --- a/build/tasks/mkrpm-task.coffee +++ b/build/tasks/mkrpm-task.coffee @@ -33,7 +33,7 @@ module.exports = (grunt) -> installDir = grunt.config.get('atom.installDir') shareDir = path.join(installDir, 'share', 'atom') iconName = 'atom' - executable = 'atom' + executable = path.join(shareDir, 'atom') data = {name, version, description, installDir, iconName, executable} specFilePath = fillTemplate(path.join('resources', 'linux', 'redhat', 'atom.spec'), data) From 02070165e43480ecc52f750f724643d618bdaea0 Mon Sep 17 00:00:00 2001 From: Ivan Zuzak Date: Wed, 22 Apr 2015 15:40:56 +0200 Subject: [PATCH 0796/1783] Move Grim deprecation calls to correctly attribute them with packages --- src/pane-view.coffee | 2 -- src/workspace.coffee | 4 ++++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pane-view.coffee b/src/pane-view.coffee index 03ca52558..4474d2d3b 100644 --- a/src/pane-view.coffee +++ b/src/pane-view.coffee @@ -119,7 +119,6 @@ class PaneView extends View deprecate 'Please return a Disposable object from your ::onDidChangeTitle method!' unless disposable?.dispose? @activeItemDisposables.add(disposable) if disposable?.dispose? else if item.on? - deprecate 'If you would like your pane item to support title change behavior, please implement a ::onDidChangeTitle() method. ::on methods for items are no longer supported. If not, ignore this message.' disposable = item.on('title-changed', @activeItemTitleChanged) @activeItemDisposables.add(disposable) if disposable?.dispose? @@ -128,7 +127,6 @@ class PaneView extends View deprecate 'Please return a Disposable object from your ::onDidChangeModified method!' unless disposable?.dispose? @activeItemDisposables.add(disposable) if disposable?.dispose? else if item.on? - deprecate 'If you would like your pane item to support modified behavior, please implement a ::onDidChangeModified() method. If not, ignore this message. ::on methods for items are no longer supported.' item.on('modified-status-changed', @activeItemModifiedChanged) @activeItemDisposables.add(disposable) if disposable?.dispose? diff --git a/src/workspace.coffee b/src/workspace.coffee index c094aaf92..50c4117fb 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -486,6 +486,10 @@ class Workspace extends Model item = opener(uri, options) if item? and typeof item.getUri is 'function' and typeof item.getURI isnt 'function' Grim.deprecate("Pane item with class `#{item.constructor.name}` should implement `::getURI` instead of `::getUri`.", {packageName}) + if item? and typeof item.on is 'function' and typeof item.onDidChangeTitle isnt 'function' + Grim.deprecate("If you would like your pane item with class `#{item.constructor.name}` to support title change behavior, please implement a `::onDidChangeTitle()` method. `::on` methods for items are no longer supported. If not, ignore this message.", {packageName}) + if item? and typeof item.on is 'function' and typeof item.onDidChangeModified isnt 'function' + Grim.deprecate("If you would like your pane item with class `#{item.constructor.name}` to support modified behavior, please implement a `::onDidChangeModified()` method. If not, ignore this message. `::on` methods for items are no longer supported.", {packageName}) item @openers.push(wrappedOpener) From 94a0bf3f905688a738c44b88881bdb1cd34df14e Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Thu, 22 Jan 2015 21:06:25 -0800 Subject: [PATCH 0797/1783] [Gutter] Create Gutter and GutterContainer w/ API to hide/show --- spec/gutter-container-spec.coffee | 49 +++++++++++++++++++ spec/gutter-spec.coffee | 64 +++++++++++++++++++++++++ src/gutter-container.coffee | 78 +++++++++++++++++++++++++++++++ src/gutter.coffee | 58 +++++++++++++++++++++++ 4 files changed, 249 insertions(+) create mode 100644 spec/gutter-container-spec.coffee create mode 100644 spec/gutter-spec.coffee create mode 100644 src/gutter-container.coffee create mode 100644 src/gutter.coffee diff --git a/spec/gutter-container-spec.coffee b/spec/gutter-container-spec.coffee new file mode 100644 index 000000000..299ae7097 --- /dev/null +++ b/spec/gutter-container-spec.coffee @@ -0,0 +1,49 @@ +Gutter = require '../src/gutter' +GutterContainer = require '../src/gutter-container' + +describe 'GutterContainer', -> + gutterContainer = null + beforeEach -> + gutterContainer = new GutterContainer + + describe 'when initialized', -> + it 'it has no gutters', -> + expect(gutterContainer.getGutters().length).toBe 0 + + describe '::addGutter', -> + it 'creates a new gutter', -> + newGutter = gutterContainer.addGutter {'test-gutter', priority: 1} + expect(gutterContainer.getGutters()).toEqual [newGutter] + expect(newGutter.priority).toBe 1 + + it 'throws an error if the provided gutter name is already in use', -> + name = 'test-gutter' + gutterContainer.addGutter {name} + expect(gutterContainer.addGutter.bind(null, {name})).toThrow() + + it 'keeps added gutters sorted by ascending priority', -> + gutter1 = gutterContainer.addGutter {name: 'first', priority: 1} + gutter3 = gutterContainer.addGutter {name: 'third', priority: 3} + gutter2 = gutterContainer.addGutter {name: 'second', priority: 2} + expect(gutterContainer.getGutters()).toEqual [gutter1, gutter2, gutter3] + + describe '::removeGutter', -> + removedGutters = null + + beforeEach -> + gutterContainer = new GutterContainer + removedGutters = [] + gutterContainer.onDidRemoveGutter (gutterName) -> + removedGutters.push gutterName + + it 'removes the gutter if it is contained by this GutterContainer', -> + gutter = gutterContainer.addGutter {'test-gutter'} + expect(gutterContainer.getGutters()).toEqual [gutter] + gutterContainer.removeGutter gutter + expect(gutterContainer.getGutters().length).toBe 0 + expect(removedGutters).toEqual [gutter.name] + + it 'throws an error if the gutter is not within this GutterContainer', -> + otherGutterContainer = new GutterContainer + gutter = new Gutter 'gutter-name', otherGutterContainer + expect(gutterContainer.removeGutter.bind(null, gutter)).toThrow() diff --git a/spec/gutter-spec.coffee b/spec/gutter-spec.coffee new file mode 100644 index 000000000..80b919423 --- /dev/null +++ b/spec/gutter-spec.coffee @@ -0,0 +1,64 @@ +Gutter = require '../src/gutter' + +describe 'Gutter', -> + fakeGutterContainer = {} + name = 'name' + + describe '::hide', -> + it 'hides the gutter if it is visible.', -> + options = + name: name + visible: true + gutter = new Gutter fakeGutterContainer, options + events = [] + gutter.onDidChangeVisible (gutter) -> + events.push gutter.isVisible() + + expect(gutter.isVisible()).toBe true + gutter.hide() + expect(gutter.isVisible()).toBe false + expect(events).toEqual [false] + gutter.hide() + expect(gutter.isVisible()).toBe false + # An event should only be emitted when the visibility changes. + expect(events.length).toBe 1 + + describe '::show', -> + it 'shows the gutter if it is hidden.', -> + options = + name: name + visible: false + gutter = new Gutter fakeGutterContainer, options + events = [] + gutter.onDidChangeVisible (gutter) -> + events.push gutter.isVisible() + + expect(gutter.isVisible()).toBe false + gutter.show() + expect(gutter.isVisible()).toBe true + expect(events).toEqual [true] + gutter.show() + expect(gutter.isVisible()).toBe true + # An event should only be emitted when the visibility changes. + expect(events.length).toBe 1 + + describe '::destroy', -> + [mockGutterContainer, mockGutterContainerRemovedGutters] = [] + + beforeEach -> + mockGutterContainerRemovedGutters = []; + mockGutterContainer = removeGutter: (destroyedGutter) -> + mockGutterContainerRemovedGutters.push destroyedGutter + + it 'removes the gutter from its container.', -> + gutter = new Gutter mockGutterContainer, {name} + gutter.destroy() + expect(mockGutterContainerRemovedGutters).toEqual([gutter]) + + it 'calls all callbacks registered on ::onDidDestroy.', -> + gutter = new Gutter mockGutterContainer, {name} + didDestroy = false + gutter.onDidDestroy -> + didDestroy = true + gutter.destroy() + expect(didDestroy).toBe true diff --git a/src/gutter-container.coffee b/src/gutter-container.coffee new file mode 100644 index 000000000..06d85a628 --- /dev/null +++ b/src/gutter-container.coffee @@ -0,0 +1,78 @@ +{Emitter} = require 'event-kit' +{Subscriber} = require 'emissary' +Gutter = require './gutter' + +# This class encapsulates the logic for adding and modifying a set of gutters. + +module.exports = +class GutterContainer + Subscriber.includeInto(this) + constructor: -> + @gutters = [] + @emitter = new Emitter + + destroy: -> + @gutters = null + @emitter.dispose() + @unsubscribe() + + # Creates and returns a {Gutter}. + # * `options` An {Object} with the following fields: + # * `name` (required) A unique {String} to identify this gutter. + # * `priority` (optional) A {Number} that determines stacking order between + # gutters. Lower priority items are forced closer to the edges of the + # window. (default: -100) + # * `visible` (optional) {Boolean} specifying whether the gutter is visible + # initially after being created. (default: true) + addGutter: (options) -> + options = options ? {} + gutterName = options.name + if gutterName == null + throw new Error 'A name is required to create a gutter.' + if @gutterWithName gutterName + throw new Error 'Tried to create a gutter with a name that is already in use.' + newGutter = new Gutter this, options + + inserted = false + # Insert the gutter into the gutters array, sorted in ascending order by 'priority'. + # This could be optimized, but there are unlikely to be many gutters. + for i in [0...@gutters.length] + if @gutters[i].priority >= newGutter.priority + @gutters.splice(i, 0, newGutter) + inserted = true + break + if !inserted + @gutters.push newGutter + return newGutter + + getGutters: -> + @gutters.slice() + + gutterWithName: (name) -> + for gutter in @gutters + if gutter.name == name then return gutter + null + + ### + Section: Event Subscription + ### + + # @param callback: function( nameOfRemovedGutter ) + onDidRemoveGutter: (callback) -> + @emitter.on 'did-remove-gutter', callback + + ### + Section: Private Methods + ### + + # Processes the destruction of the gutter. Throws an error if this gutter is + # not within this gutterContainer. + removeGutter: (gutter) -> + index = @gutters.indexOf gutter + if index > -1 + @gutters.splice(index, 1) + @unsubscribe gutter + @emitter.emit 'did-remove-gutter', gutter.name + else + throw new Error 'The given gutter cannot be removed because it is not ' + + 'within this GutterContainer.' diff --git a/src/gutter.coffee b/src/gutter.coffee new file mode 100644 index 000000000..bd50b4157 --- /dev/null +++ b/src/gutter.coffee @@ -0,0 +1,58 @@ +{Emitter} = require 'event-kit' + +# Public: This class represents a gutter within a TextEditor. + +DefaultPriority = -100 + +module.exports = +class Gutter + # * `gutterContainer` The {GutterContainer} object to which this gutter belongs. + # * `options` An {Object} with the following fields: + # * `name` (required) A unique {String} to identify this gutter. + # * `priority` (optional) A {Number} that determines stacking order between + # gutters. Lower priority items are forced closer to the edges of the + # window. (default: -100) + # * `visible` (optional) {Boolean} specifying whether the gutter is visible + # initially after being created. (default: true) + constructor: (gutterContainer, options) -> + @gutterContainer = gutterContainer + @name = options?.name + @priority = options?.priority ? DefaultPriority + @visible = options?.visible ? true + + @emitter = new Emitter + + destroy: -> + @gutterContainer.removeGutter(this) + @emitter.emit 'did-destroy' + @emitter.dispose() + + hide: -> + if @visible + @visible = false + @emitter.emit 'did-change-visible', this + + show: -> + if not @visible + @visible = true + @emitter.emit 'did-change-visible', this + + isVisible: -> + @visible + + # Calls your `callback` when the {Gutter}'s' visibility changes. + # + # * `callback` {Function} + # * `gutter` The {Gutter} whose visibility changed. + # + # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. + onDidChangeVisible: (callback) -> + @emitter.on 'did-change-visible', callback + + # Calls your `callback` when the {Gutter} is destroyed + # + # * `callback` {Function} + # + # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. + onDidDestroy: (callback) -> + @emitter.on 'did-destroy', callback From a6efa104dbef90a0b199ff77200de24d1c919fbd Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Mon, 30 Mar 2015 14:49:35 -0700 Subject: [PATCH 0798/1783] [Gutter] Don't allow the 'line-number' gutter to be destroyed --- spec/gutter-spec.coffee | 4 ++++ src/gutter.coffee | 9 ++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/spec/gutter-spec.coffee b/spec/gutter-spec.coffee index 80b919423..ba6933a05 100644 --- a/spec/gutter-spec.coffee +++ b/spec/gutter-spec.coffee @@ -62,3 +62,7 @@ describe 'Gutter', -> didDestroy = true gutter.destroy() expect(didDestroy).toBe true + + it 'does not allow destroying the line-number gutter', -> + gutter = new Gutter mockGutterContainer, {name: 'line-number'} + expect(gutter.destroy).toThrow() diff --git a/src/gutter.coffee b/src/gutter.coffee index bd50b4157..9e002674b 100644 --- a/src/gutter.coffee +++ b/src/gutter.coffee @@ -23,9 +23,12 @@ class Gutter @emitter = new Emitter destroy: -> - @gutterContainer.removeGutter(this) - @emitter.emit 'did-destroy' - @emitter.dispose() + if @name is 'line-number' + throw new Error('The line-number gutter cannot be destroyed.') + else + @gutterContainer.removeGutter(this) + @emitter.emit 'did-destroy' + @emitter.dispose() hide: -> if @visible From fccc9ebee4cdd9e26e3f9dd975c5a5d80b4dc327 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Wed, 4 Mar 2015 15:15:04 -0800 Subject: [PATCH 0799/1783] [Gutter] Rename current references to 'Gutter' -> 'LineNumberGutter' --- spec/text-editor-component-spec.coffee | 6 +++--- spec/text-editor-element-spec.coffee | 2 +- spec/text-editor-presenter-spec.coffee | 8 ++++---- src/text-editor-element.coffee | 2 +- src/text-editor-presenter.coffee | 4 ++-- src/text-editor.coffee | 18 +++++++++--------- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 955504319..80d22ddcd 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -578,10 +578,10 @@ describe "TextEditorComponent", -> nextAnimationFrame() expect(lineNumbersNode.style.backgroundColor).toBe 'rgb(255, 0, 0)' - it "hides or shows the gutter based on the '::isGutterVisible' property on the model and the global 'editor.showLineNumbers' config setting", -> + it "hides or shows the gutter based on the '::isLineNumberGutterVisible' property on the model and the global 'editor.showLineNumbers' config setting", -> expect(component.gutterComponent?).toBe true - editor.setGutterVisible(false) + editor.setLineNumberGutterVisible(false) nextAnimationFrame() expect(componentNode.querySelector('.gutter')).toBeNull() @@ -591,7 +591,7 @@ describe "TextEditorComponent", -> expect(componentNode.querySelector('.gutter')).toBeNull() - editor.setGutterVisible(true) + editor.setLineNumberGutterVisible(true) nextAnimationFrame() expect(componentNode.querySelector('.gutter')).toBeNull() diff --git a/spec/text-editor-element-spec.coffee b/spec/text-editor-element-spec.coffee index f6082b571..ba71cb236 100644 --- a/spec/text-editor-element-spec.coffee +++ b/spec/text-editor-element-spec.coffee @@ -23,7 +23,7 @@ describe "TextEditorElement", -> it "honors the 'gutter-hidden' attribute", -> jasmineContent.innerHTML = "" element = jasmineContent.firstChild - expect(element.getModel().isGutterVisible()).toBe false + expect(element.getModel().isLineNumberGutterVisible()).toBe false it "honors the text content", -> jasmineContent.innerHTML = "testing" diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 577c87401..0659abf27 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -2166,10 +2166,10 @@ describe "TextEditorPresenter", -> expect(lineNumberStateForScreenRow(presenter, 11).foldable).toBe false describe ".visible", -> - it "is true iff the editor isn't mini, ::isGutterVisible is true on the editor, and 'editor.showLineNumbers' is enabled in config", -> + it "is true iff the editor isn't mini, ::isLineNumberGutterVisible is true on the editor, and 'editor.showLineNumbers' is enabled in config", -> presenter = buildPresenter() - expect(editor.isGutterVisible()).toBe true + expect(editor.isLineNumberGutterVisible()).toBe true expect(presenter.getState().gutter.visible).toBe true expectStateUpdate presenter, -> editor.setMini(true) @@ -2178,10 +2178,10 @@ describe "TextEditorPresenter", -> expectStateUpdate presenter, -> editor.setMini(false) expect(presenter.getState().gutter.visible).toBe true - expectStateUpdate presenter, -> editor.setGutterVisible(false) + expectStateUpdate presenter, -> editor.setLineNumberGutterVisible(false) expect(presenter.getState().gutter.visible).toBe false - expectStateUpdate presenter, -> editor.setGutterVisible(true) + expectStateUpdate presenter, -> editor.setLineNumberGutterVisible(true) expect(presenter.getState().gutter.visible).toBe true expectStateUpdate presenter, -> atom.config.set('editor.showLineNumbers', false) diff --git a/src/text-editor-element.coffee b/src/text-editor-element.coffee index 99ae8ca17..0884b4248 100644 --- a/src/text-editor-element.coffee +++ b/src/text-editor-element.coffee @@ -100,7 +100,7 @@ class TextEditorElement extends HTMLElement tabLength: 2 softTabs: true mini: @hasAttribute('mini') - gutterVisible: not @hasAttribute('gutter-hidden') + lineNumberGutterVisible: not @hasAttribute('gutter-hidden') placeholderText: @getAttribute('placeholder-text') )) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 5b30178d6..0de512cf9 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -117,7 +117,7 @@ class TextEditorPresenter @updateLinesState() @updateGutterState() @updateLineNumbersState() - @disposables.add @model.onDidChangeGutterVisible => + @disposables.add @model.onDidChangeLineNumberGutterVisible => @updateGutterState() @disposables.add @model.onDidAddDecoration(@didAddDecoration.bind(this)) @disposables.add @model.onDidAddCursor(@didAddCursor.bind(this)) @@ -364,7 +364,7 @@ class TextEditorPresenter return updateGutterState: -> @batch "shouldUpdateGutterState", -> - @state.gutter.visible = not @model.isMini() and (@model.isGutterVisible() ? true) and @showLineNumbers + @state.gutter.visible = not @model.isMini() and (@model.isLineNumberGutterVisible() ? true) and @showLineNumbers @state.gutter.maxLineNumberDigits = @model.getLineCount().toString().length @state.gutter.backgroundColor = if @gutterBackgroundColor isnt "rgba(0, 0, 0, 0)" @gutterBackgroundColor diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 454abbabf..b94a05e40 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -73,7 +73,7 @@ class TextEditor extends Model 'autoDecreaseIndentForBufferRow', 'toggleLineCommentForBufferRow', 'toggleLineCommentsForBufferRows', toProperty: 'languageMode' - constructor: ({@softTabs, initialLine, initialColumn, tabLength, softWrapped, @displayBuffer, buffer, registerEditor, suppressCursorCreation, @mini, @placeholderText, @gutterVisible}) -> + constructor: ({@softTabs, initialLine, initialColumn, tabLength, softWrapped, @displayBuffer, buffer, registerEditor, suppressCursorCreation, @mini, @placeholderText, @lineNumberGutterVisible}) -> super @emitter = new Emitter @@ -488,16 +488,16 @@ class TextEditor extends Model onDidChangeMini: (callback) -> @emitter.on 'did-change-mini', callback - setGutterVisible: (gutterVisible) -> - unless gutterVisible is @gutterVisible - @gutterVisible = gutterVisible - @emitter.emit 'did-change-gutter-visible', @gutterVisible - @gutterVisible + setLineNumberGutterVisible: (lineNumberGutterVisible) -> + unless lineNumberGutterVisible is @lineNumberGutterVisible + @lineNumberGutterVisible = lineNumberGutterVisible + @emitter.emit 'did-change-line-number-gutter-visible', @lineNumberGutterVisible + @lineNumberGutterVisible - isGutterVisible: -> @gutterVisible ? true + isLineNumberGutterVisible: -> @lineNumberGutterVisible ? true - onDidChangeGutterVisible: (callback) -> - @emitter.on 'did-change-gutter-visible', callback + onDidChangeLineNumberGutterVisible: (callback) -> + @emitter.on 'did-change-line-number-gutter-visible', callback # Set the number of characters that can be displayed horizontally in the # editor. From 20d3c07bf5c9ee0586ea63991e83adb28112e77f Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Sun, 1 Feb 2015 17:58:54 -0800 Subject: [PATCH 0800/1783] [Gutter] Add add/get Gutter methods to TextEditor --- spec/text-editor-spec.coffee | 11 +++++++++++ src/text-editor.coffee | 14 ++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 5e0fef9e6..cf7107d4f 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -4242,3 +4242,14 @@ describe "TextEditor", -> editor.checkoutHeadRevision() waitsForPromise -> editor.checkoutHeadRevision() + + describe 'gutters', -> + describe '::addGutter', -> + it 'can add a gutter', -> + expect(editor.getGutters().length).toBe 0 + options = + name: 'test-gutter' + priority: 1 + gutter = editor.addGutter options + expect(editor.getGutters().length).toBe 1 + expect(editor.getGutters()[0]).toBe gutter diff --git a/src/text-editor.coffee b/src/text-editor.coffee index b94a05e40..200ec9cfa 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -12,6 +12,7 @@ Model = require './model' Selection = require './selection' TextMateScopeSelector = require('first-mate').ScopeSelector {Directory} = require "pathwatcher" +GutterContainer = require './gutter-container' # Public: This class represents all essential editing state for a single # {TextBuffer}, including cursor and selection positions, folds, and soft wraps. @@ -68,6 +69,7 @@ class TextEditor extends Model suppressSelectionMerging: false updateBatchDepth: 0 selectionFlashDuration: 500 + gutterContainer: null @delegatesMethods 'suggestedIndentForBufferRow', 'autoIndentBufferRow', 'autoIndentBufferRows', 'autoDecreaseIndentForBufferRow', 'toggleLineCommentForBufferRow', 'toggleLineCommentsForBufferRows', @@ -112,6 +114,8 @@ class TextEditor extends Model @emit 'scroll-left-changed', scrollLeft if includeDeprecatedAPIs @emitter.emit 'did-change-scroll-left', scrollLeft + @gutterContainer = new GutterContainer + atom.workspace?.editorAdded(this) if registerEditor serializeParams: -> @@ -181,6 +185,7 @@ class TextEditor extends Model @buffer.release() @displayBuffer.destroy() @languageMode.destroy() + @gutterContainer.destroy() @emitter.emit 'did-destroy' ### @@ -499,6 +504,15 @@ class TextEditor extends Model onDidChangeLineNumberGutterVisible: (callback) -> @emitter.on 'did-change-line-number-gutter-visible', callback + # Public: Creates and returns a {Gutter}. + # See {GutterContainer::addGutter} for more details. + addGutter: (options) -> + @gutterContainer.addGutter options + + # Public: Returns the {Array} of all gutters on this editor. + getGutters: -> + @gutterContainer.getGutters() + # Set the number of characters that can be displayed horizontally in the # editor. # From eb321a64c1bce8b04df2020c7361e6c72988d191 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Tue, 3 Feb 2015 08:50:10 -0800 Subject: [PATCH 0801/1783] [Gutter] Create a line-numbers Gutter on each TextEditor --- spec/text-editor-spec.coffee | 16 +++++++++++++--- src/text-editor.coffee | 23 +++++++++++++++++------ 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index cf7107d4f..890eb923f 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -4244,12 +4244,22 @@ describe "TextEditor", -> waitsForPromise -> editor.checkoutHeadRevision() describe 'gutters', -> + describe 'the TextEditor constructor', -> + it 'creates a line-number gutter', -> + expect(editor.getGutters().length).toBe 1 + lineNumberGutter = editor.gutterWithName('line-number') + expect(lineNumberGutter.name).toBe 'line-number' + expect(lineNumberGutter.priority).toBe 0 + describe '::addGutter', -> it 'can add a gutter', -> - expect(editor.getGutters().length).toBe 0 + expect(editor.getGutters().length).toBe 1 # line-number gutter options = name: 'test-gutter' priority: 1 gutter = editor.addGutter options - expect(editor.getGutters().length).toBe 1 - expect(editor.getGutters()[0]).toBe gutter + expect(editor.getGutters().length).toBe 2 + expect(editor.getGutters()[1]).toBe gutter + + it "does not allow a custom gutter with the 'line-number' name.", -> + expect(editor.addGutter.bind(editor, {name: 'line-number'})).toThrow() diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 200ec9cfa..0498ebe22 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -75,7 +75,7 @@ class TextEditor extends Model 'autoDecreaseIndentForBufferRow', 'toggleLineCommentForBufferRow', 'toggleLineCommentsForBufferRows', toProperty: 'languageMode' - constructor: ({@softTabs, initialLine, initialColumn, tabLength, softWrapped, @displayBuffer, buffer, registerEditor, suppressCursorCreation, @mini, @placeholderText, @lineNumberGutterVisible}) -> + constructor: ({@softTabs, initialLine, initialColumn, tabLength, softWrapped, @displayBuffer, buffer, registerEditor, suppressCursorCreation, @mini, @placeholderText, lineNumberGutterVisible}) -> super @emitter = new Emitter @@ -115,6 +115,10 @@ class TextEditor extends Model @emitter.emit 'did-change-scroll-left', scrollLeft @gutterContainer = new GutterContainer + @lineNumberGutter = @gutterContainer.addGutter + name: 'line-number' + priority: 0 + visible: lineNumberGutterVisible atom.workspace?.editorAdded(this) if registerEditor @@ -494,12 +498,15 @@ class TextEditor extends Model @emitter.on 'did-change-mini', callback setLineNumberGutterVisible: (lineNumberGutterVisible) -> - unless lineNumberGutterVisible is @lineNumberGutterVisible - @lineNumberGutterVisible = lineNumberGutterVisible - @emitter.emit 'did-change-line-number-gutter-visible', @lineNumberGutterVisible - @lineNumberGutterVisible + unless lineNumberGutterVisible is @lineNumberGutter.isVisible() + if lineNumberGutterVisible + @lineNumberGutter.show() + else + @lineNumberGutter.hide() + @emitter.emit 'did-change-line-number-gutter-visible', @lineNumberGutter.isVisible() + @lineNumberGutter.isVisible() - isLineNumberGutterVisible: -> @lineNumberGutterVisible ? true + isLineNumberGutterVisible: -> @lineNumberGutter.isVisible() onDidChangeLineNumberGutterVisible: (callback) -> @emitter.on 'did-change-line-number-gutter-visible', callback @@ -513,6 +520,10 @@ class TextEditor extends Model getGutters: -> @gutterContainer.getGutters() + # Public: Returns the {Gutter} with the given name, or null if it doesn't exist. + gutterWithName: (name) -> + @gutterContainer.gutterWithName name + # Set the number of characters that can be displayed horizontally in the # editor. # From 58d6712b0e39314476986fc546129638b0e99fd3 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Tue, 3 Feb 2015 18:34:51 -0800 Subject: [PATCH 0802/1783] [Gutter] Augment Decoration to discern the line-number gutter from custom gutters --- spec/display-buffer-spec.coffee | 25 ++++++++++++++++++++++++- spec/text-editor-spec.coffee | 14 ++++++++++++++ src/decoration.coffee | 25 +++++++++++++++++++++---- src/text-editor.coffee | 4 +++- 4 files changed, 62 insertions(+), 6 deletions(-) diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index b5858007e..f37c9ebf0 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -1208,7 +1208,7 @@ describe "DisplayBuffer", -> {oldProperties, newProperties} = updatedSpy.mostRecentCall.args[0] expect(oldProperties).toEqual decorationProperties - expect(newProperties).toEqual type: 'line-number', class: 'two', id: decoration.id + expect(newProperties).toEqual type: 'line-number', gutterName: 'line-number', class: 'two', id: decoration.id describe "::getDecorations(properties)", -> it "returns decorations matching the given optional properties", -> @@ -1367,3 +1367,26 @@ describe "DisplayBuffer", -> displayBuffer.setScrollTop(60) expect(displayBuffer.getVisibleRowRange()).toEqual [0, 13] + + describe "::decorateMarker", -> + describe "when decorating gutters", -> + [marker] = [] + + beforeEach -> + marker = displayBuffer.markBufferRange([[1, 0], [1, 0]]); + + it "creates a decoration that is both of 'line-number' and 'gutter' type when called with the 'line-number' type", -> + decorationProperties = {type: 'line-number', class: 'one'} + decoration = displayBuffer.decorateMarker(marker, decorationProperties) + expect(decoration.isType('line-number')).toBe true + expect(decoration.isType('gutter')).toBe true + expect(decoration.getProperties().gutterName).toBe 'line-number' + expect(decoration.getProperties().class).toBe 'one' + + it "creates a decoration that is only of 'gutter' type if called with the 'gutter' type and a 'gutterName'", -> + decorationProperties = {type: 'gutter', gutterName:'test-gutter', class: 'one'} + decoration = displayBuffer.decorateMarker(marker, decorationProperties) + expect(decoration.isType('gutter')).toBe true + expect(decoration.isType('line-number')).toBe false + expect(decoration.getProperties().gutterName).toBe 'test-gutter' + expect(decoration.getProperties().class).toBe 'one' diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 890eb923f..fec384cb1 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -4263,3 +4263,17 @@ describe "TextEditor", -> it "does not allow a custom gutter with the 'line-number' name.", -> expect(editor.addGutter.bind(editor, {name: 'line-number'})).toThrow() + + describe '::decorateMarker', -> + [marker] = [] + + beforeEach -> + marker = editor.markBufferRange([[1, 0], [1, 0]]) + + it "casts 'gutter' type to 'line-number' unless a gutter name is specified.", -> + lineNumberDecoration = editor.decorateMarker(marker, {type: 'gutter'}) + customGutterDecoration = editor.decorateMarker(marker, {type: 'gutter', gutterName: 'custom'}) + expect(lineNumberDecoration.getProperties().type).toBe 'line-number' + expect(lineNumberDecoration.getProperties().gutterName).toBe 'line-number' + expect(customGutterDecoration.getProperties().type).toBe 'gutter' + expect(customGutterDecoration.getProperties().gutterName).toBe 'custom' diff --git a/src/decoration.coffee b/src/decoration.coffee index 48b26e81f..ca239421e 100644 --- a/src/decoration.coffee +++ b/src/decoration.coffee @@ -5,6 +5,13 @@ Grim = require 'grim' idCounter = 0 nextId = -> idCounter++ +# Applies changes to a decorationsParam {Object} to make it possible to +# differentiate decorations on custom gutters versus the line-number gutter. +translateDecorationParamsOldToNew = (decorationParams) -> + if decorationParams.type is 'line-number' + decorationParams.gutterName = 'line-number' + decorationParams + # Essential: Represents a decoration that follows a {Marker}. A decoration is # basically a visual representation of a marker. It allows you to add CSS # classes to line numbers in the gutter, lines, and add selection-line regions @@ -38,19 +45,29 @@ class Decoration # type matches any in the array. # # Returns {Boolean} + # Note: 'line-number' is a special subtype of the 'gutter' type. I.e., a + # 'line-number' is a 'gutter', but a 'gutter' is not a 'line-number'. @isType: (decorationProperties, type) -> + # 'line-number' is a special case of 'gutter'. if _.isArray(decorationProperties.type) - type in decorationProperties.type + return true if type in decorationProperties.type + if type is 'gutter' + return true if 'line-number' in decorationProperties.type + return false else - type is decorationProperties.type + if type is 'gutter' + return true if decorationProperties.type in ['gutter', 'line-number'] + else + type is decorationProperties.type ### Section: Construction and Destruction ### - constructor: (@marker, @displayBuffer, @properties) -> + constructor: (@marker, @displayBuffer, properties) -> @emitter = new Emitter @id = nextId() + @setProperties properties @properties.id = @id @flashQueue = null @destroyed = false @@ -134,7 +151,7 @@ class Decoration setProperties: (newProperties) -> return if @destroyed oldProperties = @properties - @properties = newProperties + @properties = translateDecorationParamsOldToNew(newProperties) @properties.id = @id @emit 'updated', {oldParams: oldProperties, newParams: newProperties} if Grim.includeDeprecatedAPIs @emitter.emit 'did-change-properties', {oldProperties, newProperties} diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 0498ebe22..997ad6212 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -1275,10 +1275,12 @@ class TextEditor extends Model # * `position` (optional) Only applicable to decorations of type `overlay`, # controls where the overlay view is positioned relative to the marker. # Values can be `'head'` (the default), or `'tail'`. + # * `gutterName` (optional) Only applicable to the `gutter` type. If provided, + # the decoration will be applied to the gutter with the specified name. # # Returns a {Decoration} object decorateMarker: (marker, decorationParams) -> - if includeDeprecatedAPIs and decorationParams.type is 'gutter' + if decorationParams.type is 'gutter' && !decorationParams.gutterName deprecate("Decorations of `type: 'gutter'` have been renamed to `type: 'line-number'`.") decorationParams.type = 'line-number' @displayBuffer.decorateMarker(marker, decorationParams) From b361e1719cdac69552fbc746746f99f735a65392 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Mon, 2 Feb 2015 09:57:28 -0800 Subject: [PATCH 0803/1783] [Gutter] Add decorateMarker method to Gutter model --- spec/gutter-container-spec.coffee | 9 ++++++--- spec/text-editor-spec.coffee | 19 +++++++++++++++++++ src/gutter-container.coffee | 14 +++++++++++++- src/gutter.coffee | 8 ++++++++ src/text-editor.coffee | 2 +- 5 files changed, 47 insertions(+), 5 deletions(-) diff --git a/spec/gutter-container-spec.coffee b/spec/gutter-container-spec.coffee index 299ae7097..03c9ebc10 100644 --- a/spec/gutter-container-spec.coffee +++ b/spec/gutter-container-spec.coffee @@ -3,8 +3,10 @@ GutterContainer = require '../src/gutter-container' describe 'GutterContainer', -> gutterContainer = null + fakeTextEditor = {} + beforeEach -> - gutterContainer = new GutterContainer + gutterContainer = new GutterContainer fakeTextEditor describe 'when initialized', -> it 'it has no gutters', -> @@ -31,7 +33,7 @@ describe 'GutterContainer', -> removedGutters = null beforeEach -> - gutterContainer = new GutterContainer + gutterContainer = new GutterContainer fakeTextEditor removedGutters = [] gutterContainer.onDidRemoveGutter (gutterName) -> removedGutters.push gutterName @@ -44,6 +46,7 @@ describe 'GutterContainer', -> expect(removedGutters).toEqual [gutter.name] it 'throws an error if the gutter is not within this GutterContainer', -> - otherGutterContainer = new GutterContainer + fakeOtherTextEditor = {} + otherGutterContainer = new GutterContainer fakeOtherTextEditor gutter = new Gutter 'gutter-name', otherGutterContainer expect(gutterContainer.removeGutter.bind(null, gutter)).toThrow() diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index fec384cb1..8f187d189 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -4277,3 +4277,22 @@ describe "TextEditor", -> expect(lineNumberDecoration.getProperties().gutterName).toBe 'line-number' expect(customGutterDecoration.getProperties().type).toBe 'gutter' expect(customGutterDecoration.getProperties().gutterName).toBe 'custom' + + it 'reflects an added decoration when one of its custom gutters is decorated.', -> + gutter = editor.addGutter {'name': 'custom-gutter'} + decoration = gutter.decorateMarker marker, {class: 'custom-class'} + gutterDecorations = editor.getDecorations + type: 'gutter' + gutterName: 'custom-gutter' + class: 'custom-class' + expect(gutterDecorations.length).toBe 1 + expect(gutterDecorations[0]).toBe decoration + + it 'reflects an added decoration when its line-number gutter is decorated.', -> + decoration = editor.gutterWithName('line-number').decorateMarker marker, {class: 'test-class'} + gutterDecorations = editor.getDecorations + type: 'line-number' + gutterName: 'line-number' + class: 'test-class' + expect(gutterDecorations.length).toBe 1 + expect(gutterDecorations[0]).toBe decoration diff --git a/src/gutter-container.coffee b/src/gutter-container.coffee index 06d85a628..6d62da27b 100644 --- a/src/gutter-container.coffee +++ b/src/gutter-container.coffee @@ -7,8 +7,11 @@ Gutter = require './gutter' module.exports = class GutterContainer Subscriber.includeInto(this) - constructor: -> + + # * `textEditor` The {TextEditor} to which this {GutterContainer} belongs. + constructor: (textEditor) -> @gutters = [] + @textEditor = textEditor @emitter = new Emitter destroy: -> @@ -76,3 +79,12 @@ class GutterContainer else throw new Error 'The given gutter cannot be removed because it is not ' + 'within this GutterContainer.' + + # The public interface is Gutter::decorateMarker or TextEditor::decorateMarker. + addGutterDecoration: (gutter, marker, options) -> + if gutter.name is 'line-number' + options.type = 'line-number' + else + options.type = 'gutter' + options.gutterName = gutter.name + @textEditor.decorateMarker marker, options diff --git a/src/gutter.coffee b/src/gutter.coffee index 9e002674b..f59fa7acd 100644 --- a/src/gutter.coffee +++ b/src/gutter.coffee @@ -43,6 +43,14 @@ class Gutter isVisible: -> @visible + # * `marker` (required) A Marker object. + # * `options` (optional) An object with the following fields: + # * `class` (optional) + # * `item` (optional) A model {Object} with a corresponding view registered, + # or an {HTMLElement}. + decorateMarker: (marker, options) -> + @gutterContainer.addGutterDecoration this, marker, options + # Calls your `callback` when the {Gutter}'s' visibility changes. # # * `callback` {Function} diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 997ad6212..f27e7f4a0 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -114,7 +114,7 @@ class TextEditor extends Model @emit 'scroll-left-changed', scrollLeft if includeDeprecatedAPIs @emitter.emit 'did-change-scroll-left', scrollLeft - @gutterContainer = new GutterContainer + @gutterContainer = new GutterContainer this @lineNumberGutter = @gutterContainer.addGutter name: 'line-number' priority: 0 From ee7625249f75331bff6937c25643079c8f75bc60 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Thu, 12 Mar 2015 15:48:25 -0700 Subject: [PATCH 0804/1783] [Gutter] Create event subscription methods for gutter changes --- spec/text-editor-spec.coffee | 74 ++++++++++++++++++++++++++++++++++++ src/gutter-container.coffee | 12 +++++- src/text-editor.coffee | 28 ++++++++++++++ 3 files changed, 113 insertions(+), 1 deletion(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 8f187d189..6926e057f 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -4296,3 +4296,77 @@ describe "TextEditor", -> class: 'test-class' expect(gutterDecorations.length).toBe 1 expect(gutterDecorations[0]).toBe decoration + + describe '::observeGutters', -> + [payloads, callback] = [] + + beforeEach -> + payloads = [] + callback = (payload) -> + payloads.push(payload) + + it 'calls the callback immediately with each existing gutter, and with each added gutter after that.', -> + lineNumberGutter = editor.gutterWithName('line-number') + editor.observeGutters(callback) + expect(payloads).toEqual [lineNumberGutter] + gutter1 = editor.addGutter({name: 'test-gutter-1'}) + expect(payloads).toEqual [lineNumberGutter, gutter1] + gutter2 = editor.addGutter({name: 'test-gutter-2'}) + expect(payloads).toEqual [lineNumberGutter, gutter1, gutter2] + + it 'does not call the callback when a gutter is removed.', -> + gutter = editor.addGutter({name: 'test-gutter'}) + editor.observeGutters(callback) + payloads = [] + gutter.destroy() + expect(payloads).toEqual [] + + it 'does not call the callback after the subscription has been disposed.', -> + subscription = editor.observeGutters(callback) + payloads = [] + subscription.dispose() + editor.addGutter({name: 'test-gutter'}) + expect(payloads).toEqual [] + + describe '::onDidAddGutter', -> + [payloads, callback] = [] + + beforeEach -> + payloads = [] + callback = (payload) -> + payloads.push(payload) + + it 'calls the callback with each newly-added gutter, but not with existing gutters.', -> + editor.onDidAddGutter(callback) + expect(payloads).toEqual [] + gutter = editor.addGutter({name: 'test-gutter'}) + expect(payloads).toEqual [gutter] + + it 'does not call the callback after the subscription has been disposed.', -> + subscription = editor.onDidAddGutter(callback) + payloads = [] + subscription.dispose() + editor.addGutter({name: 'test-gutter'}) + expect(payloads).toEqual [] + + describe '::onDidRemoveGutter', -> + [payloads, callback] = [] + + beforeEach -> + payloads = [] + callback = (payload) -> + payloads.push(payload) + + it 'calls the callback when a gutter is removed.', -> + gutter = editor.addGutter({name: 'test-gutter'}) + editor.onDidRemoveGutter(callback) + expect(payloads).toEqual [] + gutter.destroy() + expect(payloads).toEqual ['test-gutter'] + + it 'does not call the callback after the subscription has been disposed.', -> + gutter = editor.addGutter({name: 'test-gutter'}) + subscription = editor.onDidRemoveGutter(callback) + subscription.dispose() + gutter.destroy() + expect(payloads).toEqual [] diff --git a/src/gutter-container.coffee b/src/gutter-container.coffee index 6d62da27b..396b74fc4 100644 --- a/src/gutter-container.coffee +++ b/src/gutter-container.coffee @@ -46,6 +46,7 @@ class GutterContainer break if !inserted @gutters.push newGutter + @emitter.emit 'did-add-gutter', newGutter return newGutter getGutters: -> @@ -60,7 +61,16 @@ class GutterContainer Section: Event Subscription ### - # @param callback: function( nameOfRemovedGutter ) + # See {TextEditor::observeGutters} for details. + observeGutters: (callback) -> + callback(gutter) for gutter in @getGutters() + @onDidAddGutter callback + + # See {TextEditor::onDidAddGutter} for details. + onDidAddGutter: (callback) -> + @emitter.on 'did-add-gutter', callback + + # See {TextEditor::onDidRemoveGutter} for details. onDidRemoveGutter: (callback) -> @emitter.on 'did-remove-gutter', callback diff --git a/src/text-editor.coffee b/src/text-editor.coffee index f27e7f4a0..3c7111924 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -524,6 +524,34 @@ class TextEditor extends Model gutterWithName: (name) -> @gutterContainer.gutterWithName name + # Calls your `callback` when a {Gutter} is added to the editor. + # Immediately calls your callback for each existing gutter. + # + # * `callback` {Function} + # * `gutter` {Gutter} that currently exists/was added. + # + # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. + observeGutters: (callback) -> + @gutterContainer.observeGutters callback + + # Calls your `callback` when a {Gutter} is added to the editor. + # + # * `callback` {Function} + # * `gutter` {Gutter} that was added. + # + # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. + onDidAddGutter: (callback) -> + @gutterContainer.onDidAddGutter callback + + # Calls your `callback` when a {Gutter} is removed from the editor. + # + # * `callback` {Function} + # * `name` The name of the {Gutter} that was removed. + # + # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. + onDidRemoveGutter: (callback) -> + @gutterContainer.onDidRemoveGutter callback + # Set the number of characters that can be displayed horizontally in the # editor. # From cc89f972dcfbec5804ae8c0bc3e16311ad888734 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Sat, 14 Mar 2015 17:53:03 -0700 Subject: [PATCH 0805/1783] [Gutter][style] Add parentheses to some method calls for readability --- src/gutter-container.coffee | 12 ++++++------ src/gutter.coffee | 2 +- src/text-editor.coffee | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/gutter-container.coffee b/src/gutter-container.coffee index 396b74fc4..e7b68ef52 100644 --- a/src/gutter-container.coffee +++ b/src/gutter-container.coffee @@ -31,10 +31,10 @@ class GutterContainer options = options ? {} gutterName = options.name if gutterName == null - throw new Error 'A name is required to create a gutter.' - if @gutterWithName gutterName - throw new Error 'Tried to create a gutter with a name that is already in use.' - newGutter = new Gutter this, options + throw new Error('A name is required to create a gutter.') + if @gutterWithName(gutterName) + throw new Error('Tried to create a gutter with a name that is already in use.') + newGutter = new Gutter(this, options) inserted = false # Insert the gutter into the gutters array, sorted in ascending order by 'priority'. @@ -81,7 +81,7 @@ class GutterContainer # Processes the destruction of the gutter. Throws an error if this gutter is # not within this gutterContainer. removeGutter: (gutter) -> - index = @gutters.indexOf gutter + index = @gutters.indexOf(gutter) if index > -1 @gutters.splice(index, 1) @unsubscribe gutter @@ -97,4 +97,4 @@ class GutterContainer else options.type = 'gutter' options.gutterName = gutter.name - @textEditor.decorateMarker marker, options + @textEditor.decorateMarker(marker, options) diff --git a/src/gutter.coffee b/src/gutter.coffee index f59fa7acd..cb5c36e9c 100644 --- a/src/gutter.coffee +++ b/src/gutter.coffee @@ -49,7 +49,7 @@ class Gutter # * `item` (optional) A model {Object} with a corresponding view registered, # or an {HTMLElement}. decorateMarker: (marker, options) -> - @gutterContainer.addGutterDecoration this, marker, options + @gutterContainer.addGutterDecoration(this, marker, options) # Calls your `callback` when the {Gutter}'s' visibility changes. # diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 3c7111924..6692790f6 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -114,7 +114,7 @@ class TextEditor extends Model @emit 'scroll-left-changed', scrollLeft if includeDeprecatedAPIs @emitter.emit 'did-change-scroll-left', scrollLeft - @gutterContainer = new GutterContainer this + @gutterContainer = new GutterContainer(this) @lineNumberGutter = @gutterContainer.addGutter name: 'line-number' priority: 0 @@ -514,7 +514,7 @@ class TextEditor extends Model # Public: Creates and returns a {Gutter}. # See {GutterContainer::addGutter} for more details. addGutter: (options) -> - @gutterContainer.addGutter options + @gutterContainer.addGutter(options) # Public: Returns the {Array} of all gutters on this editor. getGutters: -> @@ -522,7 +522,7 @@ class TextEditor extends Model # Public: Returns the {Gutter} with the given name, or null if it doesn't exist. gutterWithName: (name) -> - @gutterContainer.gutterWithName name + @gutterContainer.gutterWithName(name) # Calls your `callback` when a {Gutter} is added to the editor. # Immediately calls your callback for each existing gutter. From ecdf324e6237d0d158e3c11b990a3b68226fdc6b Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Wed, 18 Mar 2015 21:50:41 -0700 Subject: [PATCH 0806/1783] [Gutter] TextEditorPresenter: rename updateGutterState -> updateLineNumberGutterState --- src/text-editor-presenter.coffee | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 0de512cf9..edbf0d63f 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -87,7 +87,7 @@ class TextEditorPresenter @updateLinesState() if @shouldUpdateLinesState @updateCursorsState() if @shouldUpdateCursorsState @updateOverlaysState() if @shouldUpdateOverlaysState - @updateGutterState() if @shouldUpdateGutterState + @updateLineNumberGutterState() if @shouldUpdateLineNumberGutterState @updateLineNumbersState() if @shouldUpdateLineNumbersState @updating = false @@ -105,7 +105,7 @@ class TextEditorPresenter @updateContentState() @updateDecorations() @updateLinesState() - @updateGutterState() + @updateLineNumberGutterState() @updateLineNumbersState() @disposables.add @model.onDidChangeGrammar(@didChangeGrammar.bind(this)) @disposables.add @model.onDidChangePlaceholderText(@updateContentState.bind(this)) @@ -115,10 +115,10 @@ class TextEditorPresenter @updateContentState() @updateDecorations() @updateLinesState() - @updateGutterState() + @updateLineNumberGutterState() @updateLineNumbersState() @disposables.add @model.onDidChangeLineNumberGutterVisible => - @updateGutterState() + @updateLineNumberGutterState() @disposables.add @model.onDidAddDecoration(@didAddDecoration.bind(this)) @disposables.add @model.onDidAddCursor(@didAddCursor.bind(this)) @disposables.add @model.onDidChangeScrollTop(@setScrollTop.bind(this)) @@ -151,12 +151,12 @@ class TextEditorPresenter @updateScrollbarsState() @configDisposables.add atom.config.onDidChange 'editor.showLineNumbers', configParams, ({newValue}) => @showLineNumbers = newValue - @updateGutterState() + @updateLineNumberGutterState() didChangeGrammar: -> @observeConfig() @updateContentState() - @updateGutterState() + @updateLineNumberGutterState() buildState: -> @state = @@ -190,7 +190,7 @@ class TextEditorPresenter @updateLinesState() @updateCursorsState() @updateOverlaysState() - @updateGutterState() + @updateLineNumberGutterState() @updateLineNumbersState() updateFocusedState: -> @batch "shouldUpdateFocusedState", -> @@ -363,7 +363,7 @@ class TextEditorPresenter return - updateGutterState: -> @batch "shouldUpdateGutterState", -> + updateLineNumberGutterState: -> @batch "shouldUpdateLineNumberGutterState", -> @state.gutter.visible = not @model.isMini() and (@model.isLineNumberGutterVisible() ? true) and @showLineNumbers @state.gutter.maxLineNumberDigits = @model.getLineCount().toString().length @state.gutter.backgroundColor = if @gutterBackgroundColor isnt "rgba(0, 0, 0, 0)" @@ -708,12 +708,12 @@ class TextEditorPresenter unless @backgroundColor is backgroundColor @backgroundColor = backgroundColor @updateContentState() - @updateGutterState() + @updateLineNumberGutterState() setGutterBackgroundColor: (gutterBackgroundColor) -> unless @gutterBackgroundColor is gutterBackgroundColor @gutterBackgroundColor = gutterBackgroundColor - @updateGutterState() + @updateLineNumberGutterState() setLineHeight: (lineHeight) -> unless @lineHeight is lineHeight From 7582e98f4c80a94868b6c9c236a643d7af508ea0 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Thu, 26 Mar 2015 11:38:17 -0700 Subject: [PATCH 0807/1783] [Gutter] TextEditorPresenter: rename @state.gutter -> @state.lineNumberGutter --- spec/text-editor-presenter-spec.coffee | 71 +++++++++++++------------- src/gutter-component.coffee | 2 +- src/text-editor-component.coffee | 4 +- src/text-editor-presenter.coffee | 18 +++---- 4 files changed, 47 insertions(+), 48 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 0659abf27..28cd1890f 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -1766,107 +1766,106 @@ describe "TextEditorPresenter", -> pixelPosition: {top: 10, left: 0} } - - describe ".gutter", -> + describe ".lineNumberGutter", -> describe ".scrollHeight", -> it "is initialized based on ::lineHeight, the number of lines, and ::explicitHeight", -> presenter = buildPresenter() - expect(presenter.getState().gutter.scrollHeight).toBe editor.getScreenLineCount() * 10 + expect(presenter.getState().lineNumberGutter.scrollHeight).toBe editor.getScreenLineCount() * 10 presenter = buildPresenter(explicitHeight: 500) - expect(presenter.getState().gutter.scrollHeight).toBe 500 + expect(presenter.getState().lineNumberGutter.scrollHeight).toBe 500 it "updates when the ::lineHeight changes", -> presenter = buildPresenter() expectStateUpdate presenter, -> presenter.setLineHeight(20) - expect(presenter.getState().gutter.scrollHeight).toBe editor.getScreenLineCount() * 20 + expect(presenter.getState().lineNumberGutter.scrollHeight).toBe editor.getScreenLineCount() * 20 it "updates when the line count changes", -> presenter = buildPresenter() expectStateUpdate presenter, -> editor.getBuffer().append("\n\n\n") - expect(presenter.getState().gutter.scrollHeight).toBe editor.getScreenLineCount() * 10 + expect(presenter.getState().lineNumberGutter.scrollHeight).toBe editor.getScreenLineCount() * 10 it "updates when ::explicitHeight changes", -> presenter = buildPresenter() expectStateUpdate presenter, -> presenter.setExplicitHeight(500) - expect(presenter.getState().gutter.scrollHeight).toBe 500 + expect(presenter.getState().lineNumberGutter.scrollHeight).toBe 500 it "adds the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.getState().gutter.scrollHeight).toBe presenter.contentHeight + expect(presenter.getState().lineNumberGutter.scrollHeight).toBe presenter.contentHeight expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", true) - expect(presenter.getState().gutter.scrollHeight).toBe presenter.contentHeight + presenter.clientHeight - (presenter.lineHeight * 3) + expect(presenter.getState().lineNumberGutter.scrollHeight).toBe presenter.contentHeight + presenter.clientHeight - (presenter.lineHeight * 3) expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) - expect(presenter.getState().gutter.scrollHeight).toBe presenter.contentHeight + expect(presenter.getState().lineNumberGutter.scrollHeight).toBe presenter.contentHeight describe ".scrollTop", -> it "tracks the value of ::scrollTop", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 20) - expect(presenter.getState().gutter.scrollTop).toBe 10 + expect(presenter.getState().lineNumberGutter.scrollTop).toBe 10 expectStateUpdate presenter, -> presenter.setScrollTop(50) - expect(presenter.getState().gutter.scrollTop).toBe 50 + expect(presenter.getState().lineNumberGutter.scrollTop).toBe 50 it "never exceeds the computed scrollHeight minus the computed clientHeight", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(100) - expect(presenter.getState().gutter.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + expect(presenter.getState().lineNumberGutter.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight expectStateUpdate presenter, -> presenter.setExplicitHeight(60) - expect(presenter.getState().gutter.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + expect(presenter.getState().lineNumberGutter.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight expectStateUpdate presenter, -> presenter.setHorizontalScrollbarHeight(5) - expect(presenter.getState().gutter.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + expect(presenter.getState().lineNumberGutter.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight expectStateUpdate presenter, -> editor.getBuffer().delete([[8, 0], [12, 0]]) - expect(presenter.getState().gutter.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + expect(presenter.getState().lineNumberGutter.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight # Scroll top only gets smaller when needed as dimensions change, never bigger scrollTopBefore = presenter.getState().verticalScrollbar.scrollTop expectStateUpdate presenter, -> editor.getBuffer().insert([9, Infinity], '\n\n\n') - expect(presenter.getState().gutter.scrollTop).toBe scrollTopBefore + expect(presenter.getState().lineNumberGutter.scrollTop).toBe scrollTopBefore it "never goes negative", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(-100) - expect(presenter.getState().gutter.scrollTop).toBe 0 + expect(presenter.getState().lineNumberGutter.scrollTop).toBe 0 it "adds the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.getState().gutter.scrollTop).toBe presenter.contentHeight - presenter.clientHeight + expect(presenter.getState().lineNumberGutter.scrollTop).toBe presenter.contentHeight - presenter.clientHeight atom.config.set("editor.scrollPastEnd", true) expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.getState().gutter.scrollTop).toBe presenter.contentHeight - (presenter.lineHeight * 3) + expect(presenter.getState().lineNumberGutter.scrollTop).toBe presenter.contentHeight - (presenter.lineHeight * 3) expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) - expect(presenter.getState().gutter.scrollTop).toBe presenter.contentHeight - presenter.clientHeight + expect(presenter.getState().lineNumberGutter.scrollTop).toBe presenter.contentHeight - presenter.clientHeight describe ".backgroundColor", -> it "is assigned to ::gutterBackgroundColor if present, and to ::backgroundColor otherwise", -> presenter = buildPresenter(backgroundColor: "rgba(255, 0, 0, 0)", gutterBackgroundColor: "rgba(0, 255, 0, 0)") - expect(presenter.getState().gutter.backgroundColor).toBe "rgba(0, 255, 0, 0)" + expect(presenter.getState().lineNumberGutter.backgroundColor).toBe "rgba(0, 255, 0, 0)" expectStateUpdate presenter, -> presenter.setGutterBackgroundColor("rgba(0, 0, 255, 0)") - expect(presenter.getState().gutter.backgroundColor).toBe "rgba(0, 0, 255, 0)" + expect(presenter.getState().lineNumberGutter.backgroundColor).toBe "rgba(0, 0, 255, 0)" expectStateUpdate presenter, -> presenter.setGutterBackgroundColor("rgba(0, 0, 0, 0)") - expect(presenter.getState().gutter.backgroundColor).toBe "rgba(255, 0, 0, 0)" + expect(presenter.getState().lineNumberGutter.backgroundColor).toBe "rgba(255, 0, 0, 0)" expectStateUpdate presenter, -> presenter.setBackgroundColor("rgba(0, 0, 255, 0)") - expect(presenter.getState().gutter.backgroundColor).toBe "rgba(0, 0, 255, 0)" + expect(presenter.getState().lineNumberGutter.backgroundColor).toBe "rgba(0, 0, 255, 0)" describe ".maxLineNumberDigits", -> it "is set to the number of digits used by the greatest line number", -> presenter = buildPresenter() expect(editor.getLastBufferRow()).toBe 12 - expect(presenter.getState().gutter.maxLineNumberDigits).toBe 2 + expect(presenter.getState().lineNumberGutter.maxLineNumberDigits).toBe 2 editor.setText("1\n2\n3") - expect(presenter.getState().gutter.maxLineNumberDigits).toBe 1 + expect(presenter.getState().lineNumberGutter.maxLineNumberDigits).toBe 1 describe ".lineNumbers", -> lineNumberStateForScreenRow = (presenter, screenRow) -> @@ -1878,7 +1877,7 @@ describe "TextEditorPresenter", -> else key = bufferRow - presenter.getState().gutter.lineNumbers[key] + presenter.getState().lineNumberGutter.lineNumbers[key] it "contains states for line numbers that are visible on screen, plus and minus the overdraw margin", -> editor.foldBufferRow(4) @@ -2170,28 +2169,28 @@ describe "TextEditorPresenter", -> presenter = buildPresenter() expect(editor.isLineNumberGutterVisible()).toBe true - expect(presenter.getState().gutter.visible).toBe true + expect(presenter.getState().lineNumberGutter.visible).toBe true expectStateUpdate presenter, -> editor.setMini(true) - expect(presenter.getState().gutter.visible).toBe false + expect(presenter.getState().lineNumberGutter.visible).toBe false expectStateUpdate presenter, -> editor.setMini(false) - expect(presenter.getState().gutter.visible).toBe true + expect(presenter.getState().lineNumberGutter.visible).toBe true expectStateUpdate presenter, -> editor.setLineNumberGutterVisible(false) - expect(presenter.getState().gutter.visible).toBe false + expect(presenter.getState().lineNumberGutter.visible).toBe false expectStateUpdate presenter, -> editor.setLineNumberGutterVisible(true) - expect(presenter.getState().gutter.visible).toBe true + expect(presenter.getState().lineNumberGutter.visible).toBe true expectStateUpdate presenter, -> atom.config.set('editor.showLineNumbers', false) - expect(presenter.getState().gutter.visible).toBe false + expect(presenter.getState().lineNumberGutter.visible).toBe false it "updates when the editor's grammar changes", -> presenter = buildPresenter() atom.config.set('editor.showLineNumbers', false, scopeSelector: '.source.js') - expect(presenter.getState().gutter.visible).toBe true + expect(presenter.getState().lineNumberGutter.visible).toBe true stateUpdated = false presenter.onDidUpdateState -> stateUpdated = true @@ -2199,7 +2198,7 @@ describe "TextEditorPresenter", -> runs -> expect(stateUpdated).toBe true - expect(presenter.getState().gutter.visible).toBe false + expect(presenter.getState().lineNumberGutter.visible).toBe false describe ".height", -> it "tracks the computed content height if ::autoHeight is true so the editor auto-expands vertically", -> diff --git a/src/gutter-component.coffee b/src/gutter-component.coffee index 072ac99a0..395dc6269 100644 --- a/src/gutter-component.coffee +++ b/src/gutter-component.coffee @@ -19,7 +19,7 @@ class GutterComponent @domNode.addEventListener 'mousedown', @onMouseDown updateSync: (state) -> - @newState = state.gutter + @newState = state.lineNumberGutter @oldState ?= {lineNumbers: {}} @appendDummyLineNumber() unless @dummyLineNumberNode? diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 4c8e567f0..974b29b75 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -70,7 +70,7 @@ class TextEditorComponent @scrollViewNode.classList.add('scroll-view') @domNode.appendChild(@scrollViewNode) - @mountGutterComponent() if @presenter.getState().gutter.visible + @mountGutterComponent() if @presenter.getState().lineNumberGutter.visible @hiddenInputComponent = new InputComponent @scrollViewNode.appendChild(@hiddenInputComponent.domNode) @@ -134,7 +134,7 @@ class TextEditorComponent else @domNode.style.height = '' - if @newState.gutter.visible + if @newState.lineNumberGutter.visible @mountGutterComponent() unless @gutterComponent? @gutterComponent.updateSync(@newState) else diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index edbf0d63f..50efe3de7 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -169,7 +169,7 @@ class TextEditorPresenter lines: {} highlights: {} overlays: {} - gutter: + lineNumberGutter: lineNumbers: {} @updateState() @@ -204,11 +204,11 @@ class TextEditorPresenter updateVerticalScrollState: -> @batch "shouldUpdateVerticalScrollState", -> @state.content.scrollHeight = @scrollHeight - @state.gutter.scrollHeight = @scrollHeight + @state.lineNumberGutter.scrollHeight = @scrollHeight @state.verticalScrollbar.scrollHeight = @scrollHeight @state.content.scrollTop = @scrollTop - @state.gutter.scrollTop = @scrollTop + @state.lineNumberGutter.scrollTop = @scrollTop @state.verticalScrollbar.scrollTop = @scrollTop updateHorizontalScrollState: -> @batch "shouldUpdateHorizontalScrollState", -> @@ -364,9 +364,9 @@ class TextEditorPresenter return updateLineNumberGutterState: -> @batch "shouldUpdateLineNumberGutterState", -> - @state.gutter.visible = not @model.isMini() and (@model.isLineNumberGutterVisible() ? true) and @showLineNumbers - @state.gutter.maxLineNumberDigits = @model.getLineCount().toString().length - @state.gutter.backgroundColor = if @gutterBackgroundColor isnt "rgba(0, 0, 0, 0)" + @state.lineNumberGutter.visible = not @model.isMini() and (@model.isLineNumberGutterVisible() ? true) and @showLineNumbers + @state.lineNumberGutter.maxLineNumberDigits = @model.getLineCount().toString().length + @state.lineNumberGutter.backgroundColor = if @gutterBackgroundColor isnt "rgba(0, 0, 0, 0)" @gutterBackgroundColor else @backgroundColor @@ -401,7 +401,7 @@ class TextEditorPresenter decorationClasses = @lineNumberDecorationClassesForRow(screenRow) foldable = @model.isFoldableAtScreenRow(screenRow) - @state.gutter.lineNumbers[id] = {screenRow, bufferRow, softWrapped, top, decorationClasses, foldable} + @state.lineNumberGutter.lineNumbers[id] = {screenRow, bufferRow, softWrapped, top, decorationClasses, foldable} visibleLineNumberIds[id] = true if @mouseWheelScreenRow? @@ -411,8 +411,8 @@ class TextEditorPresenter id += '-' + wrapCount if wrapCount > 0 visibleLineNumberIds[id] = true - for id of @state.gutter.lineNumbers - delete @state.gutter.lineNumbers[id] unless visibleLineNumberIds[id] + for id of @state.lineNumberGutter.lineNumbers + delete @state.lineNumberGutter.lineNumbers[id] unless visibleLineNumberIds[id] return From d03e9e16b9c8666ac38bac1319ffc7ed8705f864 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Tue, 17 Mar 2015 13:32:10 -0700 Subject: [PATCH 0808/1783] [Gutter] Make TextEditorPresenter aware of custom gutters (no decorations yet) --- src/text-editor-presenter.coffee | 37 +++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 50efe3de7..9784b38ba 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -89,7 +89,7 @@ class TextEditorPresenter @updateOverlaysState() if @shouldUpdateOverlaysState @updateLineNumberGutterState() if @shouldUpdateLineNumberGutterState @updateLineNumbersState() if @shouldUpdateLineNumbersState - + @updateCustomGutterState() if @shouldUpdateCustomGutterState @updating = false @state @@ -106,6 +106,7 @@ class TextEditorPresenter @updateDecorations() @updateLinesState() @updateLineNumberGutterState() + @updateCustomGutterState() @updateLineNumbersState() @disposables.add @model.onDidChangeGrammar(@didChangeGrammar.bind(this)) @disposables.add @model.onDidChangePlaceholderText(@updateContentState.bind(this)) @@ -116,15 +117,18 @@ class TextEditorPresenter @updateDecorations() @updateLinesState() @updateLineNumberGutterState() + @updateCustomGutterState() @updateLineNumbersState() @disposables.add @model.onDidChangeLineNumberGutterVisible => @updateLineNumberGutterState() + @updateCustomGutterState() @disposables.add @model.onDidAddDecoration(@didAddDecoration.bind(this)) @disposables.add @model.onDidAddCursor(@didAddCursor.bind(this)) @disposables.add @model.onDidChangeScrollTop(@setScrollTop.bind(this)) @disposables.add @model.onDidChangeScrollLeft(@setScrollLeft.bind(this)) @observeDecoration(decoration) for decoration in @model.getDecorations() @observeCursor(cursor) for cursor in @model.getCursors() + @disposables.add @model.onDidAddGutter(@didAddGutter.bind(this)) return observeConfig: -> @@ -152,11 +156,13 @@ class TextEditorPresenter @configDisposables.add atom.config.onDidChange 'editor.showLineNumbers', configParams, ({newValue}) => @showLineNumbers = newValue @updateLineNumberGutterState() + @updateCustomGutterState() didChangeGrammar: -> @observeConfig() @updateContentState() @updateLineNumberGutterState() + @updateCustomGutterState() buildState: -> @state = @@ -171,6 +177,9 @@ class TextEditorPresenter overlays: {} lineNumberGutter: lineNumbers: {} + gutters: + sortedDescriptions: [] + # TODO (jssln) decorations @updateState() updateState: -> @@ -191,6 +200,7 @@ class TextEditorPresenter @updateCursorsState() @updateOverlaysState() @updateLineNumberGutterState() + @updateCustomGutterState() @updateLineNumbersState() updateFocusedState: -> @batch "shouldUpdateFocusedState", -> @@ -371,6 +381,29 @@ class TextEditorPresenter else @backgroundColor + didAddGutter: (gutter) -> + gutterDisposables = new CompositeDisposable + gutterDisposables.add gutter.onDidChangeVisible => + @updateCustomGutterState() + gutterDisposables.add gutter.onDidDestroy => + @disposables.remove(gutterDisposables) + gutterDisposables.dispose() + @updateCustomGutterState() + @disposables.add(gutterDisposables) + @updateCustomGutterState() + + updateCustomGutterState: -> + @batch "shouldUpdateCustomGutterState", -> + @state.gutters.sortedDescriptions = [] + if @model.isMini() + return + for gutter in @model.getGutters() + isVisible = gutter.isVisible() + if gutter.name is 'line-number' + isVisible = isVisible && @showLineNumbers + if isVisible + @state.gutters.sortedDescriptions.push({name: gutter.name}) + updateLineNumbersState: -> @batch "shouldUpdateLineNumbersState", -> return unless @startRow? and @endRow? and @lineHeight? @@ -709,11 +742,13 @@ class TextEditorPresenter @backgroundColor = backgroundColor @updateContentState() @updateLineNumberGutterState() + @updateCustomGutterState() setGutterBackgroundColor: (gutterBackgroundColor) -> unless @gutterBackgroundColor is gutterBackgroundColor @gutterBackgroundColor = gutterBackgroundColor @updateLineNumberGutterState() + @updateCustomGutterState() setLineHeight: (lineHeight) -> unless @lineHeight is lineHeight From a96a790bda0a795b775d7d38768bc708d392abb3 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Wed, 18 Mar 2015 12:58:24 -0700 Subject: [PATCH 0809/1783] [Gutter] Remove unused param 'presenter' from GutterComponent constructor --- src/gutter-component.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gutter-component.coffee b/src/gutter-component.coffee index 395dc6269..61e7e74c7 100644 --- a/src/gutter-component.coffee +++ b/src/gutter-component.coffee @@ -6,7 +6,7 @@ module.exports = class GutterComponent dummyLineNumberNode: null - constructor: ({@presenter, @onMouseDown, @editor}) -> + constructor: ({@onMouseDown, @editor}) -> @lineNumberNodesById = {} @domNode = document.createElement('div') From b4ffa04e4c09ac90621432d9a289e1ec42a8bbd1 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Wed, 18 Mar 2015 12:38:43 -0700 Subject: [PATCH 0810/1783] [Gutter] Rename GutterComponent to LineNumberGutterComponent --- ...r-component.coffee => line-number-gutter-component.coffee} | 2 +- src/text-editor-component.coffee | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename src/{gutter-component.coffee => line-number-gutter-component.coffee} (99%) diff --git a/src/gutter-component.coffee b/src/line-number-gutter-component.coffee similarity index 99% rename from src/gutter-component.coffee rename to src/line-number-gutter-component.coffee index 61e7e74c7..a69bb81bd 100644 --- a/src/gutter-component.coffee +++ b/src/line-number-gutter-component.coffee @@ -3,7 +3,7 @@ _ = require 'underscore-plus' WrapperDiv = document.createElement('div') module.exports = -class GutterComponent +class LineNumberGutterComponent dummyLineNumberNode: null constructor: ({@onMouseDown, @editor}) -> diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 974b29b75..db307dc5a 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -6,7 +6,7 @@ grim = require 'grim' ipc = require 'ipc' TextEditorPresenter = require './text-editor-presenter' -GutterComponent = require './gutter-component' +LineNumberGutterComponent = require './line-number-gutter-component' InputComponent = require './input-component' LinesComponent = require './lines-component' ScrollbarComponent = require './scrollbar-component' @@ -162,7 +162,7 @@ class TextEditorComponent @overlayManager?.measureOverlays() mountGutterComponent: -> - @gutterComponent = new GutterComponent({@editor, onMouseDown: @onGutterMouseDown}) + @gutterComponent = new LineNumberGutterComponent({@editor, onMouseDown: @onGutterMouseDown}) @domNode.insertBefore(@gutterComponent.domNode, @domNode.firstChild) becameVisible: -> From 28f70c912e2ee658b975576954034f57b0084635 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Thu, 19 Mar 2015 11:51:21 -0700 Subject: [PATCH 0811/1783] [Gutter] Add ::getName to LineNumberGutterComponent --- src/line-number-gutter-component.coffee | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/line-number-gutter-component.coffee b/src/line-number-gutter-component.coffee index a69bb81bd..3cd5cdf06 100644 --- a/src/line-number-gutter-component.coffee +++ b/src/line-number-gutter-component.coffee @@ -6,7 +6,7 @@ module.exports = class LineNumberGutterComponent dummyLineNumberNode: null - constructor: ({@onMouseDown, @editor}) -> + constructor: ({@onMouseDown, @editor, @name}) -> @lineNumberNodesById = {} @domNode = document.createElement('div') @@ -18,6 +18,9 @@ class LineNumberGutterComponent @domNode.addEventListener 'click', @onClick @domNode.addEventListener 'mousedown', @onMouseDown + getName: -> + @name + updateSync: (state) -> @newState = state.lineNumberGutter @oldState ?= {lineNumbers: {}} From 754b38f41017bf8d76323651b92f855d69f171e1 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Wed, 1 Apr 2015 11:11:40 -0700 Subject: [PATCH 0812/1783] [Gutter] Add ::getDomNode to LineNumberGutterComponent --- src/line-number-gutter-component.coffee | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/line-number-gutter-component.coffee b/src/line-number-gutter-component.coffee index 3cd5cdf06..87d33619c 100644 --- a/src/line-number-gutter-component.coffee +++ b/src/line-number-gutter-component.coffee @@ -18,6 +18,9 @@ class LineNumberGutterComponent @domNode.addEventListener 'click', @onClick @domNode.addEventListener 'mousedown', @onMouseDown + getDomNode: -> + @domNode + getName: -> @name @@ -47,6 +50,10 @@ class LineNumberGutterComponent @updateLineNumbers() + ### + Section: Private Methods + ### + # This dummy line number element holds the gutter to the appropriate width, # since the real line numbers are absolutely positioned for performance reasons. appendDummyLineNumber: -> From ce1d64f55019b33dab05afe5cb78f25c8e1261ba Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Tue, 17 Mar 2015 13:52:52 -0700 Subject: [PATCH 0813/1783] [Gutter] Create GutterContainerComponent --- src/gutter-container-component.coffee | 82 +++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 src/gutter-container-component.coffee diff --git a/src/gutter-container-component.coffee b/src/gutter-container-component.coffee new file mode 100644 index 000000000..886f88230 --- /dev/null +++ b/src/gutter-container-component.coffee @@ -0,0 +1,82 @@ +LineNumberGutterComponent = require './line-number-gutter-component' + +# The GutterContainerComponent manages the GutterComponents of a particular +# TextEditorComponent. + +module.exports = +class GutterContainerComponent + + constructor: ({@onLineNumberGutterMouseDown, @editor}) -> + @gutterComponents = [] + @gutterComponentsByGutterName = {} + @lineNumberGutterComponent = null + + @domNode = document.createElement('div') + @domNode.classList.add('gutter-container') + + getDomNode: -> + @domNode + + getLineNumberGutterComponent: -> + @lineNumberGutterComponent + + updateSync: (state) -> + # The GutterContainerComponent expects the gutters to be sorted in the order + # they should appear. + newState = state.gutters.sortedDescriptions + + newGutterComponents = [] + newGutterComponentsByGutterName = {} + for gutter in newState + gutterComponent = @gutterComponentsByGutterName[gutter.name] + if !gutterComponent + if gutter.name is 'line-number' + gutterComponent = new LineNumberGutterComponent({onMouseDown: @onLineNumberGutterMouseDown, @editor, name: gutter.name}) + @lineNumberGutterComponent = gutterComponent + else + # TODO (jessicalin) Implement non-line-number gutters. + continue + newGutterComponents.push(gutterComponent) + newGutterComponentsByGutterName[gutter.name] = gutterComponent + + @updateChildGutters(state, newGutterComponents, newGutterComponentsByGutterName) + + @gutterComponents = newGutterComponents + @gutterComponentsByGutterName = newGutterComponentsByGutterName + + ### + Section: Private Methods + ### + + updateChildGutters: (state, newGutterComponents, newGutterComponentsByGutterName) -> + # First, insert new gutters into the DOM. + indexInOldGutters = 0 + oldGuttersLength = @gutterComponents.length + for gutterComponent in newGutterComponents + gutterComponent.updateSync(state) + if @gutterComponentsByGutterName[gutterComponent.getName()] + # If the gutter existed previously, we first try to move the cursor to + # the point at which it occurs in the previous gutters. + matchingGutterFound = false + while indexInOldGutters < oldGuttersLength + existingGutterComponent = @gutterComponents[indexInOldGutters] + indexInOldGutters++ + if existingGutterComponent.getName() == gutterComponent.getName() + matchingGutterFound = true + break + if !matchingGutterFound + # If we've reached this point, the gutter previously existed, but its + # position has moved. Remove it from the DOM and re-insert it. + gutterComponent.getDomNode().remove() + @domNode.appendChild(gutterComponent.getDomNode()) + + else + if indexInOldGutters == oldGuttersLength + @domNode.appendChild(gutterComponent.getDomNode()) + else + @domNode.insertBefore(gutterComponent.getDomNode(), @domNode.children[indexInOldGutters]) + + # Remove any gutters that were not present in the new gutters state. + for gutterComponent in @gutterComponents + if !newGutterComponentsByGutterName[gutterComponent.getName()] + gutterComponent.getDomNode().remove() From 8d6745d8a92a8a0d822b7fbf8260217cc1060591 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Wed, 18 Mar 2015 14:25:11 -0700 Subject: [PATCH 0814/1783] [Gutter] Replace GutterComponent with GutterContainerComponent in TextEditorComponent --- spec/text-editor-component-spec.coffee | 2 +- src/text-editor-component.coffee | 29 +++++++++++++------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 80d22ddcd..793b154cd 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -579,7 +579,7 @@ describe "TextEditorComponent", -> expect(lineNumbersNode.style.backgroundColor).toBe 'rgb(255, 0, 0)' it "hides or shows the gutter based on the '::isLineNumberGutterVisible' property on the model and the global 'editor.showLineNumbers' config setting", -> - expect(component.gutterComponent?).toBe true + expect(component.gutterContainerComponent.getLineNumberGutterComponent()?).toBe true editor.setLineNumberGutterVisible(false) nextAnimationFrame() diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index db307dc5a..89f541775 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -6,7 +6,7 @@ grim = require 'grim' ipc = require 'ipc' TextEditorPresenter = require './text-editor-presenter' -LineNumberGutterComponent = require './line-number-gutter-component' +GutterContainerComponent = require './gutter-container-component' InputComponent = require './input-component' LinesComponent = require './lines-component' ScrollbarComponent = require './scrollbar-component' @@ -70,7 +70,7 @@ class TextEditorComponent @scrollViewNode.classList.add('scroll-view') @domNode.appendChild(@scrollViewNode) - @mountGutterComponent() if @presenter.getState().lineNumberGutter.visible + @mountGutterContainerComponent() if @presenter.getState().gutters.sortedDescriptions.length @hiddenInputComponent = new InputComponent @scrollViewNode.appendChild(@hiddenInputComponent.domNode) @@ -134,12 +134,12 @@ class TextEditorComponent else @domNode.style.height = '' - if @newState.lineNumberGutter.visible - @mountGutterComponent() unless @gutterComponent? - @gutterComponent.updateSync(@newState) + if @newState.gutters.sortedDescriptions.length + @mountGutterContainerComponent() unless @gutterContainerComponent? + @gutterContainerComponent.updateSync(@newState) else - @gutterComponent?.domNode?.remove() - @gutterComponent = null + @gutterContainerComponent?.domNode?.remove() + @gutterContainerComponent = null @hiddenInputComponent.updateSync(@newState) @linesComponent.updateSync(@newState) @@ -161,9 +161,9 @@ class TextEditorComponent @linesComponent.measureCharactersInNewLines() if @isVisible() and not @newState.content.scrollingVertically @overlayManager?.measureOverlays() - mountGutterComponent: -> - @gutterComponent = new LineNumberGutterComponent({@editor, onMouseDown: @onGutterMouseDown}) - @domNode.insertBefore(@gutterComponent.domNode, @domNode.firstChild) + mountGutterContainerComponent: -> + @gutterContainerComponent = new GutterContainerComponent({@editor, @onLineNumberGutterMouseDown}) + @domNode.insertBefore(@gutterContainerComponent.domNode, @domNode.firstChild) becameVisible: -> @updatesPaused = true @@ -401,7 +401,7 @@ class TextEditorComponent @handleDragUntilMouseUp event, (screenPosition) => @editor.selectToScreenPosition(screenPosition) - onGutterMouseDown: (event) => + onLineNumberGutterMouseDown: (event) => return unless event.button is 0 # only handle the left mouse button {shiftKey, metaKey, ctrlKey} = event @@ -644,8 +644,9 @@ class TextEditorComponent @presenter.setBackgroundColor(backgroundColor) - if @gutterComponent? - gutterBackgroundColor = getComputedStyle(@gutterComponent.domNode).backgroundColor + lineNumberGutter = @gutterContainerComponent?.getLineNumberGutterComponent() + if lineNumberGutter + gutterBackgroundColor = getComputedStyle(lineNumberGutter.domNode).backgroundColor @presenter.setGutterBackgroundColor(gutterBackgroundColor) measureLineHeightAndDefaultCharWidth: -> @@ -722,7 +723,7 @@ class TextEditorComponent lineNodeForScreenRow: (screenRow) -> @linesComponent.lineNodeForScreenRow(screenRow) - lineNumberNodeForScreenRow: (screenRow) -> @gutterComponent.lineNumberNodeForScreenRow(screenRow) + lineNumberNodeForScreenRow: (screenRow) -> @gutterContainerComponent.getLineNumberGutterComponent().lineNumberNodeForScreenRow(screenRow) screenRowForNode: (node) -> while node? From d734ffe545622a87928421744f94e15a46216df3 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Thu, 19 Mar 2015 15:59:20 -0700 Subject: [PATCH 0815/1783] [Gutter] Make TextEditorPresenter recognize Decorations for custom gutters --- spec/text-editor-presenter-spec.coffee | 107 +++++++++++++------- src/text-editor-presenter.coffee | 135 ++++++++++++++++++++++--- 2 files changed, 190 insertions(+), 52 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 28cd1890f..53066e26c 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -2164,42 +2164,6 @@ describe "TextEditorPresenter", -> editor.undo() expect(lineNumberStateForScreenRow(presenter, 11).foldable).toBe false - describe ".visible", -> - it "is true iff the editor isn't mini, ::isLineNumberGutterVisible is true on the editor, and 'editor.showLineNumbers' is enabled in config", -> - presenter = buildPresenter() - - expect(editor.isLineNumberGutterVisible()).toBe true - expect(presenter.getState().lineNumberGutter.visible).toBe true - - expectStateUpdate presenter, -> editor.setMini(true) - expect(presenter.getState().lineNumberGutter.visible).toBe false - - expectStateUpdate presenter, -> editor.setMini(false) - expect(presenter.getState().lineNumberGutter.visible).toBe true - - expectStateUpdate presenter, -> editor.setLineNumberGutterVisible(false) - expect(presenter.getState().lineNumberGutter.visible).toBe false - - expectStateUpdate presenter, -> editor.setLineNumberGutterVisible(true) - expect(presenter.getState().lineNumberGutter.visible).toBe true - - expectStateUpdate presenter, -> atom.config.set('editor.showLineNumbers', false) - expect(presenter.getState().lineNumberGutter.visible).toBe false - - it "updates when the editor's grammar changes", -> - presenter = buildPresenter() - - atom.config.set('editor.showLineNumbers', false, scopeSelector: '.source.js') - expect(presenter.getState().lineNumberGutter.visible).toBe true - stateUpdated = false - presenter.onDidUpdateState -> stateUpdated = true - - waitsForPromise -> atom.packages.activatePackage('language-javascript') - - runs -> - expect(stateUpdated).toBe true - expect(presenter.getState().lineNumberGutter.visible).toBe false - describe ".height", -> it "tracks the computed content height if ::autoHeight is true so the editor auto-expands vertically", -> presenter = buildPresenter(explicitHeight: null, autoHeight: true) @@ -2226,6 +2190,77 @@ describe "TextEditorPresenter", -> expectStateUpdate presenter, -> presenter.setFocused(false) expect(presenter.getState().focused).toBe false + describe ".gutters", -> + describe ".sortedDescriptions", -> + gutterDescriptionWithName = (presenter, name) -> + for gutterDesc in presenter.getState().gutters.sortedDescriptions + return gutterDesc if gutterDesc.name is name + undefined + + describe "the line-number gutter", -> + it "is present iff the editor isn't mini, ::isLineNumberGutterVisible is true on the editor, and 'editor.showLineNumbers' is enabled in config", -> + presenter = buildPresenter() + + expect(editor.isLineNumberGutterVisible()).toBe true + expect(gutterDescriptionWithName(presenter, 'line-number')).toBeDefined() + + expectStateUpdate presenter, -> editor.setMini(true) + expect(gutterDescriptionWithName(presenter, 'line-number')).toBeUndefined() + + expectStateUpdate presenter, -> editor.setMini(false) + expect(gutterDescriptionWithName(presenter, 'line-number')).toBeDefined() + + expectStateUpdate presenter, -> editor.setLineNumberGutterVisible(false) + expect(gutterDescriptionWithName(presenter, 'line-number')).toBeUndefined() + + expectStateUpdate presenter, -> editor.setLineNumberGutterVisible(true) + expect(gutterDescriptionWithName(presenter, 'line-number')).toBeDefined() + + expectStateUpdate presenter, -> atom.config.set('editor.showLineNumbers', false) + expect(gutterDescriptionWithName(presenter, 'line-number')).toBeUndefined() + + it "gets updated when the editor's grammar changes", -> + presenter = buildPresenter() + + atom.config.set('editor.showLineNumbers', false, scopeSelector: '.source.js') + expect(gutterDescriptionWithName(presenter, 'line-number')).toBeDefined() + stateUpdated = false + presenter.onDidUpdateState -> stateUpdated = true + + waitsForPromise -> atom.packages.activatePackage('language-javascript') + + runs -> + expect(stateUpdated).toBe true + expect(gutterDescriptionWithName(presenter, 'line-number')).toBeUndefined() + + it "updates when gutters are added to the editor model, and keeps the gutters sorted by priority", -> + presenter = buildPresenter() + editor.addGutter({name: 'test-gutter-1', priority: -100, visible: true}) + editor.addGutter({name: 'test-gutter-2', priority: 100, visible: false}) + expectedState = [ + {name: 'test-gutter-1'}, + {name: 'line-number'}, + ] + expect(presenter.getState().gutters.sortedDescriptions).toEqual expectedState + + it "updates when the visibility of a gutter changes", -> + presenter = buildPresenter() + gutter = editor.addGutter({name: 'test-gutter', visible: true}) + expect(gutterDescriptionWithName(presenter, 'test-gutter')).toBeDefined() + gutter.hide() + expect(gutterDescriptionWithName(presenter, 'test-gutter')).toBeUndefined() + + it "updates when a gutter is removed", -> + presenter = buildPresenter() + gutter = editor.addGutter({name: 'test-gutter', visible: true}) + expect(gutterDescriptionWithName(presenter, 'test-gutter')).toBeDefined() + gutter.destroy() + expect(gutterDescriptionWithName(presenter, 'test-gutter')).toBeUndefined() + + describe ".customDecorations", -> + # TODO (jssln) + null + # disabled until we fix an issue with display buffer markers not updating when # they are moved on screen but not in the buffer xdescribe "when the model and view measurements are mutated randomly", -> diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 9784b38ba..085244f51 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -1,6 +1,7 @@ {CompositeDisposable, Emitter} = require 'event-kit' {Point, Range} = require 'text-buffer' _ = require 'underscore-plus' +Decoration = require './decoration' module.exports = class TextEditorPresenter @@ -90,6 +91,7 @@ class TextEditorPresenter @updateLineNumberGutterState() if @shouldUpdateLineNumberGutterState @updateLineNumbersState() if @shouldUpdateLineNumbersState @updateCustomGutterState() if @shouldUpdateCustomGutterState + @updateCustomGutterDecorationState() if @shouldUpdateCustomGutterDecorationState @updating = false @state @@ -106,8 +108,9 @@ class TextEditorPresenter @updateDecorations() @updateLinesState() @updateLineNumberGutterState() - @updateCustomGutterState() @updateLineNumbersState() + @updateCustomGutterState() + @updateCustomGutterDecorationState() @disposables.add @model.onDidChangeGrammar(@didChangeGrammar.bind(this)) @disposables.add @model.onDidChangePlaceholderText(@updateContentState.bind(this)) @disposables.add @model.onDidChangeMini => @@ -117,8 +120,9 @@ class TextEditorPresenter @updateDecorations() @updateLinesState() @updateLineNumberGutterState() - @updateCustomGutterState() @updateLineNumbersState() + @updateCustomGutterState() + @updateCustomGutterDecorationState() @disposables.add @model.onDidChangeLineNumberGutterVisible => @updateLineNumberGutterState() @updateCustomGutterState() @@ -179,7 +183,7 @@ class TextEditorPresenter lineNumbers: {} gutters: sortedDescriptions: [] - # TODO (jssln) decorations + customDecorations: {} @updateState() updateState: -> @@ -200,8 +204,9 @@ class TextEditorPresenter @updateCursorsState() @updateOverlaysState() @updateLineNumberGutterState() - @updateCustomGutterState() @updateLineNumbersState() + @updateCustomGutterState() + @updateCustomGutterDecorationState() updateFocusedState: -> @batch "shouldUpdateFocusedState", -> @state.focused = @focused @@ -374,9 +379,11 @@ class TextEditorPresenter return updateLineNumberGutterState: -> @batch "shouldUpdateLineNumberGutterState", -> - @state.lineNumberGutter.visible = not @model.isMini() and (@model.isLineNumberGutterVisible() ? true) and @showLineNumbers @state.lineNumberGutter.maxLineNumberDigits = @model.getLineCount().toString().length - @state.lineNumberGutter.backgroundColor = if @gutterBackgroundColor isnt "rgba(0, 0, 0, 0)" + @state.lineNumberGutter.backgroundColor = @getGutterBackgroundColor() + + getGutterBackgroundColor: -> + if @gutterBackgroundColor isnt "rgba(0, 0, 0, 0)" @gutterBackgroundColor else @backgroundColor @@ -391,9 +398,13 @@ class TextEditorPresenter @updateCustomGutterState() @disposables.add(gutterDisposables) @updateCustomGutterState() + @updateCustomGutterDecorationState() updateCustomGutterState: -> @batch "shouldUpdateCustomGutterState", -> + # For now, just match the background color of the line-number gutter. + # TODO: Allow gutters to have different background colors. (?) + @state.gutters.backgroundColor = @getGutterBackgroundColor() @state.gutters.sortedDescriptions = [] if @model.isMini() return @@ -404,6 +415,41 @@ class TextEditorPresenter if isVisible @state.gutters.sortedDescriptions.push({name: gutter.name}) + # Updates the decoration state for the gutter with the given gutterName. + # @state.gutters.customDecorations is an {Object}, with the form: + # * gutterName : { + # decoration.id : { + # top: # of pixels from top + # height: # of pixels height of this decoration + # item (optional): HTMLElement or space-pen View + # class (optional): {String} class + # } + # } + updateCustomGutterDecorationState: () -> + @batch 'shouldUpdateCustomGutterDecorationState', => + return unless @startRow? and @endRow? and @lineHeight? + + for gutter in @model.getGutters() + gutterName = gutter.name + @state.gutters.customDecorations[gutterName] ?= {} + gutterState = @state.gutters.customDecorations[gutterName] + visibleDecorationIds = {} + + relevantDecorations = @customGutterDecorationsInRange(gutterName, @startRow, @endRow - 1) + return if !relevantDecorations + + relevantDecorations.forEach (decoration) => + visibleDecorationIds[decoration.id] = true + decorationRange = decoration.getMarker().getScreenRange() + gutterState[decoration.id] = + top: @lineHeight * decorationRange.start.row + height: @lineHeight * decorationRange.getRowCount() + item: decoration.getProperties().item + class: decoration.getProperties().class + + for decorationId of gutterState + delete gutterState[decorationId] unless visibleDecorationIds[decorationId] + updateLineNumbersState: -> @batch "shouldUpdateLineNumbersState", -> return unless @startRow? and @endRow? and @lineHeight? @@ -597,6 +643,19 @@ class TextEditorPresenter decorationClasses.push(decoration.getProperties().class) decorationClasses + # TODO (jssln) This needs tests. + # Returns a {Set} of {Decoration}s on the given custom gutter from startRow to endRow (inclusive). + customGutterDecorationsInRange: (gutterName, startRow, endRow) -> + return null if @model.isMini() or gutterName is 'line-number' + + decorations = new Set + return decorations if !@customGutterDecorationsByGutterNameAndScreenRow[gutterName] + + for bufferRow in @model.bufferRowsForScreenRows(@startRow, @endRow - 1) + for id, decoration of @customGutterDecorationsByGutterNameAndScreenRow[gutterName][bufferRow] + decorations.add(decoration) + decorations + getCursorBlinkPeriod: -> @cursorBlinkPeriod getCursorBlinkResumeDelay: -> @cursorBlinkResumeDelay @@ -626,6 +685,7 @@ class TextEditorPresenter @updateLinesState() @updateCursorsState() @updateLineNumbersState() + @updateCustomGutterDecorationState() @updateOverlaysState() didStartScrolling: -> @@ -642,6 +702,7 @@ class TextEditorPresenter @mouseWheelScreenRow = null @updateLinesState() @updateLineNumbersState() + @updateCustomGutterDecorationState() else @emitDidUpdateState() @@ -694,6 +755,7 @@ class TextEditorPresenter @updateLinesState() @updateCursorsState() @updateLineNumbersState() + @updateCustomGutterDecorationState() updateHeight: -> height = @explicitHeight ? @contentHeight @@ -768,6 +830,7 @@ class TextEditorPresenter @updateLinesState() @updateCursorsState() @updateLineNumbersState() + @updateCustomGutterDecorationState() @updateOverlaysState() setMouseWheelScreenRow: (mouseWheelScreenRow) -> @@ -879,8 +942,8 @@ class TextEditorPresenter decorationDisposables = new CompositeDisposable decorationDisposables.add decoration.getMarker().onDidChange(@decorationMarkerDidChange.bind(this, decoration)) if decoration.isType('highlight') - decorationDisposables.add decoration.onDidChangeProperties(@updateHighlightState.bind(this, decoration)) decorationDisposables.add decoration.onDidFlash(@highlightDidFlash.bind(this, decoration)) + decorationDisposables.add decoration.onDidChangeProperties(@decorationPropertiesDidChange.bind(this, decoration)) decorationDisposables.add decoration.onDidDestroy => @disposables.remove(decorationDisposables) decorationDisposables.dispose() @@ -888,7 +951,7 @@ class TextEditorPresenter @disposables.add(decorationDisposables) decorationMarkerDidChange: (decoration, change) -> - if decoration.isType('line') or decoration.isType('line-number') + if decoration.isType('line') or decoration.isType('gutter') return if change.textChanged intersectsVisibleRowRange = false @@ -905,7 +968,10 @@ class TextEditorPresenter if intersectsVisibleRowRange @updateLinesState() if decoration.isType('line') - @updateLineNumbersState() if decoration.isType('line-number') + if decoration.isType('line-number') + @updateLineNumbersState() + else if decoration.isType('gutter') + @updateCustomGutterDecorationState() if decoration.isType('highlight') return if change.textChanged @@ -915,11 +981,34 @@ class TextEditorPresenter if decoration.isType('overlay') @updateOverlaysState() + decorationPropertiesDidChange: (decoration, event) -> + {oldProperties} = event + if decoration.isType('line') or decoration.isType('gutter') + @removeDecorationInfoFromLineDecorationCaches( + decoration.id, + oldProperties, + decoration.getMarker().getScreenRange()) + @addToLineDecorationCaches(decoration, decoration.getMarker().getScreenRange()) + if decoration.isType('line') or Decoration.isType(oldProperties, 'line') + @updateLinesState() + if decoration.isType('line-number') or Decoration.isType(oldProperties, 'line-number') + @updateLineNumbersState() + if (decoration.isType('gutter') and !decoration.isType('line-number')) or + (Decoration.isType(oldProperties, 'gutter') and !Decoration.isType(oldProperties, 'line-number')) + @updateCustomGutterDecorationState() + else if decoration.isType('overlay') + @updateOverlaysState() + else if decoration.isType('highlight') + @updateHighlightState(decoration, event) + didDestroyDecoration: (decoration) -> - if decoration.isType('line') or decoration.isType('line-number') + if decoration.isType('line') or decoration.isType('gutter') @removeFromLineDecorationCaches(decoration, decoration.getMarker().getScreenRange()) @updateLinesState() if decoration.isType('line') - @updateLineNumbersState() if decoration.isType('line-number') + if decoration.isType('line-number') + @updateLineNumbersState() + else if decoration.isType('gutter') + @updateCustomGutterDecorationState(decoration.getProperties().gutterName) if decoration.isType('highlight') @updateHighlightState(decoration) if decoration.isType('overlay') @@ -936,10 +1025,13 @@ class TextEditorPresenter didAddDecoration: (decoration) -> @observeDecoration(decoration) - if decoration.isType('line') or decoration.isType('line-number') + if decoration.isType('line') or decoration.isType('gutter') @addToLineDecorationCaches(decoration, decoration.getMarker().getScreenRange()) @updateLinesState() if decoration.isType('line') - @updateLineNumbersState() if decoration.isType('line-number') + if decoration.isType('line-number') + @updateLineNumbersState() + else if decoration.isType('gutter') + @updateCustomGutterDecorationState() else if decoration.isType('highlight') @updateHighlightState(decoration) else if decoration.isType('overlay') @@ -948,6 +1040,7 @@ class TextEditorPresenter updateDecorations: -> @batch "shouldUpdateDecorations", -> @lineDecorationsByScreenRow = {} @lineNumberDecorationsByScreenRow = {} + @customGutterDecorationsByGutterNameAndScreenRow = {} @highlightDecorationsById = {} visibleHighlights = {} @@ -956,7 +1049,7 @@ class TextEditorPresenter for markerId, decorations of @model.decorationsForScreenRowRange(@startRow, @endRow - 1) range = @model.getMarker(markerId).getScreenRange() for decoration in decorations - if decoration.isType('line') or decoration.isType('line-number') + if decoration.isType('line') or decoration.isType('gutter') @addToLineDecorationCaches(decoration, range) else if decoration.isType('highlight') visibleHighlights[decoration.id] = @updateHighlightState(decoration) @@ -968,9 +1061,14 @@ class TextEditorPresenter return removeFromLineDecorationCaches: (decoration, range) -> + @removeDecorationInfoFromLineDecorationCaches(decoration.id, decoration.getProperties(), range) + + removeDecorationInfoFromLineDecorationCaches: (decorationId, decorationProperties, range) -> + gutterName = decorationProperties.gutterName for row in [range.start.row..range.end.row] by 1 - delete @lineDecorationsByScreenRow[row]?[decoration.id] - delete @lineNumberDecorationsByScreenRow[row]?[decoration.id] + delete @lineDecorationsByScreenRow[row]?[decorationId] + delete @lineNumberDecorationsByScreenRow[row]?[decorationId] + delete @customGutterDecorationsByGutterNameAndScreenRow[gutterName]?[row]?[decorationId] if gutterName return addToLineDecorationCaches: (decoration, range) -> @@ -996,6 +1094,11 @@ class TextEditorPresenter if decoration.isType('line-number') @lineNumberDecorationsByScreenRow[row] ?= {} @lineNumberDecorationsByScreenRow[row][decoration.id] = decoration + else if decoration.isType('gutter') + gutterName = decoration.getProperties().gutterName + @customGutterDecorationsByGutterNameAndScreenRow[gutterName] ?= {} + @customGutterDecorationsByGutterNameAndScreenRow[gutterName][row] ?= {} + @customGutterDecorationsByGutterNameAndScreenRow[gutterName][row][decoration.id] = decoration return From 7f1b0588f9d53eafa344ddb8ee04fd4a2f34c6c2 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Thu, 19 Mar 2015 15:46:52 -0700 Subject: [PATCH 0816/1783] [Gutter] Create CustomGutterComponent --- src/custom-gutter-component.coffee | 118 +++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 src/custom-gutter-component.coffee diff --git a/src/custom-gutter-component.coffee b/src/custom-gutter-component.coffee new file mode 100644 index 000000000..78abf92ec --- /dev/null +++ b/src/custom-gutter-component.coffee @@ -0,0 +1,118 @@ +# This class represents a gutter other than the 'line-numbers' gutter. +# The contents of this gutter may be specified by Decorations. + +# TODO (jssln) Remove these (testing-only). +TEMP_MIN_WIDTH = 25 +TEMP_DECOR_WIDTH = '50px' +TEMP_DECOR_BACKGROUND = 'white' + +module.exports = +class CustomGutterComponent + + constructor: ({@name}) -> + @decorationNodesById = {} + @decorationItemsById = {} + + @domNode = document.createElement('div') + @domNode.classList.add('gutter') + @domNode.setAttribute('gutter-name', @name) + @decorationsNode = document.createElement('div') + @decorationsNode.classList.add('custom-decorations') + @domNode.appendChild(@decorationsNode) + + @domNode.style['width'] = '' + TEMP_MIN_WIDTH + 'px' + + getDomNode: -> + @domNode + + getName: -> + @name + + updateSync: (state) -> + gutterProps = state.lineNumberGutter + decorationState = state.gutters.customDecorations[@getName()] + @oldState ?= {} + + # TODO (jessicalin) Factor this out (also in LineNumberGutterComponent). + # Also, set backgroundColor? + if gutterProps.scrollHeight isnt @oldState.scrollHeight + @decorationsNode.style.height = gutterProps.scrollHeight + 'px' + @oldState.scrollHeight = gutterProps.scrollHeight + + if gutterProps.scrollTop isnt @oldState.scrollTop + @decorationsNode.style['-webkit-transform'] = "translate3d(0px, #{-gutterProps.scrollTop}px, 0px)" + @oldState.scrollTop = gutterProps.scrollTop + + return if !decorationState + + updatedDecorationIds = new Set + for decorationId, decorationInfo of decorationState + updatedDecorationIds.add(decorationId) + existingDecoration = @decorationNodesById[decorationId] + if existingDecoration + @updateDecorationHTML(existingDecoration, decorationId, decorationInfo) + else + newNode = @buildDecorationHTML(decorationId, decorationInfo) + @decorationNodesById[decorationId] = newNode + @decorationsNode.appendChild(newNode) + + for decorationId, decorationNode of @decorationNodesById + if !updatedDecorationIds.has(decorationId) + decorationNode.remove() + delete @decorationNodesById[decorationId] + delete @decorationItemsById[decorationId] + + ### + Section: Private Methods + ### + + # Builds and returns an HTMLElement to represent the specified decoration. + buildDecorationHTML: (decorationId, decorationInfo) -> + newNode = document.createElement('div') + newNode.classList.add('decoration') + newNode.style.top = decorationInfo.top + 'px' + newNode.style.height = decorationInfo.height + 'px' + newNode.style.position = 'absolute' + newNode.style['background-color'] = TEMP_DECOR_BACKGROUND + newNode.style.width = TEMP_DECOR_WIDTH + if decorationInfo.class + newNode.classList.add(decorationInfo.class) + @setDecorationItem(decorationInfo.item, decorationInfo.height, decorationId, newNode) + newNode + + # Updates the existing HTMLNode with the new decoration info. Attempts to + # minimize changes to the DOM. + updateDecorationHTML: (existingNode, decorationId, newDecorationInfo) -> + if existingNode.style.top isnt newDecorationInfo.top + 'px' + existingNode.style.top = newDecorationInfo.top + 'px' + + if existingNode.style.height isnt newDecorationInfo.height + 'px' + existingNode.style.height = newDecorationInfo.height + 'px' + + if newDecorationInfo.class and !existingNode.classList.contains(newDecorationInfo.class) + existingNode.className = 'decoration' + existingNode.classList.add(newDecorationInfo.class) + else if !newDecorationInfo.class + existingNode.className = 'decoration' + + @setDecorationItem(newDecorationInfo.item, newDecorationInfo.height, decorationId, existingNode) + + # Sets the decorationItem on the decorationNode. + # If `decorationItem` is undefined, the decorationNode's child item will be cleared. + setDecorationItem: (newItem, decorationHeight, decorationId, decorationNode) -> + if newItem isnt @decorationItemsById[decorationId] + while decorationNode.firstChild + decorationNode.removeChild(decorationNode.firstChild) + delete @decorationItemsById[decorationId] + + if newItem + # `item` should be either an HTMLElement or a space-pen View. + newItemNode = null + if newItem instanceof HTMLElement + newItemNode = newItem + else + newItemNode = newItem.element + + newItemNode.style.height = decorationHeight + 'px' + decorationNode.appendChild(newItemNode) + @decorationItemsById[decorationId] = newItem From e2e737369aab2c38fd870a2da1de47e3ff0ebdc8 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Mon, 30 Mar 2015 15:28:41 -0700 Subject: [PATCH 0817/1783] [Gutter] Factor out method to set common gutter component properties --- src/custom-gutter-component.coffee | 12 +++--------- src/gutter-component-helpers.coffee | 16 ++++++++++++++++ src/line-number-gutter-component.coffee | 13 ++----------- 3 files changed, 21 insertions(+), 20 deletions(-) create mode 100644 src/gutter-component-helpers.coffee diff --git a/src/custom-gutter-component.coffee b/src/custom-gutter-component.coffee index 78abf92ec..3ffc2ec73 100644 --- a/src/custom-gutter-component.coffee +++ b/src/custom-gutter-component.coffee @@ -1,3 +1,5 @@ +{setDimensionsAndBackground} = require './gutter-component-helpers' + # This class represents a gutter other than the 'line-numbers' gutter. # The contents of this gutter may be specified by Decorations. @@ -33,15 +35,7 @@ class CustomGutterComponent decorationState = state.gutters.customDecorations[@getName()] @oldState ?= {} - # TODO (jessicalin) Factor this out (also in LineNumberGutterComponent). - # Also, set backgroundColor? - if gutterProps.scrollHeight isnt @oldState.scrollHeight - @decorationsNode.style.height = gutterProps.scrollHeight + 'px' - @oldState.scrollHeight = gutterProps.scrollHeight - - if gutterProps.scrollTop isnt @oldState.scrollTop - @decorationsNode.style['-webkit-transform'] = "translate3d(0px, #{-gutterProps.scrollTop}px, 0px)" - @oldState.scrollTop = gutterProps.scrollTop + setDimensionsAndBackground(@oldState, gutterProps, @decorationsNode) return if !decorationState diff --git a/src/gutter-component-helpers.coffee b/src/gutter-component-helpers.coffee new file mode 100644 index 000000000..ba7cdb613 --- /dev/null +++ b/src/gutter-component-helpers.coffee @@ -0,0 +1,16 @@ +# Helper methods shared among GutterComponent classes. + +module.exports = + # Sets scrollHeight, scrollTop, and backgroundColor on the given domNode. + setDimensionsAndBackground: (oldState, newState, domNode) -> + if newState.scrollHeight isnt oldState.scrollHeight + domNode.style.height = newState.scrollHeight + 'px' + oldState.scrollHeight = newState.scrollHeight + + if newState.scrollTop isnt oldState.scrollTop + domNode.style['-webkit-transform'] = "translate3d(0px, #{-newState.scrollTop}px, 0px)" + oldState.scrollTop = newState.scrollTop + + if newState.backgroundColor isnt oldState.backgroundColor + domNode.style.backgroundColor = newState.backgroundColor + oldState.backgroundColor = newState.backgroundColor diff --git a/src/line-number-gutter-component.coffee b/src/line-number-gutter-component.coffee index 87d33619c..0f9571865 100644 --- a/src/line-number-gutter-component.coffee +++ b/src/line-number-gutter-component.coffee @@ -1,4 +1,5 @@ _ = require 'underscore-plus' +{setDimensionsAndBackground} = require './gutter-component-helpers' WrapperDiv = document.createElement('div') @@ -30,17 +31,7 @@ class LineNumberGutterComponent @appendDummyLineNumber() unless @dummyLineNumberNode? - if @newState.scrollHeight isnt @oldState.scrollHeight - @lineNumbersNode.style.height = @newState.scrollHeight + 'px' - @oldState.scrollHeight = @newState.scrollHeight - - if @newState.scrollTop isnt @oldState.scrollTop - @lineNumbersNode.style['-webkit-transform'] = "translate3d(0px, #{-@newState.scrollTop}px, 0px)" - @oldState.scrollTop = @newState.scrollTop - - if @newState.backgroundColor isnt @oldState.backgroundColor - @lineNumbersNode.style.backgroundColor = @newState.backgroundColor - @oldState.backgroundColor = @newState.backgroundColor + setDimensionsAndBackground(@oldState, @newState, @lineNumbersNode) if @newState.maxLineNumberDigits isnt @oldState.maxLineNumberDigits @updateDummyLineNumber() From d2914bc73cb84880131e199b874e1c62e8d16d81 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Tue, 24 Mar 2015 14:32:58 -0700 Subject: [PATCH 0818/1783] [Gutter] Make the GutterContainerComponent able to create custom gutters --- src/gutter-container-component.coffee | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gutter-container-component.coffee b/src/gutter-container-component.coffee index 886f88230..aac219d03 100644 --- a/src/gutter-container-component.coffee +++ b/src/gutter-container-component.coffee @@ -1,3 +1,4 @@ +CustomGutterComponent = require './custom-gutter-component' LineNumberGutterComponent = require './line-number-gutter-component' # The GutterContainerComponent manages the GutterComponents of a particular @@ -13,6 +14,7 @@ class GutterContainerComponent @domNode = document.createElement('div') @domNode.classList.add('gutter-container') + @domNode.style.display = 'flex'; getDomNode: -> @domNode @@ -34,8 +36,7 @@ class GutterContainerComponent gutterComponent = new LineNumberGutterComponent({onMouseDown: @onLineNumberGutterMouseDown, @editor, name: gutter.name}) @lineNumberGutterComponent = gutterComponent else - # TODO (jessicalin) Implement non-line-number gutters. - continue + gutterComponent = new CustomGutterComponent({name: gutter.name}) newGutterComponents.push(gutterComponent) newGutterComponentsByGutterName[gutter.name] = gutterComponent From f3d2597bda6cde9c314e8c5763ed69408575ac2d Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Tue, 31 Mar 2015 13:38:35 -0700 Subject: [PATCH 0819/1783] [Gutter][View Registry] Make the Presenter pass sorted Gutter models instead of sorted derived state --- spec/text-editor-presenter-spec.coffee | 13 +++++-------- src/gutter-container-component.coffee | 2 +- src/text-editor-component.coffee | 4 ++-- src/text-editor-presenter.coffee | 6 +++--- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 53066e26c..f539d7f27 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -2191,9 +2191,9 @@ describe "TextEditorPresenter", -> expect(presenter.getState().focused).toBe false describe ".gutters", -> - describe ".sortedDescriptions", -> + describe ".sortedModels", -> gutterDescriptionWithName = (presenter, name) -> - for gutterDesc in presenter.getState().gutters.sortedDescriptions + for gutterDesc in presenter.getState().gutters.sortedModels return gutterDesc if gutterDesc.name is name undefined @@ -2235,13 +2235,10 @@ describe "TextEditorPresenter", -> it "updates when gutters are added to the editor model, and keeps the gutters sorted by priority", -> presenter = buildPresenter() - editor.addGutter({name: 'test-gutter-1', priority: -100, visible: true}) + gutter1 = editor.addGutter({name: 'test-gutter-1', priority: -100, visible: true}) editor.addGutter({name: 'test-gutter-2', priority: 100, visible: false}) - expectedState = [ - {name: 'test-gutter-1'}, - {name: 'line-number'}, - ] - expect(presenter.getState().gutters.sortedDescriptions).toEqual expectedState + expectedState = [gutter1, editor.gutterWithName('line-number')] + expect(presenter.getState().gutters.sortedModels).toEqual expectedState it "updates when the visibility of a gutter changes", -> presenter = buildPresenter() diff --git a/src/gutter-container-component.coffee b/src/gutter-container-component.coffee index aac219d03..9470ad11b 100644 --- a/src/gutter-container-component.coffee +++ b/src/gutter-container-component.coffee @@ -25,7 +25,7 @@ class GutterContainerComponent updateSync: (state) -> # The GutterContainerComponent expects the gutters to be sorted in the order # they should appear. - newState = state.gutters.sortedDescriptions + newState = state.gutters.sortedModels newGutterComponents = [] newGutterComponentsByGutterName = {} diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 89f541775..1355457c0 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -70,7 +70,7 @@ class TextEditorComponent @scrollViewNode.classList.add('scroll-view') @domNode.appendChild(@scrollViewNode) - @mountGutterContainerComponent() if @presenter.getState().gutters.sortedDescriptions.length + @mountGutterContainerComponent() if @presenter.getState().gutters.sortedModels.length @hiddenInputComponent = new InputComponent @scrollViewNode.appendChild(@hiddenInputComponent.domNode) @@ -134,7 +134,7 @@ class TextEditorComponent else @domNode.style.height = '' - if @newState.gutters.sortedDescriptions.length + if @newState.gutters.sortedModels.length @mountGutterContainerComponent() unless @gutterContainerComponent? @gutterContainerComponent.updateSync(@newState) else diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 085244f51..6783c10a1 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -182,7 +182,7 @@ class TextEditorPresenter lineNumberGutter: lineNumbers: {} gutters: - sortedDescriptions: [] + sortedModels: [] customDecorations: {} @updateState() @@ -405,7 +405,7 @@ class TextEditorPresenter # For now, just match the background color of the line-number gutter. # TODO: Allow gutters to have different background colors. (?) @state.gutters.backgroundColor = @getGutterBackgroundColor() - @state.gutters.sortedDescriptions = [] + @state.gutters.sortedModels = [] if @model.isMini() return for gutter in @model.getGutters() @@ -413,7 +413,7 @@ class TextEditorPresenter if gutter.name is 'line-number' isVisible = isVisible && @showLineNumbers if isVisible - @state.gutters.sortedDescriptions.push({name: gutter.name}) + @state.gutters.sortedModels.push(gutter) # Updates the decoration state for the gutter with the given gutterName. # @state.gutters.customDecorations is an {Object}, with the form: From 6319c9722aa8591eee1bb063bcb91801ecccbe10 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Tue, 31 Mar 2015 14:29:16 -0700 Subject: [PATCH 0820/1783] [Gutter][View Registry] Add Gutter view providers to the ViewRegistry --- src/gutter-component-helpers.coffee | 12 ++++++++++++ src/pane-container.coffee | 3 +++ 2 files changed, 15 insertions(+) diff --git a/src/gutter-component-helpers.coffee b/src/gutter-component-helpers.coffee index ba7cdb613..f3a94c5b4 100644 --- a/src/gutter-component-helpers.coffee +++ b/src/gutter-component-helpers.coffee @@ -1,6 +1,18 @@ # Helper methods shared among GutterComponent classes. module.exports = + createGutterView: (gutterModel) -> + domNode = document.createElement('div') + domNode.classList.add('gutter') + domNode.setAttribute('gutter-name', gutterModel.name) + childNode = document.createElement('div') + if gutterModel.name is 'line-number' + childNode.classList.add('line-numbers') + else + childNode.classList.add('custom-decorations') + domNode.appendChild(childNode) + domNode + # Sets scrollHeight, scrollTop, and backgroundColor on the given domNode. setDimensionsAndBackground: (oldState, newState, domNode) -> if newState.scrollHeight isnt oldState.scrollHeight diff --git a/src/pane-container.coffee b/src/pane-container.coffee index e6eb97075..26ef22cac 100644 --- a/src/pane-container.coffee +++ b/src/pane-container.coffee @@ -2,6 +2,8 @@ Grim = require 'grim' {Emitter, CompositeDisposable} = require 'event-kit' Serializable = require 'serializable' +{createGutterView} = require './gutter-component-helpers' +Gutter = require './gutter' Model = require './model' Pane = require './pane' PaneElement = require './pane-element' @@ -60,6 +62,7 @@ class PaneContainer extends Model new PaneElement().initialize(model) atom.views.addViewProvider TextEditor, (model) -> new TextEditorElement().initialize(model) + atom.views.addViewProvider(Gutter, createGutterView) onDidChangeRoot: (fn) -> @emitter.on 'did-change-root', fn From 66f1f33861f1bf1d71ae8cc38e6235811f9c12bf Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Tue, 31 Mar 2015 14:42:28 -0700 Subject: [PATCH 0821/1783] [Gutter][View Registry] Make LineNumber- and Custom- GutterComponent get their view from the ViewRegistry --- src/custom-gutter-component.coffee | 12 ++++-------- src/gutter-container-component.coffee | 4 ++-- src/line-number-gutter-component.coffee | 11 ++++------- 3 files changed, 10 insertions(+), 17 deletions(-) diff --git a/src/custom-gutter-component.coffee b/src/custom-gutter-component.coffee index 3ffc2ec73..e2628a451 100644 --- a/src/custom-gutter-component.coffee +++ b/src/custom-gutter-component.coffee @@ -11,16 +11,12 @@ TEMP_DECOR_BACKGROUND = 'white' module.exports = class CustomGutterComponent - constructor: ({@name}) -> + constructor: ({@gutter}) -> @decorationNodesById = {} @decorationItemsById = {} - @domNode = document.createElement('div') - @domNode.classList.add('gutter') - @domNode.setAttribute('gutter-name', @name) - @decorationsNode = document.createElement('div') - @decorationsNode.classList.add('custom-decorations') - @domNode.appendChild(@decorationsNode) + @domNode = atom.views.getView(@gutter) + @decorationsNode = @domNode.firstChild @domNode.style['width'] = '' + TEMP_MIN_WIDTH + 'px' @@ -28,7 +24,7 @@ class CustomGutterComponent @domNode getName: -> - @name + @gutter.name updateSync: (state) -> gutterProps = state.lineNumberGutter diff --git a/src/gutter-container-component.coffee b/src/gutter-container-component.coffee index 9470ad11b..3dfa67ccc 100644 --- a/src/gutter-container-component.coffee +++ b/src/gutter-container-component.coffee @@ -33,10 +33,10 @@ class GutterContainerComponent gutterComponent = @gutterComponentsByGutterName[gutter.name] if !gutterComponent if gutter.name is 'line-number' - gutterComponent = new LineNumberGutterComponent({onMouseDown: @onLineNumberGutterMouseDown, @editor, name: gutter.name}) + gutterComponent = new LineNumberGutterComponent({onMouseDown: @onLineNumberGutterMouseDown, @editor, gutter}) @lineNumberGutterComponent = gutterComponent else - gutterComponent = new CustomGutterComponent({name: gutter.name}) + gutterComponent = new CustomGutterComponent({gutter}) newGutterComponents.push(gutterComponent) newGutterComponentsByGutterName[gutter.name] = gutterComponent diff --git a/src/line-number-gutter-component.coffee b/src/line-number-gutter-component.coffee index 0f9571865..dcd890aab 100644 --- a/src/line-number-gutter-component.coffee +++ b/src/line-number-gutter-component.coffee @@ -7,14 +7,11 @@ module.exports = class LineNumberGutterComponent dummyLineNumberNode: null - constructor: ({@onMouseDown, @editor, @name}) -> + constructor: ({@onMouseDown, @editor, @gutter}) -> @lineNumberNodesById = {} - @domNode = document.createElement('div') - @domNode.classList.add('gutter') - @lineNumbersNode = document.createElement('div') - @lineNumbersNode.classList.add('line-numbers') - @domNode.appendChild(@lineNumbersNode) + @domNode = atom.views.getView(@gutter) + @lineNumbersNode = @domNode.firstChild @domNode.addEventListener 'click', @onClick @domNode.addEventListener 'mousedown', @onMouseDown @@ -23,7 +20,7 @@ class LineNumberGutterComponent @domNode getName: -> - @name + @gutter.name updateSync: (state) -> @newState = state.lineNumberGutter From 0d7f89467fb1ff495ec303e2269142f4f184d0ee Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Wed, 1 Apr 2015 11:51:04 -0700 Subject: [PATCH 0822/1783] [Gutter][DOM Persistence] Add ::hideNode and ::showNode to GutterComponent classes --- src/custom-gutter-component.coffee | 11 +++++++++++ src/line-number-gutter-component.coffee | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/custom-gutter-component.coffee b/src/custom-gutter-component.coffee index e2628a451..4b374ba22 100644 --- a/src/custom-gutter-component.coffee +++ b/src/custom-gutter-component.coffee @@ -14,6 +14,7 @@ class CustomGutterComponent constructor: ({@gutter}) -> @decorationNodesById = {} @decorationItemsById = {} + @visible = true @domNode = atom.views.getView(@gutter) @decorationsNode = @domNode.firstChild @@ -26,6 +27,16 @@ class CustomGutterComponent getName: -> @gutter.name + hideNode: -> + if @visible + @domNode.style.display = 'none' + @visible = false + + showNode: -> + if !@visible + @domNode.style.removeProperty('display') + @visible = true + updateSync: (state) -> gutterProps = state.lineNumberGutter decorationState = state.gutters.customDecorations[@getName()] diff --git a/src/line-number-gutter-component.coffee b/src/line-number-gutter-component.coffee index dcd890aab..56fc74edc 100644 --- a/src/line-number-gutter-component.coffee +++ b/src/line-number-gutter-component.coffee @@ -9,6 +9,7 @@ class LineNumberGutterComponent constructor: ({@onMouseDown, @editor, @gutter}) -> @lineNumberNodesById = {} + @visible = true @domNode = atom.views.getView(@gutter) @lineNumbersNode = @domNode.firstChild @@ -22,6 +23,16 @@ class LineNumberGutterComponent getName: -> @gutter.name + hideNode: -> + if @visible + @domNode.style.display = 'none' + @visible = false + + showNode: -> + if !@visible + @domNode.style.removeProperty('display') + @visible = true + updateSync: (state) -> @newState = state.lineNumberGutter @oldState ?= {lineNumbers: {}} From 34856d94f528b5f1d1e7c87ea6fdb8f1e4c6d4a6 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Wed, 1 Apr 2015 11:41:42 -0700 Subject: [PATCH 0823/1783] [Gutter][DOM Persistence] Keep a gutter in the DOM if it is merely hidden (not destroyed) --- spec/text-editor-component-spec.coffee | 8 +++--- spec/text-editor-presenter-spec.coffee | 36 ++++++++++++++------------ src/gutter-container-component.coffee | 5 ++-- src/text-editor-component.coffee | 4 +-- src/text-editor-presenter.coffee | 7 +++-- 5 files changed, 32 insertions(+), 28 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 793b154cd..31dff8450 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -584,22 +584,22 @@ describe "TextEditorComponent", -> editor.setLineNumberGutterVisible(false) nextAnimationFrame() - expect(componentNode.querySelector('.gutter')).toBeNull() + expect(componentNode.querySelector('.gutter').style.display).toBe 'none' atom.config.set("editor.showLineNumbers", false) nextAnimationFrame() - expect(componentNode.querySelector('.gutter')).toBeNull() + expect(componentNode.querySelector('.gutter').style.display).toBe 'none' editor.setLineNumberGutterVisible(true) nextAnimationFrame() - expect(componentNode.querySelector('.gutter')).toBeNull() + expect(componentNode.querySelector('.gutter').style.display).toBe 'none' atom.config.set("editor.showLineNumbers", true) nextAnimationFrame() - expect(componentNode.querySelector('.gutter')).toBeDefined() + expect(componentNode.querySelector('.gutter').style.display).toBe '' expect(component.lineNumberNodeForScreenRow(3)?).toBe true describe "fold decorations", -> diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index f539d7f27..e091c937e 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -2191,10 +2191,10 @@ describe "TextEditorPresenter", -> expect(presenter.getState().focused).toBe false describe ".gutters", -> - describe ".sortedModels", -> + describe ".sortedDescriptions", -> gutterDescriptionWithName = (presenter, name) -> - for gutterDesc in presenter.getState().gutters.sortedModels - return gutterDesc if gutterDesc.name is name + for gutterDesc in presenter.getState().gutters.sortedDescriptions + return gutterDesc if gutterDesc.gutter.name is name undefined describe "the line-number gutter", -> @@ -2202,28 +2202,28 @@ describe "TextEditorPresenter", -> presenter = buildPresenter() expect(editor.isLineNumberGutterVisible()).toBe true - expect(gutterDescriptionWithName(presenter, 'line-number')).toBeDefined() + expect(gutterDescriptionWithName(presenter, 'line-number').visible).toBe true expectStateUpdate presenter, -> editor.setMini(true) expect(gutterDescriptionWithName(presenter, 'line-number')).toBeUndefined() expectStateUpdate presenter, -> editor.setMini(false) - expect(gutterDescriptionWithName(presenter, 'line-number')).toBeDefined() + expect(gutterDescriptionWithName(presenter, 'line-number').visible).toBe true expectStateUpdate presenter, -> editor.setLineNumberGutterVisible(false) - expect(gutterDescriptionWithName(presenter, 'line-number')).toBeUndefined() + expect(gutterDescriptionWithName(presenter, 'line-number').visible).toBe false expectStateUpdate presenter, -> editor.setLineNumberGutterVisible(true) - expect(gutterDescriptionWithName(presenter, 'line-number')).toBeDefined() + expect(gutterDescriptionWithName(presenter, 'line-number').visible).toBe true expectStateUpdate presenter, -> atom.config.set('editor.showLineNumbers', false) - expect(gutterDescriptionWithName(presenter, 'line-number')).toBeUndefined() + expect(gutterDescriptionWithName(presenter, 'line-number').visible).toBe false it "gets updated when the editor's grammar changes", -> presenter = buildPresenter() atom.config.set('editor.showLineNumbers', false, scopeSelector: '.source.js') - expect(gutterDescriptionWithName(presenter, 'line-number')).toBeDefined() + expect(gutterDescriptionWithName(presenter, 'line-number').visible).toBe true stateUpdated = false presenter.onDidUpdateState -> stateUpdated = true @@ -2231,26 +2231,30 @@ describe "TextEditorPresenter", -> runs -> expect(stateUpdated).toBe true - expect(gutterDescriptionWithName(presenter, 'line-number')).toBeUndefined() + expect(gutterDescriptionWithName(presenter, 'line-number').visible).toBe false it "updates when gutters are added to the editor model, and keeps the gutters sorted by priority", -> presenter = buildPresenter() gutter1 = editor.addGutter({name: 'test-gutter-1', priority: -100, visible: true}) - editor.addGutter({name: 'test-gutter-2', priority: 100, visible: false}) - expectedState = [gutter1, editor.gutterWithName('line-number')] - expect(presenter.getState().gutters.sortedModels).toEqual expectedState + gutter2 = editor.addGutter({name: 'test-gutter-2', priority: 100, visible: false}) + expectedState = [ + {gutter: gutter1, visible: true}, + {gutter: editor.gutterWithName('line-number'), visible: true}, + {gutter: gutter2, visible: false}, + ] + expect(presenter.getState().gutters.sortedDescriptions).toEqual expectedState it "updates when the visibility of a gutter changes", -> presenter = buildPresenter() gutter = editor.addGutter({name: 'test-gutter', visible: true}) - expect(gutterDescriptionWithName(presenter, 'test-gutter')).toBeDefined() + expect(gutterDescriptionWithName(presenter, 'test-gutter').visible).toBe true gutter.hide() - expect(gutterDescriptionWithName(presenter, 'test-gutter')).toBeUndefined() + expect(gutterDescriptionWithName(presenter, 'test-gutter').visible).toBe false it "updates when a gutter is removed", -> presenter = buildPresenter() gutter = editor.addGutter({name: 'test-gutter', visible: true}) - expect(gutterDescriptionWithName(presenter, 'test-gutter')).toBeDefined() + expect(gutterDescriptionWithName(presenter, 'test-gutter').visible).toBe true gutter.destroy() expect(gutterDescriptionWithName(presenter, 'test-gutter')).toBeUndefined() diff --git a/src/gutter-container-component.coffee b/src/gutter-container-component.coffee index 3dfa67ccc..b478b96c3 100644 --- a/src/gutter-container-component.coffee +++ b/src/gutter-container-component.coffee @@ -25,11 +25,11 @@ class GutterContainerComponent updateSync: (state) -> # The GutterContainerComponent expects the gutters to be sorted in the order # they should appear. - newState = state.gutters.sortedModels + newState = state.gutters.sortedDescriptions newGutterComponents = [] newGutterComponentsByGutterName = {} - for gutter in newState + for {gutter, visible} in newState gutterComponent = @gutterComponentsByGutterName[gutter.name] if !gutterComponent if gutter.name is 'line-number' @@ -37,6 +37,7 @@ class GutterContainerComponent @lineNumberGutterComponent = gutterComponent else gutterComponent = new CustomGutterComponent({gutter}) + if visible then gutterComponent.showNode() else gutterComponent.hideNode() newGutterComponents.push(gutterComponent) newGutterComponentsByGutterName[gutter.name] = gutterComponent diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 1355457c0..89f541775 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -70,7 +70,7 @@ class TextEditorComponent @scrollViewNode.classList.add('scroll-view') @domNode.appendChild(@scrollViewNode) - @mountGutterContainerComponent() if @presenter.getState().gutters.sortedModels.length + @mountGutterContainerComponent() if @presenter.getState().gutters.sortedDescriptions.length @hiddenInputComponent = new InputComponent @scrollViewNode.appendChild(@hiddenInputComponent.domNode) @@ -134,7 +134,7 @@ class TextEditorComponent else @domNode.style.height = '' - if @newState.gutters.sortedModels.length + if @newState.gutters.sortedDescriptions.length @mountGutterContainerComponent() unless @gutterContainerComponent? @gutterContainerComponent.updateSync(@newState) else diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 6783c10a1..3c9264c58 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -182,7 +182,7 @@ class TextEditorPresenter lineNumberGutter: lineNumbers: {} gutters: - sortedModels: [] + sortedDescriptions: [] customDecorations: {} @updateState() @@ -405,15 +405,14 @@ class TextEditorPresenter # For now, just match the background color of the line-number gutter. # TODO: Allow gutters to have different background colors. (?) @state.gutters.backgroundColor = @getGutterBackgroundColor() - @state.gutters.sortedModels = [] + @state.gutters.sortedDescriptions = [] if @model.isMini() return for gutter in @model.getGutters() isVisible = gutter.isVisible() if gutter.name is 'line-number' isVisible = isVisible && @showLineNumbers - if isVisible - @state.gutters.sortedModels.push(gutter) + @state.gutters.sortedDescriptions.push({gutter, visible: isVisible}) # Updates the decoration state for the gutter with the given gutterName. # @state.gutters.customDecorations is an {Object}, with the form: From d78dfd86bfcb8e6b08e37d09213eb7be5ff26f48 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Wed, 1 Apr 2015 15:00:44 -0700 Subject: [PATCH 0824/1783] [Gutter][refactor] Simplify TextEditorPresenter::updateCustomGutterDecorationState --- src/text-editor-presenter.coffee | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 3c9264c58..7e3d5319e 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -424,21 +424,20 @@ class TextEditorPresenter # class (optional): {String} class # } # } - updateCustomGutterDecorationState: () -> + updateCustomGutterDecorationState: -> @batch 'shouldUpdateCustomGutterDecorationState', => return unless @startRow? and @endRow? and @lineHeight? + @state.gutters.customDecorations = {} for gutter in @model.getGutters() gutterName = gutter.name - @state.gutters.customDecorations[gutterName] ?= {} + @state.gutters.customDecorations[gutterName] = {} gutterState = @state.gutters.customDecorations[gutterName] - visibleDecorationIds = {} relevantDecorations = @customGutterDecorationsInRange(gutterName, @startRow, @endRow - 1) return if !relevantDecorations relevantDecorations.forEach (decoration) => - visibleDecorationIds[decoration.id] = true decorationRange = decoration.getMarker().getScreenRange() gutterState[decoration.id] = top: @lineHeight * decorationRange.start.row @@ -446,9 +445,6 @@ class TextEditorPresenter item: decoration.getProperties().item class: decoration.getProperties().class - for decorationId of gutterState - delete gutterState[decorationId] unless visibleDecorationIds[decorationId] - updateLineNumbersState: -> @batch "shouldUpdateLineNumbersState", -> return unless @startRow? and @endRow? and @lineHeight? From f62a27cfef9af0e7751f289bacc302ed3c074eda Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Wed, 1 Apr 2015 15:10:00 -0700 Subject: [PATCH 0825/1783] [Gutter][DOM Persistence] Clear the decorations of a gutter node if it is not visible --- src/text-editor-presenter.coffee | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 7e3d5319e..7082c1789 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -392,6 +392,7 @@ class TextEditorPresenter gutterDisposables = new CompositeDisposable gutterDisposables.add gutter.onDidChangeVisible => @updateCustomGutterState() + @updateCustomGutterDecorationState() gutterDisposables.add gutter.onDidDestroy => @disposables.remove(gutterDisposables) gutterDisposables.dispose() @@ -409,9 +410,7 @@ class TextEditorPresenter if @model.isMini() return for gutter in @model.getGutters() - isVisible = gutter.isVisible() - if gutter.name is 'line-number' - isVisible = isVisible && @showLineNumbers + isVisible = @gutterIsVisible(gutter) @state.gutters.sortedDescriptions.push({gutter, visible: isVisible}) # Updates the decoration state for the gutter with the given gutterName. @@ -434,6 +433,8 @@ class TextEditorPresenter @state.gutters.customDecorations[gutterName] = {} gutterState = @state.gutters.customDecorations[gutterName] + return if !@gutterIsVisible(gutter) + relevantDecorations = @customGutterDecorationsInRange(gutterName, @startRow, @endRow - 1) return if !relevantDecorations @@ -445,6 +446,12 @@ class TextEditorPresenter item: decoration.getProperties().item class: decoration.getProperties().class + gutterIsVisible: (gutterModel) -> + isVisible = gutterModel.isVisible() + if gutterModel.name is 'line-number' + isVisible = isVisible && @showLineNumbers + isVisible + updateLineNumbersState: -> @batch "shouldUpdateLineNumbersState", -> return unless @startRow? and @endRow? and @lineHeight? From d54e48699b25e61f9465f6a06585bad688fb4b2a Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Wed, 1 Apr 2015 15:02:39 -0700 Subject: [PATCH 0826/1783] [Gutter] Don't bother updating custom gutter decorations if editor is mini --- src/text-editor-presenter.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 7082c1789..8b2cbf825 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -428,6 +428,8 @@ class TextEditorPresenter return unless @startRow? and @endRow? and @lineHeight? @state.gutters.customDecorations = {} + return if @model.isMini() + for gutter in @model.getGutters() gutterName = gutter.name @state.gutters.customDecorations[gutterName] = {} From 14e5d38354d1828eb5fc969fd47effe906430236 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Wed, 1 Apr 2015 15:31:50 -0700 Subject: [PATCH 0827/1783] [Gutter] TextEditorPresenter: Consolidate common gutter state under @state.gutters --- spec/text-editor-presenter-spec.coffee | 182 ++++++++++++------------ src/custom-gutter-component.coffee | 9 +- src/line-number-gutter-component.coffee | 3 +- src/text-editor-presenter.coffee | 25 ++-- 4 files changed, 111 insertions(+), 108 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index e091c937e..ed07c3d70 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -1767,97 +1767,6 @@ describe "TextEditorPresenter", -> } describe ".lineNumberGutter", -> - describe ".scrollHeight", -> - it "is initialized based on ::lineHeight, the number of lines, and ::explicitHeight", -> - presenter = buildPresenter() - expect(presenter.getState().lineNumberGutter.scrollHeight).toBe editor.getScreenLineCount() * 10 - - presenter = buildPresenter(explicitHeight: 500) - expect(presenter.getState().lineNumberGutter.scrollHeight).toBe 500 - - it "updates when the ::lineHeight changes", -> - presenter = buildPresenter() - expectStateUpdate presenter, -> presenter.setLineHeight(20) - expect(presenter.getState().lineNumberGutter.scrollHeight).toBe editor.getScreenLineCount() * 20 - - it "updates when the line count changes", -> - presenter = buildPresenter() - expectStateUpdate presenter, -> editor.getBuffer().append("\n\n\n") - expect(presenter.getState().lineNumberGutter.scrollHeight).toBe editor.getScreenLineCount() * 10 - - it "updates when ::explicitHeight changes", -> - presenter = buildPresenter() - expectStateUpdate presenter, -> presenter.setExplicitHeight(500) - expect(presenter.getState().lineNumberGutter.scrollHeight).toBe 500 - - it "adds the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true", -> - presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) - expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.getState().lineNumberGutter.scrollHeight).toBe presenter.contentHeight - - expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", true) - expect(presenter.getState().lineNumberGutter.scrollHeight).toBe presenter.contentHeight + presenter.clientHeight - (presenter.lineHeight * 3) - - expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) - expect(presenter.getState().lineNumberGutter.scrollHeight).toBe presenter.contentHeight - - describe ".scrollTop", -> - it "tracks the value of ::scrollTop", -> - presenter = buildPresenter(scrollTop: 10, explicitHeight: 20) - expect(presenter.getState().lineNumberGutter.scrollTop).toBe 10 - expectStateUpdate presenter, -> presenter.setScrollTop(50) - expect(presenter.getState().lineNumberGutter.scrollTop).toBe 50 - - it "never exceeds the computed scrollHeight minus the computed clientHeight", -> - presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) - expectStateUpdate presenter, -> presenter.setScrollTop(100) - expect(presenter.getState().lineNumberGutter.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight - - expectStateUpdate presenter, -> presenter.setExplicitHeight(60) - expect(presenter.getState().lineNumberGutter.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight - - expectStateUpdate presenter, -> presenter.setHorizontalScrollbarHeight(5) - expect(presenter.getState().lineNumberGutter.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight - - expectStateUpdate presenter, -> editor.getBuffer().delete([[8, 0], [12, 0]]) - expect(presenter.getState().lineNumberGutter.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight - - # Scroll top only gets smaller when needed as dimensions change, never bigger - scrollTopBefore = presenter.getState().verticalScrollbar.scrollTop - expectStateUpdate presenter, -> editor.getBuffer().insert([9, Infinity], '\n\n\n') - expect(presenter.getState().lineNumberGutter.scrollTop).toBe scrollTopBefore - - it "never goes negative", -> - presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) - expectStateUpdate presenter, -> presenter.setScrollTop(-100) - expect(presenter.getState().lineNumberGutter.scrollTop).toBe 0 - - it "adds the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true", -> - presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) - expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.getState().lineNumberGutter.scrollTop).toBe presenter.contentHeight - presenter.clientHeight - - atom.config.set("editor.scrollPastEnd", true) - expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.getState().lineNumberGutter.scrollTop).toBe presenter.contentHeight - (presenter.lineHeight * 3) - - expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) - expect(presenter.getState().lineNumberGutter.scrollTop).toBe presenter.contentHeight - presenter.clientHeight - - describe ".backgroundColor", -> - it "is assigned to ::gutterBackgroundColor if present, and to ::backgroundColor otherwise", -> - presenter = buildPresenter(backgroundColor: "rgba(255, 0, 0, 0)", gutterBackgroundColor: "rgba(0, 255, 0, 0)") - expect(presenter.getState().lineNumberGutter.backgroundColor).toBe "rgba(0, 255, 0, 0)" - - expectStateUpdate presenter, -> presenter.setGutterBackgroundColor("rgba(0, 0, 255, 0)") - expect(presenter.getState().lineNumberGutter.backgroundColor).toBe "rgba(0, 0, 255, 0)" - - expectStateUpdate presenter, -> presenter.setGutterBackgroundColor("rgba(0, 0, 0, 0)") - expect(presenter.getState().lineNumberGutter.backgroundColor).toBe "rgba(255, 0, 0, 0)" - - expectStateUpdate presenter, -> presenter.setBackgroundColor("rgba(0, 0, 255, 0)") - expect(presenter.getState().lineNumberGutter.backgroundColor).toBe "rgba(0, 0, 255, 0)" - describe ".maxLineNumberDigits", -> it "is set to the number of digits used by the greatest line number", -> presenter = buildPresenter() @@ -2191,6 +2100,97 @@ describe "TextEditorPresenter", -> expect(presenter.getState().focused).toBe false describe ".gutters", -> + describe ".scrollHeight", -> + it "is initialized based on ::lineHeight, the number of lines, and ::explicitHeight", -> + presenter = buildPresenter() + expect(presenter.getState().gutters.scrollHeight).toBe editor.getScreenLineCount() * 10 + + presenter = buildPresenter(explicitHeight: 500) + expect(presenter.getState().gutters.scrollHeight).toBe 500 + + it "updates when the ::lineHeight changes", -> + presenter = buildPresenter() + expectStateUpdate presenter, -> presenter.setLineHeight(20) + expect(presenter.getState().gutters.scrollHeight).toBe editor.getScreenLineCount() * 20 + + it "updates when the line count changes", -> + presenter = buildPresenter() + expectStateUpdate presenter, -> editor.getBuffer().append("\n\n\n") + expect(presenter.getState().gutters.scrollHeight).toBe editor.getScreenLineCount() * 10 + + it "updates when ::explicitHeight changes", -> + presenter = buildPresenter() + expectStateUpdate presenter, -> presenter.setExplicitHeight(500) + expect(presenter.getState().gutters.scrollHeight).toBe 500 + + it "adds the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true", -> + presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) + expectStateUpdate presenter, -> presenter.setScrollTop(300) + expect(presenter.getState().gutters.scrollHeight).toBe presenter.contentHeight + + expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", true) + expect(presenter.getState().gutters.scrollHeight).toBe presenter.contentHeight + presenter.clientHeight - (presenter.lineHeight * 3) + + expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) + expect(presenter.getState().gutters.scrollHeight).toBe presenter.contentHeight + + describe ".scrollTop", -> + it "tracks the value of ::scrollTop", -> + presenter = buildPresenter(scrollTop: 10, explicitHeight: 20) + expect(presenter.getState().gutters.scrollTop).toBe 10 + expectStateUpdate presenter, -> presenter.setScrollTop(50) + expect(presenter.getState().gutters.scrollTop).toBe 50 + + it "never exceeds the computed scrollHeight minus the computed clientHeight", -> + presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) + expectStateUpdate presenter, -> presenter.setScrollTop(100) + expect(presenter.getState().gutters.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + + expectStateUpdate presenter, -> presenter.setExplicitHeight(60) + expect(presenter.getState().gutters.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + + expectStateUpdate presenter, -> presenter.setHorizontalScrollbarHeight(5) + expect(presenter.getState().gutters.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + + expectStateUpdate presenter, -> editor.getBuffer().delete([[8, 0], [12, 0]]) + expect(presenter.getState().gutters.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + + # Scroll top only gets smaller when needed as dimensions change, never bigger + scrollTopBefore = presenter.getState().verticalScrollbar.scrollTop + expectStateUpdate presenter, -> editor.getBuffer().insert([9, Infinity], '\n\n\n') + expect(presenter.getState().gutters.scrollTop).toBe scrollTopBefore + + it "never goes negative", -> + presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) + expectStateUpdate presenter, -> presenter.setScrollTop(-100) + expect(presenter.getState().gutters.scrollTop).toBe 0 + + it "adds the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true", -> + presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) + expectStateUpdate presenter, -> presenter.setScrollTop(300) + expect(presenter.getState().gutters.scrollTop).toBe presenter.contentHeight - presenter.clientHeight + + atom.config.set("editor.scrollPastEnd", true) + expectStateUpdate presenter, -> presenter.setScrollTop(300) + expect(presenter.getState().gutters.scrollTop).toBe presenter.contentHeight - (presenter.lineHeight * 3) + + expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) + expect(presenter.getState().gutters.scrollTop).toBe presenter.contentHeight - presenter.clientHeight + + describe ".backgroundColor", -> + it "is assigned to ::gutterBackgroundColor if present, and to ::backgroundColor otherwise", -> + presenter = buildPresenter(backgroundColor: "rgba(255, 0, 0, 0)", gutterBackgroundColor: "rgba(0, 255, 0, 0)") + expect(presenter.getState().gutters.backgroundColor).toBe "rgba(0, 255, 0, 0)" + + expectStateUpdate presenter, -> presenter.setGutterBackgroundColor("rgba(0, 0, 255, 0)") + expect(presenter.getState().gutters.backgroundColor).toBe "rgba(0, 0, 255, 0)" + + expectStateUpdate presenter, -> presenter.setGutterBackgroundColor("rgba(0, 0, 0, 0)") + expect(presenter.getState().gutters.backgroundColor).toBe "rgba(255, 0, 0, 0)" + + expectStateUpdate presenter, -> presenter.setBackgroundColor("rgba(0, 0, 255, 0)") + expect(presenter.getState().gutters.backgroundColor).toBe "rgba(0, 0, 255, 0)" + describe ".sortedDescriptions", -> gutterDescriptionWithName = (presenter, name) -> for gutterDesc in presenter.getState().gutters.sortedDescriptions diff --git a/src/custom-gutter-component.coffee b/src/custom-gutter-component.coffee index 4b374ba22..68f91f7ff 100644 --- a/src/custom-gutter-component.coffee +++ b/src/custom-gutter-component.coffee @@ -38,12 +38,11 @@ class CustomGutterComponent @visible = true updateSync: (state) -> - gutterProps = state.lineNumberGutter + @oldDimensionsAndBackgroundState ?= {} + newDimensionsAndBackgroundState = state.gutters + setDimensionsAndBackground(@oldDimensionsAndBackgroundState, newDimensionsAndBackgroundState, @decorationsNode) + decorationState = state.gutters.customDecorations[@getName()] - @oldState ?= {} - - setDimensionsAndBackground(@oldState, gutterProps, @decorationsNode) - return if !decorationState updatedDecorationIds = new Set diff --git a/src/line-number-gutter-component.coffee b/src/line-number-gutter-component.coffee index 56fc74edc..b79b08fdb 100644 --- a/src/line-number-gutter-component.coffee +++ b/src/line-number-gutter-component.coffee @@ -39,7 +39,8 @@ class LineNumberGutterComponent @appendDummyLineNumber() unless @dummyLineNumberNode? - setDimensionsAndBackground(@oldState, @newState, @lineNumbersNode) + newDimensionsAndBackgroundState = state.gutters + setDimensionsAndBackground(@oldState, newDimensionsAndBackgroundState, @lineNumbersNode) if @newState.maxLineNumberDigits isnt @oldState.maxLineNumberDigits @updateDummyLineNumber() diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 8b2cbf825..84400ee4f 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -121,10 +121,12 @@ class TextEditorPresenter @updateLinesState() @updateLineNumberGutterState() @updateLineNumbersState() + @updateCommonGutterState() @updateCustomGutterState() @updateCustomGutterDecorationState() @disposables.add @model.onDidChangeLineNumberGutterVisible => @updateLineNumberGutterState() + @updateCommonGutterState() @updateCustomGutterState() @disposables.add @model.onDidAddDecoration(@didAddDecoration.bind(this)) @disposables.add @model.onDidAddCursor(@didAddCursor.bind(this)) @@ -160,12 +162,14 @@ class TextEditorPresenter @configDisposables.add atom.config.onDidChange 'editor.showLineNumbers', configParams, ({newValue}) => @showLineNumbers = newValue @updateLineNumberGutterState() + @updateCommonGutterState() @updateCustomGutterState() didChangeGrammar: -> @observeConfig() @updateContentState() @updateLineNumberGutterState() + @updateCommonGutterState() @updateCustomGutterState() buildState: -> @@ -205,6 +209,7 @@ class TextEditorPresenter @updateOverlaysState() @updateLineNumberGutterState() @updateLineNumbersState() + @updateCommonGutterState() @updateCustomGutterState() @updateCustomGutterDecorationState() @@ -219,11 +224,11 @@ class TextEditorPresenter updateVerticalScrollState: -> @batch "shouldUpdateVerticalScrollState", -> @state.content.scrollHeight = @scrollHeight - @state.lineNumberGutter.scrollHeight = @scrollHeight + @state.gutters.scrollHeight = @scrollHeight @state.verticalScrollbar.scrollHeight = @scrollHeight @state.content.scrollTop = @scrollTop - @state.lineNumberGutter.scrollTop = @scrollTop + @state.gutters.scrollTop = @scrollTop @state.verticalScrollbar.scrollTop = @scrollTop updateHorizontalScrollState: -> @batch "shouldUpdateHorizontalScrollState", -> @@ -380,13 +385,12 @@ class TextEditorPresenter updateLineNumberGutterState: -> @batch "shouldUpdateLineNumberGutterState", -> @state.lineNumberGutter.maxLineNumberDigits = @model.getLineCount().toString().length - @state.lineNumberGutter.backgroundColor = @getGutterBackgroundColor() - getGutterBackgroundColor: -> - if @gutterBackgroundColor isnt "rgba(0, 0, 0, 0)" - @gutterBackgroundColor - else - @backgroundColor + updateCommonGutterState: -> + @state.gutters.backgroundColor = if @gutterBackgroundColor isnt "rgba(0, 0, 0, 0)" + @gutterBackgroundColor + else + @backgroundColor didAddGutter: (gutter) -> gutterDisposables = new CompositeDisposable @@ -403,9 +407,6 @@ class TextEditorPresenter updateCustomGutterState: -> @batch "shouldUpdateCustomGutterState", -> - # For now, just match the background color of the line-number gutter. - # TODO: Allow gutters to have different background colors. (?) - @state.gutters.backgroundColor = @getGutterBackgroundColor() @state.gutters.sortedDescriptions = [] if @model.isMini() return @@ -808,12 +809,14 @@ class TextEditorPresenter @backgroundColor = backgroundColor @updateContentState() @updateLineNumberGutterState() + @updateCommonGutterState() @updateCustomGutterState() setGutterBackgroundColor: (gutterBackgroundColor) -> unless @gutterBackgroundColor is gutterBackgroundColor @gutterBackgroundColor = gutterBackgroundColor @updateLineNumberGutterState() + @updateCommonGutterState() @updateCustomGutterState() setLineHeight: (lineHeight) -> From 93d7b47b79cf9f1793d687d48157e0168d6c66ca Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Thu, 2 Apr 2015 16:51:47 -0700 Subject: [PATCH 0828/1783] [Gutter][refactor] Simplify TextEditorPresenter::updateCustomGutterDecorationState (Pass 2) --- src/text-editor-presenter.coffee | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 84400ee4f..b76115951 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -434,16 +434,12 @@ class TextEditorPresenter for gutter in @model.getGutters() gutterName = gutter.name @state.gutters.customDecorations[gutterName] = {} - gutterState = @state.gutters.customDecorations[gutterName] - return if !@gutterIsVisible(gutter) relevantDecorations = @customGutterDecorationsInRange(gutterName, @startRow, @endRow - 1) - return if !relevantDecorations - relevantDecorations.forEach (decoration) => decorationRange = decoration.getMarker().getScreenRange() - gutterState[decoration.id] = + @state.gutters.customDecorations[gutterName][decoration.id] = top: @lineHeight * decorationRange.start.row height: @lineHeight * decorationRange.getRowCount() item: decoration.getProperties().item @@ -651,10 +647,10 @@ class TextEditorPresenter # TODO (jssln) This needs tests. # Returns a {Set} of {Decoration}s on the given custom gutter from startRow to endRow (inclusive). customGutterDecorationsInRange: (gutterName, startRow, endRow) -> - return null if @model.isMini() or gutterName is 'line-number' - decorations = new Set - return decorations if !@customGutterDecorationsByGutterNameAndScreenRow[gutterName] + + return decorations if @model.isMini() or gutterName is 'line-number' or + !@customGutterDecorationsByGutterNameAndScreenRow[gutterName] for bufferRow in @model.bufferRowsForScreenRows(@startRow, @endRow - 1) for id, decoration of @customGutterDecorationsByGutterNameAndScreenRow[gutterName][bufferRow] From 8c4d092767016d5edc25a1dcaed261f9c051e278 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Wed, 1 Apr 2015 13:27:07 -0700 Subject: [PATCH 0829/1783] [Gutter] TextEditorPresenter tests for custom gutter decorations --- spec/text-editor-presenter-spec.coffee | 242 ++++++++++++++++++++++++- src/text-editor-presenter.coffee | 1 - 2 files changed, 240 insertions(+), 3 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index ed07c3d70..9cf1c2236 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -2259,8 +2259,246 @@ describe "TextEditorPresenter", -> expect(gutterDescriptionWithName(presenter, 'test-gutter')).toBeUndefined() describe ".customDecorations", -> - # TODO (jssln) - null + [presenter, gutter, decorationItem, decorationParams] = [] + [marker1, decoration1, marker2, decoration2, marker3, decoration3] = [] + + # Set the scrollTop to 0 to show the very top of the file. + # Set the explicitHeight to make 10 lines visible. + scrollTop = 0 + lineHeight = 10 + explicitHeight = lineHeight * 10 + lineOverdrawMargin = 1 + + decorationStateForGutterName = (presenter, gutterName) -> + presenter.getState().gutters.customDecorations[gutterName] + + beforeEach -> + # At the beginning of each test, decoration1 and decoration2 are in visible range, + # but not decoration3. + presenter = buildPresenter({explicitHeight, scrollTop, lineHeight, lineOverdrawMargin}) + gutter = editor.addGutter({name: 'test-gutter', visible: true}) + decorationItem = document.createElement('div') + decorationItem.class = 'decoration-item' + decorationParams = + type: 'gutter' + gutterName: 'test-gutter' + class: 'test-class' + item: decorationItem + marker1 = editor.markBufferRange([[0,0],[1,0]]) + decoration1 = editor.decorateMarker(marker1, decorationParams) + marker2 = editor.markBufferRange([[9,0],[12,0]]) + decoration2 = editor.decorateMarker(marker2, decorationParams) + marker3 = editor.markBufferRange([[13,0],[14,0]]) + decoration3 = editor.decorateMarker(marker3, decorationParams) + + # Clear any batched state updates. + presenter.getState() + + it "contains all decorations within the visible buffer range", -> + decorationState = decorationStateForGutterName(presenter, 'test-gutter') + expect(decorationState[decoration1.id].top).toBe lineHeight * marker1.getScreenRange().start.row + expect(decorationState[decoration1.id].height).toBe lineHeight * marker1.getScreenRange().getRowCount() + expect(decorationState[decoration1.id].item).toBe decorationItem + expect(decorationState[decoration1.id].class).toBe 'test-class' + + expect(decorationState[decoration2.id].top).toBe lineHeight * marker2.getScreenRange().start.row + expect(decorationState[decoration2.id].height).toBe lineHeight * marker2.getScreenRange().getRowCount() + expect(decorationState[decoration2.id].item).toBe decorationItem + expect(decorationState[decoration2.id].class).toBe 'test-class' + + expect(decorationState[decoration3.id]).toBeUndefined() + + it "updates when ::scrollTop changes", -> + # This update will scroll decoration1 out of view, and decoration3 into view. + expectStateUpdate presenter, -> presenter.setScrollTop(scrollTop + lineHeight * 5) + + decorationState = decorationStateForGutterName(presenter, 'test-gutter') + expect(decorationState[decoration1.id]).toBeUndefined() + expect(decorationState[decoration2.id].top).toBeDefined() + expect(decorationState[decoration3.id].top).toBeDefined() + + it "updates when ::explicitHeight changes", -> + # This update will make all three decorations visible. + expectStateUpdate presenter, -> presenter.setExplicitHeight(explicitHeight + lineHeight * 5) + + decorationState = decorationStateForGutterName(presenter, 'test-gutter') + expect(decorationState[decoration1.id].top).toBeDefined() + expect(decorationState[decoration2.id].top).toBeDefined() + expect(decorationState[decoration3.id].top).toBeDefined() + + it "updates when ::lineHeight changes", -> + # This update will make all three decorations visible. + expectStateUpdate presenter, -> presenter.setLineHeight(Math.ceil(1.0 * explicitHeight / marker3.getBufferRange().end.row)) + + decorationState = decorationStateForGutterName(presenter, 'test-gutter') + expect(decorationState[decoration1.id].top).toBeDefined() + expect(decorationState[decoration2.id].top).toBeDefined() + expect(decorationState[decoration3.id].top).toBeDefined() + + it "updates when the editor's content changes", -> + # This update will add enough lines to push decoration2 out of view. + expectStateUpdate presenter, -> editor.setTextInBufferRange([[8,0],[9,0]],'\n\n\n\n\n') + + decorationState = decorationStateForGutterName(presenter, 'test-gutter') + expect(decorationState[decoration1.id].top).toBeDefined() + expect(decorationState[decoration2.id]).toBeUndefined() + expect(decorationState[decoration3.id]).toBeUndefined() + + it "updates when a decoration's marker is modified", -> + # This update will move decoration1 out of view. + expectStateUpdate presenter, -> + newRange = new Range([13,0],[14,0]) + marker1.setBufferRange(newRange) + + decorationState = decorationStateForGutterName(presenter, 'test-gutter') + expect(decorationState[decoration1.id]).toBeUndefined() + expect(decorationState[decoration2.id].top).toBeDefined() + expect(decorationState[decoration3.id]).toBeUndefined() + + describe "when a decoration's properties are modified", -> + it "updates the item applied to the decoration, if the decoration item is changed", -> + # This changes the decoration class. The visibility of the decoration should not be affected. + newItem = document.createElement('div') + newItem.class = 'new-decoration-item' + newDecorationParams = + type: 'gutter' + gutterName: 'test-gutter' + class: 'test-class' + item: newItem + expectStateUpdate presenter, -> decoration1.setProperties(newDecorationParams) + + decorationState = decorationStateForGutterName(presenter, 'test-gutter') + expect(decorationState[decoration1.id].item).toBe newItem + expect(decorationState[decoration2.id].item).toBe decorationItem + expect(decorationState[decoration3.id]).toBeUndefined() + + it "updates the class applied to the decoration, if the decoration class is changed", -> + # This changes the decoration item. The visibility of the decoration should not be affected. + newDecorationParams = + type: 'gutter' + gutterName: 'test-gutter' + class: 'new-test-class' + item: decorationItem + expectStateUpdate presenter, -> decoration1.setProperties(newDecorationParams) + + decorationState = decorationStateForGutterName(presenter, 'test-gutter') + expect(decorationState[decoration1.id].class).toBe 'new-test-class' + expect(decorationState[decoration2.id].class).toBe 'test-class' + expect(decorationState[decoration3.id]).toBeUndefined() + + it "updates the type of the decoration, if the decoration type is changed", -> + # This changes the type of the decoration. This should remove the decoration from the gutter. + newDecorationParams = + type: 'line' + gutterName: 'test-gutter' # This is an invalid/meaningless option here, but it shouldn't matter. + class: 'test-class' + item: decorationItem + expectStateUpdate presenter, -> decoration1.setProperties(newDecorationParams) + + decorationState = decorationStateForGutterName(presenter, 'test-gutter') + expect(decorationState[decoration1.id]).toBeUndefined() + expect(decorationState[decoration2.id].top).toBeDefined() + expect(decorationState[decoration3.id]).toBeUndefined() + + it "updates the gutter the decoration targets, if the decoration gutterName is changed", -> + # This changes which gutter this decoration applies to. Since this gutter does not exist, + # the decoration should not appear in the customDecorations state. + newDecorationParams = + type: 'gutter' + gutterName: 'test-gutter-2' + class: 'new-test-class' + item: decorationItem + expectStateUpdate presenter, -> decoration1.setProperties(newDecorationParams) + + decorationState = decorationStateForGutterName(presenter, 'test-gutter') + expect(decorationState[decoration1.id]).toBeUndefined() + expect(decorationState[decoration2.id].top).toBeDefined() + expect(decorationState[decoration3.id]).toBeUndefined() + + # After adding the targeted gutter, the decoration will appear in the state for that gutter, + # since it should be visible. + expectStateUpdate presenter, -> editor.addGutter({name: 'test-gutter-2'}) + newGutterDecorationState = decorationStateForGutterName(presenter, 'test-gutter-2') + expect(newGutterDecorationState[decoration1.id].top).toBeDefined() + expect(newGutterDecorationState[decoration2.id]).toBeUndefined() + expect(newGutterDecorationState[decoration3.id]).toBeUndefined() + oldGutterDecorationState = decorationStateForGutterName(presenter, 'test-gutter') + expect(oldGutterDecorationState[decoration1.id]).toBeUndefined() + expect(oldGutterDecorationState[decoration2.id].top).toBeDefined() + expect(oldGutterDecorationState[decoration3.id]).toBeUndefined() + + it "updates when the editor's mini state changes, and is cleared when the editor is mini", -> + expectStateUpdate presenter, -> editor.setMini(true) + decorationState = decorationStateForGutterName(presenter, 'test-gutter') + expect(decorationState).toBeUndefined() + + # The decorations should return to the original state. + expectStateUpdate presenter, -> editor.setMini(false) + decorationState = decorationStateForGutterName(presenter, 'test-gutter') + expect(decorationState[decoration1.id].top).toBeDefined() + expect(decorationState[decoration2.id].top).toBeDefined() + expect(decorationState[decoration3.id]).toBeUndefined() + + it "updates when a gutter's visibility changes, and is cleared when the gutter is not visible", -> + expectStateUpdate presenter, -> gutter.hide() + decorationState = decorationStateForGutterName(presenter, 'test-gutter') + expect(decorationState[decoration1.id]).toBeUndefined() + expect(decorationState[decoration2.id]).toBeUndefined() + expect(decorationState[decoration3.id]).toBeUndefined() + + # The decorations should return to the original state. + expectStateUpdate presenter, -> gutter.show() + decorationState = decorationStateForGutterName(presenter, 'test-gutter') + expect(decorationState[decoration1.id].top).toBeDefined() + expect(decorationState[decoration2.id].top).toBeDefined() + expect(decorationState[decoration3.id]).toBeUndefined() + + it "updates when a gutter is added to the editor", -> + decorationParams = + type: 'gutter' + gutterName: 'test-gutter-2' + class: 'test-class' + marker4 = editor.markBufferRange([[0,0],[1,0]]) + decoration4 = editor.decorateMarker(marker4, decorationParams) + expectStateUpdate presenter, -> editor.addGutter({name: 'test-gutter-2'}) + + decorationState = decorationStateForGutterName(presenter, 'test-gutter-2') + expect(decorationState[decoration1.id]).toBeUndefined() + expect(decorationState[decoration2.id]).toBeUndefined() + expect(decorationState[decoration3.id]).toBeUndefined() + expect(decorationState[decoration4.id].top).toBeDefined() + + it "does not update when a gutter is destroyed (because it's unnecessary)", -> + gutter.destroy() + decorationState = decorationStateForGutterName(presenter, 'test-gutter') + expect(decorationState[decoration1.id].top).toBeDefined() + expect(decorationState[decoration2.id].top).toBeDefined() + expect(decorationState[decoration3.id]).toBeUndefined() + + # However, the decoration state of the destroyed gutter should be + # cleared whenever ::updateCustomGutterDecorationState is next called. + expectStateUpdate presenter, -> editor.addGutter({name: 'a-different-gutter'}) + decorationState = decorationStateForGutterName(presenter, 'test-gutter') + expect(decorationState).toBeUndefined() + + it "updates when editor lines are folded", -> + oldDimensionsForDecoration1 = + top: lineHeight * marker1.getScreenRange().start.row + height: lineHeight * marker1.getScreenRange().getRowCount() + oldDimensionsForDecoration2 = + top: lineHeight * marker2.getScreenRange().start.row + height: lineHeight * marker2.getScreenRange().getRowCount() + + # Based on the contents of sample.js, this should affect all but the top + # part of decoration1. + expectStateUpdate presenter, -> editor.foldBufferRow(0) + + decorationState = decorationStateForGutterName(presenter, 'test-gutter') + expect(decorationState[decoration1.id].top).toBe oldDimensionsForDecoration1.top + expect(decorationState[decoration1.id].height).not.toBe oldDimensionsForDecoration1.height + expect(decorationState[decoration2.id].top).not.toBe oldDimensionsForDecoration2.top + expect(decorationState[decoration2.id].height).not.toBe oldDimensionsForDecoration2.height + expect(decorationState[decoration3.id]).toBeUndefined() # disabled until we fix an issue with display buffer markers not updating when # they are moved on screen but not in the buffer diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index b76115951..3c2e5f5ca 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -644,7 +644,6 @@ class TextEditorPresenter decorationClasses.push(decoration.getProperties().class) decorationClasses - # TODO (jssln) This needs tests. # Returns a {Set} of {Decoration}s on the given custom gutter from startRow to endRow (inclusive). customGutterDecorationsInRange: (gutterName, startRow, endRow) -> decorations = new Set From f41837601347aa8b3f202015d3559f2b4e58c015 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Fri, 3 Apr 2015 20:32:14 -0700 Subject: [PATCH 0830/1783] [Gutter] Tests for GutterContainerComponent --- spec/gutter-container-component-spec.coffee | 142 ++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 spec/gutter-container-component-spec.coffee diff --git a/spec/gutter-container-component-spec.coffee b/spec/gutter-container-component-spec.coffee new file mode 100644 index 000000000..cb3ca37eb --- /dev/null +++ b/spec/gutter-container-component-spec.coffee @@ -0,0 +1,142 @@ +Gutter = require '../src/gutter' +GutterContainerComponent = require '../src/gutter-container-component' + +describe "GutterContainerComponent", -> + [gutterContainerComponent] = [] + mockGutterContainer = {} + + buildTestState = (sortedDescriptions) -> + mockTestState = + gutters: + scrollHeight: 100 + scrollTop: 10 + backgroundColor: 'black' + sortedDescriptions: sortedDescriptions + customDecorations: {} + lineNumberGutter: + maxLineNumberDigits: 10 + lineNumbers: {} + mockTestState + + beforeEach -> + mockEditor = {} + mockMouseDown = -> + gutterContainerComponent = new GutterContainerComponent({editor: mockEditor, onMouseDown: mockMouseDown}) + + it "creates a DOM node with no child gutter nodes when it is initialized", -> + expect(gutterContainerComponent.getDomNode() instanceof HTMLElement).toBe true + expect(gutterContainerComponent.getDomNode().children.length).toBe 0 + + describe "when updated with state that contains a new line-number gutter", -> + it "adds a LineNumberGutterComponent to its children", -> + lineNumberGutter = new Gutter(mockGutterContainer, {name: 'line-number'}) + testState = buildTestState([{gutter: lineNumberGutter, visible: true}]) + + expect(gutterContainerComponent.getDomNode().children.length).toBe 0 + gutterContainerComponent.updateSync(testState) + expect(gutterContainerComponent.getDomNode().children.length).toBe 1 + expectedGutterNode = gutterContainerComponent.getDomNode().children.item(0) + expect(expectedGutterNode.classList.contains('gutter')).toBe true + expectedLineNumbersNode = expectedGutterNode.children.item(0) + expect(expectedLineNumbersNode.classList.contains('line-numbers')).toBe true + + expect(gutterContainerComponent.getLineNumberGutterComponent().getDomNode()).toBe expectedGutterNode + + describe "when updated with state that contains a new custom gutter", -> + it "adds a CustomGutterComponent to its children", -> + customGutter = new Gutter(mockGutterContainer, {name: 'custom'}) + testState = buildTestState([{gutter: customGutter, visible: true}]) + + expect(gutterContainerComponent.getDomNode().children.length).toBe 0 + gutterContainerComponent.updateSync(testState) + expect(gutterContainerComponent.getDomNode().children.length).toBe 1 + expectedGutterNode = gutterContainerComponent.getDomNode().children.item(0) + expect(expectedGutterNode.classList.contains('gutter')).toBe true + expectedCustomDecorationsNode = expectedGutterNode.children.item(0) + expect(expectedCustomDecorationsNode.classList.contains('custom-decorations')).toBe true + + describe "when updated with state that contains a new gutter that is not visible", -> + it "creates the gutter view but hides it, and unhides it when it is later updated to be visible", -> + customGutter = new Gutter(mockGutterContainer, {name: 'custom'}) + testState = buildTestState([{gutter: customGutter, visible: false}]) + + gutterContainerComponent.updateSync(testState) + expect(gutterContainerComponent.getDomNode().children.length).toBe 1 + expectedCustomGutterNode = gutterContainerComponent.getDomNode().children.item(0) + expect(expectedCustomGutterNode.style.display).toBe 'none' + + testState = buildTestState([{gutter: customGutter, visible: true}]) + gutterContainerComponent.updateSync(testState) + expect(gutterContainerComponent.getDomNode().children.length).toBe 1 + expectedCustomGutterNode = gutterContainerComponent.getDomNode().children.item(0) + expect(expectedCustomGutterNode.style.display).toBe '' + + describe "when updated with a gutter that already exists", -> + it "reuses the existing gutter view, instead of recreating it", -> + customGutter = new Gutter(mockGutterContainer, {name: 'custom'}) + testState = buildTestState([{gutter: customGutter, visible: true}]) + + gutterContainerComponent.updateSync(testState) + expect(gutterContainerComponent.getDomNode().children.length).toBe 1 + expectedCustomGutterNode = gutterContainerComponent.getDomNode().children.item(0) + + testState = buildTestState([{gutter: customGutter, visible: true}]) + gutterContainerComponent.updateSync(testState) + expect(gutterContainerComponent.getDomNode().children.length).toBe 1 + expect(gutterContainerComponent.getDomNode().children.item(0)).toBe expectedCustomGutterNode + + it "removes a gutter from the DOM if it does not appear in the latest state update", -> + lineNumberGutter = new Gutter(mockGutterContainer, {name: 'line-number'}) + testState = buildTestState([{gutter: lineNumberGutter, visible: true}]) + gutterContainerComponent.updateSync(testState) + + expect(gutterContainerComponent.getDomNode().children.length).toBe 1 + testState = buildTestState([]) + gutterContainerComponent.updateSync(testState) + expect(gutterContainerComponent.getDomNode().children.length).toBe 0 + + describe "when updated with multiple gutters", -> + it "positions (and repositions) the gutters to match the order they appear in each state update", -> + lineNumberGutter = new Gutter(mockGutterContainer, {name: 'line-number'}) + customGutter1 = new Gutter(mockGutterContainer, {name: 'custom', priority: -100}) + testState = buildTestState([{gutter: customGutter1, visible: true}, {gutter: lineNumberGutter, visible: true}]) + + gutterContainerComponent.updateSync(testState) + expect(gutterContainerComponent.getDomNode().children.length).toBe 2 + expectedCustomGutterNode = gutterContainerComponent.getDomNode().children.item(0) + expect(expectedCustomGutterNode).toBe atom.views.getView(customGutter1) + expectedLineNumbersNode = gutterContainerComponent.getDomNode().children.item(1) + expect(expectedLineNumbersNode).toBe atom.views.getView(lineNumberGutter) + + # Add a gutter. + customGutter2 = new Gutter(mockGutterContainer, {name: 'custom2', priority: -10}) + testState = buildTestState([ + {gutter: customGutter1, visible: true}, + {gutter: customGutter2, visible: true}, + {gutter: lineNumberGutter, visible: true} + ]) + gutterContainerComponent.updateSync(testState) + expect(gutterContainerComponent.getDomNode().children.length).toBe 3 + expectedCustomGutterNode1 = gutterContainerComponent.getDomNode().children.item(0) + expect(expectedCustomGutterNode1).toBe atom.views.getView(customGutter1) + expectedCustomGutterNode2 = gutterContainerComponent.getDomNode().children.item(1) + expect(expectedCustomGutterNode2).toBe atom.views.getView(customGutter2) + expectedLineNumbersNode = gutterContainerComponent.getDomNode().children.item(2) + expect(expectedLineNumbersNode).toBe atom.views.getView(lineNumberGutter) + + # Hide one gutter, reposition one gutter, remove one gutter; and add a new gutter. + customGutter3 = new Gutter(mockGutterContainer, {name: 'custom3', priority: 100}) + testState = buildTestState([ + {gutter: customGutter2, visible: false}, + {gutter: customGutter1, visible: true}, + {gutter: customGutter3, visible: true} + ]) + gutterContainerComponent.updateSync(testState) + expect(gutterContainerComponent.getDomNode().children.length).toBe 3 + expectedCustomGutterNode2 = gutterContainerComponent.getDomNode().children.item(0) + expect(expectedCustomGutterNode2).toBe atom.views.getView(customGutter2) + expect(expectedCustomGutterNode2.style.display).toBe 'none' + expectedCustomGutterNode1 = gutterContainerComponent.getDomNode().children.item(1) + expect(expectedCustomGutterNode1).toBe atom.views.getView(customGutter1) + expectedCustomGutterNode3 = gutterContainerComponent.getDomNode().children.item(2) + expect(expectedCustomGutterNode3).toBe atom.views.getView(customGutter3) From 28ff5dd3c3a357cec5d9f664a0acdda70c95dfb9 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Sat, 4 Apr 2015 12:17:22 -0700 Subject: [PATCH 0831/1783] [Gutter] Tests for CustomGutterComponent --- spec/custom-gutter-component-spec.coffee | 132 +++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 spec/custom-gutter-component-spec.coffee diff --git a/spec/custom-gutter-component-spec.coffee b/spec/custom-gutter-component-spec.coffee new file mode 100644 index 000000000..baf857455 --- /dev/null +++ b/spec/custom-gutter-component-spec.coffee @@ -0,0 +1,132 @@ +CustomGutterComponent = require '../src/custom-gutter-component' +Gutter = require '../src/gutter' + +describe "CustomGutterComponent", -> + [customGutterComponent, gutter] = [] + + beforeEach -> + mockGutterContainer = {} + gutter = new Gutter(mockGutterContainer, {name: 'test-gutter'}) + customGutterComponent = new CustomGutterComponent({gutter}) + + it "creates a gutter DOM node with only an empty 'custom-decorations' child node when it is initialized", -> + expect(customGutterComponent.getDomNode().classList.contains('gutter')).toBe true + expect(customGutterComponent.getDomNode().getAttribute('gutter-name')).toBe 'test-gutter' + expect(customGutterComponent.getDomNode().children.length).toBe 1 + decorationsWrapperNode = customGutterComponent.getDomNode().children.item(0) + expect(decorationsWrapperNode.classList.contains('custom-decorations')).toBe true + + it "makes its view accessible from the view registry", -> + expect(customGutterComponent.getDomNode()).toBe atom.views.getView(gutter) + + it "hides its DOM node when ::hideNode is called, and shows its DOM node when ::showNode is called", -> + customGutterComponent.hideNode() + expect(customGutterComponent.getDomNode().style.display).toBe 'none' + customGutterComponent.showNode() + expect(customGutterComponent.getDomNode().style.display).toBe '' + + describe "::updateSync", -> + decorationItem1 = document.createElement('div') + + buildTestState = (customDecorations) -> + mockTestState = + gutters: + scrollHeight: 100 + scrollTop: 10 + backgroundColor: 'black' + sortedDescriptions: [{gutter, visible: true}] + customDecorations: customDecorations + lineNumberGutter: + maxLineNumberDigits: 10 + lineNumbers: {} + mockTestState + + it "sets the custom-decoration wrapper's scrollHeight, scrollTop, and background color", -> + decorationsWrapperNode = customGutterComponent.getDomNode().children.item(0) + expect(decorationsWrapperNode.style.height).toBe '' + expect(decorationsWrapperNode.style['-webkit-transform']).toBe '' + expect(decorationsWrapperNode.style.backgroundColor).toBe '' + + customGutterComponent.updateSync(buildTestState({})) + expect(decorationsWrapperNode.style.height).not.toBe '' + expect(decorationsWrapperNode.style['-webkit-transform']).not.toBe '' + expect(decorationsWrapperNode.style.backgroundColor).not.toBe '' + + it "creates a new DOM node for a new decoration and adds it to the gutter at the right place", -> + customDecorations = 'test-gutter': + 'decoration-id-1': + top: 0 + height: 10 + item: decorationItem1 + class: 'test-class-1' + + customGutterComponent.updateSync(buildTestState(customDecorations)) + decorationsWrapperNode = customGutterComponent.getDomNode().children.item(0) + expect(decorationsWrapperNode.children.length).toBe 1 + + decorationNode = decorationsWrapperNode.children.item(0) + expect(decorationNode.style.top).toBe '0px' + expect(decorationNode.style.height).toBe '10px' + expect(decorationNode.classList.contains('test-class-1')).toBe true + expect(decorationNode.classList.contains('decoration')).toBe true + expect(decorationNode.children.length).toBe 1 + + decorationItem = decorationNode.children.item(0) + expect(decorationItem).toBe decorationItem1 + + it "updates the existing DOM node for a decoration that existed but has new properties", -> + initialCustomDecorations = 'test-gutter': + 'decoration-id-1': + top: 0 + height: 10 + item: decorationItem1 + class: 'test-class-1' + customGutterComponent.updateSync(buildTestState(initialCustomDecorations)) + initialDecorationNode = customGutterComponent.getDomNode().children.item(0).children.item(0) + + # Change the dimensions and item, remove the class. + decorationItem2 = document.createElement('div') + changedCustomDecorations = 'test-gutter': + 'decoration-id-1': + top: 10 + height: 20 + item: decorationItem2 + customGutterComponent.updateSync(buildTestState(changedCustomDecorations)) + changedDecorationNode = customGutterComponent.getDomNode().children.item(0).children.item(0) + expect(changedDecorationNode).toBe initialDecorationNode + expect(changedDecorationNode.style.top).toBe '10px' + expect(changedDecorationNode.style.height).toBe '20px' + expect(changedDecorationNode.classList.contains('test-class-1')).toBe false + expect(changedDecorationNode.classList.contains('decoration')).toBe true + expect(changedDecorationNode.children.length).toBe 1 + decorationItem = changedDecorationNode.children.item(0) + expect(decorationItem).toBe decorationItem2 + + # Remove the item, add a class. + changedCustomDecorations = 'test-gutter': + 'decoration-id-1': + top: 10 + height: 20 + class: 'test-class-2' + customGutterComponent.updateSync(buildTestState(changedCustomDecorations)) + changedDecorationNode = customGutterComponent.getDomNode().children.item(0).children.item(0) + expect(changedDecorationNode).toBe initialDecorationNode + expect(changedDecorationNode.style.top).toBe '10px' + expect(changedDecorationNode.style.height).toBe '20px' + expect(changedDecorationNode.classList.contains('test-class-2')).toBe true + expect(changedDecorationNode.classList.contains('decoration')).toBe true + expect(changedDecorationNode.children.length).toBe 0 + + it "removes any decorations that existed previously but aren't in the latest update", -> + customDecorations = 'test-gutter': + 'decoration-id-1': + top: 0 + height: 10 + class: 'test-class-1' + customGutterComponent.updateSync(buildTestState(customDecorations)) + decorationsWrapperNode = customGutterComponent.getDomNode().children.item(0) + expect(decorationsWrapperNode.children.length).toBe 1 + + emptyCustomDecorations = 'test-gutter': {} + customGutterComponent.updateSync(buildTestState(emptyCustomDecorations)) + expect(decorationsWrapperNode.children.length).toBe 0 From 5dfa6b3e1ecdf6578905961580067c7e3c24b268 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Sat, 4 Apr 2015 19:50:14 -0700 Subject: [PATCH 0832/1783] [Gutter] Remove test-only CSS --- src/custom-gutter-component.coffee | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/custom-gutter-component.coffee b/src/custom-gutter-component.coffee index 68f91f7ff..0549870e9 100644 --- a/src/custom-gutter-component.coffee +++ b/src/custom-gutter-component.coffee @@ -3,11 +3,6 @@ # This class represents a gutter other than the 'line-numbers' gutter. # The contents of this gutter may be specified by Decorations. -# TODO (jssln) Remove these (testing-only). -TEMP_MIN_WIDTH = 25 -TEMP_DECOR_WIDTH = '50px' -TEMP_DECOR_BACKGROUND = 'white' - module.exports = class CustomGutterComponent @@ -19,8 +14,6 @@ class CustomGutterComponent @domNode = atom.views.getView(@gutter) @decorationsNode = @domNode.firstChild - @domNode.style['width'] = '' + TEMP_MIN_WIDTH + 'px' - getDomNode: -> @domNode @@ -73,8 +66,6 @@ class CustomGutterComponent newNode.style.top = decorationInfo.top + 'px' newNode.style.height = decorationInfo.height + 'px' newNode.style.position = 'absolute' - newNode.style['background-color'] = TEMP_DECOR_BACKGROUND - newNode.style.width = TEMP_DECOR_WIDTH if decorationInfo.class newNode.classList.add(decorationInfo.class) @setDecorationItem(decorationInfo.item, decorationInfo.height, decorationId, newNode) From 79b460a0ca8cd09790fdacf470238e7d7dab5aaa Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Sat, 18 Apr 2015 16:23:30 -0700 Subject: [PATCH 0833/1783] [Gutter] Add ::getDomNode method to all 'components' --- spec/text-editor-component-spec.coffee | 6 ++--- src/cursors-component.coffee | 3 +++ src/highlights-component.coffee | 3 +++ src/input-component.coffee | 3 +++ src/lines-component.coffee | 7 ++++-- src/scrollbar-component.coffee | 3 +++ src/scrollbar-corner-component.coffee | 3 +++ src/text-editor-component.coffee | 31 ++++++++++++++------------ src/text-editor-element.coffee | 8 +++---- src/text-editor-view.coffee | 2 +- 10 files changed, 45 insertions(+), 24 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 31dff8450..a89bee1fc 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -46,7 +46,7 @@ describe "TextEditorComponent", -> lineHeightInPixels = editor.getLineHeightInPixels() charWidth = editor.getDefaultCharWidth() - componentNode = component.domNode + componentNode = component.getDomNode() verticalScrollbarNode = componentNode.querySelector('.vertical-scrollbar') horizontalScrollbarNode = componentNode.querySelector('.horizontal-scrollbar') @@ -2392,7 +2392,7 @@ describe "TextEditorComponent", -> wrapperView.appendTo(hiddenParent) {component} = wrapperView - componentNode = component.domNode + componentNode = component.getDomNode() expect(componentNode.querySelectorAll('.line').length).toBe 0 hiddenParent.style.display = 'block' @@ -2599,7 +2599,7 @@ describe "TextEditorComponent", -> expect(wrapperNode.classList.contains('mini')).toBe true it "does not have an opaque background on lines", -> - expect(component.linesComponent.domNode.getAttribute('style')).not.toContain 'background-color' + expect(component.linesComponent.getDomNode().getAttribute('style')).not.toContain 'background-color' it "does not render invisible characters", -> atom.config.set('editor.invisibles', eol: 'E') diff --git a/src/cursors-component.coffee b/src/cursors-component.coffee index bd530ce2b..2de4f1ede 100644 --- a/src/cursors-component.coffee +++ b/src/cursors-component.coffee @@ -7,6 +7,9 @@ class CursorsComponent @domNode = document.createElement('div') @domNode.classList.add('cursors') + getDomNode: -> + @domNode + updateSync: (state) -> newState = state.content @oldState ?= {cursors: {}} diff --git a/src/highlights-component.coffee b/src/highlights-component.coffee index e2c629cb9..5a5747d4c 100644 --- a/src/highlights-component.coffee +++ b/src/highlights-component.coffee @@ -17,6 +17,9 @@ class HighlightsComponent insertionPoint.setAttribute('select', '.underlayer') @domNode.appendChild(insertionPoint) + getDomNode: -> + @domNode + updateSync: (state) -> newState = state.content.highlights @oldState ?= {} diff --git a/src/input-component.coffee b/src/input-component.coffee index f6f8917f6..88c1cf480 100644 --- a/src/input-component.coffee +++ b/src/input-component.coffee @@ -7,6 +7,9 @@ class InputComponent @domNode.style['-webkit-transform'] = 'translateZ(0)' @domNode.addEventListener 'paste', (event) -> event.preventDefault() + getDomNode: -> + @domNode + updateSync: (state) -> @oldState ?= {} newState = state.hiddenInput diff --git a/src/lines-component.coffee b/src/lines-component.coffee index 5004d4060..fbec40b79 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -29,16 +29,19 @@ class LinesComponent @domNode.classList.add('lines') @cursorsComponent = new CursorsComponent(@presenter) - @domNode.appendChild(@cursorsComponent.domNode) + @domNode.appendChild(@cursorsComponent.getDomNode()) @highlightsComponent = new HighlightsComponent(@presenter) - @domNode.appendChild(@highlightsComponent.domNode) + @domNode.appendChild(@highlightsComponent.getDomNode()) if @useShadowDOM insertionPoint = document.createElement('content') insertionPoint.setAttribute('select', '.overlayer') @domNode.appendChild(insertionPoint) + getDomNode: -> + @domNode + updateSync: (state) -> @newState = state.content @oldState ?= {lines: {}} diff --git a/src/scrollbar-component.coffee b/src/scrollbar-component.coffee index 3a63a33ed..45cfbd240 100644 --- a/src/scrollbar-component.coffee +++ b/src/scrollbar-component.coffee @@ -12,6 +12,9 @@ class ScrollbarComponent @domNode.addEventListener 'scroll', @onScrollCallback + getDomNode: -> + @domNode + updateSync: (state) -> @oldState ?= {} switch @orientation diff --git a/src/scrollbar-corner-component.coffee b/src/scrollbar-corner-component.coffee index 986d28f17..bc059f12c 100644 --- a/src/scrollbar-corner-component.coffee +++ b/src/scrollbar-corner-component.coffee @@ -7,6 +7,9 @@ class ScrollbarCornerComponent @contentNode = document.createElement('div') @domNode.appendChild(@contentNode) + getDomNode: -> + @domNode + updateSync: (state) -> @oldState ?= {} @newState ?= {} diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 89f541775..136656dcc 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -73,19 +73,19 @@ class TextEditorComponent @mountGutterContainerComponent() if @presenter.getState().gutters.sortedDescriptions.length @hiddenInputComponent = new InputComponent - @scrollViewNode.appendChild(@hiddenInputComponent.domNode) + @scrollViewNode.appendChild(@hiddenInputComponent.getDomNode()) @linesComponent = new LinesComponent({@presenter, @hostElement, @useShadowDOM}) - @scrollViewNode.appendChild(@linesComponent.domNode) + @scrollViewNode.appendChild(@linesComponent.getDomNode()) @horizontalScrollbarComponent = new ScrollbarComponent({orientation: 'horizontal', onScroll: @onHorizontalScroll}) - @scrollViewNode.appendChild(@horizontalScrollbarComponent.domNode) + @scrollViewNode.appendChild(@horizontalScrollbarComponent.getDomNode()) @verticalScrollbarComponent = new ScrollbarComponent({orientation: 'vertical', onScroll: @onVerticalScroll}) - @domNode.appendChild(@verticalScrollbarComponent.domNode) + @domNode.appendChild(@verticalScrollbarComponent.getDomNode()) @scrollbarCornerComponent = new ScrollbarCornerComponent - @domNode.appendChild(@scrollbarCornerComponent.domNode) + @domNode.appendChild(@scrollbarCornerComponent.getDomNode()) @observeEditor() @listenForDOMEvents() @@ -108,6 +108,9 @@ class TextEditorComponent @presenter.destroy() window.removeEventListener 'resize', @requestHeightAndWidthMeasurement + getDomNode: -> + @domNode + updateSync: -> @oldState ?= {} @newState = @presenter.getState() @@ -138,7 +141,7 @@ class TextEditorComponent @mountGutterContainerComponent() unless @gutterContainerComponent? @gutterContainerComponent.updateSync(@newState) else - @gutterContainerComponent?.domNode?.remove() + @gutterContainerComponent?.getDomNode()?.remove() @gutterContainerComponent = null @hiddenInputComponent.updateSync(@newState) @@ -163,7 +166,7 @@ class TextEditorComponent mountGutterContainerComponent: -> @gutterContainerComponent = new GutterContainerComponent({@editor, @onLineNumberGutterMouseDown}) - @domNode.insertBefore(@gutterContainerComponent.domNode, @domNode.firstChild) + @domNode.insertBefore(@gutterContainerComponent.getDomNode(), @domNode.firstChild) becameVisible: -> @updatesPaused = true @@ -282,7 +285,7 @@ class TextEditorComponent focused: -> if @mounted @presenter.setFocused(true) - @hiddenInputComponent.domNode.focus() + @hiddenInputComponent.getDomNode().focus() blurred: -> if @mounted @@ -646,7 +649,7 @@ class TextEditorComponent lineNumberGutter = @gutterContainerComponent?.getLineNumberGutterComponent() if lineNumberGutter - gutterBackgroundColor = getComputedStyle(lineNumberGutter.domNode).backgroundColor + gutterBackgroundColor = getComputedStyle(lineNumberGutter.getDomNode()).backgroundColor @presenter.setGutterBackgroundColor(gutterBackgroundColor) measureLineHeightAndDefaultCharWidth: -> @@ -666,7 +669,7 @@ class TextEditorComponent measureScrollbars: -> @measureScrollbarsWhenShown = false - cornerNode = @scrollbarCornerComponent.domNode + cornerNode = @scrollbarCornerComponent.getDomNode() originalDisplayValue = cornerNode.style.display cornerNode.style.display = 'block' @@ -692,9 +695,9 @@ class TextEditorComponent @measureScrollbarsWhenShown = true return - verticalNode = @verticalScrollbarComponent.domNode - horizontalNode = @horizontalScrollbarComponent.domNode - cornerNode = @scrollbarCornerComponent.domNode + verticalNode = @verticalScrollbarComponent.getDomNode() + horizontalNode = @horizontalScrollbarComponent.getDomNode() + cornerNode = @scrollbarCornerComponent.getDomNode() originalVerticalDisplayValue = verticalNode.style.display originalHorizontalDisplayValue = horizontalNode.style.display @@ -764,7 +767,7 @@ class TextEditorComponent pixelPositionForMouseEvent: (event) -> {clientX, clientY} = event - linesClientRect = @linesComponent.domNode.getBoundingClientRect() + linesClientRect = @linesComponent.getDomNode().getBoundingClientRect() top = clientY - linesClientRect.top left = clientX - linesClientRect.left {top, left} diff --git a/src/text-editor-element.coffee b/src/text-editor-element.coffee index 0884b4248..95c60f9a0 100644 --- a/src/text-editor-element.coffee +++ b/src/text-editor-element.coffee @@ -113,12 +113,12 @@ class TextEditorElement extends HTMLElement lineOverdrawMargin: @lineOverdrawMargin useShadowDOM: @useShadowDOM ) - @rootElement.appendChild(@component.domNode) + @rootElement.appendChild(@component.getDomNode()) if @useShadowDOM @shadowRoot.addEventListener('blur', @shadowRootBlurred.bind(this), true) else - inputNode = @component.hiddenInputComponent.domNode + inputNode = @component.hiddenInputComponent.getDomNode() inputNode.addEventListener 'focus', @focused.bind(this) inputNode.addEventListener 'blur', => @dispatchEvent(new FocusEvent('blur', bubbles: false)) @@ -126,7 +126,7 @@ class TextEditorElement extends HTMLElement callRemoveHooks(this) if @component? @component.destroy() - @component.domNode.remove() + @component.getDomNode().remove() @component = null focused: -> @@ -134,7 +134,7 @@ class TextEditorElement extends HTMLElement blurred: (event) -> unless @useShadowDOM - if event.relatedTarget is @component.hiddenInputComponent.domNode + if event.relatedTarget is @component.hiddenInputComponent.getDomNode() event.stopImmediatePropagation() return diff --git a/src/text-editor-view.coffee b/src/text-editor-view.coffee index e75b6609b..b86367ef4 100644 --- a/src/text-editor-view.coffee +++ b/src/text-editor-view.coffee @@ -125,7 +125,7 @@ class TextEditorView extends View Object.defineProperty @::, 'firstRenderedScreenRow', get: -> @component.getRenderedRowRange()[0] Object.defineProperty @::, 'lastRenderedScreenRow', get: -> @component.getRenderedRowRange()[1] Object.defineProperty @::, 'active', get: -> @is(@getPaneView()?.activeView) - Object.defineProperty @::, 'isFocused', get: -> document.activeElement is @element or document.activeElement is @element.component?.hiddenInputComponent?.domNode + Object.defineProperty @::, 'isFocused', get: -> document.activeElement is @element or document.activeElement is @element.component?.hiddenInputComponent?.getDomNode() Object.defineProperty @::, 'mini', get: -> @model?.isMini() Object.defineProperty @::, 'component', get: -> @element?.component From 85188ced03fdac0eb61694455e69020600f067c7 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Sat, 18 Apr 2015 16:48:38 -0700 Subject: [PATCH 0834/1783] [Gutter] Move 'lineNumberGutter' state to nest under 'gutters' in the presenter state --- spec/gutter-container-component-spec.coffee | 6 +++--- spec/text-editor-presenter-spec.coffee | 6 +++--- src/line-number-gutter-component.coffee | 2 +- src/text-editor-presenter.coffee | 12 ++++++------ 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/spec/gutter-container-component-spec.coffee b/spec/gutter-container-component-spec.coffee index cb3ca37eb..1a286e522 100644 --- a/spec/gutter-container-component-spec.coffee +++ b/spec/gutter-container-component-spec.coffee @@ -13,9 +13,9 @@ describe "GutterContainerComponent", -> backgroundColor: 'black' sortedDescriptions: sortedDescriptions customDecorations: {} - lineNumberGutter: - maxLineNumberDigits: 10 - lineNumbers: {} + lineNumberGutter: + maxLineNumberDigits: 10 + lineNumbers: {} mockTestState beforeEach -> diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 9cf1c2236..5597d031c 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -1771,10 +1771,10 @@ describe "TextEditorPresenter", -> it "is set to the number of digits used by the greatest line number", -> presenter = buildPresenter() expect(editor.getLastBufferRow()).toBe 12 - expect(presenter.getState().lineNumberGutter.maxLineNumberDigits).toBe 2 + expect(presenter.getState().gutters.lineNumberGutter.maxLineNumberDigits).toBe 2 editor.setText("1\n2\n3") - expect(presenter.getState().lineNumberGutter.maxLineNumberDigits).toBe 1 + expect(presenter.getState().gutters.lineNumberGutter.maxLineNumberDigits).toBe 1 describe ".lineNumbers", -> lineNumberStateForScreenRow = (presenter, screenRow) -> @@ -1786,7 +1786,7 @@ describe "TextEditorPresenter", -> else key = bufferRow - presenter.getState().lineNumberGutter.lineNumbers[key] + presenter.getState().gutters.lineNumberGutter.lineNumbers[key] it "contains states for line numbers that are visible on screen, plus and minus the overdraw margin", -> editor.foldBufferRow(4) diff --git a/src/line-number-gutter-component.coffee b/src/line-number-gutter-component.coffee index b79b08fdb..e37244680 100644 --- a/src/line-number-gutter-component.coffee +++ b/src/line-number-gutter-component.coffee @@ -34,7 +34,7 @@ class LineNumberGutterComponent @visible = true updateSync: (state) -> - @newState = state.lineNumberGutter + @newState = state.gutters.lineNumberGutter @oldState ?= {lineNumbers: {}} @appendDummyLineNumber() unless @dummyLineNumberNode? diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 3c2e5f5ca..7ce51effe 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -183,11 +183,11 @@ class TextEditorPresenter lines: {} highlights: {} overlays: {} - lineNumberGutter: - lineNumbers: {} gutters: sortedDescriptions: [] customDecorations: {} + lineNumberGutter: + lineNumbers: {} @updateState() updateState: -> @@ -384,7 +384,7 @@ class TextEditorPresenter return updateLineNumberGutterState: -> @batch "shouldUpdateLineNumberGutterState", -> - @state.lineNumberGutter.maxLineNumberDigits = @model.getLineCount().toString().length + @state.gutters.lineNumberGutter.maxLineNumberDigits = @model.getLineCount().toString().length updateCommonGutterState: -> @state.gutters.backgroundColor = if @gutterBackgroundColor isnt "rgba(0, 0, 0, 0)" @@ -481,7 +481,7 @@ class TextEditorPresenter decorationClasses = @lineNumberDecorationClassesForRow(screenRow) foldable = @model.isFoldableAtScreenRow(screenRow) - @state.lineNumberGutter.lineNumbers[id] = {screenRow, bufferRow, softWrapped, top, decorationClasses, foldable} + @state.gutters.lineNumberGutter.lineNumbers[id] = {screenRow, bufferRow, softWrapped, top, decorationClasses, foldable} visibleLineNumberIds[id] = true if @mouseWheelScreenRow? @@ -491,8 +491,8 @@ class TextEditorPresenter id += '-' + wrapCount if wrapCount > 0 visibleLineNumberIds[id] = true - for id of @state.lineNumberGutter.lineNumbers - delete @state.lineNumberGutter.lineNumbers[id] unless visibleLineNumberIds[id] + for id of @state.gutters.lineNumberGutter.lineNumbers + delete @state.gutters.lineNumberGutter.lineNumbers[id] unless visibleLineNumberIds[id] return From af629f8416f24f32571bcc1f96022d688985e089 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Sat, 18 Apr 2015 18:12:03 -0700 Subject: [PATCH 0835/1783] [Gutter] Remove check for null decorationState in CustomGutterComponent --- src/custom-gutter-component.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/custom-gutter-component.coffee b/src/custom-gutter-component.coffee index 0549870e9..9d9ca51f0 100644 --- a/src/custom-gutter-component.coffee +++ b/src/custom-gutter-component.coffee @@ -36,7 +36,6 @@ class CustomGutterComponent setDimensionsAndBackground(@oldDimensionsAndBackgroundState, newDimensionsAndBackgroundState, @decorationsNode) decorationState = state.gutters.customDecorations[@getName()] - return if !decorationState updatedDecorationIds = new Set for decorationId, decorationInfo of decorationState From c9cbef9a0c7da32b8fb94c83af5e911da82a99ab Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Sat, 18 Apr 2015 18:43:24 -0700 Subject: [PATCH 0836/1783] [Gutter] Avoid reading position info off DOM nodes directly in CustomGutterComponent --- src/custom-gutter-component.coffee | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/custom-gutter-component.coffee b/src/custom-gutter-component.coffee index 9d9ca51f0..eb23de56d 100644 --- a/src/custom-gutter-component.coffee +++ b/src/custom-gutter-component.coffee @@ -35,6 +35,7 @@ class CustomGutterComponent newDimensionsAndBackgroundState = state.gutters setDimensionsAndBackground(@oldDimensionsAndBackgroundState, newDimensionsAndBackgroundState, @decorationsNode) + @oldDecorationPositionState ?= {}; decorationState = state.gutters.customDecorations[@getName()] updatedDecorationIds = new Set @@ -53,6 +54,7 @@ class CustomGutterComponent decorationNode.remove() delete @decorationNodesById[decorationId] delete @decorationItemsById[decorationId] + delete @oldDecorationPositionState[decorationId] ### Section: Private Methods @@ -60,10 +62,13 @@ class CustomGutterComponent # Builds and returns an HTMLElement to represent the specified decoration. buildDecorationHTML: (decorationId, decorationInfo) -> + @oldDecorationPositionState[decorationId] = positionState = {}; newNode = document.createElement('div') newNode.classList.add('decoration') newNode.style.top = decorationInfo.top + 'px' + positionState.top = decorationInfo.top + 'px' newNode.style.height = decorationInfo.height + 'px' + positionState.height = decorationInfo.height + 'px' newNode.style.position = 'absolute' if decorationInfo.class newNode.classList.add(decorationInfo.class) @@ -73,11 +78,15 @@ class CustomGutterComponent # Updates the existing HTMLNode with the new decoration info. Attempts to # minimize changes to the DOM. updateDecorationHTML: (existingNode, decorationId, newDecorationInfo) -> - if existingNode.style.top isnt newDecorationInfo.top + 'px' - existingNode.style.top = newDecorationInfo.top + 'px' + oldPositionState = @oldDecorationPositionState[decorationId]; - if existingNode.style.height isnt newDecorationInfo.height + 'px' + if oldPositionState.top isnt newDecorationInfo.top + 'px' + existingNode.style.top = newDecorationInfo.top + 'px' + oldPositionState.top = newDecorationInfo.top + 'px' + + if oldPositionState.height isnt newDecorationInfo.height + 'px' existingNode.style.height = newDecorationInfo.height + 'px' + oldPositionState.height = newDecorationInfo.height + 'px' if newDecorationInfo.class and !existingNode.classList.contains(newDecorationInfo.class) existingNode.className = 'decoration' From 09d1b977de7a13b9bcb50910f524e32cc0ee3c16 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Sat, 18 Apr 2015 18:53:52 -0700 Subject: [PATCH 0837/1783] [Gutter] Convert ! to 'not', && to 'and' --- src/custom-gutter-component.coffee | 8 ++++---- src/gutter-container-component.coffee | 6 +++--- src/gutter-container.coffee | 2 +- src/line-number-gutter-component.coffee | 2 +- src/text-editor-presenter.coffee | 10 +++++----- src/text-editor.coffee | 2 +- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/custom-gutter-component.coffee b/src/custom-gutter-component.coffee index eb23de56d..9af0abdc0 100644 --- a/src/custom-gutter-component.coffee +++ b/src/custom-gutter-component.coffee @@ -26,7 +26,7 @@ class CustomGutterComponent @visible = false showNode: -> - if !@visible + if not @visible @domNode.style.removeProperty('display') @visible = true @@ -50,7 +50,7 @@ class CustomGutterComponent @decorationsNode.appendChild(newNode) for decorationId, decorationNode of @decorationNodesById - if !updatedDecorationIds.has(decorationId) + if not updatedDecorationIds.has(decorationId) decorationNode.remove() delete @decorationNodesById[decorationId] delete @decorationItemsById[decorationId] @@ -88,10 +88,10 @@ class CustomGutterComponent existingNode.style.height = newDecorationInfo.height + 'px' oldPositionState.height = newDecorationInfo.height + 'px' - if newDecorationInfo.class and !existingNode.classList.contains(newDecorationInfo.class) + if newDecorationInfo.class and not existingNode.classList.contains(newDecorationInfo.class) existingNode.className = 'decoration' existingNode.classList.add(newDecorationInfo.class) - else if !newDecorationInfo.class + else if not newDecorationInfo.class existingNode.className = 'decoration' @setDecorationItem(newDecorationInfo.item, newDecorationInfo.height, decorationId, existingNode) diff --git a/src/gutter-container-component.coffee b/src/gutter-container-component.coffee index b478b96c3..87747acea 100644 --- a/src/gutter-container-component.coffee +++ b/src/gutter-container-component.coffee @@ -31,7 +31,7 @@ class GutterContainerComponent newGutterComponentsByGutterName = {} for {gutter, visible} in newState gutterComponent = @gutterComponentsByGutterName[gutter.name] - if !gutterComponent + if not gutterComponent if gutter.name is 'line-number' gutterComponent = new LineNumberGutterComponent({onMouseDown: @onLineNumberGutterMouseDown, @editor, gutter}) @lineNumberGutterComponent = gutterComponent @@ -66,7 +66,7 @@ class GutterContainerComponent if existingGutterComponent.getName() == gutterComponent.getName() matchingGutterFound = true break - if !matchingGutterFound + if not matchingGutterFound # If we've reached this point, the gutter previously existed, but its # position has moved. Remove it from the DOM and re-insert it. gutterComponent.getDomNode().remove() @@ -80,5 +80,5 @@ class GutterContainerComponent # Remove any gutters that were not present in the new gutters state. for gutterComponent in @gutterComponents - if !newGutterComponentsByGutterName[gutterComponent.getName()] + if not newGutterComponentsByGutterName[gutterComponent.getName()] gutterComponent.getDomNode().remove() diff --git a/src/gutter-container.coffee b/src/gutter-container.coffee index e7b68ef52..075c15f60 100644 --- a/src/gutter-container.coffee +++ b/src/gutter-container.coffee @@ -44,7 +44,7 @@ class GutterContainer @gutters.splice(i, 0, newGutter) inserted = true break - if !inserted + if not inserted @gutters.push newGutter @emitter.emit 'did-add-gutter', newGutter return newGutter diff --git a/src/line-number-gutter-component.coffee b/src/line-number-gutter-component.coffee index e37244680..d09a50619 100644 --- a/src/line-number-gutter-component.coffee +++ b/src/line-number-gutter-component.coffee @@ -29,7 +29,7 @@ class LineNumberGutterComponent @visible = false showNode: -> - if !@visible + if not @visible @domNode.style.removeProperty('display') @visible = true diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 7ce51effe..ec07aa839 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -434,7 +434,7 @@ class TextEditorPresenter for gutter in @model.getGutters() gutterName = gutter.name @state.gutters.customDecorations[gutterName] = {} - return if !@gutterIsVisible(gutter) + return if not @gutterIsVisible(gutter) relevantDecorations = @customGutterDecorationsInRange(gutterName, @startRow, @endRow - 1) relevantDecorations.forEach (decoration) => @@ -448,7 +448,7 @@ class TextEditorPresenter gutterIsVisible: (gutterModel) -> isVisible = gutterModel.isVisible() if gutterModel.name is 'line-number' - isVisible = isVisible && @showLineNumbers + isVisible = isVisible and @showLineNumbers isVisible updateLineNumbersState: -> @batch "shouldUpdateLineNumbersState", -> @@ -649,7 +649,7 @@ class TextEditorPresenter decorations = new Set return decorations if @model.isMini() or gutterName is 'line-number' or - !@customGutterDecorationsByGutterNameAndScreenRow[gutterName] + not @customGutterDecorationsByGutterNameAndScreenRow[gutterName] for bufferRow in @model.bufferRowsForScreenRows(@startRow, @endRow - 1) for id, decoration of @customGutterDecorationsByGutterNameAndScreenRow[gutterName][bufferRow] @@ -995,8 +995,8 @@ class TextEditorPresenter @updateLinesState() if decoration.isType('line-number') or Decoration.isType(oldProperties, 'line-number') @updateLineNumbersState() - if (decoration.isType('gutter') and !decoration.isType('line-number')) or - (Decoration.isType(oldProperties, 'gutter') and !Decoration.isType(oldProperties, 'line-number')) + if (decoration.isType('gutter') and not decoration.isType('line-number')) or + (Decoration.isType(oldProperties, 'gutter') and not Decoration.isType(oldProperties, 'line-number')) @updateCustomGutterDecorationState() else if decoration.isType('overlay') @updateOverlaysState() diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 6692790f6..3f01c9ff7 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -1308,7 +1308,7 @@ class TextEditor extends Model # # Returns a {Decoration} object decorateMarker: (marker, decorationParams) -> - if decorationParams.type is 'gutter' && !decorationParams.gutterName + if decorationParams.type is 'gutter' and not decorationParams.gutterName deprecate("Decorations of `type: 'gutter'` have been renamed to `type: 'line-number'`.") decorationParams.type = 'line-number' @displayBuffer.decorateMarker(marker, decorationParams) From 166f040077bf46befa19be383067e91332f62670 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Sat, 18 Apr 2015 19:00:02 -0700 Subject: [PATCH 0838/1783] [Gutter] Address rename nit in CustomGutterComponent-spec --- spec/custom-gutter-component-spec.coffee | 48 ++++++++++++------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/spec/custom-gutter-component-spec.coffee b/spec/custom-gutter-component-spec.coffee index baf857455..21db68653 100644 --- a/spec/custom-gutter-component-spec.coffee +++ b/spec/custom-gutter-component-spec.coffee @@ -2,28 +2,28 @@ CustomGutterComponent = require '../src/custom-gutter-component' Gutter = require '../src/gutter' describe "CustomGutterComponent", -> - [customGutterComponent, gutter] = [] + [gutterComponent, gutter] = [] beforeEach -> mockGutterContainer = {} gutter = new Gutter(mockGutterContainer, {name: 'test-gutter'}) - customGutterComponent = new CustomGutterComponent({gutter}) + gutterComponent = new CustomGutterComponent({gutter}) it "creates a gutter DOM node with only an empty 'custom-decorations' child node when it is initialized", -> - expect(customGutterComponent.getDomNode().classList.contains('gutter')).toBe true - expect(customGutterComponent.getDomNode().getAttribute('gutter-name')).toBe 'test-gutter' - expect(customGutterComponent.getDomNode().children.length).toBe 1 - decorationsWrapperNode = customGutterComponent.getDomNode().children.item(0) + expect(gutterComponent.getDomNode().classList.contains('gutter')).toBe true + expect(gutterComponent.getDomNode().getAttribute('gutter-name')).toBe 'test-gutter' + expect(gutterComponent.getDomNode().children.length).toBe 1 + decorationsWrapperNode = gutterComponent.getDomNode().children.item(0) expect(decorationsWrapperNode.classList.contains('custom-decorations')).toBe true it "makes its view accessible from the view registry", -> - expect(customGutterComponent.getDomNode()).toBe atom.views.getView(gutter) + expect(gutterComponent.getDomNode()).toBe atom.views.getView(gutter) it "hides its DOM node when ::hideNode is called, and shows its DOM node when ::showNode is called", -> - customGutterComponent.hideNode() - expect(customGutterComponent.getDomNode().style.display).toBe 'none' - customGutterComponent.showNode() - expect(customGutterComponent.getDomNode().style.display).toBe '' + gutterComponent.hideNode() + expect(gutterComponent.getDomNode().style.display).toBe 'none' + gutterComponent.showNode() + expect(gutterComponent.getDomNode().style.display).toBe '' describe "::updateSync", -> decorationItem1 = document.createElement('div') @@ -42,12 +42,12 @@ describe "CustomGutterComponent", -> mockTestState it "sets the custom-decoration wrapper's scrollHeight, scrollTop, and background color", -> - decorationsWrapperNode = customGutterComponent.getDomNode().children.item(0) + decorationsWrapperNode = gutterComponent.getDomNode().children.item(0) expect(decorationsWrapperNode.style.height).toBe '' expect(decorationsWrapperNode.style['-webkit-transform']).toBe '' expect(decorationsWrapperNode.style.backgroundColor).toBe '' - customGutterComponent.updateSync(buildTestState({})) + gutterComponent.updateSync(buildTestState({})) expect(decorationsWrapperNode.style.height).not.toBe '' expect(decorationsWrapperNode.style['-webkit-transform']).not.toBe '' expect(decorationsWrapperNode.style.backgroundColor).not.toBe '' @@ -60,8 +60,8 @@ describe "CustomGutterComponent", -> item: decorationItem1 class: 'test-class-1' - customGutterComponent.updateSync(buildTestState(customDecorations)) - decorationsWrapperNode = customGutterComponent.getDomNode().children.item(0) + gutterComponent.updateSync(buildTestState(customDecorations)) + decorationsWrapperNode = gutterComponent.getDomNode().children.item(0) expect(decorationsWrapperNode.children.length).toBe 1 decorationNode = decorationsWrapperNode.children.item(0) @@ -81,8 +81,8 @@ describe "CustomGutterComponent", -> height: 10 item: decorationItem1 class: 'test-class-1' - customGutterComponent.updateSync(buildTestState(initialCustomDecorations)) - initialDecorationNode = customGutterComponent.getDomNode().children.item(0).children.item(0) + gutterComponent.updateSync(buildTestState(initialCustomDecorations)) + initialDecorationNode = gutterComponent.getDomNode().children.item(0).children.item(0) # Change the dimensions and item, remove the class. decorationItem2 = document.createElement('div') @@ -91,8 +91,8 @@ describe "CustomGutterComponent", -> top: 10 height: 20 item: decorationItem2 - customGutterComponent.updateSync(buildTestState(changedCustomDecorations)) - changedDecorationNode = customGutterComponent.getDomNode().children.item(0).children.item(0) + gutterComponent.updateSync(buildTestState(changedCustomDecorations)) + changedDecorationNode = gutterComponent.getDomNode().children.item(0).children.item(0) expect(changedDecorationNode).toBe initialDecorationNode expect(changedDecorationNode.style.top).toBe '10px' expect(changedDecorationNode.style.height).toBe '20px' @@ -108,8 +108,8 @@ describe "CustomGutterComponent", -> top: 10 height: 20 class: 'test-class-2' - customGutterComponent.updateSync(buildTestState(changedCustomDecorations)) - changedDecorationNode = customGutterComponent.getDomNode().children.item(0).children.item(0) + gutterComponent.updateSync(buildTestState(changedCustomDecorations)) + changedDecorationNode = gutterComponent.getDomNode().children.item(0).children.item(0) expect(changedDecorationNode).toBe initialDecorationNode expect(changedDecorationNode.style.top).toBe '10px' expect(changedDecorationNode.style.height).toBe '20px' @@ -123,10 +123,10 @@ describe "CustomGutterComponent", -> top: 0 height: 10 class: 'test-class-1' - customGutterComponent.updateSync(buildTestState(customDecorations)) - decorationsWrapperNode = customGutterComponent.getDomNode().children.item(0) + gutterComponent.updateSync(buildTestState(customDecorations)) + decorationsWrapperNode = gutterComponent.getDomNode().children.item(0) expect(decorationsWrapperNode.children.length).toBe 1 emptyCustomDecorations = 'test-gutter': {} - customGutterComponent.updateSync(buildTestState(emptyCustomDecorations)) + gutterComponent.updateSync(buildTestState(emptyCustomDecorations)) expect(decorationsWrapperNode.children.length).toBe 0 From 303cb4c3680e2550164e7eaf3497be1323e14d19 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Mon, 20 Apr 2015 21:15:02 -0700 Subject: [PATCH 0839/1783] [Gutter] Rename 'HTML' to 'Node' in some methods --- src/custom-gutter-component.coffee | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/custom-gutter-component.coffee b/src/custom-gutter-component.coffee index 9af0abdc0..748fcac3e 100644 --- a/src/custom-gutter-component.coffee +++ b/src/custom-gutter-component.coffee @@ -43,9 +43,9 @@ class CustomGutterComponent updatedDecorationIds.add(decorationId) existingDecoration = @decorationNodesById[decorationId] if existingDecoration - @updateDecorationHTML(existingDecoration, decorationId, decorationInfo) + @updateDecorationNode(existingDecoration, decorationId, decorationInfo) else - newNode = @buildDecorationHTML(decorationId, decorationInfo) + newNode = @buildDecorationNode(decorationId, decorationInfo) @decorationNodesById[decorationId] = newNode @decorationsNode.appendChild(newNode) @@ -61,7 +61,7 @@ class CustomGutterComponent ### # Builds and returns an HTMLElement to represent the specified decoration. - buildDecorationHTML: (decorationId, decorationInfo) -> + buildDecorationNode: (decorationId, decorationInfo) -> @oldDecorationPositionState[decorationId] = positionState = {}; newNode = document.createElement('div') newNode.classList.add('decoration') @@ -77,7 +77,7 @@ class CustomGutterComponent # Updates the existing HTMLNode with the new decoration info. Attempts to # minimize changes to the DOM. - updateDecorationHTML: (existingNode, decorationId, newDecorationInfo) -> + updateDecorationNode: (existingNode, decorationId, newDecorationInfo) -> oldPositionState = @oldDecorationPositionState[decorationId]; if oldPositionState.top isnt newDecorationInfo.top + 'px' From 305147097961e83a5d98fb774edd2a29ab32d061 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Mon, 20 Apr 2015 21:33:17 -0700 Subject: [PATCH 0840/1783] [Gutter] Make CustomGutterComponent::buildDecorationNode call into ::updateDecorationNode --- src/custom-gutter-component.coffee | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/src/custom-gutter-component.coffee b/src/custom-gutter-component.coffee index 748fcac3e..02269f687 100644 --- a/src/custom-gutter-component.coffee +++ b/src/custom-gutter-component.coffee @@ -62,39 +62,32 @@ class CustomGutterComponent # Builds and returns an HTMLElement to represent the specified decoration. buildDecorationNode: (decorationId, decorationInfo) -> - @oldDecorationPositionState[decorationId] = positionState = {}; + @oldDecorationPositionState[decorationId] = {}; newNode = document.createElement('div') - newNode.classList.add('decoration') - newNode.style.top = decorationInfo.top + 'px' - positionState.top = decorationInfo.top + 'px' - newNode.style.height = decorationInfo.height + 'px' - positionState.height = decorationInfo.height + 'px' newNode.style.position = 'absolute' - if decorationInfo.class - newNode.classList.add(decorationInfo.class) - @setDecorationItem(decorationInfo.item, decorationInfo.height, decorationId, newNode) + @updateDecorationNode(newNode, decorationId, decorationInfo) newNode # Updates the existing HTMLNode with the new decoration info. Attempts to # minimize changes to the DOM. - updateDecorationNode: (existingNode, decorationId, newDecorationInfo) -> + updateDecorationNode: (node, decorationId, newDecorationInfo) -> oldPositionState = @oldDecorationPositionState[decorationId]; if oldPositionState.top isnt newDecorationInfo.top + 'px' - existingNode.style.top = newDecorationInfo.top + 'px' + node.style.top = newDecorationInfo.top + 'px' oldPositionState.top = newDecorationInfo.top + 'px' if oldPositionState.height isnt newDecorationInfo.height + 'px' - existingNode.style.height = newDecorationInfo.height + 'px' + node.style.height = newDecorationInfo.height + 'px' oldPositionState.height = newDecorationInfo.height + 'px' - if newDecorationInfo.class and not existingNode.classList.contains(newDecorationInfo.class) - existingNode.className = 'decoration' - existingNode.classList.add(newDecorationInfo.class) + if newDecorationInfo.class and not node.classList.contains(newDecorationInfo.class) + node.className = 'decoration' + node.classList.add(newDecorationInfo.class) else if not newDecorationInfo.class - existingNode.className = 'decoration' + node.className = 'decoration' - @setDecorationItem(newDecorationInfo.item, newDecorationInfo.height, decorationId, existingNode) + @setDecorationItem(newDecorationInfo.item, newDecorationInfo.height, decorationId, node) # Sets the decorationItem on the decorationNode. # If `decorationItem` is undefined, the decorationNode's child item will be cleared. From 6f66d2fd5de98b7bbad06cbb012032d9daf86103 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Mon, 20 Apr 2015 22:04:18 -0700 Subject: [PATCH 0841/1783] [Gutter] Convert GutterContainerComponent::updateChildGutters -> ::reorderGutters --- src/gutter-container-component.coffee | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/gutter-container-component.coffee b/src/gutter-container-component.coffee index 87747acea..04d0920d6 100644 --- a/src/gutter-container-component.coffee +++ b/src/gutter-container-component.coffee @@ -38,10 +38,11 @@ class GutterContainerComponent else gutterComponent = new CustomGutterComponent({gutter}) if visible then gutterComponent.showNode() else gutterComponent.hideNode() + gutterComponent.updateSync(state) newGutterComponents.push(gutterComponent) newGutterComponentsByGutterName[gutter.name] = gutterComponent - @updateChildGutters(state, newGutterComponents, newGutterComponentsByGutterName) + @reorderGutters(newGutterComponents, newGutterComponentsByGutterName) @gutterComponents = newGutterComponents @gutterComponentsByGutterName = newGutterComponentsByGutterName @@ -50,12 +51,12 @@ class GutterContainerComponent Section: Private Methods ### - updateChildGutters: (state, newGutterComponents, newGutterComponentsByGutterName) -> + reorderGutters: (newGutterComponents, newGutterComponentsByGutterName) -> # First, insert new gutters into the DOM. indexInOldGutters = 0 oldGuttersLength = @gutterComponents.length + for gutterComponent in newGutterComponents - gutterComponent.updateSync(state) if @gutterComponentsByGutterName[gutterComponent.getName()] # If the gutter existed previously, we first try to move the cursor to # the point at which it occurs in the previous gutters. From 9abd0232ce2fe3d8b9f97713e3750fb836b17fde Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Mon, 20 Apr 2015 21:07:32 -0700 Subject: [PATCH 0842/1783] [Gutter] Remove `::getName` from gutter components; save names in GutterContainerComponent --- src/custom-gutter-component.coffee | 5 +---- src/gutter-container-component.coffee | 23 ++++++++++++++++------- src/line-number-gutter-component.coffee | 3 --- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/custom-gutter-component.coffee b/src/custom-gutter-component.coffee index 02269f687..ee4282860 100644 --- a/src/custom-gutter-component.coffee +++ b/src/custom-gutter-component.coffee @@ -17,9 +17,6 @@ class CustomGutterComponent getDomNode: -> @domNode - getName: -> - @gutter.name - hideNode: -> if @visible @domNode.style.display = 'none' @@ -36,7 +33,7 @@ class CustomGutterComponent setDimensionsAndBackground(@oldDimensionsAndBackgroundState, newDimensionsAndBackgroundState, @decorationsNode) @oldDecorationPositionState ?= {}; - decorationState = state.gutters.customDecorations[@getName()] + decorationState = state.gutters.customDecorations[@gutter.name] updatedDecorationIds = new Set for decorationId, decorationInfo of decorationState diff --git a/src/gutter-container-component.coffee b/src/gutter-container-component.coffee index 04d0920d6..097214556 100644 --- a/src/gutter-container-component.coffee +++ b/src/gutter-container-component.coffee @@ -8,6 +8,7 @@ module.exports = class GutterContainerComponent constructor: ({@onLineNumberGutterMouseDown, @editor}) -> + # An array of objects of the form: {name: {String}, component: {Object}} @gutterComponents = [] @gutterComponentsByGutterName = {} @lineNumberGutterComponent = null @@ -39,7 +40,10 @@ class GutterContainerComponent gutterComponent = new CustomGutterComponent({gutter}) if visible then gutterComponent.showNode() else gutterComponent.hideNode() gutterComponent.updateSync(state) - newGutterComponents.push(gutterComponent) + newGutterComponents.push({ + name: gutter.name, + component: gutterComponent, + }) newGutterComponentsByGutterName[gutter.name] = gutterComponent @reorderGutters(newGutterComponents, newGutterComponentsByGutterName) @@ -56,15 +60,19 @@ class GutterContainerComponent indexInOldGutters = 0 oldGuttersLength = @gutterComponents.length - for gutterComponent in newGutterComponents - if @gutterComponentsByGutterName[gutterComponent.getName()] + for gutterComponentDescription in newGutterComponents + gutterComponent = gutterComponentDescription.component + gutterName = gutterComponentDescription.name + + if @gutterComponentsByGutterName[gutterName] # If the gutter existed previously, we first try to move the cursor to # the point at which it occurs in the previous gutters. matchingGutterFound = false while indexInOldGutters < oldGuttersLength - existingGutterComponent = @gutterComponents[indexInOldGutters] + existingGutterComponentDescription = @gutterComponents[indexInOldGutters] + existingGutterComponent = existingGutterComponentDescription.component indexInOldGutters++ - if existingGutterComponent.getName() == gutterComponent.getName() + if existingGutterComponent == gutterComponent matchingGutterFound = true break if not matchingGutterFound @@ -80,6 +88,7 @@ class GutterContainerComponent @domNode.insertBefore(gutterComponent.getDomNode(), @domNode.children[indexInOldGutters]) # Remove any gutters that were not present in the new gutters state. - for gutterComponent in @gutterComponents - if not newGutterComponentsByGutterName[gutterComponent.getName()] + for gutterComponentDescription in @gutterComponents + if not newGutterComponentsByGutterName[gutterComponentDescription.name] + gutterComponent = gutterComponentDescription.component gutterComponent.getDomNode().remove() diff --git a/src/line-number-gutter-component.coffee b/src/line-number-gutter-component.coffee index d09a50619..9c77b6647 100644 --- a/src/line-number-gutter-component.coffee +++ b/src/line-number-gutter-component.coffee @@ -20,9 +20,6 @@ class LineNumberGutterComponent getDomNode: -> @domNode - getName: -> - @gutter.name - hideNode: -> if @visible @domNode.style.display = 'none' From 55c6a11c361cab5c2466e835b5690e3f8d62f393 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Mon, 20 Apr 2015 22:59:03 -0700 Subject: [PATCH 0843/1783] [Gutter] Add comment to explain avoided decoration update in presenter & remove test --- spec/text-editor-presenter-spec.coffee | 13 ------------- src/text-editor-presenter.coffee | 3 +++ 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 5597d031c..970d2ab30 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -2468,19 +2468,6 @@ describe "TextEditorPresenter", -> expect(decorationState[decoration3.id]).toBeUndefined() expect(decorationState[decoration4.id].top).toBeDefined() - it "does not update when a gutter is destroyed (because it's unnecessary)", -> - gutter.destroy() - decorationState = decorationStateForGutterName(presenter, 'test-gutter') - expect(decorationState[decoration1.id].top).toBeDefined() - expect(decorationState[decoration2.id].top).toBeDefined() - expect(decorationState[decoration3.id]).toBeUndefined() - - # However, the decoration state of the destroyed gutter should be - # cleared whenever ::updateCustomGutterDecorationState is next called. - expectStateUpdate presenter, -> editor.addGutter({name: 'a-different-gutter'}) - decorationState = decorationStateForGutterName(presenter, 'test-gutter') - expect(decorationState).toBeUndefined() - it "updates when editor lines are folded", -> oldDimensionsForDecoration1 = top: lineHeight * marker1.getScreenRange().start.row diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index ec07aa839..21ebfbf22 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -401,6 +401,9 @@ class TextEditorPresenter @disposables.remove(gutterDisposables) gutterDisposables.dispose() @updateCustomGutterState() + # It is not necessary to @updateCustomGutterDecorationState here. + # The destroyed gutter will be removed from the list of gutters in @state, + # and thus will be removed from the DOM. @disposables.add(gutterDisposables) @updateCustomGutterState() @updateCustomGutterDecorationState() From c7b57927739aafe0522868a77fccd70692573a4a Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Mon, 20 Apr 2015 23:03:45 -0700 Subject: [PATCH 0844/1783] [Gutter] Rename TextEditorPresenter::updateCustomGutterState -> ::updateGutterOrderState --- src/text-editor-presenter.coffee | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 21ebfbf22..17d6f8835 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -90,7 +90,7 @@ class TextEditorPresenter @updateOverlaysState() if @shouldUpdateOverlaysState @updateLineNumberGutterState() if @shouldUpdateLineNumberGutterState @updateLineNumbersState() if @shouldUpdateLineNumbersState - @updateCustomGutterState() if @shouldUpdateCustomGutterState + @updateGutterOrderState() if @shouldUpdateGutterOrderState @updateCustomGutterDecorationState() if @shouldUpdateCustomGutterDecorationState @updating = false @@ -109,7 +109,7 @@ class TextEditorPresenter @updateLinesState() @updateLineNumberGutterState() @updateLineNumbersState() - @updateCustomGutterState() + @updateGutterOrderState() @updateCustomGutterDecorationState() @disposables.add @model.onDidChangeGrammar(@didChangeGrammar.bind(this)) @disposables.add @model.onDidChangePlaceholderText(@updateContentState.bind(this)) @@ -122,12 +122,12 @@ class TextEditorPresenter @updateLineNumberGutterState() @updateLineNumbersState() @updateCommonGutterState() - @updateCustomGutterState() + @updateGutterOrderState() @updateCustomGutterDecorationState() @disposables.add @model.onDidChangeLineNumberGutterVisible => @updateLineNumberGutterState() @updateCommonGutterState() - @updateCustomGutterState() + @updateGutterOrderState() @disposables.add @model.onDidAddDecoration(@didAddDecoration.bind(this)) @disposables.add @model.onDidAddCursor(@didAddCursor.bind(this)) @disposables.add @model.onDidChangeScrollTop(@setScrollTop.bind(this)) @@ -163,14 +163,14 @@ class TextEditorPresenter @showLineNumbers = newValue @updateLineNumberGutterState() @updateCommonGutterState() - @updateCustomGutterState() + @updateGutterOrderState() didChangeGrammar: -> @observeConfig() @updateContentState() @updateLineNumberGutterState() @updateCommonGutterState() - @updateCustomGutterState() + @updateGutterOrderState() buildState: -> @state = @@ -210,7 +210,7 @@ class TextEditorPresenter @updateLineNumberGutterState() @updateLineNumbersState() @updateCommonGutterState() - @updateCustomGutterState() + @updateGutterOrderState() @updateCustomGutterDecorationState() updateFocusedState: -> @batch "shouldUpdateFocusedState", -> @@ -395,21 +395,21 @@ class TextEditorPresenter didAddGutter: (gutter) -> gutterDisposables = new CompositeDisposable gutterDisposables.add gutter.onDidChangeVisible => - @updateCustomGutterState() + @updateGutterOrderState() @updateCustomGutterDecorationState() gutterDisposables.add gutter.onDidDestroy => @disposables.remove(gutterDisposables) gutterDisposables.dispose() - @updateCustomGutterState() + @updateGutterOrderState() # It is not necessary to @updateCustomGutterDecorationState here. # The destroyed gutter will be removed from the list of gutters in @state, # and thus will be removed from the DOM. @disposables.add(gutterDisposables) - @updateCustomGutterState() + @updateGutterOrderState() @updateCustomGutterDecorationState() - updateCustomGutterState: -> - @batch "shouldUpdateCustomGutterState", -> + updateGutterOrderState: -> + @batch "shouldUpdateGutterOrderState", -> @state.gutters.sortedDescriptions = [] if @model.isMini() return @@ -808,14 +808,14 @@ class TextEditorPresenter @updateContentState() @updateLineNumberGutterState() @updateCommonGutterState() - @updateCustomGutterState() + @updateGutterOrderState() setGutterBackgroundColor: (gutterBackgroundColor) -> unless @gutterBackgroundColor is gutterBackgroundColor @gutterBackgroundColor = gutterBackgroundColor @updateLineNumberGutterState() @updateCommonGutterState() - @updateCustomGutterState() + @updateGutterOrderState() setLineHeight: (lineHeight) -> unless @lineHeight is lineHeight From 14145e11976bf6b55b9877ec788421364b0b60df Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Mon, 20 Apr 2015 23:08:25 -0700 Subject: [PATCH 0845/1783] [Gutter] removeDecorationInfoFromLineDecorationCaches -> removePropertiesFromLineDecorationCaches --- src/text-editor-presenter.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 17d6f8835..7e187615c 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -989,7 +989,7 @@ class TextEditorPresenter decorationPropertiesDidChange: (decoration, event) -> {oldProperties} = event if decoration.isType('line') or decoration.isType('gutter') - @removeDecorationInfoFromLineDecorationCaches( + @removePropertiesFromLineDecorationCaches( decoration.id, oldProperties, decoration.getMarker().getScreenRange()) @@ -1066,9 +1066,9 @@ class TextEditorPresenter return removeFromLineDecorationCaches: (decoration, range) -> - @removeDecorationInfoFromLineDecorationCaches(decoration.id, decoration.getProperties(), range) + @removePropertiesFromLineDecorationCaches(decoration.id, decoration.getProperties(), range) - removeDecorationInfoFromLineDecorationCaches: (decorationId, decorationProperties, range) -> + removePropertiesFromLineDecorationCaches: (decorationId, decorationProperties, range) -> gutterName = decorationProperties.gutterName for row in [range.start.row..range.end.row] by 1 delete @lineDecorationsByScreenRow[row]?[decorationId] From cdca9c3ef1b3b1a5f9adef9307abcbb62854ee7f Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Mon, 20 Apr 2015 23:23:48 -0700 Subject: [PATCH 0846/1783] [Gutter] Fix coffeescript style issues --- spec/display-buffer-spec.coffee | 4 ++-- spec/gutter-container-component-spec.coffee | 14 +++++++------- spec/gutter-spec.coffee | 4 ++-- src/custom-gutter-component.coffee | 6 +++--- src/gutter-container-component.coffee | 4 ++-- src/gutter-container.coffee | 4 ++-- src/text-editor-presenter.coffee | 6 +++--- 7 files changed, 21 insertions(+), 21 deletions(-) diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index f37c9ebf0..23c4840bc 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -1373,7 +1373,7 @@ describe "DisplayBuffer", -> [marker] = [] beforeEach -> - marker = displayBuffer.markBufferRange([[1, 0], [1, 0]]); + marker = displayBuffer.markBufferRange([[1, 0], [1, 0]]) it "creates a decoration that is both of 'line-number' and 'gutter' type when called with the 'line-number' type", -> decorationProperties = {type: 'line-number', class: 'one'} @@ -1384,7 +1384,7 @@ describe "DisplayBuffer", -> expect(decoration.getProperties().class).toBe 'one' it "creates a decoration that is only of 'gutter' type if called with the 'gutter' type and a 'gutterName'", -> - decorationProperties = {type: 'gutter', gutterName:'test-gutter', class: 'one'} + decorationProperties = {type: 'gutter', gutterName: 'test-gutter', class: 'one'} decoration = displayBuffer.decorateMarker(marker, decorationProperties) expect(decoration.isType('gutter')).toBe true expect(decoration.isType('line-number')).toBe false diff --git a/spec/gutter-container-component-spec.coffee b/spec/gutter-container-component-spec.coffee index 1a286e522..218d8aae2 100644 --- a/spec/gutter-container-component-spec.coffee +++ b/spec/gutter-container-component-spec.coffee @@ -86,14 +86,14 @@ describe "GutterContainerComponent", -> expect(gutterContainerComponent.getDomNode().children.item(0)).toBe expectedCustomGutterNode it "removes a gutter from the DOM if it does not appear in the latest state update", -> - lineNumberGutter = new Gutter(mockGutterContainer, {name: 'line-number'}) - testState = buildTestState([{gutter: lineNumberGutter, visible: true}]) - gutterContainerComponent.updateSync(testState) + lineNumberGutter = new Gutter(mockGutterContainer, {name: 'line-number'}) + testState = buildTestState([{gutter: lineNumberGutter, visible: true}]) + gutterContainerComponent.updateSync(testState) - expect(gutterContainerComponent.getDomNode().children.length).toBe 1 - testState = buildTestState([]) - gutterContainerComponent.updateSync(testState) - expect(gutterContainerComponent.getDomNode().children.length).toBe 0 + expect(gutterContainerComponent.getDomNode().children.length).toBe 1 + testState = buildTestState([]) + gutterContainerComponent.updateSync(testState) + expect(gutterContainerComponent.getDomNode().children.length).toBe 0 describe "when updated with multiple gutters", -> it "positions (and repositions) the gutters to match the order they appear in each state update", -> diff --git a/spec/gutter-spec.coffee b/spec/gutter-spec.coffee index ba6933a05..30748b787 100644 --- a/spec/gutter-spec.coffee +++ b/spec/gutter-spec.coffee @@ -46,9 +46,9 @@ describe 'Gutter', -> [mockGutterContainer, mockGutterContainerRemovedGutters] = [] beforeEach -> - mockGutterContainerRemovedGutters = []; + mockGutterContainerRemovedGutters = [] mockGutterContainer = removeGutter: (destroyedGutter) -> - mockGutterContainerRemovedGutters.push destroyedGutter + mockGutterContainerRemovedGutters.push destroyedGutter it 'removes the gutter from its container.', -> gutter = new Gutter mockGutterContainer, {name} diff --git a/src/custom-gutter-component.coffee b/src/custom-gutter-component.coffee index ee4282860..380322e8b 100644 --- a/src/custom-gutter-component.coffee +++ b/src/custom-gutter-component.coffee @@ -32,7 +32,7 @@ class CustomGutterComponent newDimensionsAndBackgroundState = state.gutters setDimensionsAndBackground(@oldDimensionsAndBackgroundState, newDimensionsAndBackgroundState, @decorationsNode) - @oldDecorationPositionState ?= {}; + @oldDecorationPositionState ?= {} decorationState = state.gutters.customDecorations[@gutter.name] updatedDecorationIds = new Set @@ -59,7 +59,7 @@ class CustomGutterComponent # Builds and returns an HTMLElement to represent the specified decoration. buildDecorationNode: (decorationId, decorationInfo) -> - @oldDecorationPositionState[decorationId] = {}; + @oldDecorationPositionState[decorationId] = {} newNode = document.createElement('div') newNode.style.position = 'absolute' @updateDecorationNode(newNode, decorationId, decorationInfo) @@ -68,7 +68,7 @@ class CustomGutterComponent # Updates the existing HTMLNode with the new decoration info. Attempts to # minimize changes to the DOM. updateDecorationNode: (node, decorationId, newDecorationInfo) -> - oldPositionState = @oldDecorationPositionState[decorationId]; + oldPositionState = @oldDecorationPositionState[decorationId] if oldPositionState.top isnt newDecorationInfo.top + 'px' node.style.top = newDecorationInfo.top + 'px' diff --git a/src/gutter-container-component.coffee b/src/gutter-container-component.coffee index 097214556..e7fec35d5 100644 --- a/src/gutter-container-component.coffee +++ b/src/gutter-container-component.coffee @@ -72,7 +72,7 @@ class GutterContainerComponent existingGutterComponentDescription = @gutterComponents[indexInOldGutters] existingGutterComponent = existingGutterComponentDescription.component indexInOldGutters++ - if existingGutterComponent == gutterComponent + if existingGutterComponent is gutterComponent matchingGutterFound = true break if not matchingGutterFound @@ -82,7 +82,7 @@ class GutterContainerComponent @domNode.appendChild(gutterComponent.getDomNode()) else - if indexInOldGutters == oldGuttersLength + if indexInOldGutters is oldGuttersLength @domNode.appendChild(gutterComponent.getDomNode()) else @domNode.insertBefore(gutterComponent.getDomNode(), @domNode.children[indexInOldGutters]) diff --git a/src/gutter-container.coffee b/src/gutter-container.coffee index 075c15f60..db75daa27 100644 --- a/src/gutter-container.coffee +++ b/src/gutter-container.coffee @@ -30,7 +30,7 @@ class GutterContainer addGutter: (options) -> options = options ? {} gutterName = options.name - if gutterName == null + if gutterName is null throw new Error('A name is required to create a gutter.') if @gutterWithName(gutterName) throw new Error('Tried to create a gutter with a name that is already in use.') @@ -54,7 +54,7 @@ class GutterContainer gutterWithName: (name) -> for gutter in @gutters - if gutter.name == name then return gutter + if gutter.name is name then return gutter null ### diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 7e187615c..10e37ca9e 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -388,9 +388,9 @@ class TextEditorPresenter updateCommonGutterState: -> @state.gutters.backgroundColor = if @gutterBackgroundColor isnt "rgba(0, 0, 0, 0)" - @gutterBackgroundColor - else - @backgroundColor + @gutterBackgroundColor + else + @backgroundColor didAddGutter: (gutter) -> gutterDisposables = new CompositeDisposable From 6cbb344616723d90f2c9f0bee3eb2f25f230de80 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Mon, 20 Apr 2015 23:32:35 -0700 Subject: [PATCH 0847/1783] [Gutter] Remove emissary usage --- src/gutter-container.coffee | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/gutter-container.coffee b/src/gutter-container.coffee index db75daa27..1be52d519 100644 --- a/src/gutter-container.coffee +++ b/src/gutter-container.coffee @@ -1,12 +1,10 @@ {Emitter} = require 'event-kit' -{Subscriber} = require 'emissary' Gutter = require './gutter' # This class encapsulates the logic for adding and modifying a set of gutters. module.exports = class GutterContainer - Subscriber.includeInto(this) # * `textEditor` The {TextEditor} to which this {GutterContainer} belongs. constructor: (textEditor) -> @@ -17,7 +15,6 @@ class GutterContainer destroy: -> @gutters = null @emitter.dispose() - @unsubscribe() # Creates and returns a {Gutter}. # * `options` An {Object} with the following fields: @@ -84,7 +81,6 @@ class GutterContainer index = @gutters.indexOf(gutter) if index > -1 @gutters.splice(index, 1) - @unsubscribe gutter @emitter.emit 'did-remove-gutter', gutter.name else throw new Error 'The given gutter cannot be removed because it is not ' + From 39491533904d54d5509c83a9c002bfb233c13922 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Tue, 21 Apr 2015 08:44:17 -0700 Subject: [PATCH 0848/1783] [Gutter] Presenter should return gutter decorations for screen row range, not buffer row range --- spec/text-editor-presenter-spec.coffee | 4 +++- src/text-editor-presenter.coffee | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 970d2ab30..5a50a49a9 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -2483,9 +2483,11 @@ describe "TextEditorPresenter", -> decorationState = decorationStateForGutterName(presenter, 'test-gutter') expect(decorationState[decoration1.id].top).toBe oldDimensionsForDecoration1.top expect(decorationState[decoration1.id].height).not.toBe oldDimensionsForDecoration1.height + # Due to the issue described here: https://github.com/atom/atom/issues/6454, decoration2 + # will be bumped up to the row that was folded and still made visible, instead of being + # entirely collapsed. (The same thing will happen to decoration3.) expect(decorationState[decoration2.id].top).not.toBe oldDimensionsForDecoration2.top expect(decorationState[decoration2.id].height).not.toBe oldDimensionsForDecoration2.height - expect(decorationState[decoration3.id]).toBeUndefined() # disabled until we fix an issue with display buffer markers not updating when # they are moved on screen but not in the buffer diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 10e37ca9e..55b88f2b8 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -654,8 +654,8 @@ class TextEditorPresenter return decorations if @model.isMini() or gutterName is 'line-number' or not @customGutterDecorationsByGutterNameAndScreenRow[gutterName] - for bufferRow in @model.bufferRowsForScreenRows(@startRow, @endRow - 1) - for id, decoration of @customGutterDecorationsByGutterNameAndScreenRow[gutterName][bufferRow] + for screenRow in [@startRow..@endRow - 1] + for id, decoration of @customGutterDecorationsByGutterNameAndScreenRow[gutterName][screenRow] decorations.add(decoration) decorations From 5f38719dfcba2578e5b4547e24274d372c749856 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 22 Apr 2015 10:27:07 -0700 Subject: [PATCH 0849/1783] :arrow_up: scrollbar-style@3.1 --- package.json | 2 +- src/text-editor-component.coffee | 2 +- src/workspace-element.coffee | 2 +- src/workspace-view.coffee | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index d9debf674..dd82c0449 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "runas": "2.0.0", "scandal": "2.0.3", "scoped-property-store": "^0.17.0", - "scrollbar-style": "^2.0.0", + "scrollbar-style": "^3.1", "season": "^5.1.4", "semver": "^4.3.3", "serializable": "^1", diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 4c8e567f0..15287866e 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -95,7 +95,7 @@ class TextEditorComponent @disposables.add @stylesElement.onDidRemoveStyleElement @onStylesheetsChanged unless atom.themes.isInitialLoadComplete() @disposables.add atom.themes.onDidChangeActiveThemes @onAllThemesLoaded - @disposables.add scrollbarStyle.changes.onValue @refreshScrollbars + @disposables.add scrollbarStyle.onDidChangePreferredScrollbarStyle @refreshScrollbars @disposables.add atom.views.pollDocument(@pollDOM) diff --git a/src/workspace-element.coffee b/src/workspace-element.coffee index 85fb2f308..2d0cb4e49 100644 --- a/src/workspace-element.coffee +++ b/src/workspace-element.coffee @@ -44,7 +44,7 @@ class WorkspaceElement extends HTMLElement @appendChild(@horizontalAxis) observeScrollbarStyle: -> - @subscriptions.add scrollbarStyle.onValue (style) => + @subscriptions.add scrollbarStyle.observePreferredScrollbarStyle (style) => switch style when 'legacy' @classList.remove('scrollbars-visible-when-scrolling') diff --git a/src/workspace-view.coffee b/src/workspace-view.coffee index 6a4a685d8..6fe9f6848 100644 --- a/src/workspace-view.coffee +++ b/src/workspace-view.coffee @@ -4,7 +4,6 @@ Q = require 'q' _ = require 'underscore-plus' Delegator = require 'delegato' {deprecate, logDeprecationWarnings} = require 'grim' -scrollbarStyle = require 'scrollbar-style' {$, $$, View} = require './space-pen-extensions' fs = require 'fs-plus' Workspace = require './workspace' From df070e9f1f8056e5afc03f3e104b4744f86ede4a Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Wed, 22 Apr 2015 11:10:50 -0700 Subject: [PATCH 0850/1783] [Gutter] Add back `includeDeprecatedAPIs` gate on `gutter` type decorations --- 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 3f01c9ff7..861f6231e 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -1308,7 +1308,7 @@ class TextEditor extends Model # # Returns a {Decoration} object decorateMarker: (marker, decorationParams) -> - if decorationParams.type is 'gutter' and not decorationParams.gutterName + if includeDeprecatedAPIs and decorationParams.type is 'gutter' and not decorationParams.gutterName deprecate("Decorations of `type: 'gutter'` have been renamed to `type: 'line-number'`.") decorationParams.type = 'line-number' @displayBuffer.decorateMarker(marker, decorationParams) From ec3f37dee35b7c158fdfcb4f375e6b76e92eb2bd Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 22 Apr 2015 11:59:32 -0600 Subject: [PATCH 0851/1783] Avoid deprecation warnings in spec --- 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 6926e057f..4e990b914 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -4271,6 +4271,8 @@ describe "TextEditor", -> marker = editor.markBufferRange([[1, 0], [1, 0]]) it "casts 'gutter' type to 'line-number' unless a gutter name is specified.", -> + jasmine.snapshotDeprecations() + lineNumberDecoration = editor.decorateMarker(marker, {type: 'gutter'}) customGutterDecoration = editor.decorateMarker(marker, {type: 'gutter', gutterName: 'custom'}) expect(lineNumberDecoration.getProperties().type).toBe 'line-number' @@ -4278,6 +4280,8 @@ describe "TextEditor", -> expect(customGutterDecoration.getProperties().type).toBe 'gutter' expect(customGutterDecoration.getProperties().gutterName).toBe 'custom' + jasmine.restoreDeprecationsSnapshot() + it 'reflects an added decoration when one of its custom gutters is decorated.', -> gutter = editor.addGutter {'name': 'custom-gutter'} decoration = gutter.decorateMarker marker, {class: 'custom-class'} From 9cd1c4bbe4cd406886b89eaa61b2babe9d34c842 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 22 Apr 2015 16:38:33 -0700 Subject: [PATCH 0852/1783] :arrow_up: notifications@0.41 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dd82c0449..7529d8de5 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,7 @@ "link": "0.30.0", "markdown-preview": "0.148.0", "metrics": "0.45.0", - "notifications": "0.40.0", + "notifications": "0.41.0", "open-on-github": "0.36.0", "package-generator": "0.38.0", "release-notes": "0.52.0", From 626c9924fe681ce81adbc76a0bd06db03cab629d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 22 Apr 2015 16:46:28 -0700 Subject: [PATCH 0853/1783] Remove deprecation about returning a disposable --- src/pane-view.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/pane-view.coffee b/src/pane-view.coffee index 4474d2d3b..775514ca2 100644 --- a/src/pane-view.coffee +++ b/src/pane-view.coffee @@ -116,7 +116,6 @@ class PaneView extends View if item.onDidChangeTitle? disposable = item.onDidChangeTitle(@activeItemTitleChanged) - deprecate 'Please return a Disposable object from your ::onDidChangeTitle method!' unless disposable?.dispose? @activeItemDisposables.add(disposable) if disposable?.dispose? else if item.on? disposable = item.on('title-changed', @activeItemTitleChanged) @@ -124,7 +123,6 @@ class PaneView extends View if item.onDidChangeModified? disposable = item.onDidChangeModified(@activeItemModifiedChanged) - deprecate 'Please return a Disposable object from your ::onDidChangeModified method!' unless disposable?.dispose? @activeItemDisposables.add(disposable) if disposable?.dispose? else if item.on? item.on('modified-status-changed', @activeItemModifiedChanged) From 1a7cbbb56c9431c54bb4759c7b7317b485255bb4 Mon Sep 17 00:00:00 2001 From: "Machiste N. Quintana" Date: Thu, 23 Apr 2015 07:51:18 -0400 Subject: [PATCH 0854/1783] :arrow_up: welcome@0.27.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7529d8de5..ee182bb1b 100644 --- a/package.json +++ b/package.json @@ -120,7 +120,7 @@ "timecop": "0.31.0", "tree-view": "0.170.0", "update-package-dependencies": "0.9.0", - "welcome": "0.26.0", + "welcome": "0.27.0", "whitespace": "0.29.0", "wrap-guide": "0.32.0", "language-c": "0.44.0", From 4aea6f32a726b81f388565670e3147dfc6d5a839 Mon Sep 17 00:00:00 2001 From: "Machiste N. Quintana" Date: Thu, 23 Apr 2015 07:55:15 -0400 Subject: [PATCH 0855/1783] :arrow_up: tree-view@0.171.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7529d8de5..779cb86d2 100644 --- a/package.json +++ b/package.json @@ -118,7 +118,7 @@ "symbols-view": "0.94.0", "tabs": "0.67.0", "timecop": "0.31.0", - "tree-view": "0.170.0", + "tree-view": "0.171.0", "update-package-dependencies": "0.9.0", "welcome": "0.26.0", "whitespace": "0.29.0", From d2cd05ebdcdc6f0631367d62cadb212bb3d8e840 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Thu, 23 Apr 2015 11:59:17 -0700 Subject: [PATCH 0856/1783] Add a handler for an `unhandledRejection`. --- static/index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/static/index.js b/static/index.js index aa582f845..2db98a382 100644 --- a/static/index.js +++ b/static/index.js @@ -5,6 +5,10 @@ window.onload = function() { try { var startTime = Date.now(); + process.on('unhandledRejection', function(error, promise) { + console.error('Unhandled promise rejection %o with error: %o', promise, error); + }); + // Ensure ATOM_HOME is always set before anything else is required setupAtomHome(); From fc7825f54919f4eaed04caa0db5cc5e74acbef24 Mon Sep 17 00:00:00 2001 From: Tom Pusateri Date: Thu, 23 Apr 2015 16:02:15 -0400 Subject: [PATCH 0857/1783] Update csslint version. --- build/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/package.json b/build/package.json index e4612eb6f..82feaad92 100644 --- a/build/package.json +++ b/build/package.json @@ -17,11 +17,11 @@ "grunt-cli": "~0.1.9", "grunt-coffeelint": "git+https://github.com/atom/grunt-coffeelint.git#cfb99aa99811d52687969532bd5a98011ed95bfe", "grunt-contrib-coffee": "~0.12.0", - "grunt-contrib-csslint": "~0.1.2", + "grunt-contrib-csslint": "~0.2.0", "grunt-contrib-less": "~0.8.0", "grunt-cson": "0.14.0", "grunt-download-atom-shell": "~0.14.0", - "grunt-lesslint": "0.13.0", + "grunt-lesslint": "0.17.0", "grunt-peg": "~1.1.0", "grunt-shell": "~0.3.1", "harmony-collections": "~0.3.8", From 01927bc60c1d5e31fb6ffd11c3bea07a2d5b85b0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 23 Apr 2015 13:53:30 -0700 Subject: [PATCH 0858/1783] :arrow_up: language-perl@0.23 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2f6cd0190..5ade10cb9 100644 --- a/package.json +++ b/package.json @@ -140,7 +140,7 @@ "language-make": "0.14.0", "language-mustache": "0.11.0", "language-objective-c": "0.15.0", - "language-perl": "0.22.0", + "language-perl": "0.23.0", "language-php": "0.22.0", "language-property-list": "0.8.0", "language-python": "0.34.0", From c4c28d54298404bed53ba3ca281f6e7772606a68 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 23 Apr 2015 14:04:44 -0700 Subject: [PATCH 0859/1783] :arrow_up: language-javascript@0.74 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5ade10cb9..f94ea35a5 100644 --- a/package.json +++ b/package.json @@ -134,7 +134,7 @@ "language-html": "0.32.0", "language-hyperlink": "0.12.2", "language-java": "0.14.0", - "language-javascript": "0.73.0", + "language-javascript": "0.74.0", "language-json": "0.14.0", "language-less": "0.26.0", "language-make": "0.14.0", From af6de70154b42d48e358f3bbee950d11ad64d107 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Thu, 23 Apr 2015 17:34:41 -0400 Subject: [PATCH 0860/1783] :arrow_up: encoding-selector@0.20.0, spell-check@0.56.0, symbols-view@0.95.0 --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index f94ea35a5..ed4edd847 100644 --- a/package.json +++ b/package.json @@ -92,7 +92,7 @@ "command-palette": "0.35.0", "deprecation-cop": "0.40.0", "dev-live-reload": "0.45.0", - "encoding-selector": "0.19.0", + "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", "feedback": "0.38.0", "find-and-replace": "0.160.0", @@ -112,10 +112,10 @@ "release-notes": "0.52.0", "settings-view": "0.195.0", "snippets": "0.88.0", - "spell-check": "0.55.0", + "spell-check": "0.56.0", "status-bar": "0.69.0", "styleguide": "0.44.0", - "symbols-view": "0.94.0", + "symbols-view": "0.95.0", "tabs": "0.67.0", "timecop": "0.31.0", "tree-view": "0.171.0", From 1dbab06fe333de6f8c3ee5761a735157d15025ea Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Thu, 23 Apr 2015 18:16:29 -0400 Subject: [PATCH 0861/1783] Replace optimist with yargs --- package.json | 4 ++-- src/browser/main.coffee | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index f94ea35a5..504eb05fa 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,6 @@ "mixto": "^1", "nslog": "^2.0.0", "oniguruma": "^4.1", - "optimist": "0.4.0", "pathwatcher": "^4.4", "property-accessors": "^1.1.3", "q": "^1.1.2", @@ -67,7 +66,8 @@ "text-buffer": "^5.2", "theorist": "^1.0.2", "typescript-simple": "1.0.0", - "underscore-plus": "^1.6.6" + "underscore-plus": "^1.6.6", + "yargs": "^3.7.2" }, "packageDependencies": { "atom-dark-syntax": "0.26.0", diff --git a/src/browser/main.coffee b/src/browser/main.coffee index 469d53fae..908501a1c 100644 --- a/src/browser/main.coffee +++ b/src/browser/main.coffee @@ -4,7 +4,7 @@ crashReporter = require 'crash-reporter' app = require 'app' fs = require 'fs-plus' path = require 'path' -optimist = require 'optimist' +yargs = require 'yargs' nslog = require 'nslog' console.log = nslog @@ -85,7 +85,7 @@ setupCoffeeCache = -> parseCommandLine = -> version = app.getVersion() - options = optimist(process.argv[1..]) + options = yargs(process.argv[1..]) options.usage """ Atom Editor v#{version} From f2a4acdaaee696c3d23f8ad42d5d5ec444974a23 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 23 Apr 2015 15:44:17 -0700 Subject: [PATCH 0862/1783] :arrow_up: language-javascript@0.75 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f94ea35a5..3ea6e8d91 100644 --- a/package.json +++ b/package.json @@ -134,7 +134,7 @@ "language-html": "0.32.0", "language-hyperlink": "0.12.2", "language-java": "0.14.0", - "language-javascript": "0.74.0", + "language-javascript": "0.75.0", "language-json": "0.14.0", "language-less": "0.26.0", "language-make": "0.14.0", From 3bd0093eb32c4e9552bf4f548895fab610eddbac Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 23 Apr 2015 16:10:06 -0700 Subject: [PATCH 0863/1783] Update scrollbar style spec for new library API --- spec/workspace-view-spec.coffee | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/spec/workspace-view-spec.coffee b/spec/workspace-view-spec.coffee index 586e72fe8..a160cdb39 100644 --- a/spec/workspace-view-spec.coffee +++ b/spec/workspace-view-spec.coffee @@ -242,10 +242,15 @@ describe "WorkspaceView", -> describe "the scrollbar visibility class", -> it "has a class based on the style of the scrollbar", -> + style = 'legacy' scrollbarStyle = require 'scrollbar-style' - scrollbarStyle.emitValue 'legacy' + spyOn(scrollbarStyle, 'getPreferredScrollbarStyle').andCallFake -> style + + atom.workspaceView.element.observeScrollbarStyle() expect(atom.workspaceView).toHaveClass 'scrollbars-visible-always' - scrollbarStyle.emitValue 'overlay' + + style = 'overlay' + atom.workspaceView.element.observeScrollbarStyle() expect(atom.workspaceView).toHaveClass 'scrollbars-visible-when-scrolling' describe "editor font styling", -> From 0b243070969cf1740c86392b6bab1491af0ff97d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 22 Apr 2015 09:38:02 -0700 Subject: [PATCH 0864/1783] Mark atom.notifications public --- src/atom.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/atom.coffee b/src/atom.coffee index e2544640d..1cf63b397 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -151,7 +151,7 @@ class Atom extends Model # Public: A {TooltipManager} instance tooltips: null - # Experimental: A {NotificationManager} instance + # Public: A {NotificationManager} instance notifications: null # Public: A {Project} instance From 1cd5bb0f8d7a63642025cf383ffcafbb8e9ec44b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 22 Apr 2015 09:38:15 -0700 Subject: [PATCH 0865/1783] Mark NotificationManager public and add docs --- src/notification-manager.coffee | 35 +++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/notification-manager.coffee b/src/notification-manager.coffee index f811a501f..b1f71fe68 100644 --- a/src/notification-manager.coffee +++ b/src/notification-manager.coffee @@ -1,8 +1,8 @@ {Emitter, Disposable} = require 'event-kit' Notification = require '../src/notification' -# Experimental: Allows messaging the user. This will likely change, dont use -# quite yet! +# Public: A notification manager used to create {Notification}s to be shown +# to the user. module.exports = class NotificationManager constructor: -> @@ -13,6 +13,12 @@ class NotificationManager Section: Events ### + # Public: Invoke the given callback after a notification has been added. + # + # * `callback` {Function} to be called after the notification is added. + # * `notification` The {Notification} that was added. + # + # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. onDidAddNotification: (callback) -> @emitter.on 'did-add-notification', callback @@ -20,18 +26,43 @@ class NotificationManager Section: Adding Notifications ### + # Public: Add a success notification. + # + # * `message` A {String} message + # * `options` An options {Object} with optional keys such as: + # * `detail` A {String} with additional details about the notification addSuccess: (message, options) -> @addNotification(new Notification('success', message, options)) + # Public: Add an informational notification. + # + # * `message` A {String} message + # * `options` An options {Object} with optional keys such as: + # * `detail` A {String} with additional details about the notification addInfo: (message, options) -> @addNotification(new Notification('info', message, options)) + # Public: Add a warning notification. + # + # * `message` A {String} message + # * `options` An options {Object} with optional keys such as: + # * `detail` A {String} with additional details about the notification addWarning: (message, options) -> @addNotification(new Notification('warning', message, options)) + # Public: Add an error notification. + # + # * `message` A {String} message + # * `options` An options {Object} with optional keys such as: + # * `detail` A {String} with additional details about the notification addError: (message, options) -> @addNotification(new Notification('error', message, options)) + # Public: Add a fatal error notification. + # + # * `message` A {String} message + # * `options` An options {Object} with optional keys such as: + # * `detail` A {String} with additional details about the notification addFatalError: (message, options) -> @addNotification(new Notification('fatal', message, options)) From d4c1775cf7f5306af193643e2a1a9b0c9adc4363 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 22 Apr 2015 09:38:37 -0700 Subject: [PATCH 0866/1783] Mark Notification public and add docs --- src/notification.coffee | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/notification.coffee b/src/notification.coffee index 43044c182..5e962fea7 100644 --- a/src/notification.coffee +++ b/src/notification.coffee @@ -1,6 +1,6 @@ {Emitter} = require 'event-kit' -# Experimental: This will likely change, do not use. +# Public: A notification to the user containing a message and type. module.exports = class Notification constructor: (@type, @message, @options={}) -> @@ -18,8 +18,10 @@ class Notification getOptions: -> @options + # Public: Retrieves the {String} notification type. getType: -> @type + # Public: Retrieves the {String} notification message. getMessage: -> @message getTimestamp: -> @timestamp From 05fdc852828cccffecb4884e7b4e60034c17bbf6 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 22 Apr 2015 09:41:50 -0700 Subject: [PATCH 0867/1783] Mark getNotifications as public and return an array copy --- src/notification-manager.coffee | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/notification-manager.coffee b/src/notification-manager.coffee index b1f71fe68..f4ebd97db 100644 --- a/src/notification-manager.coffee +++ b/src/notification-manager.coffee @@ -78,7 +78,10 @@ class NotificationManager Section: Getting Notifications ### - getNotifications: -> @notifications + # Public: Get all the notifications. + # + # Returns an {Array} of {Notifications}s. + getNotifications: -> @notifications.slice() ### Section: Managing Notifications From ec9310e94f18926f5603d41d21db3251e4e9fffd Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 22 Apr 2015 16:20:31 -0700 Subject: [PATCH 0868/1783] :memo: Drop redundant notification --- src/notification.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/notification.coffee b/src/notification.coffee index 5e962fea7..9dfffc59a 100644 --- a/src/notification.coffee +++ b/src/notification.coffee @@ -18,10 +18,10 @@ class Notification getOptions: -> @options - # Public: Retrieves the {String} notification type. + # Public: Retrieves the {String} type. getType: -> @type - # Public: Retrieves the {String} notification message. + # Public: Retrieves the {String} message. getMessage: -> @message getTimestamp: -> @timestamp From cc8bbde6dc881cf67585c384c714948c2b98b1e0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 23 Apr 2015 16:59:02 -0700 Subject: [PATCH 0869/1783] Mention twitter account --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index cafeca707..c33ca7e0e 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ Atom is a hackable text editor for the 21st century, built on [Electron](https:/ Visit [atom.io](https://atom.io) to learn more or visit the [Atom forum](https://discuss.atom.io). +:bird: Follow [@AtomEditor](https://twitter.com/atomeditor) on Twitter. :bird: + Visit [issue #3684](https://github.com/atom/atom/issues/3684) to learn more about the Atom 1.0 roadmap. From 59a4ce35bbe7c8646e05d508fcd74d7c3cc6fd3a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 23 Apr 2015 17:03:37 -0700 Subject: [PATCH 0870/1783] Mention Twitter is for important stuff --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c33ca7e0e..8958f303d 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,8 @@ Atom is a hackable text editor for the 21st century, built on [Electron](https:/ Visit [atom.io](https://atom.io) to learn more or visit the [Atom forum](https://discuss.atom.io). -:bird: Follow [@AtomEditor](https://twitter.com/atomeditor) on Twitter. :bird: +Follow [@AtomEditor](https://twitter.com/atomeditor) on Twitter for important +announcements. Visit [issue #3684](https://github.com/atom/atom/issues/3684) to learn more about the Atom 1.0 roadmap. From 9510db03d4e509817a6cd98bb42f2ca9c5ee5ce7 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Fri, 24 Apr 2015 13:19:04 +0800 Subject: [PATCH 0871/1783] :arrow_up: apm@0.162.0 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index 3cd607758..a3f6fae96 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.161.0" + "atom-package-manager": "0.162.0" } } From 07f80bcb8a1192f913c0111a55e75b0d91c7d5f6 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Fri, 24 Apr 2015 13:19:29 +0800 Subject: [PATCH 0872/1783] :arrow_up: asar@0.5.0 --- build/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/package.json b/build/package.json index 82feaad92..c60bdbae5 100644 --- a/build/package.json +++ b/build/package.json @@ -6,7 +6,7 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "asar": "^0.4.4", + "asar": "^0.5.0", "async": "~0.2.9", "donna": "1.0.10", "formidable": "~1.0.14", From 0c25184624b3bccdf35635e8d1d162ca60e55930 Mon Sep 17 00:00:00 2001 From: Ivan Zuzak Date: Fri, 24 Apr 2015 16:54:41 +0200 Subject: [PATCH 0873/1783] Add package name to Grim.deprecate call for activationEvents --- src/package.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/package.coffee b/src/package.coffee index 8003d2d8d..4c1b296a1 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -465,7 +465,7 @@ class Package @activationCommands[selector].push(commands...) if includeDeprecatedAPIs and @metadata.activationEvents? - deprecate """ + deprecate(""" Use `activationCommands` instead of `activationEvents` in your package.json Commands should be grouped by selector as follows: ```json @@ -474,7 +474,7 @@ class Package "atom-text-editor": ["foo:quux"] } ``` - """ + """, {packageName: @name}) if _.isArray(@metadata.activationEvents) for eventName in @metadata.activationEvents @activationCommands['atom-workspace'] ?= [] From d75d2704264d9d383bab254bc79b8b62bda36f5f Mon Sep 17 00:00:00 2001 From: Ivan Zuzak Date: Fri, 24 Apr 2015 17:02:48 +0200 Subject: [PATCH 0874/1783] Add package name to Grim.deprecate call for configDefaults --- src/package.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/package.coffee b/src/package.coffee index 4c1b296a1..a395dfb14 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -161,9 +161,9 @@ class Package if @mainModule.config? and typeof @mainModule.config is 'object' atom.config.setSchema @name, {type: 'object', properties: @mainModule.config} else if includeDeprecatedAPIs and @mainModule.configDefaults? and typeof @mainModule.configDefaults is 'object' - deprecate """Use a config schema instead. See the configuration section + deprecate("""Use a config schema instead. See the configuration section of https://atom.io/docs/latest/hacking-atom-package-word-count and - https://atom.io/docs/api/latest/Config for more details""" + https://atom.io/docs/api/latest/Config for more details""", {packageName: @name}) atom.config.setDefaults(@name, @mainModule.configDefaults) @mainModule.activateConfig?() @configActivated = true From b90310f12f4f61858dd93e63dd279ffa8ea4bb01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=C5=BDu=C5=BEak?= Date: Sat, 25 Apr 2015 12:14:03 +0200 Subject: [PATCH 0875/1783] :arrow_up: language-shellscript@0.14.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 63b903d3c..b8e6a2331 100644 --- a/package.json +++ b/package.json @@ -147,7 +147,7 @@ "language-ruby": "0.52.0", "language-ruby-on-rails": "0.21.0", "language-sass": "0.36.0", - "language-shellscript": "0.13.0", + "language-shellscript": "0.14.0", "language-source": "0.9.0", "language-sql": "0.15.0", "language-text": "0.6.0", From c771959ea0e71cba87536a7b9c27edd5006cfbd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=C5=BDu=C5=BEak?= Date: Sun, 26 Apr 2015 09:17:51 +0200 Subject: [PATCH 0876/1783] :arrow_up: one-dark-ui@0.7.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b8e6a2331..6d6a1ad83 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "atom-light-ui": "0.41.0", "base16-tomorrow-dark-theme": "0.25.0", "base16-tomorrow-light-theme": "0.8.0", - "one-dark-ui": "0.6.3", + "one-dark-ui": "0.7.0", "one-dark-syntax": "0.3.0", "one-light-syntax": "0.4.0", "one-light-ui": "0.5.3", From 44e03fd5365df2f86610b32438090452ed0a2b68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=C5=BDu=C5=BEak?= Date: Sun, 26 Apr 2015 09:18:34 +0200 Subject: [PATCH 0877/1783] :arrow_up: one-dark-syntax@0.4.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6d6a1ad83..897a96d67 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "base16-tomorrow-dark-theme": "0.25.0", "base16-tomorrow-light-theme": "0.8.0", "one-dark-ui": "0.7.0", - "one-dark-syntax": "0.3.0", + "one-dark-syntax": "0.4.0", "one-light-syntax": "0.4.0", "one-light-ui": "0.5.3", "solarized-dark-syntax": "0.32.0", From bf3707feabe5add02c8f021cc76dc79d37788f0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=C5=BDu=C5=BEak?= Date: Sun, 26 Apr 2015 09:19:39 +0200 Subject: [PATCH 0878/1783] :arrow_up: one-light-syntax@0.5.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 897a96d67..4f746cd8c 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "base16-tomorrow-light-theme": "0.8.0", "one-dark-ui": "0.7.0", "one-dark-syntax": "0.4.0", - "one-light-syntax": "0.4.0", + "one-light-syntax": "0.5.0", "one-light-ui": "0.5.3", "solarized-dark-syntax": "0.32.0", "solarized-light-syntax": "0.19.0", From 14161a63fe1b56aed834050bd8bb56180e6acfb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=C5=BDu=C5=BEak?= Date: Sun, 26 Apr 2015 09:21:09 +0200 Subject: [PATCH 0879/1783] :arrow_up: one-light-ui@0.6.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4f746cd8c..5709941fb 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "one-dark-ui": "0.7.0", "one-dark-syntax": "0.4.0", "one-light-syntax": "0.5.0", - "one-light-ui": "0.5.3", + "one-light-ui": "0.6.0", "solarized-dark-syntax": "0.32.0", "solarized-light-syntax": "0.19.0", "archive-view": "0.55.0", From cfdf5f1bcc2127cd6c2a934600950904abb998bb Mon Sep 17 00:00:00 2001 From: Ivan Zuzak Date: Sun, 26 Apr 2015 11:22:07 +0200 Subject: [PATCH 0880/1783] Move Grim.deprecate call so that it can be correctly attributed --- src/package.coffee | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/package.coffee b/src/package.coffee index a395dfb14..b16e76ba0 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -191,7 +191,20 @@ class Package for [menuPath, map] in @menus when map['context-menu']? try - @activationDisposables.add(atom.contextMenu.add(map['context-menu'])) + itemsBySelector = map['context-menu'] + + if includeDeprecatedAPIs + # Detect deprecated format for items object + for key, value of itemsBySelector + unless _.isArray(value) + deprecate(""" + The context menu CSON format has changed. Please see + https://atom.io/docs/api/latest/ContextMenuManager#context-menu-cson-format + for more info. + """, {packageName: @name}) + itemsBySelector = atom.contextMenu.convertLegacyItemsBySelector(itemsBySelector) + + @activationDisposables.add(atom.contextMenu.add(itemsBySelector)) catch error if error.code is 'EBADSELECTOR' error.message += " in #{menuPath}" From 46ab8e7f6320c1b93fc0fd65fb3b12ce3230c681 Mon Sep 17 00:00:00 2001 From: Ivan Zuzak Date: Sun, 26 Apr 2015 11:23:13 +0200 Subject: [PATCH 0881/1783] Link to section in API docs for ContextMenuManager::add --- src/context-menu-manager.coffee | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/context-menu-manager.coffee b/src/context-menu-manager.coffee index bd5ff943e..0fdcf4ab6 100644 --- a/src/context-menu-manager.coffee +++ b/src/context-menu-manager.coffee @@ -105,9 +105,9 @@ class ContextMenuManager # Detect deprecated file path as first argument if itemsBySelector? and typeof itemsBySelector isnt 'object' Grim.deprecate """ - ContextMenuManager::add has changed to take a single object as its + `ContextMenuManager::add` has changed to take a single object as its argument. Please see - https://atom.io/docs/api/latest/ContextMenuManager for more info. + https://atom.io/docs/api/latest/ContextMenuManager#context-menu-cson-format for more info. """ itemsBySelector = arguments[1] devMode = arguments[2]?.devMode @@ -116,9 +116,9 @@ class ContextMenuManager for key, value of itemsBySelector unless _.isArray(value) Grim.deprecate """ - ContextMenuManager::add has changed to take a single object as its + `ContextMenuManager::add` has changed to take a single object as its argument. Please see - https://atom.io/docs/api/latest/ContextMenuManager for more info. + https://atom.io/docs/api/latest/ContextMenuManager#context-menu-cson-format for more info. """ itemsBySelector = @convertLegacyItemsBySelector(itemsBySelector, devMode) From 21ad8f9807bc8ad19780b35c2269bf404f0c116b Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Sun, 26 Apr 2015 19:08:19 -0700 Subject: [PATCH 0882/1783] :bug: Put a limit of 100 on max font size This will prevent Atom from crashing, but still allow folks who need large font sizes for visual impairments to have them. Fix #4880 --- src/config-schema.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/config-schema.coffee b/src/config-schema.coffee index ba8150a26..f181e0149 100644 --- a/src/config-schema.coffee +++ b/src/config-schema.coffee @@ -108,6 +108,7 @@ module.exports = type: 'integer' default: 16 minimum: 1 + maximum: 100 lineHeight: type: ['string', 'number'] default: 1.3 From 415898d597e9f6e4663031d881d7dacab653c1dd Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Sun, 26 Apr 2015 23:52:48 -0400 Subject: [PATCH 0883/1783] Add font size commands to View menu --- menus/darwin.cson | 4 ++++ menus/linux.cson | 4 ++++ menus/win32.cson | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/menus/darwin.cson b/menus/darwin.cson index effd19197..f95479d99 100644 --- a/menus/darwin.cson +++ b/menus/darwin.cson @@ -168,6 +168,10 @@ ] } { type: 'separator' } + { label: 'Increase Font Size', command: 'window:increase-font-size' } + { label: 'Decrease Font Size', command: 'window:decrease-font-size' } + { label: 'Reset Font Size', command: 'window:reset-font-size' } + { type: 'separator' } { label: 'Toggle Soft Wrap', command: 'editor:toggle-soft-wrap' } ] } diff --git a/menus/linux.cson b/menus/linux.cson index 2cfb17871..5d10aa933 100644 --- a/menus/linux.cson +++ b/menus/linux.cson @@ -125,6 +125,10 @@ ] } { type: 'separator' } + { label: '&Increase Font Size', command: 'window:increase-font-size' } + { label: '&Decrease Font Size', command: 'window:decrease-font-size' } + { label: '&Reset Font Size', command: 'window:reset-font-size' } + { type: 'separator' } { label: 'Toggle Soft &Wrap', command: 'editor:toggle-soft-wrap' } ] } diff --git a/menus/win32.cson b/menus/win32.cson index 2bd013ce3..de3f7257d 100644 --- a/menus/win32.cson +++ b/menus/win32.cson @@ -124,6 +124,10 @@ ] } { type: 'separator' } + { label: '&Increase Font Size', command: 'window:increase-font-size' } + { label: '&Decrease Font Size', command: 'window:decrease-font-size' } + { label: '&Reset Font Size', command: 'window:reset-font-size' } + { type: 'separator' } { label: 'Toggle Soft &Wrap', command: 'editor:toggle-soft-wrap' } ] } From 608f5fa656ff85fce0fd0597fd722aed6251faa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=C5=BDu=C5=BEak?= Date: Mon, 27 Apr 2015 17:47:15 +0200 Subject: [PATCH 0884/1783] :arrow_up: language-gfm@0.70.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5709941fb..4853be60b 100644 --- a/package.json +++ b/package.json @@ -128,7 +128,7 @@ "language-coffee-script": "0.39.0", "language-csharp": "0.5.0", "language-css": "0.28.0", - "language-gfm": "0.69.0", + "language-gfm": "0.70.0", "language-git": "0.10.0", "language-go": "0.25.0", "language-html": "0.32.0", From 3c2acdcf9acdad4e255f8311dfd2b18a487d8f47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=C5=BDu=C5=BEak?= Date: Mon, 27 Apr 2015 18:57:33 +0200 Subject: [PATCH 0885/1783] :arrow_up: tabs@0.68.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4853be60b..513b16c61 100644 --- a/package.json +++ b/package.json @@ -116,7 +116,7 @@ "status-bar": "0.69.0", "styleguide": "0.44.0", "symbols-view": "0.95.0", - "tabs": "0.67.0", + "tabs": "0.68.0", "timecop": "0.31.0", "tree-view": "0.171.0", "update-package-dependencies": "0.9.0", From 67e7acebbd6337c255c45d78225f7882afd0033e Mon Sep 17 00:00:00 2001 From: "Machiste N. Quintana" Date: Mon, 27 Apr 2015 13:20:39 -0400 Subject: [PATCH 0886/1783] &R -> &s --- menus/linux.cson | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/menus/linux.cson b/menus/linux.cson index 5d10aa933..a826ab6b5 100644 --- a/menus/linux.cson +++ b/menus/linux.cson @@ -127,7 +127,7 @@ { type: 'separator' } { label: '&Increase Font Size', command: 'window:increase-font-size' } { label: '&Decrease Font Size', command: 'window:decrease-font-size' } - { label: '&Reset Font Size', command: 'window:reset-font-size' } + { label: 'Re&set Font Size', command: 'window:reset-font-size' } { type: 'separator' } { label: 'Toggle Soft &Wrap', command: 'editor:toggle-soft-wrap' } ] From d586b57fef2466ab25f9a7870faecfb0d16a4952 Mon Sep 17 00:00:00 2001 From: "Machiste N. Quintana" Date: Mon, 27 Apr 2015 13:21:09 -0400 Subject: [PATCH 0887/1783] &R -> &s --- menus/win32.cson | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/menus/win32.cson b/menus/win32.cson index de3f7257d..cbefc1e5c 100644 --- a/menus/win32.cson +++ b/menus/win32.cson @@ -126,7 +126,7 @@ { type: 'separator' } { label: '&Increase Font Size', command: 'window:increase-font-size' } { label: '&Decrease Font Size', command: 'window:decrease-font-size' } - { label: '&Reset Font Size', command: 'window:reset-font-size' } + { label: 'Re&set Font Size', command: 'window:reset-font-size' } { type: 'separator' } { label: 'Toggle Soft &Wrap', command: 'editor:toggle-soft-wrap' } ] From e8bd0dc7102ca2ee029c2caba5b164958659e4a0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 27 Apr 2015 15:10:36 -0700 Subject: [PATCH 0888/1783] :arrow_up: apm@0.163 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index a3f6fae96..e0656472b 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.162.0" + "atom-package-manager": "0.163.0" } } From 3cd33f69728cb329500134175872309b3ba9139b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 27 Apr 2015 15:15:56 -0700 Subject: [PATCH 0889/1783] :arrow_up: dev-live-reload@0.46 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 513b16c61..6d44eeac6 100644 --- a/package.json +++ b/package.json @@ -91,7 +91,7 @@ "bracket-matcher": "0.73.0", "command-palette": "0.35.0", "deprecation-cop": "0.40.0", - "dev-live-reload": "0.45.0", + "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", "feedback": "0.38.0", From a50f572eec167b41f31756db727de72325d26314 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 27 Apr 2015 16:55:26 -0600 Subject: [PATCH 0890/1783] :arrow_up: git-diff --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6d44eeac6..e1c87a200 100644 --- a/package.json +++ b/package.json @@ -97,7 +97,7 @@ "feedback": "0.38.0", "find-and-replace": "0.160.0", "fuzzy-finder": "0.81.0", - "git-diff": "0.54.0", + "git-diff": "0.55.0", "go-to-line": "0.30.0", "grammar-selector": "0.46.0", "image-view": "0.54.0", From da598b4c0ae407ec889cc77c96f53c480f522ec0 Mon Sep 17 00:00:00 2001 From: Daniel Hengeveld Date: Mon, 27 Apr 2015 15:55:34 -0700 Subject: [PATCH 0891/1783] Add a scopeless access token to public Travis config. It may seem strange to commit an access token to a public repository but this one has been granted no scopes, so it doesn't have access to *do* anything, and is simply used to avoid the GH API's unauthed rate limiting when fetching public assets. This path was chosen on the advice of the GH platform team. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 993787aee..6f8ff353d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ git: env: - NODE_VERSION=0.12 + - ATOM_ACCESS_TOKEN=da809a6077bb1b0aa7c5623f7b2d5f1fec2faae4 os: - linux From 201078828a540a6ba27cbe76b6120356ce04bd58 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 27 Apr 2015 16:25:06 -0700 Subject: [PATCH 0892/1783] :arrow_up: fuzzy-finder@0.82 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e1c87a200..1abe8428c 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,7 @@ "exception-reporting": "0.24.0", "feedback": "0.38.0", "find-and-replace": "0.160.0", - "fuzzy-finder": "0.81.0", + "fuzzy-finder": "0.82.0", "git-diff": "0.55.0", "go-to-line": "0.30.0", "grammar-selector": "0.46.0", From 14b0e70a001f3e7bcf072c1cf6ebb086eaa73ed1 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 27 Apr 2015 18:11:55 -0700 Subject: [PATCH 0893/1783] :arrow_up: language-html@0.33.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1abe8428c..ff062e0db 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,7 @@ "language-gfm": "0.70.0", "language-git": "0.10.0", "language-go": "0.25.0", - "language-html": "0.32.0", + "language-html": "0.33.0", "language-hyperlink": "0.12.2", "language-java": "0.14.0", "language-javascript": "0.75.0", From d04f3e2f1765f40b80399f557ccd4cb53ad5d36c Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 28 Apr 2015 08:59:22 +0200 Subject: [PATCH 0894/1783] :green_heart: Remove ATOM_ACCESS_TOKEN from build matrix --- .travis.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6f8ff353d..56e966354 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,8 +2,11 @@ git: depth: 10 env: - - NODE_VERSION=0.12 - - ATOM_ACCESS_TOKEN=da809a6077bb1b0aa7c5623f7b2d5f1fec2faae4 + matrix: + - NODE_VERSION=0.12 + + global: + - ATOM_ACCESS_TOKEN=da809a6077bb1b0aa7c5623f7b2d5f1fec2faae4 os: - linux From 5d07713e28ac5b1faaefa84cf8b45ed72bcb28a1 Mon Sep 17 00:00:00 2001 From: Heather Date: Tue, 28 Apr 2015 11:16:36 +0400 Subject: [PATCH 0895/1783] add missing keybindings to show specific item on windows related issue on discuss: https://discuss.atom.io/t/ctrl-x-tab-selection/13615 --- keymaps/win32.cson | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/keymaps/win32.cson b/keymaps/win32.cson index 656d9ec8e..5d3629386 100644 --- a/keymaps/win32.cson +++ b/keymaps/win32.cson @@ -77,6 +77,15 @@ 'ctrl-k ctrl-down': 'window:focus-pane-below' 'ctrl-k ctrl-left': 'window:focus-pane-on-left' 'ctrl-k ctrl-right': 'window:focus-pane-on-right' + 'alt-1': 'pane:show-item-1' + 'alt-2': 'pane:show-item-2' + 'alt-3': 'pane:show-item-3' + 'alt-4': 'pane:show-item-4' + 'alt-5': 'pane:show-item-5' + 'alt-6': 'pane:show-item-6' + 'alt-7': 'pane:show-item-7' + 'alt-8': 'pane:show-item-8' + 'alt-9': 'pane:show-item-9' 'atom-workspace atom-text-editor': # Platform Bindings From b9a3b0a8bca820bb460de339b9a7b8ccee476976 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 28 Apr 2015 11:13:21 +0200 Subject: [PATCH 0896/1783] :art: --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 56e966354..ab65307ae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,11 +2,11 @@ git: depth: 10 env: - matrix: - - NODE_VERSION=0.12 - global: - ATOM_ACCESS_TOKEN=da809a6077bb1b0aa7c5623f7b2d5f1fec2faae4 + + matrix: + - NODE_VERSION=0.12 os: - linux From 324bc316f70e0c97c7d3b83581be6166b953fff1 Mon Sep 17 00:00:00 2001 From: "Machiste N. Quintana" Date: Tue, 28 Apr 2015 06:11:20 -0400 Subject: [PATCH 0897/1783] :arrow_up: bracket-matcher@0.74.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ff062e0db..b702c8828 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,7 @@ "autosave": "0.20.0", "background-tips": "0.24.0", "bookmarks": "0.35.0", - "bracket-matcher": "0.73.0", + "bracket-matcher": "0.74.0", "command-palette": "0.35.0", "deprecation-cop": "0.40.0", "dev-live-reload": "0.46.0", From f4b228c9087a8fdc2a9ce6f9c13e74c50069afae Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Mon, 27 Apr 2015 18:25:01 -0400 Subject: [PATCH 0898/1783] Reset font size to window's starting font size --- spec/workspace-spec.coffee | 13 +++++++++++++ src/workspace.coffee | 6 ++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index dac2849c0..7d8ea03b3 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -425,6 +425,19 @@ describe "Workspace", -> expect(atom.config.get('editor.fontSize')).toBe 1 workspace.decreaseFontSize() expect(atom.config.get('editor.fontSize')).toBe 1 + describe "::resetFontSize()", -> + it "resets the font size to the window's starting font size", -> + originalFontSize = 6 + + atom.config.set('editor.fontSize', originalFontSize) + workspace.increaseFontSize() + expect(atom.config.get('editor.fontSize')).toBe originalFontSize + 1 + workspace.resetFontSize() + expect(atom.config.get('editor.fontSize')).toBe originalFontSize + workspace.decreaseFontSize() + expect(atom.config.get('editor.fontSize')).toBe originalFontSize - 1 + workspace.resetFontSize() + expect(atom.config.get('editor.fontSize')).toBe originalFontSize describe "::openLicense()", -> it "opens the license as plain-text in a buffer", -> diff --git a/src/workspace.coffee b/src/workspace.coffee index 50c4117fb..7d460add0 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -612,16 +612,18 @@ class Workspace extends Model # Increase the editor font size by 1px. increaseFontSize: -> + @originalFontSize ?= atom.config.get("editor.fontSize") atom.config.set("editor.fontSize", atom.config.get("editor.fontSize") + 1) # Decrease the editor font size by 1px. decreaseFontSize: -> + @originalFontSize ?= atom.config.get("editor.fontSize") fontSize = atom.config.get("editor.fontSize") atom.config.set("editor.fontSize", fontSize - 1) if fontSize > 1 - # Restore to a default editor font size. + # Restore to the window's original editor font size. resetFontSize: -> - atom.config.unset("editor.fontSize") + atom.config.set("editor.fontSize", @originalFontSize) # Removes the item's uri from the list of potential items to reopen. itemOpened: (item) -> From 12b59cf610e08aefa22872ef76eaa8fce3ccb6d0 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Tue, 28 Apr 2015 05:49:22 -0400 Subject: [PATCH 0899/1783] Only reset font size if font size has been changed --- spec/workspace-spec.coffee | 8 ++++++++ src/workspace.coffee | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index 7d8ea03b3..61da334bb 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -425,6 +425,7 @@ describe "Workspace", -> expect(atom.config.get('editor.fontSize')).toBe 1 workspace.decreaseFontSize() expect(atom.config.get('editor.fontSize')).toBe 1 + describe "::resetFontSize()", -> it "resets the font size to the window's starting font size", -> originalFontSize = 6 @@ -439,6 +440,13 @@ describe "Workspace", -> workspace.resetFontSize() expect(atom.config.get('editor.fontSize')).toBe originalFontSize + it "does nothing if the font size has not been changed", -> + originalFontSize = 6 + + atom.config.set('editor.fontSize', originalFontSize) + workspace.resetFontSize() + expect(atom.config.get('editor.fontSize')).toBe originalFontSize + describe "::openLicense()", -> it "opens the license as plain-text in a buffer", -> waitsForPromise -> workspace.openLicense() diff --git a/src/workspace.coffee b/src/workspace.coffee index 7d460add0..2f70e4316 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -623,7 +623,8 @@ class Workspace extends Model # Restore to the window's original editor font size. resetFontSize: -> - atom.config.set("editor.fontSize", @originalFontSize) + if @originalFontSize + atom.config.set("editor.fontSize", @originalFontSize) # Removes the item's uri from the list of potential items to reopen. itemOpened: (item) -> From 0b150fc6a82137f42a83bef857675964a7a5d9ed Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 27 Apr 2015 16:40:02 -0700 Subject: [PATCH 0900/1783] Add --profile-startup --- src/browser/main.coffee | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/browser/main.coffee b/src/browser/main.coffee index 469d53fae..e73bb4c40 100644 --- a/src/browser/main.coffee +++ b/src/browser/main.coffee @@ -110,6 +110,7 @@ parseCommandLine = -> options.alias('h', 'help').boolean('h').describe('h', 'Print this usage message.') options.alias('l', 'log-file').string('l').describe('l', 'Log all output to file.') options.alias('n', 'new-window').boolean('n').describe('n', 'Open a new window.') + options.boolean('profile-startup').describe('profile-startup', 'Create a profile of startup execution time.') options.alias('r', 'resource-path').string('r').describe('r', 'Set the path to the Atom source directory and enable dev-mode.') options.alias('s', 'spec-directory').string('s').describe('s', 'Set the directory from which to run package specs (default: Atom\'s spec directory).') options.boolean('safe').describe('safe', 'Do not load packages from ~/.atom/packages or ~/.atom/dev/packages.') @@ -139,6 +140,7 @@ parseCommandLine = -> pidToKillWhenClosed = args['pid'] if args['wait'] logFile = args['log-file'] socketPath = args['socket-path'] + profileStartup = args['profile-startup'] if args['resource-path'] devMode = true @@ -165,6 +167,6 @@ parseCommandLine = -> {resourcePath, pathsToOpen, executedFrom, test, version, pidToKillWhenClosed, devMode, apiPreviewMode, safeMode, newWindow, specDirectory, logFile, - socketPath} + socketPath, profileStartup} start() From 6b1c7f7a04e63bc34ebfc3374c75b427b342d767 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 27 Apr 2015 16:40:28 -0700 Subject: [PATCH 0901/1783] :memo: Add missing the --- src/browser/main.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/browser/main.coffee b/src/browser/main.coffee index e73bb4c40..e35632104 100644 --- a/src/browser/main.coffee +++ b/src/browser/main.coffee @@ -110,7 +110,7 @@ parseCommandLine = -> options.alias('h', 'help').boolean('h').describe('h', 'Print this usage message.') options.alias('l', 'log-file').string('l').describe('l', 'Log all output to file.') options.alias('n', 'new-window').boolean('n').describe('n', 'Open a new window.') - options.boolean('profile-startup').describe('profile-startup', 'Create a profile of startup execution time.') + options.boolean('profile-startup').describe('profile-startup', 'Create a profile of the startup execution time.') options.alias('r', 'resource-path').string('r').describe('r', 'Set the path to the Atom source directory and enable dev-mode.') options.alias('s', 'spec-directory').string('s').describe('s', 'Set the directory from which to run package specs (default: Atom\'s spec directory).') options.boolean('safe').describe('safe', 'Do not load packages from ~/.atom/packages or ~/.atom/dev/packages.') From 9c7f9f74a172df70fe6e61319c44a61e96b3847a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 27 Apr 2015 18:13:01 -0700 Subject: [PATCH 0902/1783] Thread through profileStartup load setting --- src/browser/atom-application.coffee | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index dbe29caab..178755786 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -85,15 +85,16 @@ class AtomApplication else @loadState() or @openPath(options) - openWithOptions: ({pathsToOpen, urlsToOpen, test, pidToKillWhenClosed, devMode, safeMode, apiPreviewMode, newWindow, specDirectory, logFile}) -> + openWithOptions: ({pathsToOpen, urlsToOpen, test, pidToKillWhenClosed, devMode, safeMode, apiPreviewMode, newWindow, specDirectory, logFile, profileStartup}) -> if test @runSpecs({exitWhenDone: true, @resourcePath, specDirectory, logFile}) else if pathsToOpen.length > 0 - @openPaths({pathsToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, apiPreviewMode}) + @openPaths({pathsToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, apiPreviewMode, profileStartup}) else if urlsToOpen.length > 0 @openUrl({urlToOpen, devMode, safeMode, apiPreviewMode}) for urlToOpen in urlsToOpen else - @openPath({pidToKillWhenClosed, newWindow, devMode, safeMode, apiPreviewMode}) # Always open a editor window if this is the first instance of Atom. + # Always open a editor window if this is the first instance of Atom. + @openPath({pidToKillWhenClosed, newWindow, devMode, safeMode, apiPreviewMode, profileStartup}) # Public: Removes the {AtomWindow} from the global window list. removeWindow: (window) -> @@ -343,9 +344,10 @@ class AtomApplication # :devMode - Boolean to control the opened window's dev mode. # :safeMode - Boolean to control the opened window's safe mode. # :apiPreviewMode - Boolean to control the opened window's 1.0 API preview mode. + # :profileStartup - Boolean to control creating a profile of the startup time. # :window - {AtomWindow} to open file paths in. - openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, apiPreviewMode, window}) -> - @openPaths({pathsToOpen: [pathToOpen], pidToKillWhenClosed, newWindow, devMode, safeMode, apiPreviewMode, window}) + openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, apiPreviewMode, profileStartup, window}) -> + @openPaths({pathsToOpen: [pathToOpen], pidToKillWhenClosed, newWindow, devMode, safeMode, apiPreviewMode, profileStartup, window}) # Public: Opens multiple paths, in existing windows if possible. # @@ -358,7 +360,7 @@ class AtomApplication # :apiPreviewMode - Boolean to control the opened window's 1.0 API preview mode. # :windowDimensions - Object with height and width keys. # :window - {AtomWindow} to open file paths in. - openPaths: ({pathsToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, apiPreviewMode, windowDimensions, window}={}) -> + openPaths: ({pathsToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, apiPreviewMode, windowDimensions, profileStartup, window}={}) -> pathsToOpen = (fs.normalize(pathToOpen) for pathToOpen in pathsToOpen) locationsToOpen = (@locationForPathToOpen(pathToOpen) for pathToOpen in pathsToOpen) @@ -388,7 +390,7 @@ class AtomApplication bootstrapScript ?= require.resolve('../window-bootstrap') resourcePath ?= @resourcePath - openedWindow = new AtomWindow({locationsToOpen, bootstrapScript, resourcePath, devMode, safeMode, apiPreviewMode, windowDimensions}) + openedWindow = new AtomWindow({locationsToOpen, bootstrapScript, resourcePath, devMode, safeMode, apiPreviewMode, windowDimensions, profileStartup}) if pidToKillWhenClosed? @pidsToOpenWindows[pidToKillWhenClosed] = openedWindow From 3cc99d5662b6895046e8a9a1b2252395b8ea36fc Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 27 Apr 2015 18:13:35 -0700 Subject: [PATCH 0903/1783] Handle profile startup option on load --- static/index.js | 92 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 61 insertions(+), 31 deletions(-) diff --git a/static/index.js b/static/index.js index 2db98a382..c0d031d3d 100644 --- a/static/index.js +++ b/static/index.js @@ -32,46 +32,58 @@ window.onload = function() { var devMode = loadSettings.devMode || !loadSettings.resourcePath.startsWith(process.resourcesPath + path.sep); - setupCoffeeCache(cacheDir); - - ModuleCache = require('../src/module-cache'); - ModuleCache.register(loadSettings); - ModuleCache.add(loadSettings.resourcePath); - - require('grim').includeDeprecatedAPIs = !loadSettings.apiPreviewMode; - - // Start the crash reporter before anything else. - require('crash-reporter').start({ - productName: 'Atom', - companyName: 'GitHub', - // By explicitly passing the app version here, we could save the call - // of "require('remote').require('app').getVersion()". - extra: {_version: loadSettings.appVersion} - }); - - setupVmCompatibility(); - setupCsonCache(cacheDir); - setupSourceMapCache(cacheDir); - setupBabel(cacheDir); - setupTypeScript(cacheDir); - - require(loadSettings.bootstrapScript); - require('ipc').sendChannel('window-command', 'window:loaded'); + if (loadSettings.profileStartup) { + profileStartup(cacheDir, loadSettings); + } else { + setupWindow(cacheDir, loadSettings); + } if (global.atom) { global.atom.loadTime = Date.now() - startTime; console.log('Window load time: ' + global.atom.getWindowLoadTime() + 'ms'); } } catch (error) { - var currentWindow = require('remote').getCurrentWindow(); - currentWindow.setSize(800, 600); - currentWindow.center(); - currentWindow.show(); - currentWindow.openDevTools(); - console.error(error.stack || error); + handleSetupError(error); } } +var handleSetupError = function(error) { + var currentWindow = require('remote').getCurrentWindow(); + currentWindow.setSize(800, 600); + currentWindow.center(); + currentWindow.show(); + currentWindow.openDevTools(); + console.error(error.stack || error); +} + +var setupWindow = function(cacheDir, loadSettings) { + setupCoffeeCache(cacheDir); + + ModuleCache = require('../src/module-cache'); + ModuleCache.register(loadSettings); + ModuleCache.add(loadSettings.resourcePath); + + require('grim').includeDeprecatedAPIs = !loadSettings.apiPreviewMode; + + // Start the crash reporter before anything else. + require('crash-reporter').start({ + productName: 'Atom', + companyName: 'GitHub', + // By explicitly passing the app version here, we could save the call + // of "require('remote').require('app').getVersion()". + extra: {_version: loadSettings.appVersion} + }); + + setupVmCompatibility(); + setupCsonCache(cacheDir); + setupSourceMapCache(cacheDir); + setupBabel(cacheDir); + setupTypeScript(cacheDir); + + require(loadSettings.bootstrapScript); + require('ipc').sendChannel('window-command', 'window:loaded'); +} + var setupCoffeeCache = function(cacheDir) { var CoffeeCache = require('coffee-cash'); CoffeeCache.setCacheDirectory(path.join(cacheDir, 'coffee')); @@ -121,3 +133,21 @@ var setupVmCompatibility = function() { if (!vm.Script.createContext) vm.Script.createContext = vm.createContext; } + +var profileStartup = function(cacheDir, loadSettings) { + var currentWindow = require('remote').getCurrentWindow(); + currentWindow.openDevTools(); + currentWindow.once('devtools-opened', function() { + setTimeout(function() { + console.profile('startup'); + try { + setupWindow(cacheDir, loadSettings); + } catch (error) { + handleSetupError(error); + } finally { + console.profileEnd('startup'); + console.log("Switch to the Profiles tab to view the startup profile") + } + }, 100); + }); +} From b5839a8960c28a03ad965e6ca0d8bf9f73d9cd72 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 27 Apr 2015 18:19:25 -0700 Subject: [PATCH 0904/1783] Add created to profile message --- static/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/index.js b/static/index.js index c0d031d3d..e7971d9b9 100644 --- a/static/index.js +++ b/static/index.js @@ -146,7 +146,7 @@ var profileStartup = function(cacheDir, loadSettings) { handleSetupError(error); } finally { console.profileEnd('startup'); - console.log("Switch to the Profiles tab to view the startup profile") + console.log("Switch to the Profiles tab to view the created startup profile") } }, 100); }); From 313c8a73ce1cecf8ee852b8d4100a553c5065cfd Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 27 Apr 2015 18:28:29 -0700 Subject: [PATCH 0905/1783] Only pen dev tools when not already open --- static/index.js | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/static/index.js b/static/index.js index e7971d9b9..140dee8f3 100644 --- a/static/index.js +++ b/static/index.js @@ -135,19 +135,25 @@ var setupVmCompatibility = function() { } var profileStartup = function(cacheDir, loadSettings) { + var profile = function() { + console.profile('startup'); + try { + setupWindow(cacheDir, loadSettings); + } catch (error) { + handleSetupError(error); + } finally { + console.profileEnd('startup'); + console.log("Switch to the Profiles tab to view the created startup profile") + } + }; + var currentWindow = require('remote').getCurrentWindow(); - currentWindow.openDevTools(); - currentWindow.once('devtools-opened', function() { - setTimeout(function() { - console.profile('startup'); - try { - setupWindow(cacheDir, loadSettings); - } catch (error) { - handleSetupError(error); - } finally { - console.profileEnd('startup'); - console.log("Switch to the Profiles tab to view the created startup profile") - } - }, 100); - }); + if (currentWindow.devToolsWebContents) { + profile(); + } else { + currentWindow.openDevTools(); + currentWindow.once('devtools-opened', function() { + setTimeout(profile, 100); + }); + } } From 753a8023868d7b5a5b4929dc9ca30c75fe961ef8 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 28 Apr 2015 09:52:40 -0700 Subject: [PATCH 0906/1783] :arrow_up: grim@1.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b702c8828..18b15548e 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "fstream": "0.1.24", "fuzzaldrin": "^2.1", "git-utils": "^3.0.0", - "grim": "1.2.2", + "grim": "1.3.0", "jasmine-json": "~0.0", "jasmine-tagged": "^1.1.4", "jquery": "^2.1.1", From 536421287c4e0a722272add8851b51c6c3c7429a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 28 Apr 2015 09:56:48 -0700 Subject: [PATCH 0907/1783] :arrow_up: deprecation-cop@0.41 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 18b15548e..3af4021b6 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,7 @@ "bookmarks": "0.35.0", "bracket-matcher": "0.74.0", "command-palette": "0.35.0", - "deprecation-cop": "0.40.0", + "deprecation-cop": "0.41.0", "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", From 83b10d624b3768a08fb6b26f95ae5fcd396390ab Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 28 Apr 2015 12:53:29 -0700 Subject: [PATCH 0908/1783] :arrow_up: notifications@0.42 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3af4021b6..170bb9da8 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,7 @@ "link": "0.30.0", "markdown-preview": "0.148.0", "metrics": "0.45.0", - "notifications": "0.41.0", + "notifications": "0.42.0", "open-on-github": "0.36.0", "package-generator": "0.38.0", "release-notes": "0.52.0", From 6169ba2845c42efffd648cad948b7a128a9e851d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 28 Apr 2015 13:13:03 -0700 Subject: [PATCH 0909/1783] :arrow_up: keybinding-resolver@0.32 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 170bb9da8..6bf6f15a3 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "grammar-selector": "0.46.0", "image-view": "0.54.0", "incompatible-packages": "0.24.0", - "keybinding-resolver": "0.31.0", + "keybinding-resolver": "0.32.0", "link": "0.30.0", "markdown-preview": "0.148.0", "metrics": "0.45.0", From bd70637b5f5149e176518639da280e7c314c8390 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 28 Apr 2015 13:30:58 -0700 Subject: [PATCH 0910/1783] :arrow_up: archive-view@0.56 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6bf6f15a3..2f39bb6a0 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ "one-light-ui": "0.6.0", "solarized-dark-syntax": "0.32.0", "solarized-light-syntax": "0.19.0", - "archive-view": "0.55.0", + "archive-view": "0.56.0", "autocomplete": "0.44.0", "autoflow": "0.22.0", "autosave": "0.20.0", From 7afa830e864f02404c3b79223ec967b995d5b48e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 28 Apr 2015 13:48:30 -0700 Subject: [PATCH 0911/1783] :arrow_up: deprecation-cop@0.42 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2f39bb6a0..9802310d0 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,7 @@ "bookmarks": "0.35.0", "bracket-matcher": "0.74.0", "command-palette": "0.35.0", - "deprecation-cop": "0.41.0", + "deprecation-cop": "0.42.0", "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", From 3b542f0cbf317d352bdb8974d5ee81d053a3291e Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 28 Apr 2015 14:49:00 -0700 Subject: [PATCH 0912/1783] :arrow_up: language-html@0.34.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9802310d0..7f502a7f1 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,7 @@ "language-gfm": "0.70.0", "language-git": "0.10.0", "language-go": "0.25.0", - "language-html": "0.33.0", + "language-html": "0.34.0", "language-hyperlink": "0.12.2", "language-java": "0.14.0", "language-javascript": "0.75.0", From 89166749207edd40c9fc92d2b2e3f6da2b439009 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 28 Apr 2015 15:34:36 -0700 Subject: [PATCH 0913/1783] :arrow_up: language-todo@0.19.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7f502a7f1..d80dbb534 100644 --- a/package.json +++ b/package.json @@ -151,7 +151,7 @@ "language-source": "0.9.0", "language-sql": "0.15.0", "language-text": "0.6.0", - "language-todo": "0.18.0", + "language-todo": "0.19.0", "language-toml": "0.15.0", "language-xml": "0.28.0", "language-yaml": "0.22.0" From a115a0328914dbc38bdc88147afd1ee0aecceac2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 28 Apr 2015 14:04:11 -0700 Subject: [PATCH 0914/1783] :arrow_up: find-and-replace@0.161 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d80dbb534..a8af0fdba 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", "feedback": "0.38.0", - "find-and-replace": "0.160.0", + "find-and-replace": "0.161.0", "fuzzy-finder": "0.82.0", "git-diff": "0.55.0", "go-to-line": "0.30.0", From 9711e941332e788846d0798362161f6547a16a85 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 28 Apr 2015 17:13:54 -0700 Subject: [PATCH 0915/1783] :arrow_up: grim@1.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a8af0fdba..3a0e7190e 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "fstream": "0.1.24", "fuzzaldrin": "^2.1", "git-utils": "^3.0.0", - "grim": "1.3.0", + "grim": "1.4.0", "jasmine-json": "~0.0", "jasmine-tagged": "^1.1.4", "jquery": "^2.1.1", From d9afa425500c7cf48e714d70b87f5c50d10e3636 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 28 Apr 2015 17:14:06 -0700 Subject: [PATCH 0916/1783] :arrow_up: deprecation-cop@0.43 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3a0e7190e..8d8140862 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,7 @@ "bookmarks": "0.35.0", "bracket-matcher": "0.74.0", "command-palette": "0.35.0", - "deprecation-cop": "0.42.0", + "deprecation-cop": "0.43.0", "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", From 0d9d9e1056794743877652956292fd6b98dee6f9 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 28 Apr 2015 17:42:15 -0700 Subject: [PATCH 0917/1783] Track load time when profiling startup --- static/index.js | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/static/index.js b/static/index.js index 140dee8f3..0cc17d1e8 100644 --- a/static/index.js +++ b/static/index.js @@ -33,20 +33,23 @@ window.onload = function() { var devMode = loadSettings.devMode || !loadSettings.resourcePath.startsWith(process.resourcesPath + path.sep); if (loadSettings.profileStartup) { - profileStartup(cacheDir, loadSettings); + profileStartup(cacheDir, loadSettings, Date.now() - startTime); } else { setupWindow(cacheDir, loadSettings); - } - - if (global.atom) { - global.atom.loadTime = Date.now() - startTime; - console.log('Window load time: ' + global.atom.getWindowLoadTime() + 'ms'); + setLoadTime(Date.now() - startTime); } } catch (error) { handleSetupError(error); } } +var setLoadTime = function(loadTime) { + if (global.atom) { + global.atom.loadTime = loadTime; + console.log('Window load time: ' + global.atom.getWindowLoadTime() + 'ms'); + } +} + var handleSetupError = function(error) { var currentWindow = require('remote').getCurrentWindow(); currentWindow.setSize(800, 600); @@ -134,15 +137,17 @@ var setupVmCompatibility = function() { vm.Script.createContext = vm.createContext; } -var profileStartup = function(cacheDir, loadSettings) { +var profileStartup = function(cacheDir, loadSettings, initialTime) { var profile = function() { console.profile('startup'); try { + var startTime = Date.now() setupWindow(cacheDir, loadSettings); } catch (error) { handleSetupError(error); } finally { console.profileEnd('startup'); + setLoadTime(Date.now() - startTime + initialTime); console.log("Switch to the Profiles tab to view the created startup profile") } }; From df2b0664a12f60ad150494be92ee983198c52bff Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 28 Apr 2015 17:43:16 -0700 Subject: [PATCH 0918/1783] Catch errors setting load time --- static/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/index.js b/static/index.js index 0cc17d1e8..0a377044e 100644 --- a/static/index.js +++ b/static/index.js @@ -143,11 +143,11 @@ var profileStartup = function(cacheDir, loadSettings, initialTime) { try { var startTime = Date.now() setupWindow(cacheDir, loadSettings); + setLoadTime(Date.now() - startTime + initialTime); } catch (error) { handleSetupError(error); } finally { console.profileEnd('startup'); - setLoadTime(Date.now() - startTime + initialTime); console.log("Switch to the Profiles tab to view the created startup profile") } }; From d7045c3cc819d0d97b88ea11c49f949ec0667550 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 28 Apr 2015 19:57:33 -0600 Subject: [PATCH 0919/1783] Make TextEditor params object optional --- 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 861f6231e..8241cc8c9 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -75,7 +75,7 @@ class TextEditor extends Model 'autoDecreaseIndentForBufferRow', 'toggleLineCommentForBufferRow', 'toggleLineCommentsForBufferRows', toProperty: 'languageMode' - constructor: ({@softTabs, initialLine, initialColumn, tabLength, softWrapped, @displayBuffer, buffer, registerEditor, suppressCursorCreation, @mini, @placeholderText, lineNumberGutterVisible}) -> + constructor: ({@softTabs, initialLine, initialColumn, tabLength, softWrapped, @displayBuffer, buffer, registerEditor, suppressCursorCreation, @mini, @placeholderText, lineNumberGutterVisible}={}) -> super @emitter = new Emitter From 192997c8cf4479c4cae155207ad3b175c0ee9498 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 28 Apr 2015 20:05:07 -0600 Subject: [PATCH 0920/1783] Clear line numbers from previous usages of the gutter element MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In adding custom gutter APIs, I suggested to @jssln that we associate the gutter model objects with DOM nodes in the view registry to make it easy for package authors to get at the view layer for a particular gutter. She also applied this treatment to the line numbers gutter, which makes sense. However, using the view registry opened up an unexpected wrinkle… When you detach an editor, we need to tear down all the associated view logic because at that point, we don’t know whether the element is about to be reattached or whether it’s going to get garbage collected. In the case where we reattach, we end up constructing a new TextEditorComponent for the element. When this happens, the gutter component requests a DOM node for the gutter from the view registry. Except in this case the DOM element isn’t empty because it was already used by a different component for the same element before it was detached. The fix is simply to always clear out the line numbers to ensure we start in a clean state. @jssln: You should apply this same fix to custom gutters or we’ll see the same issues. --- spec/text-editor-element-spec.coffee | 14 ++++++++++++++ src/line-number-gutter-component.coffee | 1 + 2 files changed, 15 insertions(+) diff --git a/spec/text-editor-element-spec.coffee b/spec/text-editor-element-spec.coffee index ba71cb236..418e0367d 100644 --- a/spec/text-editor-element-spec.coffee +++ b/spec/text-editor-element-spec.coffee @@ -65,6 +65,20 @@ describe "TextEditorElement", -> element.getModel().destroy() expect(component.mounted).toBe false + describe "when the editor is detached from the DOM and then reattached", -> + it "does not render duplicate line numbers", -> + editor = new TextEditor + editor.setText('1\n2\n3') + element = atom.views.getView(editor) + + jasmine.attachToDOM(element) + + initialCount = element.shadowRoot.querySelectorAll('.line-number').length + + element.remove() + jasmine.attachToDOM(element) + expect(element.shadowRoot.querySelectorAll('.line-number').length).toBe initialCount + describe "focus and blur handling", -> describe "when the editor.useShadowDOM config option is true", -> it "proxies focus/blur events to/from the hidden input inside the shadow root", -> diff --git a/src/line-number-gutter-component.coffee b/src/line-number-gutter-component.coffee index 9c77b6647..c026d2d37 100644 --- a/src/line-number-gutter-component.coffee +++ b/src/line-number-gutter-component.coffee @@ -13,6 +13,7 @@ class LineNumberGutterComponent @domNode = atom.views.getView(@gutter) @lineNumbersNode = @domNode.firstChild + @lineNumbersNode.innerHTML = '' @domNode.addEventListener 'click', @onClick @domNode.addEventListener 'mousedown', @onMouseDown From 2bd7cc9a99895c8392d3a6e4909cc95724b890a1 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Tue, 28 Apr 2015 22:58:35 -0400 Subject: [PATCH 0921/1783] Reset font size if editor.fontSize is changed from anywhere --- spec/workspace-spec.coffee | 14 ++++++++++++-- src/workspace.coffee | 8 ++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index 61da334bb..9b8ce4d50 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -428,7 +428,7 @@ describe "Workspace", -> describe "::resetFontSize()", -> it "resets the font size to the window's starting font size", -> - originalFontSize = 6 + originalFontSize = atom.config.get('editor.fontSize') atom.config.set('editor.fontSize', originalFontSize) workspace.increaseFontSize() @@ -441,12 +441,22 @@ describe "Workspace", -> expect(atom.config.get('editor.fontSize')).toBe originalFontSize it "does nothing if the font size has not been changed", -> - originalFontSize = 6 + originalFontSize = atom.config.get('editor.fontSize') atom.config.set('editor.fontSize', originalFontSize) workspace.resetFontSize() expect(atom.config.get('editor.fontSize')).toBe originalFontSize + it "resets the font size when the editor's font size changes", -> + originalFontSize = atom.config.get('editor.fontSize') + + atom.config.set('editor.fontSize', originalFontSize + 1) + workspace.resetFontSize() + expect(atom.config.get('editor.fontSize')).toBe originalFontSize + atom.config.set('editor.fontSize', originalFontSize - 1) + workspace.resetFontSize() + expect(atom.config.get('editor.fontSize')).toBe originalFontSize + describe "::openLicense()", -> it "opens the license as plain-text in a buffer", -> waitsForPromise -> workspace.openLicense() diff --git a/src/workspace.coffee b/src/workspace.coffee index 2f70e4316..07040463b 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -75,6 +75,8 @@ class Workspace extends Model atom.views.addViewProvider Panel, (model) -> new PanelElement().initialize(model) + @subscribeToFontSize() + # Called by the Serializable mixin during deserialization deserializeParams: (params) -> for packageName in params.packagesWithActiveGrammars ? [] @@ -612,12 +614,10 @@ class Workspace extends Model # Increase the editor font size by 1px. increaseFontSize: -> - @originalFontSize ?= atom.config.get("editor.fontSize") atom.config.set("editor.fontSize", atom.config.get("editor.fontSize") + 1) # Decrease the editor font size by 1px. decreaseFontSize: -> - @originalFontSize ?= atom.config.get("editor.fontSize") fontSize = atom.config.get("editor.fontSize") atom.config.set("editor.fontSize", fontSize - 1) if fontSize > 1 @@ -626,6 +626,10 @@ class Workspace extends Model if @originalFontSize atom.config.set("editor.fontSize", @originalFontSize) + subscribeToFontSize: -> + atom.config.onDidChange 'editor.fontSize', ({newValue, oldValue}) => + @originalFontSize ?= oldValue + # Removes the item's uri from the list of potential items to reopen. itemOpened: (item) -> if typeof item.getURI is 'function' From a76205256d2cbee2a51c221001d0d8489d1fde95 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Tue, 28 Apr 2015 23:09:31 -0400 Subject: [PATCH 0922/1783] Only need oldValue --- src/workspace.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/workspace.coffee b/src/workspace.coffee index 07040463b..0e6fb7e40 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -627,7 +627,7 @@ class Workspace extends Model atom.config.set("editor.fontSize", @originalFontSize) subscribeToFontSize: -> - atom.config.onDidChange 'editor.fontSize', ({newValue, oldValue}) => + atom.config.onDidChange 'editor.fontSize', ({oldValue}) => @originalFontSize ?= oldValue # Removes the item's uri from the list of potential items to reopen. From 1d238dd92738f1ca7ccd7f7e18493d42dab4392e Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 28 Apr 2015 22:22:32 -0600 Subject: [PATCH 0923/1783] Fix scroll width calculation when longest line is folded With the presenter we started clipping screen positions prior to translating them to pixel positions. This interacts with the current clipping behavior on folded lines (which should change) where the cursor is always clipped to 0. So when the longest line was also folded we were miscalculating the width. :see_no_evil:! The removal of clipping also causes us to calculate the width based on the trailing whitespace of soft-wrapped lines, which I actually think is an improvement but it is slightly different. --- spec/text-editor-presenter-spec.coffee | 5 +++++ src/text-editor-component.coffee | 8 ++++---- src/text-editor-presenter.coffee | 9 ++++++++- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 5a50a49a9..9bee4a72e 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -498,6 +498,11 @@ describe "TextEditorPresenter", -> expect(presenter.getState().content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 + it "isn't clipped to 0 when the longest line is folded (regression)", -> + presenter = buildPresenter(contentFrameWidth: 50, baseCharacterWidth: 10) + editor.foldBufferRow(0) + expect(presenter.getState().content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 + describe ".scrollTop", -> it "tracks the value of ::scrollTop", -> presenter = buildPresenter(scrollTop: 10, lineHeight: 10, explicitHeight: 20) diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index e284516fa..8d728ded6 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -349,15 +349,15 @@ class TextEditorComponent if Math.abs(wheelDeltaX) > Math.abs(wheelDeltaY) # Scrolling horizontally - previousScrollLeft = @editor.getScrollLeft() + previousScrollLeft = @presenter.getScrollLeft() @presenter.setScrollLeft(previousScrollLeft - Math.round(wheelDeltaX * @scrollSensitivity)) - event.preventDefault() unless previousScrollLeft is @editor.getScrollLeft() + event.preventDefault() unless previousScrollLeft is @presenter.getScrollLeft() else # Scrolling vertically @presenter.setMouseWheelScreenRow(@screenRowForNode(event.target)) - previousScrollTop = @presenter.scrollTop + previousScrollTop = @presenter.getScrollTop() @presenter.setScrollTop(previousScrollTop - Math.round(wheelDeltaY * @scrollSensitivity)) - event.preventDefault() unless previousScrollTop is @editor.getScrollTop() + event.preventDefault() unless previousScrollTop is @presenter.getScrollTop() onScrollViewScroll: => if @mounted diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 55b88f2b8..d27dd6484 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -541,7 +541,8 @@ class TextEditorPresenter if @baseCharacterWidth? oldContentWidth = @contentWidth - @contentWidth = @pixelPositionForScreenPosition([@model.getLongestScreenRow(), Infinity]).left + clip = @model.tokenizedLineForScreenRow(@model.getLongestScreenRow())?.isSoftWrapped() + @contentWidth = @pixelPositionForScreenPosition([@model.getLongestScreenRow(), @model.getMaxScreenLineLength()], clip).left @contentWidth += 1 unless @model.isSoftWrapped() # account for cursor width if @contentHeight isnt oldContentHeight @@ -691,6 +692,9 @@ class TextEditorPresenter @updateCustomGutterDecorationState() @updateOverlaysState() + getScrollTop: -> + @scrollTop + didStartScrolling: -> if @stoppedScrollingTimeoutId? clearTimeout(@stoppedScrollingTimeoutId) @@ -720,6 +724,9 @@ class TextEditorPresenter @updateCursorsState() unless oldScrollLeft? @updateOverlaysState() + getScrollLeft: -> + @scrollLeft + setHorizontalScrollbarHeight: (horizontalScrollbarHeight) -> unless @measuredHorizontalScrollbarHeight is horizontalScrollbarHeight oldHorizontalScrollbarHeight = @measuredHorizontalScrollbarHeight From cb712fa9d3fb9ed804f4c338537371d5a85c415a Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 28 Apr 2015 23:31:28 +0200 Subject: [PATCH 0924/1783] :art: Start refactoring batched operations --- src/text-editor-presenter.coffee | 48 ++++++++++++++++---------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 55b88f2b8..9e41bf85c 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -100,34 +100,34 @@ class TextEditorPresenter @disposables.add @model.onDidChange => @updateContentDimensions() @updateEndRow() - @updateHeightState() - @updateVerticalScrollState() - @updateHorizontalScrollState() - @updateScrollbarsState() - @updateContentState() - @updateDecorations() - @updateLinesState() - @updateLineNumberGutterState() - @updateLineNumbersState() - @updateGutterOrderState() - @updateCustomGutterDecorationState() + @shouldUpdateHeightState = true + @shouldUpdateVerticalScrollState = true + @shouldUpdateHorizontalScrollState = true + @shouldUpdateScrollbarsState = true + @shouldUpdateContentState = true + @shouldUpdateDecorations = true + @shouldUpdateLinesState = true + @shouldUpdateLineNumberGutterState = true + @shouldUpdateLineNumbersState = true + @shouldUpdateGutterOrderState = true + @updateCustomGutterDecorationState() # FIXME: use `shouldUpdate...` @disposables.add @model.onDidChangeGrammar(@didChangeGrammar.bind(this)) @disposables.add @model.onDidChangePlaceholderText(@updateContentState.bind(this)) @disposables.add @model.onDidChangeMini => - @updateScrollbarDimensions() - @updateScrollbarsState() - @updateContentState() - @updateDecorations() - @updateLinesState() - @updateLineNumberGutterState() - @updateLineNumbersState() - @updateCommonGutterState() - @updateGutterOrderState() - @updateCustomGutterDecorationState() + @shouldUpdateScrollbarDimensions = true + @shouldUpdateScrollbarsState = true + @shouldUpdateContentState = true + @shouldUpdateDecorations = true + @shouldUpdateLinesState = true + @shouldUpdateLineNumberGutterState = true + @shouldUpdateLineNumbersState = true + @updateCommonGutterState() # TODO: check out later... + @updateGutterOrderState() # FIXME: use `shouldUpdate...` + @updateCustomGutterDecorationState() # FIXME: use `shouldUpdate...` @disposables.add @model.onDidChangeLineNumberGutterVisible => - @updateLineNumberGutterState() - @updateCommonGutterState() - @updateGutterOrderState() + @shouldUpdateLineNumberGutterState = true + @updateCommonGutterState() # TODO: check out later... + @updateGutterOrderState() # FIXME: use `shouldUpdate...` @disposables.add @model.onDidAddDecoration(@didAddDecoration.bind(this)) @disposables.add @model.onDidAddCursor(@didAddCursor.bind(this)) @disposables.add @model.onDidChangeScrollTop(@setScrollTop.bind(this)) From 110e73da876b073d1f5c4f4bd322bbfbc72f8f4c Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 28 Apr 2015 23:52:30 +0200 Subject: [PATCH 0925/1783] :art: Use booleans to track batched functions --- src/text-editor-presenter.coffee | 282 +++++++++++++++++++------------ 1 file changed, 174 insertions(+), 108 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 9e41bf85c..169d95541 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -94,6 +94,8 @@ class TextEditorPresenter @updateCustomGutterDecorationState() if @shouldUpdateCustomGutterDecorationState @updating = false + throw new Error("Reset @shouldUpdateBlaBla variables to `false`!!!") + @state observeModel: -> @@ -110,24 +112,30 @@ class TextEditorPresenter @shouldUpdateLineNumberGutterState = true @shouldUpdateLineNumbersState = true @shouldUpdateGutterOrderState = true - @updateCustomGutterDecorationState() # FIXME: use `shouldUpdate...` + @shouldUpdateCustomGutterDecorationState = true + + @emitDidUpdateState() @disposables.add @model.onDidChangeGrammar(@didChangeGrammar.bind(this)) @disposables.add @model.onDidChangePlaceholderText(@updateContentState.bind(this)) @disposables.add @model.onDidChangeMini => - @shouldUpdateScrollbarDimensions = true + @updateScrollbarDimensions() @shouldUpdateScrollbarsState = true @shouldUpdateContentState = true @shouldUpdateDecorations = true @shouldUpdateLinesState = true @shouldUpdateLineNumberGutterState = true @shouldUpdateLineNumbersState = true + @shouldUpdateGutterOrderState = true + @shouldUpdateCustomGutterDecorationState = true @updateCommonGutterState() # TODO: check out later... - @updateGutterOrderState() # FIXME: use `shouldUpdate...` - @updateCustomGutterDecorationState() # FIXME: use `shouldUpdate...` + + @emitDidUpdateState() @disposables.add @model.onDidChangeLineNumberGutterVisible => @shouldUpdateLineNumberGutterState = true + @shouldUpdateGutterOrderState = true @updateCommonGutterState() # TODO: check out later... - @updateGutterOrderState() # FIXME: use `shouldUpdate...` + + @emitDidUpdateState() @disposables.add @model.onDidAddDecoration(@didAddDecoration.bind(this)) @disposables.add @model.onDidAddCursor(@didAddCursor.bind(this)) @disposables.add @model.onDidChangeScrollTop(@setScrollTop.bind(this)) @@ -153,24 +161,32 @@ class TextEditorPresenter @configDisposables.add atom.config.onDidChange 'editor.showIndentGuide', configParams, ({newValue}) => @showIndentGuide = newValue - @updateContentState() + @shouldUpdateContentState = true + + @emitDidUpdateState() @configDisposables.add atom.config.onDidChange 'editor.scrollPastEnd', configParams, ({newValue}) => @scrollPastEnd = newValue + @shouldUpdateVerticalScrollState = true + @shouldUpdateScrollbarsState = true @updateScrollHeight() - @updateVerticalScrollState() - @updateScrollbarsState() + + @emitDidUpdateState() @configDisposables.add atom.config.onDidChange 'editor.showLineNumbers', configParams, ({newValue}) => @showLineNumbers = newValue - @updateLineNumberGutterState() - @updateCommonGutterState() - @updateGutterOrderState() + @shouldUpdateLineNumberGutterState = true + @shouldUpdateGutterOrderState = true + @updateCommonGutterState() # TODO: check this out + + @emitDidUpdateState() didChangeGrammar: -> @observeConfig() - @updateContentState() - @updateLineNumberGutterState() - @updateCommonGutterState() - @updateGutterOrderState() + @shouldUpdateContentState = true + @shouldUpdateLineNumberGutterState = true + @shouldUpdateGutterOrderState = true + @updateCommonGutterState() # TODO: check this out + + @emitDidUpdateState() buildState: -> @state = @@ -395,18 +411,24 @@ class TextEditorPresenter didAddGutter: (gutter) -> gutterDisposables = new CompositeDisposable gutterDisposables.add gutter.onDidChangeVisible => - @updateGutterOrderState() - @updateCustomGutterDecorationState() + @shouldUpdateGutterOrderState = true + @shouldUpdateCustomGutterDecorationState = true + + @emitDidUpdateState() gutterDisposables.add gutter.onDidDestroy => @disposables.remove(gutterDisposables) gutterDisposables.dispose() - @updateGutterOrderState() + @shouldUpdateGutterOrderState = true + + @emitDidUpdateState() # It is not necessary to @updateCustomGutterDecorationState here. # The destroyed gutter will be removed from the list of gutters in @state, # and thus will be removed from the DOM. @disposables.add(gutterDisposables) - @updateGutterOrderState() - @updateCustomGutterDecorationState() + @shouldUpdateGutterOrderState = true + @shouldUpdateCustomGutterDecorationState = true + + @emitDidUpdateState() updateGutterOrderState: -> @batch "shouldUpdateGutterOrderState", -> @@ -670,8 +692,10 @@ class TextEditorPresenter @startBlinkingCursors() else @stopBlinkingCursors(false) - @updateFocusedState() - @updateHiddenInputState() + @shouldUpdateFocusedState = true + @shouldUpdateHiddenInputState = true + + @emitDidUpdateState() setScrollTop: (scrollTop) -> scrollTop = @constrainScrollTop(scrollTop) @@ -682,14 +706,16 @@ class TextEditorPresenter @updateStartRow() @updateEndRow() @didStartScrolling() - @updateVerticalScrollState() - @updateHiddenInputState() - @updateDecorations() - @updateLinesState() - @updateCursorsState() - @updateLineNumbersState() - @updateCustomGutterDecorationState() - @updateOverlaysState() + @shouldUpdateVerticalScrollState = true + @shouldUpdateHiddenInputState = true + @shouldUpdateDecorations = true + @shouldUpdateLinesState = true + @shouldUpdateCursorsState = true + @shouldUpdateLineNumbersState = true + @shouldUpdateCustomGutterDecorationState = true + @shouldUpdateOverlaysState = true + + @emitDidUpdateState() didStartScrolling: -> if @stoppedScrollingTimeoutId? @@ -703,11 +729,11 @@ class TextEditorPresenter @state.content.scrollingVertically = false if @mouseWheelScreenRow? @mouseWheelScreenRow = null - @updateLinesState() - @updateLineNumbersState() + @shouldUpdateLinesState = true + @shouldUpdateLineNumbersState = true @updateCustomGutterDecorationState() - else - @emitDidUpdateState() + + @emitDidUpdateState() setScrollLeft: (scrollLeft) -> scrollLeft = @constrainScrollLeft(scrollLeft) @@ -715,10 +741,12 @@ class TextEditorPresenter oldScrollLeft = @scrollLeft @scrollLeft = scrollLeft @model.setScrollLeft(scrollLeft) - @updateHorizontalScrollState() - @updateHiddenInputState() - @updateCursorsState() unless oldScrollLeft? - @updateOverlaysState() + @shouldUpdateHorizontalScrollState = true + @shouldUpdateHiddenInputState = true + @shouldUpdateCursorsState = true unless oldScrollLeft? + @shouldUpdateOverlaysState = true + + @emitDidUpdateState() setHorizontalScrollbarHeight: (horizontalScrollbarHeight) -> unless @measuredHorizontalScrollbarHeight is horizontalScrollbarHeight @@ -726,10 +754,12 @@ class TextEditorPresenter @measuredHorizontalScrollbarHeight = horizontalScrollbarHeight @model.setHorizontalScrollbarHeight(horizontalScrollbarHeight) @updateScrollbarDimensions() - @updateScrollbarsState() - @updateVerticalScrollState() - @updateHorizontalScrollState() - @updateCursorsState() unless oldHorizontalScrollbarHeight? + @shouldUpdateScrollbarsState = true + @shouldUpdateVerticalScrollState = true + @shouldUpdateHorizontalScrollState = true + @shouldUpdateCursorsState = true unless oldHorizontalScrollbarHeight? + + @emitDidUpdateState() setVerticalScrollbarWidth: (verticalScrollbarWidth) -> unless @measuredVerticalScrollbarWidth is verticalScrollbarWidth @@ -737,28 +767,34 @@ class TextEditorPresenter @measuredVerticalScrollbarWidth = verticalScrollbarWidth @model.setVerticalScrollbarWidth(verticalScrollbarWidth) @updateScrollbarDimensions() - @updateScrollbarsState() - @updateVerticalScrollState() - @updateHorizontalScrollState() - @updateCursorsState() unless oldVerticalScrollbarWidth? + @shouldUpdateScrollbarsState = true + @shouldUpdateVerticalScrollState = true + @shouldUpdateHorizontalScrollState = true + @shouldUpdateCursorsState = true unless oldVerticalScrollbarWidth? + + @emitDidUpdateState() setAutoHeight: (autoHeight) -> unless @autoHeight is autoHeight @autoHeight = autoHeight - @updateHeightState() + @shouldUpdateHeightState = true + + @emitDidUpdateState() setExplicitHeight: (explicitHeight) -> unless @explicitHeight is explicitHeight @explicitHeight = explicitHeight @model.setHeight(explicitHeight) @updateHeight() - @updateVerticalScrollState() - @updateScrollbarsState() - @updateDecorations() - @updateLinesState() - @updateCursorsState() - @updateLineNumbersState() - @updateCustomGutterDecorationState() + @shouldUpdateVerticalScrollState = true + @shouldUpdateScrollbarsState = true + @shouldUpdateDecorations = true + @shouldUpdateLinesState = true + @shouldUpdateCursorsState = true + @shouldUpdateLineNumbersState = true + @shouldUpdateCustomGutterDecorationState = true + + @emitDidUpdateState() updateHeight: -> height = @explicitHeight ? @contentHeight @@ -776,18 +812,22 @@ class TextEditorPresenter @model.setWidth(contentFrameWidth) @updateScrollbarDimensions() @updateClientWidth() - @updateVerticalScrollState() - @updateHorizontalScrollState() - @updateScrollbarsState() - @updateContentState() - @updateDecorations() - @updateLinesState() - @updateCursorsState() unless oldContentFrameWidth? + @shouldUpdateVerticalScrollState = true + @shouldUpdateHorizontalScrollState = true + @shouldUpdateScrollbarsState = true + @shouldUpdateContentState = true + @shouldUpdateDecorations = true + @shouldUpdateLinesState = true + @shouldUpdateCursorsState = true unless oldContentFrameWidth? + + @emitDidUpdateState() setBoundingClientRect: (boundingClientRect) -> unless @clientRectsEqual(@boundingClientRect, boundingClientRect) @boundingClientRect = boundingClientRect - @updateOverlaysState() + @shouldUpdateOverlaysState = true + + @emitDidUpdateState() clientRectsEqual: (clientRectA, clientRectB) -> clientRectA? and clientRectB? and @@ -800,22 +840,28 @@ class TextEditorPresenter if @windowWidth isnt width or @windowHeight isnt height @windowWidth = width @windowHeight = height - @updateOverlaysState() + @shouldUpdateOverlaysState = true + + @emitDidUpdateState() setBackgroundColor: (backgroundColor) -> unless @backgroundColor is backgroundColor @backgroundColor = backgroundColor - @updateContentState() - @updateLineNumberGutterState() + @shouldUpdateContentState = true + @shouldUpdateLineNumberGutterState = true @updateCommonGutterState() - @updateGutterOrderState() + @shouldUpdateGutterOrderState = true + + @emitDidUpdateState() setGutterBackgroundColor: (gutterBackgroundColor) -> unless @gutterBackgroundColor is gutterBackgroundColor @gutterBackgroundColor = gutterBackgroundColor - @updateLineNumberGutterState() + @shouldUpdateLineNumberGutterState = true @updateCommonGutterState() - @updateGutterOrderState() + @shouldUpdateGutterOrderState = true + + @emitDidUpdateState() setLineHeight: (lineHeight) -> unless @lineHeight is lineHeight @@ -826,17 +872,19 @@ class TextEditorPresenter @updateHeight() @updateStartRow() @updateEndRow() - @updateHeightState() - @updateHorizontalScrollState() - @updateVerticalScrollState() - @updateScrollbarsState() - @updateHiddenInputState() - @updateDecorations() - @updateLinesState() - @updateCursorsState() - @updateLineNumbersState() - @updateCustomGutterDecorationState() - @updateOverlaysState() + @shouldUpdateHeightState = true + @shouldUpdateHorizontalScrollState = true + @shouldUpdateVerticalScrollState = true + @shouldUpdateScrollbarsState = true + @shouldUpdateHiddenInputState = true + @shouldUpdateDecorations = true + @shouldUpdateLinesState = true + @shouldUpdateCursorsState = true + @shouldUpdateLineNumbersState = true + @shouldUpdateCustomGutterDecorationState = true + @shouldUpdateOverlaysState = true + + @emitDidUpdateState() setMouseWheelScreenRow: (mouseWheelScreenRow) -> unless @mouseWheelScreenRow is mouseWheelScreenRow @@ -876,15 +924,17 @@ class TextEditorPresenter characterWidthsChanged: -> @updateContentDimensions() - @updateHorizontalScrollState() - @updateVerticalScrollState() - @updateScrollbarsState() - @updateHiddenInputState() - @updateContentState() - @updateDecorations() - @updateLinesState() - @updateCursorsState() - @updateOverlaysState() + @shouldUpdateHorizontalScrollState = true + @shouldUpdateVerticalScrollState = true + @shouldUpdateScrollbarsState = true + @shouldUpdateHiddenInputState = true + @shouldUpdateContentState = true + @shouldUpdateDecorations = true + @shouldUpdateLinesState = true + @shouldUpdateCursorsState = true + @shouldUpdateOverlaysState = true + + @emitDidUpdateState() clearScopedCharacterWidths: -> @characterWidthsByScope = {} @@ -972,11 +1022,11 @@ class TextEditorPresenter intersectsVisibleRowRange = true if intersectsVisibleRowRange - @updateLinesState() if decoration.isType('line') + @shouldUpdateLinesState = true if decoration.isType('line') if decoration.isType('line-number') - @updateLineNumbersState() + @shouldUpdateLineNumbersState = true else if decoration.isType('gutter') - @updateCustomGutterDecorationState() + @shouldUpdateCustomGutterDecorationState = true if decoration.isType('highlight') return if change.textChanged @@ -984,7 +1034,9 @@ class TextEditorPresenter @updateHighlightState(decoration) if decoration.isType('overlay') - @updateOverlaysState() + @shouldUpdateOverlaysState = true + + @emitDidUpdateState() decorationPropertiesDidChange: (decoration, event) -> {oldProperties} = event @@ -995,29 +1047,33 @@ class TextEditorPresenter decoration.getMarker().getScreenRange()) @addToLineDecorationCaches(decoration, decoration.getMarker().getScreenRange()) if decoration.isType('line') or Decoration.isType(oldProperties, 'line') - @updateLinesState() + @shouldUpdateLinesState = true if decoration.isType('line-number') or Decoration.isType(oldProperties, 'line-number') - @updateLineNumbersState() + @shouldUpdateLineNumbersState = true if (decoration.isType('gutter') and not decoration.isType('line-number')) or (Decoration.isType(oldProperties, 'gutter') and not Decoration.isType(oldProperties, 'line-number')) - @updateCustomGutterDecorationState() + @shouldUpdateCustomGutterDecorationState = true else if decoration.isType('overlay') - @updateOverlaysState() + @shouldUpdateOverlaysState = true else if decoration.isType('highlight') @updateHighlightState(decoration, event) + @emitDidUpdateState() + didDestroyDecoration: (decoration) -> if decoration.isType('line') or decoration.isType('gutter') @removeFromLineDecorationCaches(decoration, decoration.getMarker().getScreenRange()) - @updateLinesState() if decoration.isType('line') + @shouldUpdateLinesState = true if decoration.isType('line') if decoration.isType('line-number') - @updateLineNumbersState() + @shouldUpdateLineNumbersState = true else if decoration.isType('gutter') - @updateCustomGutterDecorationState(decoration.getProperties().gutterName) + @shouldUpdateCustomGutterDecorationState = true if decoration.isType('highlight') @updateHighlightState(decoration) if decoration.isType('overlay') - @updateOverlaysState() + @shouldUpdateOverlaysState = true + + @emitDidUpdateState() highlightDidFlash: (decoration) -> flash = decoration.consumeNextFlash() @@ -1032,15 +1088,17 @@ class TextEditorPresenter if decoration.isType('line') or decoration.isType('gutter') @addToLineDecorationCaches(decoration, decoration.getMarker().getScreenRange()) - @updateLinesState() if decoration.isType('line') + @shouldUpdateLinesState = true if decoration.isType('line') if decoration.isType('line-number') - @updateLineNumbersState() + @shouldUpdateLineNumbersState = true else if decoration.isType('gutter') - @updateCustomGutterDecorationState() + @shouldUpdateCustomGutterDecorationState = true else if decoration.isType('highlight') @updateHighlightState(decoration) else if decoration.isType('overlay') - @updateOverlaysState() + @shouldUpdateOverlaysState = true + + @emitDidUpdateState() updateDecorations: -> @batch "shouldUpdateDecorations", -> @lineDecorationsByScreenRow = {} @@ -1197,14 +1255,18 @@ class TextEditorPresenter overlayState.itemWidth = itemWidth overlayState.itemHeight = itemHeight overlayState.contentMargin = contentMargin - @updateOverlaysState() + @shouldUpdateOverlaysState = true + + @emitDidUpdateState() observeCursor: (cursor) -> didChangePositionDisposable = cursor.onDidChangePosition => - @updateHiddenInputState() if cursor.isLastCursor() + @shouldUpdateHiddenInputState = true if cursor.isLastCursor() @pauseCursorBlinking() @updateCursorState(cursor) + @emitDidUpdateState() + didChangeVisibilityDisposable = cursor.onDidChangeVisibility => @updateCursorState(cursor) @@ -1212,19 +1274,23 @@ class TextEditorPresenter @disposables.remove(didChangePositionDisposable) @disposables.remove(didChangeVisibilityDisposable) @disposables.remove(didDestroyDisposable) - @updateHiddenInputState() + @shouldUpdateHiddenInputState = true @updateCursorState(cursor, true) + @emitDidUpdateState() + @disposables.add(didChangePositionDisposable) @disposables.add(didChangeVisibilityDisposable) @disposables.add(didDestroyDisposable) didAddCursor: (cursor) -> @observeCursor(cursor) - @updateHiddenInputState() + @shouldUpdateHiddenInputState = true @pauseCursorBlinking() @updateCursorState(cursor) + @emitDidUpdateState() + startBlinkingCursors: -> unless @toggleCursorBlinkHandle @state.content.cursorsVisible = true From 319d54782a18dc2ad4c4e98cdc87b44cda217ec0 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 29 Apr 2015 08:53:28 +0200 Subject: [PATCH 0926/1783] Reset shouldUpdate... variables --- src/text-editor-presenter.coffee | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 169d95541..0078077bb 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -94,10 +94,27 @@ class TextEditorPresenter @updateCustomGutterDecorationState() if @shouldUpdateCustomGutterDecorationState @updating = false - throw new Error("Reset @shouldUpdateBlaBla variables to `false`!!!") + @resetShouldUpdateStates() @state + resetShouldUpdateStates: -> + @shouldUpdateFocusedState = false + @shouldUpdateHeightState = false + @shouldUpdateVerticalScrollState = false + @shouldUpdateHorizontalScrollState = false + @shouldUpdateScrollbarsState = false + @shouldUpdateHiddenInputState = false + @shouldUpdateContentState = false + @shouldUpdateDecorations = false + @shouldUpdateLinesState = false + @shouldUpdateCursorsState = false + @shouldUpdateOverlaysState = false + @shouldUpdateLineNumberGutterState = false + @shouldUpdateLineNumbersState = false + @shouldUpdateGutterOrderState = false + @shouldUpdateCustomGutterDecorationState = false + observeModel: -> @disposables.add @model.onDidChange => @updateContentDimensions() @@ -229,6 +246,8 @@ class TextEditorPresenter @updateGutterOrderState() @updateCustomGutterDecorationState() + @resetShouldUpdateStates() + updateFocusedState: -> @batch "shouldUpdateFocusedState", -> @state.focused = @focused From 611ede4cc9ad44befb3295fabf740155c37fd45d Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 29 Apr 2015 08:59:00 +0200 Subject: [PATCH 0927/1783] :fire: Remove `@batch` from TextEditorPresenter Please note that we will preserve the batching behavior but we will now simply use booleans to track functions that ought to be called during `@getState`. This (hopefully) expresses intent better, drawing a clear line between batched functions and "realtime" ones. --- src/text-editor-presenter.coffee | 89 ++++++++++++++------------------ 1 file changed, 39 insertions(+), 50 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 0078077bb..26c9627da 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -55,18 +55,6 @@ class TextEditorPresenter isBatching: -> @updating is false - # Private: Executes `fn` if `isBatching()` is false, otherwise sets `@[flagName]` to `true` for later processing. In either cases, it calls `emitDidUpdateState`. - # * `flagName` {String} name of a property of this presenter - # * `fn` {Function} to call when not batching. - batch: (flagName, fn) -> - if @isBatching() - @[flagName] = true - else - fn.apply(this) - @[flagName] = false - - @emitDidUpdateState() - # Public: Gets this presenter's state, updating it just in time before returning from this function. # Returns a state {Object}, useful for rendering to screen. getState: -> @@ -133,7 +121,10 @@ class TextEditorPresenter @emitDidUpdateState() @disposables.add @model.onDidChangeGrammar(@didChangeGrammar.bind(this)) - @disposables.add @model.onDidChangePlaceholderText(@updateContentState.bind(this)) + @disposables.add @model.onDidChangePlaceholderText => + @shouldUpdateContentState = true + + @emitDidUpdateState() @disposables.add @model.onDidChangeMini => @updateScrollbarDimensions() @shouldUpdateScrollbarsState = true @@ -248,16 +239,16 @@ class TextEditorPresenter @resetShouldUpdateStates() - updateFocusedState: -> @batch "shouldUpdateFocusedState", -> + updateFocusedState: -> @state.focused = @focused - updateHeightState: -> @batch "shouldUpdateHeightState", -> + updateHeightState: -> if @autoHeight @state.height = @contentHeight else @state.height = null - updateVerticalScrollState: -> @batch "shouldUpdateVerticalScrollState", -> + updateVerticalScrollState: -> @state.content.scrollHeight = @scrollHeight @state.gutters.scrollHeight = @scrollHeight @state.verticalScrollbar.scrollHeight = @scrollHeight @@ -266,14 +257,14 @@ class TextEditorPresenter @state.gutters.scrollTop = @scrollTop @state.verticalScrollbar.scrollTop = @scrollTop - updateHorizontalScrollState: -> @batch "shouldUpdateHorizontalScrollState", -> + updateHorizontalScrollState: -> @state.content.scrollWidth = @scrollWidth @state.horizontalScrollbar.scrollWidth = @scrollWidth @state.content.scrollLeft = @scrollLeft @state.horizontalScrollbar.scrollLeft = @scrollLeft - updateScrollbarsState: -> @batch "shouldUpdateScrollbarsState", -> + updateScrollbarsState: -> @state.horizontalScrollbar.visible = @horizontalScrollbarHeight > 0 @state.horizontalScrollbar.height = @measuredHorizontalScrollbarHeight @state.horizontalScrollbar.right = @verticalScrollbarWidth @@ -282,7 +273,7 @@ class TextEditorPresenter @state.verticalScrollbar.width = @measuredVerticalScrollbarWidth @state.verticalScrollbar.bottom = @horizontalScrollbarHeight - updateHiddenInputState: -> @batch "shouldUpdateHiddenInputState", -> + updateHiddenInputState: -> return unless lastCursor = @model.getLastCursor() {top, left, height, width} = @pixelRectForScreenRange(lastCursor.getScreenRange()) @@ -299,14 +290,14 @@ class TextEditorPresenter @state.hiddenInput.height = height @state.hiddenInput.width = Math.max(width, 2) - updateContentState: -> @batch "shouldUpdateContentState", -> + updateContentState: -> @state.content.scrollWidth = @scrollWidth @state.content.scrollLeft = @scrollLeft @state.content.indentGuidesVisible = not @model.isMini() and @showIndentGuide @state.content.backgroundColor = if @model.isMini() then null else @backgroundColor @state.content.placeholderText = if @model.isEmpty() then @model.getPlaceholderText() else null - updateLinesState: -> @batch "shouldUpdateLinesState", -> + updateLinesState: -> return unless @startRow? and @endRow? and @lineHeight? visibleLineIds = {} @@ -351,7 +342,7 @@ class TextEditorPresenter top: row * @lineHeight decorationClasses: @lineDecorationClassesForRow(row) - updateCursorsState: -> @batch "shouldUpdateCursorsState", -> + updateCursorsState: -> @state.content.cursors = {} @updateCursorState(cursor) for cursor in @model.cursors # using property directly to avoid allocation return @@ -369,7 +360,7 @@ class TextEditorPresenter @emitDidUpdateState() - updateOverlaysState: -> @batch "shouldUpdateOverlaysState", -> + updateOverlaysState: -> return unless @hasOverlayPositionRequirements() visibleDecorationIds = {} @@ -418,7 +409,7 @@ class TextEditorPresenter return - updateLineNumberGutterState: -> @batch "shouldUpdateLineNumberGutterState", -> + updateLineNumberGutterState: -> @state.gutters.lineNumberGutter.maxLineNumberDigits = @model.getLineCount().toString().length updateCommonGutterState: -> @@ -450,13 +441,12 @@ class TextEditorPresenter @emitDidUpdateState() updateGutterOrderState: -> - @batch "shouldUpdateGutterOrderState", -> - @state.gutters.sortedDescriptions = [] - if @model.isMini() - return - for gutter in @model.getGutters() - isVisible = @gutterIsVisible(gutter) - @state.gutters.sortedDescriptions.push({gutter, visible: isVisible}) + @state.gutters.sortedDescriptions = [] + if @model.isMini() + return + for gutter in @model.getGutters() + isVisible = @gutterIsVisible(gutter) + @state.gutters.sortedDescriptions.push({gutter, visible: isVisible}) # Updates the decoration state for the gutter with the given gutterName. # @state.gutters.customDecorations is an {Object}, with the form: @@ -469,25 +459,24 @@ class TextEditorPresenter # } # } updateCustomGutterDecorationState: -> - @batch 'shouldUpdateCustomGutterDecorationState', => - return unless @startRow? and @endRow? and @lineHeight? + return unless @startRow? and @endRow? and @lineHeight? - @state.gutters.customDecorations = {} - return if @model.isMini() + @state.gutters.customDecorations = {} + return if @model.isMini() - for gutter in @model.getGutters() - gutterName = gutter.name - @state.gutters.customDecorations[gutterName] = {} - return if not @gutterIsVisible(gutter) + for gutter in @model.getGutters() + gutterName = gutter.name + @state.gutters.customDecorations[gutterName] = {} + return if not @gutterIsVisible(gutter) - relevantDecorations = @customGutterDecorationsInRange(gutterName, @startRow, @endRow - 1) - relevantDecorations.forEach (decoration) => - decorationRange = decoration.getMarker().getScreenRange() - @state.gutters.customDecorations[gutterName][decoration.id] = - top: @lineHeight * decorationRange.start.row - height: @lineHeight * decorationRange.getRowCount() - item: decoration.getProperties().item - class: decoration.getProperties().class + relevantDecorations = @customGutterDecorationsInRange(gutterName, @startRow, @endRow - 1) + relevantDecorations.forEach (decoration) => + decorationRange = decoration.getMarker().getScreenRange() + @state.gutters.customDecorations[gutterName][decoration.id] = + top: @lineHeight * decorationRange.start.row + height: @lineHeight * decorationRange.getRowCount() + item: decoration.getProperties().item + class: decoration.getProperties().class gutterIsVisible: (gutterModel) -> isVisible = gutterModel.isVisible() @@ -495,7 +484,7 @@ class TextEditorPresenter isVisible = isVisible and @showLineNumbers isVisible - updateLineNumbersState: -> @batch "shouldUpdateLineNumbersState", -> + updateLineNumbersState: -> return unless @startRow? and @endRow? and @lineHeight? visibleLineNumberIds = {} @@ -750,7 +739,7 @@ class TextEditorPresenter @mouseWheelScreenRow = null @shouldUpdateLinesState = true @shouldUpdateLineNumbersState = true - @updateCustomGutterDecorationState() + @shouldUpdateCustomGutterDecorationState = true @emitDidUpdateState() @@ -1119,7 +1108,7 @@ class TextEditorPresenter @emitDidUpdateState() - updateDecorations: -> @batch "shouldUpdateDecorations", -> + updateDecorations: -> @lineDecorationsByScreenRow = {} @lineNumberDecorationsByScreenRow = {} @customGutterDecorationsByGutterNameAndScreenRow = {} From e1d5485516553cf830e38c49e01db436de064125 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 29 Apr 2015 09:13:27 +0200 Subject: [PATCH 0928/1783] :art: --- src/text-editor-presenter.coffee | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 26c9627da..d698b04d8 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -82,11 +82,11 @@ class TextEditorPresenter @updateCustomGutterDecorationState() if @shouldUpdateCustomGutterDecorationState @updating = false - @resetShouldUpdateStates() + @resetTrackedUpdates() @state - resetShouldUpdateStates: -> + resetTrackedUpdates: -> @shouldUpdateFocusedState = false @shouldUpdateHeightState = false @shouldUpdateVerticalScrollState = false @@ -126,7 +126,6 @@ class TextEditorPresenter @emitDidUpdateState() @disposables.add @model.onDidChangeMini => - @updateScrollbarDimensions() @shouldUpdateScrollbarsState = true @shouldUpdateContentState = true @shouldUpdateDecorations = true @@ -135,13 +134,14 @@ class TextEditorPresenter @shouldUpdateLineNumbersState = true @shouldUpdateGutterOrderState = true @shouldUpdateCustomGutterDecorationState = true - @updateCommonGutterState() # TODO: check out later... + @updateScrollbarDimensions() + @updateCommonGutterState() @emitDidUpdateState() @disposables.add @model.onDidChangeLineNumberGutterVisible => @shouldUpdateLineNumberGutterState = true @shouldUpdateGutterOrderState = true - @updateCommonGutterState() # TODO: check out later... + @updateCommonGutterState() @emitDidUpdateState() @disposables.add @model.onDidAddDecoration(@didAddDecoration.bind(this)) @@ -183,7 +183,7 @@ class TextEditorPresenter @showLineNumbers = newValue @shouldUpdateLineNumberGutterState = true @shouldUpdateGutterOrderState = true - @updateCommonGutterState() # TODO: check this out + @updateCommonGutterState() @emitDidUpdateState() @@ -192,7 +192,7 @@ class TextEditorPresenter @shouldUpdateContentState = true @shouldUpdateLineNumberGutterState = true @shouldUpdateGutterOrderState = true - @updateCommonGutterState() # TODO: check this out + @updateCommonGutterState() @emitDidUpdateState() @@ -237,7 +237,7 @@ class TextEditorPresenter @updateGutterOrderState() @updateCustomGutterDecorationState() - @resetShouldUpdateStates() + @resetTrackedUpdates() updateFocusedState: -> @state.focused = @focused From 52f06a619eded6bbc7ea44e7202c1884ea995292 Mon Sep 17 00:00:00 2001 From: simurai Date: Wed, 29 Apr 2015 16:59:24 +0900 Subject: [PATCH 0929/1783] Add DejaVu Sans Mono to font stack Should fix font issues on Linux #4201 --- static/text-editor-light.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/text-editor-light.less b/static/text-editor-light.less index 3ba4e8313..b51995dc4 100644 --- a/static/text-editor-light.less +++ b/static/text-editor-light.less @@ -4,7 +4,7 @@ atom-text-editor { display: block; - font-family: Inconsolata, Monaco, Consolas, 'Courier New', Courier; + font-family: Inconsolata, Monaco, Consolas, 'DejaVu Sans Mono', 'Courier New', Courier; line-height: 1.3; } From d97f67095e555c874ff6aaa511c1807884b6a0d0 Mon Sep 17 00:00:00 2001 From: simurai Date: Wed, 29 Apr 2015 20:02:54 +0900 Subject: [PATCH 0930/1783] Add better fallback font See comment https://github.com/atom/atom/pull/6567#commitcomment-10960397 --- static/text-editor-light.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/text-editor-light.less b/static/text-editor-light.less index b51995dc4..9d87c61ca 100644 --- a/static/text-editor-light.less +++ b/static/text-editor-light.less @@ -4,7 +4,7 @@ atom-text-editor { display: block; - font-family: Inconsolata, Monaco, Consolas, 'DejaVu Sans Mono', 'Courier New', Courier; + font-family: Inconsolata, Monaco, Consolas, 'DejaVu Sans Mono', monospace; line-height: 1.3; } From 5e766b6eee31c9d4abb2235f98c9a6395822d5ed Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Wed, 29 Apr 2015 08:53:04 -0700 Subject: [PATCH 0931/1783] [Gutter] Clear custom gutter decorations from previous usages of a custom gutter element --- spec/text-editor-element-spec.coffee | 15 +++++++++++++++ src/custom-gutter-component.coffee | 2 ++ 2 files changed, 17 insertions(+) diff --git a/spec/text-editor-element-spec.coffee b/spec/text-editor-element-spec.coffee index 418e0367d..435b3a4a5 100644 --- a/spec/text-editor-element-spec.coffee +++ b/spec/text-editor-element-spec.coffee @@ -79,6 +79,21 @@ describe "TextEditorElement", -> jasmine.attachToDOM(element) expect(element.shadowRoot.querySelectorAll('.line-number').length).toBe initialCount + it "does not render duplicate decorations in custom gutters", -> + editor = new TextEditor + editor.setText('1\n2\n3') + editor.addGutter({name: 'test-gutter'}) + marker = editor.markBufferRange([[0,0],[2,0]]) + editor.decorateMarker(marker, {type: 'gutter', gutterName: 'test-gutter'}) + element = atom.views.getView(editor) + + jasmine.attachToDOM(element) + initialDecorationCount = element.shadowRoot.querySelectorAll('.decoration').length + + element.remove() + jasmine.attachToDOM(element) + expect(element.shadowRoot.querySelectorAll('.decoration').length).toBe initialDecorationCount + describe "focus and blur handling", -> describe "when the editor.useShadowDOM config option is true", -> it "proxies focus/blur events to/from the hidden input inside the shadow root", -> diff --git a/src/custom-gutter-component.coffee b/src/custom-gutter-component.coffee index 380322e8b..1321c8990 100644 --- a/src/custom-gutter-component.coffee +++ b/src/custom-gutter-component.coffee @@ -13,6 +13,8 @@ class CustomGutterComponent @domNode = atom.views.getView(@gutter) @decorationsNode = @domNode.firstChild + # Clear the contents in case the domNode is being reused. + @decorationsNode.innerHTML = '' getDomNode: -> @domNode From e6887fd2120c234177422e3b4060a41afc46ad32 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 29 Apr 2015 09:05:35 -0700 Subject: [PATCH 0932/1783] :arrow_up: language-java@0.15 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8d8140862..2d9ade0e1 100644 --- a/package.json +++ b/package.json @@ -133,7 +133,7 @@ "language-go": "0.25.0", "language-html": "0.34.0", "language-hyperlink": "0.12.2", - "language-java": "0.14.0", + "language-java": "0.15.0", "language-javascript": "0.75.0", "language-json": "0.14.0", "language-less": "0.26.0", From 213e6fd6112f2a95b3f87c87d769d42fd92271e5 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 28 Apr 2015 11:44:56 -0700 Subject: [PATCH 0933/1783] Check process before killing --- src/buffered-process.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/buffered-process.coffee b/src/buffered-process.coffee index 9748e5557..44c870a93 100644 --- a/src/buffered-process.coffee +++ b/src/buffered-process.coffee @@ -164,6 +164,8 @@ class BufferedProcess # This is required since killing the cmd.exe does not terminate child # processes. killOnWindows: -> + return unless @process? + parentPid = @process.pid cmd = 'wmic' args = [ From a67d9615a81318f4ec2103b0a2e7d0a75e947eb0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 28 Apr 2015 11:46:04 -0700 Subject: [PATCH 0934/1783] Extract error handling helper --- src/buffered-process.coffee | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/buffered-process.coffee b/src/buffered-process.coffee index 44c870a93..809618817 100644 --- a/src/buffered-process.coffee +++ b/src/buffered-process.coffee @@ -102,17 +102,7 @@ class BufferedProcess processExited = true triggerExitCallback() - @process.on 'error', (error) => - handled = false - handle = -> handled = true - - @emitter.emit 'will-throw-error', {error, handle} - - if error.code is 'ENOENT' and error.syscall.indexOf('spawn') is 0 - error = new Error("Failed to spawn command `#{command}`. Make sure `#{command}` is installed and on your PATH", error.path) - error.name = 'BufferedProcessError' - - throw error unless handled + @process.on 'error', (error) => @handleError(error) ### Section: Event Subscription @@ -222,3 +212,15 @@ class BufferedProcess @killProcess() undefined + + handleError: (error) -> + handled = false + handle = -> handled = true + + @emitter.emit 'will-throw-error', {error, handle} + + if error.code is 'ENOENT' and error.syscall.indexOf('spawn') is 0 + error = new Error("Failed to spawn command `#{command}`. Make sure `#{command}` is installed and on your PATH", error.path) + error.name = 'BufferedProcessError' + + throw error unless handled From 99e40a788bfe643210f844c2ce0a42fb0742a656 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 28 Apr 2015 11:50:28 -0700 Subject: [PATCH 0935/1783] Handle errors thrown by child_process.spawn --- src/buffered-process.coffee | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/buffered-process.coffee b/src/buffered-process.coffee index 809618817..b96416850 100644 --- a/src/buffered-process.coffee +++ b/src/buffered-process.coffee @@ -69,9 +69,9 @@ class BufferedProcess cmdArgs = ['/s', '/c', "\"#{cmdArgs.join(' ')}\""] cmdOptions = _.clone(options) cmdOptions.windowsVerbatimArguments = true - @process = ChildProcess.spawn(@getCmdPath(), cmdArgs, cmdOptions) + @process = @spawn(@getCmdPath(), cmdArgs, cmdOptions) else - @process = ChildProcess.spawn(command, args, options) + @process = @spawn(command, args, options) @killed = false stdoutClosed = true @@ -213,6 +213,13 @@ class BufferedProcess undefined + spawn: (command, args, options) -> + try + process = ChildProcess.spawn(command, args, options) + catch spawnError + process.nextTick => @handleError(spawnError) + process + handleError: (error) -> handled = false handle = -> handled = true From fd84c5ff04d8122f84aa35b67838cd65abc7bd88 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 28 Apr 2015 11:53:18 -0700 Subject: [PATCH 0936/1783] Extract handle events helper --- src/buffered-process.coffee | 64 ++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/src/buffered-process.coffee b/src/buffered-process.coffee index b96416850..4302a0de7 100644 --- a/src/buffered-process.coffee +++ b/src/buffered-process.coffee @@ -72,37 +72,9 @@ class BufferedProcess @process = @spawn(@getCmdPath(), cmdArgs, cmdOptions) else @process = @spawn(command, args, options) + @killed = false - - stdoutClosed = true - stderrClosed = true - processExited = true - exitCode = 0 - triggerExitCallback = -> - return if @killed - if stdoutClosed and stderrClosed and processExited - exit?(exitCode) - - if stdout - stdoutClosed = false - @bufferStream @process.stdout, stdout, -> - stdoutClosed = true - triggerExitCallback() - - if stderr - stderrClosed = false - @bufferStream @process.stderr, stderr, -> - stderrClosed = true - triggerExitCallback() - - if exit - processExited = false - @process.on 'exit', (code) -> - exitCode = code - processExited = true - triggerExitCallback() - - @process.on 'error', (error) => @handleError(error) + @handeEvents(stdout, stderr, exit) if @process? ### Section: Event Subscription @@ -220,6 +192,38 @@ class BufferedProcess process.nextTick => @handleError(spawnError) process + handleEvents: (stdout, stderr, exit) -> + stdoutClosed = true + stderrClosed = true + processExited = true + exitCode = 0 + triggerExitCallback = -> + return if @killed + if stdoutClosed and stderrClosed and processExited + exit?(exitCode) + + if stdout + stdoutClosed = false + @bufferStream @process.stdout, stdout, -> + stdoutClosed = true + triggerExitCallback() + + if stderr + stderrClosed = false + @bufferStream @process.stderr, stderr, -> + stderrClosed = true + triggerExitCallback() + + if exit + processExited = false + @process.on 'exit', (code) -> + exitCode = code + processExited = true + triggerExitCallback() + + @process.on 'error', (error) => @handleError(error) + return + handleError: (error) -> handled = false handle = -> handled = true From 920def7eb0e3281ef23decf0cc36c159baf0442a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 28 Apr 2015 12:03:31 -0700 Subject: [PATCH 0937/1783] Add spec for thrown spawn error --- spec/buffered-process-spec.coffee | 47 +++++++++++++++++++++++-------- src/buffered-process.coffee | 4 +-- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/spec/buffered-process-spec.coffee b/spec/buffered-process-spec.coffee index ea9abe001..963460054 100644 --- a/spec/buffered-process-spec.coffee +++ b/spec/buffered-process-spec.coffee @@ -13,21 +13,44 @@ describe "BufferedProcess", -> window.onerror = oldOnError describe "when there is an error handler specified", -> - it "calls the error handler and does not throw an exception", -> - process = new BufferedProcess - command: 'bad-command-nope' - args: ['nothing'] - options: {} + describe "when an error event is emitted by the process", -> + it "calls the error handler and does not throw an exception", -> + process = new BufferedProcess + command: 'bad-command-nope' + args: ['nothing'] + options: {} - errorSpy = jasmine.createSpy().andCallFake (error) -> error.handle() - process.onWillThrowError(errorSpy) + errorSpy = jasmine.createSpy().andCallFake (error) -> error.handle() + process.onWillThrowError(errorSpy) - waitsFor -> errorSpy.callCount > 0 + waitsFor -> errorSpy.callCount > 0 - runs -> - expect(window.onerror).not.toHaveBeenCalled() - expect(errorSpy).toHaveBeenCalled() - expect(errorSpy.mostRecentCall.args[0].error.message).toContain 'spawn bad-command-nope ENOENT' + runs -> + expect(window.onerror).not.toHaveBeenCalled() + expect(errorSpy).toHaveBeenCalled() + expect(errorSpy.mostRecentCall.args[0].error.message).toContain 'spawn bad-command-nope ENOENT' + + describe "when an error is thrown spawning the process", -> + it "calls the error handler and does not throw an exception", -> + spyOn(ChildProcess, 'spawn').andCallFake -> + error = new Error('Something is really wrong') + error.code = 'EAGAIN' + throw error + + process = new BufferedProcess + command: 'ls' + args: [] + options: {} + + errorSpy = jasmine.createSpy().andCallFake (error) -> error.handle() + process.onWillThrowError(errorSpy) + + waitsFor -> errorSpy.callCount > 0 + + runs -> + expect(window.onerror).not.toHaveBeenCalled() + expect(errorSpy).toHaveBeenCalled() + expect(errorSpy.mostRecentCall.args[0].error.message).toContain 'Something is really wrong' describe "when there is not an error handler specified", -> it "calls the error handler and does not throw an exception", -> diff --git a/src/buffered-process.coffee b/src/buffered-process.coffee index 4302a0de7..95492449f 100644 --- a/src/buffered-process.coffee +++ b/src/buffered-process.coffee @@ -187,10 +187,10 @@ class BufferedProcess spawn: (command, args, options) -> try - process = ChildProcess.spawn(command, args, options) + spawned = ChildProcess.spawn(command, args, options) catch spawnError process.nextTick => @handleError(spawnError) - process + spawned handleEvents: (stdout, stderr, exit) -> stdoutClosed = true From 96f0916ddd19ed20d0543342cd51e7e9763d8b07 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 28 Apr 2015 18:07:09 -0700 Subject: [PATCH 0938/1783] Add missing l --- src/buffered-process.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/buffered-process.coffee b/src/buffered-process.coffee index 95492449f..b50e1a22e 100644 --- a/src/buffered-process.coffee +++ b/src/buffered-process.coffee @@ -74,7 +74,7 @@ class BufferedProcess @process = @spawn(command, args, options) @killed = false - @handeEvents(stdout, stderr, exit) if @process? + @handleEvents(stdout, stderr, exit) if @process? ### Section: Event Subscription From 78d2c868f79f6b6a535c78b1cbe83394535c08f5 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 28 Apr 2015 18:08:13 -0700 Subject: [PATCH 0939/1783] Assign process ivar from within spawn --- src/buffered-process.coffee | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/buffered-process.coffee b/src/buffered-process.coffee index b50e1a22e..030d952f5 100644 --- a/src/buffered-process.coffee +++ b/src/buffered-process.coffee @@ -69,9 +69,9 @@ class BufferedProcess cmdArgs = ['/s', '/c', "\"#{cmdArgs.join(' ')}\""] cmdOptions = _.clone(options) cmdOptions.windowsVerbatimArguments = true - @process = @spawn(@getCmdPath(), cmdArgs, cmdOptions) + @spawn(@getCmdPath(), cmdArgs, cmdOptions) else - @process = @spawn(command, args, options) + @spawn(command, args, options) @killed = false @handleEvents(stdout, stderr, exit) if @process? @@ -187,10 +187,9 @@ class BufferedProcess spawn: (command, args, options) -> try - spawned = ChildProcess.spawn(command, args, options) + @process = ChildProcess.spawn(command, args, options) catch spawnError process.nextTick => @handleError(spawnError) - spawned handleEvents: (stdout, stderr, exit) -> stdoutClosed = true From a9806d63ebc6c17085aed059eae7cfd5bead2079 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 28 Apr 2015 18:08:44 -0700 Subject: [PATCH 0940/1783] Check for process from within handleEvents --- src/buffered-process.coffee | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/buffered-process.coffee b/src/buffered-process.coffee index 030d952f5..c735509ab 100644 --- a/src/buffered-process.coffee +++ b/src/buffered-process.coffee @@ -74,7 +74,7 @@ class BufferedProcess @spawn(command, args, options) @killed = false - @handleEvents(stdout, stderr, exit) if @process? + @handleEvents(stdout, stderr, exit) ### Section: Event Subscription @@ -192,6 +192,8 @@ class BufferedProcess process.nextTick => @handleError(spawnError) handleEvents: (stdout, stderr, exit) -> + return unless @process? + stdoutClosed = true stderrClosed = true processExited = true From 63bfee1096f47ffdc3329dee0eed6a16d1eaf00f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 28 Apr 2015 18:35:55 -0700 Subject: [PATCH 0941/1783] Use the command ivar --- src/buffered-process.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/buffered-process.coffee b/src/buffered-process.coffee index c735509ab..cfb0d3703 100644 --- a/src/buffered-process.coffee +++ b/src/buffered-process.coffee @@ -48,6 +48,7 @@ class BufferedProcess constructor: ({command, args, options, stdout, stderr, exit}={}) -> @emitter = new Emitter options ?= {} + @command = command # Related to joyent/node#2318 if process.platform is 'win32' # Quote all arguments and escapes inner quotes @@ -232,7 +233,7 @@ class BufferedProcess @emitter.emit 'will-throw-error', {error, handle} if error.code is 'ENOENT' and error.syscall.indexOf('spawn') is 0 - error = new Error("Failed to spawn command `#{command}`. Make sure `#{command}` is installed and on your PATH", error.path) + error = new Error("Failed to spawn command `#{@command}`. Make sure `#{@command}` is installed and on your PATH", error.path) error.name = 'BufferedProcessError' throw error unless handled From c95d6b2c6023d51a0f696f1e81a3ab69cb0cb121 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 28 Apr 2015 18:36:38 -0700 Subject: [PATCH 0942/1783] Catch wmic spawn errors --- src/buffered-process.coffee | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/buffered-process.coffee b/src/buffered-process.coffee index cfb0d3703..c7097d711 100644 --- a/src/buffered-process.coffee +++ b/src/buffered-process.coffee @@ -139,7 +139,12 @@ class BufferedProcess 'processid' ] - wmicProcess = ChildProcess.spawn(cmd, args) + try + wmicProcess = ChildProcess.spawn(cmd, args) + catch spawnError + @killProcess() + return + wmicProcess.on 'error', -> # ignore errors output = '' wmicProcess.stdout.on 'data', (data) -> output += data From b2613f94b4e5f9c18d24beedf17b0506955d74fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Machist=C3=A9=20N=2E=20Quintana?= Date: Wed, 29 Apr 2015 12:22:25 -0400 Subject: [PATCH 0943/1783] Update yargs semver version range --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 504eb05fa..42e39c463 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "theorist": "^1.0.2", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", - "yargs": "^3.7.2" + "yargs": ">=3.7.2 <4.0" }, "packageDependencies": { "atom-dark-syntax": "0.26.0", From da0c087675db8e5bfd1b66560ba51fdead7d8db1 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 29 Apr 2015 09:43:41 -0700 Subject: [PATCH 0944/1783] Add BufferedProcess spec for invoking callbacks --- spec/buffered-process-spec.coffee | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/spec/buffered-process-spec.coffee b/spec/buffered-process-spec.coffee index 963460054..04cff0b6d 100644 --- a/spec/buffered-process-spec.coffee +++ b/spec/buffered-process-spec.coffee @@ -96,3 +96,21 @@ describe "BufferedProcess", -> expect(ChildProcess.spawn.argsForCall[0][1][0]).toBe '/s' 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 ", -> + stdout = '' + stderr = '' + exitCallback = jasmine.createSpy('exit callback') + process = new BufferedProcess + command: atom.packages.getApmPath() + args: ['-h'] + options: {} + stdout: (lines) -> stdout += lines + stderr: (lines) -> stderr += lines + exit: exitCallback + + waitsFor -> exitCallback.callCount is 1 + + runs -> + expect(stderr).toContain 'apm - Atom Package Manager' + expect(stdout).toEqual '' From 37efbe0b3510cfd1391b7e2b0bfd7a036db10af2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 29 Apr 2015 10:03:28 -0700 Subject: [PATCH 0945/1783] :arrow_up: language-hyperlink@0.13 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2d9ade0e1..704e735c7 100644 --- a/package.json +++ b/package.json @@ -132,7 +132,7 @@ "language-git": "0.10.0", "language-go": "0.25.0", "language-html": "0.34.0", - "language-hyperlink": "0.12.2", + "language-hyperlink": "0.13.0", "language-java": "0.15.0", "language-javascript": "0.75.0", "language-json": "0.14.0", From be51cc09b37b32b844834a968848af40b4a3aa99 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 29 Apr 2015 14:25:21 -0700 Subject: [PATCH 0946/1783] :arrow_up: language-javasript@0.76 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 704e735c7..1620601b4 100644 --- a/package.json +++ b/package.json @@ -134,7 +134,7 @@ "language-html": "0.34.0", "language-hyperlink": "0.13.0", "language-java": "0.15.0", - "language-javascript": "0.75.0", + "language-javascript": "0.76.0", "language-json": "0.14.0", "language-less": "0.26.0", "language-make": "0.14.0", From d3ef6c91af8d145de4671a73f5ab9ae6e1316987 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 29 Apr 2015 15:47:44 -0700 Subject: [PATCH 0947/1783] Measure gutterWidth, and pass to presenter --- spec/text-editor-presenter-spec.coffee | 11 ++++++----- src/text-editor-component.coffee | 1 + src/text-editor-presenter.coffee | 10 +++++++--- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 5a50a49a9..8091728a5 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -32,6 +32,7 @@ describe "TextEditorPresenter", -> windowWidth: 500 windowHeight: 130 boundingClientRect: {left: 0, top: 0, width: 500, height: 130} + gutterWidth: 0 lineHeight: 10 baseCharacterWidth: 10 horizontalScrollbarHeight: 10 @@ -1628,7 +1629,7 @@ describe "TextEditorPresenter", -> marker = editor.markBufferPosition([0, 26], invalidate: 'never') decoration = editor.decorateMarker(marker, {type: 'overlay', item}) - presenter = buildPresenter({scrollLeft, windowWidth, windowHeight, contentFrameWidth, boundingClientRect}) + presenter = buildPresenter({scrollLeft, windowWidth, windowHeight, contentFrameWidth, boundingClientRect, gutterWidth}) expectStateUpdate presenter, -> presenter.setOverlayDimensions(decoration.id, itemWidth, itemHeight, contentMargin) @@ -1654,7 +1655,7 @@ describe "TextEditorPresenter", -> marker = editor.markBufferPosition([5, 0], invalidate: 'never') decoration = editor.decorateMarker(marker, {type: 'overlay', item}) - presenter = buildPresenter({scrollTop, windowWidth, windowHeight, contentFrameWidth, boundingClientRect}) + presenter = buildPresenter({scrollTop, windowWidth, windowHeight, contentFrameWidth, boundingClientRect, gutterWidth}) expectStateUpdate presenter, -> presenter.setOverlayDimensions(decoration.id, itemWidth, itemHeight, contentMargin) @@ -1682,7 +1683,7 @@ describe "TextEditorPresenter", -> marker = cursor.marker decoration = editor.decorateMarker(marker, {type: 'overlay', item}) - presenter = buildPresenter({windowWidth, windowHeight, contentFrameWidth, boundingClientRect}) + presenter = buildPresenter({windowWidth, windowHeight, contentFrameWidth, boundingClientRect, gutterWidth}) expectStateUpdate presenter, -> presenter.setOverlayDimensions(decoration.id, itemWidth, itemHeight, contentMargin) @@ -1715,7 +1716,7 @@ describe "TextEditorPresenter", -> marker = editor.markBufferPosition([1, 0], invalidate: 'never') decoration = editor.decorateMarker(marker, {type: 'overlay', item}) - presenter = buildPresenter({windowWidth, windowHeight, contentFrameWidth, boundingClientRect}) + presenter = buildPresenter({windowWidth, windowHeight, contentFrameWidth, boundingClientRect, gutterWidth}) expectStateUpdate presenter, -> presenter.setOverlayDimensions(decoration.id, itemWidth, itemHeight, contentMargin) @@ -1736,7 +1737,7 @@ describe "TextEditorPresenter", -> marker = editor.markBufferPosition([0, 0], invalidate: 'never') decoration = editor.decorateMarker(marker, {type: 'overlay', item}) - presenter = buildPresenter({windowWidth, windowHeight, contentFrameWidth, boundingClientRect}) + presenter = buildPresenter({windowWidth, windowHeight, contentFrameWidth, boundingClientRect, gutterWidth}) expectStateUpdate presenter, -> presenter.setOverlayDimensions(decoration.id, itemWidth, itemHeight, contentMargin) diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index e284516fa..84d84cdbf 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -619,6 +619,7 @@ class TextEditorComponent if clientWidth > 0 @presenter.setContentFrameWidth(clientWidth) + @presenter.setGutterWidth(@gutterContainerComponent?.getDomNode().offsetWidth ? 0) @presenter.setBoundingClientRect(@hostElement.getBoundingClientRect()) measureWindowSize: -> diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 55b88f2b8..71bf52e7f 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -13,7 +13,7 @@ class TextEditorPresenter overlayDimensions: {} constructor: (params) -> - {@model, @autoHeight, @explicitHeight, @contentFrameWidth, @scrollTop, @scrollLeft, @boundingClientRect, @windowWidth, @windowHeight} = params + {@model, @autoHeight, @explicitHeight, @contentFrameWidth, @scrollTop, @scrollLeft, @boundingClientRect, @windowWidth, @windowHeight, @gutterWidth} = params {horizontalScrollbarHeight, verticalScrollbarWidth} = params {@lineHeight, @baseCharacterWidth, @lineOverdrawMargin, @backgroundColor, @gutterBackgroundColor} = params {@cursorBlinkPeriod, @cursorBlinkResumeDelay, @stoppedScrollingDelay, @focused} = params @@ -351,10 +351,9 @@ class TextEditorPresenter pixelPosition = @pixelPositionForScreenPosition(screenPosition) {scrollTop, scrollLeft} = @state.content - gutterWidth = @boundingClientRect.width - @contentFrameWidth top = pixelPosition.top + @lineHeight - scrollTop - left = pixelPosition.left + gutterWidth - scrollLeft + left = pixelPosition.left + @gutterWidth - scrollLeft if overlayDimensions = @overlayDimensions[decoration.id] {itemWidth, itemHeight, contentMargin} = overlayDimensions @@ -817,6 +816,11 @@ class TextEditorPresenter @updateCommonGutterState() @updateGutterOrderState() + setGutterWidth: (gutterWidth) -> + if @gutterWidth isnt gutterWidth + @gutterWidth = gutterWidth + @updateOverlaysState() + setLineHeight: (lineHeight) -> unless @lineHeight is lineHeight @lineHeight = lineHeight From 41143c7801d201739eccb49ceac1261e9eab6874 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 29 Apr 2015 15:54:55 -0700 Subject: [PATCH 0948/1783] Default `gutterWidth` to 0 in the presenter. --- src/text-editor-presenter.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 71bf52e7f..6007f1961 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -19,6 +19,7 @@ class TextEditorPresenter {@cursorBlinkPeriod, @cursorBlinkResumeDelay, @stoppedScrollingDelay, @focused} = params @measuredHorizontalScrollbarHeight = horizontalScrollbarHeight @measuredVerticalScrollbarWidth = verticalScrollbarWidth + @gutterWidth ?= 0 @disposables = new CompositeDisposable @emitter = new Emitter From a8283c3c9b4727c7e37eb29eea6ae6a1b3f50a39 Mon Sep 17 00:00:00 2001 From: CaptSaltyJack Date: Tue, 24 Mar 2015 17:50:16 -0700 Subject: [PATCH 0949/1783] Added delete-to-next/previous-word-boundary This is better behavior for alt-del/backspace operations, is less "greedy" and doesn't eat up excess characters. Also set default key mappings to these, feel free to trash my changes to keymaps/darwin.cson. Though I do feel this should be default behavior, personally. --- keymaps/darwin.cson | 4 +-- menus/darwin.cson | 2 ++ spec/text-editor-spec.coffee | 55 ++++++++++++++++++++++++++++++++++ src/selection.coffee | 22 ++++++++++++++ src/text-editor-element.coffee | 2 ++ src/text-editor.coffee | 8 +++++ 6 files changed, 91 insertions(+), 2 deletions(-) diff --git a/keymaps/darwin.cson b/keymaps/darwin.cson index 34d18e159..c29d9de45 100644 --- a/keymaps/darwin.cson +++ b/keymaps/darwin.cson @@ -119,8 +119,8 @@ 'cmd-right': 'editor:move-to-end-of-screen-line' 'cmd-shift-left': 'editor:select-to-first-character-of-line' 'cmd-shift-right': 'editor:select-to-end-of-line' - 'alt-backspace': 'editor:delete-to-beginning-of-word' - 'alt-delete': 'editor:delete-to-end-of-word' + 'alt-backspace': 'editor:delete-to-previous-word-boundary' + 'alt-delete': 'editor:delete-to-next-word-boundary' 'ctrl-a': 'editor:move-to-first-character-of-line' 'ctrl-e': 'editor:move-to-end-of-line' 'ctrl-k': 'editor:cut-to-end-of-line' diff --git a/menus/darwin.cson b/menus/darwin.cson index f95479d99..17072e14f 100644 --- a/menus/darwin.cson +++ b/menus/darwin.cson @@ -81,6 +81,8 @@ { label: 'Lower Case', command: 'editor:lower-case' } { type: 'separator' } { label: 'Delete to End of Word', command: 'editor:delete-to-end-of-word' } + { label: 'Delete to Previous Word Boundary', command: 'editor:delete-to-previous-word-boundary' } + { label: 'Delete to Next Word Boundary', command: 'editor:delete-to-next-word-boundary' } { label: 'Delete Line', command: 'editor:delete-line' } { type: 'separator' } { label: 'Transpose', command: 'editor:transpose' } diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 4e990b914..2c58c6018 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -2343,6 +2343,61 @@ describe "TextEditor", -> editor.backspace() expect(editor.lineTextForBufferRow(0)).toBe 'var = () {' + describe ".deleteToPreviousWordBoundary()", -> + describe "when no text is selected", -> + it "deletes to the previous word boundary", -> + editor.setCursorBufferPosition([0, 16]) + editor.addCursorAtBufferPosition([1, 21]) + [cursor1, cursor2] = editor.getCursors() + + editor.deleteToPreviousWordBoundary() + expect(buffer.lineForRow(1)).toBe 'var quicksort =function () {' + expect(buffer.lineForRow(2)).toBe ' var sort = (items) {' + expect(cursor1.getBufferPosition()).toEqual [0, 15] + expect(cursor2.getBufferPosition()).toEqual [1, 13] + + editor.deleteToPreviousWordBoundary() + expect(buffer.lineForRow(1)).toBe 'var quicksort function () {' + expect(buffer.lineForRow(2)).toBe ' var sort =(items) {' + expect(cursor1.getBufferPosition()).toEqual [0, 14] + expect(cursor2.getBufferPosition()).toEqual [1, 12] + + describe "when text is selected", -> + it "deletes only selected text", -> + editor.setSelectedBufferRange([[1, 24], [1, 27]]) + editor.deleteToEndOfWord() + expect(buffer.lineForRow(1)).toBe ' var sort = function(it) {' + + describe ".deleteToNextWordBoundary()", -> + describe "when no text is selected", -> + it "deletes to the next word boundary", -> + editor.setCursorBufferPosition([0, 15]) + editor.addCursorAtBufferPosition([1, 24]) + [cursor1, cursor2] = editor.getCursors() + + editor.deleteToNextWordBoundary() + expect(buffer.lineForRow(1)).toBe 'var quicksort =function () {' + expect(buffer.lineForRow(2)).toBe ' var sort = function(it) {' + expect(cursor1.getBufferPosition()).toEqual [0, 15] + expect(cursor2.getBufferPosition()).toEqual [1, 24] + + editor.deleteToNextWordBoundary() + expect(buffer.lineForRow(1)).toBe 'var quicksort = () {' + expect(buffer.lineForRow(2)).toBe ' var sort = function(it {' + expect(cursor1.getBufferPosition()).toEqual [1, 24] + + editor.deleteToNextWordBoundary() + expect(buffer.lineForRow(1)).toBe 'var quicksort = () {' + expect(buffer.lineForRow(2)).toBe ' var sort = function(it {' + expect(cursor1.getBufferPosition()).toEqual [1, 24] + expect(cursor2.getBufferPosition()).toEqual [2, 5] + + describe "when text is selected", -> + it "deletes only selected text", -> + editor.setSelectedBufferRange([[1, 24], [1, 27]]) + editor.deleteToEndOfWord() + expect(buffer.lineForRow(1)).toBe ' var sort = function(it) {' + describe ".deleteToBeginningOfWord()", -> describe "when no text is selected", -> it "deletes all text between the cursor and the beginning of the word", -> diff --git a/src/selection.coffee b/src/selection.coffee index f806acf43..658a50b17 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -404,6 +404,28 @@ class Selection extends Model @selectLeft() if @isEmpty() and not @editor.isFoldedAtScreenRow(@cursor.getScreenRow()) @deleteSelectedText() + # Deprecated: Use {::deleteToBeginningOfWord} instead. + backspaceToBeginningOfWord: -> + deprecate("Use Selection::deleteToBeginningOfWord() instead") + @deleteToBeginningOfWord() + + # Deprecated: Use {::deleteToBeginningOfLine} instead. + backspaceToBeginningOfLine: -> + deprecate("Use Selection::deleteToBeginningOfLine() instead") + @deleteToBeginningOfLine() + + # Public: Removes the selection or all characters from the start of the + # selection back to the previous word boundary if nothing is selected. + deleteToPreviousWordBoundary: -> + @selectToPreviousWordBoundary() if @isEmpty() + @deleteSelectedText() + + # Public: Removes the selection or all characters from the start of the + # selection up to the next word boundary if nothing is selected. + deleteToNextWordBoundary: -> + @selectToNextWordBoundary() if @isEmpty() + @deleteSelectedText() + # Public: Removes from the start of the selection to the beginning of the # current word if the selection is empty otherwise it deletes the selection. deleteToBeginningOfWord: -> diff --git a/src/text-editor-element.coffee b/src/text-editor-element.coffee index 95c60f9a0..ab18be8bf 100644 --- a/src/text-editor-element.coffee +++ b/src/text-editor-element.coffee @@ -281,6 +281,8 @@ atom.commands.add 'atom-text-editor', stopEventPropagationAndGroupUndo( 'core:cut': -> @cutSelectedText() 'core:copy': -> @copySelectedText() 'core:paste': -> @pasteText() + 'editor:delete-to-previous-word-boundary': -> @deleteToPreviousWordBoundary() + 'editor:delete-to-next-word-boundary': -> @deleteToNextWordBoundary() 'editor:delete-to-beginning-of-word': -> @deleteToBeginningOfWord() 'editor:delete-to-beginning-of-line': -> @deleteToBeginningOfLine() 'editor:delete-to-end-of-line': -> @deleteToEndOfLine() diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 8241cc8c9..886d628d9 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -1057,6 +1057,14 @@ class TextEditor extends Model deleteToBeginningOfWord: -> @mutateSelectedText (selection) -> selection.deleteToBeginningOfWord() + # Similar to above, but deletes back to the previous word boundary + deleteToPreviousWordBoundary: -> + @mutateSelectedText (selection) -> selection.deleteToPreviousWordBoundary() + + # Similar to above, but deletes up to the next word boundary + deleteToNextWordBoundary: -> + @mutateSelectedText (selection) -> selection.deleteToNextWordBoundary() + # Extended: For each selection, if the selection is empty, delete all characters # of the containing line that precede the cursor. Otherwise delete the # selected text. From 45d46a726af31ad0355a390c55d59f7cb5c28066 Mon Sep 17 00:00:00 2001 From: CaptSaltyJack Date: Wed, 29 Apr 2015 16:52:09 -0700 Subject: [PATCH 0950/1783] Added menu items to Linux/Windows --- menus/linux.cson | 2 ++ menus/win32.cson | 2 ++ 2 files changed, 4 insertions(+) diff --git a/menus/linux.cson b/menus/linux.cson index a826ab6b5..9363d02e5 100644 --- a/menus/linux.cson +++ b/menus/linux.cson @@ -55,6 +55,8 @@ { label: '&Lower Case', command: 'editor:lower-case' } { type: 'separator' } { label: 'Delete to End of &Word', command: 'editor:delete-to-end-of-word' } + { label: 'Delete to Previous Word Boundary', command: 'editor:delete-to-previous-word-boundary' } + { label: 'Delete to Next Word Boundary', command: 'editor:delete-to-next-word-boundary' } { label: '&Delete Line', command: 'editor:delete-line' } { type: 'separator' } { label: '&Transpose', command: 'editor:transpose' } diff --git a/menus/win32.cson b/menus/win32.cson index cbefc1e5c..068817888 100644 --- a/menus/win32.cson +++ b/menus/win32.cson @@ -62,6 +62,8 @@ { label: '&Lower Case', command: 'editor:lower-case' } { type: 'separator' } { label: 'Delete to End of &Word', command: 'editor:delete-to-end-of-word' } + { label: 'Delete to Previous Word Boundary', command: 'editor:delete-to-previous-word-boundary' } + { label: 'Delete to Next Word Boundary', command: 'editor:delete-to-next-word-boundary' } { label: '&Delete Line', command: 'editor:delete-line' } { type: 'separator' } { label: '&Transpose', command: 'editor:transpose' } From adb017851be0627b7ffe88d9db5f157a10e2da25 Mon Sep 17 00:00:00 2001 From: CaptSaltyJack Date: Wed, 29 Apr 2015 17:09:32 -0700 Subject: [PATCH 0951/1783] Fixed glaring mistake in test spec --- spec/text-editor-spec.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 2c58c6018..a51ac901d 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -2365,7 +2365,7 @@ describe "TextEditor", -> describe "when text is selected", -> it "deletes only selected text", -> editor.setSelectedBufferRange([[1, 24], [1, 27]]) - editor.deleteToEndOfWord() + editor.deleteToPreviousWordBoundary() expect(buffer.lineForRow(1)).toBe ' var sort = function(it) {' describe ".deleteToNextWordBoundary()", -> @@ -2395,7 +2395,7 @@ describe "TextEditor", -> describe "when text is selected", -> it "deletes only selected text", -> editor.setSelectedBufferRange([[1, 24], [1, 27]]) - editor.deleteToEndOfWord() + editor.deleteToNextWordBoundary() expect(buffer.lineForRow(1)).toBe ' var sort = function(it) {' describe ".deleteToBeginningOfWord()", -> From 15b4cefcf4ee7ec37bda0da08bc0dd391581e2c6 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 29 Apr 2015 17:29:04 -0700 Subject: [PATCH 0952/1783] :arrow_up: coffeestack@1.1.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1620601b4..3ad9ecc9d 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "clear-cut": "^2.0.1", "coffee-cash": "0.8.0", "coffee-script": "1.8.0", - "coffeestack": "^1.1.1", + "coffeestack": "^1.1.2", "color": "^0.7.3", "delegato": "^1", "emissary": "^1.3.3", From 22c915a8fd9f0c2912d5e0412d66568020a9b88b Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Wed, 29 Apr 2015 17:52:38 -0700 Subject: [PATCH 0953/1783] Fix most of the specs --- spec/text-editor-spec.coffee | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index a51ac901d..7e362a5b2 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -2343,7 +2343,7 @@ describe "TextEditor", -> editor.backspace() expect(editor.lineTextForBufferRow(0)).toBe 'var = () {' - describe ".deleteToPreviousWordBoundary()", -> + fdescribe ".deleteToPreviousWordBoundary()", -> describe "when no text is selected", -> it "deletes to the previous word boundary", -> editor.setCursorBufferPosition([0, 16]) @@ -2351,14 +2351,14 @@ describe "TextEditor", -> [cursor1, cursor2] = editor.getCursors() editor.deleteToPreviousWordBoundary() - expect(buffer.lineForRow(1)).toBe 'var quicksort =function () {' - expect(buffer.lineForRow(2)).toBe ' var sort = (items) {' + expect(buffer.lineForRow(0)).toBe 'var quicksort =function () {' + expect(buffer.lineForRow(1)).toBe ' var sort = (items) {' expect(cursor1.getBufferPosition()).toEqual [0, 15] expect(cursor2.getBufferPosition()).toEqual [1, 13] editor.deleteToPreviousWordBoundary() - expect(buffer.lineForRow(1)).toBe 'var quicksort function () {' - expect(buffer.lineForRow(2)).toBe ' var sort =(items) {' + expect(buffer.lineForRow(0)).toBe 'var quicksort function () {' + expect(buffer.lineForRow(1)).toBe ' var sort =(items) {' expect(cursor1.getBufferPosition()).toEqual [0, 14] expect(cursor2.getBufferPosition()).toEqual [1, 12] @@ -2368,7 +2368,7 @@ describe "TextEditor", -> editor.deleteToPreviousWordBoundary() expect(buffer.lineForRow(1)).toBe ' var sort = function(it) {' - describe ".deleteToNextWordBoundary()", -> + fdescribe ".deleteToNextWordBoundary()", -> describe "when no text is selected", -> it "deletes to the next word boundary", -> editor.setCursorBufferPosition([0, 15]) @@ -2376,21 +2376,22 @@ describe "TextEditor", -> [cursor1, cursor2] = editor.getCursors() editor.deleteToNextWordBoundary() - expect(buffer.lineForRow(1)).toBe 'var quicksort =function () {' - expect(buffer.lineForRow(2)).toBe ' var sort = function(it) {' + expect(buffer.lineForRow(0)).toBe 'var quicksort =function () {' + expect(buffer.lineForRow(1)).toBe ' var sort = function(it) {' expect(cursor1.getBufferPosition()).toEqual [0, 15] expect(cursor2.getBufferPosition()).toEqual [1, 24] editor.deleteToNextWordBoundary() - expect(buffer.lineForRow(1)).toBe 'var quicksort = () {' - expect(buffer.lineForRow(2)).toBe ' var sort = function(it {' - expect(cursor1.getBufferPosition()).toEqual [1, 24] + expect(buffer.lineForRow(0)).toBe 'var quicksort = () {' + expect(buffer.lineForRow(1)).toBe ' var sort = function(it {' + expect(cursor1.getBufferPosition()).toEqual [0, 15] + expect(cursor2.getBufferPosition()).toEqual [1, 24] editor.deleteToNextWordBoundary() - expect(buffer.lineForRow(1)).toBe 'var quicksort = () {' - expect(buffer.lineForRow(2)).toBe ' var sort = function(it {' - expect(cursor1.getBufferPosition()).toEqual [1, 24] - expect(cursor2.getBufferPosition()).toEqual [2, 5] + expect(buffer.lineForRow(0)).toBe 'var quicksort = () {' + expect(buffer.lineForRow(1)).toBe ' var sort = function(it {' + expect(cursor1.getBufferPosition()).toEqual [0, 15] + expect(cursor2.getBufferPosition()).toEqual [1, 24] describe "when text is selected", -> it "deletes only selected text", -> From eda1b743d76bbff29f45e6a27530f0b0649595bc Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Wed, 29 Apr 2015 18:14:16 -0700 Subject: [PATCH 0954/1783] Fix spec to expect whitespace to be removed --- spec/text-editor-spec.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 7e362a5b2..bf1b9a8c0 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -2388,8 +2388,8 @@ describe "TextEditor", -> expect(cursor2.getBufferPosition()).toEqual [1, 24] editor.deleteToNextWordBoundary() - expect(buffer.lineForRow(0)).toBe 'var quicksort = () {' - expect(buffer.lineForRow(1)).toBe ' var sort = function(it {' + expect(buffer.lineForRow(0)).toBe 'var quicksort =() {' + expect(buffer.lineForRow(1)).toBe ' var sort = function(it{' expect(cursor1.getBufferPosition()).toEqual [0, 15] expect(cursor2.getBufferPosition()).toEqual [1, 24] From be2e3404123b9b309fe3fb090d2df83109a919cc Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Wed, 29 Apr 2015 18:16:49 -0700 Subject: [PATCH 0955/1783] Remove focus --- spec/text-editor-spec.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index bf1b9a8c0..dd6b69f26 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -2343,7 +2343,7 @@ describe "TextEditor", -> editor.backspace() expect(editor.lineTextForBufferRow(0)).toBe 'var = () {' - fdescribe ".deleteToPreviousWordBoundary()", -> + describe ".deleteToPreviousWordBoundary()", -> describe "when no text is selected", -> it "deletes to the previous word boundary", -> editor.setCursorBufferPosition([0, 16]) @@ -2368,7 +2368,7 @@ describe "TextEditor", -> editor.deleteToPreviousWordBoundary() expect(buffer.lineForRow(1)).toBe ' var sort = function(it) {' - fdescribe ".deleteToNextWordBoundary()", -> + describe ".deleteToNextWordBoundary()", -> describe "when no text is selected", -> it "deletes to the next word boundary", -> editor.setCursorBufferPosition([0, 15]) From 70a8b54e50a216bee93004e245dc5a9ee432b5ea Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Wed, 29 Apr 2015 18:27:09 -0700 Subject: [PATCH 0956/1783] Delete bad merge artifacts and reword docs --- src/selection.coffee | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/selection.coffee b/src/selection.coffee index 658a50b17..6ec874203 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -404,24 +404,16 @@ class Selection extends Model @selectLeft() if @isEmpty() and not @editor.isFoldedAtScreenRow(@cursor.getScreenRow()) @deleteSelectedText() - # Deprecated: Use {::deleteToBeginningOfWord} instead. - backspaceToBeginningOfWord: -> - deprecate("Use Selection::deleteToBeginningOfWord() instead") - @deleteToBeginningOfWord() - - # Deprecated: Use {::deleteToBeginningOfLine} instead. - backspaceToBeginningOfLine: -> - deprecate("Use Selection::deleteToBeginningOfLine() instead") - @deleteToBeginningOfLine() - - # Public: Removes the selection or all characters from the start of the - # selection back to the previous word boundary if nothing is selected. + # Public: Removes the selection or, if nothing is selected, then all + # characters from the start of the selection back to the previous word + # boundary. deleteToPreviousWordBoundary: -> @selectToPreviousWordBoundary() if @isEmpty() @deleteSelectedText() - # Public: Removes the selection or all characters from the start of the - # selection up to the next word boundary if nothing is selected. + # Public: Removes the selection or, if nothing is selected, then all + # characters from the start of the selection up to the next word + # boundary. deleteToNextWordBoundary: -> @selectToNextWordBoundary() if @isEmpty() @deleteSelectedText() From 943897bb7fa379260c4d374e37a23d31c77eb41b Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Wed, 29 Apr 2015 18:29:57 -0700 Subject: [PATCH 0957/1783] Revert keymap change --- keymaps/darwin.cson | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/keymaps/darwin.cson b/keymaps/darwin.cson index c29d9de45..34d18e159 100644 --- a/keymaps/darwin.cson +++ b/keymaps/darwin.cson @@ -119,8 +119,8 @@ 'cmd-right': 'editor:move-to-end-of-screen-line' 'cmd-shift-left': 'editor:select-to-first-character-of-line' 'cmd-shift-right': 'editor:select-to-end-of-line' - 'alt-backspace': 'editor:delete-to-previous-word-boundary' - 'alt-delete': 'editor:delete-to-next-word-boundary' + 'alt-backspace': 'editor:delete-to-beginning-of-word' + 'alt-delete': 'editor:delete-to-end-of-word' 'ctrl-a': 'editor:move-to-first-character-of-line' 'ctrl-e': 'editor:move-to-end-of-line' 'ctrl-k': 'editor:cut-to-end-of-line' From 08a615eec3cbb10cfb6973eec465cc09f9e2878a Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Wed, 29 Apr 2015 18:40:16 -0700 Subject: [PATCH 0958/1783] Fix up docs with Extended tag and rewording --- src/text-editor.coffee | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 886d628d9..ac7c7d4f2 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -1057,11 +1057,13 @@ class TextEditor extends Model deleteToBeginningOfWord: -> @mutateSelectedText (selection) -> selection.deleteToBeginningOfWord() - # Similar to above, but deletes back to the previous word boundary + # Extended: Similar to {::deleteToBeginningOfWord}, but deletes only back to the + # previous word boundary. deleteToPreviousWordBoundary: -> @mutateSelectedText (selection) -> selection.deleteToPreviousWordBoundary() - # Similar to above, but deletes up to the next word boundary + # Extended: Similar to {::deleteToEndOfWord}, but deletes only up to the + # next word boundary. deleteToNextWordBoundary: -> @mutateSelectedText (selection) -> selection.deleteToNextWordBoundary() From 363817d7a7a342367af7160cee7181a3f4143c87 Mon Sep 17 00:00:00 2001 From: LEDfan Date: Thu, 30 Apr 2015 14:33:54 +0200 Subject: [PATCH 0959/1783] NodeJS-devel is required on OpenSUSE --- docs/build-instructions/linux.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/build-instructions/linux.md b/docs/build-instructions/linux.md index 7b95e8a17..4874489ab 100644 --- a/docs/build-instructions/linux.md +++ b/docs/build-instructions/linux.md @@ -38,7 +38,7 @@ Ubuntu LTS 12.04 64-bit is the recommended platform. ### openSUSE -* `sudo zypper install nodejs make gcc gcc-c++ glibc-devel git-core libgnome-keyring-devel rpmdevtools` +* `sudo zypper install nodejs nodejs-devel make gcc gcc-c++ glibc-devel git-core libgnome-keyring-devel rpmdevtools` ## Instructions From e54a2e527593b58cf7ac83b7832d6071a9f49866 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 30 Apr 2015 09:27:07 -0700 Subject: [PATCH 0960/1783] :arrow_up: language-coffee-script@0.40 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3ad9ecc9d..a7852741f 100644 --- a/package.json +++ b/package.json @@ -125,7 +125,7 @@ "wrap-guide": "0.32.0", "language-c": "0.44.0", "language-clojure": "0.14.0", - "language-coffee-script": "0.39.0", + "language-coffee-script": "0.40.0", "language-csharp": "0.5.0", "language-css": "0.28.0", "language-gfm": "0.70.0", From 8ad9e6faf152146d2bf81f9296306557cf3e26be Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 30 Apr 2015 10:16:53 -0700 Subject: [PATCH 0961/1783] :arrow_up: fuzzy-finder@0.83 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a7852741f..3037f0724 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,7 @@ "exception-reporting": "0.24.0", "feedback": "0.38.0", "find-and-replace": "0.161.0", - "fuzzy-finder": "0.82.0", + "fuzzy-finder": "0.83.0", "git-diff": "0.55.0", "go-to-line": "0.30.0", "grammar-selector": "0.46.0", From cf1e8c8706380f99761a3973983bb24a3f95d14b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 30 Apr 2015 10:25:20 -0700 Subject: [PATCH 0962/1783] :arrow_up: settings-view@0.196 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3037f0724..f48057c33 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "open-on-github": "0.36.0", "package-generator": "0.38.0", "release-notes": "0.52.0", - "settings-view": "0.195.0", + "settings-view": "0.196.0", "snippets": "0.88.0", "spell-check": "0.56.0", "status-bar": "0.69.0", From 4fb58317ec69cd5eda65e0a88315c0ccc088382c Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Thu, 30 Apr 2015 13:41:47 -0400 Subject: [PATCH 0963/1783] :fire: Redundant lines --- spec/workspace-spec.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index 9b8ce4d50..0b32ff31f 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -430,7 +430,6 @@ describe "Workspace", -> it "resets the font size to the window's starting font size", -> originalFontSize = atom.config.get('editor.fontSize') - atom.config.set('editor.fontSize', originalFontSize) workspace.increaseFontSize() expect(atom.config.get('editor.fontSize')).toBe originalFontSize + 1 workspace.resetFontSize() @@ -443,7 +442,6 @@ describe "Workspace", -> it "does nothing if the font size has not been changed", -> originalFontSize = atom.config.get('editor.fontSize') - atom.config.set('editor.fontSize', originalFontSize) workspace.resetFontSize() expect(atom.config.get('editor.fontSize')).toBe originalFontSize From 9dfd1ac5aaaea92480e0bbcfdaeaf31ea4a3c7a5 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Thu, 30 Apr 2015 11:22:52 -0700 Subject: [PATCH 0964/1783] Normalize repository short urls --- package.json | 1 + src/package.coffee | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/package.json b/package.json index f48057c33..59a678693 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "fuzzaldrin": "^2.1", "git-utils": "^3.0.0", "grim": "1.4.0", + "hosted-git-info": "^2.1.2", "jasmine-json": "~0.0", "jasmine-tagged": "^1.1.4", "jquery": "^2.1.1", diff --git a/src/package.coffee b/src/package.coffee index b16e76ba0..41b621d02 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -1,4 +1,5 @@ path = require 'path' +hostedGitInfo = require 'hosted-git-info' _ = require 'underscore-plus' async = require 'async' @@ -24,6 +25,20 @@ class Package @resourcePathWithTrailingSlash ?= "#{atom.packages.resourcePath}#{path.sep}" packagePath?.startsWith(@resourcePathWithTrailingSlash) + @normalizeMetadata: (metadata) -> + if typeof metadata.repository is 'string' + metadata.repository = + type: 'git' + url: metadata.repository + + repoUrl = metadata.repository?.url + if repoUrl + info = hostedGitInfo.fromUrl(repoUrl) + if info.getDefaultRepresentation() is 'shortcut' + metadata.repository.url = info.https().replace(/^git\+/, '') + else + metadata.repository.url = info.toString() + @loadMetadata: (packagePath, ignoreErrors=false) -> packageName = path.basename(packagePath) if @isBundledPackagePath(packagePath) @@ -34,8 +49,10 @@ class Package metadata = CSON.readFileSync(metadataPath) catch error throw error unless ignoreErrors + metadata ?= {} metadata.name = packageName + @normalizeMetadata(metadata) if includeDeprecatedAPIs and metadata.stylesheetMain? deprecate("Use the `mainStyleSheet` key instead of `stylesheetMain` in the `package.json` of `#{packageName}`", {packageName}) From c228c3fcf7d0e5320ff1c9ee00864f756abf9a3c Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Thu, 30 Apr 2015 11:23:11 -0700 Subject: [PATCH 0965/1783] Add spec and feature to test normalizing repository short urls --- .../package-with-short-url-package-json/package.json | 4 ++++ spec/package-manager-spec.coffee | 5 +++++ 2 files changed, 9 insertions(+) create mode 100644 spec/fixtures/packages/package-with-short-url-package-json/package.json diff --git a/spec/fixtures/packages/package-with-short-url-package-json/package.json b/spec/fixtures/packages/package-with-short-url-package-json/package.json new file mode 100644 index 000000000..5da40ab08 --- /dev/null +++ b/spec/fixtures/packages/package-with-short-url-package-json/package.json @@ -0,0 +1,4 @@ +{ + "name": "package-with-short-url-package-json", + "repository": "example/repo" +} diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 8dcc6bc37..ebdd1f57a 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -41,6 +41,11 @@ describe "PackageManager", -> expect(addErrorHandler.callCount).toBe 1 expect(addErrorHandler.argsForCall[0][0].message).toContain("Failed to load the package-with-broken-package-json package") + 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" + 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() From df8c462a20a694cea08286a13423b0bd786eb913 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 30 Apr 2015 11:33:49 -0700 Subject: [PATCH 0966/1783] :arrow_up: apm@0.164 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index e0656472b..b09eb087a 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.163.0" + "atom-package-manager": "0.164.0" } } From 4771435b84dde0158a0ac5e5ad873d96a1ae17c4 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Thu, 30 Apr 2015 11:41:57 -0700 Subject: [PATCH 0967/1783] Only normalize short urls --- src/package.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/package.coffee b/src/package.coffee index 41b621d02..05be6c79f 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -36,8 +36,6 @@ class Package info = hostedGitInfo.fromUrl(repoUrl) if info.getDefaultRepresentation() is 'shortcut' metadata.repository.url = info.https().replace(/^git\+/, '') - else - metadata.repository.url = info.toString() @loadMetadata: (packagePath, ignoreErrors=false) -> packageName = path.basename(packagePath) From d30c1facb95e9001f3147643782263a0b2645a2a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 30 Apr 2015 12:57:08 -0700 Subject: [PATCH 0968/1783] Prepare 0.196 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f48057c33..99a9d4bf6 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "0.195.0", + "version": "0.196.0", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From cf9b00cc8c67b6884487cc9b9bb82c5821fc1922 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 30 Apr 2015 13:36:42 -0700 Subject: [PATCH 0969/1783] :arrow_down: language-html@0.32 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 99a9d4bf6..0f2eafc81 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,7 @@ "language-gfm": "0.70.0", "language-git": "0.10.0", "language-go": "0.25.0", - "language-html": "0.34.0", + "language-html": "0.32.0", "language-hyperlink": "0.13.0", "language-java": "0.15.0", "language-javascript": "0.76.0", From 1781159470d91e3327062e70ac0ea465e8deb142 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 30 Apr 2015 13:49:21 -0700 Subject: [PATCH 0970/1783] Prepare 0.197 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0f2eafc81..0ce9d81a2 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "0.196.0", + "version": "0.197.0", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From afbc353615d1d7b651b3234d9db1ab9d1581c00c Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Thu, 30 Apr 2015 14:46:36 -0700 Subject: [PATCH 0971/1783] :arrow_up: language-html0.35.0 Closes #6584 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0ce9d81a2..8fd437aee 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,7 @@ "language-gfm": "0.70.0", "language-git": "0.10.0", "language-go": "0.25.0", - "language-html": "0.32.0", + "language-html": "0.35.0", "language-hyperlink": "0.13.0", "language-java": "0.15.0", "language-javascript": "0.76.0", From f8047ba4fc8406aadd82ff5ea37af90db7876f0a Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Thu, 30 Apr 2015 17:50:03 -0700 Subject: [PATCH 0972/1783] :arrow_up: language-html@0.36.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5e768e844..f451e3510 100644 --- a/package.json +++ b/package.json @@ -132,7 +132,7 @@ "language-gfm": "0.70.0", "language-git": "0.10.0", "language-go": "0.25.0", - "language-html": "0.35.0", + "language-html": "0.36.0", "language-hyperlink": "0.13.0", "language-java": "0.15.0", "language-javascript": "0.76.0", From 725f3d1edf9833e832576c86be383428debc17ad Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 1 May 2015 11:04:10 -0700 Subject: [PATCH 0973/1783] :arrow_up: language-gfm@0.71 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f451e3510..1e7d94f27 100644 --- a/package.json +++ b/package.json @@ -129,7 +129,7 @@ "language-coffee-script": "0.40.0", "language-csharp": "0.5.0", "language-css": "0.28.0", - "language-gfm": "0.70.0", + "language-gfm": "0.71.0", "language-git": "0.10.0", "language-go": "0.25.0", "language-html": "0.36.0", From 7ec14b5be5a0d83a8649574befef6c2c354d9a4c Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Fri, 1 May 2015 11:45:38 -0700 Subject: [PATCH 0974/1783] Remove completions from Settings --- src/config-schema.coffee | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/config-schema.coffee b/src/config-schema.coffee index f181e0149..548b35fa8 100644 --- a/src/config-schema.coffee +++ b/src/config-schema.coffee @@ -98,9 +98,6 @@ module.exports = type: ['string', 'null'] # These can be used as globals or scoped, thus defaults. - completions: - type: ['array', 'object'] - default: [] fontFamily: type: 'string' default: '' From 81075739d54be33e6f41ff82be3627e787704ff7 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Fri, 1 May 2015 13:19:07 -0700 Subject: [PATCH 0975/1783] Just remove default, leave type --- src/config-schema.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/config-schema.coffee b/src/config-schema.coffee index 548b35fa8..89d7034ba 100644 --- a/src/config-schema.coffee +++ b/src/config-schema.coffee @@ -98,6 +98,8 @@ module.exports = type: ['string', 'null'] # These can be used as globals or scoped, thus defaults. + completions: + type: ['array', 'object'] fontFamily: type: 'string' default: '' From bc0e5ad4c33c1a72470680b3478715513b6c0b46 Mon Sep 17 00:00:00 2001 From: simurai Date: Sun, 3 May 2015 00:08:03 +0900 Subject: [PATCH 0976/1783] :arrow_up: one-dark/light-ui@0.8.0 Skipping a version in one-light-ui from 0.6.0 -> 0.8.0 so it matches with the dark version --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 1e7d94f27..36ebaa55a 100644 --- a/package.json +++ b/package.json @@ -77,10 +77,10 @@ "atom-light-ui": "0.41.0", "base16-tomorrow-dark-theme": "0.25.0", "base16-tomorrow-light-theme": "0.8.0", - "one-dark-ui": "0.7.0", + "one-dark-ui": "0.8.0", "one-dark-syntax": "0.4.0", "one-light-syntax": "0.5.0", - "one-light-ui": "0.6.0", + "one-light-ui": "0.8.0", "solarized-dark-syntax": "0.32.0", "solarized-light-syntax": "0.19.0", "archive-view": "0.56.0", From 70bd04f7df37b80a4e622586b3a1ab49c6f61347 Mon Sep 17 00:00:00 2001 From: Ivan Zuzak Date: Mon, 4 May 2015 13:36:18 +0200 Subject: [PATCH 0977/1783] Allow 0 to be passed as initialLine --- src/browser/atom-application.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 178755786..c3e97defb 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -518,11 +518,11 @@ class AtomApplication [fileToOpen, initialLine, initialColumn] = path.basename(pathToOpen).split(':') return {pathToOpen} unless initialLine - return {pathToOpen} unless parseInt(initialLine) > 0 + return {pathToOpen} unless parseInt(initialLine) >= 0 # Convert line numbers to a base of 0 - initialLine -= 1 if initialLine - initialColumn -= 1 if initialColumn + initialLine = Math.max(0, initialLine - 1) if initialLine + initialColumn = Math.max(0, initialColumn - 1) if initialColumn pathToOpen = path.join(path.dirname(pathToOpen), fileToOpen) {pathToOpen, initialLine, initialColumn} From b12126a628a15a12e38f834a6f9e07e024a71f7a Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Mon, 4 May 2015 14:16:20 -0700 Subject: [PATCH 0978/1783] Revert "Just remove default, leave type" This reverts commit 81075739d54be33e6f41ff82be3627e787704ff7. --- src/config-schema.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/config-schema.coffee b/src/config-schema.coffee index 89d7034ba..548b35fa8 100644 --- a/src/config-schema.coffee +++ b/src/config-schema.coffee @@ -98,8 +98,6 @@ module.exports = type: ['string', 'null'] # These can be used as globals or scoped, thus defaults. - completions: - type: ['array', 'object'] fontFamily: type: 'string' default: '' From 97ad2f30e028eb24320f86390aadb3a4b8bd09d2 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Mon, 4 May 2015 15:04:03 -0700 Subject: [PATCH 0979/1783] normalize all of package.json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit use different module, catch throws, and still remove the ‘git’ prefix from urls. --- package.json | 2 +- src/package.coffee | 15 ++++----------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 36ebaa55a..689050b05 100644 --- a/package.json +++ b/package.json @@ -38,13 +38,13 @@ "fuzzaldrin": "^2.1", "git-utils": "^3.0.0", "grim": "1.4.0", - "hosted-git-info": "^2.1.2", "jasmine-json": "~0.0", "jasmine-tagged": "^1.1.4", "jquery": "^2.1.1", "less-cache": "0.22", "marked": "^0.3.3", "mixto": "^1", + "normalize-package-data": "^2.0.0", "nslog": "^2.0.0", "oniguruma": "^4.1", "optimist": "0.4.0", diff --git a/src/package.coffee b/src/package.coffee index 05be6c79f..473b5dc33 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -1,5 +1,5 @@ path = require 'path' -hostedGitInfo = require 'hosted-git-info' +normalizePackageData = require 'normalize-package-data' _ = require 'underscore-plus' async = require 'async' @@ -27,15 +27,8 @@ class Package @normalizeMetadata: (metadata) -> if typeof metadata.repository is 'string' - metadata.repository = - type: 'git' - url: metadata.repository - - repoUrl = metadata.repository?.url - if repoUrl - info = hostedGitInfo.fromUrl(repoUrl) - if info.getDefaultRepresentation() is 'shortcut' - metadata.repository.url = info.https().replace(/^git\+/, '') + normalizePackageData(metadata) + metadata.repository.url = metadata.repository.url.replace(/^git\+/, '') @loadMetadata: (packagePath, ignoreErrors=false) -> packageName = path.basename(packagePath) @@ -45,12 +38,12 @@ class Package if metadataPath = CSON.resolve(path.join(packagePath, 'package')) try metadata = CSON.readFileSync(metadataPath) + @normalizeMetadata(metadata) catch error throw error unless ignoreErrors metadata ?= {} metadata.name = packageName - @normalizeMetadata(metadata) if includeDeprecatedAPIs and metadata.stylesheetMain? deprecate("Use the `mainStyleSheet` key instead of `stylesheetMain` in the `package.json` of `#{packageName}`", {packageName}) From 3d4a4abd2262350a0e32901b449c03e7d761ed1b Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 4 May 2015 16:41:48 -0700 Subject: [PATCH 0980/1783] :arrow_up: snippets@0.89.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 36ebaa55a..54745a3e9 100644 --- a/package.json +++ b/package.json @@ -112,7 +112,7 @@ "package-generator": "0.38.0", "release-notes": "0.52.0", "settings-view": "0.196.0", - "snippets": "0.88.0", + "snippets": "0.89.0", "spell-check": "0.56.0", "status-bar": "0.69.0", "styleguide": "0.44.0", From 55a7508287407671ec8350cecc7f06554e52a216 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 5 May 2015 11:38:54 +0200 Subject: [PATCH 0981/1783] wip --- src/lines-presenter.coffee | 41 ++++++++++++++++++++++++++++++++ src/text-editor-presenter.coffee | 30 +++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 src/lines-presenter.coffee diff --git a/src/lines-presenter.coffee b/src/lines-presenter.coffee new file mode 100644 index 000000000..c1e3676ba --- /dev/null +++ b/src/lines-presenter.coffee @@ -0,0 +1,41 @@ +module.exports = +class LinesPresenter + startRow: null + endRow: null + lineHeight: null + + constructor: (@presenter) -> + @lines = {} + + getState: -> + visibleLineIds = {} + row = @startRow + while row < @endRow + line = @presenter.model.tokenizedLineForScreenRow(row) + unless line? + throw new Error("No line exists for row #{row}. Last screen row: #{@model.getLastScreenRow()}") + + visibleLineIds[line.id] = true + if @lines.hasOwnProperty(line.id) + lineState = @lines[line.id] + lineState.screenRow = row + lineState.top = (row - @startRow) * @lineHeight + lineState.decorationClasses = @presenter.lineDecorationClassesForRow(row) + else + @lines[line.id] = + screenRow: row + text: line.text + tokens: line.tokens + isOnlyWhitespace: line.isOnlyWhitespace() + endOfLineInvisibles: line.endOfLineInvisibles + indentLevel: line.indentLevel + tabLength: line.tabLength + fold: line.fold + top: (row - @startRow) * @lineHeight + decorationClasses: @presenter.lineDecorationClassesForRow(row) + row++ + + for id, line of @lines + delete @lines[id] unless visibleLineIds.hasOwnProperty(id) + + @lines diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index ac6d0c363..e9cba9dec 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -2,6 +2,7 @@ {Point, Range} = require 'text-buffer' _ = require 'underscore-plus' Decoration = require './decoration' +LinesPresenter = require './lines-presenter' module.exports = class TextEditorPresenter @@ -20,6 +21,8 @@ class TextEditorPresenter @measuredHorizontalScrollbarHeight = horizontalScrollbarHeight @measuredVerticalScrollbarWidth = verticalScrollbarWidth @gutterWidth ?= 0 + @tileCount ?= 3 + @linesPresentersByTileIndex = {} @disposables = new CompositeDisposable @emitter = new Emitter @@ -74,6 +77,7 @@ class TextEditorPresenter @updateHiddenInputState() if @shouldUpdateHiddenInputState @updateContentState() if @shouldUpdateContentState @updateDecorations() if @shouldUpdateDecorations + @updateTilesState() if @shouldUpdateLinesState @updateLinesState() if @shouldUpdateLinesState @updateCursorsState() if @shouldUpdateCursorsState @updateOverlaysState() if @shouldUpdateOverlaysState @@ -205,6 +209,7 @@ class TextEditorPresenter content: scrollingVertically: false cursorsVisible: false + tiles: {} lines: {} highlights: {} overlays: {} @@ -229,6 +234,7 @@ class TextEditorPresenter @updateHiddenInputState() @updateContentState() @updateDecorations() + @updateTilesState() @updateLinesState() @updateCursorsState() @updateOverlaysState() @@ -298,6 +304,30 @@ class TextEditorPresenter @state.content.backgroundColor = if @model.isMini() then null else @backgroundColor @state.content.placeholderText = if @model.isEmpty() then @model.getPlaceholderText() else null + updateTilesState: -> + return unless @startRow? and @endRow? and @lineHeight? + + linesPerTile = @height / @lineHeight / @tileCount + + startIndex = Math.floor(@startRow / linesPerTile) + endIndex = Math.ceil(@endRow / linesPerTile) + visibleIndexesRange = [startIndex..endIndex] + + for index, tile of @state.content.tiles + unless index in visibleIndexesRange + delete @state.content.tiles[index] + delete @linesPresentersByTileIndex[index] + + for index in visibleIndexesRange + presenter = @linesPresentersByTileIndex[index] ?= new LinesPresenter(@) + presenter.startRow = Math.floor(index * linesPerTile) + presenter.endRow = Math.ceil(Math.min(@endRow, (index + 1) * linesPerTile)) + presenter.lineHeight = @lineHeight + + tile = @state.content.tiles[index] ?= {} + tile.top = (index * linesPerTile * @lineHeight) - @scrollTop + tile.lines = presenter.getState() + updateLinesState: -> return unless @startRow? and @endRow? and @lineHeight? From ee85abc2ebc21bf46f730d0fdd278099b974405b Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 5 May 2015 11:41:09 +0200 Subject: [PATCH 0982/1783] :fire: Delete line handling from TextEditorPresenter --- src/text-editor-presenter.coffee | 76 ++++++-------------------------- 1 file changed, 14 insertions(+), 62 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index e9cba9dec..835a89182 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -77,8 +77,7 @@ class TextEditorPresenter @updateHiddenInputState() if @shouldUpdateHiddenInputState @updateContentState() if @shouldUpdateContentState @updateDecorations() if @shouldUpdateDecorations - @updateTilesState() if @shouldUpdateLinesState - @updateLinesState() if @shouldUpdateLinesState + @updateTilesState() if @shouldUpdateTilesState @updateCursorsState() if @shouldUpdateCursorsState @updateOverlaysState() if @shouldUpdateOverlaysState @updateLineNumberGutterState() if @shouldUpdateLineNumberGutterState @@ -100,7 +99,7 @@ class TextEditorPresenter @shouldUpdateHiddenInputState = false @shouldUpdateContentState = false @shouldUpdateDecorations = false - @shouldUpdateLinesState = false + @shouldUpdateTilesState = false @shouldUpdateCursorsState = false @shouldUpdateOverlaysState = false @shouldUpdateLineNumberGutterState = false @@ -118,7 +117,7 @@ class TextEditorPresenter @shouldUpdateScrollbarsState = true @shouldUpdateContentState = true @shouldUpdateDecorations = true - @shouldUpdateLinesState = true + @shouldUpdateTilesState = true @shouldUpdateLineNumberGutterState = true @shouldUpdateLineNumbersState = true @shouldUpdateGutterOrderState = true @@ -134,7 +133,7 @@ class TextEditorPresenter @shouldUpdateScrollbarsState = true @shouldUpdateContentState = true @shouldUpdateDecorations = true - @shouldUpdateLinesState = true + @shouldUpdateTilesState = true @shouldUpdateLineNumberGutterState = true @shouldUpdateLineNumbersState = true @shouldUpdateGutterOrderState = true @@ -210,7 +209,6 @@ class TextEditorPresenter scrollingVertically: false cursorsVisible: false tiles: {} - lines: {} highlights: {} overlays: {} gutters: @@ -235,7 +233,6 @@ class TextEditorPresenter @updateContentState() @updateDecorations() @updateTilesState() - @updateLinesState() @updateCursorsState() @updateOverlaysState() @updateLineNumberGutterState() @@ -328,51 +325,6 @@ class TextEditorPresenter tile.top = (index * linesPerTile * @lineHeight) - @scrollTop tile.lines = presenter.getState() - updateLinesState: -> - return unless @startRow? and @endRow? and @lineHeight? - - visibleLineIds = {} - row = @startRow - while row < @endRow - line = @model.tokenizedLineForScreenRow(row) - unless line? - throw new Error("No line exists for row #{row}. Last screen row: #{@model.getLastScreenRow()}") - - visibleLineIds[line.id] = true - if @state.content.lines.hasOwnProperty(line.id) - @updateLineState(row, line) - else - @buildLineState(row, line) - row++ - - if @mouseWheelScreenRow? - if preservedLine = @model.tokenizedLineForScreenRow(@mouseWheelScreenRow) - visibleLineIds[preservedLine.id] = true - - for id, line of @state.content.lines - unless visibleLineIds.hasOwnProperty(id) - delete @state.content.lines[id] - return - - updateLineState: (row, line) -> - lineState = @state.content.lines[line.id] - lineState.screenRow = row - lineState.top = row * @lineHeight - lineState.decorationClasses = @lineDecorationClassesForRow(row) - - buildLineState: (row, line) -> - @state.content.lines[line.id] = - screenRow: row - text: line.text - tokens: line.tokens - isOnlyWhitespace: line.isOnlyWhitespace() - endOfLineInvisibles: line.endOfLineInvisibles - indentLevel: line.indentLevel - tabLength: line.tabLength - fold: line.fold - top: row * @lineHeight - decorationClasses: @lineDecorationClassesForRow(row) - updateCursorsState: -> @state.content.cursors = {} @updateCursorState(cursor) for cursor in @model.cursors # using property directly to avoid allocation @@ -748,7 +700,7 @@ class TextEditorPresenter @shouldUpdateVerticalScrollState = true @shouldUpdateHiddenInputState = true @shouldUpdateDecorations = true - @shouldUpdateLinesState = true + @shouldUpdateTilesState = true @shouldUpdateCursorsState = true @shouldUpdateLineNumbersState = true @shouldUpdateCustomGutterDecorationState = true @@ -771,7 +723,7 @@ class TextEditorPresenter @state.content.scrollingVertically = false if @mouseWheelScreenRow? @mouseWheelScreenRow = null - @shouldUpdateLinesState = true + @shouldUpdateTilesState = true @shouldUpdateLineNumbersState = true @shouldUpdateCustomGutterDecorationState = true @@ -834,7 +786,7 @@ class TextEditorPresenter @shouldUpdateVerticalScrollState = true @shouldUpdateScrollbarsState = true @shouldUpdateDecorations = true - @shouldUpdateLinesState = true + @shouldUpdateTilesState = true @shouldUpdateCursorsState = true @shouldUpdateLineNumbersState = true @shouldUpdateCustomGutterDecorationState = true @@ -862,7 +814,7 @@ class TextEditorPresenter @shouldUpdateScrollbarsState = true @shouldUpdateContentState = true @shouldUpdateDecorations = true - @shouldUpdateLinesState = true + @shouldUpdateTilesState = true @shouldUpdateCursorsState = true unless oldContentFrameWidth? @emitDidUpdateState() @@ -928,7 +880,7 @@ class TextEditorPresenter @shouldUpdateScrollbarsState = true @shouldUpdateHiddenInputState = true @shouldUpdateDecorations = true - @shouldUpdateLinesState = true + @shouldUpdateTilesState = true @shouldUpdateCursorsState = true @shouldUpdateLineNumbersState = true @shouldUpdateCustomGutterDecorationState = true @@ -980,7 +932,7 @@ class TextEditorPresenter @shouldUpdateHiddenInputState = true @shouldUpdateContentState = true @shouldUpdateDecorations = true - @shouldUpdateLinesState = true + @shouldUpdateTilesState = true @shouldUpdateCursorsState = true @shouldUpdateOverlaysState = true @@ -1072,7 +1024,7 @@ class TextEditorPresenter intersectsVisibleRowRange = true if intersectsVisibleRowRange - @shouldUpdateLinesState = true if decoration.isType('line') + @shouldUpdateTilesState = true if decoration.isType('line') if decoration.isType('line-number') @shouldUpdateLineNumbersState = true else if decoration.isType('gutter') @@ -1097,7 +1049,7 @@ class TextEditorPresenter decoration.getMarker().getScreenRange()) @addToLineDecorationCaches(decoration, decoration.getMarker().getScreenRange()) if decoration.isType('line') or Decoration.isType(oldProperties, 'line') - @shouldUpdateLinesState = true + @shouldUpdateTilesState = true if decoration.isType('line-number') or Decoration.isType(oldProperties, 'line-number') @shouldUpdateLineNumbersState = true if (decoration.isType('gutter') and not decoration.isType('line-number')) or @@ -1113,7 +1065,7 @@ class TextEditorPresenter didDestroyDecoration: (decoration) -> if decoration.isType('line') or decoration.isType('gutter') @removeFromLineDecorationCaches(decoration, decoration.getMarker().getScreenRange()) - @shouldUpdateLinesState = true if decoration.isType('line') + @shouldUpdateTilesState = true if decoration.isType('line') if decoration.isType('line-number') @shouldUpdateLineNumbersState = true else if decoration.isType('gutter') @@ -1138,7 +1090,7 @@ class TextEditorPresenter if decoration.isType('line') or decoration.isType('gutter') @addToLineDecorationCaches(decoration, decoration.getMarker().getScreenRange()) - @shouldUpdateLinesState = true if decoration.isType('line') + @shouldUpdateTilesState = true if decoration.isType('line') if decoration.isType('line-number') @shouldUpdateLineNumbersState = true else if decoration.isType('gutter') From 3d3d5d00b4a476eea27800b6be94d6969b1775c7 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 5 May 2015 14:24:58 +0200 Subject: [PATCH 0983/1783] wip --- spec/text-editor-presenter-spec.coffee | 159 +++++++++++-------------- src/text-editor-presenter.coffee | 22 ++-- 2 files changed, 82 insertions(+), 99 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index de2dd780d..b2c40fc36 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -657,123 +657,96 @@ describe "TextEditorPresenter", -> expectStateUpdate presenter, -> editor.setPlaceholderText("new-placeholder-text") expect(presenter.getState().content.placeholderText).toBe "new-placeholder-text" - describe ".lines", -> - lineStateForScreenRow = (presenter, screenRow) -> - presenter.getState().content.lines[presenter.model.tokenizedLineForScreenRow(screenRow).id] + fdescribe ".tiles", -> + it "contains states for tiles that are visible on screen, plus and minus the overdraw margin", -> + presenter = buildPresenter(explicitHeight: 3, scrollTop: 1, lineHeight: 1, tileCount: 3, tileOverdrawMargin: 1) - it "contains states for lines that are visible on screen, plus and minus the overdraw margin", -> - presenter = buildPresenter(explicitHeight: 15, scrollTop: 50, lineHeight: 10, lineOverdrawMargin: 1) - - expect(lineStateForScreenRow(presenter, 3)).toBeUndefined() - - line4 = editor.tokenizedLineForScreenRow(4) - expectValues lineStateForScreenRow(presenter, 4), { - screenRow: 4 - text: line4.text - tokens: line4.tokens - top: 10 * 4 + expectValues presenter.getState().content.tiles[0], { + top: -1 } - - line5 = editor.tokenizedLineForScreenRow(5) - expectValues lineStateForScreenRow(presenter, 5), { - screenRow: 5 - text: line5.text - tokens: line5.tokens - top: 10 * 5 + expectValues presenter.getState().content.tiles[1], { + top: 0 } - - line6 = editor.tokenizedLineForScreenRow(6) - expectValues lineStateForScreenRow(presenter, 6), { - screenRow: 6 - text: line6.text - tokens: line6.tokens - top: 10 * 6 + expectValues presenter.getState().content.tiles[2], { + top: 1 } - - line7 = editor.tokenizedLineForScreenRow(7) - expectValues lineStateForScreenRow(presenter, 7), { - screenRow: 7 - text: line7.text - tokens: line7.tokens - top: 10 * 7 + expectValues presenter.getState().content.tiles[3], { + top: 2 } - - line8 = editor.tokenizedLineForScreenRow(8) - expectValues lineStateForScreenRow(presenter, 8), { - screenRow: 8 - text: line8.text - tokens: line8.tokens - top: 10 * 8 + expectValues presenter.getState().content.tiles[4], { + top: 3 } - - expect(lineStateForScreenRow(presenter, 9)).toBeUndefined() + expectValues presenter.getState().content.tiles[5], { + top: 4 + } + expect(presenter.getState().content.tiles[6]).toBeUndefined() it "does not overdraw above the first row", -> - presenter = buildPresenter(explicitHeight: 15, scrollTop: 10, lineHeight: 10, lineOverdrawMargin: 2) - expect(lineStateForScreenRow(presenter, 0)).toBeDefined() - expect(lineStateForScreenRow(presenter, 1)).toBeDefined() - expect(lineStateForScreenRow(presenter, 2)).toBeDefined() - expect(lineStateForScreenRow(presenter, 3)).toBeDefined() - expect(lineStateForScreenRow(presenter, 4)).toBeDefined() - expect(lineStateForScreenRow(presenter, 5)).toBeDefined() - expect(lineStateForScreenRow(presenter, 6)).toBeUndefined() + presenter = buildPresenter(explicitHeight: 3, scrollTop: 0, lineHeight: 1, tileCount: 3, tileOverdrawMargin: 1) + expect(presenter.getState().content.tiles[-1]).toBeUndefined() + expect(presenter.getState().content.tiles[0]).toBeDefined() + expect(presenter.getState().content.tiles[1]).toBeDefined() + expect(presenter.getState().content.tiles[2]).toBeDefined() + expect(presenter.getState().content.tiles[3]).toBeDefined() + expect(presenter.getState().content.tiles[4]).toBeDefined() + expect(presenter.getState().content.tiles[5]).toBeUndefined() it "does not overdraw below the last row", -> - presenter = buildPresenter(explicitHeight: 25, scrollTop: 105, lineHeight: 10, lineOverdrawMargin: 2) - expect(lineStateForScreenRow(presenter, 7)).toBeUndefined() - expect(lineStateForScreenRow(presenter, 8)).toBeDefined() - expect(lineStateForScreenRow(presenter, 9)).toBeDefined() - expect(lineStateForScreenRow(presenter, 10)).toBeDefined() - expect(lineStateForScreenRow(presenter, 11)).toBeDefined() - expect(lineStateForScreenRow(presenter, 12)).toBeDefined() + presenter = buildPresenter(explicitHeight: 3, scrollTop: 10, lineHeight: 1, tileCount: 3, tileOverdrawMargin: 1) + expect(presenter.getState().content.tiles[8]).toBeUndefined() + expect(presenter.getState().content.tiles[9]).toBeDefined() + expect(presenter.getState().content.tiles[10]).toBeDefined() + expect(presenter.getState().content.tiles[11]).toBeDefined() + expect(presenter.getState().content.tiles[12]).toBeDefined() + expect(presenter.getState().content.tiles[13]).toBeUndefined() - it "includes state for all lines if no external ::explicitHeight is assigned", -> - presenter = buildPresenter(explicitHeight: null) - expect(lineStateForScreenRow(presenter, 0)).toBeDefined() - expect(lineStateForScreenRow(presenter, 12)).toBeDefined() + xit "includes state for all tiles if no external ::explicitHeight is assigned", -> + presenter = buildPresenter(explicitHeight: null, tileCount: 12, tileOverdrawMargin: 1) + expect(presenter.getState().content.tiles[0]).toBeDefined() + expect(presenter.getState().content.tiles[12]).toBeDefined() it "is empty until all of the required measurements are assigned", -> - presenter = buildPresenter(explicitHeight: null, lineHeight: null, scrollTop: null) - expect(presenter.getState().content.lines).toEqual({}) + presenter = buildPresenter(explicitHeight: null, lineHeight: null, scrollTop: null, tileCount: 3, tileOverdrawMargin: 1) + expect(presenter.getState().content.tiles).toEqual({}) presenter.setExplicitHeight(25) - expect(presenter.getState().content.lines).toEqual({}) + expect(presenter.getState().content.tiles).toEqual({}) presenter.setLineHeight(10) - expect(presenter.getState().content.lines).toEqual({}) + expect(presenter.getState().content.tiles).toEqual({}) presenter.setScrollTop(0) - expect(presenter.getState().content.lines).not.toEqual({}) + expect(presenter.getState().content.tiles).not.toEqual({}) it "updates when ::scrollTop changes", -> - presenter = buildPresenter(explicitHeight: 25, scrollTop: 0, lineHeight: 10, lineOverdrawMargin: 1) + presenter = buildPresenter(explicitHeight: 3, scrollTop: 0, lineHeight: 1, tileOverdrawMargin: 1, tileCount: 3) - expect(lineStateForScreenRow(presenter, 0)).toBeDefined() - expect(lineStateForScreenRow(presenter, 4)).toBeDefined() - expect(lineStateForScreenRow(presenter, 5)).toBeUndefined() + expect(presenter.getState().content.tiles[0]).toBeDefined() + expect(presenter.getState().content.tiles[4]).toBeDefined() + expect(presenter.getState().content.tiles[5]).toBeUndefined() - expectStateUpdate presenter, -> presenter.setScrollTop(25) + expectStateUpdate presenter, -> presenter.setScrollTop(2) - expect(lineStateForScreenRow(presenter, 0)).toBeUndefined() - expect(lineStateForScreenRow(presenter, 1)).toBeDefined() - expect(lineStateForScreenRow(presenter, 6)).toBeDefined() - expect(lineStateForScreenRow(presenter, 7)).toBeUndefined() + expect(presenter.getState().content.tiles[0]).toBeUndefined() + expect(presenter.getState().content.tiles[1]).toBeDefined() + expect(presenter.getState().content.tiles[6]).toBeDefined() + expect(presenter.getState().content.tiles[7]).toBeUndefined() - it "updates when ::explicitHeight changes", -> - presenter = buildPresenter(explicitHeight: 15, scrollTop: 15, lineHeight: 10, lineOverdrawMargin: 1) + xit "updates when ::explicitHeight changes", -> + presenter = buildPresenter(explicitHeight: 3, scrollTop: 0, lineHeight: 1, tileOverdrawMargin: 1, tileCount: 3) line5 = editor.tokenizedLineForScreenRow(5) - expect(lineStateForScreenRow(presenter, 4)).toBeDefined() - expect(lineStateForScreenRow(presenter, 5)).toBeUndefined() + expect(presenter.getState().content.tiles[4]).toBeDefined() + expect(presenter.getState().content.tiles[5]).toBeUndefined() expectStateUpdate presenter, -> presenter.setExplicitHeight(35) - expect(lineStateForScreenRow(presenter, 5)).toBeDefined() - expect(lineStateForScreenRow(presenter, 6)).toBeDefined() - expect(lineStateForScreenRow(presenter, 7)).toBeUndefined() + expect(presenter.getState().content.tiles[5]).toBeDefined() + expect(presenter.getState().content.tiles[6]).toBeDefined() + expect(presenter.getState().content.tiles[7]).toBeUndefined() - it "updates when ::lineHeight changes", -> + xit "updates when ::lineHeight changes", -> presenter = buildPresenter(explicitHeight: 15, scrollTop: 10, lineHeight: 10, lineOverdrawMargin: 0) expect(lineStateForScreenRow(presenter, 0)).toBeUndefined() @@ -789,29 +762,35 @@ describe "TextEditorPresenter", -> expect(lineStateForScreenRow(presenter, 5)).toBeDefined() expect(lineStateForScreenRow(presenter, 6)).toBeUndefined() - it "updates when the editor's content changes", -> - presenter = buildPresenter(explicitHeight: 25, scrollTop: 10, lineHeight: 10) + fffit "updates when the editor's content changes", -> + lineStateForScreenRow = (presenter, tile, row) -> + lineId = presenter.model.tokenizedLineForScreenRow(row).id + presenter.getState().content.tiles[tile].lines[lineId] + + presenter = buildPresenter(explicitHeight: 25, scrollTop: 10, lineHeight: 10, tileCount: 3, tileOverdrawMargin: 1) expectStateUpdate presenter, -> buffer.insert([2, 0], "hello\nworld\n") line1 = editor.tokenizedLineForScreenRow(1) - expectValues lineStateForScreenRow(presenter, 1), { + expectValues lineStateForScreenRow(presenter, 1, 1), { text: line1.text tokens: line1.tokens } line2 = editor.tokenizedLineForScreenRow(2) - expectValues lineStateForScreenRow(presenter, 2), { + expectValues lineStateForScreenRow(presenter, 2, 2), { text: line2.text tokens: line2.tokens } line3 = editor.tokenizedLineForScreenRow(3) - expectValues lineStateForScreenRow(presenter, 3), { + expectValues lineStateForScreenRow(presenter, 3, 3), { text: line3.text tokens: line3.tokens } + xdescribe ".lines", -> + it "does not remove out-of-view lines corresponding to ::mouseWheelScreenRow until ::stoppedScrollingDelay elapses", -> presenter = buildPresenter(explicitHeight: 25, scrollTop: 0, lineHeight: 10, lineOverdrawMargin: 1, stoppedScrollingDelay: 200) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 835a89182..fb762e758 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -16,12 +16,11 @@ class TextEditorPresenter constructor: (params) -> {@model, @autoHeight, @explicitHeight, @contentFrameWidth, @scrollTop, @scrollLeft, @boundingClientRect, @windowWidth, @windowHeight, @gutterWidth} = params {horizontalScrollbarHeight, verticalScrollbarWidth} = params - {@lineHeight, @baseCharacterWidth, @lineOverdrawMargin, @backgroundColor, @gutterBackgroundColor} = params + {@lineHeight, @baseCharacterWidth, @lineOverdrawMargin, @backgroundColor, @gutterBackgroundColor, @tileCount, @tileOverdrawMargin} = params {@cursorBlinkPeriod, @cursorBlinkResumeDelay, @stoppedScrollingDelay, @focused} = params @measuredHorizontalScrollbarHeight = horizontalScrollbarHeight @measuredVerticalScrollbarWidth = verticalScrollbarWidth @gutterWidth ?= 0 - @tileCount ?= 3 @linesPresentersByTileIndex = {} @disposables = new CompositeDisposable @@ -306,16 +305,21 @@ class TextEditorPresenter linesPerTile = @height / @lineHeight / @tileCount - startIndex = Math.floor(@startRow / linesPerTile) - endIndex = Math.ceil(@endRow / linesPerTile) - visibleIndexesRange = [startIndex..endIndex] + startIndex = Math.max( + 0, Math.floor(@startRow / linesPerTile) - @tileOverdrawMargin + ) + endIndex = Math.min( + Math.ceil(@model.getScreenLineCount() / linesPerTile), + Math.ceil(@endRow / linesPerTile) + @tileOverdrawMargin + ) + visibleTilesIndexes = [startIndex...endIndex] for index, tile of @state.content.tiles - unless index in visibleIndexesRange + unless index in visibleTilesIndexes delete @state.content.tiles[index] delete @linesPresentersByTileIndex[index] - for index in visibleIndexesRange + for index in visibleTilesIndexes presenter = @linesPresentersByTileIndex[index] ?= new LinesPresenter(@) presenter.startRow = Math.floor(index * linesPerTile) presenter.endRow = Math.ceil(Math.min(@endRow, (index + 1) * linesPerTile)) @@ -514,7 +518,7 @@ class TextEditorPresenter updateStartRow: -> return unless @scrollTop? and @lineHeight? - startRow = Math.floor(@scrollTop / @lineHeight) - @lineOverdrawMargin + startRow = Math.floor(@scrollTop / @lineHeight) @startRow = Math.max(0, startRow) updateEndRow: -> @@ -522,7 +526,7 @@ class TextEditorPresenter startRow = Math.max(0, Math.floor(@scrollTop / @lineHeight)) visibleLinesCount = Math.ceil(@height / @lineHeight) + 1 - endRow = startRow + visibleLinesCount + @lineOverdrawMargin + endRow = startRow + visibleLinesCount @endRow = Math.min(@model.getScreenLineCount(), endRow) updateScrollWidth: -> From 3e78fe3019b8c539b0b30fb27c311808e18c1864 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 5 May 2015 16:21:28 +0200 Subject: [PATCH 0984/1783] wip --- src/lines-component.coffee | 196 +++----------------- src/text-editor-presenter.coffee | 5 +- src/tile-component.coffee | 301 +++++++++++++++++++++++++++++++ 3 files changed, 328 insertions(+), 174 deletions(-) create mode 100644 src/tile-component.coffee diff --git a/src/lines-component.coffee b/src/lines-component.coffee index fbec40b79..951d5499a 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -4,6 +4,7 @@ _ = require 'underscore-plus' CursorsComponent = require './cursors-component' HighlightsComponent = require './highlights-component' +TileComponent = require './tile-component' DummyLineNode = $$(-> @div className: 'line', style: 'position: absolute; visibility: hidden;', => @span 'x')[0] AcceptFilter = {acceptNode: -> NodeFilter.FILTER_ACCEPT} @@ -19,11 +20,7 @@ class LinesComponent placeholderTextDiv: null constructor: ({@presenter, @hostElement, @useShadowDOM, visible}) -> - @measuredLines = new Set - @lineNodesByLineId = {} - @screenRowsByLineId = {} - @lineIdsByScreenRow = {} - @renderedDecorationsByLineId = {} + @tileComponentsByTileId = {} @domNode = document.createElement('div') @domNode.classList.add('lines') @@ -44,15 +41,14 @@ class LinesComponent updateSync: (state) -> @newState = state.content - @oldState ?= {lines: {}} + @oldState ?= {tiles: {}} if @newState.scrollHeight isnt @oldState.scrollHeight @domNode.style.height = @newState.scrollHeight + 'px' @oldState.scrollHeight = @newState.scrollHeight - if @newState.scrollTop isnt @oldState.scrollTop or @newState.scrollLeft isnt @oldState.scrollLeft - @domNode.style['-webkit-transform'] = "translate3d(#{-@newState.scrollLeft}px, #{-@newState.scrollTop}px, 0px)" - @oldState.scrollTop = @newState.scrollTop + if @newState.scrollLeft isnt @oldState.scrollLeft + @domNode.style['-webkit-transform'] = "translate3d(#{-@newState.scrollLeft}px, 0, 0px)" @oldState.scrollLeft = @newState.scrollLeft if @newState.backgroundColor isnt @oldState.backgroundColor @@ -67,8 +63,8 @@ class LinesComponent @placeholderTextDiv.textContent = @newState.placeholderText @domNode.appendChild(@placeholderTextDiv) - @removeLineNodes() unless @oldState.indentGuidesVisible is @newState.indentGuidesVisible - @updateLineNodes() + @removeTileNodes() unless @oldState.indentGuidesVisible is @newState.indentGuidesVisible + @updateTileNodes() if @newState.scrollWidth isnt @oldState.scrollWidth @domNode.style.width = @newState.scrollWidth + 'px' @@ -80,177 +76,31 @@ class LinesComponent @oldState.indentGuidesVisible = @newState.indentGuidesVisible @oldState.scrollWidth = @newState.scrollWidth - removeLineNodes: -> - @removeLineNode(id) for id of @oldState.lines + removeTileNodes: -> + @removeTileNode(id) for id of @oldState.tiles return - removeLineNode: (id) -> - @lineNodesByLineId[id].remove() - delete @lineNodesByLineId[id] - delete @lineIdsByScreenRow[@screenRowsByLineId[id]] - delete @screenRowsByLineId[id] - delete @oldState.lines[id] + removeTileNode: (id) -> + @tileComponentsByTileId[id].getDomNode().remove() + delete @tileComponentsByTileId[id] + delete @oldState.tiles[id] - updateLineNodes: -> - for id of @oldState.lines - unless @newState.lines.hasOwnProperty(id) - @removeLineNode(id) + updateTileNodes: -> + for id of @oldState.tiles + unless @newState.tiles.hasOwnProperty(id) + @removeTileNode(id) - newLineIds = null - newLinesHTML = null + for id, tileState of @newState.tiles + tileComponent = @tileComponentsByTileId[id] ?= new TileComponent({id, @presenter}) - for id, lineState of @newState.lines - if @oldState.lines.hasOwnProperty(id) - @updateLineNode(id) - else - newLineIds ?= [] - newLinesHTML ?= "" - newLineIds.push(id) - newLinesHTML += @buildLineHTML(id) - @screenRowsByLineId[id] = lineState.screenRow - @lineIdsByScreenRow[lineState.screenRow] = id - @oldState.lines[id] = cloneObject(lineState) + unless @oldState.tiles.hasOwnProperty(id) + @domNode.appendChild(tileComponent.getDomNode()) + @oldState.tiles[id] = cloneObject(tileState) - return unless newLineIds? - - WrapperDiv.innerHTML = newLinesHTML - newLineNodes = _.toArray(WrapperDiv.children) - for id, i in newLineIds - lineNode = newLineNodes[i] - @lineNodesByLineId[id] = lineNode - @domNode.appendChild(lineNode) + tileComponent.updateSync(@newState) return - buildLineHTML: (id) -> - {scrollWidth} = @newState - {screenRow, tokens, text, top, lineEnding, fold, isSoftWrapped, indentLevel, decorationClasses} = @newState.lines[id] - - classes = '' - if decorationClasses? - for decorationClass in decorationClasses - classes += decorationClass + ' ' - classes += 'line' - - lineHTML = "

" - lineHTML - - buildEmptyLineInnerHTML: (id) -> - {indentGuidesVisible} = @newState - {indentLevel, tabLength, endOfLineInvisibles} = @newState.lines[id] - - if indentGuidesVisible and indentLevel > 0 - invisibleIndex = 0 - lineHTML = '' - for i in [0...indentLevel] - lineHTML += "" - for j in [0...tabLength] - if invisible = endOfLineInvisibles?[invisibleIndex++] - lineHTML += "#{invisible}" - else - lineHTML += ' ' - lineHTML += "" - - while invisibleIndex < endOfLineInvisibles?.length - lineHTML += "#{endOfLineInvisibles[invisibleIndex++]}" - - lineHTML - else - @buildEndOfLineHTML(id) or ' ' - - buildLineInnerHTML: (id) -> - {indentGuidesVisible} = @newState - {tokens, text, isOnlyWhitespace} = @newState.lines[id] - innerHTML = "" - - scopeStack = [] - for token in tokens - innerHTML += @updateScopeStack(scopeStack, token.scopes) - hasIndentGuide = indentGuidesVisible and (token.hasLeadingWhitespace() or (token.hasTrailingWhitespace() and isOnlyWhitespace)) - innerHTML += token.getValueAsHtml({hasIndentGuide}) - - innerHTML += @popScope(scopeStack) while scopeStack.length > 0 - innerHTML += @buildEndOfLineHTML(id) - innerHTML - - buildEndOfLineHTML: (id) -> - {endOfLineInvisibles} = @newState.lines[id] - - html = '' - if endOfLineInvisibles? - for invisible in endOfLineInvisibles - html += "#{invisible}" - html - - updateScopeStack: (scopeStack, desiredScopeDescriptor) -> - html = "" - - # Find a common prefix - for scope, i in desiredScopeDescriptor - break unless scopeStack[i] is desiredScopeDescriptor[i] - - # Pop scopeDescriptor until we're at the common prefx - until scopeStack.length is i - html += @popScope(scopeStack) - - # Push onto common prefix until scopeStack equals desiredScopeDescriptor - for j in [i...desiredScopeDescriptor.length] - html += @pushScope(scopeStack, desiredScopeDescriptor[j]) - - html - - popScope: (scopeStack) -> - scopeStack.pop() - "" - - pushScope: (scopeStack, scope) -> - scopeStack.push(scope) - "" - - updateLineNode: (id) -> - oldLineState = @oldState.lines[id] - newLineState = @newState.lines[id] - - lineNode = @lineNodesByLineId[id] - - if @newState.scrollWidth isnt @oldState.scrollWidth - lineNode.style.width = @newState.scrollWidth + 'px' - - newDecorationClasses = newLineState.decorationClasses - oldDecorationClasses = oldLineState.decorationClasses - - if oldDecorationClasses? - for decorationClass in oldDecorationClasses - unless newDecorationClasses? and decorationClass in newDecorationClasses - lineNode.classList.remove(decorationClass) - - if newDecorationClasses? - for decorationClass in newDecorationClasses - unless oldDecorationClasses? and decorationClass in oldDecorationClasses - lineNode.classList.add(decorationClass) - - oldLineState.decorationClasses = newLineState.decorationClasses - - if newLineState.top isnt oldLineState.top - lineNode.style.top = newLineState.top + 'px' - oldLineState.top = newLineState.cop - - if newLineState.screenRow isnt oldLineState.screenRow - lineNode.dataset.screenRow = newLineState.screenRow - oldLineState.screenRow = newLineState.screenRow - @lineIdsByScreenRow[newLineState.screenRow] = id - - lineNodeForScreenRow: (screenRow) -> - @lineNodesByLineId[@lineIdsByScreenRow[screenRow]] - measureLineHeightAndDefaultCharWidth: -> @domNode.appendChild(DummyLineNode) lineHeightInPixels = DummyLineNode.getBoundingClientRect().height diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index fb762e758..ac7c33609 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -21,6 +21,8 @@ class TextEditorPresenter @measuredHorizontalScrollbarHeight = horizontalScrollbarHeight @measuredVerticalScrollbarWidth = verticalScrollbarWidth @gutterWidth ?= 0 + @tileOverdrawMargin ?= 0 + @tileCount ?= 4 @linesPresentersByTileIndex = {} @disposables = new CompositeDisposable @@ -303,7 +305,7 @@ class TextEditorPresenter updateTilesState: -> return unless @startRow? and @endRow? and @lineHeight? - linesPerTile = @height / @lineHeight / @tileCount + linesPerTile = Math.floor(@height / @lineHeight / @tileCount) startIndex = Math.max( 0, Math.floor(@startRow / linesPerTile) - @tileOverdrawMargin @@ -328,6 +330,7 @@ class TextEditorPresenter tile = @state.content.tiles[index] ?= {} tile.top = (index * linesPerTile * @lineHeight) - @scrollTop tile.lines = presenter.getState() + tile.height = linesPerTile * @lineHeight updateCursorsState: -> @state.content.cursors = {} diff --git a/src/tile-component.coffee b/src/tile-component.coffee new file mode 100644 index 000000000..017856368 --- /dev/null +++ b/src/tile-component.coffee @@ -0,0 +1,301 @@ +_ = require 'underscore-plus' +{toArray} = require 'underscore-plus' +{$$} = require 'space-pen' + +CursorsComponent = require './cursors-component' +HighlightsComponent = require './highlights-component' + +DummyLineNode = $$(-> @div className: 'line', style: 'position: absolute; visibility: hidden;', => @span 'x')[0] +AcceptFilter = {acceptNode: -> NodeFilter.FILTER_ACCEPT} +WrapperDiv = document.createElement('div') + +cloneObject = (object) -> + clone = {} + clone[key] = value for key, value of object + clone + +module.exports = +class TileComponent + placeholderTextDiv: null + + constructor: ({@presenter, @id}) -> + @measuredLines = new Set + @lineNodesByLineId = {} + @screenRowsByLineId = {} + @lineIdsByScreenRow = {} + @domNode = document.createElement("div") + @domNode.style.position = "absolute" + @domNode.classList.add("tile") + + getDomNode: -> + @domNode + + updateSync: (state) -> + @newState = state + unless @oldState + @oldState = {tiles: {}} + @oldState.tiles[@id] = { lines: {}} + + if @newState.tiles[@id].height isnt @oldState.tiles[@id]?.height + @domNode.style.height = @newState.tiles[@id].height + 'px' + @oldState.tiles[@id]?.height = @newState.tiles[@id].height + + if @newState.tiles[@id].top isnt @oldState.tiles[@id]?.top + @domNode.style['-webkit-transform'] = "translate3d(0, #{@newState.tiles[@id].top}px, 0px)" + @oldState.tiles[@id]?.top = @newState.tiles[@id].top + + if @newState.backgroundColor isnt @oldState.backgroundColor + @domNode.style.backgroundColor = @newState.backgroundColor + @oldState.backgroundColor = @newState.backgroundColor + + @removeLineNodes() unless @oldState.indentGuidesVisible is @newState.indentGuidesVisible + @updateLineNodes() + + if @newState.scrollWidth isnt @oldState.scrollWidth + @domNode.style.width = @newState.scrollWidth + 'px' + @oldState.scrollWidth = @newState.scrollWidth + + @oldState.indentGuidesVisible = @newState.indentGuidesVisible + @oldState.scrollWidth = @newState.scrollWidth + + removeLineNodes: -> + @removeLineNode(id) for id of @oldState.tiles[@id]?.lines + return + + removeLineNode: (id) -> + @lineNodesByLineId[id].remove() + delete @lineNodesByLineId[id] + delete @lineIdsByScreenRow[@screenRowsByLineId[id]] + delete @screenRowsByLineId[id] + delete @oldState.tiles[@id]?.lines[id] + + updateLineNodes: -> + for id of @oldState.tiles[@id]?.lines + unless @newState.tiles[@id].lines.hasOwnProperty(id) + @removeLineNode(id) + + newLineIds = null + newLinesHTML = null + + for id, lineState of @newState.tiles[@id].lines + if @oldState.tiles[@id]?.lines.hasOwnProperty(id) + @updateLineNode(id) + else + newLineIds ?= [] + newLinesHTML ?= "" + newLineIds.push(id) + newLinesHTML += @buildLineHTML(id) + @screenRowsByLineId[id] = lineState.screenRow + @lineIdsByScreenRow[lineState.screenRow] = id + @oldState.tiles[@id]?.lines[id] = cloneObject(lineState) + + return unless newLineIds? + + WrapperDiv.innerHTML = newLinesHTML + newLineNodes = _.toArray(WrapperDiv.children) + for id, i in newLineIds + lineNode = newLineNodes[i] + @lineNodesByLineId[id] = lineNode + @domNode.appendChild(lineNode) + + return + + buildLineHTML: (id) -> + {scrollWidth} = @newState + {screenRow, tokens, text, top, lineEnding, fold, isSoftWrapped, indentLevel, decorationClasses} = @newState.tiles[@id].lines[id] + + classes = '' + if decorationClasses? + for decorationClass in decorationClasses + classes += decorationClass + ' ' + classes += 'line' + + lineHTML = "
" + + if text is "" + lineHTML += @buildEmptyLineInnerHTML(id) + else + lineHTML += @buildLineInnerHTML(id) + + lineHTML += '' if fold + lineHTML += "
" + lineHTML + + buildEmptyLineInnerHTML: (id) -> + {indentGuidesVisible} = @newState + {indentLevel, tabLength, endOfLineInvisibles} = @newState.tiles[@id].lines[id] + + if indentGuidesVisible and indentLevel > 0 + invisibleIndex = 0 + lineHTML = '' + for i in [0...indentLevel] + lineHTML += "" + for j in [0...tabLength] + if invisible = endOfLineInvisibles?[invisibleIndex++] + lineHTML += "#{invisible}" + else + lineHTML += ' ' + lineHTML += "" + + while invisibleIndex < endOfLineInvisibles?.length + lineHTML += "#{endOfLineInvisibles[invisibleIndex++]}" + + lineHTML + else + @buildEndOfLineHTML(id) or ' ' + + buildLineInnerHTML: (id) -> + {indentGuidesVisible} = @newState + {tokens, text, isOnlyWhitespace} = @newState.tiles[@id].lines[id] + innerHTML = "" + + scopeStack = [] + for token in tokens + innerHTML += @updateScopeStack(scopeStack, token.scopes) + hasIndentGuide = indentGuidesVisible and (token.hasLeadingWhitespace() or (token.hasTrailingWhitespace() and isOnlyWhitespace)) + innerHTML += token.getValueAsHtml({hasIndentGuide}) + + innerHTML += @popScope(scopeStack) while scopeStack.length > 0 + innerHTML += @buildEndOfLineHTML(id) + innerHTML + + buildEndOfLineHTML: (id) -> + {endOfLineInvisibles} = @newState.tiles[@id].lines[id] + + html = '' + if endOfLineInvisibles? + for invisible in endOfLineInvisibles + html += "#{invisible}" + html + + updateScopeStack: (scopeStack, desiredScopeDescriptor) -> + html = "" + + # Find a common prefix + for scope, i in desiredScopeDescriptor + break unless scopeStack[i] is desiredScopeDescriptor[i] + + # Pop scopeDescriptor until we're at the common prefx + until scopeStack.length is i + html += @popScope(scopeStack) + + # Push onto common prefix until scopeStack equals desiredScopeDescriptor + for j in [i...desiredScopeDescriptor.length] + html += @pushScope(scopeStack, desiredScopeDescriptor[j]) + + html + + popScope: (scopeStack) -> + scopeStack.pop() + "
" + + pushScope: (scopeStack, scope) -> + scopeStack.push(scope) + "" + + updateLineNode: (id) -> + oldLineState = @oldState.tiles[@id]?.lines[id] + newLineState = @newState.tiles[@id].lines[id] + + lineNode = @lineNodesByLineId[id] + + if @newState.scrollWidth isnt @oldState.scrollWidth + lineNode.style.width = @newState.scrollWidth + 'px' + + newDecorationClasses = newLineState.decorationClasses + oldDecorationClasses = oldLineState.decorationClasses + + if oldDecorationClasses? + for decorationClass in oldDecorationClasses + unless newDecorationClasses? and decorationClass in newDecorationClasses + lineNode.classList.remove(decorationClass) + + if newDecorationClasses? + for decorationClass in newDecorationClasses + unless oldDecorationClasses? and decorationClass in oldDecorationClasses + lineNode.classList.add(decorationClass) + + oldLineState.decorationClasses = newLineState.decorationClasses + + if newLineState.top isnt oldLineState.top + lineNode.style.top = newLineState.top + 'px' + oldLineState.top = newLineState.cop + + if newLineState.screenRow isnt oldLineState.screenRow + lineNode.dataset.screenRow = newLineState.screenRow + oldLineState.screenRow = newLineState.screenRow + @lineIdsByScreenRow[newLineState.screenRow] = id + + lineNodeForScreenRow: (screenRow) -> + @lineNodesByLineId[@lineIdsByScreenRow[screenRow]] + + measureLineHeightAndDefaultCharWidth: -> + @domNode.appendChild(DummyLineNode) + lineHeightInPixels = DummyLineNode.getBoundingClientRect().height + charWidth = DummyLineNode.firstChild.getBoundingClientRect().width + @domNode.removeChild(DummyLineNode) + + @presenter.setLineHeight(lineHeightInPixels) + @presenter.setBaseCharacterWidth(charWidth) + + remeasureCharacterWidths: -> + return unless @presenter.baseCharacterWidth + + @clearScopedCharWidths() + @measureCharactersInNewLines() + + measureCharactersInNewLines: -> + @presenter.batchCharacterMeasurement => + for id, lineState of @oldState.tiles[@id]?.lines + unless @measuredLines.has(id) + lineNode = @lineNodesByLineId[id] + @measureCharactersInLine(id, lineState, lineNode) + return + + measureCharactersInLine: (lineId, tokenizedLine, lineNode) -> + rangeForMeasurement = null + iterator = null + charIndex = 0 + + for {value, scopes, hasPairedCharacter} in tokenizedLine.tokens + charWidths = @presenter.getScopedCharacterWidths(scopes) + + valueIndex = 0 + while valueIndex < value.length + if hasPairedCharacter + char = value.substr(valueIndex, 2) + charLength = 2 + valueIndex += 2 + else + char = value[valueIndex] + charLength = 1 + valueIndex++ + + continue if char is '\0' + + unless charWidths[char]? + unless textNode? + rangeForMeasurement ?= document.createRange() + iterator = document.createNodeIterator(lineNode, NodeFilter.SHOW_TEXT, AcceptFilter) + textNode = iterator.nextNode() + textNodeIndex = 0 + nextTextNodeIndex = textNode.textContent.length + + while nextTextNodeIndex <= charIndex + textNode = iterator.nextNode() + textNodeIndex = nextTextNodeIndex + nextTextNodeIndex = textNodeIndex + textNode.textContent.length + + i = charIndex - textNodeIndex + rangeForMeasurement.setStart(textNode, i) + rangeForMeasurement.setEnd(textNode, i + charLength) + charWidth = rangeForMeasurement.getBoundingClientRect().width + @presenter.setScopedCharacterWidth(scopes, char, charWidth) + + charIndex += charLength + + @measuredLines.add(lineId) + + clearScopedCharWidths: -> + @measuredLines.clear() + @presenter.clearScopedCharacterWidths() From 414d5d1c8737fc3d0eb8c5f91b383a1a0e13d8c0 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 5 May 2015 18:10:21 +0200 Subject: [PATCH 0985/1783] wip --- 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 ac7c33609..c8d74b428 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -324,7 +324,7 @@ class TextEditorPresenter for index in visibleTilesIndexes presenter = @linesPresentersByTileIndex[index] ?= new LinesPresenter(@) presenter.startRow = Math.floor(index * linesPerTile) - presenter.endRow = Math.ceil(Math.min(@endRow, (index + 1) * linesPerTile)) + presenter.endRow = Math.ceil(Math.min(@model.getScreenLineCount(), (index + 1) * linesPerTile)) presenter.lineHeight = @lineHeight tile = @state.content.tiles[index] ?= {} From de53e1dccc911089f5daea6fba37b6acee269b57 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 5 May 2015 18:36:10 +0200 Subject: [PATCH 0986/1783] Fix char measurement --- src/lines-component.coffee | 55 +++++--------------------------------- src/tile-component.coffee | 34 +++++------------------ 2 files changed, 13 insertions(+), 76 deletions(-) diff --git a/src/lines-component.coffee b/src/lines-component.coffee index 951d5499a..547b54e56 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -118,56 +118,13 @@ class LinesComponent measureCharactersInNewLines: -> @presenter.batchCharacterMeasurement => - for id, lineState of @oldState.lines - unless @measuredLines.has(id) - lineNode = @lineNodesByLineId[id] - @measureCharactersInLine(id, lineState, lineNode) + for id, component of @tileComponentsByTileId + component.measureCharactersInNewLines() + return - measureCharactersInLine: (lineId, tokenizedLine, lineNode) -> - rangeForMeasurement = null - iterator = null - charIndex = 0 - - for {value, scopes, hasPairedCharacter} in tokenizedLine.tokens - charWidths = @presenter.getScopedCharacterWidths(scopes) - - valueIndex = 0 - while valueIndex < value.length - if hasPairedCharacter - char = value.substr(valueIndex, 2) - charLength = 2 - valueIndex += 2 - else - char = value[valueIndex] - charLength = 1 - valueIndex++ - - continue if char is '\0' - - unless charWidths[char]? - unless textNode? - rangeForMeasurement ?= document.createRange() - iterator = document.createNodeIterator(lineNode, NodeFilter.SHOW_TEXT, AcceptFilter) - textNode = iterator.nextNode() - textNodeIndex = 0 - nextTextNodeIndex = textNode.textContent.length - - while nextTextNodeIndex <= charIndex - textNode = iterator.nextNode() - textNodeIndex = nextTextNodeIndex - nextTextNodeIndex = textNodeIndex + textNode.textContent.length - - i = charIndex - textNodeIndex - rangeForMeasurement.setStart(textNode, i) - rangeForMeasurement.setEnd(textNode, i + charLength) - charWidth = rangeForMeasurement.getBoundingClientRect().width - @presenter.setScopedCharacterWidth(scopes, char, charWidth) - - charIndex += charLength - - @measuredLines.add(lineId) - clearScopedCharWidths: -> - @measuredLines.clear() + for id, component of @tileComponentsByTileId + component.clearMeasurements() + @presenter.clearScopedCharacterWidths() diff --git a/src/tile-component.coffee b/src/tile-component.coffee index 017856368..0b97467c7 100644 --- a/src/tile-component.coffee +++ b/src/tile-component.coffee @@ -2,9 +2,6 @@ _ = require 'underscore-plus' {toArray} = require 'underscore-plus' {$$} = require 'space-pen' -CursorsComponent = require './cursors-component' -HighlightsComponent = require './highlights-component' - DummyLineNode = $$(-> @div className: 'line', style: 'position: absolute; visibility: hidden;', => @span 'x')[0] AcceptFilter = {acceptNode: -> NodeFilter.FILTER_ACCEPT} WrapperDiv = document.createElement('div') @@ -219,7 +216,7 @@ class TileComponent if newLineState.top isnt oldLineState.top lineNode.style.top = newLineState.top + 'px' - oldLineState.top = newLineState.cop + oldLineState.top = newLineState.top if newLineState.screenRow isnt oldLineState.screenRow lineNode.dataset.screenRow = newLineState.screenRow @@ -229,28 +226,12 @@ class TileComponent lineNodeForScreenRow: (screenRow) -> @lineNodesByLineId[@lineIdsByScreenRow[screenRow]] - measureLineHeightAndDefaultCharWidth: -> - @domNode.appendChild(DummyLineNode) - lineHeightInPixels = DummyLineNode.getBoundingClientRect().height - charWidth = DummyLineNode.firstChild.getBoundingClientRect().width - @domNode.removeChild(DummyLineNode) - - @presenter.setLineHeight(lineHeightInPixels) - @presenter.setBaseCharacterWidth(charWidth) - - remeasureCharacterWidths: -> - return unless @presenter.baseCharacterWidth - - @clearScopedCharWidths() - @measureCharactersInNewLines() - measureCharactersInNewLines: -> - @presenter.batchCharacterMeasurement => - for id, lineState of @oldState.tiles[@id]?.lines - unless @measuredLines.has(id) - lineNode = @lineNodesByLineId[id] - @measureCharactersInLine(id, lineState, lineNode) - return + for id, lineState of @oldState.tiles[@id]?.lines + unless @measuredLines.has(id) + lineNode = @lineNodesByLineId[id] + @measureCharactersInLine(id, lineState, lineNode) + return measureCharactersInLine: (lineId, tokenizedLine, lineNode) -> rangeForMeasurement = null @@ -296,6 +277,5 @@ class TileComponent @measuredLines.add(lineId) - clearScopedCharWidths: -> + clearMeasurements: -> @measuredLines.clear() - @presenter.clearScopedCharacterWidths() From 40cde496d72d9de89e3fe36381705bfc806e5cc5 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 5 May 2015 19:03:13 +0200 Subject: [PATCH 0987/1783] Draw highlight components appropriately --- src/text-editor-presenter.coffee | 8 ++++---- src/tile-component.coffee | 4 ---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index c8d74b428..9f31c2a54 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -1218,7 +1218,7 @@ class TextEditorPresenter if spannedRows is 1 [ - top: startPixelPosition.top + top: startPixelPosition.top - @scrollTop height: lineHeightInPixels left: startPixelPosition.left width: endPixelPosition.left - startPixelPosition.left @@ -1228,7 +1228,7 @@ class TextEditorPresenter # First row, extending from selection start to the right side of screen regions.push( - top: startPixelPosition.top + top: startPixelPosition.top - @scrollTop left: startPixelPosition.left height: lineHeightInPixels right: 0 @@ -1237,7 +1237,7 @@ class TextEditorPresenter # Middle rows, extending from left side to right side of screen if spannedRows > 2 regions.push( - top: startPixelPosition.top + lineHeightInPixels + top: startPixelPosition.top + lineHeightInPixels - @scrollTop height: endPixelPosition.top - startPixelPosition.top - lineHeightInPixels left: 0 right: 0 @@ -1246,7 +1246,7 @@ class TextEditorPresenter # Last row, extending from left side of screen to selection end if screenRange.end.column > 0 regions.push( - top: endPixelPosition.top + top: endPixelPosition.top - @scrollTop height: lineHeightInPixels left: 0 width: endPixelPosition.left diff --git a/src/tile-component.coffee b/src/tile-component.coffee index 0b97467c7..550e2c272 100644 --- a/src/tile-component.coffee +++ b/src/tile-component.coffee @@ -41,10 +41,6 @@ class TileComponent @domNode.style['-webkit-transform'] = "translate3d(0, #{@newState.tiles[@id].top}px, 0px)" @oldState.tiles[@id]?.top = @newState.tiles[@id].top - if @newState.backgroundColor isnt @oldState.backgroundColor - @domNode.style.backgroundColor = @newState.backgroundColor - @oldState.backgroundColor = @newState.backgroundColor - @removeLineNodes() unless @oldState.indentGuidesVisible is @newState.indentGuidesVisible @updateLineNodes() From 936133cfdcb70a159c9d3e144ca311d02281452e Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 5 May 2015 19:06:37 +0200 Subject: [PATCH 0988/1783] Always subtract @scrollTop --- src/text-editor-presenter.coffee | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 9f31c2a54..f0fbe7f7a 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -977,11 +977,12 @@ class TextEditorPresenter charLength = 1 valueIndex++ - return {top, left} if column is targetColumn + break if column is targetColumn left += characterWidths[char] ? baseCharacterWidth unless char is '\0' column += charLength - {top, left} + + {top: top - @scrollTop, left} hasPixelRectRequirements: -> @hasPixelPositionRequirements() and @scrollWidth? @@ -1218,7 +1219,7 @@ class TextEditorPresenter if spannedRows is 1 [ - top: startPixelPosition.top - @scrollTop + top: startPixelPosition.top height: lineHeightInPixels left: startPixelPosition.left width: endPixelPosition.left - startPixelPosition.left @@ -1228,7 +1229,7 @@ class TextEditorPresenter # First row, extending from selection start to the right side of screen regions.push( - top: startPixelPosition.top - @scrollTop + top: startPixelPosition.top left: startPixelPosition.left height: lineHeightInPixels right: 0 @@ -1237,7 +1238,7 @@ class TextEditorPresenter # Middle rows, extending from left side to right side of screen if spannedRows > 2 regions.push( - top: startPixelPosition.top + lineHeightInPixels - @scrollTop + top: startPixelPosition.top + lineHeightInPixels height: endPixelPosition.top - startPixelPosition.top - lineHeightInPixels left: 0 right: 0 @@ -1246,7 +1247,7 @@ class TextEditorPresenter # Last row, extending from left side of screen to selection end if screenRange.end.column > 0 regions.push( - top: endPixelPosition.top - @scrollTop + top: endPixelPosition.top height: lineHeightInPixels left: 0 width: endPixelPosition.left From 3a1bb898c33160f3d2c8cfe37b584bb5ab6f241f Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 5 May 2015 19:09:48 +0200 Subject: [PATCH 0989/1783] Fix clicking on line --- src/text-editor-component.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 4c6480510..df88d0706 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -763,6 +763,7 @@ class TextEditorComponent screenPositionForMouseEvent: (event) -> pixelPosition = @pixelPositionForMouseEvent(event) + pixelPosition.top += @presenter.scrollTop @editor.screenPositionForPixelPosition(pixelPosition) pixelPositionForMouseEvent: (event) -> From 9aaa8b483388896ab9c5ad6ef0e680fd7f555214 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 5 May 2015 19:21:34 +0200 Subject: [PATCH 0990/1783] Better defaults --- src/text-editor-presenter.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index f0fbe7f7a..2cf2188d7 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -21,8 +21,8 @@ class TextEditorPresenter @measuredHorizontalScrollbarHeight = horizontalScrollbarHeight @measuredVerticalScrollbarWidth = verticalScrollbarWidth @gutterWidth ?= 0 - @tileOverdrawMargin ?= 0 - @tileCount ?= 4 + @tileOverdrawMargin ?= 1 + @tileCount ?= 3 @linesPresentersByTileIndex = {} @disposables = new CompositeDisposable From 216b757ac0aa5aa96f4fb6a65f17eacd841fc86b Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 5 May 2015 19:49:49 +0200 Subject: [PATCH 0991/1783] Keep scrolling tile around for mousewheel --- src/text-editor-component.coffee | 1 - src/text-editor-presenter.coffee | 18 ++++++++++-------- src/tile-component.coffee | 4 ++++ 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index df88d0706..71ca96d87 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -354,7 +354,6 @@ class TextEditorComponent event.preventDefault() unless previousScrollLeft is @presenter.getScrollLeft() else # Scrolling vertically - @presenter.setMouseWheelScreenRow(@screenRowForNode(event.target)) previousScrollTop = @presenter.getScrollTop() @presenter.setScrollTop(previousScrollTop - Math.round(wheelDeltaY * @scrollSensitivity)) event.preventDefault() unless previousScrollTop is @presenter.getScrollTop() diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 2cf2188d7..1411470c1 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -317,9 +317,11 @@ class TextEditorPresenter visibleTilesIndexes = [startIndex...endIndex] for index, tile of @state.content.tiles - unless index in visibleTilesIndexes - delete @state.content.tiles[index] - delete @linesPresentersByTileIndex[index] + continue if index is @scrollingTile + continue if index in visibleTilesIndexes + + delete @state.content.tiles[index] + delete @linesPresentersByTileIndex[index] for index in visibleTilesIndexes presenter = @linesPresentersByTileIndex[index] ?= new LinesPresenter(@) @@ -728,8 +730,8 @@ class TextEditorPresenter didStopScrolling: -> @state.content.scrollingVertically = false - if @mouseWheelScreenRow? - @mouseWheelScreenRow = null + if @scrollingTile? + @scrollingTile = null @shouldUpdateTilesState = true @shouldUpdateLineNumbersState = true @shouldUpdateCustomGutterDecorationState = true @@ -895,9 +897,9 @@ class TextEditorPresenter @emitDidUpdateState() - setMouseWheelScreenRow: (mouseWheelScreenRow) -> - unless @mouseWheelScreenRow is mouseWheelScreenRow - @mouseWheelScreenRow = mouseWheelScreenRow + setScrollingTile: (tileId) -> + if @scrollingTile isnt tileId + @scrollingTile = tileId @didStartScrolling() setBaseCharacterWidth: (baseCharacterWidth) -> diff --git a/src/tile-component.coffee b/src/tile-component.coffee index 550e2c272..ff2d7eb46 100644 --- a/src/tile-component.coffee +++ b/src/tile-component.coffee @@ -21,9 +21,13 @@ class TileComponent @screenRowsByLineId = {} @lineIdsByScreenRow = {} @domNode = document.createElement("div") + @domNode.addEventListener("mousewheel", @onMouseWheel) @domNode.style.position = "absolute" @domNode.classList.add("tile") + onMouseWheel: => + @presenter.setScrollingTile(@id) + getDomNode: -> @domNode From bc1f190c2f233c84fbaee35574ebd8c4af76e687 Mon Sep 17 00:00:00 2001 From: Jonas Gebhardt Date: Tue, 5 May 2015 11:22:14 -0700 Subject: [PATCH 0992/1783] remove babel compatibility option for legacy react versions --- src/babel.coffee | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/babel.coffee b/src/babel.coffee index 286ee45ef..7058c85c2 100644 --- a/src/babel.coffee +++ b/src/babel.coffee @@ -32,11 +32,6 @@ defaultOptions = # Target a version of the regenerator runtime that # supports yield so the transpiled code is cleaner/smaller. 'asyncToGenerator' - - # Because Atom is currently packaged with a fork of React v0.11, - # it makes sense to use the reactCompat transform so the React - # JSX transformer produces pre-v0.12 code. - 'reactCompat' ] # Includes support for es7 features listed at: From 5d7161acd76837076d7d9d28883f431693a40588 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Tue, 5 May 2015 15:26:29 -0700 Subject: [PATCH 0993/1783] Don't need to replace now, use module directly --- src/package.coffee | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/package.coffee b/src/package.coffee index 473b5dc33..8c67af2d9 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -25,11 +25,6 @@ class Package @resourcePathWithTrailingSlash ?= "#{atom.packages.resourcePath}#{path.sep}" packagePath?.startsWith(@resourcePathWithTrailingSlash) - @normalizeMetadata: (metadata) -> - if typeof metadata.repository is 'string' - normalizePackageData(metadata) - metadata.repository.url = metadata.repository.url.replace(/^git\+/, '') - @loadMetadata: (packagePath, ignoreErrors=false) -> packageName = path.basename(packagePath) if @isBundledPackagePath(packagePath) @@ -38,7 +33,7 @@ class Package if metadataPath = CSON.resolve(path.join(packagePath, 'package')) try metadata = CSON.readFileSync(metadataPath) - @normalizeMetadata(metadata) + normalizePackageData(metadata) catch error throw error unless ignoreErrors From e8ca3745b13db049b437470903a51c36918a0538 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 5 May 2015 15:27:09 -0700 Subject: [PATCH 0994/1783] :arrow_up: language-css@0.29.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 54745a3e9..26dadd7fc 100644 --- a/package.json +++ b/package.json @@ -128,7 +128,7 @@ "language-clojure": "0.14.0", "language-coffee-script": "0.40.0", "language-csharp": "0.5.0", - "language-css": "0.28.0", + "language-css": "0.29.0", "language-gfm": "0.71.0", "language-git": "0.10.0", "language-go": "0.25.0", From b563eabd7a70eac5a8228c08b764c361cdb5b992 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 5 May 2015 15:27:24 -0700 Subject: [PATCH 0995/1783] :arrow_up: language-less@0.27.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 26dadd7fc..95d6460e9 100644 --- a/package.json +++ b/package.json @@ -137,7 +137,7 @@ "language-java": "0.15.0", "language-javascript": "0.76.0", "language-json": "0.14.0", - "language-less": "0.26.0", + "language-less": "0.27.0", "language-make": "0.14.0", "language-mustache": "0.11.0", "language-objective-c": "0.15.0", From 3c6e6e4538466d38d36f7ceac120bba384080192 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 5 May 2015 15:27:38 -0700 Subject: [PATCH 0996/1783] :arrow_up: language-sass@0.37.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 95d6460e9..585e1b451 100644 --- a/package.json +++ b/package.json @@ -147,7 +147,7 @@ "language-python": "0.34.0", "language-ruby": "0.52.0", "language-ruby-on-rails": "0.21.0", - "language-sass": "0.36.0", + "language-sass": "0.37.0", "language-shellscript": "0.14.0", "language-source": "0.9.0", "language-sql": "0.15.0", From fc5927a596af05f49ef596882451dbf4f8e6905d Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Tue, 5 May 2015 16:19:50 -0700 Subject: [PATCH 0997/1783] :arrow_up: settings-view@0.197.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 585e1b451..5fa296cb4 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "open-on-github": "0.36.0", "package-generator": "0.38.0", "release-notes": "0.52.0", - "settings-view": "0.196.0", + "settings-view": "0.197.0", "snippets": "0.89.0", "spell-check": "0.56.0", "status-bar": "0.69.0", From daa4b33e649842475475f3aab985bbff505c9934 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 6 May 2015 08:55:53 +0200 Subject: [PATCH 0998/1783] wip --- spec/text-editor-presenter-spec.coffee | 4 ++-- src/text-editor-presenter.coffee | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index b2c40fc36..6db369f69 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -657,7 +657,7 @@ describe "TextEditorPresenter", -> expectStateUpdate presenter, -> editor.setPlaceholderText("new-placeholder-text") expect(presenter.getState().content.placeholderText).toBe "new-placeholder-text" - fdescribe ".tiles", -> + describe ".tiles", -> it "contains states for tiles that are visible on screen, plus and minus the overdraw margin", -> presenter = buildPresenter(explicitHeight: 3, scrollTop: 1, lineHeight: 1, tileCount: 3, tileOverdrawMargin: 1) @@ -762,7 +762,7 @@ describe "TextEditorPresenter", -> expect(lineStateForScreenRow(presenter, 5)).toBeDefined() expect(lineStateForScreenRow(presenter, 6)).toBeUndefined() - fffit "updates when the editor's content changes", -> + it "updates when the editor's content changes", -> lineStateForScreenRow = (presenter, tile, row) -> lineId = presenter.model.tokenizedLineForScreenRow(row).id presenter.getState().content.tiles[tile].lines[lineId] diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 1411470c1..071195ec3 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -21,7 +21,7 @@ class TextEditorPresenter @measuredHorizontalScrollbarHeight = horizontalScrollbarHeight @measuredVerticalScrollbarWidth = verticalScrollbarWidth @gutterWidth ?= 0 - @tileOverdrawMargin ?= 1 + @tileOverdrawMargin ?= 0 @tileCount ?= 3 @linesPresentersByTileIndex = {} From 02838ad193c6e3d06f3f32e5426476e2b9127ecf Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 6 May 2015 09:46:47 +0200 Subject: [PATCH 0999/1783] Recycle tiles --- src/lines-component.coffee | 15 +++++++++++---- src/text-editor-presenter.coffee | 4 +++- src/tile-component.coffee | 28 ++++++++++++++++++++++++---- 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/src/lines-component.coffee b/src/lines-component.coffee index 547b54e56..fda77a76a 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -21,6 +21,7 @@ class LinesComponent constructor: ({@presenter, @hostElement, @useShadowDOM, visible}) -> @tileComponentsByTileId = {} + @freeDomNodes = [] @domNode = document.createElement('div') @domNode.classList.add('lines') @@ -81,7 +82,10 @@ class LinesComponent return removeTileNode: (id) -> - @tileComponentsByTileId[id].getDomNode().remove() + node = @tileComponentsByTileId[id].getDomNode() + + node.style.display = "none" + @freeDomNodes.push(node) delete @tileComponentsByTileId[id] delete @oldState.tiles[id] @@ -91,10 +95,13 @@ class LinesComponent @removeTileNode(id) for id, tileState of @newState.tiles - tileComponent = @tileComponentsByTileId[id] ?= new TileComponent({id, @presenter}) + if @oldState.tiles.hasOwnProperty(id) + tileComponent = @tileComponentsByTileId[id] + else + domNode = @freeDomNodes.pop() + tileComponent = @tileComponentsByTileId[id] = new TileComponent({id, @presenter, domNode}) - unless @oldState.tiles.hasOwnProperty(id) - @domNode.appendChild(tileComponent.getDomNode()) + @domNode.appendChild(tileComponent.getDomNode()) unless domNode? @oldState.tiles[id] = cloneObject(tileState) tileComponent.updateSync(@newState) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 071195ec3..4ff358cec 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -318,7 +318,7 @@ class TextEditorPresenter for index, tile of @state.content.tiles continue if index is @scrollingTile - continue if index in visibleTilesIndexes + continue if startIndex <= index <= endIndex delete @state.content.tiles[index] delete @linesPresentersByTileIndex[index] @@ -329,10 +329,12 @@ class TextEditorPresenter presenter.endRow = Math.ceil(Math.min(@model.getScreenLineCount(), (index + 1) * linesPerTile)) presenter.lineHeight = @lineHeight + isNewTile = not @state.content.tiles.hasOwnProperty(index) tile = @state.content.tiles[index] ?= {} tile.top = (index * linesPerTile * @lineHeight) - @scrollTop tile.lines = presenter.getState() tile.height = linesPerTile * @lineHeight + tile.newlyCreated = isNewTile updateCursorsState: -> @state.content.cursors = {} diff --git a/src/tile-component.coffee b/src/tile-component.coffee index ff2d7eb46..023f9a369 100644 --- a/src/tile-component.coffee +++ b/src/tile-component.coffee @@ -15,14 +15,15 @@ module.exports = class TileComponent placeholderTextDiv: null - constructor: ({@presenter, @id}) -> + constructor: ({@presenter, @id, @domNode}) -> @measuredLines = new Set @lineNodesByLineId = {} @screenRowsByLineId = {} @lineIdsByScreenRow = {} - @domNode = document.createElement("div") + @domNode ?= document.createElement("div") @domNode.addEventListener("mousewheel", @onMouseWheel) @domNode.style.position = "absolute" + @domNode.style.display = "block" @domNode.classList.add("tile") onMouseWheel: => @@ -45,8 +46,27 @@ class TileComponent @domNode.style['-webkit-transform'] = "translate3d(0, #{@newState.tiles[@id].top}px, 0px)" @oldState.tiles[@id]?.top = @newState.tiles[@id].top - @removeLineNodes() unless @oldState.indentGuidesVisible is @newState.indentGuidesVisible - @updateLineNodes() + if @newState.tiles[@id].newlyCreated + newLineIds = [] + newLinesHTML = "" + + for id, lineState of @newState.tiles[@id].lines + newLineIds.push(id) + newLinesHTML += @buildLineHTML(id) + @screenRowsByLineId[id] = lineState.screenRow + @lineIdsByScreenRow[lineState.screenRow] = id + @oldState.tiles[@id]?.lines[id] = cloneObject(lineState) + + return if newLineIds.length is 0 + + @domNode.innerHTML = newLinesHTML + newLineNodes = _.toArray(@domNode.children) + for id, i in newLineIds + lineNode = newLineNodes[i] + @lineNodesByLineId[id] = lineNode + else + @removeLineNodes() unless @oldState.indentGuidesVisible is @newState.indentGuidesVisible + @updateLineNodes() if @newState.scrollWidth isnt @oldState.scrollWidth @domNode.style.width = @newState.scrollWidth + 'px' From c99ffa04f11307fab3593bf8ad3087744a4e2ede Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 6 May 2015 10:03:49 +0200 Subject: [PATCH 1000/1783] Hide scrolling tile --- src/text-editor-presenter.coffee | 24 +++++++++++++++--------- src/tile-component.coffee | 4 ++++ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 4ff358cec..59ff21afe 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -314,16 +314,9 @@ class TextEditorPresenter Math.ceil(@model.getScreenLineCount() / linesPerTile), Math.ceil(@endRow / linesPerTile) + @tileOverdrawMargin ) - visibleTilesIndexes = [startIndex...endIndex] - for index, tile of @state.content.tiles - continue if index is @scrollingTile - continue if startIndex <= index <= endIndex - - delete @state.content.tiles[index] - delete @linesPresentersByTileIndex[index] - - for index in visibleTilesIndexes + visibleTiles = {} + for index in [startIndex...endIndex] presenter = @linesPresentersByTileIndex[index] ?= new LinesPresenter(@) presenter.startRow = Math.floor(index * linesPerTile) presenter.endRow = Math.ceil(Math.min(@model.getScreenLineCount(), (index + 1) * linesPerTile)) @@ -335,6 +328,19 @@ class TextEditorPresenter tile.lines = presenter.getState() tile.height = linesPerTile * @lineHeight tile.newlyCreated = isNewTile + tile.display = "block" + + visibleTiles[index] = true + + for index, tile of @state.content.tiles + continue if visibleTiles.hasOwnProperty(index) + + if index is @scrollingTile + tile.display = "none" + else + delete @state.content.tiles[index] + delete @linesPresentersByTileIndex[index] + updateCursorsState: -> @state.content.cursors = {} diff --git a/src/tile-component.coffee b/src/tile-component.coffee index 023f9a369..0f366dbdc 100644 --- a/src/tile-component.coffee +++ b/src/tile-component.coffee @@ -38,6 +38,10 @@ class TileComponent @oldState = {tiles: {}} @oldState.tiles[@id] = { lines: {}} + if @newState.tiles[@id].display isnt @oldState.tiles[@id]?.display + @domNode.style.display = @newState.tiles[@id].display + @oldState.tiles[@id]?.display = @newState.tiles[@id].display + if @newState.tiles[@id].height isnt @oldState.tiles[@id]?.height @domNode.style.height = @newState.tiles[@id].height + 'px' @oldState.tiles[@id]?.height = @newState.tiles[@id].height From 8e8e82738806f0aa8b8e0e04b51215181b8a1bc2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 6 May 2015 09:34:59 -0700 Subject: [PATCH 1001/1783] :arrow_up: language-javascript@0.77 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 585e1b451..205b6945a 100644 --- a/package.json +++ b/package.json @@ -135,7 +135,7 @@ "language-html": "0.36.0", "language-hyperlink": "0.13.0", "language-java": "0.15.0", - "language-javascript": "0.76.0", + "language-javascript": "0.77.0", "language-json": "0.14.0", "language-less": "0.27.0", "language-make": "0.14.0", From 61a0927b26a33630875382cec1744c7497a72957 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 6 May 2015 09:56:32 -0700 Subject: [PATCH 1002/1783] Use apiPreviewMode value when running specs --- src/browser/atom-application.coffee | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 178755786..a825b0d34 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -87,7 +87,7 @@ class AtomApplication openWithOptions: ({pathsToOpen, urlsToOpen, test, pidToKillWhenClosed, devMode, safeMode, apiPreviewMode, newWindow, specDirectory, logFile, profileStartup}) -> if test - @runSpecs({exitWhenDone: true, @resourcePath, specDirectory, logFile}) + @runSpecs({exitWhenDone: true, @resourcePath, specDirectory, logFile, apiPreviewMode}) else if pathsToOpen.length > 0 @openPaths({pathsToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, apiPreviewMode, profileStartup}) else if urlsToOpen.length > 0 @@ -486,7 +486,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. - runSpecs: ({exitWhenDone, resourcePath, specDirectory, logFile, safeMode}) -> + runSpecs: ({exitWhenDone, resourcePath, specDirectory, logFile, safeMode, apiPreviewMode}) -> if resourcePath isnt @resourcePath and not fs.existsSync(resourcePath) resourcePath = @resourcePath @@ -498,7 +498,8 @@ class AtomApplication isSpec = true devMode = true safeMode ?= false - new AtomWindow({bootstrapScript, resourcePath, exitWhenDone, isSpec, devMode, specDirectory, logFile, safeMode}) + apiPreviewMode ?= false + new AtomWindow({bootstrapScript, resourcePath, exitWhenDone, isSpec, devMode, specDirectory, logFile, safeMode, apiPreviewMode}) runBenchmarks: ({exitWhenDone, specDirectory}={}) -> try From aa1dbf3c5eea00d9cc0eed12dea9545025f9558a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 6 May 2015 10:09:55 -0700 Subject: [PATCH 1003/1783] :arrow_up: apm@0.165 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index b09eb087a..52f42c0af 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.164.0" + "atom-package-manager": "0.165.0" } } From 11fe07d5d82ecc061bb8872b1388c984fc88bd1d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 6 May 2015 10:20:10 -0700 Subject: [PATCH 1004/1783] :arrow_up: symbols-view@0.96 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 205b6945a..542bd7d37 100644 --- a/package.json +++ b/package.json @@ -116,7 +116,7 @@ "spell-check": "0.56.0", "status-bar": "0.69.0", "styleguide": "0.44.0", - "symbols-view": "0.95.0", + "symbols-view": "0.96.0", "tabs": "0.68.0", "timecop": "0.31.0", "tree-view": "0.171.0", From 75289ee3ddce2406bbd64717f100462ae256da9d Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 6 May 2015 10:29:34 -0700 Subject: [PATCH 1005/1783] Fix some integration test flakiness --- spec/integration/helpers/start-atom.coffee | 28 +++++++++++++++------- spec/integration/startup-spec.coffee | 2 ++ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/spec/integration/helpers/start-atom.coffee b/spec/integration/helpers/start-atom.coffee index 0de6644b3..646281171 100644 --- a/spec/integration/helpers/start-atom.coffee +++ b/spec/integration/helpers/start-atom.coffee @@ -15,15 +15,23 @@ ChromedriverPort = 9515 ChromedriverURLBase = "/wd/hub" ChromedriverStatusURL = "http://localhost:#{ChromedriverPort}#{ChromedriverURLBase}/status" -pollChromeDriver = (done) -> +chromeDriverUp = (done) -> checkStatus = -> - http.get(ChromedriverStatusURL, (response) -> - if response.statusCode is 200 - done() - else - pollChromeDriver(done) - ).on("error", -> pollChromeDriver(done)) + http + .get ChromedriverStatusURL, (response) -> + if response.statusCode is 200 + done() + else + chromeDriverUp(done) + .on("error", -> chromeDriverUp(done)) + setTimeout(checkStatus, 100) +chromeDriverDown = (done) -> + checkStatus = -> + http + .get ChromedriverStatusURL, (response) -> + chromeDriverDown(done) + .on("error", done) setTimeout(checkStatus, 100) buildAtomClient = (args, env) -> @@ -137,9 +145,9 @@ module.exports = (args, env, fn) -> chromedriver.stderr.on "close", -> resolve(errorCode) - waitsFor("webdriver to start", pollChromeDriver, 15000) + waitsFor("webdriver to start", chromeDriverUp, 15000) - waitsFor("webdriver to finish", (done) -> + waitsFor("tests to run", (done) -> finish = once -> client .simulateQuit() @@ -162,3 +170,5 @@ module.exports = (args, env, fn) -> fn(client.init()).then(finish) , 30000) + + waitsFor("webdriver to stop", chromeDriverDown, 15000) diff --git a/spec/integration/startup-spec.coffee b/spec/integration/startup-spec.coffee index b20427954..828193e4d 100644 --- a/spec/integration/startup-spec.coffee +++ b/spec/integration/startup-spec.coffee @@ -150,10 +150,12 @@ describe "Starting Atom", -> .waitForWindowCount(2, 10000) .then ({value: windowHandles}) -> @window(windowHandles[0]) + .waitForExist("atom-workspace") .treeViewRootDirectories() .then ({value: directories}) -> windowProjectPaths.push(directories) .window(windowHandles[1]) + .waitForExist("atom-workspace") .treeViewRootDirectories() .then ({value: directories}) -> windowProjectPaths.push(directories) From 4c2f48792910b5b2026ad468395938f3250c81ed Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Wed, 6 May 2015 11:55:22 -0700 Subject: [PATCH 1006/1783] :arrow_up: autocomplete@0.45.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5fa296cb4..74d9a7344 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ "solarized-dark-syntax": "0.32.0", "solarized-light-syntax": "0.19.0", "archive-view": "0.56.0", - "autocomplete": "0.44.0", + "autocomplete": "0.45.0", "autoflow": "0.22.0", "autosave": "0.20.0", "background-tips": "0.24.0", From 06844ed60a66748802ca7c58c2f3af1d88190926 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 6 May 2015 13:14:10 -0700 Subject: [PATCH 1007/1783] :arrow_up: autocomplete@0.46.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 542bd7d37..1b5c01480 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ "solarized-dark-syntax": "0.32.0", "solarized-light-syntax": "0.19.0", "archive-view": "0.56.0", - "autocomplete": "0.44.0", + "autocomplete": "0.46.0", "autoflow": "0.22.0", "autosave": "0.20.0", "background-tips": "0.24.0", From 9c34e2273fd4c88fc5882d81f808b35b9782b978 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Wed, 6 May 2015 13:14:58 -0700 Subject: [PATCH 1008/1783] Revert ":arrow_up: autocomplete@0.45.0" This reverts commit 4c2f48792910b5b2026ad468395938f3250c81ed. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 74d9a7344..5fa296cb4 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ "solarized-dark-syntax": "0.32.0", "solarized-light-syntax": "0.19.0", "archive-view": "0.56.0", - "autocomplete": "0.45.0", + "autocomplete": "0.44.0", "autoflow": "0.22.0", "autosave": "0.20.0", "background-tips": "0.24.0", From 186448fd530102452dfb627794db2d0b2f6ee0eb Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 6 May 2015 17:35:53 -0700 Subject: [PATCH 1009/1783] :arrow_up: notifications --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9d5e66e79..2a43b70c6 100644 --- a/package.json +++ b/package.json @@ -107,7 +107,7 @@ "link": "0.30.0", "markdown-preview": "0.148.0", "metrics": "0.45.0", - "notifications": "0.42.0", + "notifications": "0.43.0", "open-on-github": "0.36.0", "package-generator": "0.38.0", "release-notes": "0.52.0", From b5c130ed18b71de369e5c697231b6f9fc0422c23 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 6 May 2015 18:02:11 -0700 Subject: [PATCH 1010/1783] :arrow_up: apm@0.166 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index 52f42c0af..423e31a12 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.165.0" + "atom-package-manager": "0.166.0" } } From a79a8fa60456a0c41d63c517fdff785b0f4f0a0a Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 7 May 2015 10:18:41 +0900 Subject: [PATCH 1011/1783] :arrow_up: one-dark/light-ui@0.8.1 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 2a43b70c6..90e15cfcd 100644 --- a/package.json +++ b/package.json @@ -77,10 +77,10 @@ "atom-light-ui": "0.41.0", "base16-tomorrow-dark-theme": "0.25.0", "base16-tomorrow-light-theme": "0.8.0", - "one-dark-ui": "0.8.0", + "one-dark-ui": "0.8.1", "one-dark-syntax": "0.4.0", "one-light-syntax": "0.5.0", - "one-light-ui": "0.8.0", + "one-light-ui": "0.8.1", "solarized-dark-syntax": "0.32.0", "solarized-light-syntax": "0.19.0", "archive-view": "0.56.0", From 4fd114a1b4c589effbe43b37dde55ada172b8c4a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 7 May 2015 09:38:09 -0700 Subject: [PATCH 1012/1783] Prepare 0.198 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 90e15cfcd..65fd5780b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "0.197.0", + "version": "0.198.0", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From 4f5e9b114d6ecac8762c69ef58bb42fd002670fb Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Thu, 7 May 2015 10:31:21 -0700 Subject: [PATCH 1013/1783] :arrow_up: language-html@0.37.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 65fd5780b..98bffd420 100644 --- a/package.json +++ b/package.json @@ -132,7 +132,7 @@ "language-gfm": "0.71.0", "language-git": "0.10.0", "language-go": "0.25.0", - "language-html": "0.36.0", + "language-html": "0.37.0", "language-hyperlink": "0.13.0", "language-java": "0.15.0", "language-javascript": "0.77.0", From a2dcdda972ae07566930063a09f9d856982da5b6 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 7 May 2015 10:58:44 -0700 Subject: [PATCH 1014/1783] Prepare 0.199 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 98bffd420..f38754551 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "0.198.0", + "version": "0.199.0", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From edf0d6f2380f9af1dc0ea267b954468e0cc8b7a0 Mon Sep 17 00:00:00 2001 From: Johnston Jiaa Date: Thu, 7 May 2015 14:18:03 -0400 Subject: [PATCH 1015/1783] :arrow_up: fs-plus@2.8.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f38754551..a62460413 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "emissary": "^1.3.3", "event-kit": "^1.1", "first-mate": "^3.1", - "fs-plus": "^2.7.1", + "fs-plus": "^2.8.0", "fstream": "0.1.24", "fuzzaldrin": "^2.1", "git-utils": "^3.0.0", From 4300ba6bb3155eb4340eb9bda42a5ab171bd24c4 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 7 May 2015 11:35:16 -0700 Subject: [PATCH 1016/1783] Make 'atom' command w/ no args reopen previous windows --- src/browser/main.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/browser/main.coffee b/src/browser/main.coffee index e35632104..746055ea4 100644 --- a/src/browser/main.coffee +++ b/src/browser/main.coffee @@ -133,7 +133,6 @@ parseCommandLine = -> safeMode = args['safe'] apiPreviewMode = args['one'] pathsToOpen = args._ - pathsToOpen = [executedFrom] if executedFrom and pathsToOpen.length is 0 test = args['test'] specDirectory = args['spec-directory'] newWindow = args['new-window'] From 5b8262bd96a9889b880bc1b54b72514c6a753f66 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 7 May 2015 12:56:29 -0700 Subject: [PATCH 1017/1783] :racehorse: Avoid repeated array allocation in ::getDecorations --- src/display-buffer.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index d86fd13be..db39eb432 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -886,7 +886,7 @@ class DisplayBuffer extends Model getDecorations: (propertyFilter) -> allDecorations = [] for markerId, decorations of @decorationsByMarkerId - allDecorations = allDecorations.concat(decorations) if decorations? + allDecorations.push(decorations...) if decorations? if propertyFilter? allDecorations = allDecorations.filter (decoration) -> for key, value of propertyFilter From b7dddeebfe71f710cf495ed7d34e16d4a238df5d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 7 May 2015 13:23:14 -0700 Subject: [PATCH 1018/1783] Guard against no hosted git info Closes #6693 --- .../package-with-invalid-url-package-json/package.json | 4 ++++ spec/package-manager-spec.coffee | 4 ++++ src/package.coffee | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 spec/fixtures/packages/package-with-invalid-url-package-json/package.json diff --git a/spec/fixtures/packages/package-with-invalid-url-package-json/package.json b/spec/fixtures/packages/package-with-invalid-url-package-json/package.json new file mode 100644 index 000000000..cc119ffaa --- /dev/null +++ b/spec/fixtures/packages/package-with-invalid-url-package-json/package.json @@ -0,0 +1,4 @@ +{ + "name": "package-with-invalid-url-package-json", + "repository": "foo" +} diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index ebdd1f57a..92dc21a13 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -46,6 +46,10 @@ describe "PackageManager", -> expect(metadata.repository.type).toBe "git" expect(metadata.repository.url).toBe "https://github.com/example/repo.git" + {metadata} = atom.packages.loadPackage("package-with-invalid-url-package-json") + expect(metadata.repository.type).toBe "git" + expect(metadata.repository.url).toBe "foo" + 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.coffee b/src/package.coffee index 05be6c79f..8f5baf44a 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -34,7 +34,7 @@ class Package repoUrl = metadata.repository?.url if repoUrl info = hostedGitInfo.fromUrl(repoUrl) - if info.getDefaultRepresentation() is 'shortcut' + if info?.getDefaultRepresentation() is 'shortcut' metadata.repository.url = info.https().replace(/^git\+/, '') @loadMetadata: (packagePath, ignoreErrors=false) -> From db3cd61344e2587410988370eb88ffc3838a4321 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 7 May 2015 14:35:17 -0700 Subject: [PATCH 1019/1783] :arrow_up: settings-view@0.198 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a62460413..6a9d42176 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "open-on-github": "0.36.0", "package-generator": "0.38.0", "release-notes": "0.52.0", - "settings-view": "0.197.0", + "settings-view": "0.198.0", "snippets": "0.89.0", "spell-check": "0.56.0", "status-bar": "0.69.0", From 55c0be05f718d57d31a8940a823940f6bf85b75b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 7 May 2015 14:35:55 -0700 Subject: [PATCH 1020/1783] :arrow_up: language-gfm@0.72 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6a9d42176..953c69800 100644 --- a/package.json +++ b/package.json @@ -129,7 +129,7 @@ "language-coffee-script": "0.40.0", "language-csharp": "0.5.0", "language-css": "0.29.0", - "language-gfm": "0.71.0", + "language-gfm": "0.72.0", "language-git": "0.10.0", "language-go": "0.25.0", "language-html": "0.37.0", From 858fc53a0cb52a6ed665bb09ea5017f691b83e05 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 7 May 2015 15:42:32 -0700 Subject: [PATCH 1021/1783] :arrow_up: event-kit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 953c69800..19e5acf9f 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "color": "^0.7.3", "delegato": "^1", "emissary": "^1.3.3", - "event-kit": "^1.1", + "event-kit": "^1.1.1", "first-mate": "^3.1", "fs-plus": "^2.8.0", "fstream": "0.1.24", From 523171061b14620a4b8156be1e687799b31f390f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 7 May 2015 15:57:58 -0700 Subject: [PATCH 1022/1783] Stop resize if detached or if siblings are missing Closes #6630 --- spec/pane-container-element-spec.coffee | 22 ++++++++++++++++++++++ src/pane-resize-handle-element.coffee | 4 ++++ 2 files changed, 26 insertions(+) diff --git a/spec/pane-container-element-spec.coffee b/spec/pane-container-element-spec.coffee index 0a5b11b39..400904f5c 100644 --- a/spec/pane-container-element-spec.coffee +++ b/spec/pane-container-element-spec.coffee @@ -132,3 +132,25 @@ describe "PaneContainerElement", -> # dynamically close pane, the pane's flexscale will recorver to origin value lowerPane.close() expectPaneScale [leftPane, 0.5], [rightPane, 1.5] + + it "unsubscribes from mouse events when the pane is detached", -> + container.getActivePane().splitRight() + element = getResizeElement(0) + spyOn(document, 'addEventListener').andCallThrough() + spyOn(document, 'removeEventListener').andCallThrough() + spyOn(element, 'resizeStopped').andCallThrough() + + element.dispatchEvent(new MouseEvent('mousedown', + view: window + bubbles: true + button: 0 + )) + + waitsFor -> + document.addEventListener.callCount is 2 + + runs -> + expect(element.resizeStopped.callCount).toBe 0 + container.destroy() + expect(element.resizeStopped.callCount).toBe 1 + expect(document.removeEventListener.callCount).toBe 2 diff --git a/src/pane-resize-handle-element.coffee b/src/pane-resize-handle-element.coffee index 47548bc60..078bb44ac 100644 --- a/src/pane-resize-handle-element.coffee +++ b/src/pane-resize-handle-element.coffee @@ -12,6 +12,9 @@ class PaneResizeHandleElement extends HTMLElement @isHorizontal = @parentElement.classList.contains("horizontal") @classList.add if @isHorizontal then 'horizontal' else 'vertical' + detachedCallback: -> + @resizeStopped() + resizeToFitContent: -> # clear flex-grow css style of both pane @previousSibling.model.setFlexScale(1) @@ -43,6 +46,7 @@ class PaneResizeHandleElement extends HTMLElement resizePane: ({clientX, clientY, which}) -> return @resizeStopped() unless which is 1 + return @resizeStopped() unless @previousSibling? and @nextSibling? if @isHorizontal totalWidth = @previousSibling.clientWidth + @nextSibling.clientWidth From 5f40ee37fa2d32da7e0d6d11e1d883a71a76f770 Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 8 May 2015 11:46:57 +0900 Subject: [PATCH 1023/1783] :arrow_up: atom-dark-syntax@0.27.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 19e5acf9f..ffb6c5259 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "underscore-plus": "^1.6.6" }, "packageDependencies": { - "atom-dark-syntax": "0.26.0", + "atom-dark-syntax": "0.27.0", "atom-dark-ui": "0.49.0", "atom-light-syntax": "0.26.0", "atom-light-ui": "0.41.0", From 14b112cf20e78929cc8f723a9a56d91d1fc4c4ce Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 8 May 2015 11:48:09 +0900 Subject: [PATCH 1024/1783] :arrow_up: atom-light-syntax@0.28.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ffb6c5259..78bdd028b 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "packageDependencies": { "atom-dark-syntax": "0.27.0", "atom-dark-ui": "0.49.0", - "atom-light-syntax": "0.26.0", + "atom-light-syntax": "0.28.0", "atom-light-ui": "0.41.0", "base16-tomorrow-dark-theme": "0.25.0", "base16-tomorrow-light-theme": "0.8.0", From bff5c8496313eae3c2dd0f594f9a096364ff5b65 Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 8 May 2015 11:49:12 +0900 Subject: [PATCH 1025/1783] :arrow_up: base16-tomorrow-dark-theme@0.26.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 78bdd028b..d5f157c05 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "atom-dark-ui": "0.49.0", "atom-light-syntax": "0.28.0", "atom-light-ui": "0.41.0", - "base16-tomorrow-dark-theme": "0.25.0", + "base16-tomorrow-dark-theme": "0.26.0", "base16-tomorrow-light-theme": "0.8.0", "one-dark-ui": "0.8.1", "one-dark-syntax": "0.4.0", From 2dde7501572454e7d8ad2bf96868237680b97efc Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 8 May 2015 11:50:14 +0900 Subject: [PATCH 1026/1783] :arrow_up: base16-tomorrow-light-theme@0.9.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d5f157c05..588a0163d 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "atom-light-syntax": "0.28.0", "atom-light-ui": "0.41.0", "base16-tomorrow-dark-theme": "0.26.0", - "base16-tomorrow-light-theme": "0.8.0", + "base16-tomorrow-light-theme": "0.9.0", "one-dark-ui": "0.8.1", "one-dark-syntax": "0.4.0", "one-light-syntax": "0.5.0", From 1f5dda1ecd7884c6926d3bcafa37627d524fb23d Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 8 May 2015 11:51:15 +0900 Subject: [PATCH 1027/1783] :arrow_up: one-dark-syntax@0.5.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 588a0163d..802c30191 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "base16-tomorrow-dark-theme": "0.26.0", "base16-tomorrow-light-theme": "0.9.0", "one-dark-ui": "0.8.1", - "one-dark-syntax": "0.4.0", + "one-dark-syntax": "0.5.0", "one-light-syntax": "0.5.0", "one-light-ui": "0.8.1", "solarized-dark-syntax": "0.32.0", From 99a30dedf8c9ecde62af49fe44261e0866617bf5 Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 8 May 2015 11:52:29 +0900 Subject: [PATCH 1028/1783] :arrow_up: one-light-syntax@0.6.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 802c30191..381fe7038 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "base16-tomorrow-light-theme": "0.9.0", "one-dark-ui": "0.8.1", "one-dark-syntax": "0.5.0", - "one-light-syntax": "0.5.0", + "one-light-syntax": "0.6.0", "one-light-ui": "0.8.1", "solarized-dark-syntax": "0.32.0", "solarized-light-syntax": "0.19.0", From bd33d8d5281f7a99c4613576a29029019ed87aaa Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 8 May 2015 11:58:26 +0900 Subject: [PATCH 1029/1783] :arrow_up: solarized-dark-syntax@0.35.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 381fe7038..60a86cfcf 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,7 @@ "one-dark-syntax": "0.5.0", "one-light-syntax": "0.6.0", "one-light-ui": "0.8.1", - "solarized-dark-syntax": "0.32.0", + "solarized-dark-syntax": "0.35.0", "solarized-light-syntax": "0.19.0", "archive-view": "0.56.0", "autocomplete": "0.46.0", From fabfd2a68fbd2a0c3bf8a62b44d1d4317d19d92a Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 8 May 2015 12:01:24 +0900 Subject: [PATCH 1030/1783] :arrow_up: solarized-light-syntax@0.21.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 60a86cfcf..144981d45 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ "one-light-syntax": "0.6.0", "one-light-ui": "0.8.1", "solarized-dark-syntax": "0.35.0", - "solarized-light-syntax": "0.19.0", + "solarized-light-syntax": "0.21.0", "archive-view": "0.56.0", "autocomplete": "0.46.0", "autoflow": "0.22.0", From 6a7d5e69459cfd6dc14c2d4e25c97353f84c49c9 Mon Sep 17 00:00:00 2001 From: Ivan Zuzak Date: Fri, 8 May 2015 18:05:45 +0200 Subject: [PATCH 1031/1783] Ignore trailing colons and whitespace when opening files from command line --- src/browser/atom-application.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 6f7f0ac4b..8adba81f2 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -517,6 +517,8 @@ class AtomApplication return {pathToOpen} unless pathToOpen return {pathToOpen} if fs.existsSync(pathToOpen) + pathToOpen = pathToOpen.replace(/[:\s]+$/, '') + [fileToOpen, initialLine, initialColumn] = path.basename(pathToOpen).split(':') return {pathToOpen} unless initialLine return {pathToOpen} unless parseInt(initialLine) >= 0 From 0d310c767f1c9e82d07b410ed342cf7125be6ead Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 8 May 2015 00:54:31 +0200 Subject: [PATCH 1032/1783] Splice in new DisplayBuffer lines in chunks to avoid stack overflows --- src/display-buffer.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index db39eb432..f4c078b17 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -1120,7 +1120,7 @@ class DisplayBuffer extends Model {screenLines, regions} = @buildScreenLines(startBufferRow, endBufferRow + bufferDelta) screenDelta = screenLines.length - (endScreenRow - startScreenRow) - @screenLines[startScreenRow...endScreenRow] = screenLines + _.spliceWithArray(@screenLines, startScreenRow, endScreenRow - startScreenRow, screenLines, 10000) @rowMap.spliceRegions(startBufferRow, endBufferRow - startBufferRow, regions) @findMaxLineLength(startScreenRow, endScreenRow, screenLines, screenDelta) From c9046a6cfae6e401da39a324d1c2da2578f016a3 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Fri, 8 May 2015 11:16:19 -0700 Subject: [PATCH 1033/1783] Add error message to Jasmine output --- spec/spec-helper.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/spec-helper.coffee b/spec/spec-helper.coffee index 0112042e2..e21876e8d 100644 --- a/spec/spec-helper.coffee +++ b/spec/spec-helper.coffee @@ -311,7 +311,7 @@ window.waitsForPromise = (args...) -> else promise.then(moveOn) promise.catch.call promise, (error) -> - jasmine.getEnv().currentSpec.fail("Expected promise to be resolved, but it was rejected with #{jasmine.pp(error)}") + jasmine.getEnv().currentSpec.fail("Expected promise to be resolved, but it was rejected with: #{error?.message} #{jasmine.pp(error)}") moveOn() window.resetTimeouts = -> From b8cd0a06283f1bac3b2c51b667f6df3d5ae2b37f Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 8 May 2015 11:19:51 -0700 Subject: [PATCH 1034/1783] Don't persist dev/safe/api-preview mode settings of windows --- src/browser/atom-application.coffee | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 6f7f0ac4b..46af91ed0 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -424,12 +424,7 @@ class AtomApplication for window in @windows if loadSettings = window.getLoadSettings() unless loadSettings.isSpec - states.push(_.pick(loadSettings, - 'initialPaths' - 'devMode' - 'safeMode' - 'apiPreviewMode' - )) + states.push(initialPaths: loadSettings.initialPaths) @storageFolder.store('application.json', states) loadState: -> @@ -438,9 +433,9 @@ class AtomApplication @openWithOptions({ pathsToOpen: state.initialPaths urlsToOpen: [] - devMode: state.devMode - safeMode: state.safeMode - apiPreviewMode: state.apiPreviewMode + devMode: @devMode + safeMode: @safeMode + apiPreviewMode: @apiPreviewMode }) true else From 01221bd4ad248c92818339c02be43def354a0333 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Fri, 8 May 2015 11:32:20 -0700 Subject: [PATCH 1035/1783] Normalize bundled package data Warn if contains incomplete package.json data --- build/tasks/compile-packages-slug-task.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build/tasks/compile-packages-slug-task.coffee b/build/tasks/compile-packages-slug-task.coffee index a56ed6e18..cf0861462 100644 --- a/build/tasks/compile-packages-slug-task.coffee +++ b/build/tasks/compile-packages-slug-task.coffee @@ -2,6 +2,7 @@ path = require 'path' CSON = require 'season' fs = require 'fs-plus' _ = require 'underscore-plus' +normalizePackageData = require 'normalize-package-data' OtherPlatforms = ['darwin', 'freebsd', 'linux', 'sunos', 'win32'].filter (platform) -> platform isnt process.platform @@ -40,6 +41,8 @@ module.exports = (grunt) -> metadata = grunt.file.readJSON(metadataPath) continue unless metadata?.engines?.atom? + normalizePackageData metadata, (msg) -> console.error(metadata.name, msg) + moduleCache = metadata._atomModuleCache ? {} rm metadataPath From 8f80e1db13ecf6b5c945d92ece3a8805dece88da Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Fri, 8 May 2015 12:24:43 -0700 Subject: [PATCH 1036/1783] Only normalize unpublished packages Packages published to APM are normalized already, this catches locally linked/developed packages. --- src/package.coffee | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/package.coffee b/src/package.coffee index 8c67af2d9..664060457 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -1,5 +1,5 @@ path = require 'path' -normalizePackageData = require 'normalize-package-data' +normalizePackageData = null _ = require 'underscore-plus' async = require 'async' @@ -25,6 +25,11 @@ class Package @resourcePathWithTrailingSlash ?= "#{atom.packages.resourcePath}#{path.sep}" packagePath?.startsWith(@resourcePathWithTrailingSlash) + @normalizeMetadata: (metadata) -> + unless metadata?._id + normalizePackageData ?= require 'normalize-package-data' + normalizePackageData(metadata) + @loadMetadata: (packagePath, ignoreErrors=false) -> packageName = path.basename(packagePath) if @isBundledPackagePath(packagePath) @@ -33,7 +38,7 @@ class Package if metadataPath = CSON.resolve(path.join(packagePath, 'package')) try metadata = CSON.readFileSync(metadataPath) - normalizePackageData(metadata) + @normalizeMetadata(metadata) catch error throw error unless ignoreErrors From 78307d5b9d1b6dc441c8c6254d8703010d5cdcd5 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Fri, 8 May 2015 12:26:26 -0700 Subject: [PATCH 1037/1783] Fail when bundled packages have bad metadata --- build/tasks/compile-packages-slug-task.coffee | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/build/tasks/compile-packages-slug-task.coffee b/build/tasks/compile-packages-slug-task.coffee index cf0861462..102c97053 100644 --- a/build/tasks/compile-packages-slug-task.coffee +++ b/build/tasks/compile-packages-slug-task.coffee @@ -33,6 +33,7 @@ module.exports = (grunt) -> modulesDirectory = path.join(appDir, 'node_modules') packages = {} + invalidPackages = false for moduleDirectory in fs.listSync(modulesDirectory) continue if path.basename(moduleDirectory) is '.bin' @@ -41,7 +42,10 @@ module.exports = (grunt) -> metadata = grunt.file.readJSON(metadataPath) continue unless metadata?.engines?.atom? - normalizePackageData metadata, (msg) -> console.error(metadata.name, msg) + reportPackageError = (msg) -> + invalidPackages = true + grunt.log.error("#{metadata.name}: #{msg}") + normalizePackageData metadata, reportPackageError, true moduleCache = metadata._atomModuleCache ? {} @@ -82,3 +86,4 @@ module.exports = (grunt) -> metadata._atomKeymaps = getKeymaps(appDir) grunt.file.write(path.join(appDir, 'package.json'), JSON.stringify(metadata)) + not invalidPackages From 9a85164090dd84515e4034c0da8560fce5cf48f4 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 8 May 2015 13:04:42 -0700 Subject: [PATCH 1038/1783] Add spec for file path with trailing colon/whitespace --- spec/integration/startup-spec.coffee | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/spec/integration/startup-spec.coffee b/spec/integration/startup-spec.coffee index 828193e4d..e0e0e32d1 100644 --- a/spec/integration/startup-spec.coffee +++ b/spec/integration/startup-spec.coffee @@ -41,6 +41,22 @@ describe "Starting Atom", -> .then ({value}) -> expect(value).toBe "Hello!" .dispatchCommand("editor:delete-line") + it "removes all trailing whitespace and colons from the specified path", -> + runAtom [path.join(tempDirPath, "new-file: ")], {ATOM_HOME: atomHome}, (client) -> + client + .waitForWindowCount(1, 1000) + .waitForExist("atom-workspace", 5000) + .waitForPaneItemCount(1, 1000) + + .treeViewRootDirectories() + .then ({value}) -> expect(value).toEqual([tempDirPath]) + + .waitForExist("atom-text-editor", 5000) + .then (exists) -> expect(exists).toBe true + .click("atom-text-editor") + .execute -> atom.workspace.getActiveTextEditor().getPath() + .then ({value}) -> expect(value).toBe path.join(tempDirPath, "new-file") + describe "when there is already a window open", -> it "reuses that window when opening files, but not when opening directories", -> tempFilePath = path.join(temp.mkdirSync("a-third-dir"), "a-file") From 1e567b62e2ca22e4963df237d74b2ab56f679776 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 8 May 2015 13:23:28 -0700 Subject: [PATCH 1039/1783] Add spec for opening file to line number --- spec/integration/startup-spec.coffee | 42 +++++++++++++++++++++------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/spec/integration/startup-spec.coffee b/spec/integration/startup-spec.coffee index e0e0e32d1..94a489021 100644 --- a/spec/integration/startup-spec.coffee +++ b/spec/integration/startup-spec.coffee @@ -1,10 +1,10 @@ # These tests are excluded by default. To run them from the command line: # # ATOM_INTEGRATION_TESTS_ENABLED=true apm test -return unless process.env.ATOM_INTEGRATION_TESTS_ENABLED +# return unless process.env.ATOM_INTEGRATION_TESTS_ENABLED # Integration tests require a fast machine and, for now, we cannot afford to # run them on Travis. -return if process.env.TRAVIS +# return if process.env.TRAVIS fs = require "fs" path = require "path" @@ -41,21 +41,43 @@ describe "Starting Atom", -> .then ({value}) -> expect(value).toBe "Hello!" .dispatchCommand("editor:delete-line") - it "removes all trailing whitespace and colons from the specified path", -> - runAtom [path.join(tempDirPath, "new-file: ")], {ATOM_HOME: atomHome}, (client) -> + it "opens the parent directory and creates an empty text editor", -> + filePath = path.join(fs.realpathSync(tempDirPath), "new-file") + fs.writeFileSync filePath, """ + 1 + 2 + 3 + 4 + """ + + runAtom ["#{filePath}:3"], {ATOM_HOME: atomHome}, (client) -> client .waitForWindowCount(1, 1000) .waitForExist("atom-workspace", 5000) .waitForPaneItemCount(1, 1000) - - .treeViewRootDirectories() - .then ({value}) -> expect(value).toEqual([tempDirPath]) - .waitForExist("atom-text-editor", 5000) .then (exists) -> expect(exists).toBe true - .click("atom-text-editor") + .execute -> atom.workspace.getActiveTextEditor().getPath() - .then ({value}) -> expect(value).toBe path.join(tempDirPath, "new-file") + .then ({value}) -> expect(value).toBe filePath + + .execute -> atom.workspace.getActiveTextEditor().getCursorBufferPosition() + .then ({value}) -> + expect(value.row).toBe 2 + expect(value.column).toBe 0 + + it "removes all trailing whitespace and colons from the specified path", -> + filePath = path.join(tempDirPath, "new-file") + runAtom ["#{filePath}: "], {ATOM_HOME: atomHome}, (client) -> + client + .waitForWindowCount(1, 1000) + .waitForExist("atom-workspace", 5000) + .waitForPaneItemCount(1, 1000) + .waitForExist("atom-text-editor", 5000) + .then (exists) -> expect(exists).toBe true + + .execute -> atom.workspace.getActiveTextEditor().getPath() + .then ({value}) -> expect(value).toBe filePath describe "when there is already a window open", -> it "reuses that window when opening files, but not when opening directories", -> From 75ac785e77647ca64b40eb78743a8681209f924d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 8 May 2015 13:24:48 -0700 Subject: [PATCH 1040/1783] Add spec for opening to line and column --- spec/integration/startup-spec.coffee | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/spec/integration/startup-spec.coffee b/spec/integration/startup-spec.coffee index 94a489021..c2730eaa5 100644 --- a/spec/integration/startup-spec.coffee +++ b/spec/integration/startup-spec.coffee @@ -41,7 +41,7 @@ describe "Starting Atom", -> .then ({value}) -> expect(value).toBe "Hello!" .dispatchCommand("editor:delete-line") - it "opens the parent directory and creates an empty text editor", -> + it "opens the file to the specified line number", -> filePath = path.join(fs.realpathSync(tempDirPath), "new-file") fs.writeFileSync filePath, """ 1 @@ -66,6 +66,31 @@ describe "Starting Atom", -> expect(value.row).toBe 2 expect(value.column).toBe 0 + it "opens the file to the specified line number and column number", -> + filePath = path.join(fs.realpathSync(tempDirPath), "new-file") + fs.writeFileSync filePath, """ + 1 + 2 + 3 + 4 + """ + + runAtom ["#{filePath}:2:2"], {ATOM_HOME: atomHome}, (client) -> + client + .waitForWindowCount(1, 1000) + .waitForExist("atom-workspace", 5000) + .waitForPaneItemCount(1, 1000) + .waitForExist("atom-text-editor", 5000) + .then (exists) -> expect(exists).toBe true + + .execute -> atom.workspace.getActiveTextEditor().getPath() + .then ({value}) -> expect(value).toBe filePath + + .execute -> atom.workspace.getActiveTextEditor().getCursorBufferPosition() + .then ({value}) -> + expect(value.row).toBe 1 + expect(value.column).toBe 1 + it "removes all trailing whitespace and colons from the specified path", -> filePath = path.join(tempDirPath, "new-file") runAtom ["#{filePath}: "], {ATOM_HOME: atomHome}, (client) -> From 02d1e0be563db5d8889b4b754270e1fbf7d24ba9 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 8 May 2015 13:25:54 -0700 Subject: [PATCH 1041/1783] Uncomment env conditionals --- spec/integration/startup-spec.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/integration/startup-spec.coffee b/spec/integration/startup-spec.coffee index c2730eaa5..f1c76c04e 100644 --- a/spec/integration/startup-spec.coffee +++ b/spec/integration/startup-spec.coffee @@ -1,10 +1,10 @@ # These tests are excluded by default. To run them from the command line: # # ATOM_INTEGRATION_TESTS_ENABLED=true apm test -# return unless process.env.ATOM_INTEGRATION_TESTS_ENABLED +return unless process.env.ATOM_INTEGRATION_TESTS_ENABLED # Integration tests require a fast machine and, for now, we cannot afford to # run them on Travis. -# return if process.env.TRAVIS +return if process.env.TRAVIS fs = require "fs" path = require "path" From 2c23d6f3ab976042f67ed57a47c975b859c7bdcd Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 8 May 2015 13:33:30 -0700 Subject: [PATCH 1042/1783] :art: --- spec/integration/startup-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/integration/startup-spec.coffee b/spec/integration/startup-spec.coffee index f1c76c04e..54817fedc 100644 --- a/spec/integration/startup-spec.coffee +++ b/spec/integration/startup-spec.coffee @@ -9,7 +9,7 @@ return if process.env.TRAVIS fs = require "fs" path = require "path" temp = require("temp").track() -runAtom = require("./helpers/start-atom") +runAtom = require "./helpers/start-atom" describe "Starting Atom", -> [tempDirPath, otherTempDirPath, atomHome] = [] From 29a4ab139671e3c4996f260e83f2e851d7d11c72 Mon Sep 17 00:00:00 2001 From: Ivan Zuzak Date: Sun, 10 May 2015 09:26:46 +0200 Subject: [PATCH 1043/1783] Electron uses 'Plus' instead of '+' in accelerators --- src/browser/application-menu.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/browser/application-menu.coffee b/src/browser/application-menu.coffee index d88314c89..793d6347f 100644 --- a/src/browser/application-menu.coffee +++ b/src/browser/application-menu.coffee @@ -163,7 +163,7 @@ class ApplicationMenu return null unless firstKeystroke modifiers = firstKeystroke.split('-') - key = modifiers.pop() + key = modifiers.pop().toUpperCase().replace('+', 'Plus') modifiers = modifiers.map (modifier) -> modifier.replace(/shift/ig, "Shift") @@ -171,5 +171,5 @@ class ApplicationMenu .replace(/ctrl/ig, "Ctrl") .replace(/alt/ig, "Alt") - keys = modifiers.concat([key.toUpperCase()]) + keys = modifiers.concat([key]) keys.join("+") From 71fba995405e2940a0ef53f9c4e8169a6c64acb0 Mon Sep 17 00:00:00 2001 From: Ivan Zuzak Date: Sun, 10 May 2015 09:46:45 +0200 Subject: [PATCH 1044/1783] Dont split keystrokes on trailing dashes --- src/browser/application-menu.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/browser/application-menu.coffee b/src/browser/application-menu.coffee index 793d6347f..a845c682f 100644 --- a/src/browser/application-menu.coffee +++ b/src/browser/application-menu.coffee @@ -162,7 +162,7 @@ class ApplicationMenu firstKeystroke = keystrokesByCommand[command]?[0] return null unless firstKeystroke - modifiers = firstKeystroke.split('-') + modifiers = firstKeystroke.split(/-(?=.)/) key = modifiers.pop().toUpperCase().replace('+', 'Plus') modifiers = modifiers.map (modifier) -> From a6e0fa6e9142d71fc5cd9c5ab79ff546d5a107f1 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 11 May 2015 09:42:04 +0200 Subject: [PATCH 1045/1783] Scroll exactly as we did before tiling Except that now we store the scrolling tile, instead of the scrolling row. --- src/text-editor-component.coffee | 8 +++++--- src/text-editor-presenter.coffee | 2 +- src/tile-component.coffee | 5 +---- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 71ca96d87..8c497bd98 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -354,6 +354,7 @@ class TextEditorComponent event.preventDefault() unless previousScrollLeft is @presenter.getScrollLeft() else # Scrolling vertically + @presenter.setScrollingTileId(@tileIdForNode(event.target)) previousScrollTop = @presenter.getScrollTop() @presenter.setScrollTop(previousScrollTop - Math.round(wheelDeltaY * @scrollSensitivity)) event.preventDefault() unless previousScrollTop is @presenter.getScrollTop() @@ -728,11 +729,12 @@ class TextEditorComponent lineNumberNodeForScreenRow: (screenRow) -> @gutterContainerComponent.getLineNumberGutterComponent().lineNumberNodeForScreenRow(screenRow) - screenRowForNode: (node) -> + tileIdForNode: (node) -> while node? - if screenRow = node.dataset.screenRow - return parseInt(screenRow) + if tileId = node.dataset.tileId + return tileId node = node.parentElement + null getFontSize: -> diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 59ff21afe..12044bff0 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -905,7 +905,7 @@ class TextEditorPresenter @emitDidUpdateState() - setScrollingTile: (tileId) -> + setScrollingTileId: (tileId) -> if @scrollingTile isnt tileId @scrollingTile = tileId @didStartScrolling() diff --git a/src/tile-component.coffee b/src/tile-component.coffee index 0f366dbdc..5bd299d79 100644 --- a/src/tile-component.coffee +++ b/src/tile-component.coffee @@ -21,14 +21,11 @@ class TileComponent @screenRowsByLineId = {} @lineIdsByScreenRow = {} @domNode ?= document.createElement("div") - @domNode.addEventListener("mousewheel", @onMouseWheel) + @domNode.dataset.tileId = @id @domNode.style.position = "absolute" @domNode.style.display = "block" @domNode.classList.add("tile") - onMouseWheel: => - @presenter.setScrollingTile(@id) - getDomNode: -> @domNode From 8aaac870dcb94696cbc8174a1d92a311e07cefa3 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 11 May 2015 09:45:55 +0200 Subject: [PATCH 1046/1783] Ensure we have at least one line per tile This will prevent, for example, a mini editor (which has no `@height` by default) from not showing characters. --- src/text-editor-presenter.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 12044bff0..0111c7a8a 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -306,6 +306,7 @@ class TextEditorPresenter return unless @startRow? and @endRow? and @lineHeight? linesPerTile = Math.floor(@height / @lineHeight / @tileCount) + linesPerTile = Math.max(1, linesPerTile) startIndex = Math.max( 0, Math.floor(@startRow / linesPerTile) - @tileOverdrawMargin From a6dab4860c7ced496f9fd4c5ffc6e3c448c5f8ff Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 11 May 2015 10:01:02 +0200 Subject: [PATCH 1047/1783] Position overlays absolutely We did so by introducing an `absolute` (optional) parameter in `pixelPositionForScreenPosition`. --- src/text-editor-presenter.coffee | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 0111c7a8a..e9944afce 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -375,7 +375,7 @@ class TextEditorPresenter else screenPosition = decoration.getMarker().getHeadScreenPosition() - pixelPosition = @pixelPositionForScreenPosition(screenPosition) + pixelPosition = @pixelPositionForScreenPosition(screenPosition, true, absolute: true) {scrollTop, scrollLeft} = @state.content @@ -963,7 +963,7 @@ class TextEditorPresenter hasPixelPositionRequirements: -> @lineHeight? and @baseCharacterWidth? - pixelPositionForScreenPosition: (screenPosition, clip=true) -> + pixelPositionForScreenPosition: (screenPosition, clip=true, {absolute}={}) -> screenPosition = Point.fromObject(screenPosition) screenPosition = @model.clipScreenPosition(screenPosition) if clip @@ -993,7 +993,8 @@ class TextEditorPresenter left += characterWidths[char] ? baseCharacterWidth unless char is '\0' column += charLength - {top: top - @scrollTop, left} + top -= @scrollTop unless absolute + {top, left} hasPixelRectRequirements: -> @hasPixelPositionRequirements() and @scrollWidth? From a64ceadad46ee569dec0df6ed30b64228aabffbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Machist=C3=A9=20N=2E=20Quintana?= Date: Mon, 11 May 2015 07:14:31 -0400 Subject: [PATCH 1048/1783] Use /usr/bin/env bash in hashbang From https://github.com/atom/apm/issues/282#issuecomment-100289741 --- atom.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom.sh b/atom.sh index ecd7da052..236f49ff6 100755 --- a/atom.sh +++ b/atom.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash if [ "$(uname)" == 'Darwin' ]; then OS='Mac' From 9c5f9c5be9eb78fcc521b948bbf8eb3f9f77bff6 Mon Sep 17 00:00:00 2001 From: Jan Niklas Hasse Date: Mon, 11 May 2015 15:18:30 +0200 Subject: [PATCH 1049/1783] Use dirname of $0 --- resources/win/atom.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/win/atom.sh b/resources/win/atom.sh index 96370bee5..8f312a2da 100644 --- a/resources/win/atom.sh +++ b/resources/win/atom.sh @@ -16,7 +16,7 @@ while getopts ":fhtvw-:" opt; do done if [ $EXPECT_OUTPUT ]; then - "$0/../../../atom.exe" "$@" + "$(dirname $0)/../../atom.exe" "$@" else - "$0/../../app/apm/bin/node.exe" "$0/../atom.js" "$@" + "$(dirname $0)/../app/apm/bin/node.exe" "$0/../atom.js" "$@" fi From 80c24f240a1ca9dce9814b04d6e7541f8abb2d5a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 11 May 2015 08:44:04 -0700 Subject: [PATCH 1050/1783] Run package specs in API preview mode --- build/tasks/spec-task.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/tasks/spec-task.coffee b/build/tasks/spec-task.coffee index 2367c9a5f..02ee09878 100644 --- a/build/tasks/spec-task.coffee +++ b/build/tasks/spec-task.coffee @@ -54,14 +54,14 @@ module.exports = (grunt) -> if process.platform in ['darwin', 'linux'] options = cmd: appPath - args: ['--test', "--resource-path=#{resourcePath}", "--spec-directory=#{path.join(packagePath, 'spec')}"] + args: ['--one', '--test', "--resource-path=#{resourcePath}", "--spec-directory=#{path.join(packagePath, 'spec')}"] opts: cwd: packagePath env: _.extend({}, process.env, ATOM_PATH: rootDir) else if process.platform is 'win32' options = cmd: process.env.comspec - args: ['/c', appPath, '--test', "--resource-path=#{resourcePath}", "--spec-directory=#{path.join(packagePath, 'spec')}", "--log-file=ci.log"] + args: ['/c', appPath, '--one', '--test', "--resource-path=#{resourcePath}", "--spec-directory=#{path.join(packagePath, 'spec')}", "--log-file=ci.log"] opts: cwd: packagePath env: _.extend({}, process.env, ATOM_PATH: rootDir) From d46b7c6a369185c1050c320f4093096f51fca77c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 11 May 2015 08:49:56 -0700 Subject: [PATCH 1051/1783] :arrow_up: language-todo@0.20 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 144981d45..512d16ca5 100644 --- a/package.json +++ b/package.json @@ -152,7 +152,7 @@ "language-source": "0.9.0", "language-sql": "0.15.0", "language-text": "0.6.0", - "language-todo": "0.19.0", + "language-todo": "0.20.0", "language-toml": "0.15.0", "language-xml": "0.28.0", "language-yaml": "0.22.0" From ab3be668347709b07c54ec8f6f45fc9feff42a7e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 11 May 2015 08:58:04 -0700 Subject: [PATCH 1052/1783] Remove --one flag from package spec command --- build/tasks/spec-task.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/tasks/spec-task.coffee b/build/tasks/spec-task.coffee index 02ee09878..2367c9a5f 100644 --- a/build/tasks/spec-task.coffee +++ b/build/tasks/spec-task.coffee @@ -54,14 +54,14 @@ module.exports = (grunt) -> if process.platform in ['darwin', 'linux'] options = cmd: appPath - args: ['--one', '--test', "--resource-path=#{resourcePath}", "--spec-directory=#{path.join(packagePath, 'spec')}"] + args: ['--test', "--resource-path=#{resourcePath}", "--spec-directory=#{path.join(packagePath, 'spec')}"] opts: cwd: packagePath env: _.extend({}, process.env, ATOM_PATH: rootDir) else if process.platform is 'win32' options = cmd: process.env.comspec - args: ['/c', appPath, '--one', '--test', "--resource-path=#{resourcePath}", "--spec-directory=#{path.join(packagePath, 'spec')}", "--log-file=ci.log"] + args: ['/c', appPath, '--test', "--resource-path=#{resourcePath}", "--spec-directory=#{path.join(packagePath, 'spec')}", "--log-file=ci.log"] opts: cwd: packagePath env: _.extend({}, process.env, ATOM_PATH: rootDir) From d7021fedce99882402aee5b9e887adf2697c4b64 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 11 May 2015 09:02:16 -0700 Subject: [PATCH 1053/1783] :arrow_up: language-go@0.26 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 512d16ca5..f4dd352f7 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,7 @@ "language-css": "0.29.0", "language-gfm": "0.72.0", "language-git": "0.10.0", - "language-go": "0.25.0", + "language-go": "0.26.0", "language-html": "0.37.0", "language-hyperlink": "0.13.0", "language-java": "0.15.0", From 6d833b53a164674b43e62b391903050dc13faf72 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 11 May 2015 09:15:37 -0700 Subject: [PATCH 1054/1783] :arrow_up: status-bar@0.70 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f4dd352f7..5babfcdc4 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "settings-view": "0.198.0", "snippets": "0.89.0", "spell-check": "0.56.0", - "status-bar": "0.69.0", + "status-bar": "0.70.0", "styleguide": "0.44.0", "symbols-view": "0.96.0", "tabs": "0.68.0", From c68af1b6d494f4c4f7349a5ace4308c9531aff8b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 11 May 2015 09:19:53 -0700 Subject: [PATCH 1055/1783] :arrow_up: status-bar@0.71 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5babfcdc4..748de2f3e 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "settings-view": "0.198.0", "snippets": "0.89.0", "spell-check": "0.56.0", - "status-bar": "0.70.0", + "status-bar": "0.71.0", "styleguide": "0.44.0", "symbols-view": "0.96.0", "tabs": "0.68.0", From 44723401eb1de00813b6f3d3bdb158e7b9f93f65 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 11 May 2015 09:35:06 -0700 Subject: [PATCH 1056/1783] :arrow_up: language-sass@0.38 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 748de2f3e..66a237bef 100644 --- a/package.json +++ b/package.json @@ -147,7 +147,7 @@ "language-python": "0.34.0", "language-ruby": "0.52.0", "language-ruby-on-rails": "0.21.0", - "language-sass": "0.37.0", + "language-sass": "0.38.0", "language-shellscript": "0.14.0", "language-source": "0.9.0", "language-sql": "0.15.0", From 7f4240bf96667f2ae5067326866d53ea69d209f4 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 11 May 2015 10:18:49 -0700 Subject: [PATCH 1057/1783] :arrow_up: wrap-guide@0.33 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 66a237bef..553ce9576 100644 --- a/package.json +++ b/package.json @@ -123,7 +123,7 @@ "update-package-dependencies": "0.9.0", "welcome": "0.27.0", "whitespace": "0.29.0", - "wrap-guide": "0.32.0", + "wrap-guide": "0.33.0", "language-c": "0.44.0", "language-clojure": "0.14.0", "language-coffee-script": "0.40.0", From d7c4986d2491b0f470d505c59e21ffe9f6452fe9 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 11 May 2015 11:19:20 -0700 Subject: [PATCH 1058/1783] :arrow_up: deprecation-cop@0.44 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 553ce9576..a3eb53322 100644 --- a/package.json +++ b/package.json @@ -91,7 +91,7 @@ "bookmarks": "0.35.0", "bracket-matcher": "0.74.0", "command-palette": "0.35.0", - "deprecation-cop": "0.43.0", + "deprecation-cop": "0.44.0", "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", From 6b7a6538f2ef9954b19815094a2a68fb35dcce0d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 11 May 2015 11:19:43 -0700 Subject: [PATCH 1059/1783] :arrow_up: deprecation-cop@0.45 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a3eb53322..efde6d87b 100644 --- a/package.json +++ b/package.json @@ -91,7 +91,7 @@ "bookmarks": "0.35.0", "bracket-matcher": "0.74.0", "command-palette": "0.35.0", - "deprecation-cop": "0.44.0", + "deprecation-cop": "0.45.0", "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", From 34b10c2eb8430f9bc66e98c82072cf7441e9f548 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 11 May 2015 11:27:10 -0700 Subject: [PATCH 1060/1783] :arrow_up: language-perl@0.24 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index efde6d87b..8b5d82b59 100644 --- a/package.json +++ b/package.json @@ -141,7 +141,7 @@ "language-make": "0.14.0", "language-mustache": "0.11.0", "language-objective-c": "0.15.0", - "language-perl": "0.23.0", + "language-perl": "0.24.0", "language-php": "0.22.0", "language-property-list": "0.8.0", "language-python": "0.34.0", From cbf32acd471b5041286d7c32aa0a6abc5d01bb60 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 11 May 2015 14:43:53 -0700 Subject: [PATCH 1061/1783] Don't pack spellchecker into asar archive --- build/tasks/generate-asar-task.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/build/tasks/generate-asar-task.coffee b/build/tasks/generate-asar-task.coffee index a71d88dfe..3de5f73b6 100644 --- a/build/tasks/generate-asar-task.coffee +++ b/build/tasks/generate-asar-task.coffee @@ -14,6 +14,7 @@ module.exports = (grunt) -> 'ctags-darwin' 'ctags-linux' 'ctags-win32.exe' + '**/node_modules/spellchecker/**' ] unpack = "{#{unpack.join(',')}}" From f0ee01964983757b4024549235795ef6e86335e1 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Mon, 11 May 2015 15:02:54 -0700 Subject: [PATCH 1062/1783] :bump_up: language-toml@0.16.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8b5d82b59..d876683f2 100644 --- a/package.json +++ b/package.json @@ -153,7 +153,7 @@ "language-sql": "0.15.0", "language-text": "0.6.0", "language-todo": "0.20.0", - "language-toml": "0.15.0", + "language-toml": "0.16.0", "language-xml": "0.28.0", "language-yaml": "0.22.0" }, From 24d08c0c3ce8f92e1b550fd10d717d4be4784c5f Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Mon, 11 May 2015 15:06:32 -0700 Subject: [PATCH 1063/1783] :bump_up: spell-check@0.57.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d876683f2..ed8a224f3 100644 --- a/package.json +++ b/package.json @@ -113,7 +113,7 @@ "release-notes": "0.52.0", "settings-view": "0.198.0", "snippets": "0.89.0", - "spell-check": "0.56.0", + "spell-check": "0.57.0", "status-bar": "0.71.0", "styleguide": "0.44.0", "symbols-view": "0.96.0", From c856aea60b86ee1eacb05d31a712ee0cc43f8e53 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Mon, 11 May 2015 15:29:01 -0700 Subject: [PATCH 1064/1783] :arrow_up: archive-view@0.57.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ed8a224f3..de826e197 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ "one-light-ui": "0.8.1", "solarized-dark-syntax": "0.35.0", "solarized-light-syntax": "0.21.0", - "archive-view": "0.56.0", + "archive-view": "0.57.0", "autocomplete": "0.46.0", "autoflow": "0.22.0", "autosave": "0.20.0", From 9377bf59e097733e8c1e9ca0343ee9c857f02013 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Mon, 11 May 2015 15:30:40 -0700 Subject: [PATCH 1065/1783] :arrow_up: autocomplete@0.47.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index de826e197..74de2bd21 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ "solarized-dark-syntax": "0.35.0", "solarized-light-syntax": "0.21.0", "archive-view": "0.57.0", - "autocomplete": "0.46.0", + "autocomplete": "0.47.0", "autoflow": "0.22.0", "autosave": "0.20.0", "background-tips": "0.24.0", From 8e8ebbe898b358b33ee3d538fb57a1630a41a531 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Mon, 11 May 2015 15:31:51 -0700 Subject: [PATCH 1066/1783] :arrow_up: autoflow@0.23.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 74de2bd21..b56bed38b 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ "solarized-light-syntax": "0.21.0", "archive-view": "0.57.0", "autocomplete": "0.47.0", - "autoflow": "0.22.0", + "autoflow": "0.23.0", "autosave": "0.20.0", "background-tips": "0.24.0", "bookmarks": "0.35.0", From 88995fe7b093bb70e4a758b6e8f92516dfd15ec6 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Mon, 11 May 2015 15:32:58 -0700 Subject: [PATCH 1067/1783] :bump_up: language-gfm@0.73.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b56bed38b..fab691218 100644 --- a/package.json +++ b/package.json @@ -129,7 +129,7 @@ "language-coffee-script": "0.40.0", "language-csharp": "0.5.0", "language-css": "0.29.0", - "language-gfm": "0.72.0", + "language-gfm": "0.73.0", "language-git": "0.10.0", "language-go": "0.26.0", "language-html": "0.37.0", From 3e73eadb6c88527b785d789673236d37ecc9d5a4 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Mon, 11 May 2015 16:08:44 -0700 Subject: [PATCH 1068/1783] Correct semver by adding 3rd digit --- .../package-with-incompatible-native-module/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/fixtures/packages/package-with-incompatible-native-module/package.json b/spec/fixtures/packages/package-with-incompatible-native-module/package.json index eec67175a..857bc7221 100644 --- a/spec/fixtures/packages/package-with-incompatible-native-module/package.json +++ b/spec/fixtures/packages/package-with-incompatible-native-module/package.json @@ -1,5 +1,5 @@ { "name": "package-with-incompatible-native-module", - "version": "1.0", + "version": "1.0.0", "main": "./main.js" } From 9b767528278ad769996afcd323a5b93f637789c6 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 11 May 2015 17:18:07 -0700 Subject: [PATCH 1069/1783] :arrow_up: spell-check@0.57 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8b5d82b59..ecaa97285 100644 --- a/package.json +++ b/package.json @@ -113,7 +113,7 @@ "release-notes": "0.52.0", "settings-view": "0.198.0", "snippets": "0.89.0", - "spell-check": "0.56.0", + "spell-check": "0.57.0", "status-bar": "0.71.0", "styleguide": "0.44.0", "symbols-view": "0.96.0", From fa4312d37ccbde7482a24a97cc69fd31617adb9b Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Mon, 11 May 2015 18:03:21 -0700 Subject: [PATCH 1070/1783] :arrow_up: grammar-selector@0.47.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fab691218..ddc175b71 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,7 @@ "fuzzy-finder": "0.83.0", "git-diff": "0.55.0", "go-to-line": "0.30.0", - "grammar-selector": "0.46.0", + "grammar-selector": "0.47.0", "image-view": "0.54.0", "incompatible-packages": "0.24.0", "keybinding-resolver": "0.32.0", From 250670be23b589c01bec26fc1eff79ee1c0ba23d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 11 May 2015 17:58:46 -0700 Subject: [PATCH 1071/1783] Guard against missing tooltip data --- src/tooltip-manager.coffee | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tooltip-manager.coffee b/src/tooltip-manager.coffee index afde69db9..ee2054b5a 100644 --- a/src/tooltip-manager.coffee +++ b/src/tooltip-manager.coffee @@ -87,8 +87,9 @@ class TooltipManager new Disposable -> tooltip = $target.data('bs.tooltip') - tooltip.leave(currentTarget: target) - tooltip.hide() + if tooltip? + tooltip.leave(currentTarget: target) + tooltip.hide() $target.tooltip('destroy') humanizeKeystrokes = (keystroke) -> From 209ed2fe13ef49a4f7ab4fef815b8a6bb725c4fc Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 11 May 2015 18:17:37 -0700 Subject: [PATCH 1072/1783] Stop shipping the feedback package --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index ddc175b71..361f98eed 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,6 @@ "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", - "feedback": "0.38.0", "find-and-replace": "0.161.0", "fuzzy-finder": "0.83.0", "git-diff": "0.55.0", From ccc6b170896d525a357fe2742fca9d698b94dd3f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 11 May 2015 18:19:46 -0700 Subject: [PATCH 1073/1783] :arrow_up: spell-check@0.58 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 361f98eed..26ed4da96 100644 --- a/package.json +++ b/package.json @@ -112,7 +112,7 @@ "release-notes": "0.52.0", "settings-view": "0.198.0", "snippets": "0.89.0", - "spell-check": "0.57.0", + "spell-check": "0.58.0", "status-bar": "0.71.0", "styleguide": "0.44.0", "symbols-view": "0.96.0", From b2dd8835b3359148d980ef208a02d86ba92a9cce Mon Sep 17 00:00:00 2001 From: Ivan Zuzak Date: Tue, 12 May 2015 12:54:15 +0200 Subject: [PATCH 1074/1783] Remove extra function wrapper --- src/decoration.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/decoration.coffee b/src/decoration.coffee index ca239421e..bc3a21748 100644 --- a/src/decoration.coffee +++ b/src/decoration.coffee @@ -201,6 +201,6 @@ if Grim.includeDeprecatedAPIs Grim.deprecate 'Use Decoration::getProperties instead' @getProperties() - Decoration::update = -> (newProperties) -> + Decoration::update = (newProperties) -> Grim.deprecate 'Use Decoration::setProperties instead' @setProperties(newProperties) From fbeae41f436a4dbe58ee7a85ac31be4e72a8ae16 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 12 May 2015 08:32:23 -0700 Subject: [PATCH 1075/1783] :arrow_up: deprecation-cop@0.46 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 26ed4da96..42e7edb3e 100644 --- a/package.json +++ b/package.json @@ -91,7 +91,7 @@ "bookmarks": "0.35.0", "bracket-matcher": "0.74.0", "command-palette": "0.35.0", - "deprecation-cop": "0.45.0", + "deprecation-cop": "0.46.0", "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", From bbc212674ade7f93feaf99fd6727c181d37640a0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 12 May 2015 08:37:33 -0700 Subject: [PATCH 1076/1783] :arrow_up: settings-view@0.199 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 42e7edb3e..7ef2568dc 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "open-on-github": "0.36.0", "package-generator": "0.38.0", "release-notes": "0.52.0", - "settings-view": "0.198.0", + "settings-view": "0.199.0", "snippets": "0.89.0", "spell-check": "0.58.0", "status-bar": "0.71.0", From 0fe9de25a6568139056edc321ca0a2426da8d88e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 12 May 2015 08:46:47 -0700 Subject: [PATCH 1077/1783] :arrow_up: package-generator@0.39 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7ef2568dc..4f1c9f0c0 100644 --- a/package.json +++ b/package.json @@ -108,7 +108,7 @@ "metrics": "0.45.0", "notifications": "0.43.0", "open-on-github": "0.36.0", - "package-generator": "0.38.0", + "package-generator": "0.39.0", "release-notes": "0.52.0", "settings-view": "0.199.0", "snippets": "0.89.0", From 9fccb0dc427d1fdfe4d5c2bd82b90c6e3e3012c1 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 12 May 2015 08:47:42 -0700 Subject: [PATCH 1078/1783] Run core package specs in 1.0 API preview mode --- build/tasks/spec-task.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/tasks/spec-task.coffee b/build/tasks/spec-task.coffee index 2367c9a5f..a3c9bbe79 100644 --- a/build/tasks/spec-task.coffee +++ b/build/tasks/spec-task.coffee @@ -54,14 +54,14 @@ module.exports = (grunt) -> if process.platform in ['darwin', 'linux'] options = cmd: appPath - args: ['--test', "--resource-path=#{resourcePath}", "--spec-directory=#{path.join(packagePath, 'spec')}"] + args: ['--test', "--resource-path=#{resourcePath}", "--spec-directory=#{path.join(packagePath, 'spec')}", '--one'] opts: cwd: packagePath env: _.extend({}, process.env, ATOM_PATH: rootDir) else if process.platform is 'win32' options = cmd: process.env.comspec - args: ['/c', appPath, '--test', "--resource-path=#{resourcePath}", "--spec-directory=#{path.join(packagePath, 'spec')}", "--log-file=ci.log"] + args: ['/c', appPath, '--test', "--resource-path=#{resourcePath}", "--spec-directory=#{path.join(packagePath, 'spec')}", "--log-file=ci.log", '--one'] opts: cwd: packagePath env: _.extend({}, process.env, ATOM_PATH: rootDir) From 4b9718f5cf719a847666cd5e6c8480dad1a2d393 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Tue, 12 May 2015 11:54:39 -0700 Subject: [PATCH 1079/1783] Remove 'git+' prefix --- build/tasks/compile-packages-slug-task.coffee | 1 + src/package.coffee | 2 ++ 2 files changed, 3 insertions(+) diff --git a/build/tasks/compile-packages-slug-task.coffee b/build/tasks/compile-packages-slug-task.coffee index 102c97053..0cf7347ec 100644 --- a/build/tasks/compile-packages-slug-task.coffee +++ b/build/tasks/compile-packages-slug-task.coffee @@ -46,6 +46,7 @@ module.exports = (grunt) -> invalidPackages = true grunt.log.error("#{metadata.name}: #{msg}") normalizePackageData metadata, reportPackageError, true + metadata.repository.url ?= metadata.repository.url?.replace(/^git\+/, '') moduleCache = metadata._atomModuleCache ? {} diff --git a/src/package.coffee b/src/package.coffee index 664060457..02749f5a6 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -29,6 +29,8 @@ class Package unless metadata?._id normalizePackageData ?= require 'normalize-package-data' normalizePackageData(metadata) + metadata.repository.url = metadata.repository.url.replace(/^git\+/, '') + metadata @loadMetadata: (packagePath, ignoreErrors=false) -> packageName = path.basename(packagePath) From d7aa2fc2c452a587c84a117a65223b9e02b75d9c Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Tue, 12 May 2015 12:13:14 -0700 Subject: [PATCH 1080/1783] Only remove 'git+' if 'git' type matches --- build/tasks/compile-packages-slug-task.coffee | 3 ++- src/package.coffee | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/build/tasks/compile-packages-slug-task.coffee b/build/tasks/compile-packages-slug-task.coffee index 0cf7347ec..715012db6 100644 --- a/build/tasks/compile-packages-slug-task.coffee +++ b/build/tasks/compile-packages-slug-task.coffee @@ -46,7 +46,8 @@ module.exports = (grunt) -> invalidPackages = true grunt.log.error("#{metadata.name}: #{msg}") normalizePackageData metadata, reportPackageError, true - metadata.repository.url ?= metadata.repository.url?.replace(/^git\+/, '') + if metadata.repository.type is 'git' + metadata.repository.url ?= metadata.repository.url?.replace(/^git\+/, '') moduleCache = metadata._atomModuleCache ? {} diff --git a/src/package.coffee b/src/package.coffee index 02749f5a6..78b19bed6 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -29,7 +29,8 @@ class Package unless metadata?._id normalizePackageData ?= require 'normalize-package-data' normalizePackageData(metadata) - metadata.repository.url = metadata.repository.url.replace(/^git\+/, '') + if metadata.repository.type is 'git' + metadata.repository.url = metadata.repository.url.replace(/^git\+/, '') metadata @loadMetadata: (packagePath, ignoreErrors=false) -> From c9d12bc130e608fc716a67909f059823fab42bf1 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Tue, 12 May 2015 12:33:30 -0700 Subject: [PATCH 1081/1783] Remove `?` --- build/tasks/compile-packages-slug-task.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/tasks/compile-packages-slug-task.coffee b/build/tasks/compile-packages-slug-task.coffee index 715012db6..75b9206c0 100644 --- a/build/tasks/compile-packages-slug-task.coffee +++ b/build/tasks/compile-packages-slug-task.coffee @@ -47,7 +47,7 @@ module.exports = (grunt) -> grunt.log.error("#{metadata.name}: #{msg}") normalizePackageData metadata, reportPackageError, true if metadata.repository.type is 'git' - metadata.repository.url ?= metadata.repository.url?.replace(/^git\+/, '') + metadata.repository.url = metadata.repository.url?.replace(/^git\+/, '') moduleCache = metadata._atomModuleCache ? {} From d03153fab5cf5eab4c42cde02a1c5e7b1554ea12 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Tue, 12 May 2015 12:58:50 -0700 Subject: [PATCH 1082/1783] No spaces in package.json name --- .../package-with-empty-activation-commands/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/fixtures/packages/package-with-empty-activation-commands/package.json b/spec/fixtures/packages/package-with-empty-activation-commands/package.json index 8b58333ab..8102a5af3 100644 --- a/spec/fixtures/packages/package-with-empty-activation-commands/package.json +++ b/spec/fixtures/packages/package-with-empty-activation-commands/package.json @@ -1,5 +1,5 @@ { - "name": "no events", + "name": "noevents", "version": "0.1.0", "activationCommands": {"atom-workspace": []} } From e64c6dfd2f54846edc416e18d3278f20ed5ee9b1 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Tue, 12 May 2015 15:00:40 -0700 Subject: [PATCH 1083/1783] Check for repository, log error (temp) --- src/package.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/package.coffee b/src/package.coffee index 78b19bed6..bf36b9d72 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -29,7 +29,7 @@ class Package unless metadata?._id normalizePackageData ?= require 'normalize-package-data' normalizePackageData(metadata) - if metadata.repository.type is 'git' + if metadata.repository?.type is 'git' metadata.repository.url = metadata.repository.url.replace(/^git\+/, '') metadata @@ -43,6 +43,7 @@ class Package metadata = CSON.readFileSync(metadataPath) @normalizeMetadata(metadata) catch error + console.log("Thew Error", metadata.name, error) throw error unless ignoreErrors metadata ?= {} From e8a20bb6b0a8619c1417d780669d3d107b5cf1f9 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Tue, 12 May 2015 15:15:35 -0700 Subject: [PATCH 1084/1783] Check for repository data --- build/tasks/compile-packages-slug-task.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/tasks/compile-packages-slug-task.coffee b/build/tasks/compile-packages-slug-task.coffee index 75b9206c0..d0ed51fd6 100644 --- a/build/tasks/compile-packages-slug-task.coffee +++ b/build/tasks/compile-packages-slug-task.coffee @@ -46,7 +46,7 @@ module.exports = (grunt) -> invalidPackages = true grunt.log.error("#{metadata.name}: #{msg}") normalizePackageData metadata, reportPackageError, true - if metadata.repository.type is 'git' + if metadata.repository?.type is 'git' metadata.repository.url = metadata.repository.url?.replace(/^git\+/, '') moduleCache = metadata._atomModuleCache ? {} From 8a89054545ab52d67ba82dfea75e37c3ef54ad07 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Tue, 12 May 2015 15:16:15 -0700 Subject: [PATCH 1085/1783] Fixture name to match fixture dir --- .../package-with-empty-activation-commands/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/fixtures/packages/package-with-empty-activation-commands/package.json b/spec/fixtures/packages/package-with-empty-activation-commands/package.json index 8102a5af3..d00fa8404 100644 --- a/spec/fixtures/packages/package-with-empty-activation-commands/package.json +++ b/spec/fixtures/packages/package-with-empty-activation-commands/package.json @@ -1,5 +1,5 @@ { - "name": "noevents", + "name": "package-with-consumed-services", "version": "0.1.0", "activationCommands": {"atom-workspace": []} } From b8c0c661eade13ca0ff179e74b002e837d52c33f Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Tue, 12 May 2015 16:57:50 -0700 Subject: [PATCH 1086/1783] Correct package name, remove log --- .../package-with-empty-activation-commands/package.json | 2 +- src/package.coffee | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/spec/fixtures/packages/package-with-empty-activation-commands/package.json b/spec/fixtures/packages/package-with-empty-activation-commands/package.json index d00fa8404..46741f3e3 100644 --- a/spec/fixtures/packages/package-with-empty-activation-commands/package.json +++ b/spec/fixtures/packages/package-with-empty-activation-commands/package.json @@ -1,5 +1,5 @@ { - "name": "package-with-consumed-services", + "name": "package-with-empty-activation-commands", "version": "0.1.0", "activationCommands": {"atom-workspace": []} } diff --git a/src/package.coffee b/src/package.coffee index bf36b9d72..7578ce66e 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -43,7 +43,6 @@ class Package metadata = CSON.readFileSync(metadataPath) @normalizeMetadata(metadata) catch error - console.log("Thew Error", metadata.name, error) throw error unless ignoreErrors metadata ?= {} From 3dbff720f2b36e7db881ff1e6974ddf0334acba4 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Tue, 12 May 2015 16:59:27 -0700 Subject: [PATCH 1087/1783] Check for url before replacing --- src/package.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package.coffee b/src/package.coffee index 7578ce66e..95f769e49 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -30,7 +30,7 @@ class Package normalizePackageData ?= require 'normalize-package-data' normalizePackageData(metadata) if metadata.repository?.type is 'git' - metadata.repository.url = metadata.repository.url.replace(/^git\+/, '') + metadata.repository.url = metadata.repository.url?.replace(/^git\+/, '') metadata @loadMetadata: (packagePath, ignoreErrors=false) -> From 3081e840304e43d19d1bd815cc38887dc84f9827 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 12 May 2015 17:31:50 -0700 Subject: [PATCH 1088/1783] :arrow_up: apm@0.167 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index 423e31a12..1dce7e90b 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.166.0" + "atom-package-manager": "0.167.0" } } From 6f5e7cdd5c6dfd10e5d8ce740e9587f90c33fd2f Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 12 May 2015 18:02:17 -0700 Subject: [PATCH 1089/1783] :arrow_up: find-and-replace --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4f1c9f0c0..56f8bf7c5 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", - "find-and-replace": "0.161.0", + "find-and-replace": "0.162.0", "fuzzy-finder": "0.83.0", "git-diff": "0.55.0", "go-to-line": "0.30.0", From 34a3ee1be9ed5d35d61a51a4d31524a567558e1e Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 12 May 2015 16:57:02 -0700 Subject: [PATCH 1090/1783] :arrow_up: text-buffer --- package.json | 2 +- spec/text-editor-component-spec.coffee | 6 ++--- src/display-buffer.coffee | 31 +++++--------------------- src/marker.coffee | 12 ---------- 4 files changed, 10 insertions(+), 41 deletions(-) diff --git a/package.json b/package.json index 56f8bf7c5..3c10667d3 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "space-pen": "3.8.2", "stacktrace-parser": "0.1.1", "temp": "0.8.1", - "text-buffer": "^5.2", + "text-buffer": "6.0.0-beta.1", "theorist": "^1.0.2", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6" diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index a89bee1fc..12d189035 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -2266,13 +2266,13 @@ describe "TextEditorComponent", -> editor.setText("") componentNode.dispatchEvent(buildTextInputEvent(data: 'x', target: inputNode)) - currentTime += 99 + currentTime += 100 componentNode.dispatchEvent(buildTextInputEvent(data: 'y', target: inputNode)) - currentTime += 99 + currentTime += 100 componentNode.dispatchEvent(new CustomEvent('editor:duplicate-lines', bubbles: true, cancelable: true)) - currentTime += 100 + currentTime += 101 componentNode.dispatchEvent(new CustomEvent('editor:duplicate-lines', bubbles: true, cancelable: true)) expect(editor.getText()).toBe "xy\nxy\nxy" diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index f4c078b17..bca978cac 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -39,7 +39,6 @@ class DisplayBuffer extends Model @decorationsByMarkerId = {} @disposables.add @tokenizedBuffer.observeGrammar @subscribeToScopedConfigSettings @disposables.add @tokenizedBuffer.onDidChange @handleTokenizedBufferChange - @disposables.add @buffer.onDidUpdateMarkers @handleBufferMarkersUpdated @disposables.add @buffer.onDidCreateMarker @handleBufferMarkerCreated @updateAllScreenLines() @createFoldForMarker(marker) for marker in @buffer.findMarkers(@getFoldMarkerAttributes()) @@ -153,12 +152,12 @@ class DisplayBuffer extends Model @emitter.on 'did-update-markers', callback emitDidChange: (eventProperties, refreshMarkers=true) -> - if refreshMarkers - @pauseMarkerChangeEvents() - @refreshMarkerScreenPositions() @emit 'changed', eventProperties if Grim.includeDeprecatedAPIs @emitter.emit 'did-change', eventProperties - @resumeMarkerChangeEvents() + if refreshMarkers + @refreshMarkerScreenPositions() + @emit 'markers-updated' if Grim.includeDeprecatedAPIs + @emitter.emit 'did-update-markers' updateWrappedScreenLines: -> start = 0 @@ -1078,15 +1077,6 @@ class DisplayBuffer extends Model getFoldMarkerAttributes: (attributes={}) -> _.extend(attributes, class: 'fold', displayBufferId: @id) - pauseMarkerChangeEvents: -> - marker.pauseChangeEvents() for marker in @getMarkers() - return - - resumeMarkerChangeEvents: -> - marker.resumeChangeEvents() for marker in @getMarkers() - @emit 'markers-updated' if Grim.includeDeprecatedAPIs - @emitter.emit 'did-update-markers' - refreshMarkerScreenPositions: -> for marker in @getMarkers() marker.notifyObservers(textChanged: false) @@ -1109,7 +1099,7 @@ class DisplayBuffer extends Model handleTokenizedBufferChange: (tokenizedBufferChange) => {start, end, delta, bufferChange} = tokenizedBufferChange - @updateScreenLines(start, end + 1, delta, delayChangeEvent: bufferChange?) + @updateScreenLines(start, end + 1, delta, refreshMarkers: false) @setScrollTop(Math.min(@getScrollTop(), @getMaxScrollTop())) if delta < 0 updateScreenLines: (startBufferRow, endBufferRow, bufferDelta=0, options={}) -> @@ -1132,11 +1122,7 @@ class DisplayBuffer extends Model screenDelta: screenDelta bufferDelta: bufferDelta - if options.delayChangeEvent - @pauseMarkerChangeEvents() - @pendingChangeEvent = changeEvent - else - @emitDidChange(changeEvent, options.refreshMarkers) + @emitDidChange(changeEvent, options.refreshMarkers) buildScreenLines: (startBufferRow, endBufferRow) -> screenLines = [] @@ -1216,11 +1202,6 @@ class DisplayBuffer extends Model @scrollWidth += 1 unless @isSoftWrapped() @setScrollLeft(Math.min(@getScrollLeft(), @getMaxScrollLeft())) - handleBufferMarkersUpdated: => - if event = @pendingChangeEvent - @pendingChangeEvent = null - @emitDidChange(event, false) - handleBufferMarkerCreated: (textBufferMarker) => @createFoldForMarker(textBufferMarker) if textBufferMarker.matchesParams(@getFoldMarkerAttributes()) if marker = @getMarker(textBufferMarker.id) diff --git a/src/marker.coffee b/src/marker.coffee index 5d1e35570..813ca78e5 100644 --- a/src/marker.coffee +++ b/src/marker.coffee @@ -359,18 +359,6 @@ class Marker @oldTailScreenPosition = newTailScreenPosition @wasValid = isValid - pauseChangeEvents: -> - @deferredChangeEvents = [] - - resumeChangeEvents: -> - if deferredChangeEvents = @deferredChangeEvents - @deferredChangeEvents = null - - for event in deferredChangeEvents - @emit 'changed', event if Grim.includeDeprecatedAPIs - @emitter.emit 'did-change', event - return - getPixelRange: -> @displayBuffer.pixelRangeForScreenRange(@getScreenRange(), false) From e780925b989d81f7eca865b7c66b6301c50641ee Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 12 May 2015 18:03:26 -0700 Subject: [PATCH 1091/1783] :arrow_up: text-buffer --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3c10667d3..75921a02b 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "space-pen": "3.8.2", "stacktrace-parser": "0.1.1", "temp": "0.8.1", - "text-buffer": "6.0.0-beta.1", + "text-buffer": "6.0.0-beta.2", "theorist": "^1.0.2", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6" From 19a95651dcbbba12550be80991b3b9086d89f3d5 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 12 May 2015 09:25:31 +0200 Subject: [PATCH 1092/1783] Relativize `pixelPositionForScreenPosition`.`top` This commit makes the method return a `top` value which is relative to the viewport. However, we still need to return an absolute value for `left` because lines are moved horizontally through a single transform on their parent node. I would prefer being consistent (i.e. make everything relative), but moving every single tile to simulate scrolling, on the other hand, seems overkill and it's not really intuitive given that we are not tiling horizontally. /cc: @nathansobo --- src/text-editor-presenter.coffee | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index e9944afce..c7bf282ed 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -375,11 +375,11 @@ class TextEditorPresenter else screenPosition = decoration.getMarker().getHeadScreenPosition() - pixelPosition = @pixelPositionForScreenPosition(screenPosition, true, absolute: true) + pixelPosition = @pixelPositionForScreenPosition(screenPosition, true) - {scrollTop, scrollLeft} = @state.content + {scrollLeft} = @state.content - top = pixelPosition.top + @lineHeight - scrollTop + top = pixelPosition.top + @lineHeight left = pixelPosition.left + @gutterWidth - scrollLeft if overlayDimensions = @overlayDimensions[decoration.id] @@ -963,7 +963,7 @@ class TextEditorPresenter hasPixelPositionRequirements: -> @lineHeight? and @baseCharacterWidth? - pixelPositionForScreenPosition: (screenPosition, clip=true, {absolute}={}) -> + pixelPositionForScreenPosition: (screenPosition, clip=true) -> screenPosition = Point.fromObject(screenPosition) screenPosition = @model.clipScreenPosition(screenPosition) if clip @@ -993,7 +993,7 @@ class TextEditorPresenter left += characterWidths[char] ? baseCharacterWidth unless char is '\0' column += charLength - top -= @scrollTop unless absolute + top -= @scrollTop {top, left} hasPixelRectRequirements: -> From 63e2764b7f455f6e590dfe1ee8ab1a57335bc449 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 13 May 2015 10:45:42 +0200 Subject: [PATCH 1093/1783] :art: Inline LinesPresenter --- src/lines-presenter.coffee | 41 ------------------------------ src/text-editor-presenter.coffee | 43 ++++++++++++++++++++++++++------ 2 files changed, 36 insertions(+), 48 deletions(-) delete mode 100644 src/lines-presenter.coffee diff --git a/src/lines-presenter.coffee b/src/lines-presenter.coffee deleted file mode 100644 index c1e3676ba..000000000 --- a/src/lines-presenter.coffee +++ /dev/null @@ -1,41 +0,0 @@ -module.exports = -class LinesPresenter - startRow: null - endRow: null - lineHeight: null - - constructor: (@presenter) -> - @lines = {} - - getState: -> - visibleLineIds = {} - row = @startRow - while row < @endRow - line = @presenter.model.tokenizedLineForScreenRow(row) - unless line? - throw new Error("No line exists for row #{row}. Last screen row: #{@model.getLastScreenRow()}") - - visibleLineIds[line.id] = true - if @lines.hasOwnProperty(line.id) - lineState = @lines[line.id] - lineState.screenRow = row - lineState.top = (row - @startRow) * @lineHeight - lineState.decorationClasses = @presenter.lineDecorationClassesForRow(row) - else - @lines[line.id] = - screenRow: row - text: line.text - tokens: line.tokens - isOnlyWhitespace: line.isOnlyWhitespace() - endOfLineInvisibles: line.endOfLineInvisibles - indentLevel: line.indentLevel - tabLength: line.tabLength - fold: line.fold - top: (row - @startRow) * @lineHeight - decorationClasses: @presenter.lineDecorationClassesForRow(row) - row++ - - for id, line of @lines - delete @lines[id] unless visibleLineIds.hasOwnProperty(id) - - @lines diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index c7bf282ed..9d8c22c3c 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -23,7 +23,6 @@ class TextEditorPresenter @gutterWidth ?= 0 @tileOverdrawMargin ?= 0 @tileCount ?= 3 - @linesPresentersByTileIndex = {} @disposables = new CompositeDisposable @emitter = new Emitter @@ -318,19 +317,18 @@ class TextEditorPresenter visibleTiles = {} for index in [startIndex...endIndex] - presenter = @linesPresentersByTileIndex[index] ?= new LinesPresenter(@) - presenter.startRow = Math.floor(index * linesPerTile) - presenter.endRow = Math.ceil(Math.min(@model.getScreenLineCount(), (index + 1) * linesPerTile)) - presenter.lineHeight = @lineHeight + startRow = Math.floor(index * linesPerTile) + endRow = Math.ceil(Math.min(@model.getScreenLineCount(), (index + 1) * linesPerTile)) isNewTile = not @state.content.tiles.hasOwnProperty(index) tile = @state.content.tiles[index] ?= {} tile.top = (index * linesPerTile * @lineHeight) - @scrollTop - tile.lines = presenter.getState() tile.height = linesPerTile * @lineHeight tile.newlyCreated = isNewTile tile.display = "block" + @updateLinesState(tile, startRow, endRow) + visibleTiles[index] = true for index, tile of @state.content.tiles @@ -340,9 +338,40 @@ class TextEditorPresenter tile.display = "none" else delete @state.content.tiles[index] - delete @linesPresentersByTileIndex[index] + updateLinesState: (tileState, startRow, endRow) -> + tileState.lines ?= {} + visibleLineIds = {} + row = startRow + while row < endRow + line = @model.tokenizedLineForScreenRow(row) + unless line? + throw new Error("No line exists for row #{row}. Last screen row: #{@model.getLastScreenRow()}") + + visibleLineIds[line.id] = true + if tileState.lines.hasOwnProperty(line.id) + lineState = tileState.lines[line.id] + lineState.screenRow = row + lineState.top = (row - startRow) * @lineHeight + lineState.decorationClasses = @lineDecorationClassesForRow(row) + else + tileState.lines[line.id] = + screenRow: row + text: line.text + tokens: line.tokens + isOnlyWhitespace: line.isOnlyWhitespace() + endOfLineInvisibles: line.endOfLineInvisibles + indentLevel: line.indentLevel + tabLength: line.tabLength + fold: line.fold + top: (row - startRow) * @lineHeight + decorationClasses: @lineDecorationClassesForRow(row) + row++ + + for id, line of tileState.lines + delete tileState.lines[id] unless visibleLineIds.hasOwnProperty(id) + updateCursorsState: -> @state.content.cursors = {} @updateCursorState(cursor) for cursor in @model.cursors # using property directly to avoid allocation From 74a0ce0720860cbca2970d1a54e8606d6c837c8d Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 13 May 2015 10:59:50 +0200 Subject: [PATCH 1094/1783] Remove require to LinesPresenter --- src/text-editor-presenter.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 9d8c22c3c..28d677734 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -2,7 +2,6 @@ {Point, Range} = require 'text-buffer' _ = require 'underscore-plus' Decoration = require './decoration' -LinesPresenter = require './lines-presenter' module.exports = class TextEditorPresenter From 4c2683a378d7a3089d1c435369ffb9276dd313a4 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 13 May 2015 11:14:21 +0200 Subject: [PATCH 1095/1783] :art: Clarify `@updateTilesState` --- src/text-editor-presenter.coffee | 59 +++++++++++++++++--------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 28d677734..37b5daee1 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -300,43 +300,48 @@ class TextEditorPresenter @state.content.backgroundColor = if @model.isMini() then null else @backgroundColor @state.content.placeholderText = if @model.isEmpty() then @model.getPlaceholderText() else null + # REFACTOR: This should be a @field rather than a function. + linesPerTile: -> + linesPerTile = Math.floor(@height / @lineHeight / @tileCount) + Math.max(1, linesPerTile) + + tileForRow: (row) -> + row - (row % @linesPerTile()) + + getVisibleTileRange: -> + startTileRow = Math.max(0, @tileForRow(@startRow) - @tileOverdrawMargin) + endTileRow = Math.min( + @tileForRow(@model.getScreenLineCount()), + @tileForRow(@endRow) + @tileOverdrawMargin + ) + + [startTileRow..endTileRow] + updateTilesState: -> return unless @startRow? and @endRow? and @lineHeight? - linesPerTile = Math.floor(@height / @lineHeight / @tileCount) - linesPerTile = Math.max(1, linesPerTile) - - startIndex = Math.max( - 0, Math.floor(@startRow / linesPerTile) - @tileOverdrawMargin - ) - endIndex = Math.min( - Math.ceil(@model.getScreenLineCount() / linesPerTile), - Math.ceil(@endRow / linesPerTile) + @tileOverdrawMargin - ) - visibleTiles = {} - for index in [startIndex...endIndex] - startRow = Math.floor(index * linesPerTile) - endRow = Math.ceil(Math.min(@model.getScreenLineCount(), (index + 1) * linesPerTile)) + for startRow in @getVisibleTileRange() by @linesPerTile() + endRow = Math.min(@model.getScreenLineCount(), startRow + @linesPerTile()) - isNewTile = not @state.content.tiles.hasOwnProperty(index) - tile = @state.content.tiles[index] ?= {} - tile.top = (index * linesPerTile * @lineHeight) - @scrollTop - tile.height = linesPerTile * @lineHeight + isNewTile = not @state.content.tiles.hasOwnProperty(startRow) + tile = @state.content.tiles[startRow] ?= {} + tile.top = startRow * @lineHeight - @scrollTop + tile.height = @linesPerTile() * @lineHeight tile.newlyCreated = isNewTile tile.display = "block" @updateLinesState(tile, startRow, endRow) - visibleTiles[index] = true + visibleTiles[startRow] = true - for index, tile of @state.content.tiles - continue if visibleTiles.hasOwnProperty(index) + for id, tile of @state.content.tiles + continue if visibleTiles.hasOwnProperty(id) - if index is @scrollingTile + if id is @scrollingTileId tile.display = "none" else - delete @state.content.tiles[index] + delete @state.content.tiles[id] updateLinesState: (tileState, startRow, endRow) -> @@ -767,8 +772,8 @@ class TextEditorPresenter didStopScrolling: -> @state.content.scrollingVertically = false - if @scrollingTile? - @scrollingTile = null + if @scrollingTileId? + @scrollingTileId = null @shouldUpdateTilesState = true @shouldUpdateLineNumbersState = true @shouldUpdateCustomGutterDecorationState = true @@ -935,8 +940,8 @@ class TextEditorPresenter @emitDidUpdateState() setScrollingTileId: (tileId) -> - if @scrollingTile isnt tileId - @scrollingTile = tileId + if @scrollingTileId isnt tileId + @scrollingTileId = tileId @didStartScrolling() setBaseCharacterWidth: (baseCharacterWidth) -> From 948b8f95339b3f335b79724c476b6374cf5c5de4 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 13 May 2015 11:22:02 +0200 Subject: [PATCH 1096/1783] Remember to fix scrolling for line-numbers --- src/text-editor-presenter.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 37b5daee1..e5eadbbcd 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -550,6 +550,7 @@ class TextEditorPresenter @state.gutters.lineNumberGutter.lineNumbers[id] = {screenRow, bufferRow, softWrapped, top, decorationClasses, foldable} visibleLineNumberIds[id] = true + # FIXME: We should either rely on @mouseWheelScreenRow or convert this to use tiles. if @mouseWheelScreenRow? bufferRow = @model.bufferRowForScreenRow(@mouseWheelScreenRow) wrapCount = @mouseWheelScreenRow - @model.screenRowForBufferRow(bufferRow) From 94373e434c5e52f64a8890bb7ee1fa90dd4f057d Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 13 May 2015 11:26:02 +0200 Subject: [PATCH 1097/1783] Make `tileSize` a field rather than a fn --- src/text-editor-presenter.coffee | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index e5eadbbcd..f5fb1257a 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -67,6 +67,7 @@ class TextEditorPresenter @updateScrollbarDimensions() @updateStartRow() @updateEndRow() + @updateTileSize() @updateFocusedState() if @shouldUpdateFocusedState @updateHeightState() if @shouldUpdateHeightState @@ -300,15 +301,10 @@ class TextEditorPresenter @state.content.backgroundColor = if @model.isMini() then null else @backgroundColor @state.content.placeholderText = if @model.isEmpty() then @model.getPlaceholderText() else null - # REFACTOR: This should be a @field rather than a function. - linesPerTile: -> - linesPerTile = Math.floor(@height / @lineHeight / @tileCount) - Math.max(1, linesPerTile) - tileForRow: (row) -> - row - (row % @linesPerTile()) + row - (row % @tileSize) - getVisibleTileRange: -> + getVisibleTilesRange: -> startTileRow = Math.max(0, @tileForRow(@startRow) - @tileOverdrawMargin) endTileRow = Math.min( @tileForRow(@model.getScreenLineCount()), @@ -321,13 +317,13 @@ class TextEditorPresenter return unless @startRow? and @endRow? and @lineHeight? visibleTiles = {} - for startRow in @getVisibleTileRange() by @linesPerTile() - endRow = Math.min(@model.getScreenLineCount(), startRow + @linesPerTile()) + for startRow in @getVisibleTilesRange() by @tileSize + endRow = Math.min(@model.getScreenLineCount(), startRow + @tileSize) isNewTile = not @state.content.tiles.hasOwnProperty(startRow) tile = @state.content.tiles[startRow] ?= {} tile.top = startRow * @lineHeight - @scrollTop - tile.height = @linesPerTile() * @lineHeight + tile.height = @tileSize * @lineHeight tile.newlyCreated = isNewTile tile.display = "block" @@ -343,7 +339,6 @@ class TextEditorPresenter else delete @state.content.tiles[id] - updateLinesState: (tileState, startRow, endRow) -> tileState.lines ?= {} visibleLineIds = {} @@ -577,6 +572,12 @@ class TextEditorPresenter endRow = startRow + visibleLinesCount @endRow = Math.min(@model.getScreenLineCount(), endRow) + updateTileSize: -> + return unless @height? and @lineHeight? and @tileCount? + + @tileSize = Math.floor(@height / @lineHeight / @tileCount) + @tileSize = Math.max(1, @tileSize) + updateScrollWidth: -> return unless @contentWidth? and @clientWidth? From 11a0fa7a1246901810cbf3fcedc00739c94931c0 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 13 May 2015 11:39:28 +0200 Subject: [PATCH 1098/1783] updateTileSize on start --- spec/text-editor-presenter-spec.coffee | 18 ++++++++---------- src/text-editor-presenter.coffee | 1 + 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 6db369f69..98c4caecb 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -658,28 +658,26 @@ describe "TextEditorPresenter", -> expect(presenter.getState().content.placeholderText).toBe "new-placeholder-text" describe ".tiles", -> - it "contains states for tiles that are visible on screen, plus and minus the overdraw margin", -> - presenter = buildPresenter(explicitHeight: 3, scrollTop: 1, lineHeight: 1, tileCount: 3, tileOverdrawMargin: 1) + fffit "contains states for tiles that are visible on screen", -> + presenter = buildPresenter(explicitHeight: 3, scrollTop: 1, lineHeight: 1, tileCount: 3) + console.log JSON.stringify(presenter.getState().content.tiles) expectValues presenter.getState().content.tiles[0], { - top: -1 - } - expectValues presenter.getState().content.tiles[1], { top: 0 } - expectValues presenter.getState().content.tiles[2], { + expectValues presenter.getState().content.tiles[1], { top: 1 } - expectValues presenter.getState().content.tiles[3], { + expectValues presenter.getState().content.tiles[2], { top: 2 } - expectValues presenter.getState().content.tiles[4], { + expectValues presenter.getState().content.tiles[3], { top: 3 } - expectValues presenter.getState().content.tiles[5], { + expectValues presenter.getState().content.tiles[4], { top: 4 } - expect(presenter.getState().content.tiles[6]).toBeUndefined() + expect(presenter.getState().content.tiles[5]).toBeUndefined() it "does not overdraw above the first row", -> presenter = buildPresenter(explicitHeight: 3, scrollTop: 0, lineHeight: 1, tileCount: 3, tileOverdrawMargin: 1) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index f5fb1257a..a8d845c72 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -223,6 +223,7 @@ class TextEditorPresenter @updateScrollbarDimensions() @updateStartRow() @updateEndRow() + @updateTileSize() @updateFocusedState() @updateHeightState() From 29c6e9d89cbef26cd55ce4fa0de89bfae17e4f00 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 13 May 2015 11:57:38 +0200 Subject: [PATCH 1099/1783] :green_heart: Start fixing presenter specs --- spec/text-editor-presenter-spec.coffee | 105 +++++++++++-------------- 1 file changed, 46 insertions(+), 59 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 98c4caecb..e0fbda5ae 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -658,53 +658,32 @@ describe "TextEditorPresenter", -> expect(presenter.getState().content.placeholderText).toBe "new-placeholder-text" describe ".tiles", -> - fffit "contains states for tiles that are visible on screen", -> - presenter = buildPresenter(explicitHeight: 3, scrollTop: 1, lineHeight: 1, tileCount: 3) + it "contains states for tiles that are visible on screen", -> + presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileCount: 3) - console.log JSON.stringify(presenter.getState().content.tiles) expectValues presenter.getState().content.tiles[0], { top: 0 } - expectValues presenter.getState().content.tiles[1], { - top: 1 - } expectValues presenter.getState().content.tiles[2], { top: 2 } - expectValues presenter.getState().content.tiles[3], { - top: 3 - } expectValues presenter.getState().content.tiles[4], { top: 4 } - expect(presenter.getState().content.tiles[5]).toBeUndefined() + expectValues presenter.getState().content.tiles[6], { + top: 6 + } - it "does not overdraw above the first row", -> - presenter = buildPresenter(explicitHeight: 3, scrollTop: 0, lineHeight: 1, tileCount: 3, tileOverdrawMargin: 1) - expect(presenter.getState().content.tiles[-1]).toBeUndefined() - expect(presenter.getState().content.tiles[0]).toBeDefined() - expect(presenter.getState().content.tiles[1]).toBeDefined() - expect(presenter.getState().content.tiles[2]).toBeDefined() - expect(presenter.getState().content.tiles[3]).toBeDefined() - expect(presenter.getState().content.tiles[4]).toBeDefined() - expect(presenter.getState().content.tiles[5]).toBeUndefined() - - it "does not overdraw below the last row", -> - presenter = buildPresenter(explicitHeight: 3, scrollTop: 10, lineHeight: 1, tileCount: 3, tileOverdrawMargin: 1) expect(presenter.getState().content.tiles[8]).toBeUndefined() - expect(presenter.getState().content.tiles[9]).toBeDefined() - expect(presenter.getState().content.tiles[10]).toBeDefined() - expect(presenter.getState().content.tiles[11]).toBeDefined() - expect(presenter.getState().content.tiles[12]).toBeDefined() - expect(presenter.getState().content.tiles[13]).toBeUndefined() - xit "includes state for all tiles if no external ::explicitHeight is assigned", -> + + it "includes state for all tiles if no external ::explicitHeight is assigned", -> presenter = buildPresenter(explicitHeight: null, tileCount: 12, tileOverdrawMargin: 1) expect(presenter.getState().content.tiles[0]).toBeDefined() expect(presenter.getState().content.tiles[12]).toBeDefined() it "is empty until all of the required measurements are assigned", -> - presenter = buildPresenter(explicitHeight: null, lineHeight: null, scrollTop: null, tileCount: 3, tileOverdrawMargin: 1) + presenter = buildPresenter(explicitHeight: null, lineHeight: null, scrollTop: null, tileCount: 3) expect(presenter.getState().content.tiles).toEqual({}) presenter.setExplicitHeight(25) @@ -717,48 +696,57 @@ describe "TextEditorPresenter", -> expect(presenter.getState().content.tiles).not.toEqual({}) it "updates when ::scrollTop changes", -> - presenter = buildPresenter(explicitHeight: 3, scrollTop: 0, lineHeight: 1, tileOverdrawMargin: 1, tileCount: 3) + presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileCount: 3) expect(presenter.getState().content.tiles[0]).toBeDefined() + expect(presenter.getState().content.tiles[2]).toBeDefined() expect(presenter.getState().content.tiles[4]).toBeDefined() - expect(presenter.getState().content.tiles[5]).toBeUndefined() + expect(presenter.getState().content.tiles[6]).toBeDefined() + expect(presenter.getState().content.tiles[8]).toBeUndefined() expectStateUpdate presenter, -> presenter.setScrollTop(2) expect(presenter.getState().content.tiles[0]).toBeUndefined() - expect(presenter.getState().content.tiles[1]).toBeDefined() - expect(presenter.getState().content.tiles[6]).toBeDefined() - expect(presenter.getState().content.tiles[7]).toBeUndefined() - - xit "updates when ::explicitHeight changes", -> - presenter = buildPresenter(explicitHeight: 3, scrollTop: 0, lineHeight: 1, tileOverdrawMargin: 1, tileCount: 3) - - line5 = editor.tokenizedLineForScreenRow(5) - + expect(presenter.getState().content.tiles[2]).toBeDefined() expect(presenter.getState().content.tiles[4]).toBeDefined() - expect(presenter.getState().content.tiles[5]).toBeUndefined() - - expectStateUpdate presenter, -> presenter.setExplicitHeight(35) - - expect(presenter.getState().content.tiles[5]).toBeDefined() expect(presenter.getState().content.tiles[6]).toBeDefined() - expect(presenter.getState().content.tiles[7]).toBeUndefined() + expect(presenter.getState().content.tiles[8]).toBeDefined() + expect(presenter.getState().content.tiles[10]).toBeUndefined() - xit "updates when ::lineHeight changes", -> - presenter = buildPresenter(explicitHeight: 15, scrollTop: 10, lineHeight: 10, lineOverdrawMargin: 0) + it "updates when ::explicitHeight changes", -> + presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileCount: 3) - expect(lineStateForScreenRow(presenter, 0)).toBeUndefined() - expect(lineStateForScreenRow(presenter, 1)).toBeDefined() - expect(lineStateForScreenRow(presenter, 2)).toBeDefined() - expect(lineStateForScreenRow(presenter, 4)).toBeUndefined() + expect(presenter.getState().content.tiles[0]).toBeDefined() + expect(presenter.getState().content.tiles[2]).toBeDefined() + expect(presenter.getState().content.tiles[4]).toBeDefined() + expect(presenter.getState().content.tiles[6]).toBeDefined() + expect(presenter.getState().content.tiles[8]).toBeUndefined() - expectStateUpdate presenter, -> presenter.setLineHeight(5) + expectStateUpdate presenter, -> presenter.setExplicitHeight(8) - expect(lineStateForScreenRow(presenter, 0)).toBeUndefined() - expect(lineStateForScreenRow(presenter, 1)).toBeUndefined() - expect(lineStateForScreenRow(presenter, 2)).toBeDefined() - expect(lineStateForScreenRow(presenter, 5)).toBeDefined() - expect(lineStateForScreenRow(presenter, 6)).toBeUndefined() + expect(presenter.getState().content.tiles[0]).toBeDefined() + expect(presenter.getState().content.tiles[2]).toBeDefined() + expect(presenter.getState().content.tiles[4]).toBeDefined() + expect(presenter.getState().content.tiles[6]).toBeDefined() + expect(presenter.getState().content.tiles[8]).toBeDefined() + expect(presenter.getState().content.tiles[10]).toBeUndefined() + + + it "updates when ::lineHeight changes", -> + presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileCount: 3) + + expect(presenter.getState().content.tiles[0]).toBeDefined() + expect(presenter.getState().content.tiles[2]).toBeDefined() + expect(presenter.getState().content.tiles[4]).toBeDefined() + expect(presenter.getState().content.tiles[6]).toBeDefined() + expect(presenter.getState().content.tiles[8]).toBeUndefined() + + expectStateUpdate presenter, -> presenter.setLineHeight(2) + + expect(presenter.getState().content.tiles[0]).toBeDefined() + expect(presenter.getState().content.tiles[2]).toBeDefined() + expect(presenter.getState().content.tiles[4]).toBeDefined() + expect(presenter.getState().content.tiles[6]).toBeUndefined() it "updates when the editor's content changes", -> lineStateForScreenRow = (presenter, tile, row) -> @@ -788,7 +776,6 @@ describe "TextEditorPresenter", -> } xdescribe ".lines", -> - it "does not remove out-of-view lines corresponding to ::mouseWheelScreenRow until ::stoppedScrollingDelay elapses", -> presenter = buildPresenter(explicitHeight: 25, scrollTop: 0, lineHeight: 10, lineOverdrawMargin: 1, stoppedScrollingDelay: 200) From 49c48234f2d094f64d6da19fd7b7bae267cbd770 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 13 May 2015 12:26:20 +0200 Subject: [PATCH 1100/1783] :green_heart: Finish fixing tiles/lines specs --- spec/text-editor-presenter-spec.coffee | 76 ++++++++++++-------------- src/text-editor-presenter.coffee | 19 ++++--- 2 files changed, 44 insertions(+), 51 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index e0fbda5ae..7c5c9d6a3 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -658,6 +658,11 @@ describe "TextEditorPresenter", -> expect(presenter.getState().content.placeholderText).toBe "new-placeholder-text" describe ".tiles", -> + lineStateForScreenRow = (presenter, row) -> + lineId = presenter.model.tokenizedLineForScreenRow(row).id + tileRow = presenter.tileForRow(row) + presenter.getState().content.tiles[tileRow].lines[lineId] + it "contains states for tiles that are visible on screen", -> presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileCount: 3) @@ -676,7 +681,6 @@ describe "TextEditorPresenter", -> expect(presenter.getState().content.tiles[8]).toBeUndefined() - it "includes state for all tiles if no external ::explicitHeight is assigned", -> presenter = buildPresenter(explicitHeight: null, tileCount: 12, tileOverdrawMargin: 1) expect(presenter.getState().content.tiles[0]).toBeDefined() @@ -749,80 +753,68 @@ describe "TextEditorPresenter", -> expect(presenter.getState().content.tiles[6]).toBeUndefined() it "updates when the editor's content changes", -> - lineStateForScreenRow = (presenter, tile, row) -> - lineId = presenter.model.tokenizedLineForScreenRow(row).id - presenter.getState().content.tiles[tile].lines[lineId] - presenter = buildPresenter(explicitHeight: 25, scrollTop: 10, lineHeight: 10, tileCount: 3, tileOverdrawMargin: 1) expectStateUpdate presenter, -> buffer.insert([2, 0], "hello\nworld\n") line1 = editor.tokenizedLineForScreenRow(1) - expectValues lineStateForScreenRow(presenter, 1, 1), { + expectValues lineStateForScreenRow(presenter, 1), { text: line1.text tokens: line1.tokens } line2 = editor.tokenizedLineForScreenRow(2) - expectValues lineStateForScreenRow(presenter, 2, 2), { + expectValues lineStateForScreenRow(presenter, 2), { text: line2.text tokens: line2.tokens } line3 = editor.tokenizedLineForScreenRow(3) - expectValues lineStateForScreenRow(presenter, 3, 3), { + expectValues lineStateForScreenRow(presenter, 3), { text: line3.text tokens: line3.tokens } - xdescribe ".lines", -> - it "does not remove out-of-view lines corresponding to ::mouseWheelScreenRow until ::stoppedScrollingDelay elapses", -> - presenter = buildPresenter(explicitHeight: 25, scrollTop: 0, lineHeight: 10, lineOverdrawMargin: 1, stoppedScrollingDelay: 200) + it "does not remove out-of-view tiles corresponding to ::scrollingTileId until ::stoppedScrollingDelay elapses", -> + presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileCount: 3, stoppedScrollingDelay: 200) - expect(lineStateForScreenRow(presenter, 0)).toBeDefined() - expect(lineStateForScreenRow(presenter, 4)).toBeDefined() - expect(lineStateForScreenRow(presenter, 5)).toBeUndefined() + expect(presenter.getState().content.tiles[0]).toBeDefined() + expect(presenter.getState().content.tiles[6]).toBeDefined() + expect(presenter.getState().content.tiles[8]).toBeUndefined() - presenter.setMouseWheelScreenRow(0) - expectStateUpdate presenter, -> presenter.setScrollTop(35) + presenter.setScrollingTileId(0) + expectStateUpdate presenter, -> presenter.setScrollTop(4) - expect(lineStateForScreenRow(presenter, 0)).toBeDefined() - expect(lineStateForScreenRow(presenter, 1)).toBeUndefined() - expect(lineStateForScreenRow(presenter, 7)).toBeDefined() - expect(lineStateForScreenRow(presenter, 8)).toBeUndefined() + expect(presenter.getState().content.tiles[0]).toBeDefined() + expect(presenter.getState().content.tiles[2]).toBeUndefined() + expect(presenter.getState().content.tiles[4]).toBeDefined() + expect(presenter.getState().content.tiles[12]).toBeUndefined() expectStateUpdate presenter, -> advanceClock(200) - expect(lineStateForScreenRow(presenter, 0)).toBeUndefined() - expect(lineStateForScreenRow(presenter, 1)).toBeUndefined() - expect(lineStateForScreenRow(presenter, 2)).toBeDefined() - expect(lineStateForScreenRow(presenter, 7)).toBeDefined() - expect(lineStateForScreenRow(presenter, 8)).toBeUndefined() + expect(presenter.getState().content.tiles[0]).toBeUndefined() + expect(presenter.getState().content.tiles[2]).toBeUndefined() + expect(presenter.getState().content.tiles[4]).toBeDefined() + expect(presenter.getState().content.tiles[12]).toBeUndefined() + # should clear ::mouseWheelScreenRow after stoppedScrollingDelay elapses even if we don't scroll first - presenter.setMouseWheelScreenRow(2) + presenter.setScrollingTileId(4) advanceClock(200) - expectStateUpdate presenter, -> presenter.setScrollTop(45) - expect(lineStateForScreenRow(presenter, 2)).toBeUndefined() + expectStateUpdate presenter, -> presenter.setScrollTop(6) + expect(presenter.getState().content.tiles[4]).toBeUndefined() - it "does not preserve on-screen lines even if they correspond to ::mouseWheelScreenRow", -> - presenter = buildPresenter(explicitHeight: 25, scrollTop: 0, lineHeight: 10, lineOverdrawMargin: 1, stoppedScrollingDelay: 200) - oldLine3 = editor.tokenizedLineForScreenRow(6) + it "does not preserve deleted on-screen tiles even if they correspond to ::scrollingTileId", -> + presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileCount: 3, stoppedScrollingDelay: 200) - presenter.setMouseWheelScreenRow(3) + presenter.setScrollingTileId(2) - expectStateUpdate presenter, -> editor.getBuffer().insert([3, Infinity], 'xyz') - newLine3 = editor.tokenizedLineForScreenRow(3) + expectStateUpdate presenter, -> editor.setText("") - expect(presenter.getState().content.lines[oldLine3.id]).toBeUndefined() - expect(presenter.getState().content.lines[newLine3.id]).toBeDefined() + expect(presenter.getState().content.tiles[2]).toBeUndefined() + expect(presenter.getState().content.tiles[0]).toBeDefined() - it "does not attempt to preserve lines corresponding to ::mouseWheelScreenRow if they have been deleted", -> - presenter = buildPresenter(explicitHeight: 25, scrollTop: 0, lineHeight: 10, lineOverdrawMargin: 1, stoppedScrollingDelay: 200) - presenter.setMouseWheelScreenRow(10) - editor.setText('') - - describe "[lineId]", -> # line state objects + describe "[tileId].lines[lineId]", -> # line state objects it "includes the .endOfLineInvisibles if the editor.showInvisibles config option is true", -> editor.setText("hello\nworld\r\n") presenter = buildPresenter(explicitHeight: 25, scrollTop: 0, lineHeight: 10) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index a8d845c72..7ca810cba 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -15,12 +15,11 @@ class TextEditorPresenter constructor: (params) -> {@model, @autoHeight, @explicitHeight, @contentFrameWidth, @scrollTop, @scrollLeft, @boundingClientRect, @windowWidth, @windowHeight, @gutterWidth} = params {horizontalScrollbarHeight, verticalScrollbarWidth} = params - {@lineHeight, @baseCharacterWidth, @lineOverdrawMargin, @backgroundColor, @gutterBackgroundColor, @tileCount, @tileOverdrawMargin} = params + {@lineHeight, @baseCharacterWidth, @lineOverdrawMargin, @backgroundColor, @gutterBackgroundColor, @tileCount} = params {@cursorBlinkPeriod, @cursorBlinkResumeDelay, @stoppedScrollingDelay, @focused} = params @measuredHorizontalScrollbarHeight = horizontalScrollbarHeight @measuredVerticalScrollbarWidth = verticalScrollbarWidth @gutterWidth ?= 0 - @tileOverdrawMargin ?= 0 @tileCount ?= 3 @disposables = new CompositeDisposable @@ -306,10 +305,9 @@ class TextEditorPresenter row - (row % @tileSize) getVisibleTilesRange: -> - startTileRow = Math.max(0, @tileForRow(@startRow) - @tileOverdrawMargin) + startTileRow = Math.max(0, @tileForRow(@startRow)) endTileRow = Math.min( - @tileForRow(@model.getScreenLineCount()), - @tileForRow(@endRow) + @tileOverdrawMargin + @tileForRow(@model.getScreenLineCount()), @tileForRow(@endRow) ) [startTileRow..endTileRow] @@ -332,13 +330,15 @@ class TextEditorPresenter visibleTiles[startRow] = true + if @scrollingTileId? + if @scrollingTileId <= @tileForRow(@model.getLastScreenRow()) + visibleTiles[@scrollingTileId] = true + @state.content.tiles[@scrollingTileId].display = "none" + for id, tile of @state.content.tiles continue if visibleTiles.hasOwnProperty(id) - if id is @scrollingTileId - tile.display = "none" - else - delete @state.content.tiles[id] + delete @state.content.tiles[id] updateLinesState: (tileState, startRow, endRow) -> tileState.lines ?= {} @@ -943,6 +943,7 @@ class TextEditorPresenter @emitDidUpdateState() setScrollingTileId: (tileId) -> + tileId = tileId.toString() if @scrollingTileId isnt tileId @scrollingTileId = tileId @didStartScrolling() From 6d38d1c4e0649ec3c564f576b25ceafb5e6265e7 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 13 May 2015 12:30:44 +0200 Subject: [PATCH 1101/1783] :fire: Remove leftover code --- src/text-editor-presenter.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 7ca810cba..7d060f367 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -943,7 +943,6 @@ class TextEditorPresenter @emitDidUpdateState() setScrollingTileId: (tileId) -> - tileId = tileId.toString() if @scrollingTileId isnt tileId @scrollingTileId = tileId @didStartScrolling() From 467f4a30d7b8d8c4e1fe4b68f55208dac805bbc0 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 13 May 2015 12:39:32 +0200 Subject: [PATCH 1102/1783] :art: Simplify conditional --- src/text-editor-presenter.coffee | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 7d060f367..82c050314 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -304,6 +304,11 @@ class TextEditorPresenter tileForRow: (row) -> row - (row % @tileSize) + isValidTile: (tileId) -> + return false unless tileId? + + tileId <= @tileForRow(@model.getLastScreenRow()) + getVisibleTilesRange: -> startTileRow = Math.max(0, @tileForRow(@startRow)) endTileRow = Math.min( @@ -330,10 +335,9 @@ class TextEditorPresenter visibleTiles[startRow] = true - if @scrollingTileId? - if @scrollingTileId <= @tileForRow(@model.getLastScreenRow()) - visibleTiles[@scrollingTileId] = true - @state.content.tiles[@scrollingTileId].display = "none" + if @isValidTile(@scrollingTileId) and not visibleTiles[@scrollingTileId]? + @state.content.tiles[@scrollingTileId].display = "none" + visibleTiles[@scrollingTileId] = true for id, tile of @state.content.tiles continue if visibleTiles.hasOwnProperty(id) From 25acaf26c19bdc0414104eacda604bb900baf396 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 13 May 2015 12:44:06 +0200 Subject: [PATCH 1103/1783] :art: `tileId` -> `tileRow` --- spec/text-editor-presenter-spec.coffee | 6 +++--- src/text-editor-component.coffee | 4 ++-- src/text-editor-presenter.coffee | 22 +++++++++++----------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 7c5c9d6a3..95f941fde 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -782,7 +782,7 @@ describe "TextEditorPresenter", -> expect(presenter.getState().content.tiles[6]).toBeDefined() expect(presenter.getState().content.tiles[8]).toBeUndefined() - presenter.setScrollingTileId(0) + presenter.setScrollingTileRow(0) expectStateUpdate presenter, -> presenter.setScrollTop(4) expect(presenter.getState().content.tiles[0]).toBeDefined() @@ -799,7 +799,7 @@ describe "TextEditorPresenter", -> # should clear ::mouseWheelScreenRow after stoppedScrollingDelay elapses even if we don't scroll first - presenter.setScrollingTileId(4) + presenter.setScrollingTileRow(4) advanceClock(200) expectStateUpdate presenter, -> presenter.setScrollTop(6) expect(presenter.getState().content.tiles[4]).toBeUndefined() @@ -807,7 +807,7 @@ describe "TextEditorPresenter", -> it "does not preserve deleted on-screen tiles even if they correspond to ::scrollingTileId", -> presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileCount: 3, stoppedScrollingDelay: 200) - presenter.setScrollingTileId(2) + presenter.setScrollingTileRow(2) expectStateUpdate presenter, -> editor.setText("") diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 8c497bd98..c97fb11a0 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -354,7 +354,7 @@ class TextEditorComponent event.preventDefault() unless previousScrollLeft is @presenter.getScrollLeft() else # Scrolling vertically - @presenter.setScrollingTileId(@tileIdForNode(event.target)) + @presenter.setScrollingTileRow(@tileRowForNode(event.target)) previousScrollTop = @presenter.getScrollTop() @presenter.setScrollTop(previousScrollTop - Math.round(wheelDeltaY * @scrollSensitivity)) event.preventDefault() unless previousScrollTop is @presenter.getScrollTop() @@ -729,7 +729,7 @@ class TextEditorComponent lineNumberNodeForScreenRow: (screenRow) -> @gutterContainerComponent.getLineNumberGutterComponent().lineNumberNodeForScreenRow(screenRow) - tileIdForNode: (node) -> + tileRowForNode: (node) -> while node? if tileId = node.dataset.tileId return tileId diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 82c050314..6b38f0114 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -304,10 +304,10 @@ class TextEditorPresenter tileForRow: (row) -> row - (row % @tileSize) - isValidTile: (tileId) -> - return false unless tileId? + isValidTile: (tileRow) -> + return false unless tileRow? - tileId <= @tileForRow(@model.getLastScreenRow()) + tileRow <= @tileForRow(@model.getLastScreenRow()) getVisibleTilesRange: -> startTileRow = Math.max(0, @tileForRow(@startRow)) @@ -335,9 +335,9 @@ class TextEditorPresenter visibleTiles[startRow] = true - if @isValidTile(@scrollingTileId) and not visibleTiles[@scrollingTileId]? - @state.content.tiles[@scrollingTileId].display = "none" - visibleTiles[@scrollingTileId] = true + if @isValidTile(@scrollingTileRow) and not visibleTiles[@scrollingTileRow]? + @state.content.tiles[@scrollingTileRow].display = "none" + visibleTiles[@scrollingTileRow] = true for id, tile of @state.content.tiles continue if visibleTiles.hasOwnProperty(id) @@ -779,8 +779,8 @@ class TextEditorPresenter didStopScrolling: -> @state.content.scrollingVertically = false - if @scrollingTileId? - @scrollingTileId = null + if @scrollingTileRow? + @scrollingTileRow = null @shouldUpdateTilesState = true @shouldUpdateLineNumbersState = true @shouldUpdateCustomGutterDecorationState = true @@ -946,9 +946,9 @@ class TextEditorPresenter @emitDidUpdateState() - setScrollingTileId: (tileId) -> - if @scrollingTileId isnt tileId - @scrollingTileId = tileId + setScrollingTileRow: (tileRow) -> + if @scrollingTileRow isnt tileRow + @scrollingTileRow = tileRow @didStartScrolling() setBaseCharacterWidth: (baseCharacterWidth) -> From ff91be791a60ebfd37c4a870630ea11b92e12b8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Machist=C3=A9=20N=2E=20Quintana?= Date: Wed, 13 May 2015 11:24:54 -0400 Subject: [PATCH 1104/1783] :arrow_up: fuzzy-finder@0.84.0 Adds fuzzy match character highlighting --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 56f8bf7c5..e2b294546 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,7 @@ "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", "find-and-replace": "0.162.0", - "fuzzy-finder": "0.83.0", + "fuzzy-finder": "0.84.0", "git-diff": "0.55.0", "go-to-line": "0.30.0", "grammar-selector": "0.47.0", From e455acec5e07062b7f4a68132458fe827e28b00a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 13 May 2015 08:56:12 -0700 Subject: [PATCH 1105/1783] :arrow_up: language-gfm@0.74 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 56f8bf7c5..020fd2f2e 100644 --- a/package.json +++ b/package.json @@ -128,7 +128,7 @@ "language-coffee-script": "0.40.0", "language-csharp": "0.5.0", "language-css": "0.29.0", - "language-gfm": "0.73.0", + "language-gfm": "0.74.0", "language-git": "0.10.0", "language-go": "0.26.0", "language-html": "0.37.0", From 4b2e23508f0267fdb8d4af002359d6819e980582 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Fri, 8 May 2015 16:02:01 -0700 Subject: [PATCH 1106/1783] Add autocomplete-plus into core :tada: --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 020fd2f2e..eeaeed69c 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ "solarized-dark-syntax": "0.35.0", "solarized-light-syntax": "0.21.0", "archive-view": "0.57.0", - "autocomplete": "0.47.0", + "autocomplete-plus": "2.13.1", "autoflow": "0.23.0", "autosave": "0.20.0", "background-tips": "0.24.0", From da646e635c170fe3eb18903ad8b14d0036eb035e Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Fri, 8 May 2015 16:02:34 -0700 Subject: [PATCH 1107/1783] Uninstall any intalled version of autocomplete-plus --- src/package-manager.coffee | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 8527188d3..1692d477a 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -303,6 +303,9 @@ class PackageManager # of the first package isn't skewed by being the first to require atom require '../exports/atom' + # TODO: remove after a few atom versions. + @uninstallAutocompletePlus() + packagePaths = @getAvailablePackagePaths() packagePaths = packagePaths.filter (packagePath) => not @isPackageDisabled(path.basename(packagePath)) packagePaths = _.uniq packagePaths, (packagePath) -> path.basename(packagePath) @@ -409,6 +412,18 @@ class PackageManager message = "Failed to load the #{path.basename(packagePath)} package" atom.notifications.addError(message, {stack, detail, dismissable: true}) + # TODO: remove these autocomplete-plus specific helpers after a few versions. + uninstallAutocompletePlus: -> + packageDir = null + devDir = path.join("dev", "packages") + for packageDirPath in @packageDirPaths + packageDir = packageDirPath if not packageDirPath.endsWith(devDir) + + if packageDir? + autocompletePlusPath = path.join(packageDir, 'autocomplete-plus') + fs.isDirectory autocompletePlusPath, (isDir, error) -> + fs.unlink(autocompletePlusPath) if isDir + if Grim.includeDeprecatedAPIs EmitterMixin = require('emissary').Emitter EmitterMixin.includeInto(PackageManager) From 1d9d9f1cf597fc598e22544b0e7a2cc1dd1d5e8b Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 11 May 2015 15:24:57 -0700 Subject: [PATCH 1108/1783] Handle deleting autocomplete-plus when symlink and dir --- src/package-manager.coffee | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 1692d477a..7ee1304c2 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -421,8 +421,10 @@ class PackageManager if packageDir? autocompletePlusPath = path.join(packageDir, 'autocomplete-plus') - fs.isDirectory autocompletePlusPath, (isDir, error) -> - fs.unlink(autocompletePlusPath) if isDir + if fs.isSymbolicLinkSync(autocompletePlusPath) + fs.unlink(autocompletePlusPath) + else if fs.isDirectorySync(autocompletePlusPath) + fs.remove(autocompletePlusPath, ->) if Grim.includeDeprecatedAPIs EmitterMixin = require('emissary').Emitter From 044c2ec37c33621933b9e1e32bdd5db8d68b46a4 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 11 May 2015 16:21:17 -0700 Subject: [PATCH 1109/1783] Bundle autocomplete-css, html and atom-api --- package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package.json b/package.json index eeaeed69c..07cf9ac55 100644 --- a/package.json +++ b/package.json @@ -84,6 +84,9 @@ "solarized-dark-syntax": "0.35.0", "solarized-light-syntax": "0.21.0", "archive-view": "0.57.0", + "autocomplete-atom-api": "0.9.0", + "autocomplete-css": "0.7.2", + "autocomplete-html": "0.7.1", "autocomplete-plus": "2.13.1", "autoflow": "0.23.0", "autosave": "0.20.0", From e7d921bfbc93b6e05c77d766130d64a165e5e83f Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 11 May 2015 16:21:35 -0700 Subject: [PATCH 1110/1783] Add specs for autocomplete deletion --- spec/package-manager-spec.coffee | 33 ++++++++++++++++++++++++++++++++ spec/spec-helper.coffee | 2 ++ 2 files changed, 35 insertions(+) diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 92dc21a13..00b05c102 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -824,3 +824,36 @@ describe "PackageManager", -> expect(atom.config.get('core.themes')).not.toContain packageName expect(atom.config.get('core.themes')).not.toContain packageName expect(atom.config.get('core.disabledPackages')).not.toContain packageName + + describe "deleting non-bundled autocomplete packages", -> + [autocompleteCSSPath, autocompletePlusPath] = [] + fs = require 'fs-plus' + path = require 'path' + + beforeEach -> + fixturePath = path.resolve(__dirname, './fixtures/packages') + autocompleteCSSPath = path.join(fixturePath, 'autocomplete-css') + autocompletePlusPath = path.join(fixturePath, 'autocomplete-plus') + + try + fs.mkdirSync(autocompleteCSSPath) + fs.writeFileSync(path.join(autocompleteCSSPath, 'package.json'), '{}') + fs.symlinkSync(path.join(fixturePath, 'package-with-main'), autocompletePlusPath, 'dir') + catch e + ; + + expect(fs.isDirectorySync(autocompleteCSSPath)).toBe true + expect(fs.isSymbolicLinkSync(autocompletePlusPath)).toBe true + + jasmine.unspy(atom.packages, 'uninstallAutocompletePlus') + + it "removes the packages", -> + atom.packages.loadPackages() + + waitsFor -> + not fs.isDirectorySync(autocompleteCSSPath) and + not fs.isSymbolicLinkSync(autocompletePlusPath) + + runs -> + expect(fs.isDirectorySync(autocompleteCSSPath)).toBe false + expect(fs.isSymbolicLinkSync(autocompletePlusPath)).toBe false diff --git a/spec/spec-helper.coffee b/spec/spec-helper.coffee index 0112042e2..2e4355a10 100644 --- a/spec/spec-helper.coffee +++ b/spec/spec-helper.coffee @@ -140,6 +140,8 @@ beforeEach -> spyOn(clipboard, 'writeText').andCallFake (text) -> clipboardContent = text spyOn(clipboard, 'readText').andCallFake -> clipboardContent + spyOn(atom.packages, 'uninstallAutocompletePlus') + addCustomMatchers(this) afterEach -> From b83b9bab074f5628f41513a0f11bf0c1d33be7cb Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 11 May 2015 16:21:51 -0700 Subject: [PATCH 1111/1783] Handle deleting multiple directories --- src/package-manager.coffee | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 7ee1304c2..60a6f7f20 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -417,14 +417,35 @@ class PackageManager packageDir = null devDir = path.join("dev", "packages") for packageDirPath in @packageDirPaths - packageDir = packageDirPath if not packageDirPath.endsWith(devDir) + if not packageDirPath.endsWith(devDir) + packageDir = packageDirPath + break if packageDir? - autocompletePlusPath = path.join(packageDir, 'autocomplete-plus') - if fs.isSymbolicLinkSync(autocompletePlusPath) - fs.unlink(autocompletePlusPath) - else if fs.isDirectorySync(autocompletePlusPath) - fs.remove(autocompletePlusPath, ->) + dirsToRemove = [ + path.join(packageDir, 'autocomplete-plus') + path.join(packageDir, 'autocomplete-atom-api') + path.join(packageDir, 'autocomplete-css') + path.join(packageDir, 'autocomplete-html') + ] + for dirToRemove in dirsToRemove + @uninstallDirectory(dirToRemove) + return + + uninstallDirectory: (directory) -> + symlinkPromise = new Promise (resolve) -> + fs.isSymbolicLink directory, (isSymLink) -> resolve(isSymLink) + + dirPromise = new Promise (resolve) -> + fs.isDirectory directory, (isDir) -> resolve(isDir) + + Promise.all([symlinkPromise, dirPromise]).then (values) -> + [isSymLink, isDir] = values + console.log directory, isSymLink, isDir + if isSymLink + fs.unlink(directory) + else if isDir + fs.remove(directory, ->) if Grim.includeDeprecatedAPIs EmitterMixin = require('emissary').Emitter From c571e3da0caeb43c2192450af44a502681378394 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 11 May 2015 16:25:23 -0700 Subject: [PATCH 1112/1783] Remove log line --- src/package-manager.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 60a6f7f20..32e55aecd 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -441,7 +441,6 @@ class PackageManager Promise.all([symlinkPromise, dirPromise]).then (values) -> [isSymLink, isDir] = values - console.log directory, isSymLink, isDir if isSymLink fs.unlink(directory) else if isDir From 3b03ef5a0b63d42732d0bd043c2d73bcbd3a4f6c Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 11 May 2015 16:36:09 -0700 Subject: [PATCH 1113/1783] :arrow_up: autocomplete-plus@2.14.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 07cf9ac55..9972dca62 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "autocomplete-atom-api": "0.9.0", "autocomplete-css": "0.7.2", "autocomplete-html": "0.7.1", - "autocomplete-plus": "2.13.1", + "autocomplete-plus": "2.14.0", "autoflow": "0.23.0", "autosave": "0.20.0", "background-tips": "0.24.0", From dd45a6f3abda2bd7cb453b465d654daf9c835b6c Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 11 May 2015 16:42:17 -0700 Subject: [PATCH 1114/1783] No parens around fn --- src/package-manager.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 32e55aecd..192c1484e 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -444,7 +444,7 @@ class PackageManager if isSymLink fs.unlink(directory) else if isDir - fs.remove(directory, ->) + fs.remove directory, -> if Grim.includeDeprecatedAPIs EmitterMixin = require('emissary').Emitter From b0c9a93420886d8fcd3dc13995d83e475efe4ab6 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 11 May 2015 16:54:14 -0700 Subject: [PATCH 1115/1783] Fix another lint error --- spec/package-manager-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 00b05c102..89e97f219 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -840,7 +840,7 @@ describe "PackageManager", -> fs.writeFileSync(path.join(autocompleteCSSPath, 'package.json'), '{}') fs.symlinkSync(path.join(fixturePath, 'package-with-main'), autocompletePlusPath, 'dir') catch e - ; + undefined expect(fs.isDirectorySync(autocompleteCSSPath)).toBe true expect(fs.isSymbolicLinkSync(autocompletePlusPath)).toBe true From 95ba6d5fa99f0c11c56c2d7ebf25b4ba1d7b1c67 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 11 May 2015 18:47:42 -0700 Subject: [PATCH 1116/1783] Bundle autocomplete-snippets --- package.json | 1 + src/package-manager.coffee | 1 + 2 files changed, 2 insertions(+) diff --git a/package.json b/package.json index 9972dca62..dd8c2fff6 100644 --- a/package.json +++ b/package.json @@ -88,6 +88,7 @@ "autocomplete-css": "0.7.2", "autocomplete-html": "0.7.1", "autocomplete-plus": "2.14.0", + "autocomplete-snippets": "1.6.1", "autoflow": "0.23.0", "autosave": "0.20.0", "background-tips": "0.24.0", diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 192c1484e..75005fe11 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -427,6 +427,7 @@ class PackageManager path.join(packageDir, 'autocomplete-atom-api') path.join(packageDir, 'autocomplete-css') path.join(packageDir, 'autocomplete-html') + path.join(packageDir, 'autocomplete-snippets') ] for dirToRemove in dirsToRemove @uninstallDirectory(dirToRemove) From a99d9bf24b936624f878d07e805261f12308e62b Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 11 May 2015 18:48:00 -0700 Subject: [PATCH 1117/1783] :arrow_up: autocomplete-plus@2.14.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dd8c2fff6..c3c76d599 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "autocomplete-atom-api": "0.9.0", "autocomplete-css": "0.7.2", "autocomplete-html": "0.7.1", - "autocomplete-plus": "2.14.0", + "autocomplete-plus": "2.14.1", "autocomplete-snippets": "1.6.1", "autoflow": "0.23.0", "autosave": "0.20.0", From 326255e6ef98cb02fd629d75a04e1618a182b94d Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 12 May 2015 09:57:46 -0700 Subject: [PATCH 1118/1783] Add callback to unlink --- src/package-manager.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 75005fe11..7789d7590 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -443,7 +443,7 @@ class PackageManager Promise.all([symlinkPromise, dirPromise]).then (values) -> [isSymLink, isDir] = values if isSymLink - fs.unlink(directory) + fs.unlink directory, -> else if isDir fs.remove directory, -> From ef224e39dba2e44ce7ce00154cd1b7eb01fb072a Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 12 May 2015 09:57:50 -0700 Subject: [PATCH 1119/1783] Remove catch --- spec/package-manager-spec.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 89e97f219..1cd961936 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -839,8 +839,6 @@ describe "PackageManager", -> fs.mkdirSync(autocompleteCSSPath) fs.writeFileSync(path.join(autocompleteCSSPath, 'package.json'), '{}') fs.symlinkSync(path.join(fixturePath, 'package-with-main'), autocompletePlusPath, 'dir') - catch e - undefined expect(fs.isDirectorySync(autocompleteCSSPath)).toBe true expect(fs.isSymbolicLinkSync(autocompletePlusPath)).toBe true From 4a2c3e90ba332beb37ed32266181e52cdd9dc4ab Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 12 May 2015 10:24:29 -0700 Subject: [PATCH 1120/1783] Bundle autocomplete-emojis --- package.json | 1 + src/package-manager.coffee | 1 + 2 files changed, 2 insertions(+) diff --git a/package.json b/package.json index c3c76d599..4261d4f29 100644 --- a/package.json +++ b/package.json @@ -86,6 +86,7 @@ "archive-view": "0.57.0", "autocomplete-atom-api": "0.9.0", "autocomplete-css": "0.7.2", + "autocomplete-emojis": "2.2.2", "autocomplete-html": "0.7.1", "autocomplete-plus": "2.14.1", "autocomplete-snippets": "1.6.1", diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 7789d7590..1262aa59e 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -427,6 +427,7 @@ class PackageManager path.join(packageDir, 'autocomplete-atom-api') path.join(packageDir, 'autocomplete-css') path.join(packageDir, 'autocomplete-html') + path.join(packageDir, 'autocomplete-emojis') path.join(packageDir, 'autocomplete-snippets') ] for dirToRemove in dirsToRemove From 400fb0cf6d0b2a73aaa1a88f8253d47d8386096f Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 12 May 2015 16:00:48 -0700 Subject: [PATCH 1121/1783] :arrow_up: autocomplete-plus@2.14.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4261d4f29..a92f48caf 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,7 @@ "autocomplete-css": "0.7.2", "autocomplete-emojis": "2.2.2", "autocomplete-html": "0.7.1", - "autocomplete-plus": "2.14.1", + "autocomplete-plus": "2.14.2", "autocomplete-snippets": "1.6.1", "autoflow": "0.23.0", "autosave": "0.20.0", From d72376aac0bc560983bc489972d7ada420242136 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 13 May 2015 09:16:53 -0700 Subject: [PATCH 1122/1783] :arrow_up: autocomplete-plus@2.15.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a92f48caf..b03c372e7 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,7 @@ "autocomplete-css": "0.7.2", "autocomplete-emojis": "2.2.2", "autocomplete-html": "0.7.1", - "autocomplete-plus": "2.14.2", + "autocomplete-plus": "2.15.0", "autocomplete-snippets": "1.6.1", "autoflow": "0.23.0", "autosave": "0.20.0", From f5078a16e3f7fd532e7b21c1c43834034821c009 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 12 May 2015 11:20:41 -0700 Subject: [PATCH 1123/1783] Remove default background style --- static/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/index.html b/static/index.html index 5559058dc..062a2db29 100644 --- a/static/index.html +++ b/static/index.html @@ -1,5 +1,5 @@ - + From 87db62a70b005969b84139f49eea23cd3da774aa Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 12 May 2015 11:20:56 -0700 Subject: [PATCH 1124/1783] Remove empty title element --- static/index.html | 2 -- 1 file changed, 2 deletions(-) diff --git a/static/index.html b/static/index.html index 062a2db29..84e8d57d4 100644 --- a/static/index.html +++ b/static/index.html @@ -1,8 +1,6 @@ - - From 22544688559761e48c38eaaa0293cf8e678e5e12 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 12 May 2015 11:21:25 -0700 Subject: [PATCH 1125/1783] Show window as early as possible --- src/atom.coffee | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/atom.coffee b/src/atom.coffee index 1cf63b397..c14e5517d 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -196,6 +196,10 @@ class Atom extends Model # # Call after this instance has been assigned to the `atom` global. initialize: -> + dimensions = @restoreWindowDimensions() + maximize = dimensions?.maximized and process.platform isnt 'darwin' + @displayWindow({maximize}) + sourceMapCache = {} window.onerror = => @@ -483,7 +487,10 @@ class Atom extends Model # Extended: Set the full screen state of the current window. setFullScreen: (fullScreen=false) -> ipc.send('call-window-method', 'setFullScreen', fullScreen) - if fullScreen then document.body.classList.add("fullscreen") else document.body.classList.remove("fullscreen") + if fullScreen + document.body.classList.add("fullscreen") + else + document.body.classList.remove("fullscreen") # Extended: Toggle the full screen state of the current window. toggleFullScreen: -> @@ -494,8 +501,9 @@ class Atom extends Model # This is done in a next tick to prevent a white flicker from occurring # if called synchronously. displayWindow: ({maximize}={}) -> + @show() + setImmediate => - @show() @focus() @setFullScreen(true) if @workspace.fullScreen @maximize() if maximize @@ -582,7 +590,6 @@ class Atom extends Model CommandInstaller.installApmCommand false, (error) -> console.warn error.message if error? - dimensions = @restoreWindowDimensions() @loadConfig() @keymaps.loadBundledKeymaps() @themes.loadBaseStylesheets() @@ -602,9 +609,6 @@ class Atom extends Model @openInitialEmptyEditorIfNecessary() - maximize = dimensions?.maximized and process.platform isnt 'darwin' - @displayWindow({maximize}) - unloadEditorWindow: -> return if not @project From 943df493005531e4bae0a8bd635357f8e17fa5b7 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 12 May 2015 11:53:04 -0700 Subject: [PATCH 1126/1783] Read/write window background in local storage --- src/atom.coffee | 12 ++++++++++-- static/index.js | 24 ++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/atom.coffee b/src/atom.coffee index c14e5517d..7ce43df66 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -282,7 +282,9 @@ class Atom extends Model deprecate "The atom.syntax global is deprecated. Use atom.grammars instead." @grammars - @disposables.add @packages.onDidActivateInitialPackages => @watchThemes() + @disposables.add @packages.onDidActivateInitialPackages => + @watchThemes() + @storeWindowBackground() Project = require './project' TextBuffer = require 'text-buffer' @@ -580,6 +582,11 @@ class Atom extends Model dimensions = @getWindowDimensions() @state.windowDimensions = dimensions if @isValidDimensions(dimensions) + storeWindowBackground: -> + workspaceElement = @views?.getView(@workspace) + backgroundColor = window.getComputedStyle(workspaceElement)['background-color'] + window.localStorage.setItem('atom:window-background-color', backgroundColor) + # Call this method when establishing a real application window. startEditorWindow: -> {safeMode} = @getLoadSettings() @@ -751,7 +758,8 @@ class Atom extends Model # Only reload stylesheets from non-theme packages for pack in @packages.getActivePackages() when pack.getType() isnt 'theme' pack.reloadStylesheets?() - null + @storeWindowBackground() + return # Notify the browser project of the window's current project path watchProjectPath: -> diff --git a/static/index.js b/static/index.js index 0a377044e..b2e580c80 100644 --- a/static/index.js +++ b/static/index.js @@ -43,6 +43,7 @@ window.onload = function() { } } + var setLoadTime = function(loadTime) { if (global.atom) { global.atom.loadTime = loadTime; @@ -162,3 +163,26 @@ var profileStartup = function(cacheDir, loadSettings, initialTime) { }); } } + +var setupWindowBackground = function() { + var backgroundColor = window.localStorage.getItem('atom:window-background-color'); + if (!backgroundColor) { + return; + } + + var backgroundStylesheet = document.createElement('style'); + backgroundStylesheet.type = 'text/css'; + backgroundStylesheet.innerText = 'html, body { background: ' + backgroundColor + ' }'; + document.head.appendChild(backgroundStylesheet); + + // Remove once the page loads + window.addEventListener("load", function loadWindow() { + window.removeEventListener("load", loadWindow, false); + setTimeout(function() { + backgroundStylesheet.remove(); + backgroundStylesheet = null; + }, 1000); + }, false); +} + +setupWindowBackground(); From ded24387008d0ef9d4d19397202f90ade5ae286e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 12 May 2015 16:15:26 -0700 Subject: [PATCH 1127/1783] Add ; to inline style --- static/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/index.js b/static/index.js index b2e580c80..63fa503ee 100644 --- a/static/index.js +++ b/static/index.js @@ -172,7 +172,7 @@ var setupWindowBackground = function() { var backgroundStylesheet = document.createElement('style'); backgroundStylesheet.type = 'text/css'; - backgroundStylesheet.innerText = 'html, body { background: ' + backgroundColor + ' }'; + backgroundStylesheet.innerText = 'html, body { background: ' + backgroundColor + '; }'; document.head.appendChild(backgroundStylesheet); // Remove once the page loads From 87fd2ec188d80ea8148edcbe71b33f7d0e345542 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 12 May 2015 16:19:33 -0700 Subject: [PATCH 1128/1783] Store background on unload --- src/atom.coffee | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/atom.coffee b/src/atom.coffee index 7ce43df66..6b9beb64c 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -282,9 +282,7 @@ class Atom extends Model deprecate "The atom.syntax global is deprecated. Use atom.grammars instead." @grammars - @disposables.add @packages.onDidActivateInitialPackages => - @watchThemes() - @storeWindowBackground() + @disposables.add @packages.onDidActivateInitialPackages => @watchThemes() Project = require './project' TextBuffer = require 'text-buffer' @@ -619,6 +617,7 @@ class Atom extends Model unloadEditorWindow: -> return if not @project + @storeWindowBackground() @state.grammars = @grammars.serialize() @state.project = @project.serialize() @state.workspace = @workspace.serialize() @@ -758,7 +757,6 @@ class Atom extends Model # Only reload stylesheets from non-theme packages for pack in @packages.getActivePackages() when pack.getType() isnt 'theme' pack.reloadStylesheets?() - @storeWindowBackground() return # Notify the browser project of the window's current project path From a0abd9ebe438cd478f7925378ebbdc0c5fa0cd11 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 12 May 2015 16:20:17 -0700 Subject: [PATCH 1129/1783] :art: --- static/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/static/index.js b/static/index.js index 63fa503ee..c00fe4c14 100644 --- a/static/index.js +++ b/static/index.js @@ -43,7 +43,6 @@ window.onload = function() { } } - var setLoadTime = function(loadTime) { if (global.atom) { global.atom.loadTime = loadTime; From 88c1c8404e0ac4fe6bfcab9dcef948d1d7399088 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 12 May 2015 16:22:31 -0700 Subject: [PATCH 1130/1783] Display window after wiring up windor.onerror --- src/atom.coffee | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/atom.coffee b/src/atom.coffee index 6b9beb64c..eec652f39 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -196,10 +196,6 @@ class Atom extends Model # # Call after this instance has been assigned to the `atom` global. initialize: -> - dimensions = @restoreWindowDimensions() - maximize = dimensions?.maximized and process.platform isnt 'darwin' - @displayWindow({maximize}) - sourceMapCache = {} window.onerror = => @@ -227,6 +223,10 @@ class Atom extends Model @disposables?.dispose() @disposables = new CompositeDisposable + dimensions = @restoreWindowDimensions() + maximize = dimensions?.maximized and process.platform isnt 'darwin' + @displayWindow({maximize}) + @setBodyPlatformClass() @loadTime = null From 104bece1191f04d1359df3586ae7662560ae2c07 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 12 May 2015 16:47:56 -0700 Subject: [PATCH 1131/1783] Add restoreWindow helper --- src/atom.coffee | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/atom.coffee b/src/atom.coffee index eec652f39..c963cd8a4 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -223,9 +223,8 @@ class Atom extends Model @disposables?.dispose() @disposables = new CompositeDisposable - dimensions = @restoreWindowDimensions() - maximize = dimensions?.maximized and process.platform isnt 'darwin' - @displayWindow({maximize}) + @restoreWindow() + @show() @setBodyPlatformClass() @@ -496,16 +495,17 @@ class Atom extends Model toggleFullScreen: -> @setFullScreen(not @isFullScreen()) - # Schedule the window to be shown and focused on the next tick. + # Restore the window to its previous dimensions. # - # This is done in a next tick to prevent a white flicker from occurring - # if called synchronously. - displayWindow: ({maximize}={}) -> - @show() + # Also restores the full screen and maximized state on the next tick to + # prevent resize glitches. + restoreWindow: -> + dimensions = @restoreWindowDimensions() + maximize = dimensions?.maximized and process.platform isnt 'darwin' setImmediate => @focus() - @setFullScreen(true) if @workspace.fullScreen + @setFullScreen(true) if @workspace?.fullScreen @maximize() if maximize # Get the dimensions of this window. From 10c65b53f98cf76a7c87607d5bc0b5fbb5de3dea Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 12 May 2015 16:50:29 -0700 Subject: [PATCH 1132/1783] Don't store background for spec windows --- src/atom.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/atom.coffee b/src/atom.coffee index c963cd8a4..0e8f85f5e 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -581,6 +581,8 @@ class Atom extends Model @state.windowDimensions = dimensions if @isValidDimensions(dimensions) storeWindowBackground: -> + return if @inSpecMode() + workspaceElement = @views?.getView(@workspace) backgroundColor = window.getComputedStyle(workspaceElement)['background-color'] window.localStorage.setItem('atom:window-background-color', backgroundColor) From 8439099a06b97cd667aac1186f41e896aa714c3e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 12 May 2015 16:54:01 -0700 Subject: [PATCH 1133/1783] Call show from within restoreWindow --- src/atom.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/atom.coffee b/src/atom.coffee index 0e8f85f5e..c8b9c718f 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -224,7 +224,6 @@ class Atom extends Model @disposables = new CompositeDisposable @restoreWindow() - @show() @setBodyPlatformClass() @@ -501,6 +500,8 @@ class Atom extends Model # prevent resize glitches. restoreWindow: -> dimensions = @restoreWindowDimensions() + @show() + maximize = dimensions?.maximized and process.platform isnt 'darwin' setImmediate => From 2707b09f00a55d3e8f52e9714c4682f27488a84b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 12 May 2015 16:54:48 -0700 Subject: [PATCH 1134/1783] restoreWindow -> displayWindow --- src/atom.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/atom.coffee b/src/atom.coffee index c8b9c718f..b33461034 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -223,7 +223,7 @@ class Atom extends Model @disposables?.dispose() @disposables = new CompositeDisposable - @restoreWindow() + @displayWindow() @setBodyPlatformClass() @@ -494,11 +494,11 @@ class Atom extends Model toggleFullScreen: -> @setFullScreen(not @isFullScreen()) - # Restore the window to its previous dimensions. + # Restore the window to its previous dimensions and show it. # # Also restores the full screen and maximized state on the next tick to # prevent resize glitches. - restoreWindow: -> + displayWindow: -> dimensions = @restoreWindowDimensions() @show() From 1f9f17f9ff24d95e5234c40a9c9c7e4991b022e9 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 12 May 2015 17:41:00 -0700 Subject: [PATCH 1135/1783] Don't display window in spec mode --- src/atom.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/atom.coffee b/src/atom.coffee index b33461034..36e40e923 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -223,7 +223,7 @@ class Atom extends Model @disposables?.dispose() @disposables = new CompositeDisposable - @displayWindow() + @displayWindow() unless @inSpecMode() @setBodyPlatformClass() From 42004ce770c2d6f64c972ce68651e28752d2b011 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 12 May 2015 17:48:40 -0700 Subject: [PATCH 1136/1783] Remove unneeded ? --- src/atom.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/atom.coffee b/src/atom.coffee index 36e40e923..702973cd9 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -584,7 +584,7 @@ class Atom extends Model storeWindowBackground: -> return if @inSpecMode() - workspaceElement = @views?.getView(@workspace) + workspaceElement = @views.getView(@workspace) backgroundColor = window.getComputedStyle(workspaceElement)['background-color'] window.localStorage.setItem('atom:window-background-color', backgroundColor) From fff546a1e5abeeda2542cba4cbbd6463903d31fe Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 13 May 2015 09:47:10 -0700 Subject: [PATCH 1137/1783] Don't set background of spec windows --- static/index.js | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/static/index.js b/static/index.js index c00fe4c14..a656ac501 100644 --- a/static/index.js +++ b/static/index.js @@ -1,6 +1,9 @@ var fs = require('fs'); var path = require('path'); +var loadSettings = null; +var loadSettingsError = null; + window.onload = function() { try { var startTime = Date.now(); @@ -18,18 +21,13 @@ window.onload = function() { cacheDir = path.join(cacheDir, 'root'); } - var rawLoadSettings = decodeURIComponent(location.hash.substr(1)); - var loadSettings; - try { - loadSettings = JSON.parse(rawLoadSettings); - } catch (error) { - console.error("Failed to parse load settings: " + rawLoadSettings); - throw error; - } - // Normalize to make sure drive letter case is consistent on Windows process.resourcesPath = path.normalize(process.resourcesPath); + if (loadSettingsError) { + throw loadSettingsError; + } + var devMode = loadSettings.devMode || !loadSettings.resourcePath.startsWith(process.resourcesPath + path.sep); if (loadSettings.profileStartup) { @@ -163,7 +161,24 @@ var profileStartup = function(cacheDir, loadSettings, initialTime) { } } +var parseLoadSettings = function() { + var rawLoadSettings = decodeURIComponent(location.hash.substr(1)); + try { + loadSettings = JSON.parse(rawLoadSettings); + } catch (error) { + loadSettingsError = error; + } + + if (!loadSettings || typeof loadSettings !== 'object') { + loadSettings = {}; + } +} + var setupWindowBackground = function() { + if (loadSettings.isSpec) { + return; + } + var backgroundColor = window.localStorage.getItem('atom:window-background-color'); if (!backgroundColor) { return; @@ -184,4 +199,5 @@ var setupWindowBackground = function() { }, false); } +parseLoadSettings(); setupWindowBackground(); From f989981d194743dc860ba9009a17a1ecee23c081 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 13 May 2015 09:50:11 -0700 Subject: [PATCH 1138/1783] Extract getCacheDirectory helper --- static/index.js | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/static/index.js b/static/index.js index a656ac501..7d9bf4467 100644 --- a/static/index.js +++ b/static/index.js @@ -15,12 +15,6 @@ window.onload = function() { // Ensure ATOM_HOME is always set before anything else is required setupAtomHome(); - var cacheDir = path.join(process.env.ATOM_HOME, 'compile-cache'); - // Use separate compile cache when sudo'ing as root to avoid permission issues - if (process.env.USER === 'root' && process.env.SUDO_USER && process.env.SUDO_USER !== process.env.USER) { - cacheDir = path.join(cacheDir, 'root'); - } - // Normalize to make sure drive letter case is consistent on Windows process.resourcesPath = path.normalize(process.resourcesPath); @@ -31,9 +25,9 @@ window.onload = function() { var devMode = loadSettings.devMode || !loadSettings.resourcePath.startsWith(process.resourcesPath + path.sep); if (loadSettings.profileStartup) { - profileStartup(cacheDir, loadSettings, Date.now() - startTime); + profileStartup(loadSettings, Date.now() - startTime); } else { - setupWindow(cacheDir, loadSettings); + setupWindow(loadSettings); setLoadTime(Date.now() - startTime); } } catch (error) { @@ -41,6 +35,15 @@ window.onload = function() { } } +var getCacheDirectory = function() { + var cacheDir = path.join(process.env.ATOM_HOME, 'compile-cache'); + // Use separate compile cache when sudo'ing as root to avoid permission issues + if (process.env.USER === 'root' && process.env.SUDO_USER && process.env.SUDO_USER !== process.env.USER) { + cacheDir = path.join(cacheDir, 'root'); + } + return cacheDir; +} + var setLoadTime = function(loadTime) { if (global.atom) { global.atom.loadTime = loadTime; @@ -57,7 +60,9 @@ var handleSetupError = function(error) { console.error(error.stack || error); } -var setupWindow = function(cacheDir, loadSettings) { +var setupWindow = function(loadSettings) { + var cacheDir = getCacheDirectory(); + setupCoffeeCache(cacheDir); ModuleCache = require('../src/module-cache'); @@ -131,16 +136,17 @@ var setupSourceMapCache = function(cacheDir) { var setupVmCompatibility = function() { var vm = require('vm'); - if (!vm.Script.createContext) + if (!vm.Script.createContext) { vm.Script.createContext = vm.createContext; + } } -var profileStartup = function(cacheDir, loadSettings, initialTime) { +var profileStartup = function(loadSettings, initialTime) { var profile = function() { console.profile('startup'); try { var startTime = Date.now() - setupWindow(cacheDir, loadSettings); + setupWindow(loadSettings); setLoadTime(Date.now() - startTime + initialTime); } catch (error) { handleSetupError(error); From f2c50bfd9e6a9a7f12af73afc8c692dbbe4f2292 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 13 May 2015 10:00:34 -0700 Subject: [PATCH 1139/1783] Remove unneeded loadSettings validation --- static/index.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/static/index.js b/static/index.js index 7d9bf4467..b0dd1c3c1 100644 --- a/static/index.js +++ b/static/index.js @@ -174,14 +174,10 @@ var parseLoadSettings = function() { } catch (error) { loadSettingsError = error; } - - if (!loadSettings || typeof loadSettings !== 'object') { - loadSettings = {}; - } } var setupWindowBackground = function() { - if (loadSettings.isSpec) { + if (loadSettings && loadSettings.isSpec) { return; } From 41d3764189d1d9737eb5b4408231be624e3997eb Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 13 May 2015 10:09:34 -0700 Subject: [PATCH 1140/1783] :art: --- src/atom.coffee | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/atom.coffee b/src/atom.coffee index 702973cd9..0d029b61d 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -502,12 +502,10 @@ class Atom extends Model dimensions = @restoreWindowDimensions() @show() - maximize = dimensions?.maximized and process.platform isnt 'darwin' - setImmediate => @focus() @setFullScreen(true) if @workspace?.fullScreen - @maximize() if maximize + @maximize() if dimensions?.maximized and process.platform isnt 'darwin' # Get the dimensions of this window. # From 9f2faa086b5de07e13620ad3fab8142cec3e4f1a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 13 May 2015 10:11:46 -0700 Subject: [PATCH 1141/1783] Add back raw load settings logging --- static/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/static/index.js b/static/index.js index b0dd1c3c1..ef61e8bce 100644 --- a/static/index.js +++ b/static/index.js @@ -172,6 +172,7 @@ var parseLoadSettings = function() { try { loadSettings = JSON.parse(rawLoadSettings); } catch (error) { + console.error("Failed to parse load settings: " + rawLoadSettings); loadSettingsError = error; } } From ef6c16de76a8f646266494639cc6ddd4879ee36b Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 13 May 2015 10:24:03 -0700 Subject: [PATCH 1142/1783] :fire: dead code for handling deferred marker change events --- src/marker.coffee | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/marker.coffee b/src/marker.coffee index 813ca78e5..942e25606 100644 --- a/src/marker.coffee +++ b/src/marker.coffee @@ -48,7 +48,6 @@ class Marker oldTailBufferPosition: null oldTailScreenPosition: null wasValid: true - deferredChangeEvents: null ### Section: Construction and Destruction @@ -332,11 +331,11 @@ class Marker newTailScreenPosition = @getTailScreenPosition() isValid = @isValid() - return if _.isEqual(isValid, @wasValid) and - _.isEqual(newHeadBufferPosition, @oldHeadBufferPosition) and - _.isEqual(newHeadScreenPosition, @oldHeadScreenPosition) and - _.isEqual(newTailBufferPosition, @oldTailBufferPosition) and - _.isEqual(newTailScreenPosition, @oldTailScreenPosition) + return if isValid is @wasValid and + newHeadBufferPosition.isEqual(@oldHeadBufferPosition) and + newHeadScreenPosition.isEqual(@oldHeadScreenPosition) and + newTailBufferPosition.isEqual(@oldTailBufferPosition) and + newTailScreenPosition.isEqual(@oldTailScreenPosition) changeEvent = { @oldHeadScreenPosition, newHeadScreenPosition, @@ -347,11 +346,8 @@ class Marker isValid } - if @deferredChangeEvents? - @deferredChangeEvents.push(changeEvent) - else - @emit 'changed', changeEvent if Grim.includeDeprecatedAPIs - @emitter.emit 'did-change', changeEvent + @emit 'changed', changeEvent if Grim.includeDeprecatedAPIs + @emitter.emit 'did-change', changeEvent @oldHeadBufferPosition = newHeadBufferPosition @oldHeadScreenPosition = newHeadScreenPosition From 1edeb7b56869f9489b51bfd3fd4a5ddae3c7bd76 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 7 May 2015 09:50:12 -0700 Subject: [PATCH 1143/1783] Save list of open windows as windows are added/removed --- src/browser/atom-application.coffee | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 0e7ff9f4d..20ebf84f9 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -100,6 +100,7 @@ class AtomApplication removeWindow: (window) -> @windows.splice @windows.indexOf(window), 1 @applicationMenu?.enableWindowSpecificItems(false) if @windows.length is 0 + @saveState() # Public: Adds the {AtomWindow} to the global window list. addWindow: (window) -> @@ -114,6 +115,7 @@ class AtomApplication window.browserWindow.once 'closed', => @lastFocusedWindow = null if window is @lastFocusedWindow window.browserWindow.removeListener 'focus', focusHandler + window.browserWindow.webContents.once 'did-finish-load', => @saveState() # Creates server to listen for additional atom application launches. # @@ -202,9 +204,6 @@ class AtomApplication app.on 'window-all-closed', -> app.quit() if process.platform in ['win32', 'linux'] - app.on 'before-quit', => - @saveState() - app.on 'will-quit', => @killAllProcesses() @deleteSocketFile() From 725a564e626eb98802c54f82c618aea3dd784507 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 7 May 2015 10:44:58 -0700 Subject: [PATCH 1144/1783] Avoid saving windows state when quitting on windows/linux --- src/browser/atom-application.coffee | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 20ebf84f9..3a36b8b72 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -99,7 +99,11 @@ class AtomApplication # Public: Removes the {AtomWindow} from the global window list. removeWindow: (window) -> @windows.splice @windows.indexOf(window), 1 - @applicationMenu?.enableWindowSpecificItems(false) if @windows.length is 0 + if @windows.length is 0 + @applicationMenu?.enableWindowSpecificItems(false) + if process.platform in ['win32', 'linux'] + app.quit() + return @saveState() # Public: Adds the {AtomWindow} to the global window list. @@ -201,9 +205,6 @@ class AtomApplication @openPathOnEvent('application:open-your-stylesheet', 'atom://.atom/stylesheet') @openPathOnEvent('application:open-license', path.join(process.resourcesPath, 'LICENSE.md')) - app.on 'window-all-closed', -> - app.quit() if process.platform in ['win32', 'linux'] - app.on 'will-quit', => @killAllProcesses() @deleteSocketFile() From 62c406f4507c768eebae78ed6ae766517ebe482b Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 7 May 2015 11:10:01 -0700 Subject: [PATCH 1145/1783] Save open window state when a window loses focus --- src/browser/atom-application.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 3a36b8b72..d7a8b0b5b 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -115,10 +115,13 @@ class AtomApplication unless window.isSpec focusHandler = => @lastFocusedWindow = window + blurHandler = => @saveState() window.browserWindow.on 'focus', focusHandler + window.browserWindow.on 'blur', blurHandler window.browserWindow.once 'closed', => @lastFocusedWindow = null if window is @lastFocusedWindow window.browserWindow.removeListener 'focus', focusHandler + window.browserWindow.removeListener 'blur', blurHandler window.browserWindow.webContents.once 'did-finish-load', => @saveState() # Creates server to listen for additional atom application launches. From 8ddfa8690b9c8825409627990abc9311853eb96f Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 7 May 2015 15:31:44 -0700 Subject: [PATCH 1146/1783] Save window state when atom.exit() is called --- 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 d7a8b0b5b..deccae4ee 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -213,6 +213,7 @@ class AtomApplication @deleteSocketFile() app.on 'will-exit', => + @saveState() @killAllProcesses() @deleteSocketFile() From 6026c78d9e0acf2a67e56dca4eba81fb97f1dd70 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 11 May 2015 09:20:07 -0700 Subject: [PATCH 1147/1783] Don't save window state when closing spec windows --- src/browser/atom-application.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index deccae4ee..b423544cc 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -104,7 +104,7 @@ class AtomApplication if process.platform in ['win32', 'linux'] app.quit() return - @saveState() + @saveState() unless window.isSpec # Public: Adds the {AtomWindow} to the global window list. addWindow: (window) -> From dabf5b5f693545bfb3cad36f82595d3515e4d040 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 13 May 2015 10:46:14 -0700 Subject: [PATCH 1148/1783] Don't save windows state when apm test finishes --- src/browser/atom-application.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index b423544cc..af6a45763 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -213,7 +213,7 @@ class AtomApplication @deleteSocketFile() app.on 'will-exit', => - @saveState() + @saveState() unless @windows.every (window) -> window.isSpec @killAllProcesses() @deleteSocketFile() @@ -426,8 +426,8 @@ class AtomApplication saveState: -> states = [] for window in @windows - if loadSettings = window.getLoadSettings() - unless loadSettings.isSpec + unless window.isSpec + if loadSettings = window.getLoadSettings() states.push(initialPaths: loadSettings.initialPaths) @storageFolder.store('application.json', states) From 8fc6d2049308a576459999d7a4ffd1cbab6e90fd Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Tue, 12 May 2015 15:03:38 -0700 Subject: [PATCH 1149/1783] [Gutter] Create separate state for shared gutter styles, and copy into @state.gutters.sortedDescriptions --- src/text-editor-presenter.coffee | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index ac6d0c363..9253c4b5f 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -213,6 +213,9 @@ class TextEditorPresenter customDecorations: {} lineNumberGutter: lineNumbers: {} + # Shared state that is copied into ``@state.gutters`. + @sharedGutterStyles = {} + @updateState() updateState: -> @@ -251,11 +254,13 @@ class TextEditorPresenter updateVerticalScrollState: -> @state.content.scrollHeight = @scrollHeight - @state.gutters.scrollHeight = @scrollHeight + @state.gutters.scrollHeight = @scrollHeight # TODO jssln Remove + @sharedGutterStyles.scrollHeight = @scrollHeight @state.verticalScrollbar.scrollHeight = @scrollHeight @state.content.scrollTop = @scrollTop - @state.gutters.scrollTop = @scrollTop + @state.gutters.scrollTop = @scrollTop # TODO jssln Remove + @sharedGutterStyles.scrollTop = @scrollTop @state.verticalScrollbar.scrollTop = @scrollTop updateHorizontalScrollState: -> @@ -413,10 +418,11 @@ class TextEditorPresenter @state.gutters.lineNumberGutter.maxLineNumberDigits = @model.getLineCount().toString().length updateCommonGutterState: -> - @state.gutters.backgroundColor = if @gutterBackgroundColor isnt "rgba(0, 0, 0, 0)" + @sharedGutterStyles.backgroundColor = if @gutterBackgroundColor isnt "rgba(0, 0, 0, 0)" @gutterBackgroundColor else @backgroundColor + @state.gutters.backgroundColor = @sharedGutterStyles.backgroundColor # TODO jssln Remove didAddGutter: (gutter) -> gutterDisposables = new CompositeDisposable @@ -446,7 +452,11 @@ class TextEditorPresenter return for gutter in @model.getGutters() isVisible = @gutterIsVisible(gutter) - @state.gutters.sortedDescriptions.push({gutter, visible: isVisible}) + @state.gutters.sortedDescriptions.push({ + gutter, + visible: isVisible, + styles: @sharedGutterStyles + }) # Updates the decoration state for the gutter with the given gutterName. # @state.gutters.customDecorations is an {Object}, with the form: From 75edb9a5f192a0424c6b27a733aa0850c303d8a2 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Tue, 12 May 2015 15:14:27 -0700 Subject: [PATCH 1150/1783] [Gutter] Add dedicated `customGutterDecorations` state --- src/text-editor-presenter.coffee | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 9253c4b5f..1fcd85de2 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -215,6 +215,7 @@ class TextEditorPresenter lineNumbers: {} # Shared state that is copied into ``@state.gutters`. @sharedGutterStyles = {} + @customGutterDecorations = {} @updateState() @@ -457,9 +458,10 @@ class TextEditorPresenter visible: isVisible, styles: @sharedGutterStyles }) + @state.gutters.customDecorations = @customGutterDecorations # TODO jssln Remove # Updates the decoration state for the gutter with the given gutterName. - # @state.gutters.customDecorations is an {Object}, with the form: + # @customGutterDecorations is an {Object}, with the form: # * gutterName : { # decoration.id : { # top: # of pixels from top @@ -471,18 +473,18 @@ class TextEditorPresenter updateCustomGutterDecorationState: -> return unless @startRow? and @endRow? and @lineHeight? - @state.gutters.customDecorations = {} + @customGutterDecorations = {} return if @model.isMini() for gutter in @model.getGutters() gutterName = gutter.name - @state.gutters.customDecorations[gutterName] = {} + @customGutterDecorations[gutterName] = {} return if not @gutterIsVisible(gutter) relevantDecorations = @customGutterDecorationsInRange(gutterName, @startRow, @endRow - 1) relevantDecorations.forEach (decoration) => decorationRange = decoration.getMarker().getScreenRange() - @state.gutters.customDecorations[gutterName][decoration.id] = + @customGutterDecorations[gutterName][decoration.id] = top: @lineHeight * decorationRange.start.row height: @lineHeight * decorationRange.getRowCount() item: decoration.getProperties().item From da360b59e7834079016f5160f10110f21df5df66 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Tue, 12 May 2015 15:44:38 -0700 Subject: [PATCH 1151/1783] [Gutter] Clear custom gutter decoration state objects instead of reassigning to new objects --- src/text-editor-presenter.coffee | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 1fcd85de2..a224f21a8 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -473,12 +473,20 @@ class TextEditorPresenter updateCustomGutterDecorationState: -> return unless @startRow? and @endRow? and @lineHeight? - @customGutterDecorations = {} - return if @model.isMini() + if @model.isMini() + # Mini editors have no gutter decorations. + # We clear instead of reassigning to preserve the reference. + @clearAllCustomGutterDecorations() for gutter in @model.getGutters() gutterName = gutter.name - @customGutterDecorations[gutterName] = {} + gutterDecorations = @customGutterDecorations[gutterName] + if not gutterDecorations + @customGutterDecorations[gutterName] = {} + else + # Clear the gutter decorations; they are rebuilt. + # We clear instead of reassigning to preserve the reference. + @clearDecorationsForCustomGutterName(gutterName) return if not @gutterIsVisible(gutter) relevantDecorations = @customGutterDecorationsInRange(gutterName, @startRow, @endRow - 1) @@ -490,6 +498,18 @@ class TextEditorPresenter item: decoration.getProperties().item class: decoration.getProperties().class + clearAllCustomGutterDecorations: -> + allGutterNames = Object.keys(@customGutterDecorations) + for gutterName in allGutterNames + @clearDecorationsForCustomGutterName(gutterName) + + clearDecorationsForCustomGutterName: (gutterName) -> + gutterDecorations = @customGutterDecorations[gutterName] + if gutterDecorations + allDecorationIds = Object.keys(gutterDecorations) + for decorationId in allDecorationIds + delete gutterDecorations[decorationId] + gutterIsVisible: (gutterModel) -> isVisible = gutterModel.isVisible() if gutterModel.name is 'line-number' From 02aacef02b6dec38add1e39c70f1df954e4cac35 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Wed, 13 May 2015 08:31:47 -0700 Subject: [PATCH 1152/1783] [Gutter] Create dedicated `lineNumberGutter` state --- src/text-editor-presenter.coffee | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index a224f21a8..8ced5ae61 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -216,6 +216,8 @@ class TextEditorPresenter # Shared state that is copied into ``@state.gutters`. @sharedGutterStyles = {} @customGutterDecorations = {} + @lineNumberGutter = + lineNumbers: {} @updateState() @@ -416,7 +418,7 @@ class TextEditorPresenter return updateLineNumberGutterState: -> - @state.gutters.lineNumberGutter.maxLineNumberDigits = @model.getLineCount().toString().length + @lineNumberGutter.maxLineNumberDigits = @model.getLineCount().toString().length updateCommonGutterState: -> @sharedGutterStyles.backgroundColor = if @gutterBackgroundColor isnt "rgba(0, 0, 0, 0)" @@ -459,6 +461,7 @@ class TextEditorPresenter styles: @sharedGutterStyles }) @state.gutters.customDecorations = @customGutterDecorations # TODO jssln Remove + @state.gutters.lineNumberGutter = @lineNumberGutter # TODO jssln Remove # Updates the decoration state for the gutter with the given gutterName. # @customGutterDecorations is an {Object}, with the form: @@ -546,7 +549,7 @@ class TextEditorPresenter decorationClasses = @lineNumberDecorationClassesForRow(screenRow) foldable = @model.isFoldableAtScreenRow(screenRow) - @state.gutters.lineNumberGutter.lineNumbers[id] = {screenRow, bufferRow, softWrapped, top, decorationClasses, foldable} + @lineNumberGutter.lineNumbers[id] = {screenRow, bufferRow, softWrapped, top, decorationClasses, foldable} visibleLineNumberIds[id] = true if @mouseWheelScreenRow? @@ -556,8 +559,8 @@ class TextEditorPresenter id += '-' + wrapCount if wrapCount > 0 visibleLineNumberIds[id] = true - for id of @state.gutters.lineNumberGutter.lineNumbers - delete @state.gutters.lineNumberGutter.lineNumbers[id] unless visibleLineNumberIds[id] + for id of @lineNumberGutter.lineNumbers + delete @lineNumberGutter.lineNumbers[id] unless visibleLineNumberIds[id] return From 03657b3ef9fdb710c505d0af1f155b474befb66f Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Wed, 13 May 2015 08:38:56 -0700 Subject: [PATCH 1153/1783] [Gutter] Insert gutter 'content' into 'sortedDescriptions' --- src/text-editor-presenter.coffee | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 8ced5ae61..be2982db1 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -455,10 +455,16 @@ class TextEditorPresenter return for gutter in @model.getGutters() isVisible = @gutterIsVisible(gutter) + if gutter.name is 'line-number' + content = @lineNumberGutter + else + @customGutterDecorations[gutter.name] ?= {} + content = @customGutterDecorations[gutter.name] @state.gutters.sortedDescriptions.push({ gutter, visible: isVisible, - styles: @sharedGutterStyles + styles: @sharedGutterStyles, + content, }) @state.gutters.customDecorations = @customGutterDecorations # TODO jssln Remove @state.gutters.lineNumberGutter = @lineNumberGutter # TODO jssln Remove From 0a7f6ae18743d76a40c567dc2cd893ad702c72f3 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Wed, 13 May 2015 09:26:06 -0700 Subject: [PATCH 1154/1783] [Gutter] Migrate LineNumberGutterComponent to consume new state format --- src/gutter-container-component.coffee | 13 +++++++++++-- src/line-number-gutter-component.coffee | 16 +++++++++++----- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/gutter-container-component.coffee b/src/gutter-container-component.coffee index e7fec35d5..ff85edd09 100644 --- a/src/gutter-container-component.coffee +++ b/src/gutter-container-component.coffee @@ -1,3 +1,4 @@ +_ = require 'underscore-plus' CustomGutterComponent = require './custom-gutter-component' LineNumberGutterComponent = require './line-number-gutter-component' @@ -30,7 +31,7 @@ class GutterContainerComponent newGutterComponents = [] newGutterComponentsByGutterName = {} - for {gutter, visible} in newState + for {gutter, visible, styles, content} in newState gutterComponent = @gutterComponentsByGutterName[gutter.name] if not gutterComponent if gutter.name is 'line-number' @@ -39,7 +40,15 @@ class GutterContainerComponent else gutterComponent = new CustomGutterComponent({gutter}) if visible then gutterComponent.showNode() else gutterComponent.hideNode() - gutterComponent.updateSync(state) + if gutter.name is 'line-number' + # Pass the gutter only the state that it needs. + # For ease of use in the gutter component, set the shared 'styles' as a + # field under the 'content'. + gutterSubstate = _.clone(content) + gutterSubstate.styles = styles + gutterComponent.updateSync(gutterSubstate) + else + gutterComponent.updateSync(state) newGutterComponents.push({ name: gutter.name, component: gutterComponent, diff --git a/src/line-number-gutter-component.coffee b/src/line-number-gutter-component.coffee index c026d2d37..351275f63 100644 --- a/src/line-number-gutter-component.coffee +++ b/src/line-number-gutter-component.coffee @@ -31,19 +31,25 @@ class LineNumberGutterComponent @domNode.style.removeProperty('display') @visible = true + # `state` is a subset of the TextEditorPresenter state that is specific + # to this line number gutter. updateSync: (state) -> - @newState = state.gutters.lineNumberGutter - @oldState ?= {lineNumbers: {}} + @newState = state + @oldState ?= + lineNumbers: {} + styles: {} @appendDummyLineNumber() unless @dummyLineNumberNode? - newDimensionsAndBackgroundState = state.gutters - setDimensionsAndBackground(@oldState, newDimensionsAndBackgroundState, @lineNumbersNode) + setDimensionsAndBackground(@oldState.styles, @newState.styles, @lineNumbersNode) if @newState.maxLineNumberDigits isnt @oldState.maxLineNumberDigits @updateDummyLineNumber() node.remove() for id, node of @lineNumberNodesById - @oldState = {maxLineNumberDigits: @newState.maxLineNumberDigits, lineNumbers: {}} + @oldState = + maxLineNumberDigits: @newState.maxLineNumberDigits + lineNumbers: {} + styles: {} @lineNumberNodesById = {} @updateLineNumbers() From c128788a3b7def898379aff65b8dec8e143e72ad Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Wed, 13 May 2015 10:01:59 -0700 Subject: [PATCH 1155/1783] [Gutter] Migrate CustomGutterComponent to consume new state format --- src/custom-gutter-component.coffee | 7 ++++--- src/gutter-container-component.coffee | 14 +++++++++----- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/custom-gutter-component.coffee b/src/custom-gutter-component.coffee index 1321c8990..39f5a80a1 100644 --- a/src/custom-gutter-component.coffee +++ b/src/custom-gutter-component.coffee @@ -29,13 +29,14 @@ class CustomGutterComponent @domNode.style.removeProperty('display') @visible = true + # `state` is a subset of the TextEditorPresenter state that is specific + # to this line number gutter. updateSync: (state) -> @oldDimensionsAndBackgroundState ?= {} - newDimensionsAndBackgroundState = state.gutters - setDimensionsAndBackground(@oldDimensionsAndBackgroundState, newDimensionsAndBackgroundState, @decorationsNode) + setDimensionsAndBackground(@oldDimensionsAndBackgroundState, state.styles, @decorationsNode) @oldDecorationPositionState ?= {} - decorationState = state.gutters.customDecorations[@gutter.name] + decorationState = state.content updatedDecorationIds = new Set for decorationId, decorationInfo of decorationState diff --git a/src/gutter-container-component.coffee b/src/gutter-container-component.coffee index ff85edd09..5dbbcd040 100644 --- a/src/gutter-container-component.coffee +++ b/src/gutter-container-component.coffee @@ -39,16 +39,20 @@ class GutterContainerComponent @lineNumberGutterComponent = gutterComponent else gutterComponent = new CustomGutterComponent({gutter}) + if visible then gutterComponent.showNode() else gutterComponent.hideNode() + # Pass the gutter only the state that it needs. if gutter.name is 'line-number' - # Pass the gutter only the state that it needs. - # For ease of use in the gutter component, set the shared 'styles' as a - # field under the 'content'. + # For ease of use in the line number gutter component, set the shared + # 'styles' as a field under the 'content'. gutterSubstate = _.clone(content) gutterSubstate.styles = styles - gutterComponent.updateSync(gutterSubstate) else - gutterComponent.updateSync(state) + # Custom gutter 'content' is keyed on gutter name, so we cannot set + # 'styles' as a subfield directly under it. + gutterSubstate = {content, styles} + gutterComponent.updateSync(gutterSubstate) + newGutterComponents.push({ name: gutter.name, component: gutterComponent, From 733e9947a4453cf358a50ee94535291403cc622d Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Wed, 13 May 2015 10:13:15 -0700 Subject: [PATCH 1156/1783] [Gutter] Kill old (now unused) state hanging off @state.gutters --- src/text-editor-presenter.coffee | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index be2982db1..bb6e05818 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -210,9 +210,6 @@ class TextEditorPresenter overlays: {} gutters: sortedDescriptions: [] - customDecorations: {} - lineNumberGutter: - lineNumbers: {} # Shared state that is copied into ``@state.gutters`. @sharedGutterStyles = {} @customGutterDecorations = {} @@ -257,12 +254,10 @@ class TextEditorPresenter updateVerticalScrollState: -> @state.content.scrollHeight = @scrollHeight - @state.gutters.scrollHeight = @scrollHeight # TODO jssln Remove @sharedGutterStyles.scrollHeight = @scrollHeight @state.verticalScrollbar.scrollHeight = @scrollHeight @state.content.scrollTop = @scrollTop - @state.gutters.scrollTop = @scrollTop # TODO jssln Remove @sharedGutterStyles.scrollTop = @scrollTop @state.verticalScrollbar.scrollTop = @scrollTop @@ -425,7 +420,6 @@ class TextEditorPresenter @gutterBackgroundColor else @backgroundColor - @state.gutters.backgroundColor = @sharedGutterStyles.backgroundColor # TODO jssln Remove didAddGutter: (gutter) -> gutterDisposables = new CompositeDisposable @@ -466,8 +460,6 @@ class TextEditorPresenter styles: @sharedGutterStyles, content, }) - @state.gutters.customDecorations = @customGutterDecorations # TODO jssln Remove - @state.gutters.lineNumberGutter = @lineNumberGutter # TODO jssln Remove # Updates the decoration state for the gutter with the given gutterName. # @customGutterDecorations is an {Object}, with the form: From 957424f987ed4b29ca37287f5e1e56280cea550e Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Wed, 13 May 2015 10:45:50 -0700 Subject: [PATCH 1157/1783] [Gutter] @state.gutter.sortedDescriptions -> @state.gutters --- src/gutter-container-component.coffee | 2 +- src/text-editor-component.coffee | 4 ++-- src/text-editor-presenter.coffee | 7 +++---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/gutter-container-component.coffee b/src/gutter-container-component.coffee index 5dbbcd040..5fa2f85f4 100644 --- a/src/gutter-container-component.coffee +++ b/src/gutter-container-component.coffee @@ -27,7 +27,7 @@ class GutterContainerComponent updateSync: (state) -> # The GutterContainerComponent expects the gutters to be sorted in the order # they should appear. - newState = state.gutters.sortedDescriptions + newState = state.gutters newGutterComponents = [] newGutterComponentsByGutterName = {} diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 4c6480510..eb01e0f23 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -70,7 +70,7 @@ class TextEditorComponent @scrollViewNode.classList.add('scroll-view') @domNode.appendChild(@scrollViewNode) - @mountGutterContainerComponent() if @presenter.getState().gutters.sortedDescriptions.length + @mountGutterContainerComponent() if @presenter.getState().gutters.length @hiddenInputComponent = new InputComponent @scrollViewNode.appendChild(@hiddenInputComponent.getDomNode()) @@ -137,7 +137,7 @@ class TextEditorComponent else @domNode.style.height = '' - if @newState.gutters.sortedDescriptions.length + if @newState.gutters.length @mountGutterContainerComponent() unless @gutterContainerComponent? @gutterContainerComponent.updateSync(@newState) else diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index bb6e05818..27966ff7a 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -208,8 +208,7 @@ class TextEditorPresenter lines: {} highlights: {} overlays: {} - gutters: - sortedDescriptions: [] + gutters: [] # Shared state that is copied into ``@state.gutters`. @sharedGutterStyles = {} @customGutterDecorations = {} @@ -444,7 +443,7 @@ class TextEditorPresenter @emitDidUpdateState() updateGutterOrderState: -> - @state.gutters.sortedDescriptions = [] + @state.gutters = [] if @model.isMini() return for gutter in @model.getGutters() @@ -454,7 +453,7 @@ class TextEditorPresenter else @customGutterDecorations[gutter.name] ?= {} content = @customGutterDecorations[gutter.name] - @state.gutters.sortedDescriptions.push({ + @state.gutters.push({ gutter, visible: isVisible, styles: @sharedGutterStyles, From 1abca560cd62c27d555f4268891b054433984085 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 13 May 2015 11:26:56 -0700 Subject: [PATCH 1158/1783] :arrow_up: autocomplete-plus@2.15.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b03c372e7..3614b5f26 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,7 @@ "autocomplete-css": "0.7.2", "autocomplete-emojis": "2.2.2", "autocomplete-html": "0.7.1", - "autocomplete-plus": "2.15.0", + "autocomplete-plus": "2.15.1", "autocomplete-snippets": "1.6.1", "autoflow": "0.23.0", "autosave": "0.20.0", From a937dc2fd4c87c06f7fbf25244564c07905b580a Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 13 May 2015 11:30:35 -0700 Subject: [PATCH 1159/1783] Dont remove symlinked autocomplete-plus packages --- spec/package-manager-spec.coffee | 9 ++++++--- src/package-manager.coffee | 4 +--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 1cd961936..1244ab984 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -845,13 +845,16 @@ describe "PackageManager", -> jasmine.unspy(atom.packages, 'uninstallAutocompletePlus') + afterEach -> + try + fs.unlink autocompletePlusPath, -> + it "removes the packages", -> atom.packages.loadPackages() waitsFor -> - not fs.isDirectorySync(autocompleteCSSPath) and - not fs.isSymbolicLinkSync(autocompletePlusPath) + not fs.isDirectorySync(autocompleteCSSPath) runs -> expect(fs.isDirectorySync(autocompleteCSSPath)).toBe false - expect(fs.isSymbolicLinkSync(autocompletePlusPath)).toBe false + expect(fs.isSymbolicLinkSync(autocompletePlusPath)).toBe true diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 1262aa59e..606f72eda 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -443,9 +443,7 @@ class PackageManager Promise.all([symlinkPromise, dirPromise]).then (values) -> [isSymLink, isDir] = values - if isSymLink - fs.unlink directory, -> - else if isDir + if not isSymLink and isDir fs.remove directory, -> if Grim.includeDeprecatedAPIs From 27319c43003a4bd03abd53262e6846210ca754e1 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Wed, 13 May 2015 10:52:25 -0700 Subject: [PATCH 1160/1783] [Gutter] Fix CustomGutterComponent spec --- spec/custom-gutter-component-spec.coffee | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/spec/custom-gutter-component-spec.coffee b/spec/custom-gutter-component-spec.coffee index 21db68653..4b7d81fba 100644 --- a/spec/custom-gutter-component-spec.coffee +++ b/spec/custom-gutter-component-spec.coffee @@ -30,15 +30,12 @@ describe "CustomGutterComponent", -> buildTestState = (customDecorations) -> mockTestState = - gutters: + content: if customDecorations then customDecorations else {} + styles: scrollHeight: 100 scrollTop: 10 backgroundColor: 'black' - sortedDescriptions: [{gutter, visible: true}] - customDecorations: customDecorations - lineNumberGutter: - maxLineNumberDigits: 10 - lineNumbers: {} + mockTestState it "sets the custom-decoration wrapper's scrollHeight, scrollTop, and background color", -> @@ -53,7 +50,7 @@ describe "CustomGutterComponent", -> expect(decorationsWrapperNode.style.backgroundColor).not.toBe '' it "creates a new DOM node for a new decoration and adds it to the gutter at the right place", -> - customDecorations = 'test-gutter': + customDecorations = 'decoration-id-1': top: 0 height: 10 @@ -75,7 +72,7 @@ describe "CustomGutterComponent", -> expect(decorationItem).toBe decorationItem1 it "updates the existing DOM node for a decoration that existed but has new properties", -> - initialCustomDecorations = 'test-gutter': + initialCustomDecorations = 'decoration-id-1': top: 0 height: 10 @@ -86,7 +83,7 @@ describe "CustomGutterComponent", -> # Change the dimensions and item, remove the class. decorationItem2 = document.createElement('div') - changedCustomDecorations = 'test-gutter': + changedCustomDecorations = 'decoration-id-1': top: 10 height: 20 @@ -103,7 +100,7 @@ describe "CustomGutterComponent", -> expect(decorationItem).toBe decorationItem2 # Remove the item, add a class. - changedCustomDecorations = 'test-gutter': + changedCustomDecorations = 'decoration-id-1': top: 10 height: 20 @@ -118,7 +115,7 @@ describe "CustomGutterComponent", -> expect(changedDecorationNode.children.length).toBe 0 it "removes any decorations that existed previously but aren't in the latest update", -> - customDecorations = 'test-gutter': + customDecorations = 'decoration-id-1': top: 0 height: 10 @@ -127,6 +124,6 @@ describe "CustomGutterComponent", -> decorationsWrapperNode = gutterComponent.getDomNode().children.item(0) expect(decorationsWrapperNode.children.length).toBe 1 - emptyCustomDecorations = 'test-gutter': {} + emptyCustomDecorations = {} gutterComponent.updateSync(buildTestState(emptyCustomDecorations)) expect(decorationsWrapperNode.children.length).toBe 0 From a84c79c65034e9bf0d9674a6b1e186afc46c9bb6 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Wed, 13 May 2015 12:01:00 -0700 Subject: [PATCH 1161/1783] [Gutter] Fix GutterContainerComponent spec --- spec/gutter-container-component-spec.coffee | 57 ++++++++++----------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/spec/gutter-container-component-spec.coffee b/spec/gutter-container-component-spec.coffee index 218d8aae2..5d815fea8 100644 --- a/spec/gutter-container-component-spec.coffee +++ b/spec/gutter-container-component-spec.coffee @@ -5,17 +5,20 @@ describe "GutterContainerComponent", -> [gutterContainerComponent] = [] mockGutterContainer = {} - buildTestState = (sortedDescriptions) -> - mockTestState = - gutters: - scrollHeight: 100 - scrollTop: 10 - backgroundColor: 'black' - sortedDescriptions: sortedDescriptions - customDecorations: {} - lineNumberGutter: - maxLineNumberDigits: 10 - lineNumbers: {} + buildTestState = (gutters) -> + styles = + scrollHeight: 100 + scrollTop: 10 + backgroundColor: 'black' + + mockTestState = {gutters: []} + for gutter in gutters + if gutter.name is 'line-number' + content = {maxLineNumberDigits: 10, lineNumbers: {}} + else + content = {} + mockTestState.gutters.push({gutter, styles, content, visible: gutter.visible}) + mockTestState beforeEach -> @@ -30,7 +33,7 @@ describe "GutterContainerComponent", -> describe "when updated with state that contains a new line-number gutter", -> it "adds a LineNumberGutterComponent to its children", -> lineNumberGutter = new Gutter(mockGutterContainer, {name: 'line-number'}) - testState = buildTestState([{gutter: lineNumberGutter, visible: true}]) + testState = buildTestState([lineNumberGutter]) expect(gutterContainerComponent.getDomNode().children.length).toBe 0 gutterContainerComponent.updateSync(testState) @@ -45,7 +48,7 @@ describe "GutterContainerComponent", -> describe "when updated with state that contains a new custom gutter", -> it "adds a CustomGutterComponent to its children", -> customGutter = new Gutter(mockGutterContainer, {name: 'custom'}) - testState = buildTestState([{gutter: customGutter, visible: true}]) + testState = buildTestState([customGutter]) expect(gutterContainerComponent.getDomNode().children.length).toBe 0 gutterContainerComponent.updateSync(testState) @@ -57,15 +60,16 @@ describe "GutterContainerComponent", -> describe "when updated with state that contains a new gutter that is not visible", -> it "creates the gutter view but hides it, and unhides it when it is later updated to be visible", -> - customGutter = new Gutter(mockGutterContainer, {name: 'custom'}) - testState = buildTestState([{gutter: customGutter, visible: false}]) + customGutter = new Gutter(mockGutterContainer, {name: 'custom', visible: false}) + testState = buildTestState([customGutter]) gutterContainerComponent.updateSync(testState) expect(gutterContainerComponent.getDomNode().children.length).toBe 1 expectedCustomGutterNode = gutterContainerComponent.getDomNode().children.item(0) expect(expectedCustomGutterNode.style.display).toBe 'none' - testState = buildTestState([{gutter: customGutter, visible: true}]) + customGutter.show() + testState = buildTestState([customGutter]) gutterContainerComponent.updateSync(testState) expect(gutterContainerComponent.getDomNode().children.length).toBe 1 expectedCustomGutterNode = gutterContainerComponent.getDomNode().children.item(0) @@ -74,20 +78,20 @@ describe "GutterContainerComponent", -> describe "when updated with a gutter that already exists", -> it "reuses the existing gutter view, instead of recreating it", -> customGutter = new Gutter(mockGutterContainer, {name: 'custom'}) - testState = buildTestState([{gutter: customGutter, visible: true}]) + testState = buildTestState([customGutter]) gutterContainerComponent.updateSync(testState) expect(gutterContainerComponent.getDomNode().children.length).toBe 1 expectedCustomGutterNode = gutterContainerComponent.getDomNode().children.item(0) - testState = buildTestState([{gutter: customGutter, visible: true}]) + testState = buildTestState([customGutter]) gutterContainerComponent.updateSync(testState) expect(gutterContainerComponent.getDomNode().children.length).toBe 1 expect(gutterContainerComponent.getDomNode().children.item(0)).toBe expectedCustomGutterNode it "removes a gutter from the DOM if it does not appear in the latest state update", -> lineNumberGutter = new Gutter(mockGutterContainer, {name: 'line-number'}) - testState = buildTestState([{gutter: lineNumberGutter, visible: true}]) + testState = buildTestState([lineNumberGutter]) gutterContainerComponent.updateSync(testState) expect(gutterContainerComponent.getDomNode().children.length).toBe 1 @@ -99,7 +103,7 @@ describe "GutterContainerComponent", -> it "positions (and repositions) the gutters to match the order they appear in each state update", -> lineNumberGutter = new Gutter(mockGutterContainer, {name: 'line-number'}) customGutter1 = new Gutter(mockGutterContainer, {name: 'custom', priority: -100}) - testState = buildTestState([{gutter: customGutter1, visible: true}, {gutter: lineNumberGutter, visible: true}]) + testState = buildTestState([customGutter1, lineNumberGutter]) gutterContainerComponent.updateSync(testState) expect(gutterContainerComponent.getDomNode().children.length).toBe 2 @@ -110,11 +114,7 @@ describe "GutterContainerComponent", -> # Add a gutter. customGutter2 = new Gutter(mockGutterContainer, {name: 'custom2', priority: -10}) - testState = buildTestState([ - {gutter: customGutter1, visible: true}, - {gutter: customGutter2, visible: true}, - {gutter: lineNumberGutter, visible: true} - ]) + testState = buildTestState([customGutter1, customGutter2, lineNumberGutter]) gutterContainerComponent.updateSync(testState) expect(gutterContainerComponent.getDomNode().children.length).toBe 3 expectedCustomGutterNode1 = gutterContainerComponent.getDomNode().children.item(0) @@ -125,12 +125,9 @@ describe "GutterContainerComponent", -> expect(expectedLineNumbersNode).toBe atom.views.getView(lineNumberGutter) # Hide one gutter, reposition one gutter, remove one gutter; and add a new gutter. + customGutter2.hide() customGutter3 = new Gutter(mockGutterContainer, {name: 'custom3', priority: 100}) - testState = buildTestState([ - {gutter: customGutter2, visible: false}, - {gutter: customGutter1, visible: true}, - {gutter: customGutter3, visible: true} - ]) + testState = buildTestState([customGutter2, customGutter1, customGutter3]) gutterContainerComponent.updateSync(testState) expect(gutterContainerComponent.getDomNode().children.length).toBe 3 expectedCustomGutterNode2 = gutterContainerComponent.getDomNode().children.item(0) From 9583ff04e6a6c711273c2decda2a352321565f16 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 6 May 2015 22:03:10 +0200 Subject: [PATCH 1162/1783] WIP: Start integrating with nested words version of first-mate --- src/tokenized-buffer.coffee | 51 ++++++++++++++++++++++++++----------- src/tokenized-line.coffee | 9 +++++-- 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index d9f1bcba7..082c923dd 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -153,7 +153,7 @@ class TokenizedBuffer extends Model row = startRow loop previousStack = @stackForRow(row) - @tokenizedLines[row] = @buildTokenizedLineForRow(row, @stackForRow(row - 1)) + @tokenizedLines[row] = @buildTokenizedLineForRow(row, @stackForRow(row - 1), @parentScopesForRow(row)) if --rowsRemaining is 0 filledRegion = false endRow = row @@ -213,7 +213,7 @@ class TokenizedBuffer extends Model @updateInvalidRows(start, end, delta) previousEndStack = @stackForRow(end) # used in spill detection below - newTokenizedLines = @buildTokenizedLinesForRows(start, end + delta, @stackForRow(start - 1)) + newTokenizedLines = @buildTokenizedLinesForRows(start, end + delta, @stackForRow(start - 1), @parentScopesForRow(start)) _.spliceWithArray(@tokenizedLines, start, end - start + 1, newTokenizedLines) start = @retokenizeWhitespaceRowsIfIndentLevelChanged(start - 1, -1) @@ -234,7 +234,7 @@ class TokenizedBuffer extends Model line = @tokenizedLines[row] if line?.isOnlyWhitespace() and @indentLevelForRow(row) isnt line.indentLevel while line?.isOnlyWhitespace() - @tokenizedLines[row] = @buildTokenizedLineForRow(row, @stackForRow(row - 1)) + @tokenizedLines[row] = @buildTokenizedLineForRow(row, @stackForRow(row - 1), @parentScopesForRow(row)) row += increment line = @tokenizedLines[row] @@ -276,16 +276,18 @@ class TokenizedBuffer extends Model @tokenizedLineForRow(row).isComment() and @tokenizedLineForRow(nextRow).isComment() - buildTokenizedLinesForRows: (startRow, endRow, startingStack) -> + buildTokenizedLinesForRows: (startRow, endRow, startingStack, startingParentScopes) -> ruleStack = startingStack + parentScopes = startingParentScopes stopTokenizingAt = startRow + @chunkSize tokenizedLines = for row in [startRow..endRow] if (ruleStack or row is 0) and row < stopTokenizingAt - screenLine = @buildTokenizedLineForRow(row, ruleStack) - ruleStack = screenLine.ruleStack + tokenizedLine = @buildTokenizedLineForRow(row, ruleStack, parentScopes) + ruleStack = tokenizedLine.ruleStack + parentScopes = @scopesFromContent(parentScopes, tokenizedLine.content) else - screenLine = @buildPlaceholderTokenizedLineForRow(row) - screenLine + tokenizedLine = @buildPlaceholderTokenizedLineForRow(row, parentScopes) + tokenizedLine if endRow >= stopTokenizingAt @invalidateRow(stopTokenizingAt) @@ -298,21 +300,22 @@ class TokenizedBuffer extends Model buildPlaceholderTokenizedLineForRow: (row) -> line = @buffer.lineForRow(row) - tokens = [new Token(value: line, scopes: [@grammar.scopeName])] + parentScopes = [@grammar.idForScope(@grammar.scopeName)] + content = [line] tabLength = @getTabLength() indentLevel = @indentLevelForRow(row) lineEnding = @buffer.lineEndingForRow(row) - new TokenizedLine({tokens, tabLength, indentLevel, @invisibles, lineEnding}) + new TokenizedLine({parentScopes, content, tabLength, indentLevel, @invisibles, lineEnding}) - buildTokenizedLineForRow: (row, ruleStack) -> - @buildTokenizedLineForRowWithText(row, @buffer.lineForRow(row), ruleStack) + buildTokenizedLineForRow: (row, ruleStack, parentScopes) -> + @buildTokenizedLineForRowWithText(row, @buffer.lineForRow(row), ruleStack, parentScopes) - buildTokenizedLineForRowWithText: (row, line, ruleStack = @stackForRow(row - 1)) -> + buildTokenizedLineForRowWithText: (row, line, ruleStack = @stackForRow(row - 1), parentScopes = @parentScopesForRow(row)) -> lineEnding = @buffer.lineEndingForRow(row) tabLength = @getTabLength() indentLevel = @indentLevelForRow(row) - {tokens, ruleStack} = @grammar.tokenizeLine(line, ruleStack, row is 0) - new TokenizedLine({tokens, ruleStack, tabLength, lineEnding, indentLevel, @invisibles}) + {content, ruleStack} = @grammar.tokenizeLine(line, ruleStack, row is 0) + new TokenizedLine({parentScopes, content, ruleStack, tabLength, lineEnding, indentLevel, @invisibles}) tokenizedLineForRow: (bufferRow) -> @tokenizedLines[bufferRow] @@ -320,6 +323,24 @@ class TokenizedBuffer extends Model stackForRow: (bufferRow) -> @tokenizedLines[bufferRow]?.ruleStack + parentScopesForRow: (bufferRow) -> + if bufferRow > 0 + precedingLine = @tokenizedLines[bufferRow - 1] + @scopesFromContent(precedingLine.parentScopes, precedingLine.content) + else + [] + + scopesFromContent: (startingScopes, content) -> + scopes = startingScopes.slice() + for symbol in content when typeof symbol is 'number' + if symbol > 0 + scopes.push(symbol) + else + popped = scopes.pop() + unless -popped is symbol + throw new Error("Encountered an invalid scope end id. Popped #{popped}, expected to pop #{-symbol}.") + scopes + indentLevelForRow: (bufferRow) -> line = @buffer.lineForRow(bufferRow) indentLevel = 0 diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index b81d972a0..942d72c1a 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -1,5 +1,6 @@ _ = require 'underscore-plus' {isPairedCharacter} = require './text-utils' +Token = require './token' NonWhitespaceRegex = /\S/ LeadingWhitespaceRegex = /^\s*/ @@ -14,9 +15,9 @@ class TokenizedLine firstNonWhitespaceIndex: 0 foldable: false - constructor: ({tokens, @lineEnding, @ruleStack, @startBufferColumn, @fold, @tabLength, @indentLevel, @invisibles}) -> + constructor: ({@parentScopes, @content, @lineEnding, @ruleStack, @startBufferColumn, @fold, @tabLength, @indentLevel, @invisibles}) -> @startBufferColumn ?= 0 - @tokens = @breakOutAtomicTokens(tokens) + # @tokens = @breakOutAtomicTokens(tokens) @text = @buildText() @bufferDelta = @buildBufferDelta() @softWrapIndentationTokens = @getSoftWrapIndentationTokens() @@ -28,6 +29,10 @@ class TokenizedLine @substituteInvisibleCharacters() @buildEndOfLineInvisibles() if @lineEnding? + Object.defineProperty @prototype, 'tokens', get: -> + tokens = atom.grammars.decodeContent(@parentScopes.concat(@content)) + tokens.map (properties) -> new Token(properties) + buildText: -> text = "" text += token.value for token in @tokens From 06b5d273575645844c76391ed6fb8cb55903c7d7 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 8 May 2015 20:57:46 +0200 Subject: [PATCH 1163/1783] Adapt to first-mate returning purely numeric tag arrays --- src/tokenized-buffer.coffee | 31 ++++++++++++++++--------------- src/tokenized-line.coffee | 9 +++++---- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 082c923dd..9dde39afe 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -284,7 +284,7 @@ class TokenizedBuffer extends Model if (ruleStack or row is 0) and row < stopTokenizingAt tokenizedLine = @buildTokenizedLineForRow(row, ruleStack, parentScopes) ruleStack = tokenizedLine.ruleStack - parentScopes = @scopesFromContent(parentScopes, tokenizedLine.content) + parentScopes = @scopesFromTags(parentScopes, tokenizedLine.tags) else tokenizedLine = @buildPlaceholderTokenizedLineForRow(row, parentScopes) tokenizedLine @@ -299,23 +299,23 @@ class TokenizedBuffer extends Model @buildPlaceholderTokenizedLineForRow(row) for row in [startRow..endRow] buildPlaceholderTokenizedLineForRow: (row) -> - line = @buffer.lineForRow(row) parentScopes = [@grammar.idForScope(@grammar.scopeName)] - content = [line] + text = @buffer.lineForRow(row) + tags = [text.length] tabLength = @getTabLength() indentLevel = @indentLevelForRow(row) lineEnding = @buffer.lineEndingForRow(row) - new TokenizedLine({parentScopes, content, tabLength, indentLevel, @invisibles, lineEnding}) + new TokenizedLine({parentScopes, text, tags, tabLength, indentLevel, @invisibles, lineEnding}) buildTokenizedLineForRow: (row, ruleStack, parentScopes) -> @buildTokenizedLineForRowWithText(row, @buffer.lineForRow(row), ruleStack, parentScopes) - buildTokenizedLineForRowWithText: (row, line, ruleStack = @stackForRow(row - 1), parentScopes = @parentScopesForRow(row)) -> + buildTokenizedLineForRowWithText: (row, text, ruleStack = @stackForRow(row - 1), parentScopes = @parentScopesForRow(row)) -> lineEnding = @buffer.lineEndingForRow(row) tabLength = @getTabLength() indentLevel = @indentLevelForRow(row) - {content, ruleStack} = @grammar.tokenizeLine(line, ruleStack, row is 0) - new TokenizedLine({parentScopes, content, ruleStack, tabLength, lineEnding, indentLevel, @invisibles}) + {tags, ruleStack} = @grammar.tokenizeLine(text, ruleStack, row is 0) + new TokenizedLine({parentScopes, text, tags, ruleStack, tabLength, lineEnding, indentLevel, @invisibles}) tokenizedLineForRow: (bufferRow) -> @tokenizedLines[bufferRow] @@ -326,19 +326,20 @@ class TokenizedBuffer extends Model parentScopesForRow: (bufferRow) -> if bufferRow > 0 precedingLine = @tokenizedLines[bufferRow - 1] - @scopesFromContent(precedingLine.parentScopes, precedingLine.content) + @scopesFromTags(precedingLine.parentScopes, precedingLine.tags) else [] - scopesFromContent: (startingScopes, content) -> + scopesFromTags: (startingScopes, tags) -> scopes = startingScopes.slice() - for symbol in content when typeof symbol is 'number' - if symbol > 0 - scopes.push(symbol) + for tag in tags when tag < 0 + if (tag % 2) is -1 + scopes.push(tag) else - popped = scopes.pop() - unless -popped is symbol - throw new Error("Encountered an invalid scope end id. Popped #{popped}, expected to pop #{-symbol}.") + expectedScope = tag + 1 + poppedScope = scopes.pop() + unless poppedScope is expectedScope + throw new Error("Encountered an invalid scope end id. Popped #{poppedScope}, expected to pop #{expectedScope}.") scopes indentLevelForRow: (bufferRow) -> diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 942d72c1a..be8a16799 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -15,10 +15,9 @@ class TokenizedLine firstNonWhitespaceIndex: 0 foldable: false - constructor: ({@parentScopes, @content, @lineEnding, @ruleStack, @startBufferColumn, @fold, @tabLength, @indentLevel, @invisibles}) -> + constructor: ({@parentScopes, @text, @tags, @lineEnding, @ruleStack, @startBufferColumn, @fold, @tabLength, @indentLevel, @invisibles}) -> @startBufferColumn ?= 0 # @tokens = @breakOutAtomicTokens(tokens) - @text = @buildText() @bufferDelta = @buildBufferDelta() @softWrapIndentationTokens = @getSoftWrapIndentationTokens() @softWrapIndentationDelta = @buildSoftWrapIndentationDelta() @@ -30,8 +29,10 @@ class TokenizedLine @buildEndOfLineInvisibles() if @lineEnding? Object.defineProperty @prototype, 'tokens', get: -> - tokens = atom.grammars.decodeContent(@parentScopes.concat(@content)) - tokens.map (properties) -> new Token(properties) + tokens = atom.grammars.decodeContent(@text, @tags, @parentScopes.slice()) + tokens.map (properties, index) => + properties.isAtomic = true if @specialTokens[index] is SoftTab + new Token(properties) buildText: -> text = "" From 43806d64167c83defd86fa51b359f3a841feaac1 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 8 May 2015 20:57:57 +0200 Subject: [PATCH 1164/1783] Break out leading soft tabs after switching to numeric tag arrays --- src/tokenized-line.coffee | 41 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index be8a16799..e99ceba8f 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -2,6 +2,8 @@ _ = require 'underscore-plus' {isPairedCharacter} = require './text-utils' Token = require './token' +SoftTab = Symbol('SoftTab') + NonWhitespaceRegex = /\S/ LeadingWhitespaceRegex = /^\s*/ TrailingWhitespaceRegex = /\s*$/ @@ -17,6 +19,11 @@ class TokenizedLine constructor: ({@parentScopes, @text, @tags, @lineEnding, @ruleStack, @startBufferColumn, @fold, @tabLength, @indentLevel, @invisibles}) -> @startBufferColumn ?= 0 + + @specialTokens = {} + + @subdivideTokens() + # @tokens = @breakOutAtomicTokens(tokens) @bufferDelta = @buildBufferDelta() @softWrapIndentationTokens = @getSoftWrapIndentationTokens() @@ -28,6 +35,40 @@ class TokenizedLine @substituteInvisibleCharacters() @buildEndOfLineInvisibles() if @lineEnding? + subdivideTokens: -> + text = '' + bufferColumn = 0 + screenColumn = 0 + tokenIndex = 0 + tokenOffset = 0 + inLeadingWhitespace = true + + while bufferColumn < @text.length + # advance to next token if we've iterated over its length + if tokenOffset is @tags[tokenIndex] + tokenIndex++ + tokenOffset = 0 + + # advance to next token tag + tokenIndex++ while @tags[tokenIndex] < 0 + + character = @text[bufferColumn] + + # split out leading soft tabs + if character is ' ' + if inLeadingWhitespace and (screenColumn + 1) % @tabLength is 0 + @specialTokens[tokenIndex] = SoftTab + @tags.splice(tokenIndex, 1, @tabLength, @tags[tokenIndex] - @tabLength) + else + inLeadingWhitespace = false + + text += character + bufferColumn++ + screenColumn++ + tokenOffset++ + + @text = text + Object.defineProperty @prototype, 'tokens', get: -> tokens = atom.grammars.decodeContent(@text, @tags, @parentScopes.slice()) tokens.map (properties, index) => From 9554bfd3938307a240ecc18b312eb47efefa6c01 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sat, 9 May 2015 01:07:50 +0200 Subject: [PATCH 1165/1783] Break out hard tabs and paired characters from numeric tag arrays --- src/tokenized-line.coffee | 82 +++++++++++++++++++++++++++++++++------ 1 file changed, 71 insertions(+), 11 deletions(-) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index e99ceba8f..6f86847de 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -3,6 +3,8 @@ _ = require 'underscore-plus' Token = require './token' SoftTab = Symbol('SoftTab') +HardTab = Symbol('HardTab') +PairedCharacter = Symbol('PairedCharacter') NonWhitespaceRegex = /\S/ LeadingWhitespaceRegex = /^\s*/ @@ -54,26 +56,84 @@ class TokenizedLine character = @text[bufferColumn] + # split out unicode surrogate pairs + if isPairedCharacter(@text, bufferColumn) + prefix = tokenOffset + suffix = @tags[tokenIndex] - tokenOffset - 2 + splitTokens = [] + splitTokens.push(prefix) if prefix > 0 + splitTokens.push(2) + splitTokens.push(suffix) if suffix > 0 + + @tags.splice(tokenIndex, 1, splitTokens...) + + text += @text.substr(bufferColumn, 2) + screenColumn++ + bufferColumn += 2 + + tokenIndex++ if prefix > 0 + @specialTokens[tokenIndex] = PairedCharacter + tokenIndex++ + tokenOffset = 0 + # split out leading soft tabs - if character is ' ' + else if character is ' ' and inLeadingWhitespace if inLeadingWhitespace and (screenColumn + 1) % @tabLength is 0 @specialTokens[tokenIndex] = SoftTab - @tags.splice(tokenIndex, 1, @tabLength, @tags[tokenIndex] - @tabLength) + suffix = @tags[tokenIndex] - @tabLength + @tags.splice(tokenIndex, 1, @tabLength) + @tags.splice(tokenIndex + 1, 0, suffix) if suffix > 0 + + text += character + screenColumn++ + bufferColumn++ + tokenOffset++ + + # expand hard tabs to the next tab stop + else if character is '\t' + tabLength = @tabLength - (screenColumn % @tabLength) + text += ' ' for i in [0...tabLength] by 1 + + prefix = tokenOffset + suffix = @tags[tokenIndex] - tokenOffset - 1 + splitTokens = [] + splitTokens.push(prefix) if prefix > 0 + splitTokens.push(tabLength) + splitTokens.push(suffix) if suffix > 0 + + @tags.splice(tokenIndex, 1, splitTokens...) + + screenColumn += tabLength + bufferColumn++ + + tokenIndex++ if prefix > 0 + @specialTokens[tokenIndex] = HardTab + tokenIndex++ + tokenOffset = 0 + + # continue past any other character else inLeadingWhitespace = false - - text += character - bufferColumn++ - screenColumn++ - tokenOffset++ + text += character + screenColumn++ + bufferColumn++ + tokenOffset++ @text = text Object.defineProperty @prototype, 'tokens', get: -> - tokens = atom.grammars.decodeContent(@text, @tags, @parentScopes.slice()) - tokens.map (properties, index) => - properties.isAtomic = true if @specialTokens[index] is SoftTab - new Token(properties) + atom.grammars.decodeContent @text, @tags, @parentScopes.slice(), (tokenProperties, index) => + switch @specialTokens[index] + when SoftTab + tokenProperties.isAtomic = true + when HardTab + tokenProperties.isAtomic = true + tokenProperties.bufferDelta = 1 + when PairedCharacter + tokenProperties.isAtomic = true + tokenProperties.hasPairedCharacter = true + + new Token(tokenProperties) buildText: -> text = "" From 9d93d18a8f85d7cfbd5692d6e2799abb7b3c2624 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sun, 10 May 2015 09:55:23 +0200 Subject: [PATCH 1166/1783] Mark leading/trailing whitespace in new TokenizedLine representation --- src/token.coffee | 6 +++++- src/tokenized-line.coffee | 25 ++++++++++++++----------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/token.coffee b/src/token.coffee index 8aa4a8706..583e25e9b 100644 --- a/src/token.coffee +++ b/src/token.coffee @@ -20,7 +20,11 @@ class Token firstTrailingWhitespaceIndex: null hasInvisibleCharacters: false - constructor: ({@value, @scopes, @isAtomic, @bufferDelta, @isHardTab, @hasPairedCharacter, @isSoftWrapIndentation}) -> + constructor: (properties) -> + {@value, @scopes, @isAtomic, @bufferDelta, @isHardTab, @hasPairedCharacter, @isSoftWrapIndentation} = properties + @firstNonWhitespaceIndex = properties.firstNonWhitespaceIndex ? null + @firstTrailingWhitespaceIndex = properties.firstTrailingWhitespaceIndex ? null + @screenDelta = @value.length @bufferDelta ?= @screenDelta @hasPairedCharacter ?= textUtils.hasPairedCharacter(@value) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 6f86847de..29ed6b88a 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -122,6 +122,8 @@ class TokenizedLine @text = text Object.defineProperty @prototype, 'tokens', get: -> + offset = 0 + atom.grammars.decodeContent @text, @tags, @parentScopes.slice(), (tokenProperties, index) => switch @specialTokens[index] when SoftTab @@ -133,6 +135,16 @@ class TokenizedLine tokenProperties.isAtomic = true tokenProperties.hasPairedCharacter = true + if offset < @firstNonWhitespaceIndex + tokenProperties.firstNonWhitespaceIndex = + Math.min(offset + tokenProperties.value.length, @firstNonWhitespaceIndex - offset) + + if @lineEnding? and (offset + tokenProperties.value.length > @firstTrailingWhitespaceIndex) + tokenProperties.firstTrailingWhitespaceIndex = + Math.max(0, @firstTrailingWhitespaceIndex - offset) + + offset += tokenProperties.value.length + new Token(tokenProperties) buildText: -> @@ -332,17 +344,8 @@ class TokenizedLine @firstNonWhitespaceIndex = @text.search(NonWhitespaceRegex) if @firstNonWhitespaceIndex > 0 and isPairedCharacter(@text, @firstNonWhitespaceIndex - 1) @firstNonWhitespaceIndex-- - firstTrailingWhitespaceIndex = @text.search(TrailingWhitespaceRegex) - @lineIsWhitespaceOnly = firstTrailingWhitespaceIndex is 0 - index = 0 - for token in @tokens - if index < @firstNonWhitespaceIndex - token.firstNonWhitespaceIndex = Math.min(index + token.value.length, @firstNonWhitespaceIndex - index) - # Only the *last* segment of a soft-wrapped line can have trailing whitespace - if @lineEnding? and (index + token.value.length > firstTrailingWhitespaceIndex) - token.firstTrailingWhitespaceIndex = Math.max(0, firstTrailingWhitespaceIndex - index) - index += token.value.length - return + @firstTrailingWhitespaceIndex = @text.search(TrailingWhitespaceRegex) + @lineIsWhitespaceOnly = @firstTrailingWhitespaceIndex is 0 substituteInvisibleCharacters: -> invisibles = @invisibles From f3f609861ea7dad88f61fd377ca7f9f0efed8942 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sun, 10 May 2015 10:21:00 +0200 Subject: [PATCH 1167/1783] Make TokenizedLine::softWrapAt work with new token representation --- src/tokenized-line.coffee | 47 ++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 29ed6b88a..f8204ee51 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -259,23 +259,38 @@ class TokenizedLine indentTokens softWrapAt: (column, hangingIndent) -> - return [new TokenizedLine([], '', [0, 0], [0, 0]), this] if column is 0 + return [null, this] if column is 0 - rightTokens = new Array(@tokens...) - leftTokens = [] - leftScreenColumn = 0 + leftText = @text.substring(0, column) + rightText = @text.substring(column) - while leftScreenColumn < column - if leftScreenColumn + rightTokens[0].screenDelta > column - rightTokens[0..0] = rightTokens[0].splitAt(column - leftScreenColumn) - nextToken = rightTokens.shift() - leftScreenColumn += nextToken.screenDelta - leftTokens.push nextToken + leftTags = [] + rightParentScopes = @parentScopes.slice() - indentationTokens = @buildSoftWrapIndentationTokens(leftTokens[0], hangingIndent) + screenColumn = 0 + for tag, index in @tags + if tag >= 0 + if screenColumn + tag < column + screenColumn += tag + else + leftTags.push(column - screenColumn) + rightTags = @tags.slice(index + 1) + rightPrefix = screenColumn + tag - column + rightTags.unshift(rightPrefix) if rightPrefix > 0 + break + else if (tag % 2) is -1 + rightParentScopes.push(tag) + else + rightParentScopes.pop() + leftTags.push(tag) + + softWrapIndent = @indentLevel * @tabLength + (hangingIndent ? 0) + rightTags.unshift(softWrapIndent) if softWrapIndent > 0 leftFragment = new TokenizedLine( - tokens: leftTokens + parentScopes: @parentScopes + text: leftText + tags: leftTags startBufferColumn: @startBufferColumn ruleStack: @ruleStack invisibles: @invisibles @@ -284,12 +299,14 @@ class TokenizedLine tabLength: @tabLength ) rightFragment = new TokenizedLine( - tokens: indentationTokens.concat(rightTokens) + parentScopes: rightParentScopes + text: rightText + tags: rightTags startBufferColumn: @bufferColumnForScreenColumn(column) ruleStack: @ruleStack invisibles: @invisibles - lineEnding: @lineEnding, - indentLevel: @indentLevel, + lineEnding: @lineEnding + indentLevel: @indentLevel tabLength: @tabLength ) [leftFragment, rightFragment] From 6274ac25fab2efe4ae28e63688720f4e62551315 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sun, 10 May 2015 10:21:11 +0200 Subject: [PATCH 1168/1783] Fix TokenizedLine::copy for new representation --- src/tokenized-line.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index f8204ee51..a990c3fe3 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -158,7 +158,7 @@ class TokenizedLine delta copy: -> - new TokenizedLine({@tokens, @lineEnding, @ruleStack, @startBufferColumn, @fold}) + new TokenizedLine({@parentScopes, @text, @tags, @lineEnding, @ruleStack, @startBufferColumn, @fold}) # This clips a given screen column to a valid column that's within the line # and not in the middle of any atomic tokens. From 6eb61d977d0c5d166580fcc5ca3d841f5ab28b0b Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sun, 10 May 2015 10:23:01 +0200 Subject: [PATCH 1169/1783] =?UTF-8?q?Delete=20spec=20that=E2=80=99s=20no?= =?UTF-8?q?=20longer=20relevant?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spec/tokenized-buffer-spec.coffee | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/spec/tokenized-buffer-spec.coffee b/spec/tokenized-buffer-spec.coffee index 3cd776c2b..768e77ba4 100644 --- a/spec/tokenized-buffer-spec.coffee +++ b/spec/tokenized-buffer-spec.coffee @@ -695,21 +695,6 @@ describe "TokenizedBuffer", -> expect(line.tokens[0].firstNonWhitespaceIndex).toBe 2 expect(line.tokens[line.tokens.length - 1].firstTrailingWhitespaceIndex).toBe 0 - it "sets the ::firstNonWhitespaceIndex and ::firstTrailingWhitespaceIndex correctly when tokens are split for soft-wrapping", -> - tokenizedBuffer.setInvisibles(space: 'S') - buffer.setText(" token ") - fullyTokenize(tokenizedBuffer) - token = tokenizedBuffer.tokenizedLines[0].tokens[0] - - [leftToken, rightToken] = token.splitAt(1) - expect(leftToken.hasInvisibleCharacters).toBe true - expect(leftToken.firstNonWhitespaceIndex).toBe 1 - expect(leftToken.firstTrailingWhitespaceIndex).toBe null - - expect(leftToken.hasInvisibleCharacters).toBe true - expect(rightToken.firstNonWhitespaceIndex).toBe null - expect(rightToken.firstTrailingWhitespaceIndex).toBe 5 - describe ".indentLevel on tokenized lines", -> beforeEach -> buffer = atom.project.bufferForPathSync('sample.js') From 24967afed14a2ca829991d1f5480b28a3e22c82d Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 11 May 2015 20:20:30 +0200 Subject: [PATCH 1170/1783] Substitute invisibles in initial scan --- src/tokenized-line.coffee | 99 +++++++++++++++++++++++++++------------ 1 file changed, 70 insertions(+), 29 deletions(-) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index a990c3fe3..063d2f6da 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -19,23 +19,23 @@ class TokenizedLine firstNonWhitespaceIndex: 0 foldable: false - constructor: ({@parentScopes, @text, @tags, @lineEnding, @ruleStack, @startBufferColumn, @fold, @tabLength, @indentLevel, @invisibles}) -> - @startBufferColumn ?= 0 - + constructor: (properties) -> + @id = idCounter++ @specialTokens = {} + return unless properties? + + {@parentScopes, @text, @tags, @lineEnding, @ruleStack} = properties + {@startBufferColumn, @fold, @tabLength, @indentLevel, @invisibles} = properties + + @startBufferColumn ?= 0 + @bufferDelta = @text.length + @subdivideTokens() + @buildEndOfLineInvisibles() if @invisibles? and @lineEnding? - # @tokens = @breakOutAtomicTokens(tokens) - @bufferDelta = @buildBufferDelta() - @softWrapIndentationTokens = @getSoftWrapIndentationTokens() - @softWrapIndentationDelta = @buildSoftWrapIndentationDelta() - - @id = idCounter++ - @markLeadingAndTrailingWhitespaceTokens() - if @invisibles - @substituteInvisibleCharacters() - @buildEndOfLineInvisibles() if @lineEnding? + # @softWrapIndentationTokens = @getSoftWrapIndentationTokens() + # @softWrapIndentationDelta = @buildSoftWrapIndentationDelta() subdivideTokens: -> text = '' @@ -43,7 +43,8 @@ class TokenizedLine screenColumn = 0 tokenIndex = 0 tokenOffset = 0 - inLeadingWhitespace = true + firstNonWhitespaceColumn = null + lastNonWhitespaceColumn = null while bufferColumn < @text.length # advance to next token if we've iterated over its length @@ -67,6 +68,9 @@ class TokenizedLine @tags.splice(tokenIndex, 1, splitTokens...) + firstNonWhitespaceColumn ?= screenColumn + lastNonWhitespaceColumn = screenColumn + text += @text.substr(bufferColumn, 2) screenColumn++ bufferColumn += 2 @@ -77,14 +81,17 @@ class TokenizedLine tokenOffset = 0 # split out leading soft tabs - else if character is ' ' and inLeadingWhitespace - if inLeadingWhitespace and (screenColumn + 1) % @tabLength is 0 - @specialTokens[tokenIndex] = SoftTab - suffix = @tags[tokenIndex] - @tabLength - @tags.splice(tokenIndex, 1, @tabLength) - @tags.splice(tokenIndex + 1, 0, suffix) if suffix > 0 + else if character is ' ' + if firstNonWhitespaceColumn? + text += ' ' + else + if (screenColumn + 1) % @tabLength is 0 + @specialTokens[tokenIndex] = SoftTab + suffix = @tags[tokenIndex] - @tabLength + @tags.splice(tokenIndex, 1, @tabLength) + @tags.splice(tokenIndex + 1, 0, suffix) if suffix > 0 + text += @invisibles?.space ? ' ' - text += character screenColumn++ bufferColumn++ tokenOffset++ @@ -92,7 +99,11 @@ class TokenizedLine # expand hard tabs to the next tab stop else if character is '\t' tabLength = @tabLength - (screenColumn % @tabLength) - text += ' ' for i in [0...tabLength] by 1 + if @invisibles?.tab + text += @invisibles.tab + else + text += ' ' + text += ' ' for i in [1...tabLength] by 1 prefix = tokenOffset suffix = @tags[tokenIndex] - tokenOffset - 1 @@ -113,7 +124,9 @@ class TokenizedLine # continue past any other character else - inLeadingWhitespace = false + firstNonWhitespaceColumn ?= screenColumn + lastNonWhitespaceColumn = screenColumn + text += character screenColumn++ bufferColumn++ @@ -121,6 +134,19 @@ class TokenizedLine @text = text + @firstNonWhitespaceIndex = firstNonWhitespaceColumn + if lastNonWhitespaceColumn? + if lastNonWhitespaceColumn + 1 < @text.length + @firstTrailingWhitespaceIndex = lastNonWhitespaceColumn + 1 + if @invisibles?.space + @text = + @text.substring(0, @firstTrailingWhitespaceIndex) + + @text.substring(@firstTrailingWhitespaceIndex) + .replace(RepeatedSpaceRegex, @invisibles.space) + else + @lineIsWhitespaceOnly = true + @firstTrailingWhitespaceIndex = 0 + Object.defineProperty @prototype, 'tokens', get: -> offset = 0 @@ -137,7 +163,7 @@ class TokenizedLine if offset < @firstNonWhitespaceIndex tokenProperties.firstNonWhitespaceIndex = - Math.min(offset + tokenProperties.value.length, @firstNonWhitespaceIndex - offset) + Math.min(tokenProperties.value.length, @firstNonWhitespaceIndex - offset) if @lineEnding? and (offset + tokenProperties.value.length > @firstTrailingWhitespaceIndex) tokenProperties.firstTrailingWhitespaceIndex = @@ -158,7 +184,20 @@ class TokenizedLine delta copy: -> - new TokenizedLine({@parentScopes, @text, @tags, @lineEnding, @ruleStack, @startBufferColumn, @fold}) + copy = new TokenizedLine + copy.indentLevel = @indentLevel + copy.parentScopes = @parentScopes + copy.text = @text + copy.tags = @tags + copy.specialTokens = @specialTokens + copy.firstNonWhitespaceIndex = @firstNonWhitespaceIndex + copy.firstTrailingWhitespaceIndex = @firstTrailingWhitespaceIndex + copy.lineEnding = @lineEnding + copy.endOfLineInvisibles = @endOfLineInvisibles + copy.ruleStack = @ruleStack + copy.startBufferColumn = @startBufferColumn + copy.fold = @fold + copy # This clips a given screen column to a valid column that's within the line # and not in the middle of any atomic tokens. @@ -315,12 +354,14 @@ class TokenizedLine @lineEnding is null isColumnInsideSoftWrapIndentation: (column) -> - return false if @softWrapIndentationTokens.length is 0 - - column < @softWrapIndentationDelta + false + # return false if @softWrapIndentationTokens.length is 0 + # + # column < @softWrapIndentationDelta getSoftWrapIndentationTokens: -> - _.select(@tokens, (token) -> token.isSoftWrapIndentation) + [] + # _.select(@tokens, (token) -> token.isSoftWrapIndentation) buildSoftWrapIndentationDelta: -> _.reduce @softWrapIndentationTokens, ((acc, token) -> acc + token.screenDelta), 0 From a8d01bcec1a8740966f5ee011fc33b05f9f0741c Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 11 May 2015 23:35:52 +0200 Subject: [PATCH 1171/1783] Fix bufferRangeForScopeAtPosition with new tags array scheme --- spec/tokenized-buffer-spec.coffee | 4 +-- src/token.coffee | 2 +- src/tokenized-buffer.coffee | 57 +++++++++++++++++++++++-------- src/tokenized-line.coffee | 6 ---- 4 files changed, 46 insertions(+), 23 deletions(-) diff --git a/spec/tokenized-buffer-spec.coffee b/spec/tokenized-buffer-spec.coffee index 768e77ba4..0c5363ad3 100644 --- a/spec/tokenized-buffer-spec.coffee +++ b/spec/tokenized-buffer-spec.coffee @@ -580,7 +580,7 @@ describe "TokenizedBuffer", -> describe "when the selector matches a run of multiple tokens at the position", -> it "returns the range covered by all contigous tokens (within a single line)", -> - expect(tokenizedBuffer.bufferRangeForScopeAtPosition('.function', [1, 18])).toEqual [[1, 6], [1, 28]] + expect(tokenizedBuffer.bufferRangeForScopeAtPosition('.meta.function', [1, 18])).toEqual [[1, 6], [1, 28]] describe "when the editor.tabLength config value changes", -> it "updates the tab length of the tokenized lines", -> @@ -734,7 +734,7 @@ describe "TokenizedBuffer", -> it "updates empty line indent guides when the empty line is the last line", -> buffer.insert([12, 2], '\n') - # The newline and he tab need to be in two different operations to surface the bug + # The newline and the tab need to be in two different operations to surface the bug buffer.insert([12, 0], ' ') expect(tokenizedBuffer.tokenizedLineForRow(13).indentLevel).toBe 1 diff --git a/src/token.coffee b/src/token.coffee index 583e25e9b..7b24764ae 100644 --- a/src/token.coffee +++ b/src/token.coffee @@ -24,7 +24,7 @@ class Token {@value, @scopes, @isAtomic, @bufferDelta, @isHardTab, @hasPairedCharacter, @isSoftWrapIndentation} = properties @firstNonWhitespaceIndex = properties.firstNonWhitespaceIndex ? null @firstTrailingWhitespaceIndex = properties.firstTrailingWhitespaceIndex ? null - + @screenDelta = @value.length @bufferDelta ?= @screenDelta @hasPairedCharacter ?= textUtils.hasPairedCharacter(@value) diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 9dde39afe..b49f55939 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -1,6 +1,7 @@ _ = require 'underscore-plus' {CompositeDisposable, Emitter} = require 'event-kit' {Point, Range} = require 'text-buffer' +{ScopeSelector} = require 'first-mate' Serializable = require 'serializable' Model = require './model' TokenizedLine = require './tokenized-line' @@ -390,25 +391,53 @@ class TokenizedBuffer extends Model new Point(row, column) bufferRangeForScopeAtPosition: (selector, position) -> + selector = new ScopeSelector(selector.replace(/^\./, '')) position = Point.fromObject(position) - tokenizedLine = @tokenizedLines[position.row] - startIndex = tokenizedLine.tokenIndexAtBufferColumn(position.column) - for index in [startIndex..0] - token = tokenizedLine.tokenAtIndex(index) - break unless token.matchesScopeSelector(selector) - firstToken = token + {parentScopes, tags} = @tokenizedLines[position.row] + scopes = parentScopes.map (tag) -> atom.grammars.scopeForId(tag) - for index in [startIndex...tokenizedLine.getTokenCount()] - token = tokenizedLine.tokenAtIndex(index) - break unless token.matchesScopeSelector(selector) - lastToken = token + startColumn = 0 + for tag, tokenIndex in tags + if tag < 0 + if tag % 2 is -1 + scopes.push(atom.grammars.scopeForId(tag)) + else + scopes.pop() + else + endColumn = startColumn + tag + if endColumn > position.column + break + else + startColumn = endColumn - return unless firstToken? and lastToken? + return unless selector.matches(scopes) - startColumn = tokenizedLine.bufferColumnForToken(firstToken) - endColumn = tokenizedLine.bufferColumnForToken(lastToken) + lastToken.bufferDelta - new Range([position.row, startColumn], [position.row, endColumn]) + startScopes = scopes.slice() + for startTokenIndex in [(tokenIndex - 1)..0] by -1 + tag = tags[startTokenIndex] + if tag < 0 + if tag % 2 is -1 + startScopes.pop() + else + startScopes.push(atom.grammars.scopeForId(tag)) + else + break unless selector.matches(startScopes) + startColumn -= tag + + endScopes = scopes.slice() + for endTokenIndex in [(tokenIndex + 1)...tags.length] by 1 + tag = tags[endTokenIndex] + if tag < 0 + if tag % 2 is -1 + endScopes.push(atom.grammars.scopeForId(tag)) + else + endScopes.pop() + else + break unless selector.matches(endScopes) + endColumn += tag + + new Range(new Point(position.row, startColumn), new Point(position.row, endColumn)) iterateTokensInBufferRange: (bufferRange, iterator) -> bufferRange = Range.fromObject(bufferRange) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 063d2f6da..160c8360e 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -459,12 +459,6 @@ class TokenizedLine getTokenCount: -> @tokens.length - bufferColumnForToken: (targetToken) -> - column = 0 - for token in @tokens - return column if token is targetToken - column += token.bufferDelta - getScopeTree: -> return @scopeTree if @scopeTree? From 70eb7f77b018b0b7154e9369364e69f26a498996 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 12 May 2015 00:12:28 +0200 Subject: [PATCH 1172/1783] Drop unused methods --- src/tokenized-line.coffee | 43 --------------------------------------- 1 file changed, 43 deletions(-) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 160c8360e..be31068b0 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -387,49 +387,6 @@ class TokenizedLine delta = nextDelta delta - breakOutAtomicTokens: (inputTokens) -> - outputTokens = [] - breakOutLeadingSoftTabs = true - column = @startBufferColumn - for token in inputTokens - newTokens = token.breakOutAtomicTokens(@tabLength, breakOutLeadingSoftTabs, column) - column += newToken.value.length for newToken in newTokens - outputTokens.push(newTokens...) - breakOutLeadingSoftTabs = token.isOnlyWhitespace() if breakOutLeadingSoftTabs - outputTokens - - markLeadingAndTrailingWhitespaceTokens: -> - @firstNonWhitespaceIndex = @text.search(NonWhitespaceRegex) - if @firstNonWhitespaceIndex > 0 and isPairedCharacter(@text, @firstNonWhitespaceIndex - 1) - @firstNonWhitespaceIndex-- - @firstTrailingWhitespaceIndex = @text.search(TrailingWhitespaceRegex) - @lineIsWhitespaceOnly = @firstTrailingWhitespaceIndex is 0 - - substituteInvisibleCharacters: -> - invisibles = @invisibles - changedText = false - - for token, i in @tokens - if token.isHardTab - if invisibles.tab - token.value = invisibles.tab + token.value.substring(invisibles.tab.length) - token.hasInvisibleCharacters = true - changedText = true - else - if invisibles.space - if token.hasLeadingWhitespace() and not token.isSoftWrapIndentation - token.value = token.value.replace LeadingWhitespaceRegex, (leadingWhitespace) -> - leadingWhitespace.replace RepeatedSpaceRegex, invisibles.space - token.hasInvisibleCharacters = true - changedText = true - if token.hasTrailingWhitespace() - token.value = token.value.replace TrailingWhitespaceRegex, (leadingWhitespace) -> - leadingWhitespace.replace RepeatedSpaceRegex, invisibles.space - token.hasInvisibleCharacters = true - changedText = true - - @text = @buildText() if changedText - buildEndOfLineInvisibles: -> @endOfLineInvisibles = [] {cr, eol} = @invisibles From b8895cdaaf02b499b7d1345b5a8988b9bc669864 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 12 May 2015 17:57:51 +0200 Subject: [PATCH 1173/1783] Update spec based on new interface for Grammar::tokenizeLine --- spec/text-editor-spec.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index dd6b69f26..66aedcf53 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -4112,8 +4112,9 @@ describe "TextEditor", -> runs -> grammar = atom.grammars.selectGrammar("text.js") - {tokens} = grammar.tokenizeLine("var i; // http://github.com") + {line, tags} = grammar.tokenizeLine("var i; // http://github.com") + tokens = atom.grammars.decodeContent(line, tags) expect(tokens[0].value).toBe "var" expect(tokens[0].scopes).toEqual ["source.js", "storage.modifier.js"] From 77e8a906c230fa791a6c5ec6cbcce287ee90261b Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 12 May 2015 17:58:16 +0200 Subject: [PATCH 1174/1783] Fix soft wrapping with tags array, including soft-wrap indent --- src/tokenized-line.coffee | 226 +++++++++++++++++++++++++------------- 1 file changed, 149 insertions(+), 77 deletions(-) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index be31068b0..352ca1264 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -5,6 +5,7 @@ Token = require './token' SoftTab = Symbol('SoftTab') HardTab = Symbol('HardTab') PairedCharacter = Symbol('PairedCharacter') +SoftWrapIndent = Symbol('SoftWrapIndent') NonWhitespaceRegex = /\S/ LeadingWhitespaceRegex = /^\s*/ @@ -34,9 +35,6 @@ class TokenizedLine @subdivideTokens() @buildEndOfLineInvisibles() if @invisibles? and @lineEnding? - # @softWrapIndentationTokens = @getSoftWrapIndentationTokens() - # @softWrapIndentationDelta = @buildSoftWrapIndentationDelta() - subdivideTokens: -> text = '' bufferColumn = 0 @@ -160,6 +158,9 @@ class TokenizedLine when PairedCharacter tokenProperties.isAtomic = true tokenProperties.hasPairedCharacter = true + when SoftWrapIndent + tokenProperties.isAtomic = true + tokenProperties.isSoftWrapIndentation = true if offset < @firstNonWhitespaceIndex tokenProperties.firstNonWhitespaceIndex = @@ -221,7 +222,7 @@ class TokenizedLine tokenStartColumn += token.screenDelta if @isColumnInsideSoftWrapIndentation(tokenStartColumn) - @softWrapIndentationDelta + @getSoftWrapIndentationDelta() else if token.isAtomic and tokenStartColumn < column if clip is 'forward' tokenStartColumn + token.screenDelta @@ -235,24 +236,59 @@ class TokenizedLine else column - screenColumnForBufferColumn: (bufferColumn, options) -> - bufferColumn = bufferColumn - @startBufferColumn - screenColumn = 0 - currentBufferColumn = 0 - for token in @tokens - break if currentBufferColumn + token.bufferDelta > bufferColumn - screenColumn += token.screenDelta - currentBufferColumn += token.bufferDelta - @clipScreenColumn(screenColumn + (bufferColumn - currentBufferColumn)) - - bufferColumnForScreenColumn: (screenColumn, options) -> + screenColumnForBufferColumn: (targetBufferColumn, options) -> bufferColumn = @startBufferColumn - currentScreenColumn = 0 - for token in @tokens - break if currentScreenColumn + token.screenDelta > screenColumn - bufferColumn += token.bufferDelta - currentScreenColumn += token.screenDelta - bufferColumn + (screenColumn - currentScreenColumn) + screenColumn = 0 + for tag, index in @tags + if tag > 0 + switch @specialTokens[index] + when HardTab + bufferDelta = 1 + screenDelta = tag + when SoftWrapIndent + bufferDelta = 0 + screenDelta = tag + else + bufferDelta = screenDelta = tag + + nextBufferColumn = bufferColumn + bufferDelta + if nextBufferColumn > targetBufferColumn + overshoot = targetBufferColumn - bufferColumn + bufferColumn += overshoot + screenColumn += Math.min(screenDelta, overshoot) + break + else + bufferColumn = nextBufferColumn + screenColumn += screenDelta + + screenColumn + + bufferColumnForScreenColumn: (targetScreenColumn) -> + bufferColumn = @startBufferColumn + screenColumn = 0 + for tag, index in @tags + if tag > 0 + switch @specialTokens[index] + when HardTab + bufferDelta = 1 + screenDelta = tag + when SoftWrapIndent + bufferDelta = 0 + screenDelta = tag + else + bufferDelta = screenDelta = tag + + nextScreenColumn = screenColumn + screenDelta + if nextScreenColumn > targetScreenColumn + overshoot = targetScreenColumn - screenColumn + screenColumn += overshoot + bufferColumn += Math.min(bufferDelta, overshoot) + break + else + screenColumn = nextScreenColumn + bufferColumn += bufferDelta + + bufferColumn getMaxScreenColumn: -> if @fold @@ -286,17 +322,6 @@ class TokenizedLine return maxColumn - buildSoftWrapIndentationTokens: (token, hangingIndent) -> - totalIndentSpaces = (@indentLevel * @tabLength) + hangingIndent - indentTokens = [] - while totalIndentSpaces > 0 - tokenLength = Math.min(@tabLength, totalIndentSpaces) - indentToken = token.buildSoftWrapIndentationToken(tokenLength) - indentTokens.push(indentToken) - totalIndentSpaces -= tokenLength - - indentTokens - softWrapAt: (column, hangingIndent) -> return [null, this] if column is 0 @@ -304,70 +329,117 @@ class TokenizedLine rightText = @text.substring(column) leftTags = [] + rightTags = [] + + leftSpecialTokens = {} + rightSpecialTokens = {} + rightParentScopes = @parentScopes.slice() screenColumn = 0 + for tag, index in @tags + # tag represents a token if tag >= 0 - if screenColumn + tag < column + # token ends before the soft wrap column + if screenColumn + tag <= column + if specialToken = @specialTokens[index] + leftSpecialTokens[index] = specialToken + leftTags.push(tag) screenColumn += tag - else - leftTags.push(column - screenColumn) - rightTags = @tags.slice(index + 1) + + # token starts before and ends after the split column + else if screenColumn <= column + leftSuffix = column - screenColumn rightPrefix = screenColumn + tag - column - rightTags.unshift(rightPrefix) if rightPrefix > 0 - break + + leftTags.push(leftSuffix) if leftSuffix > 0 + + softWrapIndent = @indentLevel * @tabLength + (hangingIndent ? 0) + rightText = ' ' + rightText for i in [0...softWrapIndent] by 1 + while softWrapIndent > 0 + indentToken = Math.min(softWrapIndent, @tabLength) + rightSpecialTokens[rightTags.length] = SoftWrapIndent + rightTags.push(indentToken) + softWrapIndent -= indentToken + + rightTags.push(rightPrefix) if rightPrefix > 0 + + screenColumn += tag + + # token is after split column + else + if specialToken = @specialTokens[index] + rightSpecialTokens[rightTags.length] = specialToken + rightTags.push(tag) + + # tag represents the start or end of a scop else if (tag % 2) is -1 - rightParentScopes.push(tag) + if screenColumn < column + leftTags.push(tag) + rightParentScopes.push(tag) + else + rightTags.push(tag) else - rightParentScopes.pop() - leftTags.push(tag) + if screenColumn < column + leftTags.push(tag) + rightParentScopes.pop() + else + rightTags.push(tag) - softWrapIndent = @indentLevel * @tabLength + (hangingIndent ? 0) - rightTags.unshift(softWrapIndent) if softWrapIndent > 0 + splitBufferColumn = @bufferColumnForScreenColumn(column) + + leftFragment = new TokenizedLine + leftFragment.parentScopes = @parentScopes + leftFragment.text = leftText + leftFragment.tags = leftTags + leftFragment.specialTokens = leftSpecialTokens + leftFragment.startBufferColumn = @startBufferColumn + leftFragment.bufferDelta = splitBufferColumn - @startBufferColumn + leftFragment.ruleStack = @ruleStack + leftFragment.invisibles = @invisibles + leftFragment.lineEnding = null + leftFragment.indentLevel = @indentLevel + leftFragment.tabLength = @tabLength + leftFragment.firstNonWhitespaceIndex = Math.min(column, @firstNonWhitespaceIndex) + leftFragment.firstTrailingWhitespaceIndex = Math.min(column, @firstTrailingWhitespaceIndex) + + rightFragment = new TokenizedLine + rightFragment.parentScopes = rightParentScopes + rightFragment.text = rightText + rightFragment.tags = rightTags + rightFragment.specialTokens = rightSpecialTokens + rightFragment.startBufferColumn = splitBufferColumn + rightFragment.bufferDelta = @bufferDelta - splitBufferColumn + rightFragment.ruleStack = @ruleStack + rightFragment.invisibles = @invisibles + rightFragment.lineEnding = @lineEnding + rightFragment.indentLevel = @indentLevel + rightFragment.tabLength = @tabLength + rightFragment.endOfLineInvisibles = @endOfLineInvisibles + rightFragment.firstNonWhitespaceIndex = Math.max(0, @firstNonWhitespaceIndex - column) + rightFragment.firstTrailingWhitespaceIndex = Math.max(0, @firstTrailingWhitespaceIndex - column) - leftFragment = new TokenizedLine( - parentScopes: @parentScopes - text: leftText - tags: leftTags - startBufferColumn: @startBufferColumn - ruleStack: @ruleStack - invisibles: @invisibles - lineEnding: null, - indentLevel: @indentLevel, - tabLength: @tabLength - ) - rightFragment = new TokenizedLine( - parentScopes: rightParentScopes - text: rightText - tags: rightTags - startBufferColumn: @bufferColumnForScreenColumn(column) - ruleStack: @ruleStack - invisibles: @invisibles - lineEnding: @lineEnding - indentLevel: @indentLevel - tabLength: @tabLength - ) [leftFragment, rightFragment] isSoftWrapped: -> @lineEnding is null - isColumnInsideSoftWrapIndentation: (column) -> - false - # return false if @softWrapIndentationTokens.length is 0 - # - # column < @softWrapIndentationDelta + isColumnInsideSoftWrapIndentation: (targetColumn) -> + targetColumn < @getSoftWrapIndentationDelta() - getSoftWrapIndentationTokens: -> - [] - # _.select(@tokens, (token) -> token.isSoftWrapIndentation) - - buildSoftWrapIndentationDelta: -> - _.reduce @softWrapIndentationTokens, ((acc, token) -> acc + token.screenDelta), 0 + getSoftWrapIndentationDelta: -> + delta = 0 + for tag, index in @tags + if tag >= 0 + if @specialTokens[index] is SoftWrapIndent + delta += tag + else + break + delta hasOnlySoftWrapIndentation: -> - @tokens.length is @softWrapIndentationTokens.length + @getSoftWrapIndentationDelta() is @text.length tokenAtBufferColumn: (bufferColumn) -> @tokens[@tokenIndexAtBufferColumn(bufferColumn)] From 2afe013f9ef514b6144e7c30a5bda827f4d13db3 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 12 May 2015 18:30:33 +0200 Subject: [PATCH 1175/1783] Assign ::hasInvisibleCharacters on Token shims --- src/token.coffee | 3 ++- src/tokenized-line.coffee | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/token.coffee b/src/token.coffee index 7b24764ae..6a6683a73 100644 --- a/src/token.coffee +++ b/src/token.coffee @@ -21,7 +21,8 @@ class Token hasInvisibleCharacters: false constructor: (properties) -> - {@value, @scopes, @isAtomic, @bufferDelta, @isHardTab, @hasPairedCharacter, @isSoftWrapIndentation} = properties + {@value, @scopes, @isAtomic, @isHardTab, @bufferDelta} = properties + {@hasInvisibleCharacters, @hasPairedCharacter, @isSoftWrapIndentation} = properties @firstNonWhitespaceIndex = properties.firstNonWhitespaceIndex ? null @firstTrailingWhitespaceIndex = properties.firstTrailingWhitespaceIndex ? null diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 352ca1264..10ed3a27e 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -155,6 +155,7 @@ class TokenizedLine when HardTab tokenProperties.isAtomic = true tokenProperties.bufferDelta = 1 + tokenProperties.hasInvisibleCharacters = true if @invisibles?.tab when PairedCharacter tokenProperties.isAtomic = true tokenProperties.hasPairedCharacter = true @@ -165,10 +166,12 @@ class TokenizedLine if offset < @firstNonWhitespaceIndex tokenProperties.firstNonWhitespaceIndex = Math.min(tokenProperties.value.length, @firstNonWhitespaceIndex - offset) + tokenProperties.hasInvisibleCharacters = true if @invisibles?.space if @lineEnding? and (offset + tokenProperties.value.length > @firstTrailingWhitespaceIndex) tokenProperties.firstTrailingWhitespaceIndex = Math.max(0, @firstTrailingWhitespaceIndex - offset) + tokenProperties.hasInvisibleCharacters = true if @invisibles?.space offset += tokenProperties.value.length From 75112a017d5f68c86eaec1f61d1087c39d50356e Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 12 May 2015 18:41:48 +0200 Subject: [PATCH 1176/1783] Fix assignment of last non-whitespace column for paired characters --- src/tokenized-line.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 10ed3a27e..55adcac89 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -67,10 +67,10 @@ class TokenizedLine @tags.splice(tokenIndex, 1, splitTokens...) firstNonWhitespaceColumn ?= screenColumn - lastNonWhitespaceColumn = screenColumn + lastNonWhitespaceColumn = screenColumn + 1 text += @text.substr(bufferColumn, 2) - screenColumn++ + screenColumn += 2 bufferColumn += 2 tokenIndex++ if prefix > 0 From 6befa0200f904fb753a1118142aec40f98081916 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 12 May 2015 19:36:32 +0200 Subject: [PATCH 1177/1783] Assign ::isHardTab to shim tokens --- src/tokenized-line.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 55adcac89..80e03caac 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -154,6 +154,7 @@ class TokenizedLine tokenProperties.isAtomic = true when HardTab tokenProperties.isAtomic = true + tokenProperties.isHardTab = true tokenProperties.bufferDelta = 1 tokenProperties.hasInvisibleCharacters = true if @invisibles?.tab when PairedCharacter From d90d1f0ea7baa713166ff126ae408b2dc3a2455b Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 12 May 2015 19:36:53 +0200 Subject: [PATCH 1178/1783] =?UTF-8?q?Don=E2=80=99t=20build=20::specialToke?= =?UTF-8?q?ns=20unless=20properties=20are=20provided?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/tokenized-line.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 80e03caac..5b13c1f80 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -22,10 +22,10 @@ class TokenizedLine constructor: (properties) -> @id = idCounter++ - @specialTokens = {} return unless properties? + @specialTokens = {} {@parentScopes, @text, @tags, @lineEnding, @ruleStack} = properties {@startBufferColumn, @fold, @tabLength, @indentLevel, @invisibles} = properties From 8ab9a9f9bb6b00d5047efa4b1a84b859ed60b0bd Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 12 May 2015 19:37:26 +0200 Subject: [PATCH 1179/1783] Account for softWrapIndent when assigning indices on soft wrap line --- src/tokenized-line.coffee | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 5b13c1f80..ec13af201 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -361,11 +361,12 @@ class TokenizedLine softWrapIndent = @indentLevel * @tabLength + (hangingIndent ? 0) rightText = ' ' + rightText for i in [0...softWrapIndent] by 1 - while softWrapIndent > 0 - indentToken = Math.min(softWrapIndent, @tabLength) + remainingSoftWrapIndent = softWrapIndent + while remainingSoftWrapIndent > 0 + indentToken = Math.min(remainingSoftWrapIndent, @tabLength) rightSpecialTokens[rightTags.length] = SoftWrapIndent rightTags.push(indentToken) - softWrapIndent -= indentToken + remainingSoftWrapIndent -= indentToken rightTags.push(rightPrefix) if rightPrefix > 0 @@ -421,8 +422,8 @@ class TokenizedLine rightFragment.indentLevel = @indentLevel rightFragment.tabLength = @tabLength rightFragment.endOfLineInvisibles = @endOfLineInvisibles - rightFragment.firstNonWhitespaceIndex = Math.max(0, @firstNonWhitespaceIndex - column) - rightFragment.firstTrailingWhitespaceIndex = Math.max(0, @firstTrailingWhitespaceIndex - column) + rightFragment.firstNonWhitespaceIndex = Math.max(softWrapIndent, @firstNonWhitespaceIndex - column + softWrapIndent) + rightFragment.firstTrailingWhitespaceIndex = Math.max(softWrapIndent, @firstTrailingWhitespaceIndex - column + softWrapIndent) [leftFragment, rightFragment] From 27657537911ef29686e7cf9459012b80ee54505f Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 12 May 2015 19:39:10 +0200 Subject: [PATCH 1180/1783] =?UTF-8?q?Don=E2=80=99t=20assume=20same=20token?= =?UTF-8?q?=20instances=20in=20spec=20now=20that=20we=20use=20shims?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spec/tokenized-line-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/tokenized-line-spec.coffee b/spec/tokenized-line-spec.coffee index 0da83c91c..59270179c 100644 --- a/spec/tokenized-line-spec.coffee +++ b/spec/tokenized-line-spec.coffee @@ -27,7 +27,7 @@ describe "TokenizedLine", -> for child in scopeTree.children ensureValidScopeTree(child, scopeDescriptor.concat([scopeTree.scope])) else - expect(scopeTree).toBe tokens[tokenIndex++] + expect(scopeTree).toEqual tokens[tokenIndex++] expect(scopeDescriptor).toEqual scopeTree.scopes waitsForPromise -> From bf6754981b95493d81c8462ef94d59e8ce8cb264 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 12 May 2015 21:05:33 +0200 Subject: [PATCH 1181/1783] decodeContent -> decodeTokens --- spec/text-editor-spec.coffee | 2 +- src/tokenized-line.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 66aedcf53..01281492a 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -4114,7 +4114,7 @@ describe "TextEditor", -> grammar = atom.grammars.selectGrammar("text.js") {line, tags} = grammar.tokenizeLine("var i; // http://github.com") - tokens = atom.grammars.decodeContent(line, tags) + tokens = atom.grammars.decodeTokens(line, tags) expect(tokens[0].value).toBe "var" expect(tokens[0].scopes).toEqual ["source.js", "storage.modifier.js"] diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index ec13af201..66d426d7c 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -148,7 +148,7 @@ class TokenizedLine Object.defineProperty @prototype, 'tokens', get: -> offset = 0 - atom.grammars.decodeContent @text, @tags, @parentScopes.slice(), (tokenProperties, index) => + atom.grammars.decodeTokens @text, @tags, @parentScopes.slice(), (tokenProperties, index) => switch @specialTokens[index] when SoftTab tokenProperties.isAtomic = true From 6b51b5d02a708c5bfa6f179492548fcda5aca429 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 13 May 2015 19:53:22 +0200 Subject: [PATCH 1182/1783] Rename parentScopes to openScopes --- src/tokenized-buffer.coffee | 36 ++++++++++++++++++------------------ src/tokenized-line.coffee | 16 ++++++++-------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index b49f55939..b33fdd8fc 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -154,7 +154,7 @@ class TokenizedBuffer extends Model row = startRow loop previousStack = @stackForRow(row) - @tokenizedLines[row] = @buildTokenizedLineForRow(row, @stackForRow(row - 1), @parentScopesForRow(row)) + @tokenizedLines[row] = @buildTokenizedLineForRow(row, @stackForRow(row - 1), @openScopesForRow(row)) if --rowsRemaining is 0 filledRegion = false endRow = row @@ -214,7 +214,7 @@ class TokenizedBuffer extends Model @updateInvalidRows(start, end, delta) previousEndStack = @stackForRow(end) # used in spill detection below - newTokenizedLines = @buildTokenizedLinesForRows(start, end + delta, @stackForRow(start - 1), @parentScopesForRow(start)) + newTokenizedLines = @buildTokenizedLinesForRows(start, end + delta, @stackForRow(start - 1), @openScopesForRow(start)) _.spliceWithArray(@tokenizedLines, start, end - start + 1, newTokenizedLines) start = @retokenizeWhitespaceRowsIfIndentLevelChanged(start - 1, -1) @@ -235,7 +235,7 @@ class TokenizedBuffer extends Model line = @tokenizedLines[row] if line?.isOnlyWhitespace() and @indentLevelForRow(row) isnt line.indentLevel while line?.isOnlyWhitespace() - @tokenizedLines[row] = @buildTokenizedLineForRow(row, @stackForRow(row - 1), @parentScopesForRow(row)) + @tokenizedLines[row] = @buildTokenizedLineForRow(row, @stackForRow(row - 1), @openScopesForRow(row)) row += increment line = @tokenizedLines[row] @@ -277,17 +277,17 @@ class TokenizedBuffer extends Model @tokenizedLineForRow(row).isComment() and @tokenizedLineForRow(nextRow).isComment() - buildTokenizedLinesForRows: (startRow, endRow, startingStack, startingParentScopes) -> + buildTokenizedLinesForRows: (startRow, endRow, startingStack, startingopenScopes) -> ruleStack = startingStack - parentScopes = startingParentScopes + openScopes = startingopenScopes stopTokenizingAt = startRow + @chunkSize tokenizedLines = for row in [startRow..endRow] if (ruleStack or row is 0) and row < stopTokenizingAt - tokenizedLine = @buildTokenizedLineForRow(row, ruleStack, parentScopes) + tokenizedLine = @buildTokenizedLineForRow(row, ruleStack, openScopes) ruleStack = tokenizedLine.ruleStack - parentScopes = @scopesFromTags(parentScopes, tokenizedLine.tags) + openScopes = @scopesFromTags(openScopes, tokenizedLine.tags) else - tokenizedLine = @buildPlaceholderTokenizedLineForRow(row, parentScopes) + tokenizedLine = @buildPlaceholderTokenizedLineForRow(row, openScopes) tokenizedLine if endRow >= stopTokenizingAt @@ -300,23 +300,23 @@ class TokenizedBuffer extends Model @buildPlaceholderTokenizedLineForRow(row) for row in [startRow..endRow] buildPlaceholderTokenizedLineForRow: (row) -> - parentScopes = [@grammar.idForScope(@grammar.scopeName)] + openScopes = [@grammar.idForScope(@grammar.scopeName)] text = @buffer.lineForRow(row) tags = [text.length] tabLength = @getTabLength() indentLevel = @indentLevelForRow(row) lineEnding = @buffer.lineEndingForRow(row) - new TokenizedLine({parentScopes, text, tags, tabLength, indentLevel, @invisibles, lineEnding}) + new TokenizedLine({openScopes, text, tags, tabLength, indentLevel, @invisibles, lineEnding}) - buildTokenizedLineForRow: (row, ruleStack, parentScopes) -> - @buildTokenizedLineForRowWithText(row, @buffer.lineForRow(row), ruleStack, parentScopes) + buildTokenizedLineForRow: (row, ruleStack, openScopes) -> + @buildTokenizedLineForRowWithText(row, @buffer.lineForRow(row), ruleStack, openScopes) - buildTokenizedLineForRowWithText: (row, text, ruleStack = @stackForRow(row - 1), parentScopes = @parentScopesForRow(row)) -> + buildTokenizedLineForRowWithText: (row, text, ruleStack = @stackForRow(row - 1), openScopes = @openScopesForRow(row)) -> lineEnding = @buffer.lineEndingForRow(row) tabLength = @getTabLength() indentLevel = @indentLevelForRow(row) {tags, ruleStack} = @grammar.tokenizeLine(text, ruleStack, row is 0) - new TokenizedLine({parentScopes, text, tags, ruleStack, tabLength, lineEnding, indentLevel, @invisibles}) + new TokenizedLine({openScopes, text, tags, ruleStack, tabLength, lineEnding, indentLevel, @invisibles}) tokenizedLineForRow: (bufferRow) -> @tokenizedLines[bufferRow] @@ -324,10 +324,10 @@ class TokenizedBuffer extends Model stackForRow: (bufferRow) -> @tokenizedLines[bufferRow]?.ruleStack - parentScopesForRow: (bufferRow) -> + openScopesForRow: (bufferRow) -> if bufferRow > 0 precedingLine = @tokenizedLines[bufferRow - 1] - @scopesFromTags(precedingLine.parentScopes, precedingLine.tags) + @scopesFromTags(precedingLine.openScopes, precedingLine.tags) else [] @@ -394,8 +394,8 @@ class TokenizedBuffer extends Model selector = new ScopeSelector(selector.replace(/^\./, '')) position = Point.fromObject(position) - {parentScopes, tags} = @tokenizedLines[position.row] - scopes = parentScopes.map (tag) -> atom.grammars.scopeForId(tag) + {openScopes, tags} = @tokenizedLines[position.row] + scopes = openScopes.map (tag) -> atom.grammars.scopeForId(tag) startColumn = 0 for tag, tokenIndex in tags diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 66d426d7c..debf4dea0 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -26,7 +26,7 @@ class TokenizedLine return unless properties? @specialTokens = {} - {@parentScopes, @text, @tags, @lineEnding, @ruleStack} = properties + {@openScopes, @text, @tags, @lineEnding, @ruleStack} = properties {@startBufferColumn, @fold, @tabLength, @indentLevel, @invisibles} = properties @startBufferColumn ?= 0 @@ -148,7 +148,7 @@ class TokenizedLine Object.defineProperty @prototype, 'tokens', get: -> offset = 0 - atom.grammars.decodeTokens @text, @tags, @parentScopes.slice(), (tokenProperties, index) => + atom.grammars.decodeTokens @text, @tags, @openScopes.slice(), (tokenProperties, index) => switch @specialTokens[index] when SoftTab tokenProperties.isAtomic = true @@ -191,7 +191,7 @@ class TokenizedLine copy: -> copy = new TokenizedLine copy.indentLevel = @indentLevel - copy.parentScopes = @parentScopes + copy.openScopes = @openScopes copy.text = @text copy.tags = @tags copy.specialTokens = @specialTokens @@ -338,7 +338,7 @@ class TokenizedLine leftSpecialTokens = {} rightSpecialTokens = {} - rightParentScopes = @parentScopes.slice() + rightopenScopes = @openScopes.slice() screenColumn = 0 @@ -382,20 +382,20 @@ class TokenizedLine else if (tag % 2) is -1 if screenColumn < column leftTags.push(tag) - rightParentScopes.push(tag) + rightopenScopes.push(tag) else rightTags.push(tag) else if screenColumn < column leftTags.push(tag) - rightParentScopes.pop() + rightopenScopes.pop() else rightTags.push(tag) splitBufferColumn = @bufferColumnForScreenColumn(column) leftFragment = new TokenizedLine - leftFragment.parentScopes = @parentScopes + leftFragment.openScopes = @openScopes leftFragment.text = leftText leftFragment.tags = leftTags leftFragment.specialTokens = leftSpecialTokens @@ -410,7 +410,7 @@ class TokenizedLine leftFragment.firstTrailingWhitespaceIndex = Math.min(column, @firstTrailingWhitespaceIndex) rightFragment = new TokenizedLine - rightFragment.parentScopes = rightParentScopes + rightFragment.openScopes = rightopenScopes rightFragment.text = rightText rightFragment.tags = rightTags rightFragment.specialTokens = rightSpecialTokens From d7f558890425ad749503234b012d317ef52bb75c Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 13 May 2015 21:17:29 +0200 Subject: [PATCH 1183/1783] Generate line HTML based on tags instead of tokens This avoids creating a bunch of tokens as temporary objects since they are no longer stored. --- src/lines-component.coffee | 146 ++++++++++++++++++++++++------- src/special-token-symbols.coffee | 6 ++ src/text-editor-presenter.coffee | 8 +- src/tokenized-line.coffee | 6 +- 4 files changed, 127 insertions(+), 39 deletions(-) create mode 100644 src/special-token-symbols.coffee diff --git a/src/lines-component.coffee b/src/lines-component.coffee index fbec40b79..9904d5702 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -4,10 +4,13 @@ _ = require 'underscore-plus' CursorsComponent = require './cursors-component' HighlightsComponent = require './highlights-component' +{HardTab} = require './special-token-symbols' DummyLineNode = $$(-> @div className: 'line', style: 'position: absolute; visibility: hidden;', => @span 'x')[0] AcceptFilter = {acceptNode: -> NodeFilter.FILTER_ACCEPT} WrapperDiv = document.createElement('div') +TokenTextEscapeRegex = /[&"'<>]/g +MaxTokenLength = 20000 cloneObject = (object) -> clone = {} @@ -167,20 +170,122 @@ class LinesComponent @buildEndOfLineHTML(id) or ' ' buildLineInnerHTML: (id) -> - {indentGuidesVisible} = @newState - {tokens, text, isOnlyWhitespace} = @newState.lines[id] + lineState = @newState.lines[id] + {text, openScopes, tags, specialTokens, invisibles} = lineState + {firstNonWhitespaceIndex, firstTrailingWhitespaceIndex} = lineState + lineIsWhitespaceOnly = firstTrailingWhitespaceIndex is 0 + innerHTML = "" - scopeStack = [] - for token in tokens - innerHTML += @updateScopeStack(scopeStack, token.scopes) - hasIndentGuide = indentGuidesVisible and (token.hasLeadingWhitespace() or (token.hasTrailingWhitespace() and isOnlyWhitespace)) - innerHTML += token.getValueAsHtml({hasIndentGuide}) + tokenStart = 0 + scopeDepth = openScopes.length + + for tag in openScopes + scope = atom.grammars.scopeForId(tag) + innerHTML += "" + + for tag, index in tags + # tag represents start or end of a scope + if tag < 0 + if (tag % 2) is -1 + scopeDepth++ + scope = atom.grammars.scopeForId(tag) + innerHTML += "" + else + scopeDepth-- + innerHTML += "" + + # tag represents a token + else + tokenEnd = tokenStart + tag + tokenText = text.substring(tokenStart, tokenEnd) + isHardTab = specialTokens[index] is HardTab + if hasLeadingWhitespace = tokenStart < firstNonWhitespaceIndex + tokenFirstNonWhitespaceIndex = firstNonWhitespaceIndex - tokenStart + else + tokenFirstNonWhitespaceIndex = null + if hasTrailingWhitespace = tokenEnd > firstTrailingWhitespaceIndex + tokenFirstTrailingWhitespaceIndex = Math.max(0, firstTrailingWhitespaceIndex - tokenStart) + else + tokenFirstTrailingWhitespaceIndex = null + hasIndentGuide = @newState.indentGuidesVisible and (hasLeadingWhitespace or lineIsWhitespaceOnly) + hasInvisibleCharacters = + (invisibles?.tab and isHardTab) or + (invisibles?.space and (hasLeadingWhitespace or hasTrailingWhitespace)) + + innerHTML += @buildTokenHTML(tokenText, isHardTab, tokenFirstNonWhitespaceIndex, tokenFirstTrailingWhitespaceIndex, hasIndentGuide, hasInvisibleCharacters) + + tokenStart = tokenEnd + + while scopeDepth > 0 + innerHTML += "" + scopeDepth-- - innerHTML += @popScope(scopeStack) while scopeStack.length > 0 innerHTML += @buildEndOfLineHTML(id) innerHTML + buildTokenHTML: (tokenText, isHardTab, firstNonWhitespaceIndex, firstTrailingWhitespaceIndex, hasIndentGuide, hasInvisibleCharacters) -> + if isHardTab + classes = 'hard-tab' + classes += ' leading-whitespace' if firstNonWhitespaceIndex? + classes += ' trailing-whitespace' if firstTrailingWhitespaceIndex? + classes += ' indent-guide' if hasIndentGuide + classes += ' invisible-character' if hasInvisibleCharacters + return "#{@escapeTokenText(tokenText)}" + else + startIndex = 0 + endIndex = tokenText.length + + leadingHtml = '' + trailingHtml = '' + + if firstNonWhitespaceIndex? + leadingWhitespace = tokenText.substring(0, firstNonWhitespaceIndex) + + classes = 'leading-whitespace' + classes += ' indent-guide' if hasIndentGuide + classes += ' invisible-character' if hasInvisibleCharacters + + leadingHtml = "#{leadingWhitespace}" + startIndex = firstNonWhitespaceIndex + + if firstTrailingWhitespaceIndex? + tokenIsOnlyWhitespace = firstTrailingWhitespaceIndex is 0 + trailingWhitespace = tokenText.substring(firstTrailingWhitespaceIndex) + + classes = 'trailing-whitespace' + classes += ' indent-guide' if hasIndentGuide and not firstNonWhitespaceIndex? and tokenIsOnlyWhitespace + classes += ' invisible-character' if hasInvisibleCharacters + + trailingHtml = "#{trailingWhitespace}" + + endIndex = firstTrailingWhitespaceIndex + + html = leadingHtml + if tokenText.length > MaxTokenLength + while startIndex < endIndex + html += "" + @escapeTokenText(tokenText, startIndex, startIndex + MaxTokenLength) + "" + startIndex += MaxTokenLength + else + html += @escapeTokenText(tokenText, startIndex, endIndex) + + html += trailingHtml + html + + escapeTokenText: (tokenText, startIndex, endIndex) -> + if startIndex? and endIndex? and startIndex > 0 or endIndex < tokenText.length + tokenText = tokenText.slice(startIndex, endIndex) + tokenText.replace(TokenTextEscapeRegex, @escapeTokenTextReplace) + + escapeTokenTextReplace: (match) -> + switch match + when '&' then '&' + when '"' then '"' + when "'" then ''' + when '<' then '<' + when '>' then '>' + else match + buildEndOfLineHTML: (id) -> {endOfLineInvisibles} = @newState.lines[id] @@ -190,31 +295,6 @@ class LinesComponent html += "#{invisible}" html - updateScopeStack: (scopeStack, desiredScopeDescriptor) -> - html = "" - - # Find a common prefix - for scope, i in desiredScopeDescriptor - break unless scopeStack[i] is desiredScopeDescriptor[i] - - # Pop scopeDescriptor until we're at the common prefx - until scopeStack.length is i - html += @popScope(scopeStack) - - # Push onto common prefix until scopeStack equals desiredScopeDescriptor - for j in [i...desiredScopeDescriptor.length] - html += @pushScope(scopeStack, desiredScopeDescriptor[j]) - - html - - popScope: (scopeStack) -> - scopeStack.pop() - "" - - pushScope: (scopeStack, scope) -> - scopeStack.push(scope) - "" - updateLineNode: (id) -> oldLineState = @oldState.lines[id] newLineState = @newState.lines[id] diff --git a/src/special-token-symbols.coffee b/src/special-token-symbols.coffee new file mode 100644 index 000000000..06884b85f --- /dev/null +++ b/src/special-token-symbols.coffee @@ -0,0 +1,6 @@ +module.exports = { + SoftTab: Symbol('SoftTab') + HardTab: Symbol('HardTab') + PairedCharacter: Symbol('PairedCharacter') + SoftWrapIndent: Symbol('SoftWrapIndent') +} diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index ac6d0c363..d5e8fc09c 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -334,9 +334,15 @@ class TextEditorPresenter @state.content.lines[line.id] = screenRow: row text: line.text + openScopes: line.openScopes + tags: line.tags + specialTokens: line.specialTokens + firstNonWhitespaceIndex: line.firstNonWhitespaceIndex + firstTrailingWhitespaceIndex: line.firstTrailingWhitespaceIndex + invisibles: line.invisibles + endOfLineInvisibles: line.endOfLineInvisibles tokens: line.tokens isOnlyWhitespace: line.isOnlyWhitespace() - endOfLineInvisibles: line.endOfLineInvisibles indentLevel: line.indentLevel tabLength: line.tabLength fold: line.fold diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index debf4dea0..c10c6693d 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -1,11 +1,7 @@ _ = require 'underscore-plus' {isPairedCharacter} = require './text-utils' Token = require './token' - -SoftTab = Symbol('SoftTab') -HardTab = Symbol('HardTab') -PairedCharacter = Symbol('PairedCharacter') -SoftWrapIndent = Symbol('SoftWrapIndent') +{SoftTab, HardTab, PairedCharacter, SoftWrapIndent} = require './special-token-symbols' NonWhitespaceRegex = /\S/ LeadingWhitespaceRegex = /^\s*/ From 00b30f7db8a248c15aa2b5128937c5231ed3ff55 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 13 May 2015 22:03:26 +0200 Subject: [PATCH 1184/1783] Remove some dead code --- spec/tokenized-line-spec.coffee | 21 ---- src/token.coffee | 192 -------------------------------- src/tokenized-line.coffee | 32 ------ 3 files changed, 245 deletions(-) diff --git a/spec/tokenized-line-spec.coffee b/spec/tokenized-line-spec.coffee index 59270179c..2914ec089 100644 --- a/spec/tokenized-line-spec.coffee +++ b/spec/tokenized-line-spec.coffee @@ -17,24 +17,3 @@ describe "TokenizedLine", -> it "returns false when the line is not only whitespace", -> expect(editor.tokenizedLineForScreenRow(0).isOnlyWhitespace()).toBe false expect(editor.tokenizedLineForScreenRow(2).isOnlyWhitespace()).toBe false - - describe "::getScopeTree()", -> - it "returns a tree whose inner nodes are scopeDescriptor and whose leaf nodes are tokens in those scopeDescriptor", -> - [tokens, tokenIndex] = [] - - ensureValidScopeTree = (scopeTree, scopeDescriptor=[]) -> - if scopeTree.children? - for child in scopeTree.children - ensureValidScopeTree(child, scopeDescriptor.concat([scopeTree.scope])) - else - expect(scopeTree).toEqual tokens[tokenIndex++] - expect(scopeDescriptor).toEqual scopeTree.scopes - - waitsForPromise -> - atom.project.open('coffee.coffee').then (o) -> editor = o - - runs -> - tokenIndex = 0 - tokens = editor.tokenizedLineForScreenRow(1).tokens - scopeTree = editor.tokenizedLineForScreenRow(1).getScopeTree() - ensureValidScopeTree(scopeTree) diff --git a/src/token.coffee b/src/token.coffee index 6a6683a73..60e8194f8 100644 --- a/src/token.coffee +++ b/src/token.coffee @@ -1,13 +1,8 @@ _ = require 'underscore-plus' -textUtils = require './text-utils' -WhitespaceRegexesByTabLength = {} -EscapeRegex = /[&"'<>]/g StartDotRegex = /^\.?/ WhitespaceRegex = /\S/ -MaxTokenLength = 20000 - # Represents a single unit of text as selected by a grammar. module.exports = class Token @@ -28,7 +23,6 @@ class Token @screenDelta = @value.length @bufferDelta ?= @screenDelta - @hasPairedCharacter ?= textUtils.hasPairedCharacter(@value) isEqual: (other) -> # TODO: scopes is deprecated. This is here for the sake of lang package tests @@ -37,126 +31,6 @@ class Token isBracket: -> /^meta\.brace\b/.test(_.last(@scopes)) - splitAt: (splitIndex) -> - leftToken = new Token(value: @value.substring(0, splitIndex), scopes: @scopes) - rightToken = new Token(value: @value.substring(splitIndex), scopes: @scopes) - - if @firstNonWhitespaceIndex? - leftToken.firstNonWhitespaceIndex = Math.min(splitIndex, @firstNonWhitespaceIndex) - leftToken.hasInvisibleCharacters = @hasInvisibleCharacters - - if @firstNonWhitespaceIndex > splitIndex - rightToken.firstNonWhitespaceIndex = @firstNonWhitespaceIndex - splitIndex - rightToken.hasInvisibleCharacters = @hasInvisibleCharacters - - if @firstTrailingWhitespaceIndex? - rightToken.firstTrailingWhitespaceIndex = Math.max(0, @firstTrailingWhitespaceIndex - splitIndex) - rightToken.hasInvisibleCharacters = @hasInvisibleCharacters - - if @firstTrailingWhitespaceIndex < splitIndex - leftToken.firstTrailingWhitespaceIndex = @firstTrailingWhitespaceIndex - leftToken.hasInvisibleCharacters = @hasInvisibleCharacters - - [leftToken, rightToken] - - whitespaceRegexForTabLength: (tabLength) -> - WhitespaceRegexesByTabLength[tabLength] ?= new RegExp("([ ]{#{tabLength}})|(\t)|([^\t]+)", "g") - - breakOutAtomicTokens: (tabLength, breakOutLeadingSoftTabs, startColumn) -> - if @hasPairedCharacter - outputTokens = [] - column = startColumn - - for token in @breakOutPairedCharacters() - if token.isAtomic - outputTokens.push(token) - else - outputTokens.push(token.breakOutAtomicTokens(tabLength, breakOutLeadingSoftTabs, column)...) - breakOutLeadingSoftTabs = token.isOnlyWhitespace() if breakOutLeadingSoftTabs - column += token.value.length - - outputTokens - else - return [this] if @isAtomic - - if breakOutLeadingSoftTabs - return [this] unless /^[ ]|\t/.test(@value) - else - return [this] unless /\t/.test(@value) - - outputTokens = [] - regex = @whitespaceRegexForTabLength(tabLength) - column = startColumn - while match = regex.exec(@value) - [fullMatch, softTab, hardTab] = match - token = null - if softTab and breakOutLeadingSoftTabs - token = @buildSoftTabToken(tabLength) - else if hardTab - breakOutLeadingSoftTabs = false - token = @buildHardTabToken(tabLength, column) - else - breakOutLeadingSoftTabs = false - value = match[0] - token = new Token({value, @scopes}) - column += token.value.length - outputTokens.push(token) - - outputTokens - - breakOutPairedCharacters: -> - outputTokens = [] - index = 0 - nonPairStart = 0 - - while index < @value.length - if textUtils.isPairedCharacter(@value, index) - if nonPairStart isnt index - outputTokens.push(new Token({value: @value[nonPairStart...index], @scopes})) - outputTokens.push(@buildPairedCharacterToken(@value, index)) - index += 2 - nonPairStart = index - else - index++ - - if nonPairStart isnt index - outputTokens.push(new Token({value: @value[nonPairStart...index], @scopes})) - - outputTokens - - buildPairedCharacterToken: (value, index) -> - new Token( - value: value[index..index + 1] - scopes: @scopes - isAtomic: true - hasPairedCharacter: true - ) - - buildHardTabToken: (tabLength, column) -> - @buildTabToken(tabLength, true, column) - - buildSoftTabToken: (tabLength) -> - @buildTabToken(tabLength, false, 0) - - buildTabToken: (tabLength, isHardTab, column=0) -> - tabStop = tabLength - (column % tabLength) - new Token( - value: _.multiplyString(" ", tabStop) - scopes: @scopes - bufferDelta: if isHardTab then 1 else tabStop - isAtomic: true - isHardTab: isHardTab - ) - - buildSoftWrapIndentationToken: (length) -> - new Token( - value: _.multiplyString(" ", length), - scopes: @scopes, - bufferDelta: 0, - isAtomic: true, - isSoftWrapIndentation: true - ) - isOnlyWhitespace: -> not WhitespaceRegex.test(@value) @@ -166,72 +40,6 @@ class Token scopeClasses = scope.split('.') _.isSubset(targetClasses, scopeClasses) - getValueAsHtml: ({hasIndentGuide}) -> - if @isHardTab - classes = 'hard-tab' - classes += ' leading-whitespace' if @hasLeadingWhitespace() - classes += ' trailing-whitespace' if @hasTrailingWhitespace() - classes += ' indent-guide' if hasIndentGuide - classes += ' invisible-character' if @hasInvisibleCharacters - html = "#{@escapeString(@value)}" - else - startIndex = 0 - endIndex = @value.length - - leadingHtml = '' - trailingHtml = '' - - if @hasLeadingWhitespace() - leadingWhitespace = @value.substring(0, @firstNonWhitespaceIndex) - - classes = 'leading-whitespace' - classes += ' indent-guide' if hasIndentGuide - classes += ' invisible-character' if @hasInvisibleCharacters - - leadingHtml = "#{leadingWhitespace}" - startIndex = @firstNonWhitespaceIndex - - if @hasTrailingWhitespace() - tokenIsOnlyWhitespace = @firstTrailingWhitespaceIndex is 0 - trailingWhitespace = @value.substring(@firstTrailingWhitespaceIndex) - - classes = 'trailing-whitespace' - classes += ' indent-guide' if hasIndentGuide and not @hasLeadingWhitespace() and tokenIsOnlyWhitespace - classes += ' invisible-character' if @hasInvisibleCharacters - - trailingHtml = "#{trailingWhitespace}" - - endIndex = @firstTrailingWhitespaceIndex - - html = leadingHtml - if @value.length > MaxTokenLength - while startIndex < endIndex - html += "" + @escapeString(@value, startIndex, startIndex + MaxTokenLength) + "" - startIndex += MaxTokenLength - else - html += @escapeString(@value, startIndex, endIndex) - - html += trailingHtml - html - - escapeString: (str, startIndex, endIndex) -> - strLength = str.length - - startIndex ?= 0 - endIndex ?= strLength - - str = str.slice(startIndex, endIndex) if startIndex > 0 or endIndex < strLength - str.replace(EscapeRegex, @escapeStringReplace) - - escapeStringReplace: (match) -> - switch match - when '&' then '&' - when '"' then '"' - when "'" then ''' - when '<' then '<' - when '>' then '>' - else match - hasLeadingWhitespace: -> @firstNonWhitespaceIndex? and @firstNonWhitespaceIndex > 0 diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index c10c6693d..99db15c3b 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -488,35 +488,3 @@ class TokenizedLine getTokenCount: -> @tokens.length - - getScopeTree: -> - return @scopeTree if @scopeTree? - - scopeStack = [] - for token in @tokens - @updateScopeStack(scopeStack, token.scopes) - _.last(scopeStack).children.push(token) - - @scopeTree = scopeStack[0] - @updateScopeStack(scopeStack, []) - @scopeTree - - updateScopeStack: (scopeStack, desiredScopeDescriptor) -> - # Find a common prefix - for scope, i in desiredScopeDescriptor - break unless scopeStack[i]?.scope is desiredScopeDescriptor[i] - - # Pop scopeDescriptor until we're at the common prefx - until scopeStack.length is i - poppedScope = scopeStack.pop() - _.last(scopeStack)?.children.push(poppedScope) - - # Push onto common prefix until scopeStack equals desiredScopeDescriptor - for j in [i...desiredScopeDescriptor.length] - scopeStack.push(new Scope(desiredScopeDescriptor[j])) - - return - -class Scope - constructor: (@scope) -> - @children = [] From dc473698a9ef2deedb69664e6a486c5b67030ea6 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 13 May 2015 22:03:29 +0200 Subject: [PATCH 1185/1783] :art: --- src/tokenized-line.coffee | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 99db15c3b..012d68996 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -334,7 +334,7 @@ class TokenizedLine leftSpecialTokens = {} rightSpecialTokens = {} - rightopenScopes = @openScopes.slice() + rightOpenScopes = @openScopes.slice() screenColumn = 0 @@ -378,13 +378,13 @@ class TokenizedLine else if (tag % 2) is -1 if screenColumn < column leftTags.push(tag) - rightopenScopes.push(tag) + rightOpenScopes.push(tag) else rightTags.push(tag) else if screenColumn < column leftTags.push(tag) - rightopenScopes.pop() + rightOpenScopes.pop() else rightTags.push(tag) @@ -406,7 +406,7 @@ class TokenizedLine leftFragment.firstTrailingWhitespaceIndex = Math.min(column, @firstTrailingWhitespaceIndex) rightFragment = new TokenizedLine - rightFragment.openScopes = rightopenScopes + rightFragment.openScopes = rightOpenScopes rightFragment.text = rightText rightFragment.tags = rightTags rightFragment.specialTokens = rightSpecialTokens From a7550666ddf84e8f44c87e2ea948f2a4e9de5e2a Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 13 May 2015 22:50:05 +0200 Subject: [PATCH 1186/1783] Remove dead code --- src/tokenized-line.coffee | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 012d68996..cbc56da99 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -174,16 +174,6 @@ class TokenizedLine new Token(tokenProperties) - buildText: -> - text = "" - text += token.value for token in @tokens - text - - buildBufferDelta: -> - delta = 0 - delta += token.bufferDelta for token in @tokens - delta - copy: -> copy = new TokenizedLine copy.indentLevel = @indentLevel From da2df2297a3944070318f139b1c5a3e4ac2d3fc2 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 14 May 2015 00:11:26 +0200 Subject: [PATCH 1187/1783] Add a TokenIterator and use it for tokens shim --- src/token-iterator.coffee | 85 +++++++++++++++++++++++++++++++++++++++ src/tokenized-line.coffee | 56 +++++++++++++------------- 2 files changed, 113 insertions(+), 28 deletions(-) create mode 100644 src/token-iterator.coffee diff --git a/src/token-iterator.coffee b/src/token-iterator.coffee new file mode 100644 index 000000000..a8b9db59e --- /dev/null +++ b/src/token-iterator.coffee @@ -0,0 +1,85 @@ +{SoftTab, HardTab, PairedCharacter, SoftWrapIndent} = require './special-token-symbols' + +module.exports = +class TokenIterator + @instance: new this + + constructor: (line) -> + @reset(line) if line? + + reset: (@line) -> + @index = null + @bufferStart = 0 + @bufferEnd = 0 + @screenStart = 0 + @screenEnd = 0 + @scopes = @line.openScopes.map (id) -> atom.grammars.scopeForId(id) + @scopeStarts = @scopes.slice() + @scopeEnds = [] + this + + next: -> + {tags} = @line + + if @index? + @index++ + @scopeEnds.length = 0 + @scopeStarts.length = 0 + @bufferStart = @bufferEnd + @screenStart = @screenEnd + else + @index = 0 + + while @index < tags.length + tag = tags[@index] + if tag < 0 + if tag % 2 is 0 + @scopeEnds.push(atom.grammars.scopeForId(tag + 1)) + @scopes.pop() + else + scope = atom.grammars.scopeForId(tag) + @scopeStarts.push(scope) + @scopes.push(scope) + @index++ + else + if @isHardTab() + @screenEnd = @screenStart + tag + @bufferEnd = @bufferStart + 1 + else if @isSoftWrapIndentation() + @screenEnd = @screenStart + tag + @bufferEnd = @bufferStart + 0 + else + @screenEnd = @screenStart + tag + @bufferEnd = @bufferStart + tag + return true + + false + + getBufferStart: -> @bufferStart + getBufferEnd: -> @bufferEnd + + getScreenStart: -> @screenStart + getScreenEnd: -> @screenEnd + + getScopeStarts: -> @scopeStarts + getScopeEnds: -> @scopeEnds + + getScopes: -> @scopes + + getText: -> + @line.text.substring(@screenStart, @screenEnd) + + isSoftTab: -> + @line.specialTokens[@index] is SoftTab + + isHardTab: -> + @line.specialTokens[@index] is HardTab + + isSoftWrapIndentation: -> + @line.specialTokens[@index] is SoftWrapIndent + + isPairedCharacter: -> + @line.specialTokens[@index] is PairedCharacter + + isAtomic: -> + @isSoftTab() or @isHardTab() or @isSoftWrapIndentation() or @isPairedCharacter() diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index cbc56da99..de1c45e96 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -1,6 +1,7 @@ _ = require 'underscore-plus' {isPairedCharacter} = require './text-utils' Token = require './token' +TokenIterator = require './token-iterator' {SoftTab, HardTab, PairedCharacter, SoftWrapIndent} = require './special-token-symbols' NonWhitespaceRegex = /\S/ @@ -28,10 +29,10 @@ class TokenizedLine @startBufferColumn ?= 0 @bufferDelta = @text.length - @subdivideTokens() + @transformContent() @buildEndOfLineInvisibles() if @invisibles? and @lineEnding? - subdivideTokens: -> + transformContent: -> text = '' bufferColumn = 0 screenColumn = 0 @@ -142,37 +143,36 @@ class TokenizedLine @firstTrailingWhitespaceIndex = 0 Object.defineProperty @prototype, 'tokens', get: -> - offset = 0 + iterator = TokenIterator.instance.reset(this) + tokens = [] - atom.grammars.decodeTokens @text, @tags, @openScopes.slice(), (tokenProperties, index) => - switch @specialTokens[index] - when SoftTab - tokenProperties.isAtomic = true - when HardTab - tokenProperties.isAtomic = true - tokenProperties.isHardTab = true - tokenProperties.bufferDelta = 1 - tokenProperties.hasInvisibleCharacters = true if @invisibles?.tab - when PairedCharacter - tokenProperties.isAtomic = true - tokenProperties.hasPairedCharacter = true - when SoftWrapIndent - tokenProperties.isAtomic = true - tokenProperties.isSoftWrapIndentation = true + while iterator.next() + properties = { + value: iterator.getText() + scopes: iterator.getScopes().slice() + isAtomic: iterator.isAtomic() + isHardTab: iterator.isHardTab() + hasPairedCharacter: iterator.isPairedCharacter() + isSoftWrapIndentation: iterator.isSoftWrapIndentation() + } - if offset < @firstNonWhitespaceIndex - tokenProperties.firstNonWhitespaceIndex = - Math.min(tokenProperties.value.length, @firstNonWhitespaceIndex - offset) - tokenProperties.hasInvisibleCharacters = true if @invisibles?.space + if iterator.isHardTab() + properties.bufferDelta = 1 + properties.hasInvisibleCharacters = true if @invisibles?.tab - if @lineEnding? and (offset + tokenProperties.value.length > @firstTrailingWhitespaceIndex) - tokenProperties.firstTrailingWhitespaceIndex = - Math.max(0, @firstTrailingWhitespaceIndex - offset) - tokenProperties.hasInvisibleCharacters = true if @invisibles?.space + if iterator.getScreenStart() < @firstNonWhitespaceIndex + properties.firstNonWhitespaceIndex = + Math.min(@firstNonWhitespaceIndex, iterator.getScreenEnd()) - iterator.getScreenStart() + properties.hasInvisibleCharacters = true if @invisibles?.space - offset += tokenProperties.value.length + if @lineEnding? and iterator.getScreenEnd() > @firstTrailingWhitespaceIndex + properties.firstTrailingWhitespaceIndex = + Math.max(0, @firstTrailingWhitespaceIndex - iterator.getScreenStart()) + properties.hasInvisibleCharacters = true if @invisibles?.space - new Token(tokenProperties) + tokens.push(new Token(properties)) + + tokens copy: -> copy = new TokenizedLine From bcd20a7cd27f8efb795485efa641c6c84808fd94 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Wed, 13 May 2015 15:06:23 -0700 Subject: [PATCH 1188/1783] Do not create an AutoUpdateManager when in test mode. --- src/browser/atom-application.coffee | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index af6a45763..3e1f19f17 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -1,7 +1,6 @@ AtomWindow = require './atom-window' ApplicationMenu = require './application-menu' AtomProtocolHandler = require './atom-protocol-handler' -AutoUpdateManager = require './auto-update-manager' BrowserWindow = require 'browser-window' StorageFolder = require '../storage-folder' Menu = require 'menu' @@ -71,7 +70,9 @@ class AtomApplication @pathsToOpen ?= [] @windows = [] - @autoUpdateManager = new AutoUpdateManager(@version) + unless options.test + AutoUpdateManager = require './auto-update-manager' + @autoUpdateManager = new AutoUpdateManager(@version) @applicationMenu = new ApplicationMenu(@version) @atomProtocolHandler = new AtomProtocolHandler(@resourcePath, @safeMode) @@ -110,8 +111,9 @@ class AtomApplication addWindow: (window) -> @windows.push window @applicationMenu?.addWindow(window.browserWindow) - window.once 'window:loaded', => - @autoUpdateManager.emitUpdateAvailableEvent(window) + if @autoUpdateManager + window.once 'window:loaded', => + @autoUpdateManager.emitUpdateAvailableEvent(window) unless window.isSpec focusHandler = => @lastFocusedWindow = window @@ -185,8 +187,8 @@ class AtomApplication @on 'application:report-issue', -> require('shell').openExternal('https://github.com/atom/atom/blob/master/CONTRIBUTING.md#submitting-issues') @on 'application:search-issues', -> require('shell').openExternal('https://github.com/issues?q=+is%3Aissue+user%3Aatom') - @on 'application:install-update', -> @autoUpdateManager.install() - @on 'application:check-for-update', => @autoUpdateManager.check() + @on 'application:install-update', -> @autoUpdateManager?.install() + @on 'application:check-for-update', => @autoUpdateManager?.check() if process.platform is 'darwin' @on 'application:about', -> Menu.sendActionToFirstResponder('orderFrontStandardAboutPanel:') From 356fa4ac24888221063d39657f938c867ea6f2f2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 13 May 2015 15:21:20 -0700 Subject: [PATCH 1189/1783] :art: --- src/browser/atom-application.coffee | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 3e1f19f17..0080e3639 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -73,6 +73,7 @@ class AtomApplication unless options.test AutoUpdateManager = require './auto-update-manager' @autoUpdateManager = new AutoUpdateManager(@version) + @applicationMenu = new ApplicationMenu(@version) @atomProtocolHandler = new AtomProtocolHandler(@resourcePath, @safeMode) @@ -111,7 +112,8 @@ class AtomApplication addWindow: (window) -> @windows.push window @applicationMenu?.addWindow(window.browserWindow) - if @autoUpdateManager + + if @autoUpdateManager? window.once 'window:loaded', => @autoUpdateManager.emitUpdateAvailableEvent(window) @@ -187,8 +189,9 @@ class AtomApplication @on 'application:report-issue', -> require('shell').openExternal('https://github.com/atom/atom/blob/master/CONTRIBUTING.md#submitting-issues') @on 'application:search-issues', -> require('shell').openExternal('https://github.com/issues?q=+is%3Aissue+user%3Aatom') - @on 'application:install-update', -> @autoUpdateManager?.install() - @on 'application:check-for-update', => @autoUpdateManager?.check() + if @autoUpdateManager? + @on 'application:install-update', => @autoUpdateManager.install() + @on 'application:check-for-update', => @autoUpdateManager.check() if process.platform is 'darwin' @on 'application:about', -> Menu.sendActionToFirstResponder('orderFrontStandardAboutPanel:') From 720deff1cdb30c426a73ebaca0ab5e28d48e8155 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 13 May 2015 15:26:23 -0700 Subject: [PATCH 1190/1783] :arrow_up: grim@1.4.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3614b5f26..855256bfb 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "fstream": "0.1.24", "fuzzaldrin": "^2.1", "git-utils": "^3.0.0", - "grim": "1.4.0", + "grim": "1.4.1", "hosted-git-info": "^2.1.2", "jasmine-json": "~0.0", "jasmine-tagged": "^1.1.4", From c8d6d883f3356d1fdb1d78c672054e6693337265 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 13 May 2015 15:30:00 -0700 Subject: [PATCH 1191/1783] :arrow_up: deprecation-cop@0.47 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 855256bfb..19b6a19e8 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,7 @@ "bookmarks": "0.35.0", "bracket-matcher": "0.74.0", "command-palette": "0.35.0", - "deprecation-cop": "0.46.0", + "deprecation-cop": "0.47.0", "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", From 0eb97e6a962d82eeb156637b8c70c87e2b287d8a Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 14 May 2015 00:33:27 +0200 Subject: [PATCH 1192/1783] Use TokenIterator for position translation --- src/token-iterator.coffee | 4 +-- src/tokenized-line.coffee | 72 ++++++++++++--------------------------- 2 files changed, 24 insertions(+), 52 deletions(-) diff --git a/src/token-iterator.coffee b/src/token-iterator.coffee index a8b9db59e..800f76d03 100644 --- a/src/token-iterator.coffee +++ b/src/token-iterator.coffee @@ -9,8 +9,8 @@ class TokenIterator reset: (@line) -> @index = null - @bufferStart = 0 - @bufferEnd = 0 + @bufferStart = @line.startBufferColumn + @bufferEnd = @bufferStart @screenStart = 0 @screenEnd = 0 @scopes = @line.openScopes.map (id) -> atom.grammars.scopeForId(id) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index de1c45e96..2183ac349 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -227,58 +227,30 @@ class TokenizedLine column screenColumnForBufferColumn: (targetBufferColumn, options) -> - bufferColumn = @startBufferColumn - screenColumn = 0 - for tag, index in @tags - if tag > 0 - switch @specialTokens[index] - when HardTab - bufferDelta = 1 - screenDelta = tag - when SoftWrapIndent - bufferDelta = 0 - screenDelta = tag - else - bufferDelta = screenDelta = tag - - nextBufferColumn = bufferColumn + bufferDelta - if nextBufferColumn > targetBufferColumn - overshoot = targetBufferColumn - bufferColumn - bufferColumn += overshoot - screenColumn += Math.min(screenDelta, overshoot) - break - else - bufferColumn = nextBufferColumn - screenColumn += screenDelta - - screenColumn + iterator = TokenIterator.instance.reset(this) + while iterator.next() + tokenBufferStart = iterator.getBufferStart() + tokenBufferEnd = iterator.getBufferEnd() + if tokenBufferStart <= targetBufferColumn < tokenBufferEnd + overshoot = targetBufferColumn - tokenBufferStart + return Math.min( + iterator.getScreenStart() + overshoot, + iterator.getScreenEnd() + ) + iterator.getScreenEnd() bufferColumnForScreenColumn: (targetScreenColumn) -> - bufferColumn = @startBufferColumn - screenColumn = 0 - for tag, index in @tags - if tag > 0 - switch @specialTokens[index] - when HardTab - bufferDelta = 1 - screenDelta = tag - when SoftWrapIndent - bufferDelta = 0 - screenDelta = tag - else - bufferDelta = screenDelta = tag - - nextScreenColumn = screenColumn + screenDelta - if nextScreenColumn > targetScreenColumn - overshoot = targetScreenColumn - screenColumn - screenColumn += overshoot - bufferColumn += Math.min(bufferDelta, overshoot) - break - else - screenColumn = nextScreenColumn - bufferColumn += bufferDelta - - bufferColumn + iterator = TokenIterator.instance.reset(this) + while iterator.next() + tokenScreenStart = iterator.getScreenStart() + tokenScreenEnd = iterator.getScreenEnd() + if tokenScreenStart <= targetScreenColumn < tokenScreenEnd + overshoot = targetScreenColumn - tokenScreenStart + return Math.min( + iterator.getBufferStart() + overshoot, + iterator.getBufferEnd() + ) + iterator.getBufferEnd() getMaxScreenColumn: -> if @fold From 2195b1a38d7e28b291199b21e0f3a6595b8ca59c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 13 May 2015 15:33:56 -0700 Subject: [PATCH 1193/1783] Pass auto update manager into application menu --- src/browser/application-menu.coffee | 7 +++---- src/browser/atom-application.coffee | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/browser/application-menu.coffee b/src/browser/application-menu.coffee index a845c682f..7fc548892 100644 --- a/src/browser/application-menu.coffee +++ b/src/browser/application-menu.coffee @@ -9,11 +9,10 @@ _ = require 'underscore-plus' # and maintain the state of all menu items. module.exports = class ApplicationMenu - constructor: (@version) -> + constructor: (@version, @autoUpdateManager) -> @windowTemplates = new WeakMap() @setActiveTemplate(@getDefaultTemplate()) - global.atomApplication.autoUpdateManager.on 'state-changed', (state) => - @showUpdateMenuItem(state) + @autoUpdateManager?.on 'state-changed', (state) => @showUpdateMenuItem(state) # Public: Updates the entire menu with the given keybindings. # @@ -33,7 +32,7 @@ class ApplicationMenu @menu = Menu.buildFromTemplate(_.deepClone(template)) Menu.setApplicationMenu(@menu) - @showUpdateMenuItem(global.atomApplication.autoUpdateManager.getState()) + @showUpdateMenuItem(@autoUpdateManager.getState()) if @autoUpdateManager? # Register a BrowserWindow with this application menu. addWindow: (window) -> diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 0080e3639..0dc269080 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -74,7 +74,7 @@ class AtomApplication AutoUpdateManager = require './auto-update-manager' @autoUpdateManager = new AutoUpdateManager(@version) - @applicationMenu = new ApplicationMenu(@version) + @applicationMenu = new ApplicationMenu(@version, @autoUpdateManager) @atomProtocolHandler = new AtomProtocolHandler(@resourcePath, @safeMode) @listenForArgumentsFromNewProcess() From d319d17dcdf6ce86dbd29adda226f240a9142a16 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 13 May 2015 15:35:27 -0700 Subject: [PATCH 1194/1783] Always call showUpdateMenuItem --- src/browser/application-menu.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/browser/application-menu.coffee b/src/browser/application-menu.coffee index 7fc548892..e3885de00 100644 --- a/src/browser/application-menu.coffee +++ b/src/browser/application-menu.coffee @@ -32,7 +32,7 @@ class ApplicationMenu @menu = Menu.buildFromTemplate(_.deepClone(template)) Menu.setApplicationMenu(@menu) - @showUpdateMenuItem(@autoUpdateManager.getState()) if @autoUpdateManager? + @showUpdateMenuItem(@autoUpdateManager?.getState()) # Register a BrowserWindow with this application menu. addWindow: (window) -> From 121e42debac36088b5a1055d26172523377af700 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 14 May 2015 00:55:06 +0200 Subject: [PATCH 1195/1783] Use TokenIterator to build line HTML --- src/lines-component.coffee | 71 ++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 38 deletions(-) diff --git a/src/lines-component.coffee b/src/lines-component.coffee index 9904d5702..80b32b88b 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -4,7 +4,7 @@ _ = require 'underscore-plus' CursorsComponent = require './cursors-component' HighlightsComponent = require './highlights-component' -{HardTab} = require './special-token-symbols' +TokenIterator = require './token-iterator' DummyLineNode = $$(-> @div className: 'line', style: 'position: absolute; visibility: hidden;', => @span 'x')[0] AcceptFilter = {acceptNode: -> NodeFilter.FILTER_ACCEPT} @@ -171,55 +171,50 @@ class LinesComponent buildLineInnerHTML: (id) -> lineState = @newState.lines[id] - {text, openScopes, tags, specialTokens, invisibles} = lineState - {firstNonWhitespaceIndex, firstTrailingWhitespaceIndex} = lineState + {firstNonWhitespaceIndex, firstTrailingWhitespaceIndex, invisibles} = lineState lineIsWhitespaceOnly = firstTrailingWhitespaceIndex is 0 innerHTML = "" + iterator = TokenIterator.instance.reset(lineState) - tokenStart = 0 - scopeDepth = openScopes.length + debugger if global.debug + while iterator.next() + for scope in iterator.getScopeEnds() + innerHTML += "" - for tag in openScopes - scope = atom.grammars.scopeForId(tag) - innerHTML += "" + for scope in iterator.getScopeStarts() + innerHTML += "" - for tag, index in tags - # tag represents start or end of a scope - if tag < 0 - if (tag % 2) is -1 - scopeDepth++ - scope = atom.grammars.scopeForId(tag) - innerHTML += "" - else - scopeDepth-- - innerHTML += "" + tokenStart = iterator.getScreenStart() + tokenEnd = iterator.getScreenEnd() + tokenText = iterator.getText() + isHardTab = iterator.isHardTab() - # tag represents a token + if hasLeadingWhitespace = tokenStart < firstNonWhitespaceIndex + tokenFirstNonWhitespaceIndex = firstNonWhitespaceIndex - tokenStart else - tokenEnd = tokenStart + tag - tokenText = text.substring(tokenStart, tokenEnd) - isHardTab = specialTokens[index] is HardTab - if hasLeadingWhitespace = tokenStart < firstNonWhitespaceIndex - tokenFirstNonWhitespaceIndex = firstNonWhitespaceIndex - tokenStart - else - tokenFirstNonWhitespaceIndex = null - if hasTrailingWhitespace = tokenEnd > firstTrailingWhitespaceIndex - tokenFirstTrailingWhitespaceIndex = Math.max(0, firstTrailingWhitespaceIndex - tokenStart) - else - tokenFirstTrailingWhitespaceIndex = null - hasIndentGuide = @newState.indentGuidesVisible and (hasLeadingWhitespace or lineIsWhitespaceOnly) - hasInvisibleCharacters = - (invisibles?.tab and isHardTab) or - (invisibles?.space and (hasLeadingWhitespace or hasTrailingWhitespace)) + tokenFirstNonWhitespaceIndex = null - innerHTML += @buildTokenHTML(tokenText, isHardTab, tokenFirstNonWhitespaceIndex, tokenFirstTrailingWhitespaceIndex, hasIndentGuide, hasInvisibleCharacters) + if hasTrailingWhitespace = tokenEnd > firstTrailingWhitespaceIndex + tokenFirstTrailingWhitespaceIndex = Math.max(0, firstTrailingWhitespaceIndex - tokenStart) + else + tokenFirstTrailingWhitespaceIndex = null - tokenStart = tokenEnd + hasIndentGuide = + @newState.indentGuidesVisible and + (hasLeadingWhitespace or lineIsWhitespaceOnly) - while scopeDepth > 0 + hasInvisibleCharacters = + (invisibles?.tab and isHardTab) or + (invisibles?.space and (hasLeadingWhitespace or hasTrailingWhitespace)) + + innerHTML += @buildTokenHTML(tokenText, isHardTab, tokenFirstNonWhitespaceIndex, tokenFirstTrailingWhitespaceIndex, hasIndentGuide, hasInvisibleCharacters) + + for scope in iterator.getScopeEnds() + innerHTML += "" + + for scope in iterator.getScopes() innerHTML += "" - scopeDepth-- innerHTML += @buildEndOfLineHTML(id) innerHTML From cb223fa03e9015fbfb5bb8a46a535d12d4690d7c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 13 May 2015 15:55:17 -0700 Subject: [PATCH 1196/1783] Don't check for updates in test mode --- src/browser/application-menu.coffee | 4 ++-- src/browser/atom-application.coffee | 16 ++++++---------- src/browser/auto-update-manager.coffee | 4 ++-- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/browser/application-menu.coffee b/src/browser/application-menu.coffee index e3885de00..74da80e43 100644 --- a/src/browser/application-menu.coffee +++ b/src/browser/application-menu.coffee @@ -12,7 +12,7 @@ class ApplicationMenu constructor: (@version, @autoUpdateManager) -> @windowTemplates = new WeakMap() @setActiveTemplate(@getDefaultTemplate()) - @autoUpdateManager?.on 'state-changed', (state) => @showUpdateMenuItem(state) + @autoUpdateManager.on 'state-changed', (state) => @showUpdateMenuItem(state) # Public: Updates the entire menu with the given keybindings. # @@ -32,7 +32,7 @@ class ApplicationMenu @menu = Menu.buildFromTemplate(_.deepClone(template)) Menu.setApplicationMenu(@menu) - @showUpdateMenuItem(@autoUpdateManager?.getState()) + @showUpdateMenuItem(@autoUpdateManager.getState()) # Register a BrowserWindow with this application menu. addWindow: (window) -> diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 0dc269080..09738b452 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -1,6 +1,7 @@ AtomWindow = require './atom-window' ApplicationMenu = require './application-menu' AtomProtocolHandler = require './atom-protocol-handler' +AutoUpdateManager = require './auto-update-manager' BrowserWindow = require 'browser-window' StorageFolder = require '../storage-folder' Menu = require 'menu' @@ -70,10 +71,7 @@ class AtomApplication @pathsToOpen ?= [] @windows = [] - unless options.test - AutoUpdateManager = require './auto-update-manager' - @autoUpdateManager = new AutoUpdateManager(@version) - + @autoUpdateManager = new AutoUpdateManager(@version, options.test) @applicationMenu = new ApplicationMenu(@version, @autoUpdateManager) @atomProtocolHandler = new AtomProtocolHandler(@resourcePath, @safeMode) @@ -113,9 +111,8 @@ class AtomApplication @windows.push window @applicationMenu?.addWindow(window.browserWindow) - if @autoUpdateManager? - window.once 'window:loaded', => - @autoUpdateManager.emitUpdateAvailableEvent(window) + window.once 'window:loaded', => + @autoUpdateManager.emitUpdateAvailableEvent(window) unless window.isSpec focusHandler = => @lastFocusedWindow = window @@ -189,9 +186,8 @@ class AtomApplication @on 'application:report-issue', -> require('shell').openExternal('https://github.com/atom/atom/blob/master/CONTRIBUTING.md#submitting-issues') @on 'application:search-issues', -> require('shell').openExternal('https://github.com/issues?q=+is%3Aissue+user%3Aatom') - if @autoUpdateManager? - @on 'application:install-update', => @autoUpdateManager.install() - @on 'application:check-for-update', => @autoUpdateManager.check() + @on 'application:install-update', => @autoUpdateManager.install() + @on 'application:check-for-update', => @autoUpdateManager.check() if process.platform is 'darwin' @on 'application:about', -> Menu.sendActionToFirstResponder('orderFrontStandardAboutPanel:') diff --git a/src/browser/auto-update-manager.coffee b/src/browser/auto-update-manager.coffee index 358390889..7c8613be5 100644 --- a/src/browser/auto-update-manager.coffee +++ b/src/browser/auto-update-manager.coffee @@ -15,7 +15,7 @@ module.exports = class AutoUpdateManager _.extend @prototype, EventEmitter.prototype - constructor: (@version) -> + constructor: (@version, @testMode) -> @state = IdleState if process.platform is 'win32' # Squirrel for Windows can't handle query params @@ -80,7 +80,7 @@ class AutoUpdateManager autoUpdater.once 'update-not-available', @onUpdateNotAvailable autoUpdater.once 'error', @onUpdateError - autoUpdater.checkForUpdates() + autoUpdater.checkForUpdates() unless @testMode install: -> autoUpdater.quitAndInstall() From 2bbdd9446db83c21fc3198f8e5749fa547aa193e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 13 May 2015 15:55:56 -0700 Subject: [PATCH 1197/1783] :art: --- src/browser/atom-application.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 09738b452..afc811144 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -110,7 +110,6 @@ class AtomApplication addWindow: (window) -> @windows.push window @applicationMenu?.addWindow(window.browserWindow) - window.once 'window:loaded', => @autoUpdateManager.emitUpdateAvailableEvent(window) From 6c81f7233b33505d1377b6e84a9318e2e2408d2d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 13 May 2015 15:58:14 -0700 Subject: [PATCH 1198/1783] Don't quit and install in test mode --- src/browser/auto-update-manager.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/browser/auto-update-manager.coffee b/src/browser/auto-update-manager.coffee index 7c8613be5..654a8de67 100644 --- a/src/browser/auto-update-manager.coffee +++ b/src/browser/auto-update-manager.coffee @@ -83,7 +83,7 @@ class AutoUpdateManager autoUpdater.checkForUpdates() unless @testMode install: -> - autoUpdater.quitAndInstall() + autoUpdater.quitAndInstall() unless @testMode onUpdateNotAvailable: => autoUpdater.removeListener 'error', @onUpdateError From c76b45206bd781f8ea0350af5e00a5000b872c5a Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 14 May 2015 01:03:34 +0200 Subject: [PATCH 1199/1783] Use TokenIterator to compute horizontal pixel positions Instead of the TokenizedLine::tokens shim --- src/text-editor-presenter.coffee | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index d5e8fc09c..9be8e9bc0 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -2,6 +2,7 @@ {Point, Range} = require 'text-buffer' _ = require 'underscore-plus' Decoration = require './decoration' +TokenIterator = require './token-iterator' module.exports = class TextEditorPresenter @@ -980,17 +981,20 @@ class TextEditorPresenter top = targetRow * @lineHeight left = 0 column = 0 - for token in @model.tokenizedLineForScreenRow(targetRow).tokens - characterWidths = @getScopedCharacterWidths(token.scopes) + + iterator = TokenIterator.instance.reset(@model.tokenizedLineForScreenRow(targetRow)) + while iterator.next() + characterWidths = @getScopedCharacterWidths(iterator.getScopes()) valueIndex = 0 - while valueIndex < token.value.length - if token.hasPairedCharacter - char = token.value.substr(valueIndex, 2) + text = iterator.getText() + while valueIndex < text.length + if iterator.isPairedCharacter() + char = text charLength = 2 valueIndex += 2 else - char = token.value[valueIndex] + char = text[valueIndex] charLength = 1 valueIndex++ From 0ca967d6b018d84ef23d104d2d5c815d3fa2d529 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 14 May 2015 01:10:29 +0200 Subject: [PATCH 1200/1783] Switch character measurement to TokenIterator Instead of using TokenizedLine::tokens shim --- src/lines-component.coffee | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/lines-component.coffee b/src/lines-component.coffee index 80b32b88b..8fa7c215f 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -354,19 +354,22 @@ class LinesComponent iterator = null charIndex = 0 - for {value, scopes, hasPairedCharacter} in tokenizedLine.tokens + tokenIterator = TokenIterator.instance.reset(tokenizedLine) + while tokenIterator.next() + scopes = tokenIterator.getScopes() + text = tokenIterator.getText() charWidths = @presenter.getScopedCharacterWidths(scopes) - valueIndex = 0 - while valueIndex < value.length - if hasPairedCharacter - char = value.substr(valueIndex, 2) + textIndex = 0 + while textIndex < text.length + if tokenIterator.isPairedCharacter() + char = text charLength = 2 - valueIndex += 2 + textIndex += 2 else - char = value[valueIndex] + char = text[textIndex] charLength = 1 - valueIndex++ + textIndex++ continue if char is '\0' From 37d9a00b375ec99ddc4fbc056a54f2ef92f0eaab Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 14 May 2015 01:15:44 +0200 Subject: [PATCH 1201/1783] Use TokenIterator in DisplayBuffer instead of tokens shim --- src/display-buffer.coffee | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index f4c078b17..e44822cc1 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -2,14 +2,15 @@ _ = require 'underscore-plus' Serializable = require 'serializable' {CompositeDisposable, Emitter} = require 'event-kit' {Point, Range} = require 'text-buffer' +Grim = require 'grim' TokenizedBuffer = require './tokenized-buffer' +TokenIterator = require './token-iterator' RowMap = require './row-map' Fold = require './fold' Model = require './model' Token = require './token' Decoration = require './decoration' Marker = require './marker' -Grim = require 'grim' class BufferToScreenConversionError extends Error constructor: (@message, @metadata) -> @@ -651,16 +652,19 @@ class DisplayBuffer extends Model top = targetRow * @lineHeightInPixels left = 0 column = 0 - for token in @tokenizedLineForScreenRow(targetRow).tokens - charWidths = @getScopedCharWidths(token.scopes) + + iterator = TokenIterator.instance.reset(@tokenizedLineForScreenRow(targetRow)) + while iterator.next() + charWidths = @getScopedCharWidths(iterator.getScopes()) valueIndex = 0 - while valueIndex < token.value.length - if token.hasPairedCharacter - char = token.value.substr(valueIndex, 2) + value = iterator.getText() + while valueIndex < value.length + if iterator.isPairedCharacter() + char = value charLength = 2 valueIndex += 2 else - char = token.value[valueIndex] + char = value[valueIndex] charLength = 1 valueIndex++ @@ -681,16 +685,19 @@ class DisplayBuffer extends Model left = 0 column = 0 - for token in @tokenizedLineForScreenRow(row).tokens - charWidths = @getScopedCharWidths(token.scopes) + + iterator = TokenIterator.instance.reset(@tokenizedLineForScreenRow(row)) + while iterator.next() + charWidths = @getScopedCharWidths(iterator.getScopes()) + value = iterator.getText() valueIndex = 0 - while valueIndex < token.value.length - if token.hasPairedCharacter - char = token.value.substr(valueIndex, 2) + while valueIndex < value.length + if iterator.isPairedCharacter() + char = value charLength = 2 valueIndex += 2 else - char = token.value[valueIndex] + char = value[valueIndex] charLength = 1 valueIndex++ From ddc603e4b8bf6c1d7aa3c11b8cd6682d9d73d176 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 13 May 2015 16:31:19 -0700 Subject: [PATCH 1202/1783] :arrow_up: autocomplete-html@0.7.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 19b6a19e8..5cfd5b6d0 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "autocomplete-atom-api": "0.9.0", "autocomplete-css": "0.7.2", "autocomplete-emojis": "2.2.2", - "autocomplete-html": "0.7.1", + "autocomplete-html": "0.7.2", "autocomplete-plus": "2.15.1", "autocomplete-snippets": "1.6.1", "autoflow": "0.23.0", From 173bc82e42460fb3855762ef774a5ff991c40988 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 14 May 2015 01:46:32 +0200 Subject: [PATCH 1203/1783] =?UTF-8?q?Don=E2=80=99t=20include=20tokens=20in?= =?UTF-8?q?=20presenter=20state=20for=20lines?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spec/text-editor-presenter-spec.coffee | 36 ++++++++++++++++++++------ src/text-editor-presenter.coffee | 1 - 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index de2dd780d..40dae08cc 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -670,7 +670,11 @@ describe "TextEditorPresenter", -> expectValues lineStateForScreenRow(presenter, 4), { screenRow: 4 text: line4.text - tokens: line4.tokens + tags: line4.tags + specialTokens: line4.specialTokens + firstNonWhitespaceIndex: line4.firstNonWhitespaceIndex + firstTrailingWhitespaceIndex: line4.firstTrailingWhitespaceIndex + invisibles: line4.invisibles top: 10 * 4 } @@ -678,7 +682,11 @@ describe "TextEditorPresenter", -> expectValues lineStateForScreenRow(presenter, 5), { screenRow: 5 text: line5.text - tokens: line5.tokens + tags: line5.tags + specialTokens: line5.specialTokens + firstNonWhitespaceIndex: line5.firstNonWhitespaceIndex + firstTrailingWhitespaceIndex: line5.firstTrailingWhitespaceIndex + invisibles: line5.invisibles top: 10 * 5 } @@ -686,7 +694,11 @@ describe "TextEditorPresenter", -> expectValues lineStateForScreenRow(presenter, 6), { screenRow: 6 text: line6.text - tokens: line6.tokens + tags: line6.tags + specialTokens: line6.specialTokens + firstNonWhitespaceIndex: line6.firstNonWhitespaceIndex + firstTrailingWhitespaceIndex: line6.firstTrailingWhitespaceIndex + invisibles: line6.invisibles top: 10 * 6 } @@ -694,7 +706,11 @@ describe "TextEditorPresenter", -> expectValues lineStateForScreenRow(presenter, 7), { screenRow: 7 text: line7.text - tokens: line7.tokens + tags: line7.tags + specialTokens: line7.specialTokens + firstNonWhitespaceIndex: line7.firstNonWhitespaceIndex + firstTrailingWhitespaceIndex: line7.firstTrailingWhitespaceIndex + invisibles: line7.invisibles top: 10 * 7 } @@ -702,7 +718,11 @@ describe "TextEditorPresenter", -> expectValues lineStateForScreenRow(presenter, 8), { screenRow: 8 text: line8.text - tokens: line8.tokens + tags: line8.tags + specialTokens: line8.specialTokens + firstNonWhitespaceIndex: line8.firstNonWhitespaceIndex + firstTrailingWhitespaceIndex: line8.firstTrailingWhitespaceIndex + invisibles: line8.invisibles top: 10 * 8 } @@ -797,19 +817,19 @@ describe "TextEditorPresenter", -> line1 = editor.tokenizedLineForScreenRow(1) expectValues lineStateForScreenRow(presenter, 1), { text: line1.text - tokens: line1.tokens + tags: line1.tags } line2 = editor.tokenizedLineForScreenRow(2) expectValues lineStateForScreenRow(presenter, 2), { text: line2.text - tokens: line2.tokens + tags: line2.tags } line3 = editor.tokenizedLineForScreenRow(3) expectValues lineStateForScreenRow(presenter, 3), { text: line3.text - tokens: line3.tokens + tags: line3.tags } it "does not remove out-of-view lines corresponding to ::mouseWheelScreenRow until ::stoppedScrollingDelay elapses", -> diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 9be8e9bc0..7fb742bae 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -342,7 +342,6 @@ class TextEditorPresenter firstTrailingWhitespaceIndex: line.firstTrailingWhitespaceIndex invisibles: line.invisibles endOfLineInvisibles: line.endOfLineInvisibles - tokens: line.tokens isOnlyWhitespace: line.isOnlyWhitespace() indentLevel: line.indentLevel tabLength: line.tabLength From 64c0ef8bd8dd4a69197a1fb76cfab6f604c92410 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 14 May 2015 01:46:49 +0200 Subject: [PATCH 1204/1783] Remove more usages of tokens shim --- src/tokenized-buffer.coffee | 7 +++++- src/tokenized-line.coffee | 43 +++++++++++++++++++++---------------- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index b33fdd8fc..4ce0f44d3 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -5,6 +5,7 @@ _ = require 'underscore-plus' Serializable = require 'serializable' Model = require './model' TokenizedLine = require './tokenized-line' +TokenIterator = require './token-iterator' Token = require './token' ScopeDescriptor = require './scope-descriptor' Grim = require 'grim' @@ -379,7 +380,11 @@ class TokenizedBuffer extends Model 0 scopeDescriptorForPosition: (position) -> - new ScopeDescriptor(scopes: @tokenForPosition(position).scopes) + {row, column} = Point.fromObject(position) + iterator = TokenIterator.instance.reset(@tokenizedLines[row]) + while iterator.next() + break if iterator.getScreenEnd() > column + new ScopeDescriptor(scopes: iterator.getScopes().slice()) tokenForPosition: (position) -> {row, column} = Point.fromObject(position) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 2183ac349..3c6851eef 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -8,6 +8,7 @@ NonWhitespaceRegex = /\S/ LeadingWhitespaceRegex = /^\s*/ TrailingWhitespaceRegex = /\s*$/ RepeatedSpaceRegex = /[ ]/g +CommentScopeRegex = /(\b|\.)comment/ idCounter = 1 module.exports = @@ -201,28 +202,30 @@ class TokenizedLine # # Returns a {Number} representing the clipped column. clipScreenColumn: (column, options={}) -> - return 0 if @tokens.length is 0 + return 0 if @tags.length is 0 {clip} = options column = Math.min(column, @getMaxScreenColumn()) tokenStartColumn = 0 - for token in @tokens - break if tokenStartColumn + token.screenDelta > column - tokenStartColumn += token.screenDelta - if @isColumnInsideSoftWrapIndentation(tokenStartColumn) - @getSoftWrapIndentationDelta() - else if token.isAtomic and tokenStartColumn < column + iterator = TokenIterator.instance.reset(this) + while iterator.next() + break if iterator.getScreenEnd() > column + + if iterator.isSoftWrapIndentation() + iterator.next() while iterator.isSoftWrapIndentation() + iterator.getScreenStart() + else if iterator.isAtomic() and iterator.getScreenStart() < column if clip is 'forward' - tokenStartColumn + token.screenDelta + iterator.getScreenEnd() else if clip is 'backward' - tokenStartColumn + iterator.getScreenStart() else #'closest' - if column > tokenStartColumn + (token.screenDelta / 2) - tokenStartColumn + token.screenDelta + if column > ((iterator.getScreenStart() + iterator.getScreenEnd()) / 2) + iterator.getScreenEnd() else - tokenStartColumn + iterator.getScreenStart() else column @@ -434,11 +437,13 @@ class TokenizedLine @endOfLineInvisibles.push(eol) if eol isComment: -> - for token in @tokens - continue if token.scopes.length is 1 - continue if token.isOnlyWhitespace() - for scope in token.scopes - return true if _.contains(scope.split('.'), 'comment') + iterator = TokenIterator.instance.reset(this) + while iterator.next() + scopes = iterator.getScopes() + continue if scopes.length is 1 + continue unless NonWhitespaceRegex.test(iterator.getText()) + for scope in scopes + return true if CommentScopeRegex.test(scope) break false @@ -449,4 +454,6 @@ class TokenizedLine @tokens[index] getTokenCount: -> - @tokens.length + count = 0 + count++ for tag in @tags when tag >= 0 + count From fdb696f4dc2305b98d002caee745108db25ac410 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Wed, 13 May 2015 14:21:27 -0700 Subject: [PATCH 1205/1783] [Gutter] Fix line-number gutter tests in TextEditorPresenter specs --- spec/text-editor-presenter-spec.coffee | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index de2dd780d..5f82a64bc 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -1772,15 +1772,22 @@ describe "TextEditorPresenter", -> pixelPosition: {top: 10, left: 0} } - describe ".lineNumberGutter", -> + # TODO jssln Move this under '.gutters' + describe "when the gutter is the line-number gutter", -> + getLineNumberGutterState = (presenter) -> + gutterDescriptions = presenter.getState().gutters + for description in gutterDescriptions + gutter = description.gutter + return description if gutter.name is 'line-number' + describe ".maxLineNumberDigits", -> it "is set to the number of digits used by the greatest line number", -> presenter = buildPresenter() expect(editor.getLastBufferRow()).toBe 12 - expect(presenter.getState().gutters.lineNumberGutter.maxLineNumberDigits).toBe 2 + expect(getLineNumberGutterState(presenter).content.maxLineNumberDigits).toBe 2 editor.setText("1\n2\n3") - expect(presenter.getState().gutters.lineNumberGutter.maxLineNumberDigits).toBe 1 + expect(getLineNumberGutterState(presenter).content.maxLineNumberDigits).toBe 1 describe ".lineNumbers", -> lineNumberStateForScreenRow = (presenter, screenRow) -> @@ -1792,7 +1799,7 @@ describe "TextEditorPresenter", -> else key = bufferRow - presenter.getState().gutters.lineNumberGutter.lineNumbers[key] + getLineNumberGutterState(presenter).content.lineNumbers[key] it "contains states for line numbers that are visible on screen, plus and minus the overdraw margin", -> editor.foldBufferRow(4) @@ -2025,13 +2032,14 @@ describe "TextEditorPresenter", -> presenter = buildPresenter() marker = editor.markBufferRange([[0, 0], [0, 0]]) decoration = editor.decorateMarker(marker, type: 'line-number', class: 'a') - expect(lineNumberStateForScreenRow(presenter, 0).decorationClasses).toBeNull() + # A mini editor will have no gutters. + expect(getLineNumberGutterState(presenter)).toBeUndefined() expectStateUpdate presenter, -> editor.setMini(false) expect(lineNumberStateForScreenRow(presenter, 0).decorationClasses).toEqual ['cursor-line', 'cursor-line-no-selection', 'a'] expectStateUpdate presenter, -> editor.setMini(true) - expect(lineNumberStateForScreenRow(presenter, 0).decorationClasses).toBeNull() + expect(getLineNumberGutterState(presenter)).toBeUndefined() it "only applies line-number decorations to screen rows that are spanned by their marker when lines are soft-wrapped", -> editor.setText("a line that wraps, ok") From b6055f3a675439d8c5dcc4072a405c2d05751b81 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Wed, 13 May 2015 14:46:53 -0700 Subject: [PATCH 1206/1783] [Gutter] Fix shared gutter styles tests in TextEditorPresenter specs --- spec/text-editor-presenter-spec.coffee | 188 ++++++++++++++++--------- 1 file changed, 119 insertions(+), 69 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 5f82a64bc..371bb1c6c 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -2114,97 +2114,147 @@ describe "TextEditorPresenter", -> expect(presenter.getState().focused).toBe false describe ".gutters", -> - describe ".scrollHeight", -> - it "is initialized based on ::lineHeight, the number of lines, and ::explicitHeight", -> - presenter = buildPresenter() - expect(presenter.getState().gutters.scrollHeight).toBe editor.getScreenLineCount() * 10 + getStateForGutterWithName = (presenter, gutterName) -> + gutterDescriptions = presenter.getState().gutters + for description in gutterDescriptions + gutter = description.gutter + return description if gutter.name is gutterName - presenter = buildPresenter(explicitHeight: 500) - expect(presenter.getState().gutters.scrollHeight).toBe 500 + it "is an array with gutter descriptions appearing in order from left to right", -> + # TODO - it "updates when the ::lineHeight changes", -> - presenter = buildPresenter() - expectStateUpdate presenter, -> presenter.setLineHeight(20) - expect(presenter.getState().gutters.scrollHeight).toBe editor.getScreenLineCount() * 20 + describe "when gutter description corresponds to a custom gutter", -> + # TODO - it "updates when the line count changes", -> - presenter = buildPresenter() - expectStateUpdate presenter, -> editor.getBuffer().append("\n\n\n") - expect(presenter.getState().gutters.scrollHeight).toBe editor.getScreenLineCount() * 10 + describe "regardless of what kind of gutter a gutter description corresponds to", -> + [customGutter] = [] - it "updates when ::explicitHeight changes", -> - presenter = buildPresenter() - expectStateUpdate presenter, -> presenter.setExplicitHeight(500) - expect(presenter.getState().gutters.scrollHeight).toBe 500 + getStylesForGutterWithName = (presenter, gutterName) -> + fullState = getStateForGutterWithName(presenter, gutterName) + return fullState.styles if fullState - it "adds the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true", -> - presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) - expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.getState().gutters.scrollHeight).toBe presenter.contentHeight + beforeEach -> + customGutter = editor.addGutter({name: 'test-gutter', priority: -1, visible: true}) - expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", true) - expect(presenter.getState().gutters.scrollHeight).toBe presenter.contentHeight + presenter.clientHeight - (presenter.lineHeight * 3) + afterEach => + customGutter.destroy() - expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) - expect(presenter.getState().gutters.scrollHeight).toBe presenter.contentHeight + describe ".scrollHeight", -> + it "is initialized based on ::lineHeight, the number of lines, and ::explicitHeight", -> + presenter = buildPresenter() + expect(getStylesForGutterWithName(presenter, 'line-number').scrollHeight).toBe editor.getScreenLineCount() * 10 + expect(getStylesForGutterWithName(presenter, 'test-gutter').scrollHeight).toBe editor.getScreenLineCount() * 10 - describe ".scrollTop", -> - it "tracks the value of ::scrollTop", -> - presenter = buildPresenter(scrollTop: 10, explicitHeight: 20) - expect(presenter.getState().gutters.scrollTop).toBe 10 - expectStateUpdate presenter, -> presenter.setScrollTop(50) - expect(presenter.getState().gutters.scrollTop).toBe 50 + presenter = buildPresenter(explicitHeight: 500) + expect(getStylesForGutterWithName(presenter, 'line-number').scrollHeight).toBe 500 + expect(getStylesForGutterWithName(presenter, 'test-gutter').scrollHeight).toBe 500 - it "never exceeds the computed scrollHeight minus the computed clientHeight", -> - presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) - expectStateUpdate presenter, -> presenter.setScrollTop(100) - expect(presenter.getState().gutters.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + it "updates when the ::lineHeight changes", -> + presenter = buildPresenter() + expectStateUpdate presenter, -> presenter.setLineHeight(20) + expect(getStylesForGutterWithName(presenter, 'line-number').scrollHeight).toBe editor.getScreenLineCount() * 20 + expect(getStylesForGutterWithName(presenter, 'test-gutter').scrollHeight).toBe editor.getScreenLineCount() * 20 - expectStateUpdate presenter, -> presenter.setExplicitHeight(60) - expect(presenter.getState().gutters.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + it "updates when the line count changes", -> + presenter = buildPresenter() + expectStateUpdate presenter, -> editor.getBuffer().append("\n\n\n") + expect(getStylesForGutterWithName(presenter, 'line-number').scrollHeight).toBe editor.getScreenLineCount() * 10 + expect(getStylesForGutterWithName(presenter, 'test-gutter').scrollHeight).toBe editor.getScreenLineCount() * 10 - expectStateUpdate presenter, -> presenter.setHorizontalScrollbarHeight(5) - expect(presenter.getState().gutters.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + it "updates when ::explicitHeight changes", -> + presenter = buildPresenter() + expectStateUpdate presenter, -> presenter.setExplicitHeight(500) + expect(getStylesForGutterWithName(presenter, 'line-number').scrollHeight).toBe 500 + expect(getStylesForGutterWithName(presenter, 'test-gutter').scrollHeight).toBe 500 - expectStateUpdate presenter, -> editor.getBuffer().delete([[8, 0], [12, 0]]) - expect(presenter.getState().gutters.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + 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(getStylesForGutterWithName(presenter, 'line-number').scrollHeight).toBe presenter.contentHeight + expect(getStylesForGutterWithName(presenter, 'test-gutter').scrollHeight).toBe presenter.contentHeight - # Scroll top only gets smaller when needed as dimensions change, never bigger - scrollTopBefore = presenter.getState().verticalScrollbar.scrollTop - expectStateUpdate presenter, -> editor.getBuffer().insert([9, Infinity], '\n\n\n') - expect(presenter.getState().gutters.scrollTop).toBe scrollTopBefore + expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", true) + expect(getStylesForGutterWithName(presenter, 'line-number').scrollHeight).toBe presenter.contentHeight + presenter.clientHeight - (presenter.lineHeight * 3) + expect(getStylesForGutterWithName(presenter, 'test-gutter').scrollHeight).toBe presenter.contentHeight + presenter.clientHeight - (presenter.lineHeight * 3) - it "never goes negative", -> - presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) - expectStateUpdate presenter, -> presenter.setScrollTop(-100) - expect(presenter.getState().gutters.scrollTop).toBe 0 + expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) + expect(getStylesForGutterWithName(presenter, 'line-number').scrollHeight).toBe presenter.contentHeight + expect(getStylesForGutterWithName(presenter, 'test-gutter').scrollHeight).toBe presenter.contentHeight - it "adds the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true", -> - presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) - expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.getState().gutters.scrollTop).toBe presenter.contentHeight - presenter.clientHeight + describe ".scrollTop", -> + it "tracks the value of ::scrollTop", -> + presenter = buildPresenter(scrollTop: 10, explicitHeight: 20) + expect(getStylesForGutterWithName(presenter, 'line-number').scrollTop).toBe 10 + expect(getStylesForGutterWithName(presenter, 'test-gutter').scrollTop).toBe 10 + expectStateUpdate presenter, -> presenter.setScrollTop(50) + expect(getStylesForGutterWithName(presenter, 'line-number').scrollTop).toBe 50 + expect(getStylesForGutterWithName(presenter, 'test-gutter').scrollTop).toBe 50 - atom.config.set("editor.scrollPastEnd", true) - expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.getState().gutters.scrollTop).toBe presenter.contentHeight - (presenter.lineHeight * 3) + it "never exceeds the computed scrollHeight minus the computed clientHeight", -> + presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) + expectStateUpdate presenter, -> presenter.setScrollTop(100) + expect(getStylesForGutterWithName(presenter, 'line-number').scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + expect(getStylesForGutterWithName(presenter, 'test-gutter').scrollTop).toBe presenter.scrollHeight - presenter.clientHeight - expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) - expect(presenter.getState().gutters.scrollTop).toBe presenter.contentHeight - presenter.clientHeight + expectStateUpdate presenter, -> presenter.setExplicitHeight(60) + expect(getStylesForGutterWithName(presenter, 'line-number').scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + expect(getStylesForGutterWithName(presenter, 'test-gutter').scrollTop).toBe presenter.scrollHeight - presenter.clientHeight - describe ".backgroundColor", -> - it "is assigned to ::gutterBackgroundColor if present, and to ::backgroundColor otherwise", -> - presenter = buildPresenter(backgroundColor: "rgba(255, 0, 0, 0)", gutterBackgroundColor: "rgba(0, 255, 0, 0)") - expect(presenter.getState().gutters.backgroundColor).toBe "rgba(0, 255, 0, 0)" + expectStateUpdate presenter, -> presenter.setHorizontalScrollbarHeight(5) + expect(getStylesForGutterWithName(presenter, 'line-number').scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + expect(getStylesForGutterWithName(presenter, 'test-gutter').scrollTop).toBe presenter.scrollHeight - presenter.clientHeight - expectStateUpdate presenter, -> presenter.setGutterBackgroundColor("rgba(0, 0, 255, 0)") - expect(presenter.getState().gutters.backgroundColor).toBe "rgba(0, 0, 255, 0)" + expectStateUpdate presenter, -> editor.getBuffer().delete([[8, 0], [12, 0]]) + expect(getStylesForGutterWithName(presenter, 'line-number').scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + expect(getStylesForGutterWithName(presenter, 'test-gutter').scrollTop).toBe presenter.scrollHeight - presenter.clientHeight - expectStateUpdate presenter, -> presenter.setGutterBackgroundColor("rgba(0, 0, 0, 0)") - expect(presenter.getState().gutters.backgroundColor).toBe "rgba(255, 0, 0, 0)" + # Scroll top only gets smaller when needed as dimensions change, never bigger + scrollTopBefore = presenter.getState().verticalScrollbar.scrollTop + expectStateUpdate presenter, -> editor.getBuffer().insert([9, Infinity], '\n\n\n') + expect(getStylesForGutterWithName(presenter, 'line-number').scrollTop).toBe scrollTopBefore + expect(getStylesForGutterWithName(presenter, 'test-gutter').scrollTop).toBe scrollTopBefore - expectStateUpdate presenter, -> presenter.setBackgroundColor("rgba(0, 0, 255, 0)") - expect(presenter.getState().gutters.backgroundColor).toBe "rgba(0, 0, 255, 0)" + it "never goes negative", -> + presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) + expectStateUpdate presenter, -> presenter.setScrollTop(-100) + expect(getStylesForGutterWithName(presenter, 'line-number').scrollTop).toBe 0 + expect(getStylesForGutterWithName(presenter, 'test-gutter').scrollTop).toBe 0 + it "adds the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true", -> + presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) + expectStateUpdate presenter, -> presenter.setScrollTop(300) + expect(getStylesForGutterWithName(presenter, 'line-number').scrollTop).toBe presenter.contentHeight - presenter.clientHeight + expect(getStylesForGutterWithName(presenter, 'test-gutter').scrollTop).toBe presenter.contentHeight - presenter.clientHeight + + atom.config.set("editor.scrollPastEnd", true) + expectStateUpdate presenter, -> presenter.setScrollTop(300) + expect(getStylesForGutterWithName(presenter, 'line-number').scrollTop).toBe presenter.contentHeight - (presenter.lineHeight * 3) + expect(getStylesForGutterWithName(presenter, 'test-gutter').scrollTop).toBe presenter.contentHeight - (presenter.lineHeight * 3) + + expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) + expect(getStylesForGutterWithName(presenter, 'line-number').scrollTop).toBe presenter.contentHeight - presenter.clientHeight + expect(getStylesForGutterWithName(presenter, 'test-gutter').scrollTop).toBe presenter.contentHeight - presenter.clientHeight + + describe ".backgroundColor", -> + it "is assigned to ::gutterBackgroundColor if present, and to ::backgroundColor otherwise", -> + presenter = buildPresenter(backgroundColor: "rgba(255, 0, 0, 0)", gutterBackgroundColor: "rgba(0, 255, 0, 0)") + expect(getStylesForGutterWithName(presenter, 'line-number').backgroundColor).toBe "rgba(0, 255, 0, 0)" + expect(getStylesForGutterWithName(presenter, 'test-gutter').backgroundColor).toBe "rgba(0, 255, 0, 0)" + + expectStateUpdate presenter, -> presenter.setGutterBackgroundColor("rgba(0, 0, 255, 0)") + expect(getStylesForGutterWithName(presenter, 'line-number').backgroundColor).toBe "rgba(0, 0, 255, 0)" + expect(getStylesForGutterWithName(presenter, 'test-gutter').backgroundColor).toBe "rgba(0, 0, 255, 0)" + + expectStateUpdate presenter, -> presenter.setGutterBackgroundColor("rgba(0, 0, 0, 0)") + expect(getStylesForGutterWithName(presenter, 'line-number').backgroundColor).toBe "rgba(255, 0, 0, 0)" + expect(getStylesForGutterWithName(presenter, 'test-gutter').backgroundColor).toBe "rgba(255, 0, 0, 0)" + + expectStateUpdate presenter, -> presenter.setBackgroundColor("rgba(0, 0, 255, 0)") + expect(getStylesForGutterWithName(presenter, 'line-number').backgroundColor).toBe "rgba(0, 0, 255, 0)" + expect(getStylesForGutterWithName(presenter, 'test-gutter').backgroundColor).toBe "rgba(0, 0, 255, 0)" + + + # TODO describe ".sortedDescriptions", -> gutterDescriptionWithName = (presenter, name) -> for gutterDesc in presenter.getState().gutters.sortedDescriptions From cd806ee7641852ceb1e2e5390d76cd401aa87485 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Wed, 13 May 2015 15:32:25 -0700 Subject: [PATCH 1207/1783] [Gutter] Fix former .sortedDescription tests in TextEditorPresenter specs --- spec/text-editor-presenter-spec.coffee | 133 ++++++++++++------------- 1 file changed, 61 insertions(+), 72 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 371bb1c6c..601539894 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -1780,7 +1780,43 @@ describe "TextEditorPresenter", -> gutter = description.gutter return description if gutter.name is 'line-number' - describe ".maxLineNumberDigits", -> + describe ".visible", -> + it "is true iff the editor isn't mini, ::isLineNumberGutterVisible is true on the editor, and the 'editor.showLineNumbers' config is enabled", -> + presenter = buildPresenter() + + expect(editor.isLineNumberGutterVisible()).toBe true + expect(getLineNumberGutterState(presenter).visible).toBe true + + expectStateUpdate presenter, -> editor.setMini(true) + expect(getLineNumberGutterState(presenter)).toBeUndefined() + + expectStateUpdate presenter, -> editor.setMini(false) + expect(getLineNumberGutterState(presenter).visible).toBe true + + expectStateUpdate presenter, -> editor.setLineNumberGutterVisible(false) + expect(getLineNumberGutterState(presenter).visible).toBe false + + expectStateUpdate presenter, -> editor.setLineNumberGutterVisible(true) + expect(getLineNumberGutterState(presenter).visible).toBe true + + expectStateUpdate presenter, -> atom.config.set('editor.showLineNumbers', false) + expect(getLineNumberGutterState(presenter).visible).toBe false + + it "gets updated when the editor's grammar changes", -> + presenter = buildPresenter() + + atom.config.set('editor.showLineNumbers', false, scopeSelector: '.source.js') + expect(getLineNumberGutterState(presenter).visible).toBe true + stateUpdated = false + presenter.onDidUpdateState -> stateUpdated = true + + waitsForPromise -> atom.packages.activatePackage('language-javascript') + + runs -> + expect(stateUpdated).toBe true + expect(getLineNumberGutterState(presenter).visible).toBe false + + describe ".content.maxLineNumberDigits", -> it "is set to the number of digits used by the greatest line number", -> presenter = buildPresenter() expect(editor.getLastBufferRow()).toBe 12 @@ -1789,7 +1825,7 @@ describe "TextEditorPresenter", -> editor.setText("1\n2\n3") expect(getLineNumberGutterState(presenter).content.maxLineNumberDigits).toBe 1 - describe ".lineNumbers", -> + describe ".content.lineNumbers", -> lineNumberStateForScreenRow = (presenter, screenRow) -> editor = presenter.model bufferRow = editor.bufferRowForScreenRow(screenRow) @@ -2120,8 +2156,29 @@ describe "TextEditorPresenter", -> gutter = description.gutter return description if gutter.name is gutterName - it "is an array with gutter descriptions appearing in order from left to right", -> - # TODO + describe "the array itself", -> + it "updates when gutters are added to the editor model, and keeps the gutters sorted by priority", -> + presenter = buildPresenter() + gutter1 = editor.addGutter({name: 'test-gutter-1', priority: -100, visible: true}) + gutter2 = editor.addGutter({name: 'test-gutter-2', priority: 100, visible: false}) + + expectedGutterOrder = [gutter1, editor.gutterWithName('line-number'), gutter2] + for gutterDescription, index in presenter.getState().gutters + expect(gutterDescription.gutter).toEqual expectedGutterOrder[index] + + it "updates when the visibility of a gutter changes", -> + presenter = buildPresenter() + gutter = editor.addGutter({name: 'test-gutter', visible: true}) + expect(getStateForGutterWithName(presenter, 'test-gutter').visible).toBe true + gutter.hide() + expect(getStateForGutterWithName(presenter, 'test-gutter').visible).toBe false + + it "updates when a gutter is removed", -> + presenter = buildPresenter() + gutter = editor.addGutter({name: 'test-gutter', visible: true}) + expect(getStateForGutterWithName(presenter, 'test-gutter').visible).toBe true + gutter.destroy() + expect(getStateForGutterWithName(presenter, 'test-gutter')).toBeUndefined() describe "when gutter description corresponds to a custom gutter", -> # TODO @@ -2253,75 +2310,7 @@ describe "TextEditorPresenter", -> expect(getStylesForGutterWithName(presenter, 'line-number').backgroundColor).toBe "rgba(0, 0, 255, 0)" expect(getStylesForGutterWithName(presenter, 'test-gutter').backgroundColor).toBe "rgba(0, 0, 255, 0)" - # TODO - describe ".sortedDescriptions", -> - gutterDescriptionWithName = (presenter, name) -> - for gutterDesc in presenter.getState().gutters.sortedDescriptions - return gutterDesc if gutterDesc.gutter.name is name - undefined - - describe "the line-number gutter", -> - it "is present iff the editor isn't mini, ::isLineNumberGutterVisible is true on the editor, and 'editor.showLineNumbers' is enabled in config", -> - presenter = buildPresenter() - - expect(editor.isLineNumberGutterVisible()).toBe true - expect(gutterDescriptionWithName(presenter, 'line-number').visible).toBe true - - expectStateUpdate presenter, -> editor.setMini(true) - expect(gutterDescriptionWithName(presenter, 'line-number')).toBeUndefined() - - expectStateUpdate presenter, -> editor.setMini(false) - expect(gutterDescriptionWithName(presenter, 'line-number').visible).toBe true - - expectStateUpdate presenter, -> editor.setLineNumberGutterVisible(false) - expect(gutterDescriptionWithName(presenter, 'line-number').visible).toBe false - - expectStateUpdate presenter, -> editor.setLineNumberGutterVisible(true) - expect(gutterDescriptionWithName(presenter, 'line-number').visible).toBe true - - expectStateUpdate presenter, -> atom.config.set('editor.showLineNumbers', false) - expect(gutterDescriptionWithName(presenter, 'line-number').visible).toBe false - - it "gets updated when the editor's grammar changes", -> - presenter = buildPresenter() - - atom.config.set('editor.showLineNumbers', false, scopeSelector: '.source.js') - expect(gutterDescriptionWithName(presenter, 'line-number').visible).toBe true - stateUpdated = false - presenter.onDidUpdateState -> stateUpdated = true - - waitsForPromise -> atom.packages.activatePackage('language-javascript') - - runs -> - expect(stateUpdated).toBe true - expect(gutterDescriptionWithName(presenter, 'line-number').visible).toBe false - - it "updates when gutters are added to the editor model, and keeps the gutters sorted by priority", -> - presenter = buildPresenter() - gutter1 = editor.addGutter({name: 'test-gutter-1', priority: -100, visible: true}) - gutter2 = editor.addGutter({name: 'test-gutter-2', priority: 100, visible: false}) - expectedState = [ - {gutter: gutter1, visible: true}, - {gutter: editor.gutterWithName('line-number'), visible: true}, - {gutter: gutter2, visible: false}, - ] - expect(presenter.getState().gutters.sortedDescriptions).toEqual expectedState - - it "updates when the visibility of a gutter changes", -> - presenter = buildPresenter() - gutter = editor.addGutter({name: 'test-gutter', visible: true}) - expect(gutterDescriptionWithName(presenter, 'test-gutter').visible).toBe true - gutter.hide() - expect(gutterDescriptionWithName(presenter, 'test-gutter').visible).toBe false - - it "updates when a gutter is removed", -> - presenter = buildPresenter() - gutter = editor.addGutter({name: 'test-gutter', visible: true}) - expect(gutterDescriptionWithName(presenter, 'test-gutter').visible).toBe true - gutter.destroy() - expect(gutterDescriptionWithName(presenter, 'test-gutter')).toBeUndefined() - describe ".customDecorations", -> [presenter, gutter, decorationItem, decorationParams] = [] [marker1, decoration1, marker2, decoration2, marker3, decoration3] = [] From e34dfc636c6728fafbeeb4ae030e6882b30c2f8e Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Wed, 13 May 2015 16:31:20 -0700 Subject: [PATCH 1208/1783] [Gutter] Fix custom decorations tests in TextEditorPresenter specs --- spec/text-editor-presenter-spec.coffee | 468 ++++++++++++------------- 1 file changed, 233 insertions(+), 235 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 601539894..8a991e34c 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -2156,7 +2156,7 @@ describe "TextEditorPresenter", -> gutter = description.gutter return description if gutter.name is gutterName - describe "the array itself", -> + describe "the array itself, an array of gutter descriptions", -> it "updates when gutters are added to the editor model, and keeps the gutters sorted by priority", -> presenter = buildPresenter() gutter1 = editor.addGutter({name: 'test-gutter-1', priority: -100, visible: true}) @@ -2180,8 +2180,238 @@ describe "TextEditorPresenter", -> gutter.destroy() expect(getStateForGutterWithName(presenter, 'test-gutter')).toBeUndefined() - describe "when gutter description corresponds to a custom gutter", -> - # TODO + describe "for a gutter description that corresponds to a custom gutter", -> + describe ".content", -> + getContentForGutterWithName = (presenter, gutterName) -> + fullState = getStateForGutterWithName(presenter, gutterName) + return fullState.content if fullState + + [presenter, gutter, decorationItem, decorationParams] = [] + [marker1, decoration1, marker2, decoration2, marker3, decoration3] = [] + + # Set the scrollTop to 0 to show the very top of the file. + # Set the explicitHeight to make 10 lines visible. + scrollTop = 0 + lineHeight = 10 + explicitHeight = lineHeight * 10 + lineOverdrawMargin = 1 + + beforeEach -> + # At the beginning of each test, decoration1 and decoration2 are in visible range, + # but not decoration3. + presenter = buildPresenter({explicitHeight, scrollTop, lineHeight, lineOverdrawMargin}) + gutter = editor.addGutter({name: 'test-gutter', visible: true}) + decorationItem = document.createElement('div') + decorationItem.class = 'decoration-item' + decorationParams = + type: 'gutter' + gutterName: 'test-gutter' + class: 'test-class' + item: decorationItem + marker1 = editor.markBufferRange([[0,0],[1,0]]) + decoration1 = editor.decorateMarker(marker1, decorationParams) + marker2 = editor.markBufferRange([[9,0],[12,0]]) + decoration2 = editor.decorateMarker(marker2, decorationParams) + marker3 = editor.markBufferRange([[13,0],[14,0]]) + decoration3 = editor.decorateMarker(marker3, decorationParams) + + # Clear any batched state updates. + presenter.getState() + + it "contains all decorations within the visible buffer range", -> + decorationState = getContentForGutterWithName(presenter, 'test-gutter') + expect(decorationState[decoration1.id].top).toBe lineHeight * marker1.getScreenRange().start.row + expect(decorationState[decoration1.id].height).toBe lineHeight * marker1.getScreenRange().getRowCount() + expect(decorationState[decoration1.id].item).toBe decorationItem + expect(decorationState[decoration1.id].class).toBe 'test-class' + + expect(decorationState[decoration2.id].top).toBe lineHeight * marker2.getScreenRange().start.row + expect(decorationState[decoration2.id].height).toBe lineHeight * marker2.getScreenRange().getRowCount() + expect(decorationState[decoration2.id].item).toBe decorationItem + expect(decorationState[decoration2.id].class).toBe 'test-class' + + expect(decorationState[decoration3.id]).toBeUndefined() + + it "updates when ::scrollTop changes", -> + # This update will scroll decoration1 out of view, and decoration3 into view. + expectStateUpdate presenter, -> presenter.setScrollTop(scrollTop + lineHeight * 5) + + decorationState = getContentForGutterWithName(presenter, 'test-gutter') + expect(decorationState[decoration1.id]).toBeUndefined() + expect(decorationState[decoration2.id].top).toBeDefined() + expect(decorationState[decoration3.id].top).toBeDefined() + + it "updates when ::explicitHeight changes", -> + # This update will make all three decorations visible. + expectStateUpdate presenter, -> presenter.setExplicitHeight(explicitHeight + lineHeight * 5) + + decorationState = getContentForGutterWithName(presenter, 'test-gutter') + expect(decorationState[decoration1.id].top).toBeDefined() + expect(decorationState[decoration2.id].top).toBeDefined() + expect(decorationState[decoration3.id].top).toBeDefined() + + it "updates when ::lineHeight changes", -> + # This update will make all three decorations visible. + expectStateUpdate presenter, -> presenter.setLineHeight(Math.ceil(1.0 * explicitHeight / marker3.getBufferRange().end.row)) + + decorationState = getContentForGutterWithName(presenter, 'test-gutter') + expect(decorationState[decoration1.id].top).toBeDefined() + expect(decorationState[decoration2.id].top).toBeDefined() + expect(decorationState[decoration3.id].top).toBeDefined() + + it "updates when the editor's content changes", -> + # This update will add enough lines to push decoration2 out of view. + expectStateUpdate presenter, -> editor.setTextInBufferRange([[8,0],[9,0]],'\n\n\n\n\n') + + decorationState = getContentForGutterWithName(presenter, 'test-gutter') + expect(decorationState[decoration1.id].top).toBeDefined() + expect(decorationState[decoration2.id]).toBeUndefined() + expect(decorationState[decoration3.id]).toBeUndefined() + + it "updates when a decoration's marker is modified", -> + # This update will move decoration1 out of view. + expectStateUpdate presenter, -> + newRange = new Range([13,0],[14,0]) + marker1.setBufferRange(newRange) + + decorationState = getContentForGutterWithName(presenter, 'test-gutter') + expect(decorationState[decoration1.id]).toBeUndefined() + expect(decorationState[decoration2.id].top).toBeDefined() + expect(decorationState[decoration3.id]).toBeUndefined() + + describe "when a decoration's properties are modified", -> + it "updates the item applied to the decoration, if the decoration item is changed", -> + # This changes the decoration class. The visibility of the decoration should not be affected. + newItem = document.createElement('div') + newItem.class = 'new-decoration-item' + newDecorationParams = + type: 'gutter' + gutterName: 'test-gutter' + class: 'test-class' + item: newItem + expectStateUpdate presenter, -> decoration1.setProperties(newDecorationParams) + + decorationState = getContentForGutterWithName(presenter, 'test-gutter') + expect(decorationState[decoration1.id].item).toBe newItem + expect(decorationState[decoration2.id].item).toBe decorationItem + expect(decorationState[decoration3.id]).toBeUndefined() + + it "updates the class applied to the decoration, if the decoration class is changed", -> + # This changes the decoration item. The visibility of the decoration should not be affected. + newDecorationParams = + type: 'gutter' + gutterName: 'test-gutter' + class: 'new-test-class' + item: decorationItem + expectStateUpdate presenter, -> decoration1.setProperties(newDecorationParams) + + decorationState = getContentForGutterWithName(presenter, 'test-gutter') + expect(decorationState[decoration1.id].class).toBe 'new-test-class' + expect(decorationState[decoration2.id].class).toBe 'test-class' + expect(decorationState[decoration3.id]).toBeUndefined() + + it "updates the type of the decoration, if the decoration type is changed", -> + # This changes the type of the decoration. This should remove the decoration from the gutter. + newDecorationParams = + type: 'line' + gutterName: 'test-gutter' # This is an invalid/meaningless option here, but it shouldn't matter. + class: 'test-class' + item: decorationItem + expectStateUpdate presenter, -> decoration1.setProperties(newDecorationParams) + + decorationState = getContentForGutterWithName(presenter, 'test-gutter') + expect(decorationState[decoration1.id]).toBeUndefined() + expect(decorationState[decoration2.id].top).toBeDefined() + expect(decorationState[decoration3.id]).toBeUndefined() + + it "updates the gutter the decoration targets, if the decoration gutterName is changed", -> + # This changes which gutter this decoration applies to. Since this gutter does not exist, + # the decoration should not appear in the customDecorations state. + newDecorationParams = + type: 'gutter' + gutterName: 'test-gutter-2' + class: 'new-test-class' + item: decorationItem + expectStateUpdate presenter, -> decoration1.setProperties(newDecorationParams) + + decorationState = getContentForGutterWithName(presenter, 'test-gutter') + expect(decorationState[decoration1.id]).toBeUndefined() + expect(decorationState[decoration2.id].top).toBeDefined() + expect(decorationState[decoration3.id]).toBeUndefined() + + # After adding the targeted gutter, the decoration will appear in the state for that gutter, + # since it should be visible. + expectStateUpdate presenter, -> editor.addGutter({name: 'test-gutter-2'}) + newGutterDecorationState = getContentForGutterWithName(presenter, 'test-gutter-2') + expect(newGutterDecorationState[decoration1.id].top).toBeDefined() + expect(newGutterDecorationState[decoration2.id]).toBeUndefined() + expect(newGutterDecorationState[decoration3.id]).toBeUndefined() + oldGutterDecorationState = getContentForGutterWithName(presenter, 'test-gutter') + expect(oldGutterDecorationState[decoration1.id]).toBeUndefined() + expect(oldGutterDecorationState[decoration2.id].top).toBeDefined() + expect(oldGutterDecorationState[decoration3.id]).toBeUndefined() + + it "updates when the editor's mini state changes, and is cleared when the editor is mini", -> + expectStateUpdate presenter, -> editor.setMini(true) + decorationState = getContentForGutterWithName(presenter, 'test-gutter') + expect(decorationState).toBeUndefined() + + # The decorations should return to the original state. + expectStateUpdate presenter, -> editor.setMini(false) + decorationState = getContentForGutterWithName(presenter, 'test-gutter') + expect(decorationState[decoration1.id].top).toBeDefined() + expect(decorationState[decoration2.id].top).toBeDefined() + expect(decorationState[decoration3.id]).toBeUndefined() + + it "updates when a gutter's visibility changes, and is cleared when the gutter is not visible", -> + expectStateUpdate presenter, -> gutter.hide() + decorationState = getContentForGutterWithName(presenter, 'test-gutter') + expect(decorationState[decoration1.id]).toBeUndefined() + expect(decorationState[decoration2.id]).toBeUndefined() + expect(decorationState[decoration3.id]).toBeUndefined() + + # The decorations should return to the original state. + expectStateUpdate presenter, -> gutter.show() + decorationState = getContentForGutterWithName(presenter, 'test-gutter') + expect(decorationState[decoration1.id].top).toBeDefined() + expect(decorationState[decoration2.id].top).toBeDefined() + expect(decorationState[decoration3.id]).toBeUndefined() + + it "updates when a gutter is added to the editor", -> + decorationParams = + type: 'gutter' + gutterName: 'test-gutter-2' + class: 'test-class' + marker4 = editor.markBufferRange([[0,0],[1,0]]) + decoration4 = editor.decorateMarker(marker4, decorationParams) + expectStateUpdate presenter, -> editor.addGutter({name: 'test-gutter-2'}) + + decorationState = getContentForGutterWithName(presenter, 'test-gutter-2') + expect(decorationState[decoration1.id]).toBeUndefined() + expect(decorationState[decoration2.id]).toBeUndefined() + expect(decorationState[decoration3.id]).toBeUndefined() + expect(decorationState[decoration4.id].top).toBeDefined() + + it "updates when editor lines are folded", -> + oldDimensionsForDecoration1 = + top: lineHeight * marker1.getScreenRange().start.row + height: lineHeight * marker1.getScreenRange().getRowCount() + oldDimensionsForDecoration2 = + top: lineHeight * marker2.getScreenRange().start.row + height: lineHeight * marker2.getScreenRange().getRowCount() + + # Based on the contents of sample.js, this should affect all but the top + # part of decoration1. + expectStateUpdate presenter, -> editor.foldBufferRow(0) + + decorationState = getContentForGutterWithName(presenter, 'test-gutter') + expect(decorationState[decoration1.id].top).toBe oldDimensionsForDecoration1.top + expect(decorationState[decoration1.id].height).not.toBe oldDimensionsForDecoration1.height + # Due to the issue described here: https://github.com/atom/atom/issues/6454, decoration2 + # will be bumped up to the row that was folded and still made visible, instead of being + # entirely collapsed. (The same thing will happen to decoration3.) + expect(decorationState[decoration2.id].top).not.toBe oldDimensionsForDecoration2.top + expect(decorationState[decoration2.id].height).not.toBe oldDimensionsForDecoration2.height describe "regardless of what kind of gutter a gutter description corresponds to", -> [customGutter] = [] @@ -2310,238 +2540,6 @@ describe "TextEditorPresenter", -> expect(getStylesForGutterWithName(presenter, 'line-number').backgroundColor).toBe "rgba(0, 0, 255, 0)" expect(getStylesForGutterWithName(presenter, 'test-gutter').backgroundColor).toBe "rgba(0, 0, 255, 0)" - # TODO - describe ".customDecorations", -> - [presenter, gutter, decorationItem, decorationParams] = [] - [marker1, decoration1, marker2, decoration2, marker3, decoration3] = [] - - # Set the scrollTop to 0 to show the very top of the file. - # Set the explicitHeight to make 10 lines visible. - scrollTop = 0 - lineHeight = 10 - explicitHeight = lineHeight * 10 - lineOverdrawMargin = 1 - - decorationStateForGutterName = (presenter, gutterName) -> - presenter.getState().gutters.customDecorations[gutterName] - - beforeEach -> - # At the beginning of each test, decoration1 and decoration2 are in visible range, - # but not decoration3. - presenter = buildPresenter({explicitHeight, scrollTop, lineHeight, lineOverdrawMargin}) - gutter = editor.addGutter({name: 'test-gutter', visible: true}) - decorationItem = document.createElement('div') - decorationItem.class = 'decoration-item' - decorationParams = - type: 'gutter' - gutterName: 'test-gutter' - class: 'test-class' - item: decorationItem - marker1 = editor.markBufferRange([[0,0],[1,0]]) - decoration1 = editor.decorateMarker(marker1, decorationParams) - marker2 = editor.markBufferRange([[9,0],[12,0]]) - decoration2 = editor.decorateMarker(marker2, decorationParams) - marker3 = editor.markBufferRange([[13,0],[14,0]]) - decoration3 = editor.decorateMarker(marker3, decorationParams) - - # Clear any batched state updates. - presenter.getState() - - it "contains all decorations within the visible buffer range", -> - decorationState = decorationStateForGutterName(presenter, 'test-gutter') - expect(decorationState[decoration1.id].top).toBe lineHeight * marker1.getScreenRange().start.row - expect(decorationState[decoration1.id].height).toBe lineHeight * marker1.getScreenRange().getRowCount() - expect(decorationState[decoration1.id].item).toBe decorationItem - expect(decorationState[decoration1.id].class).toBe 'test-class' - - expect(decorationState[decoration2.id].top).toBe lineHeight * marker2.getScreenRange().start.row - expect(decorationState[decoration2.id].height).toBe lineHeight * marker2.getScreenRange().getRowCount() - expect(decorationState[decoration2.id].item).toBe decorationItem - expect(decorationState[decoration2.id].class).toBe 'test-class' - - expect(decorationState[decoration3.id]).toBeUndefined() - - it "updates when ::scrollTop changes", -> - # This update will scroll decoration1 out of view, and decoration3 into view. - expectStateUpdate presenter, -> presenter.setScrollTop(scrollTop + lineHeight * 5) - - decorationState = decorationStateForGutterName(presenter, 'test-gutter') - expect(decorationState[decoration1.id]).toBeUndefined() - expect(decorationState[decoration2.id].top).toBeDefined() - expect(decorationState[decoration3.id].top).toBeDefined() - - it "updates when ::explicitHeight changes", -> - # This update will make all three decorations visible. - expectStateUpdate presenter, -> presenter.setExplicitHeight(explicitHeight + lineHeight * 5) - - decorationState = decorationStateForGutterName(presenter, 'test-gutter') - expect(decorationState[decoration1.id].top).toBeDefined() - expect(decorationState[decoration2.id].top).toBeDefined() - expect(decorationState[decoration3.id].top).toBeDefined() - - it "updates when ::lineHeight changes", -> - # This update will make all three decorations visible. - expectStateUpdate presenter, -> presenter.setLineHeight(Math.ceil(1.0 * explicitHeight / marker3.getBufferRange().end.row)) - - decorationState = decorationStateForGutterName(presenter, 'test-gutter') - expect(decorationState[decoration1.id].top).toBeDefined() - expect(decorationState[decoration2.id].top).toBeDefined() - expect(decorationState[decoration3.id].top).toBeDefined() - - it "updates when the editor's content changes", -> - # This update will add enough lines to push decoration2 out of view. - expectStateUpdate presenter, -> editor.setTextInBufferRange([[8,0],[9,0]],'\n\n\n\n\n') - - decorationState = decorationStateForGutterName(presenter, 'test-gutter') - expect(decorationState[decoration1.id].top).toBeDefined() - expect(decorationState[decoration2.id]).toBeUndefined() - expect(decorationState[decoration3.id]).toBeUndefined() - - it "updates when a decoration's marker is modified", -> - # This update will move decoration1 out of view. - expectStateUpdate presenter, -> - newRange = new Range([13,0],[14,0]) - marker1.setBufferRange(newRange) - - decorationState = decorationStateForGutterName(presenter, 'test-gutter') - expect(decorationState[decoration1.id]).toBeUndefined() - expect(decorationState[decoration2.id].top).toBeDefined() - expect(decorationState[decoration3.id]).toBeUndefined() - - describe "when a decoration's properties are modified", -> - it "updates the item applied to the decoration, if the decoration item is changed", -> - # This changes the decoration class. The visibility of the decoration should not be affected. - newItem = document.createElement('div') - newItem.class = 'new-decoration-item' - newDecorationParams = - type: 'gutter' - gutterName: 'test-gutter' - class: 'test-class' - item: newItem - expectStateUpdate presenter, -> decoration1.setProperties(newDecorationParams) - - decorationState = decorationStateForGutterName(presenter, 'test-gutter') - expect(decorationState[decoration1.id].item).toBe newItem - expect(decorationState[decoration2.id].item).toBe decorationItem - expect(decorationState[decoration3.id]).toBeUndefined() - - it "updates the class applied to the decoration, if the decoration class is changed", -> - # This changes the decoration item. The visibility of the decoration should not be affected. - newDecorationParams = - type: 'gutter' - gutterName: 'test-gutter' - class: 'new-test-class' - item: decorationItem - expectStateUpdate presenter, -> decoration1.setProperties(newDecorationParams) - - decorationState = decorationStateForGutterName(presenter, 'test-gutter') - expect(decorationState[decoration1.id].class).toBe 'new-test-class' - expect(decorationState[decoration2.id].class).toBe 'test-class' - expect(decorationState[decoration3.id]).toBeUndefined() - - it "updates the type of the decoration, if the decoration type is changed", -> - # This changes the type of the decoration. This should remove the decoration from the gutter. - newDecorationParams = - type: 'line' - gutterName: 'test-gutter' # This is an invalid/meaningless option here, but it shouldn't matter. - class: 'test-class' - item: decorationItem - expectStateUpdate presenter, -> decoration1.setProperties(newDecorationParams) - - decorationState = decorationStateForGutterName(presenter, 'test-gutter') - expect(decorationState[decoration1.id]).toBeUndefined() - expect(decorationState[decoration2.id].top).toBeDefined() - expect(decorationState[decoration3.id]).toBeUndefined() - - it "updates the gutter the decoration targets, if the decoration gutterName is changed", -> - # This changes which gutter this decoration applies to. Since this gutter does not exist, - # the decoration should not appear in the customDecorations state. - newDecorationParams = - type: 'gutter' - gutterName: 'test-gutter-2' - class: 'new-test-class' - item: decorationItem - expectStateUpdate presenter, -> decoration1.setProperties(newDecorationParams) - - decorationState = decorationStateForGutterName(presenter, 'test-gutter') - expect(decorationState[decoration1.id]).toBeUndefined() - expect(decorationState[decoration2.id].top).toBeDefined() - expect(decorationState[decoration3.id]).toBeUndefined() - - # After adding the targeted gutter, the decoration will appear in the state for that gutter, - # since it should be visible. - expectStateUpdate presenter, -> editor.addGutter({name: 'test-gutter-2'}) - newGutterDecorationState = decorationStateForGutterName(presenter, 'test-gutter-2') - expect(newGutterDecorationState[decoration1.id].top).toBeDefined() - expect(newGutterDecorationState[decoration2.id]).toBeUndefined() - expect(newGutterDecorationState[decoration3.id]).toBeUndefined() - oldGutterDecorationState = decorationStateForGutterName(presenter, 'test-gutter') - expect(oldGutterDecorationState[decoration1.id]).toBeUndefined() - expect(oldGutterDecorationState[decoration2.id].top).toBeDefined() - expect(oldGutterDecorationState[decoration3.id]).toBeUndefined() - - it "updates when the editor's mini state changes, and is cleared when the editor is mini", -> - expectStateUpdate presenter, -> editor.setMini(true) - decorationState = decorationStateForGutterName(presenter, 'test-gutter') - expect(decorationState).toBeUndefined() - - # The decorations should return to the original state. - expectStateUpdate presenter, -> editor.setMini(false) - decorationState = decorationStateForGutterName(presenter, 'test-gutter') - expect(decorationState[decoration1.id].top).toBeDefined() - expect(decorationState[decoration2.id].top).toBeDefined() - expect(decorationState[decoration3.id]).toBeUndefined() - - it "updates when a gutter's visibility changes, and is cleared when the gutter is not visible", -> - expectStateUpdate presenter, -> gutter.hide() - decorationState = decorationStateForGutterName(presenter, 'test-gutter') - expect(decorationState[decoration1.id]).toBeUndefined() - expect(decorationState[decoration2.id]).toBeUndefined() - expect(decorationState[decoration3.id]).toBeUndefined() - - # The decorations should return to the original state. - expectStateUpdate presenter, -> gutter.show() - decorationState = decorationStateForGutterName(presenter, 'test-gutter') - expect(decorationState[decoration1.id].top).toBeDefined() - expect(decorationState[decoration2.id].top).toBeDefined() - expect(decorationState[decoration3.id]).toBeUndefined() - - it "updates when a gutter is added to the editor", -> - decorationParams = - type: 'gutter' - gutterName: 'test-gutter-2' - class: 'test-class' - marker4 = editor.markBufferRange([[0,0],[1,0]]) - decoration4 = editor.decorateMarker(marker4, decorationParams) - expectStateUpdate presenter, -> editor.addGutter({name: 'test-gutter-2'}) - - decorationState = decorationStateForGutterName(presenter, 'test-gutter-2') - expect(decorationState[decoration1.id]).toBeUndefined() - expect(decorationState[decoration2.id]).toBeUndefined() - expect(decorationState[decoration3.id]).toBeUndefined() - expect(decorationState[decoration4.id].top).toBeDefined() - - it "updates when editor lines are folded", -> - oldDimensionsForDecoration1 = - top: lineHeight * marker1.getScreenRange().start.row - height: lineHeight * marker1.getScreenRange().getRowCount() - oldDimensionsForDecoration2 = - top: lineHeight * marker2.getScreenRange().start.row - height: lineHeight * marker2.getScreenRange().getRowCount() - - # Based on the contents of sample.js, this should affect all but the top - # part of decoration1. - expectStateUpdate presenter, -> editor.foldBufferRow(0) - - decorationState = decorationStateForGutterName(presenter, 'test-gutter') - expect(decorationState[decoration1.id].top).toBe oldDimensionsForDecoration1.top - expect(decorationState[decoration1.id].height).not.toBe oldDimensionsForDecoration1.height - # Due to the issue described here: https://github.com/atom/atom/issues/6454, decoration2 - # will be bumped up to the row that was folded and still made visible, instead of being - # entirely collapsed. (The same thing will happen to decoration3.) - expect(decorationState[decoration2.id].top).not.toBe oldDimensionsForDecoration2.top - expect(decorationState[decoration2.id].height).not.toBe oldDimensionsForDecoration2.height - # disabled until we fix an issue with display buffer markers not updating when # they are moved on screen but not in the buffer xdescribe "when the model and view measurements are mutated randomly", -> From 57d08873463b664b9e3c989d5cd95dcab0e4ef26 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Wed, 13 May 2015 16:35:40 -0700 Subject: [PATCH 1209/1783] [Gutter] Move line number gutter tests to be under .gutters in TextEditorPresenter specs --- spec/text-editor-presenter-spec.coffee | 701 ++++++++++++------------- 1 file changed, 350 insertions(+), 351 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 8a991e34c..f5ed6d90f 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -1772,357 +1772,6 @@ describe "TextEditorPresenter", -> pixelPosition: {top: 10, left: 0} } - # TODO jssln Move this under '.gutters' - describe "when the gutter is the line-number gutter", -> - getLineNumberGutterState = (presenter) -> - gutterDescriptions = presenter.getState().gutters - for description in gutterDescriptions - gutter = description.gutter - return description if gutter.name is 'line-number' - - describe ".visible", -> - it "is true iff the editor isn't mini, ::isLineNumberGutterVisible is true on the editor, and the 'editor.showLineNumbers' config is enabled", -> - presenter = buildPresenter() - - expect(editor.isLineNumberGutterVisible()).toBe true - expect(getLineNumberGutterState(presenter).visible).toBe true - - expectStateUpdate presenter, -> editor.setMini(true) - expect(getLineNumberGutterState(presenter)).toBeUndefined() - - expectStateUpdate presenter, -> editor.setMini(false) - expect(getLineNumberGutterState(presenter).visible).toBe true - - expectStateUpdate presenter, -> editor.setLineNumberGutterVisible(false) - expect(getLineNumberGutterState(presenter).visible).toBe false - - expectStateUpdate presenter, -> editor.setLineNumberGutterVisible(true) - expect(getLineNumberGutterState(presenter).visible).toBe true - - expectStateUpdate presenter, -> atom.config.set('editor.showLineNumbers', false) - expect(getLineNumberGutterState(presenter).visible).toBe false - - it "gets updated when the editor's grammar changes", -> - presenter = buildPresenter() - - atom.config.set('editor.showLineNumbers', false, scopeSelector: '.source.js') - expect(getLineNumberGutterState(presenter).visible).toBe true - stateUpdated = false - presenter.onDidUpdateState -> stateUpdated = true - - waitsForPromise -> atom.packages.activatePackage('language-javascript') - - runs -> - expect(stateUpdated).toBe true - expect(getLineNumberGutterState(presenter).visible).toBe false - - describe ".content.maxLineNumberDigits", -> - it "is set to the number of digits used by the greatest line number", -> - presenter = buildPresenter() - expect(editor.getLastBufferRow()).toBe 12 - expect(getLineNumberGutterState(presenter).content.maxLineNumberDigits).toBe 2 - - editor.setText("1\n2\n3") - expect(getLineNumberGutterState(presenter).content.maxLineNumberDigits).toBe 1 - - describe ".content.lineNumbers", -> - lineNumberStateForScreenRow = (presenter, screenRow) -> - editor = presenter.model - bufferRow = editor.bufferRowForScreenRow(screenRow) - wrapCount = screenRow - editor.screenRowForBufferRow(bufferRow) - if wrapCount > 0 - key = bufferRow + '-' + wrapCount - else - key = bufferRow - - getLineNumberGutterState(presenter).content.lineNumbers[key] - - it "contains states for line numbers that are visible on screen, plus and minus the overdraw margin", -> - editor.foldBufferRow(4) - editor.setSoftWrapped(true) - editor.setEditorWidthInChars(50) - presenter = buildPresenter(explicitHeight: 25, scrollTop: 30, lineHeight: 10, lineOverdrawMargin: 1) - - expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() - expectValues lineNumberStateForScreenRow(presenter, 2), {screenRow: 2, bufferRow: 2, softWrapped: false, top: 2 * 10} - expectValues lineNumberStateForScreenRow(presenter, 3), {screenRow: 3, bufferRow: 3, softWrapped: false, top: 3 * 10} - expectValues lineNumberStateForScreenRow(presenter, 4), {screenRow: 4, bufferRow: 3, softWrapped: true, top: 4 * 10} - expectValues lineNumberStateForScreenRow(presenter, 5), {screenRow: 5, bufferRow: 4, softWrapped: false, top: 5 * 10} - expectValues lineNumberStateForScreenRow(presenter, 6), {screenRow: 6, bufferRow: 7, softWrapped: false, top: 6 * 10} - expectValues lineNumberStateForScreenRow(presenter, 7), {screenRow: 7, bufferRow: 8, softWrapped: false, top: 7 * 10} - expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() - - it "includes states for all line numbers if no ::explicitHeight is assigned", -> - presenter = buildPresenter(explicitHeight: null) - expect(lineNumberStateForScreenRow(presenter, 0)).toBeDefined() - expect(lineNumberStateForScreenRow(presenter, 12)).toBeDefined() - - it "updates when ::scrollTop changes", -> - editor.foldBufferRow(4) - editor.setSoftWrapped(true) - editor.setEditorWidthInChars(50) - presenter = buildPresenter(explicitHeight: 25, scrollTop: 30, lineOverdrawMargin: 1) - - expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() - expectValues lineNumberStateForScreenRow(presenter, 2), {bufferRow: 2} - expectValues lineNumberStateForScreenRow(presenter, 7), {bufferRow: 8} - expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() - - expectStateUpdate presenter, -> presenter.setScrollTop(20) - - expect(lineNumberStateForScreenRow(presenter, 0)).toBeUndefined() - expectValues lineNumberStateForScreenRow(presenter, 1), {bufferRow: 1} - expectValues lineNumberStateForScreenRow(presenter, 6), {bufferRow: 7} - expect(lineNumberStateForScreenRow(presenter, 7)).toBeUndefined() - - it "updates when ::explicitHeight changes", -> - editor.foldBufferRow(4) - editor.setSoftWrapped(true) - editor.setEditorWidthInChars(50) - presenter = buildPresenter(explicitHeight: 25, scrollTop: 30, lineOverdrawMargin: 1) - - expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() - expectValues lineNumberStateForScreenRow(presenter, 2), {bufferRow: 2} - expectValues lineNumberStateForScreenRow(presenter, 7), {bufferRow: 8} - expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() - - expectStateUpdate presenter, -> presenter.setExplicitHeight(35) - - expect(lineNumberStateForScreenRow(presenter, 0)).toBeUndefined() - expectValues lineNumberStateForScreenRow(presenter, 2), {bufferRow: 2} - expectValues lineNumberStateForScreenRow(presenter, 8), {bufferRow: 8} - expect(lineNumberStateForScreenRow(presenter, 9)).toBeUndefined() - - it "updates when ::lineHeight changes", -> - editor.foldBufferRow(4) - editor.setSoftWrapped(true) - editor.setEditorWidthInChars(50) - presenter = buildPresenter(explicitHeight: 25, scrollTop: 0, lineOverdrawMargin: 0) - - expectValues lineNumberStateForScreenRow(presenter, 0), {bufferRow: 0} - expectValues lineNumberStateForScreenRow(presenter, 3), {bufferRow: 3} - expect(lineNumberStateForScreenRow(presenter, 4)).toBeUndefined() - - expectStateUpdate presenter, -> presenter.setLineHeight(5) - - expectValues lineNumberStateForScreenRow(presenter, 0), {bufferRow: 0} - expectValues lineNumberStateForScreenRow(presenter, 5), {bufferRow: 4} - expect(lineNumberStateForScreenRow(presenter, 6)).toBeUndefined() - - it "updates when the editor's content changes", -> - editor.foldBufferRow(4) - editor.setSoftWrapped(true) - editor.setEditorWidthInChars(50) - presenter = buildPresenter(explicitHeight: 35, scrollTop: 30, lineOverdrawMargin: 0) - - expect(lineNumberStateForScreenRow(presenter, 2)).toBeUndefined() - expectValues lineNumberStateForScreenRow(presenter, 3), {bufferRow: 3} - expectValues lineNumberStateForScreenRow(presenter, 4), {bufferRow: 3} - expectValues lineNumberStateForScreenRow(presenter, 5), {bufferRow: 4} - expectValues lineNumberStateForScreenRow(presenter, 6), {bufferRow: 7} - expectValues lineNumberStateForScreenRow(presenter, 7), {bufferRow: 8} - expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() - - expectStateUpdate presenter, -> - editor.getBuffer().insert([3, Infinity], new Array(25).join("x ")) - - expect(lineNumberStateForScreenRow(presenter, 2)).toBeUndefined() - expectValues lineNumberStateForScreenRow(presenter, 3), {bufferRow: 3} - expectValues lineNumberStateForScreenRow(presenter, 4), {bufferRow: 3} - expectValues lineNumberStateForScreenRow(presenter, 5), {bufferRow: 3} - expectValues lineNumberStateForScreenRow(presenter, 6), {bufferRow: 4} - expectValues lineNumberStateForScreenRow(presenter, 7), {bufferRow: 7} - expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() - - it "does not remove out-of-view line numbers corresponding to ::mouseWheelScreenRow until ::stoppedScrollingDelay elapses", -> - presenter = buildPresenter(explicitHeight: 25, lineOverdrawMargin: 1, stoppedScrollingDelay: 200) - - expect(lineNumberStateForScreenRow(presenter, 0)).toBeDefined() - expect(lineNumberStateForScreenRow(presenter, 4)).toBeDefined() - expect(lineNumberStateForScreenRow(presenter, 5)).toBeUndefined() - - presenter.setMouseWheelScreenRow(0) - expectStateUpdate presenter, -> presenter.setScrollTop(35) - - expect(lineNumberStateForScreenRow(presenter, 0)).toBeDefined() - expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() - expect(lineNumberStateForScreenRow(presenter, 7)).toBeDefined() - expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() - - expectStateUpdate presenter, -> advanceClock(200) - - expect(lineNumberStateForScreenRow(presenter, 0)).toBeUndefined() - expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() - expect(lineNumberStateForScreenRow(presenter, 7)).toBeDefined() - expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() - - it "correctly handles the first screen line being soft-wrapped", -> - editor.setSoftWrapped(true) - editor.setEditorWidthInChars(30) - presenter = buildPresenter(explicitHeight: 25, scrollTop: 50) - - expectValues lineNumberStateForScreenRow(presenter, 5), {screenRow: 5, bufferRow: 3, softWrapped: true} - expectValues lineNumberStateForScreenRow(presenter, 6), {screenRow: 6, bufferRow: 3, softWrapped: true} - expectValues lineNumberStateForScreenRow(presenter, 7), {screenRow: 7, bufferRow: 4, softWrapped: false} - - describe ".decorationClasses", -> - it "adds decoration classes to the relevant line number state objects, both initially and when decorations change", -> - marker1 = editor.markBufferRange([[4, 0], [6, 2]], invalidate: 'touch') - decoration1 = editor.decorateMarker(marker1, type: 'line-number', class: 'a') - presenter = buildPresenter() - marker2 = editor.markBufferRange([[4, 0], [6, 2]], invalidate: 'touch') - decoration2 = editor.decorateMarker(marker2, type: 'line-number', class: 'b') - - expect(lineNumberStateForScreenRow(presenter, 3).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toEqual ['a', 'b'] - expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toEqual ['a', 'b'] - expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['a', 'b'] - expect(lineNumberStateForScreenRow(presenter, 7).decorationClasses).toBeNull() - - expectStateUpdate presenter, -> editor.getBuffer().insert([5, 0], 'x') - expect(marker1.isValid()).toBe false - expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toBeNull() - - expectStateUpdate presenter, -> editor.undo() - expect(lineNumberStateForScreenRow(presenter, 3).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toEqual ['a', 'b'] - expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toEqual ['a', 'b'] - expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['a', 'b'] - expect(lineNumberStateForScreenRow(presenter, 7).decorationClasses).toBeNull() - - expectStateUpdate presenter, -> marker1.setBufferRange([[2, 0], [4, 2]]) - expect(lineNumberStateForScreenRow(presenter, 1).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 2).decorationClasses).toEqual ['a'] - expect(lineNumberStateForScreenRow(presenter, 3).decorationClasses).toEqual ['a'] - expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toEqual ['a', 'b'] - expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toEqual ['b'] - expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['b'] - expect(lineNumberStateForScreenRow(presenter, 7).decorationClasses).toBeNull() - - expectStateUpdate presenter, -> decoration1.destroy() - expect(lineNumberStateForScreenRow(presenter, 2).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 3).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toEqual ['b'] - expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toEqual ['b'] - expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['b'] - expect(lineNumberStateForScreenRow(presenter, 7).decorationClasses).toBeNull() - - expectStateUpdate presenter, -> marker2.destroy() - expect(lineNumberStateForScreenRow(presenter, 2).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 3).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 7).decorationClasses).toBeNull() - - it "honors the 'onlyEmpty' option on line-number decorations", -> - presenter = buildPresenter() - marker = editor.markBufferRange([[4, 0], [6, 1]]) - decoration = editor.decorateMarker(marker, type: 'line-number', class: 'a', onlyEmpty: true) - - expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toBeNull() - - expectStateUpdate presenter, -> marker.clearTail() - - expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['a'] - - it "honors the 'onlyNonEmpty' option on line-number decorations", -> - presenter = buildPresenter() - marker = editor.markBufferRange([[4, 0], [6, 2]]) - decoration = editor.decorateMarker(marker, type: 'line-number', class: 'a', onlyNonEmpty: true) - - expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toEqual ['a'] - expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toEqual ['a'] - expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['a'] - - expectStateUpdate presenter, -> marker.clearTail() - - expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toBeNull() - - it "honors the 'onlyHead' option on line-number decorations", -> - presenter = buildPresenter() - marker = editor.markBufferRange([[4, 0], [6, 2]]) - decoration = editor.decorateMarker(marker, type: 'line-number', class: 'a', onlyHead: true) - - expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['a'] - - it "does not decorate the last line of a non-empty line-number decoration range if it ends at column 0", -> - presenter = buildPresenter() - marker = editor.markBufferRange([[4, 0], [6, 0]]) - decoration = editor.decorateMarker(marker, type: 'line-number', class: 'a') - - expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toEqual ['a'] - expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toEqual ['a'] - expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toBeNull() - - it "does not apply line-number decorations to mini editors", -> - editor.setMini(true) - presenter = buildPresenter() - marker = editor.markBufferRange([[0, 0], [0, 0]]) - decoration = editor.decorateMarker(marker, type: 'line-number', class: 'a') - # A mini editor will have no gutters. - expect(getLineNumberGutterState(presenter)).toBeUndefined() - - expectStateUpdate presenter, -> editor.setMini(false) - expect(lineNumberStateForScreenRow(presenter, 0).decorationClasses).toEqual ['cursor-line', 'cursor-line-no-selection', 'a'] - - expectStateUpdate presenter, -> editor.setMini(true) - expect(getLineNumberGutterState(presenter)).toBeUndefined() - - it "only applies line-number decorations to screen rows that are spanned by their marker when lines are soft-wrapped", -> - editor.setText("a line that wraps, ok") - editor.setSoftWrapped(true) - editor.setEditorWidthInChars(16) - marker = editor.markBufferRange([[0, 0], [0, 2]]) - editor.decorateMarker(marker, type: 'line-number', class: 'a') - presenter = buildPresenter(explicitHeight: 10) - - expect(lineNumberStateForScreenRow(presenter, 0).decorationClasses).toContain 'a' - expect(lineNumberStateForScreenRow(presenter, 1).decorationClasses).toBeNull() - - marker.setBufferRange([[0, 0], [0, Infinity]]) - expect(lineNumberStateForScreenRow(presenter, 0).decorationClasses).toContain 'a' - expect(lineNumberStateForScreenRow(presenter, 1).decorationClasses).toContain 'a' - - describe ".foldable", -> - it "marks line numbers at the start of a foldable region as foldable", -> - presenter = buildPresenter() - expect(lineNumberStateForScreenRow(presenter, 0).foldable).toBe true - expect(lineNumberStateForScreenRow(presenter, 1).foldable).toBe true - expect(lineNumberStateForScreenRow(presenter, 2).foldable).toBe false - expect(lineNumberStateForScreenRow(presenter, 3).foldable).toBe false - expect(lineNumberStateForScreenRow(presenter, 4).foldable).toBe true - expect(lineNumberStateForScreenRow(presenter, 5).foldable).toBe false - - it "updates the foldable class on the correct line numbers when the foldable positions change", -> - presenter = buildPresenter() - editor.getBuffer().insert([0, 0], '\n') - expect(lineNumberStateForScreenRow(presenter, 0).foldable).toBe false - expect(lineNumberStateForScreenRow(presenter, 1).foldable).toBe true - expect(lineNumberStateForScreenRow(presenter, 2).foldable).toBe true - expect(lineNumberStateForScreenRow(presenter, 3).foldable).toBe false - expect(lineNumberStateForScreenRow(presenter, 4).foldable).toBe false - expect(lineNumberStateForScreenRow(presenter, 5).foldable).toBe true - expect(lineNumberStateForScreenRow(presenter, 6).foldable).toBe false - - it "updates the foldable class on a line number that becomes foldable", -> - presenter = buildPresenter() - expect(lineNumberStateForScreenRow(presenter, 11).foldable).toBe false - - editor.getBuffer().insert([11, 44], '\n fold me') - expect(lineNumberStateForScreenRow(presenter, 11).foldable).toBe true - - editor.undo() - expect(lineNumberStateForScreenRow(presenter, 11).foldable).toBe false - describe ".height", -> it "tracks the computed content height if ::autoHeight is true so the editor auto-expands vertically", -> presenter = buildPresenter(explicitHeight: null, autoHeight: true) @@ -2180,6 +1829,356 @@ describe "TextEditorPresenter", -> gutter.destroy() expect(getStateForGutterWithName(presenter, 'test-gutter')).toBeUndefined() + describe "for a gutter description that corresponds to the line-number gutter", -> + getLineNumberGutterState = (presenter) -> + gutterDescriptions = presenter.getState().gutters + for description in gutterDescriptions + gutter = description.gutter + return description if gutter.name is 'line-number' + + describe ".visible", -> + it "is true iff the editor isn't mini, ::isLineNumberGutterVisible is true on the editor, and the 'editor.showLineNumbers' config is enabled", -> + presenter = buildPresenter() + + expect(editor.isLineNumberGutterVisible()).toBe true + expect(getLineNumberGutterState(presenter).visible).toBe true + + expectStateUpdate presenter, -> editor.setMini(true) + expect(getLineNumberGutterState(presenter)).toBeUndefined() + + expectStateUpdate presenter, -> editor.setMini(false) + expect(getLineNumberGutterState(presenter).visible).toBe true + + expectStateUpdate presenter, -> editor.setLineNumberGutterVisible(false) + expect(getLineNumberGutterState(presenter).visible).toBe false + + expectStateUpdate presenter, -> editor.setLineNumberGutterVisible(true) + expect(getLineNumberGutterState(presenter).visible).toBe true + + expectStateUpdate presenter, -> atom.config.set('editor.showLineNumbers', false) + expect(getLineNumberGutterState(presenter).visible).toBe false + + it "gets updated when the editor's grammar changes", -> + presenter = buildPresenter() + + atom.config.set('editor.showLineNumbers', false, scopeSelector: '.source.js') + expect(getLineNumberGutterState(presenter).visible).toBe true + stateUpdated = false + presenter.onDidUpdateState -> stateUpdated = true + + waitsForPromise -> atom.packages.activatePackage('language-javascript') + + runs -> + expect(stateUpdated).toBe true + expect(getLineNumberGutterState(presenter).visible).toBe false + + describe ".content.maxLineNumberDigits", -> + it "is set to the number of digits used by the greatest line number", -> + presenter = buildPresenter() + expect(editor.getLastBufferRow()).toBe 12 + expect(getLineNumberGutterState(presenter).content.maxLineNumberDigits).toBe 2 + + editor.setText("1\n2\n3") + expect(getLineNumberGutterState(presenter).content.maxLineNumberDigits).toBe 1 + + describe ".content.lineNumbers", -> + lineNumberStateForScreenRow = (presenter, screenRow) -> + editor = presenter.model + bufferRow = editor.bufferRowForScreenRow(screenRow) + wrapCount = screenRow - editor.screenRowForBufferRow(bufferRow) + if wrapCount > 0 + key = bufferRow + '-' + wrapCount + else + key = bufferRow + + getLineNumberGutterState(presenter).content.lineNumbers[key] + + it "contains states for line numbers that are visible on screen, plus and minus the overdraw margin", -> + editor.foldBufferRow(4) + editor.setSoftWrapped(true) + editor.setEditorWidthInChars(50) + presenter = buildPresenter(explicitHeight: 25, scrollTop: 30, lineHeight: 10, lineOverdrawMargin: 1) + + expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() + expectValues lineNumberStateForScreenRow(presenter, 2), {screenRow: 2, bufferRow: 2, softWrapped: false, top: 2 * 10} + expectValues lineNumberStateForScreenRow(presenter, 3), {screenRow: 3, bufferRow: 3, softWrapped: false, top: 3 * 10} + expectValues lineNumberStateForScreenRow(presenter, 4), {screenRow: 4, bufferRow: 3, softWrapped: true, top: 4 * 10} + expectValues lineNumberStateForScreenRow(presenter, 5), {screenRow: 5, bufferRow: 4, softWrapped: false, top: 5 * 10} + expectValues lineNumberStateForScreenRow(presenter, 6), {screenRow: 6, bufferRow: 7, softWrapped: false, top: 6 * 10} + expectValues lineNumberStateForScreenRow(presenter, 7), {screenRow: 7, bufferRow: 8, softWrapped: false, top: 7 * 10} + expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() + + it "includes states for all line numbers if no ::explicitHeight is assigned", -> + presenter = buildPresenter(explicitHeight: null) + expect(lineNumberStateForScreenRow(presenter, 0)).toBeDefined() + expect(lineNumberStateForScreenRow(presenter, 12)).toBeDefined() + + it "updates when ::scrollTop changes", -> + editor.foldBufferRow(4) + editor.setSoftWrapped(true) + editor.setEditorWidthInChars(50) + presenter = buildPresenter(explicitHeight: 25, scrollTop: 30, lineOverdrawMargin: 1) + + expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() + expectValues lineNumberStateForScreenRow(presenter, 2), {bufferRow: 2} + expectValues lineNumberStateForScreenRow(presenter, 7), {bufferRow: 8} + expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() + + expectStateUpdate presenter, -> presenter.setScrollTop(20) + + expect(lineNumberStateForScreenRow(presenter, 0)).toBeUndefined() + expectValues lineNumberStateForScreenRow(presenter, 1), {bufferRow: 1} + expectValues lineNumberStateForScreenRow(presenter, 6), {bufferRow: 7} + expect(lineNumberStateForScreenRow(presenter, 7)).toBeUndefined() + + it "updates when ::explicitHeight changes", -> + editor.foldBufferRow(4) + editor.setSoftWrapped(true) + editor.setEditorWidthInChars(50) + presenter = buildPresenter(explicitHeight: 25, scrollTop: 30, lineOverdrawMargin: 1) + + expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() + expectValues lineNumberStateForScreenRow(presenter, 2), {bufferRow: 2} + expectValues lineNumberStateForScreenRow(presenter, 7), {bufferRow: 8} + expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() + + expectStateUpdate presenter, -> presenter.setExplicitHeight(35) + + expect(lineNumberStateForScreenRow(presenter, 0)).toBeUndefined() + expectValues lineNumberStateForScreenRow(presenter, 2), {bufferRow: 2} + expectValues lineNumberStateForScreenRow(presenter, 8), {bufferRow: 8} + expect(lineNumberStateForScreenRow(presenter, 9)).toBeUndefined() + + it "updates when ::lineHeight changes", -> + editor.foldBufferRow(4) + editor.setSoftWrapped(true) + editor.setEditorWidthInChars(50) + presenter = buildPresenter(explicitHeight: 25, scrollTop: 0, lineOverdrawMargin: 0) + + expectValues lineNumberStateForScreenRow(presenter, 0), {bufferRow: 0} + expectValues lineNumberStateForScreenRow(presenter, 3), {bufferRow: 3} + expect(lineNumberStateForScreenRow(presenter, 4)).toBeUndefined() + + expectStateUpdate presenter, -> presenter.setLineHeight(5) + + expectValues lineNumberStateForScreenRow(presenter, 0), {bufferRow: 0} + expectValues lineNumberStateForScreenRow(presenter, 5), {bufferRow: 4} + expect(lineNumberStateForScreenRow(presenter, 6)).toBeUndefined() + + it "updates when the editor's content changes", -> + editor.foldBufferRow(4) + editor.setSoftWrapped(true) + editor.setEditorWidthInChars(50) + presenter = buildPresenter(explicitHeight: 35, scrollTop: 30, lineOverdrawMargin: 0) + + expect(lineNumberStateForScreenRow(presenter, 2)).toBeUndefined() + expectValues lineNumberStateForScreenRow(presenter, 3), {bufferRow: 3} + expectValues lineNumberStateForScreenRow(presenter, 4), {bufferRow: 3} + expectValues lineNumberStateForScreenRow(presenter, 5), {bufferRow: 4} + expectValues lineNumberStateForScreenRow(presenter, 6), {bufferRow: 7} + expectValues lineNumberStateForScreenRow(presenter, 7), {bufferRow: 8} + expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() + + expectStateUpdate presenter, -> + editor.getBuffer().insert([3, Infinity], new Array(25).join("x ")) + + expect(lineNumberStateForScreenRow(presenter, 2)).toBeUndefined() + expectValues lineNumberStateForScreenRow(presenter, 3), {bufferRow: 3} + expectValues lineNumberStateForScreenRow(presenter, 4), {bufferRow: 3} + expectValues lineNumberStateForScreenRow(presenter, 5), {bufferRow: 3} + expectValues lineNumberStateForScreenRow(presenter, 6), {bufferRow: 4} + expectValues lineNumberStateForScreenRow(presenter, 7), {bufferRow: 7} + expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() + + it "does not remove out-of-view line numbers corresponding to ::mouseWheelScreenRow until ::stoppedScrollingDelay elapses", -> + presenter = buildPresenter(explicitHeight: 25, lineOverdrawMargin: 1, stoppedScrollingDelay: 200) + + expect(lineNumberStateForScreenRow(presenter, 0)).toBeDefined() + expect(lineNumberStateForScreenRow(presenter, 4)).toBeDefined() + expect(lineNumberStateForScreenRow(presenter, 5)).toBeUndefined() + + presenter.setMouseWheelScreenRow(0) + expectStateUpdate presenter, -> presenter.setScrollTop(35) + + expect(lineNumberStateForScreenRow(presenter, 0)).toBeDefined() + expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() + expect(lineNumberStateForScreenRow(presenter, 7)).toBeDefined() + expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() + + expectStateUpdate presenter, -> advanceClock(200) + + expect(lineNumberStateForScreenRow(presenter, 0)).toBeUndefined() + expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() + expect(lineNumberStateForScreenRow(presenter, 7)).toBeDefined() + expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() + + it "correctly handles the first screen line being soft-wrapped", -> + editor.setSoftWrapped(true) + editor.setEditorWidthInChars(30) + presenter = buildPresenter(explicitHeight: 25, scrollTop: 50) + + expectValues lineNumberStateForScreenRow(presenter, 5), {screenRow: 5, bufferRow: 3, softWrapped: true} + expectValues lineNumberStateForScreenRow(presenter, 6), {screenRow: 6, bufferRow: 3, softWrapped: true} + expectValues lineNumberStateForScreenRow(presenter, 7), {screenRow: 7, bufferRow: 4, softWrapped: false} + + describe ".decorationClasses", -> + it "adds decoration classes to the relevant line number state objects, both initially and when decorations change", -> + marker1 = editor.markBufferRange([[4, 0], [6, 2]], invalidate: 'touch') + decoration1 = editor.decorateMarker(marker1, type: 'line-number', class: 'a') + presenter = buildPresenter() + marker2 = editor.markBufferRange([[4, 0], [6, 2]], invalidate: 'touch') + decoration2 = editor.decorateMarker(marker2, type: 'line-number', class: 'b') + + expect(lineNumberStateForScreenRow(presenter, 3).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toEqual ['a', 'b'] + expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toEqual ['a', 'b'] + expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['a', 'b'] + expect(lineNumberStateForScreenRow(presenter, 7).decorationClasses).toBeNull() + + expectStateUpdate presenter, -> editor.getBuffer().insert([5, 0], 'x') + expect(marker1.isValid()).toBe false + expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toBeNull() + + expectStateUpdate presenter, -> editor.undo() + expect(lineNumberStateForScreenRow(presenter, 3).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toEqual ['a', 'b'] + expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toEqual ['a', 'b'] + expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['a', 'b'] + expect(lineNumberStateForScreenRow(presenter, 7).decorationClasses).toBeNull() + + expectStateUpdate presenter, -> marker1.setBufferRange([[2, 0], [4, 2]]) + expect(lineNumberStateForScreenRow(presenter, 1).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 2).decorationClasses).toEqual ['a'] + expect(lineNumberStateForScreenRow(presenter, 3).decorationClasses).toEqual ['a'] + expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toEqual ['a', 'b'] + expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toEqual ['b'] + expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['b'] + expect(lineNumberStateForScreenRow(presenter, 7).decorationClasses).toBeNull() + + expectStateUpdate presenter, -> decoration1.destroy() + expect(lineNumberStateForScreenRow(presenter, 2).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 3).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toEqual ['b'] + expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toEqual ['b'] + expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['b'] + expect(lineNumberStateForScreenRow(presenter, 7).decorationClasses).toBeNull() + + expectStateUpdate presenter, -> marker2.destroy() + expect(lineNumberStateForScreenRow(presenter, 2).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 3).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 7).decorationClasses).toBeNull() + + it "honors the 'onlyEmpty' option on line-number decorations", -> + presenter = buildPresenter() + marker = editor.markBufferRange([[4, 0], [6, 1]]) + decoration = editor.decorateMarker(marker, type: 'line-number', class: 'a', onlyEmpty: true) + + expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toBeNull() + + expectStateUpdate presenter, -> marker.clearTail() + + expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['a'] + + it "honors the 'onlyNonEmpty' option on line-number decorations", -> + presenter = buildPresenter() + marker = editor.markBufferRange([[4, 0], [6, 2]]) + decoration = editor.decorateMarker(marker, type: 'line-number', class: 'a', onlyNonEmpty: true) + + expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toEqual ['a'] + expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toEqual ['a'] + expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['a'] + + expectStateUpdate presenter, -> marker.clearTail() + + expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toBeNull() + + it "honors the 'onlyHead' option on line-number decorations", -> + presenter = buildPresenter() + marker = editor.markBufferRange([[4, 0], [6, 2]]) + decoration = editor.decorateMarker(marker, type: 'line-number', class: 'a', onlyHead: true) + + expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['a'] + + it "does not decorate the last line of a non-empty line-number decoration range if it ends at column 0", -> + presenter = buildPresenter() + marker = editor.markBufferRange([[4, 0], [6, 0]]) + decoration = editor.decorateMarker(marker, type: 'line-number', class: 'a') + + expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toEqual ['a'] + expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toEqual ['a'] + expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toBeNull() + + it "does not apply line-number decorations to mini editors", -> + editor.setMini(true) + presenter = buildPresenter() + marker = editor.markBufferRange([[0, 0], [0, 0]]) + decoration = editor.decorateMarker(marker, type: 'line-number', class: 'a') + # A mini editor will have no gutters. + expect(getLineNumberGutterState(presenter)).toBeUndefined() + + expectStateUpdate presenter, -> editor.setMini(false) + expect(lineNumberStateForScreenRow(presenter, 0).decorationClasses).toEqual ['cursor-line', 'cursor-line-no-selection', 'a'] + + expectStateUpdate presenter, -> editor.setMini(true) + expect(getLineNumberGutterState(presenter)).toBeUndefined() + + it "only applies line-number decorations to screen rows that are spanned by their marker when lines are soft-wrapped", -> + editor.setText("a line that wraps, ok") + editor.setSoftWrapped(true) + editor.setEditorWidthInChars(16) + marker = editor.markBufferRange([[0, 0], [0, 2]]) + editor.decorateMarker(marker, type: 'line-number', class: 'a') + presenter = buildPresenter(explicitHeight: 10) + + expect(lineNumberStateForScreenRow(presenter, 0).decorationClasses).toContain 'a' + expect(lineNumberStateForScreenRow(presenter, 1).decorationClasses).toBeNull() + + marker.setBufferRange([[0, 0], [0, Infinity]]) + expect(lineNumberStateForScreenRow(presenter, 0).decorationClasses).toContain 'a' + expect(lineNumberStateForScreenRow(presenter, 1).decorationClasses).toContain 'a' + + describe ".foldable", -> + it "marks line numbers at the start of a foldable region as foldable", -> + presenter = buildPresenter() + expect(lineNumberStateForScreenRow(presenter, 0).foldable).toBe true + expect(lineNumberStateForScreenRow(presenter, 1).foldable).toBe true + expect(lineNumberStateForScreenRow(presenter, 2).foldable).toBe false + expect(lineNumberStateForScreenRow(presenter, 3).foldable).toBe false + expect(lineNumberStateForScreenRow(presenter, 4).foldable).toBe true + expect(lineNumberStateForScreenRow(presenter, 5).foldable).toBe false + + it "updates the foldable class on the correct line numbers when the foldable positions change", -> + presenter = buildPresenter() + editor.getBuffer().insert([0, 0], '\n') + expect(lineNumberStateForScreenRow(presenter, 0).foldable).toBe false + expect(lineNumberStateForScreenRow(presenter, 1).foldable).toBe true + expect(lineNumberStateForScreenRow(presenter, 2).foldable).toBe true + expect(lineNumberStateForScreenRow(presenter, 3).foldable).toBe false + expect(lineNumberStateForScreenRow(presenter, 4).foldable).toBe false + expect(lineNumberStateForScreenRow(presenter, 5).foldable).toBe true + expect(lineNumberStateForScreenRow(presenter, 6).foldable).toBe false + + it "updates the foldable class on a line number that becomes foldable", -> + presenter = buildPresenter() + expect(lineNumberStateForScreenRow(presenter, 11).foldable).toBe false + + editor.getBuffer().insert([11, 44], '\n fold me') + expect(lineNumberStateForScreenRow(presenter, 11).foldable).toBe true + + editor.undo() + expect(lineNumberStateForScreenRow(presenter, 11).foldable).toBe false + describe "for a gutter description that corresponds to a custom gutter", -> describe ".content", -> getContentForGutterWithName = (presenter, gutterName) -> From fe2cfff7a67c7e5a800d7fd2467ba28621bdce9c Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 13 May 2015 17:00:30 -0700 Subject: [PATCH 1210/1783] Allocate fewer objects for fold attributes in DisplayBuffer --- src/display-buffer.coffee | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index f4c078b17..37120dd83 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -42,6 +42,7 @@ class DisplayBuffer extends Model @disposables.add @buffer.onDidUpdateMarkers @handleBufferMarkersUpdated @disposables.add @buffer.onDidCreateMarker @handleBufferMarkerCreated @updateAllScreenLines() + @foldMarkerAttributes = Object.freeze({class: 'fold', displayBufferId: @id}) @createFoldForMarker(marker) for marker in @buffer.findMarkers(@getFoldMarkerAttributes()) subscribeToScopedConfigSettings: => @@ -1075,8 +1076,11 @@ class DisplayBuffer extends Model findFoldMarkers: (attributes) -> @buffer.findMarkers(@getFoldMarkerAttributes(attributes)) - getFoldMarkerAttributes: (attributes={}) -> - _.extend(attributes, class: 'fold', displayBufferId: @id) + getFoldMarkerAttributes: (attributes) -> + if attributes + _.extend(attributes, @foldMarkerAttributes) + else + @foldMarkerAttributes pauseMarkerChangeEvents: -> marker.pauseChangeEvents() for marker in @getMarkers() From e73f47dfa30ede157c29605a798cc2a7f87e8b47 Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 14 May 2015 10:09:30 +0900 Subject: [PATCH 1211/1783] :arrow_up: status-bar@0.72.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5cfd5b6d0..3c2bf1c69 100644 --- a/package.json +++ b/package.json @@ -118,7 +118,7 @@ "settings-view": "0.199.0", "snippets": "0.89.0", "spell-check": "0.58.0", - "status-bar": "0.71.0", + "status-bar": "0.72.0", "styleguide": "0.44.0", "symbols-view": "0.96.0", "tabs": "0.68.0", From 80d41c70ee355b472ba1ef3202ffd5d4c4469f2f Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 13 May 2015 18:15:46 -0700 Subject: [PATCH 1212/1783] :arrow_up: metrics@0.46.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3c2bf1c69..33a6811cc 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "keybinding-resolver": "0.32.0", "link": "0.30.0", "markdown-preview": "0.148.0", - "metrics": "0.45.0", + "metrics": "0.46.0", "notifications": "0.43.0", "open-on-github": "0.36.0", "package-generator": "0.39.0", From 0a0c42850b64124a077d3258ead6eade9e878272 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 13 May 2015 18:18:57 -0700 Subject: [PATCH 1213/1783] :arrow_up: autocomplete-plus@2.15.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 33a6811cc..c2bdb47f5 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,7 @@ "autocomplete-css": "0.7.2", "autocomplete-emojis": "2.2.2", "autocomplete-html": "0.7.2", - "autocomplete-plus": "2.15.1", + "autocomplete-plus": "2.15.2", "autocomplete-snippets": "1.6.1", "autoflow": "0.23.0", "autosave": "0.20.0", From 19d905606b8572397c22e9ec8aa3194d3f9fdf67 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 13 May 2015 19:59:25 -0700 Subject: [PATCH 1214/1783] Avoid double computation of screen lines when opening files Previously, instantiating a TextEditor would always compute compute screen lines twice: once when the DisplayBuffer was instantiated, and once when the 'invisibles' property was set on the DisplayBuffer. --- spec/text-editor-spec.coffee | 10 +++---- spec/tokenized-buffer-spec.coffee | 13 +++++---- src/display-buffer.coffee | 11 ++++---- src/text-editor.coffee | 29 ++----------------- src/tokenized-buffer.coffee | 47 +++++++++++++++++++++++-------- 5 files changed, 54 insertions(+), 56 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index dd6b69f26..d1d311088 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -36,23 +36,21 @@ describe "TextEditor", -> it "preserves the invisibles setting", -> atom.config.set('editor.showInvisibles', true) - previousInvisibles = editor.displayBuffer.invisibles + previousInvisibles = editor.tokenizedLineForScreenRow(0).invisibles editor2 = editor.testSerialization() - expect(editor2.displayBuffer.invisibles).toEqual previousInvisibles - expect(editor2.displayBuffer.tokenizedBuffer.invisibles).toEqual previousInvisibles + expect(previousInvisibles).toBeDefined() + expect(editor2.displayBuffer.tokenizedLineForScreenRow(0).invisibles).toEqual previousInvisibles it "updates invisibles if the settings have changed between serialization and deserialization", -> atom.config.set('editor.showInvisibles', true) - previousInvisibles = editor.displayBuffer.invisibles state = editor.serialize() atom.config.set('editor.invisibles', eol: '?') editor2 = TextEditor.deserialize(state) - expect(editor2.displayBuffer.invisibles.eol).toBe '?' - expect(editor2.displayBuffer.tokenizedBuffer.invisibles.eol).toBe '?' + expect(editor.tokenizedLineForScreenRow(0).invisibles.eol).toBe '?' describe "when the editor is constructed with an initialLine option", -> it "positions the cursor on the specified line", -> diff --git a/spec/tokenized-buffer-spec.coffee b/spec/tokenized-buffer-spec.coffee index 3cd776c2b..9d92335af 100644 --- a/spec/tokenized-buffer-spec.coffee +++ b/spec/tokenized-buffer-spec.coffee @@ -611,7 +611,8 @@ describe "TokenizedBuffer", -> tokenizedBuffer = new TokenizedBuffer({buffer}) fullyTokenize(tokenizedBuffer) - tokenizedBuffer.setInvisibles(space: 'S', tab: 'T') + atom.config.set("editor.showInvisibles", true) + atom.config.set("editor.invisibles", space: 'S', tab: 'T') fullyTokenize(tokenizedBuffer) expect(tokenizedBuffer.tokenizedLineForRow(0).text).toBe "SST Sa line with tabsTand T spacesSTS" @@ -623,7 +624,7 @@ describe "TokenizedBuffer", -> tokenizedBuffer = new TokenizedBuffer({buffer}) atom.config.set('editor.showInvisibles', true) - tokenizedBuffer.setInvisibles(cr: 'R', eol: 'N') + atom.config.set("editor.invisibles", cr: 'R', eol: 'N') fullyTokenize(tokenizedBuffer) expect(tokenizedBuffer.tokenizedLineForRow(0).endOfLineInvisibles).toEqual ['R', 'N'] @@ -634,7 +635,7 @@ describe "TokenizedBuffer", -> expect(left.endOfLineInvisibles).toBe null expect(right.endOfLineInvisibles).toEqual ['R', 'N'] - tokenizedBuffer.setInvisibles(cr: 'R', eol: false) + atom.config.set("editor.invisibles", cr: 'R', eol: false) expect(tokenizedBuffer.tokenizedLineForRow(0).endOfLineInvisibles).toEqual ['R'] expect(tokenizedBuffer.tokenizedLineForRow(1).endOfLineInvisibles).toEqual [] @@ -688,7 +689,8 @@ describe "TokenizedBuffer", -> it "sets leading and trailing whitespace correctly on a line with invisible characters that is copied", -> buffer.setText(" \t a line with tabs\tand \tspaces \t ") - tokenizedBuffer.setInvisibles(space: 'S', tab: 'T') + atom.config.set("editor.showInvisibles", true) + atom.config.set("editor.invisibles", space: 'S', tab: 'T') fullyTokenize(tokenizedBuffer) line = tokenizedBuffer.tokenizedLineForRow(0).copy() @@ -696,7 +698,8 @@ describe "TokenizedBuffer", -> expect(line.tokens[line.tokens.length - 1].firstTrailingWhitespaceIndex).toBe 0 it "sets the ::firstNonWhitespaceIndex and ::firstTrailingWhitespaceIndex correctly when tokens are split for soft-wrapping", -> - tokenizedBuffer.setInvisibles(space: 'S') + atom.config.set("editor.showInvisibles", true) + atom.config.set("editor.invisibles", space: 'S') buffer.setText(" token ") fullyTokenize(tokenizedBuffer) token = tokenizedBuffer.tokenizedLines[0].tokens[0] diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index 37120dd83..d5a893fe3 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -24,13 +24,13 @@ class DisplayBuffer extends Model horizontalScrollMargin: 6 scopedCharacterWidthsChangeCount: 0 - constructor: ({tabLength, @editorWidthInChars, @tokenizedBuffer, buffer, @invisibles}={}) -> + constructor: ({tabLength, @editorWidthInChars, @tokenizedBuffer, buffer, ignoreInvisibles}={}) -> super @emitter = new Emitter @disposables = new CompositeDisposable - @tokenizedBuffer ?= new TokenizedBuffer({tabLength, buffer, @invisibles}) + @tokenizedBuffer ?= new TokenizedBuffer({tabLength, buffer, ignoreInvisibles}) @buffer = @tokenizedBuffer.buffer @charWidthsByScope = {} @markers = {} @@ -87,14 +87,13 @@ class DisplayBuffer extends Model scrollTop: @scrollTop scrollLeft: @scrollLeft tokenizedBuffer: @tokenizedBuffer.serialize() - invisibles: _.clone(@invisibles) deserializeParams: (params) -> params.tokenizedBuffer = TokenizedBuffer.deserialize(params.tokenizedBuffer) params copy: -> - newDisplayBuffer = new DisplayBuffer({@buffer, tabLength: @getTabLength(), @invisibles}) + newDisplayBuffer = new DisplayBuffer({@buffer, tabLength: @getTabLength()}) newDisplayBuffer.setScrollTop(@getScrollTop()) newDisplayBuffer.setScrollLeft(@getScrollLeft()) @@ -429,8 +428,8 @@ class DisplayBuffer extends Model setTabLength: (tabLength) -> @tokenizedBuffer.setTabLength(tabLength) - setInvisibles: (@invisibles) -> - @tokenizedBuffer.setInvisibles(@invisibles) + setIgnoreInvisibles: (ignoreInvisibles) -> + @tokenizedBuffer.setIgnoreInvisibles(ignoreInvisibles) setSoftWrapped: (softWrapped) -> if softWrapped isnt @softWrapped diff --git a/src/text-editor.coffee b/src/text-editor.coffee index ac7c7d4f2..d2bd77522 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -84,12 +84,10 @@ class TextEditor extends Model @selections = [] buffer ?= new TextBuffer - @displayBuffer ?= new DisplayBuffer({buffer, tabLength, softWrapped}) + @displayBuffer ?= new DisplayBuffer({buffer, tabLength, softWrapped, ignoreInvisibles: @mini}) @buffer = @displayBuffer.buffer @softTabs = @usesSoftTabs() ? @softTabs ? atom.config.get('editor.softTabs') ? true - @updateInvisibles() - for marker in @findMarkers(@getSelectionMarkerAttributes()) marker.setProperties(preserveFolds: true) @addSelection(marker) @@ -170,21 +168,9 @@ class TextEditor extends Model @subscribe @displayBuffer.onDidAddDecoration (decoration) => @emit 'decoration-added', decoration @subscribe @displayBuffer.onDidRemoveDecoration (decoration) => @emit 'decoration-removed', decoration - @subscribeToScopedConfigSettings() - - subscribeToScopedConfigSettings: -> - @scopedConfigSubscriptions?.dispose() - @scopedConfigSubscriptions = subscriptions = new CompositeDisposable - - scopeDescriptor = @getRootScopeDescriptor() - - subscriptions.add atom.config.onDidChange 'editor.showInvisibles', scope: scopeDescriptor, => @updateInvisibles() - subscriptions.add atom.config.onDidChange 'editor.invisibles', scope: scopeDescriptor, => @updateInvisibles() - destroyed: -> @unsubscribe() if includeDeprecatedAPIs @disposables.dispose() - @scopedConfigSubscriptions.dispose() selection.destroy() for selection in @getSelections() @buffer.release() @displayBuffer.destroy() @@ -488,7 +474,7 @@ class TextEditor extends Model setMini: (mini) -> if mini isnt @mini @mini = mini - @updateInvisibles() + @displayBuffer.setIgnoreInvisibles(@mini) @emitter.emit 'did-change-mini', @mini @mini @@ -2779,15 +2765,6 @@ class TextEditor extends Model shouldAutoIndentOnPaste: -> atom.config.get("editor.autoIndentOnPaste", scope: @getRootScopeDescriptor()) - shouldShowInvisibles: -> - not @mini and atom.config.get('editor.showInvisibles', scope: @getRootScopeDescriptor()) - - updateInvisibles: -> - if @shouldShowInvisibles() - @displayBuffer.setInvisibles(atom.config.get('editor.invisibles', scope: @getRootScopeDescriptor())) - else - @displayBuffer.setInvisibles(null) - ### Section: Event Handlers ### @@ -2796,8 +2773,6 @@ class TextEditor extends Model @softTabs = @usesSoftTabs() ? @softTabs handleGrammarChange: -> - @updateInvisibles() - @subscribeToScopedConfigSettings() @unfoldAll() @emit 'grammar-changed' if includeDeprecatedAPIs @emitter.emit 'did-change-grammar', @getGrammar() diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index d9f1bcba7..b72e712a1 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -20,8 +20,9 @@ class TokenizedBuffer extends Model chunkSize: 50 invalidRows: null visible: false + configSettings: null - constructor: ({@buffer, @tabLength, @invisibles}) -> + constructor: ({@buffer, @tabLength, @ignoreInvisibles}) -> @emitter = new Emitter @disposables = new CompositeDisposable @@ -39,7 +40,7 @@ class TokenizedBuffer extends Model serializeParams: -> bufferPath: @buffer.getPath() tabLength: @tabLength - invisibles: _.clone(@invisibles) + ignoreInvisibles: @ignoreInvisibles deserializeParams: (params) -> params.buffer = atom.project.bufferForPathSync(params.bufferPath) @@ -76,13 +77,28 @@ class TokenizedBuffer extends Model @grammarUpdateDisposable = @grammar.onDidUpdate => @retokenizeLines() @disposables.add(@grammarUpdateDisposable) - @configSettings = tabLength: atom.config.get('editor.tabLength', scope: @rootScopeDescriptor) + scopeOptions = {scope: @rootScopeDescriptor} + @configSettings = + tabLength: atom.config.get('editor.tabLength', scopeOptions) + invisibles: atom.config.get('editor.invisibles', scopeOptions) + showInvisibles: atom.config.get('editor.showInvisibles', scopeOptions) - @grammarTabLengthSubscription?.dispose() - @grammarTabLengthSubscription = atom.config.onDidChange 'editor.tabLength', scope: @rootScopeDescriptor, ({newValue}) => + if @configSubscriptions? + @configSubscriptions.dispose() + @disposables.remove(@configSubscriptions) + @configSubscriptions = new CompositeDisposable + @configSubscriptions.add atom.config.onDidChange 'editor.tabLength', scopeOptions, ({newValue}) => @configSettings.tabLength = newValue @retokenizeLines() - @disposables.add(@grammarTabLengthSubscription) + @configSubscriptions.add atom.config.onDidChange 'editor.invisibles', scopeOptions, ({newValue}) => + oldInvisibles = @getInvisiblesToShow() + @configSettings.invisibles = newValue + @retokenizeLines() unless _.isEqual(@getInvisiblesToShow(), oldInvisibles) + @configSubscriptions.add atom.config.onDidChange 'editor.showInvisibles', scopeOptions, ({newValue}) => + oldInvisibles = @getInvisiblesToShow() + @configSettings.showInvisibles = newValue + @retokenizeLines() unless _.isEqual(@getInvisiblesToShow(), oldInvisibles) + @disposables.add(@configSubscriptions) @retokenizeLines() @@ -123,10 +139,11 @@ class TokenizedBuffer extends Model @tabLength = tabLength @retokenizeLines() - setInvisibles: (invisibles) -> - unless _.isEqual(invisibles, @invisibles) - @invisibles = invisibles - @retokenizeLines() + setIgnoreInvisibles: (ignoreInvisibles) -> + if ignoreInvisibles isnt @ignoreInvisibles + @ignoreInvisibles = ignoreInvisibles + if @configSettings.showInvisibles and @configSettings.invisibles? + @retokenizeLines() tokenizeInBackground: -> return if not @visible or @pendingChunk or not @isAlive() @@ -302,7 +319,7 @@ class TokenizedBuffer extends Model tabLength = @getTabLength() indentLevel = @indentLevelForRow(row) lineEnding = @buffer.lineEndingForRow(row) - new TokenizedLine({tokens, tabLength, indentLevel, @invisibles, lineEnding}) + new TokenizedLine({tokens, tabLength, indentLevel, invisibles: @getInvisiblesToShow(), lineEnding}) buildTokenizedLineForRow: (row, ruleStack) -> @buildTokenizedLineForRowWithText(row, @buffer.lineForRow(row), ruleStack) @@ -312,7 +329,13 @@ class TokenizedBuffer extends Model tabLength = @getTabLength() indentLevel = @indentLevelForRow(row) {tokens, ruleStack} = @grammar.tokenizeLine(line, ruleStack, row is 0) - new TokenizedLine({tokens, ruleStack, tabLength, lineEnding, indentLevel, @invisibles}) + new TokenizedLine({tokens, ruleStack, tabLength, lineEnding, indentLevel, invisibles: @getInvisiblesToShow()}) + + getInvisiblesToShow: -> + if @configSettings.showInvisibles and not @ignoreInvisibles + @configSettings.invisibles + else + null tokenizedLineForRow: (bufferRow) -> @tokenizedLines[bufferRow] From 31c1ac412b4343b33ffc15befd374a8e8ae76edf Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 13 May 2015 21:23:20 -0700 Subject: [PATCH 1215/1783] :art: remove duplication in TokenizedBuffer::setGrammar --- src/tokenized-buffer.coffee | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index b72e712a1..6d8f0c018 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -90,14 +90,11 @@ class TokenizedBuffer extends Model @configSubscriptions.add atom.config.onDidChange 'editor.tabLength', scopeOptions, ({newValue}) => @configSettings.tabLength = newValue @retokenizeLines() - @configSubscriptions.add atom.config.onDidChange 'editor.invisibles', scopeOptions, ({newValue}) => - oldInvisibles = @getInvisiblesToShow() - @configSettings.invisibles = newValue - @retokenizeLines() unless _.isEqual(@getInvisiblesToShow(), oldInvisibles) - @configSubscriptions.add atom.config.onDidChange 'editor.showInvisibles', scopeOptions, ({newValue}) => - oldInvisibles = @getInvisiblesToShow() - @configSettings.showInvisibles = newValue - @retokenizeLines() unless _.isEqual(@getInvisiblesToShow(), oldInvisibles) + ['invisibles', 'showInvisibles'].forEach (key) => + @configSubscriptions.add atom.config.onDidChange "editor.#{key}", scopeOptions, ({newValue}) => + oldInvisibles = @getInvisiblesToShow() + @configSettings[key] = newValue + @retokenizeLines() unless _.isEqual(@getInvisiblesToShow(), oldInvisibles) @disposables.add(@configSubscriptions) @retokenizeLines() From 6be88fd645a199e1b68e59e46a549f2371f69160 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 14 May 2015 11:36:20 +0200 Subject: [PATCH 1216/1783] Scroll every single tile left/right --- src/lines-component.coffee | 4 ---- src/text-editor-component.coffee | 5 ++--- src/text-editor-presenter.coffee | 10 ++++++---- src/tile-component.coffee | 5 +++-- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/lines-component.coffee b/src/lines-component.coffee index fda77a76a..c4341bbbf 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -48,10 +48,6 @@ class LinesComponent @domNode.style.height = @newState.scrollHeight + 'px' @oldState.scrollHeight = @newState.scrollHeight - if @newState.scrollLeft isnt @oldState.scrollLeft - @domNode.style['-webkit-transform'] = "translate3d(#{-@newState.scrollLeft}px, 0, 0px)" - @oldState.scrollLeft = @newState.scrollLeft - if @newState.backgroundColor isnt @oldState.backgroundColor @domNode.style.backgroundColor = @newState.backgroundColor @oldState.backgroundColor = @newState.backgroundColor diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index c97fb11a0..ce17243e4 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -764,15 +764,14 @@ class TextEditorComponent screenPositionForMouseEvent: (event) -> pixelPosition = @pixelPositionForMouseEvent(event) - pixelPosition.top += @presenter.scrollTop @editor.screenPositionForPixelPosition(pixelPosition) pixelPositionForMouseEvent: (event) -> {clientX, clientY} = event linesClientRect = @linesComponent.getDomNode().getBoundingClientRect() - top = clientY - linesClientRect.top - left = clientX - linesClientRect.left + top = clientY - linesClientRect.top + @presenter.scrollTop + left = clientX - linesClientRect.left + @presenter.scrollLeft {top, left} getModel: -> diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 6b38f0114..0418fb6c2 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -327,6 +327,7 @@ class TextEditorPresenter isNewTile = not @state.content.tiles.hasOwnProperty(startRow) tile = @state.content.tiles[startRow] ?= {} tile.top = startRow * @lineHeight - @scrollTop + tile.left = -@scrollLeft tile.height = @tileSize * @lineHeight tile.newlyCreated = isNewTile tile.display = "block" @@ -410,10 +411,8 @@ class TextEditorPresenter pixelPosition = @pixelPositionForScreenPosition(screenPosition, true) - {scrollLeft} = @state.content - top = pixelPosition.top + @lineHeight - left = pixelPosition.left + @gutterWidth - scrollLeft + left = pixelPosition.left + @gutterWidth if overlayDimensions = @overlayDimensions[decoration.id] {itemWidth, itemHeight, contentMargin} = overlayDimensions @@ -795,8 +794,10 @@ class TextEditorPresenter @model.setScrollLeft(scrollLeft) @shouldUpdateHorizontalScrollState = true @shouldUpdateHiddenInputState = true - @shouldUpdateCursorsState = true unless oldScrollLeft? + @shouldUpdateCursorsState = true @shouldUpdateOverlaysState = true + @shouldUpdateDecorations = true + @shouldUpdateTilesState = true @emitDidUpdateState() @@ -1034,6 +1035,7 @@ class TextEditorPresenter column += charLength top -= @scrollTop + left -= @scrollLeft {top, left} hasPixelRectRequirements: -> diff --git a/src/tile-component.coffee b/src/tile-component.coffee index 5bd299d79..197a9adce 100644 --- a/src/tile-component.coffee +++ b/src/tile-component.coffee @@ -43,9 +43,10 @@ class TileComponent @domNode.style.height = @newState.tiles[@id].height + 'px' @oldState.tiles[@id]?.height = @newState.tiles[@id].height - if @newState.tiles[@id].top isnt @oldState.tiles[@id]?.top - @domNode.style['-webkit-transform'] = "translate3d(0, #{@newState.tiles[@id].top}px, 0px)" + if (@newState.tiles[@id].top isnt @oldState.tiles[@id]?.top) or (@newState.tiles[@id].left isnt @oldState.tiles[@id]?.left) + @domNode.style['-webkit-transform'] = "translate3d(#{@newState.tiles[@id].left}px, #{@newState.tiles[@id].top}px, 0px)" @oldState.tiles[@id]?.top = @newState.tiles[@id].top + @oldState.tiles[@id]?.left = @newState.tiles[@id].left if @newState.tiles[@id].newlyCreated newLineIds = [] From c4dff15c736022f4129c58feb33b189901ee2a81 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 14 May 2015 14:57:04 +0200 Subject: [PATCH 1217/1783] Add `@scrollLeft` when calculating `@contentWidth` --- src/text-editor-presenter.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 0418fb6c2..1caa666df 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -612,6 +612,7 @@ class TextEditorPresenter oldContentWidth = @contentWidth clip = @model.tokenizedLineForScreenRow(@model.getLongestScreenRow())?.isSoftWrapped() @contentWidth = @pixelPositionForScreenPosition([@model.getLongestScreenRow(), @model.getMaxScreenLineLength()], clip).left + @contentWidth += @scrollLeft @contentWidth += 1 unless @model.isSoftWrapped() # account for cursor width if @contentHeight isnt oldContentHeight From 5b23a002cf6b01f94619153b012f6d926cf7d243 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 14 May 2015 15:18:53 +0200 Subject: [PATCH 1218/1783] :green_heart: Fix position specs --- spec/text-editor-presenter-spec.coffee | 56 +++++++++++++------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 95f941fde..a13cc2dce 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -343,26 +343,26 @@ describe "TextEditorPresenter", -> expectValues presenter.getState().hiddenInput, {top: 3 * 10, left: 6 * 10} expectStateUpdate presenter, -> presenter.setScrollTop(15) - expectValues presenter.getState().hiddenInput, {top: (3 * 10) - 15, left: 6 * 10} + expectValues presenter.getState().hiddenInput, {top: 0, left: 6 * 10} expectStateUpdate presenter, -> presenter.setScrollLeft(35) - expectValues presenter.getState().hiddenInput, {top: (3 * 10) - 15, left: (6 * 10) - 35} + expectValues presenter.getState().hiddenInput, {top: 0, left: 0} expectStateUpdate presenter, -> presenter.setScrollTop(40) - expectValues presenter.getState().hiddenInput, {top: 0, left: (6 * 10) - 35} + expectValues presenter.getState().hiddenInput, {top: 0, left: 0} expectStateUpdate presenter, -> presenter.setScrollLeft(70) expectValues presenter.getState().hiddenInput, {top: 0, left: 0} expectStateUpdate presenter, -> editor.setCursorBufferPosition([11, 43]) - expectValues presenter.getState().hiddenInput, {top: 11 * 10 - editor.getScrollTop(), left: 43 * 10 - editor.getScrollLeft()} + expectValues presenter.getState().hiddenInput, {top: 0, left: 30} newCursor = null expectStateUpdate presenter, -> newCursor = editor.addCursorAtBufferPosition([6, 10]) - expectValues presenter.getState().hiddenInput, {top: (6 * 10) - editor.getScrollTop(), left: (10 * 10) - editor.getScrollLeft()} + expectValues presenter.getState().hiddenInput, {top: 0, left: 20} expectStateUpdate presenter, -> newCursor.destroy() - expectValues presenter.getState().hiddenInput, {top: 50 - 10, left: 300 - 10} + expectValues presenter.getState().hiddenInput, {top: 30, left: 300 - 10} expectStateUpdate presenter, -> presenter.setFocused(false) expectValues presenter.getState().hiddenInput, {top: 0, left: 0} @@ -967,9 +967,9 @@ describe "TextEditorPresenter", -> presenter = buildPresenter(explicitHeight: 30, scrollTop: 20) expect(stateForCursor(presenter, 0)).toBeUndefined() - expect(stateForCursor(presenter, 1)).toEqual {top: 2 * 10, left: 4 * 10, width: 10, height: 10} + expect(stateForCursor(presenter, 1)).toEqual {top: 0, left: 4 * 10, width: 10, height: 10} expect(stateForCursor(presenter, 2)).toBeUndefined() - expect(stateForCursor(presenter, 3)).toEqual {top: 5 * 10, left: 12 * 10, width: 10, height: 10} + expect(stateForCursor(presenter, 3)).toEqual {top: 5 * 10 - 20, left: 12 * 10, width: 10, height: 10} expect(stateForCursor(presenter, 4)).toBeUndefined() it "is empty until all of the required measurements are assigned", -> @@ -1005,8 +1005,8 @@ describe "TextEditorPresenter", -> expect(stateForCursor(presenter, 0)).toBeUndefined() expect(stateForCursor(presenter, 1)).toBeUndefined() expect(stateForCursor(presenter, 2)).toBeUndefined() - expect(stateForCursor(presenter, 3)).toEqual {top: 5 * 10, left: 12 * 10, width: 10, height: 10} - expect(stateForCursor(presenter, 4)).toEqual {top: 8 * 10, left: 4 * 10, width: 10, height: 10} + expect(stateForCursor(presenter, 3)).toEqual {top: 0, left: 12 * 10, width: 10, height: 10} + expect(stateForCursor(presenter, 4)).toEqual {top: 8 * 10 - 50, left: 4 * 10, width: 10, height: 10} it "updates when ::explicitHeight changes", -> editor.setSelectedBufferRanges([ @@ -1020,9 +1020,9 @@ describe "TextEditorPresenter", -> expectStateUpdate presenter, -> presenter.setExplicitHeight(30) expect(stateForCursor(presenter, 0)).toBeUndefined() - expect(stateForCursor(presenter, 1)).toEqual {top: 2 * 10, left: 4 * 10, width: 10, height: 10} + expect(stateForCursor(presenter, 1)).toEqual {top: 0, left: 4 * 10, width: 10, height: 10} expect(stateForCursor(presenter, 2)).toBeUndefined() - expect(stateForCursor(presenter, 3)).toEqual {top: 5 * 10, left: 12 * 10, width: 10, height: 10} + expect(stateForCursor(presenter, 3)).toEqual {top: 5 * 10 - 20, left: 12 * 10, width: 10, height: 10} expect(stateForCursor(presenter, 4)).toBeUndefined() it "updates when ::lineHeight changes", -> @@ -1039,15 +1039,15 @@ describe "TextEditorPresenter", -> expect(stateForCursor(presenter, 0)).toBeUndefined() expect(stateForCursor(presenter, 1)).toBeUndefined() expect(stateForCursor(presenter, 2)).toBeUndefined() - expect(stateForCursor(presenter, 3)).toEqual {top: 5 * 5, left: 12 * 10, width: 10, height: 5} - expect(stateForCursor(presenter, 4)).toEqual {top: 8 * 5, left: 4 * 10, width: 10, height: 5} + expect(stateForCursor(presenter, 3)).toEqual {top: 5, left: 12 * 10, width: 10, height: 5} + expect(stateForCursor(presenter, 4)).toEqual {top: 8 * 5 - 20, left: 4 * 10, width: 10, height: 5} it "updates when ::baseCharacterWidth changes", -> editor.setCursorBufferPosition([2, 4]) presenter = buildPresenter(explicitHeight: 20, scrollTop: 20) expectStateUpdate presenter, -> presenter.setBaseCharacterWidth(20) - expect(stateForCursor(presenter, 0)).toEqual {top: 2 * 10, left: 4 * 20, width: 20, height: 10} + expect(stateForCursor(presenter, 0)).toEqual {top: 0, left: 4 * 20, width: 20, height: 10} it "updates when scoped character widths change", -> waitsForPromise -> @@ -1073,11 +1073,11 @@ describe "TextEditorPresenter", -> # moving into view expect(stateForCursor(presenter, 0)).toBeUndefined() editor.getCursors()[0].setBufferPosition([2, 4]) - expect(stateForCursor(presenter, 0)).toEqual {top: 2 * 10, left: 4 * 10, width: 10, height: 10} + expect(stateForCursor(presenter, 0)).toEqual {top: 0, left: 4 * 10, width: 10, height: 10} # showing expectStateUpdate presenter, -> editor.getSelections()[1].clear() - expect(stateForCursor(presenter, 1)).toEqual {top: 3 * 10, left: 5 * 10, width: 10, height: 10} + expect(stateForCursor(presenter, 1)).toEqual {top: 5, left: 5 * 10, width: 10, height: 10} # hiding expectStateUpdate presenter, -> editor.getSelections()[1].setBufferRange([[3, 4], [3, 5]]) @@ -1089,11 +1089,11 @@ describe "TextEditorPresenter", -> # adding expectStateUpdate presenter, -> editor.addCursorAtBufferPosition([4, 4]) - expect(stateForCursor(presenter, 2)).toEqual {top: 4 * 10, left: 4 * 10, width: 10, height: 10} + expect(stateForCursor(presenter, 2)).toEqual {top: 5, left: 4 * 10, width: 10, height: 10} # moving added cursor expectStateUpdate presenter, -> editor.getCursors()[2].setBufferPosition([4, 6]) - expect(stateForCursor(presenter, 2)).toEqual {top: 4 * 10, left: 6 * 10, width: 10, height: 10} + expect(stateForCursor(presenter, 2)).toEqual {top: 5, left: 6 * 10, width: 10, height: 10} # destroying destroyedCursor = editor.getCursors()[2] @@ -1211,39 +1211,39 @@ describe "TextEditorPresenter", -> expectValues stateForHighlight(presenter, highlight2), { class: 'b' regions: [ - {top: 2 * 10, left: 0 * 10, width: 6 * 10, height: 1 * 10} + {top: 2 * 10 - 20, left: 0 * 10, width: 6 * 10, height: 1 * 10} ] } expectValues stateForHighlight(presenter, highlight3), { class: 'c' regions: [ - {top: 2 * 10, left: 0 * 10, right: 0, height: 1 * 10} - {top: 3 * 10, left: 0 * 10, width: 6 * 10, height: 1 * 10} + {top: 2 * 10 - 20, left: 0 * 10, right: 0, height: 1 * 10} + {top: 3 * 10 - 20, left: 0 * 10, width: 6 * 10, height: 1 * 10} ] } expectValues stateForHighlight(presenter, highlight4), { class: 'd' regions: [ - {top: 2 * 10, left: 6 * 10, right: 0, height: 1 * 10} - {top: 3 * 10, left: 0, right: 0, height: 1 * 10} - {top: 4 * 10, left: 0, width: 6 * 10, height: 1 * 10} + {top: 2 * 10 - 20, left: 6 * 10, right: 0, height: 1 * 10} + {top: 3 * 10 - 20, left: 0, right: 0, height: 1 * 10} + {top: 4 * 10 - 20, left: 0, width: 6 * 10, height: 1 * 10} ] } expectValues stateForHighlight(presenter, highlight5), { class: 'e' regions: [ - {top: 3 * 10, left: 6 * 10, right: 0, height: 1 * 10} - {top: 4 * 10, left: 0 * 10, right: 0, height: 2 * 10} + {top: 3 * 10 - 20, left: 6 * 10, right: 0, height: 1 * 10} + {top: 4 * 10 - 20, left: 0 * 10, right: 0, height: 2 * 10} ] } expectValues stateForHighlight(presenter, highlight6), { class: 'f' regions: [ - {top: 5 * 10, left: 6 * 10, right: 0, height: 1 * 10} + {top: 5 * 10 - 20, left: 6 * 10, right: 0, height: 1 * 10} ] } From e7ddb3d8ad61c3ba34dcc4b15cd38890bacf58db Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 14 May 2015 15:54:09 +0200 Subject: [PATCH 1219/1783] :green_heart: Fix all TextEditorPresenter specs --- spec/text-editor-presenter-spec.coffee | 76 +++++++++++++------------- src/text-editor-component.coffee | 9 ++- src/text-editor-presenter.coffee | 24 ++++---- 3 files changed, 52 insertions(+), 57 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index a13cc2dce..8d5a4c0a8 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -39,7 +39,6 @@ describe "TextEditorPresenter", -> verticalScrollbarWidth: 10 scrollTop: 0 scrollLeft: 0 - lineOverdrawMargin: 0 new TextEditorPresenter(params) @@ -775,14 +774,14 @@ describe "TextEditorPresenter", -> tokens: line3.tokens } - it "does not remove out-of-view tiles corresponding to ::scrollingTileId until ::stoppedScrollingDelay elapses", -> + it "does not remove out-of-view tiles corresponding to ::mouseWheelScreenRow until ::stoppedScrollingDelay elapses", -> presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileCount: 3, stoppedScrollingDelay: 200) expect(presenter.getState().content.tiles[0]).toBeDefined() expect(presenter.getState().content.tiles[6]).toBeDefined() expect(presenter.getState().content.tiles[8]).toBeUndefined() - presenter.setScrollingTileRow(0) + presenter.setMouseWheelScreenRow(0) expectStateUpdate presenter, -> presenter.setScrollTop(4) expect(presenter.getState().content.tiles[0]).toBeDefined() @@ -799,15 +798,15 @@ describe "TextEditorPresenter", -> # should clear ::mouseWheelScreenRow after stoppedScrollingDelay elapses even if we don't scroll first - presenter.setScrollingTileRow(4) + presenter.setMouseWheelScreenRow(4) advanceClock(200) expectStateUpdate presenter, -> presenter.setScrollTop(6) expect(presenter.getState().content.tiles[4]).toBeUndefined() - it "does not preserve deleted on-screen tiles even if they correspond to ::scrollingTileId", -> + it "does not preserve deleted on-screen tiles even if they correspond to ::mouseWheelScreenRow", -> presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileCount: 3, stoppedScrollingDelay: 200) - presenter.setScrollingTileRow(2) + presenter.setMouseWheelScreenRow(2) expectStateUpdate presenter, -> editor.setText("") @@ -1750,20 +1749,19 @@ describe "TextEditorPresenter", -> presenter.getState().gutters.lineNumberGutter.lineNumbers[key] - it "contains states for line numbers that are visible on screen, plus and minus the overdraw margin", -> + it "contains states for line numbers that are visible on screen", -> editor.foldBufferRow(4) editor.setSoftWrapped(true) editor.setEditorWidthInChars(50) - presenter = buildPresenter(explicitHeight: 25, scrollTop: 30, lineHeight: 10, lineOverdrawMargin: 1) + presenter = buildPresenter(explicitHeight: 25, scrollTop: 30, lineHeight: 10) expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() - expectValues lineNumberStateForScreenRow(presenter, 2), {screenRow: 2, bufferRow: 2, softWrapped: false, top: 2 * 10} + expect(lineNumberStateForScreenRow(presenter, 2)).toBeUndefined() expectValues lineNumberStateForScreenRow(presenter, 3), {screenRow: 3, bufferRow: 3, softWrapped: false, top: 3 * 10} expectValues lineNumberStateForScreenRow(presenter, 4), {screenRow: 4, bufferRow: 3, softWrapped: true, top: 4 * 10} expectValues lineNumberStateForScreenRow(presenter, 5), {screenRow: 5, bufferRow: 4, softWrapped: false, top: 5 * 10} expectValues lineNumberStateForScreenRow(presenter, 6), {screenRow: 6, bufferRow: 7, softWrapped: false, top: 6 * 10} - expectValues lineNumberStateForScreenRow(presenter, 7), {screenRow: 7, bufferRow: 8, softWrapped: false, top: 7 * 10} - expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() + expect(lineNumberStateForScreenRow(presenter, 7)).toBeUndefined() it "includes states for all line numbers if no ::explicitHeight is assigned", -> presenter = buildPresenter(explicitHeight: null) @@ -1774,43 +1772,43 @@ describe "TextEditorPresenter", -> editor.foldBufferRow(4) editor.setSoftWrapped(true) editor.setEditorWidthInChars(50) - presenter = buildPresenter(explicitHeight: 25, scrollTop: 30, lineOverdrawMargin: 1) + presenter = buildPresenter(explicitHeight: 25, scrollTop: 30) - expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() - expectValues lineNumberStateForScreenRow(presenter, 2), {bufferRow: 2} - expectValues lineNumberStateForScreenRow(presenter, 7), {bufferRow: 8} - expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() + expect(lineNumberStateForScreenRow(presenter, 2)).toBeUndefined() + expectValues lineNumberStateForScreenRow(presenter, 3), {bufferRow: 3} + expectValues lineNumberStateForScreenRow(presenter, 6), {bufferRow: 7} + expect(lineNumberStateForScreenRow(presenter, 7)).toBeUndefined() expectStateUpdate presenter, -> presenter.setScrollTop(20) - expect(lineNumberStateForScreenRow(presenter, 0)).toBeUndefined() - expectValues lineNumberStateForScreenRow(presenter, 1), {bufferRow: 1} - expectValues lineNumberStateForScreenRow(presenter, 6), {bufferRow: 7} - expect(lineNumberStateForScreenRow(presenter, 7)).toBeUndefined() + expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() + expectValues lineNumberStateForScreenRow(presenter, 2), {bufferRow: 2} + expectValues lineNumberStateForScreenRow(presenter, 5), {bufferRow: 4} + expect(lineNumberStateForScreenRow(presenter, 6)).toBeUndefined() it "updates when ::explicitHeight changes", -> editor.foldBufferRow(4) editor.setSoftWrapped(true) editor.setEditorWidthInChars(50) - presenter = buildPresenter(explicitHeight: 25, scrollTop: 30, lineOverdrawMargin: 1) + presenter = buildPresenter(explicitHeight: 25, scrollTop: 30) - expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() - expectValues lineNumberStateForScreenRow(presenter, 2), {bufferRow: 2} - expectValues lineNumberStateForScreenRow(presenter, 7), {bufferRow: 8} - expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() + expect(lineNumberStateForScreenRow(presenter, 2)).toBeUndefined() + expectValues lineNumberStateForScreenRow(presenter, 3), {bufferRow: 3} + expectValues lineNumberStateForScreenRow(presenter, 6), {bufferRow: 7} + expect(lineNumberStateForScreenRow(presenter, 7)).toBeUndefined() expectStateUpdate presenter, -> presenter.setExplicitHeight(35) - expect(lineNumberStateForScreenRow(presenter, 0)).toBeUndefined() - expectValues lineNumberStateForScreenRow(presenter, 2), {bufferRow: 2} - expectValues lineNumberStateForScreenRow(presenter, 8), {bufferRow: 8} - expect(lineNumberStateForScreenRow(presenter, 9)).toBeUndefined() + expect(lineNumberStateForScreenRow(presenter, 2)).toBeUndefined() + expectValues lineNumberStateForScreenRow(presenter, 3), {bufferRow: 3} + expectValues lineNumberStateForScreenRow(presenter, 7), {bufferRow: 8} + expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() it "updates when ::lineHeight changes", -> editor.foldBufferRow(4) editor.setSoftWrapped(true) editor.setEditorWidthInChars(50) - presenter = buildPresenter(explicitHeight: 25, scrollTop: 0, lineOverdrawMargin: 0) + presenter = buildPresenter(explicitHeight: 25, scrollTop: 0) expectValues lineNumberStateForScreenRow(presenter, 0), {bufferRow: 0} expectValues lineNumberStateForScreenRow(presenter, 3), {bufferRow: 3} @@ -1826,7 +1824,7 @@ describe "TextEditorPresenter", -> editor.foldBufferRow(4) editor.setSoftWrapped(true) editor.setEditorWidthInChars(50) - presenter = buildPresenter(explicitHeight: 35, scrollTop: 30, lineOverdrawMargin: 0) + presenter = buildPresenter(explicitHeight: 35, scrollTop: 30) expect(lineNumberStateForScreenRow(presenter, 2)).toBeUndefined() expectValues lineNumberStateForScreenRow(presenter, 3), {bufferRow: 3} @@ -1848,26 +1846,26 @@ describe "TextEditorPresenter", -> expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() it "does not remove out-of-view line numbers corresponding to ::mouseWheelScreenRow until ::stoppedScrollingDelay elapses", -> - presenter = buildPresenter(explicitHeight: 25, lineOverdrawMargin: 1, stoppedScrollingDelay: 200) + presenter = buildPresenter(explicitHeight: 25, stoppedScrollingDelay: 200) expect(lineNumberStateForScreenRow(presenter, 0)).toBeDefined() - expect(lineNumberStateForScreenRow(presenter, 4)).toBeDefined() - expect(lineNumberStateForScreenRow(presenter, 5)).toBeUndefined() + expect(lineNumberStateForScreenRow(presenter, 3)).toBeDefined() + expect(lineNumberStateForScreenRow(presenter, 4)).toBeUndefined() presenter.setMouseWheelScreenRow(0) expectStateUpdate presenter, -> presenter.setScrollTop(35) expect(lineNumberStateForScreenRow(presenter, 0)).toBeDefined() expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() - expect(lineNumberStateForScreenRow(presenter, 7)).toBeDefined() - expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() + expect(lineNumberStateForScreenRow(presenter, 6)).toBeDefined() + expect(lineNumberStateForScreenRow(presenter, 7)).toBeUndefined() expectStateUpdate presenter, -> advanceClock(200) expect(lineNumberStateForScreenRow(presenter, 0)).toBeUndefined() expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() - expect(lineNumberStateForScreenRow(presenter, 7)).toBeDefined() - expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() + expect(lineNumberStateForScreenRow(presenter, 6)).toBeDefined() + expect(lineNumberStateForScreenRow(presenter, 7)).toBeUndefined() it "correctly handles the first screen line being soft-wrapped", -> editor.setSoftWrapped(true) @@ -2481,7 +2479,7 @@ describe "TextEditorPresenter", -> editor.setEditorWidthInChars(80) presenterParams = model: editor - lineOverdrawMargin: 1 + presenter = new TextEditorPresenter(presenterParams) statements = [] diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index ce17243e4..703d4141e 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -354,7 +354,7 @@ class TextEditorComponent event.preventDefault() unless previousScrollLeft is @presenter.getScrollLeft() else # Scrolling vertically - @presenter.setScrollingTileRow(@tileRowForNode(event.target)) + @presenter.setMouseWheelScreenRow(@screenRowForNode(event.target)) previousScrollTop = @presenter.getScrollTop() @presenter.setScrollTop(previousScrollTop - Math.round(wheelDeltaY * @scrollSensitivity)) event.preventDefault() unless previousScrollTop is @presenter.getScrollTop() @@ -729,12 +729,11 @@ class TextEditorComponent lineNumberNodeForScreenRow: (screenRow) -> @gutterContainerComponent.getLineNumberGutterComponent().lineNumberNodeForScreenRow(screenRow) - tileRowForNode: (node) -> + screenRowForNode: (node) -> while node? - if tileId = node.dataset.tileId - return tileId + if screenRow = node.dataset.screenRow + return parseInt(screenRow) node = node.parentElement - null getFontSize: -> diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 1caa666df..4944c4842 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -304,11 +304,6 @@ class TextEditorPresenter tileForRow: (row) -> row - (row % @tileSize) - isValidTile: (tileRow) -> - return false unless tileRow? - - tileRow <= @tileForRow(@model.getLastScreenRow()) - getVisibleTilesRange: -> startTileRow = Math.max(0, @tileForRow(@startRow)) endTileRow = Math.min( @@ -336,9 +331,12 @@ class TextEditorPresenter visibleTiles[startRow] = true - if @isValidTile(@scrollingTileRow) and not visibleTiles[@scrollingTileRow]? - @state.content.tiles[@scrollingTileRow].display = "none" - visibleTiles[@scrollingTileRow] = true + if @mouseWheelScreenRow? and @model.tokenizedLineForScreenRow(@mouseWheelScreenRow)? + mouseWheelTile = @tileForRow(@mouseWheelScreenRow) + + unless visibleTiles[mouseWheelTile]? + @state.content.tiles[mouseWheelTile].display = "none" + visibleTiles[mouseWheelTile] = true for id, tile of @state.content.tiles continue if visibleTiles.hasOwnProperty(id) @@ -779,8 +777,8 @@ class TextEditorPresenter didStopScrolling: -> @state.content.scrollingVertically = false - if @scrollingTileRow? - @scrollingTileRow = null + if @mouseWheelScreenRow? + @mouseWheelScreenRow = null @shouldUpdateTilesState = true @shouldUpdateLineNumbersState = true @shouldUpdateCustomGutterDecorationState = true @@ -948,9 +946,9 @@ class TextEditorPresenter @emitDidUpdateState() - setScrollingTileRow: (tileRow) -> - if @scrollingTileRow isnt tileRow - @scrollingTileRow = tileRow + setMouseWheelScreenRow: (screenRow) -> + if @mouseWheelScreenRow isnt screenRow + @mouseWheelScreenRow = screenRow @didStartScrolling() setBaseCharacterWidth: (baseCharacterWidth) -> From 64f576624ec22b41d9209efdaa929a7734e52270 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 14 May 2015 17:39:23 +0200 Subject: [PATCH 1220/1783] Avoid tokens shim in suggestedIndent code --- src/language-mode.coffee | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/language-mode.coffee b/src/language-mode.coffee index b5529a05e..1d7def178 100644 --- a/src/language-mode.coffee +++ b/src/language-mode.coffee @@ -2,6 +2,7 @@ _ = require 'underscore-plus' {OnigRegExp} = require 'oniguruma' ScopeDescriptor = require './scope-descriptor' +TokenIterator = require './token-iterator' module.exports = class LanguageMode @@ -242,8 +243,9 @@ class LanguageMode @suggestedIndentForTokenizedLineAtBufferRow(bufferRow, tokenizedLine, options) suggestedIndentForTokenizedLineAtBufferRow: (bufferRow, tokenizedLine, options) -> - scopes = tokenizedLine.tokens[0].scopes - scopeDescriptor = new ScopeDescriptor({scopes}) + iterator = TokenIterator.instance.reset(tokenizedLine) + iterator.next() + scopeDescriptor = new ScopeDescriptor(scopes: iterator.getScopes()) currentIndentLevel = @editor.indentationForBufferRow(bufferRow) return currentIndentLevel unless increaseIndentRegex = @increaseIndentRegexForScopeDescriptor(scopeDescriptor) From 27b30303e1760a00d08c1af27bdf2829ac1a2605 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 14 May 2015 17:39:35 +0200 Subject: [PATCH 1221/1783] Avoid tokens shim in isBufferRowCommented --- src/text-editor.coffee | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index ac7c7d4f2..0c4d0cbf7 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -2471,9 +2471,8 @@ class TextEditor extends Model # Extended: Determine if the given row is entirely a comment isBufferRowCommented: (bufferRow) -> if match = @lineTextForBufferRow(bufferRow).match(/\S/) - scopeDescriptor = @tokenForBufferPosition([bufferRow, match.index]).scopes @commentScopeSelector ?= new TextMateScopeSelector('comment.*') - @commentScopeSelector.matches(scopeDescriptor) + @commentScopeSelector.matches(@scopeDescriptorForBufferPosition([bufferRow, match.index]).scopes) logCursorScope: -> scopeDescriptor = @getLastCursor().getScopeDescriptor() From ac5a5d5ba0939296cd4509d47c8270402fce7358 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 14 May 2015 17:51:46 +0200 Subject: [PATCH 1222/1783] Remove unused TokenizedBuffer methods that relied on tokens shim --- spec/tokenized-buffer-spec.coffee | 8 ----- src/tokenized-buffer.coffee | 60 ------------------------------- 2 files changed, 68 deletions(-) diff --git a/spec/tokenized-buffer-spec.coffee b/spec/tokenized-buffer-spec.coffee index 0c5363ad3..c51d6106f 100644 --- a/spec/tokenized-buffer-spec.coffee +++ b/spec/tokenized-buffer-spec.coffee @@ -296,14 +296,6 @@ describe "TokenizedBuffer", -> expect(tokenizedBuffer.tokenizedLineForRow(5).ruleStack?).toBeTruthy() expect(tokenizedBuffer.tokenizedLineForRow(6).ruleStack?).toBeTruthy() - describe ".findOpeningBracket(closingBufferPosition)", -> - it "returns the position of the matching bracket, skipping any nested brackets", -> - expect(tokenizedBuffer.findOpeningBracket([9, 2])).toEqual [1, 29] - - describe ".findClosingBracket(startBufferPosition)", -> - it "returns the position of the matching bracket, skipping any nested brackets", -> - expect(tokenizedBuffer.findClosingBracket([1, 29])).toEqual [9, 2] - it "tokenizes leading whitespace based on the new tab length", -> expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[0].isAtomic).toBeTruthy() expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[0].value).toBe " " diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 4ce0f44d3..e3f09b9b5 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -444,66 +444,6 @@ class TokenizedBuffer extends Model new Range(new Point(position.row, startColumn), new Point(position.row, endColumn)) - iterateTokensInBufferRange: (bufferRange, iterator) -> - bufferRange = Range.fromObject(bufferRange) - {start, end} = bufferRange - - keepLooping = true - stop = -> keepLooping = false - - for bufferRow in [start.row..end.row] - bufferColumn = 0 - for token in @tokenizedLines[bufferRow].tokens - startOfToken = new Point(bufferRow, bufferColumn) - iterator(token, startOfToken, {stop}) if bufferRange.containsPoint(startOfToken) - return unless keepLooping - bufferColumn += token.bufferDelta - - backwardsIterateTokensInBufferRange: (bufferRange, iterator) -> - bufferRange = Range.fromObject(bufferRange) - {start, end} = bufferRange - - keepLooping = true - stop = -> keepLooping = false - - for bufferRow in [end.row..start.row] - bufferColumn = @buffer.lineLengthForRow(bufferRow) - for token in new Array(@tokenizedLines[bufferRow].tokens...).reverse() - bufferColumn -= token.bufferDelta - startOfToken = new Point(bufferRow, bufferColumn) - iterator(token, startOfToken, {stop}) if bufferRange.containsPoint(startOfToken) - return unless keepLooping - - findOpeningBracket: (startBufferPosition) -> - range = [[0,0], startBufferPosition] - position = null - depth = 0 - @backwardsIterateTokensInBufferRange range, (token, startPosition, {stop}) -> - if token.isBracket() - if token.value is '}' - depth++ - else if token.value is '{' - depth-- - if depth is 0 - position = startPosition - stop() - position - - findClosingBracket: (startBufferPosition) -> - range = [startBufferPosition, @buffer.getEndPosition()] - position = null - depth = 0 - @iterateTokensInBufferRange range, (token, startPosition, {stop}) -> - if token.isBracket() - if token.value is '{' - depth++ - else if token.value is '}' - depth-- - if depth is 0 - position = startPosition - stop() - position - # Gets the row number of the last line. # # Returns a {Number}. From 44f6c70101b6f7c2ba0001a5d78ef44dbbbba5ea Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 14 May 2015 08:58:04 -0700 Subject: [PATCH 1223/1783] :arrow_up: notifications@0.44 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c2bdb47f5..8ffda89eb 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "link": "0.30.0", "markdown-preview": "0.148.0", "metrics": "0.46.0", - "notifications": "0.43.0", + "notifications": "0.44.0", "open-on-github": "0.36.0", "package-generator": "0.39.0", "release-notes": "0.52.0", From 64573904f93064ca68bf99ab2bb0a8055e047944 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 14 May 2015 09:12:23 -0700 Subject: [PATCH 1224/1783] :arrow_up: metrics@0.47 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4b728f95c..072279196 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "keybinding-resolver": "0.32.0", "link": "0.30.0", "markdown-preview": "0.148.0", - "metrics": "0.46.0", + "metrics": "0.47.0", "notifications": "0.44.0", "open-on-github": "0.36.0", "package-generator": "0.39.0", From 723bf5a302424383a4433e7dbd8606b3471b0454 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 14 May 2015 18:30:29 +0200 Subject: [PATCH 1225/1783] Reimplement `lineNodeForScreenRow` --- src/lines-component.coffee | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/lines-component.coffee b/src/lines-component.coffee index c4341bbbf..663dd9a31 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -131,3 +131,8 @@ class LinesComponent component.clearMeasurements() @presenter.clearScopedCharacterWidths() + + lineNodeForScreenRow: (screenRow) -> + tile = @presenter.tileForRow(screenRow) + + @tileComponentsByTileId[tile].lineNodeForScreenRow(screenRow) From 1a0d99621bfe8bd46dda2dc6072a21c777e2d5a1 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 14 May 2015 09:36:12 -0700 Subject: [PATCH 1226/1783] Avoid saving window state when closing windows after quitting --- src/browser/atom-application.coffee | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index afc811144..d81660a49 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -56,6 +56,7 @@ class AtomApplication atomProtocolHandler: null resourcePath: null version: null + quitting: false exit: (status) -> app.exit(status) @@ -104,7 +105,7 @@ class AtomApplication if process.platform in ['win32', 'linux'] app.quit() return - @saveState() unless window.isSpec + @saveState() unless window.isSpec or @quitting # Public: Adds the {AtomWindow} to the global window list. addWindow: (window) -> @@ -208,6 +209,9 @@ class AtomApplication @openPathOnEvent('application:open-your-stylesheet', 'atom://.atom/stylesheet') @openPathOnEvent('application:open-license', path.join(process.resourcesPath, 'LICENSE.md')) + app.on 'before-quit', => + @quitting = true + app.on 'will-quit', => @killAllProcesses() @deleteSocketFile() From 26b7c5e58e26529ce2dcdda8f9606f3379d943c9 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 14 May 2015 18:40:44 +0200 Subject: [PATCH 1227/1783] :fire: Get rid of unused `tileId` property --- src/tile-component.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tile-component.coffee b/src/tile-component.coffee index 197a9adce..a68eb58e5 100644 --- a/src/tile-component.coffee +++ b/src/tile-component.coffee @@ -21,7 +21,6 @@ class TileComponent @screenRowsByLineId = {} @lineIdsByScreenRow = {} @domNode ?= document.createElement("div") - @domNode.dataset.tileId = @id @domNode.style.position = "absolute" @domNode.style.display = "block" @domNode.classList.add("tile") From 265090e7bba546175607a0fd74d944a5f0700738 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 14 May 2015 18:47:51 +0200 Subject: [PATCH 1228/1783] Store tile state in a instance variable --- src/tile-component.coffee | 57 ++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/src/tile-component.coffee b/src/tile-component.coffee index a68eb58e5..dc0324e18 100644 --- a/src/tile-component.coffee +++ b/src/tile-component.coffee @@ -34,29 +34,32 @@ class TileComponent @oldState = {tiles: {}} @oldState.tiles[@id] = { lines: {}} - if @newState.tiles[@id].display isnt @oldState.tiles[@id]?.display - @domNode.style.display = @newState.tiles[@id].display - @oldState.tiles[@id]?.display = @newState.tiles[@id].display + @newTileState = @newState.tiles[@id] + @oldTileState = @oldState.tiles[@id] - if @newState.tiles[@id].height isnt @oldState.tiles[@id]?.height - @domNode.style.height = @newState.tiles[@id].height + 'px' - @oldState.tiles[@id]?.height = @newState.tiles[@id].height + if @newTileState.display isnt @oldTileState.display + @domNode.style.display = @newTileState.display + @oldTileState.display = @newTileState.display - if (@newState.tiles[@id].top isnt @oldState.tiles[@id]?.top) or (@newState.tiles[@id].left isnt @oldState.tiles[@id]?.left) - @domNode.style['-webkit-transform'] = "translate3d(#{@newState.tiles[@id].left}px, #{@newState.tiles[@id].top}px, 0px)" - @oldState.tiles[@id]?.top = @newState.tiles[@id].top - @oldState.tiles[@id]?.left = @newState.tiles[@id].left + if @newTileState.height isnt @oldTileState.height + @domNode.style.height = @newTileState.height + 'px' + @oldTileState.height = @newTileState.height - if @newState.tiles[@id].newlyCreated + if @newTileState.top isnt @oldTileState.top or @newTileState.left isnt @oldTileState.left + @domNode.style['-webkit-transform'] = "translate3d(#{@newTileState.left}px, #{@newTileState.top}px, 0px)" + @oldTileState.top = @newTileState.top + @oldTileState.left = @newTileState.left + + if @newTileState.newlyCreated newLineIds = [] newLinesHTML = "" - for id, lineState of @newState.tiles[@id].lines + for id, lineState of @newTileState.lines newLineIds.push(id) newLinesHTML += @buildLineHTML(id) @screenRowsByLineId[id] = lineState.screenRow @lineIdsByScreenRow[lineState.screenRow] = id - @oldState.tiles[@id]?.lines[id] = cloneObject(lineState) + @oldTileState.lines[id] = cloneObject(lineState) return if newLineIds.length is 0 @@ -77,7 +80,7 @@ class TileComponent @oldState.scrollWidth = @newState.scrollWidth removeLineNodes: -> - @removeLineNode(id) for id of @oldState.tiles[@id]?.lines + @removeLineNode(id) for id of @oldTileState.lines return removeLineNode: (id) -> @@ -85,18 +88,18 @@ class TileComponent delete @lineNodesByLineId[id] delete @lineIdsByScreenRow[@screenRowsByLineId[id]] delete @screenRowsByLineId[id] - delete @oldState.tiles[@id]?.lines[id] + delete @oldTileState.lines[id] updateLineNodes: -> - for id of @oldState.tiles[@id]?.lines - unless @newState.tiles[@id].lines.hasOwnProperty(id) + for id of @oldTileState.lines + unless @newTileState.lines.hasOwnProperty(id) @removeLineNode(id) newLineIds = null newLinesHTML = null - for id, lineState of @newState.tiles[@id].lines - if @oldState.tiles[@id]?.lines.hasOwnProperty(id) + for id, lineState of @newTileState.lines + if @oldTileState.lines.hasOwnProperty(id) @updateLineNode(id) else newLineIds ?= [] @@ -105,7 +108,7 @@ class TileComponent newLinesHTML += @buildLineHTML(id) @screenRowsByLineId[id] = lineState.screenRow @lineIdsByScreenRow[lineState.screenRow] = id - @oldState.tiles[@id]?.lines[id] = cloneObject(lineState) + @oldTileState.lines[id] = cloneObject(lineState) return unless newLineIds? @@ -120,7 +123,7 @@ class TileComponent buildLineHTML: (id) -> {scrollWidth} = @newState - {screenRow, tokens, text, top, lineEnding, fold, isSoftWrapped, indentLevel, decorationClasses} = @newState.tiles[@id].lines[id] + {screenRow, tokens, text, top, lineEnding, fold, isSoftWrapped, indentLevel, decorationClasses} = @newTileState.lines[id] classes = '' if decorationClasses? @@ -141,7 +144,7 @@ class TileComponent buildEmptyLineInnerHTML: (id) -> {indentGuidesVisible} = @newState - {indentLevel, tabLength, endOfLineInvisibles} = @newState.tiles[@id].lines[id] + {indentLevel, tabLength, endOfLineInvisibles} = @newTileState.lines[id] if indentGuidesVisible and indentLevel > 0 invisibleIndex = 0 @@ -164,7 +167,7 @@ class TileComponent buildLineInnerHTML: (id) -> {indentGuidesVisible} = @newState - {tokens, text, isOnlyWhitespace} = @newState.tiles[@id].lines[id] + {tokens, text, isOnlyWhitespace} = @newTileState.lines[id] innerHTML = "" scopeStack = [] @@ -178,7 +181,7 @@ class TileComponent innerHTML buildEndOfLineHTML: (id) -> - {endOfLineInvisibles} = @newState.tiles[@id].lines[id] + {endOfLineInvisibles} = @newTileState.lines[id] html = '' if endOfLineInvisibles? @@ -212,8 +215,8 @@ class TileComponent "" updateLineNode: (id) -> - oldLineState = @oldState.tiles[@id]?.lines[id] - newLineState = @newState.tiles[@id].lines[id] + oldLineState = @oldTileState.lines[id] + newLineState = @newTileState.lines[id] lineNode = @lineNodesByLineId[id] @@ -248,7 +251,7 @@ class TileComponent @lineNodesByLineId[@lineIdsByScreenRow[screenRow]] measureCharactersInNewLines: -> - for id, lineState of @oldState.tiles[@id]?.lines + for id, lineState of @oldTileState.lines unless @measuredLines.has(id) lineNode = @lineNodesByLineId[id] @measureCharactersInLine(id, lineState, lineNode) From ff56c1f0bb4d5132dd8c01e0c05f5cb0a2118e75 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 14 May 2015 09:49:04 -0700 Subject: [PATCH 1229/1783] :arrow_up: metrics@0.48 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 072279196..cdc464084 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "keybinding-resolver": "0.32.0", "link": "0.30.0", "markdown-preview": "0.148.0", - "metrics": "0.47.0", + "metrics": "0.48.0", "notifications": "0.44.0", "open-on-github": "0.36.0", "package-generator": "0.39.0", From c4d7df9e991a5743c130cd9c495ce49ca9cfe981 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 14 May 2015 09:54:22 -0700 Subject: [PATCH 1230/1783] Prevent global variables from leaking out of index.js --- spec/atom-spec.coffee | 2 +- static/index.js | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/spec/atom-spec.coffee b/spec/atom-spec.coffee index 99a7f432e..c5c4255e3 100644 --- a/spec/atom-spec.coffee +++ b/spec/atom-spec.coffee @@ -20,7 +20,7 @@ describe "the `atom` global", -> afterEach -> atom.setSize(originalSize.width, originalSize.height) - it 'sets the size of the window, and can retrieve the size just set', -> + fit 'sets the size of the window, and can retrieve the size just set', -> atom.setSize(100, 400) expect(atom.getSize()).toEqual width: 100, height: 400 diff --git a/static/index.js b/static/index.js index ef61e8bce..f41d41cd9 100644 --- a/static/index.js +++ b/static/index.js @@ -1,3 +1,5 @@ +(function() { + var fs = require('fs'); var path = require('path'); @@ -204,3 +206,5 @@ var setupWindowBackground = function() { parseLoadSettings(); setupWindowBackground(); + +})(); From b2ee37ab2925a44b840417e68427d923d5eaa197 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 14 May 2015 10:01:06 -0700 Subject: [PATCH 1231/1783] Unfocus spec --- spec/atom-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/atom-spec.coffee b/spec/atom-spec.coffee index c5c4255e3..99a7f432e 100644 --- a/spec/atom-spec.coffee +++ b/spec/atom-spec.coffee @@ -20,7 +20,7 @@ describe "the `atom` global", -> afterEach -> atom.setSize(originalSize.width, originalSize.height) - fit 'sets the size of the window, and can retrieve the size just set', -> + it 'sets the size of the window, and can retrieve the size just set', -> atom.setSize(100, 400) expect(atom.getSize()).toEqual width: 100, height: 400 From 827595fcda21c399d2129a631ab2bbacde3489f8 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 14 May 2015 10:07:42 -0700 Subject: [PATCH 1232/1783] :arrow_up: fuzzy-finder@0.85 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cdc464084..c8f726ed7 100644 --- a/package.json +++ b/package.json @@ -101,7 +101,7 @@ "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", "find-and-replace": "0.162.0", - "fuzzy-finder": "0.84.0", + "fuzzy-finder": "0.85.0", "git-diff": "0.55.0", "go-to-line": "0.30.0", "grammar-selector": "0.47.0", From 26f3fd3cdf8cb657326e14bf036b07d51f3b3c91 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 14 May 2015 10:08:47 -0700 Subject: [PATCH 1233/1783] :arrow_up: deprecation-cop@0.48 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c8f726ed7..61e1826f9 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,7 @@ "bookmarks": "0.35.0", "bracket-matcher": "0.74.0", "command-palette": "0.35.0", - "deprecation-cop": "0.47.0", + "deprecation-cop": "0.48.0", "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", From c9302e06f0ca3c4afd354e8c007e12a71064d97f Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Thu, 14 May 2015 10:10:55 -0700 Subject: [PATCH 1234/1783] Bump version of autocomplete-plus@2.16.0 Add license filed for passing tests and standardization. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cf4634cf6..4dfe23c0f 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,7 @@ "autocomplete-css": "0.7.2", "autocomplete-emojis": "2.2.2", "autocomplete-html": "0.7.2", - "autocomplete-plus": "2.15.2", + "autocomplete-plus": "2.16.0", "autocomplete-snippets": "1.6.1", "autoflow": "0.23.0", "autosave": "0.20.0", From 372fdc2ae0e4cda064d93d0a6633f30e15d0cbcf Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 14 May 2015 10:14:28 -0700 Subject: [PATCH 1235/1783] :arrow_up: update-package-dependencies@0.10 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 61e1826f9..a960b10a0 100644 --- a/package.json +++ b/package.json @@ -124,7 +124,7 @@ "tabs": "0.68.0", "timecop": "0.31.0", "tree-view": "0.171.0", - "update-package-dependencies": "0.9.0", + "update-package-dependencies": "0.10.0", "welcome": "0.27.0", "whitespace": "0.29.0", "wrap-guide": "0.33.0", From 881001b15adeea6cb2bb2234132d9c05b80c08c5 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Thu, 14 May 2015 10:19:25 -0700 Subject: [PATCH 1236/1783] [Gutter][easy] Reverse a conditional to get rid of a 'not' --- src/text-editor-presenter.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 27966ff7a..70c26a1a3 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -481,12 +481,12 @@ class TextEditorPresenter for gutter in @model.getGutters() gutterName = gutter.name gutterDecorations = @customGutterDecorations[gutterName] - if not gutterDecorations - @customGutterDecorations[gutterName] = {} - else + if gutterDecorations # Clear the gutter decorations; they are rebuilt. # We clear instead of reassigning to preserve the reference. @clearDecorationsForCustomGutterName(gutterName) + else + @customGutterDecorations[gutterName] = {} return if not @gutterIsVisible(gutter) relevantDecorations = @customGutterDecorationsInRange(gutterName, @startRow, @endRow - 1) From a78bd1b774e98f4e9790f534e6ef4e6418467309 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Thu, 14 May 2015 10:20:51 -0700 Subject: [PATCH 1237/1783] :arrow_up: autocomplete-plus@2.16.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a960b10a0..b7fd6f2a2 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,7 @@ "autocomplete-css": "0.7.2", "autocomplete-emojis": "2.2.2", "autocomplete-html": "0.7.2", - "autocomplete-plus": "2.15.2", + "autocomplete-plus": "2.16.1", "autocomplete-snippets": "1.6.1", "autoflow": "0.23.0", "autosave": "0.20.0", From 36b93069b13d869e17c31b93f9a4a89b68168678 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 14 May 2015 10:27:19 -0700 Subject: [PATCH 1238/1783] :arrow_up: command-palette@0.36 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b7fd6f2a2..b108fb291 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "background-tips": "0.24.0", "bookmarks": "0.35.0", "bracket-matcher": "0.74.0", - "command-palette": "0.35.0", + "command-palette": "0.36.0", "deprecation-cop": "0.48.0", "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", From 1c0aceaaa3aeab610b902d61214b6dde878f96e7 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 14 May 2015 10:32:11 -0700 Subject: [PATCH 1239/1783] :arrow_up: notifications@0.45 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b108fb291..e09744896 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "link": "0.30.0", "markdown-preview": "0.148.0", "metrics": "0.48.0", - "notifications": "0.44.0", + "notifications": "0.45.0", "open-on-github": "0.36.0", "package-generator": "0.39.0", "release-notes": "0.52.0", From 4f8dc77fb4e35fed099438d02190f9889d81d21f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 14 May 2015 10:35:32 -0700 Subject: [PATCH 1240/1783] :arrow_up: find-and-replace@0.163 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e09744896..ed3279ef1 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,7 @@ "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", - "find-and-replace": "0.162.0", + "find-and-replace": "0.163.0", "fuzzy-finder": "0.85.0", "git-diff": "0.55.0", "go-to-line": "0.30.0", From 5201e4547b3db895c2cc98b502c25d998344c878 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 14 May 2015 19:08:07 +0200 Subject: [PATCH 1241/1783] :art: --- src/lines-component.coffee | 8 +++----- src/text-editor-presenter.coffee | 2 -- src/tile-component.coffee | 23 ++--------------------- 3 files changed, 5 insertions(+), 28 deletions(-) diff --git a/src/lines-component.coffee b/src/lines-component.coffee index 663dd9a31..6a49f16be 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -80,8 +80,7 @@ class LinesComponent removeTileNode: (id) -> node = @tileComponentsByTileId[id].getDomNode() - node.style.display = "none" - @freeDomNodes.push(node) + node.remove() delete @tileComponentsByTileId[id] delete @oldState.tiles[id] @@ -94,10 +93,9 @@ class LinesComponent if @oldState.tiles.hasOwnProperty(id) tileComponent = @tileComponentsByTileId[id] else - domNode = @freeDomNodes.pop() - tileComponent = @tileComponentsByTileId[id] = new TileComponent({id, @presenter, domNode}) + tileComponent = @tileComponentsByTileId[id] = new TileComponent({id, @presenter}) - @domNode.appendChild(tileComponent.getDomNode()) unless domNode? + @domNode.appendChild(tileComponent.getDomNode()) @oldState.tiles[id] = cloneObject(tileState) tileComponent.updateSync(@newState) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 4944c4842..48a410faa 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -319,12 +319,10 @@ class TextEditorPresenter for startRow in @getVisibleTilesRange() by @tileSize endRow = Math.min(@model.getScreenLineCount(), startRow + @tileSize) - isNewTile = not @state.content.tiles.hasOwnProperty(startRow) tile = @state.content.tiles[startRow] ?= {} tile.top = startRow * @lineHeight - @scrollTop tile.left = -@scrollLeft tile.height = @tileSize * @lineHeight - tile.newlyCreated = isNewTile tile.display = "block" @updateLinesState(tile, startRow, endRow) diff --git a/src/tile-component.coffee b/src/tile-component.coffee index dc0324e18..c31c4dcb6 100644 --- a/src/tile-component.coffee +++ b/src/tile-component.coffee @@ -50,27 +50,8 @@ class TileComponent @oldTileState.top = @newTileState.top @oldTileState.left = @newTileState.left - if @newTileState.newlyCreated - newLineIds = [] - newLinesHTML = "" - - for id, lineState of @newTileState.lines - newLineIds.push(id) - newLinesHTML += @buildLineHTML(id) - @screenRowsByLineId[id] = lineState.screenRow - @lineIdsByScreenRow[lineState.screenRow] = id - @oldTileState.lines[id] = cloneObject(lineState) - - return if newLineIds.length is 0 - - @domNode.innerHTML = newLinesHTML - newLineNodes = _.toArray(@domNode.children) - for id, i in newLineIds - lineNode = newLineNodes[i] - @lineNodesByLineId[id] = lineNode - else - @removeLineNodes() unless @oldState.indentGuidesVisible is @newState.indentGuidesVisible - @updateLineNodes() + @removeLineNodes() unless @oldState.indentGuidesVisible is @newState.indentGuidesVisible + @updateLineNodes() if @newState.scrollWidth isnt @oldState.scrollWidth @domNode.style.width = @newState.scrollWidth + 'px' From ccaf6220ceda7bf77605f6aed99b4d7ceaacb320 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 14 May 2015 10:39:07 -0700 Subject: [PATCH 1242/1783] Add missing fs-plus require --- spec/default-directory-provider-spec.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/default-directory-provider-spec.coffee b/spec/default-directory-provider-spec.coffee index 236283d27..69370a77b 100644 --- a/spec/default-directory-provider-spec.coffee +++ b/spec/default-directory-provider-spec.coffee @@ -1,5 +1,6 @@ DefaultDirectoryProvider = require "../src/default-directory-provider" path = require "path" +fs = require 'fs-plus' temp = require "temp" describe "DefaultDirectoryProvider", -> From f1b5834c2fb96226590e94527bec3058cc542c98 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 14 May 2015 10:46:38 -0700 Subject: [PATCH 1243/1783] :arrow_up: notifications@0.46 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ed3279ef1..38553406b 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "link": "0.30.0", "markdown-preview": "0.148.0", "metrics": "0.48.0", - "notifications": "0.45.0", + "notifications": "0.46.0", "open-on-github": "0.36.0", "package-generator": "0.39.0", "release-notes": "0.52.0", From 70e326d556b963637f28177ce94111ab12c5dff0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 14 May 2015 10:53:11 -0700 Subject: [PATCH 1244/1783] :arrow_up: autocomplete-plus@2.16.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 38553406b..caff33ac2 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,7 @@ "autocomplete-css": "0.7.2", "autocomplete-emojis": "2.2.2", "autocomplete-html": "0.7.2", - "autocomplete-plus": "2.16.1", + "autocomplete-plus": "2.16.2", "autocomplete-snippets": "1.6.1", "autoflow": "0.23.0", "autosave": "0.20.0", From b5d4eebe2ab7f3b2cdcfafc8710662b4c63efbd3 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Thu, 14 May 2015 11:07:54 -0700 Subject: [PATCH 1245/1783] :arrow_up: autocomplete-plus@2.16.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index caff33ac2..2609c065d 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,7 @@ "autocomplete-css": "0.7.2", "autocomplete-emojis": "2.2.2", "autocomplete-html": "0.7.2", - "autocomplete-plus": "2.16.2", + "autocomplete-plus": "2.16.3", "autocomplete-snippets": "1.6.1", "autoflow": "0.23.0", "autosave": "0.20.0", From 5dd4a2a1dc03480121355ede3f3b51106f599b86 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 14 May 2015 11:29:39 -0700 Subject: [PATCH 1246/1783] Remove metadata return --- src/package.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/package.coffee b/src/package.coffee index 95f769e49..c8c530bed 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -31,7 +31,6 @@ class Package normalizePackageData(metadata) if metadata.repository?.type is 'git' metadata.repository.url = metadata.repository.url?.replace(/^git\+/, '') - metadata @loadMetadata: (packagePath, ignoreErrors=false) -> packageName = path.basename(packagePath) From 117080b16d9d4c2a33bad05eb26931397c033904 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 14 May 2015 11:30:41 -0700 Subject: [PATCH 1247/1783] Check that url is string before replacing prefix --- src/package.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/package.coffee b/src/package.coffee index c8c530bed..b48ed8014 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -29,8 +29,8 @@ class Package unless metadata?._id normalizePackageData ?= require 'normalize-package-data' normalizePackageData(metadata) - if metadata.repository?.type is 'git' - metadata.repository.url = metadata.repository.url?.replace(/^git\+/, '') + if metadata.repository?.type is 'git' and typeof metadata.repository.url is 'string' + metadata.repository.url = metadata.repository.url.replace(/^git\+/, '') @loadMetadata: (packagePath, ignoreErrors=false) -> packageName = path.basename(packagePath) From b006169ae70a6a747176f8f61eb1342cf64076ee Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 14 May 2015 12:29:00 -0700 Subject: [PATCH 1248/1783] Unship autocomplete-emojis until Windows/Linux support --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 4f33d15e9..f74118ca2 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,6 @@ "archive-view": "0.57.0", "autocomplete-atom-api": "0.9.0", "autocomplete-css": "0.7.2", - "autocomplete-emojis": "2.2.2", "autocomplete-html": "0.7.2", "autocomplete-plus": "2.16.3", "autocomplete-snippets": "1.6.1", From f48351ed6a762995406ea5604fda2b7d6d761405 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 14 May 2015 12:31:38 -0700 Subject: [PATCH 1249/1783] Remove uninstalling of autocomplete-emojis --- src/package-manager.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 606f72eda..8d2f4d663 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -427,7 +427,6 @@ class PackageManager path.join(packageDir, 'autocomplete-atom-api') path.join(packageDir, 'autocomplete-css') path.join(packageDir, 'autocomplete-html') - path.join(packageDir, 'autocomplete-emojis') path.join(packageDir, 'autocomplete-snippets') ] for dirToRemove in dirsToRemove From 915b13e75c50552386d821bc5ba71778109ef4a5 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 14 May 2015 21:35:51 +0200 Subject: [PATCH 1250/1783] :arrow_up: first-mate to 4.0.0 for tagged token representation --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c2bdb47f5..bfa032303 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "delegato": "^1", "emissary": "^1.3.3", "event-kit": "^1.1.1", - "first-mate": "^3.1", + "first-mate": "^4.0.0", "fs-plus": "^2.8.0", "fstream": "0.1.24", "fuzzaldrin": "^2.1", From 4235c15dd858bc63be8c634921e4b44014583c69 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 14 May 2015 21:43:45 +0200 Subject: [PATCH 1251/1783] :fire: debugger --- src/lines-component.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lines-component.coffee b/src/lines-component.coffee index 8fa7c215f..51ea65f28 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -177,7 +177,6 @@ class LinesComponent innerHTML = "" iterator = TokenIterator.instance.reset(lineState) - debugger if global.debug while iterator.next() for scope in iterator.getScopeEnds() innerHTML += "" From 9bb1b14d86218c3988eac8caf6ab3669b5dd3e44 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 14 May 2015 12:59:28 -0700 Subject: [PATCH 1252/1783] Prepare 0.200 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f74118ca2..4bf5e6d76 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "0.199.0", + "version": "0.200.0", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From 3ea59696e6f63005ccb5e3a81814c66d1815b09e Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 14 May 2015 22:31:51 +0200 Subject: [PATCH 1253/1783] :arrow_up: first-mate --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1722e5e64..bf8a4edcb 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "delegato": "^1", "emissary": "^1.3.3", "event-kit": "^1.1.1", - "first-mate": "^4.0.0", + "first-mate": "^4.1.0", "fs-plus": "^2.8.0", "fstream": "0.1.24", "fuzzaldrin": "^2.1", From ec4c453b87ad7fa6db2961e93eda689d3dfa84e8 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 14 May 2015 23:08:02 +0200 Subject: [PATCH 1254/1783] :arrow_up: first-mate --- package.json | 2 +- src/tokenized-buffer.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index bf8a4edcb..b7b03cfa7 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "delegato": "^1", "emissary": "^1.3.3", "event-kit": "^1.1.1", - "first-mate": "^4.1.0", + "first-mate": "^4.1.1", "fs-plus": "^2.8.0", "fstream": "0.1.24", "fuzzaldrin": "^2.1", diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 01631a221..03b9dcaac 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -330,7 +330,7 @@ class TokenizedBuffer extends Model lineEnding = @buffer.lineEndingForRow(row) tabLength = @getTabLength() indentLevel = @indentLevelForRow(row) - {tags, ruleStack} = @grammar.tokenizeLine(text, ruleStack, row is 0) + {tags, ruleStack} = @grammar.tokenizeLine(text, ruleStack, row is 0, false) new TokenizedLine({openScopes, text, tags, ruleStack, tabLength, lineEnding, indentLevel, invisibles: @getInvisiblesToShow()}) getInvisiblesToShow: -> From e838f0b29748c31e8364c46319b5f42d3c6e4b3f Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 14 May 2015 14:28:46 -0700 Subject: [PATCH 1255/1783] :arrow_up: text-buffer to 6.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 75921a02b..515116973 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "space-pen": "3.8.2", "stacktrace-parser": "0.1.1", "temp": "0.8.1", - "text-buffer": "6.0.0-beta.2", + "text-buffer": "6.0.0", "theorist": "^1.0.2", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6" From d9e4aa16d2a4b40315659441b27751a48b3f2364 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 14 May 2015 15:37:23 -0700 Subject: [PATCH 1256/1783] Run package specs from the active item's project folder --- spec/workspace-element-spec.coffee | 44 ++++++++++++++++++++++++++++++ src/workspace-element.coffee | 5 +++- 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 spec/workspace-element-spec.coffee diff --git a/spec/workspace-element-spec.coffee b/spec/workspace-element-spec.coffee new file mode 100644 index 000000000..1771b2363 --- /dev/null +++ b/spec/workspace-element-spec.coffee @@ -0,0 +1,44 @@ +ipc = require 'ipc' +path = require 'path' +temp = require('temp').track() + +describe "WorkspaceElement", -> + workspaceElement = null + + beforeEach -> + workspaceElement = atom.views.getView(atom.workspace) + + describe "the 'window:run-package-specs' command", -> + it "runs the package specs for the active item's project path, or the first project path", -> + spyOn(ipc, 'send') + + # No project paths. Don't try to run specs. + atom.commands.dispatch(workspaceElement, "window:run-package-specs") + expect(ipc.send).not.toHaveBeenCalledWith("run-package-specs") + + projectPaths = [temp.mkdirSync("dir1-"), temp.mkdirSync("dir2-")] + atom.project.setPaths(projectPaths) + + # No active item. Use first project directory. + atom.commands.dispatch(workspaceElement, "window:run-package-specs") + expect(ipc.send).toHaveBeenCalledWith("run-package-specs", path.join(projectPaths[0], "spec")) + ipc.send.reset() + + # Active item doesn't implement ::getPath(). Use first project directory. + item = document.createElement("div") + atom.workspace.getActivePane().activateItem(item) + atom.commands.dispatch(workspaceElement, "window:run-package-specs") + expect(ipc.send).toHaveBeenCalledWith("run-package-specs", path.join(projectPaths[0], "spec")) + ipc.send.reset() + + # Active item has no path. Use first project directory. + item.getPath = -> null + atom.commands.dispatch(workspaceElement, "window:run-package-specs") + expect(ipc.send).toHaveBeenCalledWith("run-package-specs", path.join(projectPaths[0], "spec")) + ipc.send.reset() + + # Active item has path. Use project path for item path. + item.getPath = -> path.join(projectPaths[1], "a-file.txt") + atom.commands.dispatch(workspaceElement, "window:run-package-specs") + expect(ipc.send).toHaveBeenCalledWith("run-package-specs", path.join(projectPaths[1], "spec")) + ipc.send.reset() diff --git a/src/workspace-element.coffee b/src/workspace-element.coffee index 2d0cb4e49..4f5dd6c5d 100644 --- a/src/workspace-element.coffee +++ b/src/workspace-element.coffee @@ -113,7 +113,10 @@ class WorkspaceElement extends HTMLElement focusPaneViewOnRight: -> @paneContainer.focusPaneViewOnRight() runPackageSpecs: -> - [projectPath] = atom.project.getPaths() + if activePath = atom.workspace.getActivePaneItem()?.getPath?() + [projectPath] = atom.project.relativizePath(activePath) + else + [projectPath] = atom.project.getPaths() ipc.send('run-package-specs', path.join(projectPath, 'spec')) if projectPath atom.commands.add 'atom-workspace', From 4dc109c077c8309a11d6fb82309cc9199421b3cf Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 14 May 2015 16:33:24 -0700 Subject: [PATCH 1257/1783] :arrow_up: language-todo@0.21 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a09157ff3..424ba2019 100644 --- a/package.json +++ b/package.json @@ -155,7 +155,7 @@ "language-source": "0.9.0", "language-sql": "0.15.0", "language-text": "0.6.0", - "language-todo": "0.20.0", + "language-todo": "0.21.0", "language-toml": "0.16.0", "language-xml": "0.28.0", "language-yaml": "0.22.0" From 3a51c44b559ea8e5c59a4f953d98e3c0c2d98cb5 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 14 May 2015 17:03:30 -0700 Subject: [PATCH 1258/1783] :shirt: Use skinny arrow for afterEach --- spec/text-editor-presenter-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index f5ed6d90f..7da866ab4 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -2422,7 +2422,7 @@ describe "TextEditorPresenter", -> beforeEach -> customGutter = editor.addGutter({name: 'test-gutter', priority: -1, visible: true}) - afterEach => + afterEach -> customGutter.destroy() describe ".scrollHeight", -> From 6ca8e1113d025905d79f003a93c15c97e1040db1 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 14 May 2015 18:03:05 -0700 Subject: [PATCH 1259/1783] :arrow_up: symbols-view@0.97 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 424ba2019..beea26143 100644 --- a/package.json +++ b/package.json @@ -119,7 +119,7 @@ "spell-check": "0.58.0", "status-bar": "0.72.0", "styleguide": "0.44.0", - "symbols-view": "0.96.0", + "symbols-view": "0.97.0", "tabs": "0.68.0", "timecop": "0.31.0", "tree-view": "0.171.0", From a879c247d63417e5152f301d4a584a1773c508d0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 15 May 2015 09:34:49 -0700 Subject: [PATCH 1260/1783] :arrow_up: language-gfm@0.75 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index beea26143..ad02f3e27 100644 --- a/package.json +++ b/package.json @@ -132,7 +132,7 @@ "language-coffee-script": "0.40.0", "language-csharp": "0.5.0", "language-css": "0.29.0", - "language-gfm": "0.74.0", + "language-gfm": "0.75.0", "language-git": "0.10.0", "language-go": "0.26.0", "language-html": "0.37.0", From f2491abd49d4ea9198df9ad2819b2ab9905c5cf3 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 15 May 2015 09:35:01 -0700 Subject: [PATCH 1261/1783] :arrow_up: language-php@0.23 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ad02f3e27..8545fd9cc 100644 --- a/package.json +++ b/package.json @@ -145,7 +145,7 @@ "language-mustache": "0.11.0", "language-objective-c": "0.15.0", "language-perl": "0.24.0", - "language-php": "0.22.0", + "language-php": "0.23.0", "language-property-list": "0.8.0", "language-python": "0.34.0", "language-ruby": "0.52.0", From f575274c54a786a524a345486a45b4db30a85d26 Mon Sep 17 00:00:00 2001 From: Thomas Johansen Date: Fri, 15 May 2015 19:57:55 +0200 Subject: [PATCH 1262/1783] :arrow_up: markdown-preview@0.149.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index beea26143..2a115ed10 100644 --- a/package.json +++ b/package.json @@ -108,7 +108,7 @@ "incompatible-packages": "0.24.0", "keybinding-resolver": "0.32.0", "link": "0.30.0", - "markdown-preview": "0.148.0", + "markdown-preview": "0.149.0", "metrics": "0.48.0", "notifications": "0.46.0", "open-on-github": "0.36.0", From 4b5b64f782493e32ce414acf61e2236459ffbda3 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sat, 16 May 2015 00:06:52 +0200 Subject: [PATCH 1263/1783] Return scopes at very end of token for the last token on a line --- src/tokenized-buffer.coffee | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 03b9dcaac..62a68202e 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -401,10 +401,14 @@ class TokenizedBuffer extends Model scopeDescriptorForPosition: (position) -> {row, column} = Point.fromObject(position) + positionIsEndOfLine = column is @tokenizedLines[row].text.length + iterator = TokenIterator.instance.reset(@tokenizedLines[row]) while iterator.next() - break if iterator.getScreenEnd() > column - new ScopeDescriptor(scopes: iterator.getScopes().slice()) + tokenEnd = iterator.getScreenEnd() + break if tokenEnd > column or (positionIsEndOfLine and tokenEnd is column) + + new ScopeDescriptor(scopes: iterator.getScopes()) tokenForPosition: (position) -> {row, column} = Point.fromObject(position) From 1923033198a857d248381046a2dec72e304493ad Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sat, 16 May 2015 00:12:43 +0200 Subject: [PATCH 1264/1783] Fix spurious lint error by rearranging syntax --- src/tokenized-line.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 3c6851eef..e7ed27406 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -321,7 +321,8 @@ class TokenizedLine leftTags.push(leftSuffix) if leftSuffix > 0 softWrapIndent = @indentLevel * @tabLength + (hangingIndent ? 0) - rightText = ' ' + rightText for i in [0...softWrapIndent] by 1 + for i in [0...softWrapIndent] by 1 + rightText = ' ' + rightText remainingSoftWrapIndent = softWrapIndent while remainingSoftWrapIndent > 0 indentToken = Math.min(remainingSoftWrapIndent, @tabLength) From 0c153a298e386e36a56cd21b0b42d946daea7ca3 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sat, 16 May 2015 00:46:31 +0200 Subject: [PATCH 1265/1783] Use scope of last token if we iterate off the end --- src/tokenized-buffer.coffee | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 62a68202e..3baba3b72 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -401,14 +401,19 @@ class TokenizedBuffer extends Model scopeDescriptorForPosition: (position) -> {row, column} = Point.fromObject(position) - positionIsEndOfLine = column is @tokenizedLines[row].text.length iterator = TokenIterator.instance.reset(@tokenizedLines[row]) while iterator.next() - tokenEnd = iterator.getScreenEnd() - break if tokenEnd > column or (positionIsEndOfLine and tokenEnd is column) + if iterator.getScreenEnd() > column + scopes = iterator.getScopes() + break - new ScopeDescriptor(scopes: iterator.getScopes()) + # rebuild scope of last token if we iterated off the end + unless scopes? + scopes = iterator.getScopes() + scopes.push(iterator.getScopeEnds().reverse()...) + + new ScopeDescriptor({scopes}) tokenForPosition: (position) -> {row, column} = Point.fromObject(position) From 66d9b30f990aafef47d2d45c95fb40e78534e351 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sat, 16 May 2015 02:15:42 +0200 Subject: [PATCH 1266/1783] :arrow_up: first-mate --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b7b03cfa7..d3c6f86f3 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "delegato": "^1", "emissary": "^1.3.3", "event-kit": "^1.1.1", - "first-mate": "^4.1.1", + "first-mate": "^4.1.2", "fs-plus": "^2.8.0", "fstream": "0.1.24", "fuzzaldrin": "^2.1", From 4ddbb01dfaee604e4547e3881c88dbff1f77a4a7 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sat, 16 May 2015 03:03:13 +0200 Subject: [PATCH 1267/1783] :arrow_up: language-shellscript for spec fixes against first-mate 4.x --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d3c6f86f3..7851e37a4 100644 --- a/package.json +++ b/package.json @@ -151,7 +151,7 @@ "language-ruby": "0.52.0", "language-ruby-on-rails": "0.21.0", "language-sass": "0.38.0", - "language-shellscript": "0.14.0", + "language-shellscript": "0.15.0", "language-source": "0.9.0", "language-sql": "0.15.0", "language-text": "0.6.0", From 1a8ebd561fc5f9c314b91a35fddf8f2f99ba9d49 Mon Sep 17 00:00:00 2001 From: simurai Date: Sat, 16 May 2015 14:26:01 +0900 Subject: [PATCH 1268/1783] :arrow_up: find-and-replace@v0.164.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 956aded57..bb8935277 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", - "find-and-replace": "0.163.0", + "find-and-replace": "0.164.0", "fuzzy-finder": "0.85.0", "git-diff": "0.55.0", "go-to-line": "0.30.0", From 6431807a960b2b8444079b2c56f5b6040300dc62 Mon Sep 17 00:00:00 2001 From: simurai Date: Sat, 16 May 2015 15:29:14 +0900 Subject: [PATCH 1269/1783] :arrow_up: find-and-replace@v0.165.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bb8935277..2fa31e17d 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", - "find-and-replace": "0.164.0", + "find-and-replace": "0.165.0", "fuzzy-finder": "0.85.0", "git-diff": "0.55.0", "go-to-line": "0.30.0", From aaf1e24c5da6b2b1578df8d5c420546f2afd9761 Mon Sep 17 00:00:00 2001 From: Thomas Johansen Date: Sat, 16 May 2015 09:29:17 +0200 Subject: [PATCH 1270/1783] :arrow_up: language-python@0.35.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2fa31e17d..24a740778 100644 --- a/package.json +++ b/package.json @@ -147,7 +147,7 @@ "language-perl": "0.24.0", "language-php": "0.23.0", "language-property-list": "0.8.0", - "language-python": "0.34.0", + "language-python": "0.35.0", "language-ruby": "0.52.0", "language-ruby-on-rails": "0.21.0", "language-sass": "0.38.0", From e9c4a87f88e943a74dea73a8bc9825057f21477a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Machist=C3=A9=20N=2E=20Quintana?= Date: Sun, 17 May 2015 08:26:41 -0400 Subject: [PATCH 1271/1783] :arrow_up: find-and-replace@0.166.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2fa31e17d..3d0aa9656 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", - "find-and-replace": "0.165.0", + "find-and-replace": "0.166.0", "fuzzy-finder": "0.85.0", "git-diff": "0.55.0", "go-to-line": "0.30.0", From dbc57abeb0f391119b013fb3ccd6d48712dbca1a Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 18 May 2015 11:50:13 +0200 Subject: [PATCH 1272/1783] :fire: Remove obsolete node pool --- src/lines-component.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lines-component.coffee b/src/lines-component.coffee index 6a49f16be..d99fbfbe1 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -21,7 +21,6 @@ class LinesComponent constructor: ({@presenter, @hostElement, @useShadowDOM, visible}) -> @tileComponentsByTileId = {} - @freeDomNodes = [] @domNode = document.createElement('div') @domNode.classList.add('lines') From d116a33202cd43e72da1aec0f8327d880290a805 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 18 May 2015 11:56:41 +0200 Subject: [PATCH 1273/1783] :fire: --- spec/text-editor-presenter-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 0e6632e52..889328386 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -5,7 +5,7 @@ TextBuffer = require 'text-buffer' TextEditor = require '../src/text-editor' TextEditorPresenter = require '../src/text-editor-presenter' -fdescribe "TextEditorPresenter", -> +describe "TextEditorPresenter", -> # These `describe` and `it` blocks mirror the structure of the ::state object. # Please maintain this structure when adding specs for new state fields. describe "::getState()", -> From dc6938ae377a837249a23260902cf860101537e4 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 18 May 2015 14:48:25 +0200 Subject: [PATCH 1274/1783] :art: --- src/tile-component.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tile-component.coffee b/src/tile-component.coffee index c31c4dcb6..868653d85 100644 --- a/src/tile-component.coffee +++ b/src/tile-component.coffee @@ -32,7 +32,7 @@ class TileComponent @newState = state unless @oldState @oldState = {tiles: {}} - @oldState.tiles[@id] = { lines: {}} + @oldState.tiles[@id] = {lines: {}} @newTileState = @newState.tiles[@id] @oldTileState = @oldState.tiles[@id] From ba0df9fecb64ef93a7967575334fee970827ef8f Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 18 May 2015 14:55:23 +0200 Subject: [PATCH 1275/1783] Avoid allocating an extra array --- src/text-editor-presenter.coffee | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index d65eada41..a95d4e9fd 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -306,19 +306,19 @@ class TextEditorPresenter tileForRow: (row) -> row - (row % @tileSize) - getVisibleTilesRange: -> - startTileRow = Math.max(0, @tileForRow(@startRow)) - endTileRow = Math.min( + getStartTileRow: -> + Math.max(0, @tileForRow(@startRow)) + + getEndTileRow: -> + Math.min( @tileForRow(@model.getScreenLineCount()), @tileForRow(@endRow) ) - [startTileRow..endTileRow] - updateTilesState: -> return unless @startRow? and @endRow? and @lineHeight? visibleTiles = {} - for startRow in @getVisibleTilesRange() by @tileSize + for startRow in [@getStartTileRow()..@getEndTileRow()] by @tileSize endRow = Math.min(@model.getScreenLineCount(), startRow + @tileSize) tile = @state.content.tiles[startRow] ?= {} From 77396466998322acb687b2a6a04846ca5d1b2a76 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 12 May 2015 09:00:15 -0700 Subject: [PATCH 1276/1783] Check for updates every 30 minutes --- src/browser/auto-update-manager.coffee | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/browser/auto-update-manager.coffee b/src/browser/auto-update-manager.coffee index 654a8de67..0fd5bb792 100644 --- a/src/browser/auto-update-manager.coffee +++ b/src/browser/auto-update-manager.coffee @@ -53,7 +53,11 @@ class AutoUpdateManager @emitUpdateAvailableEvent(@getWindows()...) # Only released versions should check for updates. - @check(hidePopups: true) unless /\w{7}/.test(@version) + unless /\w{7}/.test(@version) + checkForUpdates = => @check(hidePopups: true) + thirtyMinutes = 1000 * 60 * 30 + setInterval(checkForUpdates, thirtyMinutes) + checkForUpdates() switch process.platform when 'win32' From 672cb89e848c5b04ec8d6f9dd12c0d30167e15d7 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 13 May 2015 08:30:51 -0700 Subject: [PATCH 1277/1783] Extract schedule update check helper --- src/browser/auto-update-manager.coffee | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/browser/auto-update-manager.coffee b/src/browser/auto-update-manager.coffee index 0fd5bb792..5bd945310 100644 --- a/src/browser/auto-update-manager.coffee +++ b/src/browser/auto-update-manager.coffee @@ -53,11 +53,7 @@ class AutoUpdateManager @emitUpdateAvailableEvent(@getWindows()...) # Only released versions should check for updates. - unless /\w{7}/.test(@version) - checkForUpdates = => @check(hidePopups: true) - thirtyMinutes = 1000 * 60 * 30 - setInterval(checkForUpdates, thirtyMinutes) - checkForUpdates() + @scheduleUpdateCheck() unless /\w{7}/.test(@version) switch process.platform when 'win32' @@ -79,6 +75,12 @@ class AutoUpdateManager getState: -> @state + scheduleUpdateCheck: -> + checkForUpdates = => @check(hidePopups: true) + thirtyMinutes = 1000 * 60 * 30 + setInterval(checkForUpdates, thirtyMinutes) + checkForUpdates() + check: ({hidePopups}={}) -> unless hidePopups autoUpdater.once 'update-not-available', @onUpdateNotAvailable From 655ce1af77b289da481e074d309ad42d4965b207 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 15 May 2015 11:33:22 -0700 Subject: [PATCH 1278/1783] 30 minutes -> 4 hours --- src/browser/auto-update-manager.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/browser/auto-update-manager.coffee b/src/browser/auto-update-manager.coffee index 5bd945310..a2c239789 100644 --- a/src/browser/auto-update-manager.coffee +++ b/src/browser/auto-update-manager.coffee @@ -77,8 +77,8 @@ class AutoUpdateManager scheduleUpdateCheck: -> checkForUpdates = => @check(hidePopups: true) - thirtyMinutes = 1000 * 60 * 30 - setInterval(checkForUpdates, thirtyMinutes) + fourHours = 1000 * 60 * 60 * 4 + setInterval(checkForUpdates, fourHours) checkForUpdates() check: ({hidePopups}={}) -> From 9c13120c798b87fa2dd4fd577221a76512d7e3d4 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 18 May 2015 09:25:42 -0700 Subject: [PATCH 1279/1783] :arrow_up: open-on-github@0.37 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ce58fe9dc..28e35df4f 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "markdown-preview": "0.149.0", "metrics": "0.48.0", "notifications": "0.46.0", - "open-on-github": "0.36.0", + "open-on-github": "0.37.0", "package-generator": "0.39.0", "release-notes": "0.52.0", "settings-view": "0.199.0", From 4dc1dfd4fabe080fe7145aa873b5c63df691e9ab Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 18 May 2015 09:27:38 -0700 Subject: [PATCH 1280/1783] :arrow_up: language-clojure@0.15 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 28e35df4f..12d6d2b89 100644 --- a/package.json +++ b/package.json @@ -128,7 +128,7 @@ "whitespace": "0.29.0", "wrap-guide": "0.33.0", "language-c": "0.44.0", - "language-clojure": "0.14.0", + "language-clojure": "0.15.0", "language-coffee-script": "0.40.0", "language-csharp": "0.5.0", "language-css": "0.29.0", From abebdb5a35a0207c00b69a9dc6d96fe79acaca7f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 18 May 2015 09:32:20 -0700 Subject: [PATCH 1281/1783] :arrow_up: notifications@0.47 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 12d6d2b89..4249db43f 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "link": "0.30.0", "markdown-preview": "0.149.0", "metrics": "0.48.0", - "notifications": "0.46.0", + "notifications": "0.47.0", "open-on-github": "0.37.0", "package-generator": "0.39.0", "release-notes": "0.52.0", From dde59f5c6bbc79d04f17a04600b814d44e72eedf Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 18 May 2015 09:34:25 -0700 Subject: [PATCH 1282/1783] :arrow_up: language-ruby@0.53 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4249db43f..e98d5ce2d 100644 --- a/package.json +++ b/package.json @@ -148,7 +148,7 @@ "language-php": "0.23.0", "language-property-list": "0.8.0", "language-python": "0.35.0", - "language-ruby": "0.52.0", + "language-ruby": "0.53.0", "language-ruby-on-rails": "0.21.0", "language-sass": "0.38.0", "language-shellscript": "0.14.0", From 8556f39c6039a2b5b881c2374d1cc2977b2061b8 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 18 May 2015 13:58:59 -0700 Subject: [PATCH 1283/1783] :arrow_up: autocomplete-plus --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e98d5ce2d..330117ff3 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "autocomplete-atom-api": "0.9.0", "autocomplete-css": "0.7.2", "autocomplete-html": "0.7.2", - "autocomplete-plus": "2.16.3", + "autocomplete-plus": "2.17.0", "autocomplete-snippets": "1.6.1", "autoflow": "0.23.0", "autosave": "0.20.0", From db9b655d49489e0f72c39ce562612be755c7392c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 18 May 2015 11:18:33 -0700 Subject: [PATCH 1284/1783] Mark which grammars are from bundled packages --- src/package.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/package.coffee b/src/package.coffee index b48ed8014..65c7af822 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -303,6 +303,7 @@ class Package try grammar = atom.grammars.readGrammarSync(grammarPath) grammar.packageName = @name + grammar.bundledPackage = @bundledPackage @grammars.push(grammar) grammar.activate() catch error @@ -322,6 +323,7 @@ class Package atom.notifications.addFatalError("Failed to load a #{@name} package grammar", {stack, detail, dismissable: true}) else grammar.packageName = @name + grammar.bundledPackage = @bundledPackage @grammars.push(grammar) grammar.activate() if @grammarsActivated callback() From 403f7cbc6bbe6e5d567add6fd2bc4bf0f75db73a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 18 May 2015 11:19:08 -0700 Subject: [PATCH 1285/1783] Favor non bundle packages when breaking ties --- src/grammar-registry.coffee | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/grammar-registry.coffee b/src/grammar-registry.coffee index 568de483a..bccfd4569 100644 --- a/src/grammar-registry.coffee +++ b/src/grammar-registry.coffee @@ -35,7 +35,16 @@ class GrammarRegistry extends FirstMate.GrammarRegistry # * `fileContents` A {String} of text for the file path. # # Returns a {Grammar}, never null. - selectGrammar: (filePath, fileContents) -> super + selectGrammar: (filePath, fileContents) -> + bestMatch = null + highestScore = -Infinity + for grammar in @grammars + score = grammar.getScore(filePath, fileContents) + if score > highestScore + bestMatch = grammar + else if score is highestScore + bestMatch = grammar if bestMatch.bundledPackage and not grammar.bundledPackage + bestMatch clearObservers: -> @off() if includeDeprecatedAPIs From 8b25eb4f0f32a4986422faf073a7bc6c4e026329 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 18 May 2015 11:21:27 -0700 Subject: [PATCH 1286/1783] Guard against missing best match --- src/grammar-registry.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/grammar-registry.coffee b/src/grammar-registry.coffee index bccfd4569..ce08c09ce 100644 --- a/src/grammar-registry.coffee +++ b/src/grammar-registry.coffee @@ -40,10 +40,10 @@ class GrammarRegistry extends FirstMate.GrammarRegistry highestScore = -Infinity for grammar in @grammars score = grammar.getScore(filePath, fileContents) - if score > highestScore + if score > highestScore or not bestMatch? bestMatch = grammar - else if score is highestScore - bestMatch = grammar if bestMatch.bundledPackage and not grammar.bundledPackage + else if score is highestScore and bestMatch?.bundledPackage + bestMatch = grammar unless grammar.bundledPackage bestMatch clearObservers: -> From 84c4ee4c79ac0da95b6cc3e2fafdba03d15314ea Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 18 May 2015 11:24:14 -0700 Subject: [PATCH 1287/1783] atom.syntax -> atom.grammars --- spec/{syntax-spec.coffee => grammars-spec.coffee} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename spec/{syntax-spec.coffee => grammars-spec.coffee} (99%) diff --git a/spec/syntax-spec.coffee b/spec/grammars-spec.coffee similarity index 99% rename from spec/syntax-spec.coffee rename to spec/grammars-spec.coffee index ecc0c0406..975fc3ea9 100644 --- a/spec/syntax-spec.coffee +++ b/spec/grammars-spec.coffee @@ -2,7 +2,7 @@ path = require 'path' fs = require 'fs-plus' temp = require 'temp' -describe "the `syntax` global", -> +describe "the `grammars` global", -> beforeEach -> waitsForPromise -> atom.packages.activatePackage('language-text') From 4378255ab67b367a6a982da858474e73c43ed4d8 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 18 May 2015 11:24:34 -0700 Subject: [PATCH 1288/1783] syntax2 -> grammars2 --- spec/grammars-spec.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/grammars-spec.coffee b/spec/grammars-spec.coffee index 975fc3ea9..92807a32e 100644 --- a/spec/grammars-spec.coffee +++ b/spec/grammars-spec.coffee @@ -25,9 +25,9 @@ describe "the `grammars` global", -> filePath = '/foo/bar/file.js' expect(atom.grammars.selectGrammar(filePath).name).not.toBe 'Ruby' atom.grammars.setGrammarOverrideForPath(filePath, 'source.ruby') - syntax2 = atom.deserializers.deserialize(atom.grammars.serialize()) - syntax2.addGrammar(grammar) for grammar in atom.grammars.grammars when grammar isnt atom.grammars.nullGrammar - expect(syntax2.selectGrammar(filePath).name).toBe 'Ruby' + grammars2 = atom.deserializers.deserialize(atom.grammars.serialize()) + grammars2.addGrammar(grammar) for grammar in atom.grammars.grammars when grammar isnt atom.grammars.nullGrammar + expect(grammars2.selectGrammar(filePath).name).toBe 'Ruby' describe ".selectGrammar(filePath)", -> it "can use the filePath to load the correct grammar based on the grammar's filetype", -> From 00505188fa53e4d8b81e97cda5ba7ca3c63bb593 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 18 May 2015 13:49:02 -0700 Subject: [PATCH 1289/1783] Add spec for grammar score tie-breaking --- .../package-with-rb-filetype/grammars/rb.cson | 11 +++++++++++ .../packages/package-with-rb-filetype/package.json | 4 ++++ spec/grammars-spec.coffee | 10 ++++++++++ src/grammar-registry.coffee | 1 + 4 files changed, 26 insertions(+) create mode 100644 spec/fixtures/packages/package-with-rb-filetype/grammars/rb.cson create mode 100644 spec/fixtures/packages/package-with-rb-filetype/package.json diff --git a/spec/fixtures/packages/package-with-rb-filetype/grammars/rb.cson b/spec/fixtures/packages/package-with-rb-filetype/grammars/rb.cson new file mode 100644 index 000000000..8b4d85412 --- /dev/null +++ b/spec/fixtures/packages/package-with-rb-filetype/grammars/rb.cson @@ -0,0 +1,11 @@ +'name': 'Test Ruby' +'scopeName': 'test.rb' +'fileTypes': [ + 'rb' +] +'patterns': [ + { + 'match': 'ruby' + 'name': 'meta.class.ruby' + } +] diff --git a/spec/fixtures/packages/package-with-rb-filetype/package.json b/spec/fixtures/packages/package-with-rb-filetype/package.json new file mode 100644 index 000000000..350967dc5 --- /dev/null +++ b/spec/fixtures/packages/package-with-rb-filetype/package.json @@ -0,0 +1,4 @@ +{ + "name": "package-with-rb-filetype", + "version": "1.0.0" +} diff --git a/spec/grammars-spec.coffee b/spec/grammars-spec.coffee index 92807a32e..52c7ea16c 100644 --- a/spec/grammars-spec.coffee +++ b/spec/grammars-spec.coffee @@ -94,6 +94,16 @@ describe "the `grammars` global", -> grammar2 = atom.grammars.loadGrammarSync(grammarPath2) expect(atom.grammars.selectGrammar('more.test', '')).toBe grammar2 + it "favors non-bundled packages when breaking scoring ties", -> + waitsForPromise -> + atom.packages.activatePackage(path.join(__dirname, 'fixtures', 'packages', 'package-with-rb-filetype')) + + runs -> + atom.grammars.grammarForScopeName('source.ruby').bundledPackage = true + atom.grammars.grammarForScopeName('test.rb').bundledPackage = false + + expect(atom.grammars.selectGrammar('test.rb').scopeName).toBe 'test.rb' + describe "when there is no file path", -> it "does not throw an exception (regression)", -> expect(-> atom.grammars.selectGrammar(null, '#!/usr/bin/ruby')).not.toThrow() diff --git a/src/grammar-registry.coffee b/src/grammar-registry.coffee index ce08c09ce..7b1ef823f 100644 --- a/src/grammar-registry.coffee +++ b/src/grammar-registry.coffee @@ -42,6 +42,7 @@ class GrammarRegistry extends FirstMate.GrammarRegistry score = grammar.getScore(filePath, fileContents) if score > highestScore or not bestMatch? bestMatch = grammar + highestScore = score else if score is highestScore and bestMatch?.bundledPackage bestMatch = grammar unless grammar.bundledPackage bestMatch From 1ad1172847c3851abf52af4e946b4b336443ee6c Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Mon, 18 May 2015 18:34:45 -0400 Subject: [PATCH 1290/1783] :arrow_up: bootstrap@3.3.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 330117ff3..30d3deb11 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "atom-keymap": "^5.1.2", "atom-space-pen-views": "^2.0.4", "babel-core": "^5.1.11", - "bootstrap": "git+https://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372", + "bootstrap": "^3.3.4", "clear-cut": "^2.0.1", "coffee-cash": "0.8.0", "coffee-script": "1.8.0", From 33ac25479b443559f4cf695ae5b3a9233a4362d7 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 18 May 2015 15:39:57 -0700 Subject: [PATCH 1291/1783] :art: Correct indentation --- spec/grammars-spec.coffee | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/spec/grammars-spec.coffee b/spec/grammars-spec.coffee index 52c7ea16c..cc975468f 100644 --- a/spec/grammars-spec.coffee +++ b/spec/grammars-spec.coffee @@ -95,14 +95,14 @@ describe "the `grammars` global", -> expect(atom.grammars.selectGrammar('more.test', '')).toBe grammar2 it "favors non-bundled packages when breaking scoring ties", -> - waitsForPromise -> - atom.packages.activatePackage(path.join(__dirname, 'fixtures', 'packages', 'package-with-rb-filetype')) + waitsForPromise -> + atom.packages.activatePackage(path.join(__dirname, 'fixtures', 'packages', 'package-with-rb-filetype')) - runs -> - atom.grammars.grammarForScopeName('source.ruby').bundledPackage = true - atom.grammars.grammarForScopeName('test.rb').bundledPackage = false + runs -> + atom.grammars.grammarForScopeName('source.ruby').bundledPackage = true + atom.grammars.grammarForScopeName('test.rb').bundledPackage = false - expect(atom.grammars.selectGrammar('test.rb').scopeName).toBe 'test.rb' + expect(atom.grammars.selectGrammar('test.rb').scopeName).toBe 'test.rb' describe "when there is no file path", -> it "does not throw an exception (regression)", -> From c91ddbefd04ef19701884a7cf0b76000f2e2a7b2 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Mon, 18 May 2015 19:26:44 -0400 Subject: [PATCH 1292/1783] Use bash highlighting instead of bat --- docs/build-instructions/windows.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/build-instructions/windows.md b/docs/build-instructions/windows.md index 3f8c27660..8cfe74e72 100644 --- a/docs/build-instructions/windows.md +++ b/docs/build-instructions/windows.md @@ -24,14 +24,14 @@ ## Instructions - ```bat - # Use the `Git Shell` app which was installed by GitHub for Windows. Also Make - # sure you have logged into the GitHub for Windows GUI App. - cd C:\ - git clone https://github.com/atom/atom/ - cd atom - script/build # Creates application in the `Program Files` directory - ``` +```bash +# Use the `Git Shell` program which was installed by GitHub for Windows. +# Also make sure that you are logged into GitHub for Windows. +cd C:\ +git clone https://github.com/atom/atom/ +cd atom +script/build # Creates application in the `Program Files` directory +``` ## Why do I have to use GitHub for Windows? From 54ca8957776949e2bf3a1e021a3436640dd15eb3 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Mon, 18 May 2015 19:30:05 -0400 Subject: [PATCH 1293/1783] Use configured font settings in tooltips --- static/bootstrap-overrides.less | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/static/bootstrap-overrides.less b/static/bootstrap-overrides.less index 258de6320..df61c0171 100644 --- a/static/bootstrap-overrides.less +++ b/static/bootstrap-overrides.less @@ -26,3 +26,9 @@ body { font-family: inherit; // inherit from html font-size: inherit; // inherit from html } + +// Latest Bootstrap specifies the font properties again instead of inheriting +.tooltip { + font-family: @font-family; + font-size: @font-size; +} From 458b727fe0347d36dcc3f14d466341b2e3c69ca8 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 19 May 2015 01:51:53 +0200 Subject: [PATCH 1294/1783] :arrow_up: first-mate --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ba3a2e20b..d248773a6 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "delegato": "^1", "emissary": "^1.3.3", "event-kit": "^1.1.1", - "first-mate": "^4.1.2", + "first-mate": "^4.1.3", "fs-plus": "^2.8.0", "fstream": "0.1.24", "fuzzaldrin": "^2.1", From 14a5d5f59b0b9ec562af97766de7cabc468bf828 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 18 May 2015 16:55:33 -0700 Subject: [PATCH 1295/1783] :arrow_up: settings-view@0.200 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 330117ff3..9e636cae7 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "open-on-github": "0.37.0", "package-generator": "0.39.0", "release-notes": "0.52.0", - "settings-view": "0.199.0", + "settings-view": "0.200.0", "snippets": "0.89.0", "spell-check": "0.58.0", "status-bar": "0.72.0", From f8c4f50926c62f1b48cbd2b9904b1eb59ad61311 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 18 May 2015 17:09:34 -0700 Subject: [PATCH 1296/1783] :arrow_up: settings-view@0.201 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9e636cae7..b85390f9e 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "open-on-github": "0.37.0", "package-generator": "0.39.0", "release-notes": "0.52.0", - "settings-view": "0.200.0", + "settings-view": "0.201.0", "snippets": "0.89.0", "spell-check": "0.58.0", "status-bar": "0.72.0", From 7683b52dd2bbb6147bc9157356ca477584e75a4b Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 18 May 2015 17:48:45 -0700 Subject: [PATCH 1297/1783] :arrow_up: metrics@0.49.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b85390f9e..f3c25fbe8 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "keybinding-resolver": "0.32.0", "link": "0.30.0", "markdown-preview": "0.149.0", - "metrics": "0.48.0", + "metrics": "0.49.0", "notifications": "0.47.0", "open-on-github": "0.37.0", "package-generator": "0.39.0", From dea55cbc7e0e8d6e34e5a02b6f395f17206c3ee9 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 18 May 2015 18:27:44 -0700 Subject: [PATCH 1298/1783] :arrow_up: settings-view@0.202 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f3c25fbe8..0a148ba7a 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "open-on-github": "0.37.0", "package-generator": "0.39.0", "release-notes": "0.52.0", - "settings-view": "0.201.0", + "settings-view": "0.202.0", "snippets": "0.89.0", "spell-check": "0.58.0", "status-bar": "0.72.0", From 760ee81c9bc19bac156fe664ffc3d9abe1764399 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 18 May 2015 18:58:04 -0700 Subject: [PATCH 1299/1783] :arrow_up: deprecation-cop@0.49 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0a148ba7a..b5ea5f934 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "bookmarks": "0.35.0", "bracket-matcher": "0.74.0", "command-palette": "0.36.0", - "deprecation-cop": "0.48.0", + "deprecation-cop": "0.49.0", "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", From b9138967e185f238c26cbf0ff4c79a6e93c18c09 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 19 May 2015 09:24:44 +0200 Subject: [PATCH 1300/1783] :art: --- src/tile-component.coffee | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/tile-component.coffee b/src/tile-component.coffee index 868653d85..0f8fd0209 100644 --- a/src/tile-component.coffee +++ b/src/tile-component.coffee @@ -15,15 +15,14 @@ module.exports = class TileComponent placeholderTextDiv: null - constructor: ({@presenter, @id, @domNode}) -> + constructor: ({@presenter, @id}) -> @measuredLines = new Set @lineNodesByLineId = {} @screenRowsByLineId = {} @lineIdsByScreenRow = {} - @domNode ?= document.createElement("div") + @domNode = document.createElement("div") @domNode.style.position = "absolute" @domNode.style.display = "block" - @domNode.classList.add("tile") getDomNode: -> @domNode From 90b1228622d3052efdadf328148380c761606f07 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 19 May 2015 10:26:44 +0200 Subject: [PATCH 1301/1783] :racehorse: Bump tileCount to 6 --- 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 a95d4e9fd..fae99f209 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -20,7 +20,7 @@ class TextEditorPresenter @measuredHorizontalScrollbarHeight = horizontalScrollbarHeight @measuredVerticalScrollbarWidth = verticalScrollbarWidth @gutterWidth ?= 0 - @tileCount ?= 3 + @tileCount ?= 6 @disposables = new CompositeDisposable @emitter = new Emitter From 2b2e2d86ffe47997fb37c901b14eee1a3a5e04cf Mon Sep 17 00:00:00 2001 From: simurai Date: Tue, 19 May 2015 20:09:08 +0900 Subject: [PATCH 1302/1783] :arrow_up: notifications@v0.48.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b5ea5f934..e435c6517 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "link": "0.30.0", "markdown-preview": "0.149.0", "metrics": "0.49.0", - "notifications": "0.47.0", + "notifications": "0.48.0", "open-on-github": "0.37.0", "package-generator": "0.39.0", "release-notes": "0.52.0", From 4038140f5baa846fed3683bc7455a1490f05cecd Mon Sep 17 00:00:00 2001 From: simurai Date: Tue, 19 May 2015 21:34:07 +0900 Subject: [PATCH 1303/1783] :arrow_up: one-dark/light-ui@v0.8.2 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index e435c6517..e541d5609 100644 --- a/package.json +++ b/package.json @@ -77,10 +77,10 @@ "atom-light-ui": "0.41.0", "base16-tomorrow-dark-theme": "0.26.0", "base16-tomorrow-light-theme": "0.9.0", - "one-dark-ui": "0.8.1", + "one-dark-ui": "0.8.2", "one-dark-syntax": "0.5.0", "one-light-syntax": "0.6.0", - "one-light-ui": "0.8.1", + "one-light-ui": "0.8.2", "solarized-dark-syntax": "0.35.0", "solarized-light-syntax": "0.21.0", "archive-view": "0.57.0", From 564d75c534b5cf1fb0176977ac6687564048b10e Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 19 May 2015 17:22:25 +0200 Subject: [PATCH 1304/1783] :arrow_up: first-mate --- package.json | 2 +- src/tokenized-buffer.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index f5d344ea5..912fe0ede 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "delegato": "^1", "emissary": "^1.3.3", "event-kit": "^1.1.1", - "first-mate": "^4.1.3", + "first-mate": "^4.1.4", "fs-plus": "^2.8.0", "fstream": "0.1.24", "fuzzaldrin": "^2.1", diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 3baba3b72..a709d9755 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -315,7 +315,7 @@ class TokenizedBuffer extends Model @buildPlaceholderTokenizedLineForRow(row) for row in [startRow..endRow] buildPlaceholderTokenizedLineForRow: (row) -> - openScopes = [@grammar.idForScope(@grammar.scopeName)] + openScopes = [@grammar.startIdForScope(@grammar.scopeName)] text = @buffer.lineForRow(row) tags = [text.length] tabLength = @getTabLength() From 96c180d836e4ce19048e3f1d0add7d4024bf05cf Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 19 May 2015 08:45:44 -0700 Subject: [PATCH 1305/1783] :arrow_up: deprecation-cop@0.50 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e541d5609..4d3b079d0 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "bookmarks": "0.35.0", "bracket-matcher": "0.74.0", "command-palette": "0.36.0", - "deprecation-cop": "0.49.0", + "deprecation-cop": "0.50.0", "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", From 91e968cfe6f6c3685aaf782ab4e9003234b27748 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 19 May 2015 08:48:26 -0700 Subject: [PATCH 1306/1783] :arrow_up: language-ruby@0.54 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4d3b079d0..bc49e8e46 100644 --- a/package.json +++ b/package.json @@ -148,7 +148,7 @@ "language-php": "0.23.0", "language-property-list": "0.8.0", "language-python": "0.35.0", - "language-ruby": "0.53.0", + "language-ruby": "0.54.0", "language-ruby-on-rails": "0.21.0", "language-sass": "0.38.0", "language-shellscript": "0.14.0", From 13db572ac84a0979294bd3dacde8ce7f0c410713 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 19 May 2015 17:55:36 +0200 Subject: [PATCH 1307/1783] Avoid error in donna npm while generating documentation --- src/token-iterator.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/token-iterator.coffee b/src/token-iterator.coffee index 800f76d03..65a4c3100 100644 --- a/src/token-iterator.coffee +++ b/src/token-iterator.coffee @@ -2,8 +2,6 @@ module.exports = class TokenIterator - @instance: new this - constructor: (line) -> @reset(line) if line? @@ -83,3 +81,5 @@ class TokenIterator isAtomic: -> @isSoftTab() or @isHardTab() or @isSoftWrapIndentation() or @isPairedCharacter() + +TokenIterator.instance = new TokenIterator From 2ecca5b042c3d55e0b99d907e14ae070739dc8f2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 19 May 2015 09:44:33 -0700 Subject: [PATCH 1308/1783] :arrow_up: fuzzy-finder@0.86 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bc49e8e46..667a4f816 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,7 @@ "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", "find-and-replace": "0.166.0", - "fuzzy-finder": "0.85.0", + "fuzzy-finder": "0.86.0", "git-diff": "0.55.0", "go-to-line": "0.30.0", "grammar-selector": "0.47.0", From 84baab7e3f7e3e4171feace3fab82da16d640948 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 19 May 2015 09:55:15 -0700 Subject: [PATCH 1309/1783] :arrow_up: fuzzy-finder@0.87 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 667a4f816..c905f1d24 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,7 @@ "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", "find-and-replace": "0.166.0", - "fuzzy-finder": "0.86.0", + "fuzzy-finder": "0.87.0", "git-diff": "0.55.0", "go-to-line": "0.30.0", "grammar-selector": "0.47.0", From 9fee62d884b41dc3d52b4178651a294e56cff060 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 19 May 2015 19:01:11 +0200 Subject: [PATCH 1310/1783] :fire: Remove comment --- src/text-editor-presenter.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index fae99f209..a86d5afc1 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -577,7 +577,6 @@ class TextEditorPresenter @lineNumberGutter.lineNumbers[id] = {screenRow, bufferRow, softWrapped, top, decorationClasses, foldable} visibleLineNumberIds[id] = true - # FIXME: We should either rely on @mouseWheelScreenRow or convert this to use tiles. if @mouseWheelScreenRow? bufferRow = @model.bufferRowForScreenRow(@mouseWheelScreenRow) wrapCount = @mouseWheelScreenRow - @model.screenRowForBufferRow(bufferRow) From 0db34d519296e6f2d6652b495cb2fe6f71f021bf Mon Sep 17 00:00:00 2001 From: Mostafa Eweda Date: Tue, 19 May 2015 10:35:07 -0700 Subject: [PATCH 1311/1783] Update language-php to 0.24.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c905f1d24..996f1d4e4 100644 --- a/package.json +++ b/package.json @@ -145,7 +145,7 @@ "language-mustache": "0.11.0", "language-objective-c": "0.15.0", "language-perl": "0.24.0", - "language-php": "0.23.0", + "language-php": "0.24.0", "language-property-list": "0.8.0", "language-python": "0.35.0", "language-ruby": "0.54.0", From 622a18a6c56637be0e3785c192327ac4d8f0f03d Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 19 May 2015 13:16:38 -0700 Subject: [PATCH 1312/1783] :arrow_up: text-buffer --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 996f1d4e4..d330a31e2 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "space-pen": "3.8.2", "stacktrace-parser": "0.1.1", "temp": "0.8.1", - "text-buffer": "6.0.0", + "text-buffer": "6.0.1", "theorist": "^1.0.2", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6" From a109b3811c61f6115a398a757f09feae648f3eb7 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 19 May 2015 23:19:45 +0200 Subject: [PATCH 1313/1783] Add TokenizedLine::getTokenIterator This will not be part of the public API but will replace another non-public API usage in autocomplete-plus. --- src/tokenized-line.coffee | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index e7ed27406..acaa16378 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -143,8 +143,10 @@ class TokenizedLine @lineIsWhitespaceOnly = true @firstTrailingWhitespaceIndex = 0 + getTokenIterator: -> TokenIterator.instance.reset(this) + Object.defineProperty @prototype, 'tokens', get: -> - iterator = TokenIterator.instance.reset(this) + iterator = @getTokenIterator() tokens = [] while iterator.next() @@ -209,7 +211,7 @@ class TokenizedLine tokenStartColumn = 0 - iterator = TokenIterator.instance.reset(this) + iterator = @getTokenIterator() while iterator.next() break if iterator.getScreenEnd() > column @@ -230,7 +232,7 @@ class TokenizedLine column screenColumnForBufferColumn: (targetBufferColumn, options) -> - iterator = TokenIterator.instance.reset(this) + iterator = @getTokenIterator() while iterator.next() tokenBufferStart = iterator.getBufferStart() tokenBufferEnd = iterator.getBufferEnd() @@ -243,7 +245,7 @@ class TokenizedLine iterator.getScreenEnd() bufferColumnForScreenColumn: (targetScreenColumn) -> - iterator = TokenIterator.instance.reset(this) + iterator = @getTokenIterator() while iterator.next() tokenScreenStart = iterator.getScreenStart() tokenScreenEnd = iterator.getScreenEnd() @@ -438,7 +440,7 @@ class TokenizedLine @endOfLineInvisibles.push(eol) if eol isComment: -> - iterator = TokenIterator.instance.reset(this) + iterator = @getTokenIterator() while iterator.next() scopes = iterator.getScopes() continue if scopes.length is 1 From 3ddc105d6ae1f8cfafb2e836780ed256b0d08325 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 19 May 2015 14:27:08 -0700 Subject: [PATCH 1314/1783] :arrow_up: keybinding-resolver@0.33 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d330a31e2..851dbf24b 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,7 @@ "grammar-selector": "0.47.0", "image-view": "0.54.0", "incompatible-packages": "0.24.0", - "keybinding-resolver": "0.32.0", + "keybinding-resolver": "0.33.0", "link": "0.30.0", "markdown-preview": "0.149.0", "metrics": "0.49.0", From 171fb275820e4ec72982043d29c4ee528359ec01 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 19 May 2015 14:54:14 -0700 Subject: [PATCH 1315/1783] :arrow_up: notifications@0.49.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 851dbf24b..67235d654 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "link": "0.30.0", "markdown-preview": "0.149.0", "metrics": "0.49.0", - "notifications": "0.48.0", + "notifications": "0.49.0", "open-on-github": "0.37.0", "package-generator": "0.39.0", "release-notes": "0.52.0", From a1cc35b270fb0890b6a61de46a63bfe91e996228 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 19 May 2015 15:18:20 -0700 Subject: [PATCH 1316/1783] Fix DisplayBuffer spec Marker updates now happen after all buffer changes --- spec/display-buffer-spec.coffee | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index 23c4840bc..27a538464 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -1023,11 +1023,14 @@ describe "DisplayBuffer", -> expect(markerChangedHandler).not.toHaveBeenCalled() expect(marker2ChangedHandler).not.toHaveBeenCalled() expect(marker3ChangedHandler).not.toHaveBeenCalled() - # but still updates the markers + + # markers positions are updated based on the text change expect(marker.getScreenRange()).toEqual [[5, 4], [5, 10]] expect(marker.getHeadScreenPosition()).toEqual [5, 10] expect(marker.getTailScreenPosition()).toEqual [5, 4] - expect(marker2.isValid()).toBeTruthy() + + # but marker snapshots are not restored until the end of the undo. + expect(marker2.isValid()).toBeFalsy() expect(marker3.isValid()).toBeFalsy() buffer.undo() @@ -1035,6 +1038,8 @@ describe "DisplayBuffer", -> expect(markerChangedHandler).toHaveBeenCalled() expect(marker2ChangedHandler).toHaveBeenCalled() expect(marker3ChangedHandler).toHaveBeenCalled() + expect(marker2.isValid()).toBeTruthy() + expect(marker3.isValid()).toBeFalsy() # Redo change ---- @@ -1048,18 +1053,23 @@ describe "DisplayBuffer", -> expect(markerChangedHandler).not.toHaveBeenCalled() expect(marker2ChangedHandler).not.toHaveBeenCalled() expect(marker3ChangedHandler).not.toHaveBeenCalled() - # but still updates the markers + + # markers positions are updated based on the text change expect(marker.getScreenRange()).toEqual [[5, 7], [5, 13]] expect(marker.getHeadScreenPosition()).toEqual [5, 13] expect(marker.getTailScreenPosition()).toEqual [5, 7] + + # but marker snapshots are not restored until the end of the undo. expect(marker2.isValid()).toBeFalsy() - expect(marker3.isValid()).toBeTruthy() + expect(marker3.isValid()).toBeFalsy() buffer.redo() expect(changeHandler).toHaveBeenCalled() expect(markerChangedHandler).toHaveBeenCalled() expect(marker2ChangedHandler).toHaveBeenCalled() expect(marker3ChangedHandler).toHaveBeenCalled() + expect(marker2.isValid()).toBeFalsy() + expect(marker3.isValid()).toBeTruthy() it "updates the position of markers before emitting change events that aren't caused by a buffer change", -> displayBuffer.onDidChange changeHandler = jasmine.createSpy("changeHandler").andCallFake -> From e2f757ea01a7986a463839cf675811bc5adeb58b Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 19 May 2015 15:25:58 -0700 Subject: [PATCH 1317/1783] :arrow_up: settings-view@0.203.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 67235d654..29192daf0 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "open-on-github": "0.37.0", "package-generator": "0.39.0", "release-notes": "0.52.0", - "settings-view": "0.202.0", + "settings-view": "0.203.0", "snippets": "0.89.0", "spell-check": "0.58.0", "status-bar": "0.72.0", From 23f2a6a58f8a7560cdcc65d4ed4f23bb6f8b4bf2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 19 May 2015 15:51:45 -0700 Subject: [PATCH 1318/1783] Prepare 0.201 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 29192daf0..ff54ca11c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "0.200.0", + "version": "0.201.0", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From fcf7f77bf21e22f58783c6c74eb8bf11f96605a9 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 19 May 2015 16:35:52 -0700 Subject: [PATCH 1319/1783] :arrow_up: metrics@0.50.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ff54ca11c..52411da96 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "keybinding-resolver": "0.33.0", "link": "0.30.0", "markdown-preview": "0.149.0", - "metrics": "0.49.0", + "metrics": "0.50.0", "notifications": "0.49.0", "open-on-github": "0.37.0", "package-generator": "0.39.0", From db920468abadf1599e245c5e59d88319942735c1 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Tue, 19 May 2015 19:38:37 -0400 Subject: [PATCH 1320/1783] Wrap CLI columns at 100 --- src/browser/main.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/browser/main.coffee b/src/browser/main.coffee index 68b57a88e..1af0526dd 100644 --- a/src/browser/main.coffee +++ b/src/browser/main.coffee @@ -85,7 +85,7 @@ setupCoffeeCache = -> parseCommandLine = -> version = app.getVersion() - options = yargs(process.argv[1..]) + options = yargs(process.argv[1..]).wrap(100) options.usage """ Atom Editor v#{version} From f22daa42b535ee22fa87b3297d1ada62d4f24620 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Tue, 19 May 2015 19:40:31 -0400 Subject: [PATCH 1321/1783] :art: Update semver version range --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 98d763eb9..c1fadae46 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "theorist": "^1.0.2", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", - "yargs": ">=3.7.2 <4.0" + "yargs": "^3.7.2" }, "packageDependencies": { "atom-dark-syntax": "0.27.0", From ba98013eebcbe590820a6159fabd98338ca4fc6a Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 19 May 2015 16:40:39 -0700 Subject: [PATCH 1322/1783] :arrow_up: language-gfm@0.76.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 52411da96..fe27e5181 100644 --- a/package.json +++ b/package.json @@ -132,7 +132,7 @@ "language-coffee-script": "0.40.0", "language-csharp": "0.5.0", "language-css": "0.29.0", - "language-gfm": "0.75.0", + "language-gfm": "0.76.0", "language-git": "0.10.0", "language-go": "0.26.0", "language-html": "0.37.0", From 2bfbb7619e1b52f1f9ae39ed59f61bc85d543333 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 19 May 2015 17:48:53 -0700 Subject: [PATCH 1323/1783] Fix bug w/ markers mutated inside of change listeners --- spec/display-buffer-spec.coffee | 15 +++++++++++++++ src/marker.coffee | 6 +++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index 27a538464..6389f8105 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -1085,6 +1085,21 @@ describe "DisplayBuffer", -> expect(changeHandler).toHaveBeenCalled() expect(markerChangedHandler).toHaveBeenCalled() + it "emits the correct events when markers are mutated inside event listeners", -> + marker.onDidChange -> + if marker.getHeadScreenPosition().isEqual([5, 9]) + marker.setHeadScreenPosition([5, 8]) + + marker.setHeadScreenPosition([5, 9]) + + headChanges = for [event] in markerChangedHandler.argsForCall + {old: event.oldHeadScreenPosition, new: event.newHeadScreenPosition} + + expect(headChanges).toEqual [ + {old: [5, 10], new: [5, 9]} + {old: [5, 9], new: [5, 8]} + ] + describe "::findMarkers(attributes)", -> it "allows the startBufferRow and endBufferRow to be specified", -> marker1 = displayBuffer.markBufferRange([[0, 0], [3, 0]], class: 'a') diff --git a/src/marker.coffee b/src/marker.coffee index 942e25606..a0d8bda00 100644 --- a/src/marker.coffee +++ b/src/marker.coffee @@ -346,15 +346,15 @@ class Marker isValid } - @emit 'changed', changeEvent if Grim.includeDeprecatedAPIs - @emitter.emit 'did-change', changeEvent - @oldHeadBufferPosition = newHeadBufferPosition @oldHeadScreenPosition = newHeadScreenPosition @oldTailBufferPosition = newTailBufferPosition @oldTailScreenPosition = newTailScreenPosition @wasValid = isValid + @emit 'changed', changeEvent if Grim.includeDeprecatedAPIs + @emitter.emit 'did-change', changeEvent + getPixelRange: -> @displayBuffer.pixelRangeForScreenRange(@getScreenRange(), false) From 98dc253541680935745aa646317ce45af7961f92 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 19 May 2015 18:44:49 -0700 Subject: [PATCH 1324/1783] :arrow_up: apm@0.168 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index 1dce7e90b..64f937169 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.167.0" + "atom-package-manager": "0.168.0" } } From 526055cd70fa8ea58ab5657a402c0e1cd5c2820d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 19 May 2015 18:47:55 -0700 Subject: [PATCH 1325/1783] :arrow_up: yargs@3.9 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b2da54fc2..ae6f06540 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "theorist": "^1.0.2", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", - "yargs": "^3.7.2" + "yargs": "^3.9" }, "packageDependencies": { "atom-dark-syntax": "0.27.0", From 564692fd30e7c27695bb1bf79c882e4889140848 Mon Sep 17 00:00:00 2001 From: Mostafa Eweda Date: Fri, 15 May 2015 11:38:48 -0700 Subject: [PATCH 1326/1783] Update initial paths with local paths only --- src/atom.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/atom.coffee b/src/atom.coffee index 0d029b61d..2639eaca6 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -763,7 +763,8 @@ class Atom extends Model # Notify the browser project of the window's current project path watchProjectPath: -> @disposables.add @project.onDidChangePaths => - @constructor.updateLoadSetting('initialPaths', @project.getPaths()) + @constructor.updateLoadSetting('initialPaths', + @project.getPaths().filter((projectPath) -> fs.existsSync(projectPath))) exit: (status) -> app = remote.require('app') From d22eb697cc82b7dd88caf3420888772345efa922 Mon Sep 17 00:00:00 2001 From: Mostafa Eweda Date: Mon, 18 May 2015 19:03:59 -0700 Subject: [PATCH 1327/1783] Include remote paths, but skip normalization in the save/restore execution flow --- src/atom.coffee | 3 +-- src/browser/atom-application.coffee | 9 ++++++++- src/default-directory-provider.coffee | 9 ++++++++- src/window-event-handler.coffee | 8 ++++---- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/atom.coffee b/src/atom.coffee index 2639eaca6..0d029b61d 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -763,8 +763,7 @@ class Atom extends Model # Notify the browser project of the window's current project path watchProjectPath: -> @disposables.add @project.onDidChangePaths => - @constructor.updateLoadSetting('initialPaths', - @project.getPaths().filter((projectPath) -> fs.existsSync(projectPath))) + @constructor.updateLoadSetting('initialPaths', @project.getPaths()) exit: (status) -> app = remote.require('app') diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index d81660a49..91e423d15 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -369,7 +369,12 @@ class AtomApplication # :windowDimensions - Object with height and width keys. # :window - {AtomWindow} to open file paths in. openPaths: ({pathsToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, apiPreviewMode, windowDimensions, profileStartup, window}={}) -> - pathsToOpen = (fs.normalize(pathToOpen) for pathToOpen in pathsToOpen) + pathsToOpen = pathsToOpen.map (pathToOpen) -> + if fs.existsSync(pathToOpen) + fs.normalize(pathToOpen) + else + pathToOpen + locationsToOpen = (@locationForPathToOpen(pathToOpen) for pathToOpen in pathsToOpen) unless pidToKillWhenClosed or newWindow @@ -517,6 +522,8 @@ class AtomApplication new AtomWindow({bootstrapScript, @resourcePath, exitWhenDone, isSpec, specDirectory, devMode}) locationForPathToOpen: (pathToOpen) -> + {protocol} = url.parse(pathToOpen) + return {pathToOpen} if protocol? return {pathToOpen} unless pathToOpen return {pathToOpen} if fs.existsSync(pathToOpen) diff --git a/src/default-directory-provider.coffee b/src/default-directory-provider.coffee index 9e25e097b..0b3aef7c2 100644 --- a/src/default-directory-provider.coffee +++ b/src/default-directory-provider.coffee @@ -1,6 +1,7 @@ {Directory} = require 'pathwatcher' fs = require 'fs-plus' path = require 'path' +url = require 'url' module.exports = class DefaultDirectoryProvider @@ -21,7 +22,13 @@ class DefaultDirectoryProvider else projectPath - new Directory(directoryPath) + # TODO: Stop normalizing the path in pathwatcher's Directory. + directory = new Directory(directoryPath) + if (url.parse(directoryPath).protocol) + directory.path = directoryPath; + if (fs.isCaseInsensitive()) + directory.lowerCasePath = directoryPath.toLowerCase(); + directory # Public: Create a Directory that corresponds to the specified URI. # diff --git a/src/window-event-handler.coffee b/src/window-event-handler.coffee index 7d67e87ab..aeeee279c 100644 --- a/src/window-event-handler.coffee +++ b/src/window-event-handler.coffee @@ -23,12 +23,12 @@ class WindowEventHandler if pathToOpen? and needsProjectPaths if fs.existsSync(pathToOpen) atom.project.addPath(pathToOpen) + else if fs.existsSync(path.dirname(pathToOpen)) + atom.project.addPath(path.dirname(pathToOpen)) else - dirToOpen = path.dirname(pathToOpen) - if fs.existsSync(dirToOpen) - atom.project.addPath(dirToOpen) + atom.project.addPath(pathToOpen) - unless fs.isDirectorySync(pathToOpen) + if fs.isFileSync(pathToOpen) atom.workspace?.open(pathToOpen, {initialLine, initialColumn}) return From 506dbfd098b7557c363a5bb01e50aba7e2dd8219 Mon Sep 17 00:00:00 2001 From: Mostafa Eweda Date: Tue, 19 May 2015 11:14:25 -0700 Subject: [PATCH 1328/1783] Remove the trailing semicolon --- src/default-directory-provider.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/default-directory-provider.coffee b/src/default-directory-provider.coffee index 0b3aef7c2..7c900ded6 100644 --- a/src/default-directory-provider.coffee +++ b/src/default-directory-provider.coffee @@ -25,9 +25,9 @@ class DefaultDirectoryProvider # TODO: Stop normalizing the path in pathwatcher's Directory. directory = new Directory(directoryPath) if (url.parse(directoryPath).protocol) - directory.path = directoryPath; + directory.path = directoryPath if (fs.isCaseInsensitive()) - directory.lowerCasePath = directoryPath.toLowerCase(); + directory.lowerCasePath = directoryPath.toLowerCase() directory # Public: Create a Directory that corresponds to the specified URI. From c3552c95bc7d699fa5d91412c4f235fa41d50b91 Mon Sep 17 00:00:00 2001 From: Mostafa Eweda Date: Tue, 19 May 2015 17:10:45 -0700 Subject: [PATCH 1329/1783] Address comments + add tests --- spec/default-directory-provider-spec.coffee | 6 ++++++ spec/window-spec.coffee | 11 +++++++++++ src/browser/atom-application.coffee | 3 +-- src/default-directory-provider.coffee | 4 ++-- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/spec/default-directory-provider-spec.coffee b/spec/default-directory-provider-spec.coffee index 69370a77b..357348c4a 100644 --- a/spec/default-directory-provider-spec.coffee +++ b/spec/default-directory-provider-spec.coffee @@ -31,6 +31,12 @@ describe "DefaultDirectoryProvider", -> directory = provider.directoryForURISync(file) expect(directory.getPath()).toEqual tmp + it "creates a Directory with a path as a uri when passed a uri", -> + provider = new DefaultDirectoryProvider() + uri = 'remote://server:6792/path/to/a/dir' + directory = provider.directoryForURISync(uri) + expect(directory.getPath()).toEqual uri + describe ".directoryForURI(uri)", -> it "returns a Promise that resolves to a Directory with a path that matches the uri", -> provider = new DefaultDirectoryProvider() diff --git a/spec/window-spec.coffee b/spec/window-spec.coffee index 376a71ab3..94e605a36 100644 --- a/spec/window-spec.coffee +++ b/spec/window-spec.coffee @@ -293,3 +293,14 @@ describe "Window", -> pathToOpen = __dirname atom.getCurrentWindow().send 'message', 'open-locations', [{pathToOpen}] expect(atom.workspace.open.callCount).toBe 0 + + describe "when the opened path is a uri", -> + it "adds it to the project's paths as is", -> + pathToOpen = 'remote://server:7644/some/dir/path' + atom.getCurrentWindow().send 'message', 'open-locations', [{pathToOpen}] + + waitsFor -> + atom.project.getPaths().length is 1 + + runs -> + expect(atom.project.getPaths()[0]).toBe pathToOpen diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 91e423d15..aeab5bf07 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -522,9 +522,8 @@ class AtomApplication new AtomWindow({bootstrapScript, @resourcePath, exitWhenDone, isSpec, specDirectory, devMode}) locationForPathToOpen: (pathToOpen) -> - {protocol} = url.parse(pathToOpen) - return {pathToOpen} if protocol? return {pathToOpen} unless pathToOpen + return {pathToOpen} if url.parse(pathToOpen).protocol? return {pathToOpen} if fs.existsSync(pathToOpen) pathToOpen = pathToOpen.replace(/[:\s]+$/, '') diff --git a/src/default-directory-provider.coffee b/src/default-directory-provider.coffee index 7c900ded6..96740f15a 100644 --- a/src/default-directory-provider.coffee +++ b/src/default-directory-provider.coffee @@ -24,9 +24,9 @@ class DefaultDirectoryProvider # TODO: Stop normalizing the path in pathwatcher's Directory. directory = new Directory(directoryPath) - if (url.parse(directoryPath).protocol) + if url.parse(directoryPath).protocol directory.path = directoryPath - if (fs.isCaseInsensitive()) + if fs.isCaseInsensitive() directory.lowerCasePath = directoryPath.toLowerCase() directory From 74ad38596a695a73e38419f916fc4ba79cf45ac3 Mon Sep 17 00:00:00 2001 From: Mostafa Eweda Date: Tue, 19 May 2015 17:38:06 -0700 Subject: [PATCH 1330/1783] Remove the normalization done by the default-directory-provider --- src/default-directory-provider.coffee | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/default-directory-provider.coffee b/src/default-directory-provider.coffee index 96740f15a..b29353ae2 100644 --- a/src/default-directory-provider.coffee +++ b/src/default-directory-provider.coffee @@ -15,16 +15,14 @@ class DefaultDirectoryProvider # * {Directory} if the given URI is compatible with this provider. # * `null` if the given URI is not compatibile with this provider. directoryForURISync: (uri) -> - projectPath = path.normalize(uri) - - directoryPath = if not fs.isDirectorySync(projectPath) and fs.isDirectorySync(path.dirname(projectPath)) - path.dirname(projectPath) + directoryPath = if not fs.isDirectorySync(uri) and fs.isDirectorySync(path.dirname(uri)) + path.normalize(path.dirname(uri)) else - projectPath + uri # TODO: Stop normalizing the path in pathwatcher's Directory. directory = new Directory(directoryPath) - if url.parse(directoryPath).protocol + if url.parse(directoryPath).protocol? directory.path = directoryPath if fs.isCaseInsensitive() directory.lowerCasePath = directoryPath.toLowerCase() From 638d8cc13f60373d07f74e526a6831449eb1a5bd Mon Sep 17 00:00:00 2001 From: Mostafa Eweda Date: Tue, 19 May 2015 17:39:34 -0700 Subject: [PATCH 1331/1783] trigger 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 b29353ae2..3257b9ac5 100644 --- a/src/default-directory-provider.coffee +++ b/src/default-directory-provider.coffee @@ -20,7 +20,7 @@ class DefaultDirectoryProvider else uri - # TODO: Stop normalizing the path in pathwatcher's Directory. + # TODO: Stop normalizing the path in pathwatcher Directory. directory = new Directory(directoryPath) if url.parse(directoryPath).protocol? directory.path = directoryPath From e7064bfc9d8e6663be076390ebd9d752e5bc3fb1 Mon Sep 17 00:00:00 2001 From: Mostafa Eweda Date: Tue, 19 May 2015 19:04:54 -0700 Subject: [PATCH 1332/1783] Fix tests + add integration test --- spec/integration/startup-spec.coffee | 10 ++++++++++ src/browser/main.coffee | 9 ++++++--- src/default-directory-provider.coffee | 14 +++++++++----- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/spec/integration/startup-spec.coffee b/spec/integration/startup-spec.coffee index 54817fedc..d2583ed27 100644 --- a/spec/integration/startup-spec.coffee +++ b/spec/integration/startup-spec.coffee @@ -227,3 +227,13 @@ describe "Starting Atom", -> [tempDirPath] [otherTempDirPath] ].sort() + + describe "opening a remote directory", -> + it "opens the parent directory and creates an empty text editor", -> + remoteDirectory = 'remote://server:3437/some/directory/path' + runAtom [remoteDirectory], {ATOM_HOME: atomHome}, (client) -> + client + .waitForWindowCount(1, 1000) + .waitForExist("atom-workspace", 5000) + .treeViewRootDirectories() + .then ({value}) -> expect(value).toEqual([remoteDirectory]) diff --git a/src/browser/main.coffee b/src/browser/main.coffee index 1af0526dd..a15a53f25 100644 --- a/src/browser/main.coffee +++ b/src/browser/main.coffee @@ -5,6 +5,7 @@ app = require 'app' fs = require 'fs-plus' path = require 'path' yargs = require 'yargs' +url = require 'url' nslog = require 'nslog' console.log = nslog @@ -45,9 +46,11 @@ start = -> cwd = args.executedFrom?.toString() or process.cwd() args.pathsToOpen = args.pathsToOpen.map (pathToOpen) -> - pathToOpen = fs.normalize(pathToOpen) - if cwd - path.resolve(cwd, pathToOpen) + normalizedPath = fs.normalize(pathToOpen) + if url.parse(pathToOpen || '').protocol? + pathToOpen + else if cwd + path.resolve(cwd, normalizedPath) else path.resolve(pathToOpen) diff --git a/src/default-directory-provider.coffee b/src/default-directory-provider.coffee index 3257b9ac5..01de244d8 100644 --- a/src/default-directory-provider.coffee +++ b/src/default-directory-provider.coffee @@ -15,14 +15,18 @@ class DefaultDirectoryProvider # * {Directory} if the given URI is compatible with this provider. # * `null` if the given URI is not compatibile with this provider. directoryForURISync: (uri) -> - directoryPath = if not fs.isDirectorySync(uri) and fs.isDirectorySync(path.dirname(uri)) - path.normalize(path.dirname(uri)) - else + normalizedPath = path.normalize(uri); + {protocol} = url.parse(uri || '') + directoryPath = if protocol? uri + else if not fs.isDirectorySync(normalizedPath) and fs.isDirectorySync(path.dirname(normalizedPath)) + path.dirname(normalizedPath) + else + normalizedPath - # TODO: Stop normalizing the path in pathwatcher Directory. + # TODO: Stop normalizing the path in pathwatcher's Directory. directory = new Directory(directoryPath) - if url.parse(directoryPath).protocol? + if protocol? directory.path = directoryPath if fs.isCaseInsensitive() directory.lowerCasePath = directoryPath.toLowerCase() From cf893225c4a10080ceb80af184069e40d431265f Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 19 May 2015 19:33:34 -0700 Subject: [PATCH 1333/1783] :arrow_up: text-buffer --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ae6f06540..154141443 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "space-pen": "3.8.2", "stacktrace-parser": "0.1.1", "temp": "0.8.1", - "text-buffer": "6.0.1", + "text-buffer": "6.0.2", "theorist": "^1.0.2", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", From aab86b2e9de6d16ba44535f62e2deca40a594135 Mon Sep 17 00:00:00 2001 From: Mostafa Eweda Date: Tue, 19 May 2015 20:15:13 -0700 Subject: [PATCH 1334/1783] enforced test: code nits --- src/default-directory-provider.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/default-directory-provider.coffee b/src/default-directory-provider.coffee index 01de244d8..da2d17593 100644 --- a/src/default-directory-provider.coffee +++ b/src/default-directory-provider.coffee @@ -15,8 +15,8 @@ class DefaultDirectoryProvider # * {Directory} if the given URI is compatible with this provider. # * `null` if the given URI is not compatibile with this provider. directoryForURISync: (uri) -> - normalizedPath = path.normalize(uri); - {protocol} = url.parse(uri || '') + normalizedPath = path.normalize(uri) + {protocol} = url.parse(uri) directoryPath = if protocol? uri else if not fs.isDirectorySync(normalizedPath) and fs.isDirectorySync(path.dirname(normalizedPath)) From d42a660f9be938988cf875013d8c1a19821d8bec Mon Sep 17 00:00:00 2001 From: Mostafa Eweda Date: Tue, 19 May 2015 22:01:26 -0700 Subject: [PATCH 1335/1783] enforced code nit 2 --- src/browser/main.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/browser/main.coffee b/src/browser/main.coffee index a15a53f25..371dd71ea 100644 --- a/src/browser/main.coffee +++ b/src/browser/main.coffee @@ -47,7 +47,7 @@ start = -> cwd = args.executedFrom?.toString() or process.cwd() args.pathsToOpen = args.pathsToOpen.map (pathToOpen) -> normalizedPath = fs.normalize(pathToOpen) - if url.parse(pathToOpen || '').protocol? + if url.parse(pathToOpen).protocol? pathToOpen else if cwd path.resolve(cwd, normalizedPath) From ffc73f3b7bf879e547b003bbf20f2aa7f95f3f18 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 20 May 2015 12:07:12 +0200 Subject: [PATCH 1336/1783] Reduce tile count to 4 --- 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 a86d5afc1..00a884eb4 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -20,7 +20,7 @@ class TextEditorPresenter @measuredHorizontalScrollbarHeight = horizontalScrollbarHeight @measuredVerticalScrollbarWidth = verticalScrollbarWidth @gutterWidth ?= 0 - @tileCount ?= 6 + @tileCount ?= 4 @disposables = new CompositeDisposable @emitter = new Emitter From 5ae0ae7f83dcdf7da8dde101d30930f8d9083c89 Mon Sep 17 00:00:00 2001 From: simurai Date: Wed, 20 May 2015 21:42:34 +0900 Subject: [PATCH 1337/1783] :arrow_up: deprecation-cop@v0.51.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 154141443..56d263a50 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "bookmarks": "0.35.0", "bracket-matcher": "0.74.0", "command-palette": "0.36.0", - "deprecation-cop": "0.50.0", + "deprecation-cop": "0.51.0", "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", From aa9cdb3dbc3c9805adab34c03ebf4a5273738974 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 20 May 2015 08:57:56 -0700 Subject: [PATCH 1338/1783] :arrow_up: notifications@0.50 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 56d263a50..3802b6586 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "link": "0.30.0", "markdown-preview": "0.149.0", "metrics": "0.50.0", - "notifications": "0.49.0", + "notifications": "0.50.0", "open-on-github": "0.37.0", "package-generator": "0.39.0", "release-notes": "0.52.0", From 2c137e8908575aa74ad226be9c911c9f44866e93 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 20 May 2015 09:05:16 -0700 Subject: [PATCH 1339/1783] :arrow_up: language-xml@0.29 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3802b6586..2228eb319 100644 --- a/package.json +++ b/package.json @@ -157,7 +157,7 @@ "language-text": "0.6.0", "language-todo": "0.21.0", "language-toml": "0.16.0", - "language-xml": "0.28.0", + "language-xml": "0.29.0", "language-yaml": "0.22.0" }, "private": true, From 7f17a52caae7cee82d0c80c90e6bc9b68dd3c089 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 20 May 2015 09:46:56 -0700 Subject: [PATCH 1340/1783] :arrow_up: find-and-replace --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2228eb319..5df3b92f0 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", - "find-and-replace": "0.166.0", + "find-and-replace": "0.167.0", "fuzzy-finder": "0.87.0", "git-diff": "0.55.0", "go-to-line": "0.30.0", From 37f8059249e2527ee98fefcb6ad207f4813d4b48 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 20 May 2015 10:02:38 -0700 Subject: [PATCH 1341/1783] :arrow_up: autoflow@0.24 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5df3b92f0..df16f07e2 100644 --- a/package.json +++ b/package.json @@ -89,7 +89,7 @@ "autocomplete-html": "0.7.2", "autocomplete-plus": "2.17.0", "autocomplete-snippets": "1.6.1", - "autoflow": "0.23.0", + "autoflow": "0.24.0", "autosave": "0.20.0", "background-tips": "0.24.0", "bookmarks": "0.35.0", From 2beb6c0fe019de8d490e65bc27eb8346bec5752b Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 20 May 2015 19:12:22 +0200 Subject: [PATCH 1342/1783] Pass TokenIterator reference instead of using global singleton Adds an extra reference to each tokenized line but is also more sane. /cc @maxbrunsfeld --- src/display-buffer.coffee | 5 ++--- src/language-mode.coffee | 3 +-- src/lines-component.coffee | 31 ++++++++++++++++--------------- src/text-editor-presenter.coffee | 3 +-- src/token-iterator.coffee | 2 -- src/tokenized-buffer.coffee | 7 ++++--- src/tokenized-line.coffee | 8 +++++--- 7 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index 57fc64759..b156bf98a 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -4,7 +4,6 @@ Serializable = require 'serializable' {Point, Range} = require 'text-buffer' Grim = require 'grim' TokenizedBuffer = require './tokenized-buffer' -TokenIterator = require './token-iterator' RowMap = require './row-map' Fold = require './fold' Model = require './model' @@ -652,7 +651,7 @@ class DisplayBuffer extends Model left = 0 column = 0 - iterator = TokenIterator.instance.reset(@tokenizedLineForScreenRow(targetRow)) + iterator = @tokenizedLineForScreenRow(targetRow).getTokenIterator() while iterator.next() charWidths = @getScopedCharWidths(iterator.getScopes()) valueIndex = 0 @@ -685,7 +684,7 @@ class DisplayBuffer extends Model left = 0 column = 0 - iterator = TokenIterator.instance.reset(@tokenizedLineForScreenRow(row)) + iterator = @tokenizedLineForScreenRow(row).getTokenIterator() while iterator.next() charWidths = @getScopedCharWidths(iterator.getScopes()) value = iterator.getText() diff --git a/src/language-mode.coffee b/src/language-mode.coffee index 1d7def178..c9401550b 100644 --- a/src/language-mode.coffee +++ b/src/language-mode.coffee @@ -2,7 +2,6 @@ _ = require 'underscore-plus' {OnigRegExp} = require 'oniguruma' ScopeDescriptor = require './scope-descriptor' -TokenIterator = require './token-iterator' module.exports = class LanguageMode @@ -243,7 +242,7 @@ class LanguageMode @suggestedIndentForTokenizedLineAtBufferRow(bufferRow, tokenizedLine, options) suggestedIndentForTokenizedLineAtBufferRow: (bufferRow, tokenizedLine, options) -> - iterator = TokenIterator.instance.reset(tokenizedLine) + iterator = tokenizedLine.getTokenIterator() iterator.next() scopeDescriptor = new ScopeDescriptor(scopes: iterator.getScopes()) diff --git a/src/lines-component.coffee b/src/lines-component.coffee index 51ea65f28..17c904e99 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -22,6 +22,7 @@ class LinesComponent placeholderTextDiv: null constructor: ({@presenter, @hostElement, @useShadowDOM, visible}) -> + @tokenIterator = new TokenIterator @measuredLines = new Set @lineNodesByLineId = {} @screenRowsByLineId = {} @@ -175,19 +176,19 @@ class LinesComponent lineIsWhitespaceOnly = firstTrailingWhitespaceIndex is 0 innerHTML = "" - iterator = TokenIterator.instance.reset(lineState) + @tokenIterator.reset(lineState) - while iterator.next() - for scope in iterator.getScopeEnds() + while @tokenIterator.next() + for scope in @tokenIterator.getScopeEnds() innerHTML += "" - for scope in iterator.getScopeStarts() + for scope in @tokenIterator.getScopeStarts() innerHTML += "" - tokenStart = iterator.getScreenStart() - tokenEnd = iterator.getScreenEnd() - tokenText = iterator.getText() - isHardTab = iterator.isHardTab() + tokenStart = @tokenIterator.getScreenStart() + tokenEnd = @tokenIterator.getScreenEnd() + tokenText = @tokenIterator.getText() + isHardTab = @tokenIterator.isHardTab() if hasLeadingWhitespace = tokenStart < firstNonWhitespaceIndex tokenFirstNonWhitespaceIndex = firstNonWhitespaceIndex - tokenStart @@ -209,10 +210,10 @@ class LinesComponent innerHTML += @buildTokenHTML(tokenText, isHardTab, tokenFirstNonWhitespaceIndex, tokenFirstTrailingWhitespaceIndex, hasIndentGuide, hasInvisibleCharacters) - for scope in iterator.getScopeEnds() + for scope in @tokenIterator.getScopeEnds() innerHTML += "" - for scope in iterator.getScopes() + for scope in @tokenIterator.getScopes() innerHTML += "" innerHTML += @buildEndOfLineHTML(id) @@ -353,15 +354,15 @@ class LinesComponent iterator = null charIndex = 0 - tokenIterator = TokenIterator.instance.reset(tokenizedLine) - while tokenIterator.next() - scopes = tokenIterator.getScopes() - text = tokenIterator.getText() + @tokenIterator.reset(tokenizedLine) + while @tokenIterator.next() + scopes = @tokenIterator.getScopes() + text = @tokenIterator.getText() charWidths = @presenter.getScopedCharacterWidths(scopes) textIndex = 0 while textIndex < text.length - if tokenIterator.isPairedCharacter() + if @tokenIterator.isPairedCharacter() char = text charLength = 2 textIndex += 2 diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 15241625a..3aea57f29 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -2,7 +2,6 @@ {Point, Range} = require 'text-buffer' _ = require 'underscore-plus' Decoration = require './decoration' -TokenIterator = require './token-iterator' module.exports = class TextEditorPresenter @@ -1013,7 +1012,7 @@ class TextEditorPresenter left = 0 column = 0 - iterator = TokenIterator.instance.reset(@model.tokenizedLineForScreenRow(targetRow)) + iterator = @model.tokenizedLineForScreenRow(targetRow).getTokenIterator() while iterator.next() characterWidths = @getScopedCharacterWidths(iterator.getScopes()) diff --git a/src/token-iterator.coffee b/src/token-iterator.coffee index 65a4c3100..202b044ba 100644 --- a/src/token-iterator.coffee +++ b/src/token-iterator.coffee @@ -81,5 +81,3 @@ class TokenIterator isAtomic: -> @isSoftTab() or @isHardTab() or @isSoftWrapIndentation() or @isPairedCharacter() - -TokenIterator.instance = new TokenIterator diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index a709d9755..60ebe16f0 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -27,6 +27,7 @@ class TokenizedBuffer extends Model constructor: ({@buffer, @tabLength, @ignoreInvisibles}) -> @emitter = new Emitter @disposables = new CompositeDisposable + @tokenIterator = new TokenIterator @disposables.add atom.grammars.onDidAddGrammar(@grammarAddedOrUpdated) @disposables.add atom.grammars.onDidUpdateGrammar(@grammarAddedOrUpdated) @@ -321,7 +322,7 @@ class TokenizedBuffer extends Model tabLength = @getTabLength() indentLevel = @indentLevelForRow(row) lineEnding = @buffer.lineEndingForRow(row) - new TokenizedLine({openScopes, text, tags, tabLength, indentLevel, invisibles: @getInvisiblesToShow(), lineEnding}) + new TokenizedLine({openScopes, text, tags, tabLength, indentLevel, invisibles: @getInvisiblesToShow(), lineEnding, @tokenIterator}) buildTokenizedLineForRow: (row, ruleStack, openScopes) -> @buildTokenizedLineForRowWithText(row, @buffer.lineForRow(row), ruleStack, openScopes) @@ -331,7 +332,7 @@ class TokenizedBuffer extends Model tabLength = @getTabLength() indentLevel = @indentLevelForRow(row) {tags, ruleStack} = @grammar.tokenizeLine(text, ruleStack, row is 0, false) - new TokenizedLine({openScopes, text, tags, ruleStack, tabLength, lineEnding, indentLevel, invisibles: @getInvisiblesToShow()}) + new TokenizedLine({openScopes, text, tags, ruleStack, tabLength, lineEnding, indentLevel, invisibles: @getInvisiblesToShow(), @tokenIterator}) getInvisiblesToShow: -> if @configSettings.showInvisibles and not @ignoreInvisibles @@ -402,7 +403,7 @@ class TokenizedBuffer extends Model scopeDescriptorForPosition: (position) -> {row, column} = Point.fromObject(position) - iterator = TokenIterator.instance.reset(@tokenizedLines[row]) + iterator = @tokenizedLines[row].getTokenIterator() while iterator.next() if iterator.getScreenEnd() > column scopes = iterator.getScopes() diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index acaa16378..45af81e57 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -1,7 +1,6 @@ _ = require 'underscore-plus' {isPairedCharacter} = require './text-utils' Token = require './token' -TokenIterator = require './token-iterator' {SoftTab, HardTab, PairedCharacter, SoftWrapIndent} = require './special-token-symbols' NonWhitespaceRegex = /\S/ @@ -24,7 +23,7 @@ class TokenizedLine return unless properties? @specialTokens = {} - {@openScopes, @text, @tags, @lineEnding, @ruleStack} = properties + {@openScopes, @text, @tags, @lineEnding, @ruleStack, @tokenIterator} = properties {@startBufferColumn, @fold, @tabLength, @indentLevel, @invisibles} = properties @startBufferColumn ?= 0 @@ -143,7 +142,7 @@ class TokenizedLine @lineIsWhitespaceOnly = true @firstTrailingWhitespaceIndex = 0 - getTokenIterator: -> TokenIterator.instance.reset(this) + getTokenIterator: -> @tokenIterator.reset(this) Object.defineProperty @prototype, 'tokens', get: -> iterator = @getTokenIterator() @@ -179,6 +178,7 @@ class TokenizedLine copy: -> copy = new TokenizedLine + copy.tokenIterator = @tokenIterator copy.indentLevel = @indentLevel copy.openScopes = @openScopes copy.text = @text @@ -359,6 +359,7 @@ class TokenizedLine splitBufferColumn = @bufferColumnForScreenColumn(column) leftFragment = new TokenizedLine + leftFragment.tokenIterator = @tokenIterator leftFragment.openScopes = @openScopes leftFragment.text = leftText leftFragment.tags = leftTags @@ -374,6 +375,7 @@ class TokenizedLine leftFragment.firstTrailingWhitespaceIndex = Math.min(column, @firstTrailingWhitespaceIndex) rightFragment = new TokenizedLine + rightFragment.tokenIterator = @tokenIterator rightFragment.openScopes = rightOpenScopes rightFragment.text = rightText rightFragment.tags = rightTags From d75d202d337142e206e500c10fed34151b4cc750 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 20 May 2015 19:47:15 +0200 Subject: [PATCH 1343/1783] =?UTF-8?q?Remove=20defunct=20=E2=80=98editor:mo?= =?UTF-8?q?ve-to-previous-word=E2=80=99=20command?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The method this command calls was removed a very long time ago. Use ‘editor:move-to-previous-word-boundary’ instead. Fixes atom/command-palette#41 --- src/text-editor-element.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/text-editor-element.coffee b/src/text-editor-element.coffee index ab18be8bf..beeae6cc6 100644 --- a/src/text-editor-element.coffee +++ b/src/text-editor-element.coffee @@ -247,7 +247,6 @@ atom.commands.add 'atom-text-editor', stopEventPropagation( 'core:select-up': -> @selectUp() 'core:select-down': -> @selectDown() 'core:select-all': -> @selectAll() - 'editor:move-to-previous-word': -> @moveToPreviousWord() 'editor:select-word': -> @selectWordsContainingCursors() 'editor:consolidate-selections': (event) -> event.abortKeyBinding() unless @consolidateSelections() 'editor:move-to-beginning-of-next-paragraph': -> @moveToBeginningOfNextParagraph() From fdc25706c47af0f36b834cda3bdba9b473686998 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 20 May 2015 19:52:05 +0200 Subject: [PATCH 1344/1783] :arrow_up: autocomplete-plus to use token iterator --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8e73fc3be..cf89ca282 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "autocomplete-atom-api": "0.9.0", "autocomplete-css": "0.7.2", "autocomplete-html": "0.7.2", - "autocomplete-plus": "2.17.0", + "autocomplete-plus": "2.17.1", "autocomplete-snippets": "1.6.1", "autoflow": "0.24.0", "autosave": "0.20.0", From 50dd7ebbce786efbe49908b3c5000e8087188e88 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 20 May 2015 00:46:31 +0200 Subject: [PATCH 1345/1783] Only perform a single marker query for folds when updating screen lines This saves over 50ms to initialize the DisplayBuffer when opening `text-editor.coffee`. --- src/display-buffer.coffee | 36 ++++++++++++++++++++++++++---------- src/fold.coffee | 1 - 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index b156bf98a..b2460addc 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -40,9 +40,10 @@ class DisplayBuffer extends Model @disposables.add @tokenizedBuffer.observeGrammar @subscribeToScopedConfigSettings @disposables.add @tokenizedBuffer.onDidChange @handleTokenizedBufferChange @disposables.add @buffer.onDidCreateMarker @handleBufferMarkerCreated - @updateAllScreenLines() @foldMarkerAttributes = Object.freeze({class: 'fold', displayBufferId: @id}) - @createFoldForMarker(marker) for marker in @buffer.findMarkers(@getFoldMarkerAttributes()) + folds = (new Fold(this, marker) for marker in @buffer.findMarkers(@getFoldMarkerAttributes())) + @updateAllScreenLines() + @decorateFold(fold) for fold in folds subscribeToScopedConfigSettings: => @scopedConfigSubscriptions?.dispose() @@ -580,9 +581,17 @@ class DisplayBuffer extends Model # Returns the folds in the given row range (exclusive of end row) that are # not contained by any other folds. outermostFoldsInBufferRowRange: (startRow, endRow) -> - @findFoldMarkers(containedInRange: [[startRow, 0], [endRow, 0]]) - .map (marker) => @foldForMarker(marker) - .filter (fold) -> not fold.isInsideLargerFold() + folds = [] + lastFoldEndRow = -1 + + for marker in @findFoldMarkers(intersectsRowRange: [startRow, endRow]) + range = marker.getRange() + if range.start.row > lastFoldEndRow + lastFoldEndRow = range.end.row + if startRow <= range.start.row <= range.end.row < endRow + folds.push(@foldForMarker(marker)) + + folds # Public: Given a buffer row, this returns folds that include it. # @@ -1138,11 +1147,15 @@ class DisplayBuffer extends Model regions = [] rectangularRegion = null + foldsByStartRow = {} + for fold in @outermostFoldsInBufferRowRange(startBufferRow, endBufferRow) + foldsByStartRow[fold.getStartRow()] = fold + bufferRow = startBufferRow while bufferRow < endBufferRow tokenizedLine = @tokenizedBuffer.tokenizedLineForRow(bufferRow) - if fold = @largestFoldStartingAtBufferRow(bufferRow) + if fold = foldsByStartRow[bufferRow] foldLine = tokenizedLine.copy() foldLine.fold = fold screenLines.push(foldLine) @@ -1212,16 +1225,19 @@ class DisplayBuffer extends Model @setScrollLeft(Math.min(@getScrollLeft(), @getMaxScrollLeft())) handleBufferMarkerCreated: (textBufferMarker) => - @createFoldForMarker(textBufferMarker) if textBufferMarker.matchesParams(@getFoldMarkerAttributes()) + if textBufferMarker.matchesParams(@getFoldMarkerAttributes()) + fold = new Fold(this, textBufferMarker) + fold.updateDisplayBuffer() + @decorateFold(fold) + if marker = @getMarker(textBufferMarker.id) # The marker might have been removed in some other handler called before # this one. Only emit when the marker still exists. @emit 'marker-created', marker if Grim.includeDeprecatedAPIs @emitter.emit 'did-create-marker', marker - createFoldForMarker: (marker) -> - @decorateMarker(marker, type: 'line-number', class: 'folded') - new Fold(this, marker) + decorateFold: (fold) -> + @decorateMarker(fold.marker, type: 'line-number', class: 'folded') foldForMarker: (marker) -> @foldsByMarkerId[marker.id] diff --git a/src/fold.coffee b/src/fold.coffee index 4b413bd12..051be9f4c 100644 --- a/src/fold.coffee +++ b/src/fold.coffee @@ -13,7 +13,6 @@ class Fold constructor: (@displayBuffer, @marker) -> @id = @marker.id @displayBuffer.foldsByMarkerId[@marker.id] = this - @updateDisplayBuffer() @marker.onDidDestroy => @destroyed() @marker.onDidChange ({isValid}) => @destroy() unless isValid From 6cb9ebcf08f3f5ca6549a3c708ed47fc5442acb6 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 20 May 2015 16:29:17 -0700 Subject: [PATCH 1346/1783] :arrow_up: event-kit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cf89ca282..1ac079ab7 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "color": "^0.7.3", "delegato": "^1", "emissary": "^1.3.3", - "event-kit": "^1.1.1", + "event-kit": "^1.2.0", "first-mate": "^4.1.4", "fs-plus": "^2.8.0", "fstream": "0.1.24", From d1c9ec8e97ef44689de844ba21a70de414d1fd33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Machist=C3=A9=20N=2E=20Quintana?= Date: Wed, 20 May 2015 21:59:35 -0400 Subject: [PATCH 1347/1783] :arrow_up: settings-view@0.204.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7e10a11e8..7e6619ab8 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "open-on-github": "0.37.0", "package-generator": "0.39.0", "release-notes": "0.52.0", - "settings-view": "0.203.0", + "settings-view": "0.204.0", "snippets": "0.89.0", "spell-check": "0.58.0", "status-bar": "0.72.0", From 752dbf2c6eac831771c705ced0a3c6f542b5272a Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 20 May 2015 18:55:47 +0200 Subject: [PATCH 1348/1783] Manually config tileSize Dealing with a manually entered `tileSize` is actually easier to reason about, therefore we no longer calculate it based on `tileCount.` --- spec/text-editor-component-spec.coffee | 18 ++++++++++++---- spec/text-editor-presenter-spec.coffee | 30 +++++++++++++------------- src/text-editor-component.coffee | 8 +++---- src/text-editor-element.coffee | 4 ++-- src/text-editor-presenter.coffee | 14 ++---------- src/text-editor-view.coffee | 2 +- src/tile-component.coffee | 1 + 7 files changed, 39 insertions(+), 38 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 12d189035..d9a577c25 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -1920,13 +1920,23 @@ describe "TextEditorComponent", -> component.measureDimensions() nextAnimationFrame() - linesNode = componentNode.querySelector('.lines') - expect(linesNode.style['-webkit-transform']).toBe "translate3d(0px, 0px, 0px)" + tilesNodes = componentNode.querySelectorAll(".tile") + + top = 0 + for tileNode in tilesNodes + expect(tileNode.style['-webkit-transform']).toBe "translate3d(0px, #{top}px, 0px)" + top += tileNode.offsetHeight + expect(horizontalScrollbarNode.scrollLeft).toBe 0 editor.setScrollLeft(100) nextAnimationFrame() - expect(linesNode.style['-webkit-transform']).toBe "translate3d(-100px, 0px, 0px)" + + top = 0 + for tileNode in tilesNodes + expect(tileNode.style['-webkit-transform']).toBe "translate3d(-100px, #{top}px, 0px)" + top += tileNode.offsetHeight + expect(horizontalScrollbarNode.scrollLeft).toBe 100 it "updates the scrollLeft of the model when the scrollLeft of the horizontal scrollbar changes", -> @@ -2508,7 +2518,7 @@ describe "TextEditorComponent", -> advanceClock(atom.views.documentPollingInterval) nextAnimationFrame() - expect(componentNode.querySelectorAll('.line')).toHaveLength(4 + lineOverdrawMargin + 1) + expect(componentNode.querySelectorAll('.line')).toHaveLength(6) gutterWidth = componentNode.querySelector('.gutter').offsetWidth componentNode.style.width = gutterWidth + 14 * charWidth + editor.getVerticalScrollbarWidth() + 'px' diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 889328386..c147fc4e1 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -342,26 +342,26 @@ describe "TextEditorPresenter", -> expectValues presenter.getState().hiddenInput, {top: 3 * 10, left: 6 * 10} expectStateUpdate presenter, -> presenter.setScrollTop(15) - expectValues presenter.getState().hiddenInput, {top: 0, left: 6 * 10} + expectValues presenter.getState().hiddenInput, {top: (3 * 10) - 15, left: 6 * 10} expectStateUpdate presenter, -> presenter.setScrollLeft(35) - expectValues presenter.getState().hiddenInput, {top: 0, left: 0} + expectValues presenter.getState().hiddenInput, {top: (3 * 10) - 15, left: (6 * 10) - 35} expectStateUpdate presenter, -> presenter.setScrollTop(40) - expectValues presenter.getState().hiddenInput, {top: 0, left: 0} + expectValues presenter.getState().hiddenInput, {top: 0, left: (6 * 10) - 35} expectStateUpdate presenter, -> presenter.setScrollLeft(70) expectValues presenter.getState().hiddenInput, {top: 0, left: 0} expectStateUpdate presenter, -> editor.setCursorBufferPosition([11, 43]) - expectValues presenter.getState().hiddenInput, {top: 0, left: 30} + expectValues presenter.getState().hiddenInput, {top: 11 * 10 - editor.getScrollTop(), left: 43 * 10 - editor.getScrollLeft()} newCursor = null expectStateUpdate presenter, -> newCursor = editor.addCursorAtBufferPosition([6, 10]) - expectValues presenter.getState().hiddenInput, {top: 0, left: 20} + expectValues presenter.getState().hiddenInput, {top: (6 * 10) - editor.getScrollTop(), left: (10 * 10) - editor.getScrollLeft()} expectStateUpdate presenter, -> newCursor.destroy() - expectValues presenter.getState().hiddenInput, {top: 30, left: 300 - 10} + expectValues presenter.getState().hiddenInput, {top: 50 - 10, left: 300 - 10} expectStateUpdate presenter, -> presenter.setFocused(false) expectValues presenter.getState().hiddenInput, {top: 0, left: 0} @@ -663,7 +663,7 @@ describe "TextEditorPresenter", -> presenter.getState().content.tiles[tileRow].lines[lineId] it "contains states for tiles that are visible on screen", -> - presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileCount: 3) + presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileSize: 2) expectValues presenter.getState().content.tiles[0], { top: 0 @@ -681,12 +681,12 @@ describe "TextEditorPresenter", -> expect(presenter.getState().content.tiles[8]).toBeUndefined() it "includes state for all tiles if no external ::explicitHeight is assigned", -> - presenter = buildPresenter(explicitHeight: null, tileCount: 12, tileOverdrawMargin: 1) + presenter = buildPresenter(explicitHeight: null, tileSize: 2) expect(presenter.getState().content.tiles[0]).toBeDefined() expect(presenter.getState().content.tiles[12]).toBeDefined() it "is empty until all of the required measurements are assigned", -> - presenter = buildPresenter(explicitHeight: null, lineHeight: null, scrollTop: null, tileCount: 3) + presenter = buildPresenter(explicitHeight: null, lineHeight: null, scrollTop: null) expect(presenter.getState().content.tiles).toEqual({}) presenter.setExplicitHeight(25) @@ -699,7 +699,7 @@ describe "TextEditorPresenter", -> expect(presenter.getState().content.tiles).not.toEqual({}) it "updates when ::scrollTop changes", -> - presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileCount: 3) + presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileSize: 2) expect(presenter.getState().content.tiles[0]).toBeDefined() expect(presenter.getState().content.tiles[2]).toBeDefined() @@ -717,7 +717,7 @@ describe "TextEditorPresenter", -> expect(presenter.getState().content.tiles[10]).toBeUndefined() it "updates when ::explicitHeight changes", -> - presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileCount: 3) + presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileSize: 2) expect(presenter.getState().content.tiles[0]).toBeDefined() expect(presenter.getState().content.tiles[2]).toBeDefined() @@ -736,7 +736,7 @@ describe "TextEditorPresenter", -> it "updates when ::lineHeight changes", -> - presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileCount: 3) + presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileSize: 2) expect(presenter.getState().content.tiles[0]).toBeDefined() expect(presenter.getState().content.tiles[2]).toBeDefined() @@ -752,7 +752,7 @@ describe "TextEditorPresenter", -> expect(presenter.getState().content.tiles[6]).toBeUndefined() it "updates when the editor's content changes", -> - presenter = buildPresenter(explicitHeight: 25, scrollTop: 10, lineHeight: 10, tileCount: 3, tileOverdrawMargin: 1) + presenter = buildPresenter(explicitHeight: 25, scrollTop: 10, lineHeight: 10, tileSize: 2) expectStateUpdate presenter, -> buffer.insert([2, 0], "hello\nworld\n") @@ -775,7 +775,7 @@ describe "TextEditorPresenter", -> } it "does not remove out-of-view tiles corresponding to ::mouseWheelScreenRow until ::stoppedScrollingDelay elapses", -> - presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileCount: 3, stoppedScrollingDelay: 200) + presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileSize: 2, stoppedScrollingDelay: 200) expect(presenter.getState().content.tiles[0]).toBeDefined() expect(presenter.getState().content.tiles[6]).toBeDefined() @@ -804,7 +804,7 @@ describe "TextEditorPresenter", -> expect(presenter.getState().content.tiles[4]).toBeUndefined() it "does not preserve deleted on-screen tiles even if they correspond to ::mouseWheelScreenRow", -> - presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileCount: 3, stoppedScrollingDelay: 200) + presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileSize: 2, stoppedScrollingDelay: 200) presenter.setMouseWheelScreenRow(2) diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index fb840f534..f8f6de6bf 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -18,7 +18,7 @@ class TextEditorComponent scrollSensitivity: 0.4 cursorBlinkPeriod: 800 cursorBlinkResumeDelay: 100 - lineOverdrawMargin: 15 + tileSize: 12 pendingScrollTop: null pendingScrollLeft: null @@ -36,8 +36,8 @@ class TextEditorComponent gutterComponent: null mounted: true - constructor: ({@editor, @hostElement, @rootElement, @stylesElement, @useShadowDOM, lineOverdrawMargin}) -> - @lineOverdrawMargin = lineOverdrawMargin if lineOverdrawMargin? + constructor: ({@editor, @hostElement, @rootElement, @stylesElement, @useShadowDOM, tileSize}) -> + @tileSize = tileSize if tileSize? @disposables = new CompositeDisposable @observeConfig() @@ -47,7 +47,7 @@ class TextEditorComponent model: @editor scrollTop: @editor.getScrollTop() scrollLeft: @editor.getScrollLeft() - lineOverdrawMargin: lineOverdrawMargin + tileSize: tileSize cursorBlinkPeriod: @cursorBlinkPeriod cursorBlinkResumeDelay: @cursorBlinkResumeDelay stoppedScrollingDelay: 200 diff --git a/src/text-editor-element.coffee b/src/text-editor-element.coffee index ab18be8bf..bc1dc05d6 100644 --- a/src/text-editor-element.coffee +++ b/src/text-editor-element.coffee @@ -15,7 +15,7 @@ class TextEditorElement extends HTMLElement componentDescriptor: null component: null attached: false - lineOverdrawMargin: null + tileSize: null focusOnAttach: false createdCallback: -> @@ -110,7 +110,7 @@ class TextEditorElement extends HTMLElement rootElement: @rootElement stylesElement: @stylesElement editor: @model - lineOverdrawMargin: @lineOverdrawMargin + tileSize: @tileSize useShadowDOM: @useShadowDOM ) @rootElement.appendChild(@component.getDomNode()) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 00a884eb4..4db15ade4 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -15,12 +15,12 @@ class TextEditorPresenter constructor: (params) -> {@model, @autoHeight, @explicitHeight, @contentFrameWidth, @scrollTop, @scrollLeft, @boundingClientRect, @windowWidth, @windowHeight, @gutterWidth} = params {horizontalScrollbarHeight, verticalScrollbarWidth} = params - {@lineHeight, @baseCharacterWidth, @lineOverdrawMargin, @backgroundColor, @gutterBackgroundColor, @tileCount} = params + {@lineHeight, @baseCharacterWidth, @backgroundColor, @gutterBackgroundColor, @tileSize} = params {@cursorBlinkPeriod, @cursorBlinkResumeDelay, @stoppedScrollingDelay, @focused} = params @measuredHorizontalScrollbarHeight = horizontalScrollbarHeight @measuredVerticalScrollbarWidth = verticalScrollbarWidth @gutterWidth ?= 0 - @tileCount ?= 4 + @tileSize ?= 12 @disposables = new CompositeDisposable @emitter = new Emitter @@ -66,7 +66,6 @@ class TextEditorPresenter @updateScrollbarDimensions() @updateStartRow() @updateEndRow() - @updateTileSize() @updateFocusedState() if @shouldUpdateFocusedState @updateHeightState() if @shouldUpdateHeightState @@ -224,7 +223,6 @@ class TextEditorPresenter @updateScrollbarDimensions() @updateStartRow() @updateEndRow() - @updateTileSize() @updateFocusedState() @updateHeightState() @@ -285,8 +283,6 @@ class TextEditorPresenter {top, left, height, width} = @pixelRectForScreenRange(lastCursor.getScreenRange()) if @focused - top -= @scrollTop - left -= @scrollLeft @state.hiddenInput.top = Math.max(Math.min(top, @clientHeight - height), 0) @state.hiddenInput.left = Math.max(Math.min(left, @clientWidth - width), 0) else @@ -603,12 +599,6 @@ class TextEditorPresenter endRow = startRow + visibleLinesCount @endRow = Math.min(@model.getScreenLineCount(), endRow) - updateTileSize: -> - return unless @height? and @lineHeight? and @tileCount? - - @tileSize = Math.floor(@height / @lineHeight / @tileCount) - @tileSize = Math.max(1, @tileSize) - updateScrollWidth: -> return unless @contentWidth? and @clientWidth? diff --git a/src/text-editor-view.coffee b/src/text-editor-view.coffee index b86367ef4..ffb59cc66 100644 --- a/src/text-editor-view.coffee +++ b/src/text-editor-view.coffee @@ -60,7 +60,7 @@ class TextEditorView extends View placeholderText: placeholderText element = new TextEditorElement - element.lineOverdrawMargin = props?.lineOverdrawMargin + element.tileSize = props?.tileSize element.setAttribute(name, value) for name, value of attributes if attributes? element.setModel(model) return element.__spacePenView diff --git a/src/tile-component.coffee b/src/tile-component.coffee index 0f8fd0209..20c9d7ff1 100644 --- a/src/tile-component.coffee +++ b/src/tile-component.coffee @@ -21,6 +21,7 @@ class TileComponent @screenRowsByLineId = {} @lineIdsByScreenRow = {} @domNode = document.createElement("div") + @domNode.classList.add("tile") @domNode.style.position = "absolute" @domNode.style.display = "block" From 1a18cda000a7651e63b1857c93deac7f1d52c7c0 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 20 May 2015 20:54:11 +0200 Subject: [PATCH 1349/1783] :green_heart: Fix remaining specs --- spec/text-editor-component-spec.coffee | 146 ++++++++++++++++++------- src/lines-component.coffee | 2 +- 2 files changed, 106 insertions(+), 42 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index d9a577c25..30c955c57 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -7,10 +7,10 @@ nbsp = String.fromCharCode(160) describe "TextEditorComponent", -> [contentNode, editor, wrapperView, wrapperNode, component, componentNode, verticalScrollbarNode, horizontalScrollbarNode] = [] - [lineHeightInPixels, charWidth, nextAnimationFrame, noAnimationFrame, lineOverdrawMargin] = [] + [lineHeightInPixels, charWidth, nextAnimationFrame, noAnimationFrame, tileSize] = [] beforeEach -> - lineOverdrawMargin = 2 + tileSize = 3 waitsForPromise -> atom.packages.activatePackage('language-javascript') @@ -34,7 +34,7 @@ describe "TextEditorComponent", -> contentNode = document.querySelector('#jasmine-content') contentNode.style.width = '1000px' - wrapperView = new TextEditorView(editor, {lineOverdrawMargin}) + wrapperView = new TextEditorView(editor, {tileSize}) wrapperView.attachToDom() wrapperNode = wrapperView.element wrapperNode.setUpdatedSynchronously(false) @@ -68,48 +68,111 @@ describe "TextEditorComponent", -> expect(nextAnimationFrame).not.toThrow() describe "line rendering", -> - it "renders the currently-visible lines plus the overdraw margin", -> - wrapperNode.style.height = 4.5 * lineHeightInPixels + 'px' + expectLineRender = (tileNode, {screenRow, top}) -> + lineNode = tileNode.querySelector("[data-screen-row='#{screenRow}']") + tokenizedLine = editor.tokenizedLineForScreenRow(screenRow) + + expect(lineNode.offsetTop).toBe(top) + if tokenizedLine.text is "" + expect(lineNode.innerHTML).toBe(" ") + else + expect(lineNode.textContent).toBe(tokenizedLine.text) + + it "renders the currently-visible lines into a tiled fashion", -> + wrapperNode.style.height = 6.5 * lineHeightInPixels + 'px' + tileHeight = tileSize * lineHeightInPixels component.measureDimensions() nextAnimationFrame() - linesNode = componentNode.querySelector('.lines') - expect(linesNode.style['-webkit-transform']).toBe "translate3d(0px, 0px, 0px)" - expect(componentNode.querySelectorAll('.line').length).toBe 6 + 2 # no margin above - expect(component.lineNodeForScreenRow(0).textContent).toBe editor.tokenizedLineForScreenRow(0).text - expect(component.lineNodeForScreenRow(0).offsetTop).toBe 0 - expect(component.lineNodeForScreenRow(5).textContent).toBe editor.tokenizedLineForScreenRow(5).text - expect(component.lineNodeForScreenRow(5).offsetTop).toBe 5 * lineHeightInPixels + tilesNodes = componentNode.querySelectorAll(".tile") - verticalScrollbarNode.scrollTop = 4.5 * lineHeightInPixels + expect(tilesNodes.length).toBe(3) + + expect(tilesNodes[0].style['-webkit-transform']).toBe "translate3d(0px, 0px, 0px)" + expect(tilesNodes[0].children.length).toBe(tileSize) + expectLineRender(tilesNodes[0], screenRow: 0, top: 0 * lineHeightInPixels) + expectLineRender(tilesNodes[0], screenRow: 1, top: 1 * lineHeightInPixels) + expectLineRender(tilesNodes[0], screenRow: 2, top: 2 * lineHeightInPixels) + + expect(tilesNodes[1].style['-webkit-transform']).toBe "translate3d(0px, #{1 * tileHeight}px, 0px)" + expect(tilesNodes[1].children.length).toBe(tileSize) + expectLineRender(tilesNodes[1], screenRow: 3, top: 0 * lineHeightInPixels) + expectLineRender(tilesNodes[1], screenRow: 4, top: 1 * lineHeightInPixels) + expectLineRender(tilesNodes[1], screenRow: 5, top: 2 * lineHeightInPixels) + + expect(tilesNodes[2].style['-webkit-transform']).toBe "translate3d(0px, #{2 * tileHeight}px, 0px)" + expect(tilesNodes[2].children.length).toBe(tileSize) + expectLineRender(tilesNodes[2], screenRow: 6, top: 0 * lineHeightInPixels) + expectLineRender(tilesNodes[2], screenRow: 7, top: 1 * lineHeightInPixels) + expectLineRender(tilesNodes[2], screenRow: 8, top: 2 * lineHeightInPixels) + + expect(component.lineNodeForScreenRow(9)).toBeUndefined() + + verticalScrollbarNode.scrollTop = tileSize * lineHeightInPixels + 5 verticalScrollbarNode.dispatchEvent(new UIEvent('scroll')) nextAnimationFrame() - expect(linesNode.style['-webkit-transform']).toBe "translate3d(0px, #{-4.5 * lineHeightInPixels}px, 0px)" - expect(componentNode.querySelectorAll('.line').length).toBe 6 + 4 # margin above and below - expect(component.lineNodeForScreenRow(2).offsetTop).toBe 2 * lineHeightInPixels - expect(component.lineNodeForScreenRow(2).textContent).toBe editor.tokenizedLineForScreenRow(2).text - expect(component.lineNodeForScreenRow(9).offsetTop).toBe 9 * lineHeightInPixels - expect(component.lineNodeForScreenRow(9).textContent).toBe editor.tokenizedLineForScreenRow(9).text + tilesNodes = componentNode.querySelectorAll(".tile") - it "updates the top position of subsequent lines when lines are inserted or removed", -> + expect(component.lineNodeForScreenRow(2)).toBeUndefined() + expect(tilesNodes.length).toBe(3) + + expect(tilesNodes[0].style['-webkit-transform']).toBe "translate3d(0px, -5px, 0px)" + expect(tilesNodes[0].children.length).toBe(tileSize) + expectLineRender(tilesNodes[0], screenRow: 3, top: 0 * lineHeightInPixels) + expectLineRender(tilesNodes[0], screenRow: 4, top: 1 * lineHeightInPixels) + expectLineRender(tilesNodes[0], screenRow: 5, top: 2 * lineHeightInPixels) + + expect(tilesNodes[1].style['-webkit-transform']).toBe "translate3d(0px, #{1 * tileHeight - 5}px, 0px)" + expect(tilesNodes[1].children.length).toBe(tileSize) + expectLineRender(tilesNodes[1], screenRow: 6, top: 0 * lineHeightInPixels) + expectLineRender(tilesNodes[1], screenRow: 7, top: 1 * lineHeightInPixels) + expectLineRender(tilesNodes[1], screenRow: 8, top: 2 * lineHeightInPixels) + + expect(tilesNodes[2].style['-webkit-transform']).toBe "translate3d(0px, #{2 * tileHeight - 5}px, 0px)" + expect(tilesNodes[2].children.length).toBe(tileSize) + expectLineRender(tilesNodes[2], screenRow: 9, top: 0 * lineHeightInPixels) + expectLineRender(tilesNodes[2], screenRow: 10, top: 1 * lineHeightInPixels) + expectLineRender(tilesNodes[2], screenRow: 11, top: 2 * lineHeightInPixels) + + it "updates the top position of subsequent tiles when lines are inserted or removed", -> + wrapperNode.style.height = 6.5 * lineHeightInPixels + 'px' + tileHeight = tileSize * lineHeightInPixels + component.measureDimensions() editor.getBuffer().deleteRows(0, 1) nextAnimationFrame() - lineNodes = componentNode.querySelectorAll('.line') - expect(component.lineNodeForScreenRow(0).offsetTop).toBe 0 - expect(component.lineNodeForScreenRow(1).offsetTop).toBe 1 * lineHeightInPixels - expect(component.lineNodeForScreenRow(2).offsetTop).toBe 2 * lineHeightInPixels + tilesNodes = componentNode.querySelectorAll(".tile") + + expect(tilesNodes[0].style['-webkit-transform']).toBe "translate3d(0px, 0px, 0px)" + expectLineRender(tilesNodes[0], screenRow: 0, top: 0 * lineHeightInPixels) + expectLineRender(tilesNodes[0], screenRow: 1, top: 1 * lineHeightInPixels) + expectLineRender(tilesNodes[0], screenRow: 2, top: 2 * lineHeightInPixels) + + expect(tilesNodes[1].style['-webkit-transform']).toBe "translate3d(0px, #{1 * tileHeight}px, 0px)" + expectLineRender(tilesNodes[1], screenRow: 3, top: 0 * lineHeightInPixels) + expectLineRender(tilesNodes[1], screenRow: 4, top: 1 * lineHeightInPixels) + expectLineRender(tilesNodes[1], screenRow: 5, top: 2 * lineHeightInPixels) editor.getBuffer().insert([0, 0], '\n\n') nextAnimationFrame() - lineNodes = componentNode.querySelectorAll('.line') - expect(component.lineNodeForScreenRow(0).offsetTop).toBe 0 * lineHeightInPixels - expect(component.lineNodeForScreenRow(1).offsetTop).toBe 1 * lineHeightInPixels - expect(component.lineNodeForScreenRow(2).offsetTop).toBe 2 * lineHeightInPixels - expect(component.lineNodeForScreenRow(3).offsetTop).toBe 3 * lineHeightInPixels - expect(component.lineNodeForScreenRow(4).offsetTop).toBe 4 * lineHeightInPixels + tilesNodes = componentNode.querySelectorAll(".tile") + + expect(tilesNodes[0].style['-webkit-transform']).toBe "translate3d(0px, 0px, 0px)" + expectLineRender(tilesNodes[0], screenRow: 0, top: 0 * lineHeightInPixels) + expectLineRender(tilesNodes[0], screenRow: 1, top: 1 * lineHeightInPixels) + expectLineRender(tilesNodes[0], screenRow: 2, top: 2 * lineHeightInPixels) + + expect(tilesNodes[1].style['-webkit-transform']).toBe "translate3d(0px, #{1 * tileHeight}px, 0px)" + expectLineRender(tilesNodes[1], screenRow: 3, top: 0 * lineHeightInPixels) + expectLineRender(tilesNodes[1], screenRow: 4, top: 1 * lineHeightInPixels) + expectLineRender(tilesNodes[1], screenRow: 5, top: 2 * lineHeightInPixels) + + expect(tilesNodes[2].style['-webkit-transform']).toBe "translate3d(0px, #{2 * tileHeight}px, 0px)" + expectLineRender(tilesNodes[2], screenRow: 6, top: 0 * lineHeightInPixels) + expectLineRender(tilesNodes[2], screenRow: 7, top: 1 * lineHeightInPixels) + expectLineRender(tilesNodes[2], screenRow: 8, top: 2 * lineHeightInPixels) it "updates the lines when lines are inserted or removed above the rendered row range", -> wrapperNode.style.height = 4.5 * lineHeightInPixels + 'px' @@ -483,7 +546,7 @@ describe "TextEditorComponent", -> component.measureDimensions() nextAnimationFrame() - expect(componentNode.querySelectorAll('.line-number').length).toBe 6 + 2 + 1 # line overdraw margin below + dummy line number + expect(componentNode.querySelectorAll('.line-number').length).toBe 6 + 1 # visible line-numbers + dummy line number expect(component.lineNumberNodeForScreenRow(0).textContent).toBe "#{nbsp}1" expect(component.lineNumberNodeForScreenRow(5).textContent).toBe "#{nbsp}6" @@ -491,7 +554,7 @@ describe "TextEditorComponent", -> verticalScrollbarNode.dispatchEvent(new UIEvent('scroll')) nextAnimationFrame() - expect(componentNode.querySelectorAll('.line-number').length).toBe 6 + 4 + 1 # line overdraw margin above/below + dummy line number + expect(componentNode.querySelectorAll('.line-number').length).toBe 6 + 1 # visible line-numbers + dummy line number expect(component.lineNumberNodeForScreenRow(2).textContent).toBe "#{nbsp}3" expect(component.lineNumberNodeForScreenRow(2).offsetTop).toBe 2 * lineHeightInPixels @@ -527,7 +590,7 @@ describe "TextEditorComponent", -> component.measureDimensions() nextAnimationFrame() - expect(componentNode.querySelectorAll('.line-number').length).toBe 6 + lineOverdrawMargin + 1 # 1 dummy line componentNode + expect(componentNode.querySelectorAll('.line-number').length).toBe 6 + 1 # 1 dummy line expect(component.lineNumberNodeForScreenRow(0).textContent).toBe "#{nbsp}1" expect(component.lineNumberNodeForScreenRow(1).textContent).toBe "#{nbsp}•" expect(component.lineNumberNodeForScreenRow(2).textContent).toBe "#{nbsp}2" @@ -725,13 +788,13 @@ describe "TextEditorComponent", -> cursorNodes = componentNode.querySelectorAll('.cursor') expect(cursorNodes.length).toBe 2 - expect(cursorNodes[0].style['-webkit-transform']).toBe "translate(#{10 * charWidth}px, #{4 * lineHeightInPixels}px)" - expect(cursorNodes[1].style['-webkit-transform']).toBe "translate(#{11 * charWidth}px, #{8 * lineHeightInPixels}px)" + expect(cursorNodes[0].style['-webkit-transform']).toBe "translate(#{10 * charWidth - horizontalScrollbarNode.scrollLeft}px, #{4 * lineHeightInPixels - verticalScrollbarNode.scrollTop}px)" + expect(cursorNodes[1].style['-webkit-transform']).toBe "translate(#{11 * charWidth - horizontalScrollbarNode.scrollLeft}px, #{8 * lineHeightInPixels - verticalScrollbarNode.scrollTop}px)" editor.onDidChangeCursorPosition cursorMovedListener = jasmine.createSpy('cursorMovedListener') cursor3.setScreenPosition([4, 11], autoscroll: false) nextAnimationFrame() - expect(cursorNodes[0].style['-webkit-transform']).toBe "translate(#{11 * charWidth}px, #{4 * lineHeightInPixels}px)" + expect(cursorNodes[0].style['-webkit-transform']).toBe "translate(#{11 * charWidth - horizontalScrollbarNode.scrollLeft}px, #{4 * lineHeightInPixels - verticalScrollbarNode.scrollTop}px)" expect(cursorMovedListener).toHaveBeenCalled() cursor3.destroy() @@ -739,7 +802,7 @@ describe "TextEditorComponent", -> cursorNodes = componentNode.querySelectorAll('.cursor') expect(cursorNodes.length).toBe 1 - expect(cursorNodes[0].style['-webkit-transform']).toBe "translate(#{11 * charWidth}px, #{8 * lineHeightInPixels}px)" + expect(cursorNodes[0].style['-webkit-transform']).toBe "translate(#{11 * charWidth - horizontalScrollbarNode.scrollLeft}px, #{8 * lineHeightInPixels - verticalScrollbarNode.scrollTop}px)" it "accounts for character widths when positioning cursors", -> atom.config.set('editor.fontFamily', 'sans-serif') @@ -1001,7 +1064,7 @@ describe "TextEditorComponent", -> nextAnimationFrame() # Scroll decorations into view - verticalScrollbarNode.scrollTop = 2.5 * lineHeightInPixels + verticalScrollbarNode.scrollTop = 4.5 * lineHeightInPixels verticalScrollbarNode.dispatchEvent(new UIEvent('scroll')) nextAnimationFrame() expect(lineAndLineNumberHaveClass(9, 'b')).toBe true @@ -1147,15 +1210,16 @@ describe "TextEditorComponent", -> # Nothing when outside the rendered row range expect(regions.length).toBe 0 - verticalScrollbarNode.scrollTop = 4.5 * lineHeightInPixels + verticalScrollbarNode.scrollTop = 6 * lineHeightInPixels verticalScrollbarNode.dispatchEvent(new UIEvent('scroll')) nextAnimationFrame() + expect(component.presenter.endRow).toBeGreaterThan(8) regions = componentNode.querySelectorAll('.some-highlight .region') expect(regions.length).toBe 1 regionRect = regions[0].style - expect(regionRect.top).toBe 9 * lineHeightInPixels + 'px' + expect(regionRect.top).toBe (9 * lineHeightInPixels - verticalScrollbarNode.scrollTop) + 'px' expect(regionRect.height).toBe 1 * lineHeightInPixels + 'px' expect(regionRect.left).toBe 2 * charWidth + 'px' expect(regionRect.width).toBe 2 * charWidth + 'px' @@ -2397,7 +2461,7 @@ describe "TextEditorComponent", -> hiddenParent.style.display = 'none' contentNode.appendChild(hiddenParent) - wrapperView = new TextEditorView(editor, {lineOverdrawMargin}) + wrapperView = new TextEditorView(editor, {tileSize}) wrapperNode = wrapperView.element wrapperView.appendTo(hiddenParent) diff --git a/src/lines-component.coffee b/src/lines-component.coffee index d99fbfbe1..1c855e125 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -132,4 +132,4 @@ class LinesComponent lineNodeForScreenRow: (screenRow) -> tile = @presenter.tileForRow(screenRow) - @tileComponentsByTileId[tile].lineNodeForScreenRow(screenRow) + @tileComponentsByTileId[tile]?.lineNodeForScreenRow(screenRow) From f49078d394b333d8c0fc7400fa6f2c9eec22f3a4 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 21 May 2015 10:40:37 +0200 Subject: [PATCH 1350/1783] wip --- src/foo-component.coffee | 135 ++++++++++++++++ src/lines-component.coffee | 313 +++++++++++++++++++++++++++---------- src/tile-component.coffee | 286 --------------------------------- 3 files changed, 367 insertions(+), 367 deletions(-) create mode 100644 src/foo-component.coffee delete mode 100644 src/tile-component.coffee diff --git a/src/foo-component.coffee b/src/foo-component.coffee new file mode 100644 index 000000000..1c855e125 --- /dev/null +++ b/src/foo-component.coffee @@ -0,0 +1,135 @@ +_ = require 'underscore-plus' +{toArray} = require 'underscore-plus' +{$$} = require 'space-pen' + +CursorsComponent = require './cursors-component' +HighlightsComponent = require './highlights-component' +TileComponent = require './tile-component' + +DummyLineNode = $$(-> @div className: 'line', style: 'position: absolute; visibility: hidden;', => @span 'x')[0] +AcceptFilter = {acceptNode: -> NodeFilter.FILTER_ACCEPT} +WrapperDiv = document.createElement('div') + +cloneObject = (object) -> + clone = {} + clone[key] = value for key, value of object + clone + +module.exports = +class LinesComponent + placeholderTextDiv: null + + constructor: ({@presenter, @hostElement, @useShadowDOM, visible}) -> + @tileComponentsByTileId = {} + + @domNode = document.createElement('div') + @domNode.classList.add('lines') + + @cursorsComponent = new CursorsComponent(@presenter) + @domNode.appendChild(@cursorsComponent.getDomNode()) + + @highlightsComponent = new HighlightsComponent(@presenter) + @domNode.appendChild(@highlightsComponent.getDomNode()) + + if @useShadowDOM + insertionPoint = document.createElement('content') + insertionPoint.setAttribute('select', '.overlayer') + @domNode.appendChild(insertionPoint) + + getDomNode: -> + @domNode + + updateSync: (state) -> + @newState = state.content + @oldState ?= {tiles: {}} + + if @newState.scrollHeight isnt @oldState.scrollHeight + @domNode.style.height = @newState.scrollHeight + 'px' + @oldState.scrollHeight = @newState.scrollHeight + + if @newState.backgroundColor isnt @oldState.backgroundColor + @domNode.style.backgroundColor = @newState.backgroundColor + @oldState.backgroundColor = @newState.backgroundColor + + if @newState.placeholderText isnt @oldState.placeholderText + @placeholderTextDiv?.remove() + if @newState.placeholderText? + @placeholderTextDiv = document.createElement('div') + @placeholderTextDiv.classList.add('placeholder-text') + @placeholderTextDiv.textContent = @newState.placeholderText + @domNode.appendChild(@placeholderTextDiv) + + @removeTileNodes() unless @oldState.indentGuidesVisible is @newState.indentGuidesVisible + @updateTileNodes() + + if @newState.scrollWidth isnt @oldState.scrollWidth + @domNode.style.width = @newState.scrollWidth + 'px' + @oldState.scrollWidth = @newState.scrollWidth + + @cursorsComponent.updateSync(state) + @highlightsComponent.updateSync(state) + + @oldState.indentGuidesVisible = @newState.indentGuidesVisible + @oldState.scrollWidth = @newState.scrollWidth + + removeTileNodes: -> + @removeTileNode(id) for id of @oldState.tiles + return + + removeTileNode: (id) -> + node = @tileComponentsByTileId[id].getDomNode() + + node.remove() + delete @tileComponentsByTileId[id] + delete @oldState.tiles[id] + + updateTileNodes: -> + for id of @oldState.tiles + unless @newState.tiles.hasOwnProperty(id) + @removeTileNode(id) + + for id, tileState of @newState.tiles + if @oldState.tiles.hasOwnProperty(id) + tileComponent = @tileComponentsByTileId[id] + else + tileComponent = @tileComponentsByTileId[id] = new TileComponent({id, @presenter}) + + @domNode.appendChild(tileComponent.getDomNode()) + @oldState.tiles[id] = cloneObject(tileState) + + tileComponent.updateSync(@newState) + + return + + measureLineHeightAndDefaultCharWidth: -> + @domNode.appendChild(DummyLineNode) + lineHeightInPixels = DummyLineNode.getBoundingClientRect().height + charWidth = DummyLineNode.firstChild.getBoundingClientRect().width + @domNode.removeChild(DummyLineNode) + + @presenter.setLineHeight(lineHeightInPixels) + @presenter.setBaseCharacterWidth(charWidth) + + remeasureCharacterWidths: -> + return unless @presenter.baseCharacterWidth + + @clearScopedCharWidths() + @measureCharactersInNewLines() + + measureCharactersInNewLines: -> + @presenter.batchCharacterMeasurement => + for id, component of @tileComponentsByTileId + component.measureCharactersInNewLines() + + return + + clearScopedCharWidths: -> + for id, component of @tileComponentsByTileId + component.clearMeasurements() + + @presenter.clearScopedCharacterWidths() + + lineNodeForScreenRow: (screenRow) -> + tile = @presenter.tileForRow(screenRow) + + @tileComponentsByTileId[tile]?.lineNodeForScreenRow(screenRow) diff --git a/src/lines-component.coffee b/src/lines-component.coffee index 1c855e125..20c9d7ff1 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -2,10 +2,6 @@ _ = require 'underscore-plus' {toArray} = require 'underscore-plus' {$$} = require 'space-pen' -CursorsComponent = require './cursors-component' -HighlightsComponent = require './highlights-component' -TileComponent = require './tile-component' - DummyLineNode = $$(-> @div className: 'line', style: 'position: absolute; visibility: hidden;', => @span 'x')[0] AcceptFilter = {acceptNode: -> NodeFilter.FILTER_ACCEPT} WrapperDiv = document.createElement('div') @@ -16,120 +12,275 @@ cloneObject = (object) -> clone module.exports = -class LinesComponent +class TileComponent placeholderTextDiv: null - constructor: ({@presenter, @hostElement, @useShadowDOM, visible}) -> - @tileComponentsByTileId = {} - - @domNode = document.createElement('div') - @domNode.classList.add('lines') - - @cursorsComponent = new CursorsComponent(@presenter) - @domNode.appendChild(@cursorsComponent.getDomNode()) - - @highlightsComponent = new HighlightsComponent(@presenter) - @domNode.appendChild(@highlightsComponent.getDomNode()) - - if @useShadowDOM - insertionPoint = document.createElement('content') - insertionPoint.setAttribute('select', '.overlayer') - @domNode.appendChild(insertionPoint) + constructor: ({@presenter, @id}) -> + @measuredLines = new Set + @lineNodesByLineId = {} + @screenRowsByLineId = {} + @lineIdsByScreenRow = {} + @domNode = document.createElement("div") + @domNode.classList.add("tile") + @domNode.style.position = "absolute" + @domNode.style.display = "block" getDomNode: -> @domNode updateSync: (state) -> - @newState = state.content - @oldState ?= {tiles: {}} + @newState = state + unless @oldState + @oldState = {tiles: {}} + @oldState.tiles[@id] = {lines: {}} - if @newState.scrollHeight isnt @oldState.scrollHeight - @domNode.style.height = @newState.scrollHeight + 'px' - @oldState.scrollHeight = @newState.scrollHeight + @newTileState = @newState.tiles[@id] + @oldTileState = @oldState.tiles[@id] - if @newState.backgroundColor isnt @oldState.backgroundColor - @domNode.style.backgroundColor = @newState.backgroundColor - @oldState.backgroundColor = @newState.backgroundColor + if @newTileState.display isnt @oldTileState.display + @domNode.style.display = @newTileState.display + @oldTileState.display = @newTileState.display - if @newState.placeholderText isnt @oldState.placeholderText - @placeholderTextDiv?.remove() - if @newState.placeholderText? - @placeholderTextDiv = document.createElement('div') - @placeholderTextDiv.classList.add('placeholder-text') - @placeholderTextDiv.textContent = @newState.placeholderText - @domNode.appendChild(@placeholderTextDiv) + if @newTileState.height isnt @oldTileState.height + @domNode.style.height = @newTileState.height + 'px' + @oldTileState.height = @newTileState.height - @removeTileNodes() unless @oldState.indentGuidesVisible is @newState.indentGuidesVisible - @updateTileNodes() + if @newTileState.top isnt @oldTileState.top or @newTileState.left isnt @oldTileState.left + @domNode.style['-webkit-transform'] = "translate3d(#{@newTileState.left}px, #{@newTileState.top}px, 0px)" + @oldTileState.top = @newTileState.top + @oldTileState.left = @newTileState.left + + @removeLineNodes() unless @oldState.indentGuidesVisible is @newState.indentGuidesVisible + @updateLineNodes() if @newState.scrollWidth isnt @oldState.scrollWidth @domNode.style.width = @newState.scrollWidth + 'px' @oldState.scrollWidth = @newState.scrollWidth - @cursorsComponent.updateSync(state) - @highlightsComponent.updateSync(state) - @oldState.indentGuidesVisible = @newState.indentGuidesVisible @oldState.scrollWidth = @newState.scrollWidth - removeTileNodes: -> - @removeTileNode(id) for id of @oldState.tiles + removeLineNodes: -> + @removeLineNode(id) for id of @oldTileState.lines return - removeTileNode: (id) -> - node = @tileComponentsByTileId[id].getDomNode() + removeLineNode: (id) -> + @lineNodesByLineId[id].remove() + delete @lineNodesByLineId[id] + delete @lineIdsByScreenRow[@screenRowsByLineId[id]] + delete @screenRowsByLineId[id] + delete @oldTileState.lines[id] - node.remove() - delete @tileComponentsByTileId[id] - delete @oldState.tiles[id] + updateLineNodes: -> + for id of @oldTileState.lines + unless @newTileState.lines.hasOwnProperty(id) + @removeLineNode(id) - updateTileNodes: -> - for id of @oldState.tiles - unless @newState.tiles.hasOwnProperty(id) - @removeTileNode(id) + newLineIds = null + newLinesHTML = null - for id, tileState of @newState.tiles - if @oldState.tiles.hasOwnProperty(id) - tileComponent = @tileComponentsByTileId[id] + for id, lineState of @newTileState.lines + if @oldTileState.lines.hasOwnProperty(id) + @updateLineNode(id) else - tileComponent = @tileComponentsByTileId[id] = new TileComponent({id, @presenter}) + newLineIds ?= [] + newLinesHTML ?= "" + newLineIds.push(id) + newLinesHTML += @buildLineHTML(id) + @screenRowsByLineId[id] = lineState.screenRow + @lineIdsByScreenRow[lineState.screenRow] = id + @oldTileState.lines[id] = cloneObject(lineState) - @domNode.appendChild(tileComponent.getDomNode()) - @oldState.tiles[id] = cloneObject(tileState) + return unless newLineIds? - tileComponent.updateSync(@newState) + WrapperDiv.innerHTML = newLinesHTML + newLineNodes = _.toArray(WrapperDiv.children) + for id, i in newLineIds + lineNode = newLineNodes[i] + @lineNodesByLineId[id] = lineNode + @domNode.appendChild(lineNode) return - measureLineHeightAndDefaultCharWidth: -> - @domNode.appendChild(DummyLineNode) - lineHeightInPixels = DummyLineNode.getBoundingClientRect().height - charWidth = DummyLineNode.firstChild.getBoundingClientRect().width - @domNode.removeChild(DummyLineNode) + buildLineHTML: (id) -> + {scrollWidth} = @newState + {screenRow, tokens, text, top, lineEnding, fold, isSoftWrapped, indentLevel, decorationClasses} = @newTileState.lines[id] - @presenter.setLineHeight(lineHeightInPixels) - @presenter.setBaseCharacterWidth(charWidth) + classes = '' + if decorationClasses? + for decorationClass in decorationClasses + classes += decorationClass + ' ' + classes += 'line' - remeasureCharacterWidths: -> - return unless @presenter.baseCharacterWidth + lineHTML = "
" - @clearScopedCharWidths() - @measureCharactersInNewLines() + if text is "" + lineHTML += @buildEmptyLineInnerHTML(id) + else + lineHTML += @buildLineInnerHTML(id) - measureCharactersInNewLines: -> - @presenter.batchCharacterMeasurement => - for id, component of @tileComponentsByTileId - component.measureCharactersInNewLines() + lineHTML += '' if fold + lineHTML += "
" + lineHTML - return + buildEmptyLineInnerHTML: (id) -> + {indentGuidesVisible} = @newState + {indentLevel, tabLength, endOfLineInvisibles} = @newTileState.lines[id] - clearScopedCharWidths: -> - for id, component of @tileComponentsByTileId - component.clearMeasurements() + if indentGuidesVisible and indentLevel > 0 + invisibleIndex = 0 + lineHTML = '' + for i in [0...indentLevel] + lineHTML += "" + for j in [0...tabLength] + if invisible = endOfLineInvisibles?[invisibleIndex++] + lineHTML += "#{invisible}" + else + lineHTML += ' ' + lineHTML += "" - @presenter.clearScopedCharacterWidths() + while invisibleIndex < endOfLineInvisibles?.length + lineHTML += "#{endOfLineInvisibles[invisibleIndex++]}" + + lineHTML + else + @buildEndOfLineHTML(id) or ' ' + + buildLineInnerHTML: (id) -> + {indentGuidesVisible} = @newState + {tokens, text, isOnlyWhitespace} = @newTileState.lines[id] + innerHTML = "" + + scopeStack = [] + for token in tokens + innerHTML += @updateScopeStack(scopeStack, token.scopes) + hasIndentGuide = indentGuidesVisible and (token.hasLeadingWhitespace() or (token.hasTrailingWhitespace() and isOnlyWhitespace)) + innerHTML += token.getValueAsHtml({hasIndentGuide}) + + innerHTML += @popScope(scopeStack) while scopeStack.length > 0 + innerHTML += @buildEndOfLineHTML(id) + innerHTML + + buildEndOfLineHTML: (id) -> + {endOfLineInvisibles} = @newTileState.lines[id] + + html = '' + if endOfLineInvisibles? + for invisible in endOfLineInvisibles + html += "#{invisible}" + html + + updateScopeStack: (scopeStack, desiredScopeDescriptor) -> + html = "" + + # Find a common prefix + for scope, i in desiredScopeDescriptor + break unless scopeStack[i] is desiredScopeDescriptor[i] + + # Pop scopeDescriptor until we're at the common prefx + until scopeStack.length is i + html += @popScope(scopeStack) + + # Push onto common prefix until scopeStack equals desiredScopeDescriptor + for j in [i...desiredScopeDescriptor.length] + html += @pushScope(scopeStack, desiredScopeDescriptor[j]) + + html + + popScope: (scopeStack) -> + scopeStack.pop() + "" + + pushScope: (scopeStack, scope) -> + scopeStack.push(scope) + "" + + updateLineNode: (id) -> + oldLineState = @oldTileState.lines[id] + newLineState = @newTileState.lines[id] + + lineNode = @lineNodesByLineId[id] + + if @newState.scrollWidth isnt @oldState.scrollWidth + lineNode.style.width = @newState.scrollWidth + 'px' + + newDecorationClasses = newLineState.decorationClasses + oldDecorationClasses = oldLineState.decorationClasses + + if oldDecorationClasses? + for decorationClass in oldDecorationClasses + unless newDecorationClasses? and decorationClass in newDecorationClasses + lineNode.classList.remove(decorationClass) + + if newDecorationClasses? + for decorationClass in newDecorationClasses + unless oldDecorationClasses? and decorationClass in oldDecorationClasses + lineNode.classList.add(decorationClass) + + oldLineState.decorationClasses = newLineState.decorationClasses + + if newLineState.top isnt oldLineState.top + lineNode.style.top = newLineState.top + 'px' + oldLineState.top = newLineState.top + + if newLineState.screenRow isnt oldLineState.screenRow + lineNode.dataset.screenRow = newLineState.screenRow + oldLineState.screenRow = newLineState.screenRow + @lineIdsByScreenRow[newLineState.screenRow] = id lineNodeForScreenRow: (screenRow) -> - tile = @presenter.tileForRow(screenRow) + @lineNodesByLineId[@lineIdsByScreenRow[screenRow]] - @tileComponentsByTileId[tile]?.lineNodeForScreenRow(screenRow) + measureCharactersInNewLines: -> + for id, lineState of @oldTileState.lines + unless @measuredLines.has(id) + lineNode = @lineNodesByLineId[id] + @measureCharactersInLine(id, lineState, lineNode) + return + + measureCharactersInLine: (lineId, tokenizedLine, lineNode) -> + rangeForMeasurement = null + iterator = null + charIndex = 0 + + for {value, scopes, hasPairedCharacter} in tokenizedLine.tokens + charWidths = @presenter.getScopedCharacterWidths(scopes) + + valueIndex = 0 + while valueIndex < value.length + if hasPairedCharacter + char = value.substr(valueIndex, 2) + charLength = 2 + valueIndex += 2 + else + char = value[valueIndex] + charLength = 1 + valueIndex++ + + continue if char is '\0' + + unless charWidths[char]? + unless textNode? + rangeForMeasurement ?= document.createRange() + iterator = document.createNodeIterator(lineNode, NodeFilter.SHOW_TEXT, AcceptFilter) + textNode = iterator.nextNode() + textNodeIndex = 0 + nextTextNodeIndex = textNode.textContent.length + + while nextTextNodeIndex <= charIndex + textNode = iterator.nextNode() + textNodeIndex = nextTextNodeIndex + nextTextNodeIndex = textNodeIndex + textNode.textContent.length + + i = charIndex - textNodeIndex + rangeForMeasurement.setStart(textNode, i) + rangeForMeasurement.setEnd(textNode, i + charLength) + charWidth = rangeForMeasurement.getBoundingClientRect().width + @presenter.setScopedCharacterWidth(scopes, char, charWidth) + + charIndex += charLength + + @measuredLines.add(lineId) + + clearMeasurements: -> + @measuredLines.clear() diff --git a/src/tile-component.coffee b/src/tile-component.coffee deleted file mode 100644 index 20c9d7ff1..000000000 --- a/src/tile-component.coffee +++ /dev/null @@ -1,286 +0,0 @@ -_ = require 'underscore-plus' -{toArray} = require 'underscore-plus' -{$$} = require 'space-pen' - -DummyLineNode = $$(-> @div className: 'line', style: 'position: absolute; visibility: hidden;', => @span 'x')[0] -AcceptFilter = {acceptNode: -> NodeFilter.FILTER_ACCEPT} -WrapperDiv = document.createElement('div') - -cloneObject = (object) -> - clone = {} - clone[key] = value for key, value of object - clone - -module.exports = -class TileComponent - placeholderTextDiv: null - - constructor: ({@presenter, @id}) -> - @measuredLines = new Set - @lineNodesByLineId = {} - @screenRowsByLineId = {} - @lineIdsByScreenRow = {} - @domNode = document.createElement("div") - @domNode.classList.add("tile") - @domNode.style.position = "absolute" - @domNode.style.display = "block" - - getDomNode: -> - @domNode - - updateSync: (state) -> - @newState = state - unless @oldState - @oldState = {tiles: {}} - @oldState.tiles[@id] = {lines: {}} - - @newTileState = @newState.tiles[@id] - @oldTileState = @oldState.tiles[@id] - - if @newTileState.display isnt @oldTileState.display - @domNode.style.display = @newTileState.display - @oldTileState.display = @newTileState.display - - if @newTileState.height isnt @oldTileState.height - @domNode.style.height = @newTileState.height + 'px' - @oldTileState.height = @newTileState.height - - if @newTileState.top isnt @oldTileState.top or @newTileState.left isnt @oldTileState.left - @domNode.style['-webkit-transform'] = "translate3d(#{@newTileState.left}px, #{@newTileState.top}px, 0px)" - @oldTileState.top = @newTileState.top - @oldTileState.left = @newTileState.left - - @removeLineNodes() unless @oldState.indentGuidesVisible is @newState.indentGuidesVisible - @updateLineNodes() - - if @newState.scrollWidth isnt @oldState.scrollWidth - @domNode.style.width = @newState.scrollWidth + 'px' - @oldState.scrollWidth = @newState.scrollWidth - - @oldState.indentGuidesVisible = @newState.indentGuidesVisible - @oldState.scrollWidth = @newState.scrollWidth - - removeLineNodes: -> - @removeLineNode(id) for id of @oldTileState.lines - return - - removeLineNode: (id) -> - @lineNodesByLineId[id].remove() - delete @lineNodesByLineId[id] - delete @lineIdsByScreenRow[@screenRowsByLineId[id]] - delete @screenRowsByLineId[id] - delete @oldTileState.lines[id] - - updateLineNodes: -> - for id of @oldTileState.lines - unless @newTileState.lines.hasOwnProperty(id) - @removeLineNode(id) - - newLineIds = null - newLinesHTML = null - - for id, lineState of @newTileState.lines - if @oldTileState.lines.hasOwnProperty(id) - @updateLineNode(id) - else - newLineIds ?= [] - newLinesHTML ?= "" - newLineIds.push(id) - newLinesHTML += @buildLineHTML(id) - @screenRowsByLineId[id] = lineState.screenRow - @lineIdsByScreenRow[lineState.screenRow] = id - @oldTileState.lines[id] = cloneObject(lineState) - - return unless newLineIds? - - WrapperDiv.innerHTML = newLinesHTML - newLineNodes = _.toArray(WrapperDiv.children) - for id, i in newLineIds - lineNode = newLineNodes[i] - @lineNodesByLineId[id] = lineNode - @domNode.appendChild(lineNode) - - return - - buildLineHTML: (id) -> - {scrollWidth} = @newState - {screenRow, tokens, text, top, lineEnding, fold, isSoftWrapped, indentLevel, decorationClasses} = @newTileState.lines[id] - - classes = '' - if decorationClasses? - for decorationClass in decorationClasses - classes += decorationClass + ' ' - classes += 'line' - - lineHTML = "
" - - if text is "" - lineHTML += @buildEmptyLineInnerHTML(id) - else - lineHTML += @buildLineInnerHTML(id) - - lineHTML += '' if fold - lineHTML += "
" - lineHTML - - buildEmptyLineInnerHTML: (id) -> - {indentGuidesVisible} = @newState - {indentLevel, tabLength, endOfLineInvisibles} = @newTileState.lines[id] - - if indentGuidesVisible and indentLevel > 0 - invisibleIndex = 0 - lineHTML = '' - for i in [0...indentLevel] - lineHTML += "" - for j in [0...tabLength] - if invisible = endOfLineInvisibles?[invisibleIndex++] - lineHTML += "#{invisible}" - else - lineHTML += ' ' - lineHTML += "" - - while invisibleIndex < endOfLineInvisibles?.length - lineHTML += "#{endOfLineInvisibles[invisibleIndex++]}" - - lineHTML - else - @buildEndOfLineHTML(id) or ' ' - - buildLineInnerHTML: (id) -> - {indentGuidesVisible} = @newState - {tokens, text, isOnlyWhitespace} = @newTileState.lines[id] - innerHTML = "" - - scopeStack = [] - for token in tokens - innerHTML += @updateScopeStack(scopeStack, token.scopes) - hasIndentGuide = indentGuidesVisible and (token.hasLeadingWhitespace() or (token.hasTrailingWhitespace() and isOnlyWhitespace)) - innerHTML += token.getValueAsHtml({hasIndentGuide}) - - innerHTML += @popScope(scopeStack) while scopeStack.length > 0 - innerHTML += @buildEndOfLineHTML(id) - innerHTML - - buildEndOfLineHTML: (id) -> - {endOfLineInvisibles} = @newTileState.lines[id] - - html = '' - if endOfLineInvisibles? - for invisible in endOfLineInvisibles - html += "#{invisible}" - html - - updateScopeStack: (scopeStack, desiredScopeDescriptor) -> - html = "" - - # Find a common prefix - for scope, i in desiredScopeDescriptor - break unless scopeStack[i] is desiredScopeDescriptor[i] - - # Pop scopeDescriptor until we're at the common prefx - until scopeStack.length is i - html += @popScope(scopeStack) - - # Push onto common prefix until scopeStack equals desiredScopeDescriptor - for j in [i...desiredScopeDescriptor.length] - html += @pushScope(scopeStack, desiredScopeDescriptor[j]) - - html - - popScope: (scopeStack) -> - scopeStack.pop() - "
" - - pushScope: (scopeStack, scope) -> - scopeStack.push(scope) - "" - - updateLineNode: (id) -> - oldLineState = @oldTileState.lines[id] - newLineState = @newTileState.lines[id] - - lineNode = @lineNodesByLineId[id] - - if @newState.scrollWidth isnt @oldState.scrollWidth - lineNode.style.width = @newState.scrollWidth + 'px' - - newDecorationClasses = newLineState.decorationClasses - oldDecorationClasses = oldLineState.decorationClasses - - if oldDecorationClasses? - for decorationClass in oldDecorationClasses - unless newDecorationClasses? and decorationClass in newDecorationClasses - lineNode.classList.remove(decorationClass) - - if newDecorationClasses? - for decorationClass in newDecorationClasses - unless oldDecorationClasses? and decorationClass in oldDecorationClasses - lineNode.classList.add(decorationClass) - - oldLineState.decorationClasses = newLineState.decorationClasses - - if newLineState.top isnt oldLineState.top - lineNode.style.top = newLineState.top + 'px' - oldLineState.top = newLineState.top - - if newLineState.screenRow isnt oldLineState.screenRow - lineNode.dataset.screenRow = newLineState.screenRow - oldLineState.screenRow = newLineState.screenRow - @lineIdsByScreenRow[newLineState.screenRow] = id - - lineNodeForScreenRow: (screenRow) -> - @lineNodesByLineId[@lineIdsByScreenRow[screenRow]] - - measureCharactersInNewLines: -> - for id, lineState of @oldTileState.lines - unless @measuredLines.has(id) - lineNode = @lineNodesByLineId[id] - @measureCharactersInLine(id, lineState, lineNode) - return - - measureCharactersInLine: (lineId, tokenizedLine, lineNode) -> - rangeForMeasurement = null - iterator = null - charIndex = 0 - - for {value, scopes, hasPairedCharacter} in tokenizedLine.tokens - charWidths = @presenter.getScopedCharacterWidths(scopes) - - valueIndex = 0 - while valueIndex < value.length - if hasPairedCharacter - char = value.substr(valueIndex, 2) - charLength = 2 - valueIndex += 2 - else - char = value[valueIndex] - charLength = 1 - valueIndex++ - - continue if char is '\0' - - unless charWidths[char]? - unless textNode? - rangeForMeasurement ?= document.createRange() - iterator = document.createNodeIterator(lineNode, NodeFilter.SHOW_TEXT, AcceptFilter) - textNode = iterator.nextNode() - textNodeIndex = 0 - nextTextNodeIndex = textNode.textContent.length - - while nextTextNodeIndex <= charIndex - textNode = iterator.nextNode() - textNodeIndex = nextTextNodeIndex - nextTextNodeIndex = textNodeIndex + textNode.textContent.length - - i = charIndex - textNodeIndex - rangeForMeasurement.setStart(textNode, i) - rangeForMeasurement.setEnd(textNode, i + charLength) - charWidth = rangeForMeasurement.getBoundingClientRect().width - @presenter.setScopedCharacterWidth(scopes, char, charWidth) - - charIndex += charLength - - @measuredLines.add(lineId) - - clearMeasurements: -> - @measuredLines.clear() From efeb129cff9a81e38cfa8e8d8663680b63b0959c Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 21 May 2015 10:47:23 +0200 Subject: [PATCH 1351/1783] Rename LinesComponent to TileComponent --- src/{lines-component.coffee => tile-component.coffee} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{lines-component.coffee => tile-component.coffee} (100%) diff --git a/src/lines-component.coffee b/src/tile-component.coffee similarity index 100% rename from src/lines-component.coffee rename to src/tile-component.coffee From 1a5e2fe5dd6b0632b38c956822fc6223433abbca Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 21 May 2015 10:48:04 +0200 Subject: [PATCH 1352/1783] :art: --- src/{foo-component.coffee => lines-component.coffee} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{foo-component.coffee => lines-component.coffee} (100%) diff --git a/src/foo-component.coffee b/src/lines-component.coffee similarity index 100% rename from src/foo-component.coffee rename to src/lines-component.coffee From 490ab2c468605ca0165a359b3f623eee1808f149 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 21 May 2015 11:07:03 +0200 Subject: [PATCH 1353/1783] :green_heart: Conflicts: spec/text-editor-presenter-spec.coffee src/lines-component.coffee src/text-editor-presenter.coffee --- spec/text-editor-presenter-spec.coffee | 50 +++++++++++++++++++++----- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 424f4bc85..872b71c58 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -660,7 +660,7 @@ describe "TextEditorPresenter", -> lineStateForScreenRow = (presenter, row) -> lineId = presenter.model.tokenizedLineForScreenRow(row).id tileRow = presenter.tileForRow(row) - presenter.getState().content.tiles[tileRow].lines[lineId] + presenter.getState().content.tiles[tileRow]?.lines[lineId] it "contains states for tiles that are visible on screen", -> presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileSize: 2) @@ -680,6 +680,25 @@ describe "TextEditorPresenter", -> expect(presenter.getState().content.tiles[8]).toBeUndefined() + expectStateUpdate -> presenter.setScrollTop(3) + + expect(presenter.getState().content.tiles[0]).toBeUndefined() + + expectValues presenter.getState().content.tiles[2], { + top: -1 + } + expectValues presenter.getState().content.tiles[4], { + top: 1 + } + expectValues presenter.getState().content.tiles[6], { + top: 3 + } + expectValues presenter.getState().content.tiles[8], { + top: 5 + } + + expect(presenter.getState().content.tiles[10]).toBeUndefined() + it "includes state for all tiles if no external ::explicitHeight is assigned", -> presenter = buildPresenter(explicitHeight: null, tileSize: 2) expect(presenter.getState().content.tiles[0]).toBeDefined() @@ -814,8 +833,22 @@ describe "TextEditorPresenter", -> expect(presenter.getState().content.tiles[0]).toBeDefined() describe "[tileId].lines[lineId]", -> # line state objects - xit "includes the state for lines in a tile", -> - expect(lineStateForScreenRow(presenter, 3)).toBeUndefined() + it "includes the state for visible lines in a tile", -> + presenter = buildPresenter(explicitHeight: 3, scrollTop: 4, lineHeight: 1, tileSize: 3, stoppedScrollingDelay: 200) + + expect(lineStateForScreenRow(presenter, 2)).toBeUndefined() + + line3 = editor.tokenizedLineForScreenRow(3) + expectValues lineStateForScreenRow(presenter, 3), { + screenRow: 3 + text: line3.text + tags: line3.tags + specialTokens: line3.specialTokens + firstNonWhitespaceIndex: line3.firstNonWhitespaceIndex + firstTrailingWhitespaceIndex: line3.firstTrailingWhitespaceIndex + invisibles: line3.invisibles + top: 0 + } line4 = editor.tokenizedLineForScreenRow(4) expectValues lineStateForScreenRow(presenter, 4), { @@ -826,7 +859,7 @@ describe "TextEditorPresenter", -> firstNonWhitespaceIndex: line4.firstNonWhitespaceIndex firstTrailingWhitespaceIndex: line4.firstTrailingWhitespaceIndex invisibles: line4.invisibles - top: 10 * 4 + top: 1 } line5 = editor.tokenizedLineForScreenRow(5) @@ -838,7 +871,7 @@ describe "TextEditorPresenter", -> firstNonWhitespaceIndex: line5.firstNonWhitespaceIndex firstTrailingWhitespaceIndex: line5.firstTrailingWhitespaceIndex invisibles: line5.invisibles - top: 10 * 5 + top: 2 } line6 = editor.tokenizedLineForScreenRow(6) @@ -850,7 +883,7 @@ describe "TextEditorPresenter", -> firstNonWhitespaceIndex: line6.firstNonWhitespaceIndex firstTrailingWhitespaceIndex: line6.firstTrailingWhitespaceIndex invisibles: line6.invisibles - top: 10 * 6 + top: 0 } line7 = editor.tokenizedLineForScreenRow(7) @@ -862,7 +895,7 @@ describe "TextEditorPresenter", -> firstNonWhitespaceIndex: line7.firstNonWhitespaceIndex firstTrailingWhitespaceIndex: line7.firstTrailingWhitespaceIndex invisibles: line7.invisibles - top: 10 * 7 + top: 1 } line8 = editor.tokenizedLineForScreenRow(8) @@ -874,9 +907,10 @@ describe "TextEditorPresenter", -> firstNonWhitespaceIndex: line8.firstNonWhitespaceIndex firstTrailingWhitespaceIndex: line8.firstTrailingWhitespaceIndex invisibles: line8.invisibles - top: 10 * 8 + top: 2 } + expect(lineStateForScreenRow(presenter, 9)).toBeUndefined() it "includes the .endOfLineInvisibles if the editor.showInvisibles config option is true", -> editor.setText("hello\nworld\r\n") From c9a159aab39bf242383534d7365d29fc87cca5e7 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 21 May 2015 11:16:28 +0200 Subject: [PATCH 1354/1783] :fire: Remove unused requires --- src/lines-component.coffee | 4 ---- src/tile-component.coffee | 3 --- 2 files changed, 7 deletions(-) diff --git a/src/lines-component.coffee b/src/lines-component.coffee index 1c855e125..23f1c0015 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -1,5 +1,3 @@ -_ = require 'underscore-plus' -{toArray} = require 'underscore-plus' {$$} = require 'space-pen' CursorsComponent = require './cursors-component' @@ -7,8 +5,6 @@ HighlightsComponent = require './highlights-component' TileComponent = require './tile-component' DummyLineNode = $$(-> @div className: 'line', style: 'position: absolute; visibility: hidden;', => @span 'x')[0] -AcceptFilter = {acceptNode: -> NodeFilter.FILTER_ACCEPT} -WrapperDiv = document.createElement('div') cloneObject = (object) -> clone = {} diff --git a/src/tile-component.coffee b/src/tile-component.coffee index 31ff61616..88e06afd2 100644 --- a/src/tile-component.coffee +++ b/src/tile-component.coffee @@ -1,9 +1,6 @@ _ = require 'underscore-plus' -{toArray} = require 'underscore-plus' -{$$} = require 'space-pen' TokenIterator = require './token-iterator' -DummyLineNode = $$(-> @div className: 'line', style: 'position: absolute; visibility: hidden;', => @span 'x')[0] AcceptFilter = {acceptNode: -> NodeFilter.FILTER_ACCEPT} WrapperDiv = document.createElement('div') TokenTextEscapeRegex = /[&"'<>]/g From f919bc40dc033c914dcec014597c7b59da1617c5 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Thu, 21 May 2015 08:35:01 -0400 Subject: [PATCH 1355/1783] Add lsb_release as Linux dependency --- resources/linux/debian/control.in | 1 + resources/linux/redhat/atom.spec.in | 2 ++ 2 files changed, 3 insertions(+) diff --git a/resources/linux/debian/control.in b/resources/linux/debian/control.in index 1578f544b..cf2356a5d 100644 --- a/resources/linux/debian/control.in +++ b/resources/linux/debian/control.in @@ -1,6 +1,7 @@ Package: <%= name %> Version: <%= version %> Depends: git, gconf2, gconf-service, libgtk2.0-0, libudev0 | libudev1, libgcrypt11 | libgcrypt20, libnotify4, libxtst6, libnss3, python, gvfs-bin, xdg-utils +Recommends: lsb-release Suggests: libgnome-keyring0, gir1.2-gnomekeyring-1.0 Section: <%= section %> Priority: optional diff --git a/resources/linux/redhat/atom.spec.in b/resources/linux/redhat/atom.spec.in index 369aeea70..3bc37e83a 100644 --- a/resources/linux/redhat/atom.spec.in +++ b/resources/linux/redhat/atom.spec.in @@ -7,6 +7,8 @@ URL: https://atom.io/ AutoReqProv: no # Avoid libchromiumcontent.so missing dependency Prefix: <%= installDir %> +Requires: redhat-lsb-core + %description <%= description %> From 7cb0bc3bc2aaa0f01b26c8a71f7e5890f8e570d3 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 21 May 2015 16:25:23 +0200 Subject: [PATCH 1356/1783] Revert "Merge pull request #6757 from atom/ns-less-memory-for-tokens" This reverts commit 0cd1f110b581e4c29fa4cec432cdbb93ecba2409, reversing changes made to d75d202d337142e206e500c10fed34151b4cc750. Conflicts: package.json --- package.json | 4 +- spec/text-editor-presenter-spec.coffee | 36 +- spec/text-editor-spec.coffee | 3 +- spec/tokenized-buffer-spec.coffee | 28 +- spec/tokenized-line-spec.coffee | 21 + src/display-buffer.coffee | 32 +- src/language-mode.coffee | 5 +- src/lines-component.coffee | 160 ++------ src/special-token-symbols.coffee | 6 - src/text-editor-presenter.coffee | 24 +- src/text-editor.coffee | 3 +- src/token-iterator.coffee | 83 ---- src/token.coffee | 199 +++++++++- src/tokenized-buffer.coffee | 184 +++++---- src/tokenized-line.coffee | 524 +++++++++---------------- 15 files changed, 601 insertions(+), 711 deletions(-) delete mode 100644 src/special-token-symbols.coffee delete mode 100644 src/token-iterator.coffee diff --git a/package.json b/package.json index 7e6619ab8..15eb53b29 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "delegato": "^1", "emissary": "^1.3.3", "event-kit": "^1.2.0", - "first-mate": "^4.1.4", + "first-mate": "^3.1", "fs-plus": "^2.8.0", "fstream": "0.1.24", "fuzzaldrin": "^2.1", @@ -151,7 +151,7 @@ "language-ruby": "0.54.0", "language-ruby-on-rails": "0.21.0", "language-sass": "0.38.0", - "language-shellscript": "0.15.0", + "language-shellscript": "0.14.0", "language-source": "0.9.0", "language-sql": "0.15.0", "language-text": "0.6.0", diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index d15c4759d..7da866ab4 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -670,11 +670,7 @@ describe "TextEditorPresenter", -> expectValues lineStateForScreenRow(presenter, 4), { screenRow: 4 text: line4.text - tags: line4.tags - specialTokens: line4.specialTokens - firstNonWhitespaceIndex: line4.firstNonWhitespaceIndex - firstTrailingWhitespaceIndex: line4.firstTrailingWhitespaceIndex - invisibles: line4.invisibles + tokens: line4.tokens top: 10 * 4 } @@ -682,11 +678,7 @@ describe "TextEditorPresenter", -> expectValues lineStateForScreenRow(presenter, 5), { screenRow: 5 text: line5.text - tags: line5.tags - specialTokens: line5.specialTokens - firstNonWhitespaceIndex: line5.firstNonWhitespaceIndex - firstTrailingWhitespaceIndex: line5.firstTrailingWhitespaceIndex - invisibles: line5.invisibles + tokens: line5.tokens top: 10 * 5 } @@ -694,11 +686,7 @@ describe "TextEditorPresenter", -> expectValues lineStateForScreenRow(presenter, 6), { screenRow: 6 text: line6.text - tags: line6.tags - specialTokens: line6.specialTokens - firstNonWhitespaceIndex: line6.firstNonWhitespaceIndex - firstTrailingWhitespaceIndex: line6.firstTrailingWhitespaceIndex - invisibles: line6.invisibles + tokens: line6.tokens top: 10 * 6 } @@ -706,11 +694,7 @@ describe "TextEditorPresenter", -> expectValues lineStateForScreenRow(presenter, 7), { screenRow: 7 text: line7.text - tags: line7.tags - specialTokens: line7.specialTokens - firstNonWhitespaceIndex: line7.firstNonWhitespaceIndex - firstTrailingWhitespaceIndex: line7.firstTrailingWhitespaceIndex - invisibles: line7.invisibles + tokens: line7.tokens top: 10 * 7 } @@ -718,11 +702,7 @@ describe "TextEditorPresenter", -> expectValues lineStateForScreenRow(presenter, 8), { screenRow: 8 text: line8.text - tags: line8.tags - specialTokens: line8.specialTokens - firstNonWhitespaceIndex: line8.firstNonWhitespaceIndex - firstTrailingWhitespaceIndex: line8.firstTrailingWhitespaceIndex - invisibles: line8.invisibles + tokens: line8.tokens top: 10 * 8 } @@ -817,19 +797,19 @@ describe "TextEditorPresenter", -> line1 = editor.tokenizedLineForScreenRow(1) expectValues lineStateForScreenRow(presenter, 1), { text: line1.text - tags: line1.tags + tokens: line1.tokens } line2 = editor.tokenizedLineForScreenRow(2) expectValues lineStateForScreenRow(presenter, 2), { text: line2.text - tags: line2.tags + tokens: line2.tokens } line3 = editor.tokenizedLineForScreenRow(3) expectValues lineStateForScreenRow(presenter, 3), { text: line3.text - tags: line3.tags + tokens: line3.tokens } it "does not remove out-of-view lines corresponding to ::mouseWheelScreenRow until ::stoppedScrollingDelay elapses", -> diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index a845619ba..d1d311088 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -4110,9 +4110,8 @@ describe "TextEditor", -> runs -> grammar = atom.grammars.selectGrammar("text.js") - {line, tags} = grammar.tokenizeLine("var i; // http://github.com") + {tokens} = grammar.tokenizeLine("var i; // http://github.com") - tokens = atom.grammars.decodeTokens(line, tags) expect(tokens[0].value).toBe "var" expect(tokens[0].scopes).toEqual ["source.js", "storage.modifier.js"] diff --git a/spec/tokenized-buffer-spec.coffee b/spec/tokenized-buffer-spec.coffee index 45cc03a44..9d92335af 100644 --- a/spec/tokenized-buffer-spec.coffee +++ b/spec/tokenized-buffer-spec.coffee @@ -296,6 +296,14 @@ describe "TokenizedBuffer", -> expect(tokenizedBuffer.tokenizedLineForRow(5).ruleStack?).toBeTruthy() expect(tokenizedBuffer.tokenizedLineForRow(6).ruleStack?).toBeTruthy() + describe ".findOpeningBracket(closingBufferPosition)", -> + it "returns the position of the matching bracket, skipping any nested brackets", -> + expect(tokenizedBuffer.findOpeningBracket([9, 2])).toEqual [1, 29] + + describe ".findClosingBracket(startBufferPosition)", -> + it "returns the position of the matching bracket, skipping any nested brackets", -> + expect(tokenizedBuffer.findClosingBracket([1, 29])).toEqual [9, 2] + it "tokenizes leading whitespace based on the new tab length", -> expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[0].isAtomic).toBeTruthy() expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[0].value).toBe " " @@ -572,7 +580,7 @@ describe "TokenizedBuffer", -> describe "when the selector matches a run of multiple tokens at the position", -> it "returns the range covered by all contigous tokens (within a single line)", -> - expect(tokenizedBuffer.bufferRangeForScopeAtPosition('.meta.function', [1, 18])).toEqual [[1, 6], [1, 28]] + expect(tokenizedBuffer.bufferRangeForScopeAtPosition('.function', [1, 18])).toEqual [[1, 6], [1, 28]] describe "when the editor.tabLength config value changes", -> it "updates the tab length of the tokenized lines", -> @@ -689,6 +697,22 @@ describe "TokenizedBuffer", -> expect(line.tokens[0].firstNonWhitespaceIndex).toBe 2 expect(line.tokens[line.tokens.length - 1].firstTrailingWhitespaceIndex).toBe 0 + it "sets the ::firstNonWhitespaceIndex and ::firstTrailingWhitespaceIndex correctly when tokens are split for soft-wrapping", -> + atom.config.set("editor.showInvisibles", true) + atom.config.set("editor.invisibles", space: 'S') + buffer.setText(" token ") + fullyTokenize(tokenizedBuffer) + token = tokenizedBuffer.tokenizedLines[0].tokens[0] + + [leftToken, rightToken] = token.splitAt(1) + expect(leftToken.hasInvisibleCharacters).toBe true + expect(leftToken.firstNonWhitespaceIndex).toBe 1 + expect(leftToken.firstTrailingWhitespaceIndex).toBe null + + expect(leftToken.hasInvisibleCharacters).toBe true + expect(rightToken.firstNonWhitespaceIndex).toBe null + expect(rightToken.firstTrailingWhitespaceIndex).toBe 5 + describe ".indentLevel on tokenized lines", -> beforeEach -> buffer = atom.project.bufferForPathSync('sample.js') @@ -728,7 +752,7 @@ describe "TokenizedBuffer", -> it "updates empty line indent guides when the empty line is the last line", -> buffer.insert([12, 2], '\n') - # The newline and the tab need to be in two different operations to surface the bug + # The newline and he tab need to be in two different operations to surface the bug buffer.insert([12, 0], ' ') expect(tokenizedBuffer.tokenizedLineForRow(13).indentLevel).toBe 1 diff --git a/spec/tokenized-line-spec.coffee b/spec/tokenized-line-spec.coffee index 2914ec089..0da83c91c 100644 --- a/spec/tokenized-line-spec.coffee +++ b/spec/tokenized-line-spec.coffee @@ -17,3 +17,24 @@ describe "TokenizedLine", -> it "returns false when the line is not only whitespace", -> expect(editor.tokenizedLineForScreenRow(0).isOnlyWhitespace()).toBe false expect(editor.tokenizedLineForScreenRow(2).isOnlyWhitespace()).toBe false + + describe "::getScopeTree()", -> + it "returns a tree whose inner nodes are scopeDescriptor and whose leaf nodes are tokens in those scopeDescriptor", -> + [tokens, tokenIndex] = [] + + ensureValidScopeTree = (scopeTree, scopeDescriptor=[]) -> + if scopeTree.children? + for child in scopeTree.children + ensureValidScopeTree(child, scopeDescriptor.concat([scopeTree.scope])) + else + expect(scopeTree).toBe tokens[tokenIndex++] + expect(scopeDescriptor).toEqual scopeTree.scopes + + waitsForPromise -> + atom.project.open('coffee.coffee').then (o) -> editor = o + + runs -> + tokenIndex = 0 + tokens = editor.tokenizedLineForScreenRow(1).tokens + scopeTree = editor.tokenizedLineForScreenRow(1).getScopeTree() + ensureValidScopeTree(scopeTree) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index b2460addc..26bf43dce 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -2,7 +2,6 @@ _ = require 'underscore-plus' Serializable = require 'serializable' {CompositeDisposable, Emitter} = require 'event-kit' {Point, Range} = require 'text-buffer' -Grim = require 'grim' TokenizedBuffer = require './tokenized-buffer' RowMap = require './row-map' Fold = require './fold' @@ -10,6 +9,7 @@ Model = require './model' Token = require './token' Decoration = require './decoration' Marker = require './marker' +Grim = require 'grim' class BufferToScreenConversionError extends Error constructor: (@message, @metadata) -> @@ -659,19 +659,16 @@ class DisplayBuffer extends Model top = targetRow * @lineHeightInPixels left = 0 column = 0 - - iterator = @tokenizedLineForScreenRow(targetRow).getTokenIterator() - while iterator.next() - charWidths = @getScopedCharWidths(iterator.getScopes()) + for token in @tokenizedLineForScreenRow(targetRow).tokens + charWidths = @getScopedCharWidths(token.scopes) valueIndex = 0 - value = iterator.getText() - while valueIndex < value.length - if iterator.isPairedCharacter() - char = value + while valueIndex < token.value.length + if token.hasPairedCharacter + char = token.value.substr(valueIndex, 2) charLength = 2 valueIndex += 2 else - char = value[valueIndex] + char = token.value[valueIndex] charLength = 1 valueIndex++ @@ -692,19 +689,16 @@ class DisplayBuffer extends Model left = 0 column = 0 - - iterator = @tokenizedLineForScreenRow(row).getTokenIterator() - while iterator.next() - charWidths = @getScopedCharWidths(iterator.getScopes()) - value = iterator.getText() + for token in @tokenizedLineForScreenRow(row).tokens + charWidths = @getScopedCharWidths(token.scopes) valueIndex = 0 - while valueIndex < value.length - if iterator.isPairedCharacter() - char = value + while valueIndex < token.value.length + if token.hasPairedCharacter + char = token.value.substr(valueIndex, 2) charLength = 2 valueIndex += 2 else - char = value[valueIndex] + char = token.value[valueIndex] charLength = 1 valueIndex++ diff --git a/src/language-mode.coffee b/src/language-mode.coffee index c9401550b..b5529a05e 100644 --- a/src/language-mode.coffee +++ b/src/language-mode.coffee @@ -242,9 +242,8 @@ class LanguageMode @suggestedIndentForTokenizedLineAtBufferRow(bufferRow, tokenizedLine, options) suggestedIndentForTokenizedLineAtBufferRow: (bufferRow, tokenizedLine, options) -> - iterator = tokenizedLine.getTokenIterator() - iterator.next() - scopeDescriptor = new ScopeDescriptor(scopes: iterator.getScopes()) + scopes = tokenizedLine.tokens[0].scopes + scopeDescriptor = new ScopeDescriptor({scopes}) currentIndentLevel = @editor.indentationForBufferRow(bufferRow) return currentIndentLevel unless increaseIndentRegex = @increaseIndentRegexForScopeDescriptor(scopeDescriptor) diff --git a/src/lines-component.coffee b/src/lines-component.coffee index 17c904e99..fbec40b79 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -4,13 +4,10 @@ _ = require 'underscore-plus' CursorsComponent = require './cursors-component' HighlightsComponent = require './highlights-component' -TokenIterator = require './token-iterator' DummyLineNode = $$(-> @div className: 'line', style: 'position: absolute; visibility: hidden;', => @span 'x')[0] AcceptFilter = {acceptNode: -> NodeFilter.FILTER_ACCEPT} WrapperDiv = document.createElement('div') -TokenTextEscapeRegex = /[&"'<>]/g -MaxTokenLength = 20000 cloneObject = (object) -> clone = {} @@ -22,7 +19,6 @@ class LinesComponent placeholderTextDiv: null constructor: ({@presenter, @hostElement, @useShadowDOM, visible}) -> - @tokenIterator = new TokenIterator @measuredLines = new Set @lineNodesByLineId = {} @screenRowsByLineId = {} @@ -171,116 +167,20 @@ class LinesComponent @buildEndOfLineHTML(id) or ' ' buildLineInnerHTML: (id) -> - lineState = @newState.lines[id] - {firstNonWhitespaceIndex, firstTrailingWhitespaceIndex, invisibles} = lineState - lineIsWhitespaceOnly = firstTrailingWhitespaceIndex is 0 - + {indentGuidesVisible} = @newState + {tokens, text, isOnlyWhitespace} = @newState.lines[id] innerHTML = "" - @tokenIterator.reset(lineState) - while @tokenIterator.next() - for scope in @tokenIterator.getScopeEnds() - innerHTML += "" - - for scope in @tokenIterator.getScopeStarts() - innerHTML += "" - - tokenStart = @tokenIterator.getScreenStart() - tokenEnd = @tokenIterator.getScreenEnd() - tokenText = @tokenIterator.getText() - isHardTab = @tokenIterator.isHardTab() - - if hasLeadingWhitespace = tokenStart < firstNonWhitespaceIndex - tokenFirstNonWhitespaceIndex = firstNonWhitespaceIndex - tokenStart - else - tokenFirstNonWhitespaceIndex = null - - if hasTrailingWhitespace = tokenEnd > firstTrailingWhitespaceIndex - tokenFirstTrailingWhitespaceIndex = Math.max(0, firstTrailingWhitespaceIndex - tokenStart) - else - tokenFirstTrailingWhitespaceIndex = null - - hasIndentGuide = - @newState.indentGuidesVisible and - (hasLeadingWhitespace or lineIsWhitespaceOnly) - - hasInvisibleCharacters = - (invisibles?.tab and isHardTab) or - (invisibles?.space and (hasLeadingWhitespace or hasTrailingWhitespace)) - - innerHTML += @buildTokenHTML(tokenText, isHardTab, tokenFirstNonWhitespaceIndex, tokenFirstTrailingWhitespaceIndex, hasIndentGuide, hasInvisibleCharacters) - - for scope in @tokenIterator.getScopeEnds() - innerHTML += "" - - for scope in @tokenIterator.getScopes() - innerHTML += "" + scopeStack = [] + for token in tokens + innerHTML += @updateScopeStack(scopeStack, token.scopes) + hasIndentGuide = indentGuidesVisible and (token.hasLeadingWhitespace() or (token.hasTrailingWhitespace() and isOnlyWhitespace)) + innerHTML += token.getValueAsHtml({hasIndentGuide}) + innerHTML += @popScope(scopeStack) while scopeStack.length > 0 innerHTML += @buildEndOfLineHTML(id) innerHTML - buildTokenHTML: (tokenText, isHardTab, firstNonWhitespaceIndex, firstTrailingWhitespaceIndex, hasIndentGuide, hasInvisibleCharacters) -> - if isHardTab - classes = 'hard-tab' - classes += ' leading-whitespace' if firstNonWhitespaceIndex? - classes += ' trailing-whitespace' if firstTrailingWhitespaceIndex? - classes += ' indent-guide' if hasIndentGuide - classes += ' invisible-character' if hasInvisibleCharacters - return "#{@escapeTokenText(tokenText)}" - else - startIndex = 0 - endIndex = tokenText.length - - leadingHtml = '' - trailingHtml = '' - - if firstNonWhitespaceIndex? - leadingWhitespace = tokenText.substring(0, firstNonWhitespaceIndex) - - classes = 'leading-whitespace' - classes += ' indent-guide' if hasIndentGuide - classes += ' invisible-character' if hasInvisibleCharacters - - leadingHtml = "#{leadingWhitespace}" - startIndex = firstNonWhitespaceIndex - - if firstTrailingWhitespaceIndex? - tokenIsOnlyWhitespace = firstTrailingWhitespaceIndex is 0 - trailingWhitespace = tokenText.substring(firstTrailingWhitespaceIndex) - - classes = 'trailing-whitespace' - classes += ' indent-guide' if hasIndentGuide and not firstNonWhitespaceIndex? and tokenIsOnlyWhitespace - classes += ' invisible-character' if hasInvisibleCharacters - - trailingHtml = "#{trailingWhitespace}" - - endIndex = firstTrailingWhitespaceIndex - - html = leadingHtml - if tokenText.length > MaxTokenLength - while startIndex < endIndex - html += "" + @escapeTokenText(tokenText, startIndex, startIndex + MaxTokenLength) + "" - startIndex += MaxTokenLength - else - html += @escapeTokenText(tokenText, startIndex, endIndex) - - html += trailingHtml - html - - escapeTokenText: (tokenText, startIndex, endIndex) -> - if startIndex? and endIndex? and startIndex > 0 or endIndex < tokenText.length - tokenText = tokenText.slice(startIndex, endIndex) - tokenText.replace(TokenTextEscapeRegex, @escapeTokenTextReplace) - - escapeTokenTextReplace: (match) -> - switch match - when '&' then '&' - when '"' then '"' - when "'" then ''' - when '<' then '<' - when '>' then '>' - else match - buildEndOfLineHTML: (id) -> {endOfLineInvisibles} = @newState.lines[id] @@ -290,6 +190,31 @@ class LinesComponent html += "#{invisible}" html + updateScopeStack: (scopeStack, desiredScopeDescriptor) -> + html = "" + + # Find a common prefix + for scope, i in desiredScopeDescriptor + break unless scopeStack[i] is desiredScopeDescriptor[i] + + # Pop scopeDescriptor until we're at the common prefx + until scopeStack.length is i + html += @popScope(scopeStack) + + # Push onto common prefix until scopeStack equals desiredScopeDescriptor + for j in [i...desiredScopeDescriptor.length] + html += @pushScope(scopeStack, desiredScopeDescriptor[j]) + + html + + popScope: (scopeStack) -> + scopeStack.pop() + "" + + pushScope: (scopeStack, scope) -> + scopeStack.push(scope) + "" + updateLineNode: (id) -> oldLineState = @oldState.lines[id] newLineState = @newState.lines[id] @@ -354,22 +279,19 @@ class LinesComponent iterator = null charIndex = 0 - @tokenIterator.reset(tokenizedLine) - while @tokenIterator.next() - scopes = @tokenIterator.getScopes() - text = @tokenIterator.getText() + for {value, scopes, hasPairedCharacter} in tokenizedLine.tokens charWidths = @presenter.getScopedCharacterWidths(scopes) - textIndex = 0 - while textIndex < text.length - if @tokenIterator.isPairedCharacter() - char = text + valueIndex = 0 + while valueIndex < value.length + if hasPairedCharacter + char = value.substr(valueIndex, 2) charLength = 2 - textIndex += 2 + valueIndex += 2 else - char = text[textIndex] + char = value[valueIndex] charLength = 1 - textIndex++ + valueIndex++ continue if char is '\0' diff --git a/src/special-token-symbols.coffee b/src/special-token-symbols.coffee deleted file mode 100644 index 06884b85f..000000000 --- a/src/special-token-symbols.coffee +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - SoftTab: Symbol('SoftTab') - HardTab: Symbol('HardTab') - PairedCharacter: Symbol('PairedCharacter') - SoftWrapIndent: Symbol('SoftWrapIndent') -} diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 3aea57f29..70c26a1a3 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -336,14 +336,9 @@ class TextEditorPresenter @state.content.lines[line.id] = screenRow: row text: line.text - openScopes: line.openScopes - tags: line.tags - specialTokens: line.specialTokens - firstNonWhitespaceIndex: line.firstNonWhitespaceIndex - firstTrailingWhitespaceIndex: line.firstTrailingWhitespaceIndex - invisibles: line.invisibles - endOfLineInvisibles: line.endOfLineInvisibles + tokens: line.tokens isOnlyWhitespace: line.isOnlyWhitespace() + endOfLineInvisibles: line.endOfLineInvisibles indentLevel: line.indentLevel tabLength: line.tabLength fold: line.fold @@ -1011,20 +1006,17 @@ class TextEditorPresenter top = targetRow * @lineHeight left = 0 column = 0 - - iterator = @model.tokenizedLineForScreenRow(targetRow).getTokenIterator() - while iterator.next() - characterWidths = @getScopedCharacterWidths(iterator.getScopes()) + for token in @model.tokenizedLineForScreenRow(targetRow).tokens + characterWidths = @getScopedCharacterWidths(token.scopes) valueIndex = 0 - text = iterator.getText() - while valueIndex < text.length - if iterator.isPairedCharacter() - char = text + while valueIndex < token.value.length + if token.hasPairedCharacter + char = token.value.substr(valueIndex, 2) charLength = 2 valueIndex += 2 else - char = text[valueIndex] + char = token.value[valueIndex] charLength = 1 valueIndex++ diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 4489d82af..d2bd77522 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -2457,8 +2457,9 @@ class TextEditor extends Model # Extended: Determine if the given row is entirely a comment isBufferRowCommented: (bufferRow) -> if match = @lineTextForBufferRow(bufferRow).match(/\S/) + scopeDescriptor = @tokenForBufferPosition([bufferRow, match.index]).scopes @commentScopeSelector ?= new TextMateScopeSelector('comment.*') - @commentScopeSelector.matches(@scopeDescriptorForBufferPosition([bufferRow, match.index]).scopes) + @commentScopeSelector.matches(scopeDescriptor) logCursorScope: -> scopeDescriptor = @getLastCursor().getScopeDescriptor() diff --git a/src/token-iterator.coffee b/src/token-iterator.coffee deleted file mode 100644 index 202b044ba..000000000 --- a/src/token-iterator.coffee +++ /dev/null @@ -1,83 +0,0 @@ -{SoftTab, HardTab, PairedCharacter, SoftWrapIndent} = require './special-token-symbols' - -module.exports = -class TokenIterator - constructor: (line) -> - @reset(line) if line? - - reset: (@line) -> - @index = null - @bufferStart = @line.startBufferColumn - @bufferEnd = @bufferStart - @screenStart = 0 - @screenEnd = 0 - @scopes = @line.openScopes.map (id) -> atom.grammars.scopeForId(id) - @scopeStarts = @scopes.slice() - @scopeEnds = [] - this - - next: -> - {tags} = @line - - if @index? - @index++ - @scopeEnds.length = 0 - @scopeStarts.length = 0 - @bufferStart = @bufferEnd - @screenStart = @screenEnd - else - @index = 0 - - while @index < tags.length - tag = tags[@index] - if tag < 0 - if tag % 2 is 0 - @scopeEnds.push(atom.grammars.scopeForId(tag + 1)) - @scopes.pop() - else - scope = atom.grammars.scopeForId(tag) - @scopeStarts.push(scope) - @scopes.push(scope) - @index++ - else - if @isHardTab() - @screenEnd = @screenStart + tag - @bufferEnd = @bufferStart + 1 - else if @isSoftWrapIndentation() - @screenEnd = @screenStart + tag - @bufferEnd = @bufferStart + 0 - else - @screenEnd = @screenStart + tag - @bufferEnd = @bufferStart + tag - return true - - false - - getBufferStart: -> @bufferStart - getBufferEnd: -> @bufferEnd - - getScreenStart: -> @screenStart - getScreenEnd: -> @screenEnd - - getScopeStarts: -> @scopeStarts - getScopeEnds: -> @scopeEnds - - getScopes: -> @scopes - - getText: -> - @line.text.substring(@screenStart, @screenEnd) - - isSoftTab: -> - @line.specialTokens[@index] is SoftTab - - isHardTab: -> - @line.specialTokens[@index] is HardTab - - isSoftWrapIndentation: -> - @line.specialTokens[@index] is SoftWrapIndent - - isPairedCharacter: -> - @line.specialTokens[@index] is PairedCharacter - - isAtomic: -> - @isSoftTab() or @isHardTab() or @isSoftWrapIndentation() or @isPairedCharacter() diff --git a/src/token.coffee b/src/token.coffee index 60e8194f8..8aa4a8706 100644 --- a/src/token.coffee +++ b/src/token.coffee @@ -1,8 +1,13 @@ _ = require 'underscore-plus' +textUtils = require './text-utils' +WhitespaceRegexesByTabLength = {} +EscapeRegex = /[&"'<>]/g StartDotRegex = /^\.?/ WhitespaceRegex = /\S/ +MaxTokenLength = 20000 + # Represents a single unit of text as selected by a grammar. module.exports = class Token @@ -15,14 +20,10 @@ class Token firstTrailingWhitespaceIndex: null hasInvisibleCharacters: false - constructor: (properties) -> - {@value, @scopes, @isAtomic, @isHardTab, @bufferDelta} = properties - {@hasInvisibleCharacters, @hasPairedCharacter, @isSoftWrapIndentation} = properties - @firstNonWhitespaceIndex = properties.firstNonWhitespaceIndex ? null - @firstTrailingWhitespaceIndex = properties.firstTrailingWhitespaceIndex ? null - + constructor: ({@value, @scopes, @isAtomic, @bufferDelta, @isHardTab, @hasPairedCharacter, @isSoftWrapIndentation}) -> @screenDelta = @value.length @bufferDelta ?= @screenDelta + @hasPairedCharacter ?= textUtils.hasPairedCharacter(@value) isEqual: (other) -> # TODO: scopes is deprecated. This is here for the sake of lang package tests @@ -31,6 +32,126 @@ class Token isBracket: -> /^meta\.brace\b/.test(_.last(@scopes)) + splitAt: (splitIndex) -> + leftToken = new Token(value: @value.substring(0, splitIndex), scopes: @scopes) + rightToken = new Token(value: @value.substring(splitIndex), scopes: @scopes) + + if @firstNonWhitespaceIndex? + leftToken.firstNonWhitespaceIndex = Math.min(splitIndex, @firstNonWhitespaceIndex) + leftToken.hasInvisibleCharacters = @hasInvisibleCharacters + + if @firstNonWhitespaceIndex > splitIndex + rightToken.firstNonWhitespaceIndex = @firstNonWhitespaceIndex - splitIndex + rightToken.hasInvisibleCharacters = @hasInvisibleCharacters + + if @firstTrailingWhitespaceIndex? + rightToken.firstTrailingWhitespaceIndex = Math.max(0, @firstTrailingWhitespaceIndex - splitIndex) + rightToken.hasInvisibleCharacters = @hasInvisibleCharacters + + if @firstTrailingWhitespaceIndex < splitIndex + leftToken.firstTrailingWhitespaceIndex = @firstTrailingWhitespaceIndex + leftToken.hasInvisibleCharacters = @hasInvisibleCharacters + + [leftToken, rightToken] + + whitespaceRegexForTabLength: (tabLength) -> + WhitespaceRegexesByTabLength[tabLength] ?= new RegExp("([ ]{#{tabLength}})|(\t)|([^\t]+)", "g") + + breakOutAtomicTokens: (tabLength, breakOutLeadingSoftTabs, startColumn) -> + if @hasPairedCharacter + outputTokens = [] + column = startColumn + + for token in @breakOutPairedCharacters() + if token.isAtomic + outputTokens.push(token) + else + outputTokens.push(token.breakOutAtomicTokens(tabLength, breakOutLeadingSoftTabs, column)...) + breakOutLeadingSoftTabs = token.isOnlyWhitespace() if breakOutLeadingSoftTabs + column += token.value.length + + outputTokens + else + return [this] if @isAtomic + + if breakOutLeadingSoftTabs + return [this] unless /^[ ]|\t/.test(@value) + else + return [this] unless /\t/.test(@value) + + outputTokens = [] + regex = @whitespaceRegexForTabLength(tabLength) + column = startColumn + while match = regex.exec(@value) + [fullMatch, softTab, hardTab] = match + token = null + if softTab and breakOutLeadingSoftTabs + token = @buildSoftTabToken(tabLength) + else if hardTab + breakOutLeadingSoftTabs = false + token = @buildHardTabToken(tabLength, column) + else + breakOutLeadingSoftTabs = false + value = match[0] + token = new Token({value, @scopes}) + column += token.value.length + outputTokens.push(token) + + outputTokens + + breakOutPairedCharacters: -> + outputTokens = [] + index = 0 + nonPairStart = 0 + + while index < @value.length + if textUtils.isPairedCharacter(@value, index) + if nonPairStart isnt index + outputTokens.push(new Token({value: @value[nonPairStart...index], @scopes})) + outputTokens.push(@buildPairedCharacterToken(@value, index)) + index += 2 + nonPairStart = index + else + index++ + + if nonPairStart isnt index + outputTokens.push(new Token({value: @value[nonPairStart...index], @scopes})) + + outputTokens + + buildPairedCharacterToken: (value, index) -> + new Token( + value: value[index..index + 1] + scopes: @scopes + isAtomic: true + hasPairedCharacter: true + ) + + buildHardTabToken: (tabLength, column) -> + @buildTabToken(tabLength, true, column) + + buildSoftTabToken: (tabLength) -> + @buildTabToken(tabLength, false, 0) + + buildTabToken: (tabLength, isHardTab, column=0) -> + tabStop = tabLength - (column % tabLength) + new Token( + value: _.multiplyString(" ", tabStop) + scopes: @scopes + bufferDelta: if isHardTab then 1 else tabStop + isAtomic: true + isHardTab: isHardTab + ) + + buildSoftWrapIndentationToken: (length) -> + new Token( + value: _.multiplyString(" ", length), + scopes: @scopes, + bufferDelta: 0, + isAtomic: true, + isSoftWrapIndentation: true + ) + isOnlyWhitespace: -> not WhitespaceRegex.test(@value) @@ -40,6 +161,72 @@ class Token scopeClasses = scope.split('.') _.isSubset(targetClasses, scopeClasses) + getValueAsHtml: ({hasIndentGuide}) -> + if @isHardTab + classes = 'hard-tab' + classes += ' leading-whitespace' if @hasLeadingWhitespace() + classes += ' trailing-whitespace' if @hasTrailingWhitespace() + classes += ' indent-guide' if hasIndentGuide + classes += ' invisible-character' if @hasInvisibleCharacters + html = "#{@escapeString(@value)}" + else + startIndex = 0 + endIndex = @value.length + + leadingHtml = '' + trailingHtml = '' + + if @hasLeadingWhitespace() + leadingWhitespace = @value.substring(0, @firstNonWhitespaceIndex) + + classes = 'leading-whitespace' + classes += ' indent-guide' if hasIndentGuide + classes += ' invisible-character' if @hasInvisibleCharacters + + leadingHtml = "#{leadingWhitespace}" + startIndex = @firstNonWhitespaceIndex + + if @hasTrailingWhitespace() + tokenIsOnlyWhitespace = @firstTrailingWhitespaceIndex is 0 + trailingWhitespace = @value.substring(@firstTrailingWhitespaceIndex) + + classes = 'trailing-whitespace' + classes += ' indent-guide' if hasIndentGuide and not @hasLeadingWhitespace() and tokenIsOnlyWhitespace + classes += ' invisible-character' if @hasInvisibleCharacters + + trailingHtml = "#{trailingWhitespace}" + + endIndex = @firstTrailingWhitespaceIndex + + html = leadingHtml + if @value.length > MaxTokenLength + while startIndex < endIndex + html += "" + @escapeString(@value, startIndex, startIndex + MaxTokenLength) + "" + startIndex += MaxTokenLength + else + html += @escapeString(@value, startIndex, endIndex) + + html += trailingHtml + html + + escapeString: (str, startIndex, endIndex) -> + strLength = str.length + + startIndex ?= 0 + endIndex ?= strLength + + str = str.slice(startIndex, endIndex) if startIndex > 0 or endIndex < strLength + str.replace(EscapeRegex, @escapeStringReplace) + + escapeStringReplace: (match) -> + switch match + when '&' then '&' + when '"' then '"' + when "'" then ''' + when '<' then '<' + when '>' then '>' + else match + hasLeadingWhitespace: -> @firstNonWhitespaceIndex? and @firstNonWhitespaceIndex > 0 diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 60ebe16f0..6d8f0c018 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -1,11 +1,9 @@ _ = require 'underscore-plus' {CompositeDisposable, Emitter} = require 'event-kit' {Point, Range} = require 'text-buffer' -{ScopeSelector} = require 'first-mate' Serializable = require 'serializable' Model = require './model' TokenizedLine = require './tokenized-line' -TokenIterator = require './token-iterator' Token = require './token' ScopeDescriptor = require './scope-descriptor' Grim = require 'grim' @@ -27,7 +25,6 @@ class TokenizedBuffer extends Model constructor: ({@buffer, @tabLength, @ignoreInvisibles}) -> @emitter = new Emitter @disposables = new CompositeDisposable - @tokenIterator = new TokenIterator @disposables.add atom.grammars.onDidAddGrammar(@grammarAddedOrUpdated) @disposables.add atom.grammars.onDidUpdateGrammar(@grammarAddedOrUpdated) @@ -170,7 +167,7 @@ class TokenizedBuffer extends Model row = startRow loop previousStack = @stackForRow(row) - @tokenizedLines[row] = @buildTokenizedLineForRow(row, @stackForRow(row - 1), @openScopesForRow(row)) + @tokenizedLines[row] = @buildTokenizedLineForRow(row, @stackForRow(row - 1)) if --rowsRemaining is 0 filledRegion = false endRow = row @@ -230,7 +227,7 @@ class TokenizedBuffer extends Model @updateInvalidRows(start, end, delta) previousEndStack = @stackForRow(end) # used in spill detection below - newTokenizedLines = @buildTokenizedLinesForRows(start, end + delta, @stackForRow(start - 1), @openScopesForRow(start)) + newTokenizedLines = @buildTokenizedLinesForRows(start, end + delta, @stackForRow(start - 1)) _.spliceWithArray(@tokenizedLines, start, end - start + 1, newTokenizedLines) start = @retokenizeWhitespaceRowsIfIndentLevelChanged(start - 1, -1) @@ -251,7 +248,7 @@ class TokenizedBuffer extends Model line = @tokenizedLines[row] if line?.isOnlyWhitespace() and @indentLevelForRow(row) isnt line.indentLevel while line?.isOnlyWhitespace() - @tokenizedLines[row] = @buildTokenizedLineForRow(row, @stackForRow(row - 1), @openScopesForRow(row)) + @tokenizedLines[row] = @buildTokenizedLineForRow(row, @stackForRow(row - 1)) row += increment line = @tokenizedLines[row] @@ -293,18 +290,16 @@ class TokenizedBuffer extends Model @tokenizedLineForRow(row).isComment() and @tokenizedLineForRow(nextRow).isComment() - buildTokenizedLinesForRows: (startRow, endRow, startingStack, startingopenScopes) -> + buildTokenizedLinesForRows: (startRow, endRow, startingStack) -> ruleStack = startingStack - openScopes = startingopenScopes stopTokenizingAt = startRow + @chunkSize tokenizedLines = for row in [startRow..endRow] if (ruleStack or row is 0) and row < stopTokenizingAt - tokenizedLine = @buildTokenizedLineForRow(row, ruleStack, openScopes) - ruleStack = tokenizedLine.ruleStack - openScopes = @scopesFromTags(openScopes, tokenizedLine.tags) + screenLine = @buildTokenizedLineForRow(row, ruleStack) + ruleStack = screenLine.ruleStack else - tokenizedLine = @buildPlaceholderTokenizedLineForRow(row, openScopes) - tokenizedLine + screenLine = @buildPlaceholderTokenizedLineForRow(row) + screenLine if endRow >= stopTokenizingAt @invalidateRow(stopTokenizingAt) @@ -316,23 +311,22 @@ class TokenizedBuffer extends Model @buildPlaceholderTokenizedLineForRow(row) for row in [startRow..endRow] buildPlaceholderTokenizedLineForRow: (row) -> - openScopes = [@grammar.startIdForScope(@grammar.scopeName)] - text = @buffer.lineForRow(row) - tags = [text.length] + line = @buffer.lineForRow(row) + tokens = [new Token(value: line, scopes: [@grammar.scopeName])] tabLength = @getTabLength() indentLevel = @indentLevelForRow(row) lineEnding = @buffer.lineEndingForRow(row) - new TokenizedLine({openScopes, text, tags, tabLength, indentLevel, invisibles: @getInvisiblesToShow(), lineEnding, @tokenIterator}) + new TokenizedLine({tokens, tabLength, indentLevel, invisibles: @getInvisiblesToShow(), lineEnding}) - buildTokenizedLineForRow: (row, ruleStack, openScopes) -> - @buildTokenizedLineForRowWithText(row, @buffer.lineForRow(row), ruleStack, openScopes) + buildTokenizedLineForRow: (row, ruleStack) -> + @buildTokenizedLineForRowWithText(row, @buffer.lineForRow(row), ruleStack) - buildTokenizedLineForRowWithText: (row, text, ruleStack = @stackForRow(row - 1), openScopes = @openScopesForRow(row)) -> + buildTokenizedLineForRowWithText: (row, line, ruleStack = @stackForRow(row - 1)) -> lineEnding = @buffer.lineEndingForRow(row) tabLength = @getTabLength() indentLevel = @indentLevelForRow(row) - {tags, ruleStack} = @grammar.tokenizeLine(text, ruleStack, row is 0, false) - new TokenizedLine({openScopes, text, tags, ruleStack, tabLength, lineEnding, indentLevel, invisibles: @getInvisiblesToShow(), @tokenIterator}) + {tokens, ruleStack} = @grammar.tokenizeLine(line, ruleStack, row is 0) + new TokenizedLine({tokens, ruleStack, tabLength, lineEnding, indentLevel, invisibles: @getInvisiblesToShow()}) getInvisiblesToShow: -> if @configSettings.showInvisibles and not @ignoreInvisibles @@ -346,25 +340,6 @@ class TokenizedBuffer extends Model stackForRow: (bufferRow) -> @tokenizedLines[bufferRow]?.ruleStack - openScopesForRow: (bufferRow) -> - if bufferRow > 0 - precedingLine = @tokenizedLines[bufferRow - 1] - @scopesFromTags(precedingLine.openScopes, precedingLine.tags) - else - [] - - scopesFromTags: (startingScopes, tags) -> - scopes = startingScopes.slice() - for tag in tags when tag < 0 - if (tag % 2) is -1 - scopes.push(tag) - else - expectedScope = tag + 1 - poppedScope = scopes.pop() - unless poppedScope is expectedScope - throw new Error("Encountered an invalid scope end id. Popped #{poppedScope}, expected to pop #{expectedScope}.") - scopes - indentLevelForRow: (bufferRow) -> line = @buffer.lineForRow(bufferRow) indentLevel = 0 @@ -401,20 +376,7 @@ class TokenizedBuffer extends Model 0 scopeDescriptorForPosition: (position) -> - {row, column} = Point.fromObject(position) - - iterator = @tokenizedLines[row].getTokenIterator() - while iterator.next() - if iterator.getScreenEnd() > column - scopes = iterator.getScopes() - break - - # rebuild scope of last token if we iterated off the end - unless scopes? - scopes = iterator.getScopes() - scopes.push(iterator.getScopeEnds().reverse()...) - - new ScopeDescriptor({scopes}) + new ScopeDescriptor(scopes: @tokenForPosition(position).scopes) tokenForPosition: (position) -> {row, column} = Point.fromObject(position) @@ -426,53 +388,85 @@ class TokenizedBuffer extends Model new Point(row, column) bufferRangeForScopeAtPosition: (selector, position) -> - selector = new ScopeSelector(selector.replace(/^\./, '')) position = Point.fromObject(position) + tokenizedLine = @tokenizedLines[position.row] + startIndex = tokenizedLine.tokenIndexAtBufferColumn(position.column) - {openScopes, tags} = @tokenizedLines[position.row] - scopes = openScopes.map (tag) -> atom.grammars.scopeForId(tag) + for index in [startIndex..0] + token = tokenizedLine.tokenAtIndex(index) + break unless token.matchesScopeSelector(selector) + firstToken = token - startColumn = 0 - for tag, tokenIndex in tags - if tag < 0 - if tag % 2 is -1 - scopes.push(atom.grammars.scopeForId(tag)) - else - scopes.pop() - else - endColumn = startColumn + tag - if endColumn > position.column - break - else - startColumn = endColumn + for index in [startIndex...tokenizedLine.getTokenCount()] + token = tokenizedLine.tokenAtIndex(index) + break unless token.matchesScopeSelector(selector) + lastToken = token - return unless selector.matches(scopes) + return unless firstToken? and lastToken? - startScopes = scopes.slice() - for startTokenIndex in [(tokenIndex - 1)..0] by -1 - tag = tags[startTokenIndex] - if tag < 0 - if tag % 2 is -1 - startScopes.pop() - else - startScopes.push(atom.grammars.scopeForId(tag)) - else - break unless selector.matches(startScopes) - startColumn -= tag + startColumn = tokenizedLine.bufferColumnForToken(firstToken) + endColumn = tokenizedLine.bufferColumnForToken(lastToken) + lastToken.bufferDelta + new Range([position.row, startColumn], [position.row, endColumn]) - endScopes = scopes.slice() - for endTokenIndex in [(tokenIndex + 1)...tags.length] by 1 - tag = tags[endTokenIndex] - if tag < 0 - if tag % 2 is -1 - endScopes.push(atom.grammars.scopeForId(tag)) - else - endScopes.pop() - else - break unless selector.matches(endScopes) - endColumn += tag + iterateTokensInBufferRange: (bufferRange, iterator) -> + bufferRange = Range.fromObject(bufferRange) + {start, end} = bufferRange - new Range(new Point(position.row, startColumn), new Point(position.row, endColumn)) + keepLooping = true + stop = -> keepLooping = false + + for bufferRow in [start.row..end.row] + bufferColumn = 0 + for token in @tokenizedLines[bufferRow].tokens + startOfToken = new Point(bufferRow, bufferColumn) + iterator(token, startOfToken, {stop}) if bufferRange.containsPoint(startOfToken) + return unless keepLooping + bufferColumn += token.bufferDelta + + backwardsIterateTokensInBufferRange: (bufferRange, iterator) -> + bufferRange = Range.fromObject(bufferRange) + {start, end} = bufferRange + + keepLooping = true + stop = -> keepLooping = false + + for bufferRow in [end.row..start.row] + bufferColumn = @buffer.lineLengthForRow(bufferRow) + for token in new Array(@tokenizedLines[bufferRow].tokens...).reverse() + bufferColumn -= token.bufferDelta + startOfToken = new Point(bufferRow, bufferColumn) + iterator(token, startOfToken, {stop}) if bufferRange.containsPoint(startOfToken) + return unless keepLooping + + findOpeningBracket: (startBufferPosition) -> + range = [[0,0], startBufferPosition] + position = null + depth = 0 + @backwardsIterateTokensInBufferRange range, (token, startPosition, {stop}) -> + if token.isBracket() + if token.value is '}' + depth++ + else if token.value is '{' + depth-- + if depth is 0 + position = startPosition + stop() + position + + findClosingBracket: (startBufferPosition) -> + range = [startBufferPosition, @buffer.getEndPosition()] + position = null + depth = 0 + @iterateTokensInBufferRange range, (token, startPosition, {stop}) -> + if token.isBracket() + if token.value is '{' + depth++ + else if token.value is '}' + depth-- + if depth is 0 + position = startPosition + stop() + position # Gets the row number of the last line. # diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 45af81e57..b81d972a0 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -1,13 +1,10 @@ _ = require 'underscore-plus' {isPairedCharacter} = require './text-utils' -Token = require './token' -{SoftTab, HardTab, PairedCharacter, SoftWrapIndent} = require './special-token-symbols' NonWhitespaceRegex = /\S/ LeadingWhitespaceRegex = /^\s*/ TrailingWhitespaceRegex = /\s*$/ RepeatedSpaceRegex = /[ ]/g -CommentScopeRegex = /(\b|\.)comment/ idCounter = 1 module.exports = @@ -17,181 +14,32 @@ class TokenizedLine firstNonWhitespaceIndex: 0 foldable: false - constructor: (properties) -> - @id = idCounter++ - - return unless properties? - - @specialTokens = {} - {@openScopes, @text, @tags, @lineEnding, @ruleStack, @tokenIterator} = properties - {@startBufferColumn, @fold, @tabLength, @indentLevel, @invisibles} = properties - + constructor: ({tokens, @lineEnding, @ruleStack, @startBufferColumn, @fold, @tabLength, @indentLevel, @invisibles}) -> @startBufferColumn ?= 0 - @bufferDelta = @text.length + @tokens = @breakOutAtomicTokens(tokens) + @text = @buildText() + @bufferDelta = @buildBufferDelta() + @softWrapIndentationTokens = @getSoftWrapIndentationTokens() + @softWrapIndentationDelta = @buildSoftWrapIndentationDelta() - @transformContent() - @buildEndOfLineInvisibles() if @invisibles? and @lineEnding? + @id = idCounter++ + @markLeadingAndTrailingWhitespaceTokens() + if @invisibles + @substituteInvisibleCharacters() + @buildEndOfLineInvisibles() if @lineEnding? - transformContent: -> - text = '' - bufferColumn = 0 - screenColumn = 0 - tokenIndex = 0 - tokenOffset = 0 - firstNonWhitespaceColumn = null - lastNonWhitespaceColumn = null + buildText: -> + text = "" + text += token.value for token in @tokens + text - while bufferColumn < @text.length - # advance to next token if we've iterated over its length - if tokenOffset is @tags[tokenIndex] - tokenIndex++ - tokenOffset = 0 - - # advance to next token tag - tokenIndex++ while @tags[tokenIndex] < 0 - - character = @text[bufferColumn] - - # split out unicode surrogate pairs - if isPairedCharacter(@text, bufferColumn) - prefix = tokenOffset - suffix = @tags[tokenIndex] - tokenOffset - 2 - splitTokens = [] - splitTokens.push(prefix) if prefix > 0 - splitTokens.push(2) - splitTokens.push(suffix) if suffix > 0 - - @tags.splice(tokenIndex, 1, splitTokens...) - - firstNonWhitespaceColumn ?= screenColumn - lastNonWhitespaceColumn = screenColumn + 1 - - text += @text.substr(bufferColumn, 2) - screenColumn += 2 - bufferColumn += 2 - - tokenIndex++ if prefix > 0 - @specialTokens[tokenIndex] = PairedCharacter - tokenIndex++ - tokenOffset = 0 - - # split out leading soft tabs - else if character is ' ' - if firstNonWhitespaceColumn? - text += ' ' - else - if (screenColumn + 1) % @tabLength is 0 - @specialTokens[tokenIndex] = SoftTab - suffix = @tags[tokenIndex] - @tabLength - @tags.splice(tokenIndex, 1, @tabLength) - @tags.splice(tokenIndex + 1, 0, suffix) if suffix > 0 - text += @invisibles?.space ? ' ' - - screenColumn++ - bufferColumn++ - tokenOffset++ - - # expand hard tabs to the next tab stop - else if character is '\t' - tabLength = @tabLength - (screenColumn % @tabLength) - if @invisibles?.tab - text += @invisibles.tab - else - text += ' ' - text += ' ' for i in [1...tabLength] by 1 - - prefix = tokenOffset - suffix = @tags[tokenIndex] - tokenOffset - 1 - splitTokens = [] - splitTokens.push(prefix) if prefix > 0 - splitTokens.push(tabLength) - splitTokens.push(suffix) if suffix > 0 - - @tags.splice(tokenIndex, 1, splitTokens...) - - screenColumn += tabLength - bufferColumn++ - - tokenIndex++ if prefix > 0 - @specialTokens[tokenIndex] = HardTab - tokenIndex++ - tokenOffset = 0 - - # continue past any other character - else - firstNonWhitespaceColumn ?= screenColumn - lastNonWhitespaceColumn = screenColumn - - text += character - screenColumn++ - bufferColumn++ - tokenOffset++ - - @text = text - - @firstNonWhitespaceIndex = firstNonWhitespaceColumn - if lastNonWhitespaceColumn? - if lastNonWhitespaceColumn + 1 < @text.length - @firstTrailingWhitespaceIndex = lastNonWhitespaceColumn + 1 - if @invisibles?.space - @text = - @text.substring(0, @firstTrailingWhitespaceIndex) + - @text.substring(@firstTrailingWhitespaceIndex) - .replace(RepeatedSpaceRegex, @invisibles.space) - else - @lineIsWhitespaceOnly = true - @firstTrailingWhitespaceIndex = 0 - - getTokenIterator: -> @tokenIterator.reset(this) - - Object.defineProperty @prototype, 'tokens', get: -> - iterator = @getTokenIterator() - tokens = [] - - while iterator.next() - properties = { - value: iterator.getText() - scopes: iterator.getScopes().slice() - isAtomic: iterator.isAtomic() - isHardTab: iterator.isHardTab() - hasPairedCharacter: iterator.isPairedCharacter() - isSoftWrapIndentation: iterator.isSoftWrapIndentation() - } - - if iterator.isHardTab() - properties.bufferDelta = 1 - properties.hasInvisibleCharacters = true if @invisibles?.tab - - if iterator.getScreenStart() < @firstNonWhitespaceIndex - properties.firstNonWhitespaceIndex = - Math.min(@firstNonWhitespaceIndex, iterator.getScreenEnd()) - iterator.getScreenStart() - properties.hasInvisibleCharacters = true if @invisibles?.space - - if @lineEnding? and iterator.getScreenEnd() > @firstTrailingWhitespaceIndex - properties.firstTrailingWhitespaceIndex = - Math.max(0, @firstTrailingWhitespaceIndex - iterator.getScreenStart()) - properties.hasInvisibleCharacters = true if @invisibles?.space - - tokens.push(new Token(properties)) - - tokens + buildBufferDelta: -> + delta = 0 + delta += token.bufferDelta for token in @tokens + delta copy: -> - copy = new TokenizedLine - copy.tokenIterator = @tokenIterator - copy.indentLevel = @indentLevel - copy.openScopes = @openScopes - copy.text = @text - copy.tags = @tags - copy.specialTokens = @specialTokens - copy.firstNonWhitespaceIndex = @firstNonWhitespaceIndex - copy.firstTrailingWhitespaceIndex = @firstTrailingWhitespaceIndex - copy.lineEnding = @lineEnding - copy.endOfLineInvisibles = @endOfLineInvisibles - copy.ruleStack = @ruleStack - copy.startBufferColumn = @startBufferColumn - copy.fold = @fold - copy + new TokenizedLine({@tokens, @lineEnding, @ruleStack, @startBufferColumn, @fold}) # This clips a given screen column to a valid column that's within the line # and not in the middle of any atomic tokens. @@ -204,58 +52,49 @@ class TokenizedLine # # Returns a {Number} representing the clipped column. clipScreenColumn: (column, options={}) -> - return 0 if @tags.length is 0 + return 0 if @tokens.length is 0 {clip} = options column = Math.min(column, @getMaxScreenColumn()) tokenStartColumn = 0 + for token in @tokens + break if tokenStartColumn + token.screenDelta > column + tokenStartColumn += token.screenDelta - iterator = @getTokenIterator() - while iterator.next() - break if iterator.getScreenEnd() > column - - if iterator.isSoftWrapIndentation() - iterator.next() while iterator.isSoftWrapIndentation() - iterator.getScreenStart() - else if iterator.isAtomic() and iterator.getScreenStart() < column + if @isColumnInsideSoftWrapIndentation(tokenStartColumn) + @softWrapIndentationDelta + else if token.isAtomic and tokenStartColumn < column if clip is 'forward' - iterator.getScreenEnd() + tokenStartColumn + token.screenDelta else if clip is 'backward' - iterator.getScreenStart() + tokenStartColumn else #'closest' - if column > ((iterator.getScreenStart() + iterator.getScreenEnd()) / 2) - iterator.getScreenEnd() + if column > tokenStartColumn + (token.screenDelta / 2) + tokenStartColumn + token.screenDelta else - iterator.getScreenStart() + tokenStartColumn else column - screenColumnForBufferColumn: (targetBufferColumn, options) -> - iterator = @getTokenIterator() - while iterator.next() - tokenBufferStart = iterator.getBufferStart() - tokenBufferEnd = iterator.getBufferEnd() - if tokenBufferStart <= targetBufferColumn < tokenBufferEnd - overshoot = targetBufferColumn - tokenBufferStart - return Math.min( - iterator.getScreenStart() + overshoot, - iterator.getScreenEnd() - ) - iterator.getScreenEnd() + screenColumnForBufferColumn: (bufferColumn, options) -> + bufferColumn = bufferColumn - @startBufferColumn + screenColumn = 0 + currentBufferColumn = 0 + for token in @tokens + break if currentBufferColumn + token.bufferDelta > bufferColumn + screenColumn += token.screenDelta + currentBufferColumn += token.bufferDelta + @clipScreenColumn(screenColumn + (bufferColumn - currentBufferColumn)) - bufferColumnForScreenColumn: (targetScreenColumn) -> - iterator = @getTokenIterator() - while iterator.next() - tokenScreenStart = iterator.getScreenStart() - tokenScreenEnd = iterator.getScreenEnd() - if tokenScreenStart <= targetScreenColumn < tokenScreenEnd - overshoot = targetScreenColumn - tokenScreenStart - return Math.min( - iterator.getBufferStart() + overshoot, - iterator.getBufferEnd() - ) - iterator.getBufferEnd() + bufferColumnForScreenColumn: (screenColumn, options) -> + bufferColumn = @startBufferColumn + currentScreenColumn = 0 + for token in @tokens + break if currentScreenColumn + token.screenDelta > screenColumn + bufferColumn += token.bufferDelta + currentScreenColumn += token.screenDelta + bufferColumn + (screenColumn - currentScreenColumn) getMaxScreenColumn: -> if @fold @@ -289,128 +128,69 @@ class TokenizedLine return maxColumn + buildSoftWrapIndentationTokens: (token, hangingIndent) -> + totalIndentSpaces = (@indentLevel * @tabLength) + hangingIndent + indentTokens = [] + while totalIndentSpaces > 0 + tokenLength = Math.min(@tabLength, totalIndentSpaces) + indentToken = token.buildSoftWrapIndentationToken(tokenLength) + indentTokens.push(indentToken) + totalIndentSpaces -= tokenLength + + indentTokens + softWrapAt: (column, hangingIndent) -> - return [null, this] if column is 0 + return [new TokenizedLine([], '', [0, 0], [0, 0]), this] if column is 0 - leftText = @text.substring(0, column) - rightText = @text.substring(column) + rightTokens = new Array(@tokens...) + leftTokens = [] + leftScreenColumn = 0 - leftTags = [] - rightTags = [] + while leftScreenColumn < column + if leftScreenColumn + rightTokens[0].screenDelta > column + rightTokens[0..0] = rightTokens[0].splitAt(column - leftScreenColumn) + nextToken = rightTokens.shift() + leftScreenColumn += nextToken.screenDelta + leftTokens.push nextToken - leftSpecialTokens = {} - rightSpecialTokens = {} - - rightOpenScopes = @openScopes.slice() - - screenColumn = 0 - - for tag, index in @tags - # tag represents a token - if tag >= 0 - # token ends before the soft wrap column - if screenColumn + tag <= column - if specialToken = @specialTokens[index] - leftSpecialTokens[index] = specialToken - leftTags.push(tag) - screenColumn += tag - - # token starts before and ends after the split column - else if screenColumn <= column - leftSuffix = column - screenColumn - rightPrefix = screenColumn + tag - column - - leftTags.push(leftSuffix) if leftSuffix > 0 - - softWrapIndent = @indentLevel * @tabLength + (hangingIndent ? 0) - for i in [0...softWrapIndent] by 1 - rightText = ' ' + rightText - remainingSoftWrapIndent = softWrapIndent - while remainingSoftWrapIndent > 0 - indentToken = Math.min(remainingSoftWrapIndent, @tabLength) - rightSpecialTokens[rightTags.length] = SoftWrapIndent - rightTags.push(indentToken) - remainingSoftWrapIndent -= indentToken - - rightTags.push(rightPrefix) if rightPrefix > 0 - - screenColumn += tag - - # token is after split column - else - if specialToken = @specialTokens[index] - rightSpecialTokens[rightTags.length] = specialToken - rightTags.push(tag) - - # tag represents the start or end of a scop - else if (tag % 2) is -1 - if screenColumn < column - leftTags.push(tag) - rightOpenScopes.push(tag) - else - rightTags.push(tag) - else - if screenColumn < column - leftTags.push(tag) - rightOpenScopes.pop() - else - rightTags.push(tag) - - splitBufferColumn = @bufferColumnForScreenColumn(column) - - leftFragment = new TokenizedLine - leftFragment.tokenIterator = @tokenIterator - leftFragment.openScopes = @openScopes - leftFragment.text = leftText - leftFragment.tags = leftTags - leftFragment.specialTokens = leftSpecialTokens - leftFragment.startBufferColumn = @startBufferColumn - leftFragment.bufferDelta = splitBufferColumn - @startBufferColumn - leftFragment.ruleStack = @ruleStack - leftFragment.invisibles = @invisibles - leftFragment.lineEnding = null - leftFragment.indentLevel = @indentLevel - leftFragment.tabLength = @tabLength - leftFragment.firstNonWhitespaceIndex = Math.min(column, @firstNonWhitespaceIndex) - leftFragment.firstTrailingWhitespaceIndex = Math.min(column, @firstTrailingWhitespaceIndex) - - rightFragment = new TokenizedLine - rightFragment.tokenIterator = @tokenIterator - rightFragment.openScopes = rightOpenScopes - rightFragment.text = rightText - rightFragment.tags = rightTags - rightFragment.specialTokens = rightSpecialTokens - rightFragment.startBufferColumn = splitBufferColumn - rightFragment.bufferDelta = @bufferDelta - splitBufferColumn - rightFragment.ruleStack = @ruleStack - rightFragment.invisibles = @invisibles - rightFragment.lineEnding = @lineEnding - rightFragment.indentLevel = @indentLevel - rightFragment.tabLength = @tabLength - rightFragment.endOfLineInvisibles = @endOfLineInvisibles - rightFragment.firstNonWhitespaceIndex = Math.max(softWrapIndent, @firstNonWhitespaceIndex - column + softWrapIndent) - rightFragment.firstTrailingWhitespaceIndex = Math.max(softWrapIndent, @firstTrailingWhitespaceIndex - column + softWrapIndent) + indentationTokens = @buildSoftWrapIndentationTokens(leftTokens[0], hangingIndent) + leftFragment = new TokenizedLine( + tokens: leftTokens + startBufferColumn: @startBufferColumn + ruleStack: @ruleStack + invisibles: @invisibles + lineEnding: null, + indentLevel: @indentLevel, + tabLength: @tabLength + ) + rightFragment = new TokenizedLine( + tokens: indentationTokens.concat(rightTokens) + startBufferColumn: @bufferColumnForScreenColumn(column) + ruleStack: @ruleStack + invisibles: @invisibles + lineEnding: @lineEnding, + indentLevel: @indentLevel, + tabLength: @tabLength + ) [leftFragment, rightFragment] isSoftWrapped: -> @lineEnding is null - isColumnInsideSoftWrapIndentation: (targetColumn) -> - targetColumn < @getSoftWrapIndentationDelta() + isColumnInsideSoftWrapIndentation: (column) -> + return false if @softWrapIndentationTokens.length is 0 - getSoftWrapIndentationDelta: -> - delta = 0 - for tag, index in @tags - if tag >= 0 - if @specialTokens[index] is SoftWrapIndent - delta += tag - else - break - delta + column < @softWrapIndentationDelta + + getSoftWrapIndentationTokens: -> + _.select(@tokens, (token) -> token.isSoftWrapIndentation) + + buildSoftWrapIndentationDelta: -> + _.reduce @softWrapIndentationTokens, ((acc, token) -> acc + token.screenDelta), 0 hasOnlySoftWrapIndentation: -> - @getSoftWrapIndentationDelta() is @text.length + @tokens.length is @softWrapIndentationTokens.length tokenAtBufferColumn: (bufferColumn) -> @tokens[@tokenIndexAtBufferColumn(bufferColumn)] @@ -430,6 +210,58 @@ class TokenizedLine delta = nextDelta delta + breakOutAtomicTokens: (inputTokens) -> + outputTokens = [] + breakOutLeadingSoftTabs = true + column = @startBufferColumn + for token in inputTokens + newTokens = token.breakOutAtomicTokens(@tabLength, breakOutLeadingSoftTabs, column) + column += newToken.value.length for newToken in newTokens + outputTokens.push(newTokens...) + breakOutLeadingSoftTabs = token.isOnlyWhitespace() if breakOutLeadingSoftTabs + outputTokens + + markLeadingAndTrailingWhitespaceTokens: -> + @firstNonWhitespaceIndex = @text.search(NonWhitespaceRegex) + if @firstNonWhitespaceIndex > 0 and isPairedCharacter(@text, @firstNonWhitespaceIndex - 1) + @firstNonWhitespaceIndex-- + firstTrailingWhitespaceIndex = @text.search(TrailingWhitespaceRegex) + @lineIsWhitespaceOnly = firstTrailingWhitespaceIndex is 0 + index = 0 + for token in @tokens + if index < @firstNonWhitespaceIndex + token.firstNonWhitespaceIndex = Math.min(index + token.value.length, @firstNonWhitespaceIndex - index) + # Only the *last* segment of a soft-wrapped line can have trailing whitespace + if @lineEnding? and (index + token.value.length > firstTrailingWhitespaceIndex) + token.firstTrailingWhitespaceIndex = Math.max(0, firstTrailingWhitespaceIndex - index) + index += token.value.length + return + + substituteInvisibleCharacters: -> + invisibles = @invisibles + changedText = false + + for token, i in @tokens + if token.isHardTab + if invisibles.tab + token.value = invisibles.tab + token.value.substring(invisibles.tab.length) + token.hasInvisibleCharacters = true + changedText = true + else + if invisibles.space + if token.hasLeadingWhitespace() and not token.isSoftWrapIndentation + token.value = token.value.replace LeadingWhitespaceRegex, (leadingWhitespace) -> + leadingWhitespace.replace RepeatedSpaceRegex, invisibles.space + token.hasInvisibleCharacters = true + changedText = true + if token.hasTrailingWhitespace() + token.value = token.value.replace TrailingWhitespaceRegex, (leadingWhitespace) -> + leadingWhitespace.replace RepeatedSpaceRegex, invisibles.space + token.hasInvisibleCharacters = true + changedText = true + + @text = @buildText() if changedText + buildEndOfLineInvisibles: -> @endOfLineInvisibles = [] {cr, eol} = @invisibles @@ -442,13 +274,11 @@ class TokenizedLine @endOfLineInvisibles.push(eol) if eol isComment: -> - iterator = @getTokenIterator() - while iterator.next() - scopes = iterator.getScopes() - continue if scopes.length is 1 - continue unless NonWhitespaceRegex.test(iterator.getText()) - for scope in scopes - return true if CommentScopeRegex.test(scope) + for token in @tokens + continue if token.scopes.length is 1 + continue if token.isOnlyWhitespace() + for scope in token.scopes + return true if _.contains(scope.split('.'), 'comment') break false @@ -459,6 +289,42 @@ class TokenizedLine @tokens[index] getTokenCount: -> - count = 0 - count++ for tag in @tags when tag >= 0 - count + @tokens.length + + bufferColumnForToken: (targetToken) -> + column = 0 + for token in @tokens + return column if token is targetToken + column += token.bufferDelta + + getScopeTree: -> + return @scopeTree if @scopeTree? + + scopeStack = [] + for token in @tokens + @updateScopeStack(scopeStack, token.scopes) + _.last(scopeStack).children.push(token) + + @scopeTree = scopeStack[0] + @updateScopeStack(scopeStack, []) + @scopeTree + + updateScopeStack: (scopeStack, desiredScopeDescriptor) -> + # Find a common prefix + for scope, i in desiredScopeDescriptor + break unless scopeStack[i]?.scope is desiredScopeDescriptor[i] + + # Pop scopeDescriptor until we're at the common prefx + until scopeStack.length is i + poppedScope = scopeStack.pop() + _.last(scopeStack)?.children.push(poppedScope) + + # Push onto common prefix until scopeStack equals desiredScopeDescriptor + for j in [i...desiredScopeDescriptor.length] + scopeStack.push(new Scope(desiredScopeDescriptor[j])) + + return + +class Scope + constructor: (@scope) -> + @children = [] From 05d4b3da2786bb3160072d8b71771ee6df86076c Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 21 May 2015 10:24:31 -0700 Subject: [PATCH 1357/1783] :arrow_up: snippets --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 15eb53b29..807a67939 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,7 @@ "package-generator": "0.39.0", "release-notes": "0.52.0", "settings-view": "0.204.0", - "snippets": "0.89.0", + "snippets": "0.90.0", "spell-check": "0.58.0", "status-bar": "0.72.0", "styleguide": "0.44.0", From 2379b3803fbc9e09dce4192dc4c01b93d1c23249 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 21 May 2015 16:33:17 +0200 Subject: [PATCH 1358/1783] Revert "Revert "Merge pull request #6757 from atom/ns-less-memory-for-tokens"" This reverts commit 7cb0bc3bc2aaa0f01b26c8a71f7e5890f8e570d3. --- package.json | 4 +- spec/text-editor-presenter-spec.coffee | 36 +- spec/text-editor-spec.coffee | 3 +- spec/tokenized-buffer-spec.coffee | 28 +- spec/tokenized-line-spec.coffee | 21 - src/display-buffer.coffee | 32 +- src/language-mode.coffee | 5 +- src/lines-component.coffee | 160 ++++++-- src/special-token-symbols.coffee | 6 + src/text-editor-presenter.coffee | 24 +- src/text-editor.coffee | 3 +- src/token-iterator.coffee | 83 ++++ src/token.coffee | 199 +--------- src/tokenized-buffer.coffee | 184 ++++----- src/tokenized-line.coffee | 526 ++++++++++++++++--------- 15 files changed, 712 insertions(+), 602 deletions(-) create mode 100644 src/special-token-symbols.coffee create mode 100644 src/token-iterator.coffee diff --git a/package.json b/package.json index 807a67939..70526eb98 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "delegato": "^1", "emissary": "^1.3.3", "event-kit": "^1.2.0", - "first-mate": "^3.1", + "first-mate": "^4.1.4", "fs-plus": "^2.8.0", "fstream": "0.1.24", "fuzzaldrin": "^2.1", @@ -151,7 +151,7 @@ "language-ruby": "0.54.0", "language-ruby-on-rails": "0.21.0", "language-sass": "0.38.0", - "language-shellscript": "0.14.0", + "language-shellscript": "0.15.0", "language-source": "0.9.0", "language-sql": "0.15.0", "language-text": "0.6.0", diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 7da866ab4..d15c4759d 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -670,7 +670,11 @@ describe "TextEditorPresenter", -> expectValues lineStateForScreenRow(presenter, 4), { screenRow: 4 text: line4.text - tokens: line4.tokens + tags: line4.tags + specialTokens: line4.specialTokens + firstNonWhitespaceIndex: line4.firstNonWhitespaceIndex + firstTrailingWhitespaceIndex: line4.firstTrailingWhitespaceIndex + invisibles: line4.invisibles top: 10 * 4 } @@ -678,7 +682,11 @@ describe "TextEditorPresenter", -> expectValues lineStateForScreenRow(presenter, 5), { screenRow: 5 text: line5.text - tokens: line5.tokens + tags: line5.tags + specialTokens: line5.specialTokens + firstNonWhitespaceIndex: line5.firstNonWhitespaceIndex + firstTrailingWhitespaceIndex: line5.firstTrailingWhitespaceIndex + invisibles: line5.invisibles top: 10 * 5 } @@ -686,7 +694,11 @@ describe "TextEditorPresenter", -> expectValues lineStateForScreenRow(presenter, 6), { screenRow: 6 text: line6.text - tokens: line6.tokens + tags: line6.tags + specialTokens: line6.specialTokens + firstNonWhitespaceIndex: line6.firstNonWhitespaceIndex + firstTrailingWhitespaceIndex: line6.firstTrailingWhitespaceIndex + invisibles: line6.invisibles top: 10 * 6 } @@ -694,7 +706,11 @@ describe "TextEditorPresenter", -> expectValues lineStateForScreenRow(presenter, 7), { screenRow: 7 text: line7.text - tokens: line7.tokens + tags: line7.tags + specialTokens: line7.specialTokens + firstNonWhitespaceIndex: line7.firstNonWhitespaceIndex + firstTrailingWhitespaceIndex: line7.firstTrailingWhitespaceIndex + invisibles: line7.invisibles top: 10 * 7 } @@ -702,7 +718,11 @@ describe "TextEditorPresenter", -> expectValues lineStateForScreenRow(presenter, 8), { screenRow: 8 text: line8.text - tokens: line8.tokens + tags: line8.tags + specialTokens: line8.specialTokens + firstNonWhitespaceIndex: line8.firstNonWhitespaceIndex + firstTrailingWhitespaceIndex: line8.firstTrailingWhitespaceIndex + invisibles: line8.invisibles top: 10 * 8 } @@ -797,19 +817,19 @@ describe "TextEditorPresenter", -> line1 = editor.tokenizedLineForScreenRow(1) expectValues lineStateForScreenRow(presenter, 1), { text: line1.text - tokens: line1.tokens + tags: line1.tags } line2 = editor.tokenizedLineForScreenRow(2) expectValues lineStateForScreenRow(presenter, 2), { text: line2.text - tokens: line2.tokens + tags: line2.tags } line3 = editor.tokenizedLineForScreenRow(3) expectValues lineStateForScreenRow(presenter, 3), { text: line3.text - tokens: line3.tokens + tags: line3.tags } it "does not remove out-of-view lines corresponding to ::mouseWheelScreenRow until ::stoppedScrollingDelay elapses", -> diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index d1d311088..a845619ba 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -4110,8 +4110,9 @@ describe "TextEditor", -> runs -> grammar = atom.grammars.selectGrammar("text.js") - {tokens} = grammar.tokenizeLine("var i; // http://github.com") + {line, tags} = grammar.tokenizeLine("var i; // http://github.com") + tokens = atom.grammars.decodeTokens(line, tags) expect(tokens[0].value).toBe "var" expect(tokens[0].scopes).toEqual ["source.js", "storage.modifier.js"] diff --git a/spec/tokenized-buffer-spec.coffee b/spec/tokenized-buffer-spec.coffee index 9d92335af..45cc03a44 100644 --- a/spec/tokenized-buffer-spec.coffee +++ b/spec/tokenized-buffer-spec.coffee @@ -296,14 +296,6 @@ describe "TokenizedBuffer", -> expect(tokenizedBuffer.tokenizedLineForRow(5).ruleStack?).toBeTruthy() expect(tokenizedBuffer.tokenizedLineForRow(6).ruleStack?).toBeTruthy() - describe ".findOpeningBracket(closingBufferPosition)", -> - it "returns the position of the matching bracket, skipping any nested brackets", -> - expect(tokenizedBuffer.findOpeningBracket([9, 2])).toEqual [1, 29] - - describe ".findClosingBracket(startBufferPosition)", -> - it "returns the position of the matching bracket, skipping any nested brackets", -> - expect(tokenizedBuffer.findClosingBracket([1, 29])).toEqual [9, 2] - it "tokenizes leading whitespace based on the new tab length", -> expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[0].isAtomic).toBeTruthy() expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[0].value).toBe " " @@ -580,7 +572,7 @@ describe "TokenizedBuffer", -> describe "when the selector matches a run of multiple tokens at the position", -> it "returns the range covered by all contigous tokens (within a single line)", -> - expect(tokenizedBuffer.bufferRangeForScopeAtPosition('.function', [1, 18])).toEqual [[1, 6], [1, 28]] + expect(tokenizedBuffer.bufferRangeForScopeAtPosition('.meta.function', [1, 18])).toEqual [[1, 6], [1, 28]] describe "when the editor.tabLength config value changes", -> it "updates the tab length of the tokenized lines", -> @@ -697,22 +689,6 @@ describe "TokenizedBuffer", -> expect(line.tokens[0].firstNonWhitespaceIndex).toBe 2 expect(line.tokens[line.tokens.length - 1].firstTrailingWhitespaceIndex).toBe 0 - it "sets the ::firstNonWhitespaceIndex and ::firstTrailingWhitespaceIndex correctly when tokens are split for soft-wrapping", -> - atom.config.set("editor.showInvisibles", true) - atom.config.set("editor.invisibles", space: 'S') - buffer.setText(" token ") - fullyTokenize(tokenizedBuffer) - token = tokenizedBuffer.tokenizedLines[0].tokens[0] - - [leftToken, rightToken] = token.splitAt(1) - expect(leftToken.hasInvisibleCharacters).toBe true - expect(leftToken.firstNonWhitespaceIndex).toBe 1 - expect(leftToken.firstTrailingWhitespaceIndex).toBe null - - expect(leftToken.hasInvisibleCharacters).toBe true - expect(rightToken.firstNonWhitespaceIndex).toBe null - expect(rightToken.firstTrailingWhitespaceIndex).toBe 5 - describe ".indentLevel on tokenized lines", -> beforeEach -> buffer = atom.project.bufferForPathSync('sample.js') @@ -752,7 +728,7 @@ describe "TokenizedBuffer", -> it "updates empty line indent guides when the empty line is the last line", -> buffer.insert([12, 2], '\n') - # The newline and he tab need to be in two different operations to surface the bug + # The newline and the tab need to be in two different operations to surface the bug buffer.insert([12, 0], ' ') expect(tokenizedBuffer.tokenizedLineForRow(13).indentLevel).toBe 1 diff --git a/spec/tokenized-line-spec.coffee b/spec/tokenized-line-spec.coffee index 0da83c91c..2914ec089 100644 --- a/spec/tokenized-line-spec.coffee +++ b/spec/tokenized-line-spec.coffee @@ -17,24 +17,3 @@ describe "TokenizedLine", -> it "returns false when the line is not only whitespace", -> expect(editor.tokenizedLineForScreenRow(0).isOnlyWhitespace()).toBe false expect(editor.tokenizedLineForScreenRow(2).isOnlyWhitespace()).toBe false - - describe "::getScopeTree()", -> - it "returns a tree whose inner nodes are scopeDescriptor and whose leaf nodes are tokens in those scopeDescriptor", -> - [tokens, tokenIndex] = [] - - ensureValidScopeTree = (scopeTree, scopeDescriptor=[]) -> - if scopeTree.children? - for child in scopeTree.children - ensureValidScopeTree(child, scopeDescriptor.concat([scopeTree.scope])) - else - expect(scopeTree).toBe tokens[tokenIndex++] - expect(scopeDescriptor).toEqual scopeTree.scopes - - waitsForPromise -> - atom.project.open('coffee.coffee').then (o) -> editor = o - - runs -> - tokenIndex = 0 - tokens = editor.tokenizedLineForScreenRow(1).tokens - scopeTree = editor.tokenizedLineForScreenRow(1).getScopeTree() - ensureValidScopeTree(scopeTree) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index 26bf43dce..b2460addc 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -2,6 +2,7 @@ _ = require 'underscore-plus' Serializable = require 'serializable' {CompositeDisposable, Emitter} = require 'event-kit' {Point, Range} = require 'text-buffer' +Grim = require 'grim' TokenizedBuffer = require './tokenized-buffer' RowMap = require './row-map' Fold = require './fold' @@ -9,7 +10,6 @@ Model = require './model' Token = require './token' Decoration = require './decoration' Marker = require './marker' -Grim = require 'grim' class BufferToScreenConversionError extends Error constructor: (@message, @metadata) -> @@ -659,16 +659,19 @@ class DisplayBuffer extends Model top = targetRow * @lineHeightInPixels left = 0 column = 0 - for token in @tokenizedLineForScreenRow(targetRow).tokens - charWidths = @getScopedCharWidths(token.scopes) + + iterator = @tokenizedLineForScreenRow(targetRow).getTokenIterator() + while iterator.next() + charWidths = @getScopedCharWidths(iterator.getScopes()) valueIndex = 0 - while valueIndex < token.value.length - if token.hasPairedCharacter - char = token.value.substr(valueIndex, 2) + value = iterator.getText() + while valueIndex < value.length + if iterator.isPairedCharacter() + char = value charLength = 2 valueIndex += 2 else - char = token.value[valueIndex] + char = value[valueIndex] charLength = 1 valueIndex++ @@ -689,16 +692,19 @@ class DisplayBuffer extends Model left = 0 column = 0 - for token in @tokenizedLineForScreenRow(row).tokens - charWidths = @getScopedCharWidths(token.scopes) + + iterator = @tokenizedLineForScreenRow(row).getTokenIterator() + while iterator.next() + charWidths = @getScopedCharWidths(iterator.getScopes()) + value = iterator.getText() valueIndex = 0 - while valueIndex < token.value.length - if token.hasPairedCharacter - char = token.value.substr(valueIndex, 2) + while valueIndex < value.length + if iterator.isPairedCharacter() + char = value charLength = 2 valueIndex += 2 else - char = token.value[valueIndex] + char = value[valueIndex] charLength = 1 valueIndex++ diff --git a/src/language-mode.coffee b/src/language-mode.coffee index b5529a05e..c9401550b 100644 --- a/src/language-mode.coffee +++ b/src/language-mode.coffee @@ -242,8 +242,9 @@ class LanguageMode @suggestedIndentForTokenizedLineAtBufferRow(bufferRow, tokenizedLine, options) suggestedIndentForTokenizedLineAtBufferRow: (bufferRow, tokenizedLine, options) -> - scopes = tokenizedLine.tokens[0].scopes - scopeDescriptor = new ScopeDescriptor({scopes}) + iterator = tokenizedLine.getTokenIterator() + iterator.next() + scopeDescriptor = new ScopeDescriptor(scopes: iterator.getScopes()) currentIndentLevel = @editor.indentationForBufferRow(bufferRow) return currentIndentLevel unless increaseIndentRegex = @increaseIndentRegexForScopeDescriptor(scopeDescriptor) diff --git a/src/lines-component.coffee b/src/lines-component.coffee index fbec40b79..17c904e99 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -4,10 +4,13 @@ _ = require 'underscore-plus' CursorsComponent = require './cursors-component' HighlightsComponent = require './highlights-component' +TokenIterator = require './token-iterator' DummyLineNode = $$(-> @div className: 'line', style: 'position: absolute; visibility: hidden;', => @span 'x')[0] AcceptFilter = {acceptNode: -> NodeFilter.FILTER_ACCEPT} WrapperDiv = document.createElement('div') +TokenTextEscapeRegex = /[&"'<>]/g +MaxTokenLength = 20000 cloneObject = (object) -> clone = {} @@ -19,6 +22,7 @@ class LinesComponent placeholderTextDiv: null constructor: ({@presenter, @hostElement, @useShadowDOM, visible}) -> + @tokenIterator = new TokenIterator @measuredLines = new Set @lineNodesByLineId = {} @screenRowsByLineId = {} @@ -167,20 +171,116 @@ class LinesComponent @buildEndOfLineHTML(id) or ' ' buildLineInnerHTML: (id) -> - {indentGuidesVisible} = @newState - {tokens, text, isOnlyWhitespace} = @newState.lines[id] + lineState = @newState.lines[id] + {firstNonWhitespaceIndex, firstTrailingWhitespaceIndex, invisibles} = lineState + lineIsWhitespaceOnly = firstTrailingWhitespaceIndex is 0 + innerHTML = "" + @tokenIterator.reset(lineState) - scopeStack = [] - for token in tokens - innerHTML += @updateScopeStack(scopeStack, token.scopes) - hasIndentGuide = indentGuidesVisible and (token.hasLeadingWhitespace() or (token.hasTrailingWhitespace() and isOnlyWhitespace)) - innerHTML += token.getValueAsHtml({hasIndentGuide}) + while @tokenIterator.next() + for scope in @tokenIterator.getScopeEnds() + innerHTML += "" + + for scope in @tokenIterator.getScopeStarts() + innerHTML += "" + + tokenStart = @tokenIterator.getScreenStart() + tokenEnd = @tokenIterator.getScreenEnd() + tokenText = @tokenIterator.getText() + isHardTab = @tokenIterator.isHardTab() + + if hasLeadingWhitespace = tokenStart < firstNonWhitespaceIndex + tokenFirstNonWhitespaceIndex = firstNonWhitespaceIndex - tokenStart + else + tokenFirstNonWhitespaceIndex = null + + if hasTrailingWhitespace = tokenEnd > firstTrailingWhitespaceIndex + tokenFirstTrailingWhitespaceIndex = Math.max(0, firstTrailingWhitespaceIndex - tokenStart) + else + tokenFirstTrailingWhitespaceIndex = null + + hasIndentGuide = + @newState.indentGuidesVisible and + (hasLeadingWhitespace or lineIsWhitespaceOnly) + + hasInvisibleCharacters = + (invisibles?.tab and isHardTab) or + (invisibles?.space and (hasLeadingWhitespace or hasTrailingWhitespace)) + + innerHTML += @buildTokenHTML(tokenText, isHardTab, tokenFirstNonWhitespaceIndex, tokenFirstTrailingWhitespaceIndex, hasIndentGuide, hasInvisibleCharacters) + + for scope in @tokenIterator.getScopeEnds() + innerHTML += "" + + for scope in @tokenIterator.getScopes() + innerHTML += "" - innerHTML += @popScope(scopeStack) while scopeStack.length > 0 innerHTML += @buildEndOfLineHTML(id) innerHTML + buildTokenHTML: (tokenText, isHardTab, firstNonWhitespaceIndex, firstTrailingWhitespaceIndex, hasIndentGuide, hasInvisibleCharacters) -> + if isHardTab + classes = 'hard-tab' + classes += ' leading-whitespace' if firstNonWhitespaceIndex? + classes += ' trailing-whitespace' if firstTrailingWhitespaceIndex? + classes += ' indent-guide' if hasIndentGuide + classes += ' invisible-character' if hasInvisibleCharacters + return "#{@escapeTokenText(tokenText)}" + else + startIndex = 0 + endIndex = tokenText.length + + leadingHtml = '' + trailingHtml = '' + + if firstNonWhitespaceIndex? + leadingWhitespace = tokenText.substring(0, firstNonWhitespaceIndex) + + classes = 'leading-whitespace' + classes += ' indent-guide' if hasIndentGuide + classes += ' invisible-character' if hasInvisibleCharacters + + leadingHtml = "#{leadingWhitespace}" + startIndex = firstNonWhitespaceIndex + + if firstTrailingWhitespaceIndex? + tokenIsOnlyWhitespace = firstTrailingWhitespaceIndex is 0 + trailingWhitespace = tokenText.substring(firstTrailingWhitespaceIndex) + + classes = 'trailing-whitespace' + classes += ' indent-guide' if hasIndentGuide and not firstNonWhitespaceIndex? and tokenIsOnlyWhitespace + classes += ' invisible-character' if hasInvisibleCharacters + + trailingHtml = "#{trailingWhitespace}" + + endIndex = firstTrailingWhitespaceIndex + + html = leadingHtml + if tokenText.length > MaxTokenLength + while startIndex < endIndex + html += "" + @escapeTokenText(tokenText, startIndex, startIndex + MaxTokenLength) + "" + startIndex += MaxTokenLength + else + html += @escapeTokenText(tokenText, startIndex, endIndex) + + html += trailingHtml + html + + escapeTokenText: (tokenText, startIndex, endIndex) -> + if startIndex? and endIndex? and startIndex > 0 or endIndex < tokenText.length + tokenText = tokenText.slice(startIndex, endIndex) + tokenText.replace(TokenTextEscapeRegex, @escapeTokenTextReplace) + + escapeTokenTextReplace: (match) -> + switch match + when '&' then '&' + when '"' then '"' + when "'" then ''' + when '<' then '<' + when '>' then '>' + else match + buildEndOfLineHTML: (id) -> {endOfLineInvisibles} = @newState.lines[id] @@ -190,31 +290,6 @@ class LinesComponent html += "#{invisible}" html - updateScopeStack: (scopeStack, desiredScopeDescriptor) -> - html = "" - - # Find a common prefix - for scope, i in desiredScopeDescriptor - break unless scopeStack[i] is desiredScopeDescriptor[i] - - # Pop scopeDescriptor until we're at the common prefx - until scopeStack.length is i - html += @popScope(scopeStack) - - # Push onto common prefix until scopeStack equals desiredScopeDescriptor - for j in [i...desiredScopeDescriptor.length] - html += @pushScope(scopeStack, desiredScopeDescriptor[j]) - - html - - popScope: (scopeStack) -> - scopeStack.pop() - "" - - pushScope: (scopeStack, scope) -> - scopeStack.push(scope) - "" - updateLineNode: (id) -> oldLineState = @oldState.lines[id] newLineState = @newState.lines[id] @@ -279,19 +354,22 @@ class LinesComponent iterator = null charIndex = 0 - for {value, scopes, hasPairedCharacter} in tokenizedLine.tokens + @tokenIterator.reset(tokenizedLine) + while @tokenIterator.next() + scopes = @tokenIterator.getScopes() + text = @tokenIterator.getText() charWidths = @presenter.getScopedCharacterWidths(scopes) - valueIndex = 0 - while valueIndex < value.length - if hasPairedCharacter - char = value.substr(valueIndex, 2) + textIndex = 0 + while textIndex < text.length + if @tokenIterator.isPairedCharacter() + char = text charLength = 2 - valueIndex += 2 + textIndex += 2 else - char = value[valueIndex] + char = text[textIndex] charLength = 1 - valueIndex++ + textIndex++ continue if char is '\0' diff --git a/src/special-token-symbols.coffee b/src/special-token-symbols.coffee new file mode 100644 index 000000000..06884b85f --- /dev/null +++ b/src/special-token-symbols.coffee @@ -0,0 +1,6 @@ +module.exports = { + SoftTab: Symbol('SoftTab') + HardTab: Symbol('HardTab') + PairedCharacter: Symbol('PairedCharacter') + SoftWrapIndent: Symbol('SoftWrapIndent') +} diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 70c26a1a3..3aea57f29 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -336,9 +336,14 @@ class TextEditorPresenter @state.content.lines[line.id] = screenRow: row text: line.text - tokens: line.tokens - isOnlyWhitespace: line.isOnlyWhitespace() + openScopes: line.openScopes + tags: line.tags + specialTokens: line.specialTokens + firstNonWhitespaceIndex: line.firstNonWhitespaceIndex + firstTrailingWhitespaceIndex: line.firstTrailingWhitespaceIndex + invisibles: line.invisibles endOfLineInvisibles: line.endOfLineInvisibles + isOnlyWhitespace: line.isOnlyWhitespace() indentLevel: line.indentLevel tabLength: line.tabLength fold: line.fold @@ -1006,17 +1011,20 @@ class TextEditorPresenter top = targetRow * @lineHeight left = 0 column = 0 - for token in @model.tokenizedLineForScreenRow(targetRow).tokens - characterWidths = @getScopedCharacterWidths(token.scopes) + + iterator = @model.tokenizedLineForScreenRow(targetRow).getTokenIterator() + while iterator.next() + characterWidths = @getScopedCharacterWidths(iterator.getScopes()) valueIndex = 0 - while valueIndex < token.value.length - if token.hasPairedCharacter - char = token.value.substr(valueIndex, 2) + text = iterator.getText() + while valueIndex < text.length + if iterator.isPairedCharacter() + char = text charLength = 2 valueIndex += 2 else - char = token.value[valueIndex] + char = text[valueIndex] charLength = 1 valueIndex++ diff --git a/src/text-editor.coffee b/src/text-editor.coffee index d2bd77522..4489d82af 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -2457,9 +2457,8 @@ class TextEditor extends Model # Extended: Determine if the given row is entirely a comment isBufferRowCommented: (bufferRow) -> if match = @lineTextForBufferRow(bufferRow).match(/\S/) - scopeDescriptor = @tokenForBufferPosition([bufferRow, match.index]).scopes @commentScopeSelector ?= new TextMateScopeSelector('comment.*') - @commentScopeSelector.matches(scopeDescriptor) + @commentScopeSelector.matches(@scopeDescriptorForBufferPosition([bufferRow, match.index]).scopes) logCursorScope: -> scopeDescriptor = @getLastCursor().getScopeDescriptor() diff --git a/src/token-iterator.coffee b/src/token-iterator.coffee new file mode 100644 index 000000000..202b044ba --- /dev/null +++ b/src/token-iterator.coffee @@ -0,0 +1,83 @@ +{SoftTab, HardTab, PairedCharacter, SoftWrapIndent} = require './special-token-symbols' + +module.exports = +class TokenIterator + constructor: (line) -> + @reset(line) if line? + + reset: (@line) -> + @index = null + @bufferStart = @line.startBufferColumn + @bufferEnd = @bufferStart + @screenStart = 0 + @screenEnd = 0 + @scopes = @line.openScopes.map (id) -> atom.grammars.scopeForId(id) + @scopeStarts = @scopes.slice() + @scopeEnds = [] + this + + next: -> + {tags} = @line + + if @index? + @index++ + @scopeEnds.length = 0 + @scopeStarts.length = 0 + @bufferStart = @bufferEnd + @screenStart = @screenEnd + else + @index = 0 + + while @index < tags.length + tag = tags[@index] + if tag < 0 + if tag % 2 is 0 + @scopeEnds.push(atom.grammars.scopeForId(tag + 1)) + @scopes.pop() + else + scope = atom.grammars.scopeForId(tag) + @scopeStarts.push(scope) + @scopes.push(scope) + @index++ + else + if @isHardTab() + @screenEnd = @screenStart + tag + @bufferEnd = @bufferStart + 1 + else if @isSoftWrapIndentation() + @screenEnd = @screenStart + tag + @bufferEnd = @bufferStart + 0 + else + @screenEnd = @screenStart + tag + @bufferEnd = @bufferStart + tag + return true + + false + + getBufferStart: -> @bufferStart + getBufferEnd: -> @bufferEnd + + getScreenStart: -> @screenStart + getScreenEnd: -> @screenEnd + + getScopeStarts: -> @scopeStarts + getScopeEnds: -> @scopeEnds + + getScopes: -> @scopes + + getText: -> + @line.text.substring(@screenStart, @screenEnd) + + isSoftTab: -> + @line.specialTokens[@index] is SoftTab + + isHardTab: -> + @line.specialTokens[@index] is HardTab + + isSoftWrapIndentation: -> + @line.specialTokens[@index] is SoftWrapIndent + + isPairedCharacter: -> + @line.specialTokens[@index] is PairedCharacter + + isAtomic: -> + @isSoftTab() or @isHardTab() or @isSoftWrapIndentation() or @isPairedCharacter() diff --git a/src/token.coffee b/src/token.coffee index 8aa4a8706..60e8194f8 100644 --- a/src/token.coffee +++ b/src/token.coffee @@ -1,13 +1,8 @@ _ = require 'underscore-plus' -textUtils = require './text-utils' -WhitespaceRegexesByTabLength = {} -EscapeRegex = /[&"'<>]/g StartDotRegex = /^\.?/ WhitespaceRegex = /\S/ -MaxTokenLength = 20000 - # Represents a single unit of text as selected by a grammar. module.exports = class Token @@ -20,10 +15,14 @@ class Token firstTrailingWhitespaceIndex: null hasInvisibleCharacters: false - constructor: ({@value, @scopes, @isAtomic, @bufferDelta, @isHardTab, @hasPairedCharacter, @isSoftWrapIndentation}) -> + constructor: (properties) -> + {@value, @scopes, @isAtomic, @isHardTab, @bufferDelta} = properties + {@hasInvisibleCharacters, @hasPairedCharacter, @isSoftWrapIndentation} = properties + @firstNonWhitespaceIndex = properties.firstNonWhitespaceIndex ? null + @firstTrailingWhitespaceIndex = properties.firstTrailingWhitespaceIndex ? null + @screenDelta = @value.length @bufferDelta ?= @screenDelta - @hasPairedCharacter ?= textUtils.hasPairedCharacter(@value) isEqual: (other) -> # TODO: scopes is deprecated. This is here for the sake of lang package tests @@ -32,126 +31,6 @@ class Token isBracket: -> /^meta\.brace\b/.test(_.last(@scopes)) - splitAt: (splitIndex) -> - leftToken = new Token(value: @value.substring(0, splitIndex), scopes: @scopes) - rightToken = new Token(value: @value.substring(splitIndex), scopes: @scopes) - - if @firstNonWhitespaceIndex? - leftToken.firstNonWhitespaceIndex = Math.min(splitIndex, @firstNonWhitespaceIndex) - leftToken.hasInvisibleCharacters = @hasInvisibleCharacters - - if @firstNonWhitespaceIndex > splitIndex - rightToken.firstNonWhitespaceIndex = @firstNonWhitespaceIndex - splitIndex - rightToken.hasInvisibleCharacters = @hasInvisibleCharacters - - if @firstTrailingWhitespaceIndex? - rightToken.firstTrailingWhitespaceIndex = Math.max(0, @firstTrailingWhitespaceIndex - splitIndex) - rightToken.hasInvisibleCharacters = @hasInvisibleCharacters - - if @firstTrailingWhitespaceIndex < splitIndex - leftToken.firstTrailingWhitespaceIndex = @firstTrailingWhitespaceIndex - leftToken.hasInvisibleCharacters = @hasInvisibleCharacters - - [leftToken, rightToken] - - whitespaceRegexForTabLength: (tabLength) -> - WhitespaceRegexesByTabLength[tabLength] ?= new RegExp("([ ]{#{tabLength}})|(\t)|([^\t]+)", "g") - - breakOutAtomicTokens: (tabLength, breakOutLeadingSoftTabs, startColumn) -> - if @hasPairedCharacter - outputTokens = [] - column = startColumn - - for token in @breakOutPairedCharacters() - if token.isAtomic - outputTokens.push(token) - else - outputTokens.push(token.breakOutAtomicTokens(tabLength, breakOutLeadingSoftTabs, column)...) - breakOutLeadingSoftTabs = token.isOnlyWhitespace() if breakOutLeadingSoftTabs - column += token.value.length - - outputTokens - else - return [this] if @isAtomic - - if breakOutLeadingSoftTabs - return [this] unless /^[ ]|\t/.test(@value) - else - return [this] unless /\t/.test(@value) - - outputTokens = [] - regex = @whitespaceRegexForTabLength(tabLength) - column = startColumn - while match = regex.exec(@value) - [fullMatch, softTab, hardTab] = match - token = null - if softTab and breakOutLeadingSoftTabs - token = @buildSoftTabToken(tabLength) - else if hardTab - breakOutLeadingSoftTabs = false - token = @buildHardTabToken(tabLength, column) - else - breakOutLeadingSoftTabs = false - value = match[0] - token = new Token({value, @scopes}) - column += token.value.length - outputTokens.push(token) - - outputTokens - - breakOutPairedCharacters: -> - outputTokens = [] - index = 0 - nonPairStart = 0 - - while index < @value.length - if textUtils.isPairedCharacter(@value, index) - if nonPairStart isnt index - outputTokens.push(new Token({value: @value[nonPairStart...index], @scopes})) - outputTokens.push(@buildPairedCharacterToken(@value, index)) - index += 2 - nonPairStart = index - else - index++ - - if nonPairStart isnt index - outputTokens.push(new Token({value: @value[nonPairStart...index], @scopes})) - - outputTokens - - buildPairedCharacterToken: (value, index) -> - new Token( - value: value[index..index + 1] - scopes: @scopes - isAtomic: true - hasPairedCharacter: true - ) - - buildHardTabToken: (tabLength, column) -> - @buildTabToken(tabLength, true, column) - - buildSoftTabToken: (tabLength) -> - @buildTabToken(tabLength, false, 0) - - buildTabToken: (tabLength, isHardTab, column=0) -> - tabStop = tabLength - (column % tabLength) - new Token( - value: _.multiplyString(" ", tabStop) - scopes: @scopes - bufferDelta: if isHardTab then 1 else tabStop - isAtomic: true - isHardTab: isHardTab - ) - - buildSoftWrapIndentationToken: (length) -> - new Token( - value: _.multiplyString(" ", length), - scopes: @scopes, - bufferDelta: 0, - isAtomic: true, - isSoftWrapIndentation: true - ) - isOnlyWhitespace: -> not WhitespaceRegex.test(@value) @@ -161,72 +40,6 @@ class Token scopeClasses = scope.split('.') _.isSubset(targetClasses, scopeClasses) - getValueAsHtml: ({hasIndentGuide}) -> - if @isHardTab - classes = 'hard-tab' - classes += ' leading-whitespace' if @hasLeadingWhitespace() - classes += ' trailing-whitespace' if @hasTrailingWhitespace() - classes += ' indent-guide' if hasIndentGuide - classes += ' invisible-character' if @hasInvisibleCharacters - html = "#{@escapeString(@value)}" - else - startIndex = 0 - endIndex = @value.length - - leadingHtml = '' - trailingHtml = '' - - if @hasLeadingWhitespace() - leadingWhitespace = @value.substring(0, @firstNonWhitespaceIndex) - - classes = 'leading-whitespace' - classes += ' indent-guide' if hasIndentGuide - classes += ' invisible-character' if @hasInvisibleCharacters - - leadingHtml = "#{leadingWhitespace}" - startIndex = @firstNonWhitespaceIndex - - if @hasTrailingWhitespace() - tokenIsOnlyWhitespace = @firstTrailingWhitespaceIndex is 0 - trailingWhitespace = @value.substring(@firstTrailingWhitespaceIndex) - - classes = 'trailing-whitespace' - classes += ' indent-guide' if hasIndentGuide and not @hasLeadingWhitespace() and tokenIsOnlyWhitespace - classes += ' invisible-character' if @hasInvisibleCharacters - - trailingHtml = "#{trailingWhitespace}" - - endIndex = @firstTrailingWhitespaceIndex - - html = leadingHtml - if @value.length > MaxTokenLength - while startIndex < endIndex - html += "" + @escapeString(@value, startIndex, startIndex + MaxTokenLength) + "" - startIndex += MaxTokenLength - else - html += @escapeString(@value, startIndex, endIndex) - - html += trailingHtml - html - - escapeString: (str, startIndex, endIndex) -> - strLength = str.length - - startIndex ?= 0 - endIndex ?= strLength - - str = str.slice(startIndex, endIndex) if startIndex > 0 or endIndex < strLength - str.replace(EscapeRegex, @escapeStringReplace) - - escapeStringReplace: (match) -> - switch match - when '&' then '&' - when '"' then '"' - when "'" then ''' - when '<' then '<' - when '>' then '>' - else match - hasLeadingWhitespace: -> @firstNonWhitespaceIndex? and @firstNonWhitespaceIndex > 0 diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 6d8f0c018..60ebe16f0 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -1,9 +1,11 @@ _ = require 'underscore-plus' {CompositeDisposable, Emitter} = require 'event-kit' {Point, Range} = require 'text-buffer' +{ScopeSelector} = require 'first-mate' Serializable = require 'serializable' Model = require './model' TokenizedLine = require './tokenized-line' +TokenIterator = require './token-iterator' Token = require './token' ScopeDescriptor = require './scope-descriptor' Grim = require 'grim' @@ -25,6 +27,7 @@ class TokenizedBuffer extends Model constructor: ({@buffer, @tabLength, @ignoreInvisibles}) -> @emitter = new Emitter @disposables = new CompositeDisposable + @tokenIterator = new TokenIterator @disposables.add atom.grammars.onDidAddGrammar(@grammarAddedOrUpdated) @disposables.add atom.grammars.onDidUpdateGrammar(@grammarAddedOrUpdated) @@ -167,7 +170,7 @@ class TokenizedBuffer extends Model row = startRow loop previousStack = @stackForRow(row) - @tokenizedLines[row] = @buildTokenizedLineForRow(row, @stackForRow(row - 1)) + @tokenizedLines[row] = @buildTokenizedLineForRow(row, @stackForRow(row - 1), @openScopesForRow(row)) if --rowsRemaining is 0 filledRegion = false endRow = row @@ -227,7 +230,7 @@ class TokenizedBuffer extends Model @updateInvalidRows(start, end, delta) previousEndStack = @stackForRow(end) # used in spill detection below - newTokenizedLines = @buildTokenizedLinesForRows(start, end + delta, @stackForRow(start - 1)) + newTokenizedLines = @buildTokenizedLinesForRows(start, end + delta, @stackForRow(start - 1), @openScopesForRow(start)) _.spliceWithArray(@tokenizedLines, start, end - start + 1, newTokenizedLines) start = @retokenizeWhitespaceRowsIfIndentLevelChanged(start - 1, -1) @@ -248,7 +251,7 @@ class TokenizedBuffer extends Model line = @tokenizedLines[row] if line?.isOnlyWhitespace() and @indentLevelForRow(row) isnt line.indentLevel while line?.isOnlyWhitespace() - @tokenizedLines[row] = @buildTokenizedLineForRow(row, @stackForRow(row - 1)) + @tokenizedLines[row] = @buildTokenizedLineForRow(row, @stackForRow(row - 1), @openScopesForRow(row)) row += increment line = @tokenizedLines[row] @@ -290,16 +293,18 @@ class TokenizedBuffer extends Model @tokenizedLineForRow(row).isComment() and @tokenizedLineForRow(nextRow).isComment() - buildTokenizedLinesForRows: (startRow, endRow, startingStack) -> + buildTokenizedLinesForRows: (startRow, endRow, startingStack, startingopenScopes) -> ruleStack = startingStack + openScopes = startingopenScopes stopTokenizingAt = startRow + @chunkSize tokenizedLines = for row in [startRow..endRow] if (ruleStack or row is 0) and row < stopTokenizingAt - screenLine = @buildTokenizedLineForRow(row, ruleStack) - ruleStack = screenLine.ruleStack + tokenizedLine = @buildTokenizedLineForRow(row, ruleStack, openScopes) + ruleStack = tokenizedLine.ruleStack + openScopes = @scopesFromTags(openScopes, tokenizedLine.tags) else - screenLine = @buildPlaceholderTokenizedLineForRow(row) - screenLine + tokenizedLine = @buildPlaceholderTokenizedLineForRow(row, openScopes) + tokenizedLine if endRow >= stopTokenizingAt @invalidateRow(stopTokenizingAt) @@ -311,22 +316,23 @@ class TokenizedBuffer extends Model @buildPlaceholderTokenizedLineForRow(row) for row in [startRow..endRow] buildPlaceholderTokenizedLineForRow: (row) -> - line = @buffer.lineForRow(row) - tokens = [new Token(value: line, scopes: [@grammar.scopeName])] + openScopes = [@grammar.startIdForScope(@grammar.scopeName)] + text = @buffer.lineForRow(row) + tags = [text.length] tabLength = @getTabLength() indentLevel = @indentLevelForRow(row) lineEnding = @buffer.lineEndingForRow(row) - new TokenizedLine({tokens, tabLength, indentLevel, invisibles: @getInvisiblesToShow(), lineEnding}) + new TokenizedLine({openScopes, text, tags, tabLength, indentLevel, invisibles: @getInvisiblesToShow(), lineEnding, @tokenIterator}) - buildTokenizedLineForRow: (row, ruleStack) -> - @buildTokenizedLineForRowWithText(row, @buffer.lineForRow(row), ruleStack) + buildTokenizedLineForRow: (row, ruleStack, openScopes) -> + @buildTokenizedLineForRowWithText(row, @buffer.lineForRow(row), ruleStack, openScopes) - buildTokenizedLineForRowWithText: (row, line, ruleStack = @stackForRow(row - 1)) -> + buildTokenizedLineForRowWithText: (row, text, ruleStack = @stackForRow(row - 1), openScopes = @openScopesForRow(row)) -> lineEnding = @buffer.lineEndingForRow(row) tabLength = @getTabLength() indentLevel = @indentLevelForRow(row) - {tokens, ruleStack} = @grammar.tokenizeLine(line, ruleStack, row is 0) - new TokenizedLine({tokens, ruleStack, tabLength, lineEnding, indentLevel, invisibles: @getInvisiblesToShow()}) + {tags, ruleStack} = @grammar.tokenizeLine(text, ruleStack, row is 0, false) + new TokenizedLine({openScopes, text, tags, ruleStack, tabLength, lineEnding, indentLevel, invisibles: @getInvisiblesToShow(), @tokenIterator}) getInvisiblesToShow: -> if @configSettings.showInvisibles and not @ignoreInvisibles @@ -340,6 +346,25 @@ class TokenizedBuffer extends Model stackForRow: (bufferRow) -> @tokenizedLines[bufferRow]?.ruleStack + openScopesForRow: (bufferRow) -> + if bufferRow > 0 + precedingLine = @tokenizedLines[bufferRow - 1] + @scopesFromTags(precedingLine.openScopes, precedingLine.tags) + else + [] + + scopesFromTags: (startingScopes, tags) -> + scopes = startingScopes.slice() + for tag in tags when tag < 0 + if (tag % 2) is -1 + scopes.push(tag) + else + expectedScope = tag + 1 + poppedScope = scopes.pop() + unless poppedScope is expectedScope + throw new Error("Encountered an invalid scope end id. Popped #{poppedScope}, expected to pop #{expectedScope}.") + scopes + indentLevelForRow: (bufferRow) -> line = @buffer.lineForRow(bufferRow) indentLevel = 0 @@ -376,7 +401,20 @@ class TokenizedBuffer extends Model 0 scopeDescriptorForPosition: (position) -> - new ScopeDescriptor(scopes: @tokenForPosition(position).scopes) + {row, column} = Point.fromObject(position) + + iterator = @tokenizedLines[row].getTokenIterator() + while iterator.next() + if iterator.getScreenEnd() > column + scopes = iterator.getScopes() + break + + # rebuild scope of last token if we iterated off the end + unless scopes? + scopes = iterator.getScopes() + scopes.push(iterator.getScopeEnds().reverse()...) + + new ScopeDescriptor({scopes}) tokenForPosition: (position) -> {row, column} = Point.fromObject(position) @@ -388,85 +426,53 @@ class TokenizedBuffer extends Model new Point(row, column) bufferRangeForScopeAtPosition: (selector, position) -> + selector = new ScopeSelector(selector.replace(/^\./, '')) position = Point.fromObject(position) - tokenizedLine = @tokenizedLines[position.row] - startIndex = tokenizedLine.tokenIndexAtBufferColumn(position.column) - for index in [startIndex..0] - token = tokenizedLine.tokenAtIndex(index) - break unless token.matchesScopeSelector(selector) - firstToken = token + {openScopes, tags} = @tokenizedLines[position.row] + scopes = openScopes.map (tag) -> atom.grammars.scopeForId(tag) - for index in [startIndex...tokenizedLine.getTokenCount()] - token = tokenizedLine.tokenAtIndex(index) - break unless token.matchesScopeSelector(selector) - lastToken = token + startColumn = 0 + for tag, tokenIndex in tags + if tag < 0 + if tag % 2 is -1 + scopes.push(atom.grammars.scopeForId(tag)) + else + scopes.pop() + else + endColumn = startColumn + tag + if endColumn > position.column + break + else + startColumn = endColumn - return unless firstToken? and lastToken? + return unless selector.matches(scopes) - startColumn = tokenizedLine.bufferColumnForToken(firstToken) - endColumn = tokenizedLine.bufferColumnForToken(lastToken) + lastToken.bufferDelta - new Range([position.row, startColumn], [position.row, endColumn]) + startScopes = scopes.slice() + for startTokenIndex in [(tokenIndex - 1)..0] by -1 + tag = tags[startTokenIndex] + if tag < 0 + if tag % 2 is -1 + startScopes.pop() + else + startScopes.push(atom.grammars.scopeForId(tag)) + else + break unless selector.matches(startScopes) + startColumn -= tag - iterateTokensInBufferRange: (bufferRange, iterator) -> - bufferRange = Range.fromObject(bufferRange) - {start, end} = bufferRange + endScopes = scopes.slice() + for endTokenIndex in [(tokenIndex + 1)...tags.length] by 1 + tag = tags[endTokenIndex] + if tag < 0 + if tag % 2 is -1 + endScopes.push(atom.grammars.scopeForId(tag)) + else + endScopes.pop() + else + break unless selector.matches(endScopes) + endColumn += tag - keepLooping = true - stop = -> keepLooping = false - - for bufferRow in [start.row..end.row] - bufferColumn = 0 - for token in @tokenizedLines[bufferRow].tokens - startOfToken = new Point(bufferRow, bufferColumn) - iterator(token, startOfToken, {stop}) if bufferRange.containsPoint(startOfToken) - return unless keepLooping - bufferColumn += token.bufferDelta - - backwardsIterateTokensInBufferRange: (bufferRange, iterator) -> - bufferRange = Range.fromObject(bufferRange) - {start, end} = bufferRange - - keepLooping = true - stop = -> keepLooping = false - - for bufferRow in [end.row..start.row] - bufferColumn = @buffer.lineLengthForRow(bufferRow) - for token in new Array(@tokenizedLines[bufferRow].tokens...).reverse() - bufferColumn -= token.bufferDelta - startOfToken = new Point(bufferRow, bufferColumn) - iterator(token, startOfToken, {stop}) if bufferRange.containsPoint(startOfToken) - return unless keepLooping - - findOpeningBracket: (startBufferPosition) -> - range = [[0,0], startBufferPosition] - position = null - depth = 0 - @backwardsIterateTokensInBufferRange range, (token, startPosition, {stop}) -> - if token.isBracket() - if token.value is '}' - depth++ - else if token.value is '{' - depth-- - if depth is 0 - position = startPosition - stop() - position - - findClosingBracket: (startBufferPosition) -> - range = [startBufferPosition, @buffer.getEndPosition()] - position = null - depth = 0 - @iterateTokensInBufferRange range, (token, startPosition, {stop}) -> - if token.isBracket() - if token.value is '{' - depth++ - else if token.value is '}' - depth-- - if depth is 0 - position = startPosition - stop() - position + new Range(new Point(position.row, startColumn), new Point(position.row, endColumn)) # Gets the row number of the last line. # diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index b81d972a0..45af81e57 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -1,10 +1,13 @@ _ = require 'underscore-plus' {isPairedCharacter} = require './text-utils' +Token = require './token' +{SoftTab, HardTab, PairedCharacter, SoftWrapIndent} = require './special-token-symbols' NonWhitespaceRegex = /\S/ LeadingWhitespaceRegex = /^\s*/ TrailingWhitespaceRegex = /\s*$/ RepeatedSpaceRegex = /[ ]/g +CommentScopeRegex = /(\b|\.)comment/ idCounter = 1 module.exports = @@ -14,32 +17,181 @@ class TokenizedLine firstNonWhitespaceIndex: 0 foldable: false - constructor: ({tokens, @lineEnding, @ruleStack, @startBufferColumn, @fold, @tabLength, @indentLevel, @invisibles}) -> - @startBufferColumn ?= 0 - @tokens = @breakOutAtomicTokens(tokens) - @text = @buildText() - @bufferDelta = @buildBufferDelta() - @softWrapIndentationTokens = @getSoftWrapIndentationTokens() - @softWrapIndentationDelta = @buildSoftWrapIndentationDelta() - + constructor: (properties) -> @id = idCounter++ - @markLeadingAndTrailingWhitespaceTokens() - if @invisibles - @substituteInvisibleCharacters() - @buildEndOfLineInvisibles() if @lineEnding? - buildText: -> - text = "" - text += token.value for token in @tokens - text + return unless properties? - buildBufferDelta: -> - delta = 0 - delta += token.bufferDelta for token in @tokens - delta + @specialTokens = {} + {@openScopes, @text, @tags, @lineEnding, @ruleStack, @tokenIterator} = properties + {@startBufferColumn, @fold, @tabLength, @indentLevel, @invisibles} = properties + + @startBufferColumn ?= 0 + @bufferDelta = @text.length + + @transformContent() + @buildEndOfLineInvisibles() if @invisibles? and @lineEnding? + + transformContent: -> + text = '' + bufferColumn = 0 + screenColumn = 0 + tokenIndex = 0 + tokenOffset = 0 + firstNonWhitespaceColumn = null + lastNonWhitespaceColumn = null + + while bufferColumn < @text.length + # advance to next token if we've iterated over its length + if tokenOffset is @tags[tokenIndex] + tokenIndex++ + tokenOffset = 0 + + # advance to next token tag + tokenIndex++ while @tags[tokenIndex] < 0 + + character = @text[bufferColumn] + + # split out unicode surrogate pairs + if isPairedCharacter(@text, bufferColumn) + prefix = tokenOffset + suffix = @tags[tokenIndex] - tokenOffset - 2 + splitTokens = [] + splitTokens.push(prefix) if prefix > 0 + splitTokens.push(2) + splitTokens.push(suffix) if suffix > 0 + + @tags.splice(tokenIndex, 1, splitTokens...) + + firstNonWhitespaceColumn ?= screenColumn + lastNonWhitespaceColumn = screenColumn + 1 + + text += @text.substr(bufferColumn, 2) + screenColumn += 2 + bufferColumn += 2 + + tokenIndex++ if prefix > 0 + @specialTokens[tokenIndex] = PairedCharacter + tokenIndex++ + tokenOffset = 0 + + # split out leading soft tabs + else if character is ' ' + if firstNonWhitespaceColumn? + text += ' ' + else + if (screenColumn + 1) % @tabLength is 0 + @specialTokens[tokenIndex] = SoftTab + suffix = @tags[tokenIndex] - @tabLength + @tags.splice(tokenIndex, 1, @tabLength) + @tags.splice(tokenIndex + 1, 0, suffix) if suffix > 0 + text += @invisibles?.space ? ' ' + + screenColumn++ + bufferColumn++ + tokenOffset++ + + # expand hard tabs to the next tab stop + else if character is '\t' + tabLength = @tabLength - (screenColumn % @tabLength) + if @invisibles?.tab + text += @invisibles.tab + else + text += ' ' + text += ' ' for i in [1...tabLength] by 1 + + prefix = tokenOffset + suffix = @tags[tokenIndex] - tokenOffset - 1 + splitTokens = [] + splitTokens.push(prefix) if prefix > 0 + splitTokens.push(tabLength) + splitTokens.push(suffix) if suffix > 0 + + @tags.splice(tokenIndex, 1, splitTokens...) + + screenColumn += tabLength + bufferColumn++ + + tokenIndex++ if prefix > 0 + @specialTokens[tokenIndex] = HardTab + tokenIndex++ + tokenOffset = 0 + + # continue past any other character + else + firstNonWhitespaceColumn ?= screenColumn + lastNonWhitespaceColumn = screenColumn + + text += character + screenColumn++ + bufferColumn++ + tokenOffset++ + + @text = text + + @firstNonWhitespaceIndex = firstNonWhitespaceColumn + if lastNonWhitespaceColumn? + if lastNonWhitespaceColumn + 1 < @text.length + @firstTrailingWhitespaceIndex = lastNonWhitespaceColumn + 1 + if @invisibles?.space + @text = + @text.substring(0, @firstTrailingWhitespaceIndex) + + @text.substring(@firstTrailingWhitespaceIndex) + .replace(RepeatedSpaceRegex, @invisibles.space) + else + @lineIsWhitespaceOnly = true + @firstTrailingWhitespaceIndex = 0 + + getTokenIterator: -> @tokenIterator.reset(this) + + Object.defineProperty @prototype, 'tokens', get: -> + iterator = @getTokenIterator() + tokens = [] + + while iterator.next() + properties = { + value: iterator.getText() + scopes: iterator.getScopes().slice() + isAtomic: iterator.isAtomic() + isHardTab: iterator.isHardTab() + hasPairedCharacter: iterator.isPairedCharacter() + isSoftWrapIndentation: iterator.isSoftWrapIndentation() + } + + if iterator.isHardTab() + properties.bufferDelta = 1 + properties.hasInvisibleCharacters = true if @invisibles?.tab + + if iterator.getScreenStart() < @firstNonWhitespaceIndex + properties.firstNonWhitespaceIndex = + Math.min(@firstNonWhitespaceIndex, iterator.getScreenEnd()) - iterator.getScreenStart() + properties.hasInvisibleCharacters = true if @invisibles?.space + + if @lineEnding? and iterator.getScreenEnd() > @firstTrailingWhitespaceIndex + properties.firstTrailingWhitespaceIndex = + Math.max(0, @firstTrailingWhitespaceIndex - iterator.getScreenStart()) + properties.hasInvisibleCharacters = true if @invisibles?.space + + tokens.push(new Token(properties)) + + tokens copy: -> - new TokenizedLine({@tokens, @lineEnding, @ruleStack, @startBufferColumn, @fold}) + copy = new TokenizedLine + copy.tokenIterator = @tokenIterator + copy.indentLevel = @indentLevel + copy.openScopes = @openScopes + copy.text = @text + copy.tags = @tags + copy.specialTokens = @specialTokens + copy.firstNonWhitespaceIndex = @firstNonWhitespaceIndex + copy.firstTrailingWhitespaceIndex = @firstTrailingWhitespaceIndex + copy.lineEnding = @lineEnding + copy.endOfLineInvisibles = @endOfLineInvisibles + copy.ruleStack = @ruleStack + copy.startBufferColumn = @startBufferColumn + copy.fold = @fold + copy # This clips a given screen column to a valid column that's within the line # and not in the middle of any atomic tokens. @@ -52,49 +204,58 @@ class TokenizedLine # # Returns a {Number} representing the clipped column. clipScreenColumn: (column, options={}) -> - return 0 if @tokens.length is 0 + return 0 if @tags.length is 0 {clip} = options column = Math.min(column, @getMaxScreenColumn()) tokenStartColumn = 0 - for token in @tokens - break if tokenStartColumn + token.screenDelta > column - tokenStartColumn += token.screenDelta - if @isColumnInsideSoftWrapIndentation(tokenStartColumn) - @softWrapIndentationDelta - else if token.isAtomic and tokenStartColumn < column + iterator = @getTokenIterator() + while iterator.next() + break if iterator.getScreenEnd() > column + + if iterator.isSoftWrapIndentation() + iterator.next() while iterator.isSoftWrapIndentation() + iterator.getScreenStart() + else if iterator.isAtomic() and iterator.getScreenStart() < column if clip is 'forward' - tokenStartColumn + token.screenDelta + iterator.getScreenEnd() else if clip is 'backward' - tokenStartColumn + iterator.getScreenStart() else #'closest' - if column > tokenStartColumn + (token.screenDelta / 2) - tokenStartColumn + token.screenDelta + if column > ((iterator.getScreenStart() + iterator.getScreenEnd()) / 2) + iterator.getScreenEnd() else - tokenStartColumn + iterator.getScreenStart() else column - screenColumnForBufferColumn: (bufferColumn, options) -> - bufferColumn = bufferColumn - @startBufferColumn - screenColumn = 0 - currentBufferColumn = 0 - for token in @tokens - break if currentBufferColumn + token.bufferDelta > bufferColumn - screenColumn += token.screenDelta - currentBufferColumn += token.bufferDelta - @clipScreenColumn(screenColumn + (bufferColumn - currentBufferColumn)) + screenColumnForBufferColumn: (targetBufferColumn, options) -> + iterator = @getTokenIterator() + while iterator.next() + tokenBufferStart = iterator.getBufferStart() + tokenBufferEnd = iterator.getBufferEnd() + if tokenBufferStart <= targetBufferColumn < tokenBufferEnd + overshoot = targetBufferColumn - tokenBufferStart + return Math.min( + iterator.getScreenStart() + overshoot, + iterator.getScreenEnd() + ) + iterator.getScreenEnd() - bufferColumnForScreenColumn: (screenColumn, options) -> - bufferColumn = @startBufferColumn - currentScreenColumn = 0 - for token in @tokens - break if currentScreenColumn + token.screenDelta > screenColumn - bufferColumn += token.bufferDelta - currentScreenColumn += token.screenDelta - bufferColumn + (screenColumn - currentScreenColumn) + bufferColumnForScreenColumn: (targetScreenColumn) -> + iterator = @getTokenIterator() + while iterator.next() + tokenScreenStart = iterator.getScreenStart() + tokenScreenEnd = iterator.getScreenEnd() + if tokenScreenStart <= targetScreenColumn < tokenScreenEnd + overshoot = targetScreenColumn - tokenScreenStart + return Math.min( + iterator.getBufferStart() + overshoot, + iterator.getBufferEnd() + ) + iterator.getBufferEnd() getMaxScreenColumn: -> if @fold @@ -128,69 +289,128 @@ class TokenizedLine return maxColumn - buildSoftWrapIndentationTokens: (token, hangingIndent) -> - totalIndentSpaces = (@indentLevel * @tabLength) + hangingIndent - indentTokens = [] - while totalIndentSpaces > 0 - tokenLength = Math.min(@tabLength, totalIndentSpaces) - indentToken = token.buildSoftWrapIndentationToken(tokenLength) - indentTokens.push(indentToken) - totalIndentSpaces -= tokenLength - - indentTokens - softWrapAt: (column, hangingIndent) -> - return [new TokenizedLine([], '', [0, 0], [0, 0]), this] if column is 0 + return [null, this] if column is 0 - rightTokens = new Array(@tokens...) - leftTokens = [] - leftScreenColumn = 0 + leftText = @text.substring(0, column) + rightText = @text.substring(column) - while leftScreenColumn < column - if leftScreenColumn + rightTokens[0].screenDelta > column - rightTokens[0..0] = rightTokens[0].splitAt(column - leftScreenColumn) - nextToken = rightTokens.shift() - leftScreenColumn += nextToken.screenDelta - leftTokens.push nextToken + leftTags = [] + rightTags = [] - indentationTokens = @buildSoftWrapIndentationTokens(leftTokens[0], hangingIndent) + leftSpecialTokens = {} + rightSpecialTokens = {} + + rightOpenScopes = @openScopes.slice() + + screenColumn = 0 + + for tag, index in @tags + # tag represents a token + if tag >= 0 + # token ends before the soft wrap column + if screenColumn + tag <= column + if specialToken = @specialTokens[index] + leftSpecialTokens[index] = specialToken + leftTags.push(tag) + screenColumn += tag + + # token starts before and ends after the split column + else if screenColumn <= column + leftSuffix = column - screenColumn + rightPrefix = screenColumn + tag - column + + leftTags.push(leftSuffix) if leftSuffix > 0 + + softWrapIndent = @indentLevel * @tabLength + (hangingIndent ? 0) + for i in [0...softWrapIndent] by 1 + rightText = ' ' + rightText + remainingSoftWrapIndent = softWrapIndent + while remainingSoftWrapIndent > 0 + indentToken = Math.min(remainingSoftWrapIndent, @tabLength) + rightSpecialTokens[rightTags.length] = SoftWrapIndent + rightTags.push(indentToken) + remainingSoftWrapIndent -= indentToken + + rightTags.push(rightPrefix) if rightPrefix > 0 + + screenColumn += tag + + # token is after split column + else + if specialToken = @specialTokens[index] + rightSpecialTokens[rightTags.length] = specialToken + rightTags.push(tag) + + # tag represents the start or end of a scop + else if (tag % 2) is -1 + if screenColumn < column + leftTags.push(tag) + rightOpenScopes.push(tag) + else + rightTags.push(tag) + else + if screenColumn < column + leftTags.push(tag) + rightOpenScopes.pop() + else + rightTags.push(tag) + + splitBufferColumn = @bufferColumnForScreenColumn(column) + + leftFragment = new TokenizedLine + leftFragment.tokenIterator = @tokenIterator + leftFragment.openScopes = @openScopes + leftFragment.text = leftText + leftFragment.tags = leftTags + leftFragment.specialTokens = leftSpecialTokens + leftFragment.startBufferColumn = @startBufferColumn + leftFragment.bufferDelta = splitBufferColumn - @startBufferColumn + leftFragment.ruleStack = @ruleStack + leftFragment.invisibles = @invisibles + leftFragment.lineEnding = null + leftFragment.indentLevel = @indentLevel + leftFragment.tabLength = @tabLength + leftFragment.firstNonWhitespaceIndex = Math.min(column, @firstNonWhitespaceIndex) + leftFragment.firstTrailingWhitespaceIndex = Math.min(column, @firstTrailingWhitespaceIndex) + + rightFragment = new TokenizedLine + rightFragment.tokenIterator = @tokenIterator + rightFragment.openScopes = rightOpenScopes + rightFragment.text = rightText + rightFragment.tags = rightTags + rightFragment.specialTokens = rightSpecialTokens + rightFragment.startBufferColumn = splitBufferColumn + rightFragment.bufferDelta = @bufferDelta - splitBufferColumn + rightFragment.ruleStack = @ruleStack + rightFragment.invisibles = @invisibles + rightFragment.lineEnding = @lineEnding + rightFragment.indentLevel = @indentLevel + rightFragment.tabLength = @tabLength + rightFragment.endOfLineInvisibles = @endOfLineInvisibles + rightFragment.firstNonWhitespaceIndex = Math.max(softWrapIndent, @firstNonWhitespaceIndex - column + softWrapIndent) + rightFragment.firstTrailingWhitespaceIndex = Math.max(softWrapIndent, @firstTrailingWhitespaceIndex - column + softWrapIndent) - leftFragment = new TokenizedLine( - tokens: leftTokens - startBufferColumn: @startBufferColumn - ruleStack: @ruleStack - invisibles: @invisibles - lineEnding: null, - indentLevel: @indentLevel, - tabLength: @tabLength - ) - rightFragment = new TokenizedLine( - tokens: indentationTokens.concat(rightTokens) - startBufferColumn: @bufferColumnForScreenColumn(column) - ruleStack: @ruleStack - invisibles: @invisibles - lineEnding: @lineEnding, - indentLevel: @indentLevel, - tabLength: @tabLength - ) [leftFragment, rightFragment] isSoftWrapped: -> @lineEnding is null - isColumnInsideSoftWrapIndentation: (column) -> - return false if @softWrapIndentationTokens.length is 0 + isColumnInsideSoftWrapIndentation: (targetColumn) -> + targetColumn < @getSoftWrapIndentationDelta() - column < @softWrapIndentationDelta - - getSoftWrapIndentationTokens: -> - _.select(@tokens, (token) -> token.isSoftWrapIndentation) - - buildSoftWrapIndentationDelta: -> - _.reduce @softWrapIndentationTokens, ((acc, token) -> acc + token.screenDelta), 0 + getSoftWrapIndentationDelta: -> + delta = 0 + for tag, index in @tags + if tag >= 0 + if @specialTokens[index] is SoftWrapIndent + delta += tag + else + break + delta hasOnlySoftWrapIndentation: -> - @tokens.length is @softWrapIndentationTokens.length + @getSoftWrapIndentationDelta() is @text.length tokenAtBufferColumn: (bufferColumn) -> @tokens[@tokenIndexAtBufferColumn(bufferColumn)] @@ -210,58 +430,6 @@ class TokenizedLine delta = nextDelta delta - breakOutAtomicTokens: (inputTokens) -> - outputTokens = [] - breakOutLeadingSoftTabs = true - column = @startBufferColumn - for token in inputTokens - newTokens = token.breakOutAtomicTokens(@tabLength, breakOutLeadingSoftTabs, column) - column += newToken.value.length for newToken in newTokens - outputTokens.push(newTokens...) - breakOutLeadingSoftTabs = token.isOnlyWhitespace() if breakOutLeadingSoftTabs - outputTokens - - markLeadingAndTrailingWhitespaceTokens: -> - @firstNonWhitespaceIndex = @text.search(NonWhitespaceRegex) - if @firstNonWhitespaceIndex > 0 and isPairedCharacter(@text, @firstNonWhitespaceIndex - 1) - @firstNonWhitespaceIndex-- - firstTrailingWhitespaceIndex = @text.search(TrailingWhitespaceRegex) - @lineIsWhitespaceOnly = firstTrailingWhitespaceIndex is 0 - index = 0 - for token in @tokens - if index < @firstNonWhitespaceIndex - token.firstNonWhitespaceIndex = Math.min(index + token.value.length, @firstNonWhitespaceIndex - index) - # Only the *last* segment of a soft-wrapped line can have trailing whitespace - if @lineEnding? and (index + token.value.length > firstTrailingWhitespaceIndex) - token.firstTrailingWhitespaceIndex = Math.max(0, firstTrailingWhitespaceIndex - index) - index += token.value.length - return - - substituteInvisibleCharacters: -> - invisibles = @invisibles - changedText = false - - for token, i in @tokens - if token.isHardTab - if invisibles.tab - token.value = invisibles.tab + token.value.substring(invisibles.tab.length) - token.hasInvisibleCharacters = true - changedText = true - else - if invisibles.space - if token.hasLeadingWhitespace() and not token.isSoftWrapIndentation - token.value = token.value.replace LeadingWhitespaceRegex, (leadingWhitespace) -> - leadingWhitespace.replace RepeatedSpaceRegex, invisibles.space - token.hasInvisibleCharacters = true - changedText = true - if token.hasTrailingWhitespace() - token.value = token.value.replace TrailingWhitespaceRegex, (leadingWhitespace) -> - leadingWhitespace.replace RepeatedSpaceRegex, invisibles.space - token.hasInvisibleCharacters = true - changedText = true - - @text = @buildText() if changedText - buildEndOfLineInvisibles: -> @endOfLineInvisibles = [] {cr, eol} = @invisibles @@ -274,11 +442,13 @@ class TokenizedLine @endOfLineInvisibles.push(eol) if eol isComment: -> - for token in @tokens - continue if token.scopes.length is 1 - continue if token.isOnlyWhitespace() - for scope in token.scopes - return true if _.contains(scope.split('.'), 'comment') + iterator = @getTokenIterator() + while iterator.next() + scopes = iterator.getScopes() + continue if scopes.length is 1 + continue unless NonWhitespaceRegex.test(iterator.getText()) + for scope in scopes + return true if CommentScopeRegex.test(scope) break false @@ -289,42 +459,6 @@ class TokenizedLine @tokens[index] getTokenCount: -> - @tokens.length - - bufferColumnForToken: (targetToken) -> - column = 0 - for token in @tokens - return column if token is targetToken - column += token.bufferDelta - - getScopeTree: -> - return @scopeTree if @scopeTree? - - scopeStack = [] - for token in @tokens - @updateScopeStack(scopeStack, token.scopes) - _.last(scopeStack).children.push(token) - - @scopeTree = scopeStack[0] - @updateScopeStack(scopeStack, []) - @scopeTree - - updateScopeStack: (scopeStack, desiredScopeDescriptor) -> - # Find a common prefix - for scope, i in desiredScopeDescriptor - break unless scopeStack[i]?.scope is desiredScopeDescriptor[i] - - # Pop scopeDescriptor until we're at the common prefx - until scopeStack.length is i - poppedScope = scopeStack.pop() - _.last(scopeStack)?.children.push(poppedScope) - - # Push onto common prefix until scopeStack equals desiredScopeDescriptor - for j in [i...desiredScopeDescriptor.length] - scopeStack.push(new Scope(desiredScopeDescriptor[j])) - - return - -class Scope - constructor: (@scope) -> - @children = [] + count = 0 + count++ for tag in @tags when tag >= 0 + count From b4444df442790cc14f8d0e211e2402bc0fb0d19f Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 21 May 2015 01:13:33 +0200 Subject: [PATCH 1359/1783] Minimize substring calls and concatenation in transformContent --- src/tokenized-line.coffee | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 45af81e57..8b4c40ff1 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -41,6 +41,9 @@ class TokenizedLine firstNonWhitespaceColumn = null lastNonWhitespaceColumn = null + substringStart = 0 + substringEnd = 0 + while bufferColumn < @text.length # advance to next token if we've iterated over its length if tokenOffset is @tags[tokenIndex] @@ -66,7 +69,7 @@ class TokenizedLine firstNonWhitespaceColumn ?= screenColumn lastNonWhitespaceColumn = screenColumn + 1 - text += @text.substr(bufferColumn, 2) + substringEnd += 2 screenColumn += 2 bufferColumn += 2 @@ -78,14 +81,21 @@ class TokenizedLine # split out leading soft tabs else if character is ' ' if firstNonWhitespaceColumn? - text += ' ' + substringEnd += 1 else if (screenColumn + 1) % @tabLength is 0 @specialTokens[tokenIndex] = SoftTab suffix = @tags[tokenIndex] - @tabLength @tags.splice(tokenIndex, 1, @tabLength) @tags.splice(tokenIndex + 1, 0, suffix) if suffix > 0 - text += @invisibles?.space ? ' ' + + if @invisibles?.space + text += @text.substring(substringStart, substringEnd) if substringEnd > substringStart + substringStart = substringEnd + text += @invisibles.space + substringStart += 1 + + substringEnd += 1 screenColumn++ bufferColumn++ @@ -93,6 +103,9 @@ class TokenizedLine # expand hard tabs to the next tab stop else if character is '\t' + text += @text.substring(substringStart, substringEnd) if substringEnd > substringStart + substringStart = substringEnd + tabLength = @tabLength - (screenColumn % @tabLength) if @invisibles?.tab text += @invisibles.tab @@ -100,6 +113,9 @@ class TokenizedLine text += ' ' text += ' ' for i in [1...tabLength] by 1 + substringStart += 1 + substringEnd += 1 + prefix = tokenOffset suffix = @tags[tokenIndex] - tokenOffset - 1 splitTokens = [] @@ -122,12 +138,17 @@ class TokenizedLine firstNonWhitespaceColumn ?= screenColumn lastNonWhitespaceColumn = screenColumn - text += character + substringEnd += 1 screenColumn++ bufferColumn++ tokenOffset++ - @text = text + if substringEnd > substringStart + unless substringStart is 0 and substringEnd is @text.length + text += @text.substring(substringStart, substringEnd) + @text = text + else + @text = text @firstNonWhitespaceIndex = firstNonWhitespaceColumn if lastNonWhitespaceColumn? From 321d310e8a1650397d272ba84d076cd12c201a7a Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 21 May 2015 02:22:22 +0200 Subject: [PATCH 1360/1783] Avoid more allocations in transformContent --- src/tokenized-line.coffee | 54 +++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 8b4c40ff1..b7812b1f6 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -8,8 +8,26 @@ LeadingWhitespaceRegex = /^\s*/ TrailingWhitespaceRegex = /\s*$/ RepeatedSpaceRegex = /[ ]/g CommentScopeRegex = /(\b|\.)comment/ +TabCharCode = 9 +SpaceCharCode = 32 +SpaceString = ' ' +TabStringsByLength = { + 1: ' ' + 2: ' ' + 3: ' ' + 4: ' ' +} + idCounter = 1 +getTabString = (length) -> + TabStringsByLength[length] ?= buildTabString(length) + +buildTabString = (length) -> + string = SpaceString + string += SpaceString for i in [1...length] by 1 + string + module.exports = class TokenizedLine endOfLineInvisibles: null @@ -53,18 +71,18 @@ class TokenizedLine # advance to next token tag tokenIndex++ while @tags[tokenIndex] < 0 - character = @text[bufferColumn] + charCode = @text.charCodeAt(bufferColumn) # split out unicode surrogate pairs if isPairedCharacter(@text, bufferColumn) prefix = tokenOffset suffix = @tags[tokenIndex] - tokenOffset - 2 - splitTokens = [] - splitTokens.push(prefix) if prefix > 0 - splitTokens.push(2) - splitTokens.push(suffix) if suffix > 0 - @tags.splice(tokenIndex, 1, splitTokens...) + i = tokenIndex + @tags.splice(i, 1) + @tags.splice(i++, 0, prefix) if prefix > 0 + @tags.splice(i++, 0, 2) + @tags.splice(i, 0, suffix) if suffix > 0 firstNonWhitespaceColumn ?= screenColumn lastNonWhitespaceColumn = screenColumn + 1 @@ -79,7 +97,7 @@ class TokenizedLine tokenOffset = 0 # split out leading soft tabs - else if character is ' ' + else if charCode is SpaceCharCode if firstNonWhitespaceColumn? substringEnd += 1 else @@ -90,7 +108,8 @@ class TokenizedLine @tags.splice(tokenIndex + 1, 0, suffix) if suffix > 0 if @invisibles?.space - text += @text.substring(substringStart, substringEnd) if substringEnd > substringStart + if substringEnd > substringStart + text += @text.substring(substringStart, substringEnd) substringStart = substringEnd text += @invisibles.space substringStart += 1 @@ -102,28 +121,29 @@ class TokenizedLine tokenOffset++ # expand hard tabs to the next tab stop - else if character is '\t' - text += @text.substring(substringStart, substringEnd) if substringEnd > substringStart + else if charCode is TabCharCode + if substringEnd > substringStart + text += @text.substring(substringStart, substringEnd) substringStart = substringEnd tabLength = @tabLength - (screenColumn % @tabLength) if @invisibles?.tab text += @invisibles.tab + text += getTabString(tabLength - 1) if tabLength > 1 else - text += ' ' - text += ' ' for i in [1...tabLength] by 1 + text += getTabString(tabLength) substringStart += 1 substringEnd += 1 prefix = tokenOffset suffix = @tags[tokenIndex] - tokenOffset - 1 - splitTokens = [] - splitTokens.push(prefix) if prefix > 0 - splitTokens.push(tabLength) - splitTokens.push(suffix) if suffix > 0 - @tags.splice(tokenIndex, 1, splitTokens...) + i = tokenIndex + @tags.splice(i, 1) + @tags.splice(i++, 0, prefix) if prefix > 0 + @tags.splice(i++, 0, tabLength) + @tags.splice(i, 0, suffix) if suffix > 0 screenColumn += tabLength bufferColumn++ From 95806dba46b7c2191f6056b259d80cbc2ddb35d2 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 21 May 2015 19:28:34 +0200 Subject: [PATCH 1361/1783] :arrow_up: first-mate --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 70526eb98..c97cdf441 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "delegato": "^1", "emissary": "^1.3.3", "event-kit": "^1.2.0", - "first-mate": "^4.1.4", + "first-mate": "^4.1.5", "fs-plus": "^2.8.0", "fstream": "0.1.24", "fuzzaldrin": "^2.1", From 865015e47dce688b45e84fec4b5ca4d9e1a305f6 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 21 May 2015 19:56:24 +0200 Subject: [PATCH 1362/1783] Correctly compute bufferDelta for last soft wrap line segment Fixes #6885 --- spec/display-buffer-spec.coffee | 3 +++ src/tokenized-line.coffee | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index 6389f8105..be89db8ac 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -106,8 +106,11 @@ describe "DisplayBuffer", -> buffer.setTextInRange([[0, 0], [1, 0]], 'abcdefghijklmnopqrstuvwxyz\n') displayBuffer.setEditorWidthInChars(10) expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe 'abcdefghij' + expect(displayBuffer.tokenizedLineForScreenRow(0).bufferDelta).toBe 'abcdefghij'.length expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe 'klmnopqrst' + expect(displayBuffer.tokenizedLineForScreenRow(1).bufferDelta).toBe 'klmnopqrst'.length expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe 'uvwxyz' + expect(displayBuffer.tokenizedLineForScreenRow(2).bufferDelta).toBe 'uvwxyz'.length describe "when there is a whitespace character at the max length boundary", -> it "wraps the line at the first non-whitespace character following the boundary", -> diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index b7812b1f6..6761eecad 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -422,7 +422,7 @@ class TokenizedLine rightFragment.tags = rightTags rightFragment.specialTokens = rightSpecialTokens rightFragment.startBufferColumn = splitBufferColumn - rightFragment.bufferDelta = @bufferDelta - splitBufferColumn + rightFragment.bufferDelta = @startBufferColumn + @bufferDelta - splitBufferColumn rightFragment.ruleStack = @ruleStack rightFragment.invisibles = @invisibles rightFragment.lineEnding = @lineEnding From ba6e76947302983a0a7ee94db206e073cb90d1e0 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Thu, 21 May 2015 11:00:06 -0700 Subject: [PATCH 1363/1783] :arrow_up: metrics@0.51.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 807a67939..6caa958bf 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "keybinding-resolver": "0.33.0", "link": "0.30.0", "markdown-preview": "0.149.0", - "metrics": "0.50.0", + "metrics": "0.51.0", "notifications": "0.50.0", "open-on-github": "0.37.0", "package-generator": "0.39.0", From 1046c331b23be988022b7f114b3134f3ad832a9b Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Thu, 21 May 2015 15:56:54 -0400 Subject: [PATCH 1364/1783] :arrow_up: language-xml@0.30.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6caa958bf..b632f7bb7 100644 --- a/package.json +++ b/package.json @@ -157,7 +157,7 @@ "language-text": "0.6.0", "language-todo": "0.21.0", "language-toml": "0.16.0", - "language-xml": "0.29.0", + "language-xml": "0.30.0", "language-yaml": "0.22.0" }, "private": true, From 6adbdee3599f322b86a2eea68abfb47303b12b5a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 21 May 2015 13:37:38 -0700 Subject: [PATCH 1365/1783] :arrow_up: settings-view@0.205 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b632f7bb7..0271a3ea9 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "open-on-github": "0.37.0", "package-generator": "0.39.0", "release-notes": "0.52.0", - "settings-view": "0.204.0", + "settings-view": "0.205.0", "snippets": "0.90.0", "spell-check": "0.58.0", "status-bar": "0.72.0", From 135603f8dd3f468a86687d35dad70a347da6891e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 21 May 2015 15:21:06 -0700 Subject: [PATCH 1366/1783] Prepare 0.202 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0271a3ea9..69a6167b7 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "0.201.0", + "version": "0.202.0", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From 06217293418947cbc0acdf1fe4a1f7289bc22309 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 21 May 2015 17:57:26 -0700 Subject: [PATCH 1367/1783] :arrow_up: text-buffer --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index be07a083a..d4d40b58b 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "space-pen": "3.8.2", "stacktrace-parser": "0.1.1", "temp": "0.8.1", - "text-buffer": "6.0.2", + "text-buffer": "6.1.0", "theorist": "^1.0.2", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", From 186a9ee05aad42bcca1be1b5c17248f07c18ef96 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Thu, 21 May 2015 23:12:03 -0400 Subject: [PATCH 1368/1783] Lint for even more style errors --- coffeelint.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/coffeelint.json b/coffeelint.json index f3caf09cc..6de95f1d7 100644 --- a/coffeelint.json +++ b/coffeelint.json @@ -27,5 +27,17 @@ "braces_spacing": { "spaces": 0, "level": "error" + }, + "space_operators": { + "level": "error" + }, + "spacing_after_comma": { + "level": "error" + }, + "no_stand_alone_at": { + "level": "error" + }, + "newlines_after_classes": { + "level": "error" } } From 0b34de005cfbff82c972830aa3bbe3938c7bec4f Mon Sep 17 00:00:00 2001 From: Thomas Johansen Date: Fri, 22 May 2015 06:00:10 +0200 Subject: [PATCH 1369/1783] Remove mention of incorrect keybind The dev mode keybind `cmd-shift-o` was changed a while ago. --- docs/contributing-to-packages.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/contributing-to-packages.md b/docs/contributing-to-packages.md index 42de6e37b..4576635ff 100644 --- a/docs/contributing-to-packages.md +++ b/docs/contributing-to-packages.md @@ -40,9 +40,8 @@ For this reason, you'll only want to load packages in **development mode** while you are working on them. You'll perform your editing in **stable mode**, only switching to development mode to test your changes. -To open a development mode window, use the "Application: Open Dev" command, -which is normally bound to `cmd-shift-o`. You can also run dev mode from the -command line with `atom --dev`. +To open a development mode window, use the "Application: Open Dev" command. +You can also run dev mode from the command line with `atom --dev`. To load your package in development mode, create a symlink to it in `~/.atom/dev/packages`. This occurs automatically when you clone the package From 17834157147bb3cffe2ed70d71998e3ee6e81699 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 22 May 2015 09:51:48 +0200 Subject: [PATCH 1370/1783] Fix spec failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @as-cii this was just a typo, but there’s a failure later in the spec that you’re probably in a better position to fix quickly. --- spec/text-editor-presenter-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 872b71c58..d8d1dbbbb 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -680,7 +680,7 @@ describe "TextEditorPresenter", -> expect(presenter.getState().content.tiles[8]).toBeUndefined() - expectStateUpdate -> presenter.setScrollTop(3) + expectStateUpdate presenter, -> presenter.setScrollTop(3) expect(presenter.getState().content.tiles[0]).toBeUndefined() From 538fcfece349cc8acf4fe27999b22ee394124a14 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 22 May 2015 14:01:52 +0200 Subject: [PATCH 1371/1783] :art: Better test naming --- spec/text-editor-component-spec.coffee | 70 +++++++++++++------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 30c955c57..b2bb09acd 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -68,7 +68,7 @@ describe "TextEditorComponent", -> expect(nextAnimationFrame).not.toThrow() describe "line rendering", -> - expectLineRender = (tileNode, {screenRow, top}) -> + expectTileContainsRow = (tileNode, screenRow, {top}) -> lineNode = tileNode.querySelector("[data-screen-row='#{screenRow}']") tokenizedLine = editor.tokenizedLineForScreenRow(screenRow) @@ -78,7 +78,7 @@ describe "TextEditorComponent", -> else expect(lineNode.textContent).toBe(tokenizedLine.text) - it "renders the currently-visible lines into a tiled fashion", -> + it "renders the currently-visible lines in a tiled fashion", -> wrapperNode.style.height = 6.5 * lineHeightInPixels + 'px' tileHeight = tileSize * lineHeightInPixels component.measureDimensions() @@ -90,21 +90,21 @@ describe "TextEditorComponent", -> expect(tilesNodes[0].style['-webkit-transform']).toBe "translate3d(0px, 0px, 0px)" expect(tilesNodes[0].children.length).toBe(tileSize) - expectLineRender(tilesNodes[0], screenRow: 0, top: 0 * lineHeightInPixels) - expectLineRender(tilesNodes[0], screenRow: 1, top: 1 * lineHeightInPixels) - expectLineRender(tilesNodes[0], screenRow: 2, top: 2 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[0], 0, top: 0 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[0], 1, top: 1 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[0], 2, top: 2 * lineHeightInPixels) expect(tilesNodes[1].style['-webkit-transform']).toBe "translate3d(0px, #{1 * tileHeight}px, 0px)" expect(tilesNodes[1].children.length).toBe(tileSize) - expectLineRender(tilesNodes[1], screenRow: 3, top: 0 * lineHeightInPixels) - expectLineRender(tilesNodes[1], screenRow: 4, top: 1 * lineHeightInPixels) - expectLineRender(tilesNodes[1], screenRow: 5, top: 2 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[1], 3, top: 0 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[1], 4, top: 1 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[1], 5, top: 2 * lineHeightInPixels) expect(tilesNodes[2].style['-webkit-transform']).toBe "translate3d(0px, #{2 * tileHeight}px, 0px)" expect(tilesNodes[2].children.length).toBe(tileSize) - expectLineRender(tilesNodes[2], screenRow: 6, top: 0 * lineHeightInPixels) - expectLineRender(tilesNodes[2], screenRow: 7, top: 1 * lineHeightInPixels) - expectLineRender(tilesNodes[2], screenRow: 8, top: 2 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[2], 6, top: 0 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[2], 7, top: 1 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[2], 8, top: 2 * lineHeightInPixels) expect(component.lineNodeForScreenRow(9)).toBeUndefined() @@ -119,21 +119,21 @@ describe "TextEditorComponent", -> expect(tilesNodes[0].style['-webkit-transform']).toBe "translate3d(0px, -5px, 0px)" expect(tilesNodes[0].children.length).toBe(tileSize) - expectLineRender(tilesNodes[0], screenRow: 3, top: 0 * lineHeightInPixels) - expectLineRender(tilesNodes[0], screenRow: 4, top: 1 * lineHeightInPixels) - expectLineRender(tilesNodes[0], screenRow: 5, top: 2 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[0], 3, top: 0 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[0], 4, top: 1 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[0], 5, top: 2 * lineHeightInPixels) expect(tilesNodes[1].style['-webkit-transform']).toBe "translate3d(0px, #{1 * tileHeight - 5}px, 0px)" expect(tilesNodes[1].children.length).toBe(tileSize) - expectLineRender(tilesNodes[1], screenRow: 6, top: 0 * lineHeightInPixels) - expectLineRender(tilesNodes[1], screenRow: 7, top: 1 * lineHeightInPixels) - expectLineRender(tilesNodes[1], screenRow: 8, top: 2 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[1], 6, top: 0 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[1], 7, top: 1 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[1], 8, top: 2 * lineHeightInPixels) expect(tilesNodes[2].style['-webkit-transform']).toBe "translate3d(0px, #{2 * tileHeight - 5}px, 0px)" expect(tilesNodes[2].children.length).toBe(tileSize) - expectLineRender(tilesNodes[2], screenRow: 9, top: 0 * lineHeightInPixels) - expectLineRender(tilesNodes[2], screenRow: 10, top: 1 * lineHeightInPixels) - expectLineRender(tilesNodes[2], screenRow: 11, top: 2 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[2], 9, top: 0 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[2], 10, top: 1 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[2], 11, top: 2 * lineHeightInPixels) it "updates the top position of subsequent tiles when lines are inserted or removed", -> wrapperNode.style.height = 6.5 * lineHeightInPixels + 'px' @@ -145,14 +145,14 @@ describe "TextEditorComponent", -> tilesNodes = componentNode.querySelectorAll(".tile") expect(tilesNodes[0].style['-webkit-transform']).toBe "translate3d(0px, 0px, 0px)" - expectLineRender(tilesNodes[0], screenRow: 0, top: 0 * lineHeightInPixels) - expectLineRender(tilesNodes[0], screenRow: 1, top: 1 * lineHeightInPixels) - expectLineRender(tilesNodes[0], screenRow: 2, top: 2 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[0], 0, top: 0 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[0], 1, top: 1 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[0], 2, top: 2 * lineHeightInPixels) expect(tilesNodes[1].style['-webkit-transform']).toBe "translate3d(0px, #{1 * tileHeight}px, 0px)" - expectLineRender(tilesNodes[1], screenRow: 3, top: 0 * lineHeightInPixels) - expectLineRender(tilesNodes[1], screenRow: 4, top: 1 * lineHeightInPixels) - expectLineRender(tilesNodes[1], screenRow: 5, top: 2 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[1], 3, top: 0 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[1], 4, top: 1 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[1], 5, top: 2 * lineHeightInPixels) editor.getBuffer().insert([0, 0], '\n\n') nextAnimationFrame() @@ -160,19 +160,19 @@ describe "TextEditorComponent", -> tilesNodes = componentNode.querySelectorAll(".tile") expect(tilesNodes[0].style['-webkit-transform']).toBe "translate3d(0px, 0px, 0px)" - expectLineRender(tilesNodes[0], screenRow: 0, top: 0 * lineHeightInPixels) - expectLineRender(tilesNodes[0], screenRow: 1, top: 1 * lineHeightInPixels) - expectLineRender(tilesNodes[0], screenRow: 2, top: 2 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[0], 0, top: 0 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[0], 1, top: 1 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[0], 2, top: 2 * lineHeightInPixels) expect(tilesNodes[1].style['-webkit-transform']).toBe "translate3d(0px, #{1 * tileHeight}px, 0px)" - expectLineRender(tilesNodes[1], screenRow: 3, top: 0 * lineHeightInPixels) - expectLineRender(tilesNodes[1], screenRow: 4, top: 1 * lineHeightInPixels) - expectLineRender(tilesNodes[1], screenRow: 5, top: 2 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[1], 3, top: 0 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[1], 4, top: 1 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[1], 5, top: 2 * lineHeightInPixels) expect(tilesNodes[2].style['-webkit-transform']).toBe "translate3d(0px, #{2 * tileHeight}px, 0px)" - expectLineRender(tilesNodes[2], screenRow: 6, top: 0 * lineHeightInPixels) - expectLineRender(tilesNodes[2], screenRow: 7, top: 1 * lineHeightInPixels) - expectLineRender(tilesNodes[2], screenRow: 8, top: 2 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[2], 6, top: 0 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[2], 7, top: 1 * lineHeightInPixels) + expectTileContainsRow(tilesNodes[2], 8, top: 2 * lineHeightInPixels) it "updates the lines when lines are inserted or removed above the rendered row range", -> wrapperNode.style.height = 4.5 * lineHeightInPixels + 'px' From 80a3294f8e97e606f77ae3dd622adce8b8a17d3d Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 22 May 2015 14:05:21 +0200 Subject: [PATCH 1372/1783] :green_heart: Fix wrong spec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @nathansobo: I just forgot to include an actually visible tile in this test which, therefore, complained. “Production code”-wise the behavior was consistent and correct. --- spec/text-editor-presenter-spec.coffee | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index d8d1dbbbb..6a1b2a6d0 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -696,8 +696,11 @@ describe "TextEditorPresenter", -> expectValues presenter.getState().content.tiles[8], { top: 5 } + expectValues presenter.getState().content.tiles[10], { + top: 7 + } - expect(presenter.getState().content.tiles[10]).toBeUndefined() + expect(presenter.getState().content.tiles[12]).toBeUndefined() it "includes state for all tiles if no external ::explicitHeight is assigned", -> presenter = buildPresenter(explicitHeight: null, tileSize: 2) From 5be251321c49f6132aa97e3286cb4ca5af610997 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Fri, 22 May 2015 08:45:30 -0400 Subject: [PATCH 1373/1783] Skip linting fixtures --- .coffeelintignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .coffeelintignore diff --git a/.coffeelintignore b/.coffeelintignore new file mode 100644 index 000000000..1db51fed7 --- /dev/null +++ b/.coffeelintignore @@ -0,0 +1 @@ +spec/fixtures From 42d7a1b428b7f00a000b93dd3cf75e26267fae5c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 22 May 2015 08:28:14 -0700 Subject: [PATCH 1374/1783] :arrow_up: atom-keymap@5.1.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d4d40b58b..fb1f099bb 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "atomShellVersion": "0.22.3", "dependencies": { "async": "0.2.6", - "atom-keymap": "^5.1.2", + "atom-keymap": "^5.1.3", "atom-space-pen-views": "^2.0.4", "babel-core": "^5.1.11", "bootstrap": "^3.3.4", From 96f425c292dce0f45ec2e4c7950589af6a0d4f77 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 22 May 2015 08:54:08 -0700 Subject: [PATCH 1375/1783] :arrow_up: language-todo@0.22 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fb1f099bb..ef72e421c 100644 --- a/package.json +++ b/package.json @@ -155,7 +155,7 @@ "language-source": "0.9.0", "language-sql": "0.15.0", "language-text": "0.6.0", - "language-todo": "0.21.0", + "language-todo": "0.22.0", "language-toml": "0.16.0", "language-xml": "0.30.0", "language-yaml": "0.22.0" From 39e402d0c8a42270c5e05c98f0507516c733a76c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Machist=C3=A9=20N=2E=20Quintana?= Date: Fri, 22 May 2015 14:18:30 -0400 Subject: [PATCH 1376/1783] :fire: Remove space_operators rule --- coffeelint.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/coffeelint.json b/coffeelint.json index 6de95f1d7..624d927ad 100644 --- a/coffeelint.json +++ b/coffeelint.json @@ -28,9 +28,6 @@ "spaces": 0, "level": "error" }, - "space_operators": { - "level": "error" - }, "spacing_after_comma": { "level": "error" }, From 6666a25da7ab3aa877748b5490b256014ea974a7 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 22 May 2015 12:08:32 -0700 Subject: [PATCH 1377/1783] :arrow_up: text-buffer --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ef72e421c..f451e1bcd 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "space-pen": "3.8.2", "stacktrace-parser": "0.1.1", "temp": "0.8.1", - "text-buffer": "6.1.0", + "text-buffer": "6.1.1", "theorist": "^1.0.2", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", From b0dd7b974f60d3146b33a5581ee37a44f6d5e83d Mon Sep 17 00:00:00 2001 From: Mostafa Eweda Date: Fri, 22 May 2015 12:49:25 -0700 Subject: [PATCH 1378/1783] Fix integration tests --- src/window-event-handler.coffee | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/window-event-handler.coffee b/src/window-event-handler.coffee index aeeee279c..0855b27a1 100644 --- a/src/window-event-handler.coffee +++ b/src/window-event-handler.coffee @@ -5,6 +5,7 @@ ipc = require 'ipc' shell = require 'shell' {Subscriber} = require 'emissary' fs = require 'fs-plus' +url = require 'url' # Handles low-level events related to the window. module.exports = @@ -28,7 +29,8 @@ class WindowEventHandler else atom.project.addPath(pathToOpen) - if fs.isFileSync(pathToOpen) + {protocol} = url.parse(pathToOpen) + unless fs.isDirectorySync(pathToOpen) or protocol? atom.workspace?.open(pathToOpen, {initialLine, initialColumn}) return From ffd3d7a61f0696ee2c0d2723738cb58c968948fd Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Fri, 22 May 2015 16:07:07 -0400 Subject: [PATCH 1379/1783] Require 2 newlines after class definitions --- coffeelint.json | 1 + 1 file changed, 1 insertion(+) diff --git a/coffeelint.json b/coffeelint.json index 624d927ad..9ee65d6e5 100644 --- a/coffeelint.json +++ b/coffeelint.json @@ -35,6 +35,7 @@ "level": "error" }, "newlines_after_classes": { + "value": 2, "level": "error" } } From d5bcc0433d1501b8b2cb343bf6c3a4257ca712ce Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Fri, 22 May 2015 16:29:12 -0400 Subject: [PATCH 1380/1783] WIP: :shirt: Fix linter errors --- spec/display-buffer-spec.coffee | 6 +++--- spec/selection-spec.coffee | 12 ++++++------ spec/text-editor-element-spec.coffee | 2 +- spec/tokenized-buffer-spec.coffee | 20 ++++++++++---------- spec/workspace-spec.coffee | 2 +- src/browser/atom-application.coffee | 2 +- src/cursor.coffee | 6 +++--- 7 files changed, 25 insertions(+), 25 deletions(-) diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index be89db8ac..140ca2f9e 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -44,7 +44,7 @@ describe "DisplayBuffer", -> it "renders line numbers correctly", -> originalLineCount = displayBuffer.getLineCount() oneHundredLines = [0..100].join("\n") - buffer.insert([0,0], oneHundredLines) + buffer.insert([0, 0], oneHundredLines) expect(displayBuffer.getLineCount()).toBe 100 + originalLineCount it "reassigns the scrollTop if it exceeds the max possible value after lines are removed", -> @@ -382,10 +382,10 @@ describe "DisplayBuffer", -> describe "when creating a fold where one already exists", -> it "returns existing fold and does't create new fold", -> - fold = displayBuffer.createFold(0,10) + fold = displayBuffer.createFold(0, 10) expect(displayBuffer.findMarkers(class: 'fold').length).toBe 1 - newFold = displayBuffer.createFold(0,10) + newFold = displayBuffer.createFold(0, 10) expect(newFold).toBe fold expect(displayBuffer.findMarkers(class: 'fold').length).toBe 1 diff --git a/spec/selection-spec.coffee b/spec/selection-spec.coffee index 0e64b60fd..bdccb799d 100644 --- a/spec/selection-spec.coffee +++ b/spec/selection-spec.coffee @@ -14,18 +14,18 @@ describe "Selection", -> describe ".deleteSelectedText()", -> describe "when nothing is selected", -> it "deletes nothing", -> - selection.setBufferRange [[0,3], [0,3]] + selection.setBufferRange [[0, 3], [0, 3]] selection.deleteSelectedText() expect(buffer.lineForRow(0)).toBe "var quicksort = function () {" describe "when one line is selected", -> it "deletes selected text and clears the selection", -> - selection.setBufferRange [[0,4], [0,14]] + selection.setBufferRange [[0, 4], [0, 14]] selection.deleteSelectedText() expect(buffer.lineForRow(0)).toBe "var = function () {" endOfLine = buffer.lineForRow(0).length - selection.setBufferRange [[0,0], [0, endOfLine]] + selection.setBufferRange [[0, 0], [0, endOfLine]] selection.deleteSelectedText() expect(buffer.lineForRow(0)).toBe "" @@ -33,15 +33,15 @@ describe "Selection", -> describe "when multiple lines are selected", -> it "deletes selected text and clears the selection", -> - selection.setBufferRange [[0,1], [2,39]] + selection.setBufferRange [[0, 1], [2, 39]] selection.deleteSelectedText() expect(buffer.lineForRow(0)).toBe "v;" expect(selection.isEmpty()).toBeTruthy() describe "when the cursor precedes the tail", -> it "deletes selected text and clears the selection", -> - selection.cursor.setScreenPosition [0,13] - selection.selectToScreenPosition [0,4] + selection.cursor.setScreenPosition [0, 13] + selection.selectToScreenPosition [0, 4] selection.delete() expect(buffer.lineForRow(0)).toBe "var = function () {" diff --git a/spec/text-editor-element-spec.coffee b/spec/text-editor-element-spec.coffee index 435b3a4a5..ea5f55968 100644 --- a/spec/text-editor-element-spec.coffee +++ b/spec/text-editor-element-spec.coffee @@ -83,7 +83,7 @@ describe "TextEditorElement", -> editor = new TextEditor editor.setText('1\n2\n3') editor.addGutter({name: 'test-gutter'}) - marker = editor.markBufferRange([[0,0],[2,0]]) + marker = editor.markBufferRange([[0, 0], [2, 0]]) editor.decorateMarker(marker, {type: 'gutter', gutterName: 'test-gutter'}) element = atom.views.getView(editor) diff --git a/spec/tokenized-buffer-spec.coffee b/spec/tokenized-buffer-spec.coffee index 45cc03a44..9d94cb80a 100644 --- a/spec/tokenized-buffer-spec.coffee +++ b/spec/tokenized-buffer-spec.coffee @@ -287,7 +287,7 @@ describe "TokenizedBuffer", -> describe "when there is an insertion that is larger than the chunk size", -> it "tokenizes the initial chunk synchronously, then tokenizes the remaining lines in the background", -> commentBlock = _.multiplyString("// a comment\n", tokenizedBuffer.chunkSize + 2) - buffer.insert([0,0], commentBlock) + buffer.insert([0, 0], commentBlock) expect(tokenizedBuffer.tokenizedLineForRow(0).ruleStack?).toBeTruthy() expect(tokenizedBuffer.tokenizedLineForRow(4).ruleStack?).toBeTruthy() expect(tokenizedBuffer.tokenizedLineForRow(5).ruleStack?).toBeFalsy() @@ -541,7 +541,7 @@ describe "TokenizedBuffer", -> runs -> fullyTokenize(tokenizedBuffer) {tokens} = tokenizedBuffer.tokenizedLineForRow(0) - expect(tokens[0]).toEqual value: '<', scopes: ["text.html.ruby","meta.tag.block.any.html","punctuation.definition.tag.begin.html"] + expect(tokens[0]).toEqual value: '<', scopes: ["text.html.ruby", "meta.tag.block.any.html", "punctuation.definition.tag.begin.html"] describe ".tokenForPosition(position)", -> afterEach -> @@ -552,9 +552,9 @@ describe "TokenizedBuffer", -> buffer = atom.project.bufferForPathSync('sample.js') tokenizedBuffer = new TokenizedBuffer({buffer}) fullyTokenize(tokenizedBuffer) - expect(tokenizedBuffer.tokenForPosition([1,0]).scopes).toEqual ["source.js"] - expect(tokenizedBuffer.tokenForPosition([1,1]).scopes).toEqual ["source.js"] - expect(tokenizedBuffer.tokenForPosition([1,2]).scopes).toEqual ["source.js", "storage.modifier.js"] + expect(tokenizedBuffer.tokenForPosition([1, 0]).scopes).toEqual ["source.js"] + expect(tokenizedBuffer.tokenForPosition([1, 1]).scopes).toEqual ["source.js"] + expect(tokenizedBuffer.tokenForPosition([1, 2]).scopes).toEqual ["source.js", "storage.modifier.js"] describe ".bufferRangeForScopeAtPosition(selector, position)", -> beforeEach -> @@ -580,20 +580,20 @@ describe "TokenizedBuffer", -> buffer.setText('\ttest') tokenizedBuffer = new TokenizedBuffer({buffer}) fullyTokenize(tokenizedBuffer) - expect(tokenizedBuffer.tokenForPosition([0,0]).value).toBe ' ' + expect(tokenizedBuffer.tokenForPosition([0, 0]).value).toBe ' ' atom.config.set('editor.tabLength', 6) - expect(tokenizedBuffer.tokenForPosition([0,0]).value).toBe ' ' + expect(tokenizedBuffer.tokenForPosition([0, 0]).value).toBe ' ' it "does not allow the tab length to be less than 1", -> buffer = atom.project.bufferForPathSync('sample.js') buffer.setText('\ttest') tokenizedBuffer = new TokenizedBuffer({buffer}) fullyTokenize(tokenizedBuffer) - expect(tokenizedBuffer.tokenForPosition([0,0]).value).toBe ' ' + expect(tokenizedBuffer.tokenForPosition([0, 0]).value).toBe ' ' atom.config.set('editor.tabLength', 1) - expect(tokenizedBuffer.tokenForPosition([0,0]).value).toBe ' ' + expect(tokenizedBuffer.tokenForPosition([0, 0]).value).toBe ' ' atom.config.set('editor.tabLength', 0) - expect(tokenizedBuffer.tokenForPosition([0,0]).value).toBe ' ' + expect(tokenizedBuffer.tokenForPosition([0, 0]).value).toBe ' ' describe "when the invisibles value changes", -> beforeEach -> diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index 0b32ff31f..009f95a1c 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -1027,7 +1027,7 @@ describe "Workspace", -> atom.project.open('sample.js').then (o) -> editor = o runs -> - editor.buffer.setTextInRange([[0,0],[0,0]], 'omg') + editor.buffer.setTextInRange([[0, 0], [0, 0]], 'omg') expect(editor.isModified()).toBeTruthy() waitsForPromise -> diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index d81660a49..1b2aa2e86 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -174,7 +174,7 @@ class AtomApplication @on 'application:open-safe', -> @promptForPathToOpen('all', safeMode: true) @on 'application:open-api-preview', -> @promptForPathToOpen('all', apiPreviewMode: true) @on 'application:open-dev-api-preview', -> @promptForPathToOpen('all', {apiPreviewMode: true, devMode: true}) - @on 'application:inspect', ({x,y, atomWindow}) -> + @on 'application:inspect', ({x, y, atomWindow}) -> atomWindow ?= @focusedWindow() atomWindow?.browserWindow.inspectElement(x, y) diff --git a/src/cursor.coffee b/src/cursor.coffee index b54cc6bcd..0681e51ca 100644 --- a/src/cursor.coffee +++ b/src/cursor.coffee @@ -333,7 +333,7 @@ class Cursor extends Model # Public: Moves the cursor to the top of the buffer. moveToTop: -> - @setBufferPosition([0,0]) + @setBufferPosition([0, 0]) # Public: Moves the cursor to the bottom of the buffer. moveToBottom: -> @@ -673,9 +673,9 @@ class Cursor extends Model start = @getBufferPosition() {row, column} = start - scanRange = [[row-1, column], [0,0]] + scanRange = [[row-1, column], [0, 0]] position = new Point(0, 0) - zero = new Point(0,0) + zero = new Point(0, 0) @editor.backwardsScanInBufferRange /^\n*$/g, scanRange, ({range, stop}) -> unless range.start.isEqual(zero) position = range.start From 10d5229b806db975084048851d2c75cd7139616f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 22 May 2015 13:49:48 -0700 Subject: [PATCH 1381/1783] :arrow_up: language-css@0.30 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f451e1bcd..efffa073e 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,7 @@ "language-clojure": "0.15.0", "language-coffee-script": "0.40.0", "language-csharp": "0.5.0", - "language-css": "0.29.0", + "language-css": "0.30.0", "language-gfm": "0.76.0", "language-git": "0.10.0", "language-go": "0.26.0", From 52beb9a2413811cbd8cee63960f6be4940937498 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 22 May 2015 13:51:08 -0700 Subject: [PATCH 1382/1783] :arrow_up: wrap-guide@0.34 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index efffa073e..9abb93abd 100644 --- a/package.json +++ b/package.json @@ -126,7 +126,7 @@ "update-package-dependencies": "0.10.0", "welcome": "0.27.0", "whitespace": "0.29.0", - "wrap-guide": "0.33.0", + "wrap-guide": "0.34.0", "language-c": "0.44.0", "language-clojure": "0.15.0", "language-coffee-script": "0.40.0", From ec5b807056ae10a43d0853f21d9d0ae24417ac11 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 22 May 2015 13:55:58 -0700 Subject: [PATCH 1383/1783] :arrow_up: text-buffer --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9abb93abd..b22bee26e 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "space-pen": "3.8.2", "stacktrace-parser": "0.1.1", "temp": "0.8.1", - "text-buffer": "6.1.1", + "text-buffer": "6.1.2", "theorist": "^1.0.2", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", From 82958d5aa09cc346ee26a430cf2c6f9526731d24 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Fri, 22 May 2015 17:03:06 -0400 Subject: [PATCH 1384/1783] WIP: :shirt: Fix even more linter errors --- spec/language-mode-spec.coffee | 20 ++++++------ spec/text-editor-presenter-spec.coffee | 12 ++++---- spec/text-editor-spec.coffee | 42 +++++++++++++------------- 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/spec/language-mode-spec.coffee b/spec/language-mode-spec.coffee index 47fa30bdf..9c4fc2c1e 100644 --- a/spec/language-mode-spec.coffee +++ b/spec/language-mode-spec.coffee @@ -134,23 +134,23 @@ describe "LanguageMode", -> it "will limit paragraph range to comments", -> range = languageMode.rowRangeForParagraphAtBufferRow(0) - expect(range).toEqual [[0,0], [0,29]] + expect(range).toEqual [[0, 0], [0, 29]] range = languageMode.rowRangeForParagraphAtBufferRow(10) - expect(range).toEqual [[10,0], [10,14]] + expect(range).toEqual [[10, 0], [10, 14]] range = languageMode.rowRangeForParagraphAtBufferRow(11) expect(range).toBeFalsy() range = languageMode.rowRangeForParagraphAtBufferRow(12) - expect(range).toEqual [[12,0], [13,10]] + expect(range).toEqual [[12, 0], [13, 10]] range = languageMode.rowRangeForParagraphAtBufferRow(14) - expect(range).toEqual [[14,0], [14,32]] + expect(range).toEqual [[14, 0], [14, 32]] range = languageMode.rowRangeForParagraphAtBufferRow(15) - expect(range).toEqual [[15,0], [15,26]] + expect(range).toEqual [[15, 0], [15, 26]] range = languageMode.rowRangeForParagraphAtBufferRow(18) - expect(range).toEqual [[17,0], [19,3]] + expect(range).toEqual [[17, 0], [19, 3]] describe "coffeescript", -> beforeEach -> @@ -305,9 +305,9 @@ describe "LanguageMode", -> atom.packages.unloadPackages() it "maintains cursor buffer position when a folding/unfolding", -> - editor.setCursorBufferPosition([5,5]) + editor.setCursorBufferPosition([5, 5]) languageMode.foldAll() - expect(editor.getCursorBufferPosition()).toEqual([5,5]) + expect(editor.getCursorBufferPosition()).toEqual([5, 5]) describe ".unfoldAll()", -> it "unfolds every folded line", -> @@ -359,7 +359,7 @@ describe "LanguageMode", -> describe "when the bufferRow is in a multi-line comment", -> it "searches upward and downward for surrounding comment lines and folds them as a single fold", -> - buffer.insert([1,0], " //this is a comment\n // and\n //more docs\n\n//second comment") + buffer.insert([1, 0], " //this is a comment\n // and\n //more docs\n\n//second comment") languageMode.foldBufferRow(1) fold = editor.tokenizedLineForScreenRow(1).fold expect(fold.getStartRow()).toBe 1 @@ -367,7 +367,7 @@ describe "LanguageMode", -> describe "when the bufferRow is a single-line comment", -> it "searches upward for the first row that begins a syntatic region containing the folded row (and folds it)", -> - buffer.insert([1,0], " //this is a single line comment\n") + buffer.insert([1, 0], " //this is a single line comment\n") languageMode.foldBufferRow(1) fold = editor.tokenizedLineForScreenRow(0).fold expect(fold.getStartRow()).toBe 0 diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index d15c4759d..1ad18da5a 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -2227,11 +2227,11 @@ describe "TextEditorPresenter", -> gutterName: 'test-gutter' class: 'test-class' item: decorationItem - marker1 = editor.markBufferRange([[0,0],[1,0]]) + marker1 = editor.markBufferRange([[0, 0], [1, 0]]) decoration1 = editor.decorateMarker(marker1, decorationParams) - marker2 = editor.markBufferRange([[9,0],[12,0]]) + marker2 = editor.markBufferRange([[9, 0], [12, 0]]) decoration2 = editor.decorateMarker(marker2, decorationParams) - marker3 = editor.markBufferRange([[13,0],[14,0]]) + marker3 = editor.markBufferRange([[13, 0], [14, 0]]) decoration3 = editor.decorateMarker(marker3, decorationParams) # Clear any batched state updates. @@ -2280,7 +2280,7 @@ describe "TextEditorPresenter", -> it "updates when the editor's content changes", -> # This update will add enough lines to push decoration2 out of view. - expectStateUpdate presenter, -> editor.setTextInBufferRange([[8,0],[9,0]],'\n\n\n\n\n') + expectStateUpdate presenter, -> editor.setTextInBufferRange([[8, 0], [9, 0]], '\n\n\n\n\n') decorationState = getContentForGutterWithName(presenter, 'test-gutter') expect(decorationState[decoration1.id].top).toBeDefined() @@ -2290,7 +2290,7 @@ describe "TextEditorPresenter", -> it "updates when a decoration's marker is modified", -> # This update will move decoration1 out of view. expectStateUpdate presenter, -> - newRange = new Range([13,0],[14,0]) + newRange = new Range([13, 0], [14, 0]) marker1.setBufferRange(newRange) decorationState = getContentForGutterWithName(presenter, 'test-gutter') @@ -2401,7 +2401,7 @@ describe "TextEditorPresenter", -> type: 'gutter' gutterName: 'test-gutter-2' class: 'test-class' - marker4 = editor.markBufferRange([[0,0],[1,0]]) + marker4 = editor.markBufferRange([[0, 0], [1, 0]]) decoration4 = editor.decorateMarker(marker4, decorationParams) expectStateUpdate presenter, -> editor.addGutter({name: 'test-gutter-2'}) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index a845619ba..bf675fdf9 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -227,7 +227,7 @@ describe "TextEditor", -> describe "when the cursor moves", -> it "clears a goal column established by vertical movement", -> editor.setText('b') - editor.setCursorBufferPosition([0,0]) + editor.setCursorBufferPosition([0, 0]) editor.insertNewline() editor.moveUp() editor.insertText('a') @@ -262,7 +262,7 @@ describe "TextEditor", -> expect(editor.getCursorScreenPosition().column).not.toBe 6 # clear the goal column by explicitly setting the cursor position - editor.setCursorScreenPosition([4,6]) + editor.setCursorScreenPosition([4, 6]) expect(editor.getCursorScreenPosition().column).toBe 6 editor.moveDown() @@ -317,7 +317,7 @@ describe "TextEditor", -> describe "when there is a selection", -> beforeEach -> - editor.setSelectedBufferRange([[4, 9],[5, 10]]) + editor.setSelectedBufferRange([[4, 9], [5, 10]]) it "moves above the selection", -> cursor = editor.getLastCursor() @@ -330,7 +330,7 @@ describe "TextEditor", -> editor.moveUp() expect(editor.getCursors()).toEqual [cursor1] - expect(cursor1.getBufferPosition()).toEqual [0,0] + expect(cursor1.getBufferPosition()).toEqual [0, 0] describe "when the cursor was moved down from the beginning of an indented soft-wrapped line", -> it "moves to the beginning of the previous line", -> @@ -396,7 +396,7 @@ describe "TextEditor", -> describe "when there is a selection", -> beforeEach -> - editor.setSelectedBufferRange([[4, 9],[5, 10]]) + editor.setSelectedBufferRange([[4, 9], [5, 10]]) it "moves below the selection", -> cursor = editor.getLastCursor() @@ -410,7 +410,7 @@ describe "TextEditor", -> editor.moveDown() expect(editor.getCursors()).toEqual [cursor1] - expect(cursor1.getBufferPosition()).toEqual [12,2] + expect(cursor1.getBufferPosition()).toEqual [12, 2] describe ".moveLeft()", -> it "moves the cursor by one column to the left", -> @@ -481,7 +481,7 @@ describe "TextEditor", -> describe "when there is a selection", -> beforeEach -> - editor.setSelectedBufferRange([[5, 22],[5, 27]]) + editor.setSelectedBufferRange([[5, 22], [5, 27]]) it "moves to the left of the selection", -> cursor = editor.getLastCursor() @@ -498,7 +498,7 @@ describe "TextEditor", -> [cursor1, cursor2] = editor.getCursors() editor.moveLeft() expect(editor.getCursors()).toEqual [cursor1] - expect(cursor1.getBufferPosition()).toEqual [0,0] + expect(cursor1.getBufferPosition()).toEqual [0, 0] describe ".moveRight()", -> it "moves the cursor by one column to the right", -> @@ -578,15 +578,15 @@ describe "TextEditor", -> editor.addCursorAtScreenPosition [12,0] editor.moveToTop() expect(editor.getCursors().length).toBe 1 - expect(editor.getCursorBufferPosition()).toEqual [0,0] + expect(editor.getCursorBufferPosition()).toEqual [0, 0] describe ".moveToBottom()", -> it "moves the cusor to the bottom of the buffer", -> - editor.setCursorScreenPosition [0,0] - editor.addCursorAtScreenPosition [1,0] + editor.setCursorScreenPosition [0, 0] + editor.addCursorAtScreenPosition [1, 0] editor.moveToBottom() expect(editor.getCursors().length).toBe 1 - expect(editor.getCursorBufferPosition()).toEqual [12,2] + expect(editor.getCursorBufferPosition()).toEqual [12, 2] describe ".moveToBeginningOfScreenLine()", -> describe "when soft wrap is on", -> @@ -599,14 +599,14 @@ describe "TextEditor", -> expect(cursor.getScreenPosition()).toEqual [1, 0] describe "when soft wrap is off", -> - it "moves cursor to the beginning of then line", -> - editor.setCursorScreenPosition [0,5] - editor.addCursorAtScreenPosition [1,7] + it "moves cursor to the beginning of the line", -> + editor.setCursorScreenPosition [0, 5] + editor.addCursorAtScreenPosition [1, 7] editor.moveToBeginningOfScreenLine() expect(editor.getCursors().length).toBe 2 [cursor1, cursor2] = editor.getCursors() - expect(cursor1.getBufferPosition()).toEqual [0,0] - expect(cursor2.getBufferPosition()).toEqual [1,0] + expect(cursor1.getBufferPosition()).toEqual [0, 0] + expect(cursor2.getBufferPosition()).toEqual [1, 0] describe ".moveToEndOfScreenLine()", -> describe "when soft wrap is on", -> @@ -620,13 +620,13 @@ describe "TextEditor", -> describe "when soft wrap is off", -> it "moves cursor to the end of line", -> - editor.setCursorScreenPosition [0,0] - editor.addCursorAtScreenPosition [1,0] + editor.setCursorScreenPosition [0, 0] + editor.addCursorAtScreenPosition [1, 0] editor.moveToEndOfScreenLine() expect(editor.getCursors().length).toBe 2 [cursor1, cursor2] = editor.getCursors() - expect(cursor1.getBufferPosition()).toEqual [0,29] - expect(cursor2.getBufferPosition()).toEqual [1,30] + expect(cursor1.getBufferPosition()).toEqual [0, 29] + expect(cursor2.getBufferPosition()).toEqual [1, 30] describe ".moveToBeginningOfLine()", -> it "moves cursor to the beginning of the buffer line", -> From 93eeda1ccc8a14048c5df2f1cbd6fa430bcc0798 Mon Sep 17 00:00:00 2001 From: Thomas Johansen Date: Fri, 22 May 2015 23:29:40 +0200 Subject: [PATCH 1385/1783] :memo: Document command name standard Resolves #6893 --- src/command-registry.coffee | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/command-registry.coffee b/src/command-registry.coffee index 3969dc283..9764af027 100644 --- a/src/command-registry.coffee +++ b/src/command-registry.coffee @@ -18,6 +18,11 @@ SequenceCount = 0 # command event listeners globally on `atom.commands` and constrain them to # specific kinds of elements with CSS selectors. # +# Command names must follow the `namespace:event` pattern, where both parts can +# be further split into words by hyphens. Typically `namespace` will be the +# name of your package, and `event` the name of your command. +# E.g. `awesome-package:toggle`. +# # As the event bubbles upward through the DOM, all registered event listeners # with matching selectors are invoked in order of specificity. In the event of a # specificity tie, the most recently registered listener is invoked first. This From dfd365cf51acd11958dd166c54ddffe9e83045a4 Mon Sep 17 00:00:00 2001 From: Thomas Johansen Date: Fri, 22 May 2015 23:42:23 +0200 Subject: [PATCH 1386/1783] :memo: Rephrase the description of `event` --- src/command-registry.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/command-registry.coffee b/src/command-registry.coffee index 9764af027..ebf0f50fe 100644 --- a/src/command-registry.coffee +++ b/src/command-registry.coffee @@ -20,7 +20,7 @@ SequenceCount = 0 # # Command names must follow the `namespace:event` pattern, where both parts can # be further split into words by hyphens. Typically `namespace` will be the -# name of your package, and `event` the name of your command. +# name of your package, and `event` describes the behavior of your command. # E.g. `awesome-package:toggle`. # # As the event bubbles upward through the DOM, all registered event listeners From b4ff2e15d19eb0b1fd3864b94bec74f5c9cb7026 Mon Sep 17 00:00:00 2001 From: Thomas Johansen Date: Sat, 23 May 2015 00:03:01 +0200 Subject: [PATCH 1387/1783] :memo: Stronger wording, and change `event` to `action` --- src/command-registry.coffee | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/command-registry.coffee b/src/command-registry.coffee index ebf0f50fe..2de076d1a 100644 --- a/src/command-registry.coffee +++ b/src/command-registry.coffee @@ -18,10 +18,10 @@ SequenceCount = 0 # command event listeners globally on `atom.commands` and constrain them to # specific kinds of elements with CSS selectors. # -# Command names must follow the `namespace:event` pattern, where both parts can -# be further split into words by hyphens. Typically `namespace` will be the -# name of your package, and `event` describes the behavior of your command. -# E.g. `awesome-package:toggle`. +# Command names must follow the `namespace:action` pattern, where `namespace` +# will typically be the name of your package, and `action` describes the +# behavior of your command. If either part consists of multiple words, these +# must be separated by hyphens. E.g. `awesome-package:turn-it-up-to-eleven`. # # As the event bubbles upward through the DOM, all registered event listeners # with matching selectors are invoked in order of specificity. In the event of a From 8ca1cf2c9821c7cdf6ae4ae7eb930c63908b566c Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Fri, 22 May 2015 19:50:04 -0400 Subject: [PATCH 1388/1783] :shirt: Fix linter errors in text-editor-spec --- spec/text-editor-spec.coffee | 356 +++++++++++++++++------------------ 1 file changed, 178 insertions(+), 178 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index bf675fdf9..28dbaaff8 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -553,7 +553,7 @@ describe "TextEditor", -> describe "when there is a selection", -> beforeEach -> - editor.setSelectedBufferRange([[5, 22],[5, 27]]) + editor.setSelectedBufferRange([[5, 22], [5, 27]]) it "moves to the left of the selection", -> cursor = editor.getLastCursor() @@ -570,12 +570,12 @@ describe "TextEditor", -> editor.moveRight() expect(editor.getCursors()).toEqual [cursor1] - expect(cursor1.getBufferPosition()).toEqual [12,2] + expect(cursor1.getBufferPosition()).toEqual [12, 2] describe ".moveToTop()", -> it "moves the cursor to the top of the buffer", -> - editor.setCursorScreenPosition [11,1] - editor.addCursorAtScreenPosition [12,0] + editor.setCursorScreenPosition [11, 1] + editor.addCursorAtScreenPosition [12, 0] editor.moveToTop() expect(editor.getCursors().length).toBe 1 expect(editor.getCursorBufferPosition()).toEqual [0, 0] @@ -651,58 +651,58 @@ describe "TextEditor", -> it "moves to the first character of the current screen line or the beginning of the screen line if it's already on the first character", -> editor.setSoftWrapped(true) editor.setEditorWidthInChars(10) - editor.setCursorScreenPosition [2,5] - editor.addCursorAtScreenPosition [8,7] + editor.setCursorScreenPosition [2, 5] + editor.addCursorAtScreenPosition [8, 7] editor.moveToFirstCharacterOfLine() [cursor1, cursor2] = editor.getCursors() - expect(cursor1.getScreenPosition()).toEqual [2,0] - expect(cursor2.getScreenPosition()).toEqual [8,2] + expect(cursor1.getScreenPosition()).toEqual [2, 0] + expect(cursor2.getScreenPosition()).toEqual [8, 2] editor.moveToFirstCharacterOfLine() - expect(cursor1.getScreenPosition()).toEqual [2,0] - expect(cursor2.getScreenPosition()).toEqual [8,2] + expect(cursor1.getScreenPosition()).toEqual [2, 0] + expect(cursor2.getScreenPosition()).toEqual [8, 2] describe "when soft wrap is off", -> it "moves to the first character of the current line or the beginning of the line if it's already on the first character", -> - editor.setCursorScreenPosition [0,5] - editor.addCursorAtScreenPosition [1,7] + editor.setCursorScreenPosition [0, 5] + editor.addCursorAtScreenPosition [1, 7] editor.moveToFirstCharacterOfLine() [cursor1, cursor2] = editor.getCursors() - expect(cursor1.getBufferPosition()).toEqual [0,0] - expect(cursor2.getBufferPosition()).toEqual [1,2] + expect(cursor1.getBufferPosition()).toEqual [0, 0] + expect(cursor2.getBufferPosition()).toEqual [1, 2] editor.moveToFirstCharacterOfLine() - expect(cursor1.getBufferPosition()).toEqual [0,0] - expect(cursor2.getBufferPosition()).toEqual [1,0] + expect(cursor1.getBufferPosition()).toEqual [0, 0] + expect(cursor2.getBufferPosition()).toEqual [1, 0] it "moves to the beginning of the line if it only contains whitespace ", -> editor.setText("first\n \nthird") - editor.setCursorScreenPosition [1,2] + editor.setCursorScreenPosition [1, 2] editor.moveToFirstCharacterOfLine() cursor = editor.getLastCursor() - expect(cursor.getBufferPosition()).toEqual [1,0] + expect(cursor.getBufferPosition()).toEqual [1, 0] describe "when invisible characters are enabled with soft tabs", -> it "moves to the first character of the current line without being confused by the invisible characters", -> atom.config.set('editor.showInvisibles', true) - editor.setCursorScreenPosition [1,7] + editor.setCursorScreenPosition [1, 7] editor.moveToFirstCharacterOfLine() - expect(editor.getCursorBufferPosition()).toEqual [1,2] + expect(editor.getCursorBufferPosition()).toEqual [1, 2] editor.moveToFirstCharacterOfLine() - expect(editor.getCursorBufferPosition()).toEqual [1,0] + expect(editor.getCursorBufferPosition()).toEqual [1, 0] describe "when invisible characters are enabled with hard tabs", -> it "moves to the first character of the current line without being confused by the invisible characters", -> atom.config.set('editor.showInvisibles', true) buffer.setTextInRange([[1, 0], [1, Infinity]], '\t\t\ta', normalizeLineEndings: false) - editor.setCursorScreenPosition [1,7] + editor.setCursorScreenPosition [1, 7] editor.moveToFirstCharacterOfLine() - expect(editor.getCursorBufferPosition()).toEqual [1,3] + expect(editor.getCursorBufferPosition()).toEqual [1, 3] editor.moveToFirstCharacterOfLine() - expect(editor.getCursorBufferPosition()).toEqual [1,0] + expect(editor.getCursorBufferPosition()).toEqual [1, 0] describe ".moveToBeginningOfWord()", -> it "moves the cursor to the beginning of the word", -> @@ -792,9 +792,9 @@ describe "TextEditor", -> describe ".moveToBeginningOfNextWord()", -> it "moves the cursor before the first character of the next word", -> - editor.setCursorBufferPosition [0,6] - editor.addCursorAtBufferPosition [1,11] - editor.addCursorAtBufferPosition [2,0] + editor.setCursorBufferPosition [0, 6] + editor.addCursorAtBufferPosition [1, 11] + editor.addCursorAtBufferPosition [2, 0] [cursor1, cursor2, cursor3] = editor.getCursors() editor.moveToBeginningOfNextWord() @@ -805,7 +805,7 @@ describe "TextEditor", -> # When the cursor is on whitespace editor.setText("ab cde- ") - editor.setCursorBufferPosition [0,2] + editor.setCursorBufferPosition [0, 2] cursor = editor.getLastCursor() editor.moveToBeginningOfNextWord() @@ -900,15 +900,15 @@ describe "TextEditor", -> describe "addCursorAtScreenPosition(screenPosition)", -> describe "when a cursor already exists at the position", -> it "returns the existing cursor", -> - cursor1 = editor.addCursorAtScreenPosition([0,2]) - cursor2 = editor.addCursorAtScreenPosition([0,2]) + cursor1 = editor.addCursorAtScreenPosition([0, 2]) + cursor2 = editor.addCursorAtScreenPosition([0, 2]) expect(cursor2.marker).toBe cursor1.marker describe "addCursorAtBufferPosition(bufferPosition)", -> describe "when a cursor already exists at the position", -> it "returns the existing cursor", -> - cursor1 = editor.addCursorAtBufferPosition([1,4]) - cursor2 = editor.addCursorAtBufferPosition([1,4]) + cursor1 = editor.addCursorAtBufferPosition([1, 4]) + cursor2 = editor.addCursorAtBufferPosition([1, 4]) expect(cursor2.marker).toBe cursor1.marker describe "autoscroll", -> @@ -1056,28 +1056,28 @@ describe "TextEditor", -> describe ".selectUp/Down/Left/Right()", -> it "expands each selection to its cursor's new location", -> - editor.setSelectedBufferRanges([[[0,9], [0,13]], [[3,16], [3,21]]]) + editor.setSelectedBufferRanges([[[0, 9], [0, 13]], [[3, 16], [3, 21]]]) [selection1, selection2] = editor.getSelections() editor.selectRight() - expect(selection1.getBufferRange()).toEqual [[0,9], [0,14]] - expect(selection2.getBufferRange()).toEqual [[3,16], [3,22]] + expect(selection1.getBufferRange()).toEqual [[0, 9], [0, 14]] + expect(selection2.getBufferRange()).toEqual [[3, 16], [3, 22]] editor.selectLeft() editor.selectLeft() - expect(selection1.getBufferRange()).toEqual [[0,9], [0,12]] - expect(selection2.getBufferRange()).toEqual [[3,16], [3,20]] + expect(selection1.getBufferRange()).toEqual [[0, 9], [0, 12]] + expect(selection2.getBufferRange()).toEqual [[3, 16], [3, 20]] editor.selectDown() - expect(selection1.getBufferRange()).toEqual [[0,9], [1,12]] - expect(selection2.getBufferRange()).toEqual [[3,16], [4,20]] + expect(selection1.getBufferRange()).toEqual [[0, 9], [1, 12]] + expect(selection2.getBufferRange()).toEqual [[3, 16], [4, 20]] editor.selectUp() - expect(selection1.getBufferRange()).toEqual [[0,9], [0,12]] - expect(selection2.getBufferRange()).toEqual [[3,16], [3,20]] + expect(selection1.getBufferRange()).toEqual [[0, 9], [0, 12]] + expect(selection2.getBufferRange()).toEqual [[3, 16], [3, 20]] it "merges selections when they intersect when moving down", -> - editor.setSelectedBufferRanges([[[0,9], [0,13]], [[1,10], [1,20]], [[2,15], [3,25]]]) + editor.setSelectedBufferRanges([[[0, 9], [0, 13]], [[1, 10], [1, 20]], [[2, 15], [3, 25]]]) [selection1, selection2, selection3] = editor.getSelections() editor.selectDown() @@ -1086,7 +1086,7 @@ describe "TextEditor", -> expect(selection1.isReversed()).toBeFalsy() it "merges selections when they intersect when moving up", -> - editor.setSelectedBufferRanges([[[0,9], [0,13]], [[1,10], [1,20]]], reversed: true) + editor.setSelectedBufferRanges([[[0, 9], [0, 13]], [[1, 10], [1, 20]]], reversed: true) [selection1, selection2] = editor.getSelections() editor.selectUp() @@ -1096,7 +1096,7 @@ describe "TextEditor", -> expect(selection1.isReversed()).toBeTruthy() it "merges selections when they intersect when moving left", -> - editor.setSelectedBufferRanges([[[0,9], [0,13]], [[0,13], [1,20]]], reversed: true) + editor.setSelectedBufferRanges([[[0, 9], [0, 13]], [[0, 13], [1, 20]]], reversed: true) [selection1, selection2] = editor.getSelections() editor.selectLeft() @@ -1105,7 +1105,7 @@ describe "TextEditor", -> expect(selection1.isReversed()).toBeTruthy() it "merges selections when they intersect when moving right", -> - editor.setSelectedBufferRanges([[[0,9], [0,14]], [[0,14], [1,20]]]) + editor.setSelectedBufferRanges([[[0, 9], [0, 14]], [[0, 14], [1, 20]]]) [selection1, selection2] = editor.getSelections() editor.selectRight() @@ -1115,24 +1115,24 @@ describe "TextEditor", -> describe "when counts are passed into the selection functions", -> it "expands each selection to its cursor's new location", -> - editor.setSelectedBufferRanges([[[0,9], [0,13]], [[3,16], [3,21]]]) + editor.setSelectedBufferRanges([[[0, 9], [0, 13]], [[3, 16], [3, 21]]]) [selection1, selection2] = editor.getSelections() editor.selectRight(2) - expect(selection1.getBufferRange()).toEqual [[0,9], [0,15]] - expect(selection2.getBufferRange()).toEqual [[3,16], [3,23]] + expect(selection1.getBufferRange()).toEqual [[0, 9], [0, 15]] + expect(selection2.getBufferRange()).toEqual [[3, 16], [3, 23]] editor.selectLeft(3) - expect(selection1.getBufferRange()).toEqual [[0,9], [0,12]] - expect(selection2.getBufferRange()).toEqual [[3,16], [3,20]] + expect(selection1.getBufferRange()).toEqual [[0, 9], [0, 12]] + expect(selection2.getBufferRange()).toEqual [[3, 16], [3, 20]] editor.selectDown(3) - expect(selection1.getBufferRange()).toEqual [[0,9], [3,12]] - expect(selection2.getBufferRange()).toEqual [[3,16], [6,20]] + expect(selection1.getBufferRange()).toEqual [[0, 9], [3, 12]] + expect(selection2.getBufferRange()).toEqual [[3, 16], [6, 20]] editor.selectUp(2) - expect(selection1.getBufferRange()).toEqual [[0,9], [1,12]] - expect(selection2.getBufferRange()).toEqual [[3,16], [4,20]] + expect(selection1.getBufferRange()).toEqual [[0, 9], [1, 12]] + expect(selection2.getBufferRange()).toEqual [[3, 16], [4, 20]] describe ".selectToBufferPosition(bufferPosition)", -> it "expands the last selection to the given position", -> @@ -1205,22 +1205,22 @@ describe "TextEditor", -> describe ".selectToTop()", -> it "selects text from cusor position to the top of the buffer", -> - editor.setCursorScreenPosition [11,2] - editor.addCursorAtScreenPosition [10,0] + editor.setCursorScreenPosition [11, 2] + editor.addCursorAtScreenPosition [10, 0] editor.selectToTop() expect(editor.getCursors().length).toBe 1 - expect(editor.getCursorBufferPosition()).toEqual [0,0] - expect(editor.getLastSelection().getBufferRange()).toEqual [[0,0], [11,2]] + expect(editor.getCursorBufferPosition()).toEqual [0, 0] + expect(editor.getLastSelection().getBufferRange()).toEqual [[0, 0], [11, 2]] expect(editor.getLastSelection().isReversed()).toBeTruthy() describe ".selectToBottom()", -> it "selects text from cusor position to the bottom of the buffer", -> - editor.setCursorScreenPosition [10,0] - editor.addCursorAtScreenPosition [9,3] + editor.setCursorScreenPosition [10, 0] + editor.addCursorAtScreenPosition [9, 3] editor.selectToBottom() expect(editor.getCursors().length).toBe 1 - expect(editor.getCursorBufferPosition()).toEqual [12,2] - expect(editor.getLastSelection().getBufferRange()).toEqual [[9,3], [12,2]] + expect(editor.getCursorBufferPosition()).toEqual [12, 2] + expect(editor.getLastSelection().getBufferRange()).toEqual [[9, 3], [12, 2]] expect(editor.getLastSelection().isReversed()).toBeFalsy() describe ".selectAll()", -> @@ -1230,57 +1230,57 @@ describe "TextEditor", -> describe ".selectToBeginningOfLine()", -> it "selects text from cusor position to beginning of line", -> - editor.setCursorScreenPosition [12,2] - editor.addCursorAtScreenPosition [11,3] + editor.setCursorScreenPosition [12, 2] + editor.addCursorAtScreenPosition [11, 3] editor.selectToBeginningOfLine() expect(editor.getCursors().length).toBe 2 [cursor1, cursor2] = editor.getCursors() - expect(cursor1.getBufferPosition()).toEqual [12,0] - expect(cursor2.getBufferPosition()).toEqual [11,0] + expect(cursor1.getBufferPosition()).toEqual [12, 0] + expect(cursor2.getBufferPosition()).toEqual [11, 0] expect(editor.getSelections().length).toBe 2 [selection1, selection2] = editor.getSelections() - expect(selection1.getBufferRange()).toEqual [[12,0], [12,2]] + expect(selection1.getBufferRange()).toEqual [[12, 0], [12, 2]] expect(selection1.isReversed()).toBeTruthy() - expect(selection2.getBufferRange()).toEqual [[11,0], [11,3]] + expect(selection2.getBufferRange()).toEqual [[11, 0], [11, 3]] expect(selection2.isReversed()).toBeTruthy() describe ".selectToEndOfLine()", -> it "selects text from cusor position to end of line", -> - editor.setCursorScreenPosition [12,0] - editor.addCursorAtScreenPosition [11,3] + editor.setCursorScreenPosition [12, 0] + editor.addCursorAtScreenPosition [11, 3] editor.selectToEndOfLine() expect(editor.getCursors().length).toBe 2 [cursor1, cursor2] = editor.getCursors() - expect(cursor1.getBufferPosition()).toEqual [12,2] - expect(cursor2.getBufferPosition()).toEqual [11,44] + expect(cursor1.getBufferPosition()).toEqual [12, 2] + expect(cursor2.getBufferPosition()).toEqual [11, 44] expect(editor.getSelections().length).toBe 2 [selection1, selection2] = editor.getSelections() - expect(selection1.getBufferRange()).toEqual [[12,0], [12,2]] + expect(selection1.getBufferRange()).toEqual [[12, 0], [12, 2]] expect(selection1.isReversed()).toBeFalsy() - expect(selection2.getBufferRange()).toEqual [[11,3], [11,44]] + expect(selection2.getBufferRange()).toEqual [[11, 3], [11, 44]] expect(selection2.isReversed()).toBeFalsy() describe ".selectLinesContainingCursors()", -> it "selects the entire line (including newlines) at given row", -> editor.setCursorScreenPosition([1, 2]) editor.selectLinesContainingCursors() - expect(editor.getSelectedBufferRange()).toEqual [[1,0], [2,0]] + expect(editor.getSelectedBufferRange()).toEqual [[1, 0], [2, 0]] expect(editor.getSelectedText()).toBe " var sort = function(items) {\n" editor.setCursorScreenPosition([12, 2]) editor.selectLinesContainingCursors() - expect(editor.getSelectedBufferRange()).toEqual [[12,0], [12,2]] + expect(editor.getSelectedBufferRange()).toEqual [[12, 0], [12, 2]] editor.setCursorBufferPosition([0, 2]) editor.selectLinesContainingCursors() editor.selectLinesContainingCursors() - expect(editor.getSelectedBufferRange()).toEqual [[0,0], [2,0]] + expect(editor.getSelectedBufferRange()).toEqual [[0, 0], [2, 0]] it "autoscrolls to the selection", -> editor.setLineHeightInPixels(10) @@ -1298,59 +1298,59 @@ describe "TextEditor", -> describe ".selectToBeginningOfWord()", -> it "selects text from cusor position to beginning of word", -> - editor.setCursorScreenPosition [0,13] - editor.addCursorAtScreenPosition [3,49] + editor.setCursorScreenPosition [0, 13] + editor.addCursorAtScreenPosition [3, 49] editor.selectToBeginningOfWord() expect(editor.getCursors().length).toBe 2 [cursor1, cursor2] = editor.getCursors() - expect(cursor1.getBufferPosition()).toEqual [0,4] - expect(cursor2.getBufferPosition()).toEqual [3,47] + expect(cursor1.getBufferPosition()).toEqual [0, 4] + expect(cursor2.getBufferPosition()).toEqual [3, 47] expect(editor.getSelections().length).toBe 2 [selection1, selection2] = editor.getSelections() - expect(selection1.getBufferRange()).toEqual [[0,4], [0,13]] + expect(selection1.getBufferRange()).toEqual [[0, 4], [0, 13]] expect(selection1.isReversed()).toBeTruthy() - expect(selection2.getBufferRange()).toEqual [[3,47], [3,49]] + expect(selection2.getBufferRange()).toEqual [[3, 47], [3, 49]] expect(selection2.isReversed()).toBeTruthy() describe ".selectToEndOfWord()", -> it "selects text from cusor position to end of word", -> - editor.setCursorScreenPosition [0,4] - editor.addCursorAtScreenPosition [3,48] + editor.setCursorScreenPosition [0, 4] + editor.addCursorAtScreenPosition [3, 48] editor.selectToEndOfWord() expect(editor.getCursors().length).toBe 2 [cursor1, cursor2] = editor.getCursors() - expect(cursor1.getBufferPosition()).toEqual [0,13] - expect(cursor2.getBufferPosition()).toEqual [3,50] + expect(cursor1.getBufferPosition()).toEqual [0, 13] + expect(cursor2.getBufferPosition()).toEqual [3, 50] expect(editor.getSelections().length).toBe 2 [selection1, selection2] = editor.getSelections() - expect(selection1.getBufferRange()).toEqual [[0,4], [0,13]] + expect(selection1.getBufferRange()).toEqual [[0, 4], [0, 13]] expect(selection1.isReversed()).toBeFalsy() - expect(selection2.getBufferRange()).toEqual [[3,48], [3,50]] + expect(selection2.getBufferRange()).toEqual [[3, 48], [3, 50]] expect(selection2.isReversed()).toBeFalsy() describe ".selectToBeginningOfNextWord()", -> it "selects text from cusor position to beginning of next word", -> - editor.setCursorScreenPosition [0,4] - editor.addCursorAtScreenPosition [3,48] + editor.setCursorScreenPosition [0, 4] + editor.addCursorAtScreenPosition [3, 48] editor.selectToBeginningOfNextWord() expect(editor.getCursors().length).toBe 2 [cursor1, cursor2] = editor.getCursors() - expect(cursor1.getBufferPosition()).toEqual [0,14] - expect(cursor2.getBufferPosition()).toEqual [3,51] + expect(cursor1.getBufferPosition()).toEqual [0, 14] + expect(cursor2.getBufferPosition()).toEqual [3, 51] expect(editor.getSelections().length).toBe 2 [selection1, selection2] = editor.getSelections() - expect(selection1.getBufferRange()).toEqual [[0,4], [0,14]] + expect(selection1.getBufferRange()).toEqual [[0, 4], [0, 14]] expect(selection1.isReversed()).toBeFalsy() - expect(selection2.getBufferRange()).toEqual [[3,48], [3,51]] + expect(selection2.getBufferRange()).toEqual [[3, 48], [3, 51]] expect(selection2.isReversed()).toBeFalsy() describe ".selectToPreviousWordBoundary()", -> @@ -1364,13 +1364,13 @@ describe "TextEditor", -> expect(editor.getSelections().length).toBe 4 [selection1, selection2, selection3, selection4] = editor.getSelections() - expect(selection1.getBufferRange()).toEqual [[0,8], [0,4]] + expect(selection1.getBufferRange()).toEqual [[0, 8], [0, 4]] expect(selection1.isReversed()).toBeTruthy() - expect(selection2.getBufferRange()).toEqual [[2,0], [1,30]] + expect(selection2.getBufferRange()).toEqual [[2, 0], [1, 30]] expect(selection2.isReversed()).toBeTruthy() - expect(selection3.getBufferRange()).toEqual [[3,4], [3,0]] + expect(selection3.getBufferRange()).toEqual [[3, 4], [3, 0]] expect(selection3.isReversed()).toBeTruthy() - expect(selection4.getBufferRange()).toEqual [[3,14], [3,13]] + expect(selection4.getBufferRange()).toEqual [[3, 14], [3, 13]] expect(selection4.isReversed()).toBeTruthy() describe ".selectToNextWordBoundary()", -> @@ -1384,13 +1384,13 @@ describe "TextEditor", -> expect(editor.getSelections().length).toBe 4 [selection1, selection2, selection3, selection4] = editor.getSelections() - expect(selection1.getBufferRange()).toEqual [[0,8], [0,13]] + expect(selection1.getBufferRange()).toEqual [[0, 8], [0, 13]] expect(selection1.isReversed()).toBeFalsy() - expect(selection2.getBufferRange()).toEqual [[2,40], [3,0]] + expect(selection2.getBufferRange()).toEqual [[2, 40], [3, 0]] expect(selection2.isReversed()).toBeFalsy() - expect(selection3.getBufferRange()).toEqual [[4,0], [4,4]] + expect(selection3.getBufferRange()).toEqual [[4, 0], [4, 4]] expect(selection3.isReversed()).toBeFalsy() - expect(selection4.getBufferRange()).toEqual [[3,30], [3,31]] + expect(selection4.getBufferRange()).toEqual [[3, 30], [3, 31]] expect(selection4.isReversed()).toBeFalsy() describe ".selectWordsContainingCursors()", -> @@ -1452,27 +1452,27 @@ describe "TextEditor", -> describe ".selectToFirstCharacterOfLine()", -> it "moves to the first character of the current line or the beginning of the line if it's already on the first character", -> - editor.setCursorScreenPosition [0,5] - editor.addCursorAtScreenPosition [1,7] + editor.setCursorScreenPosition [0, 5] + editor.addCursorAtScreenPosition [1, 7] editor.selectToFirstCharacterOfLine() [cursor1, cursor2] = editor.getCursors() - expect(cursor1.getBufferPosition()).toEqual [0,0] - expect(cursor2.getBufferPosition()).toEqual [1,2] + expect(cursor1.getBufferPosition()).toEqual [0, 0] + expect(cursor2.getBufferPosition()).toEqual [1, 2] expect(editor.getSelections().length).toBe 2 [selection1, selection2] = editor.getSelections() - expect(selection1.getBufferRange()).toEqual [[0,0], [0,5]] + expect(selection1.getBufferRange()).toEqual [[0, 0], [0, 5]] expect(selection1.isReversed()).toBeTruthy() - expect(selection2.getBufferRange()).toEqual [[1,2], [1,7]] + expect(selection2.getBufferRange()).toEqual [[1, 2], [1, 7]] expect(selection2.isReversed()).toBeTruthy() editor.selectToFirstCharacterOfLine() [selection1, selection2] = editor.getSelections() - expect(selection1.getBufferRange()).toEqual [[0,0], [0,5]] + expect(selection1.getBufferRange()).toEqual [[0, 0], [0, 5]] expect(selection1.isReversed()).toBeTruthy() - expect(selection2.getBufferRange()).toEqual [[1,0], [1,7]] + expect(selection2.getBufferRange()).toEqual [[1, 0], [1, 7]] expect(selection2.isReversed()).toBeTruthy() describe ".setSelectedBufferRanges(ranges)", -> @@ -1501,7 +1501,7 @@ describe "TextEditor", -> describe "when the 'preserveFolds' option is false (the default)", -> it "removes folds that contain the selections", -> - editor.setSelectedBufferRange([[0,0], [0,0]]) + editor.setSelectedBufferRange([[0, 0], [0, 0]]) editor.createFold(1, 4) editor.createFold(2, 3) editor.createFold(6, 8) @@ -1515,7 +1515,7 @@ describe "TextEditor", -> describe "when the 'preserveFolds' option is true", -> it "does not remove folds that contain the selections", -> - editor.setSelectedBufferRange([[0,0], [0,0]]) + editor.setSelectedBufferRange([[0, 0], [0, 0]]) editor.createFold(1, 4) editor.createFold(6, 8) editor.setSelectedBufferRanges([[[2, 2], [3, 3]], [[6, 0], [6, 1]]], preserveFolds: true) @@ -1965,7 +1965,7 @@ describe "TextEditor", -> describe "when there are multiple non-empty selections", -> describe "when the selections are on the same line", -> it "replaces each selection range with the inserted characters", -> - editor.setSelectedBufferRanges([[[0,4], [0,13]], [[0,22], [0,24]]]) + editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[0, 22], [0, 24]]]) editor.insertText("x") [cursor1, cursor2] = editor.getCursors() @@ -1995,8 +1995,8 @@ describe "TextEditor", -> describe "when there is a selection that ends on a folded line", -> it "destroys the selection", -> - editor.createFold(2,4) - editor.setSelectedBufferRange([[1,0], [2,0]]) + editor.createFold(2, 4) + editor.setSelectedBufferRange([[1, 0], [2, 0]]) editor.insertText('holy cow') expect(editor.tokenizedLineForScreenRow(2).fold).toBeUndefined() @@ -2117,17 +2117,17 @@ describe "TextEditor", -> expect(editor.lineTextForBufferRow(9)).toBe " }" [cursor1, cursor2] = editor.getCursors() - expect(cursor1.getBufferPosition()).toEqual [4,0] - expect(cursor2.getBufferPosition()).toEqual [8,0] + expect(cursor1.getBufferPosition()).toEqual [4, 0] + expect(cursor2.getBufferPosition()).toEqual [8, 0] describe ".insertNewlineBelow()", -> describe "when the operation is undone", -> it "places the cursor back at the previous location", -> - editor.setCursorBufferPosition([0,2]) + editor.setCursorBufferPosition([0, 2]) editor.insertNewlineBelow() - expect(editor.getCursorBufferPosition()).toEqual [1,0] + expect(editor.getCursorBufferPosition()).toEqual [1, 0] editor.undo() - expect(editor.getCursorBufferPosition()).toEqual [0,2] + expect(editor.getCursorBufferPosition()).toEqual [0, 2] it "inserts a newline below the cursor's current line, autoindents it, and moves the cursor to the end of the line", -> atom.config.set("editor.autoIndent", true) @@ -2141,48 +2141,48 @@ describe "TextEditor", -> it "inserts a newline on the first line and moves the cursor to the first line", -> editor.setCursorBufferPosition([0]) editor.insertNewlineAbove() - expect(editor.getCursorBufferPosition()).toEqual [0,0] + expect(editor.getCursorBufferPosition()).toEqual [0, 0] expect(editor.lineTextForBufferRow(0)).toBe '' expect(editor.lineTextForBufferRow(1)).toBe 'var quicksort = function () {' expect(editor.buffer.getLineCount()).toBe 14 describe "when the cursor is not on the first line", -> it "inserts a newline above the current line and moves the cursor to the inserted line", -> - editor.setCursorBufferPosition([3,4]) + editor.setCursorBufferPosition([3, 4]) editor.insertNewlineAbove() - expect(editor.getCursorBufferPosition()).toEqual [3,0] + expect(editor.getCursorBufferPosition()).toEqual [3, 0] expect(editor.lineTextForBufferRow(3)).toBe '' expect(editor.lineTextForBufferRow(4)).toBe ' var pivot = items.shift(), current, left = [], right = [];' expect(editor.buffer.getLineCount()).toBe 14 editor.undo() - expect(editor.getCursorBufferPosition()).toEqual [3,4] + expect(editor.getCursorBufferPosition()).toEqual [3, 4] it "indents the new line to the correct level when editor.autoIndent is true", -> atom.config.set('editor.autoIndent', true) editor.setText(' var test') - editor.setCursorBufferPosition([0,2]) + editor.setCursorBufferPosition([0, 2]) editor.insertNewlineAbove() - expect(editor.getCursorBufferPosition()).toEqual [0,2] + expect(editor.getCursorBufferPosition()).toEqual [0, 2] expect(editor.lineTextForBufferRow(0)).toBe ' ' expect(editor.lineTextForBufferRow(1)).toBe ' var test' editor.setText('\n var test') - editor.setCursorBufferPosition([1,2]) + editor.setCursorBufferPosition([1, 2]) editor.insertNewlineAbove() - expect(editor.getCursorBufferPosition()).toEqual [1,2] + expect(editor.getCursorBufferPosition()).toEqual [1, 2] expect(editor.lineTextForBufferRow(0)).toBe '' expect(editor.lineTextForBufferRow(1)).toBe ' ' expect(editor.lineTextForBufferRow(2)).toBe ' var test' editor.setText('function() {\n}') - editor.setCursorBufferPosition([1,1]) + editor.setCursorBufferPosition([1, 1]) editor.insertNewlineAbove() - expect(editor.getCursorBufferPosition()).toEqual [1,2] + expect(editor.getCursorBufferPosition()).toEqual [1, 2] expect(editor.lineTextForBufferRow(0)).toBe 'function() {' expect(editor.lineTextForBufferRow(1)).toBe ' ' expect(editor.lineTextForBufferRow(2)).toBe '}' @@ -2190,7 +2190,7 @@ describe "TextEditor", -> describe "when a new line is appended before a closing tag (e.g. by pressing enter before a selection)", -> it "moves the line down and keeps the indentation level the same when editor.autoIndent is true", -> atom.config.set('editor.autoIndent', true) - editor.setCursorBufferPosition([9,2]) + editor.setCursorBufferPosition([9, 2]) editor.insertNewline() expect(editor.lineTextForBufferRow(10)).toBe ' };' @@ -2240,9 +2240,9 @@ describe "TextEditor", -> describe "when the cursor is on the first column of a line below a fold", -> it "deletes the folded lines", -> - editor.setCursorScreenPosition([4,0]) + editor.setCursorScreenPosition([4, 0]) editor.foldCurrentRow() - editor.setCursorScreenPosition([5,0]) + editor.setCursorScreenPosition([5, 0]) editor.backspace() expect(buffer.lineForRow(4)).toBe " return sort(left).concat(pivot).concat(sort(right));" @@ -2250,9 +2250,9 @@ describe "TextEditor", -> describe "when the cursor is in the middle of a line below a fold", -> it "backspaces as normal", -> - editor.setCursorScreenPosition([4,0]) + editor.setCursorScreenPosition([4, 0]) editor.foldCurrentRow() - editor.setCursorScreenPosition([5,5]) + editor.setCursorScreenPosition([5, 5]) editor.backspace() expect(buffer.lineForRow(7)).toBe " }" @@ -2317,18 +2317,18 @@ describe "TextEditor", -> expect(editor.lineTextForBufferRow(5)).toBe " }" [cursor1, cursor2] = editor.getCursors() - expect(cursor1.getBufferPosition()).toEqual [2,40] - expect(cursor2.getBufferPosition()).toEqual [4,30] + expect(cursor1.getBufferPosition()).toEqual [2, 40] + expect(cursor2.getBufferPosition()).toEqual [4, 30] describe "when there is a single selection", -> it "deletes the selection, but not the character before it", -> - editor.setSelectedBufferRange([[0,5], [0,9]]) + editor.setSelectedBufferRange([[0, 5], [0, 9]]) editor.backspace() expect(editor.buffer.lineForRow(0)).toBe 'var qsort = function () {' describe "when the selection ends on a folded line", -> it "preserves the fold", -> - editor.setSelectedBufferRange([[3,0], [4,0]]) + editor.setSelectedBufferRange([[3, 0], [4, 0]]) editor.foldBufferRow(4) editor.backspace() @@ -2337,7 +2337,7 @@ describe "TextEditor", -> describe "when there are multiple selections", -> it "removes all selected text", -> - editor.setSelectedBufferRanges([[[0,4], [0,13]], [[0,16], [0,24]]]) + editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[0, 16], [0, 24]]]) editor.backspace() expect(editor.lineTextForBufferRow(0)).toBe 'var = () {' @@ -2533,8 +2533,8 @@ describe "TextEditor", -> describe "when the cursor is on a folded line", -> it "removes the lines contained by the fold", -> editor.setSelectedBufferRange([[2, 0], [2, 0]]) - editor.createFold(2,4) - editor.createFold(2,6) + editor.createFold(2, 4) + editor.createFold(2, 6) oldLine7 = buffer.lineForRow(7) oldLine8 = buffer.lineForRow(8) @@ -2589,8 +2589,8 @@ describe "TextEditor", -> expect(editor.lineTextForBufferRow(0)).toBe "var quicksort = function () { var sort = function(items) { if (items.length <= 1) return items;" [cursor1, cursor2] = editor.getCursors() - expect(cursor1.getBufferPosition()).toEqual [0,29] - expect(cursor2.getBufferPosition()).toEqual [0,59] + expect(cursor1.getBufferPosition()).toEqual [0, 29] + expect(cursor2.getBufferPosition()).toEqual [0, 59] describe "when there is a single selection", -> it "deletes the selection, but not the character following it", -> @@ -2603,7 +2603,7 @@ describe "TextEditor", -> describe "when there are multiple selections", -> describe "when selections are on the same line", -> it "removes all selected text", -> - editor.setSelectedBufferRanges([[[0,4], [0,13]], [[0,16], [0,24]]]) + editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[0, 16], [0, 24]]]) editor.delete() expect(editor.lineTextForBufferRow(0)).toBe 'var = () {' @@ -2781,9 +2781,9 @@ describe "TextEditor", -> describe "when many selections get added in shuffle order", -> it "cuts them in order", -> editor.setSelectedBufferRanges([ - [[2,8], [2, 13]] - [[0,4], [0,13]], - [[1,6], [1, 10]], + [[2, 8], [2, 13]] + [[0, 4], [0, 13]], + [[1, 6], [1, 10]], ]) editor.cutSelectedText() expect(atom.clipboard.read()).toEqual """ @@ -2813,7 +2813,7 @@ describe "TextEditor", -> describe "when text is selected", -> it "only cuts the selected text, not to the end of the line", -> - editor.setSelectedBufferRanges([[[2,20], [2, 30]], [[3, 20], [3, 20]]]) + editor.setSelectedBufferRanges([[[2, 20], [2, 30]], [[3, 20], [3, 20]]]) editor.cutToEndOfLine() @@ -2823,7 +2823,7 @@ describe "TextEditor", -> describe ".copySelectedText()", -> it "copies selected text onto the clipboard", -> - editor.setSelectedBufferRanges([[[0,4], [0,13]], [[1,6], [1, 10]], [[2,8], [2, 13]]]) + editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[1, 6], [1, 10]], [[2, 8], [2, 13]]]) editor.copySelectedText() expect(buffer.lineForRow(0)).toBe "var quicksort = function () {" @@ -2857,9 +2857,9 @@ describe "TextEditor", -> describe "when many selections get added in shuffle order", -> it "copies them in order", -> editor.setSelectedBufferRanges([ - [[2,8], [2, 13]] - [[0,4], [0,13]], - [[1,6], [1, 10]], + [[2, 8], [2, 13]] + [[0, 4], [0, 13]], + [[1, 6], [1, 10]], ]) editor.copySelectedText() expect(atom.clipboard.read()).toEqual """ @@ -2876,7 +2876,7 @@ describe "TextEditor", -> textEditor.insertText(text) numberOfNewlines = text.match(/\n/g)?.length endColumn = text.match(/[^\n]*$/)[0]?.length - textEditor.getLastSelection().setBufferRange([[0,startColumn], [numberOfNewlines,endColumn]]) + textEditor.getLastSelection().setBufferRange([[0, startColumn], [numberOfNewlines, endColumn]]) textEditor.cutSelectedText() it "pastes text into the buffer", -> @@ -3020,7 +3020,7 @@ describe "TextEditor", -> describe "when nothing is selected", -> describe "when softTabs is enabled", -> it "indents line and retains selection", -> - editor.setSelectedBufferRange([[0,3], [0,3]]) + editor.setSelectedBufferRange([[0, 3], [0, 3]]) editor.indentSelectedRows() expect(buffer.lineForRow(0)).toBe " var quicksort = function () {" expect(editor.getSelectedBufferRange()).toEqual [[0, 3 + editor.getTabLength()], [0, 3 + editor.getTabLength()]] @@ -3029,7 +3029,7 @@ describe "TextEditor", -> it "indents line and retains selection", -> convertToHardTabs(buffer) editor.setSoftTabs(false) - editor.setSelectedBufferRange([[0,3], [0,3]]) + editor.setSelectedBufferRange([[0, 3], [0, 3]]) editor.indentSelectedRows() expect(buffer.lineForRow(0)).toBe "\tvar quicksort = function () {" expect(editor.getSelectedBufferRange()).toEqual [[0, 3 + 1], [0, 3 + 1]] @@ -3037,7 +3037,7 @@ describe "TextEditor", -> describe "when one line is selected", -> describe "when softTabs is enabled", -> it "indents line and retains selection", -> - editor.setSelectedBufferRange([[0,4], [0,14]]) + editor.setSelectedBufferRange([[0, 4], [0, 14]]) editor.indentSelectedRows() expect(buffer.lineForRow(0)).toBe "#{editor.getTabText()}var quicksort = function () {" expect(editor.getSelectedBufferRange()).toEqual [[0, 4 + editor.getTabLength()], [0, 14 + editor.getTabLength()]] @@ -3046,7 +3046,7 @@ describe "TextEditor", -> it "indents line and retains selection", -> convertToHardTabs(buffer) editor.setSoftTabs(false) - editor.setSelectedBufferRange([[0,4], [0,14]]) + editor.setSelectedBufferRange([[0, 4], [0, 14]]) editor.indentSelectedRows() expect(buffer.lineForRow(0)).toBe "\tvar quicksort = function () {" expect(editor.getSelectedBufferRange()).toEqual [[0, 4 + 1], [0, 14 + 1]] @@ -3054,7 +3054,7 @@ describe "TextEditor", -> describe "when multiple lines are selected", -> describe "when softTabs is enabled", -> it "indents selected lines (that are not empty) and retains selection", -> - editor.setSelectedBufferRange([[9,1], [11,15]]) + editor.setSelectedBufferRange([[9, 1], [11, 15]]) editor.indentSelectedRows() expect(buffer.lineForRow(9)).toBe " };" expect(buffer.lineForRow(10)).toBe "" @@ -3062,7 +3062,7 @@ describe "TextEditor", -> expect(editor.getSelectedBufferRange()).toEqual [[9, 1 + editor.getTabLength()], [11, 15 + editor.getTabLength()]] it "does not indent the last row if the selection ends at column 0", -> - editor.setSelectedBufferRange([[9,1], [11,0]]) + editor.setSelectedBufferRange([[9, 1], [11, 0]]) editor.indentSelectedRows() expect(buffer.lineForRow(9)).toBe " };" expect(buffer.lineForRow(10)).toBe "" @@ -3073,7 +3073,7 @@ describe "TextEditor", -> it "indents selected lines (that are not empty) and retains selection", -> convertToHardTabs(buffer) editor.setSoftTabs(false) - editor.setSelectedBufferRange([[9,1], [11,15]]) + editor.setSelectedBufferRange([[9, 1], [11, 15]]) editor.indentSelectedRows() expect(buffer.lineForRow(9)).toBe "\t\t};" expect(buffer.lineForRow(10)).toBe "" @@ -3083,7 +3083,7 @@ describe "TextEditor", -> describe ".outdentSelectedRows()", -> describe "when nothing is selected", -> it "outdents line and retains selection", -> - editor.setSelectedBufferRange([[1,3], [1,3]]) + editor.setSelectedBufferRange([[1, 3], [1, 3]]) editor.outdentSelectedRows() expect(buffer.lineForRow(1)).toBe "var sort = function(items) {" expect(editor.getSelectedBufferRange()).toEqual [[1, 3 - editor.getTabLength()], [1, 3 - editor.getTabLength()]] @@ -3120,14 +3120,14 @@ describe "TextEditor", -> describe "when one line is selected", -> it "outdents line and retains editor", -> - editor.setSelectedBufferRange([[1,4], [1,14]]) + editor.setSelectedBufferRange([[1, 4], [1, 14]]) editor.outdentSelectedRows() expect(buffer.lineForRow(1)).toBe "var sort = function(items) {" expect(editor.getSelectedBufferRange()).toEqual [[1, 4 - editor.getTabLength()], [1, 14 - editor.getTabLength()]] describe "when multiple lines are selected", -> it "outdents selected lines and retains editor", -> - editor.setSelectedBufferRange([[0,1], [3,15]]) + editor.setSelectedBufferRange([[0, 1], [3, 15]]) editor.outdentSelectedRows() expect(buffer.lineForRow(0)).toBe "var quicksort = function () {" expect(buffer.lineForRow(1)).toBe "var sort = function(items) {" @@ -3136,7 +3136,7 @@ describe "TextEditor", -> expect(editor.getSelectedBufferRange()).toEqual [[0, 1], [3, 15 - editor.getTabLength()]] it "does not outdent the last line of the selection if it ends at column 0", -> - editor.setSelectedBufferRange([[0,1], [3,0]]) + editor.setSelectedBufferRange([[0, 1], [3, 0]]) editor.outdentSelectedRows() expect(buffer.lineForRow(0)).toBe "var quicksort = function () {" expect(buffer.lineForRow(1)).toBe "var sort = function(items) {" @@ -3149,7 +3149,7 @@ describe "TextEditor", -> it "auto-indents the selection", -> editor.setCursorBufferPosition([2, 0]) editor.insertText("function() {\ninside=true\n}\n i=1\n") - editor.getLastSelection().setBufferRange([[2,0], [6,0]]) + editor.getLastSelection().setBufferRange([[2, 0], [6, 0]]) editor.autoIndentSelectedRows() expect(editor.lineTextForBufferRow(2)).toBe " function() {" @@ -3385,8 +3385,8 @@ describe "TextEditor", -> expect(editor.getCursors().length).toBe 2 expect(editor.getCursors()).toEqual [cursor1, cursor3] - expect(cursor1.getBufferPosition()).toEqual [0,0] - expect(cursor3.getBufferPosition()).toEqual [1,2] + expect(cursor1.getBufferPosition()).toEqual [0, 0] + expect(cursor3.getBufferPosition()).toEqual [1, 2] describe 'reading text', -> it '.lineTextForScreenRow(row)', -> @@ -3544,7 +3544,7 @@ describe "TextEditor", -> describe "when there is a selection", -> it "upper cases the current selection", -> editor.buffer.setText("abc") - editor.setSelectedBufferRange([[0,0], [0,2]]) + editor.setSelectedBufferRange([[0, 0], [0, 2]]) editor.upperCase() expect(editor.lineTextForBufferRow(0)).toBe 'ABc' expect(editor.getSelectedBufferRange()).toEqual [[0, 0], [0, 2]] @@ -3561,7 +3561,7 @@ describe "TextEditor", -> describe "when there is a selection", -> it "lower cases the current selection", -> editor.buffer.setText("ABC") - editor.setSelectedBufferRange([[0,0], [0,2]]) + editor.setSelectedBufferRange([[0, 0], [0, 2]]) editor.lowerCase() expect(editor.lineTextForBufferRow(0)).toBe 'abC' expect(editor.getSelectedBufferRange()).toEqual [[0, 0], [0, 2]] @@ -3652,7 +3652,7 @@ describe "TextEditor", -> it "preserves the current cursor position", -> editor.setCursorScreenPosition([0, 1]) editor.buffer.reload() - expect(editor.getCursorScreenPosition()).toEqual [0,1] + expect(editor.getCursorScreenPosition()).toEqual [0, 1] describe "when a better-matched grammar is added to syntax", -> it "switches to the better-matched grammar and re-tokenizes the buffer", -> @@ -4235,28 +4235,28 @@ describe "TextEditor", -> editor.selectPageDown() expect(editor.getScrollTop()).toBe 30 - expect(editor.getSelectedBufferRanges()).toEqual [[[0,0], [5,0]]] + expect(editor.getSelectedBufferRanges()).toEqual [[[0, 0], [5, 0]]] editor.selectPageDown() expect(editor.getScrollTop()).toBe 80 - expect(editor.getSelectedBufferRanges()).toEqual [[[0,0], [10,0]]] + expect(editor.getSelectedBufferRanges()).toEqual [[[0, 0], [10, 0]]] editor.selectPageDown() expect(editor.getScrollTop()).toBe 80 - expect(editor.getSelectedBufferRanges()).toEqual [[[0,0], [12,2]]] + expect(editor.getSelectedBufferRanges()).toEqual [[[0, 0], [12, 2]]] editor.moveToBottom() editor.selectPageUp() expect(editor.getScrollTop()).toBe 50 - expect(editor.getSelectedBufferRanges()).toEqual [[[7,0], [12,2]]] + expect(editor.getSelectedBufferRanges()).toEqual [[[7, 0], [12, 2]]] editor.selectPageUp() expect(editor.getScrollTop()).toBe 0 - expect(editor.getSelectedBufferRanges()).toEqual [[[2,0], [12,2]]] + expect(editor.getSelectedBufferRanges()).toEqual [[[2, 0], [12, 2]]] editor.selectPageUp() expect(editor.getScrollTop()).toBe 0 - expect(editor.getSelectedBufferRanges()).toEqual [[[0,0], [12,2]]] + expect(editor.getSelectedBufferRanges()).toEqual [[[0, 0], [12, 2]]] describe '.get/setPlaceholderText()', -> it 'can be created with placeholderText', -> From 544d650d227c846650b3cfb5f6618a1072fa096c Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Fri, 22 May 2015 19:57:41 -0400 Subject: [PATCH 1389/1783] :shirt: Fix linter errors in text-editor-view --- src/text-editor-view.coffee | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/text-editor-view.coffee b/src/text-editor-view.coffee index b86367ef4..7f17ddaad 100644 --- a/src/text-editor-view.coffee +++ b/src/text-editor-view.coffee @@ -120,14 +120,14 @@ class TextEditorView extends View getEditor: -> @model - Object.defineProperty @::, 'lineHeight', get: -> @model.getLineHeightInPixels() - Object.defineProperty @::, 'charWidth', get: -> @model.getDefaultCharWidth() - Object.defineProperty @::, 'firstRenderedScreenRow', get: -> @component.getRenderedRowRange()[0] - Object.defineProperty @::, 'lastRenderedScreenRow', get: -> @component.getRenderedRowRange()[1] - Object.defineProperty @::, 'active', get: -> @is(@getPaneView()?.activeView) - Object.defineProperty @::, 'isFocused', get: -> document.activeElement is @element or document.activeElement is @element.component?.hiddenInputComponent?.getDomNode() - Object.defineProperty @::, 'mini', get: -> @model?.isMini() - Object.defineProperty @::, 'component', get: -> @element?.component + Object.defineProperty @prototype, 'lineHeight', get: -> @model.getLineHeightInPixels() + Object.defineProperty @prototype, 'charWidth', get: -> @model.getDefaultCharWidth() + Object.defineProperty @prototype, 'firstRenderedScreenRow', get: -> @component.getRenderedRowRange()[0] + Object.defineProperty @prototype, 'lastRenderedScreenRow', get: -> @component.getRenderedRowRange()[1] + Object.defineProperty @prototype, 'active', get: -> @is(@getPaneView()?.activeView) + Object.defineProperty @prototype, 'isFocused', get: -> document.activeElement is @element or document.activeElement is @element.component?.hiddenInputComponent?.getDomNode() + Object.defineProperty @prototype, 'mini', get: -> @model?.isMini() + Object.defineProperty @prototype, 'component', get: -> @element?.component afterAttach: (onDom) -> return unless onDom From 4a8fa01e2c812a3290d137a3191e43c7dc7fba33 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Fri, 22 May 2015 20:08:29 -0400 Subject: [PATCH 1390/1783] :fire: Remove newlines_after_classes rule This rule, although it would be nice, is a bit too buggy for use right now - see https://github.com/clutchski/coffeelint/issues/245 --- coffeelint.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/coffeelint.json b/coffeelint.json index 9ee65d6e5..a5dd715e3 100644 --- a/coffeelint.json +++ b/coffeelint.json @@ -33,9 +33,5 @@ }, "no_stand_alone_at": { "level": "error" - }, - "newlines_after_classes": { - "value": 2, - "level": "error" } } From 04400be946e54691725193b518c10a2d3caeea3b Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Fri, 22 May 2015 20:20:35 -0400 Subject: [PATCH 1391/1783] :memo: Update CONTRIBUTING with latest style guidelines --- CONTRIBUTING.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fe9a742b4..333eb0913 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -100,6 +100,9 @@ For more information on how to work with Atom's official packages, see * Set parameter defaults without spaces around the equal sign * `clear = (count=1) ->` instead of `clear = (count = 1) ->` +* Use spaces around operators + * `count + 1` instead of `count+1` +* Use spaces after commas (unless separated by newlines) * Use parentheses if it improves code clarity. * Prefer alphabetic keywords to symbolic keywords: * `a is b` instead of `a == b` @@ -113,6 +116,8 @@ For more information on how to work with Atom's official packages, see * Use `slice()` to copy an array * Add an explicit `return` when your function ends with a `for`/`while` loop and you don't want it to return a collected array. +* Use `this` instead of a standalone `@` + * `return this` instead of `return @` ## Specs Styleguide From 8fa1614d694b6da15fc58edbbb55eb387adbf057 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Fri, 22 May 2015 20:28:15 -0400 Subject: [PATCH 1392/1783] :shirt: Fix linter error in build/tasks/install-task --- build/tasks/install-task.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/tasks/install-task.coffee b/build/tasks/install-task.coffee index 5131f512c..71d3c4ae8 100644 --- a/build/tasks/install-task.coffee +++ b/build/tasks/install-task.coffee @@ -31,7 +31,7 @@ module.exports = (grunt) -> binDir = path.join(installDir, 'bin') shareDir = path.join(installDir, 'share', 'atom') - iconName = path.join(shareDir,'resources', 'app', 'resources', 'atom.png') + iconName = path.join(shareDir, 'resources', 'app', 'resources', 'atom.png') mkdir binDir cp 'atom.sh', path.join(binDir, 'atom') From c5a8c8ad34bd318a57660f3002183af06c8d4d26 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Fri, 22 May 2015 22:05:04 -0400 Subject: [PATCH 1393/1783] :bug: Fix application:open-license command --- src/workspace.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/workspace.coffee b/src/workspace.coffee index 0e6fb7e40..0285cf99d 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -377,7 +377,7 @@ class Workspace extends Model # Open Atom's license in the active pane. openLicense: -> - @open(join(atom.getLoadSettings().resourcePath, 'LICENSE.md')) + @open(path.join(process.resourcesPath, 'LICENSE.md')) # Synchronously open the given URI in the active pane. **Only use this method # in specs. Calling this in production code will block the UI thread and From 08c4e8e0075725abbecb9042cab72c22f264c0a1 Mon Sep 17 00:00:00 2001 From: simurai Date: Sun, 24 May 2015 16:37:36 +0900 Subject: [PATCH 1394/1783] Unstyle that got intruduced in latest Boostrap upgrade. Fixes #6923 --- static/bootstrap-overrides.less | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/static/bootstrap-overrides.less b/static/bootstrap-overrides.less index df61c0171..115f672f2 100644 --- a/static/bootstrap-overrides.less +++ b/static/bootstrap-overrides.less @@ -32,3 +32,10 @@ body { font-family: @font-family; font-size: @font-size; } + +// disable some styling, will be styled in themes +kbd { + color: inherit; + background-color: none; + box-shadow: none; +} From 4bbfe37448bcf955fcaa8c208869d17994e82d75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=C5=BDu=C5=BEak?= Date: Mon, 25 May 2015 13:52:11 +0200 Subject: [PATCH 1395/1783] :arrow_up: status-bar@0.73.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b22bee26e..e67d918df 100644 --- a/package.json +++ b/package.json @@ -117,7 +117,7 @@ "settings-view": "0.205.0", "snippets": "0.90.0", "spell-check": "0.58.0", - "status-bar": "0.72.0", + "status-bar": "0.73.0", "styleguide": "0.44.0", "symbols-view": "0.97.0", "tabs": "0.68.0", From 513fc70154118ff1ae2915c3d842ddcb2503f52a Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Mon, 25 May 2015 11:50:20 -0400 Subject: [PATCH 1396/1783] :memo: Add docs about passing a function to a tooltip title --- src/tooltip-manager.coffee | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/tooltip-manager.coffee b/src/tooltip-manager.coffee index ee2054b5a..3c9777123 100644 --- a/src/tooltip-manager.coffee +++ b/src/tooltip-manager.coffee @@ -57,9 +57,10 @@ class TooltipManager # Essential: Add a tooltip to the given element. # # * `target` An `HTMLElement` - # * `options` See http://getbootstrap.com/javascript/#tooltips for a full list - # of options. You can also supply the following additional options: - # * `title` {String} Text in the tip. + # * `options` See http://getbootstrap.com/javascript/#tooltips-options for a + # 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. # * `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. From e9077beb411e9d8439b34b134f1c2bd5b4c17d22 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Mon, 25 May 2015 12:14:12 -0400 Subject: [PATCH 1397/1783] Document build flags --- docs/build-instructions/freebsd.md | 14 ++++++++++++++ docs/build-instructions/os-x.md | 5 +++++ docs/build-instructions/windows.md | 5 +++++ 3 files changed, 24 insertions(+) diff --git a/docs/build-instructions/freebsd.md b/docs/build-instructions/freebsd.md index 147c9da23..8029aa5f2 100644 --- a/docs/build-instructions/freebsd.md +++ b/docs/build-instructions/freebsd.md @@ -19,4 +19,18 @@ FreeBSD -RELEASE 64-bit is the recommended platform. sudo script/grunt install # Installs command to /usr/local/bin/atom ``` +## Advanced Options + +### Custom install directory + +```sh +sudo script/grunt install --install-dir /install/atom/here +``` + +### Custom build directory + +```sh +script/build --build-dir /build/atom/here +``` + ## Troubleshooting diff --git a/docs/build-instructions/os-x.md b/docs/build-instructions/os-x.md index d8685cff8..334a33653 100644 --- a/docs/build-instructions/os-x.md +++ b/docs/build-instructions/os-x.md @@ -14,6 +14,11 @@ script/build # Creates application at /Applications/Atom.app ``` +### `script/build` Options + * `--install-dir` - Creates the final built application in this directory. + * `--build-dir` - Build the application in this directory. + * `--verbose` - Verbose mode. A lot more information output. + ## Troubleshooting ### OSX build error reports in atom/atom diff --git a/docs/build-instructions/windows.md b/docs/build-instructions/windows.md index 8cfe74e72..a5d0757cb 100644 --- a/docs/build-instructions/windows.md +++ b/docs/build-instructions/windows.md @@ -33,6 +33,11 @@ cd atom script/build # Creates application in the `Program Files` directory ``` +### `script/build` Options + * `--install-dir` - Creates the final built application in this directory. + * `--build-dir` - Build the application in this directory. + * `--verbose` - Verbose mode. A lot more information output. + ## Why do I have to use GitHub for Windows? You don't. You can use your existing Git! GitHub for Windows's Git Shell is just From ae5590446576b5fbc160d24f2bdeae42ed01381d Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Mon, 25 May 2015 12:52:03 -0400 Subject: [PATCH 1398/1783] :memo: Update --install-dir docs for OS X --- docs/build-instructions/os-x.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/build-instructions/os-x.md b/docs/build-instructions/os-x.md index 334a33653..2ffde8ec0 100644 --- a/docs/build-instructions/os-x.md +++ b/docs/build-instructions/os-x.md @@ -15,7 +15,7 @@ ``` ### `script/build` Options - * `--install-dir` - Creates the final built application in this directory. + * `--install-dir` - The full path to the final built application (must include `.app` in the path), e.g. `script/build --install-dir full/path/to/Atom.app` * `--build-dir` - Build the application in this directory. * `--verbose` - Verbose mode. A lot more information output. From 2e8bb9e41fccbbf00d3eae080c76e9631333af96 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Mon, 25 May 2015 13:14:00 -0400 Subject: [PATCH 1399/1783] :memo: Update example path --- docs/build-instructions/os-x.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/build-instructions/os-x.md b/docs/build-instructions/os-x.md index 2ffde8ec0..7201676b1 100644 --- a/docs/build-instructions/os-x.md +++ b/docs/build-instructions/os-x.md @@ -15,7 +15,7 @@ ``` ### `script/build` Options - * `--install-dir` - The full path to the final built application (must include `.app` in the path), e.g. `script/build --install-dir full/path/to/Atom.app` + * `--install-dir` - The full path to the final built application (must include `.app` in the path), e.g. `script/build --install-dir /Users/username/full/path/to/Atom.app` * `--build-dir` - Build the application in this directory. * `--verbose` - Verbose mode. A lot more information output. From a62525ffd5653bdb5c72ad575bcbee7e7d793739 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 26 May 2015 09:08:08 -0700 Subject: [PATCH 1400/1783] :arrow_up: background-tips@0.25 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e67d918df..5ec1e705d 100644 --- a/package.json +++ b/package.json @@ -91,7 +91,7 @@ "autocomplete-snippets": "1.6.1", "autoflow": "0.24.0", "autosave": "0.20.0", - "background-tips": "0.24.0", + "background-tips": "0.25.0", "bookmarks": "0.35.0", "bracket-matcher": "0.74.0", "command-palette": "0.36.0", From bd16d25ea25a040ac420bb859acb4d3efd6b28cb Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 26 May 2015 09:12:21 -0700 Subject: [PATCH 1401/1783] :arrow_up: language-ruby@0.55 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5ec1e705d..dde0064bf 100644 --- a/package.json +++ b/package.json @@ -148,7 +148,7 @@ "language-php": "0.24.0", "language-property-list": "0.8.0", "language-python": "0.35.0", - "language-ruby": "0.54.0", + "language-ruby": "0.55.0", "language-ruby-on-rails": "0.21.0", "language-sass": "0.38.0", "language-shellscript": "0.15.0", From 1090c8611387c1cda68712828249154dff920c1b Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 26 May 2015 13:25:52 -0700 Subject: [PATCH 1402/1783] :arrow_up: find-and-replace@0.168.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dde0064bf..223c53650 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", - "find-and-replace": "0.167.0", + "find-and-replace": "0.168.0", "fuzzy-finder": "0.87.0", "git-diff": "0.55.0", "go-to-line": "0.30.0", From fc9a8c7f713efdbd0155cc3d46278cfaaef97d30 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 26 May 2015 13:36:37 -0700 Subject: [PATCH 1403/1783] Add descriptions to softwrap settings. Closes #6920 --- src/config-schema.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/config-schema.coffee b/src/config-schema.coffee index 548b35fa8..426bbee50 100644 --- a/src/config-schema.coffee +++ b/src/config-schema.coffee @@ -139,12 +139,14 @@ module.exports = softWrap: type: 'boolean' default: false + description: 'Wraps lines that exceeed the width of the window. When `Soft Wrap At Preferred Line Length` is set, it will wrap to the number characters defined by the `Preferred Line Length` setting.' softTabs: type: 'boolean' default: true softWrapAtPreferredLineLength: type: 'boolean' default: false + description: 'Will wrap to the number characters defined by the `Preferred Line Length` setting. This will only take effect when soft wrap is enabled globally or for the current language.' softWrapHangingIndent: type: 'integer' default: 0 From 1a3904aad1437f2f4f0aeac8c6607a2b0c2c58fb Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 26 May 2015 14:15:00 -0700 Subject: [PATCH 1404/1783] Add `of` Thanks @50Wliu --- src/config-schema.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config-schema.coffee b/src/config-schema.coffee index 426bbee50..8f974d2f4 100644 --- a/src/config-schema.coffee +++ b/src/config-schema.coffee @@ -139,14 +139,14 @@ module.exports = softWrap: type: 'boolean' default: false - description: 'Wraps lines that exceeed the width of the window. When `Soft Wrap At Preferred Line Length` is set, it will wrap to the number characters defined by the `Preferred Line Length` setting.' + description: 'Wraps lines that exceeed the width of the window. When `Soft Wrap At Preferred Line Length` is set, it will wrap to the number of characters defined by the `Preferred Line Length` setting.' softTabs: type: 'boolean' default: true softWrapAtPreferredLineLength: type: 'boolean' default: false - description: 'Will wrap to the number characters defined by the `Preferred Line Length` setting. This will only take effect when soft wrap is enabled globally or for the current language.' + description: 'Will wrap to the number of characters defined by the `Preferred Line Length` setting. This will only take effect when soft wrap is enabled globally or for the current language.' softWrapHangingIndent: type: 'integer' default: 0 From 2953d67660adb67599b0130baf63b781b72c2025 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 26 May 2015 23:20:30 +0200 Subject: [PATCH 1405/1783] :arrow_up: atom-keymap --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 223c53650..2ffb2ab3c 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "atomShellVersion": "0.22.3", "dependencies": { "async": "0.2.6", - "atom-keymap": "^5.1.3", + "atom-keymap": "^5.1.4", "atom-space-pen-views": "^2.0.4", "babel-core": "^5.1.11", "bootstrap": "^3.3.4", From 290c5c76e5b07eb8c92198c00a4b5064d4b3c750 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Machist=C3=A9=20N=2E=20Quintana?= Date: Tue, 26 May 2015 19:31:16 -0400 Subject: [PATCH 1406/1783] Add coffeelint config files to ignored build paths --- build/tasks/build-task.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build/tasks/build-task.coffee b/build/tasks/build-task.coffee index 343960f61..6c2c4f309 100644 --- a/build/tasks/build-task.coffee +++ b/build/tasks/build-task.coffee @@ -103,6 +103,8 @@ module.exports = (grunt) -> '.lintignore' '.eslintrc' '.jshintignore' + 'coffeelint.json' + '.coffeelintignore' '.gitattributes' '.gitkeep' ] From 9068f217cba8a85f838f02a497f12a4dc0d97da2 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 26 May 2015 16:50:43 -0700 Subject: [PATCH 1407/1783] :arrow_up: text-buffer --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2ffb2ab3c..0a6c83037 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "space-pen": "3.8.2", "stacktrace-parser": "0.1.1", "temp": "0.8.1", - "text-buffer": "6.1.2", + "text-buffer": "6.1.3", "theorist": "^1.0.2", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", From 49d9f349a408b79c1ea8d8cc9f2f819099939e25 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 26 May 2015 16:54:17 -0700 Subject: [PATCH 1408/1783] :arrow_up: language-ruby@0.56 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0a6c83037..2b0674268 100644 --- a/package.json +++ b/package.json @@ -148,7 +148,7 @@ "language-php": "0.24.0", "language-property-list": "0.8.0", "language-python": "0.35.0", - "language-ruby": "0.55.0", + "language-ruby": "0.56.0", "language-ruby-on-rails": "0.21.0", "language-sass": "0.38.0", "language-shellscript": "0.15.0", From c1e80610a83d3caa691becb1ed83ef7430a3541b Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 26 May 2015 17:01:44 -0700 Subject: [PATCH 1409/1783] Speling --- src/config-schema.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config-schema.coffee b/src/config-schema.coffee index 8f974d2f4..b814e21de 100644 --- a/src/config-schema.coffee +++ b/src/config-schema.coffee @@ -139,7 +139,7 @@ module.exports = softWrap: type: 'boolean' default: false - description: 'Wraps lines that exceeed the width of the window. When `Soft Wrap At Preferred Line Length` is set, it will wrap to the number of characters defined by the `Preferred Line Length` setting.' + description: 'Wraps lines that exceed the width of the window. When `Soft Wrap At Preferred Line Length` is set, it will wrap to the number of characters defined by the `Preferred Line Length` setting.' softTabs: type: 'boolean' default: true From 9e3c2d093b9b9ca3178d44a510625f367fa64083 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 26 May 2015 17:09:59 -0700 Subject: [PATCH 1410/1783] Avoid double transaction when typing --- src/text-editor-component.coffee | 3 +-- src/text-editor.coffee | 24 ++++++++++++++++-------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index eb01e0f23..431966910 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -309,8 +309,7 @@ class TextEditorComponent selectedLength = inputNode.selectionEnd - inputNode.selectionStart @editor.selectLeft() if selectedLength is 1 - insertedRange = @editor.transact atom.config.get('editor.undoGroupingInterval'), => - @editor.insertText(event.data) + insertedRange = @editor.insertText(event.data, groupUndo: true) inputNode.value = event.data if insertedRange onVerticalScroll: (scrollTop) => diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 4489d82af..6d979fdf7 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -761,15 +761,23 @@ class TextEditor extends Model @emit('will-insert-text', willInsertEvent) if includeDeprecatedAPIs @emitter.emit 'will-insert-text', willInsertEvent + groupingInterval = if options.groupUndo + atom.config.get('editor.undoGroupingInterval') + else + 0 + if willInsert options.autoIndentNewline ?= @shouldAutoIndent() options.autoDecreaseIndent ?= @shouldAutoIndent() - @mutateSelectedText (selection) => - range = selection.insertText(text, options) - didInsertEvent = {text, range} - @emit('did-insert-text', didInsertEvent) if includeDeprecatedAPIs - @emitter.emit 'did-insert-text', didInsertEvent - range + @mutateSelectedText( + (selection) => + range = selection.insertText(text, options) + didInsertEvent = {text, range} + @emit('did-insert-text', didInsertEvent) if includeDeprecatedAPIs + @emitter.emit 'did-insert-text', didInsertEvent + range + , groupingInterval + ) else false @@ -795,9 +803,9 @@ class TextEditor extends Model # * `fn` A {Function} that will be called once for each {Selection}. The first # argument will be a {Selection} and the second argument will be the # {Number} index of that selection. - mutateSelectedText: (fn) -> + mutateSelectedText: (fn, groupingInterval=0) -> @mergeIntersectingSelections => - @transact => + @transact groupingInterval, => fn(selection, index) for selection, index in @getSelectionsOrderedByBufferPosition() # Move lines intersection the most recent selection up by one row in screen From 8b73c44d6f036240613e9728f39e474673aefa7f Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 26 May 2015 18:11:45 -0700 Subject: [PATCH 1411/1783] :arrow_up: autocomplete-snippets --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2b0674268..a5711ce51 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,7 @@ "autocomplete-css": "0.7.2", "autocomplete-html": "0.7.2", "autocomplete-plus": "2.17.1", - "autocomplete-snippets": "1.6.1", + "autocomplete-snippets": "1.6.2", "autoflow": "0.24.0", "autosave": "0.20.0", "background-tips": "0.25.0", From 60fbb1d3745514ad39ce0ca64a44bda8530a2a39 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 26 May 2015 18:16:50 -0700 Subject: [PATCH 1412/1783] :arrow_up: autocomplete-snippets --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a5711ce51..ce4b16fc0 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,7 @@ "autocomplete-css": "0.7.2", "autocomplete-html": "0.7.2", "autocomplete-plus": "2.17.1", - "autocomplete-snippets": "1.6.2", + "autocomplete-snippets": "1.6.3", "autoflow": "0.24.0", "autosave": "0.20.0", "background-tips": "0.25.0", From 71b0a365dc7b160dd42d0ffe0ad7460243ea041d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Machist=C3=A9=20N=2E=20Quintana?= Date: Tue, 26 May 2015 21:26:31 -0400 Subject: [PATCH 1413/1783] :arrow_up: status-bar@0.74.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ce4b16fc0..b0800ab91 100644 --- a/package.json +++ b/package.json @@ -117,7 +117,7 @@ "settings-view": "0.205.0", "snippets": "0.90.0", "spell-check": "0.58.0", - "status-bar": "0.73.0", + "status-bar": "0.74.0", "styleguide": "0.44.0", "symbols-view": "0.97.0", "tabs": "0.68.0", From 7926ca5f231c9cd361a1c6f2781b39a273df09ce Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 27 May 2015 09:01:41 +0200 Subject: [PATCH 1414/1783] Declare `atom.hasTiledEditor = true` This way packages that are affected by relative coordinates will be able to smoothly upgrade using a feature toggle. --- src/atom.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/atom.coffee b/src/atom.coffee index 0d029b61d..35ee786f7 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -34,6 +34,8 @@ class Atom extends Model atom = @deserialize(@loadState(mode)) ? new this({mode, @version}) atom.deserializeTimings.atom = Date.now() - startTime + Object.defineProperty(atom, "hasTiledEditor", value: true) + if includeDeprecatedAPIs workspaceViewDeprecationMessage = """ atom.workspaceView is no longer available. From a0ce1e6d01e581f4461c6b42d57319eb682bb8e5 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 27 May 2015 12:59:36 +0200 Subject: [PATCH 1415/1783] Narrow scope and rename flag --- src/atom.coffee | 2 -- src/text-editor-element.coffee | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/atom.coffee b/src/atom.coffee index 35ee786f7..0d029b61d 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -34,8 +34,6 @@ class Atom extends Model atom = @deserialize(@loadState(mode)) ? new this({mode, @version}) atom.deserializeTimings.atom = Date.now() - startTime - Object.defineProperty(atom, "hasTiledEditor", value: true) - if includeDeprecatedAPIs workspaceViewDeprecationMessage = """ atom.workspaceView is no longer available. diff --git a/src/text-editor-element.coffee b/src/text-editor-element.coffee index 88e07a18d..e3eaaeb2a 100644 --- a/src/text-editor-element.coffee +++ b/src/text-editor-element.coffee @@ -17,6 +17,7 @@ class TextEditorElement extends HTMLElement attached: false tileSize: null focusOnAttach: false + hasTiledRendering: true createdCallback: -> @emitter = new Emitter From 1c06f9eb26639ed8a796413216a5cb7416020fb6 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 27 May 2015 08:45:04 -0700 Subject: [PATCH 1416/1783] :arrow_up: markdown-preview@0.150 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ce4b16fc0..16ce7cd06 100644 --- a/package.json +++ b/package.json @@ -108,7 +108,7 @@ "incompatible-packages": "0.24.0", "keybinding-resolver": "0.33.0", "link": "0.30.0", - "markdown-preview": "0.149.0", + "markdown-preview": "0.150.0", "metrics": "0.51.0", "notifications": "0.50.0", "open-on-github": "0.37.0", From bdce576ab9c7e7a1a9cd0736999db5c38eac2a94 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 27 May 2015 09:05:59 -0700 Subject: [PATCH 1417/1783] :arrow_up: packages to remove bang from status bar --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 16ce7cd06..19df574b0 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "bookmarks": "0.35.0", "bracket-matcher": "0.74.0", "command-palette": "0.36.0", - "deprecation-cop": "0.51.0", + "deprecation-cop": "0.52.0", "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", @@ -114,7 +114,7 @@ "open-on-github": "0.37.0", "package-generator": "0.39.0", "release-notes": "0.52.0", - "settings-view": "0.205.0", + "settings-view": "0.206.0", "snippets": "0.90.0", "spell-check": "0.58.0", "status-bar": "0.73.0", From 0dcdfa1e89f06f7fd78f645d4981e2df9debbff8 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 27 May 2015 10:26:59 -0700 Subject: [PATCH 1418/1783] Revert "Initial paths shouldn't be normalized on save and restore (could contain uris)" --- spec/default-directory-provider-spec.coffee | 6 ------ spec/integration/startup-spec.coffee | 10 --------- spec/window-spec.coffee | 11 ---------- src/browser/atom-application.coffee | 8 +------ src/browser/main.coffee | 9 +++----- src/default-directory-provider.coffee | 23 +++++++-------------- src/window-event-handler.coffee | 10 ++++----- 7 files changed, 15 insertions(+), 62 deletions(-) diff --git a/spec/default-directory-provider-spec.coffee b/spec/default-directory-provider-spec.coffee index 357348c4a..69370a77b 100644 --- a/spec/default-directory-provider-spec.coffee +++ b/spec/default-directory-provider-spec.coffee @@ -31,12 +31,6 @@ describe "DefaultDirectoryProvider", -> directory = provider.directoryForURISync(file) expect(directory.getPath()).toEqual tmp - it "creates a Directory with a path as a uri when passed a uri", -> - provider = new DefaultDirectoryProvider() - uri = 'remote://server:6792/path/to/a/dir' - directory = provider.directoryForURISync(uri) - expect(directory.getPath()).toEqual uri - describe ".directoryForURI(uri)", -> it "returns a Promise that resolves to a Directory with a path that matches the uri", -> provider = new DefaultDirectoryProvider() diff --git a/spec/integration/startup-spec.coffee b/spec/integration/startup-spec.coffee index d2583ed27..54817fedc 100644 --- a/spec/integration/startup-spec.coffee +++ b/spec/integration/startup-spec.coffee @@ -227,13 +227,3 @@ describe "Starting Atom", -> [tempDirPath] [otherTempDirPath] ].sort() - - describe "opening a remote directory", -> - it "opens the parent directory and creates an empty text editor", -> - remoteDirectory = 'remote://server:3437/some/directory/path' - runAtom [remoteDirectory], {ATOM_HOME: atomHome}, (client) -> - client - .waitForWindowCount(1, 1000) - .waitForExist("atom-workspace", 5000) - .treeViewRootDirectories() - .then ({value}) -> expect(value).toEqual([remoteDirectory]) diff --git a/spec/window-spec.coffee b/spec/window-spec.coffee index 94e605a36..376a71ab3 100644 --- a/spec/window-spec.coffee +++ b/spec/window-spec.coffee @@ -293,14 +293,3 @@ describe "Window", -> pathToOpen = __dirname atom.getCurrentWindow().send 'message', 'open-locations', [{pathToOpen}] expect(atom.workspace.open.callCount).toBe 0 - - describe "when the opened path is a uri", -> - it "adds it to the project's paths as is", -> - pathToOpen = 'remote://server:7644/some/dir/path' - atom.getCurrentWindow().send 'message', 'open-locations', [{pathToOpen}] - - waitsFor -> - atom.project.getPaths().length is 1 - - runs -> - expect(atom.project.getPaths()[0]).toBe pathToOpen diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 5bd6be73e..1b2aa2e86 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -369,12 +369,7 @@ class AtomApplication # :windowDimensions - Object with height and width keys. # :window - {AtomWindow} to open file paths in. openPaths: ({pathsToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, apiPreviewMode, windowDimensions, profileStartup, window}={}) -> - pathsToOpen = pathsToOpen.map (pathToOpen) -> - if fs.existsSync(pathToOpen) - fs.normalize(pathToOpen) - else - pathToOpen - + pathsToOpen = (fs.normalize(pathToOpen) for pathToOpen in pathsToOpen) locationsToOpen = (@locationForPathToOpen(pathToOpen) for pathToOpen in pathsToOpen) unless pidToKillWhenClosed or newWindow @@ -523,7 +518,6 @@ class AtomApplication locationForPathToOpen: (pathToOpen) -> return {pathToOpen} unless pathToOpen - return {pathToOpen} if url.parse(pathToOpen).protocol? return {pathToOpen} if fs.existsSync(pathToOpen) pathToOpen = pathToOpen.replace(/[:\s]+$/, '') diff --git a/src/browser/main.coffee b/src/browser/main.coffee index 371dd71ea..1af0526dd 100644 --- a/src/browser/main.coffee +++ b/src/browser/main.coffee @@ -5,7 +5,6 @@ app = require 'app' fs = require 'fs-plus' path = require 'path' yargs = require 'yargs' -url = require 'url' nslog = require 'nslog' console.log = nslog @@ -46,11 +45,9 @@ start = -> cwd = args.executedFrom?.toString() or process.cwd() args.pathsToOpen = args.pathsToOpen.map (pathToOpen) -> - normalizedPath = fs.normalize(pathToOpen) - if url.parse(pathToOpen).protocol? - pathToOpen - else if cwd - path.resolve(cwd, normalizedPath) + pathToOpen = fs.normalize(pathToOpen) + if cwd + path.resolve(cwd, pathToOpen) else path.resolve(pathToOpen) diff --git a/src/default-directory-provider.coffee b/src/default-directory-provider.coffee index da2d17593..9e25e097b 100644 --- a/src/default-directory-provider.coffee +++ b/src/default-directory-provider.coffee @@ -1,7 +1,6 @@ {Directory} = require 'pathwatcher' fs = require 'fs-plus' path = require 'path' -url = require 'url' module.exports = class DefaultDirectoryProvider @@ -15,22 +14,14 @@ class DefaultDirectoryProvider # * {Directory} if the given URI is compatible with this provider. # * `null` if the given URI is not compatibile with this provider. directoryForURISync: (uri) -> - normalizedPath = path.normalize(uri) - {protocol} = url.parse(uri) - directoryPath = if protocol? - uri - else if not fs.isDirectorySync(normalizedPath) and fs.isDirectorySync(path.dirname(normalizedPath)) - path.dirname(normalizedPath) - else - normalizedPath + projectPath = path.normalize(uri) - # TODO: Stop normalizing the path in pathwatcher's Directory. - directory = new Directory(directoryPath) - if protocol? - directory.path = directoryPath - if fs.isCaseInsensitive() - directory.lowerCasePath = directoryPath.toLowerCase() - directory + directoryPath = if not fs.isDirectorySync(projectPath) and fs.isDirectorySync(path.dirname(projectPath)) + path.dirname(projectPath) + else + projectPath + + new Directory(directoryPath) # Public: Create a Directory that corresponds to the specified URI. # diff --git a/src/window-event-handler.coffee b/src/window-event-handler.coffee index 0855b27a1..7d67e87ab 100644 --- a/src/window-event-handler.coffee +++ b/src/window-event-handler.coffee @@ -5,7 +5,6 @@ ipc = require 'ipc' shell = require 'shell' {Subscriber} = require 'emissary' fs = require 'fs-plus' -url = require 'url' # Handles low-level events related to the window. module.exports = @@ -24,13 +23,12 @@ class WindowEventHandler if pathToOpen? and needsProjectPaths if fs.existsSync(pathToOpen) atom.project.addPath(pathToOpen) - else if fs.existsSync(path.dirname(pathToOpen)) - atom.project.addPath(path.dirname(pathToOpen)) else - atom.project.addPath(pathToOpen) + dirToOpen = path.dirname(pathToOpen) + if fs.existsSync(dirToOpen) + atom.project.addPath(dirToOpen) - {protocol} = url.parse(pathToOpen) - unless fs.isDirectorySync(pathToOpen) or protocol? + unless fs.isDirectorySync(pathToOpen) atom.workspace?.open(pathToOpen, {initialLine, initialColumn}) return From abd4c26eb978552d2054e905019470ac2fc616ad Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 27 May 2015 10:48:25 -0700 Subject: [PATCH 1419/1783] :arrow_up: language-javascript@0.78 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 01a8f9663..0753eb772 100644 --- a/package.json +++ b/package.json @@ -138,7 +138,7 @@ "language-html": "0.37.0", "language-hyperlink": "0.13.0", "language-java": "0.15.0", - "language-javascript": "0.77.0", + "language-javascript": "0.78.0", "language-json": "0.14.0", "language-less": "0.27.0", "language-make": "0.14.0", From e052a102734f80f83b904821a9c84f8c2dd7477c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 27 May 2015 10:49:49 -0700 Subject: [PATCH 1420/1783] :arrow_up: language-c@0.45 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0753eb772..ee5566f69 100644 --- a/package.json +++ b/package.json @@ -127,7 +127,7 @@ "welcome": "0.27.0", "whitespace": "0.29.0", "wrap-guide": "0.34.0", - "language-c": "0.44.0", + "language-c": "0.45.0", "language-clojure": "0.15.0", "language-coffee-script": "0.40.0", "language-csharp": "0.5.0", From c84dc541845623c3a80661e11f568695fed0edd3 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 27 May 2015 11:00:30 -0700 Subject: [PATCH 1421/1783] :arrow_up: tabs@0.69 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ee5566f69..0fc08f37e 100644 --- a/package.json +++ b/package.json @@ -120,7 +120,7 @@ "status-bar": "0.74.0", "styleguide": "0.44.0", "symbols-view": "0.97.0", - "tabs": "0.68.0", + "tabs": "0.69.0", "timecop": "0.31.0", "tree-view": "0.171.0", "update-package-dependencies": "0.10.0", From 4c9e6c5a27e9c12cf2fba2b264596728e252aad2 Mon Sep 17 00:00:00 2001 From: Mostafa Eweda Date: Wed, 27 May 2015 11:18:15 -0700 Subject: [PATCH 1422/1783] Revert "Merge pull request #6977 from atom/revert-6813-local-initial-paths" This reverts commit 0c668022789a06330e2a6ddc73478a458bc3c625, reversing changes made to bdce576ab9c7e7a1a9cd0736999db5c38eac2a94. --- spec/default-directory-provider-spec.coffee | 6 ++++++ spec/integration/startup-spec.coffee | 10 ++++++++++ spec/window-spec.coffee | 11 +++++++++++ src/browser/atom-application.coffee | 8 +++++++- src/browser/main.coffee | 9 ++++++--- src/default-directory-provider.coffee | 21 +++++++++++++++------ src/window-event-handler.coffee | 10 ++++++---- 7 files changed, 61 insertions(+), 14 deletions(-) diff --git a/spec/default-directory-provider-spec.coffee b/spec/default-directory-provider-spec.coffee index 69370a77b..357348c4a 100644 --- a/spec/default-directory-provider-spec.coffee +++ b/spec/default-directory-provider-spec.coffee @@ -31,6 +31,12 @@ describe "DefaultDirectoryProvider", -> directory = provider.directoryForURISync(file) expect(directory.getPath()).toEqual tmp + it "creates a Directory with a path as a uri when passed a uri", -> + provider = new DefaultDirectoryProvider() + uri = 'remote://server:6792/path/to/a/dir' + directory = provider.directoryForURISync(uri) + expect(directory.getPath()).toEqual uri + describe ".directoryForURI(uri)", -> it "returns a Promise that resolves to a Directory with a path that matches the uri", -> provider = new DefaultDirectoryProvider() diff --git a/spec/integration/startup-spec.coffee b/spec/integration/startup-spec.coffee index 54817fedc..d2583ed27 100644 --- a/spec/integration/startup-spec.coffee +++ b/spec/integration/startup-spec.coffee @@ -227,3 +227,13 @@ describe "Starting Atom", -> [tempDirPath] [otherTempDirPath] ].sort() + + describe "opening a remote directory", -> + it "opens the parent directory and creates an empty text editor", -> + remoteDirectory = 'remote://server:3437/some/directory/path' + runAtom [remoteDirectory], {ATOM_HOME: atomHome}, (client) -> + client + .waitForWindowCount(1, 1000) + .waitForExist("atom-workspace", 5000) + .treeViewRootDirectories() + .then ({value}) -> expect(value).toEqual([remoteDirectory]) diff --git a/spec/window-spec.coffee b/spec/window-spec.coffee index 376a71ab3..94e605a36 100644 --- a/spec/window-spec.coffee +++ b/spec/window-spec.coffee @@ -293,3 +293,14 @@ describe "Window", -> pathToOpen = __dirname atom.getCurrentWindow().send 'message', 'open-locations', [{pathToOpen}] expect(atom.workspace.open.callCount).toBe 0 + + describe "when the opened path is a uri", -> + it "adds it to the project's paths as is", -> + pathToOpen = 'remote://server:7644/some/dir/path' + atom.getCurrentWindow().send 'message', 'open-locations', [{pathToOpen}] + + waitsFor -> + atom.project.getPaths().length is 1 + + runs -> + expect(atom.project.getPaths()[0]).toBe pathToOpen diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 1b2aa2e86..5bd6be73e 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -369,7 +369,12 @@ class AtomApplication # :windowDimensions - Object with height and width keys. # :window - {AtomWindow} to open file paths in. openPaths: ({pathsToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, apiPreviewMode, windowDimensions, profileStartup, window}={}) -> - pathsToOpen = (fs.normalize(pathToOpen) for pathToOpen in pathsToOpen) + pathsToOpen = pathsToOpen.map (pathToOpen) -> + if fs.existsSync(pathToOpen) + fs.normalize(pathToOpen) + else + pathToOpen + locationsToOpen = (@locationForPathToOpen(pathToOpen) for pathToOpen in pathsToOpen) unless pidToKillWhenClosed or newWindow @@ -518,6 +523,7 @@ class AtomApplication locationForPathToOpen: (pathToOpen) -> return {pathToOpen} unless pathToOpen + return {pathToOpen} if url.parse(pathToOpen).protocol? return {pathToOpen} if fs.existsSync(pathToOpen) pathToOpen = pathToOpen.replace(/[:\s]+$/, '') diff --git a/src/browser/main.coffee b/src/browser/main.coffee index 1af0526dd..371dd71ea 100644 --- a/src/browser/main.coffee +++ b/src/browser/main.coffee @@ -5,6 +5,7 @@ app = require 'app' fs = require 'fs-plus' path = require 'path' yargs = require 'yargs' +url = require 'url' nslog = require 'nslog' console.log = nslog @@ -45,9 +46,11 @@ start = -> cwd = args.executedFrom?.toString() or process.cwd() args.pathsToOpen = args.pathsToOpen.map (pathToOpen) -> - pathToOpen = fs.normalize(pathToOpen) - if cwd - path.resolve(cwd, pathToOpen) + normalizedPath = fs.normalize(pathToOpen) + if url.parse(pathToOpen).protocol? + pathToOpen + else if cwd + path.resolve(cwd, normalizedPath) else path.resolve(pathToOpen) diff --git a/src/default-directory-provider.coffee b/src/default-directory-provider.coffee index 9e25e097b..da2d17593 100644 --- a/src/default-directory-provider.coffee +++ b/src/default-directory-provider.coffee @@ -1,6 +1,7 @@ {Directory} = require 'pathwatcher' fs = require 'fs-plus' path = require 'path' +url = require 'url' module.exports = class DefaultDirectoryProvider @@ -14,14 +15,22 @@ class DefaultDirectoryProvider # * {Directory} if the given URI is compatible with this provider. # * `null` if the given URI is not compatibile with this provider. directoryForURISync: (uri) -> - projectPath = path.normalize(uri) - - directoryPath = if not fs.isDirectorySync(projectPath) and fs.isDirectorySync(path.dirname(projectPath)) - path.dirname(projectPath) + normalizedPath = path.normalize(uri) + {protocol} = url.parse(uri) + directoryPath = if protocol? + uri + else if not fs.isDirectorySync(normalizedPath) and fs.isDirectorySync(path.dirname(normalizedPath)) + path.dirname(normalizedPath) else - projectPath + normalizedPath - new Directory(directoryPath) + # TODO: Stop normalizing the path in pathwatcher's Directory. + directory = new Directory(directoryPath) + if protocol? + directory.path = directoryPath + if fs.isCaseInsensitive() + directory.lowerCasePath = directoryPath.toLowerCase() + directory # Public: Create a Directory that corresponds to the specified URI. # diff --git a/src/window-event-handler.coffee b/src/window-event-handler.coffee index 7d67e87ab..0855b27a1 100644 --- a/src/window-event-handler.coffee +++ b/src/window-event-handler.coffee @@ -5,6 +5,7 @@ ipc = require 'ipc' shell = require 'shell' {Subscriber} = require 'emissary' fs = require 'fs-plus' +url = require 'url' # Handles low-level events related to the window. module.exports = @@ -23,12 +24,13 @@ class WindowEventHandler if pathToOpen? and needsProjectPaths if fs.existsSync(pathToOpen) atom.project.addPath(pathToOpen) + else if fs.existsSync(path.dirname(pathToOpen)) + atom.project.addPath(path.dirname(pathToOpen)) else - dirToOpen = path.dirname(pathToOpen) - if fs.existsSync(dirToOpen) - atom.project.addPath(dirToOpen) + atom.project.addPath(pathToOpen) - unless fs.isDirectorySync(pathToOpen) + {protocol} = url.parse(pathToOpen) + unless fs.isDirectorySync(pathToOpen) or protocol? atom.workspace?.open(pathToOpen, {initialLine, initialColumn}) return From 5e7bc308d4a0a78d1a99ac4fb1750623c7b13f3d Mon Sep 17 00:00:00 2001 From: Mostafa Eweda Date: Wed, 27 May 2015 11:20:49 -0700 Subject: [PATCH 1423/1783] Remove the protocol parse and check in the window-event-handler --- src/window-event-handler.coffee | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/window-event-handler.coffee b/src/window-event-handler.coffee index 0855b27a1..c9fd94681 100644 --- a/src/window-event-handler.coffee +++ b/src/window-event-handler.coffee @@ -29,8 +29,7 @@ class WindowEventHandler else atom.project.addPath(pathToOpen) - {protocol} = url.parse(pathToOpen) - unless fs.isDirectorySync(pathToOpen) or protocol? + unless fs.isDirectorySync(pathToOpen) atom.workspace?.open(pathToOpen, {initialLine, initialColumn}) return From 7573cd250dde92d081305cd34195e5a3b8d18edc Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 27 May 2015 11:23:18 -0700 Subject: [PATCH 1424/1783] :arrow_up: snippets and lang-html to fix html rendering --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 0fc08f37e..86f615d0d 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,7 @@ "package-generator": "0.39.0", "release-notes": "0.52.0", "settings-view": "0.206.0", - "snippets": "0.90.0", + "snippets": "0.91.0", "spell-check": "0.58.0", "status-bar": "0.74.0", "styleguide": "0.44.0", @@ -135,7 +135,7 @@ "language-gfm": "0.76.0", "language-git": "0.10.0", "language-go": "0.26.0", - "language-html": "0.37.0", + "language-html": "0.38.0", "language-hyperlink": "0.13.0", "language-java": "0.15.0", "language-javascript": "0.78.0", From 952f92c367bccd1128d338bab539ea5aefef817f Mon Sep 17 00:00:00 2001 From: Mostafa Eweda Date: Wed, 27 May 2015 11:38:06 -0700 Subject: [PATCH 1425/1783] Remove uneeded require to url --- src/window-event-handler.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/window-event-handler.coffee b/src/window-event-handler.coffee index c9fd94681..3b9d54b96 100644 --- a/src/window-event-handler.coffee +++ b/src/window-event-handler.coffee @@ -5,7 +5,6 @@ ipc = require 'ipc' shell = require 'shell' {Subscriber} = require 'emissary' fs = require 'fs-plus' -url = require 'url' # Handles low-level events related to the window. module.exports = From a89e67a3f506c6db3bd805182a8a830274ace92e Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 27 May 2015 20:49:23 +0200 Subject: [PATCH 1426/1783] :arrow_up: wrap-guide --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 86f615d0d..fdee7f9be 100644 --- a/package.json +++ b/package.json @@ -126,7 +126,7 @@ "update-package-dependencies": "0.10.0", "welcome": "0.27.0", "whitespace": "0.29.0", - "wrap-guide": "0.34.0", + "wrap-guide": "0.35.0", "language-c": "0.45.0", "language-clojure": "0.15.0", "language-coffee-script": "0.40.0", From ccd76f6876417dea6ba01e65b770f01569bb7b69 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 27 May 2015 12:44:33 -0700 Subject: [PATCH 1427/1783] :arrow_up: autocomplete-plus@2.17.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fdee7f9be..dc07331d6 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "autocomplete-atom-api": "0.9.0", "autocomplete-css": "0.7.2", "autocomplete-html": "0.7.2", - "autocomplete-plus": "2.17.1", + "autocomplete-plus": "2.17.2", "autocomplete-snippets": "1.6.3", "autoflow": "0.24.0", "autosave": "0.20.0", From 6dad5615d9eaf299ed08127f4b9b7638032fb741 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 27 May 2015 12:56:32 -0700 Subject: [PATCH 1428/1783] :arrow_up: autocomplete-plus@2.17.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dc07331d6..5bbeb7879 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "autocomplete-atom-api": "0.9.0", "autocomplete-css": "0.7.2", "autocomplete-html": "0.7.2", - "autocomplete-plus": "2.17.2", + "autocomplete-plus": "2.17.3", "autocomplete-snippets": "1.6.3", "autoflow": "0.24.0", "autosave": "0.20.0", From b7b5ceca2ddeac1721ba906bd7ae289d6e6ef3ef Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 27 May 2015 12:59:06 -0700 Subject: [PATCH 1429/1783] Save window state when quitting if windows are open --- src/browser/atom-application.coffee | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 1b2aa2e86..ae56fb1d4 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -99,12 +99,12 @@ class AtomApplication # Public: Removes the {AtomWindow} from the global window list. removeWindow: (window) -> - @windows.splice @windows.indexOf(window), 1 - if @windows.length is 0 + if @windows.length is 1 @applicationMenu?.enableWindowSpecificItems(false) if process.platform in ['win32', 'linux'] app.quit() return + @windows.splice(@windows.indexOf(window), 1) @saveState() unless window.isSpec or @quitting # Public: Adds the {AtomWindow} to the global window list. @@ -210,6 +210,7 @@ class AtomApplication @openPathOnEvent('application:open-license', path.join(process.resourcesPath, 'LICENSE.md')) app.on 'before-quit', => + @saveState() if @hasEditorWindows() @quitting = true app.on 'will-quit', => @@ -217,7 +218,7 @@ class AtomApplication @deleteSocketFile() app.on 'will-exit', => - @saveState() unless @windows.every (window) -> window.isSpec + @saveState() if @hasEditorWindows() @killAllProcesses() @deleteSocketFile() @@ -435,6 +436,9 @@ class AtomApplication states.push(initialPaths: loadSettings.initialPaths) @storageFolder.store('application.json', states) + hasEditorWindows: -> + @windows.some (window) -> not window.isSpec + loadState: -> if (states = @storageFolder.load('application.json'))?.length > 0 for state in states From 78fae88bed50dadaa449c6274f39bb8d6bab3ea3 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 27 May 2015 15:04:37 -0700 Subject: [PATCH 1430/1783] :arrow_up: find-and-replace --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5bbeb7879..e3cb86382 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", - "find-and-replace": "0.168.0", + "find-and-replace": "0.169.0", "fuzzy-finder": "0.87.0", "git-diff": "0.55.0", "go-to-line": "0.30.0", From c17287437395f158b76636ce752a7deee4e59f99 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 27 May 2015 14:50:41 -0700 Subject: [PATCH 1431/1783] Prepare 0.203 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e3cb86382..4fe81884d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "0.202.0", + "version": "0.203.0", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From 7fe8abe494d09a39c8dd33c5d96bb69fbfbceb01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=C5=BDu=C5=BEak?= Date: Thu, 28 May 2015 09:22:23 +0200 Subject: [PATCH 1432/1783] :arrow_up: language-todo@0.23.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4fe81884d..d0c445d5c 100644 --- a/package.json +++ b/package.json @@ -155,7 +155,7 @@ "language-source": "0.9.0", "language-sql": "0.15.0", "language-text": "0.6.0", - "language-todo": "0.22.0", + "language-todo": "0.23.0", "language-toml": "0.16.0", "language-xml": "0.30.0", "language-yaml": "0.22.0" From 31cf19a205f953cc9f800afa52d72e9f319d1d7a Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 28 May 2015 10:38:20 +0200 Subject: [PATCH 1433/1783] Use previous definition of scope selector match to fix API breakage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I switched to first-mate Selector because I didn’t want to replicate the poorly-defined Token::matchesScopeSelector method now that tokens are not stored on lines. However, the first-mate semantics are stricter and that broke the API. Perhaps using selector-kit here would be better, but I just wanted to put back exactly to how it was for now. /cc @ypresto --- spec/tokenized-buffer-spec.coffee | 2 +- src/tokenized-buffer.coffee | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/spec/tokenized-buffer-spec.coffee b/spec/tokenized-buffer-spec.coffee index 9d94cb80a..dc57d3fee 100644 --- a/spec/tokenized-buffer-spec.coffee +++ b/spec/tokenized-buffer-spec.coffee @@ -572,7 +572,7 @@ describe "TokenizedBuffer", -> describe "when the selector matches a run of multiple tokens at the position", -> it "returns the range covered by all contigous tokens (within a single line)", -> - expect(tokenizedBuffer.bufferRangeForScopeAtPosition('.meta.function', [1, 18])).toEqual [[1, 6], [1, 28]] + expect(tokenizedBuffer.bufferRangeForScopeAtPosition('.function', [1, 18])).toEqual [[1, 6], [1, 28]] describe "when the editor.tabLength config value changes", -> it "updates the tab length of the tokenized lines", -> diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 60ebe16f0..55d2e7e37 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -426,7 +426,6 @@ class TokenizedBuffer extends Model new Point(row, column) bufferRangeForScopeAtPosition: (selector, position) -> - selector = new ScopeSelector(selector.replace(/^\./, '')) position = Point.fromObject(position) {openScopes, tags} = @tokenizedLines[position.row] @@ -446,7 +445,8 @@ class TokenizedBuffer extends Model else startColumn = endColumn - return unless selector.matches(scopes) + + return unless selectorMatchesAnyScope(selector, scopes) startScopes = scopes.slice() for startTokenIndex in [(tokenIndex - 1)..0] by -1 @@ -457,7 +457,7 @@ class TokenizedBuffer extends Model else startScopes.push(atom.grammars.scopeForId(tag)) else - break unless selector.matches(startScopes) + break unless selectorMatchesAnyScope(selector, startScopes) startColumn -= tag endScopes = scopes.slice() @@ -469,7 +469,7 @@ class TokenizedBuffer extends Model else endScopes.pop() else - break unless selector.matches(endScopes) + break unless selectorMatchesAnyScope(selector, endScopes) endColumn += tag new Range(new Point(position.row, startColumn), new Point(position.row, endColumn)) @@ -504,3 +504,9 @@ if Grim.includeDeprecatedAPIs Grim.deprecate("TokenizedBuffer::on is deprecated. Use event subscription methods instead.") EmitterMixin::on.apply(this, arguments) + +selectorMatchesAnyScope = (selector, scopes) -> + targetClasses = selector.replace(/^\./, '').split('.') + _.any scopes, (scope) -> + scopeClasses = scope.split('.') + _.isSubset(targetClasses, scopeClasses) From 2031e3dfde4a91d881894887135764da2b701574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Machist=C3=A9=20N=2E=20Quintana?= Date: Thu, 28 May 2015 09:12:49 -0400 Subject: [PATCH 1434/1783] Use lsb virtual package instead of hard require --- resources/linux/redhat/atom.spec.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/linux/redhat/atom.spec.in b/resources/linux/redhat/atom.spec.in index 3bc37e83a..2bd89cb9a 100644 --- a/resources/linux/redhat/atom.spec.in +++ b/resources/linux/redhat/atom.spec.in @@ -7,7 +7,7 @@ URL: https://atom.io/ AutoReqProv: no # Avoid libchromiumcontent.so missing dependency Prefix: <%= installDir %> -Requires: redhat-lsb-core +Requires: lsb %description <%= description %> From 7298d141a63854ac1c109e2382bb8be2c236819a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 28 May 2015 08:47:15 -0700 Subject: [PATCH 1435/1783] Prepare 0.204 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d0c445d5c..1602fa446 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "0.203.0", + "version": "0.204.0", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From 67f9d502264fb63c284d233c86cf0977c552b478 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 28 May 2015 09:06:56 -0700 Subject: [PATCH 1436/1783] :arrow_up: atom-keymap@5.1.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1602fa446..100bc6a71 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "atomShellVersion": "0.22.3", "dependencies": { "async": "0.2.6", - "atom-keymap": "^5.1.4", + "atom-keymap": "^5.1.5", "atom-space-pen-views": "^2.0.4", "babel-core": "^5.1.11", "bootstrap": "^3.3.4", From 99d4d90d85cf41446029405f115f46fe13b985d2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 28 May 2015 09:23:21 -0700 Subject: [PATCH 1437/1783] Prepare 0.205 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 100bc6a71..e93cbb160 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "0.204.0", + "version": "0.205.0", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From 60633de701d730994d742a587d09249018da37c7 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 28 May 2015 12:24:35 -0700 Subject: [PATCH 1438/1783] :arrow_up: find-and-replace --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e93cbb160..5165c61eb 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", - "find-and-replace": "0.169.0", + "find-and-replace": "0.170.0", "fuzzy-finder": "0.87.0", "git-diff": "0.55.0", "go-to-line": "0.30.0", From 7034846d4ff665a87470408cbfb9630c255bdd68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Machist=C3=A9=20N=2E=20Quintana?= Date: Thu, 28 May 2015 15:26:54 -0400 Subject: [PATCH 1439/1783] Skip linting for benchmark fixtures --- .coffeelintignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.coffeelintignore b/.coffeelintignore index 1db51fed7..5c4e30278 100644 --- a/.coffeelintignore +++ b/.coffeelintignore @@ -1 +1,2 @@ spec/fixtures +benchmark/fixtures From 447dfd8bec6df7841df255edae73a8c43f854074 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 28 May 2015 22:58:29 +0200 Subject: [PATCH 1440/1783] =?UTF-8?q?If=20a=20keystroke=20is=20bound=20to?= =?UTF-8?q?=20=E2=80=98unset!=E2=80=99,=20omit=20it=20in=20the=20applicati?= =?UTF-8?q?on=20menu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes atom/atom-keymap#79 This is more general than I would like. If the keystroke is unset in any context, we err on the side of caution and don’t add it to the application menu for any command. Since our application menu isn’t context aware, this should be good enough for now and solve the 80% case. Someday we should make the application menu update / gray out options when the focused element changes. --- spec/menu-manager-spec.coffee | 30 ++++++++++++++++++++++++++++++ src/menu-manager.coffee | 12 +++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/spec/menu-manager-spec.coffee b/spec/menu-manager-spec.coffee index d92c921c4..f86b6e1a0 100644 --- a/spec/menu-manager-spec.coffee +++ b/spec/menu-manager-spec.coffee @@ -1,3 +1,4 @@ +path = require 'path' MenuManager = require '../src/menu-manager' describe "MenuManager", -> @@ -46,3 +47,32 @@ describe "MenuManager", -> menu.add [{label: "A", submenu: [{label: "B", command: "b"}]}] menu.add [{label: "A", submenu: [{label: "B", command: "b"}]}] expect(menu.template[originalItemCount]).toEqual {label: "A", submenu: [{label: "B", command: "b"}]} + + describe "::update()", -> + it "sends the current menu template and associated key bindings to the browser process", -> + spyOn(menu, 'sendToBrowserProcess') + menu.add [{label: "A", submenu: [{label: "B", command: "b"}]}] + atom.keymap.add 'test', 'atom-workspace': 'ctrl-b': 'b' + menu.update() + + waits 1 + + runs -> expect(menu.sendToBrowserProcess.argsForCall[0][1]['b']).toEqual ['ctrl-b'] + + it "omits key bindings that are mapped to unset! in any context", -> + # it would be nice to be smarter about omitting, but that would require a much + # more dynamic interaction between the currently focused element and the menu + spyOn(menu, 'sendToBrowserProcess') + menu.add [{label: "A", submenu: [{label: "B", command: "b"}]}] + atom.keymap.add 'test', 'atom-workspace': 'ctrl-b': 'b' + atom.keymap.add 'test', 'atom-text-editor': 'ctrl-b': 'unset!' + + waits 1 + + runs -> expect(menu.sendToBrowserProcess.argsForCall[0][1]['b']).toBeUndefined() + + it "updates the application menu when a keymap is reloaded", -> + spyOn(menu, 'update') + keymapPath = path.join(__dirname, 'fixtures', 'packages', 'package-with-keymaps', 'keymaps', 'keymap-1.cson') + atom.keymaps.reloadKeymap(keymapPath) + expect(menu.update).toHaveBeenCalled() diff --git a/src/menu-manager.coffee b/src/menu-manager.coffee index b5c9a80e3..b138f2da2 100644 --- a/src/menu-manager.coffee +++ b/src/menu-manager.coffee @@ -63,6 +63,7 @@ class MenuManager @pendingUpdateOperation = null @template = [] atom.keymaps.onDidLoadBundledKeymaps => @loadPlatformItems() + atom.keymaps.onDidReloadKeymap => @update() atom.packages.onDidActivateInitialPackages => @sortPackagesMenu() # Public: Adds the given items to the application menu. @@ -139,10 +140,19 @@ class MenuManager update: -> clearImmediate(@pendingUpdateOperation) if @pendingUpdateOperation? @pendingUpdateOperation = setImmediate => - keystrokesByCommand = {} + includedBindings = [] + unsetKeystrokes = new Set + for binding in atom.keymaps.getKeyBindings() when @includeSelector(binding.selector) + includedBindings.push(binding) + if binding.command is 'unset!' + unsetKeystrokes.add(binding.keystrokes) + + keystrokesByCommand = {} + for binding in includedBindings when not unsetKeystrokes.has(binding.keystrokes) keystrokesByCommand[binding.command] ?= [] keystrokesByCommand[binding.command].unshift binding.keystrokes + @sendToBrowserProcess(@template, keystrokesByCommand) loadPlatformItems: -> From 98dc2f9d7f717944b7a3a928a5a8880e8c6038eb Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Thu, 28 May 2015 16:09:15 -0700 Subject: [PATCH 1441/1783] Style links and code blocks in text-* classes --- static/atom.less | 1 + static/text.less | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 static/text.less diff --git a/static/atom.less b/static/atom.less index b45d7b29a..1acb0f54b 100644 --- a/static/atom.less +++ b/static/atom.less @@ -25,5 +25,6 @@ @import "text-editor-light"; @import "select-list"; @import "syntax"; +@import "text"; @import "utilities"; @import "octicons"; diff --git a/static/text.less b/static/text.less new file mode 100644 index 000000000..4782ee7f9 --- /dev/null +++ b/static/text.less @@ -0,0 +1,35 @@ +.text-bits (@type) { + @text-color: "text-color-@{type}"; + @bg-color: "background-color-@{type}"; + + code { + color: @@text-color; + background: fadeout(@@bg-color, 80%); + } + + a, a code { + color: @@text-color; + text-decoration: underline; + color: darken(@@text-color, 10%); + + &:hover { + color: darken(@@text-color, 15%); + } + } +} + +.text-info { + .text-bits(info); +} + +.text-success { + .text-bits(success); +} + +.text-warning { + .text-bits(warning); +} + +.text-error { + .text-bits(error); +} From ba9c0c65c1e61d4b38d9d9f41d5754bd7f0bc124 Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 29 May 2015 15:12:34 +0900 Subject: [PATCH 1442/1783] :arrow_up: one-dark/light-syntax@0.7.0 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 5165c61eb..5bb2738bc 100644 --- a/package.json +++ b/package.json @@ -78,8 +78,8 @@ "base16-tomorrow-dark-theme": "0.26.0", "base16-tomorrow-light-theme": "0.9.0", "one-dark-ui": "0.8.2", - "one-dark-syntax": "0.5.0", - "one-light-syntax": "0.6.0", + "one-dark-syntax": "0.7.0", + "one-light-syntax": "0.7.0", "one-light-ui": "0.8.2", "solarized-dark-syntax": "0.35.0", "solarized-light-syntax": "0.21.0", From 7c968542faccb5d09d501475c3761c0b65582950 Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 29 May 2015 15:13:50 +0900 Subject: [PATCH 1443/1783] :arrow_up: one-dark/light-ui@0.9.0 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 5bb2738bc..54ef562b4 100644 --- a/package.json +++ b/package.json @@ -77,10 +77,10 @@ "atom-light-ui": "0.41.0", "base16-tomorrow-dark-theme": "0.26.0", "base16-tomorrow-light-theme": "0.9.0", - "one-dark-ui": "0.8.2", + "one-dark-ui": "0.9.0", "one-dark-syntax": "0.7.0", "one-light-syntax": "0.7.0", - "one-light-ui": "0.8.2", + "one-light-ui": "0.9.0", "solarized-dark-syntax": "0.35.0", "solarized-light-syntax": "0.21.0", "archive-view": "0.57.0", From 9b4d62b687bc91b28ac4be16453f5fb148d5f1c7 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 29 May 2015 15:21:00 +0200 Subject: [PATCH 1444/1783] :bug: Update cursors after model changes /cc: @nathansobo --- spec/text-editor-presenter-spec.coffee | 13 +++++++++++++ src/text-editor-presenter.coffee | 1 + 2 files changed, 14 insertions(+) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 0d5c5cffb..142026913 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -1108,6 +1108,19 @@ describe "TextEditorPresenter", -> expect(stateForCursor(presenter, 3)).toEqual {top: 0, left: 12 * 10, width: 10, height: 10} expect(stateForCursor(presenter, 4)).toEqual {top: 8 * 10 - 50, left: 4 * 10, width: 10, height: 10} + it "updates when ::scrollTop changes after the model was changed", -> + editor.setCursorBufferPosition([8, 22]) + presenter = buildPresenter(explicitHeight: 50, scrollTop: 10 * 8) + + expect(stateForCursor(presenter, 0)).toEqual {top: 0, left: 10 * 22, width: 10, height: 10} + + expectStateUpdate presenter, -> + editor.getBuffer().deleteRow(12) + editor.getBuffer().deleteRow(11) + editor.getBuffer().deleteRow(10) + + expect(stateForCursor(presenter, 0)).toEqual {top: 20, left: 10 * 22, width: 10, height: 10} + it "updates when ::explicitHeight changes", -> editor.setSelectedBufferRanges([ [[1, 2], [1, 2]], diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 2acd39863..7b63fa10a 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -115,6 +115,7 @@ class TextEditorPresenter @shouldUpdateScrollbarsState = true @shouldUpdateContentState = true @shouldUpdateDecorations = true + @shouldUpdateCursorsState = true @shouldUpdateTilesState = true @shouldUpdateLineNumberGutterState = true @shouldUpdateLineNumbersState = true From 68030e1793aa7bb25daa01a3b823ce2832cdd1f4 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Fri, 29 May 2015 10:30:56 -0700 Subject: [PATCH 1445/1783] :arrow_up: autocomplete-snippets to fix exception --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 54ef562b4..430d9cfc8 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,7 @@ "autocomplete-css": "0.7.2", "autocomplete-html": "0.7.2", "autocomplete-plus": "2.17.3", - "autocomplete-snippets": "1.6.3", + "autocomplete-snippets": "1.7.0", "autoflow": "0.24.0", "autosave": "0.20.0", "background-tips": "0.25.0", From fd6e8fabb16ce652d0b89e8df7e364357aded91e Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Fri, 29 May 2015 10:31:19 -0700 Subject: [PATCH 1446/1783] :arrow_up: snippets to load bundled snippets first --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 430d9cfc8..86c238011 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,7 @@ "package-generator": "0.39.0", "release-notes": "0.52.0", "settings-view": "0.206.0", - "snippets": "0.91.0", + "snippets": "0.92.0", "spell-check": "0.58.0", "status-bar": "0.74.0", "styleguide": "0.44.0", From fad99c69e617389d532fc7483a4425cfb15a19d0 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Fri, 29 May 2015 10:38:37 -0700 Subject: [PATCH 1447/1783] Fix build issue: import ui vars. --- static/text.less | 2 ++ 1 file changed, 2 insertions(+) diff --git a/static/text.less b/static/text.less index 4782ee7f9..249cf820d 100644 --- a/static/text.less +++ b/static/text.less @@ -1,3 +1,5 @@ +@import "ui-variables"; + .text-bits (@type) { @text-color: "text-color-@{type}"; @bg-color: "background-color-@{type}"; From 5389156d767f33fa9513549b8fed56c85b9c8f1d Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 29 May 2015 20:23:08 +0200 Subject: [PATCH 1448/1783] :arrow_up: first-mate to fix regression --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 86c238011..81b2771ec 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "delegato": "^1", "emissary": "^1.3.3", "event-kit": "^1.2.0", - "first-mate": "^4.1.5", + "first-mate": "^4.1.6", "fs-plus": "^2.8.0", "fstream": "0.1.24", "fuzzaldrin": "^2.1", From 97f817c542f2a567af70a685f75942a5255bc9e7 Mon Sep 17 00:00:00 2001 From: Thomas Johansen Date: Fri, 29 May 2015 21:51:27 +0200 Subject: [PATCH 1449/1783] :memo: Add sentence about lowercasing command names --- src/command-registry.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/command-registry.coffee b/src/command-registry.coffee index 2de076d1a..72098eda0 100644 --- a/src/command-registry.coffee +++ b/src/command-registry.coffee @@ -22,6 +22,7 @@ SequenceCount = 0 # will typically be the name of your package, and `action` describes the # behavior of your command. If either part consists of multiple words, these # must be separated by hyphens. E.g. `awesome-package:turn-it-up-to-eleven`. +# All words should be lowercased. # # As the event bubbles upward through the DOM, all registered event listeners # with matching selectors are invoked in order of specificity. In the event of a From 604e41966de70bd28ae8a0ab06621b01aa3cf58f Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 29 May 2015 22:13:22 +0200 Subject: [PATCH 1450/1783] :arrow_up: bracket-matcher --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 81b2771ec..37fb79894 100644 --- a/package.json +++ b/package.json @@ -93,7 +93,7 @@ "autosave": "0.20.0", "background-tips": "0.25.0", "bookmarks": "0.35.0", - "bracket-matcher": "0.74.0", + "bracket-matcher": "0.75.0", "command-palette": "0.36.0", "deprecation-cop": "0.52.0", "dev-live-reload": "0.46.0", From 49c8a10c08d0f8b08a440287e59ae73643ad6b26 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Fri, 29 May 2015 13:21:45 -0700 Subject: [PATCH 1451/1783] Fix text lint error --- static/text.less | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/static/text.less b/static/text.less index 249cf820d..a189fbf9a 100644 --- a/static/text.less +++ b/static/text.less @@ -1,21 +1,23 @@ @import "ui-variables"; .text-bits (@type) { - @text-color: "text-color-@{type}"; - @bg-color: "background-color-@{type}"; + @text-color-name: "text-color-@{type}"; + @bg-color-name: "background-color-@{type}"; + + @text-color: @@text-color-name; + @bg-color: @@bg-color-name; code { - color: @@text-color; - background: fadeout(@@bg-color, 80%); + color: @text-color; + background: fadeout(@bg-color, 80%); } a, a code { - color: @@text-color; text-decoration: underline; - color: darken(@@text-color, 10%); + color: darken(@text-color, 10%); &:hover { - color: darken(@@text-color, 15%); + color: darken(@text-color, 15%); } } } From 224575fc46757e22f6206e64aa28a1b43e91177f Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 29 May 2015 16:32:19 -0700 Subject: [PATCH 1452/1783] Always fall back on default lineOverdrawMargin --- src/text-editor-component.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 431966910..45a8a9720 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -47,7 +47,7 @@ class TextEditorComponent model: @editor scrollTop: @editor.getScrollTop() scrollLeft: @editor.getScrollLeft() - lineOverdrawMargin: lineOverdrawMargin + lineOverdrawMargin: @lineOverdrawMargin cursorBlinkPeriod: @cursorBlinkPeriod cursorBlinkResumeDelay: @cursorBlinkResumeDelay stoppedScrollingDelay: 200 From b59bec5f9db1314053a4704c359a0fda1ab3eb45 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 29 May 2015 17:18:48 -0700 Subject: [PATCH 1453/1783] Add Set::isEqual method in specs This allows us to use the .toEqual matcher to compare Set objects. --- spec/spec-helper.coffee | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/spec/spec-helper.coffee b/spec/spec-helper.coffee index 15874ff6f..5ba54a242 100644 --- a/spec/spec-helper.coffee +++ b/spec/spec-helper.coffee @@ -49,6 +49,25 @@ Object.defineProperty document, 'title', get: -> documentTitle set: (title) -> documentTitle = title +Set.prototype.jasmineToString = -> + result = "Set {" + first = true + @forEach (element) -> + result += ", " unless first + result += element.toString() + first = false + result + "}" + +Set.prototype.isEqual = (other) -> + if other instanceof Set + return false if @size isnt other.size + values = @values() + until (next = values.next()).done + return false unless other.has(next.value) + true + else + false + jasmine.getEnv().addEqualityTester(_.isEqual) # Use underscore's definition of equality for toEqual assertions if process.env.CI From 6f553f234cdedb6f6720e2fd767a9c8bfcbaf20f Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 29 May 2015 17:21:23 -0700 Subject: [PATCH 1454/1783] Add TextEditor::observeMarkers, use it in presenter Signed-off-by: Nathan Sobo --- spec/display-buffer-spec.coffee | 44 +++++++++++++ src/display-buffer.coffee | 7 +++ src/marker-observation-window.coffee | 12 ++++ src/text-editor-presenter.coffee | 94 +++++++++++++++++----------- src/text-editor.coffee | 22 +++++++ 5 files changed, 141 insertions(+), 38 deletions(-) create mode 100644 src/marker-observation-window.coffee diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index 140ca2f9e..4c48607a5 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -1207,6 +1207,50 @@ describe "DisplayBuffer", -> expect(markerCreated1).toHaveBeenCalled() expect(markerCreated2).not.toHaveBeenCalled() + describe "::observeMarkers(callback)", -> + [observationWindow, events] = [] + + beforeEach -> + events = [] + observationWindow = displayBuffer.observeMarkers (event) -> events.push(event) + displayBuffer.unfoldBufferRow(4, 7) + + it "calls the callback when markers enter, leave, or move within the screen range", -> + expect(events).toHaveLength 0 + + observationWindow.setScreenRange([[0, 0], [4, 0]]) + expect(events).toHaveLength 0 + + marker1 = displayBuffer.markScreenPosition([4, 2]) + expect(events).toHaveLength 0 + + observationWindow.setScreenRange([[0, 0], [5, 0]]) + expect(events).toHaveLength 1 + expect(events[0]).toEqual { + insert: new Set([marker1.id]) + update: new Set + remove: new Set + } + + marker2 = displayBuffer.markScreenPosition([5, 2]) + expect(events).toHaveLength 1 + + observationWindow.setBufferRange([[1, 0], [6, 0]]) + expect(events).toHaveLength 2 + expect(events[1]).toEqual { + insert: new Set([marker2.id]) + update: new Set([marker1.id]) + remove: new Set + } + + marker1.destroy() + expect(events).toHaveLength 3 + expect(events[2]).toEqual { + insert: new Set + update: new Set + remove: new Set([marker1.id]) + } + describe "decorations", -> [marker, decoration, decorationProperties] = [] beforeEach -> diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index b2460addc..b361e416b 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -10,6 +10,7 @@ Model = require './model' Token = require './token' Decoration = require './decoration' Marker = require './marker' +MarkerObservationWindow = require './marker-observation-window' class BufferToScreenConversionError extends Error constructor: (@message, @metadata) -> @@ -950,6 +951,9 @@ class DisplayBuffer extends Model @emitter.emit 'did-remove-decoration', decoration delete @decorationsByMarkerId[marker.id] if decorations.length is 0 + decorationsForMarkerId: (markerId) -> + @decorationsByMarkerId[markerId] + # Retrieves a {Marker} based on its id. # # id - A {Number} representing a marker id @@ -1045,6 +1049,9 @@ class DisplayBuffer extends Model params = @translateToBufferMarkerParams(params) @buffer.findMarkers(params).map (stringMarker) => @getMarker(stringMarker.id) + observeMarkers: (callback) -> + new MarkerObservationWindow(this, @buffer.observeMarkers(callback)) + translateToBufferMarkerParams: (params) -> bufferMarkerParams = {} for key, value of params diff --git a/src/marker-observation-window.coffee b/src/marker-observation-window.coffee new file mode 100644 index 000000000..aa7b71f69 --- /dev/null +++ b/src/marker-observation-window.coffee @@ -0,0 +1,12 @@ +module.exports = +class MarkerObservationWindow + constructor: (@displayBuffer, @bufferWindow) -> + + setScreenRange: (range) -> + @bufferWindow.setRange(@displayBuffer.bufferRangeForScreenRange(range)) + + setBufferRange: (range) -> + @bufferWindow.setRange(range) + + destroy: -> + @bufferWindow.destroy() diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 3aea57f29..e3e3ad5a7 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -1,4 +1,4 @@ -{CompositeDisposable, Emitter} = require 'event-kit' +{CompositeDisposable, Disposable, Emitter} = require 'event-kit' {Point, Range} = require 'text-buffer' _ = require 'underscore-plus' Decoration = require './decoration' @@ -24,6 +24,11 @@ class TextEditorPresenter @disposables = new CompositeDisposable @emitter = new Emitter @characterWidthsByScope = {} + @rangesByDecorationId = {} + @lineDecorationsByScreenRow = {} + @lineNumberDecorationsByScreenRow = {} + @customGutterDecorationsByGutterNameAndScreenRow = {} + @highlightDecorationsById = {} @transferMeasurementsToModel() @observeModel() @observeConfig() @@ -121,6 +126,10 @@ class TextEditorPresenter @shouldUpdateCustomGutterDecorationState = true @emitDidUpdateState() + + @markerObservationWindow = @model.observeMarkers(@markersInRangeDidChange.bind(this)) + @disposables.add new Disposable => @markerObservationWindow.destroy() + @disposables.add @model.onDidChangeGrammar(@didChangeGrammar.bind(this)) @disposables.add @model.onDidChangePlaceholderText => @shouldUpdateContentState = true @@ -579,6 +588,7 @@ class TextEditorPresenter visibleLinesCount = Math.ceil(@height / @lineHeight) + 1 endRow = startRow + visibleLinesCount + @lineOverdrawMargin @endRow = Math.min(@model.getScreenLineCount(), endRow) + @markerObservationWindow.setScreenRange(Range(Point(@startRow, 0), Point(@endRow, 0))) updateScrollWidth: -> return unless @contentWidth? and @clientWidth? @@ -1055,7 +1065,6 @@ class TextEditorPresenter observeDecoration: (decoration) -> decorationDisposables = new CompositeDisposable - decorationDisposables.add decoration.getMarker().onDidChange(@decorationMarkerDidChange.bind(this, decoration)) if decoration.isType('highlight') decorationDisposables.add decoration.onDidFlash(@highlightDidFlash.bind(this, decoration)) decorationDisposables.add decoration.onDidChangeProperties(@decorationPropertiesDidChange.bind(this, decoration)) @@ -1065,38 +1074,41 @@ class TextEditorPresenter @didDestroyDecoration(decoration) @disposables.add(decorationDisposables) - decorationMarkerDidChange: (decoration, change) -> - if decoration.isType('line') or decoration.isType('gutter') - return if change.textChanged - - intersectsVisibleRowRange = false - oldRange = new Range(change.oldTailScreenPosition, change.oldHeadScreenPosition) - newRange = new Range(change.newTailScreenPosition, change.newHeadScreenPosition) - - if oldRange.intersectsRowRange(@startRow, @endRow - 1) - @removeFromLineDecorationCaches(decoration, oldRange) - intersectsVisibleRowRange = true - - if newRange.intersectsRowRange(@startRow, @endRow - 1) - @addToLineDecorationCaches(decoration, newRange) - intersectsVisibleRowRange = true - - if intersectsVisibleRowRange - @shouldUpdateLinesState = true if decoration.isType('line') - if decoration.isType('line-number') - @shouldUpdateLineNumbersState = true - else if decoration.isType('gutter') - @shouldUpdateCustomGutterDecorationState = true + markersInRangeDidChange: (event) -> + event.insert.forEach (markerId) => + range = @model.getMarker(markerId).getScreenRange() + if decorations = @model.decorationsForMarkerId(markerId) + for decoration in decorations + @decorationMarkerDidChange(decoration) + if decoration.isType('line') or decoration.isType('gutter') + @addToLineDecorationCaches(decoration, range) + event.update.forEach (markerId) => + range = @model.getMarker(markerId).getScreenRange() + if decorations = @model.decorationsForMarkerId(markerId) + for decoration in decorations + @decorationMarkerDidChange(decoration) + if decoration.isType('line') or decoration.isType('gutter') + @removeFromLineDecorationCaches(decoration) + @addToLineDecorationCaches(decoration, range) + event.remove.forEach (markerId) => + if decorations = @model.decorationsForMarkerId(markerId) + for decoration in decorations + @decorationMarkerDidChange(decoration) + if decoration.isType('line') or decoration.isType('gutter') + @removeFromLineDecorationCaches(decoration) + @emitDidUpdateState() + decorationMarkerDidChange: (decoration) -> if decoration.isType('highlight') - return if change.textChanged - @updateHighlightState(decoration) - if decoration.isType('overlay') @shouldUpdateOverlaysState = true - - @emitDidUpdateState() + if decoration.isType('line') + @shouldUpdateLinesState = true + if decoration.isType('line-number') + @shouldUpdateLineNumbersState = true + else if decoration.isType('gutter') + @shouldUpdateCustomGutterDecorationState = true decorationPropertiesDidChange: (decoration, event) -> {oldProperties} = event @@ -1161,6 +1173,7 @@ class TextEditorPresenter @emitDidUpdateState() updateDecorations: -> + @rangesByDecorationId = {} @lineDecorationsByScreenRow = {} @lineNumberDecorationsByScreenRow = {} @customGutterDecorationsByGutterNameAndScreenRow = {} @@ -1183,16 +1196,19 @@ class TextEditorPresenter return - removeFromLineDecorationCaches: (decoration, range) -> - @removePropertiesFromLineDecorationCaches(decoration.id, decoration.getProperties(), range) + removeFromLineDecorationCaches: (decoration) -> + @removePropertiesFromLineDecorationCaches(decoration.id, decoration.getProperties()) - removePropertiesFromLineDecorationCaches: (decorationId, decorationProperties, range) -> - gutterName = decorationProperties.gutterName - for row in [range.start.row..range.end.row] by 1 - delete @lineDecorationsByScreenRow[row]?[decorationId] - delete @lineNumberDecorationsByScreenRow[row]?[decorationId] - delete @customGutterDecorationsByGutterNameAndScreenRow[gutterName]?[row]?[decorationId] if gutterName - return + removePropertiesFromLineDecorationCaches: (decorationId, decorationProperties) -> + if range = @rangesByDecorationId[decorationId] + delete @rangesByDecorationId[decorationId] + + gutterName = decorationProperties.gutterName + for row in [range.start.row..range.end.row] by 1 + delete @lineDecorationsByScreenRow[row]?[decorationId] + delete @lineNumberDecorationsByScreenRow[row]?[decorationId] + delete @customGutterDecorationsByGutterNameAndScreenRow[gutterName]?[row]?[decorationId] if gutterName + return addToLineDecorationCaches: (decoration, range) -> marker = decoration.getMarker() @@ -1206,6 +1222,8 @@ class TextEditorPresenter return if properties.onlyEmpty omitLastRow = range.end.column is 0 + @rangesByDecorationId[decoration.id] = range + for row in [range.start.row..range.end.row] by 1 continue if properties.onlyHead and row isnt marker.getHeadScreenPosition().row continue if omitLastRow and row is range.end.row diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 6d979fdf7..edfc17e0d 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -1378,6 +1378,9 @@ class TextEditor extends Model decorationForId: (id) -> @displayBuffer.decorationForId(id) + decorationsForMarkerId: (id) -> + @displayBuffer.decorationsForMarkerId(id) + ### Section: Markers ### @@ -1480,6 +1483,25 @@ class TextEditor extends Model findMarkers: (properties) -> @displayBuffer.findMarkers(properties) + # Extended: Observe changes in the set of markers that intersect a particular + # region of the editor. + # + # * `callback` A {Function} to call whenever one or more {Marker}s appears, + # disappears, or moves within the given region. + # * `event` An {Object} with the following keys: + # * `insert` A {Set} containing the ids of all markers that appeared + # in the range. + # * `update` A {Set} containing the ids of all markers that moved within + # the region. + # * `remove` A {Set} containing the ids of all markers that disappeared + # from the region. + # + # Returns a {MarkerObservationWindow}, which allows you to specify the region + # of interest by calling {MarkerObservationWindow::setBufferRange} or + # {MarkerObservationWindow::setScreenRange}. + observeMarkers: (callback) -> + @displayBuffer.observeMarkers(callback) + # Extended: Get the {Marker} for the given marker id. # # * `id` {Number} id of the marker From eed1ecbbdcbc1c571be7ed439cddafe737a6b823 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 29 May 2015 17:29:03 -0700 Subject: [PATCH 1455/1783] Wait to observe buffer markers until Marker::onDidChange called Signed-off-by: Nathan Sobo --- src/marker.coffee | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/marker.coffee b/src/marker.coffee index a0d8bda00..536edfb63 100644 --- a/src/marker.coffee +++ b/src/marker.coffee @@ -48,6 +48,7 @@ class Marker oldTailBufferPosition: null oldTailScreenPosition: null wasValid: true + hasChangeObservers: false ### Section: Construction and Destruction @@ -57,14 +58,8 @@ class Marker @emitter = new Emitter @disposables = new CompositeDisposable @id = @bufferMarker.id - @oldHeadBufferPosition = @getHeadBufferPosition() - @oldHeadScreenPosition = @getHeadScreenPosition() - @oldTailBufferPosition = @getTailBufferPosition() - @oldTailScreenPosition = @getTailScreenPosition() - @wasValid = @isValid() @disposables.add @bufferMarker.onDidDestroy => @destroyed() - @disposables.add @bufferMarker.onDidChange (event) => @notifyObservers(event) # Essential: Destroys the marker, causing it to emit the 'destroyed' event. Once # destroyed, a marker cannot be restored by undo/redo operations. @@ -102,6 +97,14 @@ class Marker # # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. onDidChange: (callback) -> + unless @hasChangeObservers + @oldHeadBufferPosition = @getHeadBufferPosition() + @oldHeadScreenPosition = @getHeadScreenPosition() + @oldTailBufferPosition = @getTailBufferPosition() + @oldTailScreenPosition = @getTailScreenPosition() + @wasValid = @isValid() + @disposables.add @bufferMarker.onDidChange (event) => @notifyObservers(event) + @hasChangeObservers = true @emitter.on 'did-change', callback # Essential: Invoke the given callback when the marker is destroyed. From 5884525648fd7a5357273dc9dd29cfb385439204 Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Sun, 31 May 2015 05:27:38 -0700 Subject: [PATCH 1456/1783] :memo: Add returns Disposable to ContextMenuManager.add --- src/context-menu-manager.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/context-menu-manager.coffee b/src/context-menu-manager.coffee index 0fdcf4ab6..73bcbf440 100644 --- a/src/context-menu-manager.coffee +++ b/src/context-menu-manager.coffee @@ -100,6 +100,9 @@ class ContextMenuManager # whether to display this item on a given context menu deployment. Called # with the following argument: # * `event` The click event that deployed the context menu. + # + # Returns a {Disposable} on which `.dispose()` can be called to remove the + # added menu items. add: (itemsBySelector) -> if Grim.includeDeprecatedAPIs # Detect deprecated file path as first argument From c81409cf90e09f3e37e0a62b2b6001001bb4f6ef Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Sun, 31 May 2015 11:15:48 -0400 Subject: [PATCH 1457/1783] :arrow_up: language-json@0.15.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 37fb79894..25dda7539 100644 --- a/package.json +++ b/package.json @@ -139,7 +139,7 @@ "language-hyperlink": "0.13.0", "language-java": "0.15.0", "language-javascript": "0.78.0", - "language-json": "0.14.0", + "language-json": "0.15.0", "language-less": "0.27.0", "language-make": "0.14.0", "language-mustache": "0.11.0", From eaaa6b15e5bd786a66281e2e00cd33962f4ee0cd Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 1 Jun 2015 09:35:41 -0700 Subject: [PATCH 1458/1783] :non-potable_water: Prevent stdout/stderr data listener leaks Old listeners were not cleaned up before new ones were being added causing the following console message: warning: possible EventEmitter memory leak detected. Refs #7033 --- spec/task-spec.coffee | 13 +++++++++++++ src/task.coffee | 11 +++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/spec/task-spec.coffee b/spec/task-spec.coffee index 81a8713ad..bddb59d86 100644 --- a/spec/task-spec.coffee +++ b/spec/task-spec.coffee @@ -57,3 +57,16 @@ describe "Task", -> expect(deprecations.length).toBe 1 expect(deprecations[0].getStacks()[0][1].fileName).toBe handlerPath jasmine.restoreDeprecationsSnapshot() + + it "adds data listeners to standard out and error to report output", -> + task = new Task(require.resolve('./fixtures/task-spec-handler')) + {stdout, stderr} = task.childProcess + + task.start() + task.start() + expect(stdout.listeners('data').length).toBe 1 + expect(stderr.listeners('data').length).toBe 1 + + task.terminate() + expect(stdout.listeners('data').length).toBe 0 + expect(stderr.listeners('data').length).toBe 0 diff --git a/src/task.coffee b/src/task.coffee index d752ea11d..939b71635 100644 --- a/src/task.coffee +++ b/src/task.coffee @@ -100,11 +100,12 @@ class Task @childProcess.removeAllListeners() @childProcess.on 'message', ({event, args}) => @emit(event, args...) if @childProcess? + # Catch the errors that happened before task-bootstrap. - @childProcess.stdout.on 'data', (data) -> - console.log data.toString() - @childProcess.stderr.on 'data', (data) -> - console.error data.toString() + @childProcess.stdout.removeAllListeners() + @childProcess.stdout.on 'data', (data) -> console.log data.toString() + @childProcess.stderr.removeAllListeners() + @childProcess.stderr.on 'data', (data) -> console.error data.toString() # Public: Starts the task. # @@ -152,6 +153,8 @@ class Task return unless @childProcess? @childProcess.removeAllListeners() + @childProcess.stdout.removeAllListeners() + @childProcess.stderr.removeAllListeners() @childProcess.kill() @childProcess = null From b68902dd8303e99e85aa814be1be36c638ebe938 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 29 May 2015 21:53:52 +0200 Subject: [PATCH 1459/1783] :art: --- spec/config-spec.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/config-spec.coffee b/spec/config-spec.coffee index 2c5ba2fc2..d64ac2d27 100644 --- a/spec/config-spec.coffee +++ b/spec/config-spec.coffee @@ -805,7 +805,6 @@ describe "Config", -> atom.config.loadUserConfig() expect(atom.config.get("foo.bar")).toBe "baz" - describe ".observeUserConfig()", -> updatedHandler = null From e723b26eb0dc3a4b7213f4d41b0a709579eab457 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 29 May 2015 21:54:29 +0200 Subject: [PATCH 1460/1783] Add maximumLength schema enforcer for strings --- spec/config-spec.coffee | 10 ++++++++++ src/config.coffee | 6 ++++++ 2 files changed, 16 insertions(+) diff --git a/spec/config-spec.coffee b/spec/config-spec.coffee index d64ac2d27..b75a121a1 100644 --- a/spec/config-spec.coffee +++ b/spec/config-spec.coffee @@ -1380,6 +1380,16 @@ describe "Config", -> expect(atom.config.set('foo.bar.aString', nope: 'nope')).toBe false expect(atom.config.get('foo.bar.aString')).toBe 'ok' + describe 'when the schema has a "maximumLength" key', -> + it "trims the string to be no longer than the specified maximum", -> + schema = + type: 'string' + default: 'ok' + maximumLength: 3 + atom.config.setSchema('foo.bar.aString', schema) + atom.config.set('foo.bar.aString', 'abcdefg') + expect(atom.config.get('foo.bar.aString')).toBe 'abc' + describe 'when the value has an "object" type', -> beforeEach -> schema = diff --git a/src/config.coffee b/src/config.coffee index b97ce99ec..9ab8ce607 100644 --- a/src/config.coffee +++ b/src/config.coffee @@ -1060,6 +1060,12 @@ Config.addSchemaEnforcers throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} must be a string") value + validateMaximumLength: (keyPath, value, schema) -> + if typeof schema.maximumLength is 'number' and value.length > schema.maximumLength + value.slice(0, schema.maximumLength) + else + value + 'null': # null sort of isnt supported. It will just unset in this case coerce: (keyPath, value, schema) -> From e258dd2f8e4d1057013c63cb75d71dd52030b5b2 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 29 May 2015 21:55:20 +0200 Subject: [PATCH 1461/1783] Use maximumLength schema enforcer to constrain invisible characters Fixes #7014 --- src/config-schema.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/config-schema.coffee b/src/config-schema.coffee index b814e21de..fd35d2b07 100644 --- a/src/config-schema.coffee +++ b/src/config-schema.coffee @@ -179,15 +179,19 @@ module.exports = eol: type: ['boolean', 'string'] default: '\u00ac' + maximumLength: 1 space: type: ['boolean', 'string'] default: '\u00b7' + maximumLength: 1 tab: type: ['boolean', 'string'] default: '\u00bb' + maximumLength: 1 cr: type: ['boolean', 'string'] default: '\u00a4' + maximumLength: 1 zoomFontWhenCtrlScrolling: type: 'boolean' default: process.platform isnt 'darwin' From 703a36b62073614392a890dc8a519404e89a5592 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 1 Jun 2015 11:19:45 -0700 Subject: [PATCH 1462/1783] :arrow_up: snippets to fix spec --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 25dda7539..e5afd1beb 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,7 @@ "package-generator": "0.39.0", "release-notes": "0.52.0", "settings-view": "0.206.0", - "snippets": "0.92.0", + "snippets": "0.93.0", "spell-check": "0.58.0", "status-bar": "0.74.0", "styleguide": "0.44.0", From 7e34164c4bed65394f7c9818cb0b84eec8375adb Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 29 May 2015 14:55:48 -0700 Subject: [PATCH 1463/1783] Keep old folder names in api preview mode --- src/package.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/package.coffee b/src/package.coffee index 65c7af822..d55de19db 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -277,7 +277,7 @@ class Package [stylesheetPath, atom.themes.loadStylesheet(stylesheetPath, true)] getStylesheetsPath: -> - if includeDeprecatedAPIs and fs.isDirectorySync(path.join(@path, 'stylesheets')) + if fs.isDirectorySync(path.join(@path, 'stylesheets')) deprecate("Store package style sheets in the `styles/` directory instead of `stylesheets/` in the `#{@name}` package", packageName: @name) path.join(@path, 'stylesheets') else @@ -353,7 +353,7 @@ class Package deferred = Q.defer() - if includeDeprecatedAPIs and fs.isDirectorySync(path.join(@path, 'scoped-properties')) + if fs.isDirectorySync(path.join(@path, 'scoped-properties')) settingsDirPath = path.join(@path, 'scoped-properties') deprecate("Store package settings files in the `settings/` directory instead of `scoped-properties/`", packageName: @name) else From 3c647dc7af65f6bde49a1993ddf004d3c749408c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 29 May 2015 14:56:40 -0700 Subject: [PATCH 1464/1783] Keep activate events in api preview mode --- src/package.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package.coffee b/src/package.coffee index d55de19db..130918af7 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -489,7 +489,7 @@ class Package else if _.isArray(commands) @activationCommands[selector].push(commands...) - if includeDeprecatedAPIs and @metadata.activationEvents? + if @metadata.activationEvents? deprecate(""" Use `activationCommands` instead of `activationEvents` in your package.json Commands should be grouped by selector as follows: From 558d10434ab0b76ea07f420594f51f1a11fd5460 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 29 May 2015 14:58:39 -0700 Subject: [PATCH 1465/1783] Keep old context menu format in api preview mode --- src/package.coffee | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/package.coffee b/src/package.coffee index 130918af7..a3fbf9e39 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -203,16 +203,15 @@ class Package try itemsBySelector = map['context-menu'] - if includeDeprecatedAPIs - # Detect deprecated format for items object - for key, value of itemsBySelector - unless _.isArray(value) - deprecate(""" - The context menu CSON format has changed. Please see - https://atom.io/docs/api/latest/ContextMenuManager#context-menu-cson-format - for more info. - """, {packageName: @name}) - itemsBySelector = atom.contextMenu.convertLegacyItemsBySelector(itemsBySelector) + # Detect deprecated format for items object + for key, value of itemsBySelector + unless _.isArray(value) + deprecate(""" + The context menu CSON format has changed. Please see + https://atom.io/docs/api/latest/ContextMenuManager#context-menu-cson-format + for more info. + """, {packageName: @name}) + itemsBySelector = atom.contextMenu.convertLegacyItemsBySelector(itemsBySelector) @activationDisposables.add(atom.contextMenu.add(itemsBySelector)) catch error From fed19872b36296e1c1f4756ea5e0b6e036ca8e7b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 29 May 2015 14:59:49 -0700 Subject: [PATCH 1466/1783] Keep old configDefaults support in api preview mode --- src/package.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package.coffee b/src/package.coffee index a3fbf9e39..b404f99e8 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -170,7 +170,7 @@ class Package if @mainModule? if @mainModule.config? and typeof @mainModule.config is 'object' atom.config.setSchema @name, {type: 'object', properties: @mainModule.config} - else if includeDeprecatedAPIs and @mainModule.configDefaults? and typeof @mainModule.configDefaults is 'object' + else if @mainModule.configDefaults? and typeof @mainModule.configDefaults is 'object' deprecate("""Use a config schema instead. See the configuration section of https://atom.io/docs/latest/hacking-atom-package-word-count and https://atom.io/docs/api/latest/Config for more details""", {packageName: @name}) From 703eaac7ca159b041352f47bb615bdd74d20adf3 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 1 Jun 2015 13:32:03 -0700 Subject: [PATCH 1467/1783] Keep around atom.config.unobserve no-op --- src/config.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/config.coffee b/src/config.coffee index 9ab8ce607..de907b8dd 100644 --- a/src/config.coffee +++ b/src/config.coffee @@ -1158,6 +1158,9 @@ withoutEmptyObjects = (object) -> resultObject = object resultObject +Config::unobserve = (keyPath) -> + Grim.deprecate 'Config::unobserve no longer does anything. Call `.dispose()` on the object returned by Config::observe instead.' + if Grim.includeDeprecatedAPIs EmitterMixin = require('emissary').Emitter EmitterMixin.includeInto(Config) @@ -1207,9 +1210,6 @@ if Grim.includeDeprecatedAPIs Grim.deprecate 'Config::toggle is no longer supported. Please remove from your code.' @set(keyPath, not @get(keyPath)) - Config::unobserve = (keyPath) -> - Grim.deprecate 'Config::unobserve no longer does anything. Call `.dispose()` on the object returned by Config::observe instead.' - Config::addScopedSettings = (source, selector, value, options) -> Grim.deprecate("Use ::set instead") settingsBySelector = {} From 66620f85105fed8ec095a802bd5e1cc9014348da Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 1 Jun 2015 13:32:38 -0700 Subject: [PATCH 1468/1783] Add TODO comment --- src/config.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/config.coffee b/src/config.coffee index de907b8dd..f781e02e9 100644 --- a/src/config.coffee +++ b/src/config.coffee @@ -1158,6 +1158,7 @@ withoutEmptyObjects = (object) -> resultObject = object resultObject +# TODO remove in 1.0 API Config::unobserve = (keyPath) -> Grim.deprecate 'Config::unobserve no longer does anything. Call `.dispose()` on the object returned by Config::observe instead.' From 4812dcc355b595b098a9bfa27551b54c754641c7 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 1 Jun 2015 20:14:39 +0200 Subject: [PATCH 1469/1783] Include invisibles in TokenizedLine::copy --- src/tokenized-line.coffee | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 6761eecad..b8f7226c8 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -220,17 +220,20 @@ class TokenizedLine copy: -> copy = new TokenizedLine copy.tokenIterator = @tokenIterator - copy.indentLevel = @indentLevel copy.openScopes = @openScopes copy.text = @text copy.tags = @tags copy.specialTokens = @specialTokens + copy.startBufferColumn = @startBufferColumn + copy.bufferDelta = @bufferDelta + copy.ruleStack = @ruleStack + copy.lineEnding = @lineEnding + copy.invisibles = @invisibles + copy.endOfLineInvisibles = @endOfLineInvisibles + copy.indentLevel = @indentLevel + copy.tabLength = @tabLength copy.firstNonWhitespaceIndex = @firstNonWhitespaceIndex copy.firstTrailingWhitespaceIndex = @firstTrailingWhitespaceIndex - copy.lineEnding = @lineEnding - copy.endOfLineInvisibles = @endOfLineInvisibles - copy.ruleStack = @ruleStack - copy.startBufferColumn = @startBufferColumn copy.fold = @fold copy From 86dd4773fbdf6b0997fbc087ccc912e00a703e08 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Mon, 1 Jun 2015 18:26:23 -0400 Subject: [PATCH 1470/1783] :arrow_up: language-sql@0.16.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e5afd1beb..a8a5c6eb0 100644 --- a/package.json +++ b/package.json @@ -153,7 +153,7 @@ "language-sass": "0.38.0", "language-shellscript": "0.15.0", "language-source": "0.9.0", - "language-sql": "0.15.0", + "language-sql": "0.16.0", "language-text": "0.6.0", "language-todo": "0.23.0", "language-toml": "0.16.0", From 34591d3542e049b49c800f9fc80247a28a793080 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 1 Jun 2015 17:54:43 -0700 Subject: [PATCH 1471/1783] Catch read errors during deserialization Prevents Atom from failing to open because of a read error with a serialized editor. --- spec/workspace-spec.coffee | 13 +++++++++++++ src/text-editor.coffee | 10 +++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index 009f95a1c..f198fbe94 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -16,6 +16,19 @@ describe "Workspace", -> atom.project.setPaths([atom.project.getDirectories()[0]?.resolve('dir')]) atom.workspace = workspace = new Workspace + describe "serialization", -> + it "does not deserialize text editors for files that can't be read", -> + pathToOpen = path.join(temp.mkdirSync(), 'file.txt') + + waitsForPromise -> + workspace.open(pathToOpen) + + runs -> + expect(workspace.getPaneItems().length).toBe 1 + fs.mkdirSync(pathToOpen) + deserializedWorkspace = atom.workspace.testSerialization() + expect(deserializedWorkspace.getPaneItems().length).toBe 0 + describe "::open(uri, options)", -> openEvents = null diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 6d979fdf7..1eedc884d 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -128,7 +128,15 @@ class TextEditor extends Model displayBuffer: @displayBuffer.serialize() deserializeParams: (params) -> - params.displayBuffer = DisplayBuffer.deserialize(params.displayBuffer) + try + displayBuffer = DisplayBuffer.deserialize(params.displayBuffer) + catch error + if error.syscall is 'read' + return # Error reading the file, don't deserialize an editor for it + else + throw error + + params.displayBuffer = displayBuffer params.registerEditor = true params From 82eb01d13ee12f2b1c75e6adc74ac6d82ba5a28f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 1 Jun 2015 18:01:34 -0700 Subject: [PATCH 1472/1783] Move deserialize spec to text-editor-spec --- spec/text-editor-spec.coffee | 14 ++++++++++++++ spec/workspace-spec.coffee | 13 ------------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 28dbaaff8..8ad1ce390 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -1,3 +1,6 @@ +fs = require 'fs-plus' +path = require 'path' +temp = require 'temp' clipboard = require '../src/safe-clipboard' TextEditor = require '../src/text-editor' @@ -19,6 +22,17 @@ describe "TextEditor", -> atom.packages.activatePackage('language-javascript') describe "when the editor is deserialized", -> + it "returns undefined when the path cannot be read", -> + pathToOpen = path.join(temp.mkdirSync(), 'file.txt') + editor1 = null + + waitsForPromise -> + atom.project.open(pathToOpen).then (o) -> editor1 = o + + runs -> + fs.mkdirSync(pathToOpen) + expect(editor1.testSerialization()).toBeUndefined() + it "restores selections and folds based on markers in the buffer", -> editor.setSelectedBufferRange([[1, 2], [3, 4]]) editor.addSelectionForBufferRange([[5, 6], [7, 5]], reversed: true) diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index f198fbe94..009f95a1c 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -16,19 +16,6 @@ describe "Workspace", -> atom.project.setPaths([atom.project.getDirectories()[0]?.resolve('dir')]) atom.workspace = workspace = new Workspace - describe "serialization", -> - it "does not deserialize text editors for files that can't be read", -> - pathToOpen = path.join(temp.mkdirSync(), 'file.txt') - - waitsForPromise -> - workspace.open(pathToOpen) - - runs -> - expect(workspace.getPaneItems().length).toBe 1 - fs.mkdirSync(pathToOpen) - deserializedWorkspace = atom.workspace.testSerialization() - expect(deserializedWorkspace.getPaneItems().length).toBe 0 - describe "::open(uri, options)", -> openEvents = null From 81ff6678bd0446f36743935432188acd0bae1d78 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 2 Jun 2015 12:57:27 -0700 Subject: [PATCH 1473/1783] Prepare 0.206 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a8a5c6eb0..74a07659d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "0.205.0", + "version": "0.206.0", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From a1b4f89dddf23cdce2f1025784f6b5c54d0781bd Mon Sep 17 00:00:00 2001 From: My-khael Pierce Date: Tue, 2 Jun 2015 16:36:14 -0400 Subject: [PATCH 1474/1783] remove unnecessary line break --- static/index.html | 1 - 1 file changed, 1 deletion(-) diff --git a/static/index.html b/static/index.html index 84e8d57d4..5fcb30ad2 100644 --- a/static/index.html +++ b/static/index.html @@ -2,7 +2,6 @@ - From de0a76c84a4a7b566889a0590d47480e125d15eb Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 2 Jun 2015 16:28:12 -0700 Subject: [PATCH 1475/1783] :arrow_up: tabs@0.70 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 74a07659d..8188994dd 100644 --- a/package.json +++ b/package.json @@ -120,7 +120,7 @@ "status-bar": "0.74.0", "styleguide": "0.44.0", "symbols-view": "0.97.0", - "tabs": "0.69.0", + "tabs": "0.70.0", "timecop": "0.31.0", "tree-view": "0.171.0", "update-package-dependencies": "0.10.0", From 1fad4bae47af0361bd10ebfa08f20dfd2a8833ab Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Tue, 2 Jun 2015 19:29:02 -0400 Subject: [PATCH 1476/1783] Add libcap2 as a dependency for Debian Closes #7066 --- resources/linux/debian/control.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/linux/debian/control.in b/resources/linux/debian/control.in index cf2356a5d..7e47f27c6 100644 --- a/resources/linux/debian/control.in +++ b/resources/linux/debian/control.in @@ -1,6 +1,6 @@ Package: <%= name %> Version: <%= version %> -Depends: git, gconf2, gconf-service, libgtk2.0-0, libudev0 | libudev1, libgcrypt11 | libgcrypt20, libnotify4, libxtst6, libnss3, python, gvfs-bin, xdg-utils +Depends: git, gconf2, gconf-service, libgtk2.0-0, libudev0 | libudev1, libgcrypt11 | libgcrypt20, libnotify4, libxtst6, libnss3, python, gvfs-bin, xdg-utils, libcap2 Recommends: lsb-release Suggests: libgnome-keyring0, gir1.2-gnomekeyring-1.0 Section: <%= section %> From bf37a66831b98f08efed20dab4319065adc04262 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 1 Jun 2015 16:17:04 -0700 Subject: [PATCH 1477/1783] Rename --one to --include-deprecated-apis --- src/browser/atom-application.coffee | 44 ++++++++++++++--------------- src/browser/atom-window.coffee | 4 +-- src/browser/main.coffee | 6 ++-- src/workspace-element.coffee | 4 +-- static/index.js | 2 +- 5 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index fb038c07c..6b90aba4c 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -61,7 +61,7 @@ class AtomApplication exit: (status) -> app.exit(status) constructor: (options) -> - {@resourcePath, @version, @devMode, @safeMode, @apiPreviewMode, @socketPath} = options + {@resourcePath, @version, @devMode, @safeMode, @includeDeprecatedAPIs, @socketPath} = options # Normalize to make sure drive letter case is consistent on Windows @resourcePath = path.normalize(@resourcePath) if @resourcePath @@ -86,16 +86,16 @@ class AtomApplication else @loadState() or @openPath(options) - openWithOptions: ({pathsToOpen, urlsToOpen, test, pidToKillWhenClosed, devMode, safeMode, apiPreviewMode, newWindow, specDirectory, logFile, profileStartup}) -> + openWithOptions: ({pathsToOpen, urlsToOpen, test, pidToKillWhenClosed, devMode, safeMode, includeDeprecatedAPIs, newWindow, specDirectory, logFile, profileStartup}) -> if test - @runSpecs({exitWhenDone: true, @resourcePath, specDirectory, logFile, apiPreviewMode}) + @runSpecs({exitWhenDone: true, @resourcePath, specDirectory, logFile, includeDeprecatedAPIs}) else if pathsToOpen.length > 0 - @openPaths({pathsToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, apiPreviewMode, profileStartup}) + @openPaths({pathsToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, includeDeprecatedAPIs, profileStartup}) else if urlsToOpen.length > 0 - @openUrl({urlToOpen, devMode, safeMode, apiPreviewMode}) for urlToOpen in urlsToOpen + @openUrl({urlToOpen, devMode, safeMode, includeDeprecatedAPIs}) for urlToOpen in urlsToOpen else # Always open a editor window if this is the first instance of Atom. - @openPath({pidToKillWhenClosed, newWindow, devMode, safeMode, apiPreviewMode, profileStartup}) + @openPath({pidToKillWhenClosed, newWindow, devMode, safeMode, includeDeprecatedAPIs, profileStartup}) # Public: Removes the {AtomWindow} from the global window list. removeWindow: (window) -> @@ -160,7 +160,7 @@ class AtomApplication getLoadSettings = => devMode: @focusedWindow()?.devMode safeMode: @focusedWindow()?.safeMode - apiPreviewMode: @focusedWindow()?.apiPreviewMode + includeDeprecatedAPIs: @focusedWindow()?.includeDeprecatedAPIs @on 'application:run-all-specs', -> @runSpecs(exitWhenDone: false, resourcePath: global.devResourcePath, safeMode: @focusedWindow()?.safeMode) @on 'application:run-benchmarks', -> @runBenchmarks() @@ -172,8 +172,8 @@ class AtomApplication @on 'application:open-folder', -> @promptForPathToOpen('folder', getLoadSettings()) @on 'application:open-dev', -> @promptForPathToOpen('all', devMode: true) @on 'application:open-safe', -> @promptForPathToOpen('all', safeMode: true) - @on 'application:open-api-preview', -> @promptForPathToOpen('all', apiPreviewMode: true) - @on 'application:open-dev-api-preview', -> @promptForPathToOpen('all', {apiPreviewMode: true, devMode: true}) + @on 'application:open-with-deprecated-apis', -> @promptForPathToOpen('all', includeDeprecatedAPIs: true) + @on 'application:open-dev-with-deprecated-apis', -> @promptForPathToOpen('all', {includeDeprecatedAPIs: true, devMode: true}) @on 'application:inspect', ({x, y, atomWindow}) -> atomWindow ?= @focusedWindow() atomWindow?.browserWindow.inspectElement(x, y) @@ -228,7 +228,7 @@ class AtomApplication app.on 'open-url', (event, urlToOpen) => event.preventDefault() - @openUrl({urlToOpen, @devMode, @safeMode, @apiPreviewMode}) + @openUrl({urlToOpen, @devMode, @safeMode, @includeDeprecatedAPIs}) app.on 'activate-with-no-open-windows', (event) => event.preventDefault() @@ -352,11 +352,11 @@ class AtomApplication # :newWindow - Boolean of whether this should be opened in a new window. # :devMode - Boolean to control the opened window's dev mode. # :safeMode - Boolean to control the opened window's safe mode. - # :apiPreviewMode - Boolean to control the opened window's 1.0 API preview mode. + # :includeDeprecatedAPIs - Boolean to control the opened window's 1.0 API preview mode. # :profileStartup - Boolean to control creating a profile of the startup time. # :window - {AtomWindow} to open file paths in. - openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, apiPreviewMode, profileStartup, window}) -> - @openPaths({pathsToOpen: [pathToOpen], pidToKillWhenClosed, newWindow, devMode, safeMode, apiPreviewMode, profileStartup, window}) + openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, includeDeprecatedAPIs, profileStartup, window}) -> + @openPaths({pathsToOpen: [pathToOpen], pidToKillWhenClosed, newWindow, devMode, safeMode, includeDeprecatedAPIs, profileStartup, window}) # Public: Opens multiple paths, in existing windows if possible. # @@ -366,10 +366,10 @@ class AtomApplication # :newWindow - Boolean of whether this should be opened in a new window. # :devMode - Boolean to control the opened window's dev mode. # :safeMode - Boolean to control the opened window's safe mode. - # :apiPreviewMode - Boolean to control the opened window's 1.0 API preview mode. + # :includeDeprecatedAPIs - Boolean to control the opened window's 1.0 API preview mode. # :windowDimensions - Object with height and width keys. # :window - {AtomWindow} to open file paths in. - openPaths: ({pathsToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, apiPreviewMode, windowDimensions, profileStartup, window}={}) -> + openPaths: ({pathsToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, includeDeprecatedAPIs, windowDimensions, profileStartup, window}={}) -> pathsToOpen = pathsToOpen.map (pathToOpen) -> if fs.existsSync(pathToOpen) fs.normalize(pathToOpen) @@ -404,7 +404,7 @@ class AtomApplication bootstrapScript ?= require.resolve('../window-bootstrap') resourcePath ?= @resourcePath - openedWindow = new AtomWindow({locationsToOpen, bootstrapScript, resourcePath, devMode, safeMode, apiPreviewMode, windowDimensions, profileStartup}) + openedWindow = new AtomWindow({locationsToOpen, bootstrapScript, resourcePath, devMode, safeMode, includeDeprecatedAPIs, windowDimensions, profileStartup}) if pidToKillWhenClosed? @pidsToOpenWindows[pidToKillWhenClosed] = openedWindow @@ -452,7 +452,7 @@ class AtomApplication urlsToOpen: [] devMode: @devMode safeMode: @safeMode - apiPreviewMode: @apiPreviewMode + includeDeprecatedAPIs: @includeDeprecatedAPIs }) true else @@ -498,7 +498,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. - runSpecs: ({exitWhenDone, resourcePath, specDirectory, logFile, safeMode, apiPreviewMode}) -> + runSpecs: ({exitWhenDone, resourcePath, specDirectory, logFile, safeMode, includeDeprecatedAPIs}) -> if resourcePath isnt @resourcePath and not fs.existsSync(resourcePath) resourcePath = @resourcePath @@ -510,8 +510,8 @@ class AtomApplication isSpec = true devMode = true safeMode ?= false - apiPreviewMode ?= false - new AtomWindow({bootstrapScript, resourcePath, exitWhenDone, isSpec, devMode, specDirectory, logFile, safeMode, apiPreviewMode}) + includeDeprecatedAPIs ?= false + new AtomWindow({bootstrapScript, resourcePath, exitWhenDone, isSpec, devMode, specDirectory, logFile, safeMode, includeDeprecatedAPIs}) runBenchmarks: ({exitWhenDone, specDirectory}={}) -> try @@ -554,9 +554,9 @@ class AtomApplication # :safeMode - A Boolean which controls whether any newly opened windows # should be in safe mode or not. # :window - An {AtomWindow} to use for opening a selected file path. - promptForPathToOpen: (type, {devMode, safeMode, apiPreviewMode, window}) -> + promptForPathToOpen: (type, {devMode, safeMode, includeDeprecatedAPIs, window}) -> @promptForPath type, (pathsToOpen) => - @openPaths({pathsToOpen, devMode, safeMode, apiPreviewMode, window}) + @openPaths({pathsToOpen, devMode, safeMode, includeDeprecatedAPIs, window}) promptForPath: (type, callback) -> properties = diff --git a/src/browser/atom-window.coffee b/src/browser/atom-window.coffee index 6a6abb4b9..9b7c35d03 100644 --- a/src/browser/atom-window.coffee +++ b/src/browser/atom-window.coffee @@ -18,7 +18,7 @@ class AtomWindow isSpec: null constructor: (settings={}) -> - {@resourcePath, pathToOpen, locationsToOpen, @isSpec, @exitWhenDone, @safeMode, @devMode, @apiPreviewMode} = settings + {@resourcePath, pathToOpen, locationsToOpen, @isSpec, @exitWhenDone, @safeMode, @devMode, @includeDeprecatedAPIs} = settings locationsToOpen ?= [{pathToOpen}] if pathToOpen locationsToOpen ?= [] @@ -47,7 +47,7 @@ class AtomWindow loadSettings.resourcePath = @resourcePath loadSettings.devMode ?= false loadSettings.safeMode ?= false - loadSettings.apiPreviewMode ?= false + loadSettings.includeDeprecatedAPIs ?= false # Only send to the first non-spec window created if @constructor.includeShellLoadTime and not @isSpec diff --git a/src/browser/main.coffee b/src/browser/main.coffee index 371dd71ea..5cf412808 100644 --- a/src/browser/main.coffee +++ b/src/browser/main.coffee @@ -107,7 +107,7 @@ parseCommandLine = -> ATOM_HOME The root path for all configuration files and folders. Defaults to `~/.atom`. """ - options.alias('1', 'one').boolean('1').describe('1', 'Run in 1.0 API preview mode.') + options.boolean('include-deprecated-apis').describe('include-deprecated-apis', 'Include deprecated APIs') options.alias('d', 'dev').boolean('d').describe('d', 'Run in development mode.') options.alias('f', 'foreground').boolean('f').describe('f', 'Keep the browser process in the foreground.') options.alias('h', 'help').boolean('h').describe('h', 'Print this usage message.') @@ -134,7 +134,7 @@ parseCommandLine = -> executedFrom = args['executed-from'] devMode = args['dev'] safeMode = args['safe'] - apiPreviewMode = args['one'] + includeDeprecatedAPIs = args['include-deprecated-apis'] pathsToOpen = args._ test = args['test'] specDirectory = args['spec-directory'] @@ -168,7 +168,7 @@ parseCommandLine = -> process.env.PATH = args['path-environment'] if args['path-environment'] {resourcePath, pathsToOpen, executedFrom, test, version, pidToKillWhenClosed, - devMode, apiPreviewMode, safeMode, newWindow, specDirectory, logFile, + devMode, includeDeprecatedAPIs, safeMode, newWindow, specDirectory, logFile, socketPath, profileStartup} start() diff --git a/src/workspace-element.coffee b/src/workspace-element.coffee index 4f5dd6c5d..20dad16e1 100644 --- a/src/workspace-element.coffee +++ b/src/workspace-element.coffee @@ -139,8 +139,8 @@ atom.commands.add 'atom-workspace', 'application:open-folder': -> ipc.send('command', 'application:open-folder') 'application:open-dev': -> ipc.send('command', 'application:open-dev') 'application:open-safe': -> ipc.send('command', 'application:open-safe') - 'application:open-api-preview': -> ipc.send('command', 'application:open-api-preview') - 'application:open-dev-api-preview': -> ipc.send('command', 'application:open-dev-api-preview') + 'application:open-with-deprecated-apis': -> ipc.send('command', 'application:open-with-deprecated-apis') + 'application:open-dev-with-deprecated-apis': -> ipc.send('command', 'application:open-dev-with-deprecated-apis') 'application:add-project-folder': -> atom.addProjectFolder() 'application:minimize': -> ipc.send('command', 'application:minimize') 'application:zoom': -> ipc.send('command', 'application:zoom') diff --git a/static/index.js b/static/index.js index f41d41cd9..a0a0a0c40 100644 --- a/static/index.js +++ b/static/index.js @@ -71,7 +71,7 @@ var setupWindow = function(loadSettings) { ModuleCache.register(loadSettings); ModuleCache.add(loadSettings.resourcePath); - require('grim').includeDeprecatedAPIs = !loadSettings.apiPreviewMode; + require('grim').includeDeprecatedAPIs = !!loadSettings.includeDeprecatedAPIs; // Start the crash reporter before anything else. require('crash-reporter').start({ From 5bce950839610db48fbcb33764aca02dec4b00d0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 1 Jun 2015 16:34:37 -0700 Subject: [PATCH 1478/1783] :memo: Update includeDeprecatedAPIs description --- src/browser/atom-application.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 6b90aba4c..59a8a4e92 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -352,7 +352,7 @@ class AtomApplication # :newWindow - Boolean of whether this should be opened in a new window. # :devMode - Boolean to control the opened window's dev mode. # :safeMode - Boolean to control the opened window's safe mode. - # :includeDeprecatedAPIs - Boolean to control the opened window's 1.0 API preview mode. + # :includeDeprecatedAPIs - Boolean to control the opened window's included deprecated APIs. # :profileStartup - Boolean to control creating a profile of the startup time. # :window - {AtomWindow} to open file paths in. openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, includeDeprecatedAPIs, profileStartup, window}) -> @@ -366,7 +366,7 @@ class AtomApplication # :newWindow - Boolean of whether this should be opened in a new window. # :devMode - Boolean to control the opened window's dev mode. # :safeMode - Boolean to control the opened window's safe mode. - # :includeDeprecatedAPIs - Boolean to control the opened window's 1.0 API preview mode. + # :includeDeprecatedAPIs - Boolean to control the opened window's included deprecated APIs. # :windowDimensions - Object with height and width keys. # :window - {AtomWindow} to open file paths in. openPaths: ({pathsToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, includeDeprecatedAPIs, windowDimensions, profileStartup, window}={}) -> From a2ed26a6f39141a4b87b0487859dacdde311c52c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 1 Jun 2015 16:47:51 -0700 Subject: [PATCH 1479/1783] Include deprecated APIs when running specs --- src/browser/atom-application.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 59a8a4e92..19b1eb790 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -510,7 +510,7 @@ class AtomApplication isSpec = true devMode = true safeMode ?= false - includeDeprecatedAPIs ?= false + includeDeprecatedAPIs ?= true new AtomWindow({bootstrapScript, resourcePath, exitWhenDone, isSpec, devMode, specDirectory, logFile, safeMode, includeDeprecatedAPIs}) runBenchmarks: ({exitWhenDone, specDirectory}={}) -> From bf109b0e615cdd827db79a8810ec197846a06459 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 2 Jun 2015 08:58:38 -0700 Subject: [PATCH 1480/1783] Remove --one flag --- build/tasks/spec-task.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/tasks/spec-task.coffee b/build/tasks/spec-task.coffee index a3c9bbe79..2367c9a5f 100644 --- a/build/tasks/spec-task.coffee +++ b/build/tasks/spec-task.coffee @@ -54,14 +54,14 @@ module.exports = (grunt) -> if process.platform in ['darwin', 'linux'] options = cmd: appPath - args: ['--test', "--resource-path=#{resourcePath}", "--spec-directory=#{path.join(packagePath, 'spec')}", '--one'] + args: ['--test', "--resource-path=#{resourcePath}", "--spec-directory=#{path.join(packagePath, 'spec')}"] opts: cwd: packagePath env: _.extend({}, process.env, ATOM_PATH: rootDir) else if process.platform is 'win32' options = cmd: process.env.comspec - args: ['/c', appPath, '--test', "--resource-path=#{resourcePath}", "--spec-directory=#{path.join(packagePath, 'spec')}", "--log-file=ci.log", '--one'] + args: ['/c', appPath, '--test', "--resource-path=#{resourcePath}", "--spec-directory=#{path.join(packagePath, 'spec')}", "--log-file=ci.log"] opts: cwd: packagePath env: _.extend({}, process.env, ATOM_PATH: rootDir) From 40adc9fef64370f6e1cf81bdbc080982adfe92af Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 2 Jun 2015 11:56:56 -0700 Subject: [PATCH 1481/1783] Include deprecated APIs when running core specs --- build/tasks/spec-task.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/tasks/spec-task.coffee b/build/tasks/spec-task.coffee index 2367c9a5f..6f1476556 100644 --- a/build/tasks/spec-task.coffee +++ b/build/tasks/spec-task.coffee @@ -95,7 +95,7 @@ module.exports = (grunt) -> if process.platform in ['darwin', 'linux'] options = cmd: appPath - args: ['--test', "--resource-path=#{resourcePath}", "--spec-directory=#{coreSpecsPath}"] + args: ['--test', "--resource-path=#{resourcePath}", "--spec-directory=#{coreSpecsPath}", '--include-deprecated-apis'] opts: env: _.extend({}, process.env, ATOM_INTEGRATION_TESTS_ENABLED: true @@ -104,7 +104,7 @@ module.exports = (grunt) -> else if process.platform is 'win32' options = cmd: process.env.comspec - args: ['/c', appPath, '--test', "--resource-path=#{resourcePath}", "--spec-directory=#{coreSpecsPath}", "--log-file=ci.log"] + args: ['/c', appPath, '--test', "--resource-path=#{resourcePath}", "--spec-directory=#{coreSpecsPath}", '--log-file=ci.log', '--include-deprecated-apis'] opts: env: _.extend({}, process.env, ATOM_INTEGRATION_TESTS_ENABLED: true From 1fa1ae8021c469b3754fe2d783be46686381a220 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Machist=C3=A9=20N=2E=20Quintana?= Date: Tue, 2 Jun 2015 21:28:33 -0400 Subject: [PATCH 1482/1783] Revert "Use /usr/bin/env bash in hashbang" --- atom.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom.sh b/atom.sh index 236f49ff6..ecd7da052 100755 --- a/atom.sh +++ b/atom.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash if [ "$(uname)" == 'Darwin' ]; then OS='Mac' From 4941229a1b26353ea5bb5c181f219698239f5e0b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 2 Jun 2015 18:47:49 -0700 Subject: [PATCH 1483/1783] :arrow_up: tabs@0.71 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8188994dd..7d9d87fee 100644 --- a/package.json +++ b/package.json @@ -120,7 +120,7 @@ "status-bar": "0.74.0", "styleguide": "0.44.0", "symbols-view": "0.97.0", - "tabs": "0.70.0", + "tabs": "0.71.0", "timecop": "0.31.0", "tree-view": "0.171.0", "update-package-dependencies": "0.10.0", From ab36e690d049a3fcc37e9f86d435916bc9580dc5 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 29 May 2015 12:41:36 -0700 Subject: [PATCH 1484/1783] Add deprecated packages metadata --- build/deprecated-packages.json | 1710 ++++++++++++++++++++++++++++++++ 1 file changed, 1710 insertions(+) create mode 100644 build/deprecated-packages.json diff --git a/build/deprecated-packages.json b/build/deprecated-packages.json new file mode 100644 index 000000000..bd6216a07 --- /dev/null +++ b/build/deprecated-packages.json @@ -0,0 +1,1710 @@ +{ + "advanced-new-file": { + "version": "<=0.4.1", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "agda-mode": { + "version": "<=0.2.17", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "apex-ui-personalize": { + "version": "<=0.1.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "api-blueprint-preview": { + "version": "<=0.3.2", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "asciidoc-preview": { + "version": "<=0.5.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "ask-stack": { + "version": "<=1.1.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "assign-align": { + "version": "<=0.1.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "atom-2048": { + "version": "<=1.2.3", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "atom-angularjs": { + "hasAlternative": true, + "alternative": "angularjs" + }, + "atom-beautifier": { + "version": "<=0.5.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "atom-beautify": { + "version": "<=0.27.7", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "atom-browser-webview": { + "version": "<=0.6.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "atom-charcode": { + "version": "<=0.4.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "atom-cli-diff": { + "version": "<=0.11.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "atom-compile-coffee": { + "version": "<=1.4.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "atom-ctags": { + "version": "<=3.2.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "atom-deconsole": { + "version": "<=0.0.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "atom-faker": { + "version": "<=0.2.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "atom-flake8": { + "version": "<=0.1.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "atom-grunt-configs": { + "version": "<=0.1.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "atom-html-preview": { + "version": "<=0.1.4", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "atom-html5-boilerplate": { + "version": "<=0.2.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "atom-htmlizer": { + "version": "<=0.1.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "atom-jsfmt": { + "version": "<=0.6.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "atom-jshint": { + "version": "<=1.5.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "atom-lint": { + "hasAlternative": true, + "alternative": "linter" + }, + "atom-pair": { + "version": "<=1.1.5", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "atom-prettify": { + "version": "<=0.1.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "atom-processing": { + "version": "<=0.1.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "atom-python-debugger": { + "version": "<=0.2.2", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "atom-rails": { + "version": "<=0.4.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "atom-raml-preview": { + "version": "<=0.0.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "atom-runner": { + "version": "<=2.3.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "atom-semicolons": { + "version": "<=0.1.5", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "atom-spotify": { + "version": "<=1.2.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "atom-terminal-panel": { + "version": "<=4.3.1", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "atom-yeoman": { + "version": "<=0.2.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "atomatigit": { + "version": "<=1.5.1", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "atomic-emacs": { + "version": "<=0.5.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "atomic-rest": { + "version": "<=0.2.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "auto-copyright": { + "version": "<=0.3.1", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "auto-detect-indentation": { + "version": "<=0.3.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "auto-indent": { + "version": "<=0.1.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "auto-replace-in-selection": { + "version": "<=2.1.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "auto-update-packages": { + "version": "<=0.2.2", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "autoclose-html": { + "version": "<=0.15.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "autocomplete-haskell": { + "version": "<=0.2.1", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "autocomplete-jedi": { + "hasAlternative": true, + "alternative": "autocomplete-plus-python-jedi" + }, + "autocomplete-modules": { + "version": "<=0.3.2", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "autocomplete-paths": { + "version": "<=1.0.1", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "autocomplete-phpunit": { + "version": "<=1.0.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "autocomplete-plus-async": { + "hasAlternative": true, + "message": "`autocomplete-plus-async` has been replaced by `autocomplete-plus` which is bundled in core", + "alternative": "core" + }, + "autocomplete-plus-jedi": { + "version": "<=0.0.9", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "autocomplete-snippets": { + "version": "<=1.0.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "bezier-curve-editor": { + "version": "<=0.6.6", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "block-comment": { + "version": "<=0.4.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "block-travel": { + "version": "<=0.10.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "browser-refresh": { + "version": "<=0.8.3", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "build-systems": { + "version": "<=0.5.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "cabal": { + "version": "<=0.0.13", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "caniuse": { + "version": "<=0.1.1", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "change-case": { + "version": "<=0.5.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "circle-ci": { + "version": "<=0.9.1", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "clang-format": { + "version": "<=1.5.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "clipboard-history": { + "version": "<=0.6.5", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "close-after-last-tab": { + "version": "<=0.1.5", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "closure-linter": { + "version": "<=0.2.5", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "codeship-status": { + "version": "<=0.1.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "coffee-compile": { + "version": "<=0.4.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "coffee-lint": { + "version": "<=0.7.3", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "coffee-navigator": { + "version": "<=0.0.16", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "coffee-trace": { + "version": "<=0.2.2", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "coffeescript-preview": { + "hasAlternative": true, + "alternative": "preview" + }, + "color": { + "version": "<=0.5.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "color-picker": { + "version": "<=1.7.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "command-logger": { + "version": "<=0.20.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "comment": { + "version": "<=0.2.7", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "compass": { + "version": "<=0.8.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "composer": { + "version": "<=0.3.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "convert-to-utf8": { + "version": "<=0.1.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "coverage": { + "version": "<=0.6.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "csscomb": { + "version": "<=0.1.2", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "ctags-status": { + "version": "<=1.2.3", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "cucumber-runner": { + "version": "<=0.1.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "cucumber-step": { + "version": "<=0.1.2", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "custom-title": { + "version": "<=0.7.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "cut-line": { + "hasAlternative": true, + "alternative": "core" + }, + "dart-tools": { + "version": "<=0.9.11", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "dash": { + "version": "<=1.0.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "data-atom": { + "version": "<=0.4.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "devdocs": { + "version": "<=0.2.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "django-templates": { + "version": "<=0.3.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "docblockr": { + "version": "<=0.6.3", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "easy-motion": { + "version": "<=1.1.4", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "editor-stats": { + "version": "<=0.16.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "editorconfig": { + "version": "<=0.3.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "elixir-cmd": { + "version": "<=0.2.6", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "emacs-mode": { + "version": "<=0.0.29", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "ember-cli-helper": { + "version": "<=0.4.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "emmet": { + "version": "<=2.3.7", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "emp-debugger": { + "version": "<=0.6.13", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "emp-template-management": { + "version": "<=0.1.13", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "enhanced-package-list": { + "version": "<=1.0.3", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "enhanced-tabs": { + "version": "<=1.1.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "erb-snippets": { + "version": "<=0.5.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "error-status": { + "version": "<=0.3.3", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "eslint": { + "version": "<=0.15.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "eval": { + "version": "<=0.2.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "ever-notedown": { + "version": "<=0.1.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "ex-mode": { + "version": "<=0.4.1", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "execute-as-ruby": { + "version": "<=0.1.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "expand-selection": { + "version": "<=0.2.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "explicit-reload": { + "version": "<=0.2.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "fancy-new-file": { + "version": "<=0.7.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "file-icon-supplement": { + "version": "<=0.7.10", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "file-types": { + "version": "<=0.3.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "filetype-color": { + "version": "<=0.1.4", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "firepad": { + "version": "<=0.3.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "flake8": { + "hasAlternative": true, + "alternative": "linter" + }, + "floobits": { + "version": "<=0.4.2", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "function-name-in-status-bar": { + "version": "<=0.2.6", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "fuzzy-finder": { + "version": "<=0.54.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "fuzzy-finder-plus": { + "version": "<=1.4.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "get-routes": { + "version": "<=0.1.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "gist-it": { + "version": "<=0.6.10", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "git-blame": { + "version": "<=0.4.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "git-control": { + "version": "<=0.2.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "git-diff-details": { + "version": "<=0.8.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "git-grep": { + "version": "<=0.9.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "git-log": { + "version": "<=0.3.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "git-plus": { + "version": "<=4.5.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "git-projects": { + "version": "<=1.14.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "git-tab-status": { + "version": "<=1.5.3", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "github-issues": { + "version": "<=0.5.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "go-oracle": { + "version": "<=0.2.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "go-plus": { + "version": "<=3.0.9", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "go-to-view": { + "version": "<=0.1.2", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "gradle-ci": { + "version": "<=0.2.3", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "grammar-selector": { + "version": "<=0.35.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "grunt-runner": { + "version": "<=0.8.2", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "gulp-helper": { + "version": "<=4.1.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "gutter-shadow": { + "version": "<=0.1.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "hiera-eyaml": { + "version": "<=0.4.7", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "highlight-column": { + "version": "<=0.3.2", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "highlight-cov": { + "version": "<=0.1.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "highlight-css-color": { + "version": "<=1.3.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "highlight-line": { + "version": "<=0.9.3", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "highlight-selected": { + "version": "<=0.7.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "hipster-ipsum": { + "version": "<=0.1.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "html-entities": { + "version": "<=0.2.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "html-helper": { + "version": "<=0.2.3", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "html-img": { + "version": "<=0.4.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "html2haml": { + "version": "<=0.6.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "html2jade": { + "version": "<=0.7.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "htmlhint": { + "version": "<=1.0.2", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "icon-font-picker": { + "version": "<=0.0.2", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "ide-flow": { + "version": "<=0.7.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "ide-haskell": { + "version": "<=0.1.1", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "inc-dec-value": { + "version": "<=0.0.7", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "increment-number": { + "version": "<=0.1.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "indent-guide-improved": { + "version": "<=1.1.1", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "indent-helper": { + "version": "<=0.1.1", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "indentation-jumper": { + "version": "<=0.1.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "inline-autocomplete": { + "version": "<=1.0.4", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "ionic-atom": { + "version": "<=0.3.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "ionic-preview": { + "version": "<=0.3.1", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "japanese-zen-han-convert": { + "version": "<=0.3.2", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "jekyll": { + "version": "<=0.4.3", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "jsdoc": { + "version": "<=0.9.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "jsformat": { + "version": "<=0.8.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "jslint": { + "version": "<=0.10.2", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "jsonlint": { + "version": "<=1.0.2", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "jsonpp": { + "version": "<=0.0.7", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "keycodes": { + "version": "<=0.1.2", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "language-javascript-semantic": { + "version": "<=0.1.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "language-jsoniq": { + "version": "<=1.4.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "language-rspec": { + "version": "<=0.2.1", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "language-typescript": { + "hasAlternative": true, + "alternative": "atom-typescript" + }, + "laravel-facades": { + "version": "<=1.0.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "last-cursor-position": { + "version": "<=0.6.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "layout-manager": { + "version": "<=0.2.3", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "less-autocompile": { + "version": "<=0.3.3", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "less-than-slash": { + "version": "<=0.4.1", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "letter-spacing": { + "version": "<=0.2.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "line-jumper": { + "version": "<=0.13.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "linter": { + "version": "<=0.11.1", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "linter-flow": { + "version": "<=0.1.4", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "livereload": { + "version": "<=0.2.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "local-history": { + "version": "<=3.1.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "local-server": { + "version": "<=0.1.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "local-server-express": { + "version": "<=0.2.2", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "local-settings": { + "version": "<=0.3.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "localeapp": { + "version": "<=0.1.3", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "localization": { + "version": "<=1.16.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "log-console": { + "version": "<=0.1.2", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "lorem-ipsum": { + "version": "<=0.4.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "mark-ring": { + "version": "<=3.0.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "markdown-format": { + "version": "<=2.5.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "markdown-helpers": { + "version": "<=0.2.2", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "markdown-pdf": { + "version": "<=1.3.6", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "markdown-preview-pandoc": { + "version": "<=0.0.13", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "markdown-preview-plus": { + "version": "<=1.4.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "markdown-stream": { + "version": "<=0.6.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "markdown-writer": { + "version": "<=1.3.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "marked": { + "version": "<=0.1.8", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "mate-subword-navigation": { + "version": "<=3.0.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "MavensMate-Atom": { + "version": "<=0.0.20", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "max-tabs": { + "version": "<=0.3.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "maximize-panes": { + "version": "<=0.1.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "mechanical-keyboard": { + "version": "<=0.1.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "minifier": { + "version": "<=0.2.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "minimap": { + "version": "<=3.5.6", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "minimap-color-highlight": { + "version": "<=4.1.3", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "minimap-git-diff": { + "version": "<=3.0.4", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "mocha": { + "version": "<=0.0.5", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "mocha-ui": { + "version": "<=0.1.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "move-panes": { + "version": "<=0.1.2", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "node-debugger": { + "version": "<=0.2.3", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "node-resolver": { + "version": "<=1.0.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "npm-autocomplete": { + "version": "<=0.1.2", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "npm-docs": { + "version": "<=0.2.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "npm-install": { + "version": "<=3.0.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "nrepl": { + "version": "<=0.0.6", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "omni-ruler": { + "version": "<=0.3.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "omnisharp-atom": { + "version": "<=0.4.9", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "open-in": { + "version": "<=3.1.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "open-in-github-app": { + "version": "<=0.2.3", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "open-last-project": { + "hasAlternative": true, + "alternative": "core" + }, + "open-plus": { + "version": "<=0.3.2", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "open-recent": { + "version": "<=2.2.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "open-sesame": { + "version": "<=0.3.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "package-cop": { + "version": "<=0.2.5", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "package-list-downloader": { + "version": "<=0.2.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "pain-split": { + "version": "<=1.1.2", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "pane-layout-switcher": { + "version": "<=0.0.3", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "party-hard": { + "version": "<=0.3.3", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "pep8": { + "hasAlternative": true, + "alternative": "linter" + }, + "pepper-autocomplete": { + "version": "<=0.6.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "perltidy": { + "version": "<=2.1.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "permute": { + "version": "<=0.1.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "php-documentation-online": { + "version": "<=0.2.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "php-getters-setters": { + "version": "<=0.3.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "phpunit": { + "version": "<=1.0.9", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "playlist": { + "version": "<=0.1.7", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "pretty-json": { + "version": "<=0.3.1", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "preview": { + "version": "<=0.14.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "preview-plus": { + "version": "<=1.1.19", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "project-manager": { + "version": "<=1.15.5", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "project-palette-finder": { + "version": "<=2.4.17", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "project-ring": { + "version": "<=0.19.6", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "python": { + "hasAlternative": true, + "alternative": "script" + }, + "python-coverage": { + "version": "<=0.2.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "python-isort": { + "version": "<=0.0.6", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "python-jedi": { + "version": "<=0.1.7", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "quick-move-file": { + "version": "<=0.7.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "rails-navigation": { + "version": "<=0.1.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "react": { + "version": "<=0.7.8", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "recent-files": { + "version": "<=0.3.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "recent-projects": { + "version": "<=0.3.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "regex-railroad-diagram": { + "version": "<=0.7.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "related-files": { + "version": "<=0.3.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "remote-atom": { + "version": "<=1.1.10", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "remote-edit": { + "version": "<=1.6.4", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "remote-sync": { + "version": "<=3.1.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "resize-panes": { + "hasAlternative": true, + "alternative": "core" + }, + "rest-client": { + "version": "<=0.3.3", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "revert-buffer": { + "version": "<=0.4.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "rhino-python": { + "version": "<=0.6.1", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "rsense": { + "version": "<=0.6.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "rspec": { + "version": "<=0.3.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "rst-preview-pandoc": { + "version": "<=0.1.6", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "ruby-define-method": { + "version": "<=0.2.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "ruby-hash-rocket": { + "version": "<=1.1.2", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "ruby-quick-test": { + "version": "<=0.3.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "ruby-strftime-reference": { + "version": "<=0.3.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "ruby-test": { + "version": "<=0.9.5", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "run-command": { + "version": "<=0.1.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "run-in-browser": { + "version": "<=0.1.1", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "runcoderun": { + "version": "<=0.5.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "sass-autocompile": { + "version": "<=0.6.1", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "sassbeautify": { + "version": "<=0.2.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "save-commands": { + "version": "<=0.6.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "save-session": { + "version": "<=0.15.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "scope-inspector": { + "version": "<=0.2.1", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "script": { + "version": "<=2.20.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "script-runner": { + "version": "<=1.6.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "selection-count": { + "hasAlternative": true, + "alternative": "core" + }, + "slash-closer": { + "version": "<=0.7.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "sloc": { + "version": "<=0.1.3", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "smarter-delete-line": { + "version": "<=1.0.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "space-block-jumper": { + "version": "<=0.4.3", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "space-tab": { + "version": "<=0.1.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "spark-dfu-util": { + "version": "<=0.4.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "status-tab-spacing": { + "version": "<=0.3.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "sublime-tabs": { + "version": "<=0.5.6", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "supercollider": { + "version": "<=0.4.2", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "supercopair": { + "version": "<=0.9.34", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "swift-playground": { + "version": "<=0.2.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "symbol-gen": { + "version": "<=0.3.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "synced-sidebar": { + "version": "<=0.2.3", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "tab-history": { + "version": "<=0.4.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "tab-move-key": { + "version": "<=0.1.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "tab-switcher": { + "version": "<=0.2.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "tabs-to-spaces": { + "version": "<=0.8.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "tag": { + "version": "<=0.2.3", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "task-list": { + "version": "<=0.7.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "tasks": { + "version": "<=1.0.1", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "terminal-panel": { + "version": "<=1.11.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "terminal-status": { + "version": "<=1.6.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "test-status": { + "version": "<=0.27.1", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "ti-alloy-related": { + "version": "<=0.6.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "tidal": { + "version": "<=0.6.6", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "tidy-markdown": { + "version": "<=0.2.2", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "todo-list": { + "version": "<=1.0.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "toggle-tabs": { + "version": "<=0.1.8", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "travis-ci-status": { + "version": "<=0.13.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "tree-view": { + "version": "<=0.172.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "tree-view-breadcrumb": { + "version": "<=0.2.1", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "turbo-javascript": { + "version": "<=0.0.10", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "turnip-step": { + "version": "<=1.0.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "unity-dark-ui": { + "version": "<=1.1.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "unity-ui": { + "version": "<=1.0.5", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "update-packages": { + "version": "<=0.1.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "url-encode": { + "version": "<=0.4.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "vertical-align": { + "version": "<=0.6.1", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "view-tail-large-files": { + "version": "<=0.1.16", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "vim-mode": { + "version": "<=0.46.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "virtualenv": { + "version": "<=0.6.2", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "visual-bell": { + "version": "<=0.11.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "voicecode": { + "version": "<=0.9.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "w3c-validation": { + "version": "<=0.1.3", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "weather-package": { + "version": "<=1.5.4", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "web-view": { + "version": "<=0.3.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "webbox-color": { + "version": "<=0.5.4", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "webview-pane": { + "version": "<=0.0.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "wercker-status": { + "version": "<=0.3.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "whitespace": { + "version": "<=0.24.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "word-count": { + "version": "<=0.1.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "word-jumper": { + "version": "<=0.2.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "wordcount": { + "version": "<=2.1.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "wrap-lines": { + "hasAlternative": true, + "message": "`wrap-lines` has been replaced by a feature in core. Open the command palette and search for `autoflow`.", + "alternative": "core" + }, + "yosemite-unity-ui": { + "version": "<=0.3.13", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "yuno-commit": { + "version": "<=0.0.2", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "zentabs": { + "version": "<=0.6.1", + "hasDeprecations": true, + "latestHasDeprecations": false + } +} \ No newline at end of file From 90ea63393cddb06c60991f9e2c688f7e57f894da Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 29 May 2015 12:50:22 -0700 Subject: [PATCH 1485/1783] Include deprecated packages in package.json --- build/tasks/compile-packages-slug-task.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/build/tasks/compile-packages-slug-task.coffee b/build/tasks/compile-packages-slug-task.coffee index d0ed51fd6..7b9938527 100644 --- a/build/tasks/compile-packages-slug-task.coffee +++ b/build/tasks/compile-packages-slug-task.coffee @@ -86,6 +86,7 @@ module.exports = (grunt) -> metadata._atomPackages = packages metadata._atomMenu = getMenu(appDir) metadata._atomKeymaps = getKeymaps(appDir) + metadata._deprecatedPackages = require('../deprecated-packages') grunt.file.write(path.join(appDir, 'package.json'), JSON.stringify(metadata)) not invalidPackages From b7c2cd7ba150ad5e6cee937e9c0f8283208131f8 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 29 May 2015 12:57:35 -0700 Subject: [PATCH 1486/1783] Precheck ranges just to be safe --- build/tasks/compile-packages-slug-task.coffee | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/build/tasks/compile-packages-slug-task.coffee b/build/tasks/compile-packages-slug-task.coffee index 7b9938527..974b63b15 100644 --- a/build/tasks/compile-packages-slug-task.coffee +++ b/build/tasks/compile-packages-slug-task.coffee @@ -3,6 +3,7 @@ CSON = require 'season' fs = require 'fs-plus' _ = require 'underscore-plus' normalizePackageData = require 'normalize-package-data' +semver = require 'semver' OtherPlatforms = ['darwin', 'freebsd', 'linux', 'sunos', 'win32'].filter (platform) -> platform isnt process.platform @@ -88,5 +89,10 @@ module.exports = (grunt) -> metadata._atomKeymaps = getKeymaps(appDir) metadata._deprecatedPackages = require('../deprecated-packages') + for name, {version} of metadata._deprecatedPackages + unless semver.validRange(version) + invalidPackages = true + grunt.log.error("Invalid range: #{version} (#{name})") + grunt.file.write(path.join(appDir, 'package.json'), JSON.stringify(metadata)) not invalidPackages From 59e3b01dd1c9048255a9fb3bd1938de7a1472fda Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 29 May 2015 13:04:53 -0700 Subject: [PATCH 1487/1783] Ignore missing versions --- build/tasks/compile-packages-slug-task.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/tasks/compile-packages-slug-task.coffee b/build/tasks/compile-packages-slug-task.coffee index 974b63b15..7317f158a 100644 --- a/build/tasks/compile-packages-slug-task.coffee +++ b/build/tasks/compile-packages-slug-task.coffee @@ -90,7 +90,7 @@ module.exports = (grunt) -> metadata._deprecatedPackages = require('../deprecated-packages') for name, {version} of metadata._deprecatedPackages - unless semver.validRange(version) + if version and not semver.validRange(version) invalidPackages = true grunt.log.error("Invalid range: #{version} (#{name})") From 06c4f17af09f5b91250a0f15af32b4f6425935e0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 29 May 2015 13:16:10 -0700 Subject: [PATCH 1488/1783] Don't load deprecated packages --- src/deprecated-packages.coffee | 37 ++++++++++++++++++++++++++++++++++ src/package-manager.coffee | 4 ++++ 2 files changed, 41 insertions(+) create mode 100644 src/deprecated-packages.coffee diff --git a/src/deprecated-packages.coffee b/src/deprecated-packages.coffee new file mode 100644 index 000000000..91a541e98 --- /dev/null +++ b/src/deprecated-packages.coffee @@ -0,0 +1,37 @@ +semver = require 'semver' + +deprecatedPackages = require('../package.json')?._deprecatedPackages ? {} +ranges = {} + +exports.isPackageDeprecated = (name, version) -> + return false unless deprecatedPackages.hasOwnProperty(name) + return false unless semver.valid(version) + + deprecatedVersionRange = deprecatedPackages[name].version + console.log name, version, deprecatedVersionRange + return true unless deprecatedVersionRange + satisfies(version, deprecatedVersionRange) + +satisfies = (version, rawRange) -> + unless parsedRange = ranges[rawRange] + parsedRange = new Range(rawRange) + ranges[rawRange] = parsedRange + parsedRange.test(version) + +# Extend semver.Range to memoize matched versions for speed +class Range extends semver.Range + constructor: -> + super + @matchedVersions = new Set() + @unmatchedVersions = new Set() + + test: (version) -> + return true if @matchedVersions.has(version) + return false if @unmatchedVersions.has(version) + + matches = super + if matches + @matchedVersions.add(version) + else + @unmatchedVersions.add(version) + matches diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 8d2f4d663..8f42da784 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -9,6 +9,7 @@ Grim = require 'grim' ServiceHub = require 'service-hub' Package = require './package' ThemePackage = require './theme-package' +{isPackageDeprecated} = require './deprecated-packages' # Extended: Package manager for coordinating the lifecycle of Atom packages. # @@ -326,6 +327,9 @@ class PackageManager @handleMetadataError(error, packagePath) return null + unless @isBundledPackage(metadata.name) + return null if isPackageDeprecated(metadata.name, metadata.version) + if metadata.theme pack = new ThemePackage(packagePath, metadata) else From 22f2de77d1cb71d0214122ccbc415e06599684fc Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 29 May 2015 13:17:22 -0700 Subject: [PATCH 1489/1783] Expose a atom.packages.isPackageDeprecated helper --- src/deprecated-packages.coffee | 2 +- src/package-manager.coffee | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/deprecated-packages.coffee b/src/deprecated-packages.coffee index 91a541e98..e1eb9a968 100644 --- a/src/deprecated-packages.coffee +++ b/src/deprecated-packages.coffee @@ -3,7 +3,7 @@ semver = require 'semver' deprecatedPackages = require('../package.json')?._deprecatedPackages ? {} ranges = {} -exports.isPackageDeprecated = (name, version) -> +exports.isDeprecatedPackage = (name, version) -> return false unless deprecatedPackages.hasOwnProperty(name) return false unless semver.valid(version) diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 8f42da784..d63ab928e 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -150,6 +150,9 @@ class PackageManager isBundledPackage: (name) -> @getPackageDependencies().hasOwnProperty(name) + isDeprecatedPackage: (name, version) -> + isDeprecatedDeprecated(metadata.name, metadata.version) + ### Section: Enabling and disabling packages ### @@ -328,7 +331,7 @@ class PackageManager return null unless @isBundledPackage(metadata.name) - return null if isPackageDeprecated(metadata.name, metadata.version) + return null if @isDeprecatedPackage(metadata.name, metadata.version) if metadata.theme pack = new ThemePackage(packagePath, metadata) From d557e78847ff9082d6672a915975b4742833fb6e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 29 May 2015 13:35:09 -0700 Subject: [PATCH 1490/1783] Add spec for deprecated packages --- build/deprecated-packages.json | 2 +- spec/fixtures/packages/wordcount/package.json | 4 ++++ spec/package-manager-spec.coffee | 7 +++++++ spec/spec-helper.coffee | 3 +++ src/deprecated-packages.coffee | 1 - src/package-manager.coffee | 4 ++-- 6 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 spec/fixtures/packages/wordcount/package.json diff --git a/build/deprecated-packages.json b/build/deprecated-packages.json index bd6216a07..2383d79b2 100644 --- a/build/deprecated-packages.json +++ b/build/deprecated-packages.json @@ -1707,4 +1707,4 @@ "hasDeprecations": true, "latestHasDeprecations": false } -} \ No newline at end of file +} diff --git a/spec/fixtures/packages/wordcount/package.json b/spec/fixtures/packages/wordcount/package.json new file mode 100644 index 000000000..bf04495aa --- /dev/null +++ b/spec/fixtures/packages/wordcount/package.json @@ -0,0 +1,4 @@ +{ + "name": "wordcount", + "version": "2.0.9" +} diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 1244ab984..2789e2a37 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -1,3 +1,4 @@ +path = require 'path' {$, $$} = require '../src/space-pen-extensions' Package = require '../src/package' {Disposable} = require 'atom' @@ -56,6 +57,12 @@ describe "PackageManager", -> expect(console.warn.callCount).toBe(1) expect(console.warn.argsForCall[0][0]).toContain("Could not resolve") + it "returns null if the package is deprecated", -> + expect(atom.packages.loadPackage(path.join(__dirname, 'fixtures', 'packages', 'wordcount'))).toBeNull() + expect(atom.packages.isDeprecatedPackage('wordcount', '2.0.9')).toBe true + expect(atom.packages.isDeprecatedPackage('wordcount', '2.1.0')).toBe true + expect(atom.packages.isDeprecatedPackage('wordcount', '2.1.1')).toBe false + it "invokes ::onDidLoadPackage listeners with the loaded package", -> loadedPackage = null atom.packages.onDidLoadPackage (pack) -> loadedPackage = pack diff --git a/spec/spec-helper.coffee b/spec/spec-helper.coffee index 15874ff6f..d6f072941 100644 --- a/spec/spec-helper.coffee +++ b/spec/spec-helper.coffee @@ -1,3 +1,6 @@ +# Ensure deprecated packages are populated +require('../package.json')._deprecatedPackages = require('../build/deprecated-packages') + require '../src/window' atom.initialize() atom.restoreWindowDimensions() diff --git a/src/deprecated-packages.coffee b/src/deprecated-packages.coffee index e1eb9a968..deaf8a6d9 100644 --- a/src/deprecated-packages.coffee +++ b/src/deprecated-packages.coffee @@ -8,7 +8,6 @@ exports.isDeprecatedPackage = (name, version) -> return false unless semver.valid(version) deprecatedVersionRange = deprecatedPackages[name].version - console.log name, version, deprecatedVersionRange return true unless deprecatedVersionRange satisfies(version, deprecatedVersionRange) diff --git a/src/package-manager.coffee b/src/package-manager.coffee index d63ab928e..f8beec4e8 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -9,7 +9,7 @@ Grim = require 'grim' ServiceHub = require 'service-hub' Package = require './package' ThemePackage = require './theme-package' -{isPackageDeprecated} = require './deprecated-packages' +{isDeprecatedPackage} = require './deprecated-packages' # Extended: Package manager for coordinating the lifecycle of Atom packages. # @@ -151,7 +151,7 @@ class PackageManager @getPackageDependencies().hasOwnProperty(name) isDeprecatedPackage: (name, version) -> - isDeprecatedDeprecated(metadata.name, metadata.version) + isDeprecatedPackage(name, version) ### Section: Enabling and disabling packages From 4bb6728784b1f37a9868ff2d6a871c951ed33d61 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 29 May 2015 14:42:55 -0700 Subject: [PATCH 1491/1783] Add atom.packages.getDeprecatedPackageMetadata --- spec/package-manager-spec.coffee | 1 + src/deprecated-packages.coffee | 7 +++++++ src/package-manager.coffee | 5 ++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 2789e2a37..0cf9b728a 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -62,6 +62,7 @@ describe "PackageManager", -> expect(atom.packages.isDeprecatedPackage('wordcount', '2.0.9')).toBe true expect(atom.packages.isDeprecatedPackage('wordcount', '2.1.0')).toBe true expect(atom.packages.isDeprecatedPackage('wordcount', '2.1.1')).toBe false + expect(atom.packages.getDeprecatedPackageMetadata('wordcount').version).toBe '<=2.1.0' it "invokes ::onDidLoadPackage listeners with the loaded package", -> loadedPackage = null diff --git a/src/deprecated-packages.coffee b/src/deprecated-packages.coffee index deaf8a6d9..0a1cc1ce1 100644 --- a/src/deprecated-packages.coffee +++ b/src/deprecated-packages.coffee @@ -3,6 +3,13 @@ semver = require 'semver' deprecatedPackages = require('../package.json')?._deprecatedPackages ? {} ranges = {} +exports.getDeprecatedPackageMetadata = (name) -> + metadata = null + if deprecatedPackages.hasOwnProperty(name) + metadata = deprecatedPackages[name] + metadata = Object.freeze(metadata) if metadata + metadata + exports.isDeprecatedPackage = (name, version) -> return false unless deprecatedPackages.hasOwnProperty(name) return false unless semver.valid(version) diff --git a/src/package-manager.coffee b/src/package-manager.coffee index f8beec4e8..934def3b5 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -9,7 +9,7 @@ Grim = require 'grim' ServiceHub = require 'service-hub' Package = require './package' ThemePackage = require './theme-package' -{isDeprecatedPackage} = require './deprecated-packages' +{isDeprecatedPackage, getDeprecatedPackageMetadata} = require './deprecated-packages' # Extended: Package manager for coordinating the lifecycle of Atom packages. # @@ -153,6 +153,9 @@ class PackageManager isDeprecatedPackage: (name, version) -> isDeprecatedPackage(name, version) + getDeprecatedPackageMetadata: (name) -> + getDeprecatedPackageMetadata(name) + ### Section: Enabling and disabling packages ### From 51611c24b59c5fcbd79dfa80d463180b60412069 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 29 May 2015 14:52:15 -0700 Subject: [PATCH 1492/1783] Don't validate version until checking for empty range --- src/deprecated-packages.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/deprecated-packages.coffee b/src/deprecated-packages.coffee index 0a1cc1ce1..7117531e9 100644 --- a/src/deprecated-packages.coffee +++ b/src/deprecated-packages.coffee @@ -12,11 +12,11 @@ exports.getDeprecatedPackageMetadata = (name) -> exports.isDeprecatedPackage = (name, version) -> return false unless deprecatedPackages.hasOwnProperty(name) - return false unless semver.valid(version) deprecatedVersionRange = deprecatedPackages[name].version return true unless deprecatedVersionRange - satisfies(version, deprecatedVersionRange) + + semver.valid(version) and satisfies(version, deprecatedVersionRange) satisfies = (version, rawRange) -> unless parsedRange = ranges[rawRange] From 87bbf15c6d42a433ea257892118f08a138eb9dc9 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 1 Jun 2015 11:22:43 -0700 Subject: [PATCH 1493/1783] Log to console about not loading deprecated packages --- src/package-manager.coffee | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 934def3b5..9e0475900 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -334,7 +334,9 @@ class PackageManager return null unless @isBundledPackage(metadata.name) - return null if @isDeprecatedPackage(metadata.name, metadata.version) + if @isDeprecatedPackage(metadata.name, metadata.version) + console.warn "Did not load #{metadata.name}@#{metadata.version} because it uses deprecated APIs that have been removed." + return null if metadata.theme pack = new ThemePackage(packagePath, metadata) From 8dbec4afe2b439dab36b0218627b21c9ff8968bd Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 1 Jun 2015 11:26:39 -0700 Subject: [PATCH 1494/1783] :art: --- src/deprecated-packages.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/deprecated-packages.coffee b/src/deprecated-packages.coffee index 7117531e9..2eeea435c 100644 --- a/src/deprecated-packages.coffee +++ b/src/deprecated-packages.coffee @@ -7,7 +7,7 @@ exports.getDeprecatedPackageMetadata = (name) -> metadata = null if deprecatedPackages.hasOwnProperty(name) metadata = deprecatedPackages[name] - metadata = Object.freeze(metadata) if metadata + Object.freeze(metadata) if metadata metadata exports.isDeprecatedPackage = (name, version) -> From 551636d59e6151274a872f20b121ab7b5463a5a8 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 1 Jun 2015 11:28:21 -0700 Subject: [PATCH 1495/1783] :memo: Tweak deprecated load message --- src/package-manager.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 9e0475900..313ffd31d 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -335,7 +335,7 @@ class PackageManager unless @isBundledPackage(metadata.name) if @isDeprecatedPackage(metadata.name, metadata.version) - console.warn "Did not load #{metadata.name}@#{metadata.version} because it uses deprecated APIs that have been removed." + console.warn "Could not load #{metadata.name}@#{metadata.version} because it uses deprecated APIs that have been removed." return null if metadata.theme From df2bd62327b357f51de1f4028a468ecb956a595b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 3 Jun 2015 09:47:13 -0700 Subject: [PATCH 1496/1783] Load deprecated packages when including deprecated APIs --- spec/package-manager-spec.coffee | 22 ++++++++++++++++------ src/package-manager.coffee | 2 +- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 0cf9b728a..cab063e00 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -57,12 +57,22 @@ describe "PackageManager", -> expect(console.warn.callCount).toBe(1) expect(console.warn.argsForCall[0][0]).toContain("Could not resolve") - it "returns null if the package is deprecated", -> - expect(atom.packages.loadPackage(path.join(__dirname, 'fixtures', 'packages', 'wordcount'))).toBeNull() - expect(atom.packages.isDeprecatedPackage('wordcount', '2.0.9')).toBe true - expect(atom.packages.isDeprecatedPackage('wordcount', '2.1.0')).toBe true - expect(atom.packages.isDeprecatedPackage('wordcount', '2.1.1')).toBe false - expect(atom.packages.getDeprecatedPackageMetadata('wordcount').version).toBe '<=2.1.0' + describe "when the package is deprecated", -> + includeDeprecatedAPIs = null + + beforeEach -> + {includeDeprecatedAPIs} = require('grim') + + afterEach -> + require('grim').includeDeprecatedAPIs = includeDeprecatedAPIs + + it "returns null", -> + require('grim').includeDeprecatedAPIs = false + expect(atom.packages.loadPackage(path.join(__dirname, 'fixtures', 'packages', 'wordcount'))).toBeNull() + expect(atom.packages.isDeprecatedPackage('wordcount', '2.0.9')).toBe true + expect(atom.packages.isDeprecatedPackage('wordcount', '2.1.0')).toBe true + expect(atom.packages.isDeprecatedPackage('wordcount', '2.1.1')).toBe false + expect(atom.packages.getDeprecatedPackageMetadata('wordcount').version).toBe '<=2.1.0' it "invokes ::onDidLoadPackage listeners with the loaded package", -> loadedPackage = null diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 313ffd31d..306e553a8 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -333,7 +333,7 @@ class PackageManager @handleMetadataError(error, packagePath) return null - unless @isBundledPackage(metadata.name) + unless @isBundledPackage(metadata.name) or Grim.includeDeprecatedAPIs if @isDeprecatedPackage(metadata.name, metadata.version) console.warn "Could not load #{metadata.name}@#{metadata.version} because it uses deprecated APIs that have been removed." return null From 2523e72e50903a365f5939363c571576b2ffe100 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 3 Jun 2015 09:49:03 -0700 Subject: [PATCH 1497/1783] :art: --- spec/package-manager-spec.coffee | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index cab063e00..6f424465c 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -58,16 +58,17 @@ describe "PackageManager", -> expect(console.warn.argsForCall[0][0]).toContain("Could not resolve") describe "when the package is deprecated", -> + grim = require 'grim' includeDeprecatedAPIs = null beforeEach -> - {includeDeprecatedAPIs} = require('grim') + {includeDeprecatedAPIs} = grim afterEach -> - require('grim').includeDeprecatedAPIs = includeDeprecatedAPIs + grim.includeDeprecatedAPIs = includeDeprecatedAPIs it "returns null", -> - require('grim').includeDeprecatedAPIs = false + grim.includeDeprecatedAPIs = false expect(atom.packages.loadPackage(path.join(__dirname, 'fixtures', 'packages', 'wordcount'))).toBeNull() expect(atom.packages.isDeprecatedPackage('wordcount', '2.0.9')).toBe true expect(atom.packages.isDeprecatedPackage('wordcount', '2.1.0')).toBe true From b467a7d126aee151f1bd52321ab7ebfc241c68c1 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 3 Jun 2015 10:08:54 -0700 Subject: [PATCH 1498/1783] :arrow_up: tabs@0.73 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7d9d87fee..7483221a8 100644 --- a/package.json +++ b/package.json @@ -120,7 +120,7 @@ "status-bar": "0.74.0", "styleguide": "0.44.0", "symbols-view": "0.97.0", - "tabs": "0.71.0", + "tabs": "0.73.0", "timecop": "0.31.0", "tree-view": "0.171.0", "update-package-dependencies": "0.10.0", From 0db71fa11578acad9a278db6b5c646da1ae15392 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Wed, 3 Jun 2015 10:20:34 -0700 Subject: [PATCH 1499/1783] Add 'Show Preferences' command to open Settings --- src/workspace-element.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/workspace-element.coffee b/src/workspace-element.coffee index 20dad16e1..6a276a7fc 100644 --- a/src/workspace-element.coffee +++ b/src/workspace-element.coffee @@ -126,6 +126,7 @@ atom.commands.add 'atom-workspace', 'application:about': -> ipc.send('command', 'application:about') 'application:run-all-specs': -> ipc.send('command', 'application:run-all-specs') 'application:run-benchmarks': -> ipc.send('command', 'application:run-benchmarks') + 'application:show-preferences': -> ipc.send('command', 'application:show-settings') 'application:show-settings': -> ipc.send('command', 'application:show-settings') 'application:quit': -> ipc.send('command', 'application:quit') 'application:hide': -> ipc.send('command', 'application:hide') From d44aeb28f7744b46f168d226948fe9ecc894a867 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 3 Jun 2015 10:59:05 -0700 Subject: [PATCH 1500/1783] :arrow_up: apm@0.169 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index 64f937169..108e3c206 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.168.0" + "atom-package-manager": "0.169.0" } } From 6ebbb58a80ab24e7bcf2b97f270e68afb28f8ddf Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 3 Jun 2015 10:23:52 -0700 Subject: [PATCH 1501/1783] Log message about --one being removed --- atom.sh | 6 +++--- src/browser/main.coffee | 8 ++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/atom.sh b/atom.sh index ecd7da052..460fdd2a8 100755 --- a/atom.sh +++ b/atom.sh @@ -11,14 +11,14 @@ else exit 1 fi -while getopts ":wtfvh-:" opt; do +while getopts ":wtfvh1-:" opt; do case "$opt" in -) case "${OPTARG}" in wait) WAIT=1 ;; - help|version) + help|version|one) REDIRECT_STDERR=1 EXPECT_OUTPUT=1 ;; @@ -30,7 +30,7 @@ while getopts ":wtfvh-:" opt; do w) WAIT=1 ;; - h|v) + h|v|1) REDIRECT_STDERR=1 EXPECT_OUTPUT=1 ;; diff --git a/src/browser/main.coffee b/src/browser/main.coffee index 5cf412808..ac6a8e6e0 100644 --- a/src/browser/main.coffee +++ b/src/browser/main.coffee @@ -121,8 +121,16 @@ parseCommandLine = -> options.alias('v', 'version').boolean('v').describe('v', 'Print the version.') options.alias('w', 'wait').boolean('w').describe('w', 'Wait for window to be closed before returning.') options.string('socket-path') + options.alias('1', 'one').boolean('one') # Deprecated 1.0 API preview flag args = options.argv + if args.one + process.stdout.write """ + The -1/--one option has been removed. Atom now defaults to launching with + the 1.0 API. Use --include-deprecated-apis to run Atom with deprecated APIs. + + """ + if args.help process.stdout.write(options.help()) process.exit(0) From 75f2ce148a8710aefeed55f9f410fa79ca5ccb37 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 3 Jun 2015 10:28:43 -0700 Subject: [PATCH 1502/1783] Use consistent default format --- src/browser/main.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/browser/main.coffee b/src/browser/main.coffee index ac6a8e6e0..0ebb13950 100644 --- a/src/browser/main.coffee +++ b/src/browser/main.coffee @@ -121,7 +121,7 @@ parseCommandLine = -> options.alias('v', 'version').boolean('v').describe('v', 'Print the version.') options.alias('w', 'wait').boolean('w').describe('w', 'Wait for window to be closed before returning.') options.string('socket-path') - options.alias('1', 'one').boolean('one') # Deprecated 1.0 API preview flag + options.alias('1', 'one').boolean('1') # Deprecated 1.0 API preview flag args = options.argv if args.one From d965abce38e09fb8464ada40cc7efc2976c0f693 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 3 Jun 2015 11:47:49 -0700 Subject: [PATCH 1503/1783] Remove atom.sh -1/--one checks --- atom.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/atom.sh b/atom.sh index 460fdd2a8..ecd7da052 100755 --- a/atom.sh +++ b/atom.sh @@ -11,14 +11,14 @@ else exit 1 fi -while getopts ":wtfvh1-:" opt; do +while getopts ":wtfvh-:" opt; do case "$opt" in -) case "${OPTARG}" in wait) WAIT=1 ;; - help|version|one) + help|version) REDIRECT_STDERR=1 EXPECT_OUTPUT=1 ;; @@ -30,7 +30,7 @@ while getopts ":wtfvh1-:" opt; do w) WAIT=1 ;; - h|v|1) + h|v) REDIRECT_STDERR=1 EXPECT_OUTPUT=1 ;; From 6a5bf633e95f56c5b2d1e6fa229bec780bc92994 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 3 Jun 2015 11:53:59 -0700 Subject: [PATCH 1504/1783] Show deprecation text via usage message --- src/browser/main.coffee | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/browser/main.coffee b/src/browser/main.coffee index 0ebb13950..75573291e 100644 --- a/src/browser/main.coffee +++ b/src/browser/main.coffee @@ -107,7 +107,7 @@ parseCommandLine = -> ATOM_HOME The root path for all configuration files and folders. Defaults to `~/.atom`. """ - options.boolean('include-deprecated-apis').describe('include-deprecated-apis', 'Include deprecated APIs') + options.boolean('include-deprecated-apis').describe('include-deprecated-apis', 'Include deprecated APIs.') options.alias('d', 'dev').boolean('d').describe('d', 'Run in development mode.') options.alias('f', 'foreground').boolean('f').describe('f', 'Keep the browser process in the foreground.') options.alias('h', 'help').boolean('h').describe('h', 'Print this usage message.') @@ -121,16 +121,12 @@ parseCommandLine = -> options.alias('v', 'version').boolean('v').describe('v', 'Print the version.') options.alias('w', 'wait').boolean('w').describe('w', 'Wait for window to be closed before returning.') options.string('socket-path') - options.alias('1', 'one').boolean('1') # Deprecated 1.0 API preview flag + + # Deprecated 1.0 API preview flag + options.alias('1', 'one').boolean('1').describe('1', 'The option is no longer supported. Atom now defaults to launching with the 1.0 API. Use --include-deprecated-apis to run Atom with deprecated APIs.') + args = options.argv - if args.one - process.stdout.write """ - The -1/--one option has been removed. Atom now defaults to launching with - the 1.0 API. Use --include-deprecated-apis to run Atom with deprecated APIs. - - """ - if args.help process.stdout.write(options.help()) process.exit(0) From 205059cd2f77ad97c60bf3deb37d7a0b05d1b6d8 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 3 Jun 2015 12:00:48 -0700 Subject: [PATCH 1505/1783] The -> This --- src/browser/main.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/browser/main.coffee b/src/browser/main.coffee index 75573291e..7e087eba4 100644 --- a/src/browser/main.coffee +++ b/src/browser/main.coffee @@ -123,7 +123,7 @@ parseCommandLine = -> options.string('socket-path') # Deprecated 1.0 API preview flag - options.alias('1', 'one').boolean('1').describe('1', 'The option is no longer supported. Atom now defaults to launching with the 1.0 API. Use --include-deprecated-apis to run Atom with deprecated APIs.') + options.alias('1', 'one').boolean('1').describe('1', 'This option is no longer supported. Atom now defaults to launching with the 1.0 API. Use --include-deprecated-apis to run Atom with deprecated APIs.') args = options.argv From 281e0b420df934b5c6f88739511be02c3762310a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 3 Jun 2015 15:00:33 -0700 Subject: [PATCH 1506/1783] :art: Move one flag near deprecated flag --- src/browser/main.coffee | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/browser/main.coffee b/src/browser/main.coffee index 7e087eba4..eb08ebe61 100644 --- a/src/browser/main.coffee +++ b/src/browser/main.coffee @@ -107,6 +107,8 @@ parseCommandLine = -> ATOM_HOME The root path for all configuration files and folders. Defaults to `~/.atom`. """ + # Deprecated 1.0 API preview flag + options.alias('1', 'one').boolean('1').describe('1', 'This option is no longer supported. Atom now defaults to launching with the 1.0 API. Use --include-deprecated-apis to run Atom with deprecated APIs.') options.boolean('include-deprecated-apis').describe('include-deprecated-apis', 'Include deprecated APIs.') options.alias('d', 'dev').boolean('d').describe('d', 'Run in development mode.') options.alias('f', 'foreground').boolean('f').describe('f', 'Keep the browser process in the foreground.') @@ -122,9 +124,6 @@ parseCommandLine = -> options.alias('w', 'wait').boolean('w').describe('w', 'Wait for window to be closed before returning.') options.string('socket-path') - # Deprecated 1.0 API preview flag - options.alias('1', 'one').boolean('1').describe('1', 'This option is no longer supported. Atom now defaults to launching with the 1.0 API. Use --include-deprecated-apis to run Atom with deprecated APIs.') - args = options.argv if args.help From 74389fee43710d7e1f0bbb16603f2ff9fe9f4139 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 3 Jun 2015 15:25:55 -0700 Subject: [PATCH 1507/1783] :arrow_up: language-gfm@0.77 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7483221a8..f3b654f45 100644 --- a/package.json +++ b/package.json @@ -132,7 +132,7 @@ "language-coffee-script": "0.40.0", "language-csharp": "0.5.0", "language-css": "0.30.0", - "language-gfm": "0.76.0", + "language-gfm": "0.77.0", "language-git": "0.10.0", "language-go": "0.26.0", "language-html": "0.38.0", From c9eb9d71cce533ba8f1e026d2a0ba0b1146d50f0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 3 Jun 2015 16:11:16 -0700 Subject: [PATCH 1508/1783] Setup deprecated packages in dev mode --- spec/spec-helper.coffee | 3 --- static/index.js | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/spec/spec-helper.coffee b/spec/spec-helper.coffee index d6f072941..15874ff6f 100644 --- a/spec/spec-helper.coffee +++ b/spec/spec-helper.coffee @@ -1,6 +1,3 @@ -# Ensure deprecated packages are populated -require('../package.json')._deprecatedPackages = require('../build/deprecated-packages') - require '../src/window' atom.initialize() atom.restoreWindowDimensions() diff --git a/static/index.js b/static/index.js index a0a0a0c40..b10e723ae 100644 --- a/static/index.js +++ b/static/index.js @@ -26,6 +26,10 @@ window.onload = function() { var devMode = loadSettings.devMode || !loadSettings.resourcePath.startsWith(process.resourcesPath + path.sep); + if (devMode) { + setupDeprecatedPackages(); + } + if (loadSettings.profileStartup) { profileStartup(loadSettings, Date.now() - startTime); } else { @@ -143,6 +147,17 @@ var setupVmCompatibility = function() { } } +var setupDeprecatedPackages = function() { + var metadata = require('../package.json'); + if (!metadata._deprecatedPackages) { + try { + metadata._deprecatedPackages = require('../build/deprecated-packages.json'); + } catch(requireError) { + // Ignored + } + } +} + var profileStartup = function(loadSettings, initialTime) { var profile = function() { console.profile('startup'); From 37939f6c7655d724d1de2d7cc2e22f314f5c0319 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 3 Jun 2015 16:12:48 -0700 Subject: [PATCH 1509/1783] Log deprecated-packages require error --- static/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/index.js b/static/index.js index b10e723ae..24c59c975 100644 --- a/static/index.js +++ b/static/index.js @@ -153,7 +153,7 @@ var setupDeprecatedPackages = function() { try { metadata._deprecatedPackages = require('../build/deprecated-packages.json'); } catch(requireError) { - // Ignored + console.error('Failed to setup deprecated packages list', requireError.stack); } } } From f524ce728ed76334fb9f1afb40f043982edbc057 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 3 Jun 2015 17:46:08 -0700 Subject: [PATCH 1510/1783] :arrow_up: settings-view@0.207.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f3b654f45..c84549343 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "open-on-github": "0.37.0", "package-generator": "0.39.0", "release-notes": "0.52.0", - "settings-view": "0.206.0", + "settings-view": "0.207.0", "snippets": "0.93.0", "spell-check": "0.58.0", "status-bar": "0.74.0", From f5895d8b0b09e68391d034fd458007e9913f09d7 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 3 Jun 2015 17:58:44 -0700 Subject: [PATCH 1511/1783] presenter: use 'markers-updated' event for state updates Signed-off-by: Nathan Sobo --- spec/display-buffer-spec.coffee | 44 ------------- spec/text-editor-presenter-spec.coffee | 16 +++-- src/display-buffer.coffee | 5 +- src/text-editor-presenter.coffee | 91 +++++++------------------- src/text-editor.coffee | 5 +- 5 files changed, 41 insertions(+), 120 deletions(-) diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index 4c48607a5..140ca2f9e 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -1207,50 +1207,6 @@ describe "DisplayBuffer", -> expect(markerCreated1).toHaveBeenCalled() expect(markerCreated2).not.toHaveBeenCalled() - describe "::observeMarkers(callback)", -> - [observationWindow, events] = [] - - beforeEach -> - events = [] - observationWindow = displayBuffer.observeMarkers (event) -> events.push(event) - displayBuffer.unfoldBufferRow(4, 7) - - it "calls the callback when markers enter, leave, or move within the screen range", -> - expect(events).toHaveLength 0 - - observationWindow.setScreenRange([[0, 0], [4, 0]]) - expect(events).toHaveLength 0 - - marker1 = displayBuffer.markScreenPosition([4, 2]) - expect(events).toHaveLength 0 - - observationWindow.setScreenRange([[0, 0], [5, 0]]) - expect(events).toHaveLength 1 - expect(events[0]).toEqual { - insert: new Set([marker1.id]) - update: new Set - remove: new Set - } - - marker2 = displayBuffer.markScreenPosition([5, 2]) - expect(events).toHaveLength 1 - - observationWindow.setBufferRange([[1, 0], [6, 0]]) - expect(events).toHaveLength 2 - expect(events[1]).toEqual { - insert: new Set([marker2.id]) - update: new Set([marker1.id]) - remove: new Set - } - - marker1.destroy() - expect(events).toHaveLength 3 - expect(events[2]).toEqual { - insert: new Set - update: new Set - remove: new Set([marker1.id]) - } - describe "decorations", -> [marker, decoration, decorationProperties] = [] beforeEach -> diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 142026913..fc52c4828 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -1532,21 +1532,27 @@ describe "TextEditorPresenter", -> expect(stateForHighlight(presenter, destroyedSelection.decoration)).toBeUndefined() it "updates when highlight decorations' properties are updated", -> - marker = editor.markBufferRange([[2, 2], [2, 4]]) + marker = editor.markBufferPosition([2, 2]) highlight = editor.decorateMarker(marker, type: 'highlight', class: 'a') presenter = buildPresenter(explicitHeight: 30, scrollTop: 20) - expectValues stateForHighlight(presenter, highlight), {class: 'a'} - expectStateUpdate presenter, -> highlight.setProperties(class: 'b', type: 'highlight') + expect(stateForHighlight(presenter, highlight)).toBeUndefined() + + expectStateUpdate presenter, -> + marker.setBufferRange([[2, 2], [2, 4]]) + highlight.setProperties(class: 'b', type: 'highlight') + expectValues stateForHighlight(presenter, highlight), {class: 'b'} it "increments the .flashCount and sets the .flashClass and .flashDuration when the highlight model flashes", -> presenter = buildPresenter(explicitHeight: 30, scrollTop: 20) - marker = editor.markBufferRange([[2, 2], [2, 4]]) + marker = editor.markBufferPosition([2, 2]) highlight = editor.decorateMarker(marker, type: 'highlight', class: 'a') - expectStateUpdate presenter, -> highlight.flash('b', 500) + expectStateUpdate presenter, -> + marker.setBufferRange([[2, 2], [2, 4]]) + highlight.flash('b', 500) expectValues stateForHighlight(presenter, highlight), { flashClass: 'b' diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index b361e416b..aa6abb7b7 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -10,7 +10,6 @@ Model = require './model' Token = require './token' Decoration = require './decoration' Marker = require './marker' -MarkerObservationWindow = require './marker-observation-window' class BufferToScreenConversionError extends Error constructor: (@message, @metadata) -> @@ -41,6 +40,7 @@ class DisplayBuffer extends Model @disposables.add @tokenizedBuffer.observeGrammar @subscribeToScopedConfigSettings @disposables.add @tokenizedBuffer.onDidChange @handleTokenizedBufferChange @disposables.add @buffer.onDidCreateMarker @handleBufferMarkerCreated + @disposables.add @buffer.onDidUpdateMarkers => @emitter.emit 'did-update-markers' @foldMarkerAttributes = Object.freeze({class: 'fold', displayBufferId: @id}) folds = (new Fold(this, marker) for marker in @buffer.findMarkers(@getFoldMarkerAttributes())) @updateAllScreenLines() @@ -1049,9 +1049,6 @@ class DisplayBuffer extends Model params = @translateToBufferMarkerParams(params) @buffer.findMarkers(params).map (stringMarker) => @getMarker(stringMarker.id) - observeMarkers: (callback) -> - new MarkerObservationWindow(this, @buffer.observeMarkers(callback)) - translateToBufferMarkerParams: (params) -> bufferMarkerParams = {} for key, value of params diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index c2a1d88a5..03cfd5a21 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -29,7 +29,6 @@ class TextEditorPresenter @lineDecorationsByScreenRow = {} @lineNumberDecorationsByScreenRow = {} @customGutterDecorationsByGutterNameAndScreenRow = {} - @highlightDecorationsById = {} @transferMeasurementsToModel() @observeModel() @observeConfig() @@ -126,17 +125,21 @@ class TextEditorPresenter @shouldUpdateLineNumbersState = true @shouldUpdateGutterOrderState = true @shouldUpdateCustomGutterDecorationState = true - @emitDidUpdateState() - @markerObservationWindow = @model.observeMarkers(@markersInRangeDidChange.bind(this)) - @disposables.add new Disposable => @markerObservationWindow.destroy() + @model.onDidUpdateMarkers => + @shouldUpdateTilesState = true + @shouldUpdateLineNumbersState = true + @shouldUpdateDecorations = true + @shouldUpdateOverlaysState = true + @shouldUpdateCustomGutterDecorationState = true + @emitDidUpdateState() @disposables.add @model.onDidChangeGrammar(@didChangeGrammar.bind(this)) @disposables.add @model.onDidChangePlaceholderText => @shouldUpdateContentState = true - @emitDidUpdateState() + @disposables.add @model.onDidChangeMini => @shouldUpdateScrollbarsState = true @shouldUpdateContentState = true @@ -148,14 +151,14 @@ class TextEditorPresenter @shouldUpdateCustomGutterDecorationState = true @updateScrollbarDimensions() @updateCommonGutterState() - @emitDidUpdateState() + @disposables.add @model.onDidChangeLineNumberGutterVisible => @shouldUpdateLineNumberGutterState = true @shouldUpdateGutterOrderState = true @updateCommonGutterState() - @emitDidUpdateState() + @disposables.add @model.onDidAddDecoration(@didAddDecoration.bind(this)) @disposables.add @model.onDidAddCursor(@didAddCursor.bind(this)) @disposables.add @model.onDidChangeScrollTop(@setScrollTop.bind(this)) @@ -614,7 +617,6 @@ class TextEditorPresenter visibleLinesCount = Math.ceil(@height / @lineHeight) + 1 endRow = startRow + visibleLinesCount @endRow = Math.min(@model.getScreenLineCount(), endRow) - @markerObservationWindow.setScreenRange(Range(Point(@startRow, 0), Point(@endRow, 0))) updateScrollWidth: -> return unless @contentWidth? and @clientWidth? @@ -1098,58 +1100,21 @@ class TextEditorPresenter observeDecoration: (decoration) -> decorationDisposables = new CompositeDisposable if decoration.isType('highlight') - decorationDisposables.add decoration.onDidFlash(@highlightDidFlash.bind(this, decoration)) - decorationDisposables.add decoration.onDidChangeProperties(@decorationPropertiesDidChange.bind(this, decoration)) + decorationDisposables.add decoration.onDidFlash => + @shouldUpdateDecorations = true + @emitDidUpdateState() + + decorationDisposables.add decoration.onDidChangeProperties (event) => + @decorationPropertiesDidChange(decoration, event) decorationDisposables.add decoration.onDidDestroy => @disposables.remove(decorationDisposables) decorationDisposables.dispose() @didDestroyDecoration(decoration) @disposables.add(decorationDisposables) - markersInRangeDidChange: (event) -> - event.insert.forEach (markerId) => - range = @model.getMarker(markerId).getScreenRange() - if decorations = @model.decorationsForMarkerId(markerId) - for decoration in decorations - @decorationMarkerDidChange(decoration) - if decoration.isType('line') or decoration.isType('gutter') - @addToLineDecorationCaches(decoration, range) - event.update.forEach (markerId) => - range = @model.getMarker(markerId).getScreenRange() - if decorations = @model.decorationsForMarkerId(markerId) - for decoration in decorations - @decorationMarkerDidChange(decoration) - if decoration.isType('line') or decoration.isType('gutter') - @removeFromLineDecorationCaches(decoration) - @addToLineDecorationCaches(decoration, range) - event.remove.forEach (markerId) => - if decorations = @model.decorationsForMarkerId(markerId) - for decoration in decorations - @decorationMarkerDidChange(decoration) - if decoration.isType('line') or decoration.isType('gutter') - @removeFromLineDecorationCaches(decoration) - @emitDidUpdateState() - - decorationMarkerDidChange: (decoration) -> - if decoration.isType('highlight') - @updateHighlightState(decoration) - if decoration.isType('overlay') - @shouldUpdateOverlaysState = true - if decoration.isType('line') - @shouldUpdateTilesState = true - if decoration.isType('line-number') - @shouldUpdateLineNumbersState = true - else if decoration.isType('gutter') - @shouldUpdateCustomGutterDecorationState = true - - decorationPropertiesDidChange: (decoration, event) -> - {oldProperties} = event + decorationPropertiesDidChange: (decoration, {oldProperties}) -> + @shouldUpdateDecorations = true if decoration.isType('line') or decoration.isType('gutter') - @removePropertiesFromLineDecorationCaches( - decoration.id, - oldProperties, - decoration.getMarker().getScreenRange()) - @addToLineDecorationCaches(decoration, decoration.getMarker().getScreenRange()) if decoration.isType('line') or Decoration.isType(oldProperties, 'line') @shouldUpdateTilesState = true if decoration.isType('line-number') or Decoration.isType(oldProperties, 'line-number') @@ -1159,14 +1124,11 @@ class TextEditorPresenter @shouldUpdateCustomGutterDecorationState = true else if decoration.isType('overlay') @shouldUpdateOverlaysState = true - else if decoration.isType('highlight') - @updateHighlightState(decoration, event) - @emitDidUpdateState() didDestroyDecoration: (decoration) -> + @shouldUpdateDecorations = true if decoration.isType('line') or decoration.isType('gutter') - @removeFromLineDecorationCaches(decoration, decoration.getMarker().getScreenRange()) @shouldUpdateTilesState = true if decoration.isType('line') if decoration.isType('line-number') @shouldUpdateLineNumbersState = true @@ -1179,14 +1141,6 @@ class TextEditorPresenter @emitDidUpdateState() - highlightDidFlash: (decoration) -> - flash = decoration.consumeNextFlash() - if decorationState = @state.content.highlights[decoration.id] - decorationState.flashCount++ - decorationState.flashClass = flash.class - decorationState.flashDuration = flash.duration - @emitDidUpdateState() - didAddDecoration: (decoration) -> @observeDecoration(decoration) @@ -1209,7 +1163,6 @@ class TextEditorPresenter @lineDecorationsByScreenRow = {} @lineNumberDecorationsByScreenRow = {} @customGutterDecorationsByGutterNameAndScreenRow = {} - @highlightDecorationsById = {} visibleHighlights = {} return unless 0 <= @startRow <= @endRow <= Infinity @@ -1304,6 +1257,12 @@ class TextEditorPresenter flashDuration: null flashClass: null } + + if flash = decoration.consumeNextFlash() + highlightState.flashCount++ + highlightState.flashClass = flash.class + highlightState.flashDuration = flash.duration + highlightState.class = properties.class highlightState.deprecatedRegionClass = properties.deprecatedRegionClass highlightState.regions = @buildHighlightRegions(range) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index f2d8445aa..4aacb3dfa 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -163,10 +163,10 @@ class TextEditor extends Model subscribeToDisplayBuffer: -> @disposables.add @displayBuffer.onDidCreateMarker @handleMarkerCreated - @disposables.add @displayBuffer.onDidUpdateMarkers => @mergeIntersectingSelections() @disposables.add @displayBuffer.onDidChangeGrammar => @handleGrammarChange() @disposables.add @displayBuffer.onDidTokenize => @handleTokenization() @disposables.add @displayBuffer.onDidChange (e) => + @mergeIntersectingSelections() @emit 'screen-lines-changed', e if includeDeprecatedAPIs @emitter.emit 'did-change', e @@ -461,6 +461,9 @@ class TextEditor extends Model onDidChangeIcon: (callback) -> @emitter.on 'did-change-icon', callback + onDidUpdateMarkers: (callback) -> + @displayBuffer.onDidUpdateMarkers(callback) + # Public: Retrieves the current {TextBuffer}. getBuffer: -> @buffer From e1514cf363eb2a70b7af3f76d7e7593b2ab80a8c Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 3 Jun 2015 18:30:53 -0700 Subject: [PATCH 1512/1783] Update to latest deprecation data --- build/deprecated-packages.json | 488 ++++++++++++++++----------------- 1 file changed, 235 insertions(+), 253 deletions(-) diff --git a/build/deprecated-packages.json b/build/deprecated-packages.json index 2383d79b2..8d41a53ea 100644 --- a/build/deprecated-packages.json +++ b/build/deprecated-packages.json @@ -4,10 +4,10 @@ "hasDeprecations": true, "latestHasDeprecations": false }, - "agda-mode": { - "version": "<=0.2.17", + "angularjs-helper": { + "version": "<=0.9.2", "hasDeprecations": true, - "latestHasDeprecations": false + "latestHasDeprecations": true }, "apex-ui-personalize": { "version": "<=0.1.0", @@ -15,7 +15,7 @@ "latestHasDeprecations": true }, "api-blueprint-preview": { - "version": "<=0.3.2", + "version": "<=0.3.0", "hasDeprecations": true, "latestHasDeprecations": false }, @@ -34,6 +34,11 @@ "hasDeprecations": true, "latestHasDeprecations": true }, + "asteroids": { + "version": "<=0.2.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, "atom-2048": { "version": "<=1.2.3", "hasDeprecations": true, @@ -49,7 +54,7 @@ "latestHasDeprecations": true }, "atom-beautify": { - "version": "<=0.27.7", + "version": "<=0.27.6", "hasDeprecations": true, "latestHasDeprecations": false }, @@ -76,12 +81,7 @@ "atom-ctags": { "version": "<=3.2.0", "hasDeprecations": true, - "latestHasDeprecations": true - }, - "atom-deconsole": { - "version": "<=0.0.1", - "hasDeprecations": true, - "latestHasDeprecations": true + "latestHasDeprecations": false }, "atom-faker": { "version": "<=0.2.0", @@ -89,9 +89,8 @@ "latestHasDeprecations": true }, "atom-flake8": { - "version": "<=0.1.0", - "hasDeprecations": true, - "latestHasDeprecations": true + "hasAlternative": true, + "alternative": "linter" }, "atom-grunt-configs": { "version": "<=0.1.0", @@ -99,9 +98,9 @@ "latestHasDeprecations": true }, "atom-html-preview": { - "version": "<=0.1.4", + "version": "<=0.1.6", "hasDeprecations": true, - "latestHasDeprecations": false + "latestHasDeprecations": true }, "atom-html5-boilerplate": { "version": "<=0.2.0", @@ -143,9 +142,9 @@ "latestHasDeprecations": true }, "atom-python-debugger": { - "version": "<=0.2.2", + "version": "<=0.3.0", "hasDeprecations": true, - "latestHasDeprecations": false + "latestHasDeprecations": true }, "atom-rails": { "version": "<=0.4.0", @@ -177,31 +176,36 @@ "hasDeprecations": true, "latestHasDeprecations": false }, + "atom-typescript": { + "version": "<=4.1.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "atom-ungit": { + "version": "<=0.4.3", + "hasDeprecations": true, + "latestHasDeprecations": true + }, "atom-yeoman": { "version": "<=0.2.0", "hasDeprecations": true, "latestHasDeprecations": false }, "atomatigit": { - "version": "<=1.5.1", + "version": "<=1.3.0", "hasDeprecations": true, "latestHasDeprecations": false }, "atomic-emacs": { "version": "<=0.5.1", "hasDeprecations": true, - "latestHasDeprecations": true + "latestHasDeprecations": false }, "atomic-rest": { "version": "<=0.2.1", "hasDeprecations": true, "latestHasDeprecations": true }, - "auto-copyright": { - "version": "<=0.3.1", - "hasDeprecations": true, - "latestHasDeprecations": false - }, "auto-detect-indentation": { "version": "<=0.3.0", "hasDeprecations": true, @@ -236,11 +240,6 @@ "hasAlternative": true, "alternative": "autocomplete-plus-python-jedi" }, - "autocomplete-modules": { - "version": "<=0.3.2", - "hasDeprecations": true, - "latestHasDeprecations": false - }, "autocomplete-paths": { "version": "<=1.0.1", "hasDeprecations": true, @@ -271,13 +270,13 @@ "hasDeprecations": true, "latestHasDeprecations": false }, - "block-comment": { - "version": "<=0.4.1", + "big-cursor": { + "version": "<=0.1.0", "hasDeprecations": true, "latestHasDeprecations": true }, - "block-travel": { - "version": "<=0.10.0", + "block-comment": { + "version": "<=0.4.1", "hasDeprecations": true, "latestHasDeprecations": false }, @@ -286,21 +285,11 @@ "hasDeprecations": true, "latestHasDeprecations": true }, - "build-systems": { - "version": "<=0.5.0", - "hasDeprecations": true, - "latestHasDeprecations": true - }, "cabal": { "version": "<=0.0.13", "hasDeprecations": true, "latestHasDeprecations": false }, - "caniuse": { - "version": "<=0.1.1", - "hasDeprecations": true, - "latestHasDeprecations": false - }, "change-case": { "version": "<=0.5.1", "hasDeprecations": true, @@ -312,7 +301,7 @@ "latestHasDeprecations": false }, "clang-format": { - "version": "<=1.5.0", + "version": "<=1.8.0", "hasDeprecations": true, "latestHasDeprecations": false }, @@ -321,8 +310,8 @@ "hasDeprecations": true, "latestHasDeprecations": true }, - "close-after-last-tab": { - "version": "<=0.1.5", + "clone-cursor": { + "version": "<=1.0.0", "hasDeprecations": true, "latestHasDeprecations": true }, @@ -331,25 +320,24 @@ "hasDeprecations": true, "latestHasDeprecations": true }, + "code-links": { + "version": "<=0.3.8", + "hasDeprecations": true, + "latestHasDeprecations": false + }, "codeship-status": { "version": "<=0.1.1", "hasDeprecations": true, "latestHasDeprecations": true }, "coffee-compile": { - "version": "<=0.4.0", + "version": "<=0.5.0", "hasDeprecations": true, "latestHasDeprecations": false }, "coffee-lint": { - "version": "<=0.7.3", - "hasDeprecations": true, - "latestHasDeprecations": true - }, - "coffee-navigator": { - "version": "<=0.0.16", - "hasDeprecations": true, - "latestHasDeprecations": true + "hasAlternative": true, + "alternative": "linter" }, "coffee-trace": { "version": "<=0.2.2", @@ -429,13 +417,8 @@ "hasAlternative": true, "alternative": "core" }, - "dart-tools": { - "version": "<=0.9.11", - "hasDeprecations": true, - "latestHasDeprecations": true - }, "dash": { - "version": "<=1.0.0", + "version": "<=1.0.3", "hasDeprecations": true, "latestHasDeprecations": false }, @@ -502,11 +485,6 @@ "emp-template-management": { "version": "<=0.1.13", "hasDeprecations": true, - "latestHasDeprecations": false - }, - "enhanced-package-list": { - "version": "<=1.0.3", - "hasDeprecations": true, "latestHasDeprecations": true }, "enhanced-tabs": { @@ -534,11 +512,6 @@ "hasDeprecations": true, "latestHasDeprecations": true }, - "ever-notedown": { - "version": "<=0.1.1", - "hasDeprecations": true, - "latestHasDeprecations": true - }, "ex-mode": { "version": "<=0.4.1", "hasDeprecations": true, @@ -565,7 +538,12 @@ "latestHasDeprecations": true }, "file-icon-supplement": { - "version": "<=0.7.10", + "version": "<=0.7.3", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "file-icons": { + "version": "<=0.3.0", "hasDeprecations": true, "latestHasDeprecations": false }, @@ -599,19 +577,14 @@ "latestHasDeprecations": true }, "fuzzy-finder": { - "version": "<=0.54.0", + "version": "<=0.60.0", "hasDeprecations": true, "latestHasDeprecations": false }, - "fuzzy-finder-plus": { - "version": "<=1.4.0", - "hasDeprecations": true, - "latestHasDeprecations": true - }, "get-routes": { - "version": "<=0.1.0", + "version": "<=0.2.0", "hasDeprecations": true, - "latestHasDeprecations": false + "latestHasDeprecations": true }, "gist-it": { "version": "<=0.6.10", @@ -621,23 +594,23 @@ "git-blame": { "version": "<=0.4.0", "hasDeprecations": true, - "latestHasDeprecations": true + "latestHasDeprecations": false }, "git-control": { "version": "<=0.2.0", "hasDeprecations": true, "latestHasDeprecations": false }, + "git-diff": { + "version": "<=0.43.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, "git-diff-details": { "version": "<=0.8.0", "hasDeprecations": true, "latestHasDeprecations": false }, - "git-grep": { - "version": "<=0.9.0", - "hasDeprecations": true, - "latestHasDeprecations": true - }, "git-log": { "version": "<=0.3.0", "hasDeprecations": true, @@ -648,8 +621,8 @@ "hasDeprecations": true, "latestHasDeprecations": false }, - "git-projects": { - "version": "<=1.14.1", + "git-review": { + "version": "<=0.2.1", "hasDeprecations": true, "latestHasDeprecations": true }, @@ -663,13 +636,23 @@ "hasDeprecations": true, "latestHasDeprecations": true }, + "gitignore-snippets": { + "version": "<=0.2.3", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "gitter": { + "version": "<=0.6.2", + "hasDeprecations": true, + "latestHasDeprecations": true + }, "go-oracle": { "version": "<=0.2.0", "hasDeprecations": true, "latestHasDeprecations": false }, "go-plus": { - "version": "<=3.0.9", + "version": "<=2.0.8", "hasDeprecations": true, "latestHasDeprecations": false }, @@ -678,16 +661,16 @@ "hasDeprecations": true, "latestHasDeprecations": true }, + "gocode": { + "version": "<=0.2.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, "gradle-ci": { "version": "<=0.2.3", "hasDeprecations": true, "latestHasDeprecations": true }, - "grammar-selector": { - "version": "<=0.35.0", - "hasDeprecations": true, - "latestHasDeprecations": false - }, "grunt-runner": { "version": "<=0.8.2", "hasDeprecations": true, @@ -701,7 +684,7 @@ "gutter-shadow": { "version": "<=0.1.1", "hasDeprecations": true, - "latestHasDeprecations": true + "latestHasDeprecations": false }, "hiera-eyaml": { "version": "<=0.4.7", @@ -764,7 +747,7 @@ "latestHasDeprecations": true }, "htmlhint": { - "version": "<=1.0.2", + "version": "<=0.4.0", "hasDeprecations": true, "latestHasDeprecations": false }, @@ -779,10 +762,15 @@ "latestHasDeprecations": false }, "ide-haskell": { - "version": "<=0.1.1", + "version": "<=0.3.0", "hasDeprecations": true, "latestHasDeprecations": false }, + "import": { + "version": "<=1.3.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, "inc-dec-value": { "version": "<=0.0.7", "hasDeprecations": true, @@ -793,11 +781,6 @@ "hasDeprecations": true, "latestHasDeprecations": true }, - "indent-guide-improved": { - "version": "<=1.1.1", - "hasDeprecations": true, - "latestHasDeprecations": false - }, "indent-helper": { "version": "<=0.1.1", "hasDeprecations": true, @@ -818,21 +801,11 @@ "hasDeprecations": true, "latestHasDeprecations": true }, - "ionic-preview": { - "version": "<=0.3.1", - "hasDeprecations": true, - "latestHasDeprecations": false - }, "japanese-zen-han-convert": { "version": "<=0.3.2", "hasDeprecations": true, "latestHasDeprecations": false }, - "jekyll": { - "version": "<=0.4.3", - "hasDeprecations": true, - "latestHasDeprecations": true - }, "jsdoc": { "version": "<=0.9.0", "hasDeprecations": true, @@ -841,10 +814,10 @@ "jsformat": { "version": "<=0.8.1", "hasDeprecations": true, - "latestHasDeprecations": true + "latestHasDeprecations": false }, "jslint": { - "version": "<=0.10.2", + "version": "<=1.2.1", "hasDeprecations": true, "latestHasDeprecations": false }, @@ -854,7 +827,7 @@ "latestHasDeprecations": false }, "jsonpp": { - "version": "<=0.0.7", + "version": "<=0.0.6", "hasDeprecations": true, "latestHasDeprecations": false }, @@ -863,6 +836,11 @@ "hasDeprecations": true, "latestHasDeprecations": true }, + "kinetic": { + "version": "<=0.2.5", + "hasDeprecations": true, + "latestHasDeprecations": true + }, "language-javascript-semantic": { "version": "<=0.1.0", "hasDeprecations": true, @@ -871,7 +849,7 @@ "language-jsoniq": { "version": "<=1.4.0", "hasDeprecations": true, - "latestHasDeprecations": true + "latestHasDeprecations": false }, "language-rspec": { "version": "<=0.2.1", @@ -902,16 +880,16 @@ "hasDeprecations": true, "latestHasDeprecations": false }, - "less-than-slash": { - "version": "<=0.4.1", - "hasDeprecations": true, - "latestHasDeprecations": false - }, "letter-spacing": { "version": "<=0.2.0", "hasDeprecations": true, "latestHasDeprecations": false }, + "line-count": { + "version": "<=0.3.3", + "hasDeprecations": true, + "latestHasDeprecations": true + }, "line-jumper": { "version": "<=0.13.0", "hasDeprecations": true, @@ -952,11 +930,6 @@ "hasDeprecations": true, "latestHasDeprecations": false }, - "localeapp": { - "version": "<=0.1.3", - "hasDeprecations": true, - "latestHasDeprecations": true - }, "localization": { "version": "<=1.16.1", "hasDeprecations": true, @@ -965,10 +938,10 @@ "log-console": { "version": "<=0.1.2", "hasDeprecations": true, - "latestHasDeprecations": true + "latestHasDeprecations": false }, "lorem-ipsum": { - "version": "<=0.4.0", + "version": "<=0.5.0", "hasDeprecations": true, "latestHasDeprecations": true }, @@ -992,15 +965,10 @@ "hasDeprecations": true, "latestHasDeprecations": false }, - "markdown-preview-pandoc": { - "version": "<=0.0.13", - "hasDeprecations": true, - "latestHasDeprecations": true - }, "markdown-preview-plus": { "version": "<=1.4.0", "hasDeprecations": true, - "latestHasDeprecations": true + "latestHasDeprecations": false }, "markdown-stream": { "version": "<=0.6.0", @@ -1008,9 +976,9 @@ "latestHasDeprecations": true }, "markdown-writer": { - "version": "<=1.3.0", + "version": "<=1.3.2", "hasDeprecations": true, - "latestHasDeprecations": false + "latestHasDeprecations": true }, "marked": { "version": "<=0.1.8", @@ -1020,7 +988,7 @@ "mate-subword-navigation": { "version": "<=3.0.1", "hasDeprecations": true, - "latestHasDeprecations": true + "latestHasDeprecations": false }, "MavensMate-Atom": { "version": "<=0.0.20", @@ -1037,6 +1005,11 @@ "hasDeprecations": true, "latestHasDeprecations": true }, + "mdurl": { + "version": "<=0.2.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, "mechanical-keyboard": { "version": "<=0.1.0", "hasDeprecations": true, @@ -1072,41 +1045,16 @@ "hasDeprecations": true, "latestHasDeprecations": false }, - "move-panes": { - "version": "<=0.1.2", - "hasDeprecations": true, - "latestHasDeprecations": true - }, "node-debugger": { "version": "<=0.2.3", "hasDeprecations": true, "latestHasDeprecations": false }, - "node-resolver": { - "version": "<=1.0.1", - "hasDeprecations": true, - "latestHasDeprecations": true - }, "npm-autocomplete": { "version": "<=0.1.2", "hasDeprecations": true, "latestHasDeprecations": true }, - "npm-docs": { - "version": "<=0.2.0", - "hasDeprecations": true, - "latestHasDeprecations": true - }, - "npm-install": { - "version": "<=3.0.1", - "hasDeprecations": true, - "latestHasDeprecations": true - }, - "nrepl": { - "version": "<=0.0.6", - "hasDeprecations": true, - "latestHasDeprecations": false - }, "omni-ruler": { "version": "<=0.3.1", "hasDeprecations": true, @@ -1117,8 +1065,8 @@ "hasDeprecations": true, "latestHasDeprecations": false }, - "open-in": { - "version": "<=3.1.0", + "open-git-modified-files": { + "version": "<=0.1.0", "hasDeprecations": true, "latestHasDeprecations": true }, @@ -1127,50 +1075,60 @@ "hasDeprecations": true, "latestHasDeprecations": true }, + "open-in-gitx": { + "version": "<=0.1.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "open-in-sourcetree": { + "version": "<=0.1.3", + "hasDeprecations": true, + "latestHasDeprecations": true + }, "open-last-project": { "hasAlternative": true, "alternative": "core" }, - "open-plus": { - "version": "<=0.3.2", - "hasDeprecations": true, - "latestHasDeprecations": true - }, "open-recent": { "version": "<=2.2.0", "hasDeprecations": true, "latestHasDeprecations": false }, - "open-sesame": { - "version": "<=0.3.0", - "hasDeprecations": true, - "latestHasDeprecations": false - }, "package-cop": { "version": "<=0.2.5", "hasDeprecations": true, - "latestHasDeprecations": true + "latestHasDeprecations": false }, "package-list-downloader": { "version": "<=0.2.1", "hasDeprecations": true, "latestHasDeprecations": true }, - "pain-split": { - "version": "<=1.1.2", + "pair-programming": { + "version": "<=0.7.0", "hasDeprecations": true, - "latestHasDeprecations": false + "latestHasDeprecations": true }, "pane-layout-switcher": { "version": "<=0.0.3", "hasDeprecations": true, "latestHasDeprecations": true }, + "paredit": { + "version": "<=1.0.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, "party-hard": { "version": "<=0.3.3", "hasDeprecations": true, "latestHasDeprecations": true }, + "path": { + "version": "<=0.4.1", + "hasDeprecations": true, + "latestHasDeprecations": true + }, "pep8": { "hasAlternative": true, "alternative": "linter" @@ -1180,11 +1138,6 @@ "hasDeprecations": true, "latestHasDeprecations": true }, - "perltidy": { - "version": "<=2.1.0", - "hasDeprecations": true, - "latestHasDeprecations": false - }, "permute": { "version": "<=0.1.0", "hasDeprecations": true, @@ -1196,7 +1149,12 @@ "latestHasDeprecations": true }, "php-getters-setters": { - "version": "<=0.3.0", + "version": "<=0.5.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "php-server": { + "version": "<=0.4.0", "hasDeprecations": true, "latestHasDeprecations": true }, @@ -1211,7 +1169,7 @@ "latestHasDeprecations": true }, "pretty-json": { - "version": "<=0.3.1", + "version": "<=0.3.2", "hasDeprecations": true, "latestHasDeprecations": false }, @@ -1221,25 +1179,30 @@ "latestHasDeprecations": false }, "preview-plus": { - "version": "<=1.1.19", + "version": "<=1.1.42", + "hasDeprecations": true, + "latestHasDeprecations": true + }, + "project-colorize": { + "version": "<=0.1.0", "hasDeprecations": true, "latestHasDeprecations": false }, "project-manager": { - "version": "<=1.15.5", + "version": "<=1.11.1", "hasDeprecations": true, "latestHasDeprecations": false }, "project-palette-finder": { - "version": "<=2.4.17", - "hasDeprecations": true, - "latestHasDeprecations": true - }, - "project-ring": { - "version": "<=0.19.6", + "version": "<=2.4.7", "hasDeprecations": true, "latestHasDeprecations": false }, + "project-ring": { + "version": "<=0.20.5", + "hasDeprecations": true, + "latestHasDeprecations": true + }, "python": { "hasAlternative": true, "alternative": "script" @@ -1252,7 +1215,7 @@ "python-isort": { "version": "<=0.0.6", "hasDeprecations": true, - "latestHasDeprecations": true + "latestHasDeprecations": false }, "python-jedi": { "version": "<=0.1.7", @@ -1264,21 +1227,21 @@ "hasDeprecations": true, "latestHasDeprecations": true }, + "r-exec": { + "version": "<=0.1.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, "rails-navigation": { "version": "<=0.1.1", "hasDeprecations": true, "latestHasDeprecations": true }, "react": { - "version": "<=0.7.8", + "version": "<=0.5.3", "hasDeprecations": true, "latestHasDeprecations": false }, - "recent-files": { - "version": "<=0.3.0", - "hasDeprecations": true, - "latestHasDeprecations": true - }, "recent-projects": { "version": "<=0.3.0", "hasDeprecations": true, @@ -1295,7 +1258,7 @@ "latestHasDeprecations": true }, "remote-atom": { - "version": "<=1.1.10", + "version": "<=1.2.0", "hasDeprecations": true, "latestHasDeprecations": false }, @@ -1307,7 +1270,7 @@ "remote-sync": { "version": "<=3.1.1", "hasDeprecations": true, - "latestHasDeprecations": true + "latestHasDeprecations": false }, "resize-panes": { "hasAlternative": true, @@ -1323,11 +1286,6 @@ "hasDeprecations": true, "latestHasDeprecations": false }, - "rhino-python": { - "version": "<=0.6.1", - "hasDeprecations": true, - "latestHasDeprecations": false - }, "rsense": { "version": "<=0.6.0", "hasDeprecations": true, @@ -1353,11 +1311,6 @@ "hasDeprecations": true, "latestHasDeprecations": true }, - "ruby-quick-test": { - "version": "<=0.3.0", - "hasDeprecations": true, - "latestHasDeprecations": true - }, "ruby-strftime-reference": { "version": "<=0.3.0", "hasDeprecations": true, @@ -1368,9 +1321,19 @@ "hasDeprecations": true, "latestHasDeprecations": false }, + "ruler": { + "version": "<=0.2.3", + "hasDeprecations": true, + "latestHasDeprecations": true + }, "run-command": { "version": "<=0.1.1", "hasDeprecations": true, + "latestHasDeprecations": false + }, + "run-file": { + "version": "<=0.9.0", + "hasDeprecations": true, "latestHasDeprecations": true }, "run-in-browser": { @@ -1418,6 +1381,11 @@ "hasDeprecations": true, "latestHasDeprecations": false }, + "select-scope": { + "version": "<=0.2.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, "selection-count": { "hasAlternative": true, "alternative": "core" @@ -1435,7 +1403,7 @@ "smarter-delete-line": { "version": "<=1.0.0", "hasDeprecations": true, - "latestHasDeprecations": true + "latestHasDeprecations": false }, "space-block-jumper": { "version": "<=0.4.3", @@ -1445,7 +1413,7 @@ "space-tab": { "version": "<=0.1.0", "hasDeprecations": true, - "latestHasDeprecations": true + "latestHasDeprecations": false }, "spark-dfu-util": { "version": "<=0.4.0", @@ -1458,20 +1426,25 @@ "latestHasDeprecations": true }, "sublime-tabs": { - "version": "<=0.5.6", - "hasDeprecations": true, - "latestHasDeprecations": true + "hasAlternative": true, + "message": "`sublime-tabs` has been replaced by the 'Use Preview Tabs' option in the `tabs` package settings.", + "alternative": "core" }, "supercollider": { "version": "<=0.4.2", "hasDeprecations": true, - "latestHasDeprecations": true + "latestHasDeprecations": false }, "supercopair": { "version": "<=0.9.34", "hasDeprecations": true, "latestHasDeprecations": true }, + "support-gbk": { + "version": "<=1.1.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, "swift-playground": { "version": "<=0.2.0", "hasDeprecations": true, @@ -1492,11 +1465,6 @@ "hasDeprecations": true, "latestHasDeprecations": true }, - "tab-move-key": { - "version": "<=0.1.0", - "hasDeprecations": true, - "latestHasDeprecations": true - }, "tab-switcher": { "version": "<=0.2.0", "hasDeprecations": true, @@ -1512,23 +1480,23 @@ "hasDeprecations": true, "latestHasDeprecations": false }, - "task-list": { - "version": "<=0.7.0", - "hasDeprecations": true, - "latestHasDeprecations": true - }, "tasks": { "version": "<=1.0.1", "hasDeprecations": true, "latestHasDeprecations": false }, + "term": { + "version": "<=0.2.2", + "hasDeprecations": true, + "latestHasDeprecations": true + }, "terminal-panel": { "version": "<=1.11.0", "hasDeprecations": true, "latestHasDeprecations": false }, "terminal-status": { - "version": "<=1.6.0", + "version": "<=1.6.4", "hasDeprecations": true, "latestHasDeprecations": false }, @@ -1537,11 +1505,16 @@ "hasDeprecations": true, "latestHasDeprecations": false }, - "ti-alloy-related": { - "version": "<=0.6.0", + "the-closer": { + "version": "<=0.1.0", "hasDeprecations": true, "latestHasDeprecations": false }, + "ti-alloy-related": { + "version": "<=0.8.0", + "hasDeprecations": true, + "latestHasDeprecations": true + }, "tidal": { "version": "<=0.6.6", "hasDeprecations": true, @@ -1552,8 +1525,13 @@ "hasDeprecations": true, "latestHasDeprecations": false }, - "todo-list": { - "version": "<=1.0.0", + "timecop": { + "version": "<=0.23.0", + "hasDeprecations": true, + "latestHasDeprecations": false + }, + "timekeeper": { + "version": "<=0.4.0", "hasDeprecations": true, "latestHasDeprecations": true }, @@ -1572,40 +1550,34 @@ "hasDeprecations": true, "latestHasDeprecations": true }, - "tree-view-breadcrumb": { - "version": "<=0.2.1", + "true-color": { + "version": "<=0.4.1", "hasDeprecations": true, - "latestHasDeprecations": false + "latestHasDeprecations": true }, "turbo-javascript": { "version": "<=0.0.10", "hasDeprecations": true, - "latestHasDeprecations": true + "latestHasDeprecations": false }, "turnip-step": { "version": "<=1.0.0", "hasDeprecations": true, "latestHasDeprecations": true }, - "unity-dark-ui": { - "version": "<=1.1.0", - "hasDeprecations": true, - "latestHasDeprecations": false - }, "unity-ui": { "version": "<=1.0.5", "hasDeprecations": true, "latestHasDeprecations": false }, - "update-packages": { - "version": "<=0.1.0", + "update-package-dependencies": { + "version": "<=0.6.0", "hasDeprecations": true, - "latestHasDeprecations": true + "latestHasDeprecations": false }, - "url-encode": { - "version": "<=0.4.0", - "hasDeprecations": true, - "latestHasDeprecations": true + "update-packages": { + "hasAlternative": true, + "alternative": "core" }, "vertical-align": { "version": "<=0.6.1", @@ -1613,7 +1585,7 @@ "latestHasDeprecations": false }, "view-tail-large-files": { - "version": "<=0.1.16", + "version": "<=0.1.17", "hasDeprecations": true, "latestHasDeprecations": true }, @@ -1632,6 +1604,11 @@ "hasDeprecations": true, "latestHasDeprecations": false }, + "vnc": { + "version": "<=0.1.3", + "hasDeprecations": true, + "latestHasDeprecations": true + }, "voicecode": { "version": "<=0.9.0", "hasDeprecations": true, @@ -1667,6 +1644,11 @@ "hasDeprecations": true, "latestHasDeprecations": false }, + "white-cursor": { + "version": "<=0.5.1", + "hasDeprecations": true, + "latestHasDeprecations": false + }, "whitespace": { "version": "<=0.24.0", "hasDeprecations": true, @@ -1683,7 +1665,7 @@ "latestHasDeprecations": false }, "wordcount": { - "version": "<=2.1.0", + "version": "<=2.2.0", "hasDeprecations": true, "latestHasDeprecations": false }, @@ -1707,4 +1689,4 @@ "hasDeprecations": true, "latestHasDeprecations": false } -} +} \ No newline at end of file From 0b1aadf168780a5bccfe432f76aaee6b50dcf0bb Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 3 Jun 2015 21:28:17 +0200 Subject: [PATCH 1513/1783] :art: Rename to `shouldUpdateLinesState` --- src/text-editor-presenter.coffee | 37 ++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 7b63fa10a..c086677c8 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -75,7 +75,7 @@ class TextEditorPresenter @updateHiddenInputState() if @shouldUpdateHiddenInputState @updateContentState() if @shouldUpdateContentState @updateDecorations() if @shouldUpdateDecorations - @updateTilesState() if @shouldUpdateTilesState + @updateTilesState() if @shouldUpdateLinesState @updateCursorsState() if @shouldUpdateCursorsState @updateOverlaysState() if @shouldUpdateOverlaysState @updateLineNumberGutterState() if @shouldUpdateLineNumberGutterState @@ -97,7 +97,7 @@ class TextEditorPresenter @shouldUpdateHiddenInputState = false @shouldUpdateContentState = false @shouldUpdateDecorations = false - @shouldUpdateTilesState = false + @shouldUpdateLinesState = false @shouldUpdateCursorsState = false @shouldUpdateOverlaysState = false @shouldUpdateLineNumberGutterState = false @@ -116,7 +116,7 @@ class TextEditorPresenter @shouldUpdateContentState = true @shouldUpdateDecorations = true @shouldUpdateCursorsState = true - @shouldUpdateTilesState = true + @shouldUpdateLinesState = true @shouldUpdateLineNumberGutterState = true @shouldUpdateLineNumbersState = true @shouldUpdateGutterOrderState = true @@ -132,7 +132,7 @@ class TextEditorPresenter @shouldUpdateScrollbarsState = true @shouldUpdateContentState = true @shouldUpdateDecorations = true - @shouldUpdateTilesState = true + @shouldUpdateLinesState = true @shouldUpdateLineNumberGutterState = true @shouldUpdateLineNumbersState = true @shouldUpdateGutterOrderState = true @@ -220,6 +220,8 @@ class TextEditorPresenter @updateState() updateState: -> + @shouldUpdateLinesState = true + @updateContentDimensions() @updateScrollbarDimensions() @updateStartRow() @@ -324,7 +326,7 @@ class TextEditorPresenter tile.height = @tileSize * @lineHeight tile.display = "block" - @updateLinesState(tile, startRow, endRow) + @updateLinesState(tile, startRow, endRow) if @shouldUpdateLinesState visibleTiles[startRow] = true @@ -782,7 +784,7 @@ class TextEditorPresenter @shouldUpdateVerticalScrollState = true @shouldUpdateHiddenInputState = true @shouldUpdateDecorations = true - @shouldUpdateTilesState = true + @shouldUpdateLinesState = true @shouldUpdateCursorsState = true @shouldUpdateLineNumbersState = true @shouldUpdateCustomGutterDecorationState = true @@ -805,7 +807,7 @@ class TextEditorPresenter @state.content.scrollingVertically = false if @mouseWheelScreenRow? @mouseWheelScreenRow = null - @shouldUpdateTilesState = true + @shouldUpdateLinesState = true @shouldUpdateLineNumbersState = true @shouldUpdateCustomGutterDecorationState = true @@ -822,7 +824,7 @@ class TextEditorPresenter @shouldUpdateCursorsState = true @shouldUpdateOverlaysState = true @shouldUpdateDecorations = true - @shouldUpdateTilesState = true + @shouldUpdateLinesState = true @emitDidUpdateState() @@ -870,7 +872,7 @@ class TextEditorPresenter @shouldUpdateVerticalScrollState = true @shouldUpdateScrollbarsState = true @shouldUpdateDecorations = true - @shouldUpdateTilesState = true + @shouldUpdateLinesState = true @shouldUpdateCursorsState = true @shouldUpdateLineNumbersState = true @shouldUpdateCustomGutterDecorationState = true @@ -898,7 +900,7 @@ class TextEditorPresenter @shouldUpdateScrollbarsState = true @shouldUpdateContentState = true @shouldUpdateDecorations = true - @shouldUpdateTilesState = true + @shouldUpdateLinesState = true @shouldUpdateCursorsState = true unless oldContentFrameWidth? @emitDidUpdateState() @@ -964,7 +966,7 @@ class TextEditorPresenter @shouldUpdateScrollbarsState = true @shouldUpdateHiddenInputState = true @shouldUpdateDecorations = true - @shouldUpdateTilesState = true + @shouldUpdateLinesState = true @shouldUpdateCursorsState = true @shouldUpdateLineNumbersState = true @shouldUpdateCustomGutterDecorationState = true @@ -1016,7 +1018,7 @@ class TextEditorPresenter @shouldUpdateHiddenInputState = true @shouldUpdateContentState = true @shouldUpdateDecorations = true - @shouldUpdateTilesState = true + @shouldUpdateLinesState = true @shouldUpdateCursorsState = true @shouldUpdateOverlaysState = true @@ -1114,7 +1116,8 @@ class TextEditorPresenter intersectsVisibleRowRange = true if intersectsVisibleRowRange - @shouldUpdateTilesState = true if decoration.isType('line') + if decoration.isType('line') + @shouldUpdateLinesState = true if decoration.isType('line-number') @shouldUpdateLineNumbersState = true else if decoration.isType('gutter') @@ -1139,7 +1142,7 @@ class TextEditorPresenter decoration.getMarker().getScreenRange()) @addToLineDecorationCaches(decoration, decoration.getMarker().getScreenRange()) if decoration.isType('line') or Decoration.isType(oldProperties, 'line') - @shouldUpdateTilesState = true + @shouldUpdateLinesState = true if decoration.isType('line-number') or Decoration.isType(oldProperties, 'line-number') @shouldUpdateLineNumbersState = true if (decoration.isType('gutter') and not decoration.isType('line-number')) or @@ -1155,7 +1158,8 @@ class TextEditorPresenter didDestroyDecoration: (decoration) -> if decoration.isType('line') or decoration.isType('gutter') @removeFromLineDecorationCaches(decoration, decoration.getMarker().getScreenRange()) - @shouldUpdateTilesState = true if decoration.isType('line') + if decoration.isType('line') + @shouldUpdateLinesState = true if decoration.isType('line-number') @shouldUpdateLineNumbersState = true else if decoration.isType('gutter') @@ -1180,7 +1184,8 @@ class TextEditorPresenter if decoration.isType('line') or decoration.isType('gutter') @addToLineDecorationCaches(decoration, decoration.getMarker().getScreenRange()) - @shouldUpdateTilesState = true if decoration.isType('line') + if decoration.isType('line') + @shouldUpdateLinesState = true if decoration.isType('line-number') @shouldUpdateLineNumbersState = true else if decoration.isType('gutter') From f0ca0d52f2778eb36c0cc462bd42a2adbd31a933 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 4 Jun 2015 10:13:13 +0200 Subject: [PATCH 1514/1783] Tile line numbers in `TextEditorPresenter` --- src/text-editor-presenter.coffee | 41 ++++++++++++++++---------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index c086677c8..ad0e91336 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -75,11 +75,10 @@ class TextEditorPresenter @updateHiddenInputState() if @shouldUpdateHiddenInputState @updateContentState() if @shouldUpdateContentState @updateDecorations() if @shouldUpdateDecorations - @updateTilesState() if @shouldUpdateLinesState + @updateTilesState() if @shouldUpdateLinesState or @shouldUpdateLineNumbersState @updateCursorsState() if @shouldUpdateCursorsState @updateOverlaysState() if @shouldUpdateOverlaysState @updateLineNumberGutterState() if @shouldUpdateLineNumberGutterState - @updateLineNumbersState() if @shouldUpdateLineNumbersState @updateGutterOrderState() if @shouldUpdateGutterOrderState @updateCustomGutterDecorationState() if @shouldUpdateCustomGutterDecorationState @updating = false @@ -326,7 +325,14 @@ class TextEditorPresenter tile.height = @tileSize * @lineHeight tile.display = "block" + gutterTile = @lineNumberGutter.tiles[startRow] ?= {} + gutterTile.top = startRow * @lineHeight - @scrollTop + gutterTile.left = -@scrollLeft + gutterTile.height = @tileSize * @lineHeight + gutterTile.display = "block" + @updateLinesState(tile, startRow, endRow) if @shouldUpdateLinesState + @updateLineNumbersState(gutterTile, startRow, endRow) if @shouldUpdateLineNumbersState visibleTiles[startRow] = true @@ -334,6 +340,7 @@ class TextEditorPresenter mouseWheelTile = @tileForRow(@mouseWheelScreenRow) unless visibleTiles[mouseWheelTile]? + @lineNumberGutter.tiles[mouseWheelTile].display = "none" @state.content.tiles[mouseWheelTile].display = "none" visibleTiles[mouseWheelTile] = true @@ -341,6 +348,7 @@ class TextEditorPresenter continue if visibleTiles.hasOwnProperty(id) delete @state.content.tiles[id] + delete @lineNumberGutter.tiles[id] updateLinesState: (tileState, startRow, endRow) -> tileState.lines ?= {} @@ -549,21 +557,19 @@ class TextEditorPresenter isVisible = isVisible and @showLineNumbers isVisible - updateLineNumbersState: -> - return unless @startRow? and @endRow? and @lineHeight? - + updateLineNumbersState: (tileState, startRow, endRow) -> visibleLineNumberIds = {} - if @startRow > 0 - rowBeforeStartRow = @startRow - 1 + if startRow > 0 + rowBeforeStartRow = startRow - 1 lastBufferRow = @model.bufferRowForScreenRow(rowBeforeStartRow) wrapCount = rowBeforeStartRow - @model.screenRowForBufferRow(lastBufferRow) else lastBufferRow = null wrapCount = 0 - if @endRow > @startRow - for bufferRow, i in @model.bufferRowsForScreenRows(@startRow, @endRow - 1) + if endRow > startRow + for bufferRow, i in @model.bufferRowsForScreenRows(startRow, endRow - 1) if bufferRow is lastBufferRow wrapCount++ id = bufferRow + '-' + wrapCount @@ -574,23 +580,16 @@ class TextEditorPresenter lastBufferRow = bufferRow softWrapped = false - screenRow = @startRow + i - top = screenRow * @lineHeight + screenRow = startRow + i + top = (screenRow - startRow) * @lineHeight decorationClasses = @lineNumberDecorationClassesForRow(screenRow) foldable = @model.isFoldableAtScreenRow(screenRow) - @lineNumberGutter.lineNumbers[id] = {screenRow, bufferRow, softWrapped, top, decorationClasses, foldable} + tileState.lineNumbers[id] = {screenRow, bufferRow, softWrapped, top, decorationClasses, foldable} visibleLineNumberIds[id] = true - if @mouseWheelScreenRow? - bufferRow = @model.bufferRowForScreenRow(@mouseWheelScreenRow) - wrapCount = @mouseWheelScreenRow - @model.screenRowForBufferRow(bufferRow) - id = bufferRow - id += '-' + wrapCount if wrapCount > 0 - visibleLineNumberIds[id] = true - - for id of @lineNumberGutter.lineNumbers - delete @lineNumberGutter.lineNumbers[id] unless visibleLineNumberIds[id] + for id of tileState.lineNumbers + delete tileState.lineNumbers[id] unless visibleLineNumberIds[id] return From 7769c464da25f3fc94a5c798a10082ac3e889b42 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 4 Jun 2015 10:50:46 +0200 Subject: [PATCH 1515/1783] Extract `TiledComponent` --- src/lines-component.coffee | 67 +++++++------------------------------- src/tiled-component.coffee | 58 +++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 56 deletions(-) create mode 100644 src/tiled-component.coffee diff --git a/src/lines-component.coffee b/src/lines-component.coffee index 23f1c0015..233a4575b 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -3,21 +3,15 @@ CursorsComponent = require './cursors-component' HighlightsComponent = require './highlights-component' TileComponent = require './tile-component' +TiledComponent = require './tiled-component' DummyLineNode = $$(-> @div className: 'line', style: 'position: absolute; visibility: hidden;', => @span 'x')[0] -cloneObject = (object) -> - clone = {} - clone[key] = value for key, value of object - clone - module.exports = -class LinesComponent +class LinesComponent extends TiledComponent placeholderTextDiv: null constructor: ({@presenter, @hostElement, @useShadowDOM, visible}) -> - @tileComponentsByTileId = {} - @domNode = document.createElement('div') @domNode.classList.add('lines') @@ -35,18 +29,10 @@ class LinesComponent getDomNode: -> @domNode - updateSync: (state) -> - @newState = state.content - @oldState ?= {tiles: {}} - - if @newState.scrollHeight isnt @oldState.scrollHeight - @domNode.style.height = @newState.scrollHeight + 'px' - @oldState.scrollHeight = @newState.scrollHeight - - if @newState.backgroundColor isnt @oldState.backgroundColor - @domNode.style.backgroundColor = @newState.backgroundColor - @oldState.backgroundColor = @newState.backgroundColor + shouldRecreateAllTilesOnUpdate: -> + @oldState.indentGuidesVisible isnt @newState.indentGuidesVisible + afterUpdateSync: (state) -> if @newState.placeholderText isnt @oldState.placeholderText @placeholderTextDiv?.remove() if @newState.placeholderText? @@ -55,47 +41,16 @@ class LinesComponent @placeholderTextDiv.textContent = @newState.placeholderText @domNode.appendChild(@placeholderTextDiv) - @removeTileNodes() unless @oldState.indentGuidesVisible is @newState.indentGuidesVisible - @updateTileNodes() - - if @newState.scrollWidth isnt @oldState.scrollWidth - @domNode.style.width = @newState.scrollWidth + 'px' - @oldState.scrollWidth = @newState.scrollWidth - @cursorsComponent.updateSync(state) @highlightsComponent.updateSync(state) @oldState.indentGuidesVisible = @newState.indentGuidesVisible @oldState.scrollWidth = @newState.scrollWidth - removeTileNodes: -> - @removeTileNode(id) for id of @oldState.tiles - return + buildComponentForTile: (id) -> new TileComponent({id, @presenter}) - removeTileNode: (id) -> - node = @tileComponentsByTileId[id].getDomNode() - - node.remove() - delete @tileComponentsByTileId[id] - delete @oldState.tiles[id] - - updateTileNodes: -> - for id of @oldState.tiles - unless @newState.tiles.hasOwnProperty(id) - @removeTileNode(id) - - for id, tileState of @newState.tiles - if @oldState.tiles.hasOwnProperty(id) - tileComponent = @tileComponentsByTileId[id] - else - tileComponent = @tileComponentsByTileId[id] = new TileComponent({id, @presenter}) - - @domNode.appendChild(tileComponent.getDomNode()) - @oldState.tiles[id] = cloneObject(tileState) - - tileComponent.updateSync(@newState) - - return + buildEmptyState: -> + {tiles: {}} measureLineHeightAndDefaultCharWidth: -> @domNode.appendChild(DummyLineNode) @@ -114,13 +69,13 @@ class LinesComponent measureCharactersInNewLines: -> @presenter.batchCharacterMeasurement => - for id, component of @tileComponentsByTileId + for id, component of @componentsByTileId component.measureCharactersInNewLines() return clearScopedCharWidths: -> - for id, component of @tileComponentsByTileId + for id, component of @componentsByTileId component.clearMeasurements() @presenter.clearScopedCharacterWidths() @@ -128,4 +83,4 @@ class LinesComponent lineNodeForScreenRow: (screenRow) -> tile = @presenter.tileForRow(screenRow) - @tileComponentsByTileId[tile]?.lineNodeForScreenRow(screenRow) + @componentsByTileId[tile]?.lineNodeForScreenRow(screenRow) diff --git a/src/tiled-component.coffee b/src/tiled-component.coffee new file mode 100644 index 000000000..ad7322013 --- /dev/null +++ b/src/tiled-component.coffee @@ -0,0 +1,58 @@ +cloneObject = (object) -> + clone = {} + clone[key] = value for key, value of object + clone + +module.exports = +class TiledComponent + componentsByTileId: {} + + updateSync: (state) -> + @newState = state.content + @oldState ?= @buildEmptyState() + + if @newState.scrollHeight isnt @oldState.scrollHeight + @domNode.style.height = @newState.scrollHeight + 'px' + @oldState.scrollHeight = @newState.scrollHeight + + if @newState.backgroundColor isnt @oldState.backgroundColor + @domNode.style.backgroundColor = @newState.backgroundColor + @oldState.backgroundColor = @newState.backgroundColor + + if @newState.scrollWidth isnt @oldState.scrollWidth + @domNode.style.width = @newState.scrollWidth + 'px' + @oldState.scrollWidth = @newState.scrollWidth + + @removeTileNodes() if @shouldRecreateAllTilesOnUpdate() + @updateTileNodes() + + @afterUpdateSync(state) + + removeTileNodes: -> + @removeTileNode(id) for id of @oldState.tiles + return + + removeTileNode: (id) -> + node = @componentsByTileId[id].getDomNode() + + node.remove() + delete @componentsByTileId[id] + delete @oldState.tiles[id] + + updateTileNodes: -> + for id of @oldState.tiles + unless @newState.tiles.hasOwnProperty(id) + @removeTileNode(id) + + for id, tileState of @newState.tiles + if @oldState.tiles.hasOwnProperty(id) + component = @componentsByTileId[id] + else + component = @componentsByTileId[id] = @buildComponentForTile(id) + + @domNode.appendChild(component.getDomNode()) + @oldState.tiles[id] = cloneObject(tileState) + + component.updateSync(@newState) + + return From 44991f1fb3d8e3aa5c7b935a619c4837cd9c88c6 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 4 Jun 2015 14:31:15 +0200 Subject: [PATCH 1516/1783] Make `LineNumberGutterComponent` a `TiledComponent` --- src/gutter-component-helpers.coffee | 4 - src/line-number-gutter-component.coffee | 115 +++++----------------- src/line-numbers-tile-component.coffee | 125 ++++++++++++++++++++++++ src/lines-component.coffee | 18 ++++ src/text-editor-presenter.coffee | 5 +- src/tiled-component.coffee | 24 ++--- 6 files changed, 175 insertions(+), 116 deletions(-) create mode 100644 src/line-numbers-tile-component.coffee diff --git a/src/gutter-component-helpers.coffee b/src/gutter-component-helpers.coffee index f3a94c5b4..499b90552 100644 --- a/src/gutter-component-helpers.coffee +++ b/src/gutter-component-helpers.coffee @@ -19,10 +19,6 @@ module.exports = domNode.style.height = newState.scrollHeight + 'px' oldState.scrollHeight = newState.scrollHeight - if newState.scrollTop isnt oldState.scrollTop - domNode.style['-webkit-transform'] = "translate3d(0px, #{-newState.scrollTop}px, 0px)" - oldState.scrollTop = newState.scrollTop - if newState.backgroundColor isnt oldState.backgroundColor domNode.style.backgroundColor = newState.backgroundColor oldState.backgroundColor = newState.backgroundColor diff --git a/src/line-number-gutter-component.coffee b/src/line-number-gutter-component.coffee index 351275f63..7b68c2acd 100644 --- a/src/line-number-gutter-component.coffee +++ b/src/line-number-gutter-component.coffee @@ -1,10 +1,12 @@ -_ = require 'underscore-plus' {setDimensionsAndBackground} = require './gutter-component-helpers' +TiledComponent = require './tiled-component' +LineNumbersTileComponent = require './line-numbers-tile-component' WrapperDiv = document.createElement('div') +DummyLineNumberComponent = new LineNumbersTileComponent(id: -1) module.exports = -class LineNumberGutterComponent +class LineNumberGutterComponent extends TiledComponent dummyLineNumberNode: null constructor: ({@onMouseDown, @editor, @gutter}) -> @@ -31,28 +33,29 @@ class LineNumberGutterComponent @domNode.style.removeProperty('display') @visible = true - # `state` is a subset of the TextEditorPresenter state that is specific - # to this line number gutter. - updateSync: (state) -> - @newState = state - @oldState ?= - lineNumbers: {} + buildEmptyState: -> + { + tiles: {} styles: {} + } + getNewState: (state) -> state + + getTilesNode: -> @lineNumbersNode + + beforeUpdateSync: (state) -> @appendDummyLineNumber() unless @dummyLineNumberNode? setDimensionsAndBackground(@oldState.styles, @newState.styles, @lineNumbersNode) if @newState.maxLineNumberDigits isnt @oldState.maxLineNumberDigits @updateDummyLineNumber() - node.remove() for id, node of @lineNumberNodesById - @oldState = - maxLineNumberDigits: @newState.maxLineNumberDigits - lineNumbers: {} - styles: {} - @lineNumberNodesById = {} + @oldState.styles = {} - @updateLineNumbers() + afterUpdateSync: (state) -> + @oldState.maxLineNumberDigits = @newState.maxLineNumberDigits + + buildComponentForTile: (id) -> new LineNumbersTileComponent({id}) ### Section: Private Methods @@ -61,88 +64,14 @@ class LineNumberGutterComponent # This dummy line number element holds the gutter to the appropriate width, # since the real line numbers are absolutely positioned for performance reasons. appendDummyLineNumber: -> - WrapperDiv.innerHTML = @buildLineNumberHTML({bufferRow: -1}) + DummyLineNumberComponent.newState = @newState + WrapperDiv.innerHTML = DummyLineNumberComponent.buildLineNumberHTML({bufferRow: -1}) @dummyLineNumberNode = WrapperDiv.children[0] @lineNumbersNode.appendChild(@dummyLineNumberNode) updateDummyLineNumber: -> - @dummyLineNumberNode.innerHTML = @buildLineNumberInnerHTML(0, false) - - updateLineNumbers: -> - newLineNumberIds = null - newLineNumbersHTML = null - - for id, lineNumberState of @newState.lineNumbers - if @oldState.lineNumbers.hasOwnProperty(id) - @updateLineNumberNode(id, lineNumberState) - else - newLineNumberIds ?= [] - newLineNumbersHTML ?= "" - newLineNumberIds.push(id) - newLineNumbersHTML += @buildLineNumberHTML(lineNumberState) - @oldState.lineNumbers[id] = _.clone(lineNumberState) - - if newLineNumberIds? - WrapperDiv.innerHTML = newLineNumbersHTML - newLineNumberNodes = _.toArray(WrapperDiv.children) - - node = @lineNumbersNode - for id, i in newLineNumberIds - lineNumberNode = newLineNumberNodes[i] - @lineNumberNodesById[id] = lineNumberNode - node.appendChild(lineNumberNode) - - for id, lineNumberState of @oldState.lineNumbers - unless @newState.lineNumbers.hasOwnProperty(id) - @lineNumberNodesById[id].remove() - delete @lineNumberNodesById[id] - delete @oldState.lineNumbers[id] - - return - - buildLineNumberHTML: (lineNumberState) -> - {screenRow, bufferRow, softWrapped, top, decorationClasses} = lineNumberState - if screenRow? - style = "position: absolute; top: #{top}px;" - else - style = "visibility: hidden;" - className = @buildLineNumberClassName(lineNumberState) - innerHTML = @buildLineNumberInnerHTML(bufferRow, softWrapped) - - "
#{innerHTML}
" - - buildLineNumberInnerHTML: (bufferRow, softWrapped) -> - {maxLineNumberDigits} = @newState - - if softWrapped - lineNumber = "•" - else - lineNumber = (bufferRow + 1).toString() - - padding = _.multiplyString(' ', maxLineNumberDigits - lineNumber.length) - iconHTML = '
' - padding + lineNumber + iconHTML - - updateLineNumberNode: (lineNumberId, newLineNumberState) -> - oldLineNumberState = @oldState.lineNumbers[lineNumberId] - node = @lineNumberNodesById[lineNumberId] - - unless oldLineNumberState.foldable is newLineNumberState.foldable and _.isEqual(oldLineNumberState.decorationClasses, newLineNumberState.decorationClasses) - node.className = @buildLineNumberClassName(newLineNumberState) - oldLineNumberState.foldable = newLineNumberState.foldable - oldLineNumberState.decorationClasses = _.clone(newLineNumberState.decorationClasses) - - unless oldLineNumberState.top is newLineNumberState.top - node.style.top = newLineNumberState.top + 'px' - node.dataset.screenRow = newLineNumberState.screenRow - oldLineNumberState.top = newLineNumberState.top - oldLineNumberState.screenRow = newLineNumberState.screenRow - - buildLineNumberClassName: ({bufferRow, foldable, decorationClasses, softWrapped}) -> - className = "line-number line-number-#{bufferRow}" - className += " " + decorationClasses.join(' ') if decorationClasses? - className += " foldable" if foldable and not softWrapped - className + DummyLineNumberComponent.newState = @newState + @dummyLineNumberNode.innerHTML = DummyLineNumberComponent.buildLineNumberInnerHTML(0, false) lineNumberNodeForScreenRow: (screenRow) -> for id, lineNumberState of @oldState.lineNumbers diff --git a/src/line-numbers-tile-component.coffee b/src/line-numbers-tile-component.coffee new file mode 100644 index 000000000..dd5d2e5af --- /dev/null +++ b/src/line-numbers-tile-component.coffee @@ -0,0 +1,125 @@ +_ = require 'underscore-plus' +WrapperDiv = document.createElement('div') + +module.exports = +class LineNumbersTileComponent + constructor: ({@id}) -> + @lineNumberNodesById = {} + @domNode = document.createElement("div") + @domNode.classList.add("tile") + @domNode.style.position = "absolute" + @domNode.style.display = "block" + @domNode.style.top = 0 + + getDomNode: -> + @domNode + + updateSync: (state) -> + @newState = state + unless @oldState + @oldState = {tiles: {}} + @oldState.tiles[@id] = {lineNumbers: {}} + + @newTileState = @newState.tiles[@id] + @oldTileState = @oldState.tiles[@id] + + if @newTileState.display isnt @oldTileState.display + @domNode.style.display = @newTileState.display + @oldTileState.display = @newTileState.display + + if @newTileState.height isnt @oldTileState.height + @domNode.style.height = @newTileState.height + 'px' + @oldTileState.height = @newTileState.height + + if @newTileState.top isnt @oldTileState.top + @domNode.style['-webkit-transform'] = "translate3d(#{@newTileState.left}px, #{@newTileState.top}px, 0px)" + @oldTileState.top = @newTileState.top + @oldTileState.left = @newTileState.left + + # if @newState.maxLineNumberDigits isnt @oldState.maxLineNumberDigits + # node.remove() for id, node of @lineNumberNodesById + # @oldState.tiles[@id] = {lineNumbers: {}} + # @oldTileState = @oldState.tiles[@id] + # @lineNumberNodesById = {} + + if @newState.scrollWidth isnt @oldState.scrollWidth + @domNode.style.width = @newState.scrollWidth + 'px' + @oldState.scrollWidth = @newState.scrollWidth + + @updateLineNumbers() + + updateLineNumbers: -> + newLineNumberIds = null + newLineNumbersHTML = null + + for id, lineNumberState of @oldTileState.lineNumbers + unless @newTileState.lineNumbers.hasOwnProperty(id) + @lineNumberNodesById[id].remove() + delete @lineNumberNodesById[id] + delete @oldState.lineNumbers[id] + + for id, lineNumberState of @newTileState.lineNumbers + if @oldTileState.lineNumbers.hasOwnProperty(id) + @updateLineNumberNode(id, lineNumberState) + else + newLineNumberIds ?= [] + newLineNumbersHTML ?= "" + newLineNumberIds.push(id) + newLineNumbersHTML += @buildLineNumberHTML(lineNumberState) + @oldTileState.lineNumbers[id] = _.clone(lineNumberState) + + if newLineNumberIds? + WrapperDiv.innerHTML = newLineNumbersHTML + newLineNumberNodes = _.toArray(WrapperDiv.children) + + node = @domNode + for id, i in newLineNumberIds + lineNumberNode = newLineNumberNodes[i] + @lineNumberNodesById[id] = lineNumberNode + node.appendChild(lineNumberNode) + + return + + buildLineNumberHTML: (lineNumberState) -> + {screenRow, bufferRow, softWrapped, top, decorationClasses} = lineNumberState + if screenRow? + style = "position: absolute; top: #{top}px;" + else + style = "visibility: hidden;" + className = @buildLineNumberClassName(lineNumberState) + innerHTML = @buildLineNumberInnerHTML(bufferRow, softWrapped) + + "
#{innerHTML}
" + + buildLineNumberInnerHTML: (bufferRow, softWrapped) -> + {maxLineNumberDigits} = @newState + + if softWrapped + lineNumber = "•" + else + lineNumber = (bufferRow + 1).toString() + + padding = _.multiplyString(' ', maxLineNumberDigits - lineNumber.length) + iconHTML = '
' + padding + lineNumber + iconHTML + + updateLineNumberNode: (lineNumberId, newLineNumberState) -> + oldLineNumberState = @oldTileState.lineNumbers[lineNumberId] + node = @lineNumberNodesById[lineNumberId] + + unless oldLineNumberState.foldable is newLineNumberState.foldable and _.isEqual(oldLineNumberState.decorationClasses, newLineNumberState.decorationClasses) + node.className = @buildLineNumberClassName(newLineNumberState) + oldLineNumberState.foldable = newLineNumberState.foldable + oldLineNumberState.decorationClasses = _.clone(newLineNumberState.decorationClasses) + + unless oldLineNumberState.top is newLineNumberState.top + node.style.top = newLineNumberState.top + 'px' + node.dataset.screenRow = newLineNumberState.screenRow + oldLineNumberState.top = newLineNumberState.top + oldLineNumberState.screenRow = newLineNumberState.screenRow + + buildLineNumberClassName: ({bufferRow, foldable, decorationClasses, softWrapped}) -> + className = "line-number line-number-#{bufferRow}" + className += " " + decorationClasses.join(' ') if decorationClasses? + className += " foldable" if foldable and not softWrapped + className diff --git a/src/lines-component.coffee b/src/lines-component.coffee index 233a4575b..92823daf1 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -32,6 +32,19 @@ class LinesComponent extends TiledComponent shouldRecreateAllTilesOnUpdate: -> @oldState.indentGuidesVisible isnt @newState.indentGuidesVisible + beforeUpdateSync: (state) -> + if @newState.scrollHeight isnt @oldState.scrollHeight + @domNode.style.height = @newState.scrollHeight + 'px' + @oldState.scrollHeight = @newState.scrollHeight + + if @newState.backgroundColor isnt @oldState.backgroundColor + @domNode.style.backgroundColor = @newState.backgroundColor + @oldState.backgroundColor = @newState.backgroundColor + + if @newState.scrollWidth isnt @oldState.scrollWidth + @domNode.style.width = @newState.scrollWidth + 'px' + @oldState.scrollWidth = @newState.scrollWidth + afterUpdateSync: (state) -> if @newState.placeholderText isnt @oldState.placeholderText @placeholderTextDiv?.remove() @@ -52,6 +65,11 @@ class LinesComponent extends TiledComponent buildEmptyState: -> {tiles: {}} + getNewState: (state) -> + state.content + + getTilesNode: -> @domNode + measureLineHeightAndDefaultCharWidth: -> @domNode.appendChild(DummyLineNode) lineHeightInPixels = DummyLineNode.getBoundingClientRect().height diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index ad0e91336..df58ea76c 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -214,12 +214,13 @@ class TextEditorPresenter @sharedGutterStyles = {} @customGutterDecorations = {} @lineNumberGutter = - lineNumbers: {} + tiles: {} @updateState() updateState: -> @shouldUpdateLinesState = true + @shouldUpdateLineNumbersState = true @updateContentDimensions() @updateScrollbarDimensions() @@ -238,7 +239,6 @@ class TextEditorPresenter @updateCursorsState() @updateOverlaysState() @updateLineNumberGutterState() - @updateLineNumbersState() @updateCommonGutterState() @updateGutterOrderState() @updateCustomGutterDecorationState() @@ -558,6 +558,7 @@ class TextEditorPresenter isVisible updateLineNumbersState: (tileState, startRow, endRow) -> + tileState.lineNumbers ?= {} visibleLineNumberIds = {} if startRow > 0 diff --git a/src/tiled-component.coffee b/src/tiled-component.coffee index ad7322013..51af7b57d 100644 --- a/src/tiled-component.coffee +++ b/src/tiled-component.coffee @@ -5,28 +5,16 @@ cloneObject = (object) -> module.exports = class TiledComponent - componentsByTileId: {} - updateSync: (state) -> - @newState = state.content + @newState = @getNewState(state) @oldState ?= @buildEmptyState() - if @newState.scrollHeight isnt @oldState.scrollHeight - @domNode.style.height = @newState.scrollHeight + 'px' - @oldState.scrollHeight = @newState.scrollHeight + @beforeUpdateSync?(state) - if @newState.backgroundColor isnt @oldState.backgroundColor - @domNode.style.backgroundColor = @newState.backgroundColor - @oldState.backgroundColor = @newState.backgroundColor - - if @newState.scrollWidth isnt @oldState.scrollWidth - @domNode.style.width = @newState.scrollWidth + 'px' - @oldState.scrollWidth = @newState.scrollWidth - - @removeTileNodes() if @shouldRecreateAllTilesOnUpdate() + @removeTileNodes() if @shouldRecreateAllTilesOnUpdate?() @updateTileNodes() - @afterUpdateSync(state) + @afterUpdateSync?(state) removeTileNodes: -> @removeTileNode(id) for id of @oldState.tiles @@ -40,6 +28,8 @@ class TiledComponent delete @oldState.tiles[id] updateTileNodes: -> + @componentsByTileId ?= {} + for id of @oldState.tiles unless @newState.tiles.hasOwnProperty(id) @removeTileNode(id) @@ -50,7 +40,7 @@ class TiledComponent else component = @componentsByTileId[id] = @buildComponentForTile(id) - @domNode.appendChild(component.getDomNode()) + @getTilesNode().appendChild(component.getDomNode()) @oldState.tiles[id] = cloneObject(tileState) component.updateSync(@newState) From 57fd553c695701c3fa3111863ade834ed2feb188 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 4 Jun 2015 15:09:15 +0200 Subject: [PATCH 1517/1783] Use `clientHeight` for line-numbers and lines containers --- src/gutter-component-helpers.coffee | 3 --- src/line-number-gutter-component.coffee | 4 ++++ src/lines-component.coffee | 6 +++--- src/text-editor-presenter.coffee | 2 ++ 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/gutter-component-helpers.coffee b/src/gutter-component-helpers.coffee index 499b90552..d938ed10d 100644 --- a/src/gutter-component-helpers.coffee +++ b/src/gutter-component-helpers.coffee @@ -15,9 +15,6 @@ module.exports = # Sets scrollHeight, scrollTop, and backgroundColor on the given domNode. setDimensionsAndBackground: (oldState, newState, domNode) -> - if newState.scrollHeight isnt oldState.scrollHeight - domNode.style.height = newState.scrollHeight + 'px' - oldState.scrollHeight = newState.scrollHeight if newState.backgroundColor isnt oldState.backgroundColor domNode.style.backgroundColor = newState.backgroundColor diff --git a/src/line-number-gutter-component.coffee b/src/line-number-gutter-component.coffee index 7b68c2acd..2d0d5049f 100644 --- a/src/line-number-gutter-component.coffee +++ b/src/line-number-gutter-component.coffee @@ -48,6 +48,10 @@ class LineNumberGutterComponent extends TiledComponent setDimensionsAndBackground(@oldState.styles, @newState.styles, @lineNumbersNode) + if @newState.height isnt @oldState.height + @lineNumbersNode.style.height = @newState.height + "px" + @oldState.height = @newState.height + if @newState.maxLineNumberDigits isnt @oldState.maxLineNumberDigits @updateDummyLineNumber() @oldState.styles = {} diff --git a/src/lines-component.coffee b/src/lines-component.coffee index 92823daf1..039425f7e 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -33,9 +33,9 @@ class LinesComponent extends TiledComponent @oldState.indentGuidesVisible isnt @newState.indentGuidesVisible beforeUpdateSync: (state) -> - if @newState.scrollHeight isnt @oldState.scrollHeight - @domNode.style.height = @newState.scrollHeight + 'px' - @oldState.scrollHeight = @newState.scrollHeight + if @newState.clientHeight isnt @oldState.clientHeight + @domNode.style.height = @newState.clientHeight + 'px' + @oldState.clientHeight = @newState.clientHeight if @newState.backgroundColor isnt @oldState.backgroundColor @domNode.style.backgroundColor = @newState.backgroundColor diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index df58ea76c..6188eb144 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -453,6 +453,7 @@ class TextEditorPresenter return updateLineNumberGutterState: -> + @lineNumberGutter.height = @clientHeight @lineNumberGutter.maxLineNumberDigits = @model.getLineCount().toString().length updateCommonGutterState: -> @@ -656,6 +657,7 @@ class TextEditorPresenter clientHeight = @height - @horizontalScrollbarHeight unless @clientHeight is clientHeight @clientHeight = clientHeight + @state.content.clientHeight = @clientHeight @updateScrollHeight() @updateScrollTop() From 3e517e687a84fb7580eec4d7e4643ed8a9eba482 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 4 Jun 2015 15:10:48 +0200 Subject: [PATCH 1518/1783] :bug: Fix typo --- src/line-numbers-tile-component.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/line-numbers-tile-component.coffee b/src/line-numbers-tile-component.coffee index dd5d2e5af..edbb8ecf7 100644 --- a/src/line-numbers-tile-component.coffee +++ b/src/line-numbers-tile-component.coffee @@ -56,7 +56,7 @@ class LineNumbersTileComponent unless @newTileState.lineNumbers.hasOwnProperty(id) @lineNumberNodesById[id].remove() delete @lineNumberNodesById[id] - delete @oldState.lineNumbers[id] + delete @oldTileState.lineNumbers[id] for id, lineNumberState of @newTileState.lineNumbers if @oldTileState.lineNumbers.hasOwnProperty(id) From 8abdc67e7e5cb96ff49ec6cb0d6c7b89c4ac6029 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 4 Jun 2015 15:15:29 +0200 Subject: [PATCH 1519/1783] Revert "Use `clientHeight` for line-numbers and lines containers" This reverts commit f2bab35f57c05d5a0bb21e9fb02117f802ff278b. It didn't actually improve performance, nor memory usage, therefore I decided to avoid changing it for the time being. --- src/gutter-component-helpers.coffee | 3 +++ src/line-number-gutter-component.coffee | 4 ---- src/lines-component.coffee | 6 +++--- src/text-editor-presenter.coffee | 2 -- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/gutter-component-helpers.coffee b/src/gutter-component-helpers.coffee index d938ed10d..499b90552 100644 --- a/src/gutter-component-helpers.coffee +++ b/src/gutter-component-helpers.coffee @@ -15,6 +15,9 @@ module.exports = # Sets scrollHeight, scrollTop, and backgroundColor on the given domNode. setDimensionsAndBackground: (oldState, newState, domNode) -> + if newState.scrollHeight isnt oldState.scrollHeight + domNode.style.height = newState.scrollHeight + 'px' + oldState.scrollHeight = newState.scrollHeight if newState.backgroundColor isnt oldState.backgroundColor domNode.style.backgroundColor = newState.backgroundColor diff --git a/src/line-number-gutter-component.coffee b/src/line-number-gutter-component.coffee index 2d0d5049f..7b68c2acd 100644 --- a/src/line-number-gutter-component.coffee +++ b/src/line-number-gutter-component.coffee @@ -48,10 +48,6 @@ class LineNumberGutterComponent extends TiledComponent setDimensionsAndBackground(@oldState.styles, @newState.styles, @lineNumbersNode) - if @newState.height isnt @oldState.height - @lineNumbersNode.style.height = @newState.height + "px" - @oldState.height = @newState.height - if @newState.maxLineNumberDigits isnt @oldState.maxLineNumberDigits @updateDummyLineNumber() @oldState.styles = {} diff --git a/src/lines-component.coffee b/src/lines-component.coffee index 039425f7e..92823daf1 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -33,9 +33,9 @@ class LinesComponent extends TiledComponent @oldState.indentGuidesVisible isnt @newState.indentGuidesVisible beforeUpdateSync: (state) -> - if @newState.clientHeight isnt @oldState.clientHeight - @domNode.style.height = @newState.clientHeight + 'px' - @oldState.clientHeight = @newState.clientHeight + if @newState.scrollHeight isnt @oldState.scrollHeight + @domNode.style.height = @newState.scrollHeight + 'px' + @oldState.scrollHeight = @newState.scrollHeight if @newState.backgroundColor isnt @oldState.backgroundColor @domNode.style.backgroundColor = @newState.backgroundColor diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 6188eb144..df58ea76c 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -453,7 +453,6 @@ class TextEditorPresenter return updateLineNumberGutterState: -> - @lineNumberGutter.height = @clientHeight @lineNumberGutter.maxLineNumberDigits = @model.getLineCount().toString().length updateCommonGutterState: -> @@ -657,7 +656,6 @@ class TextEditorPresenter clientHeight = @height - @horizontalScrollbarHeight unless @clientHeight is clientHeight @clientHeight = clientHeight - @state.content.clientHeight = @clientHeight @updateScrollHeight() @updateScrollTop() From b80c480d863e8ac9a8f98659445741f4b1684fe1 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 4 Jun 2015 10:27:36 -0700 Subject: [PATCH 1520/1783] Store overlay decorations to optimize ::getOverlayDecorations() --- src/decoration.coffee | 2 ++ src/display-buffer.coffee | 20 +++++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/decoration.coffee b/src/decoration.coffee index bc3a21748..d8f0b5edf 100644 --- a/src/decoration.coffee +++ b/src/decoration.coffee @@ -153,6 +153,8 @@ class Decoration oldProperties = @properties @properties = translateDecorationParamsOldToNew(newProperties) @properties.id = @id + if newProperties.type? + @displayBuffer.decorationDidChangeType(this) @emit 'updated', {oldParams: oldProperties, newParams: newProperties} if Grim.includeDeprecatedAPIs @emitter.emit 'did-change-properties', {oldProperties, newProperties} diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index aa6abb7b7..d98f93fe3 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -37,6 +37,7 @@ class DisplayBuffer extends Model @foldsByMarkerId = {} @decorationsById = {} @decorationsByMarkerId = {} + @overlayDecorationsById = {} @disposables.add @tokenizedBuffer.observeGrammar @subscribeToScopedConfigSettings @disposables.add @tokenizedBuffer.onDidChange @handleTokenizedBufferChange @disposables.add @buffer.onDidCreateMarker @handleBufferMarkerCreated @@ -919,7 +920,16 @@ class DisplayBuffer extends Model @getDecorations(propertyFilter).filter (decoration) -> decoration.isType('highlight') getOverlayDecorations: (propertyFilter) -> - @getDecorations(propertyFilter).filter (decoration) -> decoration.isType('overlay') + result = [] + for id, decoration of @overlayDecorationsById + result.push(decoration) + if propertyFilter? + result.filter (decoration) -> + for key, value of propertyFilter + return false unless decoration.properties[key] is value + true + else + result decorationsForScreenRowRange: (startScreenRow, endScreenRow) -> decorationsByMarkerId = {} @@ -934,6 +944,7 @@ class DisplayBuffer extends Model @disposables.add decoration.onDidDestroy => @removeDecoration(decoration) @decorationsByMarkerId[marker.id] ?= [] @decorationsByMarkerId[marker.id].push(decoration) + @overlayDecorationsById[decoration.id] = decoration if decoration.isType('overlay') @decorationsById[decoration.id] = decoration @emit 'decoration-added', decoration if Grim.includeDeprecatedAPIs @emitter.emit 'did-add-decoration', decoration @@ -950,6 +961,7 @@ class DisplayBuffer extends Model @emit 'decoration-removed', decoration if Grim.includeDeprecatedAPIs @emitter.emit 'did-remove-decoration', decoration delete @decorationsByMarkerId[marker.id] if decorations.length is 0 + delete @overlayDecorationsById[decoration.id] decorationsForMarkerId: (markerId) -> @decorationsByMarkerId[markerId] @@ -1246,6 +1258,12 @@ class DisplayBuffer extends Model foldForMarker: (marker) -> @foldsByMarkerId[marker.id] + decorationDidChangeType: (decoration) -> + if decoration.isType('overlay') + @overlayDecorationsById[decoration.id] = decoration + else + delete @overlayDecorationsById[decoration.id] + if Grim.includeDeprecatedAPIs DisplayBuffer.properties softWrapped: null From ee3cd3994d005099428b2c7943dba3e45ce5a6c8 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 4 Jun 2015 10:38:44 -0700 Subject: [PATCH 1521/1783] :arrow_up: text-buffer --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 74a07659d..83ff9b06c 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "space-pen": "3.8.2", "stacktrace-parser": "0.1.1", "temp": "0.8.1", - "text-buffer": "6.1.3", + "text-buffer": "6.2.0", "theorist": "^1.0.2", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", From bb680fc942f8ab71f2bba5093aa83b3d49624829 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 4 Jun 2015 10:46:52 -0700 Subject: [PATCH 1522/1783] :arrow_up: apm@0.170 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index 108e3c206..1dde8b9a6 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.169.0" + "atom-package-manager": "0.170.0" } } From 91e3a76d17fa87b6245e79d4eedb47bfa19ad173 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 4 Jun 2015 10:53:12 -0700 Subject: [PATCH 1523/1783] Update spec for new deprecation data --- spec/package-manager-spec.coffee | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 6f424465c..f09f43824 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -70,10 +70,10 @@ describe "PackageManager", -> it "returns null", -> grim.includeDeprecatedAPIs = false expect(atom.packages.loadPackage(path.join(__dirname, 'fixtures', 'packages', 'wordcount'))).toBeNull() - expect(atom.packages.isDeprecatedPackage('wordcount', '2.0.9')).toBe true - expect(atom.packages.isDeprecatedPackage('wordcount', '2.1.0')).toBe true - expect(atom.packages.isDeprecatedPackage('wordcount', '2.1.1')).toBe false - expect(atom.packages.getDeprecatedPackageMetadata('wordcount').version).toBe '<=2.1.0' + expect(atom.packages.isDeprecatedPackage('wordcount', '2.1.9')).toBe true + expect(atom.packages.isDeprecatedPackage('wordcount', '2.2.0')).toBe true + expect(atom.packages.isDeprecatedPackage('wordcount', '2.2.1')).toBe false + expect(atom.packages.getDeprecatedPackageMetadata('wordcount').version).toBe '<=2.2.0' it "invokes ::onDidLoadPackage listeners with the loaded package", -> loadedPackage = null From 63fbf7382e7e4bdd32904b1cd6cd4813bfe61d64 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 4 Jun 2015 10:57:31 -0700 Subject: [PATCH 1524/1783] :arrow_up: find-and-replace --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a39bf2c7f..79ae74c6a 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", - "find-and-replace": "0.170.0", + "find-and-replace": "0.171.0", "fuzzy-finder": "0.87.0", "git-diff": "0.55.0", "go-to-line": "0.30.0", From 65831f1a4dff9dbcf68dbaf9b1d78b2617ed229a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 4 Jun 2015 11:22:11 -0700 Subject: [PATCH 1525/1783] :arrow_up: language-html@0.39 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 79ae74c6a..dd5ffbbec 100644 --- a/package.json +++ b/package.json @@ -135,7 +135,7 @@ "language-gfm": "0.77.0", "language-git": "0.10.0", "language-go": "0.26.0", - "language-html": "0.38.0", + "language-html": "0.39.0", "language-hyperlink": "0.13.0", "language-java": "0.15.0", "language-javascript": "0.78.0", From 2f26de3e26cbf02cf7f9fcb63373b8eb33e62c44 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Thu, 4 Jun 2015 13:51:50 -0700 Subject: [PATCH 1526/1783] Remove treeview from the deprecated packages --- build/deprecated-packages.json | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/build/deprecated-packages.json b/build/deprecated-packages.json index 8d41a53ea..ac980e165 100644 --- a/build/deprecated-packages.json +++ b/build/deprecated-packages.json @@ -1545,11 +1545,6 @@ "hasDeprecations": true, "latestHasDeprecations": false }, - "tree-view": { - "version": "<=0.172.0", - "hasDeprecations": true, - "latestHasDeprecations": true - }, "true-color": { "version": "<=0.4.1", "hasDeprecations": true, @@ -1689,4 +1684,4 @@ "hasDeprecations": true, "latestHasDeprecations": false } -} \ No newline at end of file +} From 5793919f3b981e664b7a9a89234a9587863ed94b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 4 Jun 2015 14:07:53 -0700 Subject: [PATCH 1527/1783] :arrow_up: apm@0.171 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index 1dde8b9a6..bb9fd4647 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.170.0" + "atom-package-manager": "0.171.0" } } From f585b5bb126056b16e9534864df45e90b7f7d50a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 4 Jun 2015 15:05:05 -0700 Subject: [PATCH 1528/1783] Prepare 0.207 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dd5ffbbec..6e20ca50f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "0.206.0", + "version": "0.207.0", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From 5b494b7b174be6774b786fcc8ea81eb41ab83118 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 5 Jun 2015 01:19:12 +0200 Subject: [PATCH 1529/1783] Lazily construct placeholder lines in TokenizedBuffer --- src/tokenized-buffer.coffee | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 55d2e7e37..72a972967 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -112,14 +112,14 @@ class TokenizedBuffer extends Model throw new Error("No grammar found for path: #{path}") hasTokenForSelector: (selector) -> - for {tokens} in @tokenizedLines - for token in tokens + for tokenizedLine in @tokenizedLines when tokenizedLine? + for token in tokenizedLine.tokens return true if selector.matches(token.scopes) false retokenizeLines: -> lastRow = @buffer.getLastRow() - @tokenizedLines = @buildPlaceholderTokenizedLinesForRows(0, lastRow) + @tokenizedLines = new Array(lastRow + 1) @invalidRows = [] @invalidateRow(0) @fullyTokenized = false @@ -248,12 +248,12 @@ class TokenizedBuffer extends Model @emitter.emit 'did-change', event retokenizeWhitespaceRowsIfIndentLevelChanged: (row, increment) -> - line = @tokenizedLines[row] + line = @tokenizedLineForRow(row) if line?.isOnlyWhitespace() and @indentLevelForRow(row) isnt line.indentLevel while line?.isOnlyWhitespace() @tokenizedLines[row] = @buildTokenizedLineForRow(row, @stackForRow(row - 1), @openScopesForRow(row)) row += increment - line = @tokenizedLines[row] + line = @tokenizedLineForRow(row) row - increment @@ -313,7 +313,7 @@ class TokenizedBuffer extends Model tokenizedLines buildPlaceholderTokenizedLinesForRows: (startRow, endRow) -> - @buildPlaceholderTokenizedLineForRow(row) for row in [startRow..endRow] + @buildPlaceholderTokenizedLineForRow(row) for row in [startRow..endRow] by 1 buildPlaceholderTokenizedLineForRow: (row) -> openScopes = [@grammar.startIdForScope(@grammar.scopeName)] @@ -341,7 +341,8 @@ class TokenizedBuffer extends Model null tokenizedLineForRow: (bufferRow) -> - @tokenizedLines[bufferRow] + if 0 <= bufferRow < @tokenizedLines.length + @tokenizedLines[bufferRow] ?= @buildPlaceholderTokenizedLineForRow(bufferRow) stackForRow: (bufferRow) -> @tokenizedLines[bufferRow]?.ruleStack @@ -418,17 +419,17 @@ class TokenizedBuffer extends Model tokenForPosition: (position) -> {row, column} = Point.fromObject(position) - @tokenizedLines[row].tokenAtBufferColumn(column) + @tokenizedLineForRow(row).tokenAtBufferColumn(column) tokenStartPositionForPosition: (position) -> {row, column} = Point.fromObject(position) - column = @tokenizedLines[row].tokenStartColumnForBufferColumn(column) + column = @tokenizedLineForRow(row).tokenStartColumnForBufferColumn(column) new Point(row, column) bufferRangeForScopeAtPosition: (selector, position) -> position = Point.fromObject(position) - {openScopes, tags} = @tokenizedLines[position.row] + {openScopes, tags} = @tokenizedLineForRow(position.row) scopes = openScopes.map (tag) -> atom.grammars.scopeForId(tag) startColumn = 0 From de508db9b2c9cb609f565b38adeeaee0823c7e48 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 5 Jun 2015 02:25:57 +0200 Subject: [PATCH 1530/1783] Implement basic large file mode for editor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Don’t tokenize * Don’t build metadata to support folds and soft wraps Remaining issues: * Max line length is hard coded * Foldable indicators should be disabled * Folding via API should be disallowed --- src/display-buffer.coffee | 68 +++++++++++++++++++++++++++---------- src/project.coffee | 8 ++--- src/text-editor.coffee | 4 +-- src/tokenized-buffer.coffee | 13 +++++-- 4 files changed, 65 insertions(+), 28 deletions(-) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index d98f93fe3..32f374776 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -24,13 +24,13 @@ class DisplayBuffer extends Model horizontalScrollMargin: 6 scopedCharacterWidthsChangeCount: 0 - constructor: ({tabLength, @editorWidthInChars, @tokenizedBuffer, buffer, ignoreInvisibles}={}) -> + constructor: ({tabLength, @editorWidthInChars, @tokenizedBuffer, buffer, ignoreInvisibles, @largeFileMode}={}) -> super @emitter = new Emitter @disposables = new CompositeDisposable - @tokenizedBuffer ?= new TokenizedBuffer({tabLength, buffer, ignoreInvisibles}) + @tokenizedBuffer ?= new TokenizedBuffer({tabLength, buffer, ignoreInvisibles, @largeFileMode}) @buffer = @tokenizedBuffer.buffer @charWidthsByScope = {} @markers = {} @@ -478,7 +478,10 @@ class DisplayBuffer extends Model # # Returns {TokenizedLine} tokenizedLineForScreenRow: (screenRow) -> - @screenLines[screenRow] + if @largeFileMode + @tokenizedBuffer.tokenizedLineForRow(screenRow) + else + @screenLines[screenRow] # Gets the screen lines for the given screen row range. # @@ -487,13 +490,19 @@ class DisplayBuffer extends Model # # Returns an {Array} of {TokenizedLine}s. tokenizedLinesForScreenRows: (startRow, endRow) -> - @screenLines[startRow..endRow] + if @largeFileMode + @tokenizedBuffer.tokenizedLinesForRows(startRow, endRow) + else + @screenLines[startRow..endRow] # Gets all the screen lines. # # Returns an {Array} of {TokenizedLine}s. getTokenizedLines: -> - new Array(@screenLines...) + if @largeFileMode + @tokenizedBuffer.tokenizedLinesForRows(0, @getLastRow()) + else + new Array(@screenLines...) indentLevelForLine: (line) -> @tokenizedBuffer.indentLevelForLine(line) @@ -506,8 +515,11 @@ class DisplayBuffer extends Model # # Returns an {Array} of buffer rows as {Numbers}s. bufferRowsForScreenRows: (startScreenRow, endScreenRow) -> - for screenRow in [startScreenRow..endScreenRow] - @rowMap.bufferRowRangeForScreenRow(screenRow)[0] + if @largeFileMode + [startScreenRow..endScreenRow] + else + for screenRow in [startScreenRow..endScreenRow] + @rowMap.bufferRowRangeForScreenRow(screenRow)[0] # Creates a new fold between two row numbers. # @@ -611,10 +623,16 @@ class DisplayBuffer extends Model # # Returns a {Number}. screenRowForBufferRow: (bufferRow) -> - @rowMap.screenRowRangeForBufferRow(bufferRow)[0] + if @largeFileMode + bufferRow + else + @rowMap.screenRowRangeForBufferRow(bufferRow)[0] lastScreenRowForBufferRow: (bufferRow) -> - @rowMap.screenRowRangeForBufferRow(bufferRow)[1] - 1 + if @largeFileMode + bufferRow + else + @rowMap.screenRowRangeForBufferRow(bufferRow)[1] - 1 # Given a screen row, this converts it into a buffer row. # @@ -622,7 +640,10 @@ class DisplayBuffer extends Model # # Returns a {Number}. bufferRowForScreenRow: (screenRow) -> - @rowMap.bufferRowRangeForScreenRow(screenRow)[0] + if @largeFileMode + screenRow + else + @rowMap.bufferRowRangeForScreenRow(screenRow)[0] # Given a buffer range, this converts it into a screen position. # @@ -724,7 +745,10 @@ class DisplayBuffer extends Model # # Returns a {Number}. getLineCount: -> - @screenLines.length + if @largeFileMode + @tokenizedBuffer.getLineCount() + else + @screenLines.length # Gets the number of the last screen line. # @@ -736,13 +760,19 @@ class DisplayBuffer extends Model # # Returns a {Number}. getMaxLineLength: -> - @maxLineLength + if @largeFileMode + 100 + else + @maxLineLength # Gets the row number of the longest screen line. # # Return a {} getLongestScreenRow: -> - @longestScreenRow + if @largeFileMode + 0 + else + @longestScreenRow # Given a buffer position, this converts it into a screen position. # @@ -759,7 +789,7 @@ class DisplayBuffer extends Model {row, column} = @buffer.clipPosition(bufferPosition) [startScreenRow, endScreenRow] = @rowMap.screenRowRangeForBufferRow(row) for screenRow in [startScreenRow...endScreenRow] - screenLine = @screenLines[screenRow] + screenLine = @tokenizedLineForScreenRow(screenRow) unless screenLine? throw new BufferToScreenConversionError "No screen line exists when converting buffer row to screen row", @@ -792,7 +822,7 @@ class DisplayBuffer extends Model bufferPositionForScreenPosition: (screenPosition, options) -> {row, column} = @clipScreenPosition(Point.fromObject(screenPosition), options) [bufferRow] = @rowMap.bufferRowRangeForScreenRow(row) - new Point(bufferRow, @screenLines[row].bufferColumnForScreenColumn(column)) + new Point(bufferRow, @tokenizedLineForScreenRow(row).bufferColumnForScreenColumn(column)) # Retrieves the grammar's token scopeDescriptor for a buffer position. # @@ -856,13 +886,13 @@ class DisplayBuffer extends Model else if column < 0 column = 0 - screenLine = @screenLines[row] + screenLine = @tokenizedLineForScreenRow(row) maxScreenColumn = screenLine.getMaxScreenColumn() if screenLine.isSoftWrapped() and column >= maxScreenColumn if wrapAtSoftNewlines row++ - column = @screenLines[row].clipScreenColumn(0) + column = @tokenizedLineForScreenRow(row).clipScreenColumn(0) else column = screenLine.clipScreenColumn(maxScreenColumn - 1) else if screenLine.isColumnInsideSoftWrapIndentation(column) @@ -870,7 +900,7 @@ class DisplayBuffer extends Model column = screenLine.clipScreenColumn(0) else row-- - column = @screenLines[row].getMaxScreenColumn() - 1 + column = @tokenizedLineForScreenRow(row).getMaxScreenColumn() - 1 else if wrapBeyondNewlines and column > maxScreenColumn and row < @getLastRow() row++ column = 0 @@ -1137,6 +1167,8 @@ class DisplayBuffer extends Model @setScrollTop(Math.min(@getScrollTop(), @getMaxScrollTop())) if delta < 0 updateScreenLines: (startBufferRow, endBufferRow, bufferDelta=0, options={}) -> + return if @largeFileMode + startBufferRow = @rowMap.bufferRowRangeForBufferRow(startBufferRow)[0] endBufferRow = @rowMap.bufferRowRangeForBufferRow(endBufferRow - 1)[1] startScreenRow = @rowMap.screenRowRangeForBufferRow(startBufferRow)[0] diff --git a/src/project.coffee b/src/project.coffee index 75cdb714f..e2eed7ac5 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -376,11 +376,6 @@ class Project extends Model # # Returns a promise that resolves to the {TextBuffer}. buildBuffer: (absoluteFilePath) -> - if fs.getSizeSync(absoluteFilePath) >= 2 * 1048576 # 2MB - error = new Error("Atom can only handle files < 2MB for now.") - error.code = 'EFILETOOLARGE' - throw error - buffer = new TextBuffer({filePath: absoluteFilePath}) @addBuffer(buffer) buffer.load() @@ -410,7 +405,8 @@ class Project extends Model buffer?.destroy() buildEditorForBuffer: (buffer, editorOptions) -> - editor = new TextEditor(_.extend({buffer, registerEditor: true}, editorOptions)) + largeFileMode = fs.getSizeSync(buffer.getPath()) >= 2 * 1048576 # 2MB + editor = new TextEditor(_.extend({buffer, largeFileMode, registerEditor: true}, editorOptions)) editor eachBuffer: (args...) -> diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 4aacb3dfa..9a9262e50 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -75,7 +75,7 @@ class TextEditor extends Model 'autoDecreaseIndentForBufferRow', 'toggleLineCommentForBufferRow', 'toggleLineCommentsForBufferRows', toProperty: 'languageMode' - constructor: ({@softTabs, initialLine, initialColumn, tabLength, softWrapped, @displayBuffer, buffer, registerEditor, suppressCursorCreation, @mini, @placeholderText, lineNumberGutterVisible}={}) -> + constructor: ({@softTabs, initialLine, initialColumn, tabLength, softWrapped, @displayBuffer, buffer, registerEditor, suppressCursorCreation, @mini, @placeholderText, lineNumberGutterVisible, largeFileMode}={}) -> super @emitter = new Emitter @@ -84,7 +84,7 @@ class TextEditor extends Model @selections = [] buffer ?= new TextBuffer - @displayBuffer ?= new DisplayBuffer({buffer, tabLength, softWrapped, ignoreInvisibles: @mini}) + @displayBuffer ?= new DisplayBuffer({buffer, tabLength, softWrapped, ignoreInvisibles: @mini, largeFileMode}) @buffer = @displayBuffer.buffer @softTabs = @usesSoftTabs() ? @softTabs ? atom.config.get('editor.softTabs') ? true diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 72a972967..5aa3482a9 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -24,7 +24,7 @@ class TokenizedBuffer extends Model visible: false configSettings: null - constructor: ({@buffer, @tabLength, @ignoreInvisibles}) -> + constructor: ({@buffer, @tabLength, @ignoreInvisibles, @largeFileMode}) -> @emitter = new Emitter @disposables = new CompositeDisposable @tokenIterator = new TokenIterator @@ -209,6 +209,8 @@ class TokenizedBuffer extends Model return invalidateRow: (row) -> + return if @largeFileMode + @invalidRows.push(row) @invalidRows.sort (a, b) -> a - b @tokenizeInBackground() @@ -230,7 +232,10 @@ class TokenizedBuffer extends Model @updateInvalidRows(start, end, delta) previousEndStack = @stackForRow(end) # used in spill detection below - newTokenizedLines = @buildTokenizedLinesForRows(start, end + delta, @stackForRow(start - 1), @openScopesForRow(start)) + if @largeFileMode + newTokenizedLines = @buildPlaceholderTokenizedLinesForRows(start, end + delta) + else + newTokenizedLines = @buildTokenizedLinesForRows(start, end + delta, @stackForRow(start - 1), @openScopesForRow(start)) _.spliceWithArray(@tokenizedLines, start, end - start + 1, newTokenizedLines) start = @retokenizeWhitespaceRowsIfIndentLevelChanged(start - 1, -1) @@ -344,6 +349,10 @@ class TokenizedBuffer extends Model if 0 <= bufferRow < @tokenizedLines.length @tokenizedLines[bufferRow] ?= @buildPlaceholderTokenizedLineForRow(bufferRow) + tokenizedLinesForRows: (startRow, endRow) -> + for row in [startRow..endRow] by 1 + @tokenizedLineForRow(row) + stackForRow: (bufferRow) -> @tokenizedLines[bufferRow]?.ruleStack From d139ef9399ae8e5c42606dc7bd1270a450bf42b7 Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 5 Jun 2015 16:12:15 +0900 Subject: [PATCH 1531/1783] :arrow_up: one-dark-syntax@v0.7.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6e20ca50f..eabbf5978 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "base16-tomorrow-dark-theme": "0.26.0", "base16-tomorrow-light-theme": "0.9.0", "one-dark-ui": "0.9.0", - "one-dark-syntax": "0.7.0", + "one-dark-syntax": "0.7.1", "one-light-syntax": "0.7.0", "one-light-ui": "0.9.0", "solarized-dark-syntax": "0.35.0", From 9f21ccf54dac77dfc08cfb2b79d6382b3f91fc66 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 5 Jun 2015 12:07:44 +0200 Subject: [PATCH 1532/1783] Give tiles an opaque background --- src/tile-component.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tile-component.coffee b/src/tile-component.coffee index 88e06afd2..5659b73a9 100644 --- a/src/tile-component.coffee +++ b/src/tile-component.coffee @@ -38,6 +38,10 @@ class TileComponent @newTileState = @newState.tiles[@id] @oldTileState = @oldState.tiles[@id] + if @newState.backgroundColor isnt @oldState.backgroundColor + @domNode.style.backgroundColor = @newState.backgroundColor + @oldState.backgroundColor = @newState.backgroundColor + if @newTileState.display isnt @oldTileState.display @domNode.style.display = @newTileState.display @oldTileState.display = @newTileState.display From 4735ce60d99d77b9fd569569d7b8ba0d35043342 Mon Sep 17 00:00:00 2001 From: verrazanof Date: Fri, 5 Jun 2015 12:55:25 +0000 Subject: [PATCH 1533/1783] Update linux.md For Arch, `export PYTHON=/usr/bin/python2` should correct for `export python=/usr/bin/python2` --- docs/build-instructions/linux.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/build-instructions/linux.md b/docs/build-instructions/linux.md index 4874489ab..7b81786b7 100644 --- a/docs/build-instructions/linux.md +++ b/docs/build-instructions/linux.md @@ -30,7 +30,7 @@ Ubuntu LTS 12.04 64-bit is the recommended platform. ### Arch * `sudo pacman -S gconf base-devel git nodejs libgnome-keyring python2` -* `export PYTHON=/usr/bin/python2` before building Atom. +* `export python=/usr/bin/python2` before building Atom. ### Slackware From da05e1e2348d9fb784f02c5ece1a69734ef8024a Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 5 Jun 2015 16:05:30 +0200 Subject: [PATCH 1534/1783] wip --- src/highlights-component.coffee | 2 +- src/lines-component.coffee | 5 --- src/text-editor-presenter.coffee | 76 ++++++++++++++++++++++---------- src/tile-component.coffee | 6 +++ 4 files changed, 60 insertions(+), 29 deletions(-) diff --git a/src/highlights-component.coffee b/src/highlights-component.coffee index 5a5747d4c..eb64b9bc4 100644 --- a/src/highlights-component.coffee +++ b/src/highlights-component.coffee @@ -21,7 +21,7 @@ class HighlightsComponent @domNode updateSync: (state) -> - newState = state.content.highlights + newState = state.highlights @oldState ?= {} # remove highlights diff --git a/src/lines-component.coffee b/src/lines-component.coffee index 23f1c0015..bac1c9616 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -1,7 +1,6 @@ {$$} = require 'space-pen' CursorsComponent = require './cursors-component' -HighlightsComponent = require './highlights-component' TileComponent = require './tile-component' DummyLineNode = $$(-> @div className: 'line', style: 'position: absolute; visibility: hidden;', => @span 'x')[0] @@ -24,9 +23,6 @@ class LinesComponent @cursorsComponent = new CursorsComponent(@presenter) @domNode.appendChild(@cursorsComponent.getDomNode()) - @highlightsComponent = new HighlightsComponent(@presenter) - @domNode.appendChild(@highlightsComponent.getDomNode()) - if @useShadowDOM insertionPoint = document.createElement('content') insertionPoint.setAttribute('select', '.overlayer') @@ -63,7 +59,6 @@ class LinesComponent @oldState.scrollWidth = @newState.scrollWidth @cursorsComponent.updateSync(state) - @highlightsComponent.updateSync(state) @oldState.indentGuidesVisible = @newState.indentGuidesVisible @oldState.scrollWidth = @newState.scrollWidth diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 03cfd5a21..5d447edaa 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -335,6 +335,7 @@ class TextEditorPresenter tile.left = -@scrollLeft tile.height = @tileSize * @lineHeight tile.display = "block" + tile.highlights ?= {} @updateLinesState(tile, startRow, endRow) @@ -1041,7 +1042,7 @@ class TextEditorPresenter hasPixelPositionRequirements: -> @lineHeight? and @baseCharacterWidth? - pixelPositionForScreenPosition: (screenPosition, clip=true) -> + pixelPositionForScreenPosition: (screenPosition, clip=true, foo) -> screenPosition = Point.fromObject(screenPosition) screenPosition = @model.clipScreenPosition(screenPosition) if clip @@ -1050,6 +1051,7 @@ class TextEditorPresenter baseCharacterWidth = @baseCharacterWidth top = targetRow * @lineHeight + top -= foo * @lineHeight if foo? left = 0 column = 0 @@ -1074,8 +1076,8 @@ class TextEditorPresenter left += characterWidths[char] ? baseCharacterWidth unless char is '\0' column += charLength - top -= @scrollTop - left -= @scrollLeft + top -= @scrollTop unless foo? + left -= @scrollLeft unless foo? {top, left} hasPixelRectRequirements: -> @@ -1175,9 +1177,10 @@ class TextEditorPresenter else if decoration.isType('highlight') visibleHighlights[decoration.id] = @updateHighlightState(decoration) - for id of @state.content.highlights - unless visibleHighlights[id] - delete @state.content.highlights[id] + for tileId, tileState of @state.content.tiles + for id, highlight of tileState.highlights + unless visibleHighlights[id] + delete tileState.highlights[id] return @@ -1236,7 +1239,12 @@ class TextEditorPresenter range = marker.getScreenRange() if decoration.isDestroyed() or not marker.isValid() or range.isEmpty() or not range.intersectsRowRange(@startRow, @endRow - 1) - delete @state.content.highlights[decoration.id] + tileStartRow = @tileForRow(range.start.row) + tileEndRow = @tileForRow(range.end.row) + + for tile in [tileStartRow..tileEndRow] by @tileSize + delete @state.content.tiles[tile]?.highlights[decoration.id] + @emitDidUpdateState() return @@ -1248,32 +1256,54 @@ class TextEditorPresenter range.end.column = 0 if range.isEmpty() - delete @state.content.highlights[decoration.id] + tileState = @state.content.tiles[@tileForRow(range.start.row)] + delete tileState.highlights[decoration.id] @emitDidUpdateState() return - highlightState = @state.content.highlights[decoration.id] ?= { - flashCount: 0 - flashDuration: null - flashClass: null - } + flash = decoration.consumeNextFlash() - if flash = decoration.consumeNextFlash() - highlightState.flashCount++ - highlightState.flashClass = flash.class - highlightState.flashDuration = flash.duration + startRow = range.start.row + while startRow <= range.end.row + tileStartRow = @tileForRow(startRow) + tileEndRow = tileStartRow + @tileSize + tileState = @state.content.tiles[tileStartRow] ?= {highlights: {}} + endRow = Math.min(tileEndRow, range.end.row) + + tileRange = new Range(new Point(startRow, 0), new Point(endRow, Infinity)) + + if startRow is range.start.row + tileRange.start.column = range.start.column + + if endRow is range.end.row + tileRange.end.column = range.end.column + + highlightState = tileState.highlights[decoration.id] ?= { + flashCount: 0 + flashDuration: null + flashClass: null + tileRow: tileStartRow + } + + if flash? + highlightState.flashCount++ + highlightState.flashClass = flash.class + highlightState.flashDuration = flash.duration + + highlightState.class = properties.class + highlightState.deprecatedRegionClass = properties.deprecatedRegionClass + highlightState.regions = @buildHighlightRegions(tileStartRow, tileRange) + + startRow = tileEndRow - highlightState.class = properties.class - highlightState.deprecatedRegionClass = properties.deprecatedRegionClass - highlightState.regions = @buildHighlightRegions(range) @emitDidUpdateState() true - buildHighlightRegions: (screenRange) -> + buildHighlightRegions: (tileStartRow, screenRange) -> lineHeightInPixels = @lineHeight - startPixelPosition = @pixelPositionForScreenPosition(screenRange.start, true) - endPixelPosition = @pixelPositionForScreenPosition(screenRange.end, true) + startPixelPosition = @pixelPositionForScreenPosition(screenRange.start, true, tileStartRow) + endPixelPosition = @pixelPositionForScreenPosition(screenRange.end, true, tileStartRow) spannedRows = screenRange.end.row - screenRange.start.row + 1 if spannedRows is 1 diff --git a/src/tile-component.coffee b/src/tile-component.coffee index 5659b73a9..1aeeea952 100644 --- a/src/tile-component.coffee +++ b/src/tile-component.coffee @@ -1,5 +1,6 @@ _ = require 'underscore-plus' +HighlightsComponent = require './highlights-component' TokenIterator = require './token-iterator' AcceptFilter = {acceptNode: -> NodeFilter.FILTER_ACCEPT} WrapperDiv = document.createElement('div') @@ -26,6 +27,9 @@ class TileComponent @domNode.style.position = "absolute" @domNode.style.display = "block" + @highlightsComponent = new HighlightsComponent(@presenter) + @domNode.appendChild(@highlightsComponent.getDomNode()) + getDomNode: -> @domNode @@ -62,6 +66,8 @@ class TileComponent @domNode.style.width = @newState.scrollWidth + 'px' @oldState.scrollWidth = @newState.scrollWidth + @highlightsComponent.updateSync(@newTileState) + @oldState.indentGuidesVisible = @newState.indentGuidesVisible @oldState.scrollWidth = @newState.scrollWidth From 79b0bc2bad17f3a14fc8cafaada75630216867c3 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 5 Jun 2015 16:11:37 +0200 Subject: [PATCH 1535/1783] :art: Use `pixelPositionForScreenPositionInTile` --- src/text-editor-presenter.coffee | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 5d447edaa..d8322d061 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -1042,7 +1042,14 @@ class TextEditorPresenter hasPixelPositionRequirements: -> @lineHeight? and @baseCharacterWidth? - pixelPositionForScreenPosition: (screenPosition, clip=true, foo) -> + pixelPositionForScreenPositionInTile: (tileStartRow, screenPosition, clip) -> + position = @pixelPositionForScreenPosition(screenPosition, clip) + position.top -= tileStartRow * @lineHeight + position.top += @scrollTop + position.left += @scrollLeft + position + + pixelPositionForScreenPosition: (screenPosition, clip=true) -> screenPosition = Point.fromObject(screenPosition) screenPosition = @model.clipScreenPosition(screenPosition) if clip @@ -1051,7 +1058,6 @@ class TextEditorPresenter baseCharacterWidth = @baseCharacterWidth top = targetRow * @lineHeight - top -= foo * @lineHeight if foo? left = 0 column = 0 @@ -1076,8 +1082,8 @@ class TextEditorPresenter left += characterWidths[char] ? baseCharacterWidth unless char is '\0' column += charLength - top -= @scrollTop unless foo? - left -= @scrollLeft unless foo? + top -= @scrollTop + left -= @scrollLeft {top, left} hasPixelRectRequirements: -> @@ -1302,8 +1308,8 @@ class TextEditorPresenter buildHighlightRegions: (tileStartRow, screenRange) -> lineHeightInPixels = @lineHeight - startPixelPosition = @pixelPositionForScreenPosition(screenRange.start, true, tileStartRow) - endPixelPosition = @pixelPositionForScreenPosition(screenRange.end, true, tileStartRow) + startPixelPosition = @pixelPositionForScreenPositionInTile(tileStartRow, screenRange.start, true) + endPixelPosition = @pixelPositionForScreenPositionInTile(tileStartRow, screenRange.end, true) spannedRows = screenRange.end.row - screenRange.start.row + 1 if spannedRows is 1 From d294f35849e931d65a43ef6b333268dae49e2e15 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 5 Jun 2015 16:26:33 +0200 Subject: [PATCH 1536/1783] Get rid of `.underlayer` /cc: @nathansobo --- src/highlights-component.coffee | 5 ----- static/text-editor-light.less | 9 --------- static/text-editor-shadow.less | 9 --------- 3 files changed, 23 deletions(-) diff --git a/src/highlights-component.coffee b/src/highlights-component.coffee index eb64b9bc4..5e364f90c 100644 --- a/src/highlights-component.coffee +++ b/src/highlights-component.coffee @@ -12,11 +12,6 @@ class HighlightsComponent @domNode = document.createElement('div') @domNode.classList.add('highlights') - if atom.config.get('editor.useShadowDOM') - insertionPoint = document.createElement('content') - insertionPoint.setAttribute('select', '.underlayer') - @domNode.appendChild(insertionPoint) - getDomNode: -> @domNode diff --git a/static/text-editor-light.less b/static/text-editor-light.less index 9d87c61ca..a8b99f0bc 100644 --- a/static/text-editor-light.less +++ b/static/text-editor-light.less @@ -100,15 +100,6 @@ atom-text-editor { min-width: 0; } - .underlayer { - position: absolute; - z-index: -2; - top: 0; - bottom: 0; - left: 0; - right: 0; - } - .highlight { background: none; padding: 0; diff --git a/static/text-editor-shadow.less b/static/text-editor-shadow.less index c67637290..cb63b45b0 100644 --- a/static/text-editor-shadow.less +++ b/static/text-editor-shadow.less @@ -81,15 +81,6 @@ min-width: 0; } -.underlayer { - position: absolute; - z-index: -2; - top: 0; - bottom: 0; - left: 0; - right: 0; -} - .highlight { background: none; padding: 0; From ccd739ff65b5cfd9f043bb9c0c1ced466c655554 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=C5=BDu=C5=BEak?= Date: Fri, 5 Jun 2015 16:35:48 +0200 Subject: [PATCH 1537/1783] :arrow_up: notifications@0.51.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index eabbf5978..1db19fde1 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "link": "0.30.0", "markdown-preview": "0.150.0", "metrics": "0.51.0", - "notifications": "0.50.0", + "notifications": "0.51.0", "open-on-github": "0.37.0", "package-generator": "0.39.0", "release-notes": "0.52.0", From c1b4b743b47192d9e2c4a8eecff113e3b5d381a4 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 5 Jun 2015 17:00:17 +0200 Subject: [PATCH 1538/1783] Organize visible highlights by tile --- src/text-editor-presenter.coffee | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index d8322d061..4277c6193 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -24,6 +24,7 @@ class TextEditorPresenter @disposables = new CompositeDisposable @emitter = new Emitter + @visibleHighlights = {} @characterWidthsByScope = {} @rangesByDecorationId = {} @lineDecorationsByScreenRow = {} @@ -331,6 +332,7 @@ class TextEditorPresenter endRow = Math.min(@model.getScreenLineCount(), startRow + @tileSize) tile = @state.content.tiles[startRow] ?= {} + tile.startRow = startRow tile.top = startRow * @lineHeight - @scrollTop tile.left = -@scrollLeft tile.height = @tileSize * @lineHeight @@ -1171,8 +1173,8 @@ class TextEditorPresenter @lineDecorationsByScreenRow = {} @lineNumberDecorationsByScreenRow = {} @customGutterDecorationsByGutterNameAndScreenRow = {} + @visibleHighlights = {} - visibleHighlights = {} return unless 0 <= @startRow <= @endRow <= Infinity for markerId, decorations of @model.decorationsForScreenRowRange(@startRow, @endRow - 1) @@ -1181,12 +1183,11 @@ class TextEditorPresenter if decoration.isType('line') or decoration.isType('gutter') @addToLineDecorationCaches(decoration, range) else if decoration.isType('highlight') - visibleHighlights[decoration.id] = @updateHighlightState(decoration) + @updateHighlightState(decoration) for tileId, tileState of @state.content.tiles for id, highlight of tileState.highlights - unless visibleHighlights[id] - delete tileState.highlights[id] + delete tileState.highlights[id] unless @visibleHighlights[tileId]?[id]? return @@ -1300,6 +1301,9 @@ class TextEditorPresenter highlightState.deprecatedRegionClass = properties.deprecatedRegionClass highlightState.regions = @buildHighlightRegions(tileStartRow, tileRange) + @visibleHighlights[tileStartRow] ?= {} + @visibleHighlights[tileStartRow][decoration.id] = true + startRow = tileEndRow @emitDidUpdateState() From b20394e323ad975c1a176666423a0f60f696c6fd Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 5 Jun 2015 17:34:34 +0200 Subject: [PATCH 1539/1783] :art: --- src/text-editor-presenter.coffee | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 4277c6193..193e62324 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -1270,14 +1270,19 @@ class TextEditorPresenter flash = decoration.consumeNextFlash() - startRow = range.start.row - while startRow <= range.end.row - tileStartRow = @tileForRow(startRow) - tileEndRow = tileStartRow + @tileSize - tileState = @state.content.tiles[tileStartRow] ?= {highlights: {}} - endRow = Math.min(tileEndRow, range.end.row) - tileRange = new Range(new Point(startRow, 0), new Point(endRow, Infinity)) + startTile = @tileForRow(range.start.row) + endTile = @tileForRow(range.end.row) + + for currentTile in [startTile..endTile] by @tileSize + startRow = Math.max(currentTile, range.start.row) + endRow = Math.min(currentTile + @tileSize - 1, range.end.row) + + tileState = @state.content.tiles[currentTile] ?= {highlights: {}} + tileRange = new Range( + new Point(startRow, 0), + new Point(endRow, Infinity) + ) if startRow is range.start.row tileRange.start.column = range.start.column @@ -1285,11 +1290,13 @@ class TextEditorPresenter if endRow is range.end.row tileRange.end.column = range.end.column + console.log "Range for tile #{currentTile}: #{tileRange.toString()}" + highlightState = tileState.highlights[decoration.id] ?= { flashCount: 0 flashDuration: null flashClass: null - tileRow: tileStartRow + tileRow: currentTile } if flash? @@ -1299,12 +1306,10 @@ class TextEditorPresenter highlightState.class = properties.class highlightState.deprecatedRegionClass = properties.deprecatedRegionClass - highlightState.regions = @buildHighlightRegions(tileStartRow, tileRange) + highlightState.regions = @buildHighlightRegions(currentTile, tileRange) - @visibleHighlights[tileStartRow] ?= {} - @visibleHighlights[tileStartRow][decoration.id] = true - - startRow = tileEndRow + @visibleHighlights[currentTile] ?= {} + @visibleHighlights[currentTile][decoration.id] = true @emitDidUpdateState() From 022d0cead3633711d9f15da5f56d64ead667e1c2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 5 Jun 2015 08:43:11 -0700 Subject: [PATCH 1540/1783] Re-enable tree-view and tabs sublime-tabs is installed --- .../packages/sublime-tabs/package.json | 4 ++++ spec/package-manager-spec.coffee | 19 +++++++++++++++++++ src/package-manager.coffee | 11 +++++++++++ 3 files changed, 34 insertions(+) create mode 100644 spec/fixtures/packages/sublime-tabs/package.json diff --git a/spec/fixtures/packages/sublime-tabs/package.json b/spec/fixtures/packages/sublime-tabs/package.json new file mode 100644 index 000000000..2fd01501d --- /dev/null +++ b/spec/fixtures/packages/sublime-tabs/package.json @@ -0,0 +1,4 @@ +{ + "name": "sublime-tabs", + "version": "1.0.0" +} diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index f09f43824..af9378caa 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -877,3 +877,22 @@ describe "PackageManager", -> runs -> expect(fs.isDirectorySync(autocompleteCSSPath)).toBe false expect(fs.isSymbolicLinkSync(autocompletePlusPath)).toBe true + + describe "when the deprecated sublime-tabs package is installed", -> + it "enables the tree-view and tabs package", -> + atom.config.pushAtKeyPath('core.disabledPackages', 'tree-view') + atom.config.pushAtKeyPath('core.disabledPackages', 'tabs') + + spyOn(atom.packages, 'getAvailablePackagePaths').andReturn [ + path.join(__dirname, 'fixtures', 'packages', 'sublime-tabs') + path.resolve(__dirname, '..', 'node_modules', 'tree-view') + path.resolve(__dirname, '..', 'node_modules', 'tabs') + ] + atom.packages.loadPackages() + + waitsFor -> + not atom.packages.isPackageDisabled('tree-view') and not atom.packages.isPackageDisabled('tabs') + + runs -> + expect(atom.packages.isPackageLoaded('tree-view')).toBe true + expect(atom.packages.isPackageLoaded('tabs')).toBe true diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 306e553a8..478f16dd7 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -314,6 +314,10 @@ class PackageManager @uninstallAutocompletePlus() packagePaths = @getAvailablePackagePaths() + + # TODO: remove after a few atom versions. + @migrateSublimeTabsSettings(packagePaths) + packagePaths = packagePaths.filter (packagePath) => not @isPackageDisabled(path.basename(packagePath)) packagePaths = _.uniq packagePaths, (packagePath) -> path.basename(packagePath) @loadPackage(packagePath) for packagePath in packagePaths @@ -445,6 +449,13 @@ class PackageManager @uninstallDirectory(dirToRemove) return + # TODO: remove this after a few versions + migrateSublimeTabsSettings: (packagePaths) -> + for packagePath in packagePaths when path.basename(packagePath) is 'sublime-tabs' + atom.config.removeAtKeyPath('core.disabledPackages', 'tree-view') + atom.config.removeAtKeyPath('core.disabledPackages', 'tabs') + return + uninstallDirectory: (directory) -> symlinkPromise = new Promise (resolve) -> fs.isSymbolicLink directory, (isSymLink) -> resolve(isSymLink) From 71f9c2641846eeaffbfbf9b664250d474eb12e8d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 5 Jun 2015 08:47:00 -0700 Subject: [PATCH 1541/1783] Only migrate config when not including deprecated APIs --- spec/package-manager-spec.coffee | 10 ++++++++++ src/package-manager.coffee | 1 + 2 files changed, 11 insertions(+) diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index af9378caa..26b675975 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -879,6 +879,16 @@ describe "PackageManager", -> expect(fs.isSymbolicLinkSync(autocompletePlusPath)).toBe true describe "when the deprecated sublime-tabs package is installed", -> + grim = require 'grim' + includeDeprecatedAPIs = null + + beforeEach -> + {includeDeprecatedAPIs} = grim + grim.includeDeprecatedAPIs = false + + afterEach -> + grim.includeDeprecatedAPIs = includeDeprecatedAPIs + it "enables the tree-view and tabs package", -> atom.config.pushAtKeyPath('core.disabledPackages', 'tree-view') atom.config.pushAtKeyPath('core.disabledPackages', 'tabs') diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 478f16dd7..aeb67ea3b 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -451,6 +451,7 @@ class PackageManager # TODO: remove this after a few versions migrateSublimeTabsSettings: (packagePaths) -> + return if Grim.includeDeprecatedAPIs for packagePath in packagePaths when path.basename(packagePath) is 'sublime-tabs' atom.config.removeAtKeyPath('core.disabledPackages', 'tree-view') atom.config.removeAtKeyPath('core.disabledPackages', 'tabs') From 786bfc7ebdd3d56457f12ae4d8588c657db2075f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=C5=BDu=C5=BEak?= Date: Fri, 5 Jun 2015 17:51:42 +0200 Subject: [PATCH 1542/1783] :arrow_up: notifications@0.52.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1db19fde1..e9755c850 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "link": "0.30.0", "markdown-preview": "0.150.0", "metrics": "0.51.0", - "notifications": "0.51.0", + "notifications": "0.52.0", "open-on-github": "0.37.0", "package-generator": "0.39.0", "release-notes": "0.52.0", From 2b3329673fdf6882797c65f9e1e428198e0b1346 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 5 Jun 2015 09:03:22 -0700 Subject: [PATCH 1543/1783] :arrow_up: settings-view@0.208 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e9755c850..20cb1a580 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "open-on-github": "0.37.0", "package-generator": "0.39.0", "release-notes": "0.52.0", - "settings-view": "0.207.0", + "settings-view": "0.208.0", "snippets": "0.93.0", "spell-check": "0.58.0", "status-bar": "0.74.0", From 53a3239379e0ae63c136f1e513e65b103705af82 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 5 Jun 2015 18:17:30 +0200 Subject: [PATCH 1544/1783] Use buffer coordinates in TokenizedBuffer::scopeDescriptorForPosition Fixes #7073 --- src/tokenized-buffer.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 55d2e7e37..6b25847c9 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -405,7 +405,7 @@ class TokenizedBuffer extends Model iterator = @tokenizedLines[row].getTokenIterator() while iterator.next() - if iterator.getScreenEnd() > column + if iterator.getBufferEnd() > column scopes = iterator.getScopes() break From b3c9a9a77dae7ca832ef1d1e6cae091fba03283f Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 5 Jun 2015 18:33:32 +0200 Subject: [PATCH 1545/1783] :bug: Correctly display highlight regions --- src/text-editor-presenter.coffee | 33 +++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 193e62324..76f532ec6 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -1270,7 +1270,6 @@ class TextEditorPresenter flash = decoration.consumeNextFlash() - startTile = @tileForRow(range.start.row) endTile = @tileForRow(range.end.row) @@ -1290,8 +1289,6 @@ class TextEditorPresenter if endRow is range.end.row tileRange.end.column = range.end.column - console.log "Range for tile #{currentTile}: #{tileRange.toString()}" - highlightState = tileState.highlights[decoration.id] ?= { flashCount: 0 flashDuration: null @@ -1317,20 +1314,25 @@ class TextEditorPresenter buildHighlightRegions: (tileStartRow, screenRange) -> lineHeightInPixels = @lineHeight - startPixelPosition = @pixelPositionForScreenPositionInTile(tileStartRow, screenRange.start, true) + startPixelPosition = @pixelPositionForScreenPositionInTile(tileStartRow, screenRange.start, false) endPixelPosition = @pixelPositionForScreenPositionInTile(tileStartRow, screenRange.end, true) spannedRows = screenRange.end.row - screenRange.start.row + 1 + regions = [] + if spannedRows is 1 - [ + region = top: startPixelPosition.top height: lineHeightInPixels left: startPixelPosition.left - width: endPixelPosition.left - startPixelPosition.left - ] - else - regions = [] + if screenRange.end.column is Infinity + region.right = 0 + else + region.width = endPixelPosition.left - startPixelPosition.left + + regions.push(region) + else # First row, extending from selection start to the right side of screen regions.push( top: startPixelPosition.top @@ -1350,14 +1352,19 @@ class TextEditorPresenter # Last row, extending from left side of screen to selection end if screenRange.end.column > 0 - regions.push( + region = top: endPixelPosition.top height: lineHeightInPixels left: 0 - width: endPixelPosition.left - ) - regions + if screenRange.end.column is Infinity + region.right = 0 + else + region.width = endPixelPosition.left + + regions.push(region) + + regions setOverlayDimensions: (decorationId, itemWidth, itemHeight, contentMargin) -> @overlayDimensions[decorationId] ?= {} From c34838277d68bd19f0b97ecede4d86c684a111b8 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 5 Jun 2015 19:55:34 +0200 Subject: [PATCH 1546/1783] =?UTF-8?q?In=20largeFileMode,=20base=20maxLineL?= =?UTF-8?q?ength=20on=20the=20longest=20line=20we=E2=80=99ve=20seen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is pretty hacky. If we want to compute the true longest line, we’ll need to process every line, which is what large file mode is designed to avoid. So now whenever the display buffer returns a line, it has the potential to update the longest line. This is a bit weird because retrieving a line now has a side effect. It’s even more weird because the longest line will actually be wrong for the initial state updates in the TextEditorPresenter. But as soon as the user interacts in any way the dimensions are recomputed, so it works for now. A better approach may be to set a visible region on the display buffer. But I’d like to keep this low-touch until we have a chance to revisit the design of DisplayBuffer in a bigger way. --- src/display-buffer.coffee | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index 32f374776..388182c8f 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -479,7 +479,11 @@ class DisplayBuffer extends Model # Returns {TokenizedLine} tokenizedLineForScreenRow: (screenRow) -> if @largeFileMode - @tokenizedBuffer.tokenizedLineForRow(screenRow) + line = @tokenizedBuffer.tokenizedLineForRow(screenRow) + if line.text.length > @maxLineLength + @maxLineLength = line.text.length + @longestScreenRow = screenRow + line else @screenLines[screenRow] @@ -760,19 +764,13 @@ class DisplayBuffer extends Model # # Returns a {Number}. getMaxLineLength: -> - if @largeFileMode - 100 - else - @maxLineLength + @maxLineLength # Gets the row number of the longest screen line. # # Return a {} getLongestScreenRow: -> - if @largeFileMode - 0 - else - @longestScreenRow + @longestScreenRow # Given a buffer position, this converts it into a screen position. # From 0f24e369c60d5b021d46228315bac9c1eca3713d Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 5 Jun 2015 11:29:36 -0700 Subject: [PATCH 1547/1783] :arrow_up: text-buffer --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 20cb1a580..879348d77 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "space-pen": "3.8.2", "stacktrace-parser": "0.1.1", "temp": "0.8.1", - "text-buffer": "6.2.0", + "text-buffer": "6.2.1", "theorist": "^1.0.2", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", From 2337254afbe827b8bea2b7819800c9aa663de687 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 5 Jun 2015 12:05:05 -0700 Subject: [PATCH 1548/1783] Fix text-editor-component-spec failure Grouping intervals are exclusive now. It shouldn't affect anybody since it's a one-millisecond change to the meaning of grouping-interval, but it required changing some time intervals in this spec. --- spec/text-editor-component-spec.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index b2bb09acd..e4d502ded 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -2340,10 +2340,10 @@ describe "TextEditorComponent", -> editor.setText("") componentNode.dispatchEvent(buildTextInputEvent(data: 'x', target: inputNode)) - currentTime += 100 + currentTime += 99 componentNode.dispatchEvent(buildTextInputEvent(data: 'y', target: inputNode)) - currentTime += 100 + currentTime += 99 componentNode.dispatchEvent(new CustomEvent('editor:duplicate-lines', bubbles: true, cancelable: true)) currentTime += 101 From 639647d1158eb90c510811ab3cb66d199e7a2904 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 5 Jun 2015 21:31:06 +0200 Subject: [PATCH 1549/1783] Disallow fold creation in large file mode --- src/display-buffer.coffee | 9 +++++---- src/tokenized-buffer.coffee | 7 ++++++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index 388182c8f..2fccc4eb0 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -532,10 +532,11 @@ class DisplayBuffer extends Model # # Returns the new {Fold}. createFold: (startRow, endRow) -> - foldMarker = - @findFoldMarker({startRow, endRow}) ? - @buffer.markRange([[startRow, 0], [endRow, Infinity]], @getFoldMarkerAttributes()) - @foldForMarker(foldMarker) + unless @largeFileMode + foldMarker = + @findFoldMarker({startRow, endRow}) ? + @buffer.markRange([[startRow, 0], [endRow, Infinity]], @getFoldMarkerAttributes()) + @foldForMarker(foldMarker) isFoldedAtBufferRow: (bufferRow) -> @largestFoldContainingBufferRow(bufferRow)? diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 5aa3482a9..f051cb4be 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -263,6 +263,8 @@ class TokenizedBuffer extends Model row - increment updateFoldableStatus: (startRow, endRow) -> + return [startRow, endRow] if @largeFileMode + scanStartRow = @buffer.previousNonBlankRow(startRow) ? startRow scanStartRow-- while scanStartRow > 0 and @tokenizedLineForRow(scanStartRow).isComment() scanEndRow = @buffer.nextNonBlankRow(endRow) ? endRow @@ -278,7 +280,10 @@ class TokenizedBuffer extends Model [startRow, endRow] isFoldableAtRow: (row) -> - @isFoldableCodeAtRow(row) or @isFoldableCommentAtRow(row) + if @largeFileMode + false + else + @isFoldableCodeAtRow(row) or @isFoldableCommentAtRow(row) # Returns a {Boolean} indicating whether the given buffer row starts # a a foldable row range due to the code's indentation patterns. From efd4662de0af4776bca54ed1a79a5c7e4c8f98b2 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 5 Jun 2015 21:36:11 +0200 Subject: [PATCH 1550/1783] =?UTF-8?q?Don=E2=80=99t=20allow=20soft=20wrap?= =?UTF-8?q?=20to=20be=20enabled=20in=20large=20file=20mode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/display-buffer.coffee | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index 2fccc4eb0..8aa6e9d1b 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -445,7 +445,10 @@ class DisplayBuffer extends Model @isSoftWrapped() isSoftWrapped: -> - @softWrapped ? @configSettings.softWrap ? false + if @largeFileMode + false + else + @softWrapped ? @configSettings.softWrap ? false # Set the number of characters that fit horizontally in the editor. # From 56273e7eef6c16093ca45eebf346c9903ddb614e Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 5 Jun 2015 21:44:23 +0200 Subject: [PATCH 1551/1783] Preserve large file mode across serialization and pane splits --- src/display-buffer.coffee | 3 ++- src/tokenized-buffer.coffee | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index 8aa6e9d1b..910f7b177 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -89,13 +89,14 @@ class DisplayBuffer extends Model scrollTop: @scrollTop scrollLeft: @scrollLeft tokenizedBuffer: @tokenizedBuffer.serialize() + largeFileMode: @largeFileMode deserializeParams: (params) -> params.tokenizedBuffer = TokenizedBuffer.deserialize(params.tokenizedBuffer) params copy: -> - newDisplayBuffer = new DisplayBuffer({@buffer, tabLength: @getTabLength()}) + newDisplayBuffer = new DisplayBuffer({@buffer, tabLength: @getTabLength(), @largeFileMode}) newDisplayBuffer.setScrollTop(@getScrollTop()) newDisplayBuffer.setScrollLeft(@getScrollLeft()) diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index f051cb4be..6337aa3c6 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -44,6 +44,7 @@ class TokenizedBuffer extends Model bufferPath: @buffer.getPath() tabLength: @tabLength ignoreInvisibles: @ignoreInvisibles + largeFileMode: @largeFileMode deserializeParams: (params) -> params.buffer = atom.project.bufferForPathSync(params.bufferPath) From 1800a9fb1d6a6cd147a275a6efd2458606974928 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 5 Jun 2015 12:52:34 -0700 Subject: [PATCH 1552/1783] Prepare 0.208 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 879348d77..4e998abb4 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "0.207.0", + "version": "0.208.0", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From 48ce361bd0f81b369a5f10ce7e9a4c2e5d3c339f Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 5 Jun 2015 22:24:49 +0200 Subject: [PATCH 1553/1783] Select grammars based on first 10 lines of content, not the entire file --- src/tokenized-buffer.coffee | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 6337aa3c6..758aef501 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -67,7 +67,7 @@ class TokenizedBuffer extends Model if grammar.injectionSelector? @retokenizeLines() if @hasTokenForSelector(grammar.injectionSelector) else - newScore = grammar.getScore(@buffer.getPath(), @buffer.getText()) + newScore = grammar.getScore(@buffer.getPath(), @getGrammarSelectionContent()) @setGrammar(grammar, newScore) if newScore > @currentGrammarScore setGrammar: (grammar, score) -> @@ -75,7 +75,7 @@ class TokenizedBuffer extends Model @grammar = grammar @rootScopeDescriptor = new ScopeDescriptor(scopes: [@grammar.scopeName]) - @currentGrammarScore = score ? grammar.getScore(@buffer.getPath(), @buffer.getText()) + @currentGrammarScore = score ? grammar.getScore(@buffer.getPath(), @getGrammarSelectionContent()) @grammarUpdateDisposable?.dispose() @grammarUpdateDisposable = @grammar.onDidUpdate => @retokenizeLines() @@ -106,8 +106,11 @@ class TokenizedBuffer extends Model @emit 'grammar-changed', grammar if Grim.includeDeprecatedAPIs @emitter.emit 'did-change-grammar', grammar + getGrammarSelectionContent: -> + @buffer.getTextInRange([[0, 0], [10, 0]]) + reloadGrammar: -> - if grammar = atom.grammars.selectGrammar(@buffer.getPath(), @buffer.getText()) + if grammar = atom.grammars.selectGrammar(@buffer.getPath(), @getGrammarSelectionContent()) @setGrammar(grammar) else throw new Error("No grammar found for path: #{path}") From 2732e0dcacea193bbf54a96384320a15f4644935 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 5 Jun 2015 13:31:24 -0700 Subject: [PATCH 1554/1783] presenter: :fire: redundant decoration state updates --- src/text-editor-presenter.coffee | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 03cfd5a21..2acb59c27 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -1134,8 +1134,6 @@ class TextEditorPresenter @shouldUpdateLineNumbersState = true else if decoration.isType('gutter') @shouldUpdateCustomGutterDecorationState = true - if decoration.isType('highlight') - @updateHighlightState(decoration) if decoration.isType('overlay') @shouldUpdateOverlaysState = true @@ -1145,14 +1143,14 @@ class TextEditorPresenter @observeDecoration(decoration) if decoration.isType('line') or decoration.isType('gutter') - @addToLineDecorationCaches(decoration, decoration.getMarker().getScreenRange()) + @shouldUpdateDecorations = true @shouldUpdateTilesState = true if decoration.isType('line') if decoration.isType('line-number') @shouldUpdateLineNumbersState = true else if decoration.isType('gutter') @shouldUpdateCustomGutterDecorationState = true else if decoration.isType('highlight') - @updateHighlightState(decoration) + @shouldUpdateDecorations = true else if decoration.isType('overlay') @shouldUpdateOverlaysState = true @@ -1357,7 +1355,6 @@ class TextEditorPresenter @shouldUpdateHiddenInputState = true @pauseCursorBlinking() @updateCursorState(cursor) - @emitDidUpdateState() startBlinkingCursors: -> From ffcebdad33bc863e88152ffa94717dfc2d669d84 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 5 Jun 2015 23:14:11 +0200 Subject: [PATCH 1555/1783] Remove outdated test --- spec/workspace-spec.coffee | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index 009f95a1c..3e94727d4 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -272,20 +272,6 @@ describe "Workspace", -> beforeEach -> atom.notifications.onDidAddNotification notificationSpy = jasmine.createSpy() - describe "when a large file is opened", -> - beforeEach -> - spyOn(fs, 'getSizeSync').andReturn 2 * 1048577 # 2MB - - it "creates a notification", -> - waitsForPromise -> - workspace.open('file1') - - runs -> - expect(notificationSpy).toHaveBeenCalled() - notification = notificationSpy.mostRecentCall.args[0] - expect(notification.getType()).toBe 'warning' - expect(notification.getMessage()).toContain '< 2MB' - describe "when a file does not exist", -> it "creates an empty buffer for the specified path", -> waitsForPromise -> From df733aa3de889976d43f9d209d15a947883018c0 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 5 Jun 2015 23:25:48 +0200 Subject: [PATCH 1556/1783] Add a basic test for opening an editor in largeFileMode if >= 2MB --- spec/workspace-spec.coffee | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index 3e94727d4..4918fc65f 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -224,6 +224,17 @@ describe "Workspace", -> expect(workspace.paneContainer.root.children[0]).toBe pane1 expect(workspace.paneContainer.root.children[1]).toBe pane4 + describe "when the file is large (over 2mb)", -> + it "opens the editor with largeFileMode: true", -> + spyOn(fs, 'getSizeSync').andReturn 2 * 1048577 # 2MB + + editor = null + waitsForPromise -> + workspace.open('sample.js').then (e) -> editor = e + + runs -> + expect(editor.displayBuffer.largeFileMode).toBe true + describe "when passed a path that matches a custom opener", -> it "returns the resource returned by the custom opener", -> fooOpener = (pathToOpen, options) -> {foo: pathToOpen, options} if pathToOpen?.match(/\.foo/) From 3ac9d539ce99d09d17b4dfd2d33c140edeb54e8f Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 5 Jun 2015 23:40:29 +0200 Subject: [PATCH 1557/1783] Add a super basic test for large file mode --- spec/text-editor-spec.coffee | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 8ad1ce390..63b01a178 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -66,6 +66,25 @@ describe "TextEditor", -> expect(editor.tokenizedLineForScreenRow(0).invisibles.eol).toBe '?' + describe "when the editor is constructed with the largeFileMode option set to true", -> + it "loads the editor but doesn't tokenize", -> + editor = null + + waitsForPromise -> + atom.workspace.open('sample.js', largeFileMode: true).then (o) -> editor = o + + runs -> + buffer = editor.getBuffer() + expect(editor.tokenizedLineForScreenRow(0).text).toBe buffer.lineForRow(0) + expect(editor.tokenizedLineForScreenRow(0).tokens.length).toBe 1 + expect(editor.tokenizedLineForScreenRow(1).tokens.length).toBe 2 # soft tab + expect(editor.tokenizedLineForScreenRow(12).text).toBe buffer.lineForRow(12) + expect(editor.tokenizedLineForScreenRow(0).tokens.length).toBe 1 + expect(editor.getCursorScreenPosition()).toEqual [0, 0] + editor.insertText('hey"') + expect(editor.tokenizedLineForScreenRow(0).tokens.length).toBe 1 + expect(editor.tokenizedLineForScreenRow(1).tokens.length).toBe 2 # sof tab + describe "when the editor is constructed with an initialLine option", -> it "positions the cursor on the specified line", -> editor = null From 88812831ce248315f908fe048d0bd38a8d81d86e Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 5 Jun 2015 23:40:56 +0200 Subject: [PATCH 1558/1783] Only check for max line length when lines exist --- src/display-buffer.coffee | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index 910f7b177..2519fa6d6 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -483,11 +483,11 @@ class DisplayBuffer extends Model # Returns {TokenizedLine} tokenizedLineForScreenRow: (screenRow) -> if @largeFileMode - line = @tokenizedBuffer.tokenizedLineForRow(screenRow) - if line.text.length > @maxLineLength - @maxLineLength = line.text.length - @longestScreenRow = screenRow - line + if line = @tokenizedBuffer.tokenizedLineForRow(screenRow) + if line.text.length > @maxLineLength + @maxLineLength = line.text.length + @longestScreenRow = screenRow + line else @screenLines[screenRow] From 02140c718214c3a9e0160ff1f66cd7ba90042962 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 5 Jun 2015 16:26:53 -0700 Subject: [PATCH 1559/1783] :arrow_up: find-and-replace, text-buffer --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 4e998abb4..cf19292e7 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "space-pen": "3.8.2", "stacktrace-parser": "0.1.1", "temp": "0.8.1", - "text-buffer": "6.2.1", + "text-buffer": "6.3.0", "theorist": "^1.0.2", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", @@ -99,7 +99,7 @@ "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", - "find-and-replace": "0.171.0", + "find-and-replace": "0.172.0", "fuzzy-finder": "0.87.0", "git-diff": "0.55.0", "go-to-line": "0.30.0", From f850750707950cf7d022e467cd5079c75cdf0f4d Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 5 Jun 2015 16:44:43 -0700 Subject: [PATCH 1560/1783] :arrow_up: spell-check --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cf19292e7..4e082676a 100644 --- a/package.json +++ b/package.json @@ -116,7 +116,7 @@ "release-notes": "0.52.0", "settings-view": "0.208.0", "snippets": "0.93.0", - "spell-check": "0.58.0", + "spell-check": "0.59.0", "status-bar": "0.74.0", "styleguide": "0.44.0", "symbols-view": "0.97.0", From cf70739bf19f3f082c5370aa1e132da0062f1de7 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Sat, 6 Jun 2015 08:34:28 +0200 Subject: [PATCH 1561/1783] Don't clip when building highlight regions --- 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 76f532ec6..77cdd7c6d 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -1315,7 +1315,7 @@ class TextEditorPresenter buildHighlightRegions: (tileStartRow, screenRange) -> lineHeightInPixels = @lineHeight startPixelPosition = @pixelPositionForScreenPositionInTile(tileStartRow, screenRange.start, false) - endPixelPosition = @pixelPositionForScreenPositionInTile(tileStartRow, screenRange.end, true) + endPixelPosition = @pixelPositionForScreenPositionInTile(tileStartRow, screenRange.end, false) spannedRows = screenRange.end.row - screenRange.start.row + 1 regions = [] From 11202ebb6965f51233bb6e8c5cbd9d6bd6ba992a Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Sat, 6 Jun 2015 09:15:10 +0200 Subject: [PATCH 1562/1783] :art: --- src/text-editor-presenter.coffee | 56 +++++++++++++++++++------------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 77cdd7c6d..6af2c6524 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -1238,6 +1238,22 @@ class TextEditorPresenter return + intersectRangeWithTile: (range, tileStartRow) -> + intersectingStartRow = Math.max(tileStartRow, range.start.row) + intersectingEndRow = Math.min(tileStartRow + @tileSize - 1, range.end.row) + intersectingRange = new Range( + new Point(intersectingStartRow, 0), + new Point(intersectingEndRow, Infinity) + ) + + if intersectingStartRow is range.start.row + intersectingRange.start.column = range.start.column + + if intersectingEndRow is range.end.row + intersectingRange.end.column = range.end.column + + intersectingRange + updateHighlightState: (decoration) -> return unless @startRow? and @endRow? and @lineHeight? and @hasPixelPositionRequirements() @@ -1273,27 +1289,13 @@ class TextEditorPresenter startTile = @tileForRow(range.start.row) endTile = @tileForRow(range.end.row) - for currentTile in [startTile..endTile] by @tileSize - startRow = Math.max(currentTile, range.start.row) - endRow = Math.min(currentTile + @tileSize - 1, range.end.row) - - tileState = @state.content.tiles[currentTile] ?= {highlights: {}} - tileRange = new Range( - new Point(startRow, 0), - new Point(endRow, Infinity) - ) - - if startRow is range.start.row - tileRange.start.column = range.start.column - - if endRow is range.end.row - tileRange.end.column = range.end.column - + for tileStartRow in [startTile..endTile] by @tileSize + tileState = @state.content.tiles[tileStartRow] ?= {highlights: {}} highlightState = tileState.highlights[decoration.id] ?= { flashCount: 0 flashDuration: null flashClass: null - tileRow: currentTile + tileRow: tileStartRow } if flash? @@ -1301,21 +1303,29 @@ class TextEditorPresenter highlightState.flashClass = flash.class highlightState.flashDuration = flash.duration + intersectingRange = @intersectRangeWithTile(range, tileStartRow) highlightState.class = properties.class highlightState.deprecatedRegionClass = properties.deprecatedRegionClass - highlightState.regions = @buildHighlightRegions(currentTile, tileRange) + highlightState.regions = @buildHighlightRegions(intersectingRange) - @visibleHighlights[currentTile] ?= {} - @visibleHighlights[currentTile][decoration.id] = true + for region in highlightState.regions + @repositionRegionWithinTile(region, tileStartRow) + + @visibleHighlights[tileStartRow] ?= {} + @visibleHighlights[tileStartRow][decoration.id] = true @emitDidUpdateState() true - buildHighlightRegions: (tileStartRow, screenRange) -> + repositionRegionWithinTile: (region, tileStartRow) -> + region.top += @scrollTop - tileStartRow * @lineHeight + region.left += @scrollLeft + + buildHighlightRegions: (screenRange) -> lineHeightInPixels = @lineHeight - startPixelPosition = @pixelPositionForScreenPositionInTile(tileStartRow, screenRange.start, false) - endPixelPosition = @pixelPositionForScreenPositionInTile(tileStartRow, screenRange.end, false) + startPixelPosition = @pixelPositionForScreenPosition(screenRange.start, false) + endPixelPosition = @pixelPositionForScreenPosition(screenRange.end, false) spannedRows = screenRange.end.row - screenRange.start.row + 1 regions = [] From 8319eae0d7f986f1563569a0e8a4f42db1031c3d Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Sat, 6 Jun 2015 09:29:40 +0200 Subject: [PATCH 1563/1783] :fire: Delete unused code --- src/text-editor-presenter.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 6af2c6524..23f4a12f9 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -332,7 +332,6 @@ class TextEditorPresenter endRow = Math.min(@model.getScreenLineCount(), startRow + @tileSize) tile = @state.content.tiles[startRow] ?= {} - tile.startRow = startRow tile.top = startRow * @lineHeight - @scrollTop tile.left = -@scrollLeft tile.height = @tileSize * @lineHeight @@ -1295,7 +1294,6 @@ class TextEditorPresenter flashCount: 0 flashDuration: null flashClass: null - tileRow: tileStartRow } if flash? From f7b82f2411d745e58eadcaf28644dc03631de226 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Sat, 6 Jun 2015 09:31:38 +0200 Subject: [PATCH 1564/1783] :fire: --- src/text-editor-presenter.coffee | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 23f4a12f9..95b683b9e 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -1043,13 +1043,6 @@ class TextEditorPresenter hasPixelPositionRequirements: -> @lineHeight? and @baseCharacterWidth? - pixelPositionForScreenPositionInTile: (tileStartRow, screenPosition, clip) -> - position = @pixelPositionForScreenPosition(screenPosition, clip) - position.top -= tileStartRow * @lineHeight - position.top += @scrollTop - position.left += @scrollLeft - position - pixelPositionForScreenPosition: (screenPosition, clip=true) -> screenPosition = Point.fromObject(screenPosition) screenPosition = @model.clipScreenPosition(screenPosition) if clip From de766afee79ae0cdee6b7111f0172eeefbe5f1e3 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Sat, 6 Jun 2015 10:18:26 +0200 Subject: [PATCH 1565/1783] Start porting specs --- spec/text-editor-presenter-spec.coffee | 65 +++++++++++++++++--------- src/text-editor-presenter.coffee | 7 ++- 2 files changed, 48 insertions(+), 24 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index fc52c4828..41400d605 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -1277,8 +1277,13 @@ describe "TextEditorPresenter", -> expect(presenter.getState().content.cursorsVisible).toBe false describe ".highlights", -> - stateForHighlight = (presenter, decoration) -> - presenter.getState().content.highlights[decoration.id] + expectUndefinedStateForHighlight = (presenter, decoration) -> + for startRow, tileState of presenter.getState().content.tiles + state = stateForHighlightInTile(presenter, decoration, startRow) + expect(state).toBeUndefined() + + stateForHighlightInTile = (presenter, decoration, tile) -> + presenter.getState().content.tiles[tile]?.highlights[decoration.id] stateForSelection = (presenter, selectionIndex) -> selection = presenter.model.getSelections()[selectionIndex] @@ -1297,11 +1302,11 @@ describe "TextEditorPresenter", -> marker3 = editor.markBufferRange([[0, 6], [3, 6]]) highlight3 = editor.decorateMarker(marker3, type: 'highlight', class: 'c') - # on-screen + # on-screen, spans over 2 tiles marker4 = editor.markBufferRange([[2, 6], [4, 6]]) highlight4 = editor.decorateMarker(marker4, type: 'highlight', class: 'd') - # partially off-screen below, 2 of 3 regions on screen + # partially off-screen below, spans over 3 tiles, 2 of 3 regions on screen marker5 = editor.markBufferRange([[3, 6], [6, 6]]) highlight5 = editor.decorateMarker(marker5, type: 'highlight', class: 'e') @@ -1317,51 +1322,67 @@ describe "TextEditorPresenter", -> marker8 = editor.markBufferRange([[2, 2], [2, 2]]) highlight8 = editor.decorateMarker(marker8, type: 'highlight', class: 'h') - presenter = buildPresenter(explicitHeight: 30, scrollTop: 20) + presenter = buildPresenter(explicitHeight: 30, scrollTop: 20, tileSize: 2) - expect(stateForHighlight(presenter, highlight1)).toBeUndefined() + expectUndefinedStateForHighlight(presenter, highlight1) - expectValues stateForHighlight(presenter, highlight2), { + expectValues stateForHighlightInTile(presenter, highlight2, 2), { class: 'b' regions: [ - {top: 2 * 10 - 20, left: 0 * 10, width: 6 * 10, height: 1 * 10} + {top: 0, left: 0 * 10, width: 6 * 10, height: 1 * 10} ] } - expectValues stateForHighlight(presenter, highlight3), { + expectValues stateForHighlightInTile(presenter, highlight3, 2), { class: 'c' regions: [ - {top: 2 * 10 - 20, left: 0 * 10, right: 0, height: 1 * 10} - {top: 3 * 10 - 20, left: 0 * 10, width: 6 * 10, height: 1 * 10} + {top: 0, left: 0 * 10, right: 0, height: 1 * 10} + {top: 10, left: 0 * 10, width: 6 * 10, height: 1 * 10} ] } - expectValues stateForHighlight(presenter, highlight4), { + expectValues stateForHighlightInTile(presenter, highlight4, 2), { class: 'd' regions: [ - {top: 2 * 10 - 20, left: 6 * 10, right: 0, height: 1 * 10} - {top: 3 * 10 - 20, left: 0, right: 0, height: 1 * 10} - {top: 4 * 10 - 20, left: 0, width: 6 * 10, height: 1 * 10} + {top: 0, left: 6 * 10, right: 0, height: 1 * 10} + {top: 10, left: 0, right: 0, height: 1 * 10} + ] + } + expectValues stateForHighlightInTile(presenter, highlight4, 4), { + class: 'd' + regions: [ + {top: 0, left: 0, width: 60, height: 1 * 10} ] } - expectValues stateForHighlight(presenter, highlight5), { + expectValues stateForHighlightInTile(presenter, highlight5, 2), { class: 'e' regions: [ - {top: 3 * 10 - 20, left: 6 * 10, right: 0, height: 1 * 10} - {top: 4 * 10 - 20, left: 0 * 10, right: 0, height: 2 * 10} + {top: 10, left: 6 * 10, right: 0, height: 1 * 10} ] } - expectValues stateForHighlight(presenter, highlight6), { + expectValues stateForHighlightInTile(presenter, highlight5, 4), { + class: 'e' + regions: [ + {top: 0, left: 0, right: 0, height: 1 * 10} + {top: 10, left: 0, right: 0, height: 1 * 10} + ] + } + + expect(stateForHighlightInTile(presenter, highlight5, 6)).toBeUndefined() + + expectValues stateForHighlightInTile(presenter, highlight6, 4), { class: 'f' regions: [ - {top: 5 * 10 - 20, left: 6 * 10, right: 0, height: 1 * 10} + {top: 10, left: 6 * 10, right: 0, height: 1 * 10} ] } - expect(stateForHighlight(presenter, highlight7)).toBeUndefined() - expect(stateForHighlight(presenter, highlight8)).toBeUndefined() + expect(stateForHighlightInTile(presenter, highlight6, 6)).toBeUndefined() + + expectUndefinedStateForHighlight(presenter, highlight7) + expectUndefinedStateForHighlight(presenter, highlight8) it "is empty until all of the required measurements are assigned", -> editor.setSelectedBufferRanges([ diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 95b683b9e..7cbc434d5 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -1282,6 +1282,10 @@ class TextEditorPresenter endTile = @tileForRow(range.end.row) for tileStartRow in [startTile..endTile] by @tileSize + rangeWithinTile = @intersectRangeWithTile(range, tileStartRow) + + continue if rangeWithinTile.isEmpty() + tileState = @state.content.tiles[tileStartRow] ?= {highlights: {}} highlightState = tileState.highlights[decoration.id] ?= { flashCount: 0 @@ -1294,10 +1298,9 @@ class TextEditorPresenter highlightState.flashClass = flash.class highlightState.flashDuration = flash.duration - intersectingRange = @intersectRangeWithTile(range, tileStartRow) highlightState.class = properties.class highlightState.deprecatedRegionClass = properties.deprecatedRegionClass - highlightState.regions = @buildHighlightRegions(intersectingRange) + highlightState.regions = @buildHighlightRegions(rangeWithinTile) for region in highlightState.regions @repositionRegionWithinTile(region, tileStartRow) From b68da1e19bbca1dbd71cf45459a968ed541835c0 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Sat, 6 Jun 2015 10:21:24 +0200 Subject: [PATCH 1566/1783] :green_heart: Finish porting `TextEditorPresenter` specs --- spec/text-editor-presenter-spec.coffee | 147 +++++++++++++++---------- 1 file changed, 86 insertions(+), 61 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 41400d605..25fde69c1 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -1278,16 +1278,21 @@ describe "TextEditorPresenter", -> describe ".highlights", -> expectUndefinedStateForHighlight = (presenter, decoration) -> - for startRow, tileState of presenter.getState().content.tiles - state = stateForHighlightInTile(presenter, decoration, startRow) + for tileId, tileState of presenter.getState().content.tiles + state = stateForHighlightInTile(presenter, decoration, tileId) expect(state).toBeUndefined() stateForHighlightInTile = (presenter, decoration, tile) -> presenter.getState().content.tiles[tile]?.highlights[decoration.id] - stateForSelection = (presenter, selectionIndex) -> + stateForSelectionInTile = (presenter, selectionIndex, tile) -> selection = presenter.model.getSelections()[selectionIndex] - stateForHighlight(presenter, selection.decoration) + stateForHighlightInTile(presenter, selection.decoration, tile) + + expectUndefinedStateForSelection = (presenter, selectionIndex) -> + for tileId, tileState of presenter.getState().content.tiles + state = stateForSelectionInTile(presenter, selectionIndex, tileId) + expect(state).toBeUndefined() it "contains states for highlights that are visible on screen", -> # off-screen above @@ -1389,56 +1394,66 @@ describe "TextEditorPresenter", -> [[0, 2], [2, 4]], ]) - presenter = buildPresenter(explicitHeight: null, lineHeight: null, scrollTop: null, baseCharacterWidth: null) - expect(presenter.getState().content.highlights).toEqual({}) + presenter = buildPresenter(explicitHeight: null, lineHeight: null, scrollTop: null, baseCharacterWidth: null, tileSize: 2) + for tileId, tileState of presenter.getState().content.tiles + expect(tileState.highlights).toEqual({}) presenter.setExplicitHeight(25) - expect(presenter.getState().content.highlights).toEqual({}) + for tileId, tileState of presenter.getState().content.tiles + expect(tileState.highlights).toEqual({}) presenter.setLineHeight(10) - expect(presenter.getState().content.highlights).toEqual({}) + for tileId, tileState of presenter.getState().content.tiles + expect(tileState.highlights).toEqual({}) presenter.setScrollTop(0) - expect(presenter.getState().content.highlights).toEqual({}) + for tileId, tileState of presenter.getState().content.tiles + expect(tileState.highlights).toEqual({}) presenter.setBaseCharacterWidth(8) - expect(presenter.getState().content.highlights).not.toEqual({}) + assignedAnyHighlight = false + for tileId, tileState of presenter.getState().content.tiles + assignedAnyHighlight ||= _.isEqual(tileState.highlights, {}) + + expect(assignedAnyHighlight).toBe(true) it "does not include highlights for invalid markers", -> marker = editor.markBufferRange([[2, 2], [2, 4]], invalidate: 'touch') highlight = editor.decorateMarker(marker, type: 'highlight', class: 'h') - presenter = buildPresenter(explicitHeight: 30, scrollTop: 20) + presenter = buildPresenter(explicitHeight: 30, scrollTop: 20, tileSize: 2) + + expect(stateForHighlightInTile(presenter, highlight, 2)).toBeDefined() - expect(stateForHighlight(presenter, highlight)).toBeDefined() expectStateUpdate presenter, -> editor.getBuffer().insert([2, 2], "stuff") - expect(stateForHighlight(presenter, highlight)).toBeUndefined() + + expectUndefinedStateForHighlight(presenter, highlight) it "updates when ::scrollTop changes", -> editor.setSelectedBufferRanges([ [[6, 2], [6, 4]], ]) - presenter = buildPresenter(explicitHeight: 30, scrollTop: 20) + presenter = buildPresenter(explicitHeight: 30, scrollTop: 20, tileSize: 2) - expect(stateForSelection(presenter, 0)).toBeUndefined() + expectUndefinedStateForSelection(presenter, 0) expectStateUpdate presenter, -> presenter.setScrollTop(5 * 10) - expect(stateForSelection(presenter, 0)).toBeDefined() + expect(stateForSelectionInTile(presenter, 0, 6)).toBeDefined() expectStateUpdate presenter, -> presenter.setScrollTop(2 * 10) - expect(stateForSelection(presenter, 0)).toBeUndefined() + expectUndefinedStateForSelection(presenter, 0) it "updates when ::explicitHeight changes", -> editor.setSelectedBufferRanges([ [[6, 2], [6, 4]], ]) - presenter = buildPresenter(explicitHeight: 20, scrollTop: 20) + presenter = buildPresenter(explicitHeight: 20, scrollTop: 20, tileSize: 2) - expect(stateForSelection(presenter, 0)).toBeUndefined() + expectUndefinedStateForSelection(presenter, 0) expectStateUpdate presenter, -> presenter.setExplicitHeight(60) - expect(stateForSelection(presenter, 0)).toBeDefined() + expect(stateForSelectionInTile(presenter, 0, 6)).toBeDefined() expectStateUpdate presenter, -> presenter.setExplicitHeight(20) - expect(stateForSelection(presenter, 0)).toBeUndefined() + expectUndefinedStateForSelection(presenter, 0) it "updates when ::lineHeight changes", -> editor.setSelectedBufferRanges([ @@ -1446,26 +1461,26 @@ describe "TextEditorPresenter", -> [[3, 4], [3, 6]], ]) - presenter = buildPresenter(explicitHeight: 20, scrollTop: 0) + presenter = buildPresenter(explicitHeight: 20, scrollTop: 0, tileSize: 2) - expectValues stateForSelection(presenter, 0), { + expectValues stateForSelectionInTile(presenter, 0, 2), { regions: [ - {top: 2 * 10, left: 2 * 10, width: 2 * 10, height: 10} + {top: 0, left: 2 * 10, width: 2 * 10, height: 10} ] } - expect(stateForSelection(presenter, 1)).toBeUndefined() + expectUndefinedStateForSelection(presenter, 1) expectStateUpdate presenter, -> presenter.setLineHeight(5) - expectValues stateForSelection(presenter, 0), { + expectValues stateForSelectionInTile(presenter, 0, 2), { regions: [ - {top: 2 * 5, left: 2 * 10, width: 2 * 10, height: 5} + {top: 0, left: 2 * 10, width: 2 * 10, height: 5} ] } - expectValues stateForSelection(presenter, 1), { + expectValues stateForSelectionInTile(presenter, 1, 2), { regions: [ - {top: 3 * 5, left: 4 * 10, width: 2 * 10, height: 5} + {top: 5, left: 4 * 10, width: 2 * 10, height: 5} ] } @@ -1474,14 +1489,14 @@ describe "TextEditorPresenter", -> [[2, 2], [2, 4]], ]) - presenter = buildPresenter(explicitHeight: 20, scrollTop: 0) + presenter = buildPresenter(explicitHeight: 20, scrollTop: 0, tileSize: 2) - expectValues stateForSelection(presenter, 0), { - regions: [{top: 2 * 10, left: 2 * 10, width: 2 * 10, height: 10}] + expectValues stateForSelectionInTile(presenter, 0, 2), { + regions: [{top: 0, left: 2 * 10, width: 2 * 10, height: 10}] } expectStateUpdate presenter, -> presenter.setBaseCharacterWidth(20) - expectValues stateForSelection(presenter, 0), { - regions: [{top: 2 * 10, left: 2 * 20, width: 2 * 20, height: 10}] + expectValues stateForSelectionInTile(presenter, 0, 2), { + regions: [{top: 0, left: 2 * 20, width: 2 * 20, height: 10}] } it "updates when scoped character widths change", -> @@ -1493,14 +1508,14 @@ describe "TextEditorPresenter", -> [[2, 4], [2, 6]], ]) - presenter = buildPresenter(explicitHeight: 20, scrollTop: 0) + presenter = buildPresenter(explicitHeight: 20, scrollTop: 0, tileSize: 2) - expectValues stateForSelection(presenter, 0), { - regions: [{top: 2 * 10, left: 4 * 10, width: 2 * 10, height: 10}] + expectValues stateForSelectionInTile(presenter, 0, 2), { + regions: [{top: 0, left: 4 * 10, width: 2 * 10, height: 10}] } expectStateUpdate presenter, -> presenter.setScopedCharacterWidth(['source.js', 'keyword.control.js'], 'i', 20) - expectValues stateForSelection(presenter, 0), { - regions: [{top: 2 * 10, left: 4 * 10, width: 20 + 10, height: 10}] + expectValues stateForSelectionInTile(presenter, 0, 2), { + regions: [{top: 0, left: 4 * 10, width: 20 + 10, height: 10}] } it "updates when highlight decorations are added, moved, hidden, shown, or destroyed", -> @@ -1508,74 +1523,79 @@ describe "TextEditorPresenter", -> [[1, 2], [1, 4]], [[3, 4], [3, 6]] ]) - presenter = buildPresenter(explicitHeight: 20, scrollTop: 0) + presenter = buildPresenter(explicitHeight: 20, scrollTop: 0, tileSize: 2) - expectValues stateForSelection(presenter, 0), { - regions: [{top: 1 * 10, left: 2 * 10, width: 2 * 10, height: 10}] + expectValues stateForSelectionInTile(presenter, 0, 0), { + regions: [{top: 10, left: 2 * 10, width: 2 * 10, height: 10}] } - expect(stateForSelection(presenter, 1)).toBeUndefined() + expectUndefinedStateForSelection(presenter, 1) # moving into view expectStateUpdate presenter, -> editor.getSelections()[1].setBufferRange([[2, 4], [2, 6]], autoscroll: false) - expectValues stateForSelection(presenter, 1), { - regions: [{top: 2 * 10, left: 4 * 10, width: 2 * 10, height: 10}] + expectValues stateForSelectionInTile(presenter, 1, 2), { + regions: [{top: 0, left: 4 * 10, width: 2 * 10, height: 10}] } # becoming empty expectStateUpdate presenter, -> editor.getSelections()[1].clear(autoscroll: false) - expect(stateForSelection(presenter, 1)).toBeUndefined() + expectUndefinedStateForSelection(presenter, 1) # becoming non-empty expectStateUpdate presenter, -> editor.getSelections()[1].setBufferRange([[2, 4], [2, 6]], autoscroll: false) - expectValues stateForSelection(presenter, 1), { - regions: [{top: 2 * 10, left: 4 * 10, width: 2 * 10, height: 10}] + expectValues stateForSelectionInTile(presenter, 1, 2), { + regions: [{top: 0, left: 4 * 10, width: 2 * 10, height: 10}] } # moving out of view expectStateUpdate presenter, -> editor.getSelections()[1].setBufferRange([[3, 4], [3, 6]], autoscroll: false) - expect(stateForSelection(presenter, 1)).toBeUndefined() + expectUndefinedStateForSelection(presenter, 1) # adding expectStateUpdate presenter, -> editor.addSelectionForBufferRange([[1, 4], [1, 6]], autoscroll: false) - expectValues stateForSelection(presenter, 2), { - regions: [{top: 1 * 10, left: 4 * 10, width: 2 * 10, height: 10}] + expectValues stateForSelectionInTile(presenter, 2, 0), { + regions: [{top: 10, left: 4 * 10, width: 2 * 10, height: 10}] } # moving added selection expectStateUpdate presenter, -> editor.getSelections()[2].setBufferRange([[1, 4], [1, 8]], autoscroll: false) - expectValues stateForSelection(presenter, 2), { - regions: [{top: 1 * 10, left: 4 * 10, width: 4 * 10, height: 10}] + expectValues stateForSelectionInTile(presenter, 2, 0), { + regions: [{top: 10, left: 4 * 10, width: 4 * 10, height: 10}] } # destroying destroyedSelection = editor.getSelections()[2] expectStateUpdate presenter, -> destroyedSelection.destroy() - expect(stateForHighlight(presenter, destroyedSelection.decoration)).toBeUndefined() + expectUndefinedStateForHighlight(presenter, destroyedSelection.decoration) it "updates when highlight decorations' properties are updated", -> marker = editor.markBufferPosition([2, 2]) highlight = editor.decorateMarker(marker, type: 'highlight', class: 'a') - presenter = buildPresenter(explicitHeight: 30, scrollTop: 20) + presenter = buildPresenter(explicitHeight: 30, scrollTop: 20, tileSize: 2) - expect(stateForHighlight(presenter, highlight)).toBeUndefined() + expectUndefinedStateForHighlight(presenter, highlight) expectStateUpdate presenter, -> marker.setBufferRange([[2, 2], [2, 4]]) highlight.setProperties(class: 'b', type: 'highlight') - expectValues stateForHighlight(presenter, highlight), {class: 'b'} + expectValues stateForHighlightInTile(presenter, highlight, 2), {class: 'b'} it "increments the .flashCount and sets the .flashClass and .flashDuration when the highlight model flashes", -> - presenter = buildPresenter(explicitHeight: 30, scrollTop: 20) + presenter = buildPresenter(explicitHeight: 30, scrollTop: 20, tileSize: 2) marker = editor.markBufferPosition([2, 2]) highlight = editor.decorateMarker(marker, type: 'highlight', class: 'a') expectStateUpdate presenter, -> - marker.setBufferRange([[2, 2], [2, 4]]) + marker.setBufferRange([[2, 2], [5, 2]]) highlight.flash('b', 500) - expectValues stateForHighlight(presenter, highlight), { + expectValues stateForHighlightInTile(presenter, highlight, 2), { + flashClass: 'b' + flashDuration: 500 + flashCount: 1 + } + expectValues stateForHighlightInTile(presenter, highlight, 4), { flashClass: 'b' flashDuration: 500 flashCount: 1 @@ -1583,7 +1603,12 @@ describe "TextEditorPresenter", -> expectStateUpdate presenter, -> highlight.flash('c', 600) - expectValues stateForHighlight(presenter, highlight), { + expectValues stateForHighlightInTile(presenter, highlight, 2), { + flashClass: 'c' + flashDuration: 600 + flashCount: 2 + } + expectValues stateForHighlightInTile(presenter, highlight, 4), { flashClass: 'c' flashDuration: 600 flashCount: 2 From fcb965306656e4d20acf3523d114a4032300bff6 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Sat, 6 Jun 2015 15:41:15 +0200 Subject: [PATCH 1567/1783] Start porting `TextEditorComponent` specs --- spec/text-editor-component-spec.coffee | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index e4d502ded..3f62e7fd0 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -89,19 +89,19 @@ describe "TextEditorComponent", -> expect(tilesNodes.length).toBe(3) expect(tilesNodes[0].style['-webkit-transform']).toBe "translate3d(0px, 0px, 0px)" - expect(tilesNodes[0].children.length).toBe(tileSize) + expect(tilesNodes[0].querySelectorAll(".line").length).toBe(tileSize) expectTileContainsRow(tilesNodes[0], 0, top: 0 * lineHeightInPixels) expectTileContainsRow(tilesNodes[0], 1, top: 1 * lineHeightInPixels) expectTileContainsRow(tilesNodes[0], 2, top: 2 * lineHeightInPixels) expect(tilesNodes[1].style['-webkit-transform']).toBe "translate3d(0px, #{1 * tileHeight}px, 0px)" - expect(tilesNodes[1].children.length).toBe(tileSize) + expect(tilesNodes[1].querySelectorAll(".line").length).toBe(tileSize) expectTileContainsRow(tilesNodes[1], 3, top: 0 * lineHeightInPixels) expectTileContainsRow(tilesNodes[1], 4, top: 1 * lineHeightInPixels) expectTileContainsRow(tilesNodes[1], 5, top: 2 * lineHeightInPixels) expect(tilesNodes[2].style['-webkit-transform']).toBe "translate3d(0px, #{2 * tileHeight}px, 0px)" - expect(tilesNodes[2].children.length).toBe(tileSize) + expect(tilesNodes[2].querySelectorAll(".line").length).toBe(tileSize) expectTileContainsRow(tilesNodes[2], 6, top: 0 * lineHeightInPixels) expectTileContainsRow(tilesNodes[2], 7, top: 1 * lineHeightInPixels) expectTileContainsRow(tilesNodes[2], 8, top: 2 * lineHeightInPixels) @@ -118,19 +118,19 @@ describe "TextEditorComponent", -> expect(tilesNodes.length).toBe(3) expect(tilesNodes[0].style['-webkit-transform']).toBe "translate3d(0px, -5px, 0px)" - expect(tilesNodes[0].children.length).toBe(tileSize) + expect(tilesNodes[0].querySelectorAll(".line").length).toBe(tileSize) expectTileContainsRow(tilesNodes[0], 3, top: 0 * lineHeightInPixels) expectTileContainsRow(tilesNodes[0], 4, top: 1 * lineHeightInPixels) expectTileContainsRow(tilesNodes[0], 5, top: 2 * lineHeightInPixels) expect(tilesNodes[1].style['-webkit-transform']).toBe "translate3d(0px, #{1 * tileHeight - 5}px, 0px)" - expect(tilesNodes[1].children.length).toBe(tileSize) + expect(tilesNodes[1].querySelectorAll(".line").length).toBe(tileSize) expectTileContainsRow(tilesNodes[1], 6, top: 0 * lineHeightInPixels) expectTileContainsRow(tilesNodes[1], 7, top: 1 * lineHeightInPixels) expectTileContainsRow(tilesNodes[1], 8, top: 2 * lineHeightInPixels) expect(tilesNodes[2].style['-webkit-transform']).toBe "translate3d(0px, #{2 * tileHeight - 5}px, 0px)" - expect(tilesNodes[2].children.length).toBe(tileSize) + expect(tilesNodes[2].querySelectorAll(".line").length).toBe(tileSize) expectTileContainsRow(tilesNodes[2], 9, top: 0 * lineHeightInPixels) expectTileContainsRow(tilesNodes[2], 10, top: 1 * lineHeightInPixels) expectTileContainsRow(tilesNodes[2], 11, top: 2 * lineHeightInPixels) @@ -1219,7 +1219,7 @@ describe "TextEditorComponent", -> expect(regions.length).toBe 1 regionRect = regions[0].style - expect(regionRect.top).toBe (9 * lineHeightInPixels - verticalScrollbarNode.scrollTop) + 'px' + expect(regionRect.top).toBe (0 + 'px') expect(regionRect.height).toBe 1 * lineHeightInPixels + 'px' expect(regionRect.left).toBe 2 * charWidth + 'px' expect(regionRect.width).toBe 2 * charWidth + 'px' @@ -1263,10 +1263,10 @@ describe "TextEditorComponent", -> it "allows multiple space-delimited decoration classes", -> decoration.setProperties(type: 'highlight', class: 'foo bar') nextAnimationFrame() - expect(componentNode.querySelectorAll('.foo.bar').length).toBe 1 + expect(componentNode.querySelectorAll('.foo.bar').length).toBe 2 decoration.setProperties(type: 'highlight', class: 'bar baz') nextAnimationFrame() - expect(componentNode.querySelectorAll('.bar.baz').length).toBe 1 + expect(componentNode.querySelectorAll('.bar.baz').length).toBe 2 it "renders classes on the regions directly if 'deprecatedRegionClass' option is defined", -> decoration = editor.decorateMarker(marker, type: 'highlight', class: 'test-highlight', deprecatedRegionClass: 'test-highlight-region') @@ -1278,7 +1278,7 @@ describe "TextEditorComponent", -> describe "when flashing a decoration via Decoration::flash()", -> highlightNode = null beforeEach -> - highlightNode = componentNode.querySelector('.test-highlight') + highlightNode = componentNode.querySelectorAll('.test-highlight')[1] it "adds and removes the flash class specified in ::flash", -> expect(highlightNode.classList.contains('flash-class')).toBe false @@ -1314,13 +1314,15 @@ describe "TextEditorComponent", -> regionStyle = componentNode.querySelector('.test-highlight .region').style originalTop = parseInt(regionStyle.top) + expect(originalTop).toBe(2 * lineHeightInPixels) + editor.getBuffer().insert([0, 0], '\n') nextAnimationFrame() regionStyle = componentNode.querySelector('.test-highlight .region').style newTop = parseInt(regionStyle.top) - expect(newTop).toBe originalTop + lineHeightInPixels + expect(newTop).toBe(0) it "moves rendered highlights when the marker is manually moved", -> regionStyle = componentNode.querySelector('.test-highlight .region').style @@ -1330,7 +1332,7 @@ describe "TextEditorComponent", -> nextAnimationFrame() regionStyle = componentNode.querySelector('.test-highlight .region').style - expect(parseInt(regionStyle.top)).toBe 5 * lineHeightInPixels + expect(parseInt(regionStyle.top)).toBe 2 * lineHeightInPixels describe "when a decoration is updated via Decoration::update", -> it "renders the decoration's new params", -> From 465043f213a6e267e7ea50834e28cfa2b786edb2 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Sat, 6 Jun 2015 16:22:33 +0200 Subject: [PATCH 1568/1783] :fire: --- src/tile-component.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/tile-component.coffee b/src/tile-component.coffee index 1aeeea952..9ceca8e54 100644 --- a/src/tile-component.coffee +++ b/src/tile-component.coffee @@ -14,8 +14,6 @@ cloneObject = (object) -> module.exports = class TileComponent - placeholderTextDiv: null - constructor: ({@presenter, @id}) -> @tokenIterator = new TokenIterator @measuredLines = new Set From c4503fc13735988f8aa3774119856647fc30038f Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Sat, 6 Jun 2015 16:55:00 +0200 Subject: [PATCH 1569/1783] :green_heart: --- spec/text-editor-component-spec.coffee | 38 +++++++++++++++++++++----- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 3f62e7fd0..eec4c004f 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -972,21 +972,45 @@ describe "TextEditorComponent", -> expect(region2Rect.left).toBe scrollViewClientLeft + 0 expect(region2Rect.width).toBe 10 * charWidth - it "renders 3 regions for selections with more than 2 lines", -> - editor.setSelectedScreenRange([[1, 6], [5, 10]]) + it "renders 3 regions per tile for selections with more than 2 lines", -> + editor.setSelectedScreenRange([[0, 6], [5, 10]]) nextAnimationFrame() - regions = componentNode.querySelectorAll('.selection .region') - expect(regions.length).toBe 3 + + # Tile 0 + regions = componentNode.querySelectorAll(".tile")[0].querySelectorAll('.selection .region') + expect(regions.length).toBe(3) region1Rect = regions[0].getBoundingClientRect() - expect(region1Rect.top).toBe 1 * lineHeightInPixels + expect(region1Rect.top).toBe 0 expect(region1Rect.height).toBe 1 * lineHeightInPixels expect(region1Rect.left).toBe scrollViewClientLeft + 6 * charWidth expect(region1Rect.right).toBe scrollViewNode.getBoundingClientRect().right region2Rect = regions[1].getBoundingClientRect() - expect(region2Rect.top).toBe 2 * lineHeightInPixels - expect(region2Rect.height).toBe 3 * lineHeightInPixels + expect(region2Rect.top).toBe 1 * lineHeightInPixels + expect(region2Rect.height).toBe 1 * lineHeightInPixels + expect(region2Rect.left).toBe scrollViewClientLeft + 0 + expect(region2Rect.right).toBe scrollViewNode.getBoundingClientRect().right + + region3Rect = regions[2].getBoundingClientRect() + expect(region3Rect.top).toBe 2 * lineHeightInPixels + expect(region3Rect.height).toBe 1 * lineHeightInPixels + expect(region3Rect.left).toBe scrollViewClientLeft + 0 + expect(region3Rect.right).toBe scrollViewNode.getBoundingClientRect().right + + # Tile 3 + regions = componentNode.querySelectorAll(".tile")[1].querySelectorAll('.selection .region') + expect(regions.length).toBe(3) + + region1Rect = regions[0].getBoundingClientRect() + expect(region1Rect.top).toBe 3 * lineHeightInPixels + expect(region1Rect.height).toBe 1 * lineHeightInPixels + expect(region1Rect.left).toBe scrollViewClientLeft + 0 + expect(region1Rect.right).toBe scrollViewNode.getBoundingClientRect().right + + region2Rect = regions[1].getBoundingClientRect() + expect(region2Rect.top).toBe 4 * lineHeightInPixels + expect(region2Rect.height).toBe 1 * lineHeightInPixels expect(region2Rect.left).toBe scrollViewClientLeft + 0 expect(region2Rect.right).toBe scrollViewNode.getBoundingClientRect().right From 515ae7acb780c7f514dc6190e1c2bc35e3657b73 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Sat, 6 Jun 2015 17:19:24 +0200 Subject: [PATCH 1570/1783] Use tile node as the reference for highlights width --- spec/text-editor-component-spec.coffee | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index eec4c004f..264ff9b11 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -957,14 +957,15 @@ describe "TextEditorComponent", -> it "renders 2 regions for 2-line selections", -> editor.setSelectedScreenRange([[1, 6], [2, 10]]) nextAnimationFrame() - regions = componentNode.querySelectorAll('.selection .region') + tileNode = componentNode.querySelectorAll(".tile")[0] + regions = tileNode.querySelectorAll('.selection .region') expect(regions.length).toBe 2 region1Rect = regions[0].getBoundingClientRect() expect(region1Rect.top).toBe 1 * lineHeightInPixels expect(region1Rect.height).toBe 1 * lineHeightInPixels expect(region1Rect.left).toBe scrollViewClientLeft + 6 * charWidth - expect(region1Rect.right).toBe scrollViewNode.getBoundingClientRect().right + expect(region1Rect.right).toBe tileNode.getBoundingClientRect().right region2Rect = regions[1].getBoundingClientRect() expect(region2Rect.top).toBe 2 * lineHeightInPixels @@ -977,42 +978,44 @@ describe "TextEditorComponent", -> nextAnimationFrame() # Tile 0 - regions = componentNode.querySelectorAll(".tile")[0].querySelectorAll('.selection .region') + tileNode = componentNode.querySelectorAll(".tile")[0] + regions = tileNode.querySelectorAll('.selection .region') expect(regions.length).toBe(3) region1Rect = regions[0].getBoundingClientRect() expect(region1Rect.top).toBe 0 expect(region1Rect.height).toBe 1 * lineHeightInPixels expect(region1Rect.left).toBe scrollViewClientLeft + 6 * charWidth - expect(region1Rect.right).toBe scrollViewNode.getBoundingClientRect().right + expect(region1Rect.right).toBe tileNode.getBoundingClientRect().right region2Rect = regions[1].getBoundingClientRect() expect(region2Rect.top).toBe 1 * lineHeightInPixels expect(region2Rect.height).toBe 1 * lineHeightInPixels expect(region2Rect.left).toBe scrollViewClientLeft + 0 - expect(region2Rect.right).toBe scrollViewNode.getBoundingClientRect().right + expect(region2Rect.right).toBe tileNode.getBoundingClientRect().right region3Rect = regions[2].getBoundingClientRect() expect(region3Rect.top).toBe 2 * lineHeightInPixels expect(region3Rect.height).toBe 1 * lineHeightInPixels expect(region3Rect.left).toBe scrollViewClientLeft + 0 - expect(region3Rect.right).toBe scrollViewNode.getBoundingClientRect().right + expect(region3Rect.right).toBe tileNode.getBoundingClientRect().right # Tile 3 - regions = componentNode.querySelectorAll(".tile")[1].querySelectorAll('.selection .region') + tileNode = componentNode.querySelectorAll(".tile")[1] + regions = tileNode.querySelectorAll('.selection .region') expect(regions.length).toBe(3) region1Rect = regions[0].getBoundingClientRect() expect(region1Rect.top).toBe 3 * lineHeightInPixels expect(region1Rect.height).toBe 1 * lineHeightInPixels expect(region1Rect.left).toBe scrollViewClientLeft + 0 - expect(region1Rect.right).toBe scrollViewNode.getBoundingClientRect().right + expect(region1Rect.right).toBe tileNode.getBoundingClientRect().right region2Rect = regions[1].getBoundingClientRect() expect(region2Rect.top).toBe 4 * lineHeightInPixels expect(region2Rect.height).toBe 1 * lineHeightInPixels expect(region2Rect.left).toBe scrollViewClientLeft + 0 - expect(region2Rect.right).toBe scrollViewNode.getBoundingClientRect().right + expect(region2Rect.right).toBe tileNode.getBoundingClientRect().right region3Rect = regions[2].getBoundingClientRect() expect(region3Rect.top).toBe 5 * lineHeightInPixels From f88e21cbb06eec1b8d5d12d2fd0452e77b754b9f Mon Sep 17 00:00:00 2001 From: Jesse Grosjean Date: Sat, 6 Jun 2015 22:21:51 -0400 Subject: [PATCH 1571/1783] Allow items to provide savePanel options. --- spec/pane-spec.coffee | 4 ++-- src/atom.coffee | 7 ++++--- src/pane.coffee | 5 +++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/spec/pane-spec.coffee b/spec/pane-spec.coffee index 7d6410048..51bb07e8c 100644 --- a/spec/pane-spec.coffee +++ b/spec/pane-spec.coffee @@ -3,7 +3,7 @@ Pane = require '../src/pane' PaneAxis = require '../src/pane-axis' PaneContainer = require '../src/pane-container' -describe "Pane", -> +fdescribe "Pane", -> deserializerDisposable = null class Item extends Model @@ -414,7 +414,7 @@ describe "Pane", -> pane.getActiveItem().path = __filename pane.getActiveItem().saveAs = jasmine.createSpy("saveAs") pane.saveActiveItemAs() - expect(atom.showSaveDialogSync).toHaveBeenCalledWith(__filename) + expect(atom.showSaveDialogSync).toHaveBeenCalledWith(defaultPath: __filename) expect(pane.getActiveItem().saveAs).toHaveBeenCalledWith('/selected/path') describe "when the current item does not have a saveAs method", -> diff --git a/src/atom.coffee b/src/atom.coffee index 0d029b61d..dde0960ab 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -783,11 +783,12 @@ class Atom extends Model showSaveDialog: (callback) -> callback(showSaveDialogSync()) - showSaveDialogSync: (defaultPath) -> - defaultPath ?= @project?.getPaths()[0] + showSaveDialogSync: (options={}) -> currentWindow = @getCurrentWindow() dialog = remote.require('dialog') - dialog.showSaveDialog currentWindow, {title: 'Save File', defaultPath} + options.title ?= 'Save File' + options.defaultPath ?= @project?.getPaths()[0] + dialog.showSaveDialog currentWindow, options saveSync: -> if storageKey = @constructor.getStateKey(@project?.getPaths(), @mode) diff --git a/src/pane.coffee b/src/pane.coffee index 38c8d9201..b38e6fa46 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -492,8 +492,9 @@ class Pane extends Model saveItemAs: (item, nextAction) -> return unless item?.saveAs? - itemPath = item.getPath?() - newItemPath = atom.showSaveDialogSync(itemPath) + saveOptions = item.getSaveOptions?() or {} + saveOptions.defaultPath ?= item.getPath() + newItemPath = atom.showSaveDialogSync(saveOptions) if newItemPath try item.saveAs(newItemPath) From 05e6d9e55d6b080f5eb66b04a334ce80888b9c26 Mon Sep 17 00:00:00 2001 From: Jesse Grosjean Date: Sat, 6 Jun 2015 22:22:47 -0400 Subject: [PATCH 1572/1783] Stop focusing specs on "Pane" --- spec/pane-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/pane-spec.coffee b/spec/pane-spec.coffee index 51bb07e8c..ba2f02802 100644 --- a/spec/pane-spec.coffee +++ b/spec/pane-spec.coffee @@ -3,7 +3,7 @@ Pane = require '../src/pane' PaneAxis = require '../src/pane-axis' PaneContainer = require '../src/pane-container' -fdescribe "Pane", -> +describe "Pane", -> deserializerDisposable = null class Item extends Model From 786f3399addeadf54ca1def408384256034efdb8 Mon Sep 17 00:00:00 2001 From: Devon Carew Date: Sat, 6 Jun 2015 22:17:14 -0700 Subject: [PATCH 1573/1783] Update text-editor.coffee Fix a type in `src/text-editor.coffee` (`adter` => `after`). --- 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 9a9262e50..977b94ed1 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -325,7 +325,7 @@ class TextEditor extends Model onWillInsertText: (callback) -> @emitter.on 'will-insert-text', callback - # Extended: Calls your `callback` adter text has been inserted. + # Extended: Calls your `callback` after text has been inserted. # # * `callback` {Function} # * `event` event {Object} From fbf58d072595e9e0178f12983423241bd1cf693e Mon Sep 17 00:00:00 2001 From: Thomas Johansen Date: Sun, 7 Jun 2015 09:30:02 +0200 Subject: [PATCH 1574/1783] :memo: Remove mention of WorkspaceView which no longer exists Fixes #7146 --- src/workspace.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/workspace.coffee b/src/workspace.coffee index 0285cf99d..157d002de 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -22,8 +22,8 @@ Task = require './task' # An instance of this class is available via the `atom.workspace` global. # # Interact with this object to open files, be notified of current and future -# editors, and manipulate panes. To add panels, you'll need to use the -# {WorkspaceView} class for now until we establish APIs at the model layer. +# editors, and manipulate panes. To add panels, use {Workspace::addTopPanel} +# and friends. # # * `editor` {TextEditor} the new editor # From 9d70aec316d4123c030a3134b98a10e87b0c6df9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Machist=C3=A9=20N=2E=20Quintana?= Date: Sun, 7 Jun 2015 10:49:25 -0400 Subject: [PATCH 1575/1783] Only use lsb-core instead of full lsb suite --- resources/linux/redhat/atom.spec.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/linux/redhat/atom.spec.in b/resources/linux/redhat/atom.spec.in index 2bd89cb9a..8ef886e31 100644 --- a/resources/linux/redhat/atom.spec.in +++ b/resources/linux/redhat/atom.spec.in @@ -7,7 +7,7 @@ URL: https://atom.io/ AutoReqProv: no # Avoid libchromiumcontent.so missing dependency Prefix: <%= installDir %> -Requires: lsb +Requires: lsb-core-noarch %description <%= description %> From ca72b802acbd2d7206d6e2278a55d5735f71a79e Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Sun, 7 Jun 2015 11:23:42 -0400 Subject: [PATCH 1576/1783] Enable "Downloading Update" context menu entry Previously 'update-downloaded' would get emitted right after 'update-available' which would suppress the "Downloading Update" menu entry --- src/browser/auto-updater-win32.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/browser/auto-updater-win32.coffee b/src/browser/auto-updater-win32.coffee index 89018a396..d1ed277e2 100644 --- a/src/browser/auto-updater-win32.coffee +++ b/src/browser/auto-updater-win32.coffee @@ -14,6 +14,8 @@ class AutoUpdater require('auto-updater').quitAndInstall() downloadUpdate: (callback) -> + @emit 'update-available' + SquirrelUpdate.spawn ['--download', @updateUrl], (error, stdout) -> return callback(error) if error? @@ -56,7 +58,6 @@ class AutoUpdater @emit 'update-not-available' return - @emit 'update-available' @emit 'update-downloaded', {}, update.releaseNotes, update.version, new Date(), 'https://atom.io', => @quitAndInstall() module.exports = new AutoUpdater() From 9e6e05a5a6c28eeb5d4e321d58a035beb6326e84 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Sun, 7 Jun 2015 11:33:26 -0400 Subject: [PATCH 1577/1783] Put 'update-available' in @downloadUpdate instead So that it only shows up when there's an actual update --- src/browser/auto-updater-win32.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/browser/auto-updater-win32.coffee b/src/browser/auto-updater-win32.coffee index d1ed277e2..4d043ac4e 100644 --- a/src/browser/auto-updater-win32.coffee +++ b/src/browser/auto-updater-win32.coffee @@ -14,8 +14,6 @@ class AutoUpdater require('auto-updater').quitAndInstall() downloadUpdate: (callback) -> - @emit 'update-available' - SquirrelUpdate.spawn ['--download', @updateUrl], (error, stdout) -> return callback(error) if error? @@ -53,6 +51,8 @@ class AutoUpdater @emit 'update-not-available' return + @emit 'update-available' + @installUpdate (error) => if error? @emit 'update-not-available' From 0db3b701772a5d1d11c2161c85f32166d0bff133 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Machist=C3=A9=20N=2E=20Quintana?= Date: Mon, 8 Jun 2015 10:59:34 -0400 Subject: [PATCH 1578/1783] :memo: Update Project::getRepositories() example --- src/project.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/project.coffee b/src/project.coffee index e2eed7ac5..c10ce4a3b 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -128,8 +128,8 @@ class Project extends Model # Prefer the following, which evaluates to a {Promise} that resolves to an # {Array} of {Repository} objects: # ``` - # Promise.all(project.getDirectories().map( - # project.repositoryForDirectory.bind(project))) + # Promise.all(atom.project.getDirectories().map( + # atom.project.repositoryForDirectory.bind(atom.project))) # ``` getRepositories: -> @repositories From 02c8cd682d7f1cf78821eaed49856014b298d0d1 Mon Sep 17 00:00:00 2001 From: atrotors Date: Tue, 9 Jun 2015 01:00:45 +1000 Subject: [PATCH 1579/1783] fixed missing icon when building from source --- build/tasks/generate-asar-task.coffee | 1 + build/tasks/install-task.coffee | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/build/tasks/generate-asar-task.coffee b/build/tasks/generate-asar-task.coffee index 3de5f73b6..bb00c6b0f 100644 --- a/build/tasks/generate-asar-task.coffee +++ b/build/tasks/generate-asar-task.coffee @@ -15,6 +15,7 @@ module.exports = (grunt) -> 'ctags-linux' 'ctags-win32.exe' '**/node_modules/spellchecker/**' + 'atom.png' ] unpack = "{#{unpack.join(',')}}" diff --git a/build/tasks/install-task.coffee b/build/tasks/install-task.coffee index 71d3c4ae8..8db654941 100644 --- a/build/tasks/install-task.coffee +++ b/build/tasks/install-task.coffee @@ -46,7 +46,7 @@ module.exports = (grunt) -> desktopInstallFile = path.join(installDir, 'share', 'applications', 'atom.desktop') {description} = grunt.file.readJSON('package.json') - iconName = path.join(shareDir, 'resources', 'app', 'resources', 'atom.png') + iconName = path.join(shareDir, 'resources', 'app.asar.unpacked', 'resources', 'atom.png') executable = path.join(shareDir, 'atom') template = _.template(String(fs.readFileSync(desktopFile))) filled = template({description, iconName, executable}) From 06b30b7d02a2493f21be3496dfe3669e3a0f3ff3 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 8 Jun 2015 18:03:06 +0200 Subject: [PATCH 1580/1783] :arrow_up: text-buffer Fixes #6899 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4e082676a..5aa732adf 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "space-pen": "3.8.2", "stacktrace-parser": "0.1.1", "temp": "0.8.1", - "text-buffer": "6.3.0", + "text-buffer": "6.3.1", "theorist": "^1.0.2", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", From d986cda5220c804eea2b979d2d18dd8a7d8c61f3 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 8 Jun 2015 09:06:28 -0700 Subject: [PATCH 1581/1783] :arrow_up: language-javscript@0.79 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5aa732adf..d747b77dd 100644 --- a/package.json +++ b/package.json @@ -138,7 +138,7 @@ "language-html": "0.39.0", "language-hyperlink": "0.13.0", "language-java": "0.15.0", - "language-javascript": "0.78.0", + "language-javascript": "0.79.0", "language-json": "0.15.0", "language-less": "0.27.0", "language-make": "0.14.0", From 0cb79a24cf097ac0417a16ab35b388217bf69368 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 8 Jun 2015 09:10:35 -0700 Subject: [PATCH 1582/1783] :arrow_up: archive-view@0.58 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d747b77dd..a4a56ce99 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ "one-light-ui": "0.9.0", "solarized-dark-syntax": "0.35.0", "solarized-light-syntax": "0.21.0", - "archive-view": "0.57.0", + "archive-view": "0.58.0", "autocomplete-atom-api": "0.9.0", "autocomplete-css": "0.7.2", "autocomplete-html": "0.7.2", From 39117956877f63d7c6c1893c71d841624cc5f4ef Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 8 Jun 2015 09:29:35 -0700 Subject: [PATCH 1583/1783] :arrow_up: whitespace@0.30 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a4a56ce99..bc3ab4953 100644 --- a/package.json +++ b/package.json @@ -125,7 +125,7 @@ "tree-view": "0.171.0", "update-package-dependencies": "0.10.0", "welcome": "0.27.0", - "whitespace": "0.29.0", + "whitespace": "0.30.0", "wrap-guide": "0.35.0", "language-c": "0.45.0", "language-clojure": "0.15.0", From f96def7b7aadcb67a4f7ac71ef93bc103b27f4d1 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 8 Jun 2015 09:40:05 -0700 Subject: [PATCH 1584/1783] :arrow_up: release-notes@0.53 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bc3ab4953..e95667c7c 100644 --- a/package.json +++ b/package.json @@ -113,7 +113,7 @@ "notifications": "0.52.0", "open-on-github": "0.37.0", "package-generator": "0.39.0", - "release-notes": "0.52.0", + "release-notes": "0.53.0", "settings-view": "0.208.0", "snippets": "0.93.0", "spell-check": "0.59.0", From cec6959e0867cc2b070e13b72534c8e8c87d0b2c Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 8 Jun 2015 18:58:04 +0200 Subject: [PATCH 1585/1783] Extend highlights to the full editor width --- spec/text-editor-component-spec.coffee | 4 +++- src/lines-component.coffee | 6 +++--- src/text-editor-presenter.coffee | 1 + src/tile-component.coffee | 16 +++++++--------- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 264ff9b11..6749e7803 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -246,8 +246,10 @@ describe "TextEditorComponent", -> # lines caused full-screen repaints after switching away from an editor # and back again Please ensure you don't cause a performance regression if # you change this behavior. + editorFullWidth = editor.getScrollWidth() + editor.getVerticalScrollbarWidth() + for lineNode in lineNodes - expect(lineNode.style.width).toBe editor.getScrollWidth() + 'px' + expect(lineNode.style.width).toBe editorFullWidth + 'px' componentNode.style.width = gutterWidth + editor.getScrollWidth() + 100 + 'px' component.measureDimensions() diff --git a/src/lines-component.coffee b/src/lines-component.coffee index bac1c9616..f8b6579a5 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -54,14 +54,14 @@ class LinesComponent @removeTileNodes() unless @oldState.indentGuidesVisible is @newState.indentGuidesVisible @updateTileNodes() - if @newState.scrollWidth isnt @oldState.scrollWidth - @domNode.style.width = @newState.scrollWidth + 'px' - @oldState.scrollWidth = @newState.scrollWidth + if @newState.width isnt @oldState.width + @domNode.style.width = @newState.width + 'px' @cursorsComponent.updateSync(state) @oldState.indentGuidesVisible = @newState.indentGuidesVisible @oldState.scrollWidth = @newState.scrollWidth + @oldState.width = @newState.width removeTileNodes: -> @removeTileNode(id) for id of @oldState.tiles diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 3149faf56..0e7e448fa 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -307,6 +307,7 @@ class TextEditorPresenter @state.hiddenInput.width = Math.max(width, 2) updateContentState: -> + @state.content.width = Math.max(@contentWidth + @verticalScrollbarWidth, @contentFrameWidth) @state.content.scrollWidth = @scrollWidth @state.content.scrollLeft = @scrollLeft @state.content.indentGuidesVisible = not @model.isMini() and @showIndentGuide diff --git a/src/tile-component.coffee b/src/tile-component.coffee index 9ceca8e54..99dfc6ced 100644 --- a/src/tile-component.coffee +++ b/src/tile-component.coffee @@ -52,6 +52,9 @@ class TileComponent @domNode.style.height = @newTileState.height + 'px' @oldTileState.height = @newTileState.height + if @newState.width isnt @oldState.width + @domNode.style.width = @newState.width + 'px' + if @newTileState.top isnt @oldTileState.top or @newTileState.left isnt @oldTileState.left @domNode.style['-webkit-transform'] = "translate3d(#{@newTileState.left}px, #{@newTileState.top}px, 0px)" @oldTileState.top = @newTileState.top @@ -60,14 +63,9 @@ class TileComponent @removeLineNodes() unless @oldState.indentGuidesVisible is @newState.indentGuidesVisible @updateLineNodes() - if @newState.scrollWidth isnt @oldState.scrollWidth - @domNode.style.width = @newState.scrollWidth + 'px' - @oldState.scrollWidth = @newState.scrollWidth - @highlightsComponent.updateSync(@newTileState) @oldState.indentGuidesVisible = @newState.indentGuidesVisible - @oldState.scrollWidth = @newState.scrollWidth removeLineNodes: -> @removeLineNode(id) for id of @oldTileState.lines @@ -112,7 +110,7 @@ class TileComponent return buildLineHTML: (id) -> - {scrollWidth} = @newState + {width} = @newState {screenRow, tokens, text, top, lineEnding, fold, isSoftWrapped, indentLevel, decorationClasses} = @newTileState.lines[id] classes = '' @@ -121,7 +119,7 @@ class TileComponent classes += decorationClass + ' ' classes += 'line' - lineHTML = "
" + lineHTML = "
" if text is "" lineHTML += @buildEmptyLineInnerHTML(id) @@ -281,8 +279,8 @@ class TileComponent lineNode = @lineNodesByLineId[id] - if @newState.scrollWidth isnt @oldState.scrollWidth - lineNode.style.width = @newState.scrollWidth + 'px' + if @newState.width isnt @oldState.width + lineNode.style.width = @newState.width + 'px' newDecorationClasses = newLineState.decorationClasses oldDecorationClasses = oldLineState.decorationClasses From fccaa9791c1e7912ed6d3bc5710f1a4a3a3aea48 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 8 Jun 2015 10:03:46 -0700 Subject: [PATCH 1586/1783] :arrow_up: welcome@0.28 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e95667c7c..74ec09cae 100644 --- a/package.json +++ b/package.json @@ -124,7 +124,7 @@ "timecop": "0.31.0", "tree-view": "0.171.0", "update-package-dependencies": "0.10.0", - "welcome": "0.27.0", + "welcome": "0.28.0", "whitespace": "0.30.0", "wrap-guide": "0.35.0", "language-c": "0.45.0", From 53b537737ff3b7fde859a20ad1e43f72209e57b3 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 8 Jun 2015 10:05:56 -0700 Subject: [PATCH 1587/1783] :arrow_up: language-ruby-on-rails@0.22 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 74ec09cae..4c88a7b99 100644 --- a/package.json +++ b/package.json @@ -149,7 +149,7 @@ "language-property-list": "0.8.0", "language-python": "0.35.0", "language-ruby": "0.56.0", - "language-ruby-on-rails": "0.21.0", + "language-ruby-on-rails": "0.22.0", "language-sass": "0.38.0", "language-shellscript": "0.15.0", "language-source": "0.9.0", From 82e37cc64fcdcac5fb0a9ca837db101e6c220a2e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 8 Jun 2015 10:09:44 -0700 Subject: [PATCH 1588/1783] :arrow_up: bracket-matcher@0.76 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4c88a7b99..99c70aa4a 100644 --- a/package.json +++ b/package.json @@ -93,7 +93,7 @@ "autosave": "0.20.0", "background-tips": "0.25.0", "bookmarks": "0.35.0", - "bracket-matcher": "0.75.0", + "bracket-matcher": "0.76.0", "command-palette": "0.36.0", "deprecation-cop": "0.52.0", "dev-live-reload": "0.46.0", From e19dec5adcd248c41f6cd815680da1c29fe047c2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 8 Jun 2015 10:22:40 -0700 Subject: [PATCH 1589/1783] :arrow_up: autoflow@0.25 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 99c70aa4a..45107389a 100644 --- a/package.json +++ b/package.json @@ -89,7 +89,7 @@ "autocomplete-html": "0.7.2", "autocomplete-plus": "2.17.3", "autocomplete-snippets": "1.7.0", - "autoflow": "0.24.0", + "autoflow": "0.25.0", "autosave": "0.20.0", "background-tips": "0.25.0", "bookmarks": "0.35.0", From 1877e10b9c722f2734ac8ddf0266dd263fb26fb8 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 8 Jun 2015 11:13:48 -0700 Subject: [PATCH 1590/1783] :arrow_up: language-python@0.36 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 45107389a..d15854cef 100644 --- a/package.json +++ b/package.json @@ -147,7 +147,7 @@ "language-perl": "0.24.0", "language-php": "0.24.0", "language-property-list": "0.8.0", - "language-python": "0.35.0", + "language-python": "0.36.0", "language-ruby": "0.56.0", "language-ruby-on-rails": "0.22.0", "language-sass": "0.38.0", From 678820df220de457ebf6235d958146186c4868a8 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 8 Jun 2015 12:30:50 -0700 Subject: [PATCH 1591/1783] :arrow_up: symbols-view@0.98 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d15854cef..63d0d5082 100644 --- a/package.json +++ b/package.json @@ -119,7 +119,7 @@ "spell-check": "0.59.0", "status-bar": "0.74.0", "styleguide": "0.44.0", - "symbols-view": "0.97.0", + "symbols-view": "0.98.0", "tabs": "0.73.0", "timecop": "0.31.0", "tree-view": "0.171.0", From 21176f3cdc83809324e61902ed47e1920fd253d9 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 8 Jun 2015 12:47:28 -0700 Subject: [PATCH 1592/1783] :arrow_up: tree-view@0.172 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 63d0d5082..22d83da0a 100644 --- a/package.json +++ b/package.json @@ -122,7 +122,7 @@ "symbols-view": "0.98.0", "tabs": "0.73.0", "timecop": "0.31.0", - "tree-view": "0.171.0", + "tree-view": "0.172.0", "update-package-dependencies": "0.10.0", "welcome": "0.28.0", "whitespace": "0.30.0", From 656c91beb455f788adfb1006ffc041b4aabca9e6 Mon Sep 17 00:00:00 2001 From: Jesse Grosjean Date: Mon, 8 Jun 2015 16:19:39 -0400 Subject: [PATCH 1593/1783] Preserve previous API behavior --- src/atom.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/atom.coffee b/src/atom.coffee index dde0960ab..8903a9cef 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -784,6 +784,8 @@ class Atom extends Model callback(showSaveDialogSync()) showSaveDialogSync: (options={}) -> + if _.isString(options) + options = defaultPath: options currentWindow = @getCurrentWindow() dialog = remote.require('dialog') options.title ?= 'Save File' From 1dbfd0b5ac2379160ec73db301546556c2534c83 Mon Sep 17 00:00:00 2001 From: Jesse Grosjean Date: Mon, 8 Jun 2015 16:20:53 -0400 Subject: [PATCH 1594/1783] Rename to getSaveDialogOptions and document in TextEditor --- src/pane.coffee | 2 +- src/text-editor.coffee | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/pane.coffee b/src/pane.coffee index b38e6fa46..477239bdd 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -492,7 +492,7 @@ class Pane extends Model saveItemAs: (item, nextAction) -> return unless item?.saveAs? - saveOptions = item.getSaveOptions?() or {} + saveOptions = item.getSaveDialogOptions?() ? {} saveOptions.defaultPath ?= item.getPath() newItemPath = atom.showSaveDialogSync(saveOptions) if newItemPath diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 9a9262e50..99e6f27cc 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -593,6 +593,16 @@ class TextEditor extends Model # Essential: Returns the {String} path of this editor's text buffer. getPath: -> @buffer.getPath() + # Private: Return [save options](http://electron.atom.io/docs/v0.27.0/api/di + # alog/#dialog.showsavedialog(%5Bbrowserwindow%5D,-%5Boptions%5D,-%5Bcallbac + # k%5D)) to be used when displaying the save dialog. + # + # Default empty options are returned now. In the future this would be the + # place to start implementing things like: https://discuss.atom.io/t + # /request-saving- file-with-correct-extension/17521 + getSaveDialogOptions: -> + {} + # Extended: Returns the {String} character set encoding of this editor's text # buffer. getEncoding: -> @buffer.getEncoding() From 36d55c93849950eebd568a798b0976336f3c2fc2 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 8 Jun 2015 22:56:18 +0200 Subject: [PATCH 1595/1783] =?UTF-8?q?Don=E2=80=99t=20break=20out=20soft=20?= =?UTF-8?q?tabs=20that=20are=20interrupted=20by=20a=20scope=20boundary?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spec/tokenized-buffer-spec.coffee | 16 ++++++++++++++++ src/tokenized-line.coffee | 7 ++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/spec/tokenized-buffer-spec.coffee b/spec/tokenized-buffer-spec.coffee index dc57d3fee..23520518a 100644 --- a/spec/tokenized-buffer-spec.coffee +++ b/spec/tokenized-buffer-spec.coffee @@ -322,6 +322,22 @@ describe "TokenizedBuffer", -> expect(tokens[2].value).toBe " \u030b" expect(tokens[2].hasLeadingWhitespace()).toBe false + it "does not break out soft tabs across a scope boundary", -> + waitsForPromise -> + atom.packages.activatePackage('language-gfm') + + runs -> + tokenizedBuffer.setTabLength(4) + tokenizedBuffer.setGrammar(atom.grammars.selectGrammar('.md')) + buffer.setText(' 0 + + expect(length).toBe 4 + describe "when the buffer contains hard-tabs", -> beforeEach -> waitsForPromise -> diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index b8f7226c8..bd871fc4f 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -102,10 +102,11 @@ class TokenizedLine substringEnd += 1 else if (screenColumn + 1) % @tabLength is 0 - @specialTokens[tokenIndex] = SoftTab suffix = @tags[tokenIndex] - @tabLength - @tags.splice(tokenIndex, 1, @tabLength) - @tags.splice(tokenIndex + 1, 0, suffix) if suffix > 0 + if suffix >= 0 + @specialTokens[tokenIndex] = SoftTab + @tags.splice(tokenIndex, 1, @tabLength) + @tags.splice(tokenIndex + 1, 0, suffix) if suffix > 0 if @invisibles?.space if substringEnd > substringStart From af85ee701a3ecc2248ff394947efd22de28ec2ee Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 8 Jun 2015 14:34:12 -0700 Subject: [PATCH 1596/1783] :arrow_up: tabs@0.74 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 22d83da0a..fee22497f 100644 --- a/package.json +++ b/package.json @@ -120,7 +120,7 @@ "status-bar": "0.74.0", "styleguide": "0.44.0", "symbols-view": "0.98.0", - "tabs": "0.73.0", + "tabs": "0.74.0", "timecop": "0.31.0", "tree-view": "0.172.0", "update-package-dependencies": "0.10.0", From cdd4e496ccbc65b906de403331387a66454f264d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 8 Jun 2015 14:37:19 -0700 Subject: [PATCH 1597/1783] :arrow_up: language-html@0.40 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fee22497f..fd454c6f0 100644 --- a/package.json +++ b/package.json @@ -135,7 +135,7 @@ "language-gfm": "0.77.0", "language-git": "0.10.0", "language-go": "0.26.0", - "language-html": "0.39.0", + "language-html": "0.40.0", "language-hyperlink": "0.13.0", "language-java": "0.15.0", "language-javascript": "0.79.0", From 39dce7ae3ce832d66983c17537ed304d39f2bb1a Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 8 Jun 2015 23:57:44 +0200 Subject: [PATCH 1598/1783] :arrow_up: text-buffer --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fd454c6f0..cb58a4375 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "space-pen": "3.8.2", "stacktrace-parser": "0.1.1", "temp": "0.8.1", - "text-buffer": "6.3.1", + "text-buffer": "6.3.2", "theorist": "^1.0.2", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", From 5c57cb0cfe2c5e3337e9fd870a603a1afde52748 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 8 Jun 2015 23:50:27 +0200 Subject: [PATCH 1599/1783] Show a warning prompt when opening files over 20MB We still have some trouble on files this large. I want to show a progress bar, but for now this is better than freezing without any warning at all. --- spec/workspace-spec.coffee | 26 +++++++++++++++++++++++++- src/project.coffee | 23 ++++++++++++++++++----- src/workspace.coffee | 7 ++++--- 3 files changed, 47 insertions(+), 9 deletions(-) diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index 4918fc65f..7dfee3c1a 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -224,7 +224,7 @@ describe "Workspace", -> expect(workspace.paneContainer.root.children[0]).toBe pane1 expect(workspace.paneContainer.root.children[1]).toBe pane4 - describe "when the file is large (over 2mb)", -> + describe "when the file is over 2MB", -> it "opens the editor with largeFileMode: true", -> spyOn(fs, 'getSizeSync').andReturn 2 * 1048577 # 2MB @@ -235,6 +235,30 @@ describe "Workspace", -> runs -> expect(editor.displayBuffer.largeFileMode).toBe true + describe "when the file is over 20MB", -> + it "prompts the user to make sure they want to open a file this big", -> + spyOn(fs, 'getSizeSync').andReturn 20 * 1048577 # 20MB + spyOn(atom, 'confirm').andCallFake -> selectedButtonIndex + selectedButtonIndex = 1 # cancel + + editor = null + waitsForPromise -> + workspace.open('sample.js').then (e) -> editor = e + + runs -> + expect(editor).toBeUndefined() + expect(atom.confirm).toHaveBeenCalled() + + atom.confirm.reset() + selectedButtonIndex = 0 # open the file + + waitsForPromise -> + workspace.open('sample.js').then (e) -> editor = e + + runs -> + expect(atom.confirm).toHaveBeenCalled() + expect(editor.displayBuffer.largeFileMode).toBe true + describe "when passed a path that matches a custom opener", -> it "returns the resource returned by the custom opener", -> fooOpener = (pathToOpen, options) -> {foo: pathToOpen, options} if pathToOpen?.match(/\.foo/) diff --git a/src/project.coffee b/src/project.coffee index c10ce4a3b..e2079b22f 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -323,8 +323,22 @@ class Project extends Model # allow ENOENT errors to create an editor for paths that dont exist throw error unless error.code is 'ENOENT' - @bufferForPath(filePath).then (buffer) => - @buildEditorForBuffer(buffer, options) + absoluteFilePath = @resolvePath(filePath) + + fileSize = fs.getSizeSync(absoluteFilePath) + + if fileSize >= 20 * 1048576 # 20MB + choice = atom.confirm + message: 'Atom can have issues with files over 20MB.' + detailedMessage: "Do you still want to try to load this?" + buttons: ["Open", "Cancel"] + if choice is 1 + error = new Error + error.code = 'CANCELLED' + throw error + + @bufferForPath(absoluteFilePath).then (buffer) => + @buildEditorForBuffer(buffer, _.extend({fileSize}, options)) # Retrieves all the {TextBuffer}s in the project; that is, the # buffers for all open files. @@ -354,8 +368,7 @@ class Project extends Model # * `filePath` A {String} representing a path. If `null`, an "Untitled" buffer is created. # # Returns a promise that resolves to the {TextBuffer}. - bufferForPath: (filePath) -> - absoluteFilePath = @resolvePath(filePath) + bufferForPath: (absoluteFilePath) -> existingBuffer = @findBufferForPath(absoluteFilePath) if absoluteFilePath Q(existingBuffer ? @buildBuffer(absoluteFilePath)) @@ -405,7 +418,7 @@ class Project extends Model buffer?.destroy() buildEditorForBuffer: (buffer, editorOptions) -> - largeFileMode = fs.getSizeSync(buffer.getPath()) >= 2 * 1048576 # 2MB + largeFileMode = editorOptions.fileSize >= 2 * 1048576 # 2MB editor = new TextEditor(_.extend({buffer, largeFileMode, registerEditor: true}, editorOptions)) editor diff --git a/src/workspace.coffee b/src/workspace.coffee index 157d002de..c399250d6 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -429,15 +429,16 @@ class Workspace extends Model item ?= atom.project.open(uri, options) catch error switch error.code - when 'EFILETOOLARGE' - atom.notifications.addWarning("#{error.message} Large file support is being tracked at [atom/atom#307](https://github.com/atom/atom/issues/307).") + when 'CANCELLED' + return Q() when 'EACCES' atom.notifications.addWarning("Permission denied '#{error.path}'") + return Q() when 'EPERM', 'EBUSY' atom.notifications.addWarning("Unable to open '#{error.path}'", detail: error.message) + return Q() else throw error - return Q() Q(item) .then (item) => From 2893772d1a5df8b6ea394e14ebb8eab637cb731b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 8 Jun 2015 15:32:03 -0700 Subject: [PATCH 1600/1783] Add stricter atom.png glob pattern --- build/tasks/generate-asar-task.coffee | 2 +- build/tasks/install-task.coffee | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/build/tasks/generate-asar-task.coffee b/build/tasks/generate-asar-task.coffee index bb00c6b0f..800721fee 100644 --- a/build/tasks/generate-asar-task.coffee +++ b/build/tasks/generate-asar-task.coffee @@ -15,7 +15,7 @@ module.exports = (grunt) -> 'ctags-linux' 'ctags-win32.exe' '**/node_modules/spellchecker/**' - 'atom.png' + '**/resources/atom.png' ] unpack = "{#{unpack.join(',')}}" diff --git a/build/tasks/install-task.coffee b/build/tasks/install-task.coffee index 8db654941..86a827a1b 100644 --- a/build/tasks/install-task.coffee +++ b/build/tasks/install-task.coffee @@ -31,8 +31,6 @@ module.exports = (grunt) -> binDir = path.join(installDir, 'bin') shareDir = path.join(installDir, 'share', 'atom') - iconName = path.join(shareDir, 'resources', 'app', 'resources', 'atom.png') - mkdir binDir cp 'atom.sh', path.join(binDir, 'atom') rm shareDir From 6859a2924aabb9bc8c83420d1db24d93fafa4dbc Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 8 Jun 2015 15:35:22 -0700 Subject: [PATCH 1601/1783] Keep upgrading deprecated selectors until 1.0 --- src/styles-element.coffee | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/styles-element.coffee b/src/styles-element.coffee index 74ebd23ba..fc3b888cf 100644 --- a/src/styles-element.coffee +++ b/src/styles-element.coffee @@ -1,5 +1,4 @@ {Emitter, CompositeDisposable} = require 'event-kit' -{includeDeprecatedAPIs} = require 'grim' class StylesElement extends HTMLElement subscriptions: null @@ -19,7 +18,7 @@ class StylesElement extends HTMLElement @styleElementClonesByOriginalElement = new WeakMap attachedCallback: -> - if includeDeprecatedAPIs and @context is 'atom-text-editor' + if @context is 'atom-text-editor' for styleElement in @children @upgradeDeprecatedSelectors(styleElement) @initialize() @@ -67,7 +66,7 @@ class StylesElement extends HTMLElement @insertBefore(styleElementClone, insertBefore) - if includeDeprecatedAPIs and @context is 'atom-text-editor' + if @context is 'atom-text-editor' @upgradeDeprecatedSelectors(styleElementClone) @emitter.emit 'did-add-style-element', styleElementClone From 609fc6cb6e2d63e988088b37afb7a953d7921eee Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 8 Jun 2015 15:54:24 -0700 Subject: [PATCH 1602/1783] :arrow_up: tabs@0.75 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cb58a4375..d6930ab69 100644 --- a/package.json +++ b/package.json @@ -120,7 +120,7 @@ "status-bar": "0.74.0", "styleguide": "0.44.0", "symbols-view": "0.98.0", - "tabs": "0.74.0", + "tabs": "0.75.0", "timecop": "0.31.0", "tree-view": "0.172.0", "update-package-dependencies": "0.10.0", From c370263e27163895e0cda611545f1940168b8e4f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 8 Jun 2015 15:58:48 -0700 Subject: [PATCH 1603/1783] :arrow_up: language-perl@0.25 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d6930ab69..cd76a7853 100644 --- a/package.json +++ b/package.json @@ -144,7 +144,7 @@ "language-make": "0.14.0", "language-mustache": "0.11.0", "language-objective-c": "0.15.0", - "language-perl": "0.24.0", + "language-perl": "0.25.0", "language-php": "0.24.0", "language-property-list": "0.8.0", "language-python": "0.36.0", From 66d40858dc226b31e9178efc1ba47cb3ae79d039 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 8 Jun 2015 16:41:50 -0700 Subject: [PATCH 1604/1783] :arrow_up: tabs@0.76 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cd76a7853..b1ec1ed1c 100644 --- a/package.json +++ b/package.json @@ -120,7 +120,7 @@ "status-bar": "0.74.0", "styleguide": "0.44.0", "symbols-view": "0.98.0", - "tabs": "0.75.0", + "tabs": "0.76.0", "timecop": "0.31.0", "tree-view": "0.172.0", "update-package-dependencies": "0.10.0", From f92e224db769206113c8d75b1729a58f64b986d8 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 8 Jun 2015 16:51:41 -0700 Subject: [PATCH 1605/1783] :arrow_up: language-javascript@0.80 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b1ec1ed1c..e8bf3233f 100644 --- a/package.json +++ b/package.json @@ -138,7 +138,7 @@ "language-html": "0.40.0", "language-hyperlink": "0.13.0", "language-java": "0.15.0", - "language-javascript": "0.79.0", + "language-javascript": "0.80.0", "language-json": "0.15.0", "language-less": "0.27.0", "language-make": "0.14.0", From 6a007a7061480009ad8a11a79f384bcf6662a3d8 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 8 Jun 2015 16:52:51 -0700 Subject: [PATCH 1606/1783] :arrow_up: language-coffee-script@0.41 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e8bf3233f..9f982b91b 100644 --- a/package.json +++ b/package.json @@ -129,7 +129,7 @@ "wrap-guide": "0.35.0", "language-c": "0.45.0", "language-clojure": "0.15.0", - "language-coffee-script": "0.40.0", + "language-coffee-script": "0.41.0", "language-csharp": "0.5.0", "language-css": "0.30.0", "language-gfm": "0.77.0", From c06d62e607411e4e42c451daf98aa54106f8477e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 8 Jun 2015 17:26:59 -0700 Subject: [PATCH 1607/1783] :arrow_up: snippets@0.94 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9f982b91b..c331fb413 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,7 @@ "package-generator": "0.39.0", "release-notes": "0.53.0", "settings-view": "0.208.0", - "snippets": "0.93.0", + "snippets": "0.94.0", "spell-check": "0.59.0", "status-bar": "0.74.0", "styleguide": "0.44.0", From 6cdc555a9343f265f1b6e1a376266bd065fb3cc1 Mon Sep 17 00:00:00 2001 From: Jesse Grosjean Date: Mon, 8 Jun 2015 20:40:15 -0400 Subject: [PATCH 1608/1783] Clone options parameter before modifying it. --- src/atom.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/atom.coffee b/src/atom.coffee index 8903a9cef..ddc2e024d 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -786,6 +786,8 @@ class Atom extends Model showSaveDialogSync: (options={}) -> if _.isString(options) options = defaultPath: options + else + options = _.clone(options) currentWindow = @getCurrentWindow() dialog = remote.require('dialog') options.title ?= 'Save File' From 50f4fe5b6c650d27cc3c91da8843c76615bbbcb3 Mon Sep 17 00:00:00 2001 From: Nikhil Narula Date: Mon, 8 Jun 2015 20:38:23 -0400 Subject: [PATCH 1609/1783] Correct isMaximixed misspelling to isMaximized --- src/atom.coffee | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/atom.coffee b/src/atom.coffee index 0d029b61d..c3fff388d 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -472,9 +472,13 @@ class Atom extends Model ipc.send('call-window-method', 'restart') # Extended: Returns a {Boolean} true when the current window is maximized. - isMaximixed: -> + isMaximized: -> @getCurrentWindow().isMaximized() + isMaximixed: -> + deprecate "Use atom.isMaximized() instead" + @isMaximized() + maximize: -> ipc.send('call-window-method', 'maximize') From 0f876a73cc07e3aefea367d32e3ccef0c4d09d4b Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Mon, 8 Jun 2015 20:45:41 -0400 Subject: [PATCH 1610/1783] Only use package directory name as fallback Fixes https://github.com/atom/atom/issues/7174 --- src/package.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/package.coffee b/src/package.coffee index b404f99e8..02c1f49fb 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -43,9 +43,9 @@ class Package @normalizeMetadata(metadata) catch error throw error unless ignoreErrors - - metadata ?= {} - metadata.name = packageName + else + metadata ?= {} + metadata.name = packageName if includeDeprecatedAPIs and metadata.stylesheetMain? deprecate("Use the `mainStyleSheet` key instead of `stylesheetMain` in the `package.json` of `#{packageName}`", {packageName}) From 659ddb67ad93bcf1ea65f9f1426cdbb937796211 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Mon, 8 Jun 2015 20:57:35 -0400 Subject: [PATCH 1611/1783] Add Package.loadMetadata() specs --- .../package-with-different-directory-name/package.json | 4 ++++ spec/package-spec.coffee | 10 ++++++++++ 2 files changed, 14 insertions(+) create mode 100644 spec/fixtures/packages/package-with-different-directory-name/package.json diff --git a/spec/fixtures/packages/package-with-different-directory-name/package.json b/spec/fixtures/packages/package-with-different-directory-name/package.json new file mode 100644 index 000000000..079d0dfb2 --- /dev/null +++ b/spec/fixtures/packages/package-with-different-directory-name/package.json @@ -0,0 +1,4 @@ +{ + "name": "package-with-a-totally-different-name", + "version": "1.0.0" +} diff --git a/spec/package-spec.coffee b/spec/package-spec.coffee index 87d243ce2..9ea000ab9 100644 --- a/spec/package-spec.coffee +++ b/spec/package-spec.coffee @@ -105,3 +105,13 @@ describe "Package", -> theme.onDidDeactivate spy = jasmine.createSpy() theme.deactivate() expect(spy).toHaveBeenCalled() + + describe ".loadMetadata()", -> + [packagePath, pack, metadata] = [] + + beforeEach -> + packagePath = atom.project.getDirectories()[0]?.resolve('packages/package-with-different-directory-name') + metadata = Package.loadMetadata(packagePath, true) + + it "uses the package name defined in package.json", -> + expect(metadata.name).toBe 'package-with-a-totally-different-name' From d78bc3f234f2a80c5d8b71b894b836b6bf01e6f8 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Mon, 8 Jun 2015 21:14:11 -0400 Subject: [PATCH 1612/1783] :art: --- src/package.coffee | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/package.coffee b/src/package.coffee index 02c1f49fb..fa031d84b 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -44,8 +44,7 @@ class Package catch error throw error unless ignoreErrors else - metadata ?= {} - metadata.name = packageName + metadata.name ?= packageName if includeDeprecatedAPIs and metadata.stylesheetMain? deprecate("Use the `mainStyleSheet` key instead of `stylesheetMain` in the `package.json` of `#{packageName}`", {packageName}) From 07da68c95e2beebeeafae5ee8b51bf4a3f496ebd Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Mon, 8 Jun 2015 21:18:21 -0400 Subject: [PATCH 1613/1783] Don't reassign metadata.name --- src/package.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/package.coffee b/src/package.coffee index fa031d84b..d5fd6ac20 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -43,8 +43,8 @@ class Package @normalizeMetadata(metadata) catch error throw error unless ignoreErrors - else - metadata.name ?= packageName + + metadata.name ?= packageName if includeDeprecatedAPIs and metadata.stylesheetMain? deprecate("Use the `mainStyleSheet` key instead of `stylesheetMain` in the `package.json` of `#{packageName}`", {packageName}) From f9c612d1c8275398525f10f241afb763722aa998 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Mon, 8 Jun 2015 21:33:07 -0400 Subject: [PATCH 1614/1783] Use an empty object if metadata is ~null --- src/package.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/package.coffee b/src/package.coffee index d5fd6ac20..2019f0731 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -44,6 +44,7 @@ class Package catch error throw error unless ignoreErrors + metadata ?= {} metadata.name ?= packageName if includeDeprecatedAPIs and metadata.stylesheetMain? From 384b88eecf6aae287f9a7a5c79a1f52dd0755494 Mon Sep 17 00:00:00 2001 From: Roy Martin Date: Tue, 9 Jun 2015 01:06:45 -0700 Subject: [PATCH 1615/1783] Fix inconsistency with pane resize cursors. --- static/panes.less | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/static/panes.less b/static/panes.less index 163721fcc..1d6d268d8 100644 --- a/static/panes.less +++ b/static/panes.less @@ -25,7 +25,7 @@ atom-pane-container { width: 100%; height: 8px; margin-top: -4px; - cursor: ns-resize; + cursor: row-resize; border-bottom: none; } } @@ -37,7 +37,7 @@ atom-pane-container { width: 8px; height: 100%; margin-left: -4px; - cursor: ew-resize; + cursor: col-resize; border-right: none; } } From 7781e34ba28eb3981363d8420a6cb2fcb9d13968 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Fri, 29 May 2015 11:27:00 -0700 Subject: [PATCH 1616/1783] Introduce atom.directory-searcher service v0.1.0. The contract for a provider for the `atom.directory-searcher` service is defined by the spec of the `DefaultDirectorySearcher`. This modifies `Workspace::scan()` to use the appropriate `DirectorySearcher` for each member of `atom.project.getDirectories()` when scanning the workspace for files that match the specified regex. --- spec/task-spec.coffee | 26 ++++++++ spec/workspace-spec.coffee | 70 +++++++++++++++++++ src/default-directory-searcher.coffee | 61 +++++++++++++++++ src/task.coffee | 10 ++- src/workspace.coffee | 96 ++++++++++++++++++++++----- 5 files changed, 245 insertions(+), 18 deletions(-) create mode 100644 src/default-directory-searcher.coffee diff --git a/spec/task-spec.coffee b/spec/task-spec.coffee index bddb59d86..947db5567 100644 --- a/spec/task-spec.coffee +++ b/spec/task-spec.coffee @@ -70,3 +70,29 @@ describe "Task", -> task.terminate() expect(stdout.listeners('data').length).toBe 0 expect(stderr.listeners('data').length).toBe 0 + + describe "::cancel()", -> + it "dispatches 'task:cancelled' when invoked on an active task", -> + task = new Task(require.resolve('./fixtures/task-spec-handler')) + cancelledEventSpy = jasmine.createSpy('eventSpy') + task.on('task:cancelled', cancelledEventSpy) + completedEventSpy = jasmine.createSpy('eventSpy') + task.on('task:completed', completedEventSpy) + + expect(task.cancel()).toBe(true) + expect(cancelledEventSpy).toHaveBeenCalled() + expect(completedEventSpy).not.toHaveBeenCalled() + + it "does not dispatch 'task:cancelled' when invoked on an inactive task", -> + handlerResult = null + task = Task.once require.resolve('./fixtures/task-spec-handler'), (result) -> + handlerResult = result + + waitsFor -> + handlerResult? + + runs -> + cancelledEventSpy = jasmine.createSpy('eventSpy') + task.on('task:cancelled', cancelledEventSpy) + expect(task.cancel()).toBe(false) + expect(cancelledEventSpy).not.toHaveBeenCalled() diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index 4918fc65f..6b0b1af96 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -938,6 +938,76 @@ describe "Workspace", -> .then -> expect(resultPaths).toEqual([file2]) + describe "when a custom directory searcher is registered", -> + it "can override the DefaultDirectorySearcher on a per-directory basis", -> + foreignFilePath = 'ssh://foreign-directory:8080/hello.txt' + numPathsSearchedInDir2 = 1 + numPathsToPretendToSearchInCustomDirectorySearcher = 10 + class CustomDirectorySearcher + canSearchDirectory: (directory) -> directory.getPath() is dir1 + search: (directory, regexSource, onSearchResult, onSearchError, onPathsSearched, options) -> + searchResult1 = + filePath: foreignFilePath, + matches: [ + { + lineText: 'Hello world', + lineTextOffset: 0, + matchText: 'Hello', + range: [[0, 0], [0, 5]], + } + ] + onSearchResult(searchResult1) + onPathsSearched(numPathsToPretendToSearchInCustomDirectorySearcher) + promise = Promise.resolve() + promise.cancel = -> + promise + + atom.packages.serviceHub.provide( + "atom.directory-searcher", "0.1.0", new CustomDirectorySearcher()) + + resultPaths = [] + onPathsSearched = jasmine.createSpy('onPathsSearched') + waitsForPromise -> + atom.workspace.scan /aaaa/, {onPathsSearched}, ({filePath}) -> + resultPaths.push(filePath) + + runs -> + expect(resultPaths.sort()).toEqual([foreignFilePath, file2].sort()) + # onPathsSearched should be called once by each DirectorySearcher. The order is not + # guaranteed, so we can only verify the total number of paths searched is correct + # after the second call. + expect(onPathsSearched.callCount).toBe(2) + expect(onPathsSearched.mostRecentCall.args[0]).toBe( + numPathsToPretendToSearchInCustomDirectorySearcher + numPathsSearchedInDir2) + + it "can be cancelled by cancelling one of the DirectorySearchers", -> + customDirectorySearcherPromiseInstance = null + class CustomDirectorySearcherToCancel + canSearchDirectory: (directory) -> directory.getPath() is dir1 + search: (directory, regexSource, onSearchResult, onSearchError, onPathsSearched, options) -> + # Note that hoisting reject in this way is generally frowned upon. + hoistedReject = null + promise = new Promise (resolve, reject) -> + hoistedReject = reject + promise.cancel = -> hoistedReject() + customDirectorySearcherPromiseInstance = promise + promise + + atom.packages.serviceHub.provide( + "atom.directory-searcher", "0.1.0", new CustomDirectorySearcherToCancel()) + + resultPaths = [] + cancelableSearch = atom.workspace.scan /aaaa/, ({filePath}) -> + resultPaths.push(filePath) + customDirectorySearcherPromiseInstance.cancel() + + resultOfPromiseSearch = null + waitsForPromise -> + cancelableSearch.then (promiseResult) -> resultOfPromiseSearch = promiseResult + + runs -> + expect(resultOfPromiseSearch).toBe('cancelled') + describe "::replace(regex, replacementText, paths, iterator)", -> [filePath, commentFilePath, sampleContent, sampleCommentContent] = [] diff --git a/src/default-directory-searcher.coffee b/src/default-directory-searcher.coffee new file mode 100644 index 000000000..7adf409c6 --- /dev/null +++ b/src/default-directory-searcher.coffee @@ -0,0 +1,61 @@ +Task = require './task' + +# Default provider for the `atom.directory-searcher` service. +module.exports = +class DefaultDirectorySearcher + # Public: Determines whether this object supports search for a `Directory`. + # + # * `directory` {Directory} whose search needs might be supported by this object. + # + # Returns a `boolean` indicating whether this object can search this `Directory`. + canSearchDirectory: (directory) -> true + + # Public: Performs a text search for files in the specified `Directory`, subject to the + # specified parameters. + # + # Results are streamed back to the caller via `recordSearchResult()` and `recordSearchError()`. + # + # * `directory` {Directory} that has been accepted by this provider's `canSearchDirectory()` + # predicate. + # * `regexSource` {String} regex to search with. Produced via `RegExp::source`. + # (Note this reflects the "Use Regex" option exposed via the ProjectFindView UI.) + # * `onSearchResult` {Function} Should be called with each matching search result. + # * `searchResult` {Object} with the following keys: + # * `filePath` {String} absolute path to the matching file. + # * `matches` {Array} with object elements with the following keys: + # * `lineText` {String} The full text of the matching line (without a line terminator character). + # * `lineTextOffset` {Number} (This always seems to be 0?) + # * `matchText` {String} The text that matched the `regex` used for the search. + # * `range` {Range} Identifies the matching region in the file. (Likely as an array of numeric arrays.) + # * `onSearchError` {Function} Should be called to report a search error. + # * `onPathsSearched` {Function} callback that should be invoked periodically with the number of + # paths searched. + # * `options` {Object} with the following properties: + # * `ignoreCase` {boolean} + # * `inclusions` {Array} of glob patterns (as strings) to search within. Note that this + # array may be empty, indicating that all files should be searched. + # + # Each item in the array is a file/directory pattern, e.g., `src` to search in the "src" + # directory or `*.js` to search all JavaScript files. In practice, this often comes from the + # comma-delimited list of patterns in the bottom text input of the ProjectFindView dialog. + # * `ignoreHidden` {boolean} + # * `excludeVcsIgnores` {boolean} + # * `exclusions` {Array} similar to inclusions + # * `follow` {boolean} whether symlinks should be followed + # + # Returns a `Promise` that includes a `cancel()` method. If invoked before the `Proimse` is + # determined, it will reject the `Promise`. + search: (directory, regexSource, onSearchResult, onSearchError, onPathsSearched, options) -> + task = null + rootPaths = [directory.getPath()] + promise = new Promise (resolve, reject) -> + task = Task.once require.resolve('./scan-handler'), rootPaths, regexSource, options, resolve + task.on 'task:cancelled', reject + promise.cancel = -> + task.cancel() + + task.on 'scan:result-found', onSearchResult + task.on 'scan:file-error', onSearchError + task.on 'scan:paths-searched', onPathsSearched + + promise diff --git a/src/task.coffee b/src/task.coffee index 939b71635..34c943c6a 100644 --- a/src/task.coffee +++ b/src/task.coffee @@ -150,7 +150,7 @@ class Task # # No more events are emitted once this method is called. terminate: -> - return unless @childProcess? + return false unless @childProcess? @childProcess.removeAllListeners() @childProcess.stdout.removeAllListeners() @@ -158,4 +158,10 @@ class Task @childProcess.kill() @childProcess = null - undefined + true + + cancel: -> + didForcefullyTerminate = @terminate() + if didForcefullyTerminate + @emit('task:cancelled') + didForcefullyTerminate diff --git a/src/workspace.coffee b/src/workspace.coffee index 157d002de..c7c5d51b1 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -7,6 +7,7 @@ Serializable = require 'serializable' {Emitter, Disposable, CompositeDisposable} = require 'event-kit' Grim = require 'grim' fs = require 'fs-plus' +DefaultDirectorySearcher = require './default-directory-searcher' Model = require './model' TextEditor = require './text-editor' PaneContainer = require './pane-container' @@ -46,6 +47,14 @@ class Workspace extends Model @paneContainer ?= new PaneContainer() @paneContainer.onDidDestroyPaneItem(@didDestroyPaneItem) + @searchProviders = [new DefaultDirectorySearcher()] + atom.packages.serviceHub.consume( + 'atom.directory-searcher', + '^0.1.0', + # New providers are added to the front of @searchProviders because + # DefaultDirectorySearcher is a catch-all that will always claim to search a Directory. + (provider) => @searchProviders.unshift(provider)) + @panelContainers = top: new PanelContainer({location: 'top'}) left: new PanelContainer({location: 'left'}) @@ -791,36 +800,72 @@ class Workspace extends Model # * `regex` {RegExp} to search with. # * `options` (optional) {Object} (default: {}) # * `paths` An {Array} of glob patterns to search within + # * `onPathsSearched` (optional) {Function} # * `iterator` {Function} callback on each file found # - # Returns a `Promise`. + # Returns a `Promise` with a `cancel()` method. scan: (regex, options={}, iterator) -> if _.isFunction(options) iterator = options options = {} - deferred = Q.defer() - searchOptions = ignoreCase: regex.ignoreCase - inclusions: options.paths + inclusions: options.paths or [] includeHidden: true excludeVcsIgnores: atom.config.get('core.excludeVcsIgnoredPaths') exclusions: atom.config.get('core.ignoredNames') follow: atom.config.get('core.followSymlinks') - task = Task.once require.resolve('./scan-handler'), atom.project.getPaths(), regex.source, searchOptions, -> - deferred.resolve() + # Find a search provider for every Directory in the project. + providersAndDirectories = [] + for directory in atom.project.getDirectories() + providerForDirectory = null + for provider in @searchProviders + if provider.canSearchDirectory(directory) + providerForDirectory = provider + break + if providerForDirectory + providersAndDirectories.push({provider, directory}) + else + throw Error("Could not find search provider for #{directory.getPath()}") - task.on 'scan:result-found', (result) -> + # Now that we are sure every Directory has a provider, construct the search options. + onSearchResult = (result) -> iterator(result) unless atom.project.isPathModified(result.filePath) - - task.on 'scan:file-error', (error) -> + onSearchError = (error) -> iterator(null, error) + # Define the onPathsSearched callback. if _.isFunction(options.onPathsSearched) - task.on 'scan:paths-searched', (numberOfPathsSearched) -> - options.onPathsSearched(numberOfPathsSearched) + # Maintain a map of providers to the number of search results. When notified of a new count, + # replace the entry in the map and update the total. + onPathsSearchedOption = options.onPathsSearched + totalNumberOfPathsSearched = 0 + numberOfPathsSearchedForProvider = new Map() + onPathsSearched = (provider, numberOfPathsSearched) -> + oldValue = numberOfPathsSearchedForProvider.get(provider) + if oldValue + totalNumberOfPathsSearched -= oldValue + numberOfPathsSearchedForProvider.set(provider, numberOfPathsSearched) + totalNumberOfPathsSearched += numberOfPathsSearched + onPathsSearchedOption(totalNumberOfPathsSearched) + else + onPathsSearched = -> + + # Kick off all of the searches and unify them into one Promise. + allSearchPromises = [] + for entry in providersAndDirectories + {provider, directory} = entry + recordNumPathsSearched = onPathsSearched.bind(undefined, provider) + allSearchPromises.push(provider.search( + directory, + regex.source, + onSearchResult, + onSearchError, + recordNumPathsSearched, + searchOptions)) + searchPromise = Promise.all(allSearchPromises) for buffer in atom.project.getBuffers() when buffer.isModified() filePath = buffer.getPath() @@ -829,11 +874,30 @@ class Workspace extends Model buffer.scan regex, (match) -> matches.push match iterator {filePath, matches} if matches.length > 0 - promise = deferred.promise - promise.cancel = -> - task.terminate() - deferred.resolve('cancelled') - promise + # Make sure the Promise that is returned to the client is cancelable. To be consistent + # with the existing behavior, instead of cancel() rejecting the promise, it should + # resolve it with the special value 'cancelled'. At least the built-in find-and-replace + # package relies on this behavior. + cancellablePromise = new Promise (resolve, reject) -> + onSuccess = -> + resolve(null) + return + onFailure = -> + resolve('cancelled') + return + searchPromise.then(onSuccess, onFailure) + cancellablePromise.cancel = -> + # Note that cancelling all (or actually, any) of the members of allSearchPromises + # will cause searchPromise to reject, which will cause cancellablePromise to resolve + # in the desired way. + promise.cancel() for promise in allSearchPromises + + # Although this method claims to return a `Promise`, the `ResultsPaneView.onSearch()` + # method in the find-and-replace package expects the object returned by this method to have a + # `done()` method. Include a done() method until find-and-replace can be updated. + cancellablePromise.done = (f) -> + cancellablePromise.then(f, f) + cancellablePromise # Public: Performs a replace across all the specified files in the project. # From 986640f67085427503faddc320d8251b095d0aed Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Tue, 2 Jun 2015 12:01:23 -0400 Subject: [PATCH 1617/1783] Respond to comments from @maxbrunsfeld and @kevinsawicki. --- src/workspace.coffee | 50 ++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/workspace.coffee b/src/workspace.coffee index c7c5d51b1..a22e2409d 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -47,13 +47,13 @@ class Workspace extends Model @paneContainer ?= new PaneContainer() @paneContainer.onDidDestroyPaneItem(@didDestroyPaneItem) - @searchProviders = [new DefaultDirectorySearcher()] + @directorySearchers = [new DefaultDirectorySearcher()] atom.packages.serviceHub.consume( 'atom.directory-searcher', '^0.1.0', - # New providers are added to the front of @searchProviders because + # New providers are added to the front of @directorySearchers because # DefaultDirectorySearcher is a catch-all that will always claim to search a Directory. - (provider) => @searchProviders.unshift(provider)) + (provider) => @directorySearchers.unshift(provider)) @panelContainers = top: new PanelContainer({location: 'top'}) @@ -817,20 +817,20 @@ class Workspace extends Model exclusions: atom.config.get('core.ignoredNames') follow: atom.config.get('core.followSymlinks') - # Find a search provider for every Directory in the project. - providersAndDirectories = [] + # Find a searcher for every Directory in the project. + searchersAndDirectories = [] for directory in atom.project.getDirectories() - providerForDirectory = null - for provider in @searchProviders - if provider.canSearchDirectory(directory) - providerForDirectory = provider + searcher = null + for directorySearcher in @directorySearchers + if directorySearcher.canSearchDirectory(directory) + searcher = directorySearcher break - if providerForDirectory - providersAndDirectories.push({provider, directory}) + if searcher + searchersAndDirectories.push({searcher, directory}) else - throw Error("Could not find search provider for #{directory.getPath()}") + throw Error("Could not find directory searcher for #{directory.getPath()}") - # Now that we are sure every Directory has a provider, construct the search options. + # Now that we are sure every Directory has a searcher, construct the search options. onSearchResult = (result) -> iterator(result) unless atom.project.isPathModified(result.filePath) onSearchError = (error) -> @@ -838,16 +838,16 @@ class Workspace extends Model # Define the onPathsSearched callback. if _.isFunction(options.onPathsSearched) - # Maintain a map of providers to the number of search results. When notified of a new count, + # Maintain a map of directories to the number of search results. When notified of a new count, # replace the entry in the map and update the total. onPathsSearchedOption = options.onPathsSearched totalNumberOfPathsSearched = 0 - numberOfPathsSearchedForProvider = new Map() - onPathsSearched = (provider, numberOfPathsSearched) -> - oldValue = numberOfPathsSearchedForProvider.get(provider) + numberOfPathsSearchedForDirectory = new Map() + onPathsSearched = (directory, numberOfPathsSearched) -> + oldValue = numberOfPathsSearchedForDirectory.get(directory) if oldValue totalNumberOfPathsSearched -= oldValue - numberOfPathsSearchedForProvider.set(provider, numberOfPathsSearched) + numberOfPathsSearchedForDirectory.set(directory, numberOfPathsSearched) totalNumberOfPathsSearched += numberOfPathsSearched onPathsSearchedOption(totalNumberOfPathsSearched) else @@ -855,15 +855,15 @@ class Workspace extends Model # Kick off all of the searches and unify them into one Promise. allSearchPromises = [] - for entry in providersAndDirectories - {provider, directory} = entry - recordNumPathsSearched = onPathsSearched.bind(undefined, provider) - allSearchPromises.push(provider.search( + for entry in searchersAndDirectories + {searcher, directory} = entry + recordNumberOfPathsSearched = onPathsSearched.bind(undefined, directory) + allSearchPromises.push(searcher.search( directory, regex.source, onSearchResult, onSearchError, - recordNumPathsSearched, + recordNumberOfPathsSearched, searchOptions)) searchPromise = Promise.all(allSearchPromises) @@ -895,8 +895,8 @@ class Workspace extends Model # Although this method claims to return a `Promise`, the `ResultsPaneView.onSearch()` # method in the find-and-replace package expects the object returned by this method to have a # `done()` method. Include a done() method until find-and-replace can be updated. - cancellablePromise.done = (f) -> - cancellablePromise.then(f, f) + cancellablePromise.done = (onSuccessOrFailure) -> + cancellablePromise.then(onSuccessOrFailure, onSuccessOrFailure) cancellablePromise # Public: Performs a replace across all the specified files in the project. From 7294e0cda409803cbd3956119eeb35cee4596ba0 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Tue, 2 Jun 2015 14:04:59 -0400 Subject: [PATCH 1618/1783] Change DirectorySearcher to return a DirectorySearch. --- spec/workspace-spec.coffee | 57 +++++++++++++++++------- src/default-directory-searcher.coffee | 62 ++++++++++++++++++++------- src/workspace.coffee | 21 +++++---- 3 files changed, 100 insertions(+), 40 deletions(-) diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index 6b0b1af96..19775e6fa 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -1,5 +1,6 @@ path = require 'path' temp = require 'temp' +{Disposable} = require 'event-kit' Workspace = require '../src/workspace' Pane = require '../src/pane' {View} = require '../src/space-pen-extensions' @@ -943,9 +944,13 @@ describe "Workspace", -> foreignFilePath = 'ssh://foreign-directory:8080/hello.txt' numPathsSearchedInDir2 = 1 numPathsToPretendToSearchInCustomDirectorySearcher = 10 - class CustomDirectorySearcher - canSearchDirectory: (directory) -> directory.getPath() is dir1 - search: (directory, regexSource, onSearchResult, onSearchError, onPathsSearched, options) -> + class CustomDirectorySearch + constructor: () -> + @promise = Promise.resolve() + then: (args...) -> + @promise.then.apply(@promise, args) + onDidMatch: (callback) -> + # Invoke the callback with the only result we plan to return. searchResult1 = filePath: foreignFilePath, matches: [ @@ -956,11 +961,20 @@ describe "Workspace", -> range: [[0, 0], [0, 5]], } ] - onSearchResult(searchResult1) - onPathsSearched(numPathsToPretendToSearchInCustomDirectorySearcher) - promise = Promise.resolve() - promise.cancel = -> - promise + callback(searchResult1) + new Disposable + onDidError: (callback) -> + new Disposable + onDidSearchPaths: (callback) -> + # Invoke the callback with the one notification we plan to send. + callback(numPathsToPretendToSearchInCustomDirectorySearcher) + new Disposable + cancel: -> + + class CustomDirectorySearcher + canSearchDirectory: (directory) -> directory.getPath() is dir1 + search: (directory, options) -> + new CustomDirectorySearch atom.packages.serviceHub.provide( "atom.directory-searcher", "0.1.0", new CustomDirectorySearcher()) @@ -982,16 +996,27 @@ describe "Workspace", -> it "can be cancelled by cancelling one of the DirectorySearchers", -> customDirectorySearcherPromiseInstance = null + class CustomDirectorySearchToCancel + constructor: () -> + # Note that hoisting reject in this way is generally frowned upon. + @promise = new Promise (resolve, reject) => + @hoistedReject = reject + customDirectorySearcherPromiseInstance = this + then: (args...) -> + @promise.then.apply(@promise, args) + onDidMatch: (callback) -> + new Disposable + onDidError: (callback) -> + new Disposable + onDidSearchPaths: (callback) -> + new Disposable + cancel: -> + @hoistedReject() + class CustomDirectorySearcherToCancel canSearchDirectory: (directory) -> directory.getPath() is dir1 - search: (directory, regexSource, onSearchResult, onSearchError, onPathsSearched, options) -> - # Note that hoisting reject in this way is generally frowned upon. - hoistedReject = null - promise = new Promise (resolve, reject) -> - hoistedReject = reject - promise.cancel = -> hoistedReject() - customDirectorySearcherPromiseInstance = promise - promise + search: (directory, options) -> + new CustomDirectorySearchToCancel atom.packages.serviceHub.provide( "atom.directory-searcher", "0.1.0", new CustomDirectorySearcherToCancel()) diff --git a/src/default-directory-searcher.coffee b/src/default-directory-searcher.coffee index 7adf409c6..a1304d26c 100644 --- a/src/default-directory-searcher.coffee +++ b/src/default-directory-searcher.coffee @@ -1,5 +1,47 @@ Task = require './task' +# Public: +# Implements thenable so it can be used with `Promise.all()`. +class DirectorySearch + # Public: + constructor: (directory, options) -> + @task = new Task(require.resolve('./scan-handler')) + rootPaths = [directory.getPath()] + @promise = new Promise (resolve, reject) => + myResolve = (arg) -> + resolve(arg) + @task.start(rootPaths, options.regexSource, options, myResolve) + @task.on('task:cancelled', reject) + + # Public: + # Returns `Promise`. + then: (args...) -> + @promise.then.apply(@promise, args) + + # Public: + # Returns `Disposable`. + onDidMatch: (callback) -> + @task.on 'scan:result-found', callback + + # Public: + # Returns `Disposable`. + onDidError: (callback) -> + @task.on 'scan:file-error', callback + + # Public: + # + # * `callback` {Function} called with the number of paths searched thus far. + # + # Returns `Disposable`. + onDidSearchPaths: (callback) -> + @task.on 'scan:paths-searched', callback + + # Public: + cancel: -> + # This will cause @promise to reject. + @task.cancel() + + # Default provider for the `atom.directory-searcher` service. module.exports = class DefaultDirectorySearcher @@ -17,7 +59,6 @@ class DefaultDirectorySearcher # # * `directory` {Directory} that has been accepted by this provider's `canSearchDirectory()` # predicate. - # * `regexSource` {String} regex to search with. Produced via `RegExp::source`. # (Note this reflects the "Use Regex" option exposed via the ProjectFindView UI.) # * `onSearchResult` {Function} Should be called with each matching search result. # * `searchResult` {Object} with the following keys: @@ -31,6 +72,7 @@ class DefaultDirectorySearcher # * `onPathsSearched` {Function} callback that should be invoked periodically with the number of # paths searched. # * `options` {Object} with the following properties: + # * `regexSource` {String} regex to search with. Produced via `RegExp::source`. # * `ignoreCase` {boolean} # * `inclusions` {Array} of glob patterns (as strings) to search within. Note that this # array may be empty, indicating that all files should be searched. @@ -43,19 +85,7 @@ class DefaultDirectorySearcher # * `exclusions` {Array} similar to inclusions # * `follow` {boolean} whether symlinks should be followed # - # Returns a `Promise` that includes a `cancel()` method. If invoked before the `Proimse` is + # Returns a `DirectorySearch` that includes a `cancel()` method. If invoked before the `Proimse` is # determined, it will reject the `Promise`. - search: (directory, regexSource, onSearchResult, onSearchError, onPathsSearched, options) -> - task = null - rootPaths = [directory.getPath()] - promise = new Promise (resolve, reject) -> - task = Task.once require.resolve('./scan-handler'), rootPaths, regexSource, options, resolve - task.on 'task:cancelled', reject - promise.cancel = -> - task.cancel() - - task.on 'scan:result-found', onSearchResult - task.on 'scan:file-error', onSearchError - task.on 'scan:paths-searched', onPathsSearched - - promise + search: (directory, options) -> + new DirectorySearch(directory, options) diff --git a/src/workspace.coffee b/src/workspace.coffee index a22e2409d..fe79f5d17 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -803,13 +803,14 @@ class Workspace extends Model # * `onPathsSearched` (optional) {Function} # * `iterator` {Function} callback on each file found # - # Returns a `Promise` with a `cancel()` method. + # Returns a `Promise`. scan: (regex, options={}, iterator) -> if _.isFunction(options) iterator = options options = {} searchOptions = + regexSource: regex.source ignoreCase: regex.ignoreCase inclusions: options.paths or [] includeHidden: true @@ -855,18 +856,22 @@ class Workspace extends Model # Kick off all of the searches and unify them into one Promise. allSearchPromises = [] + disposables = new CompositeDisposable for entry in searchersAndDirectories {searcher, directory} = entry + directorySearcher = searcher.search(directory, searchOptions) + disposables.add(directorySearcher.onDidMatch(onSearchResult)) + disposables.add(directorySearcher.onDidError(onSearchError)) recordNumberOfPathsSearched = onPathsSearched.bind(undefined, directory) - allSearchPromises.push(searcher.search( - directory, - regex.source, - onSearchResult, - onSearchError, - recordNumberOfPathsSearched, - searchOptions)) + disposables.add(directorySearcher.onDidSearchPaths(recordNumberOfPathsSearched)) + allSearchPromises.push(directorySearcher) searchPromise = Promise.all(allSearchPromises) + # Make sure to clean up the disposables once the searchPromise is determined. + disposeAll = (args...) -> + disposables.dispose() + searchPromise.then(disposeAll, disposeAll) + for buffer in atom.project.getBuffers() when buffer.isModified() filePath = buffer.getPath() continue unless atom.project.contains(filePath) From 4330c3a181c63b5dfed453702296cb38796c5721 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Tue, 2 Jun 2015 14:15:55 -0400 Subject: [PATCH 1619/1783] Fix some nits I found during my self-review. --- spec/workspace-spec.coffee | 4 ++-- src/workspace.coffee | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index 19775e6fa..3a709165b 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -945,7 +945,7 @@ describe "Workspace", -> numPathsSearchedInDir2 = 1 numPathsToPretendToSearchInCustomDirectorySearcher = 10 class CustomDirectorySearch - constructor: () -> + constructor: -> @promise = Promise.resolve() then: (args...) -> @promise.then.apply(@promise, args) @@ -997,7 +997,7 @@ describe "Workspace", -> it "can be cancelled by cancelling one of the DirectorySearchers", -> customDirectorySearcherPromiseInstance = null class CustomDirectorySearchToCancel - constructor: () -> + constructor: -> # Note that hoisting reject in this way is generally frowned upon. @promise = new Promise (resolve, reject) => @hoistedReject = reject diff --git a/src/workspace.coffee b/src/workspace.coffee index fe79f5d17..f5cbe2049 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -855,7 +855,7 @@ class Workspace extends Model onPathsSearched = -> # Kick off all of the searches and unify them into one Promise. - allSearchPromises = [] + allSearches = [] disposables = new CompositeDisposable for entry in searchersAndDirectories {searcher, directory} = entry @@ -864,8 +864,8 @@ class Workspace extends Model disposables.add(directorySearcher.onDidError(onSearchError)) recordNumberOfPathsSearched = onPathsSearched.bind(undefined, directory) disposables.add(directorySearcher.onDidSearchPaths(recordNumberOfPathsSearched)) - allSearchPromises.push(directorySearcher) - searchPromise = Promise.all(allSearchPromises) + allSearches.push(directorySearcher) + searchPromise = Promise.all(allSearches) # Make sure to clean up the disposables once the searchPromise is determined. disposeAll = (args...) -> @@ -887,15 +887,15 @@ class Workspace extends Model onSuccess = -> resolve(null) return - onFailure = -> + onFailure = -> resolve('cancelled') return searchPromise.then(onSuccess, onFailure) cancellablePromise.cancel = -> - # Note that cancelling all (or actually, any) of the members of allSearchPromises + # Note that cancelling all (or actually, any) of the members of allSearches # will cause searchPromise to reject, which will cause cancellablePromise to resolve # in the desired way. - promise.cancel() for promise in allSearchPromises + promise.cancel() for promise in allSearches # Although this method claims to return a `Promise`, the `ResultsPaneView.onSearch()` # method in the find-and-replace package expects the object returned by this method to have a From fd670a4dd4096413e65545d0c34ce27643febbbb Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Tue, 2 Jun 2015 14:19:55 -0400 Subject: [PATCH 1620/1783] Remove `myResolve` local variable that I was using for debugging. --- src/default-directory-searcher.coffee | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/default-directory-searcher.coffee b/src/default-directory-searcher.coffee index a1304d26c..af04792eb 100644 --- a/src/default-directory-searcher.coffee +++ b/src/default-directory-searcher.coffee @@ -8,9 +8,7 @@ class DirectorySearch @task = new Task(require.resolve('./scan-handler')) rootPaths = [directory.getPath()] @promise = new Promise (resolve, reject) => - myResolve = (arg) -> - resolve(arg) - @task.start(rootPaths, options.regexSource, options, myResolve) + @task.start(rootPaths, options.regexSource, options, resolve) @task.on('task:cancelled', reject) # Public: From 735bdcca0874561373b7eb5debeea8c79cc4cfa2 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Tue, 2 Jun 2015 16:25:44 -0400 Subject: [PATCH 1621/1783] Two things: 1. Update documentation for `default-directory-search.coffee`. 2. Ensure that multiple `DirectorySearch` searches are run in series rather than in parallel to conserve resources. --- src/default-directory-searcher.coffee | 94 ++++++++++++++++++--------- 1 file changed, 65 insertions(+), 29 deletions(-) diff --git a/src/default-directory-searcher.coffee b/src/default-directory-searcher.coffee index af04792eb..448c47377 100644 --- a/src/default-directory-searcher.coffee +++ b/src/default-directory-searcher.coffee @@ -1,32 +1,73 @@ +{EventEmitter} = require 'events' Task = require './task' -# Public: +# Maintain a queue of ids of searches to run. When a search is complete, the active +# search is cleared and the next search (if any) in the queue is notified to run. +# This ensures there is at most one scan-handler task running at a time. +searchQueue = [] +nextId = 1 +activeSearchId = 0 +emitter = new EventEmitter + +onSearchFinished = () -> + activeSearchId = null + runNextSearch() + +runNextSearch = () -> + unless activeSearchId + activeSearchId = searchQueue.shift() + emitter.emit(activeSearchId, null) if activeSearchId + +enqueue = (id) -> + searchQueue.push(id) + runNextSearch() + + +# Public: Searches local files for lines matching a specified regex. +# # Implements thenable so it can be used with `Promise.all()`. class DirectorySearch - # Public: - constructor: (directory, options) -> + # Public: Creates a new DirectorySearch that will not start running until the + # `emitter` that is private to this file emits an event with the specified `id`. + constructor: (directory, options, id) -> @task = new Task(require.resolve('./scan-handler')) rootPaths = [directory.getPath()] @promise = new Promise (resolve, reject) => - @task.start(rootPaths, options.regexSource, options, resolve) @task.on('task:cancelled', reject) + emitter.once id, => + @task.start(rootPaths, options.regexSource, options, resolve) - # Public: + # Public: Implementation of `then()` to satisfy the *thenable* contract. + # This makes it possible to use a `DirectorySearch` with `Promise.all()`. + # # Returns `Promise`. then: (args...) -> @promise.then.apply(@promise, args) - # Public: + # Public: Get notified when a search result is found. + # + # * `callback` {Function} called with a search result structured as follows: + # * `searchResult` {Object} with the following keys: + # * `filePath` {String} absolute path to the matching file. + # * `matches` {Array} with object elements with the following keys: + # * `lineText` {String} The full text of the matching line (without a line terminator character). + # * `lineTextOffset` {Number} (This always seems to be 0?) + # * `matchText` {String} The text that matched the `regex` used for the search. + # * `range` {Range} Identifies the matching region in the file. (Likely as an array of numeric arrays.) + # # Returns `Disposable`. onDidMatch: (callback) -> @task.on 'scan:result-found', callback - # Public: + # Public: Get notified about any search errors. + # + # * `callback` {Function} called with an Error if there is a problem during the search. + # # Returns `Disposable`. onDidError: (callback) -> @task.on 'scan:file-error', callback - # Public: + # Public: Get notified with the number of paths searched thus far. # # * `callback` {Function} called with the number of paths searched thus far. # @@ -34,10 +75,11 @@ class DirectorySearch onDidSearchPaths: (callback) -> @task.on 'scan:paths-searched', callback - # Public: + # Public: Cancels the search. cancel: -> # This will cause @promise to reject. @task.cancel() + null # Default provider for the `atom.directory-searcher` service. @@ -53,37 +95,31 @@ class DefaultDirectorySearcher # Public: Performs a text search for files in the specified `Directory`, subject to the # specified parameters. # - # Results are streamed back to the caller via `recordSearchResult()` and `recordSearchError()`. + # Results are streamed back to the caller by adding callbacks to the `DirectorySearch` returned by + # this method. # # * `directory` {Directory} that has been accepted by this provider's `canSearchDirectory()` # predicate. - # (Note this reflects the "Use Regex" option exposed via the ProjectFindView UI.) - # * `onSearchResult` {Function} Should be called with each matching search result. - # * `searchResult` {Object} with the following keys: - # * `filePath` {String} absolute path to the matching file. - # * `matches` {Array} with object elements with the following keys: - # * `lineText` {String} The full text of the matching line (without a line terminator character). - # * `lineTextOffset` {Number} (This always seems to be 0?) - # * `matchText` {String} The text that matched the `regex` used for the search. - # * `range` {Range} Identifies the matching region in the file. (Likely as an array of numeric arrays.) - # * `onSearchError` {Function} Should be called to report a search error. - # * `onPathsSearched` {Function} callback that should be invoked periodically with the number of - # paths searched. # * `options` {Object} with the following properties: # * `regexSource` {String} regex to search with. Produced via `RegExp::source`. - # * `ignoreCase` {boolean} + # * `ignoreCase` {boolean} reflects whether the regex should be run with the `i` option. # * `inclusions` {Array} of glob patterns (as strings) to search within. Note that this # array may be empty, indicating that all files should be searched. # # Each item in the array is a file/directory pattern, e.g., `src` to search in the "src" # directory or `*.js` to search all JavaScript files. In practice, this often comes from the # comma-delimited list of patterns in the bottom text input of the ProjectFindView dialog. - # * `ignoreHidden` {boolean} - # * `excludeVcsIgnores` {boolean} + # * `ignoreHidden` {boolean} whether to ignore hidden files. + # * `excludeVcsIgnores` {boolean} whether to exclude VCS ignored paths. # * `exclusions` {Array} similar to inclusions - # * `follow` {boolean} whether symlinks should be followed + # * `follow` {boolean} whether symlinks should be followed. # - # Returns a `DirectorySearch` that includes a `cancel()` method. If invoked before the `Proimse` is - # determined, it will reject the `Promise`. + # Returns a *thenable* `DirectorySearch` that includes a `cancel()` method. If `cancel()` is + # invoked before the `DirectorySearch` is determined, it will reject the `DirectorySearch`. search: (directory, options) -> - new DirectorySearch(directory, options) + id = nextId + nextId += 1 + directorySearch = new DirectorySearch(directory, options, id) + directorySearch.then(onSearchFinished, onSearchFinished) + enqueue(id) + directorySearch From fa3fd9c50c6f196772c26bfb396ddcb8b23b1dc9 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Tue, 2 Jun 2015 16:28:31 -0400 Subject: [PATCH 1622/1783] Remove empty param lists as per the linter. --- src/default-directory-searcher.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/default-directory-searcher.coffee b/src/default-directory-searcher.coffee index 448c47377..b244e4f94 100644 --- a/src/default-directory-searcher.coffee +++ b/src/default-directory-searcher.coffee @@ -9,11 +9,11 @@ nextId = 1 activeSearchId = 0 emitter = new EventEmitter -onSearchFinished = () -> +onSearchFinished = -> activeSearchId = null runNextSearch() -runNextSearch = () -> +runNextSearch = -> unless activeSearchId activeSearchId = searchQueue.shift() emitter.emit(activeSearchId, null) if activeSearchId From 4eb30f39259c1c226bab655c39739ecbaec50b57 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Tue, 2 Jun 2015 17:40:27 -0400 Subject: [PATCH 1623/1783] Switch to the delegate pattern, eliminating a nasty race condition and deleting a lot of code. --- spec/workspace-spec.coffee | 30 ++++----------- src/default-directory-searcher.coffee | 54 +++++++++------------------ src/workspace.coffee | 26 ++++++------- 3 files changed, 38 insertions(+), 72 deletions(-) diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index 3a709165b..1b05d6c10 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -945,12 +945,8 @@ describe "Workspace", -> numPathsSearchedInDir2 = 1 numPathsToPretendToSearchInCustomDirectorySearcher = 10 class CustomDirectorySearch - constructor: -> + constructor: (delegate) -> @promise = Promise.resolve() - then: (args...) -> - @promise.then.apply(@promise, args) - onDidMatch: (callback) -> - # Invoke the callback with the only result we plan to return. searchResult1 = filePath: foreignFilePath, matches: [ @@ -959,22 +955,18 @@ describe "Workspace", -> lineTextOffset: 0, matchText: 'Hello', range: [[0, 0], [0, 5]], - } + }, ] - callback(searchResult1) - new Disposable - onDidError: (callback) -> - new Disposable - onDidSearchPaths: (callback) -> - # Invoke the callback with the one notification we plan to send. - callback(numPathsToPretendToSearchInCustomDirectorySearcher) - new Disposable + delegate.onDidMatch(searchResult1) + delegate.onDidSearchPaths(numPathsToPretendToSearchInCustomDirectorySearcher) + then: (args...) -> + @promise.then.apply(@promise, args) cancel: -> class CustomDirectorySearcher canSearchDirectory: (directory) -> directory.getPath() is dir1 - search: (directory, options) -> - new CustomDirectorySearch + search: (directory, delegate, options) -> + new CustomDirectorySearch(delegate) atom.packages.serviceHub.provide( "atom.directory-searcher", "0.1.0", new CustomDirectorySearcher()) @@ -1004,12 +996,6 @@ describe "Workspace", -> customDirectorySearcherPromiseInstance = this then: (args...) -> @promise.then.apply(@promise, args) - onDidMatch: (callback) -> - new Disposable - onDidError: (callback) -> - new Disposable - onDidSearchPaths: (callback) -> - new Disposable cancel: -> @hoistedReject() diff --git a/src/default-directory-searcher.coffee b/src/default-directory-searcher.coffee index b244e4f94..eec1ae4de 100644 --- a/src/default-directory-searcher.coffee +++ b/src/default-directory-searcher.coffee @@ -29,13 +29,16 @@ enqueue = (id) -> class DirectorySearch # Public: Creates a new DirectorySearch that will not start running until the # `emitter` that is private to this file emits an event with the specified `id`. - constructor: (directory, options, id) -> + constructor: (directory, delegate, options, id) -> @task = new Task(require.resolve('./scan-handler')) rootPaths = [directory.getPath()] @promise = new Promise (resolve, reject) => @task.on('task:cancelled', reject) emitter.once id, => @task.start(rootPaths, options.regexSource, options, resolve) + @task.on 'scan:result-found', delegate.onDidMatch + @task.on 'scan:file-error', delegate.onDidError + @task.on 'scan:paths-searched', delegate.onDidSearchPaths # Public: Implementation of `then()` to satisfy the *thenable* contract. # This makes it possible to use a `DirectorySearch` with `Promise.all()`. @@ -44,37 +47,6 @@ class DirectorySearch then: (args...) -> @promise.then.apply(@promise, args) - # Public: Get notified when a search result is found. - # - # * `callback` {Function} called with a search result structured as follows: - # * `searchResult` {Object} with the following keys: - # * `filePath` {String} absolute path to the matching file. - # * `matches` {Array} with object elements with the following keys: - # * `lineText` {String} The full text of the matching line (without a line terminator character). - # * `lineTextOffset` {Number} (This always seems to be 0?) - # * `matchText` {String} The text that matched the `regex` used for the search. - # * `range` {Range} Identifies the matching region in the file. (Likely as an array of numeric arrays.) - # - # Returns `Disposable`. - onDidMatch: (callback) -> - @task.on 'scan:result-found', callback - - # Public: Get notified about any search errors. - # - # * `callback` {Function} called with an Error if there is a problem during the search. - # - # Returns `Disposable`. - onDidError: (callback) -> - @task.on 'scan:file-error', callback - - # Public: Get notified with the number of paths searched thus far. - # - # * `callback` {Function} called with the number of paths searched thus far. - # - # Returns `Disposable`. - onDidSearchPaths: (callback) -> - @task.on 'scan:paths-searched', callback - # Public: Cancels the search. cancel: -> # This will cause @promise to reject. @@ -95,11 +67,21 @@ class DefaultDirectorySearcher # Public: Performs a text search for files in the specified `Directory`, subject to the # specified parameters. # - # Results are streamed back to the caller by adding callbacks to the `DirectorySearch` returned by - # this method. + # Results are streamed back to the caller by invoking methods on the specified `delegate`. # # * `directory` {Directory} that has been accepted by this provider's `canSearchDirectory()` # predicate. + # * `delegate` {Object} with the following properties: + # * `onDidMatch` {Function} call with a search result structured as follows: + # * `searchResult` {Object} with the following keys: + # * `filePath` {String} absolute path to the matching file. + # * `matches` {Array} with object elements with the following keys: + # * `lineText` {String} The full text of the matching line (without a line terminator character). + # * `lineTextOffset` {Number} (This always seems to be 0?) + # * `matchText` {String} The text that matched the `regex` used for the search. + # * `range` {Range} Identifies the matching region in the file. (Likely as an array of numeric arrays.) + # * `onDidError` {Function} call with an Error if there is a problem during the search. + # * `onDidSearchPaths` {Function} periodically call with the number of paths searched thus far. # * `options` {Object} with the following properties: # * `regexSource` {String} regex to search with. Produced via `RegExp::source`. # * `ignoreCase` {boolean} reflects whether the regex should be run with the `i` option. @@ -116,10 +98,10 @@ class DefaultDirectorySearcher # # Returns a *thenable* `DirectorySearch` that includes a `cancel()` method. If `cancel()` is # invoked before the `DirectorySearch` is determined, it will reject the `DirectorySearch`. - search: (directory, options) -> + search: (directory, delegate, options) -> id = nextId nextId += 1 - directorySearch = new DirectorySearch(directory, options, id) + directorySearch = new DirectorySearch(directory, delegate, options, id) directorySearch.then(onSearchFinished, onSearchFinished) enqueue(id) directorySearch diff --git a/src/workspace.coffee b/src/workspace.coffee index f5cbe2049..e92b3ac34 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -832,10 +832,12 @@ class Workspace extends Model throw Error("Could not find directory searcher for #{directory.getPath()}") # Now that we are sure every Directory has a searcher, construct the search options. - onSearchResult = (result) -> - iterator(result) unless atom.project.isPathModified(result.filePath) - onSearchError = (error) -> - iterator(null, error) + delegateProto = { + onDidMatch: (result) -> + iterator(result) unless atom.project.isPathModified(result.filePath) + onDidError: (error) -> + iterator(null, error) + } # Define the onPathsSearched callback. if _.isFunction(options.onPathsSearched) @@ -856,22 +858,18 @@ class Workspace extends Model # Kick off all of the searches and unify them into one Promise. allSearches = [] - disposables = new CompositeDisposable for entry in searchersAndDirectories {searcher, directory} = entry - directorySearcher = searcher.search(directory, searchOptions) - disposables.add(directorySearcher.onDidMatch(onSearchResult)) - disposables.add(directorySearcher.onDidError(onSearchError)) recordNumberOfPathsSearched = onPathsSearched.bind(undefined, directory) - disposables.add(directorySearcher.onDidSearchPaths(recordNumberOfPathsSearched)) + delegate = Object.create(delegateProto, { + onDidSearchPaths: { + value: recordNumberOfPathsSearched, + } + }) + directorySearcher = searcher.search(directory, delegate, searchOptions) allSearches.push(directorySearcher) searchPromise = Promise.all(allSearches) - # Make sure to clean up the disposables once the searchPromise is determined. - disposeAll = (args...) -> - disposables.dispose() - searchPromise.then(disposeAll, disposeAll) - for buffer in atom.project.getBuffers() when buffer.isModified() filePath = buffer.getPath() continue unless atom.project.contains(filePath) From f7e822d41f7533358dece61980a37a43531a5c68 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Tue, 2 Jun 2015 17:52:03 -0400 Subject: [PATCH 1624/1783] Make delegate method names more delegate-like. --- spec/workspace-spec.coffee | 4 ++-- src/default-directory-searcher.coffee | 12 ++++++------ src/workspace.coffee | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index 1b05d6c10..29e4350b0 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -957,8 +957,8 @@ describe "Workspace", -> range: [[0, 0], [0, 5]], }, ] - delegate.onDidMatch(searchResult1) - delegate.onDidSearchPaths(numPathsToPretendToSearchInCustomDirectorySearcher) + delegate.didMatch(searchResult1) + delegate.didSearchPaths(numPathsToPretendToSearchInCustomDirectorySearcher) then: (args...) -> @promise.then.apply(@promise, args) cancel: -> diff --git a/src/default-directory-searcher.coffee b/src/default-directory-searcher.coffee index eec1ae4de..b209cca70 100644 --- a/src/default-directory-searcher.coffee +++ b/src/default-directory-searcher.coffee @@ -36,9 +36,9 @@ class DirectorySearch @task.on('task:cancelled', reject) emitter.once id, => @task.start(rootPaths, options.regexSource, options, resolve) - @task.on 'scan:result-found', delegate.onDidMatch - @task.on 'scan:file-error', delegate.onDidError - @task.on 'scan:paths-searched', delegate.onDidSearchPaths + @task.on 'scan:result-found', delegate.didMatch + @task.on 'scan:file-error', delegate.didError + @task.on 'scan:paths-searched', delegate.didSearchPaths # Public: Implementation of `then()` to satisfy the *thenable* contract. # This makes it possible to use a `DirectorySearch` with `Promise.all()`. @@ -72,7 +72,7 @@ class DefaultDirectorySearcher # * `directory` {Directory} that has been accepted by this provider's `canSearchDirectory()` # predicate. # * `delegate` {Object} with the following properties: - # * `onDidMatch` {Function} call with a search result structured as follows: + # * `didMatch` {Function} call with a search result structured as follows: # * `searchResult` {Object} with the following keys: # * `filePath` {String} absolute path to the matching file. # * `matches` {Array} with object elements with the following keys: @@ -80,8 +80,8 @@ class DefaultDirectorySearcher # * `lineTextOffset` {Number} (This always seems to be 0?) # * `matchText` {String} The text that matched the `regex` used for the search. # * `range` {Range} Identifies the matching region in the file. (Likely as an array of numeric arrays.) - # * `onDidError` {Function} call with an Error if there is a problem during the search. - # * `onDidSearchPaths` {Function} periodically call with the number of paths searched thus far. + # * `didError` {Function} call with an Error if there is a problem during the search. + # * `didSearchPaths` {Function} periodically call with the number of paths searched thus far. # * `options` {Object} with the following properties: # * `regexSource` {String} regex to search with. Produced via `RegExp::source`. # * `ignoreCase` {boolean} reflects whether the regex should be run with the `i` option. diff --git a/src/workspace.coffee b/src/workspace.coffee index e92b3ac34..f57888777 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -833,9 +833,9 @@ class Workspace extends Model # Now that we are sure every Directory has a searcher, construct the search options. delegateProto = { - onDidMatch: (result) -> + didMatch: (result) -> iterator(result) unless atom.project.isPathModified(result.filePath) - onDidError: (error) -> + didError: (error) -> iterator(null, error) } @@ -862,7 +862,7 @@ class Workspace extends Model {searcher, directory} = entry recordNumberOfPathsSearched = onPathsSearched.bind(undefined, directory) delegate = Object.create(delegateProto, { - onDidSearchPaths: { + didSearchPaths: { value: recordNumberOfPathsSearched, } }) From 898f7b87e8c43eb545f89394fa53a3d14b2ec347 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Tue, 2 Jun 2015 18:02:25 -0400 Subject: [PATCH 1625/1783] remove require for Disposable that is no longer needed --- spec/workspace-spec.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index 29e4350b0..b1e7b033c 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -1,6 +1,5 @@ path = require 'path' temp = require 'temp' -{Disposable} = require 'event-kit' Workspace = require '../src/workspace' Pane = require '../src/pane' {View} = require '../src/space-pen-extensions' From 10d9111f681d668dabe85a5c54f877ad0236c29a Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Tue, 2 Jun 2015 19:11:08 -0400 Subject: [PATCH 1626/1783] Clean up test to verify that an individual failed search fails the overall search. --- spec/workspace-spec.coffee | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index b1e7b033c..524adde5f 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -985,31 +985,27 @@ describe "Workspace", -> expect(onPathsSearched.mostRecentCall.args[0]).toBe( numPathsToPretendToSearchInCustomDirectorySearcher + numPathsSearchedInDir2) - it "can be cancelled by cancelling one of the DirectorySearchers", -> - customDirectorySearcherPromiseInstance = null - class CustomDirectorySearchToCancel + it "will have the side-effect of failing the overall search if it fails", -> + # Note that hoisting reject in this way is generally frowned upon. + hoistedReject = null + class CustomDirectorySearchThatWillFail constructor: -> - # Note that hoisting reject in this way is generally frowned upon. - @promise = new Promise (resolve, reject) => - @hoistedReject = reject - customDirectorySearcherPromiseInstance = this + @promise = new Promise (resolve, reject) -> + hoistedReject = reject then: (args...) -> @promise.then.apply(@promise, args) cancel: -> - @hoistedReject() class CustomDirectorySearcherToCancel canSearchDirectory: (directory) -> directory.getPath() is dir1 search: (directory, options) -> - new CustomDirectorySearchToCancel + new CustomDirectorySearchThatWillFail atom.packages.serviceHub.provide( "atom.directory-searcher", "0.1.0", new CustomDirectorySearcherToCancel()) - resultPaths = [] - cancelableSearch = atom.workspace.scan /aaaa/, ({filePath}) -> - resultPaths.push(filePath) - customDirectorySearcherPromiseInstance.cancel() + cancelableSearch = atom.workspace.scan /aaaa/, -> + hoistedReject() resultOfPromiseSearch = null waitsForPromise -> From 5fc9d9e01afe5ff381ae3662d2629ed8bf4d5618 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Tue, 2 Jun 2015 19:14:02 -0400 Subject: [PATCH 1627/1783] Document and test the `cancel()` method on the object returned by `atom.workspace.scan()`. --- spec/workspace-spec.coffee | 31 +++++++++++++++++++++++++++++++ src/workspace.coffee | 3 ++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index 524adde5f..07c543968 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -985,6 +985,37 @@ describe "Workspace", -> expect(onPathsSearched.mostRecentCall.args[0]).toBe( numPathsToPretendToSearchInCustomDirectorySearcher + numPathsSearchedInDir2) + it "can be cancelled when the object returned by scan() has its cancel() method invoked", -> + lastCustomDirectorySearchCreated = null + class CustomDirectorySearch + constructor: -> + lastCustomDirectorySearchCreated = this + @promise = Promise.resolve() + then: (args...) -> + @promise.then.apply(@promise, args) + cancel: -> + + class CustomDirectorySearcher + canSearchDirectory: (directory) -> directory.getPath() is dir1 + search: (directory, delegate, options) -> + new CustomDirectorySearch + + atom.packages.serviceHub.provide( + "atom.directory-searcher", "0.1.0", new CustomDirectorySearcher()) + + thenable = atom.workspace.scan /aaaa/, -> + cancelSpy = spyOn(lastCustomDirectorySearchCreated, 'cancel').andCallThrough() + expect(cancelSpy).not.toHaveBeenCalled() + thenable.cancel() + expect(cancelSpy).toHaveBeenCalled() + + resultOfPromiseSearch = null + waitsForPromise -> + thenable.then (promiseResult) -> resultOfPromiseSearch = promiseResult + + runs -> + expect(resultOfPromiseSearch).toBe('cancelled') + it "will have the side-effect of failing the overall search if it fails", -> # Note that hoisting reject in this way is generally frowned upon. hoistedReject = null diff --git a/src/workspace.coffee b/src/workspace.coffee index f57888777..77706fd69 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -803,7 +803,8 @@ class Workspace extends Model # * `onPathsSearched` (optional) {Function} # * `iterator` {Function} callback on each file found # - # Returns a `Promise`. + # Returns a *thenable* object with a `cancel()` method that will cancel all + # of the underlying searches that were started as part of this scan. scan: (regex, options={}, iterator) -> if _.isFunction(options) iterator = options From 318498464a766ad8f946bf126d083fefb5773003 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Wed, 3 Jun 2015 21:35:30 -0400 Subject: [PATCH 1628/1783] Responded to all of @maxbrunsfeld's comments except for: * The effect of a failed search. * Letting `DirectorySearcher::search` take multiple directories. I'm working on those now. --- spec/workspace-spec.coffee | 105 ++++++++++---------------- src/default-directory-searcher.coffee | 31 +++++--- src/workspace.coffee | 46 ++++------- 3 files changed, 75 insertions(+), 107 deletions(-) diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index 07c543968..26e348f72 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -939,36 +939,47 @@ describe "Workspace", -> expect(resultPaths).toEqual([file2]) describe "when a custom directory searcher is registered", -> + fakeSearch = null + # Function that is invoked once all of the fields on fakeSearch are set. + onFakeSearchCreated = null + + class FakeSearch + constructor: (@options) -> + # Note that hoisting resolve and reject in this way is generally frowned upon. + @promise = new Promise (resolve, reject) => + @hoistedResolve = resolve + @hoistedReject = reject + onFakeSearchCreated?(this) + then: (args...) -> + @promise.then.apply(@promise, args) + cancel: -> @cancelled = true + + beforeEach -> + fakeSearch = null + onFakeSearchCreated = null + atom.packages.serviceHub.provide('atom.directory-searcher', '0.1.0', { + canSearchDirectory: (directory) -> directory.getPath() is dir1 + search: (directory, regex, options) -> fakeSearch = new FakeSearch(options) + }) + it "can override the DefaultDirectorySearcher on a per-directory basis", -> foreignFilePath = 'ssh://foreign-directory:8080/hello.txt' numPathsSearchedInDir2 = 1 numPathsToPretendToSearchInCustomDirectorySearcher = 10 - class CustomDirectorySearch - constructor: (delegate) -> - @promise = Promise.resolve() - searchResult1 = - filePath: foreignFilePath, - matches: [ - { - lineText: 'Hello world', - lineTextOffset: 0, - matchText: 'Hello', - range: [[0, 0], [0, 5]], - }, - ] - delegate.didMatch(searchResult1) - delegate.didSearchPaths(numPathsToPretendToSearchInCustomDirectorySearcher) - then: (args...) -> - @promise.then.apply(@promise, args) - cancel: -> - - class CustomDirectorySearcher - canSearchDirectory: (directory) -> directory.getPath() is dir1 - search: (directory, delegate, options) -> - new CustomDirectorySearch(delegate) - - atom.packages.serviceHub.provide( - "atom.directory-searcher", "0.1.0", new CustomDirectorySearcher()) + searchResult = + filePath: foreignFilePath, + matches: [ + { + lineText: 'Hello world', + lineTextOffset: 0, + matchText: 'Hello', + range: [[0, 0], [0, 5]], + }, + ] + onFakeSearchCreated = (fakeSearch) -> + fakeSearch.options.didMatch(searchResult) + fakeSearch.options.didSearchPaths(numPathsToPretendToSearchInCustomDirectorySearcher) + fakeSearch.hoistedResolve() resultPaths = [] onPathsSearched = jasmine.createSpy('onPathsSearched') @@ -986,28 +997,10 @@ describe "Workspace", -> numPathsToPretendToSearchInCustomDirectorySearcher + numPathsSearchedInDir2) it "can be cancelled when the object returned by scan() has its cancel() method invoked", -> - lastCustomDirectorySearchCreated = null - class CustomDirectorySearch - constructor: -> - lastCustomDirectorySearchCreated = this - @promise = Promise.resolve() - then: (args...) -> - @promise.then.apply(@promise, args) - cancel: -> - - class CustomDirectorySearcher - canSearchDirectory: (directory) -> directory.getPath() is dir1 - search: (directory, delegate, options) -> - new CustomDirectorySearch - - atom.packages.serviceHub.provide( - "atom.directory-searcher", "0.1.0", new CustomDirectorySearcher()) - thenable = atom.workspace.scan /aaaa/, -> - cancelSpy = spyOn(lastCustomDirectorySearchCreated, 'cancel').andCallThrough() - expect(cancelSpy).not.toHaveBeenCalled() + expect(fakeSearch.cancelled).toBe(undefined) thenable.cancel() - expect(cancelSpy).toHaveBeenCalled() + expect(fakeSearch.cancelled).toBe(true) resultOfPromiseSearch = null waitsForPromise -> @@ -1017,26 +1010,8 @@ describe "Workspace", -> expect(resultOfPromiseSearch).toBe('cancelled') it "will have the side-effect of failing the overall search if it fails", -> - # Note that hoisting reject in this way is generally frowned upon. - hoistedReject = null - class CustomDirectorySearchThatWillFail - constructor: -> - @promise = new Promise (resolve, reject) -> - hoistedReject = reject - then: (args...) -> - @promise.then.apply(@promise, args) - cancel: -> - - class CustomDirectorySearcherToCancel - canSearchDirectory: (directory) -> directory.getPath() is dir1 - search: (directory, options) -> - new CustomDirectorySearchThatWillFail - - atom.packages.serviceHub.provide( - "atom.directory-searcher", "0.1.0", new CustomDirectorySearcherToCancel()) - cancelableSearch = atom.workspace.scan /aaaa/, -> - hoistedReject() + fakeSearch.hoistedReject() resultOfPromiseSearch = null waitsForPromise -> diff --git a/src/default-directory-searcher.coffee b/src/default-directory-searcher.coffee index b209cca70..912ad818f 100644 --- a/src/default-directory-searcher.coffee +++ b/src/default-directory-searcher.coffee @@ -29,16 +29,24 @@ enqueue = (id) -> class DirectorySearch # Public: Creates a new DirectorySearch that will not start running until the # `emitter` that is private to this file emits an event with the specified `id`. - constructor: (directory, delegate, options, id) -> + constructor: (directory, regex, options, id) -> + scanHandlerOptions = + ignoreCase: regex.ignoreCase + inclusions: options.inclusions + includeHidden: options.includeHidden + excludeVcsIgnores: options.excludeVcsIgnores + exclusions: options.exclusions + follow: options.follow + @task = new Task(require.resolve('./scan-handler')) rootPaths = [directory.getPath()] @promise = new Promise (resolve, reject) => @task.on('task:cancelled', reject) emitter.once id, => - @task.start(rootPaths, options.regexSource, options, resolve) - @task.on 'scan:result-found', delegate.didMatch - @task.on 'scan:file-error', delegate.didError - @task.on 'scan:paths-searched', delegate.didSearchPaths + @task.start(rootPaths, regex.source, scanHandlerOptions, resolve) + @task.on 'scan:result-found', options.didMatch + @task.on 'scan:file-error', options.didError + @task.on 'scan:paths-searched', options.didSearchPaths # Public: Implementation of `then()` to satisfy the *thenable* contract. # This makes it possible to use a `DirectorySearch` with `Promise.all()`. @@ -67,11 +75,13 @@ class DefaultDirectorySearcher # Public: Performs a text search for files in the specified `Directory`, subject to the # specified parameters. # - # Results are streamed back to the caller by invoking methods on the specified `delegate`. + # Results are streamed back to the caller by invoking methods on the specified `options`, + # such as `didMatch` and `didError`. # # * `directory` {Directory} that has been accepted by this provider's `canSearchDirectory()` # predicate. - # * `delegate` {Object} with the following properties: + # * `regex` {RegExp} to search with. + # * `options` {Object} with the following properties: # * `didMatch` {Function} call with a search result structured as follows: # * `searchResult` {Object} with the following keys: # * `filePath` {String} absolute path to the matching file. @@ -82,9 +92,6 @@ class DefaultDirectorySearcher # * `range` {Range} Identifies the matching region in the file. (Likely as an array of numeric arrays.) # * `didError` {Function} call with an Error if there is a problem during the search. # * `didSearchPaths` {Function} periodically call with the number of paths searched thus far. - # * `options` {Object} with the following properties: - # * `regexSource` {String} regex to search with. Produced via `RegExp::source`. - # * `ignoreCase` {boolean} reflects whether the regex should be run with the `i` option. # * `inclusions` {Array} of glob patterns (as strings) to search within. Note that this # array may be empty, indicating that all files should be searched. # @@ -98,10 +105,10 @@ class DefaultDirectorySearcher # # Returns a *thenable* `DirectorySearch` that includes a `cancel()` method. If `cancel()` is # invoked before the `DirectorySearch` is determined, it will reject the `DirectorySearch`. - search: (directory, delegate, options) -> + search: (directory, regex, options) -> id = nextId nextId += 1 - directorySearch = new DirectorySearch(directory, delegate, options, id) + directorySearch = new DirectorySearch(directory, regex, options, id) directorySearch.then(onSearchFinished, onSearchFinished) enqueue(id) directorySearch diff --git a/src/workspace.coffee b/src/workspace.coffee index 77706fd69..e9ac46bd2 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -47,7 +47,8 @@ class Workspace extends Model @paneContainer ?= new PaneContainer() @paneContainer.onDidDestroyPaneItem(@didDestroyPaneItem) - @directorySearchers = [new DefaultDirectorySearcher()] + @directorySearchers = [] + @defaultDirectorySearcher = new DefaultDirectorySearcher() atom.packages.serviceHub.consume( 'atom.directory-searcher', '^0.1.0', @@ -810,35 +811,15 @@ class Workspace extends Model iterator = options options = {} - searchOptions = - regexSource: regex.source - ignoreCase: regex.ignoreCase - inclusions: options.paths or [] - includeHidden: true - excludeVcsIgnores: atom.config.get('core.excludeVcsIgnoredPaths') - exclusions: atom.config.get('core.ignoredNames') - follow: atom.config.get('core.followSymlinks') - # Find a searcher for every Directory in the project. searchersAndDirectories = [] for directory in atom.project.getDirectories() - searcher = null + searcher = @defaultDirectorySearcher for directorySearcher in @directorySearchers if directorySearcher.canSearchDirectory(directory) searcher = directorySearcher break - if searcher - searchersAndDirectories.push({searcher, directory}) - else - throw Error("Could not find directory searcher for #{directory.getPath()}") - - # Now that we are sure every Directory has a searcher, construct the search options. - delegateProto = { - didMatch: (result) -> - iterator(result) unless atom.project.isPathModified(result.filePath) - didError: (error) -> - iterator(null, error) - } + searchersAndDirectories.push({searcher, directory}) # Define the onPathsSearched callback. if _.isFunction(options.onPathsSearched) @@ -861,13 +842,18 @@ class Workspace extends Model allSearches = [] for entry in searchersAndDirectories {searcher, directory} = entry - recordNumberOfPathsSearched = onPathsSearched.bind(undefined, directory) - delegate = Object.create(delegateProto, { - didSearchPaths: { - value: recordNumberOfPathsSearched, - } - }) - directorySearcher = searcher.search(directory, delegate, searchOptions) + searchOptions = + inclusions: options.paths or [] + includeHidden: true + excludeVcsIgnores: atom.config.get('core.excludeVcsIgnoredPaths') + exclusions: atom.config.get('core.ignoredNames') + follow: atom.config.get('core.followSymlinks') + didMatch: (result) -> + iterator(result) unless atom.project.isPathModified(result.filePath) + didError: (error) -> + iterator(null, error) + didSearchPaths: onPathsSearched.bind(undefined, directory) + directorySearcher = searcher.search(directory, regex, searchOptions) allSearches.push(directorySearcher) searchPromise = Promise.all(allSearches) From 36123faf5d33c5aba6f1a11d2a20d6cc4b2348e4 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Wed, 3 Jun 2015 21:54:41 -0400 Subject: [PATCH 1629/1783] Changed DefaultDirectorySearcher to take multiple directories. Still need to update `workspace.coffee` to make better use of this. --- src/default-directory-searcher.coffee | 63 ++++++++++----------------- src/workspace.coffee | 2 +- 2 files changed, 25 insertions(+), 40 deletions(-) diff --git a/src/default-directory-searcher.coffee b/src/default-directory-searcher.coffee index 912ad818f..5db5db8c2 100644 --- a/src/default-directory-searcher.coffee +++ b/src/default-directory-searcher.coffee @@ -1,35 +1,12 @@ -{EventEmitter} = require 'events' Task = require './task' -# Maintain a queue of ids of searches to run. When a search is complete, the active -# search is cleared and the next search (if any) in the queue is notified to run. -# This ensures there is at most one scan-handler task running at a time. -searchQueue = [] -nextId = 1 -activeSearchId = 0 -emitter = new EventEmitter - -onSearchFinished = -> - activeSearchId = null - runNextSearch() - -runNextSearch = -> - unless activeSearchId - activeSearchId = searchQueue.shift() - emitter.emit(activeSearchId, null) if activeSearchId - -enqueue = (id) -> - searchQueue.push(id) - runNextSearch() - - # Public: Searches local files for lines matching a specified regex. # # Implements thenable so it can be used with `Promise.all()`. class DirectorySearch # Public: Creates a new DirectorySearch that will not start running until the # `emitter` that is private to this file emits an event with the specified `id`. - constructor: (directory, regex, options, id) -> + constructor: (rootPath, regex, options) -> scanHandlerOptions = ignoreCase: regex.ignoreCase inclusions: options.inclusions @@ -37,16 +14,13 @@ class DirectorySearch excludeVcsIgnores: options.excludeVcsIgnores exclusions: options.exclusions follow: options.follow - @task = new Task(require.resolve('./scan-handler')) - rootPaths = [directory.getPath()] - @promise = new Promise (resolve, reject) => - @task.on('task:cancelled', reject) - emitter.once id, => - @task.start(rootPaths, regex.source, scanHandlerOptions, resolve) @task.on 'scan:result-found', options.didMatch @task.on 'scan:file-error', options.didError @task.on 'scan:paths-searched', options.didSearchPaths + @promise = new Promise (resolve, reject) => + @task.on('task:cancelled', reject) + @task.start([rootPath], regex.source, scanHandlerOptions, resolve) # Public: Implementation of `then()` to satisfy the *thenable* contract. # This makes it possible to use a `DirectorySearch` with `Promise.all()`. @@ -78,8 +52,8 @@ class DefaultDirectorySearcher # Results are streamed back to the caller by invoking methods on the specified `options`, # such as `didMatch` and `didError`. # - # * `directory` {Directory} that has been accepted by this provider's `canSearchDirectory()` - # predicate. + # * `directories` {Array} of {Directory} objects to search, all of which have been accepted by + # this searcher's `canSearchDirectory()` predicate. # * `regex` {RegExp} to search with. # * `options` {Object} with the following properties: # * `didMatch` {Function} call with a search result structured as follows: @@ -105,10 +79,21 @@ class DefaultDirectorySearcher # # Returns a *thenable* `DirectorySearch` that includes a `cancel()` method. If `cancel()` is # invoked before the `DirectorySearch` is determined, it will reject the `DirectorySearch`. - search: (directory, regex, options) -> - id = nextId - nextId += 1 - directorySearch = new DirectorySearch(directory, regex, options, id) - directorySearch.then(onSearchFinished, onSearchFinished) - enqueue(id) - directorySearch + search: (directories, regex, options) -> + rootPaths = directories.map (directory) -> directory.getPath() + isCancelled = false + promise = new Promise (resolve, reject) -> + run = -> + if isCancelled + reject() + else if rootPaths.length + rootPath = rootPaths.shift() + thenable = new DirectorySearch(rootPath, regex, options) + thenable.then(run, reject) + else + resolve() + run() + return { + then: promise.then.bind(promise) + cancel: -> isCancelled = true + } diff --git a/src/workspace.coffee b/src/workspace.coffee index e9ac46bd2..a2d3059de 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -853,7 +853,7 @@ class Workspace extends Model didError: (error) -> iterator(null, error) didSearchPaths: onPathsSearched.bind(undefined, directory) - directorySearcher = searcher.search(directory, regex, searchOptions) + directorySearcher = searcher.search([directory], regex, searchOptions) allSearches.push(directorySearcher) searchPromise = Promise.all(allSearches) From 7dc3d07f8aa3e8251bcc6b8caf0a87f48dbc2bff Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Wed, 3 Jun 2015 22:20:39 -0400 Subject: [PATCH 1630/1783] Changed the contract of `DefaultDirectorySearcher` in two significant ways: * `search()` takes an array of `Directory` objects rather than an individual object. * `options.didSearchPaths` now takes the `Directory` in addition to the `count` as an argument. --- spec/workspace-spec.coffee | 3 +- src/default-directory-searcher.coffee | 18 ++++++------ src/workspace.coffee | 40 +++++++++++++++------------ 3 files changed, 34 insertions(+), 27 deletions(-) diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index 26e348f72..bfada8b43 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -978,7 +978,8 @@ describe "Workspace", -> ] onFakeSearchCreated = (fakeSearch) -> fakeSearch.options.didMatch(searchResult) - fakeSearch.options.didSearchPaths(numPathsToPretendToSearchInCustomDirectorySearcher) + directory1 = atom.project.getDirectories()[atom.project.getPaths().indexOf(dir1)] + fakeSearch.options.didSearchPaths(directory1, numPathsToPretendToSearchInCustomDirectorySearcher) fakeSearch.hoistedResolve() resultPaths = [] diff --git a/src/default-directory-searcher.coffee b/src/default-directory-searcher.coffee index 5db5db8c2..4767a0313 100644 --- a/src/default-directory-searcher.coffee +++ b/src/default-directory-searcher.coffee @@ -4,9 +4,7 @@ Task = require './task' # # Implements thenable so it can be used with `Promise.all()`. class DirectorySearch - # Public: Creates a new DirectorySearch that will not start running until the - # `emitter` that is private to this file emits an event with the specified `id`. - constructor: (rootPath, regex, options) -> + constructor: (directory, regex, options) -> scanHandlerOptions = ignoreCase: regex.ignoreCase inclusions: options.inclusions @@ -17,10 +15,10 @@ class DirectorySearch @task = new Task(require.resolve('./scan-handler')) @task.on 'scan:result-found', options.didMatch @task.on 'scan:file-error', options.didError - @task.on 'scan:paths-searched', options.didSearchPaths + @task.on 'scan:paths-searched', (count) -> options.didSearchPaths(directory, count) @promise = new Promise (resolve, reject) => @task.on('task:cancelled', reject) - @task.start([rootPath], regex.source, scanHandlerOptions, resolve) + @task.start([directory.getPath()], regex.source, scanHandlerOptions, resolve) # Public: Implementation of `then()` to satisfy the *thenable* contract. # This makes it possible to use a `DirectorySearch` with `Promise.all()`. @@ -66,6 +64,7 @@ class DefaultDirectorySearcher # * `range` {Range} Identifies the matching region in the file. (Likely as an array of numeric arrays.) # * `didError` {Function} call with an Error if there is a problem during the search. # * `didSearchPaths` {Function} periodically call with the number of paths searched thus far. + # This takes two arguments: the `Directory` and the count. # * `inclusions` {Array} of glob patterns (as strings) to search within. Note that this # array may be empty, indicating that all files should be searched. # @@ -80,15 +79,16 @@ class DefaultDirectorySearcher # Returns a *thenable* `DirectorySearch` that includes a `cancel()` method. If `cancel()` is # invoked before the `DirectorySearch` is determined, it will reject the `DirectorySearch`. search: (directories, regex, options) -> - rootPaths = directories.map (directory) -> directory.getPath() + # Make a mutable copy of the directories array. + directories = directories.slice(0) isCancelled = false promise = new Promise (resolve, reject) -> run = -> if isCancelled reject() - else if rootPaths.length - rootPath = rootPaths.shift() - thenable = new DirectorySearch(rootPath, regex, options) + else if directories.length + directory = directories.shift() + thenable = new DirectorySearch(directory, regex, options) thenable.then(run, reject) else resolve() diff --git a/src/workspace.coffee b/src/workspace.coffee index a2d3059de..638fa8a0a 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -811,15 +811,20 @@ class Workspace extends Model iterator = options options = {} - # Find a searcher for every Directory in the project. - searchersAndDirectories = [] + # Find a searcher for every Directory in the project. Each searcher that is matched + # will be associated with an Array of Directory objects in the Map. + directoriesForSearcher = new Map() for directory in atom.project.getDirectories() searcher = @defaultDirectorySearcher for directorySearcher in @directorySearchers if directorySearcher.canSearchDirectory(directory) searcher = directorySearcher break - searchersAndDirectories.push({searcher, directory}) + directories = directoriesForSearcher.get(searcher) + unless directories + directories = [] + directoriesForSearcher.set(searcher, directories) + directories.push(directory) # Define the onPathsSearched callback. if _.isFunction(options.onPathsSearched) @@ -838,22 +843,23 @@ class Workspace extends Model else onPathsSearched = -> + # Build up the options object that will be shared by all searchers. + searchOptions = + inclusions: options.paths or [] + includeHidden: true + excludeVcsIgnores: atom.config.get('core.excludeVcsIgnoredPaths') + exclusions: atom.config.get('core.ignoredNames') + follow: atom.config.get('core.followSymlinks') + didMatch: (result) -> + iterator(result) unless atom.project.isPathModified(result.filePath) + didError: (error) -> + iterator(null, error) + didSearchPaths: onPathsSearched + # Kick off all of the searches and unify them into one Promise. allSearches = [] - for entry in searchersAndDirectories - {searcher, directory} = entry - searchOptions = - inclusions: options.paths or [] - includeHidden: true - excludeVcsIgnores: atom.config.get('core.excludeVcsIgnoredPaths') - exclusions: atom.config.get('core.ignoredNames') - follow: atom.config.get('core.followSymlinks') - didMatch: (result) -> - iterator(result) unless atom.project.isPathModified(result.filePath) - didError: (error) -> - iterator(null, error) - didSearchPaths: onPathsSearched.bind(undefined, directory) - directorySearcher = searcher.search([directory], regex, searchOptions) + directoriesForSearcher.forEach (directories, searcher) -> + directorySearcher = searcher.search(directories, regex, searchOptions) allSearches.push(directorySearcher) searchPromise = Promise.all(allSearches) From 028ac79836ac4e326230bc89f76aa4af3c0e3a01 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Wed, 3 Jun 2015 22:41:58 -0400 Subject: [PATCH 1631/1783] Changed the behavior so that if a searcher rejects, then the thenable returned by `atom.workspace.scan()` rejects. --- spec/workspace-spec.coffee | 6 +++--- src/workspace.coffee | 9 ++++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index bfada8b43..7e7ee406a 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -1014,12 +1014,12 @@ describe "Workspace", -> cancelableSearch = atom.workspace.scan /aaaa/, -> fakeSearch.hoistedReject() - resultOfPromiseSearch = null + didReject = false waitsForPromise -> - cancelableSearch.then (promiseResult) -> resultOfPromiseSearch = promiseResult + cancelableSearch.catch -> didReject = true runs -> - expect(resultOfPromiseSearch).toBe('cancelled') + expect(didReject).toBe(true) describe "::replace(regex, replacementText, paths, iterator)", -> [filePath, commentFilePath, sampleContent, sampleCommentContent] = [] diff --git a/src/workspace.coffee b/src/workspace.coffee index 638fa8a0a..924ad3bc5 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -874,15 +874,18 @@ class Workspace extends Model # with the existing behavior, instead of cancel() rejecting the promise, it should # resolve it with the special value 'cancelled'. At least the built-in find-and-replace # package relies on this behavior. + isCancelled = false cancellablePromise = new Promise (resolve, reject) -> onSuccess = -> resolve(null) - return onFailure = -> - resolve('cancelled') - return + if isCancelled + resolve('cancelled') + else + reject() searchPromise.then(onSuccess, onFailure) cancellablePromise.cancel = -> + isCancelled = true # Note that cancelling all (or actually, any) of the members of allSearches # will cause searchPromise to reject, which will cause cancellablePromise to resolve # in the desired way. From 18ac7d0cbcbafd0ffabb019839c8e0dff3d8b3d5 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Wed, 3 Jun 2015 23:01:02 -0400 Subject: [PATCH 1632/1783] Comment excised, as recommended by @maxbrunsfeld. --- src/workspace.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/workspace.coffee b/src/workspace.coffee index 924ad3bc5..61c16a5c1 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -52,8 +52,6 @@ class Workspace extends Model atom.packages.serviceHub.consume( 'atom.directory-searcher', '^0.1.0', - # New providers are added to the front of @directorySearchers because - # DefaultDirectorySearcher is a catch-all that will always claim to search a Directory. (provider) => @directorySearchers.unshift(provider)) @panelContainers = From 0630bce95c6dadc6f212f4129528043ecef47edd Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Wed, 3 Jun 2015 23:29:56 -0400 Subject: [PATCH 1633/1783] Two things: * Removed the `Directory` argument to `didSearchPaths`. Now each searcher gets its own instance of `didSearchPaths` that is parameterized by provider. * Simplified `DefaultDirectorySearcher.search()` so it creates one `DirectorySearch` rather than one per `Directory` passed to `search()`. --- spec/workspace-spec.coffee | 7 ++++--- src/default-directory-searcher.coffee | 26 ++++++++++------------- src/workspace.coffee | 30 +++++++++++++-------------- 3 files changed, 29 insertions(+), 34 deletions(-) diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index 7e7ee406a..4666177c6 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -952,7 +952,9 @@ describe "Workspace", -> onFakeSearchCreated?(this) then: (args...) -> @promise.then.apply(@promise, args) - cancel: -> @cancelled = true + cancel: -> + @cancelled = true + @hoistedReject() beforeEach -> fakeSearch = null @@ -978,8 +980,7 @@ describe "Workspace", -> ] onFakeSearchCreated = (fakeSearch) -> fakeSearch.options.didMatch(searchResult) - directory1 = atom.project.getDirectories()[atom.project.getPaths().indexOf(dir1)] - fakeSearch.options.didSearchPaths(directory1, numPathsToPretendToSearchInCustomDirectorySearcher) + fakeSearch.options.didSearchPaths(numPathsToPretendToSearchInCustomDirectorySearcher) fakeSearch.hoistedResolve() resultPaths = [] diff --git a/src/default-directory-searcher.coffee b/src/default-directory-searcher.coffee index 4767a0313..a5f113eeb 100644 --- a/src/default-directory-searcher.coffee +++ b/src/default-directory-searcher.coffee @@ -4,7 +4,7 @@ Task = require './task' # # Implements thenable so it can be used with `Promise.all()`. class DirectorySearch - constructor: (directory, regex, options) -> + constructor: (rootPaths, regex, options) -> scanHandlerOptions = ignoreCase: regex.ignoreCase inclusions: options.inclusions @@ -15,10 +15,10 @@ class DirectorySearch @task = new Task(require.resolve('./scan-handler')) @task.on 'scan:result-found', options.didMatch @task.on 'scan:file-error', options.didError - @task.on 'scan:paths-searched', (count) -> options.didSearchPaths(directory, count) + @task.on 'scan:paths-searched', options.didSearchPaths @promise = new Promise (resolve, reject) => @task.on('task:cancelled', reject) - @task.start([directory.getPath()], regex.source, scanHandlerOptions, resolve) + @task.start(rootPaths, regex.source, scanHandlerOptions, resolve) # Public: Implementation of `then()` to satisfy the *thenable* contract. # This makes it possible to use a `DirectorySearch` with `Promise.all()`. @@ -64,7 +64,6 @@ class DefaultDirectorySearcher # * `range` {Range} Identifies the matching region in the file. (Likely as an array of numeric arrays.) # * `didError` {Function} call with an Error if there is a problem during the search. # * `didSearchPaths` {Function} periodically call with the number of paths searched thus far. - # This takes two arguments: the `Directory` and the count. # * `inclusions` {Array} of glob patterns (as strings) to search within. Note that this # array may be empty, indicating that all files should be searched. # @@ -79,21 +78,18 @@ class DefaultDirectorySearcher # Returns a *thenable* `DirectorySearch` that includes a `cancel()` method. If `cancel()` is # invoked before the `DirectorySearch` is determined, it will reject the `DirectorySearch`. search: (directories, regex, options) -> - # Make a mutable copy of the directories array. - directories = directories.slice(0) + rootPaths = directories.map (directory) -> directory.getPath() isCancelled = false + directorySearch = new DirectorySearch(rootPaths, regex, options) promise = new Promise (resolve, reject) -> - run = -> + directorySearch.then resolve, -> if isCancelled - reject() - else if directories.length - directory = directories.shift() - thenable = new DirectorySearch(directory, regex, options) - thenable.then(run, reject) - else resolve() - run() + else + reject() return { then: promise.then.bind(promise) - cancel: -> isCancelled = true + cancel: -> + isCancelled = true + directorySearch.cancel() } diff --git a/src/workspace.coffee b/src/workspace.coffee index 61c16a5c1..23cf25620 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -831,32 +831,30 @@ class Workspace extends Model onPathsSearchedOption = options.onPathsSearched totalNumberOfPathsSearched = 0 numberOfPathsSearchedForDirectory = new Map() - onPathsSearched = (directory, numberOfPathsSearched) -> - oldValue = numberOfPathsSearchedForDirectory.get(directory) + onPathsSearched = (searcher, numberOfPathsSearched) -> + oldValue = numberOfPathsSearchedForDirectory.get(searcher) if oldValue totalNumberOfPathsSearched -= oldValue - numberOfPathsSearchedForDirectory.set(directory, numberOfPathsSearched) + numberOfPathsSearchedForDirectory.set(searcher, numberOfPathsSearched) totalNumberOfPathsSearched += numberOfPathsSearched onPathsSearchedOption(totalNumberOfPathsSearched) else onPathsSearched = -> - # Build up the options object that will be shared by all searchers. - searchOptions = - inclusions: options.paths or [] - includeHidden: true - excludeVcsIgnores: atom.config.get('core.excludeVcsIgnoredPaths') - exclusions: atom.config.get('core.ignoredNames') - follow: atom.config.get('core.followSymlinks') - didMatch: (result) -> - iterator(result) unless atom.project.isPathModified(result.filePath) - didError: (error) -> - iterator(null, error) - didSearchPaths: onPathsSearched - # Kick off all of the searches and unify them into one Promise. allSearches = [] directoriesForSearcher.forEach (directories, searcher) -> + searchOptions = + inclusions: options.paths or [] + includeHidden: true + excludeVcsIgnores: atom.config.get('core.excludeVcsIgnoredPaths') + exclusions: atom.config.get('core.ignoredNames') + follow: atom.config.get('core.followSymlinks') + didMatch: (result) -> + iterator(result) unless atom.project.isPathModified(result.filePath) + didError: (error) -> + iterator(null, error) + didSearchPaths: (count) -> onPathsSearched(searcher, count) directorySearcher = searcher.search(directories, regex, searchOptions) allSearches.push(directorySearcher) searchPromise = Promise.all(allSearches) From 6b1b57c89cd43b21487b5d8d0fd130797395ec04 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Wed, 3 Jun 2015 23:33:10 -0400 Subject: [PATCH 1634/1783] Rename a variable to reflect a change in the previous commit. --- src/workspace.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/workspace.coffee b/src/workspace.coffee index 23cf25620..7a0787dcd 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -830,12 +830,12 @@ class Workspace extends Model # replace the entry in the map and update the total. onPathsSearchedOption = options.onPathsSearched totalNumberOfPathsSearched = 0 - numberOfPathsSearchedForDirectory = new Map() + numberOfPathsSearchedForSearcher = new Map() onPathsSearched = (searcher, numberOfPathsSearched) -> - oldValue = numberOfPathsSearchedForDirectory.get(searcher) + oldValue = numberOfPathsSearchedForSearcher.get(searcher) if oldValue totalNumberOfPathsSearched -= oldValue - numberOfPathsSearchedForDirectory.set(searcher, numberOfPathsSearched) + numberOfPathsSearchedForSearcher.set(searcher, numberOfPathsSearched) totalNumberOfPathsSearched += numberOfPathsSearched onPathsSearchedOption(totalNumberOfPathsSearched) else From 1a6c542b45a8a0868c94629acedd6277fe84a594 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Wed, 3 Jun 2015 23:38:52 -0400 Subject: [PATCH 1635/1783] Update comment. --- src/default-directory-searcher.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/default-directory-searcher.coffee b/src/default-directory-searcher.coffee index a5f113eeb..ebe3a35f9 100644 --- a/src/default-directory-searcher.coffee +++ b/src/default-directory-searcher.coffee @@ -76,7 +76,7 @@ class DefaultDirectorySearcher # * `follow` {boolean} whether symlinks should be followed. # # Returns a *thenable* `DirectorySearch` that includes a `cancel()` method. If `cancel()` is - # invoked before the `DirectorySearch` is determined, it will reject the `DirectorySearch`. + # invoked before the `DirectorySearch` is determined, it will resolve the `DirectorySearch`. search: (directories, regex, options) -> rootPaths = directories.map (directory) -> directory.getPath() isCancelled = false From 535c0e2f3441bfd3bad81b1d38f57626aef9456b Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Thu, 4 Jun 2015 20:15:49 -0400 Subject: [PATCH 1636/1783] Fix documentation bug. --- src/workspace.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/workspace.coffee b/src/workspace.coffee index 7a0787dcd..6311cdd6d 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -802,7 +802,7 @@ class Workspace extends Model # * `onPathsSearched` (optional) {Function} # * `iterator` {Function} callback on each file found # - # Returns a *thenable* object with a `cancel()` method that will cancel all + # Returns a `Promise` with a `cancel()` method that will cancel all # of the underlying searches that were started as part of this scan. scan: (regex, options={}, iterator) -> if _.isFunction(options) From fb48b38aa72fba4652529b9a6fb7d8c7f65438af Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 9 Jun 2015 09:36:20 -0700 Subject: [PATCH 1637/1783] Guard against no resizing with no siblings Closes #7091 --- spec/pane-container-element-spec.coffee | 6 ++++++ src/pane-resize-handle-element.coffee | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/spec/pane-container-element-spec.coffee b/spec/pane-container-element-spec.coffee index 400904f5c..8947a6d31 100644 --- a/spec/pane-container-element-spec.coffee +++ b/spec/pane-container-element-spec.coffee @@ -154,3 +154,9 @@ describe "PaneContainerElement", -> container.destroy() expect(element.resizeStopped.callCount).toBe 1 expect(document.removeEventListener.callCount).toBe 2 + + it "does not throw an error when resized to fit content in a detached state", -> + container.getActivePane().splitRight() + element = getResizeElement(0) + element.remove() + expect(-> element.resizeToFitContent()).not.toThrow() diff --git a/src/pane-resize-handle-element.coffee b/src/pane-resize-handle-element.coffee index 078bb44ac..836dead52 100644 --- a/src/pane-resize-handle-element.coffee +++ b/src/pane-resize-handle-element.coffee @@ -17,8 +17,8 @@ class PaneResizeHandleElement extends HTMLElement resizeToFitContent: -> # clear flex-grow css style of both pane - @previousSibling.model.setFlexScale(1) - @nextSibling.model.setFlexScale(1) + @previousSibling?.model.setFlexScale(1) + @nextSibling?.model.setFlexScale(1) resizeStarted: (e) -> e.stopPropagation() From 51f0a6bc9a3878453302b208c4a0392949a614fa Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 9 Jun 2015 11:09:02 -0700 Subject: [PATCH 1638/1783] :arrow_up: tabs@0.77 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c331fb413..4937730b5 100644 --- a/package.json +++ b/package.json @@ -120,7 +120,7 @@ "status-bar": "0.74.0", "styleguide": "0.44.0", "symbols-view": "0.98.0", - "tabs": "0.76.0", + "tabs": "0.77.0", "timecop": "0.31.0", "tree-view": "0.172.0", "update-package-dependencies": "0.10.0", From a3f6a9e64c8fe6897257a0e824c4cc8660c90c20 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 9 Jun 2015 11:38:27 -0700 Subject: [PATCH 1639/1783] :arrow_up: welcome@0.29 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4937730b5..cc3902e99 100644 --- a/package.json +++ b/package.json @@ -124,7 +124,7 @@ "timecop": "0.31.0", "tree-view": "0.172.0", "update-package-dependencies": "0.10.0", - "welcome": "0.28.0", + "welcome": "0.29.0", "whitespace": "0.30.0", "wrap-guide": "0.35.0", "language-c": "0.45.0", From 262d41c3064b9fd899d9e158e5207b35052ef742 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 9 Jun 2015 11:51:30 -0700 Subject: [PATCH 1640/1783] Revert "Introduce atom.directory-searcher service v0.1.0." --- spec/task-spec.coffee | 26 ------ spec/workspace-spec.coffee | 84 ------------------- src/default-directory-searcher.coffee | 95 ---------------------- src/task.coffee | 10 +-- src/workspace.coffee | 111 ++++++-------------------- 5 files changed, 28 insertions(+), 298 deletions(-) delete mode 100644 src/default-directory-searcher.coffee diff --git a/spec/task-spec.coffee b/spec/task-spec.coffee index 947db5567..bddb59d86 100644 --- a/spec/task-spec.coffee +++ b/spec/task-spec.coffee @@ -70,29 +70,3 @@ describe "Task", -> task.terminate() expect(stdout.listeners('data').length).toBe 0 expect(stderr.listeners('data').length).toBe 0 - - describe "::cancel()", -> - it "dispatches 'task:cancelled' when invoked on an active task", -> - task = new Task(require.resolve('./fixtures/task-spec-handler')) - cancelledEventSpy = jasmine.createSpy('eventSpy') - task.on('task:cancelled', cancelledEventSpy) - completedEventSpy = jasmine.createSpy('eventSpy') - task.on('task:completed', completedEventSpy) - - expect(task.cancel()).toBe(true) - expect(cancelledEventSpy).toHaveBeenCalled() - expect(completedEventSpy).not.toHaveBeenCalled() - - it "does not dispatch 'task:cancelled' when invoked on an inactive task", -> - handlerResult = null - task = Task.once require.resolve('./fixtures/task-spec-handler'), (result) -> - handlerResult = result - - waitsFor -> - handlerResult? - - runs -> - cancelledEventSpy = jasmine.createSpy('eventSpy') - task.on('task:cancelled', cancelledEventSpy) - expect(task.cancel()).toBe(false) - expect(cancelledEventSpy).not.toHaveBeenCalled() diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index 4666177c6..4918fc65f 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -938,90 +938,6 @@ describe "Workspace", -> .then -> expect(resultPaths).toEqual([file2]) - describe "when a custom directory searcher is registered", -> - fakeSearch = null - # Function that is invoked once all of the fields on fakeSearch are set. - onFakeSearchCreated = null - - class FakeSearch - constructor: (@options) -> - # Note that hoisting resolve and reject in this way is generally frowned upon. - @promise = new Promise (resolve, reject) => - @hoistedResolve = resolve - @hoistedReject = reject - onFakeSearchCreated?(this) - then: (args...) -> - @promise.then.apply(@promise, args) - cancel: -> - @cancelled = true - @hoistedReject() - - beforeEach -> - fakeSearch = null - onFakeSearchCreated = null - atom.packages.serviceHub.provide('atom.directory-searcher', '0.1.0', { - canSearchDirectory: (directory) -> directory.getPath() is dir1 - search: (directory, regex, options) -> fakeSearch = new FakeSearch(options) - }) - - it "can override the DefaultDirectorySearcher on a per-directory basis", -> - foreignFilePath = 'ssh://foreign-directory:8080/hello.txt' - numPathsSearchedInDir2 = 1 - numPathsToPretendToSearchInCustomDirectorySearcher = 10 - searchResult = - filePath: foreignFilePath, - matches: [ - { - lineText: 'Hello world', - lineTextOffset: 0, - matchText: 'Hello', - range: [[0, 0], [0, 5]], - }, - ] - onFakeSearchCreated = (fakeSearch) -> - fakeSearch.options.didMatch(searchResult) - fakeSearch.options.didSearchPaths(numPathsToPretendToSearchInCustomDirectorySearcher) - fakeSearch.hoistedResolve() - - resultPaths = [] - onPathsSearched = jasmine.createSpy('onPathsSearched') - waitsForPromise -> - atom.workspace.scan /aaaa/, {onPathsSearched}, ({filePath}) -> - resultPaths.push(filePath) - - runs -> - expect(resultPaths.sort()).toEqual([foreignFilePath, file2].sort()) - # onPathsSearched should be called once by each DirectorySearcher. The order is not - # guaranteed, so we can only verify the total number of paths searched is correct - # after the second call. - expect(onPathsSearched.callCount).toBe(2) - expect(onPathsSearched.mostRecentCall.args[0]).toBe( - numPathsToPretendToSearchInCustomDirectorySearcher + numPathsSearchedInDir2) - - it "can be cancelled when the object returned by scan() has its cancel() method invoked", -> - thenable = atom.workspace.scan /aaaa/, -> - expect(fakeSearch.cancelled).toBe(undefined) - thenable.cancel() - expect(fakeSearch.cancelled).toBe(true) - - resultOfPromiseSearch = null - waitsForPromise -> - thenable.then (promiseResult) -> resultOfPromiseSearch = promiseResult - - runs -> - expect(resultOfPromiseSearch).toBe('cancelled') - - it "will have the side-effect of failing the overall search if it fails", -> - cancelableSearch = atom.workspace.scan /aaaa/, -> - fakeSearch.hoistedReject() - - didReject = false - waitsForPromise -> - cancelableSearch.catch -> didReject = true - - runs -> - expect(didReject).toBe(true) - describe "::replace(regex, replacementText, paths, iterator)", -> [filePath, commentFilePath, sampleContent, sampleCommentContent] = [] diff --git a/src/default-directory-searcher.coffee b/src/default-directory-searcher.coffee deleted file mode 100644 index ebe3a35f9..000000000 --- a/src/default-directory-searcher.coffee +++ /dev/null @@ -1,95 +0,0 @@ -Task = require './task' - -# Public: Searches local files for lines matching a specified regex. -# -# Implements thenable so it can be used with `Promise.all()`. -class DirectorySearch - constructor: (rootPaths, regex, options) -> - scanHandlerOptions = - ignoreCase: regex.ignoreCase - inclusions: options.inclusions - includeHidden: options.includeHidden - excludeVcsIgnores: options.excludeVcsIgnores - exclusions: options.exclusions - follow: options.follow - @task = new Task(require.resolve('./scan-handler')) - @task.on 'scan:result-found', options.didMatch - @task.on 'scan:file-error', options.didError - @task.on 'scan:paths-searched', options.didSearchPaths - @promise = new Promise (resolve, reject) => - @task.on('task:cancelled', reject) - @task.start(rootPaths, regex.source, scanHandlerOptions, resolve) - - # Public: Implementation of `then()` to satisfy the *thenable* contract. - # This makes it possible to use a `DirectorySearch` with `Promise.all()`. - # - # Returns `Promise`. - then: (args...) -> - @promise.then.apply(@promise, args) - - # Public: Cancels the search. - cancel: -> - # This will cause @promise to reject. - @task.cancel() - null - - -# Default provider for the `atom.directory-searcher` service. -module.exports = -class DefaultDirectorySearcher - # Public: Determines whether this object supports search for a `Directory`. - # - # * `directory` {Directory} whose search needs might be supported by this object. - # - # Returns a `boolean` indicating whether this object can search this `Directory`. - canSearchDirectory: (directory) -> true - - # Public: Performs a text search for files in the specified `Directory`, subject to the - # specified parameters. - # - # Results are streamed back to the caller by invoking methods on the specified `options`, - # such as `didMatch` and `didError`. - # - # * `directories` {Array} of {Directory} objects to search, all of which have been accepted by - # this searcher's `canSearchDirectory()` predicate. - # * `regex` {RegExp} to search with. - # * `options` {Object} with the following properties: - # * `didMatch` {Function} call with a search result structured as follows: - # * `searchResult` {Object} with the following keys: - # * `filePath` {String} absolute path to the matching file. - # * `matches` {Array} with object elements with the following keys: - # * `lineText` {String} The full text of the matching line (without a line terminator character). - # * `lineTextOffset` {Number} (This always seems to be 0?) - # * `matchText` {String} The text that matched the `regex` used for the search. - # * `range` {Range} Identifies the matching region in the file. (Likely as an array of numeric arrays.) - # * `didError` {Function} call with an Error if there is a problem during the search. - # * `didSearchPaths` {Function} periodically call with the number of paths searched thus far. - # * `inclusions` {Array} of glob patterns (as strings) to search within. Note that this - # array may be empty, indicating that all files should be searched. - # - # Each item in the array is a file/directory pattern, e.g., `src` to search in the "src" - # directory or `*.js` to search all JavaScript files. In practice, this often comes from the - # comma-delimited list of patterns in the bottom text input of the ProjectFindView dialog. - # * `ignoreHidden` {boolean} whether to ignore hidden files. - # * `excludeVcsIgnores` {boolean} whether to exclude VCS ignored paths. - # * `exclusions` {Array} similar to inclusions - # * `follow` {boolean} whether symlinks should be followed. - # - # Returns a *thenable* `DirectorySearch` that includes a `cancel()` method. If `cancel()` is - # invoked before the `DirectorySearch` is determined, it will resolve the `DirectorySearch`. - search: (directories, regex, options) -> - rootPaths = directories.map (directory) -> directory.getPath() - isCancelled = false - directorySearch = new DirectorySearch(rootPaths, regex, options) - promise = new Promise (resolve, reject) -> - directorySearch.then resolve, -> - if isCancelled - resolve() - else - reject() - return { - then: promise.then.bind(promise) - cancel: -> - isCancelled = true - directorySearch.cancel() - } diff --git a/src/task.coffee b/src/task.coffee index 34c943c6a..939b71635 100644 --- a/src/task.coffee +++ b/src/task.coffee @@ -150,7 +150,7 @@ class Task # # No more events are emitted once this method is called. terminate: -> - return false unless @childProcess? + return unless @childProcess? @childProcess.removeAllListeners() @childProcess.stdout.removeAllListeners() @@ -158,10 +158,4 @@ class Task @childProcess.kill() @childProcess = null - true - - cancel: -> - didForcefullyTerminate = @terminate() - if didForcefullyTerminate - @emit('task:cancelled') - didForcefullyTerminate + undefined diff --git a/src/workspace.coffee b/src/workspace.coffee index 6311cdd6d..157d002de 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -7,7 +7,6 @@ Serializable = require 'serializable' {Emitter, Disposable, CompositeDisposable} = require 'event-kit' Grim = require 'grim' fs = require 'fs-plus' -DefaultDirectorySearcher = require './default-directory-searcher' Model = require './model' TextEditor = require './text-editor' PaneContainer = require './pane-container' @@ -47,13 +46,6 @@ class Workspace extends Model @paneContainer ?= new PaneContainer() @paneContainer.onDidDestroyPaneItem(@didDestroyPaneItem) - @directorySearchers = [] - @defaultDirectorySearcher = new DefaultDirectorySearcher() - atom.packages.serviceHub.consume( - 'atom.directory-searcher', - '^0.1.0', - (provider) => @directorySearchers.unshift(provider)) - @panelContainers = top: new PanelContainer({location: 'top'}) left: new PanelContainer({location: 'left'}) @@ -799,65 +791,36 @@ class Workspace extends Model # * `regex` {RegExp} to search with. # * `options` (optional) {Object} (default: {}) # * `paths` An {Array} of glob patterns to search within - # * `onPathsSearched` (optional) {Function} # * `iterator` {Function} callback on each file found # - # Returns a `Promise` with a `cancel()` method that will cancel all - # of the underlying searches that were started as part of this scan. + # Returns a `Promise`. scan: (regex, options={}, iterator) -> if _.isFunction(options) iterator = options options = {} - # Find a searcher for every Directory in the project. Each searcher that is matched - # will be associated with an Array of Directory objects in the Map. - directoriesForSearcher = new Map() - for directory in atom.project.getDirectories() - searcher = @defaultDirectorySearcher - for directorySearcher in @directorySearchers - if directorySearcher.canSearchDirectory(directory) - searcher = directorySearcher - break - directories = directoriesForSearcher.get(searcher) - unless directories - directories = [] - directoriesForSearcher.set(searcher, directories) - directories.push(directory) + deferred = Q.defer() + + searchOptions = + ignoreCase: regex.ignoreCase + inclusions: options.paths + includeHidden: true + excludeVcsIgnores: atom.config.get('core.excludeVcsIgnoredPaths') + exclusions: atom.config.get('core.ignoredNames') + follow: atom.config.get('core.followSymlinks') + + task = Task.once require.resolve('./scan-handler'), atom.project.getPaths(), regex.source, searchOptions, -> + deferred.resolve() + + task.on 'scan:result-found', (result) -> + iterator(result) unless atom.project.isPathModified(result.filePath) + + task.on 'scan:file-error', (error) -> + iterator(null, error) - # Define the onPathsSearched callback. if _.isFunction(options.onPathsSearched) - # Maintain a map of directories to the number of search results. When notified of a new count, - # replace the entry in the map and update the total. - onPathsSearchedOption = options.onPathsSearched - totalNumberOfPathsSearched = 0 - numberOfPathsSearchedForSearcher = new Map() - onPathsSearched = (searcher, numberOfPathsSearched) -> - oldValue = numberOfPathsSearchedForSearcher.get(searcher) - if oldValue - totalNumberOfPathsSearched -= oldValue - numberOfPathsSearchedForSearcher.set(searcher, numberOfPathsSearched) - totalNumberOfPathsSearched += numberOfPathsSearched - onPathsSearchedOption(totalNumberOfPathsSearched) - else - onPathsSearched = -> - - # Kick off all of the searches and unify them into one Promise. - allSearches = [] - directoriesForSearcher.forEach (directories, searcher) -> - searchOptions = - inclusions: options.paths or [] - includeHidden: true - excludeVcsIgnores: atom.config.get('core.excludeVcsIgnoredPaths') - exclusions: atom.config.get('core.ignoredNames') - follow: atom.config.get('core.followSymlinks') - didMatch: (result) -> - iterator(result) unless atom.project.isPathModified(result.filePath) - didError: (error) -> - iterator(null, error) - didSearchPaths: (count) -> onPathsSearched(searcher, count) - directorySearcher = searcher.search(directories, regex, searchOptions) - allSearches.push(directorySearcher) - searchPromise = Promise.all(allSearches) + task.on 'scan:paths-searched', (numberOfPathsSearched) -> + options.onPathsSearched(numberOfPathsSearched) for buffer in atom.project.getBuffers() when buffer.isModified() filePath = buffer.getPath() @@ -866,33 +829,11 @@ class Workspace extends Model buffer.scan regex, (match) -> matches.push match iterator {filePath, matches} if matches.length > 0 - # Make sure the Promise that is returned to the client is cancelable. To be consistent - # with the existing behavior, instead of cancel() rejecting the promise, it should - # resolve it with the special value 'cancelled'. At least the built-in find-and-replace - # package relies on this behavior. - isCancelled = false - cancellablePromise = new Promise (resolve, reject) -> - onSuccess = -> - resolve(null) - onFailure = -> - if isCancelled - resolve('cancelled') - else - reject() - searchPromise.then(onSuccess, onFailure) - cancellablePromise.cancel = -> - isCancelled = true - # Note that cancelling all (or actually, any) of the members of allSearches - # will cause searchPromise to reject, which will cause cancellablePromise to resolve - # in the desired way. - promise.cancel() for promise in allSearches - - # Although this method claims to return a `Promise`, the `ResultsPaneView.onSearch()` - # method in the find-and-replace package expects the object returned by this method to have a - # `done()` method. Include a done() method until find-and-replace can be updated. - cancellablePromise.done = (onSuccessOrFailure) -> - cancellablePromise.then(onSuccessOrFailure, onSuccessOrFailure) - cancellablePromise + promise = deferred.promise + promise.cancel = -> + task.terminate() + deferred.resolve('cancelled') + promise # Public: Performs a replace across all the specified files in the project. # From f73435e0537c72af9638cb668e0c56e48002bdc7 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 9 Jun 2015 21:35:01 +0200 Subject: [PATCH 1641/1783] :bug: Delete partially off-screen markers which are empty MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * :fire: Delete old code which was used to support some non-batched methods in a previous version; * :white_check_mark: Cover “partially off-screen markers which are empty” scenario, since that code path was not hit by previous specs Fixes #7183 --- spec/text-editor-presenter-spec.coffee | 5 +++++ src/text-editor-presenter.coffee | 15 +-------------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 25fde69c1..a0ce19b96 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -1327,6 +1327,10 @@ describe "TextEditorPresenter", -> marker8 = editor.markBufferRange([[2, 2], [2, 2]]) highlight8 = editor.decorateMarker(marker8, type: 'highlight', class: 'h') + # partially off-screen above, empty + marker9 = editor.markBufferRange([[0, 0], [2, 0]], invalidate: 'touch') + highlight9 = editor.decorateMarker(marker9, type: 'highlight', class: 'h') + presenter = buildPresenter(explicitHeight: 30, scrollTop: 20, tileSize: 2) expectUndefinedStateForHighlight(presenter, highlight1) @@ -1388,6 +1392,7 @@ describe "TextEditorPresenter", -> expectUndefinedStateForHighlight(presenter, highlight7) expectUndefinedStateForHighlight(presenter, highlight8) + expectUndefinedStateForHighlight(presenter, highlight9) it "is empty until all of the required measurements are assigned", -> editor.setSelectedBufferRanges([ diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 0e7e448fa..9fa923255 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -1253,13 +1253,6 @@ class TextEditorPresenter range = marker.getScreenRange() if decoration.isDestroyed() or not marker.isValid() or range.isEmpty() or not range.intersectsRowRange(@startRow, @endRow - 1) - tileStartRow = @tileForRow(range.start.row) - tileEndRow = @tileForRow(range.end.row) - - for tile in [tileStartRow..tileEndRow] by @tileSize - delete @state.content.tiles[tile]?.highlights[decoration.id] - - @emitDidUpdateState() return if range.start.row < @startRow @@ -1269,11 +1262,7 @@ class TextEditorPresenter range.end.row = @endRow range.end.column = 0 - if range.isEmpty() - tileState = @state.content.tiles[@tileForRow(range.start.row)] - delete tileState.highlights[decoration.id] - @emitDidUpdateState() - return + return if range.isEmpty() flash = decoration.consumeNextFlash() @@ -1307,8 +1296,6 @@ class TextEditorPresenter @visibleHighlights[tileStartRow] ?= {} @visibleHighlights[tileStartRow][decoration.id] = true - @emitDidUpdateState() - true repositionRegionWithinTile: (region, tileStartRow) -> From 091b25c8b3fb1d3b124a3f46d717428b896ca429 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 9 Jun 2015 12:49:29 -0700 Subject: [PATCH 1642/1783] Prepare 0.209 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cc3902e99..96c6af9df 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "0.208.0", + "version": "0.209.0", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From bb53c07539f15982bdaa99a24810458b1dadfeee Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 9 Jun 2015 12:53:45 -0700 Subject: [PATCH 1643/1783] :arrow_up: tabs@0.78 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 96c6af9df..07d41dfe1 100644 --- a/package.json +++ b/package.json @@ -120,7 +120,7 @@ "status-bar": "0.74.0", "styleguide": "0.44.0", "symbols-view": "0.98.0", - "tabs": "0.77.0", + "tabs": "0.78.0", "timecop": "0.31.0", "tree-view": "0.172.0", "update-package-dependencies": "0.10.0", From 7db0ab8d36fe806361b4277e5f280cb15f98cfd0 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 9 Jun 2015 14:16:20 -0700 Subject: [PATCH 1644/1783] :arrow_up: text-buffer --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 07d41dfe1..557cd35a1 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "space-pen": "3.8.2", "stacktrace-parser": "0.1.1", "temp": "0.8.1", - "text-buffer": "6.3.2", + "text-buffer": "6.3.3", "theorist": "^1.0.2", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", From 04c95671819cad198c786b2bb40b5f37fa5a786f Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 10 Jun 2015 01:30:12 +0200 Subject: [PATCH 1645/1783] Massage message a bit --- src/project.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/project.coffee b/src/project.coffee index e2079b22f..12bccaae8 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -329,9 +329,9 @@ class Project extends Model if fileSize >= 20 * 1048576 # 20MB choice = atom.confirm - message: 'Atom can have issues with files over 20MB.' - detailedMessage: "Do you still want to try to load this?" - buttons: ["Open", "Cancel"] + message: 'Atom currently freezes during the loading of very large files.' + detailedMessage: "Do you still want to load this file?" + buttons: ["Proceed", "Cancel"] if choice is 1 error = new Error error.code = 'CANCELLED' From 6bccfcd0a3521dd3b158af3ead3d562f6ee66465 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 9 Jun 2015 16:45:14 -0700 Subject: [PATCH 1646/1783] Guard for atom windows w/ no webContents --- src/browser/atom-window.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/browser/atom-window.coffee b/src/browser/atom-window.coffee index 9b7c35d03..36b194cd0 100644 --- a/src/browser/atom-window.coffee +++ b/src/browser/atom-window.coffee @@ -87,7 +87,7 @@ class AtomWindow hash: encodeURIComponent(JSON.stringify(loadSettings)) getLoadSettings: -> - if @browserWindow.webContents.loaded + if @browserWindow.webContents?.loaded hash = url.parse(@browserWindow.webContents.getUrl()).hash.substr(1) JSON.parse(decodeURIComponent(hash)) From cd42d8acbbecd49f7dc797b7a1edf85760216ab6 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 9 Jun 2015 16:54:14 -0700 Subject: [PATCH 1647/1783] :arrow_up: text-buffer --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 557cd35a1..42a532e5b 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "space-pen": "3.8.2", "stacktrace-parser": "0.1.1", "temp": "0.8.1", - "text-buffer": "6.3.3", + "text-buffer": "6.3.4", "theorist": "^1.0.2", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", From 7d7b2375e1de3fdf2ff2ef705b8732101f57c97b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 9 Jun 2015 16:03:08 -0700 Subject: [PATCH 1648/1783] Focus right after showing --- src/atom.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/atom.coffee b/src/atom.coffee index c3fff388d..47014ff98 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -505,9 +505,9 @@ class Atom extends Model displayWindow: -> dimensions = @restoreWindowDimensions() @show() + @focus() setImmediate => - @focus() @setFullScreen(true) if @workspace?.fullScreen @maximize() if dimensions?.maximized and process.platform isnt 'darwin' From c3953dbbd4cfae3ee209f8e163efe99dfd441300 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 9 Jun 2015 16:09:37 -0700 Subject: [PATCH 1649/1783] Don't focus when opening locations --- src/browser/atom-window.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/browser/atom-window.coffee b/src/browser/atom-window.coffee index 36b194cd0..eaa58ffa5 100644 --- a/src/browser/atom-window.coffee +++ b/src/browser/atom-window.coffee @@ -166,7 +166,6 @@ class AtomWindow openLocations: (locationsToOpen) -> if @loaded - @focus() @sendMessage 'open-locations', locationsToOpen else @browserWindow.once 'window:loaded', => @openLocations(locationsToOpen) From f55c95bd01b652d5b22bf789391770e8aa694c43 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 10 Jun 2015 10:06:06 -0700 Subject: [PATCH 1650/1783] :arrow_up: tabs@0.79 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 42a532e5b..f40896442 100644 --- a/package.json +++ b/package.json @@ -120,7 +120,7 @@ "status-bar": "0.74.0", "styleguide": "0.44.0", "symbols-view": "0.98.0", - "tabs": "0.78.0", + "tabs": "0.79.0", "timecop": "0.31.0", "tree-view": "0.172.0", "update-package-dependencies": "0.10.0", From 5d2314cb8b274d78997bcbd788c6b3366a66aaaa Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 10 Jun 2015 13:50:58 -0700 Subject: [PATCH 1651/1783] :arrow_up: text-buffer --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f40896442..fb9207210 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "space-pen": "3.8.2", "stacktrace-parser": "0.1.1", "temp": "0.8.1", - "text-buffer": "6.3.4", + "text-buffer": "6.3.5", "theorist": "^1.0.2", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", From 1bb0c2ca31a60176c1f6997179cbd4ddf8feeab4 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 10 Jun 2015 22:58:36 +0200 Subject: [PATCH 1652/1783] :arrow_up: first-mate Fixes #7177 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fb9207210..8588def28 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "delegato": "^1", "emissary": "^1.3.3", "event-kit": "^1.2.0", - "first-mate": "^4.1.6", + "first-mate": "^4.1.7", "fs-plus": "^2.8.0", "fstream": "0.1.24", "fuzzaldrin": "^2.1", From 201fcc0cb459b34a1763dfe55339599dca4d98b4 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 10 Jun 2015 23:02:41 +0200 Subject: [PATCH 1653/1783] :arrow_up: tabs --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8588def28..dfee5a569 100644 --- a/package.json +++ b/package.json @@ -120,7 +120,7 @@ "status-bar": "0.74.0", "styleguide": "0.44.0", "symbols-view": "0.98.0", - "tabs": "0.79.0", + "tabs": "0.80.0", "timecop": "0.31.0", "tree-view": "0.172.0", "update-package-dependencies": "0.10.0", From 165ce8a13af87d21d3862f787c2f4ba31cca9ca2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 10 Jun 2015 14:46:16 -0700 Subject: [PATCH 1654/1783] :arrow_up: season@5.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dfee5a569..40c50d5e4 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "scandal": "2.0.3", "scoped-property-store": "^0.17.0", "scrollbar-style": "^3.1", - "season": "^5.1.4", + "season": "^5.3", "semver": "^4.3.3", "serializable": "^1", "service-hub": "^0.5.0", From 0d6bbc1c35db51030a223d7d43cefe86e7b6ff6a Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 10 Jun 2015 15:25:30 -0700 Subject: [PATCH 1655/1783] :arrow_up: text-buffer --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 40c50d5e4..620fda2f4 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "space-pen": "3.8.2", "stacktrace-parser": "0.1.1", "temp": "0.8.1", - "text-buffer": "6.3.5", + "text-buffer": "6.3.6", "theorist": "^1.0.2", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", From 3c44bc06f416075d8d58681bac5f078f9f56dcfb Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Wed, 10 Jun 2015 23:30:25 +0100 Subject: [PATCH 1656/1783] Revert "Revert "Introduce atom.directory-searcher service v0.1.0."" This reverts commit 262d41c3064b9fd899d9e158e5207b35052ef742. --- spec/task-spec.coffee | 26 ++++++ spec/workspace-spec.coffee | 84 +++++++++++++++++++ src/default-directory-searcher.coffee | 95 ++++++++++++++++++++++ src/task.coffee | 10 ++- src/workspace.coffee | 111 ++++++++++++++++++++------ 5 files changed, 298 insertions(+), 28 deletions(-) create mode 100644 src/default-directory-searcher.coffee diff --git a/spec/task-spec.coffee b/spec/task-spec.coffee index bddb59d86..947db5567 100644 --- a/spec/task-spec.coffee +++ b/spec/task-spec.coffee @@ -70,3 +70,29 @@ describe "Task", -> task.terminate() expect(stdout.listeners('data').length).toBe 0 expect(stderr.listeners('data').length).toBe 0 + + describe "::cancel()", -> + it "dispatches 'task:cancelled' when invoked on an active task", -> + task = new Task(require.resolve('./fixtures/task-spec-handler')) + cancelledEventSpy = jasmine.createSpy('eventSpy') + task.on('task:cancelled', cancelledEventSpy) + completedEventSpy = jasmine.createSpy('eventSpy') + task.on('task:completed', completedEventSpy) + + expect(task.cancel()).toBe(true) + expect(cancelledEventSpy).toHaveBeenCalled() + expect(completedEventSpy).not.toHaveBeenCalled() + + it "does not dispatch 'task:cancelled' when invoked on an inactive task", -> + handlerResult = null + task = Task.once require.resolve('./fixtures/task-spec-handler'), (result) -> + handlerResult = result + + waitsFor -> + handlerResult? + + runs -> + cancelledEventSpy = jasmine.createSpy('eventSpy') + task.on('task:cancelled', cancelledEventSpy) + expect(task.cancel()).toBe(false) + expect(cancelledEventSpy).not.toHaveBeenCalled() diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index 4918fc65f..4666177c6 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -938,6 +938,90 @@ describe "Workspace", -> .then -> expect(resultPaths).toEqual([file2]) + describe "when a custom directory searcher is registered", -> + fakeSearch = null + # Function that is invoked once all of the fields on fakeSearch are set. + onFakeSearchCreated = null + + class FakeSearch + constructor: (@options) -> + # Note that hoisting resolve and reject in this way is generally frowned upon. + @promise = new Promise (resolve, reject) => + @hoistedResolve = resolve + @hoistedReject = reject + onFakeSearchCreated?(this) + then: (args...) -> + @promise.then.apply(@promise, args) + cancel: -> + @cancelled = true + @hoistedReject() + + beforeEach -> + fakeSearch = null + onFakeSearchCreated = null + atom.packages.serviceHub.provide('atom.directory-searcher', '0.1.0', { + canSearchDirectory: (directory) -> directory.getPath() is dir1 + search: (directory, regex, options) -> fakeSearch = new FakeSearch(options) + }) + + it "can override the DefaultDirectorySearcher on a per-directory basis", -> + foreignFilePath = 'ssh://foreign-directory:8080/hello.txt' + numPathsSearchedInDir2 = 1 + numPathsToPretendToSearchInCustomDirectorySearcher = 10 + searchResult = + filePath: foreignFilePath, + matches: [ + { + lineText: 'Hello world', + lineTextOffset: 0, + matchText: 'Hello', + range: [[0, 0], [0, 5]], + }, + ] + onFakeSearchCreated = (fakeSearch) -> + fakeSearch.options.didMatch(searchResult) + fakeSearch.options.didSearchPaths(numPathsToPretendToSearchInCustomDirectorySearcher) + fakeSearch.hoistedResolve() + + resultPaths = [] + onPathsSearched = jasmine.createSpy('onPathsSearched') + waitsForPromise -> + atom.workspace.scan /aaaa/, {onPathsSearched}, ({filePath}) -> + resultPaths.push(filePath) + + runs -> + expect(resultPaths.sort()).toEqual([foreignFilePath, file2].sort()) + # onPathsSearched should be called once by each DirectorySearcher. The order is not + # guaranteed, so we can only verify the total number of paths searched is correct + # after the second call. + expect(onPathsSearched.callCount).toBe(2) + expect(onPathsSearched.mostRecentCall.args[0]).toBe( + numPathsToPretendToSearchInCustomDirectorySearcher + numPathsSearchedInDir2) + + it "can be cancelled when the object returned by scan() has its cancel() method invoked", -> + thenable = atom.workspace.scan /aaaa/, -> + expect(fakeSearch.cancelled).toBe(undefined) + thenable.cancel() + expect(fakeSearch.cancelled).toBe(true) + + resultOfPromiseSearch = null + waitsForPromise -> + thenable.then (promiseResult) -> resultOfPromiseSearch = promiseResult + + runs -> + expect(resultOfPromiseSearch).toBe('cancelled') + + it "will have the side-effect of failing the overall search if it fails", -> + cancelableSearch = atom.workspace.scan /aaaa/, -> + fakeSearch.hoistedReject() + + didReject = false + waitsForPromise -> + cancelableSearch.catch -> didReject = true + + runs -> + expect(didReject).toBe(true) + describe "::replace(regex, replacementText, paths, iterator)", -> [filePath, commentFilePath, sampleContent, sampleCommentContent] = [] diff --git a/src/default-directory-searcher.coffee b/src/default-directory-searcher.coffee new file mode 100644 index 000000000..ebe3a35f9 --- /dev/null +++ b/src/default-directory-searcher.coffee @@ -0,0 +1,95 @@ +Task = require './task' + +# Public: Searches local files for lines matching a specified regex. +# +# Implements thenable so it can be used with `Promise.all()`. +class DirectorySearch + constructor: (rootPaths, regex, options) -> + scanHandlerOptions = + ignoreCase: regex.ignoreCase + inclusions: options.inclusions + includeHidden: options.includeHidden + excludeVcsIgnores: options.excludeVcsIgnores + exclusions: options.exclusions + follow: options.follow + @task = new Task(require.resolve('./scan-handler')) + @task.on 'scan:result-found', options.didMatch + @task.on 'scan:file-error', options.didError + @task.on 'scan:paths-searched', options.didSearchPaths + @promise = new Promise (resolve, reject) => + @task.on('task:cancelled', reject) + @task.start(rootPaths, regex.source, scanHandlerOptions, resolve) + + # Public: Implementation of `then()` to satisfy the *thenable* contract. + # This makes it possible to use a `DirectorySearch` with `Promise.all()`. + # + # Returns `Promise`. + then: (args...) -> + @promise.then.apply(@promise, args) + + # Public: Cancels the search. + cancel: -> + # This will cause @promise to reject. + @task.cancel() + null + + +# Default provider for the `atom.directory-searcher` service. +module.exports = +class DefaultDirectorySearcher + # Public: Determines whether this object supports search for a `Directory`. + # + # * `directory` {Directory} whose search needs might be supported by this object. + # + # Returns a `boolean` indicating whether this object can search this `Directory`. + canSearchDirectory: (directory) -> true + + # Public: Performs a text search for files in the specified `Directory`, subject to the + # specified parameters. + # + # Results are streamed back to the caller by invoking methods on the specified `options`, + # such as `didMatch` and `didError`. + # + # * `directories` {Array} of {Directory} objects to search, all of which have been accepted by + # this searcher's `canSearchDirectory()` predicate. + # * `regex` {RegExp} to search with. + # * `options` {Object} with the following properties: + # * `didMatch` {Function} call with a search result structured as follows: + # * `searchResult` {Object} with the following keys: + # * `filePath` {String} absolute path to the matching file. + # * `matches` {Array} with object elements with the following keys: + # * `lineText` {String} The full text of the matching line (without a line terminator character). + # * `lineTextOffset` {Number} (This always seems to be 0?) + # * `matchText` {String} The text that matched the `regex` used for the search. + # * `range` {Range} Identifies the matching region in the file. (Likely as an array of numeric arrays.) + # * `didError` {Function} call with an Error if there is a problem during the search. + # * `didSearchPaths` {Function} periodically call with the number of paths searched thus far. + # * `inclusions` {Array} of glob patterns (as strings) to search within. Note that this + # array may be empty, indicating that all files should be searched. + # + # Each item in the array is a file/directory pattern, e.g., `src` to search in the "src" + # directory or `*.js` to search all JavaScript files. In practice, this often comes from the + # comma-delimited list of patterns in the bottom text input of the ProjectFindView dialog. + # * `ignoreHidden` {boolean} whether to ignore hidden files. + # * `excludeVcsIgnores` {boolean} whether to exclude VCS ignored paths. + # * `exclusions` {Array} similar to inclusions + # * `follow` {boolean} whether symlinks should be followed. + # + # Returns a *thenable* `DirectorySearch` that includes a `cancel()` method. If `cancel()` is + # invoked before the `DirectorySearch` is determined, it will resolve the `DirectorySearch`. + search: (directories, regex, options) -> + rootPaths = directories.map (directory) -> directory.getPath() + isCancelled = false + directorySearch = new DirectorySearch(rootPaths, regex, options) + promise = new Promise (resolve, reject) -> + directorySearch.then resolve, -> + if isCancelled + resolve() + else + reject() + return { + then: promise.then.bind(promise) + cancel: -> + isCancelled = true + directorySearch.cancel() + } diff --git a/src/task.coffee b/src/task.coffee index 939b71635..34c943c6a 100644 --- a/src/task.coffee +++ b/src/task.coffee @@ -150,7 +150,7 @@ class Task # # No more events are emitted once this method is called. terminate: -> - return unless @childProcess? + return false unless @childProcess? @childProcess.removeAllListeners() @childProcess.stdout.removeAllListeners() @@ -158,4 +158,10 @@ class Task @childProcess.kill() @childProcess = null - undefined + true + + cancel: -> + didForcefullyTerminate = @terminate() + if didForcefullyTerminate + @emit('task:cancelled') + didForcefullyTerminate diff --git a/src/workspace.coffee b/src/workspace.coffee index 157d002de..6311cdd6d 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -7,6 +7,7 @@ Serializable = require 'serializable' {Emitter, Disposable, CompositeDisposable} = require 'event-kit' Grim = require 'grim' fs = require 'fs-plus' +DefaultDirectorySearcher = require './default-directory-searcher' Model = require './model' TextEditor = require './text-editor' PaneContainer = require './pane-container' @@ -46,6 +47,13 @@ class Workspace extends Model @paneContainer ?= new PaneContainer() @paneContainer.onDidDestroyPaneItem(@didDestroyPaneItem) + @directorySearchers = [] + @defaultDirectorySearcher = new DefaultDirectorySearcher() + atom.packages.serviceHub.consume( + 'atom.directory-searcher', + '^0.1.0', + (provider) => @directorySearchers.unshift(provider)) + @panelContainers = top: new PanelContainer({location: 'top'}) left: new PanelContainer({location: 'left'}) @@ -791,36 +799,65 @@ class Workspace extends Model # * `regex` {RegExp} to search with. # * `options` (optional) {Object} (default: {}) # * `paths` An {Array} of glob patterns to search within + # * `onPathsSearched` (optional) {Function} # * `iterator` {Function} callback on each file found # - # Returns a `Promise`. + # Returns a `Promise` with a `cancel()` method that will cancel all + # of the underlying searches that were started as part of this scan. scan: (regex, options={}, iterator) -> if _.isFunction(options) iterator = options options = {} - deferred = Q.defer() - - searchOptions = - ignoreCase: regex.ignoreCase - inclusions: options.paths - includeHidden: true - excludeVcsIgnores: atom.config.get('core.excludeVcsIgnoredPaths') - exclusions: atom.config.get('core.ignoredNames') - follow: atom.config.get('core.followSymlinks') - - task = Task.once require.resolve('./scan-handler'), atom.project.getPaths(), regex.source, searchOptions, -> - deferred.resolve() - - task.on 'scan:result-found', (result) -> - iterator(result) unless atom.project.isPathModified(result.filePath) - - task.on 'scan:file-error', (error) -> - iterator(null, error) + # Find a searcher for every Directory in the project. Each searcher that is matched + # will be associated with an Array of Directory objects in the Map. + directoriesForSearcher = new Map() + for directory in atom.project.getDirectories() + searcher = @defaultDirectorySearcher + for directorySearcher in @directorySearchers + if directorySearcher.canSearchDirectory(directory) + searcher = directorySearcher + break + directories = directoriesForSearcher.get(searcher) + unless directories + directories = [] + directoriesForSearcher.set(searcher, directories) + directories.push(directory) + # Define the onPathsSearched callback. if _.isFunction(options.onPathsSearched) - task.on 'scan:paths-searched', (numberOfPathsSearched) -> - options.onPathsSearched(numberOfPathsSearched) + # Maintain a map of directories to the number of search results. When notified of a new count, + # replace the entry in the map and update the total. + onPathsSearchedOption = options.onPathsSearched + totalNumberOfPathsSearched = 0 + numberOfPathsSearchedForSearcher = new Map() + onPathsSearched = (searcher, numberOfPathsSearched) -> + oldValue = numberOfPathsSearchedForSearcher.get(searcher) + if oldValue + totalNumberOfPathsSearched -= oldValue + numberOfPathsSearchedForSearcher.set(searcher, numberOfPathsSearched) + totalNumberOfPathsSearched += numberOfPathsSearched + onPathsSearchedOption(totalNumberOfPathsSearched) + else + onPathsSearched = -> + + # Kick off all of the searches and unify them into one Promise. + allSearches = [] + directoriesForSearcher.forEach (directories, searcher) -> + searchOptions = + inclusions: options.paths or [] + includeHidden: true + excludeVcsIgnores: atom.config.get('core.excludeVcsIgnoredPaths') + exclusions: atom.config.get('core.ignoredNames') + follow: atom.config.get('core.followSymlinks') + didMatch: (result) -> + iterator(result) unless atom.project.isPathModified(result.filePath) + didError: (error) -> + iterator(null, error) + didSearchPaths: (count) -> onPathsSearched(searcher, count) + directorySearcher = searcher.search(directories, regex, searchOptions) + allSearches.push(directorySearcher) + searchPromise = Promise.all(allSearches) for buffer in atom.project.getBuffers() when buffer.isModified() filePath = buffer.getPath() @@ -829,11 +866,33 @@ class Workspace extends Model buffer.scan regex, (match) -> matches.push match iterator {filePath, matches} if matches.length > 0 - promise = deferred.promise - promise.cancel = -> - task.terminate() - deferred.resolve('cancelled') - promise + # Make sure the Promise that is returned to the client is cancelable. To be consistent + # with the existing behavior, instead of cancel() rejecting the promise, it should + # resolve it with the special value 'cancelled'. At least the built-in find-and-replace + # package relies on this behavior. + isCancelled = false + cancellablePromise = new Promise (resolve, reject) -> + onSuccess = -> + resolve(null) + onFailure = -> + if isCancelled + resolve('cancelled') + else + reject() + searchPromise.then(onSuccess, onFailure) + cancellablePromise.cancel = -> + isCancelled = true + # Note that cancelling all (or actually, any) of the members of allSearches + # will cause searchPromise to reject, which will cause cancellablePromise to resolve + # in the desired way. + promise.cancel() for promise in allSearches + + # Although this method claims to return a `Promise`, the `ResultsPaneView.onSearch()` + # method in the find-and-replace package expects the object returned by this method to have a + # `done()` method. Include a done() method until find-and-replace can be updated. + cancellablePromise.done = (onSuccessOrFailure) -> + cancellablePromise.then(onSuccessOrFailure, onSuccessOrFailure) + cancellablePromise # Public: Performs a replace across all the specified files in the project. # From ad46b37cfece271c46e1778fffbb204e6477ec59 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Wed, 10 Jun 2015 13:25:24 +0100 Subject: [PATCH 1657/1783] In workspace-spec.coffee, updated FakeSearch to match the spec, which helped uncover a bug. --- spec/workspace-spec.coffee | 4 +++- src/workspace.coffee | 12 +++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index 4666177c6..636755346 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -954,7 +954,9 @@ describe "Workspace", -> @promise.then.apply(@promise, args) cancel: -> @cancelled = true - @hoistedReject() + # According to the spec for a DirectorySearcher, invoking `cancel()` should + # resolve the thenable rather than reject it. + @hoistedResolve() beforeEach -> fakeSearch = null diff --git a/src/workspace.coffee b/src/workspace.coffee index 6311cdd6d..afc197792 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -873,18 +873,16 @@ class Workspace extends Model isCancelled = false cancellablePromise = new Promise (resolve, reject) -> onSuccess = -> - resolve(null) - onFailure = -> if isCancelled resolve('cancelled') else - reject() - searchPromise.then(onSuccess, onFailure) + resolve(null) + searchPromise.then(onSuccess, reject) cancellablePromise.cancel = -> isCancelled = true - # Note that cancelling all (or actually, any) of the members of allSearches - # will cause searchPromise to reject, which will cause cancellablePromise to resolve - # in the desired way. + # Note that cancelling all of the members of allSearches will cause all of the searches + # to resolve, which causes searchPromise to resolve, which is ultimately what causes + # cancellablePromise to resolve. promise.cancel() for promise in allSearches # Although this method claims to return a `Promise`, the `ResultsPaneView.onSearch()` From 6fa8a4088473005bbc8990038bd8c01f42571bac Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 10 Jun 2015 15:37:56 -0700 Subject: [PATCH 1658/1783] :arrow_up: language-csharp@0.6 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 620fda2f4..2f677f63e 100644 --- a/package.json +++ b/package.json @@ -130,7 +130,7 @@ "language-c": "0.45.0", "language-clojure": "0.15.0", "language-coffee-script": "0.41.0", - "language-csharp": "0.5.0", + "language-csharp": "0.6.0", "language-css": "0.30.0", "language-gfm": "0.77.0", "language-git": "0.10.0", From f59382dbdaa640b88b2881560d6548ace42e2f58 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 10 Jun 2015 16:10:40 -0700 Subject: [PATCH 1659/1783] Use dirname in win/apm.sh Refs #6738 Refs #7141 --- resources/win/apm.sh | 3 ++- resources/win/atom.sh | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/resources/win/apm.sh b/resources/win/apm.sh index c895f2bce..b50a70a82 100644 --- a/resources/win/apm.sh +++ b/resources/win/apm.sh @@ -1,3 +1,4 @@ #!/bin/sh -"$0/../../app/apm/bin/node.exe" "$0/../../app/apm/lib/cli.js" "$@" +directory=$(dirname "$0") +"$directory/../app/apm/bin/node.exe" "$directory/../app/apm/lib/cli.js" "$@" diff --git a/resources/win/atom.sh b/resources/win/atom.sh index 8f312a2da..b6edeeb57 100644 --- a/resources/win/atom.sh +++ b/resources/win/atom.sh @@ -15,8 +15,10 @@ while getopts ":fhtvw-:" opt; do esac done +directory=$(dirname "$0") + if [ $EXPECT_OUTPUT ]; then - "$(dirname $0)/../../atom.exe" "$@" + "$directory/../../atom.exe" "$@" else - "$(dirname $0)/../app/apm/bin/node.exe" "$0/../atom.js" "$@" + "$directory/../app/apm/bin/node.exe" "$directory/atom.js" "$@" fi From 4d76e607f0ae840daea9ee7cc885658b25f505ac Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 10 Jun 2015 16:30:54 -0700 Subject: [PATCH 1660/1783] Use dirname for forwarding atom/apm commands Refs #7141 --- src/browser/squirrel-update.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/browser/squirrel-update.coffee b/src/browser/squirrel-update.coffee index 1603a7c0a..be90e6cd6 100644 --- a/src/browser/squirrel-update.coffee +++ b/src/browser/squirrel-update.coffee @@ -139,7 +139,7 @@ addCommandsToPath = (callback) -> atomShCommandPath = path.join(binFolder, 'atom') relativeAtomShPath = path.relative(binFolder, path.join(appFolder, 'resources', 'cli', 'atom.sh')) - atomShCommand = "#!/bin/sh\r\n\"$0/../#{relativeAtomShPath.replace(/\\/g, '/')}\" \"$@\"" + atomShCommand = "#!/bin/sh\r\n\"$(dirname \"$0\")/#{relativeAtomShPath.replace(/\\/g, '/')}\" \"$@\"" apmCommandPath = path.join(binFolder, 'apm.cmd') relativeApmPath = path.relative(binFolder, path.join(process.resourcesPath, 'app', 'apm', 'bin', 'apm.cmd')) @@ -147,7 +147,7 @@ addCommandsToPath = (callback) -> apmShCommandPath = path.join(binFolder, 'apm') relativeApmShPath = path.relative(binFolder, path.join(appFolder, 'resources', 'cli', 'apm.sh')) - apmShCommand = "#!/bin/sh\r\n\"$0/../#{relativeApmShPath.replace(/\\/g, '/')}\" \"$@\"" + apmShCommand = "#!/bin/sh\r\n\"$(dirname \"$0\")/#{relativeApmShPath.replace(/\\/g, '/')}\" \"$@\"" fs.writeFile atomCommandPath, atomCommand, -> fs.writeFile atomShCommandPath, atomShCommand, -> From 0edce07446a7a4f424ce621c20d83c8fea955267 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 10 Jun 2015 16:46:35 -0700 Subject: [PATCH 1661/1783] Use folder name when metadata name is empty string or non-string --- .../package-with-invalid-activation-commands/package.json | 2 +- spec/fixtures/packages/package-with-main/package.cson | 2 +- src/package.coffee | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/spec/fixtures/packages/package-with-invalid-activation-commands/package.json b/spec/fixtures/packages/package-with-invalid-activation-commands/package.json index d98b7ef92..c2e317fa8 100644 --- a/spec/fixtures/packages/package-with-invalid-activation-commands/package.json +++ b/spec/fixtures/packages/package-with-invalid-activation-commands/package.json @@ -1,5 +1,5 @@ { - "name": "package-with-invalid-selectors", + "name": "package-with-invalid-commands", "version": "1.0.0", "activationCommands": { "<>": [ diff --git a/spec/fixtures/packages/package-with-main/package.cson b/spec/fixtures/packages/package-with-main/package.cson index a93a109c4..e799f6ca8 100644 --- a/spec/fixtures/packages/package-with-main/package.cson +++ b/spec/fixtures/packages/package-with-main/package.cson @@ -1 +1 @@ -'main': 'main-module.coffee' \ No newline at end of file +'main': 'main-module.coffee' diff --git a/src/package.coffee b/src/package.coffee index 2019f0731..3de79ff51 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -45,7 +45,8 @@ class Package throw error unless ignoreErrors metadata ?= {} - metadata.name ?= packageName + unless typeof metadata.name is 'string' and metadata.name.length > 0 + metadata.name = packageName if includeDeprecatedAPIs and metadata.stylesheetMain? deprecate("Use the `mainStyleSheet` key instead of `stylesheetMain` in the `package.json` of `#{packageName}`", {packageName}) From 33accdf1f31e48bfcafcd3fcb29a2d4fbdac462a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 10 Jun 2015 17:06:08 -0700 Subject: [PATCH 1662/1783] Match directory name to package.json name --- .../package-with-invalid-activation-commands/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/fixtures/packages/package-with-invalid-activation-commands/package.json b/spec/fixtures/packages/package-with-invalid-activation-commands/package.json index c2e317fa8..aa3398f59 100644 --- a/spec/fixtures/packages/package-with-invalid-activation-commands/package.json +++ b/spec/fixtures/packages/package-with-invalid-activation-commands/package.json @@ -1,5 +1,5 @@ { - "name": "package-with-invalid-commands", + "name": "package-with-invalid-activation-commands", "version": "1.0.0", "activationCommands": { "<>": [ From b3687265bbf686a5bfaf3a089fa856e7441c2492 Mon Sep 17 00:00:00 2001 From: herkyl Date: Thu, 11 Jun 2015 10:37:38 +0300 Subject: [PATCH 1663/1783] Fixed 'setBufferRange' documentation parameter name --- src/selection.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/selection.coffee b/src/selection.coffee index 6ec874203..b96139e98 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -84,7 +84,7 @@ class Selection extends Model # Public: Modifies the buffer {Range} for the selection. # - # * `screenRange` The new {Range} to select. + # * `bufferRange` The new {Range} to select. # * `options` (optional) {Object} with the keys: # * `preserveFolds` if `true`, the fold settings are preserved after the # selection moves. From 5822eb11f1a2d8fe6bcb3f510340044eb464b5e9 Mon Sep 17 00:00:00 2001 From: Luke Pommersheim Date: Thu, 11 Jun 2015 13:02:14 +0200 Subject: [PATCH 1664/1783] function that returns the first matched Cursor at a given screen position Point if it exists in that location --- spec/text-editor-spec.coffee | 6 ++++++ src/text-editor.coffee | 11 +++++++++++ 2 files changed, 17 insertions(+) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 63b01a178..9cf5d783b 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -916,6 +916,12 @@ describe "TextEditor", -> editor.setCursorBufferPosition([3, 1]) expect(editor.getCurrentParagraphBufferRange()).toBeUndefined() + describe "getCursorAtScreenPosition(screenPosition)", -> + it "returns the cursor at the given screenPosition", -> + cursor1 = editor.addCursorAtScreenPosition([0, 2]) + cursor2 = editor.getCursorAtScreenPosition(cursor1.getScreenPosition()) + expect(cursor2.marker).toBe cursor1.marker + describe "::getCursorScreenPositions()", -> it "returns the cursor positions in the order they were added", -> editor.foldBufferRow(4) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 977b94ed1..8c6bc0104 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -1561,6 +1561,17 @@ class TextEditor extends Model setCursorBufferPosition: (position, options) -> @moveCursors (cursor) -> cursor.setBufferPosition(position, options) + # Essential: Get a {Cursor} at given screen coordinates {Point} + # + #* `position` A {Point} + # + # Returns the first matched {Cursor} or undefined + getCursorAtScreenPosition: (position) -> + cursorsAtPoint = @cursors.filter (cursor) -> + cursorPosition = cursor.getScreenPosition() + cursorPosition.row is position.row and cursorPosition.column is position.column + if cursorsAtPoint.length > 0 then cursorsAtPoint[0] else undefined + # Essential: Get the position of the most recently added cursor in screen # coordinates. # From c67f98febbcb9b09f510345c94ad924c0350e06b Mon Sep 17 00:00:00 2001 From: Luke Pommersheim Date: Thu, 11 Jun 2015 13:03:33 +0200 Subject: [PATCH 1665/1783] if there are multiple cursors and you click a cursor, it is removed, otherwise new cursor is added. Cannot remove if there is only one cursor and you click on it --- spec/text-editor-component-spec.coffee | 27 +++++++++++++++++++++----- src/text-editor-component.coffee | 6 +++++- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 6749e7803..9ea11f0a8 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -1569,11 +1569,28 @@ describe "TextEditorComponent", -> expect(editor.getSelectedScreenRange()).toEqual [[3, 4], [5, 6]] describe "when the command key is held down", -> - it "adds a cursor at the nearest screen position", -> - editor.setCursorScreenPosition([3, 4]) - linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([5, 6]), metaKey: true)) - nextAnimationFrame() - expect(editor.getSelectedScreenRanges()).toEqual [[[3, 4], [3, 4]], [[5, 6], [5, 6]]] + describe "the current cursor position and screen position do not match", -> + it "adds a cursor at the nearest screen position", -> + editor.setCursorScreenPosition([3, 4]) + linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([5, 6]), metaKey: true)) + nextAnimationFrame() + expect(editor.getSelectedScreenRanges()).toEqual [[[3, 4], [3, 4]], [[5, 6], [5, 6]]] + + describe "when there are multiple cursors, and one of the cursor's screen position is the same as the mouse click screen position", -> + it "removes a cursor at the mouse screen position", -> + editor.setCursorScreenPosition([3,4]) + editor.addCursorAtScreenPosition([5,2]) + editor.addCursorAtScreenPosition([7, 5]) + linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([3,4]), metaKey: true)) + nextAnimationFrame() + expect(editor.getSelectedScreenRanges()).toEqual [[[5,2], [5,2]], [[7,5], [7,5]]] + + describe "when there is a single cursor and the click occurs at the cursor's screen position", -> + it "neither adds a new cursor nor removes the current cursor", -> + editor.setCursorScreenPosition([3, 4]) + linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([3,4]), metaKey: true)) + nextAnimationFrame() + expect(editor.getSelectedScreenRanges()).toEqual [[[3,4], [3,4]]] describe "when a non-folded line is double-clicked", -> describe "when no modifier keys are held down", -> diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index ac71da748..e0ab143c5 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -392,7 +392,11 @@ class TextEditorComponent if shiftKey @editor.selectToScreenPosition(screenPosition) else if metaKey or (ctrlKey and process.platform isnt 'darwin') - @editor.addCursorAtScreenPosition(screenPosition) + cursorAtScreenPosition = @editor.getCursorAtScreenPosition(screenPosition) + if cursorAtScreenPosition and @editor.hasMultipleCursors() + cursorAtScreenPosition.destroy() + else + @editor.addCursorAtScreenPosition(screenPosition) else @editor.setCursorScreenPosition(screenPosition) when 2 From 2765b54374504588b7ff9fe98cdee74c9435cd5d Mon Sep 17 00:00:00 2001 From: Luke Pommersheim Date: Thu, 11 Jun 2015 13:33:46 +0200 Subject: [PATCH 1666/1783] fix of coffeelint errors in spec tests --- spec/text-editor-component-spec.coffee | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 9ea11f0a8..f9effd047 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -1578,19 +1578,19 @@ describe "TextEditorComponent", -> describe "when there are multiple cursors, and one of the cursor's screen position is the same as the mouse click screen position", -> it "removes a cursor at the mouse screen position", -> - editor.setCursorScreenPosition([3,4]) - editor.addCursorAtScreenPosition([5,2]) + editor.setCursorScreenPosition([3, 4]) + editor.addCursorAtScreenPosition([5, 2]) editor.addCursorAtScreenPosition([7, 5]) - linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([3,4]), metaKey: true)) + linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([3, 4]), metaKey: true)) nextAnimationFrame() - expect(editor.getSelectedScreenRanges()).toEqual [[[5,2], [5,2]], [[7,5], [7,5]]] + expect(editor.getSelectedScreenRanges()).toEqual [[[5, 2], [5, 2]], [[7, 5], [7, 5]]] describe "when there is a single cursor and the click occurs at the cursor's screen position", -> it "neither adds a new cursor nor removes the current cursor", -> editor.setCursorScreenPosition([3, 4]) - linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([3,4]), metaKey: true)) + linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([3, 4]), metaKey: true)) nextAnimationFrame() - expect(editor.getSelectedScreenRanges()).toEqual [[[3,4], [3,4]]] + expect(editor.getSelectedScreenRanges()).toEqual [[[3, 4], [3, 4]]] describe "when a non-folded line is double-clicked", -> describe "when no modifier keys are held down", -> From d965eb77aa00f3af8daa94bd347cdaea3a703333 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 11 Jun 2015 09:57:30 -0700 Subject: [PATCH 1667/1783] :arrow_up: notifications@0.53 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2f677f63e..80fa58d5e 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "link": "0.30.0", "markdown-preview": "0.150.0", "metrics": "0.51.0", - "notifications": "0.52.0", + "notifications": "0.53.0", "open-on-github": "0.37.0", "package-generator": "0.39.0", "release-notes": "0.53.0", From 5651a7cfc3716bccb3b8624789f8756fa8e97f89 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 11 Jun 2015 10:20:47 -0700 Subject: [PATCH 1668/1783] Prepare 0.210 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 80fa58d5e..4e2a4cac4 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "0.209.0", + "version": "0.210.0", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From ca73e90a43d9366c10630d90d9ce72035f9a4872 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Machist=C3=A9=20N=2E=20Quintana?= Date: Thu, 11 Jun 2015 15:40:24 -0400 Subject: [PATCH 1669/1783] Add Slack readme badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 8958f303d..24c7ce370 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![Build Status](https://travis-ci.org/atom/atom.svg?branch=master)](https://travis-ci.org/atom/atom) [![Dependency Status](https://david-dm.org/atom/atom.svg)](https://david-dm.org/atom/atom) +[![Join the Atom Community on Slack](http://atom-slack.herokuapp.com/badge.svg)](http://atom-slack.herokuapp.com/) Atom is a hackable text editor for the 21st century, built on [Electron](https://github.com/atom/electron), and based on everything we love about our favorite editors. We designed it to be deeply customizable, but still approachable using the default configuration. From 844cfcb7aeb87589710d0a56fe24155a08872b81 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 11 Jun 2015 12:51:36 -0700 Subject: [PATCH 1670/1783] Avoid saving state when closing windows due to auto-update --- src/browser/atom-application.coffee | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 19b1eb790..db4c7ff2c 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -186,7 +186,10 @@ class AtomApplication @on 'application:report-issue', -> require('shell').openExternal('https://github.com/atom/atom/blob/master/CONTRIBUTING.md#submitting-issues') @on 'application:search-issues', -> require('shell').openExternal('https://github.com/issues?q=+is%3Aissue+user%3Aatom') - @on 'application:install-update', => @autoUpdateManager.install() + @on 'application:install-update', => + @quitting = true + @autoUpdateManager.install() + @on 'application:check-for-update', => @autoUpdateManager.check() if process.platform is 'darwin' From b27a56df8abc9778f0e96227b444d9f93f77f45e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Machist=C3=A9=20N=2E=20Quintana?= Date: Thu, 11 Jun 2015 16:27:38 -0400 Subject: [PATCH 1671/1783] :arrow_up: tabs@0.81.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4e2a4cac4..e6e01485c 100644 --- a/package.json +++ b/package.json @@ -120,7 +120,7 @@ "status-bar": "0.74.0", "styleguide": "0.44.0", "symbols-view": "0.98.0", - "tabs": "0.80.0", + "tabs": "0.81.0", "timecop": "0.31.0", "tree-view": "0.172.0", "update-package-dependencies": "0.10.0", From 51016550c30c64f8cd78cbc10e1eb9ca536a6743 Mon Sep 17 00:00:00 2001 From: Ross Allen Date: Thu, 11 Jun 2015 13:45:06 -0700 Subject: [PATCH 1672/1783] Add missing docs for GitRepository Add argument and return type docs to fill in the documentation site. --- src/git-repository.coffee | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/git-repository.coffee b/src/git-repository.coffee index 145b2bf96..09ae42dcf 100644 --- a/src/git-repository.coffee +++ b/src/git-repository.coffee @@ -120,6 +120,10 @@ class GitRepository # Public: Invoke the given callback when this GitRepository's destroy() method # is invoked. + # + # * `callback` {Function} + # + # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. onDidDestroy: (callback) -> @emitter.on 'did-destroy', callback @@ -273,14 +277,24 @@ class GitRepository ### # Public: Returns true if the given path is modified. + # + # * `path` The {String} path to check. + # + # Returns a {Boolean} that's true if the `path` is modified. isPathModified: (path) -> @isStatusModified(@getPathStatus(path)) # Public: Returns true if the given path is new. + # + # * `path` The {String} path to check. + # + # Returns a {Boolean} that's true if the `path` is new. isPathNew: (path) -> @isStatusNew(@getPathStatus(path)) # Public: Is the given path ignored? # - # Returns a {Boolean}. + # * `path` The {String} path to check. + # + # Returns a {Boolean} that's true if the `path` is ignored. isPathIgnored: (path) -> @getRepo().isIgnored(@relativize(path)) # Public: Get the status of a directory in the repository's working directory. @@ -327,9 +341,17 @@ class GitRepository @statuses[@relativize(path)] # Public: Returns true if the given status indicates modification. + # + # * `status` A {Number} representing the status. + # + # Returns a {Boolean} that's true if the `status` indicates modification. isStatusModified: (status) -> @getRepo().isStatusModified(status) # Public: Returns true if the given status indicates a new path. + # + # * `status` A {Number} representing the status. + # + # Returns a {Boolean} that's true if the `status` indicates a new path. isStatusNew: (status) -> @getRepo().isStatusNew(status) ### From 51dcc84fce92eee37cef6047ce438443178cfe21 Mon Sep 17 00:00:00 2001 From: Nicklas Gummesson Date: Thu, 11 Jun 2015 23:10:26 +0200 Subject: [PATCH 1673/1783] Bind core:cut to native action Using same pattern as the others --- src/window-event-handler.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/window-event-handler.coffee b/src/window-event-handler.coffee index 3b9d54b96..ea0eb2e03 100644 --- a/src/window-event-handler.coffee +++ b/src/window-event-handler.coffee @@ -127,6 +127,7 @@ class WindowEventHandler bindCommandToAction('core:undo', 'undo:') bindCommandToAction('core:redo', 'redo:') bindCommandToAction('core:select-all', 'selectAll:') + bindCommandToAction('core:cut', 'cut:') onKeydown: (event) -> atom.keymaps.handleKeyboardEvent(event) From 7a6a48d7ea7fc50c7ba4070a19093cbef722a6fb Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 11 Jun 2015 15:31:33 -0700 Subject: [PATCH 1674/1783] Move getSaveDialogOptions near other save methods --- src/text-editor.coffee | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 20ef23264..4469be580 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -593,16 +593,6 @@ class TextEditor extends Model # Essential: Returns the {String} path of this editor's text buffer. getPath: -> @buffer.getPath() - # Private: Return [save options](http://electron.atom.io/docs/v0.27.0/api/di - # alog/#dialog.showsavedialog(%5Bbrowserwindow%5D,-%5Boptions%5D,-%5Bcallbac - # k%5D)) to be used when displaying the save dialog. - # - # Default empty options are returned now. In the future this would be the - # place to start implementing things like: https://discuss.atom.io/t - # /request-saving- file-with-correct-extension/17521 - getSaveDialogOptions: -> - {} - # Extended: Returns the {String} character set encoding of this editor's text # buffer. getEncoding: -> @buffer.getEncoding() @@ -648,6 +638,10 @@ class TextEditor extends Model else @isModified() and not @buffer.hasMultipleEditors() + # Returns an {Object} to configure dialog shown when this editor is saved + # via {Pane::saveItemAs}. + getSaveDialogOptions: -> {} + checkoutHeadRevision: -> if filePath = this.getPath() atom.project.repositoryForDirectory(new Directory(path.dirname(filePath))) From e47221bc3ffe86260a9c67f18d6233033e10fe12 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 11 Jun 2015 17:24:12 -0700 Subject: [PATCH 1675/1783] Never save window state in the middle of quitting --- src/browser/atom-application.coffee | 6 +++++- src/window-event-handler.coffee | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index db4c7ff2c..a59a6c8d2 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -105,7 +105,7 @@ class AtomApplication app.quit() return @windows.splice(@windows.indexOf(window), 1) - @saveState() unless window.isSpec or @quitting + @saveState() unless window.isSpec # Public: Adds the {AtomWindow} to the global window list. addWindow: (window) -> @@ -273,6 +273,9 @@ class AtomApplication @promptForPath "folder", (selectedPaths) -> event.sender.send(responseChannel, selectedPaths) + ipc.on 'cancel-window-close', => + @quitting = false + clipboard = null ipc.on 'write-text-to-selection-clipboard', (event, selectedText) -> clipboard ?= require '../safe-clipboard' @@ -437,6 +440,7 @@ class AtomApplication delete @pidsToOpenWindows[pid] saveState: -> + return if @quitting states = [] for window in @windows unless window.isSpec diff --git a/src/window-event-handler.coffee b/src/window-event-handler.coffee index 3b9d54b96..6f7a4cb6b 100644 --- a/src/window-event-handler.coffee +++ b/src/window-event-handler.coffee @@ -64,7 +64,10 @@ class WindowEventHandler atom.storeDefaultWindowDimensions() atom.storeWindowDimensions() - atom.unloadEditorWindow() if confirmed + if confirmed + atom.unloadEditorWindow() + else + ipc.send('cancel-window-close') confirmed From 4306d3816932d5e5a05a3c088e928d668d6a558c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Machist=C3=A9=20N=2E=20Quintana?= Date: Thu, 11 Jun 2015 21:42:59 -0400 Subject: [PATCH 1676/1783] :arrow_up: notifications@0.54.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e6e01485c..7a23846d8 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "link": "0.30.0", "markdown-preview": "0.150.0", "metrics": "0.51.0", - "notifications": "0.53.0", + "notifications": "0.54.0", "open-on-github": "0.37.0", "package-generator": "0.39.0", "release-notes": "0.53.0", From 3b3dc83a387fb42e7d79e1a652d1e2858ff09f0f Mon Sep 17 00:00:00 2001 From: Luke Pommersheim Date: Fri, 12 Jun 2015 08:36:44 +0200 Subject: [PATCH 1677/1783] :memo: updating docs for getCursorAtScreenPosition - can also take an {Array} --- 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 8c6bc0104..7a31ffad6 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -1563,7 +1563,7 @@ class TextEditor extends Model # Essential: Get a {Cursor} at given screen coordinates {Point} # - #* `position` A {Point} + # * `position` A {Point} or {Array} of `[row, column]` # # Returns the first matched {Cursor} or undefined getCursorAtScreenPosition: (position) -> From 63e491affa1d89e1ea81a8d7ddb47ac796a11b06 Mon Sep 17 00:00:00 2001 From: Luke Pommersheim Date: Fri, 12 Jun 2015 08:37:40 +0200 Subject: [PATCH 1678/1783] spec now checks if the cursors are the same, not their markers --- spec/text-editor-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 9cf5d783b..f8e0aa56b 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -941,7 +941,7 @@ describe "TextEditor", -> it "returns the existing cursor", -> cursor1 = editor.addCursorAtScreenPosition([0, 2]) cursor2 = editor.addCursorAtScreenPosition([0, 2]) - expect(cursor2.marker).toBe cursor1.marker + expect(cursor2).toBe cursor1 describe "addCursorAtBufferPosition(bufferPosition)", -> describe "when a cursor already exists at the position", -> From 9f0f4c05305e61e7d8a74309eec470d60fd649b5 Mon Sep 17 00:00:00 2001 From: Luke Pommersheim Date: Fri, 12 Jun 2015 08:38:25 +0200 Subject: [PATCH 1679/1783] refactor getCursorAtScreenPosition to avoid temporary array --- src/text-editor.coffee | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 7a31ffad6..64cbe513c 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -1567,10 +1567,9 @@ class TextEditor extends Model # # Returns the first matched {Cursor} or undefined getCursorAtScreenPosition: (position) -> - cursorsAtPoint = @cursors.filter (cursor) -> - cursorPosition = cursor.getScreenPosition() - cursorPosition.row is position.row and cursorPosition.column is position.column - if cursorsAtPoint.length > 0 then cursorsAtPoint[0] else undefined + for cursor in @cursors + return cursor if cursor.getScreenPosition().isEqual(position) + undefined # Essential: Get the position of the most recently added cursor in screen # coordinates. From d14e7b94567134fc5c124d568d7e8a3ac333cec1 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 12 Jun 2015 10:41:50 +0200 Subject: [PATCH 1680/1783] Enable `maxLineNumberDigits` --- src/line-number-gutter-component.coffee | 2 +- src/line-numbers-tile-component.coffee | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/line-number-gutter-component.coffee b/src/line-number-gutter-component.coffee index 7b68c2acd..a848e600c 100644 --- a/src/line-number-gutter-component.coffee +++ b/src/line-number-gutter-component.coffee @@ -3,7 +3,7 @@ TiledComponent = require './tiled-component' LineNumbersTileComponent = require './line-numbers-tile-component' WrapperDiv = document.createElement('div') -DummyLineNumberComponent = new LineNumbersTileComponent(id: -1) +DummyLineNumberComponent = LineNumbersTileComponent.createDummy() module.exports = class LineNumberGutterComponent extends TiledComponent diff --git a/src/line-numbers-tile-component.coffee b/src/line-numbers-tile-component.coffee index edbb8ecf7..d29925c1e 100644 --- a/src/line-numbers-tile-component.coffee +++ b/src/line-numbers-tile-component.coffee @@ -3,6 +3,9 @@ WrapperDiv = document.createElement('div') module.exports = class LineNumbersTileComponent + @createDummy: -> + new LineNumbersTileComponent({id: -1}) + constructor: ({@id}) -> @lineNumberNodesById = {} @domNode = document.createElement("div") @@ -36,11 +39,11 @@ class LineNumbersTileComponent @oldTileState.top = @newTileState.top @oldTileState.left = @newTileState.left - # if @newState.maxLineNumberDigits isnt @oldState.maxLineNumberDigits - # node.remove() for id, node of @lineNumberNodesById - # @oldState.tiles[@id] = {lineNumbers: {}} - # @oldTileState = @oldState.tiles[@id] - # @lineNumberNodesById = {} + if @newState.maxLineNumberDigits isnt @oldState.maxLineNumberDigits + node.remove() for id, node of @lineNumberNodesById + @oldState.tiles[@id] = {lineNumbers: {}} + @oldTileState = @oldState.tiles[@id] + @lineNumberNodesById = {} if @newState.scrollWidth isnt @oldState.scrollWidth @domNode.style.width = @newState.scrollWidth + 'px' From d45fc8a41f088ff527465cb25f283180f2c9b837 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 12 Jun 2015 12:10:55 +0200 Subject: [PATCH 1681/1783] Port `TextEditorPresenter` specs --- spec/text-editor-presenter-spec.coffee | 100 +++++++++++++------------ src/line-numbers-tile-component.coffee | 10 +-- 2 files changed, 59 insertions(+), 51 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index a0ce19b96..d39a672f1 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -2010,6 +2010,7 @@ describe "TextEditorPresenter", -> describe ".content.lineNumbers", -> lineNumberStateForScreenRow = (presenter, screenRow) -> editor = presenter.model + tileRow = presenter.tileForRow(screenRow) bufferRow = editor.bufferRowForScreenRow(screenRow) wrapCount = screenRow - editor.screenRowForBufferRow(bufferRow) if wrapCount > 0 @@ -2017,23 +2018,26 @@ describe "TextEditorPresenter", -> else key = bufferRow - getLineNumberGutterState(presenter).content.lineNumbers[key] + gutterState = getLineNumberGutterState(presenter) + gutterState.content.tiles[tileRow]?.lineNumbers[key] it "contains states for line numbers that are visible on screen", -> editor.foldBufferRow(4) editor.setSoftWrapped(true) editor.setEditorWidthInChars(50) - presenter = buildPresenter(explicitHeight: 25, scrollTop: 30, lineHeight: 10) + presenter = buildPresenter(explicitHeight: 25, scrollTop: 30, lineHeight: 10, tileSize: 2) - expect(lineNumberStateForScreenRow(presenter, 2)).toBeUndefined() - expectValues lineNumberStateForScreenRow(presenter, 3), {screenRow: 3, bufferRow: 3, softWrapped: false, top: 3 * 10} - expectValues lineNumberStateForScreenRow(presenter, 4), {screenRow: 4, bufferRow: 3, softWrapped: true, top: 4 * 10} - expectValues lineNumberStateForScreenRow(presenter, 5), {screenRow: 5, bufferRow: 4, softWrapped: false, top: 5 * 10} - expectValues lineNumberStateForScreenRow(presenter, 6), {screenRow: 6, bufferRow: 7, softWrapped: false, top: 6 * 10} - expect(lineNumberStateForScreenRow(presenter, 7)).toBeUndefined() + expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() + expectValues lineNumberStateForScreenRow(presenter, 2), {screenRow: 2, bufferRow: 2, softWrapped: false, top: 0 * 10} + expectValues lineNumberStateForScreenRow(presenter, 3), {screenRow: 3, bufferRow: 3, softWrapped: false, top: 1 * 10} + expectValues lineNumberStateForScreenRow(presenter, 4), {screenRow: 4, bufferRow: 3, softWrapped: true, top: 0 * 10} + expectValues lineNumberStateForScreenRow(presenter, 5), {screenRow: 5, bufferRow: 4, softWrapped: false, top: 1 * 10} + expectValues lineNumberStateForScreenRow(presenter, 6), {screenRow: 6, bufferRow: 7, softWrapped: false, top: 0 * 10} + expectValues lineNumberStateForScreenRow(presenter, 7), {screenRow: 7, bufferRow: 8, softWrapped: false, top: 1 * 10} + expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() it "includes states for all line numbers if no ::explicitHeight is assigned", -> - presenter = buildPresenter(explicitHeight: null) + presenter = buildPresenter(explicitHeight: null, tileSize: 2) expect(lineNumberStateForScreenRow(presenter, 0)).toBeDefined() expect(lineNumberStateForScreenRow(presenter, 12)).toBeDefined() @@ -2041,17 +2045,16 @@ describe "TextEditorPresenter", -> editor.foldBufferRow(4) editor.setSoftWrapped(true) editor.setEditorWidthInChars(50) - presenter = buildPresenter(explicitHeight: 25, scrollTop: 30) - - expect(lineNumberStateForScreenRow(presenter, 2)).toBeUndefined() - expectValues lineNumberStateForScreenRow(presenter, 3), {bufferRow: 3} - expectValues lineNumberStateForScreenRow(presenter, 6), {bufferRow: 7} - expect(lineNumberStateForScreenRow(presenter, 7)).toBeUndefined() - - expectStateUpdate presenter, -> presenter.setScrollTop(20) + presenter = buildPresenter(explicitHeight: 25, scrollTop: 30, tileSize: 2) expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() expectValues lineNumberStateForScreenRow(presenter, 2), {bufferRow: 2} + expectValues lineNumberStateForScreenRow(presenter, 7), {bufferRow: 8} + expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() + + expectStateUpdate presenter, -> presenter.setScrollTop(10) + + expectValues lineNumberStateForScreenRow(presenter, 0), {bufferRow: 0} expectValues lineNumberStateForScreenRow(presenter, 5), {bufferRow: 4} expect(lineNumberStateForScreenRow(presenter, 6)).toBeUndefined() @@ -2059,87 +2062,92 @@ describe "TextEditorPresenter", -> editor.foldBufferRow(4) editor.setSoftWrapped(true) editor.setEditorWidthInChars(50) - presenter = buildPresenter(explicitHeight: 25, scrollTop: 30) + presenter = buildPresenter(explicitHeight: 25, scrollTop: 30, tileSize: 2) expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() - expectValues lineNumberStateForScreenRow(presenter, 3), {bufferRow: 3} - expectValues lineNumberStateForScreenRow(presenter, 6), {bufferRow: 7} - expect(lineNumberStateForScreenRow(presenter, 7)).toBeUndefined() + expectValues lineNumberStateForScreenRow(presenter, 2), {bufferRow: 2} + expectValues lineNumberStateForScreenRow(presenter, 7), {bufferRow: 8} + expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() expectStateUpdate presenter, -> presenter.setExplicitHeight(35) - expect(lineNumberStateForScreenRow(presenter, 0)).toBeUndefined() + expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() expectValues lineNumberStateForScreenRow(presenter, 3), {bufferRow: 3} - expectValues lineNumberStateForScreenRow(presenter, 7), {bufferRow: 8} - expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() + expectValues lineNumberStateForScreenRow(presenter, 9), {bufferRow: 9} + expect(lineNumberStateForScreenRow(presenter, 10)).toBeUndefined() it "updates when ::lineHeight changes", -> editor.foldBufferRow(4) editor.setSoftWrapped(true) editor.setEditorWidthInChars(50) - presenter = buildPresenter(explicitHeight: 25, scrollTop: 0) - - expectValues lineNumberStateForScreenRow(presenter, 0), {bufferRow: 0} - expectValues lineNumberStateForScreenRow(presenter, 3), {bufferRow: 3} - expect(lineNumberStateForScreenRow(presenter, 4)).toBeUndefined() - - expectStateUpdate presenter, -> presenter.setLineHeight(5) + presenter = buildPresenter(explicitHeight: 25, scrollTop: 0, tileSize: 2) expectValues lineNumberStateForScreenRow(presenter, 0), {bufferRow: 0} expectValues lineNumberStateForScreenRow(presenter, 5), {bufferRow: 4} expect(lineNumberStateForScreenRow(presenter, 6)).toBeUndefined() + expectStateUpdate presenter, -> presenter.setLineHeight(5) + + expectValues lineNumberStateForScreenRow(presenter, 0), {bufferRow: 0} + expectValues lineNumberStateForScreenRow(presenter, 7), {bufferRow: 8} + expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() + it "updates when the editor's content changes", -> editor.foldBufferRow(4) editor.setSoftWrapped(true) editor.setEditorWidthInChars(50) - presenter = buildPresenter(explicitHeight: 35, scrollTop: 30) + presenter = buildPresenter(explicitHeight: 35, scrollTop: 30, tileSize: 2) - expect(lineNumberStateForScreenRow(presenter, 2)).toBeUndefined() + expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() + expectValues lineNumberStateForScreenRow(presenter, 2), {bufferRow: 2} expectValues lineNumberStateForScreenRow(presenter, 3), {bufferRow: 3} expectValues lineNumberStateForScreenRow(presenter, 4), {bufferRow: 3} expectValues lineNumberStateForScreenRow(presenter, 5), {bufferRow: 4} expectValues lineNumberStateForScreenRow(presenter, 6), {bufferRow: 7} expectValues lineNumberStateForScreenRow(presenter, 7), {bufferRow: 8} - expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() + expectValues lineNumberStateForScreenRow(presenter, 8), {bufferRow: 8} + expectValues lineNumberStateForScreenRow(presenter, 9), {bufferRow: 9} + expect(lineNumberStateForScreenRow(presenter, 10)).toBeUndefined() expectStateUpdate presenter, -> editor.getBuffer().insert([3, Infinity], new Array(25).join("x ")) - expect(lineNumberStateForScreenRow(presenter, 2)).toBeUndefined() + expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() + expectValues lineNumberStateForScreenRow(presenter, 2), {bufferRow: 2} expectValues lineNumberStateForScreenRow(presenter, 3), {bufferRow: 3} expectValues lineNumberStateForScreenRow(presenter, 4), {bufferRow: 3} expectValues lineNumberStateForScreenRow(presenter, 5), {bufferRow: 3} expectValues lineNumberStateForScreenRow(presenter, 6), {bufferRow: 4} expectValues lineNumberStateForScreenRow(presenter, 7), {bufferRow: 7} - expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() + expectValues lineNumberStateForScreenRow(presenter, 8), {bufferRow: 8} + expectValues lineNumberStateForScreenRow(presenter, 9), {bufferRow: 8} + expect(lineNumberStateForScreenRow(presenter, 10)).toBeUndefined() - it "does not remove out-of-view line numbers corresponding to ::mouseWheelScreenRow until ::stoppedScrollingDelay elapses", -> - presenter = buildPresenter(explicitHeight: 25, stoppedScrollingDelay: 200) + it "does not remove out-of-view tiles corresponding to ::mouseWheelScreenRow until ::stoppedScrollingDelay elapses", -> + presenter = buildPresenter(explicitHeight: 25, stoppedScrollingDelay: 200, tileSize: 2) expect(lineNumberStateForScreenRow(presenter, 0)).toBeDefined() - expect(lineNumberStateForScreenRow(presenter, 3)).toBeDefined() - expect(lineNumberStateForScreenRow(presenter, 4)).toBeUndefined() + expect(lineNumberStateForScreenRow(presenter, 4)).toBeDefined() + expect(lineNumberStateForScreenRow(presenter, 6)).toBeUndefined() presenter.setMouseWheelScreenRow(0) - expectStateUpdate presenter, -> presenter.setScrollTop(35) + expectStateUpdate presenter, -> presenter.setScrollTop(45) expect(lineNumberStateForScreenRow(presenter, 0)).toBeDefined() - expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() + expect(lineNumberStateForScreenRow(presenter, 2)).toBeUndefined() expect(lineNumberStateForScreenRow(presenter, 6)).toBeDefined() - expect(lineNumberStateForScreenRow(presenter, 7)).toBeUndefined() + expect(lineNumberStateForScreenRow(presenter, 10)).toBeUndefined() expectStateUpdate presenter, -> advanceClock(200) expect(lineNumberStateForScreenRow(presenter, 0)).toBeUndefined() - expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() expect(lineNumberStateForScreenRow(presenter, 6)).toBeDefined() - expect(lineNumberStateForScreenRow(presenter, 7)).toBeUndefined() + expect(lineNumberStateForScreenRow(presenter, 10)).toBeUndefined() it "correctly handles the first screen line being soft-wrapped", -> editor.setSoftWrapped(true) editor.setEditorWidthInChars(30) - presenter = buildPresenter(explicitHeight: 25, scrollTop: 50) + presenter = buildPresenter(explicitHeight: 25, scrollTop: 50, tileSize: 2) expectValues lineNumberStateForScreenRow(presenter, 5), {screenRow: 5, bufferRow: 3, softWrapped: true} expectValues lineNumberStateForScreenRow(presenter, 6), {screenRow: 6, bufferRow: 3, softWrapped: true} diff --git a/src/line-numbers-tile-component.coffee b/src/line-numbers-tile-component.coffee index d29925c1e..b18426a56 100644 --- a/src/line-numbers-tile-component.coffee +++ b/src/line-numbers-tile-component.coffee @@ -39,11 +39,11 @@ class LineNumbersTileComponent @oldTileState.top = @newTileState.top @oldTileState.left = @newTileState.left - if @newState.maxLineNumberDigits isnt @oldState.maxLineNumberDigits - node.remove() for id, node of @lineNumberNodesById - @oldState.tiles[@id] = {lineNumbers: {}} - @oldTileState = @oldState.tiles[@id] - @lineNumberNodesById = {} + # if @newState.maxLineNumberDigits isnt @oldState.maxLineNumberDigits + # node.remove() for id, node of @lineNumberNodesById + # @oldState.tiles[@id] = {lineNumbers: {}} + # @oldTileState = @oldState.tiles[@id] + # @lineNumberNodesById = {} if @newState.scrollWidth isnt @oldState.scrollWidth @domNode.style.width = @newState.scrollWidth + 'px' From 13087eb58e7a5f1cae6cb3278b09f673adcc2347 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 12 Jun 2015 12:39:24 +0200 Subject: [PATCH 1682/1783] Handle Max Line Number Digits --- src/line-numbers-tile-component.coffee | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/line-numbers-tile-component.coffee b/src/line-numbers-tile-component.coffee index b18426a56..a0ae8d49a 100644 --- a/src/line-numbers-tile-component.coffee +++ b/src/line-numbers-tile-component.coffee @@ -39,11 +39,12 @@ class LineNumbersTileComponent @oldTileState.top = @newTileState.top @oldTileState.left = @newTileState.left - # if @newState.maxLineNumberDigits isnt @oldState.maxLineNumberDigits - # node.remove() for id, node of @lineNumberNodesById - # @oldState.tiles[@id] = {lineNumbers: {}} - # @oldTileState = @oldState.tiles[@id] - # @lineNumberNodesById = {} + if @newState.maxLineNumberDigits isnt @oldState.maxLineNumberDigits + node.remove() for id, node of @lineNumberNodesById + @oldState.tiles[@id] = {lineNumbers: {}} + @oldTileState = @oldState.tiles[@id] + @lineNumberNodesById = {} + @oldState.maxLineNumberDigits = @newState.maxLineNumberDigits if @newState.scrollWidth isnt @oldState.scrollWidth @domNode.style.width = @newState.scrollWidth + 'px' From 605f584d2eb1394c8e9088416eaacc06a0039323 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 12 Jun 2015 12:53:29 +0200 Subject: [PATCH 1683/1783] Extract tiles specs into `tiledContentContract` --- spec/text-editor-presenter-spec.coffee | 349 +++++++++++++------------ 1 file changed, 177 insertions(+), 172 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index d39a672f1..a659ec4f5 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -58,6 +58,157 @@ describe "TextEditorPresenter", -> expectNoStateUpdate = (presenter, fn) -> expectStateUpdatedToBe(false, presenter, fn) + tiledContentContract = (stateFn) -> + it "contains states for tiles that are visible on screen", -> + presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileSize: 2) + + expectValues stateFn(presenter).tiles[0], { + top: 0 + } + expectValues stateFn(presenter).tiles[2], { + top: 2 + } + expectValues stateFn(presenter).tiles[4], { + top: 4 + } + expectValues stateFn(presenter).tiles[6], { + top: 6 + } + + expect(stateFn(presenter).tiles[8]).toBeUndefined() + + expectStateUpdate presenter, -> presenter.setScrollTop(3) + + expect(stateFn(presenter).tiles[0]).toBeUndefined() + + expectValues stateFn(presenter).tiles[2], { + top: -1 + } + expectValues stateFn(presenter).tiles[4], { + top: 1 + } + expectValues stateFn(presenter).tiles[6], { + top: 3 + } + expectValues stateFn(presenter).tiles[8], { + top: 5 + } + expectValues stateFn(presenter).tiles[10], { + top: 7 + } + + expect(stateFn(presenter).tiles[12]).toBeUndefined() + + it "includes state for all tiles if no external ::explicitHeight is assigned", -> + presenter = buildPresenter(explicitHeight: null, tileSize: 2) + expect(stateFn(presenter).tiles[0]).toBeDefined() + expect(stateFn(presenter).tiles[12]).toBeDefined() + + it "is empty until all of the required measurements are assigned", -> + presenter = buildPresenter(explicitHeight: null, lineHeight: null, scrollTop: null) + expect(stateFn(presenter).tiles).toEqual({}) + + presenter.setExplicitHeight(25) + expect(stateFn(presenter).tiles).toEqual({}) + + presenter.setLineHeight(10) + expect(stateFn(presenter).tiles).toEqual({}) + + presenter.setScrollTop(0) + expect(stateFn(presenter).tiles).not.toEqual({}) + + it "updates when ::scrollTop changes", -> + presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileSize: 2) + + expect(stateFn(presenter).tiles[0]).toBeDefined() + expect(stateFn(presenter).tiles[2]).toBeDefined() + expect(stateFn(presenter).tiles[4]).toBeDefined() + expect(stateFn(presenter).tiles[6]).toBeDefined() + expect(stateFn(presenter).tiles[8]).toBeUndefined() + + expectStateUpdate presenter, -> presenter.setScrollTop(2) + + expect(stateFn(presenter).tiles[0]).toBeUndefined() + expect(stateFn(presenter).tiles[2]).toBeDefined() + expect(stateFn(presenter).tiles[4]).toBeDefined() + expect(stateFn(presenter).tiles[6]).toBeDefined() + expect(stateFn(presenter).tiles[8]).toBeDefined() + expect(stateFn(presenter).tiles[10]).toBeUndefined() + + it "updates when ::explicitHeight changes", -> + presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileSize: 2) + + expect(stateFn(presenter).tiles[0]).toBeDefined() + expect(stateFn(presenter).tiles[2]).toBeDefined() + expect(stateFn(presenter).tiles[4]).toBeDefined() + expect(stateFn(presenter).tiles[6]).toBeDefined() + expect(stateFn(presenter).tiles[8]).toBeUndefined() + + expectStateUpdate presenter, -> presenter.setExplicitHeight(8) + + expect(stateFn(presenter).tiles[0]).toBeDefined() + expect(stateFn(presenter).tiles[2]).toBeDefined() + expect(stateFn(presenter).tiles[4]).toBeDefined() + expect(stateFn(presenter).tiles[6]).toBeDefined() + expect(stateFn(presenter).tiles[8]).toBeDefined() + expect(stateFn(presenter).tiles[10]).toBeUndefined() + + + it "updates when ::lineHeight changes", -> + presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileSize: 2) + + expect(stateFn(presenter).tiles[0]).toBeDefined() + expect(stateFn(presenter).tiles[2]).toBeDefined() + expect(stateFn(presenter).tiles[4]).toBeDefined() + expect(stateFn(presenter).tiles[6]).toBeDefined() + expect(stateFn(presenter).tiles[8]).toBeUndefined() + + expectStateUpdate presenter, -> presenter.setLineHeight(2) + + expect(stateFn(presenter).tiles[0]).toBeDefined() + expect(stateFn(presenter).tiles[2]).toBeDefined() + expect(stateFn(presenter).tiles[4]).toBeDefined() + expect(stateFn(presenter).tiles[6]).toBeUndefined() + + it "does not remove out-of-view tiles corresponding to ::mouseWheelScreenRow until ::stoppedScrollingDelay elapses", -> + presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileSize: 2, stoppedScrollingDelay: 200) + + expect(stateFn(presenter).tiles[0]).toBeDefined() + expect(stateFn(presenter).tiles[6]).toBeDefined() + expect(stateFn(presenter).tiles[8]).toBeUndefined() + + presenter.setMouseWheelScreenRow(0) + expectStateUpdate presenter, -> presenter.setScrollTop(4) + + expect(stateFn(presenter).tiles[0]).toBeDefined() + expect(stateFn(presenter).tiles[2]).toBeUndefined() + expect(stateFn(presenter).tiles[4]).toBeDefined() + expect(stateFn(presenter).tiles[12]).toBeUndefined() + + expectStateUpdate presenter, -> advanceClock(200) + + expect(stateFn(presenter).tiles[0]).toBeUndefined() + expect(stateFn(presenter).tiles[2]).toBeUndefined() + expect(stateFn(presenter).tiles[4]).toBeDefined() + expect(stateFn(presenter).tiles[12]).toBeUndefined() + + + # should clear ::mouseWheelScreenRow after stoppedScrollingDelay elapses even if we don't scroll first + presenter.setMouseWheelScreenRow(4) + advanceClock(200) + expectStateUpdate presenter, -> presenter.setScrollTop(6) + expect(stateFn(presenter).tiles[4]).toBeUndefined() + + it "does not preserve deleted on-screen tiles even if they correspond to ::mouseWheelScreenRow", -> + presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileSize: 2, stoppedScrollingDelay: 200) + + presenter.setMouseWheelScreenRow(2) + + expectStateUpdate presenter, -> editor.setText("") + + expect(stateFn(presenter).tiles[2]).toBeUndefined() + expect(stateFn(presenter).tiles[0]).toBeDefined() + describe "during state retrieval", -> it "does not trigger onDidUpdateState events", -> presenter = buildPresenter() @@ -662,178 +813,7 @@ describe "TextEditorPresenter", -> tileRow = presenter.tileForRow(row) presenter.getState().content.tiles[tileRow]?.lines[lineId] - it "contains states for tiles that are visible on screen", -> - presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileSize: 2) - - expectValues presenter.getState().content.tiles[0], { - top: 0 - } - expectValues presenter.getState().content.tiles[2], { - top: 2 - } - expectValues presenter.getState().content.tiles[4], { - top: 4 - } - expectValues presenter.getState().content.tiles[6], { - top: 6 - } - - expect(presenter.getState().content.tiles[8]).toBeUndefined() - - expectStateUpdate presenter, -> presenter.setScrollTop(3) - - expect(presenter.getState().content.tiles[0]).toBeUndefined() - - expectValues presenter.getState().content.tiles[2], { - top: -1 - } - expectValues presenter.getState().content.tiles[4], { - top: 1 - } - expectValues presenter.getState().content.tiles[6], { - top: 3 - } - expectValues presenter.getState().content.tiles[8], { - top: 5 - } - expectValues presenter.getState().content.tiles[10], { - top: 7 - } - - expect(presenter.getState().content.tiles[12]).toBeUndefined() - - it "includes state for all tiles if no external ::explicitHeight is assigned", -> - presenter = buildPresenter(explicitHeight: null, tileSize: 2) - expect(presenter.getState().content.tiles[0]).toBeDefined() - expect(presenter.getState().content.tiles[12]).toBeDefined() - - it "is empty until all of the required measurements are assigned", -> - presenter = buildPresenter(explicitHeight: null, lineHeight: null, scrollTop: null) - expect(presenter.getState().content.tiles).toEqual({}) - - presenter.setExplicitHeight(25) - expect(presenter.getState().content.tiles).toEqual({}) - - presenter.setLineHeight(10) - expect(presenter.getState().content.tiles).toEqual({}) - - presenter.setScrollTop(0) - expect(presenter.getState().content.tiles).not.toEqual({}) - - it "updates when ::scrollTop changes", -> - presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileSize: 2) - - expect(presenter.getState().content.tiles[0]).toBeDefined() - expect(presenter.getState().content.tiles[2]).toBeDefined() - expect(presenter.getState().content.tiles[4]).toBeDefined() - expect(presenter.getState().content.tiles[6]).toBeDefined() - expect(presenter.getState().content.tiles[8]).toBeUndefined() - - expectStateUpdate presenter, -> presenter.setScrollTop(2) - - expect(presenter.getState().content.tiles[0]).toBeUndefined() - expect(presenter.getState().content.tiles[2]).toBeDefined() - expect(presenter.getState().content.tiles[4]).toBeDefined() - expect(presenter.getState().content.tiles[6]).toBeDefined() - expect(presenter.getState().content.tiles[8]).toBeDefined() - expect(presenter.getState().content.tiles[10]).toBeUndefined() - - it "updates when ::explicitHeight changes", -> - presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileSize: 2) - - expect(presenter.getState().content.tiles[0]).toBeDefined() - expect(presenter.getState().content.tiles[2]).toBeDefined() - expect(presenter.getState().content.tiles[4]).toBeDefined() - expect(presenter.getState().content.tiles[6]).toBeDefined() - expect(presenter.getState().content.tiles[8]).toBeUndefined() - - expectStateUpdate presenter, -> presenter.setExplicitHeight(8) - - expect(presenter.getState().content.tiles[0]).toBeDefined() - expect(presenter.getState().content.tiles[2]).toBeDefined() - expect(presenter.getState().content.tiles[4]).toBeDefined() - expect(presenter.getState().content.tiles[6]).toBeDefined() - expect(presenter.getState().content.tiles[8]).toBeDefined() - expect(presenter.getState().content.tiles[10]).toBeUndefined() - - - it "updates when ::lineHeight changes", -> - presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileSize: 2) - - expect(presenter.getState().content.tiles[0]).toBeDefined() - expect(presenter.getState().content.tiles[2]).toBeDefined() - expect(presenter.getState().content.tiles[4]).toBeDefined() - expect(presenter.getState().content.tiles[6]).toBeDefined() - expect(presenter.getState().content.tiles[8]).toBeUndefined() - - expectStateUpdate presenter, -> presenter.setLineHeight(2) - - expect(presenter.getState().content.tiles[0]).toBeDefined() - expect(presenter.getState().content.tiles[2]).toBeDefined() - expect(presenter.getState().content.tiles[4]).toBeDefined() - expect(presenter.getState().content.tiles[6]).toBeUndefined() - - it "updates when the editor's content changes", -> - presenter = buildPresenter(explicitHeight: 25, scrollTop: 10, lineHeight: 10, tileSize: 2) - - expectStateUpdate presenter, -> buffer.insert([2, 0], "hello\nworld\n") - - line1 = editor.tokenizedLineForScreenRow(1) - expectValues lineStateForScreenRow(presenter, 1), { - text: line1.text - tags: line1.tags - } - - line2 = editor.tokenizedLineForScreenRow(2) - expectValues lineStateForScreenRow(presenter, 2), { - text: line2.text - tags: line2.tags - } - - line3 = editor.tokenizedLineForScreenRow(3) - expectValues lineStateForScreenRow(presenter, 3), { - text: line3.text - tags: line3.tags - } - - it "does not remove out-of-view tiles corresponding to ::mouseWheelScreenRow until ::stoppedScrollingDelay elapses", -> - presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileSize: 2, stoppedScrollingDelay: 200) - - expect(presenter.getState().content.tiles[0]).toBeDefined() - expect(presenter.getState().content.tiles[6]).toBeDefined() - expect(presenter.getState().content.tiles[8]).toBeUndefined() - - presenter.setMouseWheelScreenRow(0) - expectStateUpdate presenter, -> presenter.setScrollTop(4) - - expect(presenter.getState().content.tiles[0]).toBeDefined() - expect(presenter.getState().content.tiles[2]).toBeUndefined() - expect(presenter.getState().content.tiles[4]).toBeDefined() - expect(presenter.getState().content.tiles[12]).toBeUndefined() - - expectStateUpdate presenter, -> advanceClock(200) - - expect(presenter.getState().content.tiles[0]).toBeUndefined() - expect(presenter.getState().content.tiles[2]).toBeUndefined() - expect(presenter.getState().content.tiles[4]).toBeDefined() - expect(presenter.getState().content.tiles[12]).toBeUndefined() - - - # should clear ::mouseWheelScreenRow after stoppedScrollingDelay elapses even if we don't scroll first - presenter.setMouseWheelScreenRow(4) - advanceClock(200) - expectStateUpdate presenter, -> presenter.setScrollTop(6) - expect(presenter.getState().content.tiles[4]).toBeUndefined() - - it "does not preserve deleted on-screen tiles even if they correspond to ::mouseWheelScreenRow", -> - presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileSize: 2, stoppedScrollingDelay: 200) - - presenter.setMouseWheelScreenRow(2) - - expectStateUpdate presenter, -> editor.setText("") - - expect(presenter.getState().content.tiles[2]).toBeUndefined() - expect(presenter.getState().content.tiles[0]).toBeDefined() + tiledContentContract (presenter) -> presenter.getState().content describe "[tileId].lines[lineId]", -> # line state objects it "includes the state for visible lines in a tile", -> @@ -915,6 +895,29 @@ describe "TextEditorPresenter", -> expect(lineStateForScreenRow(presenter, 9)).toBeUndefined() + it "updates when the editor's content changes", -> + presenter = buildPresenter(explicitHeight: 25, scrollTop: 10, lineHeight: 10, tileSize: 2) + + expectStateUpdate presenter, -> buffer.insert([2, 0], "hello\nworld\n") + + line1 = editor.tokenizedLineForScreenRow(1) + expectValues lineStateForScreenRow(presenter, 1), { + text: line1.text + tags: line1.tags + } + + line2 = editor.tokenizedLineForScreenRow(2) + expectValues lineStateForScreenRow(presenter, 2), { + text: line2.text + tags: line2.tags + } + + line3 = editor.tokenizedLineForScreenRow(3) + expectValues lineStateForScreenRow(presenter, 3), { + text: line3.text + tags: line3.tags + } + it "includes the .endOfLineInvisibles if the editor.showInvisibles config option is true", -> editor.setText("hello\nworld\r\n") presenter = buildPresenter(explicitHeight: 25, scrollTop: 0, lineHeight: 10) @@ -2021,6 +2024,8 @@ describe "TextEditorPresenter", -> gutterState = getLineNumberGutterState(presenter) gutterState.content.tiles[tileRow]?.lineNumbers[key] + tiledContentContract (presenter) -> getLineNumberGutterState(presenter).content + it "contains states for line numbers that are visible on screen", -> editor.foldBufferRow(4) editor.setSoftWrapped(true) From 5dee3ce5950d972d3f275ad1a93d62f542d42aeb Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 12 Jun 2015 09:03:55 -0700 Subject: [PATCH 1684/1783] :arrow_up: language-sass@0.39 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7a23846d8..fef17f3a3 100644 --- a/package.json +++ b/package.json @@ -150,7 +150,7 @@ "language-python": "0.36.0", "language-ruby": "0.56.0", "language-ruby-on-rails": "0.22.0", - "language-sass": "0.38.0", + "language-sass": "0.39.0", "language-shellscript": "0.15.0", "language-source": "0.9.0", "language-sql": "0.16.0", From 7ac0cdcbf5ec5e06779ea6e51ab704d525984443 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 12 Jun 2015 13:12:50 +0200 Subject: [PATCH 1685/1783] Start porting `TextEditorComponent` spec --- spec/text-editor-component-spec.coffee | 123 ++++++++++++++++-------- src/gutter-container-component.coffee | 5 +- src/line-number-gutter-component.coffee | 9 +- src/line-numbers-tile-component.coffee | 12 ++- src/text-editor-component.coffee | 2 +- 5 files changed, 102 insertions(+), 49 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 6749e7803..808eb527e 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -5,9 +5,9 @@ TextEditorView = require '../src/text-editor-view' TextEditorComponent = require '../src/text-editor-component' nbsp = String.fromCharCode(160) -describe "TextEditorComponent", -> +fdescribe "TextEditorComponent", -> [contentNode, editor, wrapperView, wrapperNode, component, componentNode, verticalScrollbarNode, horizontalScrollbarNode] = [] - [lineHeightInPixels, charWidth, nextAnimationFrame, noAnimationFrame, tileSize] = [] + [lineHeightInPixels, charWidth, nextAnimationFrame, noAnimationFrame, tileSize, tileHeightInPixels] = [] beforeEach -> tileSize = 3 @@ -45,6 +45,7 @@ describe "TextEditorComponent", -> component.setFontSize(20) lineHeightInPixels = editor.getLineHeightInPixels() + tileHeightInPixels = tileSize * lineHeightInPixels charWidth = editor.getDefaultCharWidth() componentNode = component.getDomNode() verticalScrollbarNode = componentNode.querySelector('.vertical-scrollbar') @@ -80,11 +81,10 @@ describe "TextEditorComponent", -> it "renders the currently-visible lines in a tiled fashion", -> wrapperNode.style.height = 6.5 * lineHeightInPixels + 'px' - tileHeight = tileSize * lineHeightInPixels component.measureDimensions() nextAnimationFrame() - tilesNodes = componentNode.querySelectorAll(".tile") + tilesNodes = componentNode.querySelector(".lines").querySelectorAll(".tile") expect(tilesNodes.length).toBe(3) @@ -94,13 +94,13 @@ describe "TextEditorComponent", -> expectTileContainsRow(tilesNodes[0], 1, top: 1 * lineHeightInPixels) expectTileContainsRow(tilesNodes[0], 2, top: 2 * lineHeightInPixels) - expect(tilesNodes[1].style['-webkit-transform']).toBe "translate3d(0px, #{1 * tileHeight}px, 0px)" + expect(tilesNodes[1].style['-webkit-transform']).toBe "translate3d(0px, #{1 * tileHeightInPixels}px, 0px)" expect(tilesNodes[1].querySelectorAll(".line").length).toBe(tileSize) expectTileContainsRow(tilesNodes[1], 3, top: 0 * lineHeightInPixels) expectTileContainsRow(tilesNodes[1], 4, top: 1 * lineHeightInPixels) expectTileContainsRow(tilesNodes[1], 5, top: 2 * lineHeightInPixels) - expect(tilesNodes[2].style['-webkit-transform']).toBe "translate3d(0px, #{2 * tileHeight}px, 0px)" + expect(tilesNodes[2].style['-webkit-transform']).toBe "translate3d(0px, #{2 * tileHeightInPixels}px, 0px)" expect(tilesNodes[2].querySelectorAll(".line").length).toBe(tileSize) expectTileContainsRow(tilesNodes[2], 6, top: 0 * lineHeightInPixels) expectTileContainsRow(tilesNodes[2], 7, top: 1 * lineHeightInPixels) @@ -112,24 +112,24 @@ describe "TextEditorComponent", -> verticalScrollbarNode.dispatchEvent(new UIEvent('scroll')) nextAnimationFrame() - tilesNodes = componentNode.querySelectorAll(".tile") + tilesNodes = componentNode.querySelector(".lines").querySelectorAll(".tile") expect(component.lineNodeForScreenRow(2)).toBeUndefined() expect(tilesNodes.length).toBe(3) - expect(tilesNodes[0].style['-webkit-transform']).toBe "translate3d(0px, -5px, 0px)" + expect(tilesNodes[0].style['-webkit-transform']).toBe "translate3d(0px, #{0 * tileHeightInPixels - 5}px, 0px)" expect(tilesNodes[0].querySelectorAll(".line").length).toBe(tileSize) expectTileContainsRow(tilesNodes[0], 3, top: 0 * lineHeightInPixels) expectTileContainsRow(tilesNodes[0], 4, top: 1 * lineHeightInPixels) expectTileContainsRow(tilesNodes[0], 5, top: 2 * lineHeightInPixels) - expect(tilesNodes[1].style['-webkit-transform']).toBe "translate3d(0px, #{1 * tileHeight - 5}px, 0px)" + expect(tilesNodes[1].style['-webkit-transform']).toBe "translate3d(0px, #{1 * tileHeightInPixels - 5}px, 0px)" expect(tilesNodes[1].querySelectorAll(".line").length).toBe(tileSize) expectTileContainsRow(tilesNodes[1], 6, top: 0 * lineHeightInPixels) expectTileContainsRow(tilesNodes[1], 7, top: 1 * lineHeightInPixels) expectTileContainsRow(tilesNodes[1], 8, top: 2 * lineHeightInPixels) - expect(tilesNodes[2].style['-webkit-transform']).toBe "translate3d(0px, #{2 * tileHeight - 5}px, 0px)" + expect(tilesNodes[2].style['-webkit-transform']).toBe "translate3d(0px, #{2 * tileHeightInPixels - 5}px, 0px)" expect(tilesNodes[2].querySelectorAll(".line").length).toBe(tileSize) expectTileContainsRow(tilesNodes[2], 9, top: 0 * lineHeightInPixels) expectTileContainsRow(tilesNodes[2], 10, top: 1 * lineHeightInPixels) @@ -137,19 +137,18 @@ describe "TextEditorComponent", -> it "updates the top position of subsequent tiles when lines are inserted or removed", -> wrapperNode.style.height = 6.5 * lineHeightInPixels + 'px' - tileHeight = tileSize * lineHeightInPixels component.measureDimensions() editor.getBuffer().deleteRows(0, 1) nextAnimationFrame() - tilesNodes = componentNode.querySelectorAll(".tile") + tilesNodes = componentNode.querySelector(".lines").querySelectorAll(".tile") expect(tilesNodes[0].style['-webkit-transform']).toBe "translate3d(0px, 0px, 0px)" expectTileContainsRow(tilesNodes[0], 0, top: 0 * lineHeightInPixels) expectTileContainsRow(tilesNodes[0], 1, top: 1 * lineHeightInPixels) expectTileContainsRow(tilesNodes[0], 2, top: 2 * lineHeightInPixels) - expect(tilesNodes[1].style['-webkit-transform']).toBe "translate3d(0px, #{1 * tileHeight}px, 0px)" + expect(tilesNodes[1].style['-webkit-transform']).toBe "translate3d(0px, #{1 * tileHeightInPixels}px, 0px)" expectTileContainsRow(tilesNodes[1], 3, top: 0 * lineHeightInPixels) expectTileContainsRow(tilesNodes[1], 4, top: 1 * lineHeightInPixels) expectTileContainsRow(tilesNodes[1], 5, top: 2 * lineHeightInPixels) @@ -157,19 +156,19 @@ describe "TextEditorComponent", -> editor.getBuffer().insert([0, 0], '\n\n') nextAnimationFrame() - tilesNodes = componentNode.querySelectorAll(".tile") + tilesNodes = componentNode.querySelector(".lines").querySelectorAll(".tile") expect(tilesNodes[0].style['-webkit-transform']).toBe "translate3d(0px, 0px, 0px)" expectTileContainsRow(tilesNodes[0], 0, top: 0 * lineHeightInPixels) expectTileContainsRow(tilesNodes[0], 1, top: 1 * lineHeightInPixels) expectTileContainsRow(tilesNodes[0], 2, top: 2 * lineHeightInPixels) - expect(tilesNodes[1].style['-webkit-transform']).toBe "translate3d(0px, #{1 * tileHeight}px, 0px)" + expect(tilesNodes[1].style['-webkit-transform']).toBe "translate3d(0px, #{1 * tileHeightInPixels}px, 0px)" expectTileContainsRow(tilesNodes[1], 3, top: 0 * lineHeightInPixels) expectTileContainsRow(tilesNodes[1], 4, top: 1 * lineHeightInPixels) expectTileContainsRow(tilesNodes[1], 5, top: 2 * lineHeightInPixels) - expect(tilesNodes[2].style['-webkit-transform']).toBe "translate3d(0px, #{2 * tileHeight}px, 0px)" + expect(tilesNodes[2].style['-webkit-transform']).toBe "translate3d(0px, #{2 * tileHeightInPixels}px, 0px)" expectTileContainsRow(tilesNodes[2], 6, top: 0 * lineHeightInPixels) expectTileContainsRow(tilesNodes[2], 7, top: 1 * lineHeightInPixels) expectTileContainsRow(tilesNodes[2], 8, top: 2 * lineHeightInPixels) @@ -543,47 +542,90 @@ describe "TextEditorComponent", -> expect(foldedLineNode.querySelector('.fold-marker')).toBeFalsy() describe "gutter rendering", -> - it "renders the currently-visible line numbers", -> + expectTileContainsRow = (tileNode, screenRow, {top, text}) -> + lineNode = tileNode.querySelector("[data-screen-row='#{screenRow}']") + + expect(lineNode.offsetTop).toBe(top) + expect(lineNode.textContent).toBe(text) + + it "renders the currently-visible line numbers in a tiled fashion", -> wrapperNode.style.height = 4.5 * lineHeightInPixels + 'px' component.measureDimensions() nextAnimationFrame() - expect(componentNode.querySelectorAll('.line-number').length).toBe 6 + 1 # visible line-numbers + dummy line number - expect(component.lineNumberNodeForScreenRow(0).textContent).toBe "#{nbsp}1" - expect(component.lineNumberNodeForScreenRow(5).textContent).toBe "#{nbsp}6" + tilesNodes = componentNode.querySelector(".line-numbers").querySelectorAll(".tile") - verticalScrollbarNode.scrollTop = 2.5 * lineHeightInPixels + expect(tilesNodes.length).toBe(3) + expect(tilesNodes[0].style['-webkit-transform']).toBe "translate3d(0px, 0px, 0px)" + + expect(tilesNodes[0].querySelectorAll('.line-number').length).toBe 3 + expectTileContainsRow(tilesNodes[0], 0, top: lineHeightInPixels * 0, text: "#{nbsp}1") + expectTileContainsRow(tilesNodes[0], 1, top: lineHeightInPixels * 1, text: "#{nbsp}2") + expectTileContainsRow(tilesNodes[0], 2, top: lineHeightInPixels * 2, text: "#{nbsp}3") + + expect(tilesNodes[1].style['-webkit-transform']).toBe "translate3d(0px, #{1 * tileHeightInPixels}px, 0px)" + expect(tilesNodes[1].querySelectorAll('.line-number').length).toBe 3 + expectTileContainsRow(tilesNodes[1], 3, top: lineHeightInPixels * 0, text: "#{nbsp}4") + expectTileContainsRow(tilesNodes[1], 4, top: lineHeightInPixels * 1, text: "#{nbsp}5") + expectTileContainsRow(tilesNodes[1], 5, top: lineHeightInPixels * 2, text: "#{nbsp}6") + + expect(tilesNodes[2].style['-webkit-transform']).toBe "translate3d(0px, #{2 * tileHeightInPixels}px, 0px)" + expect(tilesNodes[2].querySelectorAll('.line-number').length).toBe 3 + expectTileContainsRow(tilesNodes[2], 6, top: lineHeightInPixels * 0, text: "#{nbsp}7") + expectTileContainsRow(tilesNodes[2], 7, top: lineHeightInPixels * 1, text: "#{nbsp}8") + expectTileContainsRow(tilesNodes[2], 8, top: lineHeightInPixels * 2, text: "#{nbsp}9") + + verticalScrollbarNode.scrollTop = tileSize * lineHeightInPixels + 5 verticalScrollbarNode.dispatchEvent(new UIEvent('scroll')) nextAnimationFrame() - expect(componentNode.querySelectorAll('.line-number').length).toBe 6 + 1 # visible line-numbers + dummy line number + tilesNodes = componentNode.querySelector(".line-numbers").querySelectorAll(".tile") - expect(component.lineNumberNodeForScreenRow(2).textContent).toBe "#{nbsp}3" - expect(component.lineNumberNodeForScreenRow(2).offsetTop).toBe 2 * lineHeightInPixels - expect(component.lineNumberNodeForScreenRow(7).textContent).toBe "#{nbsp}8" - expect(component.lineNumberNodeForScreenRow(7).offsetTop).toBe 7 * lineHeightInPixels + expect(component.lineNumberNodeForScreenRow(2)).toBeUndefined() + expect(tilesNodes.length).toBe(3) + + expect(tilesNodes[0].style['-webkit-transform']).toBe "translate3d(0px, #{0 * tileHeightInPixels - 5}px, 0px)" + expect(tilesNodes[0].querySelectorAll(".line-number").length).toBe(tileSize) + expectTileContainsRow(tilesNodes[0], 3, top: lineHeightInPixels * 0, text: "#{nbsp}4") + expectTileContainsRow(tilesNodes[0], 4, top: lineHeightInPixels * 1, text: "#{nbsp}5") + expectTileContainsRow(tilesNodes[0], 5, top: lineHeightInPixels * 2, text: "#{nbsp}6") + + expect(tilesNodes[1].style['-webkit-transform']).toBe "translate3d(0px, #{1 * tileHeightInPixels - 5}px, 0px)" + expect(tilesNodes[1].querySelectorAll(".line-number").length).toBe(tileSize) + expectTileContainsRow(tilesNodes[1], 6, top: 0 * lineHeightInPixels, text: "#{nbsp}7") + expectTileContainsRow(tilesNodes[1], 7, top: 1 * lineHeightInPixels, text: "#{nbsp}8") + expectTileContainsRow(tilesNodes[1], 8, top: 2 * lineHeightInPixels, text: "#{nbsp}9") + + expect(tilesNodes[2].style['-webkit-transform']).toBe "translate3d(0px, #{2 * tileHeightInPixels - 5}px, 0px)" + expect(tilesNodes[2].querySelectorAll(".line-number").length).toBe(tileSize) + expectTileContainsRow(tilesNodes[2], 9, top: 0 * lineHeightInPixels, text: "10") + expectTileContainsRow(tilesNodes[2], 10, top: 1 * lineHeightInPixels, text: "11") + expectTileContainsRow(tilesNodes[2], 11, top: 2 * lineHeightInPixels, text: "12") it "updates the translation of subsequent line numbers when lines are inserted or removed", -> editor.getBuffer().insert([0, 0], '\n\n') nextAnimationFrame() lineNumberNodes = componentNode.querySelectorAll('.line-number') - expect(component.lineNumberNodeForScreenRow(0).offsetTop).toBe 0 + expect(component.lineNumberNodeForScreenRow(0).offsetTop).toBe 0 * lineHeightInPixels expect(component.lineNumberNodeForScreenRow(1).offsetTop).toBe 1 * lineHeightInPixels expect(component.lineNumberNodeForScreenRow(2).offsetTop).toBe 2 * lineHeightInPixels - expect(component.lineNumberNodeForScreenRow(3).offsetTop).toBe 3 * lineHeightInPixels - expect(component.lineNumberNodeForScreenRow(4).offsetTop).toBe 4 * lineHeightInPixels + expect(component.lineNumberNodeForScreenRow(3).offsetTop).toBe 0 * lineHeightInPixels + expect(component.lineNumberNodeForScreenRow(4).offsetTop).toBe 1 * lineHeightInPixels + expect(component.lineNumberNodeForScreenRow(5).offsetTop).toBe 2 * lineHeightInPixels editor.getBuffer().insert([0, 0], '\n\n') nextAnimationFrame() - expect(component.lineNumberNodeForScreenRow(0).offsetTop).toBe 0 + expect(component.lineNumberNodeForScreenRow(0).offsetTop).toBe 0 * lineHeightInPixels expect(component.lineNumberNodeForScreenRow(1).offsetTop).toBe 1 * lineHeightInPixels expect(component.lineNumberNodeForScreenRow(2).offsetTop).toBe 2 * lineHeightInPixels - expect(component.lineNumberNodeForScreenRow(3).offsetTop).toBe 3 * lineHeightInPixels - expect(component.lineNumberNodeForScreenRow(4).offsetTop).toBe 4 * lineHeightInPixels - expect(component.lineNumberNodeForScreenRow(5).offsetTop).toBe 5 * lineHeightInPixels - expect(component.lineNumberNodeForScreenRow(6).offsetTop).toBe 6 * lineHeightInPixels + expect(component.lineNumberNodeForScreenRow(3).offsetTop).toBe 0 * lineHeightInPixels + expect(component.lineNumberNodeForScreenRow(4).offsetTop).toBe 1 * lineHeightInPixels + expect(component.lineNumberNodeForScreenRow(5).offsetTop).toBe 2 * lineHeightInPixels + expect(component.lineNumberNodeForScreenRow(6).offsetTop).toBe 0 * lineHeightInPixels + expect(component.lineNumberNodeForScreenRow(7).offsetTop).toBe 1 * lineHeightInPixels + expect(component.lineNumberNodeForScreenRow(8).offsetTop).toBe 2 * lineHeightInPixels it "renders • characters for soft-wrapped lines", -> editor.setSoftWrapped(true) @@ -592,13 +634,16 @@ describe "TextEditorComponent", -> component.measureDimensions() nextAnimationFrame() - expect(componentNode.querySelectorAll('.line-number').length).toBe 6 + 1 # 1 dummy line + expect(componentNode.querySelectorAll('.line-number').length).toBe 9 + 1 # 3 line-numbers tiles + 1 dummy line expect(component.lineNumberNodeForScreenRow(0).textContent).toBe "#{nbsp}1" expect(component.lineNumberNodeForScreenRow(1).textContent).toBe "#{nbsp}•" expect(component.lineNumberNodeForScreenRow(2).textContent).toBe "#{nbsp}2" expect(component.lineNumberNodeForScreenRow(3).textContent).toBe "#{nbsp}•" expect(component.lineNumberNodeForScreenRow(4).textContent).toBe "#{nbsp}3" expect(component.lineNumberNodeForScreenRow(5).textContent).toBe "#{nbsp}•" + expect(component.lineNumberNodeForScreenRow(6).textContent).toBe "#{nbsp}4" + expect(component.lineNumberNodeForScreenRow(7).textContent).toBe "#{nbsp}•" + expect(component.lineNumberNodeForScreenRow(8).textContent).toBe "#{nbsp}•" it "pads line numbers to be right-justified based on the maximum number of line number digits", -> editor.getBuffer().setText([1..10].join('\n')) @@ -959,7 +1004,7 @@ describe "TextEditorComponent", -> it "renders 2 regions for 2-line selections", -> editor.setSelectedScreenRange([[1, 6], [2, 10]]) nextAnimationFrame() - tileNode = componentNode.querySelectorAll(".tile")[0] + tileNode = componentNode.querySelector(".lines").querySelectorAll(".tile")[0] regions = tileNode.querySelectorAll('.selection .region') expect(regions.length).toBe 2 @@ -980,7 +1025,7 @@ describe "TextEditorComponent", -> nextAnimationFrame() # Tile 0 - tileNode = componentNode.querySelectorAll(".tile")[0] + tileNode = componentNode.querySelector(".lines").querySelectorAll(".tile")[0] regions = tileNode.querySelectorAll('.selection .region') expect(regions.length).toBe(3) @@ -1003,7 +1048,7 @@ describe "TextEditorComponent", -> expect(region3Rect.right).toBe tileNode.getBoundingClientRect().right # Tile 3 - tileNode = componentNode.querySelectorAll(".tile")[1] + tileNode = componentNode.querySelector(".lines").querySelectorAll(".tile")[1] regions = tileNode.querySelectorAll('.selection .region') expect(regions.length).toBe(3) @@ -2015,7 +2060,7 @@ describe "TextEditorComponent", -> component.measureDimensions() nextAnimationFrame() - tilesNodes = componentNode.querySelectorAll(".tile") + tilesNodes = componentNode.querySelector(".lines").querySelectorAll(".tile") top = 0 for tileNode in tilesNodes diff --git a/src/gutter-container-component.coffee b/src/gutter-container-component.coffee index 5fa2f85f4..9e0be4d8d 100644 --- a/src/gutter-container-component.coffee +++ b/src/gutter-container-component.coffee @@ -7,8 +7,7 @@ LineNumberGutterComponent = require './line-number-gutter-component' module.exports = class GutterContainerComponent - - constructor: ({@onLineNumberGutterMouseDown, @editor}) -> + constructor: ({@onLineNumberGutterMouseDown, @editor, @presenter}) -> # An array of objects of the form: {name: {String}, component: {Object}} @gutterComponents = [] @gutterComponentsByGutterName = {} @@ -35,7 +34,7 @@ class GutterContainerComponent gutterComponent = @gutterComponentsByGutterName[gutter.name] if not gutterComponent if gutter.name is 'line-number' - gutterComponent = new LineNumberGutterComponent({onMouseDown: @onLineNumberGutterMouseDown, @editor, gutter}) + gutterComponent = new LineNumberGutterComponent({onMouseDown: @onLineNumberGutterMouseDown, @presenter, @editor, gutter}) @lineNumberGutterComponent = gutterComponent else gutterComponent = new CustomGutterComponent({gutter}) diff --git a/src/line-number-gutter-component.coffee b/src/line-number-gutter-component.coffee index a848e600c..602558fc5 100644 --- a/src/line-number-gutter-component.coffee +++ b/src/line-number-gutter-component.coffee @@ -9,7 +9,7 @@ module.exports = class LineNumberGutterComponent extends TiledComponent dummyLineNumberNode: null - constructor: ({@onMouseDown, @editor, @gutter}) -> + constructor: ({@onMouseDown, @editor, @presenter, @gutter}) -> @lineNumberNodesById = {} @visible = true @@ -74,10 +74,9 @@ class LineNumberGutterComponent extends TiledComponent @dummyLineNumberNode.innerHTML = DummyLineNumberComponent.buildLineNumberInnerHTML(0, false) lineNumberNodeForScreenRow: (screenRow) -> - for id, lineNumberState of @oldState.lineNumbers - if lineNumberState.screenRow is screenRow - return @lineNumberNodesById[id] - null + tile = @presenter.tileForRow(screenRow) + + @componentsByTileId[tile]?.lineNumberNodeForScreenRow(screenRow) onMouseDown: (event) => {target} = event diff --git a/src/line-numbers-tile-component.coffee b/src/line-numbers-tile-component.coffee index a0ae8d49a..a36ed4330 100644 --- a/src/line-numbers-tile-component.coffee +++ b/src/line-numbers-tile-component.coffee @@ -30,12 +30,16 @@ class LineNumbersTileComponent @domNode.style.display = @newTileState.display @oldTileState.display = @newTileState.display + if @newState.backgroundColor isnt @oldState.backgroundColor + @domNode.style.backgroundColor = @newState.backgroundColor + @oldState.backgroundColor = @newState.backgroundColor + if @newTileState.height isnt @oldTileState.height @domNode.style.height = @newTileState.height + 'px' @oldTileState.height = @newTileState.height if @newTileState.top isnt @oldTileState.top - @domNode.style['-webkit-transform'] = "translate3d(#{@newTileState.left}px, #{@newTileState.top}px, 0px)" + @domNode.style['-webkit-transform'] = "translate3d(0, #{@newTileState.top}px, 0px)" @oldTileState.top = @newTileState.top @oldTileState.left = @newTileState.left @@ -127,3 +131,9 @@ class LineNumbersTileComponent className += " " + decorationClasses.join(' ') if decorationClasses? className += " foldable" if foldable and not softWrapped className + + lineNumberNodeForScreenRow: (screenRow) -> + for id, lineNumberState of @oldTileState.lineNumbers + if lineNumberState.screenRow is screenRow + return @lineNumberNodesById[id] + null diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index ac71da748..8802d8022 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -165,7 +165,7 @@ class TextEditorComponent @overlayManager?.measureOverlays() mountGutterContainerComponent: -> - @gutterContainerComponent = new GutterContainerComponent({@editor, @onLineNumberGutterMouseDown}) + @gutterContainerComponent = new GutterContainerComponent({@editor, @onLineNumberGutterMouseDown, @presenter}) @domNode.insertBefore(@gutterContainerComponent.getDomNode(), @domNode.firstChild) becameVisible: -> From 57350b7492c328bc2d94b4b02ef660327bc82ed2 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 12 Jun 2015 15:53:37 +0200 Subject: [PATCH 1686/1783] Finish porting `TextEditorComponent` specs --- spec/text-editor-component-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 808eb527e..a6dbe0385 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -5,7 +5,7 @@ TextEditorView = require '../src/text-editor-view' TextEditorComponent = require '../src/text-editor-component' nbsp = String.fromCharCode(160) -fdescribe "TextEditorComponent", -> +describe "TextEditorComponent", -> [contentNode, editor, wrapperView, wrapperNode, component, componentNode, verticalScrollbarNode, horizontalScrollbarNode] = [] [lineHeightInPixels, charWidth, nextAnimationFrame, noAnimationFrame, tileSize, tileHeightInPixels] = [] From 6bff934b764a88fa14206f1bf05ae56cdc3acfda Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 12 Jun 2015 15:57:31 +0200 Subject: [PATCH 1687/1783] :art: --- src/gutter-component-helpers.coffee | 4 ++++ src/line-number-gutter-component.coffee | 10 +++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/gutter-component-helpers.coffee b/src/gutter-component-helpers.coffee index 499b90552..f3a94c5b4 100644 --- a/src/gutter-component-helpers.coffee +++ b/src/gutter-component-helpers.coffee @@ -19,6 +19,10 @@ module.exports = domNode.style.height = newState.scrollHeight + 'px' oldState.scrollHeight = newState.scrollHeight + if newState.scrollTop isnt oldState.scrollTop + domNode.style['-webkit-transform'] = "translate3d(0px, #{-newState.scrollTop}px, 0px)" + oldState.scrollTop = newState.scrollTop + if newState.backgroundColor isnt oldState.backgroundColor domNode.style.backgroundColor = newState.backgroundColor oldState.backgroundColor = newState.backgroundColor diff --git a/src/line-number-gutter-component.coffee b/src/line-number-gutter-component.coffee index 602558fc5..c33555979 100644 --- a/src/line-number-gutter-component.coffee +++ b/src/line-number-gutter-component.coffee @@ -1,5 +1,3 @@ -{setDimensionsAndBackground} = require './gutter-component-helpers' - TiledComponent = require './tiled-component' LineNumbersTileComponent = require './line-numbers-tile-component' WrapperDiv = document.createElement('div') @@ -46,7 +44,13 @@ class LineNumberGutterComponent extends TiledComponent beforeUpdateSync: (state) -> @appendDummyLineNumber() unless @dummyLineNumberNode? - setDimensionsAndBackground(@oldState.styles, @newState.styles, @lineNumbersNode) + if @newState.styles.scrollHeight isnt @oldState.styles.scrollHeight + @lineNumbersNode.style.height = @newState.styles.scrollHeight + 'px' + @oldState.scrollHeight = @newState.scrollHeight + + if @newState.styles.backgroundColor isnt @oldState.styles.backgroundColor + @lineNumbersNode.style.backgroundColor = @newState.styles.backgroundColor + @oldState.styles.backgroundColor = @newState.styles.backgroundColor if @newState.maxLineNumberDigits isnt @oldState.maxLineNumberDigits @updateDummyLineNumber() From 374aaac7b55676146e562f82060ae9d581ccf662 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 12 Jun 2015 18:32:40 +0200 Subject: [PATCH 1688/1783] Rename to `LinesTileComponent` --- src/lines-component.coffee | 4 ++-- src/{tile-component.coffee => lines-tile-component.coffee} | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename src/{tile-component.coffee => lines-tile-component.coffee} (99%) diff --git a/src/lines-component.coffee b/src/lines-component.coffee index 6902e8aa3..32ea119c9 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -1,7 +1,7 @@ {$$} = require 'space-pen' CursorsComponent = require './cursors-component' -TileComponent = require './tile-component' +LinesTileComponent = require './lines-tile-component' TiledComponent = require './tiled-component' DummyLineNode = $$(-> @div className: 'line', style: 'position: absolute; visibility: hidden;', => @span 'x')[0] @@ -58,7 +58,7 @@ class LinesComponent extends TiledComponent @oldState.width = @newState.width @oldState.backgroundColor = @newState.backgroundColor - buildComponentForTile: (id) -> new TileComponent({id, @presenter}) + buildComponentForTile: (id) -> new LinesTileComponent({id, @presenter}) buildEmptyState: -> {tiles: {}} diff --git a/src/tile-component.coffee b/src/lines-tile-component.coffee similarity index 99% rename from src/tile-component.coffee rename to src/lines-tile-component.coffee index 99dfc6ced..e0e47c3e7 100644 --- a/src/tile-component.coffee +++ b/src/lines-tile-component.coffee @@ -13,7 +13,7 @@ cloneObject = (object) -> clone module.exports = -class TileComponent +class LinesTileComponent constructor: ({@presenter, @id}) -> @tokenIterator = new TokenIterator @measuredLines = new Set From ce3304b788b3e8dd30ff6da6ad0f48b8b2c13db0 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 12 Jun 2015 18:41:19 +0200 Subject: [PATCH 1689/1783] :fire: Delete redundant specs --- spec/text-editor-presenter-spec.coffee | 488 +++++++++++-------------- 1 file changed, 206 insertions(+), 282 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index a659ec4f5..5acbc447a 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -2010,7 +2010,7 @@ describe "TextEditorPresenter", -> editor.setText("1\n2\n3") expect(getLineNumberGutterState(presenter).content.maxLineNumberDigits).toBe 1 - describe ".content.lineNumbers", -> + describe ".content.tiles", -> lineNumberStateForScreenRow = (presenter, screenRow) -> editor = presenter.model tileRow = presenter.tileForRow(screenRow) @@ -2026,295 +2026,219 @@ describe "TextEditorPresenter", -> tiledContentContract (presenter) -> getLineNumberGutterState(presenter).content - it "contains states for line numbers that are visible on screen", -> - editor.foldBufferRow(4) - editor.setSoftWrapped(true) - editor.setEditorWidthInChars(50) - presenter = buildPresenter(explicitHeight: 25, scrollTop: 30, lineHeight: 10, tileSize: 2) - - expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() - expectValues lineNumberStateForScreenRow(presenter, 2), {screenRow: 2, bufferRow: 2, softWrapped: false, top: 0 * 10} - expectValues lineNumberStateForScreenRow(presenter, 3), {screenRow: 3, bufferRow: 3, softWrapped: false, top: 1 * 10} - expectValues lineNumberStateForScreenRow(presenter, 4), {screenRow: 4, bufferRow: 3, softWrapped: true, top: 0 * 10} - expectValues lineNumberStateForScreenRow(presenter, 5), {screenRow: 5, bufferRow: 4, softWrapped: false, top: 1 * 10} - expectValues lineNumberStateForScreenRow(presenter, 6), {screenRow: 6, bufferRow: 7, softWrapped: false, top: 0 * 10} - expectValues lineNumberStateForScreenRow(presenter, 7), {screenRow: 7, bufferRow: 8, softWrapped: false, top: 1 * 10} - expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() - - it "includes states for all line numbers if no ::explicitHeight is assigned", -> - presenter = buildPresenter(explicitHeight: null, tileSize: 2) - expect(lineNumberStateForScreenRow(presenter, 0)).toBeDefined() - expect(lineNumberStateForScreenRow(presenter, 12)).toBeDefined() - - it "updates when ::scrollTop changes", -> - editor.foldBufferRow(4) - editor.setSoftWrapped(true) - editor.setEditorWidthInChars(50) - presenter = buildPresenter(explicitHeight: 25, scrollTop: 30, tileSize: 2) - - expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() - expectValues lineNumberStateForScreenRow(presenter, 2), {bufferRow: 2} - expectValues lineNumberStateForScreenRow(presenter, 7), {bufferRow: 8} - expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() - - expectStateUpdate presenter, -> presenter.setScrollTop(10) - - expectValues lineNumberStateForScreenRow(presenter, 0), {bufferRow: 0} - expectValues lineNumberStateForScreenRow(presenter, 5), {bufferRow: 4} - expect(lineNumberStateForScreenRow(presenter, 6)).toBeUndefined() - - it "updates when ::explicitHeight changes", -> - editor.foldBufferRow(4) - editor.setSoftWrapped(true) - editor.setEditorWidthInChars(50) - presenter = buildPresenter(explicitHeight: 25, scrollTop: 30, tileSize: 2) - - expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() - expectValues lineNumberStateForScreenRow(presenter, 2), {bufferRow: 2} - expectValues lineNumberStateForScreenRow(presenter, 7), {bufferRow: 8} - expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() - - expectStateUpdate presenter, -> presenter.setExplicitHeight(35) - - expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() - expectValues lineNumberStateForScreenRow(presenter, 3), {bufferRow: 3} - expectValues lineNumberStateForScreenRow(presenter, 9), {bufferRow: 9} - expect(lineNumberStateForScreenRow(presenter, 10)).toBeUndefined() - - it "updates when ::lineHeight changes", -> - editor.foldBufferRow(4) - editor.setSoftWrapped(true) - editor.setEditorWidthInChars(50) - presenter = buildPresenter(explicitHeight: 25, scrollTop: 0, tileSize: 2) - - expectValues lineNumberStateForScreenRow(presenter, 0), {bufferRow: 0} - expectValues lineNumberStateForScreenRow(presenter, 5), {bufferRow: 4} - expect(lineNumberStateForScreenRow(presenter, 6)).toBeUndefined() - - expectStateUpdate presenter, -> presenter.setLineHeight(5) - - expectValues lineNumberStateForScreenRow(presenter, 0), {bufferRow: 0} - expectValues lineNumberStateForScreenRow(presenter, 7), {bufferRow: 8} - expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() - - it "updates when the editor's content changes", -> - editor.foldBufferRow(4) - editor.setSoftWrapped(true) - editor.setEditorWidthInChars(50) - presenter = buildPresenter(explicitHeight: 35, scrollTop: 30, tileSize: 2) - - expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() - expectValues lineNumberStateForScreenRow(presenter, 2), {bufferRow: 2} - expectValues lineNumberStateForScreenRow(presenter, 3), {bufferRow: 3} - expectValues lineNumberStateForScreenRow(presenter, 4), {bufferRow: 3} - expectValues lineNumberStateForScreenRow(presenter, 5), {bufferRow: 4} - expectValues lineNumberStateForScreenRow(presenter, 6), {bufferRow: 7} - expectValues lineNumberStateForScreenRow(presenter, 7), {bufferRow: 8} - expectValues lineNumberStateForScreenRow(presenter, 8), {bufferRow: 8} - expectValues lineNumberStateForScreenRow(presenter, 9), {bufferRow: 9} - expect(lineNumberStateForScreenRow(presenter, 10)).toBeUndefined() - - expectStateUpdate presenter, -> - editor.getBuffer().insert([3, Infinity], new Array(25).join("x ")) - - expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() - expectValues lineNumberStateForScreenRow(presenter, 2), {bufferRow: 2} - expectValues lineNumberStateForScreenRow(presenter, 3), {bufferRow: 3} - expectValues lineNumberStateForScreenRow(presenter, 4), {bufferRow: 3} - expectValues lineNumberStateForScreenRow(presenter, 5), {bufferRow: 3} - expectValues lineNumberStateForScreenRow(presenter, 6), {bufferRow: 4} - expectValues lineNumberStateForScreenRow(presenter, 7), {bufferRow: 7} - expectValues lineNumberStateForScreenRow(presenter, 8), {bufferRow: 8} - expectValues lineNumberStateForScreenRow(presenter, 9), {bufferRow: 8} - expect(lineNumberStateForScreenRow(presenter, 10)).toBeUndefined() - - it "does not remove out-of-view tiles corresponding to ::mouseWheelScreenRow until ::stoppedScrollingDelay elapses", -> - presenter = buildPresenter(explicitHeight: 25, stoppedScrollingDelay: 200, tileSize: 2) - - expect(lineNumberStateForScreenRow(presenter, 0)).toBeDefined() - expect(lineNumberStateForScreenRow(presenter, 4)).toBeDefined() - expect(lineNumberStateForScreenRow(presenter, 6)).toBeUndefined() - - presenter.setMouseWheelScreenRow(0) - expectStateUpdate presenter, -> presenter.setScrollTop(45) - - expect(lineNumberStateForScreenRow(presenter, 0)).toBeDefined() - expect(lineNumberStateForScreenRow(presenter, 2)).toBeUndefined() - expect(lineNumberStateForScreenRow(presenter, 6)).toBeDefined() - expect(lineNumberStateForScreenRow(presenter, 10)).toBeUndefined() - - expectStateUpdate presenter, -> advanceClock(200) - - expect(lineNumberStateForScreenRow(presenter, 0)).toBeUndefined() - expect(lineNumberStateForScreenRow(presenter, 6)).toBeDefined() - expect(lineNumberStateForScreenRow(presenter, 10)).toBeUndefined() - - it "correctly handles the first screen line being soft-wrapped", -> - editor.setSoftWrapped(true) - editor.setEditorWidthInChars(30) - presenter = buildPresenter(explicitHeight: 25, scrollTop: 50, tileSize: 2) - - expectValues lineNumberStateForScreenRow(presenter, 5), {screenRow: 5, bufferRow: 3, softWrapped: true} - expectValues lineNumberStateForScreenRow(presenter, 6), {screenRow: 6, bufferRow: 3, softWrapped: true} - expectValues lineNumberStateForScreenRow(presenter, 7), {screenRow: 7, bufferRow: 4, softWrapped: false} - - describe ".decorationClasses", -> - it "adds decoration classes to the relevant line number state objects, both initially and when decorations change", -> - marker1 = editor.markBufferRange([[4, 0], [6, 2]], invalidate: 'touch') - decoration1 = editor.decorateMarker(marker1, type: 'line-number', class: 'a') - presenter = buildPresenter() - marker2 = editor.markBufferRange([[4, 0], [6, 2]], invalidate: 'touch') - decoration2 = editor.decorateMarker(marker2, type: 'line-number', class: 'b') - - expect(lineNumberStateForScreenRow(presenter, 3).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toEqual ['a', 'b'] - expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toEqual ['a', 'b'] - expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['a', 'b'] - expect(lineNumberStateForScreenRow(presenter, 7).decorationClasses).toBeNull() - - expectStateUpdate presenter, -> editor.getBuffer().insert([5, 0], 'x') - expect(marker1.isValid()).toBe false - expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toBeNull() - - expectStateUpdate presenter, -> editor.undo() - expect(lineNumberStateForScreenRow(presenter, 3).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toEqual ['a', 'b'] - expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toEqual ['a', 'b'] - expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['a', 'b'] - expect(lineNumberStateForScreenRow(presenter, 7).decorationClasses).toBeNull() - - expectStateUpdate presenter, -> marker1.setBufferRange([[2, 0], [4, 2]]) - expect(lineNumberStateForScreenRow(presenter, 1).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 2).decorationClasses).toEqual ['a'] - expect(lineNumberStateForScreenRow(presenter, 3).decorationClasses).toEqual ['a'] - expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toEqual ['a', 'b'] - expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toEqual ['b'] - expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['b'] - expect(lineNumberStateForScreenRow(presenter, 7).decorationClasses).toBeNull() - - expectStateUpdate presenter, -> decoration1.destroy() - expect(lineNumberStateForScreenRow(presenter, 2).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 3).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toEqual ['b'] - expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toEqual ['b'] - expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['b'] - expect(lineNumberStateForScreenRow(presenter, 7).decorationClasses).toBeNull() - - expectStateUpdate presenter, -> marker2.destroy() - expect(lineNumberStateForScreenRow(presenter, 2).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 3).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 7).decorationClasses).toBeNull() - - it "honors the 'onlyEmpty' option on line-number decorations", -> - presenter = buildPresenter() - marker = editor.markBufferRange([[4, 0], [6, 1]]) - decoration = editor.decorateMarker(marker, type: 'line-number', class: 'a', onlyEmpty: true) - - expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toBeNull() - - expectStateUpdate presenter, -> marker.clearTail() - - expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['a'] - - it "honors the 'onlyNonEmpty' option on line-number decorations", -> - presenter = buildPresenter() - marker = editor.markBufferRange([[4, 0], [6, 2]]) - decoration = editor.decorateMarker(marker, type: 'line-number', class: 'a', onlyNonEmpty: true) - - expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toEqual ['a'] - expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toEqual ['a'] - expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['a'] - - expectStateUpdate presenter, -> marker.clearTail() - - expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toBeNull() - - it "honors the 'onlyHead' option on line-number decorations", -> - presenter = buildPresenter() - marker = editor.markBufferRange([[4, 0], [6, 2]]) - decoration = editor.decorateMarker(marker, type: 'line-number', class: 'a', onlyHead: true) - - expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toBeNull() - expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['a'] - - it "does not decorate the last line of a non-empty line-number decoration range if it ends at column 0", -> - presenter = buildPresenter() - marker = editor.markBufferRange([[4, 0], [6, 0]]) - decoration = editor.decorateMarker(marker, type: 'line-number', class: 'a') - - expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toEqual ['a'] - expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toEqual ['a'] - expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toBeNull() - - it "does not apply line-number decorations to mini editors", -> - editor.setMini(true) - presenter = buildPresenter() - marker = editor.markBufferRange([[0, 0], [0, 0]]) - decoration = editor.decorateMarker(marker, type: 'line-number', class: 'a') - # A mini editor will have no gutters. - expect(getLineNumberGutterState(presenter)).toBeUndefined() - - expectStateUpdate presenter, -> editor.setMini(false) - expect(lineNumberStateForScreenRow(presenter, 0).decorationClasses).toEqual ['cursor-line', 'cursor-line-no-selection', 'a'] - - expectStateUpdate presenter, -> editor.setMini(true) - expect(getLineNumberGutterState(presenter)).toBeUndefined() - - it "only applies line-number decorations to screen rows that are spanned by their marker when lines are soft-wrapped", -> - editor.setText("a line that wraps, ok") + describe ".lineNumbers[id]", -> + it "contains states for line numbers that are visible on screen", -> + editor.foldBufferRow(4) editor.setSoftWrapped(true) - editor.setEditorWidthInChars(16) - marker = editor.markBufferRange([[0, 0], [0, 2]]) - editor.decorateMarker(marker, type: 'line-number', class: 'a') - presenter = buildPresenter(explicitHeight: 10) + editor.setEditorWidthInChars(50) + presenter = buildPresenter(explicitHeight: 25, scrollTop: 30, lineHeight: 10, tileSize: 2) - expect(lineNumberStateForScreenRow(presenter, 0).decorationClasses).toContain 'a' - expect(lineNumberStateForScreenRow(presenter, 1).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() + expectValues lineNumberStateForScreenRow(presenter, 2), {screenRow: 2, bufferRow: 2, softWrapped: false, top: 0 * 10} + expectValues lineNumberStateForScreenRow(presenter, 3), {screenRow: 3, bufferRow: 3, softWrapped: false, top: 1 * 10} + expectValues lineNumberStateForScreenRow(presenter, 4), {screenRow: 4, bufferRow: 3, softWrapped: true, top: 0 * 10} + expectValues lineNumberStateForScreenRow(presenter, 5), {screenRow: 5, bufferRow: 4, softWrapped: false, top: 1 * 10} + expectValues lineNumberStateForScreenRow(presenter, 6), {screenRow: 6, bufferRow: 7, softWrapped: false, top: 0 * 10} + expectValues lineNumberStateForScreenRow(presenter, 7), {screenRow: 7, bufferRow: 8, softWrapped: false, top: 1 * 10} + expect(lineNumberStateForScreenRow(presenter, 8)).toBeUndefined() - marker.setBufferRange([[0, 0], [0, Infinity]]) - expect(lineNumberStateForScreenRow(presenter, 0).decorationClasses).toContain 'a' - expect(lineNumberStateForScreenRow(presenter, 1).decorationClasses).toContain 'a' + it "updates when the editor's content changes", -> + editor.foldBufferRow(4) + editor.setSoftWrapped(true) + editor.setEditorWidthInChars(50) + presenter = buildPresenter(explicitHeight: 35, scrollTop: 30, tileSize: 2) - describe ".foldable", -> - it "marks line numbers at the start of a foldable region as foldable", -> - presenter = buildPresenter() - expect(lineNumberStateForScreenRow(presenter, 0).foldable).toBe true - expect(lineNumberStateForScreenRow(presenter, 1).foldable).toBe true - expect(lineNumberStateForScreenRow(presenter, 2).foldable).toBe false - expect(lineNumberStateForScreenRow(presenter, 3).foldable).toBe false - expect(lineNumberStateForScreenRow(presenter, 4).foldable).toBe true - expect(lineNumberStateForScreenRow(presenter, 5).foldable).toBe false + expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() + expectValues lineNumberStateForScreenRow(presenter, 2), {bufferRow: 2} + expectValues lineNumberStateForScreenRow(presenter, 3), {bufferRow: 3} + expectValues lineNumberStateForScreenRow(presenter, 4), {bufferRow: 3} + expectValues lineNumberStateForScreenRow(presenter, 5), {bufferRow: 4} + expectValues lineNumberStateForScreenRow(presenter, 6), {bufferRow: 7} + expectValues lineNumberStateForScreenRow(presenter, 7), {bufferRow: 8} + expectValues lineNumberStateForScreenRow(presenter, 8), {bufferRow: 8} + expectValues lineNumberStateForScreenRow(presenter, 9), {bufferRow: 9} + expect(lineNumberStateForScreenRow(presenter, 10)).toBeUndefined() - it "updates the foldable class on the correct line numbers when the foldable positions change", -> - presenter = buildPresenter() - editor.getBuffer().insert([0, 0], '\n') - expect(lineNumberStateForScreenRow(presenter, 0).foldable).toBe false - expect(lineNumberStateForScreenRow(presenter, 1).foldable).toBe true - expect(lineNumberStateForScreenRow(presenter, 2).foldable).toBe true - expect(lineNumberStateForScreenRow(presenter, 3).foldable).toBe false - expect(lineNumberStateForScreenRow(presenter, 4).foldable).toBe false - expect(lineNumberStateForScreenRow(presenter, 5).foldable).toBe true - expect(lineNumberStateForScreenRow(presenter, 6).foldable).toBe false + expectStateUpdate presenter, -> + editor.getBuffer().insert([3, Infinity], new Array(25).join("x ")) - it "updates the foldable class on a line number that becomes foldable", -> - presenter = buildPresenter() - expect(lineNumberStateForScreenRow(presenter, 11).foldable).toBe false + expect(lineNumberStateForScreenRow(presenter, 1)).toBeUndefined() + expectValues lineNumberStateForScreenRow(presenter, 2), {bufferRow: 2} + expectValues lineNumberStateForScreenRow(presenter, 3), {bufferRow: 3} + expectValues lineNumberStateForScreenRow(presenter, 4), {bufferRow: 3} + expectValues lineNumberStateForScreenRow(presenter, 5), {bufferRow: 3} + expectValues lineNumberStateForScreenRow(presenter, 6), {bufferRow: 4} + expectValues lineNumberStateForScreenRow(presenter, 7), {bufferRow: 7} + expectValues lineNumberStateForScreenRow(presenter, 8), {bufferRow: 8} + expectValues lineNumberStateForScreenRow(presenter, 9), {bufferRow: 8} + expect(lineNumberStateForScreenRow(presenter, 10)).toBeUndefined() - editor.getBuffer().insert([11, 44], '\n fold me') - expect(lineNumberStateForScreenRow(presenter, 11).foldable).toBe true + it "correctly handles the first screen line being soft-wrapped", -> + editor.setSoftWrapped(true) + editor.setEditorWidthInChars(30) + presenter = buildPresenter(explicitHeight: 25, scrollTop: 50, tileSize: 2) - editor.undo() - expect(lineNumberStateForScreenRow(presenter, 11).foldable).toBe false + expectValues lineNumberStateForScreenRow(presenter, 5), {screenRow: 5, bufferRow: 3, softWrapped: true} + expectValues lineNumberStateForScreenRow(presenter, 6), {screenRow: 6, bufferRow: 3, softWrapped: true} + expectValues lineNumberStateForScreenRow(presenter, 7), {screenRow: 7, bufferRow: 4, softWrapped: false} + + describe ".decorationClasses", -> + it "adds decoration classes to the relevant line number state objects, both initially and when decorations change", -> + marker1 = editor.markBufferRange([[4, 0], [6, 2]], invalidate: 'touch') + decoration1 = editor.decorateMarker(marker1, type: 'line-number', class: 'a') + presenter = buildPresenter() + marker2 = editor.markBufferRange([[4, 0], [6, 2]], invalidate: 'touch') + decoration2 = editor.decorateMarker(marker2, type: 'line-number', class: 'b') + + expect(lineNumberStateForScreenRow(presenter, 3).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toEqual ['a', 'b'] + expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toEqual ['a', 'b'] + expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['a', 'b'] + expect(lineNumberStateForScreenRow(presenter, 7).decorationClasses).toBeNull() + + expectStateUpdate presenter, -> editor.getBuffer().insert([5, 0], 'x') + expect(marker1.isValid()).toBe false + expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toBeNull() + + expectStateUpdate presenter, -> editor.undo() + expect(lineNumberStateForScreenRow(presenter, 3).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toEqual ['a', 'b'] + expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toEqual ['a', 'b'] + expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['a', 'b'] + expect(lineNumberStateForScreenRow(presenter, 7).decorationClasses).toBeNull() + + expectStateUpdate presenter, -> marker1.setBufferRange([[2, 0], [4, 2]]) + expect(lineNumberStateForScreenRow(presenter, 1).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 2).decorationClasses).toEqual ['a'] + expect(lineNumberStateForScreenRow(presenter, 3).decorationClasses).toEqual ['a'] + expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toEqual ['a', 'b'] + expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toEqual ['b'] + expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['b'] + expect(lineNumberStateForScreenRow(presenter, 7).decorationClasses).toBeNull() + + expectStateUpdate presenter, -> decoration1.destroy() + expect(lineNumberStateForScreenRow(presenter, 2).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 3).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toEqual ['b'] + expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toEqual ['b'] + expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['b'] + expect(lineNumberStateForScreenRow(presenter, 7).decorationClasses).toBeNull() + + expectStateUpdate presenter, -> marker2.destroy() + expect(lineNumberStateForScreenRow(presenter, 2).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 3).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 7).decorationClasses).toBeNull() + + it "honors the 'onlyEmpty' option on line-number decorations", -> + presenter = buildPresenter() + marker = editor.markBufferRange([[4, 0], [6, 1]]) + decoration = editor.decorateMarker(marker, type: 'line-number', class: 'a', onlyEmpty: true) + + expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toBeNull() + + expectStateUpdate presenter, -> marker.clearTail() + + expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['a'] + + it "honors the 'onlyNonEmpty' option on line-number decorations", -> + presenter = buildPresenter() + marker = editor.markBufferRange([[4, 0], [6, 2]]) + decoration = editor.decorateMarker(marker, type: 'line-number', class: 'a', onlyNonEmpty: true) + + expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toEqual ['a'] + expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toEqual ['a'] + expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['a'] + + expectStateUpdate presenter, -> marker.clearTail() + + expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toBeNull() + + it "honors the 'onlyHead' option on line-number decorations", -> + presenter = buildPresenter() + marker = editor.markBufferRange([[4, 0], [6, 2]]) + decoration = editor.decorateMarker(marker, type: 'line-number', class: 'a', onlyHead: true) + + expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toBeNull() + expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['a'] + + it "does not decorate the last line of a non-empty line-number decoration range if it ends at column 0", -> + presenter = buildPresenter() + marker = editor.markBufferRange([[4, 0], [6, 0]]) + decoration = editor.decorateMarker(marker, type: 'line-number', class: 'a') + + expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toEqual ['a'] + expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toEqual ['a'] + expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toBeNull() + + it "does not apply line-number decorations to mini editors", -> + editor.setMini(true) + presenter = buildPresenter() + marker = editor.markBufferRange([[0, 0], [0, 0]]) + decoration = editor.decorateMarker(marker, type: 'line-number', class: 'a') + # A mini editor will have no gutters. + expect(getLineNumberGutterState(presenter)).toBeUndefined() + + expectStateUpdate presenter, -> editor.setMini(false) + expect(lineNumberStateForScreenRow(presenter, 0).decorationClasses).toEqual ['cursor-line', 'cursor-line-no-selection', 'a'] + + expectStateUpdate presenter, -> editor.setMini(true) + expect(getLineNumberGutterState(presenter)).toBeUndefined() + + it "only applies line-number decorations to screen rows that are spanned by their marker when lines are soft-wrapped", -> + editor.setText("a line that wraps, ok") + editor.setSoftWrapped(true) + editor.setEditorWidthInChars(16) + marker = editor.markBufferRange([[0, 0], [0, 2]]) + editor.decorateMarker(marker, type: 'line-number', class: 'a') + presenter = buildPresenter(explicitHeight: 10) + + expect(lineNumberStateForScreenRow(presenter, 0).decorationClasses).toContain 'a' + expect(lineNumberStateForScreenRow(presenter, 1).decorationClasses).toBeNull() + + marker.setBufferRange([[0, 0], [0, Infinity]]) + expect(lineNumberStateForScreenRow(presenter, 0).decorationClasses).toContain 'a' + expect(lineNumberStateForScreenRow(presenter, 1).decorationClasses).toContain 'a' + + describe ".foldable", -> + it "marks line numbers at the start of a foldable region as foldable", -> + presenter = buildPresenter() + expect(lineNumberStateForScreenRow(presenter, 0).foldable).toBe true + expect(lineNumberStateForScreenRow(presenter, 1).foldable).toBe true + expect(lineNumberStateForScreenRow(presenter, 2).foldable).toBe false + expect(lineNumberStateForScreenRow(presenter, 3).foldable).toBe false + expect(lineNumberStateForScreenRow(presenter, 4).foldable).toBe true + expect(lineNumberStateForScreenRow(presenter, 5).foldable).toBe false + + it "updates the foldable class on the correct line numbers when the foldable positions change", -> + presenter = buildPresenter() + editor.getBuffer().insert([0, 0], '\n') + expect(lineNumberStateForScreenRow(presenter, 0).foldable).toBe false + expect(lineNumberStateForScreenRow(presenter, 1).foldable).toBe true + expect(lineNumberStateForScreenRow(presenter, 2).foldable).toBe true + expect(lineNumberStateForScreenRow(presenter, 3).foldable).toBe false + expect(lineNumberStateForScreenRow(presenter, 4).foldable).toBe false + expect(lineNumberStateForScreenRow(presenter, 5).foldable).toBe true + expect(lineNumberStateForScreenRow(presenter, 6).foldable).toBe false + + it "updates the foldable class on a line number that becomes foldable", -> + presenter = buildPresenter() + expect(lineNumberStateForScreenRow(presenter, 11).foldable).toBe false + + editor.getBuffer().insert([11, 44], '\n fold me') + expect(lineNumberStateForScreenRow(presenter, 11).foldable).toBe true + + editor.undo() + expect(lineNumberStateForScreenRow(presenter, 11).foldable).toBe false describe "for a gutter description that corresponds to a custom gutter", -> describe ".content", -> From b6049857edaa867545f2931cfeb05076ddf8f782 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 12 Jun 2015 19:00:15 +0200 Subject: [PATCH 1690/1783] :art: --- src/lines-component.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lines-component.coffee b/src/lines-component.coffee index 32ea119c9..644278550 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -35,6 +35,7 @@ class LinesComponent extends TiledComponent if @newState.backgroundColor isnt @oldState.backgroundColor @domNode.style.backgroundColor = @newState.backgroundColor + @oldState.backgroundColor = @newState.backgroundColor afterUpdateSync: (state) -> if @newState.placeholderText isnt @oldState.placeholderText @@ -56,7 +57,6 @@ class LinesComponent extends TiledComponent @oldState.indentGuidesVisible = @newState.indentGuidesVisible @oldState.scrollWidth = @newState.scrollWidth @oldState.width = @newState.width - @oldState.backgroundColor = @newState.backgroundColor buildComponentForTile: (id) -> new LinesTileComponent({id, @presenter}) From 8521b81051253434ecee7080dded0dccf81c8bc9 Mon Sep 17 00:00:00 2001 From: Luke Pommersheim Date: Fri, 12 Jun 2015 19:21:37 +0200 Subject: [PATCH 1691/1783] spec - getCursorAtScreenPosition checks cursors instead of cursor.marker --- spec/text-editor-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index f8e0aa56b..53eb32acb 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -920,7 +920,7 @@ describe "TextEditor", -> it "returns the cursor at the given screenPosition", -> cursor1 = editor.addCursorAtScreenPosition([0, 2]) cursor2 = editor.getCursorAtScreenPosition(cursor1.getScreenPosition()) - expect(cursor2.marker).toBe cursor1.marker + expect(cursor2).toBe cursor1 describe "::getCursorScreenPositions()", -> it "returns the cursor positions in the order they were added", -> From 715238c3cd8bf55e3baa529fdafbe57672cf12ad Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 12 Jun 2015 16:38:07 -0700 Subject: [PATCH 1692/1783] Add by clauses to for loops to avoid complex loop increments --- src/language-mode.coffee | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/language-mode.coffee b/src/language-mode.coffee index c9401550b..bf1e0e101 100644 --- a/src/language-mode.coffee +++ b/src/language-mode.coffee @@ -56,7 +56,7 @@ class LanguageMode allBlank = true allBlankOrCommented = true - for row in [start..end] + for row in [start..end] by 1 line = buffer.lineForRow(row) blank = line?.match(/^\s*$/) @@ -66,7 +66,7 @@ class LanguageMode shouldUncomment = allBlankOrCommented and not allBlank if shouldUncomment - for row in [start..end] + for row in [start..end] by 1 if match = commentStartRegex.searchSync(buffer.lineForRow(row)) columnStart = match[1].length columnEnd = columnStart + match[2].length @@ -79,7 +79,7 @@ class LanguageMode indentString = @editor.buildIndentString(indent) tabLength = @editor.getTabLength() indentRegex = new RegExp("(\t|[ ]{#{tabLength}}){#{Math.floor(indent)}}") - for row in [start..end] + for row in [start..end] by 1 line = buffer.lineForRow(row) if indentLength = line.match(indentRegex)?[0].length buffer.insert([row, indentLength], commentStartString) @@ -89,7 +89,7 @@ class LanguageMode # Folds all the foldable lines in the buffer. foldAll: -> - for currentRow in [0..@buffer.getLastRow()] + for currentRow in [0..@buffer.getLastRow()] by 1 [startRow, endRow] = @rowRangeForFoldAtBufferRow(currentRow) ? [] continue unless startRow? @editor.createFold(startRow, endRow) @@ -97,7 +97,7 @@ class LanguageMode # Unfolds all the foldable lines in the buffer. unfoldAll: -> - for row in [@buffer.getLastRow()..0] + for row in [@buffer.getLastRow()..0] by -1 fold.destroy() for fold in @editor.displayBuffer.foldsStartingAtBufferRow(row) return @@ -106,7 +106,7 @@ class LanguageMode # indentLevel - A {Number} indicating indentLevel; 0 based. foldAllAtIndentLevel: (indentLevel) -> @unfoldAll() - for currentRow in [0..@buffer.getLastRow()] + for currentRow in [0..@buffer.getLastRow()] by 1 [startRow, endRow] = @rowRangeForFoldAtBufferRow(currentRow) ? [] continue unless startRow? @@ -121,7 +121,7 @@ class LanguageMode # # Returns the new {Fold}. foldBufferRow: (bufferRow) -> - for currentRow in [bufferRow..0] + for currentRow in [bufferRow..0] by -1 [startRow, endRow] = @rowRangeForFoldAtBufferRow(currentRow) ? [] continue unless startRow? and startRow <= bufferRow <= endRow fold = @editor.displayBuffer.largestFoldStartingAtBufferRow(startRow) @@ -145,13 +145,13 @@ class LanguageMode endRow = bufferRow if bufferRow > 0 - for currentRow in [bufferRow-1..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()] + for currentRow in [bufferRow+1..@buffer.getLastRow()] by 1 break if @buffer.isRowBlank(currentRow) break unless @editor.displayBuffer.tokenizedBuffer.tokenizedLineForRow(currentRow).isComment() endRow = currentRow @@ -163,7 +163,7 @@ class LanguageMode startIndentLevel = @editor.indentationForBufferRow(bufferRow) scopeDescriptor = @editor.scopeDescriptorForBufferPosition([bufferRow, 0]) - for row in [(bufferRow + 1)..@editor.getLastBufferRow()] + for row in [(bufferRow + 1)..@editor.getLastBufferRow()] by 1 continue if @editor.isBufferRowBlank(row) indentation = @editor.indentationForBufferRow(row) if indentation <= startIndentLevel @@ -272,7 +272,7 @@ class LanguageMode # # Returns a {Number} of the indent level of the block of lines. minIndentLevelForRowRange: (startRow, endRow) -> - indents = (@editor.indentationForBufferRow(row) for row in [startRow..endRow] when not @editor.isBufferRowBlank(row)) + indents = (@editor.indentationForBufferRow(row) for row in [startRow..endRow] by 1 when not @editor.isBufferRowBlank(row)) indents = [0] unless indents.length Math.min(indents...) @@ -281,7 +281,7 @@ class LanguageMode # startRow - The row {Number} to start at # endRow - The row {Number} to end at autoIndentBufferRows: (startRow, endRow) -> - @autoIndentBufferRow(row) for row in [startRow..endRow] + @autoIndentBufferRow(row) for row in [startRow..endRow] by 1 return # Given a buffer row, this indents it. From e893b5105b5510b2cc03409dd9e3f629705acae4 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Sat, 13 Jun 2015 14:18:36 +0200 Subject: [PATCH 1693/1783] Remove `presenter` as a dependency where possible Although we have a couple of components which still access it, we agreed it would have been just better to avoid relying on `TextEditorPresenter` where possible and use it purposefully in other places (e.g. `LinesComponent` which needs it to store text measurements). /cc: @jssln --- src/gutter-container-component.coffee | 4 ++-- src/line-number-gutter-component.coffee | 7 +----- src/lines-component.coffee | 7 +----- src/lines-tile-component.coffee | 2 +- src/text-editor-component.coffee | 15 ++++++++++--- src/tiled-component.coffee | 29 ++++++++++++++----------- 6 files changed, 33 insertions(+), 31 deletions(-) diff --git a/src/gutter-container-component.coffee b/src/gutter-container-component.coffee index 9e0be4d8d..2dd5f21fb 100644 --- a/src/gutter-container-component.coffee +++ b/src/gutter-container-component.coffee @@ -7,7 +7,7 @@ LineNumberGutterComponent = require './line-number-gutter-component' module.exports = class GutterContainerComponent - constructor: ({@onLineNumberGutterMouseDown, @editor, @presenter}) -> + constructor: ({@onLineNumberGutterMouseDown, @editor}) -> # An array of objects of the form: {name: {String}, component: {Object}} @gutterComponents = [] @gutterComponentsByGutterName = {} @@ -34,7 +34,7 @@ class GutterContainerComponent gutterComponent = @gutterComponentsByGutterName[gutter.name] if not gutterComponent if gutter.name is 'line-number' - gutterComponent = new LineNumberGutterComponent({onMouseDown: @onLineNumberGutterMouseDown, @presenter, @editor, gutter}) + gutterComponent = new LineNumberGutterComponent({onMouseDown: @onLineNumberGutterMouseDown, @editor, gutter}) @lineNumberGutterComponent = gutterComponent else gutterComponent = new CustomGutterComponent({gutter}) diff --git a/src/line-number-gutter-component.coffee b/src/line-number-gutter-component.coffee index c33555979..5b399570a 100644 --- a/src/line-number-gutter-component.coffee +++ b/src/line-number-gutter-component.coffee @@ -7,7 +7,7 @@ module.exports = class LineNumberGutterComponent extends TiledComponent dummyLineNumberNode: null - constructor: ({@onMouseDown, @editor, @presenter, @gutter}) -> + constructor: ({@onMouseDown, @editor, @gutter}) -> @lineNumberNodesById = {} @visible = true @@ -77,11 +77,6 @@ class LineNumberGutterComponent extends TiledComponent DummyLineNumberComponent.newState = @newState @dummyLineNumberNode.innerHTML = DummyLineNumberComponent.buildLineNumberInnerHTML(0, false) - lineNumberNodeForScreenRow: (screenRow) -> - tile = @presenter.tileForRow(screenRow) - - @componentsByTileId[tile]?.lineNumberNodeForScreenRow(screenRow) - onMouseDown: (event) => {target} = event lineNumber = target.parentNode diff --git a/src/lines-component.coffee b/src/lines-component.coffee index 644278550..bef14aec3 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -14,7 +14,7 @@ class LinesComponent extends TiledComponent @domNode = document.createElement('div') @domNode.classList.add('lines') - @cursorsComponent = new CursorsComponent(@presenter) + @cursorsComponent = new CursorsComponent @domNode.appendChild(@cursorsComponent.getDomNode()) if @useShadowDOM @@ -95,8 +95,3 @@ class LinesComponent extends TiledComponent component.clearMeasurements() @presenter.clearScopedCharacterWidths() - - lineNodeForScreenRow: (screenRow) -> - tile = @presenter.tileForRow(screenRow) - - @componentsByTileId[tile]?.lineNodeForScreenRow(screenRow) diff --git a/src/lines-tile-component.coffee b/src/lines-tile-component.coffee index e0e47c3e7..d39df0a9e 100644 --- a/src/lines-tile-component.coffee +++ b/src/lines-tile-component.coffee @@ -25,7 +25,7 @@ class LinesTileComponent @domNode.style.position = "absolute" @domNode.style.display = "block" - @highlightsComponent = new HighlightsComponent(@presenter) + @highlightsComponent = new HighlightsComponent @domNode.appendChild(@highlightsComponent.getDomNode()) getDomNode: -> diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 8802d8022..647faded6 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -165,7 +165,7 @@ class TextEditorComponent @overlayManager?.measureOverlays() mountGutterContainerComponent: -> - @gutterContainerComponent = new GutterContainerComponent({@editor, @onLineNumberGutterMouseDown, @presenter}) + @gutterContainerComponent = new GutterContainerComponent({@editor, @onLineNumberGutterMouseDown}) @domNode.insertBefore(@gutterContainerComponent.getDomNode(), @domNode.firstChild) becameVisible: -> @@ -724,9 +724,18 @@ class TextEditorComponent consolidateSelections: (e) -> e.abortKeyBinding() unless @editor.consolidateSelections() - lineNodeForScreenRow: (screenRow) -> @linesComponent.lineNodeForScreenRow(screenRow) + lineNodeForScreenRow: (screenRow) -> + tileRow = @presenter.tileForRow(screenRow) + tileComponent = @linesComponent.getComponentForTile(tileRow) - lineNumberNodeForScreenRow: (screenRow) -> @gutterContainerComponent.getLineNumberGutterComponent().lineNumberNodeForScreenRow(screenRow) + tileComponent?.lineNodeForScreenRow(screenRow) + + lineNumberNodeForScreenRow: (screenRow) -> + tileRow = @presenter.tileForRow(screenRow) + gutterComponent = @gutterContainerComponent.getLineNumberGutterComponent() + tileComponent = gutterComponent.getComponentForTile(tileRow) + + tileComponent?.lineNumberNodeForScreenRow(screenRow) screenRowForNode: (node) -> while node? diff --git a/src/tiled-component.coffee b/src/tiled-component.coffee index 51af7b57d..33719dda5 100644 --- a/src/tiled-component.coffee +++ b/src/tiled-component.coffee @@ -17,32 +17,35 @@ class TiledComponent @afterUpdateSync?(state) removeTileNodes: -> - @removeTileNode(id) for id of @oldState.tiles + @removeTileNode(tileRow) for tileRow of @oldState.tiles return - removeTileNode: (id) -> - node = @componentsByTileId[id].getDomNode() + removeTileNode: (tileRow) -> + node = @componentsByTileId[tileRow].getDomNode() node.remove() - delete @componentsByTileId[id] - delete @oldState.tiles[id] + delete @componentsByTileId[tileRow] + delete @oldState.tiles[tileRow] updateTileNodes: -> @componentsByTileId ?= {} - for id of @oldState.tiles - unless @newState.tiles.hasOwnProperty(id) - @removeTileNode(id) + for tileRow of @oldState.tiles + unless @newState.tiles.hasOwnProperty(tileRow) + @removeTileNode(tileRow) - for id, tileState of @newState.tiles - if @oldState.tiles.hasOwnProperty(id) - component = @componentsByTileId[id] + for tileRow, tileState of @newState.tiles + if @oldState.tiles.hasOwnProperty(tileRow) + component = @componentsByTileId[tileRow] else - component = @componentsByTileId[id] = @buildComponentForTile(id) + component = @componentsByTileId[tileRow] = @buildComponentForTile(tileRow) @getTilesNode().appendChild(component.getDomNode()) - @oldState.tiles[id] = cloneObject(tileState) + @oldState.tiles[tileRow] = cloneObject(tileState) component.updateSync(@newState) return + + getComponentForTile: (tileRow) -> + @componentsByTileId[tileRow] From e190d441ed3e07c335c9d0fcfdf3cc5fc595cade Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Sat, 13 Jun 2015 14:25:50 +0200 Subject: [PATCH 1694/1783] :fire: --- src/line-numbers-tile-component.coffee | 5 ----- src/lines-tile-component.coffee | 1 + src/text-editor-presenter.coffee | 1 - 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/line-numbers-tile-component.coffee b/src/line-numbers-tile-component.coffee index a36ed4330..9a5dc4055 100644 --- a/src/line-numbers-tile-component.coffee +++ b/src/line-numbers-tile-component.coffee @@ -41,7 +41,6 @@ class LineNumbersTileComponent if @newTileState.top isnt @oldTileState.top @domNode.style['-webkit-transform'] = "translate3d(0, #{@newTileState.top}px, 0px)" @oldTileState.top = @newTileState.top - @oldTileState.left = @newTileState.left if @newState.maxLineNumberDigits isnt @oldState.maxLineNumberDigits node.remove() for id, node of @lineNumberNodesById @@ -50,10 +49,6 @@ class LineNumbersTileComponent @lineNumberNodesById = {} @oldState.maxLineNumberDigits = @newState.maxLineNumberDigits - if @newState.scrollWidth isnt @oldState.scrollWidth - @domNode.style.width = @newState.scrollWidth + 'px' - @oldState.scrollWidth = @newState.scrollWidth - @updateLineNumbers() updateLineNumbers: -> diff --git a/src/lines-tile-component.coffee b/src/lines-tile-component.coffee index d39df0a9e..5fdadf212 100644 --- a/src/lines-tile-component.coffee +++ b/src/lines-tile-component.coffee @@ -54,6 +54,7 @@ class LinesTileComponent if @newState.width isnt @oldState.width @domNode.style.width = @newState.width + 'px' + @oldTileState.width = @newTileState.width if @newTileState.top isnt @oldTileState.top or @newTileState.left isnt @oldTileState.left @domNode.style['-webkit-transform'] = "translate3d(#{@newTileState.left}px, #{@newTileState.top}px, 0px)" diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 6a4612ffa..933ddd4aa 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -342,7 +342,6 @@ class TextEditorPresenter gutterTile = @lineNumberGutter.tiles[startRow] ?= {} gutterTile.top = startRow * @lineHeight - @scrollTop - gutterTile.left = -@scrollLeft gutterTile.height = @tileSize * @lineHeight gutterTile.display = "block" From a7ff49ebaa71f0c29119dd5a6113e8a3baa28648 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Sat, 13 Jun 2015 17:36:20 +0200 Subject: [PATCH 1695/1783] :art: --- src/line-number-gutter-component.coffee | 5 +---- src/line-numbers-tile-component.coffee | 2 +- src/lines-component.coffee | 6 +----- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/line-number-gutter-component.coffee b/src/line-number-gutter-component.coffee index 5b399570a..b31131ab0 100644 --- a/src/line-number-gutter-component.coffee +++ b/src/line-number-gutter-component.coffee @@ -8,7 +8,6 @@ class LineNumberGutterComponent extends TiledComponent dummyLineNumberNode: null constructor: ({@onMouseDown, @editor, @gutter}) -> - @lineNumberNodesById = {} @visible = true @domNode = atom.views.getView(@gutter) @@ -55,9 +54,7 @@ class LineNumberGutterComponent extends TiledComponent if @newState.maxLineNumberDigits isnt @oldState.maxLineNumberDigits @updateDummyLineNumber() @oldState.styles = {} - - afterUpdateSync: (state) -> - @oldState.maxLineNumberDigits = @newState.maxLineNumberDigits + @oldState.maxLineNumberDigits = @newState.maxLineNumberDigits buildComponentForTile: (id) -> new LineNumbersTileComponent({id}) diff --git a/src/line-numbers-tile-component.coffee b/src/line-numbers-tile-component.coffee index 9a5dc4055..155c9a23a 100644 --- a/src/line-numbers-tile-component.coffee +++ b/src/line-numbers-tile-component.coffee @@ -12,7 +12,7 @@ class LineNumbersTileComponent @domNode.classList.add("tile") @domNode.style.position = "absolute" @domNode.style.display = "block" - @domNode.style.top = 0 + @domNode.style.top = 0 # Cover the space occupied by a dummy lineNumber getDomNode: -> @domNode diff --git a/src/lines-component.coffee b/src/lines-component.coffee index bef14aec3..70a428b57 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -46,17 +46,13 @@ class LinesComponent extends TiledComponent @placeholderTextDiv.textContent = @newState.placeholderText @domNode.appendChild(@placeholderTextDiv) - @removeTileNodes() unless @oldState.indentGuidesVisible is @newState.indentGuidesVisible - @updateTileNodes() - if @newState.width isnt @oldState.width @domNode.style.width = @newState.width + 'px' + @oldState.width = @newState.width @cursorsComponent.updateSync(state) @oldState.indentGuidesVisible = @newState.indentGuidesVisible - @oldState.scrollWidth = @newState.scrollWidth - @oldState.width = @newState.width buildComponentForTile: (id) -> new LinesTileComponent({id, @presenter}) From e4ba689e40451f1f4b99979f0ddeee5f42fa94de Mon Sep 17 00:00:00 2001 From: simurai Date: Mon, 15 Jun 2015 16:03:50 +0900 Subject: [PATCH 1696/1783] Replaces default editor font Only affects OS X --- src/config-schema.coffee | 4 ++-- static/text-editor-light.less | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/config-schema.coffee b/src/config-schema.coffee index fd35d2b07..71ab26386 100644 --- a/src/config-schema.coffee +++ b/src/config-schema.coffee @@ -103,12 +103,12 @@ module.exports = default: '' fontSize: type: 'integer' - default: 16 + default: 14 minimum: 1 maximum: 100 lineHeight: type: ['string', 'number'] - default: 1.3 + default: 1.4 showInvisibles: type: 'boolean' default: false diff --git a/static/text-editor-light.less b/static/text-editor-light.less index a8b99f0bc..819fc565f 100644 --- a/static/text-editor-light.less +++ b/static/text-editor-light.less @@ -4,8 +4,7 @@ atom-text-editor { display: block; - font-family: Inconsolata, Monaco, Consolas, 'DejaVu Sans Mono', monospace; - line-height: 1.3; + font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; } atom-text-editor[mini] { From d075a64e62591b36fc091c7cfb4c95e023d1cffe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Machist=C3=A9=20N=2E=20Quintana?= Date: Mon, 15 Jun 2015 07:41:25 -0400 Subject: [PATCH 1697/1783] :arrow_up: autosave@0.21.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fef17f3a3..15c63ea52 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,7 @@ "autocomplete-plus": "2.17.3", "autocomplete-snippets": "1.7.0", "autoflow": "0.25.0", - "autosave": "0.20.0", + "autosave": "0.21.0", "background-tips": "0.25.0", "bookmarks": "0.35.0", "bracket-matcher": "0.76.0", From 9affa8d6dd94466d0af2c71a2fa5dd87aa9060c3 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 15 Jun 2015 07:47:13 -0700 Subject: [PATCH 1698/1783] :arrow_up: symbols-view@0.99 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 15c63ea52..fde15ad08 100644 --- a/package.json +++ b/package.json @@ -119,7 +119,7 @@ "spell-check": "0.59.0", "status-bar": "0.74.0", "styleguide": "0.44.0", - "symbols-view": "0.98.0", + "symbols-view": "0.99.0", "tabs": "0.81.0", "timecop": "0.31.0", "tree-view": "0.172.0", From fcf45ea0ce05d5d63a6761864b6d3b194dfa354a Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 15 Jun 2015 11:13:39 -0700 Subject: [PATCH 1699/1783] :arrow_up: find-and-replace --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fde15ad08..ac4cdd6c8 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", "exception-reporting": "0.24.0", - "find-and-replace": "0.172.0", + "find-and-replace": "0.173.0", "fuzzy-finder": "0.87.0", "git-diff": "0.55.0", "go-to-line": "0.30.0", From 749e894070123d5ea4cc549d7f3819cf5e858152 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 15 Jun 2015 13:46:14 -0700 Subject: [PATCH 1700/1783] :arrow_up: text-buffer --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ac4cdd6c8..97ca936bd 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "space-pen": "3.8.2", "stacktrace-parser": "0.1.1", "temp": "0.8.1", - "text-buffer": "6.3.6", + "text-buffer": "6.3.7", "theorist": "^1.0.2", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", From 41773b086114932f39c9f6fa1e1d8f2e3b7c83e6 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 15 Jun 2015 14:14:08 -0700 Subject: [PATCH 1701/1783] Fix incorrect state save when exiting --- src/browser/atom-application.coffee | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index a59a6c8d2..d451c2457 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -105,7 +105,7 @@ class AtomApplication app.quit() return @windows.splice(@windows.indexOf(window), 1) - @saveState() unless window.isSpec + @saveState(true) unless window.isSpec # Public: Adds the {AtomWindow} to the global window list. addWindow: (window) -> @@ -116,14 +116,14 @@ class AtomApplication unless window.isSpec focusHandler = => @lastFocusedWindow = window - blurHandler = => @saveState() + blurHandler = => @saveState(false) window.browserWindow.on 'focus', focusHandler window.browserWindow.on 'blur', blurHandler window.browserWindow.once 'closed', => @lastFocusedWindow = null if window is @lastFocusedWindow window.browserWindow.removeListener 'focus', focusHandler window.browserWindow.removeListener 'blur', blurHandler - window.browserWindow.webContents.once 'did-finish-load', => @saveState() + window.browserWindow.webContents.once 'did-finish-load', => @saveState(false) # Creates server to listen for additional atom application launches. # @@ -213,7 +213,7 @@ class AtomApplication @openPathOnEvent('application:open-license', path.join(process.resourcesPath, 'LICENSE.md')) app.on 'before-quit', => - @saveState() if @hasEditorWindows() + @saveState(false) @quitting = true app.on 'will-quit', => @@ -221,7 +221,7 @@ class AtomApplication @deleteSocketFile() app.on 'will-exit', => - @saveState() if @hasEditorWindows() + @saveState(false) @killAllProcesses() @deleteSocketFile() @@ -439,14 +439,15 @@ class AtomApplication console.log("Killing process #{pid} failed: #{error.code ? error.message}") delete @pidsToOpenWindows[pid] - saveState: -> + saveState: (allowEmpty=false) -> return if @quitting states = [] for window in @windows unless window.isSpec if loadSettings = window.getLoadSettings() states.push(initialPaths: loadSettings.initialPaths) - @storageFolder.store('application.json', states) + if states.length > 0 or allowEmpty + @storageFolder.store('application.json', states) hasEditorWindows: -> @windows.some (window) -> not window.isSpec From 449c03cb35886279f03b6ef113a076f78df8caf9 Mon Sep 17 00:00:00 2001 From: aki Date: Tue, 16 Jun 2015 18:05:45 +0900 Subject: [PATCH 1702/1783] Fix destroy listeners --- spec/display-buffer-spec.coffee | 5 +++++ src/display-buffer.coffee | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index 140ca2f9e..7d82ebcf5 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -1229,6 +1229,11 @@ describe "DisplayBuffer", -> decoration.destroy() expect(displayBuffer.decorationForId(decoration.id)).not.toBeDefined() + it "does not leak disposables", -> + disposablesSize = displayBuffer.disposables.disposables.size + decoration.destroy() + expect(displayBuffer.disposables.disposables.size).toBe(disposablesSize - 1) + describe "when a decoration is updated via Decoration::update()", -> it "emits an 'updated' event containing the new and old params", -> decoration.onDidChangeProperties updatedSpy = jasmine.createSpy() diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index 2519fa6d6..179795db5 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -974,7 +974,10 @@ class DisplayBuffer extends Model decorateMarker: (marker, decorationParams) -> marker = @getMarker(marker.id) decoration = new Decoration(marker, this, decorationParams) - @disposables.add decoration.onDidDestroy => @removeDecoration(decoration) + decorationDestroyedDisposable = decoration.onDidDestroy => + @removeDecoration(decoration) + @disposables.remove(decorationDestroyedDisposable) + @disposables.add(decorationDestroyedDisposable) @decorationsByMarkerId[marker.id] ?= [] @decorationsByMarkerId[marker.id].push(decoration) @overlayDecorationsById[decoration.id] = decoration if decoration.isType('overlay') From 1bbeca6801e2e08b85b5bed87fda4fb7e4c42791 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 16 Jun 2015 14:29:29 -0700 Subject: [PATCH 1703/1783] :arrow_up: snippets --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 97ca936bd..3d5affb9b 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,7 @@ "package-generator": "0.39.0", "release-notes": "0.53.0", "settings-view": "0.208.0", - "snippets": "0.94.0", + "snippets": "0.95.0", "spell-check": "0.59.0", "status-bar": "0.74.0", "styleguide": "0.44.0", From dbb1200e1b6cec2ee0643125070d9d8ef5dd2aca Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 16 Jun 2015 14:54:01 -0700 Subject: [PATCH 1704/1783] :fire: unused method --- src/browser/atom-application.coffee | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index d451c2457..b35bd5b5b 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -449,9 +449,6 @@ class AtomApplication if states.length > 0 or allowEmpty @storageFolder.store('application.json', states) - hasEditorWindows: -> - @windows.some (window) -> not window.isSpec - loadState: -> if (states = @storageFolder.load('application.json'))?.length > 0 for state in states From fe4654c9ea377c39636caa18af97d4fd39ecca7d Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Tue, 16 Jun 2015 20:18:16 -0400 Subject: [PATCH 1705/1783] :bug: Fix pane resize cursors on Windows --- static/panes.less | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/static/panes.less b/static/panes.less index 1d6d268d8..e7ca02880 100644 --- a/static/panes.less +++ b/static/panes.less @@ -71,3 +71,20 @@ atom-pane-container { } } } + +// Windows doesn't have row- and col-resize cursors +.platform-win32 { + atom-pane-container { + atom-pane-axis.vertical { + & > atom-pane-resize-handle { + cursor: ns-resize; + } + } + + atom-pane-axis.vertical { + & > atom-pane-resize-handle { + cursor: ew-resize; + } + } + } +} From 1bd94c670fef30d80ad6076d37f354fd053049c4 Mon Sep 17 00:00:00 2001 From: Machiste Quintana Date: Tue, 16 Jun 2015 20:23:41 -0400 Subject: [PATCH 1706/1783] Fix copypasta selector --- static/panes.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/panes.less b/static/panes.less index e7ca02880..a1a649e54 100644 --- a/static/panes.less +++ b/static/panes.less @@ -81,7 +81,7 @@ atom-pane-container { } } - atom-pane-axis.vertical { + atom-pane-axis.horizontal { & > atom-pane-resize-handle { cursor: ew-resize; } From b0d93accf7871c09b9d14bedb887bb25ef47d142 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 17 Jun 2015 12:24:35 +0200 Subject: [PATCH 1707/1783] :bug: Remove Gutter from ViewRegistry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #7306 We started noticing that when a `TextEditor` pane got split, the same view for `Gutter` was being shared amongst several models, thereby making the same DOM element accessible simultaneously by more than one object. This made us experience *orphaned line numbers*, caused by two instances of `LineNumberGutterComponent` mutating `.line-numbers` at the same time. This is a typical race condition which I would normally address by understanding and possibly locking the correct order in which operations should happen. However, I believe in this situation we shouldn’t actually care about ordering at all, since I think views should be kept “local”, thus avoiding to expose them to the world and/or reusing them across other views (either accidentally as in this case or on purpose). --- spec/custom-gutter-component-spec.coffee | 3 -- spec/gutter-container-component-spec.coffee | 38 ++++++++++++--------- src/custom-gutter-component.coffee | 6 ++-- src/line-number-gutter-component.coffee | 5 ++- src/pane-container.coffee | 3 -- 5 files changed, 25 insertions(+), 30 deletions(-) diff --git a/spec/custom-gutter-component-spec.coffee b/spec/custom-gutter-component-spec.coffee index 4b7d81fba..37da68807 100644 --- a/spec/custom-gutter-component-spec.coffee +++ b/spec/custom-gutter-component-spec.coffee @@ -16,9 +16,6 @@ describe "CustomGutterComponent", -> decorationsWrapperNode = gutterComponent.getDomNode().children.item(0) expect(decorationsWrapperNode.classList.contains('custom-decorations')).toBe true - it "makes its view accessible from the view registry", -> - expect(gutterComponent.getDomNode()).toBe atom.views.getView(gutter) - it "hides its DOM node when ::hideNode is called, and shows its DOM node when ::showNode is called", -> gutterComponent.hideNode() expect(gutterComponent.getDomNode().style.display).toBe 'none' diff --git a/spec/gutter-container-component-spec.coffee b/spec/gutter-container-component-spec.coffee index 5d815fea8..6048655f1 100644 --- a/spec/gutter-container-component-spec.coffee +++ b/spec/gutter-container-component-spec.coffee @@ -107,22 +107,24 @@ describe "GutterContainerComponent", -> gutterContainerComponent.updateSync(testState) expect(gutterContainerComponent.getDomNode().children.length).toBe 2 - expectedCustomGutterNode = gutterContainerComponent.getDomNode().children.item(0) - expect(expectedCustomGutterNode).toBe atom.views.getView(customGutter1) - expectedLineNumbersNode = gutterContainerComponent.getDomNode().children.item(1) - expect(expectedLineNumbersNode).toBe atom.views.getView(lineNumberGutter) + + initialCustomGutterNode1 = gutterContainerComponent.getDomNode().children.item(0) + initialLineNumbersNode = gutterContainerComponent.getDomNode().children.item(1) # Add a gutter. customGutter2 = new Gutter(mockGutterContainer, {name: 'custom2', priority: -10}) testState = buildTestState([customGutter1, customGutter2, lineNumberGutter]) gutterContainerComponent.updateSync(testState) + expect(gutterContainerComponent.getDomNode().children.length).toBe 3 - expectedCustomGutterNode1 = gutterContainerComponent.getDomNode().children.item(0) - expect(expectedCustomGutterNode1).toBe atom.views.getView(customGutter1) - expectedCustomGutterNode2 = gutterContainerComponent.getDomNode().children.item(1) - expect(expectedCustomGutterNode2).toBe atom.views.getView(customGutter2) - expectedLineNumbersNode = gutterContainerComponent.getDomNode().children.item(2) - expect(expectedLineNumbersNode).toBe atom.views.getView(lineNumberGutter) + + unchangedCustomGutterNode1 = gutterContainerComponent.getDomNode().children.item(0) + insertedCustomGutterNode2 = gutterContainerComponent.getDomNode().children.item(1) + repositionedLineNumbersNode = gutterContainerComponent.getDomNode().children.item(2) + + expect(initialCustomGutterNode1).toBe(unchangedCustomGutterNode1) + expect(initialLineNumbersNode).toBe(repositionedLineNumbersNode) + expect(insertedCustomGutterNode2).toBeDefined() # Hide one gutter, reposition one gutter, remove one gutter; and add a new gutter. customGutter2.hide() @@ -130,10 +132,12 @@ describe "GutterContainerComponent", -> testState = buildTestState([customGutter2, customGutter1, customGutter3]) gutterContainerComponent.updateSync(testState) expect(gutterContainerComponent.getDomNode().children.length).toBe 3 - expectedCustomGutterNode2 = gutterContainerComponent.getDomNode().children.item(0) - expect(expectedCustomGutterNode2).toBe atom.views.getView(customGutter2) - expect(expectedCustomGutterNode2.style.display).toBe 'none' - expectedCustomGutterNode1 = gutterContainerComponent.getDomNode().children.item(1) - expect(expectedCustomGutterNode1).toBe atom.views.getView(customGutter1) - expectedCustomGutterNode3 = gutterContainerComponent.getDomNode().children.item(2) - expect(expectedCustomGutterNode3).toBe atom.views.getView(customGutter3) + + repositionedCustomGutterNode2 = gutterContainerComponent.getDomNode().children.item(0) + repositionedCustomGutterNode1 = gutterContainerComponent.getDomNode().children.item(1) + insertedCustomGutterNode3 = gutterContainerComponent.getDomNode().children.item(2) + + expect(initialCustomGutterNode1).toBe(repositionedCustomGutterNode1) + expect(repositionedCustomGutterNode2).toBe(insertedCustomGutterNode2) + expect(repositionedCustomGutterNode2.style.display).toBe('none') + expect(insertedCustomGutterNode3).toBeDefined() diff --git a/src/custom-gutter-component.coffee b/src/custom-gutter-component.coffee index 39f5a80a1..5694f6182 100644 --- a/src/custom-gutter-component.coffee +++ b/src/custom-gutter-component.coffee @@ -1,4 +1,4 @@ -{setDimensionsAndBackground} = require './gutter-component-helpers' +{createGutterView, setDimensionsAndBackground} = require './gutter-component-helpers' # This class represents a gutter other than the 'line-numbers' gutter. # The contents of this gutter may be specified by Decorations. @@ -11,10 +11,8 @@ class CustomGutterComponent @decorationItemsById = {} @visible = true - @domNode = atom.views.getView(@gutter) + @domNode = createGutterView(@gutter) @decorationsNode = @domNode.firstChild - # Clear the contents in case the domNode is being reused. - @decorationsNode.innerHTML = '' getDomNode: -> @domNode diff --git a/src/line-number-gutter-component.coffee b/src/line-number-gutter-component.coffee index 351275f63..4efcf8dd7 100644 --- a/src/line-number-gutter-component.coffee +++ b/src/line-number-gutter-component.coffee @@ -1,5 +1,5 @@ _ = require 'underscore-plus' -{setDimensionsAndBackground} = require './gutter-component-helpers' +{createGutterView, setDimensionsAndBackground} = require './gutter-component-helpers' WrapperDiv = document.createElement('div') @@ -11,9 +11,8 @@ class LineNumberGutterComponent @lineNumberNodesById = {} @visible = true - @domNode = atom.views.getView(@gutter) + @domNode = createGutterView(@gutter) @lineNumbersNode = @domNode.firstChild - @lineNumbersNode.innerHTML = '' @domNode.addEventListener 'click', @onClick @domNode.addEventListener 'mousedown', @onMouseDown diff --git a/src/pane-container.coffee b/src/pane-container.coffee index 26ef22cac..e6eb97075 100644 --- a/src/pane-container.coffee +++ b/src/pane-container.coffee @@ -2,8 +2,6 @@ Grim = require 'grim' {Emitter, CompositeDisposable} = require 'event-kit' Serializable = require 'serializable' -{createGutterView} = require './gutter-component-helpers' -Gutter = require './gutter' Model = require './model' Pane = require './pane' PaneElement = require './pane-element' @@ -62,7 +60,6 @@ class PaneContainer extends Model new PaneElement().initialize(model) atom.views.addViewProvider TextEditor, (model) -> new TextEditorElement().initialize(model) - atom.views.addViewProvider(Gutter, createGutterView) onDidChangeRoot: (fn) -> @emitter.on 'did-change-root', fn From b04b0a8dc45ca9d437ab00bf50f3527be05023e1 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 17 Jun 2015 13:48:31 +0200 Subject: [PATCH 1708/1783] :bug: Fix race condition as well --- spec/text-editor-component-spec.coffee | 9 +++++++++ src/text-editor-component.coffee | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index f9effd047..31467bed4 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -67,6 +67,15 @@ describe "TextEditorComponent", -> expect(nextAnimationFrame).not.toThrow() + it "doesn't update when an animation frame was requested but the component got destroyed before its delivery", -> + editor.setText("You shouldn't see this update.") + expect(nextAnimationFrame).not.toBe(noAnimationFrame) + + component.destroy() + nextAnimationFrame() + + expect(component.lineNodeForScreenRow(0).textContent).not.toBe("You shouldn't see this update.") + describe "line rendering", -> expectTileContainsRow = (tileNode, screenRow, {top}) -> lineNode = tileNode.querySelector("[data-screen-row='#{screenRow}']") diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index e0ab143c5..66996a996 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -195,7 +195,7 @@ class TextEditorComponent @updateRequested = true atom.views.updateDocument => @updateRequested = false - @updateSync() if @editor.isAlive() + @updateSync() if @canUpdate() atom.views.readDocument(@readAfterUpdateSync) canUpdate: -> From 3cdeaa8b51561e21ca268d377151e6942c04bc69 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 17 Jun 2015 10:57:21 -0700 Subject: [PATCH 1709/1783] Don't auto-indent when pasting text w/ no line breaks --- spec/text-editor-spec.coffee | 41 +++++++++++++++++++++++------------- src/selection.coffee | 2 +- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 53eb32acb..128fa5235 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -2929,34 +2929,45 @@ describe "TextEditor", -> beforeEach -> atom.config.set("editor.autoIndentOnPaste", true) - describe "when only whitespace precedes the cursor", -> + describe "when pasting multiple lines before any non-whitespace characters", -> it "auto-indents the lines spanned by the pasted text, based on the first pasted line", -> - expect(editor.indentationForBufferRow(5)).toBe(3) - atom.clipboard.write("a(x);\n b(x);\n c(x);\n", indentBasis: 0) editor.setCursorBufferPosition([5, 0]) editor.pasteText() - # Adjust the indentation of the pasted block - expect(editor.indentationForBufferRow(5)).toBe(3) - expect(editor.indentationForBufferRow(6)).toBe(4) - expect(editor.indentationForBufferRow(7)).toBe(5) + # Adjust the indentation of the pasted lines while preserving + # their indentation relative to each other. Also preserve the + # indentation of the following line. + expect(editor.lineTextForBufferRow(5)).toBe " a(x);" + expect(editor.lineTextForBufferRow(6)).toBe " b(x);" + expect(editor.lineTextForBufferRow(7)).toBe " c(x);" + expect(editor.lineTextForBufferRow(8)).toBe " current = items.shift();" - # Preserve the indentation of the next row - expect(editor.indentationForBufferRow(8)).toBe(3) + describe "when pasting a single line of text", -> + it "does not auto-indent the text", -> + atom.clipboard.write("a(x);", indentBasis: 0) + editor.setCursorBufferPosition([5, 0]) + editor.pasteText() - describe "when non-whitespace characters precede the cursor", -> - it "does not auto-indent the first line being pasted", -> + expect(editor.lineTextForBufferRow(5)).toBe "a(x); current = items.shift();" + expect(editor.lineTextForBufferRow(6)).toBe " current < pivot ? left.push(current) : right.push(current);" + + describe "when pasting on a line after non-whitespace characters", -> + it "does not auto-indent the affected line", -> + # Before the paste, the indentation is non-standard. editor.setText """ - if (x) { - y(); - } + if (x) { + y(); + } """ - atom.clipboard.write(" z();") + atom.clipboard.write(" z();\n h();") editor.setCursorBufferPosition([1, Infinity]) + + # The indentation of the non-standard line is unchanged. editor.pasteText() expect(editor.lineTextForBufferRow(1)).toBe(" y(); z();") + expect(editor.lineTextForBufferRow(2)).toBe(" h();") describe "when `autoIndentOnPaste` is false", -> beforeEach -> diff --git a/src/selection.coffee b/src/selection.coffee index b96139e98..6a4d4726f 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -366,7 +366,7 @@ class Selection extends Model indentAdjustment = @editor.indentLevelForLine(precedingText) - options.indentBasis @adjustIndent(remainingLines, indentAdjustment) - if options.autoIndent and not NonWhitespaceRegExp.test(precedingText) + 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 64dfda572dd3db46ff841db9659f413a5f9b3b21 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 17 Jun 2015 12:07:42 -0700 Subject: [PATCH 1710/1783] Use raw buffer text (w/o invisibles) when testing decreaseIndentRegex --- spec/language-mode-spec.coffee | 12 ++++++++++++ src/language-mode.coffee | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/spec/language-mode-spec.coffee b/spec/language-mode-spec.coffee index 9c4fc2c1e..7ea4a1ae9 100644 --- a/spec/language-mode-spec.coffee +++ b/spec/language-mode-spec.coffee @@ -101,6 +101,18 @@ describe "LanguageMode", -> expect(languageMode.suggestedIndentForBufferRow(0)).toBe 0 expect(languageMode.suggestedIndentForBufferRow(1)).toBe 1 expect(languageMode.suggestedIndentForBufferRow(2)).toBe 2 + expect(languageMode.suggestedIndentForBufferRow(5)).toBe 3 + expect(languageMode.suggestedIndentForBufferRow(7)).toBe 2 + expect(languageMode.suggestedIndentForBufferRow(9)).toBe 1 + expect(languageMode.suggestedIndentForBufferRow(11)).toBe 1 + + it "does not take invisibles into account", -> + atom.config.set('editor.showInvisibles', true) + expect(languageMode.suggestedIndentForBufferRow(0)).toBe 0 + expect(languageMode.suggestedIndentForBufferRow(1)).toBe 1 + expect(languageMode.suggestedIndentForBufferRow(2)).toBe 2 + expect(languageMode.suggestedIndentForBufferRow(5)).toBe 3 + expect(languageMode.suggestedIndentForBufferRow(7)).toBe 2 expect(languageMode.suggestedIndentForBufferRow(9)).toBe 1 expect(languageMode.suggestedIndentForBufferRow(11)).toBe 1 diff --git a/src/language-mode.coffee b/src/language-mode.coffee index bf1e0e101..d99e69477 100644 --- a/src/language-mode.coffee +++ b/src/language-mode.coffee @@ -261,7 +261,8 @@ class LanguageMode desiredIndentLevel += 1 if increaseIndentRegex.testSync(precedingLine) and not @editor.isBufferRowCommented(precedingRow) return desiredIndentLevel unless decreaseIndentRegex = @decreaseIndentRegexForScopeDescriptor(scopeDescriptor) - desiredIndentLevel -= 1 if decreaseIndentRegex.testSync(tokenizedLine.text) + line = @buffer.lineForRow(bufferRow) + desiredIndentLevel -= 1 if decreaseIndentRegex.testSync(line) Math.max(desiredIndentLevel, 0) From 2f41fb300fa7b2ddc03263cf92ba931d5a4f1bce Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 17 Jun 2015 13:59:29 -0700 Subject: [PATCH 1711/1783] :arrow_up: notifications to fix error --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3d5affb9b..0576c4d11 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "link": "0.30.0", "markdown-preview": "0.150.0", "metrics": "0.51.0", - "notifications": "0.54.0", + "notifications": "0.55.0", "open-on-github": "0.37.0", "package-generator": "0.39.0", "release-notes": "0.53.0", From fae42ca107f1e2c6ac9fdcbba0acc0df53110d9b Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 17 Jun 2015 13:59:56 -0700 Subject: [PATCH 1712/1783] :arrow_up: autocomplete-plus@2.17.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0576c4d11..53b541427 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "autocomplete-atom-api": "0.9.0", "autocomplete-css": "0.7.2", "autocomplete-html": "0.7.2", - "autocomplete-plus": "2.17.3", + "autocomplete-plus": "2.17.4", "autocomplete-snippets": "1.7.0", "autoflow": "0.25.0", "autosave": "0.21.0", From 8890f78fae0f6d2e9c490d4e4fdcf5e5f2957408 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 17 Jun 2015 23:04:31 +0200 Subject: [PATCH 1713/1783] :arrow_up: exception-reporting --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 53b541427..59d3c9b8e 100644 --- a/package.json +++ b/package.json @@ -98,7 +98,7 @@ "deprecation-cop": "0.52.0", "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", - "exception-reporting": "0.24.0", + "exception-reporting": "0.25.0", "find-and-replace": "0.173.0", "fuzzy-finder": "0.87.0", "git-diff": "0.55.0", From 17235e706b51114f51d31e788bf489bc3a6528ef Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 17 Jun 2015 14:11:12 -0700 Subject: [PATCH 1714/1783] :arrow_up: notifications@0.56.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 59d3c9b8e..9e5536f0e 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "link": "0.30.0", "markdown-preview": "0.150.0", "metrics": "0.51.0", - "notifications": "0.55.0", + "notifications": "0.56.0", "open-on-github": "0.37.0", "package-generator": "0.39.0", "release-notes": "0.53.0", From 309410f3f43594deb7e583be7183f975448fa9f4 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 17 Jun 2015 14:42:32 -0700 Subject: [PATCH 1715/1783] Prepare 0.211 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9e5536f0e..fab07be6a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "0.210.0", + "version": "0.211.0", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From 68cc5154d64ea859aa7810f59721333bcc417142 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 18 Jun 2015 08:33:51 -0700 Subject: [PATCH 1716/1783] :arrow_up: language-text@0.7 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fab07be6a..7a50b0de2 100644 --- a/package.json +++ b/package.json @@ -154,7 +154,7 @@ "language-shellscript": "0.15.0", "language-source": "0.9.0", "language-sql": "0.16.0", - "language-text": "0.6.0", + "language-text": "0.7.0", "language-todo": "0.23.0", "language-toml": "0.16.0", "language-xml": "0.30.0", From 4675fc52e2f11edafe8f272a865e8ddb59a91b17 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 18 Jun 2015 08:35:27 -0700 Subject: [PATCH 1717/1783] :arrow_up: language-go@0.27 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7a50b0de2..2f1577c23 100644 --- a/package.json +++ b/package.json @@ -134,7 +134,7 @@ "language-css": "0.30.0", "language-gfm": "0.77.0", "language-git": "0.10.0", - "language-go": "0.26.0", + "language-go": "0.27.0", "language-html": "0.40.0", "language-hyperlink": "0.13.0", "language-java": "0.15.0", From c8f24d2358603a623754fdfa4c777e8825c784c9 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 18 Jun 2015 19:54:37 +0200 Subject: [PATCH 1718/1783] Revert ":bug: Remove Gutter from ViewRegistry" This reverts commit b0d93accf7871c09b9d14bedb887bb25ef47d142. --- spec/custom-gutter-component-spec.coffee | 3 ++ spec/gutter-container-component-spec.coffee | 38 +++++++++------------ src/custom-gutter-component.coffee | 6 ++-- src/line-number-gutter-component.coffee | 5 +-- src/pane-container.coffee | 3 ++ 5 files changed, 30 insertions(+), 25 deletions(-) diff --git a/spec/custom-gutter-component-spec.coffee b/spec/custom-gutter-component-spec.coffee index 37da68807..4b7d81fba 100644 --- a/spec/custom-gutter-component-spec.coffee +++ b/spec/custom-gutter-component-spec.coffee @@ -16,6 +16,9 @@ describe "CustomGutterComponent", -> decorationsWrapperNode = gutterComponent.getDomNode().children.item(0) expect(decorationsWrapperNode.classList.contains('custom-decorations')).toBe true + it "makes its view accessible from the view registry", -> + expect(gutterComponent.getDomNode()).toBe atom.views.getView(gutter) + it "hides its DOM node when ::hideNode is called, and shows its DOM node when ::showNode is called", -> gutterComponent.hideNode() expect(gutterComponent.getDomNode().style.display).toBe 'none' diff --git a/spec/gutter-container-component-spec.coffee b/spec/gutter-container-component-spec.coffee index 6048655f1..5d815fea8 100644 --- a/spec/gutter-container-component-spec.coffee +++ b/spec/gutter-container-component-spec.coffee @@ -107,24 +107,22 @@ describe "GutterContainerComponent", -> gutterContainerComponent.updateSync(testState) expect(gutterContainerComponent.getDomNode().children.length).toBe 2 - - initialCustomGutterNode1 = gutterContainerComponent.getDomNode().children.item(0) - initialLineNumbersNode = gutterContainerComponent.getDomNode().children.item(1) + expectedCustomGutterNode = gutterContainerComponent.getDomNode().children.item(0) + expect(expectedCustomGutterNode).toBe atom.views.getView(customGutter1) + expectedLineNumbersNode = gutterContainerComponent.getDomNode().children.item(1) + expect(expectedLineNumbersNode).toBe atom.views.getView(lineNumberGutter) # Add a gutter. customGutter2 = new Gutter(mockGutterContainer, {name: 'custom2', priority: -10}) testState = buildTestState([customGutter1, customGutter2, lineNumberGutter]) gutterContainerComponent.updateSync(testState) - expect(gutterContainerComponent.getDomNode().children.length).toBe 3 - - unchangedCustomGutterNode1 = gutterContainerComponent.getDomNode().children.item(0) - insertedCustomGutterNode2 = gutterContainerComponent.getDomNode().children.item(1) - repositionedLineNumbersNode = gutterContainerComponent.getDomNode().children.item(2) - - expect(initialCustomGutterNode1).toBe(unchangedCustomGutterNode1) - expect(initialLineNumbersNode).toBe(repositionedLineNumbersNode) - expect(insertedCustomGutterNode2).toBeDefined() + expectedCustomGutterNode1 = gutterContainerComponent.getDomNode().children.item(0) + expect(expectedCustomGutterNode1).toBe atom.views.getView(customGutter1) + expectedCustomGutterNode2 = gutterContainerComponent.getDomNode().children.item(1) + expect(expectedCustomGutterNode2).toBe atom.views.getView(customGutter2) + expectedLineNumbersNode = gutterContainerComponent.getDomNode().children.item(2) + expect(expectedLineNumbersNode).toBe atom.views.getView(lineNumberGutter) # Hide one gutter, reposition one gutter, remove one gutter; and add a new gutter. customGutter2.hide() @@ -132,12 +130,10 @@ describe "GutterContainerComponent", -> testState = buildTestState([customGutter2, customGutter1, customGutter3]) gutterContainerComponent.updateSync(testState) expect(gutterContainerComponent.getDomNode().children.length).toBe 3 - - repositionedCustomGutterNode2 = gutterContainerComponent.getDomNode().children.item(0) - repositionedCustomGutterNode1 = gutterContainerComponent.getDomNode().children.item(1) - insertedCustomGutterNode3 = gutterContainerComponent.getDomNode().children.item(2) - - expect(initialCustomGutterNode1).toBe(repositionedCustomGutterNode1) - expect(repositionedCustomGutterNode2).toBe(insertedCustomGutterNode2) - expect(repositionedCustomGutterNode2.style.display).toBe('none') - expect(insertedCustomGutterNode3).toBeDefined() + expectedCustomGutterNode2 = gutterContainerComponent.getDomNode().children.item(0) + expect(expectedCustomGutterNode2).toBe atom.views.getView(customGutter2) + expect(expectedCustomGutterNode2.style.display).toBe 'none' + expectedCustomGutterNode1 = gutterContainerComponent.getDomNode().children.item(1) + expect(expectedCustomGutterNode1).toBe atom.views.getView(customGutter1) + expectedCustomGutterNode3 = gutterContainerComponent.getDomNode().children.item(2) + expect(expectedCustomGutterNode3).toBe atom.views.getView(customGutter3) diff --git a/src/custom-gutter-component.coffee b/src/custom-gutter-component.coffee index 5694f6182..39f5a80a1 100644 --- a/src/custom-gutter-component.coffee +++ b/src/custom-gutter-component.coffee @@ -1,4 +1,4 @@ -{createGutterView, setDimensionsAndBackground} = require './gutter-component-helpers' +{setDimensionsAndBackground} = require './gutter-component-helpers' # This class represents a gutter other than the 'line-numbers' gutter. # The contents of this gutter may be specified by Decorations. @@ -11,8 +11,10 @@ class CustomGutterComponent @decorationItemsById = {} @visible = true - @domNode = createGutterView(@gutter) + @domNode = atom.views.getView(@gutter) @decorationsNode = @domNode.firstChild + # Clear the contents in case the domNode is being reused. + @decorationsNode.innerHTML = '' getDomNode: -> @domNode diff --git a/src/line-number-gutter-component.coffee b/src/line-number-gutter-component.coffee index 4efcf8dd7..351275f63 100644 --- a/src/line-number-gutter-component.coffee +++ b/src/line-number-gutter-component.coffee @@ -1,5 +1,5 @@ _ = require 'underscore-plus' -{createGutterView, setDimensionsAndBackground} = require './gutter-component-helpers' +{setDimensionsAndBackground} = require './gutter-component-helpers' WrapperDiv = document.createElement('div') @@ -11,8 +11,9 @@ class LineNumberGutterComponent @lineNumberNodesById = {} @visible = true - @domNode = createGutterView(@gutter) + @domNode = atom.views.getView(@gutter) @lineNumbersNode = @domNode.firstChild + @lineNumbersNode.innerHTML = '' @domNode.addEventListener 'click', @onClick @domNode.addEventListener 'mousedown', @onMouseDown diff --git a/src/pane-container.coffee b/src/pane-container.coffee index e6eb97075..26ef22cac 100644 --- a/src/pane-container.coffee +++ b/src/pane-container.coffee @@ -2,6 +2,8 @@ Grim = require 'grim' {Emitter, CompositeDisposable} = require 'event-kit' Serializable = require 'serializable' +{createGutterView} = require './gutter-component-helpers' +Gutter = require './gutter' Model = require './model' Pane = require './pane' PaneElement = require './pane-element' @@ -60,6 +62,7 @@ class PaneContainer extends Model new PaneElement().initialize(model) atom.views.addViewProvider TextEditor, (model) -> new TextEditorElement().initialize(model) + atom.views.addViewProvider(Gutter, createGutterView) onDidChangeRoot: (fn) -> @emitter.on 'did-change-root', fn From 2017e3fe235f330518273421d0b9ead3351859e1 Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 19 Jun 2015 10:22:26 +0900 Subject: [PATCH 1719/1783] Increase default line height --- src/config-schema.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config-schema.coffee b/src/config-schema.coffee index 71ab26386..43bf41403 100644 --- a/src/config-schema.coffee +++ b/src/config-schema.coffee @@ -108,7 +108,7 @@ module.exports = maximum: 100 lineHeight: type: ['string', 'number'] - default: 1.4 + default: 1.44 showInvisibles: type: 'boolean' default: false From 351b407751650d9383ff88d24a87c738c9955f6f Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 19 Jun 2015 15:57:09 +0900 Subject: [PATCH 1720/1783] Add style.less examples that can get uncommented --- dot-atom/styles.less | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dot-atom/styles.less b/dot-atom/styles.less index 50c5066e6..a9e374058 100644 --- a/dot-atom/styles.less +++ b/dot-atom/styles.less @@ -8,18 +8,18 @@ * http://www.lesscss.org */ +// style the background color of the tree view .tree-view { - + // background-color: whitesmoke; } -// style the background and foreground colors on the atom-text-editor-element -// itself +// style the background and foreground colors on the atom-text-editor-element itself atom-text-editor { - + // color: white; + // background-color: hsl(180, 24%, 12%); } -// To style other content in the text editor's shadow DOM, use the ::shadow -// expression +// To style other content in the text editor's shadow DOM, use the ::shadow expression atom-text-editor::shadow .cursor { - + // border-color: red; } From d922c1804fca6bdf49680ab2e5cbff20edd7e1b1 Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 19 Jun 2015 16:05:03 +0900 Subject: [PATCH 1721/1783] Update note about Less Mentioning that you can use plain CSS should make it less intimitaing. --- dot-atom/styles.less | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dot-atom/styles.less b/dot-atom/styles.less index a9e374058..bb8eb3146 100644 --- a/dot-atom/styles.less +++ b/dot-atom/styles.less @@ -4,8 +4,7 @@ * This stylesheet is loaded when Atom starts up and is reloaded automatically * when it is changed. * - * If you are unfamiliar with LESS, you can read more about it here: - * http://www.lesscss.org + * Uncomment the examples below to test or add your own CSS or Less. */ // style the background color of the tree view From d7156ff387eb51e3b2a201a767cb287c849243b7 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 19 Jun 2015 10:24:48 +0200 Subject: [PATCH 1722/1783] Remove event listeners from orphaned gutters --- spec/text-editor-component-spec.coffee | 18 ++++++++++++++++++ src/gutter-container-component.coffee | 7 ++++++- src/line-number-gutter-component.coffee | 4 ++++ src/text-editor-component.coffee | 1 + 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 31467bed4..a9e98efc1 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -743,6 +743,16 @@ describe "TextEditorComponent", -> beforeEach -> gutterNode = componentNode.querySelector('.gutter') + describe "when the component is destroyed", -> + it "stops listening for folding events", -> + component.destroy() + + lineNumber = component.lineNumberNodeForScreenRow(1) + target = lineNumber.querySelector('.icon-right') + target.dispatchEvent(buildClickEvent(target)) + + expect(nextAnimationFrame).toBe(noAnimationFrame) + it "folds and unfolds the block represented by the fold indicator when clicked", -> expect(lineNumberHasClass(1, 'folded')).toBe false @@ -1727,6 +1737,14 @@ describe "TextEditorComponent", -> beforeEach -> gutterNode = componentNode.querySelector('.gutter') + describe "when the component is destroyed", -> + it "stops listening for selection events", -> + component.destroy() + + gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(1))) + + expect(editor.getSelectedScreenRange()).toEqual [[0, 0], [0, 0]] + describe "when the gutter is clicked", -> it "selects the clicked row", -> gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(4))) diff --git a/src/gutter-container-component.coffee b/src/gutter-container-component.coffee index 5fa2f85f4..92ef5e8b6 100644 --- a/src/gutter-container-component.coffee +++ b/src/gutter-container-component.coffee @@ -16,7 +16,12 @@ class GutterContainerComponent @domNode = document.createElement('div') @domNode.classList.add('gutter-container') - @domNode.style.display = 'flex'; + @domNode.style.display = 'flex' + + destroy: -> + for {name, component} in @gutterComponents + component.destroy?() + return getDomNode: -> @domNode diff --git a/src/line-number-gutter-component.coffee b/src/line-number-gutter-component.coffee index 351275f63..7675493de 100644 --- a/src/line-number-gutter-component.coffee +++ b/src/line-number-gutter-component.coffee @@ -18,6 +18,10 @@ class LineNumberGutterComponent @domNode.addEventListener 'click', @onClick @domNode.addEventListener 'mousedown', @onMouseDown + destroy: -> + @domNode.removeEventListener 'click', @onClick + @domNode.removeEventListener 'mousedown', @onMouseDown + getDomNode: -> @domNode diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 66996a996..b8fe39976 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -106,6 +106,7 @@ class TextEditorComponent @mounted = false @disposables.dispose() @presenter.destroy() + @gutterContainerComponent?.destroy() window.removeEventListener 'resize', @requestHeightAndWidthMeasurement getDomNode: -> From 533abc5a63bd19040f901cd22d4a247b7e6946e8 Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 19 Jun 2015 21:31:36 +0900 Subject: [PATCH 1723/1783] Increase default line height even a bit more --- src/config-schema.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config-schema.coffee b/src/config-schema.coffee index 43bf41403..6e8fbfdb7 100644 --- a/src/config-schema.coffee +++ b/src/config-schema.coffee @@ -108,7 +108,7 @@ module.exports = maximum: 100 lineHeight: type: ['string', 'number'] - default: 1.44 + default: 1.5 showInvisibles: type: 'boolean' default: false From 67cf747a20846436261322b1ec6856b662196cd3 Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 19 Jun 2015 21:37:57 +0900 Subject: [PATCH 1724/1783] :memo: Add back link to the Less docs --- dot-atom/styles.less | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dot-atom/styles.less b/dot-atom/styles.less index bb8eb3146..b1e02ca5c 100644 --- a/dot-atom/styles.less +++ b/dot-atom/styles.less @@ -4,7 +4,9 @@ * This stylesheet is loaded when Atom starts up and is reloaded automatically * when it is changed. * - * Uncomment the examples below to test or add your own CSS or Less. + * Uncomment the examples below to try it out. Or add your own CSS or Less. + * If you are unfamiliar with Less, you can read more about it here: + * http://lesscss.org */ // style the background color of the tree view From cfd61afd38187c163b29834222230d0f31a06469 Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 19 Jun 2015 23:21:36 +0900 Subject: [PATCH 1725/1783] :memo: Update styles.less copy --- dot-atom/styles.less | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/dot-atom/styles.less b/dot-atom/styles.less index b1e02ca5c..a321469e7 100644 --- a/dot-atom/styles.less +++ b/dot-atom/styles.less @@ -2,13 +2,19 @@ * Your Stylesheet * * This stylesheet is loaded when Atom starts up and is reloaded automatically - * when it is changed. + * when it is changed and saved. * - * Uncomment the examples below to try it out. Or add your own CSS or Less. + * Add your own CSS or Less to fully customize Atom. * If you are unfamiliar with Less, you can read more about it here: * http://lesscss.org */ + +/* + * Examples + * (To see them, uncomment and save) + */ + // style the background color of the tree view .tree-view { // background-color: whitesmoke; From af42c6bbab302ae17135c12cdc5fedf6478654ac Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Fri, 19 Jun 2015 09:10:55 -0600 Subject: [PATCH 1726/1783] :arrow_up: language-css@0.31.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2f1577c23..94ad87f80 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,7 @@ "language-clojure": "0.15.0", "language-coffee-script": "0.41.0", "language-csharp": "0.6.0", - "language-css": "0.30.0", + "language-css": "0.31.0", "language-gfm": "0.77.0", "language-git": "0.10.0", "language-go": "0.27.0", From 82fe556af855f7ad2c8e7cae09891275babc2f58 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 19 Jun 2015 09:17:22 -0700 Subject: [PATCH 1727/1783] :arrow_up: language-clojure@0.16 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 94ad87f80..0d1c07fae 100644 --- a/package.json +++ b/package.json @@ -128,7 +128,7 @@ "whitespace": "0.30.0", "wrap-guide": "0.35.0", "language-c": "0.45.0", - "language-clojure": "0.15.0", + "language-clojure": "0.16.0", "language-coffee-script": "0.41.0", "language-csharp": "0.6.0", "language-css": "0.31.0", From fc4f2a102ebf3aa5b1f3e2de07023a33c92f4ee6 Mon Sep 17 00:00:00 2001 From: simurai Date: Sat, 20 Jun 2015 16:16:05 +0900 Subject: [PATCH 1728/1783] :arrow_up: one-dark/light-ui@v0.9.1 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 0d1c07fae..3de65bf7e 100644 --- a/package.json +++ b/package.json @@ -77,10 +77,10 @@ "atom-light-ui": "0.41.0", "base16-tomorrow-dark-theme": "0.26.0", "base16-tomorrow-light-theme": "0.9.0", - "one-dark-ui": "0.9.0", + "one-dark-ui": "0.9.1", "one-dark-syntax": "0.7.1", "one-light-syntax": "0.7.0", - "one-light-ui": "0.9.0", + "one-light-ui": "0.9.1", "solarized-dark-syntax": "0.35.0", "solarized-light-syntax": "0.21.0", "archive-view": "0.58.0", From 776eee2413038f556320db726395280691859a05 Mon Sep 17 00:00:00 2001 From: Tony Han Date: Sat, 20 Jun 2015 17:55:19 +0800 Subject: [PATCH 1729/1783] :memo: fix doc for TextEditor setText --- src/text-editor.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 7afc99236..3b19970b8 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -749,6 +749,8 @@ class TextEditor extends Model ### # Essential: Replaces the entire contents of the buffer with the given {String}. + # + # * `text` A {String} to replace with setText: (text) -> @buffer.setText(text) # Essential: Set the text in the given {Range} in buffer coordinates. From cd35107f8c10cf46b51b4ededbaf51f0d222d5c1 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 17 Jun 2015 21:35:33 +0200 Subject: [PATCH 1730/1783] Call atom.onDidThrowError handlers with the error object MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …and remove a bunch of dead source maps handling. Source map handling for stack traces is now built into Chromium so it shouldn’t be needed here. Original event properties maintained for backward compatibility with the 1.0 API. Can be deprecated for 2.0 once we transition exception-reporter. --- spec/atom-spec.coffee | 41 ++++++++++++++++++++++++++++------------- src/atom.coffee | 36 ++++++++++++++++-------------------- 2 files changed, 44 insertions(+), 33 deletions(-) diff --git a/spec/atom-spec.coffee b/spec/atom-spec.coffee index 99a7f432e..9a03981d0 100644 --- a/spec/atom-spec.coffee +++ b/spec/atom-spec.coffee @@ -86,13 +86,13 @@ describe "the `atom` global", -> error = e window.onerror.call(window, e.toString(), 'abc', 2, 3, e) - delete willThrowSpy.mostRecentCall.args[0].preventDefault - expect(willThrowSpy).toHaveBeenCalledWith - message: error.toString() - url: 'abc' - line: 2 - column: 3 - originalError: error + expect(willThrowSpy).toHaveBeenCalledWith(error) + + # Deprecated event properties + expect(error.url).toBe 'abc' + expect(error.line).toBe 2 + expect(error.column).toBe 3 + expect(error.originalError).toBe error it "will not show the devtools when preventDefault() is called", -> willThrowSpy.andCallFake (errorObject) -> errorObject.preventDefault() @@ -120,12 +120,27 @@ describe "the `atom` global", -> catch e error = e window.onerror.call(window, e.toString(), 'abc', 2, 3, e) - expect(didThrowSpy).toHaveBeenCalledWith - message: error.toString() - url: 'abc' - line: 2 - column: 3 - originalError: error + + expect(didThrowSpy).toHaveBeenCalledWith(error) + + # Deprecated event properties + expect(error.url).toBe 'abc' + expect(error.line).toBe 2 + expect(error.column).toBe 3 + expect(error.originalError).toBe error + + it "will not show the devtools when preventDefault() is called", -> + didThrowSpy.andCallFake (errorObject) -> errorObject.preventDefault() + atom.onDidThrowError(didThrowSpy) + + try + a + 1 + catch e + window.onerror.call(window, e.toString(), 'abc', 2, 3, e) + + expect(didThrowSpy).toHaveBeenCalled() + expect(atom.openDevTools).not.toHaveBeenCalled() + expect(atom.executeJavaScriptInDevTools).not.toHaveBeenCalled() describe "saving and loading", -> afterEach -> atom.mode = "spec" diff --git a/src/atom.coffee b/src/atom.coffee index 316c51e29..9e89aa784 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -198,28 +198,29 @@ class Atom extends Model initialize: -> sourceMapCache = {} - window.onerror = => - @lastUncaughtError = Array::slice.call(arguments) - [message, url, line, column, originalError] = @lastUncaughtError + window.onerror = (message, url, line, column, error) => + @lastUncaughtError = error - convertedLine = convertLine(url, line, column, sourceMapCache) - {line, column} = convertedLine if convertedLine? - originalError.stack = convertStackTrace(originalError.stack, sourceMapCache) if originalError - - eventObject = {message, url, line, column, originalError} + # TODO: These should be deprecated for 2.0 once we transition the + # exception-reporting package to the new API. + error.url = url + error.line = line + error.column = column + error.originalError = error openDevTools = true - eventObject.preventDefault = -> openDevTools = false + error.preventDefault = -> openDevTools = false - @emitter.emit 'will-throw-error', eventObject + # TODO: Deprecate onWillThrowError once we transition the notifications + # package to use onDidThrowError instead. + @emitter.emit 'will-throw-error', error + @emit 'uncaught-error', arguments... if includeDeprecatedAPIs + @emitter.emit 'did-throw-error', error if openDevTools @openDevTools() @executeJavaScriptInDevTools('DevToolsAPI.showConsole()') - @emit 'uncaught-error', arguments... if includeDeprecatedAPIs - @emitter.emit 'did-throw-error', {message, url, line, column, originalError} - @disposables?.dispose() @disposables = new CompositeDisposable @@ -321,13 +322,8 @@ class Atom extends Model # Extended: Invoke the given callback whenever there is an unhandled error. # - # * `callback` {Function} to be called whenever there is an unhandled error - # * `event` {Object} - # * `originalError` {Object} the original error object - # * `message` {String} the original error object - # * `url` {String} Url to the file where the error originated. - # * `line` {Number} - # * `column` {Number} + # * `callback` {Function} to be called whenever there is an unhandled error. + # * `error` The unhandled {Error} object. # # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. onDidThrowError: (callback) -> From a1f6a15c0b98f14731a83565ad418f36112985b0 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 17 Jun 2015 22:33:18 +0200 Subject: [PATCH 1731/1783] Add atom.assert and atom.onDidFailAssertion --- spec/atom-spec.coffee | 31 +++++++++++++++++++++++++++++++ src/atom.coffee | 17 +++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/spec/atom-spec.coffee b/spec/atom-spec.coffee index 9a03981d0..15af4ad50 100644 --- a/spec/atom-spec.coffee +++ b/spec/atom-spec.coffee @@ -142,6 +142,37 @@ describe "the `atom` global", -> expect(atom.openDevTools).not.toHaveBeenCalled() expect(atom.executeJavaScriptInDevTools).not.toHaveBeenCalled() + describe ".assert(condition, message, metadata)", -> + errors = null + + beforeEach -> + errors = [] + atom.onDidFailAssertion (error) -> errors.push(error) + + describe "if the condition is false", -> + it "notifies onDidFailAssertion handlers with an error object based on the call site of the assertion", -> + atom.assert(false, "a == b") + expect(errors.length).toBe 1 + expect(errors[0].message).toBe "Assertion failed: a == b" + expect(errors[0].stack).toContain('atom-spec') + + describe "if metadata is an object", -> + it "assigns the object on the error as `metadata`", -> + metadata = {foo: 'bar'} + atom.assert(false, "a == b", metadata) + expect(errors[0].metadata).toBe metadata + + describe "if metadata is a function", -> + it "assigns the function's return value on the error as `metadata`", -> + metadata = {foo: 'bar'} + atom.assert(false, "a == b", -> metadata) + expect(errors[0].metadata).toBe metadata + + describe "if the condition is true", -> + it "does nothing", -> + atom.assert(true, "a == b") + expect(errors).toEqual [] + describe "saving and loading", -> afterEach -> atom.mode = "spec" diff --git a/src/atom.coffee b/src/atom.coffee index 9e89aa784..4af35a91e 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -329,6 +329,9 @@ class Atom extends Model onDidThrowError: (callback) -> @emitter.on 'did-throw-error', callback + onDidFailAssertion: (callback) -> + @emitter.on 'did-fail-assertion', callback + ### Section: Atom Details ### @@ -711,6 +714,20 @@ class Atom extends Model Section: Private ### + assert: (condition, message, metadata) -> + return if condition + + error = new Error("Assertion failed: " + message) + Error.captureStackTrace(error, @assert) + + if metadata? + if typeof metadata is 'function' + error.metadata = metadata() + else + error.metadata = metadata + + @emitter.emit 'did-fail-assertion', error + deserializeProject: -> Project = require './project' From 11c3b3444b5756966e9778628c666fd767342348 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sat, 20 Jun 2015 17:34:42 +0200 Subject: [PATCH 1732/1783] Return a boolean from atom.assert --- spec/atom-spec.coffee | 6 ++++-- src/atom.coffee | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/spec/atom-spec.coffee b/spec/atom-spec.coffee index 15af4ad50..c8c4a598f 100644 --- a/spec/atom-spec.coffee +++ b/spec/atom-spec.coffee @@ -151,7 +151,8 @@ describe "the `atom` global", -> describe "if the condition is false", -> it "notifies onDidFailAssertion handlers with an error object based on the call site of the assertion", -> - atom.assert(false, "a == b") + result = atom.assert(false, "a == b") + expect(result).toBe false expect(errors.length).toBe 1 expect(errors[0].message).toBe "Assertion failed: a == b" expect(errors[0].stack).toContain('atom-spec') @@ -170,7 +171,8 @@ describe "the `atom` global", -> describe "if the condition is true", -> it "does nothing", -> - atom.assert(true, "a == b") + result = atom.assert(true, "a == b") + expect(result).toBe true expect(errors).toEqual [] describe "saving and loading", -> diff --git a/src/atom.coffee b/src/atom.coffee index 4af35a91e..209a39e9c 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -715,7 +715,7 @@ class Atom extends Model ### assert: (condition, message, metadata) -> - return if condition + return true if condition error = new Error("Assertion failed: " + message) Error.captureStackTrace(error, @assert) @@ -728,6 +728,8 @@ class Atom extends Model @emitter.emit 'did-fail-assertion', error + false + deserializeProject: -> Project = require './project' From 64fca5db2081ae208e9bf262bbfe72c60941c862 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sat, 20 Jun 2015 17:36:12 +0200 Subject: [PATCH 1733/1783] Absorb exception in isFoldableCodeAtRow and report assertion failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Can’t figure out what’s going on in this bug, but we can hopefully make it less damaging and collect more information via the new assertion system. Refs #5905 --- src/tokenized-buffer.coffee | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 7fb21937d..bbb6b3748 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -292,7 +292,17 @@ class TokenizedBuffer extends Model # Returns a {Boolean} indicating whether the given buffer row starts # a a foldable row range due to the code's indentation patterns. isFoldableCodeAtRow: (row) -> - return false if @buffer.isRowBlank(row) or @tokenizedLineForRow(row).isComment() + # Investigating an exception that's occurring here due to the line being + # undefined. This should paper over the problem but we want to figure out + # what is happening: + tokenizedLine = @tokenizedLineForRow(row) + atom.assert tokenizedLine?, "TokenizedLine is defined", => + metadata: + row: row + rowCount: @tokenizedLines.length + return false unless tokenizedLine? + + return false if @buffer.isRowBlank(row) or tokenizedLine.isComment() nextRow = @buffer.nextNonBlankRow(row) return false unless nextRow? From a24816f76b513cea1078cd3511978686e5332bd0 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sat, 20 Jun 2015 18:07:47 +0200 Subject: [PATCH 1734/1783] Handle null errors to support existing uses in tests --- src/atom.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/atom.coffee b/src/atom.coffee index 209a39e9c..f3bbafcc2 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -203,6 +203,7 @@ class Atom extends Model # TODO: These should be deprecated for 2.0 once we transition the # exception-reporting package to the new API. + error ?= {} error.url = url error.line = line error.column = column From d1057b5de7fbcdf4f2acd1c73789b6785b8ce203 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sat, 20 Jun 2015 18:27:35 +0200 Subject: [PATCH 1735/1783] Fill error message in if needed for package specs --- src/atom.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/atom.coffee b/src/atom.coffee index f3bbafcc2..0704f0bfb 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -204,6 +204,7 @@ class Atom extends Model # TODO: These should be deprecated for 2.0 once we transition the # exception-reporting package to the new API. error ?= {} + error.message ?= message error.url = url error.line = line error.column = column From 4e1d47b09f2fb90fd84e6969231bb245dd273068 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Machist=C3=A9=20N=2E=20Quintana?= Date: Sat, 20 Jun 2015 12:45:47 -0400 Subject: [PATCH 1736/1783] :memo: Mark Clipboard::write's metadata argument as optional --- src/clipboard.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clipboard.coffee b/src/clipboard.coffee index 2412394a6..84ff9ab3b 100644 --- a/src/clipboard.coffee +++ b/src/clipboard.coffee @@ -31,7 +31,7 @@ class Clipboard # {::readWithMetadata}. # # * `text` The {String} to store. - # * `metadata` The additional info to associate with the text. + # * `metadata` (optional) The additional info to associate with the text. write: (text, metadata) -> @signatureForMetadata = @md5(text) @metadata = metadata From e3ee6231d4bd75413919d929051c2333685eadbc Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sat, 20 Jun 2015 19:00:48 +0200 Subject: [PATCH 1737/1783] :arrow_up: notifications --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3de65bf7e..17c7f084b 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "link": "0.30.0", "markdown-preview": "0.150.0", "metrics": "0.51.0", - "notifications": "0.56.0", + "notifications": "0.57.0", "open-on-github": "0.37.0", "package-generator": "0.39.0", "release-notes": "0.53.0", From d32f30780ae710ad5cdf8e3f4d076c4d99c02fe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=C5=BDu=C5=BEak?= Date: Sun, 21 Jun 2015 17:48:32 +0200 Subject: [PATCH 1738/1783] Massage the message a bit more --- src/project.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/project.coffee b/src/project.coffee index 12bccaae8..b21e74076 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -329,7 +329,7 @@ class Project extends Model if fileSize >= 20 * 1048576 # 20MB choice = atom.confirm - message: 'Atom currently freezes during the loading of very large files.' + message: 'Atom will be unresponsive during the loading of very large files.' detailedMessage: "Do you still want to load this file?" buttons: ["Proceed", "Cancel"] if choice is 1 From 720ea9a8118ccc92373a364cf79838dffba3e4e9 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Sun, 21 Jun 2015 20:38:19 -0600 Subject: [PATCH 1739/1783] :arrow_up: language-css@0.32.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3de65bf7e..e28046038 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,7 @@ "language-clojure": "0.16.0", "language-coffee-script": "0.41.0", "language-csharp": "0.6.0", - "language-css": "0.31.0", + "language-css": "0.32.0", "language-gfm": "0.77.0", "language-git": "0.10.0", "language-go": "0.27.0", From d9282f89d96a37c52b31986cd5360ecc12af171f Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Sun, 21 Jun 2015 20:38:34 -0600 Subject: [PATCH 1740/1783] :arrow_up: language-todo@0.24.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e28046038..a39105844 100644 --- a/package.json +++ b/package.json @@ -155,7 +155,7 @@ "language-source": "0.9.0", "language-sql": "0.16.0", "language-text": "0.7.0", - "language-todo": "0.23.0", + "language-todo": "0.24.0", "language-toml": "0.16.0", "language-xml": "0.30.0", "language-yaml": "0.22.0" From e817de4f3f06d16dd6d11bbdcef35c32ab6d9a5b Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Sun, 21 Jun 2015 20:55:46 -0600 Subject: [PATCH 1741/1783] :arrow_up: autocomplete-css@0.8.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a39105844..6bf6a5a6c 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ "solarized-light-syntax": "0.21.0", "archive-view": "0.58.0", "autocomplete-atom-api": "0.9.0", - "autocomplete-css": "0.7.2", + "autocomplete-css": "0.8.0", "autocomplete-html": "0.7.2", "autocomplete-plus": "2.17.4", "autocomplete-snippets": "1.7.0", From 6521c869c45d8af4612d996871ba7df803daca89 Mon Sep 17 00:00:00 2001 From: Ivan Zuzak Date: Mon, 22 Jun 2015 07:56:21 +0200 Subject: [PATCH 1742/1783] Failing test to demonstrate problem --- spec/command-registry-spec.coffee | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/spec/command-registry-spec.coffee b/spec/command-registry-spec.coffee index b92d3e6b0..799bceb8e 100644 --- a/spec/command-registry-spec.coffee +++ b/spec/command-registry-spec.coffee @@ -158,6 +158,15 @@ describe "CommandRegistry", -> addError = error expect(addError.message).toContain(badSelector) + it "throws an error when called with an non-function callback", -> + badCallback = null + addError = null + try + registry.add '.selector', 'foo:bar', badCallback + catch error + addError = error + expect(addError.message).toContain("Can't register a command with non-function callback.") + describe "::findCommands({target})", -> it "returns commands that can be invoked on the target or its ancestors", -> registry.add '.parent', 'namespace:command-1', -> From d47737718be131781c7af48b1414049e7784c705 Mon Sep 17 00:00:00 2001 From: Ivan Zuzak Date: Mon, 22 Jun 2015 07:59:08 +0200 Subject: [PATCH 1743/1783] Throw error for commands with non-function callbacks --- src/command-registry.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/command-registry.coffee b/src/command-registry.coffee index 72098eda0..a9b953536 100644 --- a/src/command-registry.coffee +++ b/src/command-registry.coffee @@ -93,6 +93,9 @@ class CommandRegistry return disposable if typeof target is 'string' + if typeof callback isnt 'function' + throw new Error("Can't register a command with non-function callback.") + validateSelector(target) @addSelectorBasedListener(target, commandName, callback) else From 4336cdf0af15537d2c2556077c6d07db4e7b4fcc Mon Sep 17 00:00:00 2001 From: Alex Mayer Date: Mon, 22 Jun 2015 11:42:21 -0400 Subject: [PATCH 1744/1783] Add Fedora 22 Install Directions To README Fedora 22 uses dnf yum command will not work --- README.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 24c7ce370..93fe03c8b 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ Currently only a 64-bit version is available. The Linux version does not currently automatically update so you will need to repeat these steps to upgrade to future releases. -### Red Hat Linux (Fedora, CentOS, Red Hat) +### Red Hat Linux (Fedora 21 and under, CentOS, Red Hat) Currently only a 64-bit version is available. @@ -62,6 +62,17 @@ Currently only a 64-bit version is available. The Linux version does not currently automatically update so you will need to repeat these steps to upgrade to future releases. +### Fedora 22+ + +Currently only a 64-bit version is available. + +1. Download `atom.x86_64.rpm` from the [Atom releases page](https://github.com/atom/atom/releases/latest). +2. Run `sudo dnf atom.x86_64.rpm` on the downloaded package. +3. Launch Atom using the installed `atom` command. + +The Linux version does not currently automatically update so you will need to +repeat these steps to upgrade to future releases. + ## Building * [Linux](docs/build-instructions/linux.md) From a0e3335bff0afa8ebca789227d684d4802195bc2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 22 Jun 2015 08:48:59 -0700 Subject: [PATCH 1745/1783] :arrow_up: language-perl@0.26 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6bf6a5a6c..9d1144549 100644 --- a/package.json +++ b/package.json @@ -144,7 +144,7 @@ "language-make": "0.14.0", "language-mustache": "0.11.0", "language-objective-c": "0.15.0", - "language-perl": "0.25.0", + "language-perl": "0.26.0", "language-php": "0.24.0", "language-property-list": "0.8.0", "language-python": "0.36.0", From b660ec2bb1b28b2c8144db8072e3bf673c716c34 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 22 Jun 2015 09:05:24 -0700 Subject: [PATCH 1746/1783] :arrow_up: language-sql@0.17 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9d1144549..4c3a8a932 100644 --- a/package.json +++ b/package.json @@ -153,7 +153,7 @@ "language-sass": "0.39.0", "language-shellscript": "0.15.0", "language-source": "0.9.0", - "language-sql": "0.16.0", + "language-sql": "0.17.0", "language-text": "0.7.0", "language-todo": "0.24.0", "language-toml": "0.16.0", From a25f8729dcf4e585625f284ddb53933ac4881d89 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 22 Jun 2015 09:23:13 -0700 Subject: [PATCH 1747/1783] :arrow_up: language-php@0.25 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4c3a8a932..946f07777 100644 --- a/package.json +++ b/package.json @@ -145,7 +145,7 @@ "language-mustache": "0.11.0", "language-objective-c": "0.15.0", "language-perl": "0.26.0", - "language-php": "0.24.0", + "language-php": "0.25.0", "language-property-list": "0.8.0", "language-python": "0.36.0", "language-ruby": "0.56.0", From 941d4a207a29882c7ad5d3b5ba18c0aab0344160 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 22 Jun 2015 09:25:21 -0700 Subject: [PATCH 1748/1783] :arrow_up: language-php@0.26 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 946f07777..6209a8952 100644 --- a/package.json +++ b/package.json @@ -145,7 +145,7 @@ "language-mustache": "0.11.0", "language-objective-c": "0.15.0", "language-perl": "0.26.0", - "language-php": "0.25.0", + "language-php": "0.26.0", "language-property-list": "0.8.0", "language-python": "0.36.0", "language-ruby": "0.56.0", From 9aa78606b326cfbe0e82acff388230f76b2c5987 Mon Sep 17 00:00:00 2001 From: Ivan Zuzak Date: Mon, 22 Jun 2015 18:47:41 +0200 Subject: [PATCH 1749/1783] Catch both string and object targets --- src/command-registry.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/command-registry.coffee b/src/command-registry.coffee index a9b953536..870093e2f 100644 --- a/src/command-registry.coffee +++ b/src/command-registry.coffee @@ -92,10 +92,10 @@ class CommandRegistry disposable.add @add(target, commandName, callback) return disposable - if typeof target is 'string' - if typeof callback isnt 'function' - throw new Error("Can't register a command with non-function callback.") + if typeof callback isnt 'function' + throw new Error("Can't register a command with non-function callback.") + if typeof target is 'string' validateSelector(target) @addSelectorBasedListener(target, commandName, callback) else From 326457d21b6a5f3bf74b6d11761db97e10edda51 Mon Sep 17 00:00:00 2001 From: Ivan Zuzak Date: Mon, 22 Jun 2015 18:55:08 +0200 Subject: [PATCH 1750/1783] Add test for object target case --- spec/command-registry-spec.coffee | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/spec/command-registry-spec.coffee b/spec/command-registry-spec.coffee index 799bceb8e..0a8cafa6b 100644 --- a/spec/command-registry-spec.coffee +++ b/spec/command-registry-spec.coffee @@ -158,15 +158,26 @@ describe "CommandRegistry", -> addError = error expect(addError.message).toContain(badSelector) - it "throws an error when called with an non-function callback", -> + it "throws an error when called with a non-function callback and selector target", -> badCallback = null addError = null + try registry.add '.selector', 'foo:bar', badCallback catch error addError = error expect(addError.message).toContain("Can't register a command with non-function callback.") + it "throws an error when called with an non-function callback and object target", -> + badCallback = null + addError = null + + try + registry.add document.body, 'foo:bar', badCallback + catch error + addError = error + expect(addError.message).toContain("Can't register a command with non-function callback.") + describe "::findCommands({target})", -> it "returns commands that can be invoked on the target or its ancestors", -> registry.add '.parent', 'namespace:command-1', -> From 9de1f3daff65df8b477ac65a3d1d0aa206d9cd4b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 22 Jun 2015 10:11:04 -0700 Subject: [PATCH 1751/1783] :arrow_up: legal-eagle@0.10 Closes atom/atom#7366 --- build/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/package.json b/build/package.json index c60bdbae5..c02ff68aa 100644 --- a/build/package.json +++ b/build/package.json @@ -25,7 +25,7 @@ "grunt-peg": "~1.1.0", "grunt-shell": "~0.3.1", "harmony-collections": "~0.3.8", - "legal-eagle": "~0.9.0", + "legal-eagle": "~0.10.0", "minidump": "~0.8", "npm": "2.5.1", "rcedit": "~0.3.0", From 0e932025d8e2c8e2166ca63d95e4b65f327e6296 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 22 Jun 2015 12:19:24 -0500 Subject: [PATCH 1752/1783] :arrow_up: exception-reporting --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a44a60319..70112b2e2 100644 --- a/package.json +++ b/package.json @@ -98,7 +98,7 @@ "deprecation-cop": "0.52.0", "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", - "exception-reporting": "0.25.0", + "exception-reporting": "0.26.0", "find-and-replace": "0.173.0", "fuzzy-finder": "0.87.0", "git-diff": "0.55.0", From b7a8ddd1532a019843ea6619f22046ebccd271a1 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 22 Jun 2015 14:27:05 -0500 Subject: [PATCH 1753/1783] Revert "Add assertion mechanism" --- package.json | 2 +- spec/atom-spec.coffee | 74 +++++++------------------------------ src/atom.coffee | 57 ++++++++++------------------ src/tokenized-buffer.coffee | 12 +----- 4 files changed, 35 insertions(+), 110 deletions(-) diff --git a/package.json b/package.json index 70112b2e2..135c8d2c0 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "link": "0.30.0", "markdown-preview": "0.150.0", "metrics": "0.51.0", - "notifications": "0.57.0", + "notifications": "0.56.0", "open-on-github": "0.37.0", "package-generator": "0.39.0", "release-notes": "0.53.0", diff --git a/spec/atom-spec.coffee b/spec/atom-spec.coffee index c8c4a598f..99a7f432e 100644 --- a/spec/atom-spec.coffee +++ b/spec/atom-spec.coffee @@ -86,13 +86,13 @@ describe "the `atom` global", -> error = e window.onerror.call(window, e.toString(), 'abc', 2, 3, e) - expect(willThrowSpy).toHaveBeenCalledWith(error) - - # Deprecated event properties - expect(error.url).toBe 'abc' - expect(error.line).toBe 2 - expect(error.column).toBe 3 - expect(error.originalError).toBe error + delete willThrowSpy.mostRecentCall.args[0].preventDefault + expect(willThrowSpy).toHaveBeenCalledWith + message: error.toString() + url: 'abc' + line: 2 + column: 3 + originalError: error it "will not show the devtools when preventDefault() is called", -> willThrowSpy.andCallFake (errorObject) -> errorObject.preventDefault() @@ -120,60 +120,12 @@ describe "the `atom` global", -> catch e error = e window.onerror.call(window, e.toString(), 'abc', 2, 3, e) - - expect(didThrowSpy).toHaveBeenCalledWith(error) - - # Deprecated event properties - expect(error.url).toBe 'abc' - expect(error.line).toBe 2 - expect(error.column).toBe 3 - expect(error.originalError).toBe error - - it "will not show the devtools when preventDefault() is called", -> - didThrowSpy.andCallFake (errorObject) -> errorObject.preventDefault() - atom.onDidThrowError(didThrowSpy) - - try - a + 1 - catch e - window.onerror.call(window, e.toString(), 'abc', 2, 3, e) - - expect(didThrowSpy).toHaveBeenCalled() - expect(atom.openDevTools).not.toHaveBeenCalled() - expect(atom.executeJavaScriptInDevTools).not.toHaveBeenCalled() - - describe ".assert(condition, message, metadata)", -> - errors = null - - beforeEach -> - errors = [] - atom.onDidFailAssertion (error) -> errors.push(error) - - describe "if the condition is false", -> - it "notifies onDidFailAssertion handlers with an error object based on the call site of the assertion", -> - result = atom.assert(false, "a == b") - expect(result).toBe false - expect(errors.length).toBe 1 - expect(errors[0].message).toBe "Assertion failed: a == b" - expect(errors[0].stack).toContain('atom-spec') - - describe "if metadata is an object", -> - it "assigns the object on the error as `metadata`", -> - metadata = {foo: 'bar'} - atom.assert(false, "a == b", metadata) - expect(errors[0].metadata).toBe metadata - - describe "if metadata is a function", -> - it "assigns the function's return value on the error as `metadata`", -> - metadata = {foo: 'bar'} - atom.assert(false, "a == b", -> metadata) - expect(errors[0].metadata).toBe metadata - - describe "if the condition is true", -> - it "does nothing", -> - result = atom.assert(true, "a == b") - expect(result).toBe true - expect(errors).toEqual [] + expect(didThrowSpy).toHaveBeenCalledWith + message: error.toString() + url: 'abc' + line: 2 + column: 3 + originalError: error describe "saving and loading", -> afterEach -> atom.mode = "spec" diff --git a/src/atom.coffee b/src/atom.coffee index 0704f0bfb..316c51e29 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -198,31 +198,28 @@ class Atom extends Model initialize: -> sourceMapCache = {} - window.onerror = (message, url, line, column, error) => - @lastUncaughtError = error + window.onerror = => + @lastUncaughtError = Array::slice.call(arguments) + [message, url, line, column, originalError] = @lastUncaughtError - # TODO: These should be deprecated for 2.0 once we transition the - # exception-reporting package to the new API. - error ?= {} - error.message ?= message - error.url = url - error.line = line - error.column = column - error.originalError = error + convertedLine = convertLine(url, line, column, sourceMapCache) + {line, column} = convertedLine if convertedLine? + originalError.stack = convertStackTrace(originalError.stack, sourceMapCache) if originalError + + eventObject = {message, url, line, column, originalError} openDevTools = true - error.preventDefault = -> openDevTools = false + eventObject.preventDefault = -> openDevTools = false - # TODO: Deprecate onWillThrowError once we transition the notifications - # package to use onDidThrowError instead. - @emitter.emit 'will-throw-error', error - @emit 'uncaught-error', arguments... if includeDeprecatedAPIs - @emitter.emit 'did-throw-error', error + @emitter.emit 'will-throw-error', eventObject if openDevTools @openDevTools() @executeJavaScriptInDevTools('DevToolsAPI.showConsole()') + @emit 'uncaught-error', arguments... if includeDeprecatedAPIs + @emitter.emit 'did-throw-error', {message, url, line, column, originalError} + @disposables?.dispose() @disposables = new CompositeDisposable @@ -324,16 +321,18 @@ class Atom extends Model # Extended: Invoke the given callback whenever there is an unhandled error. # - # * `callback` {Function} to be called whenever there is an unhandled error. - # * `error` The unhandled {Error} object. + # * `callback` {Function} to be called whenever there is an unhandled error + # * `event` {Object} + # * `originalError` {Object} the original error object + # * `message` {String} the original error object + # * `url` {String} Url to the file where the error originated. + # * `line` {Number} + # * `column` {Number} # # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. onDidThrowError: (callback) -> @emitter.on 'did-throw-error', callback - onDidFailAssertion: (callback) -> - @emitter.on 'did-fail-assertion', callback - ### Section: Atom Details ### @@ -716,22 +715,6 @@ class Atom extends Model Section: Private ### - assert: (condition, message, metadata) -> - return true if condition - - error = new Error("Assertion failed: " + message) - Error.captureStackTrace(error, @assert) - - if metadata? - if typeof metadata is 'function' - error.metadata = metadata() - else - error.metadata = metadata - - @emitter.emit 'did-fail-assertion', error - - false - deserializeProject: -> Project = require './project' diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index bbb6b3748..7fb21937d 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -292,17 +292,7 @@ class TokenizedBuffer extends Model # Returns a {Boolean} indicating whether the given buffer row starts # a a foldable row range due to the code's indentation patterns. isFoldableCodeAtRow: (row) -> - # Investigating an exception that's occurring here due to the line being - # undefined. This should paper over the problem but we want to figure out - # what is happening: - tokenizedLine = @tokenizedLineForRow(row) - atom.assert tokenizedLine?, "TokenizedLine is defined", => - metadata: - row: row - rowCount: @tokenizedLines.length - return false unless tokenizedLine? - - return false if @buffer.isRowBlank(row) or tokenizedLine.isComment() + return false if @buffer.isRowBlank(row) or @tokenizedLineForRow(row).isComment() nextRow = @buffer.nextNonBlankRow(row) return false unless nextRow? From efd518ecb39a7588e5f04b7e2e9e19416a888d2f Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 22 Jun 2015 14:27:46 -0500 Subject: [PATCH 1754/1783] :arrow_down: exception-reporting --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 70112b2e2..a44a60319 100644 --- a/package.json +++ b/package.json @@ -98,7 +98,7 @@ "deprecation-cop": "0.52.0", "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", - "exception-reporting": "0.26.0", + "exception-reporting": "0.25.0", "find-and-replace": "0.173.0", "fuzzy-finder": "0.87.0", "git-diff": "0.55.0", From 1aab5e74d962bb6160a9844300c596234940a169 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 22 Jun 2015 14:48:28 -0500 Subject: [PATCH 1755/1783] :arrow_up: find-and-replace --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a44a60319..605388378 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", "exception-reporting": "0.25.0", - "find-and-replace": "0.173.0", + "find-and-replace": "0.174.0", "fuzzy-finder": "0.87.0", "git-diff": "0.55.0", "go-to-line": "0.30.0", From 8de583b3571e381f55ebce292bd301cf404a0074 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 22 Jun 2015 13:32:48 -0700 Subject: [PATCH 1756/1783] Prepare 0.212 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4c0dde1a2..7b0274aeb 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "0.211.0", + "version": "0.212.0", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From 8384fdbaf382aa678dfe39d39388323ec3476b2c Mon Sep 17 00:00:00 2001 From: Bo Lopker Date: Tue, 23 Jun 2015 02:12:02 -0700 Subject: [PATCH 1757/1783] Correct Fedora 22 install instructions --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 93fe03c8b..18d4e78ab 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ repeat these steps to upgrade to future releases. Currently only a 64-bit version is available. 1. Download `atom.x86_64.rpm` from the [Atom releases page](https://github.com/atom/atom/releases/latest). -2. Run `sudo dnf atom.x86_64.rpm` on the downloaded package. +2. Run `sudo dnf install atom.x86_64.rpm` on the downloaded package. 3. Launch Atom using the installed `atom` command. The Linux version does not currently automatically update so you will need to From 6527400bae13cff97f06fe1ce9edcd80703f4b13 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 24 Jun 2015 12:06:46 -0500 Subject: [PATCH 1758/1783] :arrow_up: language-todo@0.25 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7b0274aeb..2ef1addaf 100644 --- a/package.json +++ b/package.json @@ -155,7 +155,7 @@ "language-source": "0.9.0", "language-sql": "0.17.0", "language-text": "0.7.0", - "language-todo": "0.24.0", + "language-todo": "0.25.0", "language-toml": "0.16.0", "language-xml": "0.30.0", "language-yaml": "0.22.0" From e82d6461ec5319b5e5774d2fa59fc1608af62e82 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 18 Jun 2015 08:53:49 -0700 Subject: [PATCH 1759/1783] Prepare 1.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2ef1addaf..bbf3974ce 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "0.212.0", + "version": "1.0.0", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From 40534fa6d73af616ca55a2a861be798583fc3c0c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 22 Jun 2015 09:41:16 -0700 Subject: [PATCH 1760/1783] Remove 1.0 roadmap link from README --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 18d4e78ab..13f7374f2 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,6 @@ Visit [atom.io](https://atom.io) to learn more or visit the [Atom forum](https:/ Follow [@AtomEditor](https://twitter.com/atomeditor) on Twitter for important announcements. -Visit [issue #3684](https://github.com/atom/atom/issues/3684) to learn more -about the Atom 1.0 roadmap. - ## Documentation If you want to read about using Atom or developing packages in Atom, the [Atom Flight Manual](https://atom.io/docs/latest/) is free and available online, along with ePub, PDF and mobi versions. You can find the source to the manual in [atom/docs](https://github.com/atom/docs). From 367322ef26269e91249a1c9f10e73426123f5900 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 22 Jun 2015 09:42:17 -0700 Subject: [PATCH 1761/1783] Remove react/reactionary --- exports/atom.coffee | 8 -------- package.json | 2 -- 2 files changed, 10 deletions(-) diff --git a/exports/atom.coffee b/exports/atom.coffee index 67cd23741..5a3d9673e 100644 --- a/exports/atom.coffee +++ b/exports/atom.coffee @@ -120,14 +120,6 @@ unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE """ require '../src/select-list-view' - Object.defineProperty module.exports, 'React', get: -> - deprecate "Please require `react-atom-fork` instead: `React = require 'react-atom-fork'`. Add `\"react-atom-fork\": \"^0.11\"` to your package dependencies." - require 'react-atom-fork' - - Object.defineProperty module.exports, 'Reactionary', get: -> - deprecate "Please require `reactionary-atom-fork` instead: `Reactionary = require 'reactionary-atom-fork'`. Add `\"reactionary-atom-fork\": \"^0.9\"` to your package dependencies." - require 'reactionary-atom-fork' - if includeDeprecatedAPIs Object.defineProperty module.exports, 'Git', get: -> deprecate "Please require `GitRepository` instead of `Git`: `{GitRepository} = require 'atom'`" diff --git a/package.json b/package.json index bbf3974ce..e1bbac5fe 100644 --- a/package.json +++ b/package.json @@ -51,8 +51,6 @@ "property-accessors": "^1.1.3", "q": "^1.1.2", "random-words": "0.0.1", - "react-atom-fork": "^0.11.5", - "reactionary-atom-fork": "^1.0.0", "runas": "2.0.0", "scandal": "2.0.3", "scoped-property-store": "^0.17.0", From 0fa514b6e1c740ae45915878f698378d2f35cca7 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 22 Jun 2015 09:45:42 -0700 Subject: [PATCH 1762/1783] Remove open with deprecated APIs commands --- src/browser/atom-application.coffee | 2 -- src/workspace-element.coffee | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index b35bd5b5b..907828b6f 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -172,8 +172,6 @@ class AtomApplication @on 'application:open-folder', -> @promptForPathToOpen('folder', getLoadSettings()) @on 'application:open-dev', -> @promptForPathToOpen('all', devMode: true) @on 'application:open-safe', -> @promptForPathToOpen('all', safeMode: true) - @on 'application:open-with-deprecated-apis', -> @promptForPathToOpen('all', includeDeprecatedAPIs: true) - @on 'application:open-dev-with-deprecated-apis', -> @promptForPathToOpen('all', {includeDeprecatedAPIs: true, devMode: true}) @on 'application:inspect', ({x, y, atomWindow}) -> atomWindow ?= @focusedWindow() atomWindow?.browserWindow.inspectElement(x, y) diff --git a/src/workspace-element.coffee b/src/workspace-element.coffee index 6a276a7fc..028a6e561 100644 --- a/src/workspace-element.coffee +++ b/src/workspace-element.coffee @@ -140,8 +140,6 @@ atom.commands.add 'atom-workspace', 'application:open-folder': -> ipc.send('command', 'application:open-folder') 'application:open-dev': -> ipc.send('command', 'application:open-dev') 'application:open-safe': -> ipc.send('command', 'application:open-safe') - 'application:open-with-deprecated-apis': -> ipc.send('command', 'application:open-with-deprecated-apis') - 'application:open-dev-with-deprecated-apis': -> ipc.send('command', 'application:open-dev-with-deprecated-apis') 'application:add-project-folder': -> atom.addProjectFolder() 'application:minimize': -> ipc.send('command', 'application:minimize') 'application:zoom': -> ipc.send('command', 'application:zoom') From 85a4ae7fea820f5846edec4fc7438d089ef33b0b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 22 Jun 2015 09:48:25 -0700 Subject: [PATCH 1763/1783] Remove --include-deprecated-apis command line option --- src/browser/atom-application.coffee | 35 +++++++++++++---------------- src/browser/atom-window.coffee | 3 +-- src/browser/main.coffee | 4 +--- static/index.js | 2 +- 4 files changed, 18 insertions(+), 26 deletions(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 907828b6f..29996f33d 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -61,7 +61,7 @@ class AtomApplication exit: (status) -> app.exit(status) constructor: (options) -> - {@resourcePath, @version, @devMode, @safeMode, @includeDeprecatedAPIs, @socketPath} = options + {@resourcePath, @version, @devMode, @safeMode, @socketPath} = options # Normalize to make sure drive letter case is consistent on Windows @resourcePath = path.normalize(@resourcePath) if @resourcePath @@ -86,16 +86,16 @@ class AtomApplication else @loadState() or @openPath(options) - openWithOptions: ({pathsToOpen, urlsToOpen, test, pidToKillWhenClosed, devMode, safeMode, includeDeprecatedAPIs, newWindow, specDirectory, logFile, profileStartup}) -> + openWithOptions: ({pathsToOpen, urlsToOpen, test, pidToKillWhenClosed, devMode, safeMode, newWindow, specDirectory, logFile, profileStartup}) -> if test - @runSpecs({exitWhenDone: true, @resourcePath, specDirectory, logFile, includeDeprecatedAPIs}) + @runSpecs({exitWhenDone: true, @resourcePath, specDirectory, logFile}) else if pathsToOpen.length > 0 - @openPaths({pathsToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, includeDeprecatedAPIs, profileStartup}) + @openPaths({pathsToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup}) else if urlsToOpen.length > 0 - @openUrl({urlToOpen, devMode, safeMode, includeDeprecatedAPIs}) for urlToOpen in urlsToOpen + @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, includeDeprecatedAPIs, profileStartup}) + @openPath({pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup}) # Public: Removes the {AtomWindow} from the global window list. removeWindow: (window) -> @@ -160,7 +160,6 @@ class AtomApplication getLoadSettings = => devMode: @focusedWindow()?.devMode safeMode: @focusedWindow()?.safeMode - includeDeprecatedAPIs: @focusedWindow()?.includeDeprecatedAPIs @on 'application:run-all-specs', -> @runSpecs(exitWhenDone: false, resourcePath: global.devResourcePath, safeMode: @focusedWindow()?.safeMode) @on 'application:run-benchmarks', -> @runBenchmarks() @@ -229,7 +228,7 @@ class AtomApplication app.on 'open-url', (event, urlToOpen) => event.preventDefault() - @openUrl({urlToOpen, @devMode, @safeMode, @includeDeprecatedAPIs}) + @openUrl({urlToOpen, @devMode, @safeMode}) app.on 'activate-with-no-open-windows', (event) => event.preventDefault() @@ -356,11 +355,10 @@ class AtomApplication # :newWindow - Boolean of whether this should be opened in a new window. # :devMode - Boolean to control the opened window's dev mode. # :safeMode - Boolean to control the opened window's safe mode. - # :includeDeprecatedAPIs - Boolean to control the opened window's included deprecated APIs. # :profileStartup - Boolean to control creating a profile of the startup time. # :window - {AtomWindow} to open file paths in. - openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, includeDeprecatedAPIs, profileStartup, window}) -> - @openPaths({pathsToOpen: [pathToOpen], pidToKillWhenClosed, newWindow, devMode, safeMode, includeDeprecatedAPIs, profileStartup, window}) + openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, window}) -> + @openPaths({pathsToOpen: [pathToOpen], pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, window}) # Public: Opens multiple paths, in existing windows if possible. # @@ -370,10 +368,9 @@ class AtomApplication # :newWindow - Boolean of whether this should be opened in a new window. # :devMode - Boolean to control the opened window's dev mode. # :safeMode - Boolean to control the opened window's safe mode. - # :includeDeprecatedAPIs - Boolean to control the opened window's included deprecated APIs. # :windowDimensions - Object with height and width keys. # :window - {AtomWindow} to open file paths in. - openPaths: ({pathsToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, includeDeprecatedAPIs, windowDimensions, profileStartup, window}={}) -> + openPaths: ({pathsToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, windowDimensions, profileStartup, window}={}) -> pathsToOpen = pathsToOpen.map (pathToOpen) -> if fs.existsSync(pathToOpen) fs.normalize(pathToOpen) @@ -408,7 +405,7 @@ class AtomApplication bootstrapScript ?= require.resolve('../window-bootstrap') resourcePath ?= @resourcePath - openedWindow = new AtomWindow({locationsToOpen, bootstrapScript, resourcePath, devMode, safeMode, includeDeprecatedAPIs, windowDimensions, profileStartup}) + openedWindow = new AtomWindow({locationsToOpen, bootstrapScript, resourcePath, devMode, safeMode, windowDimensions, profileStartup}) if pidToKillWhenClosed? @pidsToOpenWindows[pidToKillWhenClosed] = openedWindow @@ -455,7 +452,6 @@ class AtomApplication urlsToOpen: [] devMode: @devMode safeMode: @safeMode - includeDeprecatedAPIs: @includeDeprecatedAPIs }) true else @@ -501,7 +497,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. - runSpecs: ({exitWhenDone, resourcePath, specDirectory, logFile, safeMode, includeDeprecatedAPIs}) -> + runSpecs: ({exitWhenDone, resourcePath, specDirectory, logFile, safeMode}) -> if resourcePath isnt @resourcePath and not fs.existsSync(resourcePath) resourcePath = @resourcePath @@ -513,8 +509,7 @@ class AtomApplication isSpec = true devMode = true safeMode ?= false - includeDeprecatedAPIs ?= true - new AtomWindow({bootstrapScript, resourcePath, exitWhenDone, isSpec, devMode, specDirectory, logFile, safeMode, includeDeprecatedAPIs}) + new AtomWindow({bootstrapScript, resourcePath, exitWhenDone, isSpec, devMode, specDirectory, logFile, safeMode}) runBenchmarks: ({exitWhenDone, specDirectory}={}) -> try @@ -557,9 +552,9 @@ class AtomApplication # :safeMode - A Boolean which controls whether any newly opened windows # should be in safe mode or not. # :window - An {AtomWindow} to use for opening a selected file path. - promptForPathToOpen: (type, {devMode, safeMode, includeDeprecatedAPIs, window}) -> + promptForPathToOpen: (type, {devMode, safeMode, window}) -> @promptForPath type, (pathsToOpen) => - @openPaths({pathsToOpen, devMode, safeMode, includeDeprecatedAPIs, window}) + @openPaths({pathsToOpen, devMode, safeMode, window}) promptForPath: (type, callback) -> properties = diff --git a/src/browser/atom-window.coffee b/src/browser/atom-window.coffee index eaa58ffa5..f20e69c5a 100644 --- a/src/browser/atom-window.coffee +++ b/src/browser/atom-window.coffee @@ -18,7 +18,7 @@ class AtomWindow isSpec: null constructor: (settings={}) -> - {@resourcePath, pathToOpen, locationsToOpen, @isSpec, @exitWhenDone, @safeMode, @devMode, @includeDeprecatedAPIs} = settings + {@resourcePath, pathToOpen, locationsToOpen, @isSpec, @exitWhenDone, @safeMode, @devMode} = settings locationsToOpen ?= [{pathToOpen}] if pathToOpen locationsToOpen ?= [] @@ -47,7 +47,6 @@ class AtomWindow loadSettings.resourcePath = @resourcePath loadSettings.devMode ?= false loadSettings.safeMode ?= false - loadSettings.includeDeprecatedAPIs ?= false # Only send to the first non-spec window created if @constructor.includeShellLoadTime and not @isSpec diff --git a/src/browser/main.coffee b/src/browser/main.coffee index eb08ebe61..392fd1995 100644 --- a/src/browser/main.coffee +++ b/src/browser/main.coffee @@ -137,7 +137,6 @@ parseCommandLine = -> executedFrom = args['executed-from'] devMode = args['dev'] safeMode = args['safe'] - includeDeprecatedAPIs = args['include-deprecated-apis'] pathsToOpen = args._ test = args['test'] specDirectory = args['spec-directory'] @@ -171,7 +170,6 @@ parseCommandLine = -> process.env.PATH = args['path-environment'] if args['path-environment'] {resourcePath, pathsToOpen, executedFrom, test, version, pidToKillWhenClosed, - devMode, includeDeprecatedAPIs, safeMode, newWindow, specDirectory, logFile, - socketPath, profileStartup} + devMode, safeMode, newWindow, specDirectory, logFile, socketPath, profileStartup} start() diff --git a/static/index.js b/static/index.js index 24c59c975..c0ee749eb 100644 --- a/static/index.js +++ b/static/index.js @@ -75,7 +75,7 @@ var setupWindow = function(loadSettings) { ModuleCache.register(loadSettings); ModuleCache.add(loadSettings.resourcePath); - require('grim').includeDeprecatedAPIs = !!loadSettings.includeDeprecatedAPIs; + require('grim').includeDeprecatedAPIs = false; // Start the crash reporter before anything else. require('crash-reporter').start({ From 0c4e052247c8891378a2517a5b696661220ce2af Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 22 Jun 2015 09:49:40 -0700 Subject: [PATCH 1764/1783] Remove --include-deprecated-apis from apm test commands --- build/tasks/spec-task.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/tasks/spec-task.coffee b/build/tasks/spec-task.coffee index 6f1476556..bfd5a8604 100644 --- a/build/tasks/spec-task.coffee +++ b/build/tasks/spec-task.coffee @@ -95,7 +95,7 @@ module.exports = (grunt) -> if process.platform in ['darwin', 'linux'] options = cmd: appPath - args: ['--test', "--resource-path=#{resourcePath}", "--spec-directory=#{coreSpecsPath}", '--include-deprecated-apis'] + args: ['--test', "--resource-path=#{resourcePath}", "--spec-directory=#{coreSpecsPath}"] opts: env: _.extend({}, process.env, ATOM_INTEGRATION_TESTS_ENABLED: true @@ -104,7 +104,7 @@ module.exports = (grunt) -> else if process.platform is 'win32' options = cmd: process.env.comspec - args: ['/c', appPath, '--test', "--resource-path=#{resourcePath}", "--spec-directory=#{coreSpecsPath}", '--log-file=ci.log', '--include-deprecated-apis'] + args: ['/c', appPath, '--test', "--resource-path=#{resourcePath}", "--spec-directory=#{coreSpecsPath}", '--log-file=ci.log'] opts: env: _.extend({}, process.env, ATOM_INTEGRATION_TESTS_ENABLED: true From 993d702ce986af14cfb76e588fe8d802fbc3753f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 22 Jun 2015 13:41:27 -0700 Subject: [PATCH 1765/1783] Include deprecated APIs when running core specs --- static/index.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/static/index.js b/static/index.js index c0ee749eb..8fe71a6a9 100644 --- a/static/index.js +++ b/static/index.js @@ -75,7 +75,8 @@ var setupWindow = function(loadSettings) { ModuleCache.register(loadSettings); ModuleCache.add(loadSettings.resourcePath); - require('grim').includeDeprecatedAPIs = false; + // Only include deprecated APIs when running core spec + require('grim').includeDeprecatedAPIs = isRunningCoreSpecs(loadSettings); // Start the crash reporter before anything else. require('crash-reporter').start({ @@ -219,6 +220,14 @@ var setupWindowBackground = function() { }, false); } +var isRunningCoreSpecs = function(loadSettings) { + return !!(loadSettings && + loadSettings.isSpec && + loadSettings.specDirectory && + loadSettings.resourcePath && + path.dirname(loadSettings.specDirectory) === loadSettings.resourcePath); +} + parseLoadSettings(); setupWindowBackground(); From 4d75175bdd8824a037cc626941420ec94d96ef3a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 22 Jun 2015 15:36:03 -0700 Subject: [PATCH 1766/1783] :arrow_up: apm@1.0.0 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index bb9fd4647..66462db4e 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "0.171.0" + "atom-package-manager": "1.0.0" } } From 3e1c18ed409d97ad209cab8b223071dd64ee5ba6 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 22 Jun 2015 15:36:49 -0700 Subject: [PATCH 1767/1783] :arrow_up: apm@1.0.1 --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index 66462db4e..d1f210f29 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.0.0" + "atom-package-manager": "1.0.1" } } From 38745761e2b67d613d7104808a5c8f50b0abf474 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 25 Jun 2015 05:05:58 -0500 Subject: [PATCH 1768/1783] :arrow_up: pathwatcher@4.4.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e1bbac5fe..2f9289ded 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "normalize-package-data": "^2.0.0", "nslog": "^2.0.0", "oniguruma": "^4.1", - "pathwatcher": "^4.4", + "pathwatcher": "^4.4.1", "property-accessors": "^1.1.3", "q": "^1.1.2", "random-words": "0.0.1", From 2ff8f90608d0b493748530a2607a195283c6cac6 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 25 Jun 2015 09:40:30 -0500 Subject: [PATCH 1769/1783] Prepare 1.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2f9289ded..0f56d7962 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "1.0.0", + "version": "1.0.1", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From f30e352f6f2dae5c60cfd932c841dc6682082732 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 25 Jun 2015 13:19:14 -0500 Subject: [PATCH 1770/1783] :arrow_up: deprecation-cop@0.53 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0f56d7962..dd7b53893 100644 --- a/package.json +++ b/package.json @@ -93,7 +93,7 @@ "bookmarks": "0.35.0", "bracket-matcher": "0.76.0", "command-palette": "0.36.0", - "deprecation-cop": "0.52.0", + "deprecation-cop": "0.53.0", "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", "exception-reporting": "0.25.0", From 77d7e7a69ffe3b6457dfd581ac3c7e4baeb0c4d3 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 25 Jun 2015 13:20:27 -0500 Subject: [PATCH 1771/1783] :arrow_up: settings-view@0.209 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dd7b53893..9fbe029ae 100644 --- a/package.json +++ b/package.json @@ -112,7 +112,7 @@ "open-on-github": "0.37.0", "package-generator": "0.39.0", "release-notes": "0.53.0", - "settings-view": "0.208.0", + "settings-view": "0.209.0", "snippets": "0.95.0", "spell-check": "0.59.0", "status-bar": "0.74.0", From 3a3e4c1eb9e05a4c4ad34f7e7a6d0712afddb252 Mon Sep 17 00:00:00 2001 From: Andrew Burkett Date: Thu, 25 Jun 2015 16:12:30 -0700 Subject: [PATCH 1772/1783] Fix Arch build instructions --- docs/build-instructions/linux.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/build-instructions/linux.md b/docs/build-instructions/linux.md index 7b81786b7..4874489ab 100644 --- a/docs/build-instructions/linux.md +++ b/docs/build-instructions/linux.md @@ -30,7 +30,7 @@ Ubuntu LTS 12.04 64-bit is the recommended platform. ### Arch * `sudo pacman -S gconf base-devel git nodejs libgnome-keyring python2` -* `export python=/usr/bin/python2` before building Atom. +* `export PYTHON=/usr/bin/python2` before building Atom. ### Slackware From 13272728a2bf3b5aa08cd664efe7755d95d07fc4 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 26 Jun 2015 09:34:03 -0500 Subject: [PATCH 1773/1783] :arrow_up: language-python@0.37 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9fbe029ae..66b9d2b5d 100644 --- a/package.json +++ b/package.json @@ -145,7 +145,7 @@ "language-perl": "0.26.0", "language-php": "0.26.0", "language-property-list": "0.8.0", - "language-python": "0.36.0", + "language-python": "0.37.0", "language-ruby": "0.56.0", "language-ruby-on-rails": "0.22.0", "language-sass": "0.39.0", From 85879ffdb5b1975ed5208300bc43bc71695d3c98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Cascos?= Date: Mon, 29 Jun 2015 01:38:25 +0200 Subject: [PATCH 1774/1783] Update license in package.json --- package.json | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/package.json b/package.json index 66b9d2b5d..923cad95d 100644 --- a/package.json +++ b/package.json @@ -11,12 +11,7 @@ "bugs": { "url": "https://github.com/atom/atom/issues" }, - "licenses": [ - { - "type": "MIT", - "url": "http://github.com/atom/atom/raw/master/LICENSE.md" - } - ], + "license": "MIT", "atomShellVersion": "0.22.3", "dependencies": { "async": "0.2.6", From 9c4dd71de2c8e4efc220ffe3a0c9c51bee87b062 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 29 Jun 2015 13:30:37 -0700 Subject: [PATCH 1775/1783] Remove deferred browser process requires --- src/browser/atom-application.coffee | 3 +-- src/browser/atom-window.coffee | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 29996f33d..6b2651ac1 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -273,9 +273,8 @@ class AtomApplication ipc.on 'cancel-window-close', => @quitting = false - clipboard = null + clipboard = require '../safe-clipboard' ipc.on 'write-text-to-selection-clipboard', (event, selectedText) -> - clipboard ?= require '../safe-clipboard' clipboard.writeText(selectedText, 'selection') # Public: Executes the given command. diff --git a/src/browser/atom-window.coffee b/src/browser/atom-window.coffee index f20e69c5a..7b0b2cb85 100644 --- a/src/browser/atom-window.coffee +++ b/src/browser/atom-window.coffee @@ -93,10 +93,9 @@ class AtomWindow hasProjectPath: -> @getLoadSettings().initialPaths?.length > 0 setupContextMenu: -> - ContextMenu = null + ContextMenu = require './context-menu' @browserWindow.on 'context-menu', (menuTemplate) => - ContextMenu ?= require './context-menu' new ContextMenu(menuTemplate, this) containsPaths: (paths) -> From b6d099ac7823f4d52500d521eb948b999a2b4925 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 29 Jun 2015 17:05:28 -0500 Subject: [PATCH 1776/1783] Consider tabs or spaces mutually exclusively as indentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, we allowed a mix of tabs and spaces to be counted toward the indentation of a line. This caused problems when auto-indenting lines in a hard-tabbed file that contained “alignment spaces”, such as occurs in aligned comment blocks. For this case, it makes more sense to assume that the line is indented via tabs only, and consider the subsequent alignment space as part of the line’s content. Since it’s hard to imagine actual source code in which a mixed treatment of tabs and spaces is desirable, I’m going with this over any more complex approach. --- spec/text-editor-spec.coffee | 25 ++++++++++++++++++++----- src/selection.coffee | 2 +- src/tokenized-buffer.coffee | 9 ++++----- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 128fa5235..f20184e01 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -2943,6 +2943,20 @@ describe "TextEditor", -> expect(editor.lineTextForBufferRow(7)).toBe " c(x);" expect(editor.lineTextForBufferRow(8)).toBe " current = items.shift();" + it "auto-indents lines with a mix of hard tabs and spaces without removing spaces", -> + editor.setSoftTabs(false) + expect(editor.indentationForBufferRow(5)).toBe(3) + + atom.clipboard.write("/**\n\t * testing\n\t * indent\n\t **/\n", indentBasis: 1) + editor.setCursorBufferPosition([5, 0]) + editor.pasteText() + + # Do not lose the alignment spaces + expect(editor.lineTextForBufferRow(5)).toBe("\t\t\t/**") + expect(editor.lineTextForBufferRow(6)).toBe("\t\t\t * testing") + expect(editor.lineTextForBufferRow(7)).toBe("\t\t\t * indent") + expect(editor.lineTextForBufferRow(8)).toBe("\t\t\t **/") + describe "when pasting a single line of text", -> it "does not auto-indent the text", -> atom.clipboard.write("a(x);", indentBasis: 0) @@ -3692,11 +3706,12 @@ describe "TextEditor", -> it "returns the indent level when the line has only leading tabs", -> expect(editor.indentLevelForLine("\t\thello")).toBe(2) - it "returns the indent level when the line has mixed leading whitespace and tabs", -> - expect(editor.indentLevelForLine("\t hello")).toBe(2) - expect(editor.indentLevelForLine(" \thello")).toBe(2) - expect(editor.indentLevelForLine(" \t hello")).toBe(2.5) - expect(editor.indentLevelForLine(" \t \thello")).toBe(3.5) + it "returns the indent level based on the character starting the line when the leading whitespace contains both spaces and tabs", -> + expect(editor.indentLevelForLine("\t hello")).toBe(1) + expect(editor.indentLevelForLine(" \thello")).toBe(1) + expect(editor.indentLevelForLine(" \t hello")).toBe(1) + expect(editor.indentLevelForLine(" \t \thello")).toBe(2) + expect(editor.indentLevelForLine(" \t \thello")).toBe(2.5) describe "when the buffer is reloaded", -> it "preserves the current cursor position", -> diff --git a/src/selection.coffee b/src/selection.coffee index 6a4d4726f..3f7878195 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -622,7 +622,7 @@ class Selection extends Model else currentIndentLevel = @editor.indentLevelForLine(lines[i]) indentLevel = Math.max(0, currentIndentLevel + indentAdjustment) - lines[i] = line.replace(/^[\t ]+/, @editor.buildIndentString(indentLevel)) + lines[i] = line.replace(/^(\t+| +)/, @editor.buildIndentString(indentLevel)) return # Indent the current line(s). diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 7fb21937d..c764c1a1f 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -411,11 +411,10 @@ class TokenizedBuffer extends Model @indentLevelForLine(line) indentLevelForLine: (line) -> - if match = line.match(/^[\t ]+/) - leadingWhitespace = match[0] - tabCount = leadingWhitespace.match(/\t/g)?.length ? 0 - spaceCount = leadingWhitespace.match(/[ ]/g)?.length ? 0 - tabCount + (spaceCount / @getTabLength()) + if match = line.match(/^\t+/) + match[0].length + else if match = line.match(/^ +/) + match[0].length / @getTabLength() else 0 From 5fcdb8fdf41b114ec7d140904edf31047db0cbb3 Mon Sep 17 00:00:00 2001 From: Nicklas Gummesson Date: Tue, 30 Jun 2015 08:43:17 +0200 Subject: [PATCH 1777/1783] :arrow_up: tree-view@0.173.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 923cad95d..96b86594b 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,7 @@ "symbols-view": "0.99.0", "tabs": "0.81.0", "timecop": "0.31.0", - "tree-view": "0.172.0", + "tree-view": "0.173.0", "update-package-dependencies": "0.10.0", "welcome": "0.29.0", "whitespace": "0.30.0", From 6735357dd115d5f01d0732358fdf2d054abcb54c Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 30 Jun 2015 14:46:29 +0200 Subject: [PATCH 1778/1783] Retrieve `backgroundColor` from the correct object Thanks, @nathansobo! :sparkles: --- src/line-numbers-tile-component.coffee | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/line-numbers-tile-component.coffee b/src/line-numbers-tile-component.coffee index 155c9a23a..cf58c54f3 100644 --- a/src/line-numbers-tile-component.coffee +++ b/src/line-numbers-tile-component.coffee @@ -20,7 +20,7 @@ class LineNumbersTileComponent updateSync: (state) -> @newState = state unless @oldState - @oldState = {tiles: {}} + @oldState = {tiles: {}, styles: {}} @oldState.tiles[@id] = {lineNumbers: {}} @newTileState = @newState.tiles[@id] @@ -30,9 +30,9 @@ class LineNumbersTileComponent @domNode.style.display = @newTileState.display @oldTileState.display = @newTileState.display - if @newState.backgroundColor isnt @oldState.backgroundColor - @domNode.style.backgroundColor = @newState.backgroundColor - @oldState.backgroundColor = @newState.backgroundColor + if @newState.styles.backgroundColor isnt @oldState.styles.backgroundColor + @domNode.style.backgroundColor = @newState.styles.backgroundColor + @oldState.styles.backgroundColor = @newState.styles.backgroundColor if @newTileState.height isnt @oldTileState.height @domNode.style.height = @newTileState.height + 'px' From eb3e1437d046c075e1f44469c767a16a7103c1f8 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 30 Jun 2015 14:52:47 +0200 Subject: [PATCH 1779/1783] :white_check_mark: Add spec to check for tile background color --- spec/text-editor-component-spec.coffee | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index df632a3b3..358fd099f 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -271,16 +271,22 @@ describe "TextEditorComponent", -> atom.config.set("editor.showInvisibles", false) expect(component.lineNodeForScreenRow(10).textContent).toBe nbsp - it "gives the lines div the same background color as the editor to improve GPU performance", -> + it "gives the lines and tiles divs the same background color as the editor to improve GPU performance", -> linesNode = componentNode.querySelector('.lines') backgroundColor = getComputedStyle(wrapperNode).backgroundColor expect(linesNode.style.backgroundColor).toBe backgroundColor + for tileNode in linesNode.querySelectorAll(".tile") + expect(tileNode.style.backgroundColor).toBe(backgroundColor) + wrapperNode.style.backgroundColor = 'rgb(255, 0, 0)' advanceClock(atom.views.documentPollingInterval) nextAnimationFrame() expect(linesNode.style.backgroundColor).toBe 'rgb(255, 0, 0)' + for tileNode in linesNode.querySelectorAll(".tile") + expect(tileNode.style.backgroundColor).toBe("rgb(255, 0, 0)") + it "applies .leading-whitespace for lines with leading spaces and/or tabs", -> editor.setText(' a') @@ -690,12 +696,16 @@ describe "TextEditorComponent", -> lineNumbersNode = gutterNode.querySelector('.line-numbers') {backgroundColor} = getComputedStyle(wrapperNode) expect(lineNumbersNode.style.backgroundColor).toBe backgroundColor + for tileNode in lineNumbersNode.querySelectorAll(".tile") + expect(tileNode.style.backgroundColor).toBe(backgroundColor) # favor gutter color if it's assigned gutterNode.style.backgroundColor = 'rgb(255, 0, 0)' advanceClock(atom.views.documentPollingInterval) nextAnimationFrame() expect(lineNumbersNode.style.backgroundColor).toBe 'rgb(255, 0, 0)' + for tileNode in lineNumbersNode.querySelectorAll(".tile") + expect(tileNode.style.backgroundColor).toBe("rgb(255, 0, 0)") it "hides or shows the gutter based on the '::isLineNumberGutterVisible' property on the model and the global 'editor.showLineNumbers' config setting", -> expect(component.gutterContainerComponent.getLineNumberGutterComponent()?).toBe true From 67e968833344ad2c5186eb2856bfedc5231b591c Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 30 Jun 2015 10:33:53 -0700 Subject: [PATCH 1780/1783] :arrow_up: find-and-replace@0.174.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 96b86594b..aec3a9a5a 100644 --- a/package.json +++ b/package.json @@ -92,7 +92,7 @@ "dev-live-reload": "0.46.0", "encoding-selector": "0.20.0", "exception-reporting": "0.25.0", - "find-and-replace": "0.174.0", + "find-and-replace": "0.174.1", "fuzzy-finder": "0.87.0", "git-diff": "0.55.0", "go-to-line": "0.30.0", From 93931328f0ab7ffb88df1e41478a78d905d85651 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 30 Jun 2015 10:57:50 -0700 Subject: [PATCH 1781/1783] :arrow_up: solarized syntax themes. Thanks @schmittyjd --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index aec3a9a5a..1495d3d82 100644 --- a/package.json +++ b/package.json @@ -74,8 +74,8 @@ "one-dark-syntax": "0.7.1", "one-light-syntax": "0.7.0", "one-light-ui": "0.9.1", - "solarized-dark-syntax": "0.35.0", - "solarized-light-syntax": "0.21.0", + "solarized-dark-syntax": "0.38.0", + "solarized-light-syntax": "0.22.0", "archive-view": "0.58.0", "autocomplete-atom-api": "0.9.0", "autocomplete-css": "0.8.0", From ea11d19a1de37cf795468984261a8e1bfd5556cb Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 30 Jun 2015 15:03:18 -0500 Subject: [PATCH 1782/1783] Revert ":arrow_up: solarized syntax themes." This reverts commit 93931328f0ab7ffb88df1e41478a78d905d85651. --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 1495d3d82..aec3a9a5a 100644 --- a/package.json +++ b/package.json @@ -74,8 +74,8 @@ "one-dark-syntax": "0.7.1", "one-light-syntax": "0.7.0", "one-light-ui": "0.9.1", - "solarized-dark-syntax": "0.38.0", - "solarized-light-syntax": "0.22.0", + "solarized-dark-syntax": "0.35.0", + "solarized-light-syntax": "0.21.0", "archive-view": "0.58.0", "autocomplete-atom-api": "0.9.0", "autocomplete-css": "0.8.0", From c0132ea04ab5db830fed5d116de20787f71a33cb Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 30 Jun 2015 13:28:38 -0700 Subject: [PATCH 1783/1783] :arrow_up: tree-view@0.174 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index aec3a9a5a..8cca44bf7 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,7 @@ "symbols-view": "0.99.0", "tabs": "0.81.0", "timecop": "0.31.0", - "tree-view": "0.173.0", + "tree-view": "0.174.0", "update-package-dependencies": "0.10.0", "welcome": "0.29.0", "whitespace": "0.30.0",

CRB8PA}VNCX1zTI^&DR98RZ3spRqb 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