Comparar commits
157 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 7e59be6461 | |||
| 81422d71cb | |||
| fa242dca7a | |||
| 2ac15bad90 | |||
| 1e6e724be7 | |||
| 05e7e9fc1d | |||
| 80c354aad4 | |||
| aa5c09cf0b | |||
| d79ca646a8 | |||
| d8137cfcad | |||
| 12683571e3 | |||
| c0991447ff | |||
| f9fcb9f2e2 | |||
| 1daab1b956 | |||
| fc7f922de0 | |||
| 5f1f2cd9be | |||
| dca0576496 | |||
| aa7d8fb382 | |||
| 08f20adc35 | |||
| c5f1165f61 | |||
| 58499aeec7 | |||
| 83c73fc94a | |||
| b28a1aa5c7 | |||
| bcb72394f9 | |||
| efe7baf140 | |||
| 4b07103fcf | |||
| 9d60fd2322 | |||
| 71228a5f45 | |||
| 6b3ba8e332 | |||
| de619a731b | |||
| d2283b0567 | |||
| 2a00acfdaf | |||
| b2025ebad0 | |||
| 0b44cee8db | |||
| 5fed6199ec | |||
| ddc04f2278 | |||
| f64a813fc6 | |||
| 68bc3f6ead | |||
| ffbcddf063 | |||
| b341749d54 | |||
| d2ab75382a | |||
| b125565776 | |||
| 9cec02420c | |||
| 6f82281b8f | |||
| ffda2386c3 | |||
| aefc647155 | |||
| 83455a7f3a | |||
| d8f64c15b8 | |||
| c927e95c2c | |||
| 5b12646a44 | |||
| 68bb43ee7d | |||
| 4048fb978c | |||
| 2d885496a3 | |||
| 64222d3096 | |||
| 2c7bbf8e9f | |||
| a45e9a1e8b | |||
| 3fd5ba9b3c | |||
| eb0e3df720 | |||
| 60a49d9c81 | |||
| 43ccf0a041 | |||
| 1f6764e708 | |||
| 48f714d5fb | |||
| e2813b4dd9 | |||
| 41b3d65e05 | |||
| 1e50985ec7 | |||
| 1d6087fcd3 | |||
| f2e74f216c | |||
| b9950ef2df | |||
| 28eb03ed29 | |||
| 2843af458b | |||
| 163a7587f9 | |||
| 18f83e90f7 | |||
| 7094701c66 | |||
| d7d23f7fc9 | |||
| bdbc850695 | |||
| 4e0ab92827 | |||
| b662281958 | |||
| 4d2cc86ada | |||
| 19fcc1c441 | |||
| 1f5fa27113 | |||
| 362bd2e61a | |||
| 4cb80d3c7e | |||
| 7f108dab38 | |||
| cec5a83eff | |||
| a7c3c15885 | |||
| 1c16738969 | |||
| b4a456d911 | |||
| c92f805e6e | |||
| 859a4db242 | |||
| 3a94b70270 | |||
| 85d6689344 | |||
| e0726b0354 | |||
| 0abd25ad6f | |||
| 42522686d7 | |||
| 1e9a8b92f2 | |||
| dda2b2e893 | |||
| e04c05ffee | |||
| 8cb0197638 | |||
| 73763d3e41 | |||
| 9d1c3124ee | |||
| aaee54bd08 | |||
| 1ae8862a9c | |||
| f3dd757537 | |||
| 68693e3ca0 | |||
| e24a562387 | |||
| 9c6a5fb4fa | |||
| 25caaa92f1 | |||
| 78ee02f0c6 | |||
| e462fdc4ce | |||
| 96d8721c9e | |||
| 568151b1a5 | |||
| 3d6c9ee554 | |||
| d5d6422d28 | |||
| 8cf24bc7de | |||
| 5727865b94 | |||
| b95b86396e | |||
| d75c35285c | |||
| a7bc7c198d | |||
| d2f24615c1 | |||
| e4b942e991 | |||
| c9f8ffc749 | |||
| c2086eee0e | |||
| d5a66c590a | |||
| b374c1a11a | |||
| 509d16b65a | |||
| e8e13ca645 | |||
| 35f8e6a5a7 | |||
| 36a9ad7d90 | |||
| 6ff304094f | |||
| 0e51def6be | |||
| f366a67fee | |||
| f30f0de45e | |||
| 9e36cd705e | |||
| 2a5081f0e0 | |||
| 2c93b1459e | |||
| bf83fb7b10 | |||
| f4cc8c31b3 | |||
| e62ecbab6b | |||
| 4cef3bfef5 | |||
| 85fae83195 | |||
| f79b78054c | |||
| e803c06b28 | |||
| 1963a7f437 | |||
| 48eb5307e6 | |||
| 95d6ab1d4f | |||
| 9224c86452 | |||
| 0fa2b4426a | |||
| 1e4e59ad1c | |||
| 97a56574e0 | |||
| c06fefce14 | |||
| d4dee07b41 | |||
| f475552673 | |||
| 32f2a95f07 | |||
| d53d01d95b | |||
| 131522f93d | |||
| fc90a3c2ba | |||
| 382a06028c |
@@ -1,7 +1,8 @@
|
||||
require '../spec/spec-helper'
|
||||
|
||||
path = require 'path'
|
||||
{$, Point} = require 'atom'
|
||||
{$} = require '../src/space-pen-extensions'
|
||||
{Point} = require 'atom'
|
||||
_ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
Project = require '../src/project'
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
require './benchmark-helper'
|
||||
{$, _, WorkspaceView} = require 'atom'
|
||||
{$} = require '../src/space-pen-extensions'
|
||||
_ = require 'underscore-plus'
|
||||
{WorkspaceView} = require 'atom'
|
||||
TokenizedBuffer = require '../src/tokenized-buffer'
|
||||
|
||||
describe "editorView.", ->
|
||||
@@ -7,7 +9,7 @@ describe "editorView.", ->
|
||||
|
||||
beforeEach ->
|
||||
atom.workspaceViewParentSelector = '#jasmine-content'
|
||||
atom.workspaceView = atom.views.getView(atom.workspace).__spacePenView
|
||||
atom.workspaceView = atom.views.createView(atom.workspace).__spacePenView
|
||||
atom.workspaceView.attachToDom()
|
||||
|
||||
atom.workspaceView.width(1024)
|
||||
|
||||
@@ -11,32 +11,34 @@ value of a namespaced config key with `atom.config.get`:
|
||||
@showInvisibles() if atom.config.get "editor.showInvisibles"
|
||||
```
|
||||
|
||||
Or you can use the `::subscribe` with `atom.config.observe` to track changes
|
||||
from any view object.
|
||||
Or you can subscribe via `atom.config.observe` to track changes from any view
|
||||
object.
|
||||
|
||||
```coffeescript
|
||||
{View} = require 'space-pen'
|
||||
|
||||
class MyView extends View
|
||||
initialize: ->
|
||||
@subscribe atom.config.observe 'editor.fontSize', (newValue, {previous}) =>
|
||||
@adjustFontSize()
|
||||
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.
|
||||
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.
|
||||
|
||||
Subscriptions made with `::subscribe` are automatically canceled when the
|
||||
view is removed. You can cancel config subscriptions manually via the
|
||||
`off` method on the subscription object that `atom.config.observe` returns.
|
||||
|
||||
```coffeescript
|
||||
fontSizeSubscription = atom.config.observe 'editor.fontSize', (newValue, {previous}) =>
|
||||
@adjustFontSize()
|
||||
|
||||
# ... later on
|
||||
|
||||
fontSizeSubscription.off() # Stop observing
|
||||
```
|
||||
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
|
||||
|
||||
@@ -48,10 +50,9 @@ but you can programmatically write to it with `atom.config.set`:
|
||||
atom.config.set("core.showInvisibles", true)
|
||||
```
|
||||
|
||||
You can also use `setDefaults`, which will assign default values for keys that
|
||||
are always overridden by values assigned with `set`. Defaults are not written
|
||||
out to the the `config.json` file to prevent it from becoming cluttered.
|
||||
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].
|
||||
|
||||
```coffeescript
|
||||
atom.config.setDefaults("editor", fontSize: 18, showInvisibles: true)
|
||||
```
|
||||
[composite-disposable]: https://atom.io/docs/api/latest/CompositeDisposable
|
||||
[config-api]: https://atom.io/docs/api/latest/Config
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
# Globals
|
||||
|
||||
Atom exposes several services through singleton objects accessible via the
|
||||
`atom` global:
|
||||
|
||||
* atom
|
||||
* workspace:
|
||||
Manipulate and query the state of the user interface for the current
|
||||
window. Open editors, manipulate panes.
|
||||
* project:
|
||||
Access the directory associated with the current window. Load editors,
|
||||
perform project-wide searches, register custom openers for special file
|
||||
types.
|
||||
* config:
|
||||
Read, write, and observe user configuration settings.
|
||||
* keymap:
|
||||
Add and query the currently active keybindings.
|
||||
* deserializers:
|
||||
Deserialize instances from their state objects and register deserializers.
|
||||
* packages:
|
||||
Activate, deactivate, and query user packages.
|
||||
* themes:
|
||||
Activate, deactivate, and query user themes.
|
||||
* contextMenu:
|
||||
Register context menus.
|
||||
* menu:
|
||||
Register application menus.
|
||||
* pasteboard:
|
||||
Read from and write to the system pasteboard.
|
||||
* syntax:
|
||||
Assign and query syntactically-scoped properties.
|
||||
@@ -30,6 +30,8 @@ All requests that take parameters require `application/json`.
|
||||
Parameters:
|
||||
|
||||
- **page** (optional)
|
||||
- **sort** (optional, values: `created_at`, `updated_at`, `downloads`)
|
||||
- **direction** (optional, values: `asc`, `desc`)
|
||||
|
||||
Returns a list of all packages in the following format:
|
||||
```json
|
||||
@@ -57,6 +59,20 @@ Link: <https://www.atom.io/api/packages?page=1>; rel="self",
|
||||
<https://www.atom.io/api/packages?page=2>; rel="next"
|
||||
```
|
||||
|
||||
By default, results are sorted by download count, descending.
|
||||
|
||||
#### GET /api/packages/search
|
||||
|
||||
Parameters:
|
||||
|
||||
- **q** String query to search
|
||||
- **sort** (optional, values: `created_at`, `updated_at`, `downloads`)
|
||||
- **direction** (optional, values: `asc`, `desc`)
|
||||
|
||||
Returns a list of all packages in the same format as `/api/packages`.
|
||||
|
||||
By default, results sorted by relevance to search query.
|
||||
|
||||
### Showing package details
|
||||
|
||||
#### GET /api/packages/:package_name
|
||||
|
||||
@@ -40,7 +40,7 @@ package.json files have their own additions.
|
||||
- `main` (**Required**): the path to the CoffeeScript file that's the entry point
|
||||
to your package
|
||||
- `stylesheets` (**Optional**): an Array of Strings identifying the order of the
|
||||
stylesheets your package needs to load. If not specified, stylesheets in the
|
||||
style sheets your package needs to load. If not specified, style sheets in the
|
||||
_stylesheets_ 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
|
||||
@@ -119,27 +119,27 @@ Also, 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.
|
||||
|
||||
## Stylesheets
|
||||
## Style Sheets
|
||||
|
||||
Stylesheets for your package should be placed in the _stylesheets_ directory.
|
||||
Any stylesheets in this directory will be loaded and attached to the DOM when
|
||||
your package is activated. Stylesheets can be written as CSS or [LESS] (but LESS
|
||||
is recommended).
|
||||
Style sheets for your package should be placed in the _stylesheets_ 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`.
|
||||
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
|
||||
stylesheets. 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!
|
||||
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 stylesheets
|
||||
by name to specify a loading order; otherwise, stylesheets are loaded
|
||||
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
|
||||
@@ -157,9 +157,9 @@ 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.
|
||||
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.
|
||||
@@ -195,7 +195,8 @@ with your package that aren't tied to a specific element:
|
||||
```
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
@@ -118,7 +118,6 @@ You can open this file in an editor from the _Atom > Open Your Config_ menu.
|
||||
- `cr`: Carriage return (for Microsoft-style line endings)
|
||||
- `eol`: `\n` characters
|
||||
- `space`: Leading and trailing space characters
|
||||
- `normalizeIndentOnPaste`: Enable/disable conversion of pasted tabs to spaces
|
||||
- `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
|
||||
|
||||
@@ -6,6 +6,7 @@ module.exports =
|
||||
BufferedNodeProcess: require '../src/buffered-node-process'
|
||||
BufferedProcess: require '../src/buffered-process'
|
||||
GitRepository: require '../src/git-repository'
|
||||
Notification: require '../src/notification'
|
||||
Point: Point
|
||||
Range: Range
|
||||
Emitter: Emitter
|
||||
@@ -32,7 +33,8 @@ unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
|
||||
Object.defineProperty module.exports, 'WorkspaceView', get: ->
|
||||
deprecate """
|
||||
Requiring `WorkspaceView` from `atom` is no longer supported.
|
||||
Use `atom.view.getView(atom.workspace)` instead.
|
||||
Use `document.querySelector('atom-workspace')` if you need to access
|
||||
the workspace element.
|
||||
"""
|
||||
require '../src/workspace-view'
|
||||
|
||||
@@ -43,7 +45,7 @@ unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
|
||||
`{$} = require 'space-pen'`
|
||||
or
|
||||
`$ = require 'jquery'`
|
||||
Add `"space-pen": "^3"` to your package dependencies.
|
||||
Add `"space-pen": "^4"` to your package dependencies.
|
||||
Or add `"jquery": "^2"` to your package dependencies.
|
||||
"""
|
||||
$
|
||||
@@ -53,7 +55,7 @@ unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
|
||||
Requiring `$$` from `atom` is no longer supported.
|
||||
Please require `space-pen` instead:
|
||||
`{$$} = require 'space-pen'`
|
||||
Add `"space-pen": "^3"` to your package dependencies.
|
||||
Add `"space-pen": "^4"` to your package dependencies.
|
||||
"""
|
||||
$$
|
||||
|
||||
@@ -62,7 +64,7 @@ unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
|
||||
Requiring `$$$` from `atom` is no longer supported.
|
||||
Please require `space-pen` instead:
|
||||
`{$$$} = require 'space-pen'`
|
||||
Add `"space-pen": "^3"` to your package dependencies.
|
||||
Add `"space-pen": "^4"` to your package dependencies.
|
||||
"""
|
||||
$$$
|
||||
|
||||
@@ -71,7 +73,7 @@ unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
|
||||
Requiring `View` from `atom` is no longer supported.
|
||||
Please require `space-pen` instead:
|
||||
`{View} = require 'space-pen'`
|
||||
Add `"space-pen": "^3"` to your package dependencies.
|
||||
Add `"space-pen": "^4"` to your package dependencies.
|
||||
"""
|
||||
View
|
||||
|
||||
@@ -118,8 +120,8 @@ unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
|
||||
require 'react-atom-fork'
|
||||
|
||||
Object.defineProperty module.exports, 'Reactionary', get: ->
|
||||
deprecate "Please require `reactionary` instead: `Reactionary = require 'reactionary'`. Add `\"reactionary\": \"^0.9\"` to your package dependencies."
|
||||
require 'reactionary'
|
||||
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'`"
|
||||
|
||||
+33
-32
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "atom",
|
||||
"productName": "Atom",
|
||||
"version": "0.150.0",
|
||||
"version": "0.153.0",
|
||||
"description": "A hackable text editor for the 21st Century.",
|
||||
"main": "./src/browser/main.js",
|
||||
"repository": {
|
||||
@@ -17,10 +17,10 @@
|
||||
"url": "http://github.com/atom/atom/raw/master/LICENSE.md"
|
||||
}
|
||||
],
|
||||
"atomShellVersion": "0.19.2",
|
||||
"atomShellVersion": "0.19.4",
|
||||
"dependencies": {
|
||||
"async": "0.2.6",
|
||||
"atom-keymap": "^2.2.2",
|
||||
"atom-keymap": "^2.3.0",
|
||||
"bootstrap": "git+https://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372",
|
||||
"clear-cut": "0.4.0",
|
||||
"coffee-script": "1.7.0",
|
||||
@@ -45,7 +45,7 @@
|
||||
"nslog": "^1.0.1",
|
||||
"oniguruma": "^3.0.4",
|
||||
"optimist": "0.4.0",
|
||||
"pathwatcher": "^2.3.2",
|
||||
"pathwatcher": "^2.3.5",
|
||||
"property-accessors": "^1",
|
||||
"q": "^1.0.1",
|
||||
"random-words": "0.0.1",
|
||||
@@ -60,29 +60,29 @@
|
||||
"serializable": "^1",
|
||||
"space-pen": "3.8.2",
|
||||
"temp": "0.7.0",
|
||||
"text-buffer": "^3.6.1",
|
||||
"text-buffer": "^3.8.0",
|
||||
"theorist": "^1.0.2",
|
||||
"underscore-plus": "^1.6.1",
|
||||
"vm-compatibility-layer": "0.1.0"
|
||||
},
|
||||
"packageDependencies": {
|
||||
"atom-dark-syntax": "0.22.0",
|
||||
"atom-dark-ui": "0.40.0",
|
||||
"atom-dark-syntax": "0.23.0",
|
||||
"atom-dark-ui": "0.42.0",
|
||||
"atom-light-syntax": "0.22.0",
|
||||
"atom-light-ui": "0.34.0",
|
||||
"atom-light-ui": "0.36.0",
|
||||
"base16-tomorrow-dark-theme": "0.22.0",
|
||||
"base16-tomorrow-light-theme": "0.5.0",
|
||||
"solarized-dark-syntax": "0.23.0",
|
||||
"solarized-dark-syntax": "0.24.0",
|
||||
"solarized-light-syntax": "0.13.0",
|
||||
"archive-view": "0.37.0",
|
||||
"autocomplete": "0.33.0",
|
||||
"autocomplete": "0.33.1",
|
||||
"autoflow": "0.18.0",
|
||||
"autosave": "0.18.0",
|
||||
"background-tips": "0.17.0",
|
||||
"bookmarks": "0.30.0",
|
||||
"bracket-matcher": "0.62.0",
|
||||
"command-palette": "0.28.0",
|
||||
"deprecation-cop": "0.15.0",
|
||||
"command-palette": "0.29.0",
|
||||
"deprecation-cop": "0.18.0",
|
||||
"dev-live-reload": "0.35.0",
|
||||
"encoding-selector": "0.8.0",
|
||||
"exception-reporting": "0.20.0",
|
||||
@@ -91,58 +91,59 @@
|
||||
"git-diff": "0.43.0",
|
||||
"go-to-line": "0.26.0",
|
||||
"grammar-selector": "0.37.0",
|
||||
"image-view": "0.40.0",
|
||||
"image-view": "0.42.0",
|
||||
"incompatible-packages": "0.10.0",
|
||||
"keybinding-resolver": "0.20.0",
|
||||
"link": "0.26.0",
|
||||
"markdown-preview": "0.110.0",
|
||||
"metrics": "0.39.0",
|
||||
"notifications": "0.4.0",
|
||||
"open-on-github": "0.30.0",
|
||||
"package-generator": "0.32.0",
|
||||
"release-notes": "0.36.0",
|
||||
"settings-view": "0.161.0",
|
||||
"snippets": "0.56.0",
|
||||
"snippets": "0.57.0",
|
||||
"spell-check": "0.44.0",
|
||||
"status-bar": "0.46.0",
|
||||
"status-bar": "0.48.0",
|
||||
"styleguide": "0.30.0",
|
||||
"symbols-view": "0.68.0",
|
||||
"tabs": "0.56.0",
|
||||
"timecop": "0.23.0",
|
||||
"tree-view": "0.132.0",
|
||||
"tree-view": "0.134.0",
|
||||
"update-package-dependencies": "0.6.0",
|
||||
"welcome": "0.19.0",
|
||||
"whitespace": "0.26.0",
|
||||
"wrap-guide": "0.24.0",
|
||||
"language-c": "0.31.0",
|
||||
"language-coffee-script": "0.38.0",
|
||||
"language-css": "0.23.0",
|
||||
"language-gfm": "0.53.0",
|
||||
"language-coffee-script": "0.38.1",
|
||||
"language-css": "0.23.1",
|
||||
"language-gfm": "0.54.1",
|
||||
"language-git": "0.9.0",
|
||||
"language-go": "0.19.0",
|
||||
"language-html": "0.26.0",
|
||||
"language-hyperlink": "0.12.0",
|
||||
"language-go": "0.19.1",
|
||||
"language-html": "0.26.1",
|
||||
"language-hyperlink": "0.12.2",
|
||||
"language-java": "0.11.0",
|
||||
"language-javascript": "0.44.0",
|
||||
"language-javascript": "0.45.1",
|
||||
"language-json": "0.8.0",
|
||||
"language-less": "0.18.0",
|
||||
"language-less": "0.18.1",
|
||||
"language-make": "0.12.0",
|
||||
"language-mustache": "0.10.0",
|
||||
"language-mustache": "0.10.1",
|
||||
"language-objective-c": "0.11.0",
|
||||
"language-perl": "0.9.0",
|
||||
"language-php": "0.18.0",
|
||||
"language-property-list": "0.7.0",
|
||||
"language-python": "0.24.0",
|
||||
"language-ruby": "0.41.0",
|
||||
"language-python": "0.24.1",
|
||||
"language-ruby": "0.42.0",
|
||||
"language-ruby-on-rails": "0.18.0",
|
||||
"language-sass": "0.26.0",
|
||||
"language-shellscript": "0.10.0",
|
||||
"language-sass": "0.26.1",
|
||||
"language-shellscript": "0.10.1",
|
||||
"language-source": "0.8.0",
|
||||
"language-sql": "0.11.0",
|
||||
"language-text": "0.6.0",
|
||||
"language-todo": "0.13.0",
|
||||
"language-toml": "0.14.0",
|
||||
"language-xml": "0.24.0",
|
||||
"language-yaml": "0.20.0"
|
||||
"language-toml": "0.14.1",
|
||||
"language-xml": "0.25.0",
|
||||
"language-yaml": "0.20.1"
|
||||
},
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{$} = require 'atom'
|
||||
{$} = require '../src/space-pen-extensions'
|
||||
|
||||
describe '"atom" protocol URL', ->
|
||||
it 'sends the file relative in the package as response', ->
|
||||
|
||||
+12
-9
@@ -1,4 +1,4 @@
|
||||
{$, $$, WorkspaceView} = require 'atom'
|
||||
{$, $$} = require '../src/space-pen-extensions'
|
||||
Exec = require('child_process').exec
|
||||
path = require 'path'
|
||||
Package = require '../src/package'
|
||||
@@ -30,13 +30,16 @@ describe "the `atom` global", ->
|
||||
version = '36b5518'
|
||||
expect(atom.isReleasedVersion()).toBe false
|
||||
|
||||
describe "window:update-available", ->
|
||||
it "is triggered when the auto-updater sends the update-downloaded event", ->
|
||||
# FIXME: We need to figure out a way minus workspaceView to handle update-available events.
|
||||
atom.workspaceView = atom.views.getView(atom.workspace).__spacePenView
|
||||
describe "when an update becomes available", ->
|
||||
subscription = null
|
||||
|
||||
afterEach ->
|
||||
subscription?.dispose()
|
||||
|
||||
it "invokes onUpdateAvailable listeners", ->
|
||||
updateAvailableHandler = jasmine.createSpy("update-available-handler")
|
||||
atom.workspaceView.on 'window:update-available', updateAvailableHandler
|
||||
subscription = atom.onUpdateAvailable updateAvailableHandler
|
||||
|
||||
autoUpdater = require('remote').require('auto-updater')
|
||||
autoUpdater.emit 'update-downloaded', null, "notes", "version"
|
||||
|
||||
@@ -44,9 +47,9 @@ describe "the `atom` global", ->
|
||||
updateAvailableHandler.callCount > 0
|
||||
|
||||
runs ->
|
||||
[event, version, notes] = updateAvailableHandler.mostRecentCall.args
|
||||
expect(notes).toBe 'notes'
|
||||
expect(version).toBe 'version'
|
||||
{releaseVersion, releaseNotes} = updateAvailableHandler.mostRecentCall.args[0]
|
||||
expect(releaseVersion).toBe 'version'
|
||||
expect(releaseNotes).toBe 'notes'
|
||||
|
||||
describe "loading default config", ->
|
||||
it 'loads the default core config', ->
|
||||
|
||||
@@ -128,6 +128,12 @@ describe "Config", ->
|
||||
expect(atom.config.get("foo")).toEqual 'a\\.b': 1, b: 2
|
||||
|
||||
describe ".toggle(keyPath)", ->
|
||||
beforeEach ->
|
||||
jasmine.snapshotDeprecations()
|
||||
|
||||
afterEach ->
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
it "negates the boolean value of the current key path value", ->
|
||||
atom.config.set('foo.a', 1)
|
||||
atom.config.toggle('foo.a')
|
||||
@@ -298,6 +304,12 @@ describe "Config", ->
|
||||
expect(observeHandler).toHaveBeenCalledWith atom.config.get("foo.bar.baz")
|
||||
|
||||
describe ".getPositiveInt(keyPath, defaultValue)", ->
|
||||
beforeEach ->
|
||||
jasmine.snapshotDeprecations()
|
||||
|
||||
afterEach ->
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
it "returns the proper coerced value", ->
|
||||
atom.config.set('editor.preferredLineLength', 0)
|
||||
expect(atom.config.getPositiveInt('editor.preferredLineLength', 80)).toBe 1
|
||||
@@ -470,7 +482,7 @@ describe "Config", ->
|
||||
|
||||
it "does not fire the callback once the observe subscription is off'ed", ->
|
||||
observeHandler.reset() # clear the initial call
|
||||
observeSubscription.off()
|
||||
observeSubscription.dispose()
|
||||
atom.config.set('foo.bar.baz', "value 2")
|
||||
expect(observeHandler).not.toHaveBeenCalled()
|
||||
|
||||
@@ -554,11 +566,13 @@ describe "Config", ->
|
||||
describe "when the config file contains invalid cson", ->
|
||||
beforeEach ->
|
||||
spyOn(console, 'error')
|
||||
spyOn(atom.notifications, 'addError')
|
||||
fs.writeFileSync(atom.config.configFilePath, "{{{{{")
|
||||
|
||||
it "logs an error to the console and does not overwrite the config file on a subsequent save", ->
|
||||
atom.config.loadUserConfig()
|
||||
expect(console.error).toHaveBeenCalled()
|
||||
expect(atom.notifications.addError.callCount).toBe 1
|
||||
atom.config.set("hair", "blonde") # trigger a save
|
||||
expect(atom.config.save).not.toHaveBeenCalled()
|
||||
|
||||
@@ -692,7 +706,6 @@ describe "Config", ->
|
||||
expect(atom.config.get(['.source.ruby'], 'foo.bar')).toBe 'baz'
|
||||
expect(atom.config.get(['.source.ruby'], 'foo.scoped')).toBe true
|
||||
|
||||
|
||||
describe "when the config file changes to omit a setting with a default", ->
|
||||
it "resets the setting back to the default", ->
|
||||
fs.writeFileSync(atom.config.configFilePath, "foo: { baz: 'new'}")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{$$} = require 'atom'
|
||||
{$$} = require '../src/space-pen-extensions'
|
||||
|
||||
ContextMenuManager = require '../src/context-menu-manager'
|
||||
|
||||
@@ -151,24 +151,31 @@ describe "ContextMenuManager", ->
|
||||
shouldDisplay = false
|
||||
expect(contextMenu.templateForEvent(dispatchedEvent)).toEqual []
|
||||
|
||||
it "allows items to be specified in the legacy format for now", ->
|
||||
contextMenu.add '.parent':
|
||||
'A': 'a'
|
||||
'Separator 1': '-'
|
||||
'B':
|
||||
'C': 'c'
|
||||
'Separator 2': '-'
|
||||
'D': 'd'
|
||||
describe "when the menus are specified in a legacy format", ->
|
||||
beforeEach ->
|
||||
jasmine.snapshotDeprecations()
|
||||
|
||||
expect(contextMenu.templateForElement(parent)).toEqual [
|
||||
{label: 'A', command: 'a'}
|
||||
{type: 'separator'}
|
||||
{
|
||||
label: 'B'
|
||||
submenu: [
|
||||
{label: 'C', command: 'c'}
|
||||
{type: 'separator'}
|
||||
{label: 'D', command: 'd'}
|
||||
]
|
||||
}
|
||||
]
|
||||
afterEach ->
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
it "allows items to be specified in the legacy format for now", ->
|
||||
contextMenu.add '.parent':
|
||||
'A': 'a'
|
||||
'Separator 1': '-'
|
||||
'B':
|
||||
'C': 'c'
|
||||
'Separator 2': '-'
|
||||
'D': 'd'
|
||||
|
||||
expect(contextMenu.templateForElement(parent)).toEqual [
|
||||
{label: 'A', command: 'a'}
|
||||
{type: 'separator'}
|
||||
{
|
||||
label: 'B'
|
||||
submenu: [
|
||||
{label: 'C', command: 'c'}
|
||||
{type: 'separator'}
|
||||
{label: 'D', command: 'd'}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -9,6 +9,6 @@ module.exports =
|
||||
atom.commands.add 'atom-workspace', 'activation-command', =>
|
||||
@activationCommandCallCount++
|
||||
|
||||
editorView = atom.views.getView(atom.workspace.getActiveEditor())?.__spacePenView
|
||||
editorView = document.querySelector('atom-workspace').getView(atom.workspace.getActiveEditor())?.__spacePenView
|
||||
editorView?.command 'activation-command', =>
|
||||
@legacyActivationCommandCallCount++
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
]
|
||||
|
||||
'context-menu':
|
||||
'.test-1':
|
||||
'Menu item 1': 'command-1'
|
||||
'.test-1': [
|
||||
{label: 'Menu item 1', command: 'command-1'}
|
||||
]
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
]
|
||||
|
||||
'context-menu':
|
||||
'.test-1':
|
||||
'Menu item 2': 'command-2'
|
||||
'.test-1': [
|
||||
{label: 'Menu item 2', command: 'command-2'}
|
||||
]
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
'context-menu':
|
||||
'.test-1':
|
||||
'Menu item 3': 'command-3'
|
||||
'.test-1': [
|
||||
{label: 'Menu item 3', command: 'command-3'}
|
||||
]
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
NotificationManager = require '../src/notification-manager'
|
||||
|
||||
describe "NotificationManager", ->
|
||||
[manager] = []
|
||||
|
||||
beforeEach ->
|
||||
manager = new NotificationManager
|
||||
|
||||
describe "the atom global", ->
|
||||
it "has a notifications instance", ->
|
||||
expect(atom.notifications instanceof NotificationManager).toBe true
|
||||
|
||||
describe "adding events", ->
|
||||
addSpy = null
|
||||
|
||||
beforeEach ->
|
||||
addSpy = jasmine.createSpy()
|
||||
manager.onDidAddNotification(addSpy)
|
||||
|
||||
it "emits an event when a notification has been added", ->
|
||||
manager.add('error', 'Some error!', icon: 'someIcon')
|
||||
expect(addSpy).toHaveBeenCalled()
|
||||
|
||||
notification = addSpy.mostRecentCall.args[0]
|
||||
expect(notification.getType()).toBe 'error'
|
||||
expect(notification.getMessage()).toBe 'Some error!'
|
||||
expect(notification.getIcon()).toBe 'someIcon'
|
||||
|
||||
it "emits a fatal error ::addFatalError has been called", ->
|
||||
manager.addFatalError('Some error!', icon: 'someIcon')
|
||||
expect(addSpy).toHaveBeenCalled()
|
||||
notification = addSpy.mostRecentCall.args[0]
|
||||
expect(notification.getType()).toBe 'fatal'
|
||||
|
||||
it "emits an error ::addError has been called", ->
|
||||
manager.addError('Some error!', icon: 'someIcon')
|
||||
expect(addSpy).toHaveBeenCalled()
|
||||
notification = addSpy.mostRecentCall.args[0]
|
||||
expect(notification.getType()).toBe 'error'
|
||||
|
||||
it "emits a warning notification ::addWarning has been called", ->
|
||||
manager.addWarning('Something!', icon: 'someIcon')
|
||||
expect(addSpy).toHaveBeenCalled()
|
||||
notification = addSpy.mostRecentCall.args[0]
|
||||
expect(notification.getType()).toBe 'warning'
|
||||
|
||||
it "emits an info notification ::addInfo has been called", ->
|
||||
manager.addInfo('Something!', icon: 'someIcon')
|
||||
expect(addSpy).toHaveBeenCalled()
|
||||
notification = addSpy.mostRecentCall.args[0]
|
||||
expect(notification.getType()).toBe 'info'
|
||||
|
||||
it "emits a success notification ::addSuccess has been called", ->
|
||||
manager.addSuccess('Something!', icon: 'someIcon')
|
||||
expect(addSpy).toHaveBeenCalled()
|
||||
notification = addSpy.mostRecentCall.args[0]
|
||||
expect(notification.getType()).toBe 'success'
|
||||
@@ -0,0 +1,18 @@
|
||||
Notification = require '../src/notification'
|
||||
|
||||
describe "Notification", ->
|
||||
[notification] = []
|
||||
|
||||
describe "::getTimestamp()", ->
|
||||
it "returns a Date object", ->
|
||||
notification = new Notification('error', 'message!')
|
||||
expect(notification.getTimestamp() instanceof Date).toBe true
|
||||
|
||||
describe "::getIcon()", ->
|
||||
it "returns a default when no icon specified", ->
|
||||
notification = new Notification('error', 'message!')
|
||||
expect(notification.getIcon()).toBe 'flame'
|
||||
|
||||
it "returns the icon specified", ->
|
||||
notification = new Notification('error', 'message!', icon: 'my-icon')
|
||||
expect(notification.getIcon()).toBe 'my-icon'
|
||||
@@ -1,10 +1,10 @@
|
||||
{$, $$, WorkspaceView} = require 'atom'
|
||||
{$, $$} = require '../src/space-pen-extensions'
|
||||
Package = require '../src/package'
|
||||
|
||||
describe "PackageManager", ->
|
||||
workspaceElement = null
|
||||
beforeEach ->
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
workspaceElement = atom.views.createView(atom.workspace)
|
||||
|
||||
describe "::loadPackage(name)", ->
|
||||
it "continues if the package has an invalid package.json", ->
|
||||
@@ -98,15 +98,23 @@ describe "PackageManager", ->
|
||||
expect(atom.config.set('package-with-config-schema.numbers.one', '10')).toBe true
|
||||
expect(atom.config.get('package-with-config-schema.numbers.one')).toBe 10
|
||||
|
||||
it "still assigns configDefaults from the module though deprecated", ->
|
||||
expect(atom.config.get('package-with-config-defaults.numbers.one')).toBeUndefined()
|
||||
describe "when a package has configDefaults", ->
|
||||
beforeEach ->
|
||||
jasmine.snapshotDeprecations()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-config-defaults')
|
||||
afterEach ->
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
runs ->
|
||||
expect(atom.config.get('package-with-config-defaults.numbers.one')).toBe 1
|
||||
expect(atom.config.get('package-with-config-defaults.numbers.two')).toBe 2
|
||||
it "still assigns configDefaults from the module though deprecated", ->
|
||||
|
||||
expect(atom.config.get('package-with-config-defaults.numbers.one')).toBeUndefined()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-config-defaults')
|
||||
|
||||
runs ->
|
||||
expect(atom.config.get('package-with-config-defaults.numbers.one')).toBe 1
|
||||
expect(atom.config.get('package-with-config-defaults.numbers.two')).toBe 2
|
||||
|
||||
describe "when the package metadata includes `activationCommands`", ->
|
||||
[mainModule, promise, workspaceCommandListener] = []
|
||||
@@ -136,7 +144,7 @@ describe "PackageManager", ->
|
||||
atom.workspace.open()
|
||||
|
||||
runs ->
|
||||
editorView = atom.views.getView(atom.workspace.getActiveEditor()).__spacePenView
|
||||
editorView = workspaceElement.getView(atom.workspace.getActiveEditor()).__spacePenView
|
||||
legacyCommandListener = jasmine.createSpy("legacyCommandListener")
|
||||
editorView.command 'activation-command', legacyCommandListener
|
||||
editorCommandListener = jasmine.createSpy("editorCommandListener")
|
||||
@@ -350,8 +358,8 @@ describe "PackageManager", ->
|
||||
atom.packages.activatePackage('package-with-grammars')
|
||||
|
||||
runs ->
|
||||
expect(atom.syntax.selectGrammar('a.alot').name).toBe 'Alot'
|
||||
expect(atom.syntax.selectGrammar('a.alittle').name).toBe 'Alittle'
|
||||
expect(atom.grammars.selectGrammar('a.alot').name).toBe 'Alot'
|
||||
expect(atom.grammars.selectGrammar('a.alittle').name).toBe 'Alittle'
|
||||
|
||||
describe "scoped-property loading", ->
|
||||
it "loads the scoped properties", ->
|
||||
@@ -363,13 +371,13 @@ describe "PackageManager", ->
|
||||
|
||||
describe "converted textmate packages", ->
|
||||
it "loads the package's grammars", ->
|
||||
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Null Grammar"
|
||||
expect(atom.grammars.selectGrammar("file.rb").name).toBe "Null Grammar"
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-ruby')
|
||||
|
||||
runs ->
|
||||
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Ruby"
|
||||
expect(atom.grammars.selectGrammar("file.rb").name).toBe "Ruby"
|
||||
|
||||
it "loads the translated scoped properties", ->
|
||||
expect(atom.config.get(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
|
||||
@@ -455,8 +463,8 @@ describe "PackageManager", ->
|
||||
|
||||
runs ->
|
||||
atom.packages.deactivatePackage('package-with-grammars')
|
||||
expect(atom.syntax.selectGrammar('a.alot').name).toBe 'Null Grammar'
|
||||
expect(atom.syntax.selectGrammar('a.alittle').name).toBe 'Null Grammar'
|
||||
expect(atom.grammars.selectGrammar('a.alot').name).toBe 'Null Grammar'
|
||||
expect(atom.grammars.selectGrammar('a.alittle').name).toBe 'Null Grammar'
|
||||
|
||||
it "removes the package's keymaps", ->
|
||||
waitsForPromise ->
|
||||
@@ -491,15 +499,15 @@ describe "PackageManager", ->
|
||||
|
||||
describe "textmate packages", ->
|
||||
it "removes the package's grammars", ->
|
||||
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Null Grammar"
|
||||
expect(atom.grammars.selectGrammar("file.rb").name).toBe "Null Grammar"
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-ruby')
|
||||
|
||||
runs ->
|
||||
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Ruby"
|
||||
expect(atom.grammars.selectGrammar("file.rb").name).toBe "Ruby"
|
||||
atom.packages.deactivatePackage('language-ruby')
|
||||
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Null Grammar"
|
||||
expect(atom.grammars.selectGrammar("file.rb").name).toBe "Null Grammar"
|
||||
|
||||
it "removes the package's scoped properties", ->
|
||||
waitsForPromise ->
|
||||
@@ -514,6 +522,7 @@ describe "PackageManager", ->
|
||||
themeActivator = null
|
||||
|
||||
beforeEach ->
|
||||
jasmine.snapshotDeprecations()
|
||||
spyOn(console, 'warn')
|
||||
atom.packages.loadPackages()
|
||||
|
||||
@@ -527,8 +536,9 @@ describe "PackageManager", ->
|
||||
atom.packages.deactivatePackages()
|
||||
atom.packages.unloadPackages()
|
||||
|
||||
Syntax = require '../src/syntax'
|
||||
atom.syntax = window.syntax = new Syntax()
|
||||
GrammarRegistry = require '../src/grammar-registry'
|
||||
atom.grammars = window.syntax = new GrammarRegistry()
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
it "activates all the packages, and none of the themes", ->
|
||||
atom.packages.activate()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{$} = require 'atom'
|
||||
{$} = require '../src/space-pen-extensions'
|
||||
path = require 'path'
|
||||
Package = require '../src/package'
|
||||
ThemePackage = require '../src/theme-package'
|
||||
|
||||
@@ -3,10 +3,12 @@ temp = require 'temp'
|
||||
PaneContainer = require '../src/pane-container'
|
||||
PaneContainerView = require '../src/pane-container-view'
|
||||
PaneView = require '../src/pane-view'
|
||||
{$, View, $$} = require 'atom'
|
||||
{Disposable} = require 'event-kit'
|
||||
{$, View, $$} = require '../src/space-pen-extensions'
|
||||
ViewRegistry = require '../src/view-registry'
|
||||
|
||||
describe "PaneContainerView", ->
|
||||
[TestView, container, pane1, pane2, pane3, deserializerDisposable] = []
|
||||
[viewRegistry, TestView, container, pane1, pane2, pane3, deserializerDisposable] = []
|
||||
|
||||
beforeEach ->
|
||||
class TestView extends View
|
||||
@@ -18,8 +20,11 @@ describe "PaneContainerView", ->
|
||||
getUri: -> path.join(temp.dir, @name)
|
||||
save: -> @saved = true
|
||||
isEqual: (other) -> @name is other?.name
|
||||
onDidChangeTitle: -> new Disposable(->)
|
||||
onDidChangeModified: -> new Disposable(->)
|
||||
|
||||
container = atom.views.getView(atom.workspace.paneContainer).__spacePenView
|
||||
viewRegistry = new ViewRegistry(atom.views)
|
||||
container = atom.views.createView(atom.workspace.paneContainer, {viewRegistry}).__spacePenView
|
||||
pane1 = container.getRoot()
|
||||
pane1.activateItem(new TestView('1'))
|
||||
pane2 = pane1.splitRight(new TestView('2'))
|
||||
@@ -73,7 +78,7 @@ describe "PaneContainerView", ->
|
||||
|
||||
describe "serialization", ->
|
||||
it "can be serialized and deserialized, and correctly adjusts dimensions of deserialized panes after attach", ->
|
||||
newContainer = atom.views.getView(container.model.testSerialization()).__spacePenView
|
||||
newContainer = atom.views.createView(container.model.testSerialization(), {viewRegistry}).__spacePenView
|
||||
expect(newContainer.find('atom-pane-axis.horizontal > :contains(1)')).toExist()
|
||||
expect(newContainer.find('atom-pane-axis.horizontal > atom-pane-axis.vertical > :contains(2)')).toExist()
|
||||
expect(newContainer.find('atom-pane-axis.horizontal > atom-pane-axis.vertical > :contains(3)')).toExist()
|
||||
@@ -89,14 +94,14 @@ describe "PaneContainerView", ->
|
||||
|
||||
describe "if the 'core.destroyEmptyPanes' config option is false (the default)", ->
|
||||
it "leaves the empty panes intact", ->
|
||||
newContainer = atom.views.getView(container.model.testSerialization()).__spacePenView
|
||||
newContainer = atom.views.createView(container.model.testSerialization(), {viewRegistry}).__spacePenView
|
||||
expect(newContainer.find('atom-pane-axis.horizontal > :contains(1)')).toExist()
|
||||
expect(newContainer.find('atom-pane-axis.horizontal > atom-pane-axis.vertical > atom-pane').length).toBe 2
|
||||
|
||||
describe "if the 'core.destroyEmptyPanes' config option is true", ->
|
||||
it "removes empty panes on deserialization", ->
|
||||
atom.config.set('core.destroyEmptyPanes', true)
|
||||
newContainer = atom.views.getView(container.model.testSerialization()).__spacePenView
|
||||
newContainer = atom.views.createView(container.model.testSerialization(), {viewRegistry}).__spacePenView
|
||||
expect(newContainer.find('atom-pane-axis.horizontal, atom-pane-axis.vertical')).not.toExist()
|
||||
expect(newContainer.find('> :contains(1)')).toExist()
|
||||
|
||||
@@ -109,7 +114,7 @@ describe "PaneContainerView", ->
|
||||
item2b = new TestView('2b')
|
||||
item3a = new TestView('3a')
|
||||
|
||||
container = atom.views.getView(new PaneContainer).__spacePenView
|
||||
container = atom.views.createView(new PaneContainer, {viewRegistry}).__spacePenView
|
||||
pane1 = container.getRoot()
|
||||
pane1.activateItem(item1a)
|
||||
container.attachToDom()
|
||||
@@ -259,7 +264,7 @@ describe "PaneContainerView", ->
|
||||
# |7|8|9|
|
||||
# -------
|
||||
|
||||
container = atom.views.getView(new PaneContainer).__spacePenView
|
||||
container = atom.views.createView(new PaneContainer, {viewRegistry}).__spacePenView
|
||||
pane1 = container.getRoot()
|
||||
pane1.activateItem(new TestView('1'))
|
||||
pane4 = pane1.splitDown(new TestView('4'))
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
PaneContainer = require '../src/pane-container'
|
||||
PaneView = require '../src/pane-view'
|
||||
ViewRegistry = require '../src/view-registry'
|
||||
fs = require 'fs-plus'
|
||||
{Emitter} = require 'event-kit'
|
||||
{$, View} = require 'atom'
|
||||
{Emitter, Disposable} = require 'event-kit'
|
||||
{$, View} = require '../src/space-pen-extensions'
|
||||
path = require 'path'
|
||||
temp = require 'temp'
|
||||
|
||||
describe "PaneView", ->
|
||||
[container, containerModel, view1, view2, editor1, editor2, pane, paneModel, deserializerDisposable] = []
|
||||
[viewRegistry, container, containerModel, view1, view2, editor1, editor2, pane, paneModel, deserializerDisposable] = []
|
||||
|
||||
class TestView extends View
|
||||
@deserialize: ({id, text}) -> new TestView({id, text})
|
||||
@@ -21,10 +22,14 @@ describe "PaneView", ->
|
||||
@emitter.emit 'did-change-title', 'title'
|
||||
onDidChangeTitle: (callback) ->
|
||||
@emitter.on 'did-change-title', callback
|
||||
onDidChangeModified: -> new Disposable(->)
|
||||
|
||||
beforeEach ->
|
||||
jasmine.snapshotDeprecations()
|
||||
|
||||
deserializerDisposable = atom.deserializers.add(TestView)
|
||||
container = atom.views.getView(new PaneContainer).__spacePenView
|
||||
viewRegistry = new ViewRegistry(atom.views)
|
||||
container = atom.views.createView(new PaneContainer, {viewRegistry}).__spacePenView
|
||||
containerModel = container.model
|
||||
view1 = new TestView(id: 'view-1', text: 'View 1')
|
||||
view2 = new TestView(id: 'view-2', text: 'View 2')
|
||||
@@ -41,6 +46,7 @@ describe "PaneView", ->
|
||||
|
||||
afterEach ->
|
||||
deserializerDisposable.dispose()
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
describe "when the active pane item changes", ->
|
||||
it "hides all item views except the active one", ->
|
||||
@@ -155,14 +161,19 @@ describe "PaneView", ->
|
||||
expect(view1.is(':visible')).toBe true
|
||||
|
||||
describe "when the title of the active item changes", ->
|
||||
describe 'when there is no onDidChangeTitle method', ->
|
||||
describe 'when there is no onDidChangeTitle method (deprecated)', ->
|
||||
beforeEach ->
|
||||
jasmine.snapshotDeprecations()
|
||||
|
||||
view1.onDidChangeTitle = null
|
||||
view2.onDidChangeTitle = null
|
||||
|
||||
pane.activateItem(view2)
|
||||
pane.activateItem(view1)
|
||||
|
||||
afterEach ->
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
it "emits pane:active-item-title-changed", ->
|
||||
activeItemTitleChangedHandler = jasmine.createSpy("activeItemTitleChangedHandler")
|
||||
pane.on 'pane:active-item-title-changed', activeItemTitleChangedHandler
|
||||
@@ -220,7 +231,7 @@ describe "PaneView", ->
|
||||
|
||||
beforeEach ->
|
||||
pane2Model = paneModel.splitRight() # Can't destroy the last pane, so we add another
|
||||
pane2 = containerModel.getView(pane2Model).__spacePenView
|
||||
pane2 = viewRegistry.getView(pane2Model).__spacePenView
|
||||
|
||||
it "triggers a 'pane:removed' event with the pane", ->
|
||||
removedHandler = jasmine.createSpy("removedHandler")
|
||||
@@ -253,7 +264,7 @@ describe "PaneView", ->
|
||||
|
||||
beforeEach ->
|
||||
pane2Model = paneModel.splitRight(items: [pane.copyActiveItem()])
|
||||
pane2 = containerModel.getView(pane2Model).__spacePenView
|
||||
pane2 = viewRegistry.getView(pane2Model).__spacePenView
|
||||
expect(pane2Model.isActive()).toBe true
|
||||
|
||||
it "adds or removes the .active class as appropriate", ->
|
||||
@@ -300,8 +311,8 @@ describe "PaneView", ->
|
||||
pane2Model = pane1Model.splitRight(items: [pane1Model.copyActiveItem()])
|
||||
pane3Model = pane2Model.splitDown(items: [pane2Model.copyActiveItem()])
|
||||
pane2 = pane2Model._view
|
||||
pane2 = containerModel.getView(pane2Model).__spacePenView
|
||||
pane3 = containerModel.getView(pane3Model).__spacePenView
|
||||
pane2 = viewRegistry.getView(pane2Model).__spacePenView
|
||||
pane3 = viewRegistry.getView(pane3Model).__spacePenView
|
||||
|
||||
expect(container.find('> atom-pane-axis.horizontal > atom-pane').toArray()).toEqual [pane1[0]]
|
||||
expect(container.find('> atom-pane-axis.horizontal > atom-pane-axis.vertical > atom-pane').toArray()).toEqual [pane2[0], pane3[0]]
|
||||
@@ -314,13 +325,13 @@ describe "PaneView", ->
|
||||
container.attachToDom()
|
||||
pane.focus()
|
||||
|
||||
container2 = atom.views.getView(container.model.testSerialization()).__spacePenView
|
||||
container2 = viewRegistry.getView(container.model.testSerialization()).__spacePenView
|
||||
pane2 = container2.getRoot()
|
||||
container2.attachToDom()
|
||||
expect(pane2).toMatchSelector(':has(:focus)')
|
||||
|
||||
$(document.activeElement).blur()
|
||||
container3 = atom.views.getView(container.model.testSerialization()).__spacePenView
|
||||
container3 = viewRegistry.getView(container.model.testSerialization()).__spacePenView
|
||||
pane3 = container3.getRoot()
|
||||
container3.attachToDom()
|
||||
expect(pane3).not.toMatchSelector(':has(:focus)')
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
ViewRegistry = require '../src/view-registry'
|
||||
Panel = require '../src/panel'
|
||||
PanelElement = require '../src/panel-element'
|
||||
PanelContainer = require '../src/panel-container'
|
||||
PanelContainerElement = require '../src/panel-container-element'
|
||||
ViewRegistry = require '../src/view-registry'
|
||||
|
||||
describe "PanelContainerElement", ->
|
||||
[jasmineContent, element, container, viewRegistry] = []
|
||||
@@ -13,25 +13,26 @@ describe "PanelContainerElement", ->
|
||||
class TestPanelContainerItemElement extends HTMLElement
|
||||
createdCallback: ->
|
||||
@classList.add('test-root')
|
||||
setModel: (@model) ->
|
||||
initialize: ({@model}) ->
|
||||
TestPanelContainerItemElement = document.registerElement 'atom-test-container-item-element', prototype: TestPanelContainerItemElement.prototype
|
||||
|
||||
beforeEach ->
|
||||
jasmineContent = document.body.querySelector('#jasmine-content')
|
||||
|
||||
viewRegistry = new ViewRegistry
|
||||
viewRegistry.addViewProvider
|
||||
atom.views.addViewProvider
|
||||
modelConstructor: Panel
|
||||
viewConstructor: PanelElement
|
||||
viewRegistry.addViewProvider
|
||||
atom.views.addViewProvider
|
||||
modelConstructor: PanelContainer
|
||||
viewConstructor: PanelContainerElement
|
||||
viewRegistry.addViewProvider
|
||||
atom.views.addViewProvider
|
||||
modelConstructor: TestPanelContainerItem
|
||||
viewConstructor: TestPanelContainerItemElement
|
||||
|
||||
container = new PanelContainer({viewRegistry, location: 'left'})
|
||||
element = container.getView()
|
||||
|
||||
container = new PanelContainer({location: 'left'})
|
||||
viewRegistry = new ViewRegistry(atom.views)
|
||||
element = viewRegistry.getView(container, {viewRegistry})
|
||||
jasmineContent.appendChild(element)
|
||||
|
||||
it 'has a location class with value from the model', ->
|
||||
@@ -43,23 +44,38 @@ describe "PanelContainerElement", ->
|
||||
expect(element.parentNode).not.toBe jasmineContent
|
||||
|
||||
describe "adding and removing panels", ->
|
||||
it "allows panels to be inserted at any position", ->
|
||||
panel1 = new Panel({item: new TestPanelContainerItem(), priority: 10})
|
||||
panel2 = new Panel({item: new TestPanelContainerItem(), priority: 5})
|
||||
panel3 = new Panel({item: new TestPanelContainerItem(), priority: 8})
|
||||
|
||||
container.addPanel(panel1)
|
||||
container.addPanel(panel2)
|
||||
container.addPanel(panel3)
|
||||
|
||||
expect(element.childNodes[2].getModel()).toBe(panel1)
|
||||
expect(element.childNodes[1].getModel()).toBe(panel3)
|
||||
expect(element.childNodes[0].getModel()).toBe(panel2)
|
||||
|
||||
describe "when the container is at the left location", ->
|
||||
it "adds atom-panel elements when a new panel is added to the container; removes them when the panels are destroyed", ->
|
||||
expect(element.childNodes.length).toBe 0
|
||||
|
||||
panel1 = new Panel({viewRegistry, item: new TestPanelContainerItem()})
|
||||
panel1 = new Panel({item: new TestPanelContainerItem()})
|
||||
container.addPanel(panel1)
|
||||
expect(element.childNodes.length).toBe 1
|
||||
expect(element.childNodes[0]).toHaveClass 'left'
|
||||
expect(element.childNodes[0]).toHaveClass 'tool-panel' # legacy selector support
|
||||
expect(element.childNodes[0]).toHaveClass 'panel-left' # legacy selector support
|
||||
|
||||
expect(element.childNodes[0].tagName).toBe 'ATOM-PANEL'
|
||||
|
||||
panel2 = new Panel({viewRegistry, item: new TestPanelContainerItem()})
|
||||
panel2 = new Panel({item: new TestPanelContainerItem()})
|
||||
container.addPanel(panel2)
|
||||
expect(element.childNodes.length).toBe 2
|
||||
|
||||
expect(panel1.getView().style.display).not.toBe 'none'
|
||||
expect(panel2.getView().style.display).not.toBe 'none'
|
||||
expect(viewRegistry.getView(panel1).style.display).not.toBe 'none'
|
||||
expect(viewRegistry.getView(panel2).style.display).not.toBe 'none'
|
||||
|
||||
panel1.destroy()
|
||||
expect(element.childNodes.length).toBe 1
|
||||
@@ -69,24 +85,26 @@ describe "PanelContainerElement", ->
|
||||
|
||||
describe "when the container is at the bottom location", ->
|
||||
beforeEach ->
|
||||
container = new PanelContainer({viewRegistry, location: 'bottom'})
|
||||
element = container.getView()
|
||||
container = new PanelContainer({location: 'bottom'})
|
||||
element = viewRegistry.getView(container)
|
||||
jasmineContent.appendChild(element)
|
||||
|
||||
it "adds atom-panel elements when a new panel is added to the container; removes them when the panels are destroyed", ->
|
||||
expect(element.childNodes.length).toBe 0
|
||||
|
||||
panel1 = new Panel({viewRegistry, item: new TestPanelContainerItem(), className: 'one'})
|
||||
panel1 = new Panel({item: new TestPanelContainerItem(), className: 'one'})
|
||||
container.addPanel(panel1)
|
||||
expect(element.childNodes.length).toBe 1
|
||||
expect(element.childNodes[0]).toHaveClass 'bottom'
|
||||
expect(element.childNodes[0]).toHaveClass 'tool-panel' # legacy selector support
|
||||
expect(element.childNodes[0]).toHaveClass 'panel-bottom' # legacy selector support
|
||||
expect(element.childNodes[0].tagName).toBe 'ATOM-PANEL'
|
||||
expect(panel1.getView()).toHaveClass 'one'
|
||||
expect(viewRegistry.getView(panel1)).toHaveClass 'one'
|
||||
|
||||
panel2 = new Panel({viewRegistry, item: new TestPanelContainerItem(), className: 'two'})
|
||||
panel2 = new Panel({item: new TestPanelContainerItem(), className: 'two'})
|
||||
container.addPanel(panel2)
|
||||
expect(element.childNodes.length).toBe 2
|
||||
expect(panel2.getView()).toHaveClass 'two'
|
||||
expect(viewRegistry.getView(panel2)).toHaveClass 'two'
|
||||
|
||||
panel1.destroy()
|
||||
expect(element.childNodes.length).toBe 1
|
||||
@@ -96,23 +114,34 @@ describe "PanelContainerElement", ->
|
||||
|
||||
describe "when the container is modal", ->
|
||||
beforeEach ->
|
||||
container = new PanelContainer({viewRegistry, location: 'modal'})
|
||||
element = container.getView()
|
||||
container = new PanelContainer({location: 'modal'})
|
||||
element = viewRegistry.getView(container)
|
||||
jasmineContent.appendChild(element)
|
||||
|
||||
it "allows only one panel to be visible at a time", ->
|
||||
panel1 = new Panel({viewRegistry, item: new TestPanelContainerItem()})
|
||||
panel1 = new Panel({item: new TestPanelContainerItem()})
|
||||
container.addPanel(panel1)
|
||||
|
||||
expect(panel1.getView().style.display).not.toBe 'none'
|
||||
expect(viewRegistry.getView(panel1).style.display).not.toBe 'none'
|
||||
|
||||
panel2 = new Panel({viewRegistry, item: new TestPanelContainerItem()})
|
||||
panel2 = new Panel({item: new TestPanelContainerItem()})
|
||||
container.addPanel(panel2)
|
||||
|
||||
expect(panel1.getView().style.display).toBe 'none'
|
||||
expect(panel2.getView().style.display).not.toBe 'none'
|
||||
expect(viewRegistry.getView(panel1).style.display).toBe 'none'
|
||||
expect(viewRegistry.getView(panel2).style.display).not.toBe 'none'
|
||||
|
||||
panel1.show()
|
||||
|
||||
expect(panel1.getView().style.display).not.toBe 'none'
|
||||
expect(panel2.getView().style.display).toBe 'none'
|
||||
expect(viewRegistry.getView(panel1).style.display).not.toBe 'none'
|
||||
expect(viewRegistry.getView(panel2).style.display).toBe 'none'
|
||||
|
||||
it "adds the 'modal' class to panels", ->
|
||||
panel1 = new Panel({item: new TestPanelContainerItem()})
|
||||
container.addPanel(panel1)
|
||||
|
||||
expect(viewRegistry.getView(panel1)).toHaveClass 'modal'
|
||||
|
||||
# legacy selector support
|
||||
expect(viewRegistry.getView(panel1)).not.toHaveClass 'tool-panel'
|
||||
expect(viewRegistry.getView(panel1)).toHaveClass 'overlay'
|
||||
expect(viewRegistry.getView(panel1)).toHaveClass 'from-top'
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
ViewRegistry = require '../src/view-registry'
|
||||
Panel = require '../src/panel'
|
||||
PanelContainer = require '../src/panel-container'
|
||||
|
||||
describe "PanelContainer", ->
|
||||
[container, viewRegistry] = []
|
||||
[container] = []
|
||||
|
||||
class TestPanelItem
|
||||
constructior: ->
|
||||
|
||||
beforeEach ->
|
||||
viewRegistry = new ViewRegistry
|
||||
container = new PanelContainer({viewRegistry})
|
||||
container = new PanelContainer
|
||||
|
||||
describe "::addPanel(panel)", ->
|
||||
it 'emits an onDidAddPanel event with the index the panel was inserted at', ->
|
||||
@@ -46,7 +44,7 @@ describe "PanelContainer", ->
|
||||
[initialPanel] = []
|
||||
beforeEach ->
|
||||
# 'left' logic is the same as 'top'
|
||||
container = new PanelContainer({viewRegistry, location: 'left'})
|
||||
container = new PanelContainer({location: 'left'})
|
||||
initialPanel = new Panel(item: new TestPanelItem())
|
||||
container.addPanel(initialPanel)
|
||||
|
||||
@@ -75,7 +73,7 @@ describe "PanelContainer", ->
|
||||
[initialPanel] = []
|
||||
beforeEach ->
|
||||
# 'bottom' logic is the same as 'right'
|
||||
container = new PanelContainer({viewRegistry, location: 'right'})
|
||||
container = new PanelContainer({location: 'right'})
|
||||
initialPanel = new Panel(item: new TestPanelItem())
|
||||
container.addPanel(initialPanel)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
ViewRegistry = require '../src/view-registry'
|
||||
Panel = require '../src/panel'
|
||||
PanelElement = require '../src/panel-element'
|
||||
ViewRegistry = require '../src/view-registry'
|
||||
|
||||
describe "PanelElement", ->
|
||||
[jasmineContent, element, panel, viewRegistry] = []
|
||||
@@ -11,23 +11,30 @@ describe "PanelElement", ->
|
||||
class TestPanelItemElement extends HTMLElement
|
||||
createdCallback: ->
|
||||
@classList.add('test-root')
|
||||
setModel: (@model) ->
|
||||
initialize: ({@model}) ->
|
||||
TestPanelItemElement = document.registerElement 'atom-test-item-element', prototype: TestPanelItemElement.prototype
|
||||
|
||||
beforeEach ->
|
||||
jasmineContent = document.body.querySelector('#jasmine-content')
|
||||
|
||||
viewRegistry = new ViewRegistry
|
||||
viewRegistry.addViewProvider
|
||||
atom.views.addViewProvider
|
||||
modelConstructor: Panel
|
||||
viewConstructor: PanelElement
|
||||
viewRegistry.addViewProvider
|
||||
atom.views.addViewProvider
|
||||
modelConstructor: TestPanelItem
|
||||
viewConstructor: TestPanelItemElement
|
||||
|
||||
viewRegistry = new ViewRegistry(atom.views)
|
||||
|
||||
it "renders a view for the panel's item", ->
|
||||
panel = new Panel({item: new TestPanelItem})
|
||||
element = atom.views.createView(panel, {viewRegistry})
|
||||
jasmineContent.appendChild(element)
|
||||
expect(element.firstChild).toBe viewRegistry.getView(panel.getItem())
|
||||
|
||||
it 'removes the element when the panel is destroyed', ->
|
||||
panel = new Panel({viewRegistry, item: new TestPanelItem})
|
||||
element = panel.getView()
|
||||
panel = new Panel({item: new TestPanelItem})
|
||||
element = atom.views.createView(panel, {viewRegistry})
|
||||
jasmineContent.appendChild(element)
|
||||
|
||||
expect(element.parentNode).toBe jasmineContent
|
||||
@@ -36,15 +43,15 @@ describe "PanelElement", ->
|
||||
|
||||
describe "changing panel visibility", ->
|
||||
it 'initially renders panel created with visibile: false', ->
|
||||
panel = new Panel({viewRegistry, visible: false, item: new TestPanelItem})
|
||||
element = panel.getView()
|
||||
panel = new Panel({visible: false, item: new TestPanelItem})
|
||||
element = atom.views.createView(panel, {viewRegistry})
|
||||
jasmineContent.appendChild(element)
|
||||
|
||||
expect(element.style.display).toBe 'none'
|
||||
|
||||
it 'hides and shows the panel element when Panel::hide() and Panel::show() are called', ->
|
||||
panel = new Panel({viewRegistry, item: new TestPanelItem})
|
||||
element = panel.getView()
|
||||
panel = new Panel({item: new TestPanelItem})
|
||||
element = atom.views.createView(panel, {viewRegistry})
|
||||
jasmineContent.appendChild(element)
|
||||
|
||||
expect(element.style.display).not.toBe 'none'
|
||||
@@ -57,8 +64,8 @@ describe "PanelElement", ->
|
||||
|
||||
describe "when a class name is specified", ->
|
||||
it 'initially renders panel created with visibile: false', ->
|
||||
panel = new Panel({viewRegistry, className: 'some classes', item: new TestPanelItem})
|
||||
element = panel.getView()
|
||||
panel = new Panel({className: 'some classes', item: new TestPanelItem})
|
||||
element = atom.views.createView(panel, {viewRegistry})
|
||||
jasmineContent.appendChild(element)
|
||||
|
||||
expect(element).toHaveClass 'some'
|
||||
|
||||
@@ -170,30 +170,30 @@ describe "Project", ->
|
||||
absolutePath = fs.absolute(__dirname)
|
||||
expect(atom.project.resolve(absolutePath)).toBe absolutePath
|
||||
|
||||
describe ".setPath(path)", ->
|
||||
describe ".setPaths(path)", ->
|
||||
describe "when path is a file", ->
|
||||
it "sets its path to the files parent directory and updates the root directory", ->
|
||||
atom.project.setPaths([require.resolve('./fixtures/dir/a')])
|
||||
expect(atom.project.getPaths()[0]).toEqual path.dirname(require.resolve('./fixtures/dir/a'))
|
||||
expect(atom.project.getRootDirectory().path).toEqual path.dirname(require.resolve('./fixtures/dir/a'))
|
||||
expect(atom.project.getDirectories()[0].path).toEqual path.dirname(require.resolve('./fixtures/dir/a'))
|
||||
|
||||
describe "when path is a directory", ->
|
||||
it "sets its path to the directory and updates the root directory", ->
|
||||
directory = fs.absolute(path.join(__dirname, 'fixtures', 'dir', 'a-dir'))
|
||||
atom.project.setPaths([directory])
|
||||
expect(atom.project.getPaths()[0]).toEqual directory
|
||||
expect(atom.project.getRootDirectory().path).toEqual directory
|
||||
expect(atom.project.getDirectories()[0].path).toEqual directory
|
||||
|
||||
describe "when path is null", ->
|
||||
it "sets its path and root directory to null", ->
|
||||
atom.project.setPaths([])
|
||||
expect(atom.project.getPaths()[0]?).toBeFalsy()
|
||||
expect(atom.project.getRootDirectory()?).toBeFalsy()
|
||||
expect(atom.project.getDirectories()[0]?).toBeFalsy()
|
||||
|
||||
it "normalizes the path to remove consecutive slashes, ., and .. segments", ->
|
||||
atom.project.setPaths(["#{require.resolve('./fixtures/dir/a')}#{path.sep}b#{path.sep}#{path.sep}.."])
|
||||
expect(atom.project.getPaths()[0]).toEqual path.dirname(require.resolve('./fixtures/dir/a'))
|
||||
expect(atom.project.getRootDirectory().path).toEqual path.dirname(require.resolve('./fixtures/dir/a'))
|
||||
expect(atom.project.getDirectories()[0].path).toEqual path.dirname(require.resolve('./fixtures/dir/a'))
|
||||
|
||||
describe ".replace()", ->
|
||||
[filePath, commentFilePath, sampleContent, sampleCommentContent] = []
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
SelectListView = require '../src/select-list-view'
|
||||
{$, $$} = require 'atom'
|
||||
{$, $$} = require '../src/space-pen-extensions'
|
||||
|
||||
describe "SelectListView", ->
|
||||
[selectList, items, list, filterEditorView] = []
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{View, $, $$} = require 'atom'
|
||||
{View, $, $$} = require '../src/space-pen-extensions'
|
||||
|
||||
describe "SpacePen extensions", ->
|
||||
class TestView extends View
|
||||
|
||||
@@ -9,12 +9,17 @@ _ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
Grim = require 'grim'
|
||||
KeymapManager = require '../src/keymap-extensions'
|
||||
{$, WorkspaceView, Workspace} = require 'atom'
|
||||
|
||||
# FIXME: Remove jquery from this
|
||||
{$} = require '../src/space-pen-extensions'
|
||||
|
||||
Config = require '../src/config'
|
||||
{Point} = require 'text-buffer'
|
||||
Project = require '../src/project'
|
||||
Workspace = require '../src/workspace'
|
||||
TextEditor = require '../src/text-editor'
|
||||
TextEditorView = require '../src/text-editor-view'
|
||||
TextEditorElement = require '../src/text-editor-element'
|
||||
TokenizedBuffer = require '../src/tokenized-buffer'
|
||||
TextEditorComponent = require '../src/text-editor-component'
|
||||
pathwatcher = require 'pathwatcher'
|
||||
@@ -76,13 +81,15 @@ beforeEach ->
|
||||
atom.commands.restoreSnapshot(commandsToRestore)
|
||||
atom.styles.restoreSnapshot(styleElementsToRestore)
|
||||
|
||||
atom.workspaceViewParentSelector = '#jasmine-content'
|
||||
|
||||
window.resetTimeouts()
|
||||
atom.packages.packageStates = {}
|
||||
|
||||
serializedWindowState = null
|
||||
|
||||
spyOn(atom, 'saveSync')
|
||||
atom.syntax.clearGrammarOverrides()
|
||||
atom.grammars.clearGrammarOverrides()
|
||||
|
||||
spy = spyOn(atom.packages, 'resolvePackagePath').andCallFake (packageName) ->
|
||||
if specPackageName and packageName is specPackageName
|
||||
@@ -111,8 +118,7 @@ beforeEach ->
|
||||
config.save.reset()
|
||||
|
||||
# make editor display updates synchronous
|
||||
spyOn(TextEditorView.prototype, 'requestDisplayUpdate').andCallFake -> @updateDisplay()
|
||||
TextEditorComponent.performSyncUpdates = true
|
||||
TextEditorElement::setUpdatedSynchronously(true)
|
||||
|
||||
spyOn(atom, "setRepresentedFilename")
|
||||
spyOn(window, "setTimeout").andCallFake window.fakeSetTimeout
|
||||
@@ -151,7 +157,7 @@ afterEach ->
|
||||
|
||||
jasmine.unspy(atom, 'saveSync')
|
||||
ensureNoPathSubscriptions()
|
||||
atom.syntax.clearObservers()
|
||||
atom.grammars.clearObservers()
|
||||
waits(0) # yield to ui thread to make screen update more frequently
|
||||
|
||||
ensureNoPathSubscriptions = ->
|
||||
@@ -196,6 +202,13 @@ jasmine.attachToDOM = (element) ->
|
||||
jasmineContent = document.querySelector('#jasmine-content')
|
||||
jasmineContent.appendChild(element) unless jasmineContent.contains(element)
|
||||
|
||||
deprecationsSnapshot = null
|
||||
jasmine.snapshotDeprecations = ->
|
||||
deprecationsSnapshot = Grim.getDeprecations() # suppress deprecations!!
|
||||
|
||||
jasmine.restoreDeprecationsSnapshot = ->
|
||||
Grim.grimDeprecations = deprecationsSnapshot
|
||||
|
||||
addCustomMatchers = (spec) ->
|
||||
spec.addMatchers
|
||||
toBeInstanceOf: (expected) ->
|
||||
@@ -291,6 +304,9 @@ window.waitsForPromise = (args...) ->
|
||||
jasmine.getEnv().currentSpec.fail("Expected promise to be resolved, but it was rejected with #{jasmine.pp(error)}")
|
||||
moveOn()
|
||||
|
||||
window.waitsForAnimationFrame = ->
|
||||
waitsFor "next animation frame", (done) -> requestAnimationFrame(done)
|
||||
|
||||
window.resetTimeouts = ->
|
||||
window.now = 0
|
||||
window.timeoutCount = 0
|
||||
|
||||
+29
-56
@@ -23,10 +23,10 @@ describe "the `syntax` global", ->
|
||||
describe "serialization", ->
|
||||
it "remembers grammar overrides by path", ->
|
||||
filePath = '/foo/bar/file.js'
|
||||
expect(atom.syntax.selectGrammar(filePath).name).not.toBe 'Ruby'
|
||||
atom.syntax.setGrammarOverrideForPath(filePath, 'source.ruby')
|
||||
syntax2 = atom.deserializers.deserialize(atom.syntax.serialize())
|
||||
syntax2.addGrammar(grammar) for grammar in atom.syntax.grammars when grammar isnt atom.syntax.nullGrammar
|
||||
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'
|
||||
|
||||
describe ".selectGrammar(filePath)", ->
|
||||
@@ -35,15 +35,15 @@ describe "the `syntax` global", ->
|
||||
atom.packages.activatePackage('language-git')
|
||||
|
||||
runs ->
|
||||
expect(atom.syntax.selectGrammar("file.js").name).toBe "JavaScript" # based on extension (.js)
|
||||
expect(atom.syntax.selectGrammar(path.join(temp.dir, '.git', 'config')).name).toBe "Git Config" # based on end of the path (.git/config)
|
||||
expect(atom.syntax.selectGrammar("Rakefile").name).toBe "Ruby" # based on the file's basename (Rakefile)
|
||||
expect(atom.syntax.selectGrammar("curb").name).toBe "Null Grammar"
|
||||
expect(atom.syntax.selectGrammar("/hu.git/config").name).toBe "Null Grammar"
|
||||
expect(atom.grammars.selectGrammar("file.js").name).toBe "JavaScript" # based on extension (.js)
|
||||
expect(atom.grammars.selectGrammar(path.join(temp.dir, '.git', 'config')).name).toBe "Git Config" # based on end of the path (.git/config)
|
||||
expect(atom.grammars.selectGrammar("Rakefile").name).toBe "Ruby" # based on the file's basename (Rakefile)
|
||||
expect(atom.grammars.selectGrammar("curb").name).toBe "Null Grammar"
|
||||
expect(atom.grammars.selectGrammar("/hu.git/config").name).toBe "Null Grammar"
|
||||
|
||||
it "uses the filePath's shebang line if the grammar cannot be determined by the extension or basename", ->
|
||||
filePath = require.resolve("./fixtures/shebang")
|
||||
expect(atom.syntax.selectGrammar(filePath).name).toBe "Ruby"
|
||||
expect(atom.grammars.selectGrammar(filePath).name).toBe "Ruby"
|
||||
|
||||
it "uses the number of newlines in the first line regex to determine the number of lines to test against", ->
|
||||
waitsForPromise ->
|
||||
@@ -51,28 +51,28 @@ describe "the `syntax` global", ->
|
||||
|
||||
runs ->
|
||||
fileContent = "first-line\n<html>"
|
||||
expect(atom.syntax.selectGrammar("dummy.coffee", fileContent).name).toBe "CoffeeScript"
|
||||
expect(atom.grammars.selectGrammar("dummy.coffee", fileContent).name).toBe "CoffeeScript"
|
||||
|
||||
fileContent = '<?xml version="1.0" encoding="UTF-8"?>'
|
||||
expect(atom.syntax.selectGrammar("grammar.tmLanguage", fileContent).name).toBe "Null Grammar"
|
||||
expect(atom.grammars.selectGrammar("grammar.tmLanguage", fileContent).name).toBe "Null Grammar"
|
||||
|
||||
fileContent += '\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">'
|
||||
expect(atom.syntax.selectGrammar("grammar.tmLanguage", fileContent).name).toBe "Property List (XML)"
|
||||
expect(atom.grammars.selectGrammar("grammar.tmLanguage", fileContent).name).toBe "Property List (XML)"
|
||||
|
||||
it "doesn't read the file when the file contents are specified", ->
|
||||
filePath = require.resolve("./fixtures/shebang")
|
||||
filePathContents = fs.readFileSync(filePath, 'utf8')
|
||||
spyOn(fs, 'read').andCallThrough()
|
||||
expect(atom.syntax.selectGrammar(filePath, filePathContents).name).toBe "Ruby"
|
||||
expect(atom.grammars.selectGrammar(filePath, filePathContents).name).toBe "Ruby"
|
||||
expect(fs.read).not.toHaveBeenCalled()
|
||||
|
||||
it "allows the default grammar to be overridden for a path", ->
|
||||
filePath = '/foo/bar/file.js'
|
||||
expect(atom.syntax.selectGrammar(filePath).name).not.toBe 'Ruby'
|
||||
atom.syntax.setGrammarOverrideForPath(filePath, 'source.ruby')
|
||||
expect(atom.syntax.selectGrammar(filePath).name).toBe 'Ruby'
|
||||
atom.syntax.clearGrammarOverrideForPath(filePath)
|
||||
expect(atom.syntax.selectGrammar(filePath).name).not.toBe 'Ruby'
|
||||
expect(atom.grammars.selectGrammar(filePath).name).not.toBe 'Ruby'
|
||||
atom.grammars.setGrammarOverrideForPath(filePath, 'source.ruby')
|
||||
expect(atom.grammars.selectGrammar(filePath).name).toBe 'Ruby'
|
||||
atom.grammars.clearGrammarOverrideForPath(filePath)
|
||||
expect(atom.grammars.selectGrammar(filePath).name).not.toBe 'Ruby'
|
||||
|
||||
describe "when multiple grammars have matching fileTypes", ->
|
||||
it "selects the grammar with the longest fileType match", ->
|
||||
@@ -82,8 +82,8 @@ describe "the `syntax` global", ->
|
||||
scopeName: 'source1'
|
||||
fileTypes: ['test']
|
||||
)
|
||||
grammar1 = atom.syntax.loadGrammarSync(grammarPath1)
|
||||
expect(atom.syntax.selectGrammar('more.test', '')).toBe grammar1
|
||||
grammar1 = atom.grammars.loadGrammarSync(grammarPath1)
|
||||
expect(atom.grammars.selectGrammar('more.test', '')).toBe grammar1
|
||||
|
||||
grammarPath2 = temp.path(suffix: '.json')
|
||||
fs.writeFileSync grammarPath2, JSON.stringify(
|
||||
@@ -91,44 +91,17 @@ describe "the `syntax` global", ->
|
||||
scopeName: 'source2'
|
||||
fileTypes: ['test', 'more.test']
|
||||
)
|
||||
grammar2 = atom.syntax.loadGrammarSync(grammarPath2)
|
||||
expect(atom.syntax.selectGrammar('more.test', '')).toBe grammar2
|
||||
grammar2 = atom.grammars.loadGrammarSync(grammarPath2)
|
||||
expect(atom.grammars.selectGrammar('more.test', '')).toBe grammar2
|
||||
|
||||
describe "when there is no file path", ->
|
||||
it "does not throw an exception (regression)", ->
|
||||
expect(-> atom.syntax.selectGrammar(null, '#!/usr/bin/ruby')).not.toThrow()
|
||||
expect(-> atom.syntax.selectGrammar(null, '')).not.toThrow()
|
||||
expect(-> atom.syntax.selectGrammar(null, null)).not.toThrow()
|
||||
expect(-> atom.grammars.selectGrammar(null, '#!/usr/bin/ruby')).not.toThrow()
|
||||
expect(-> atom.grammars.selectGrammar(null, '')).not.toThrow()
|
||||
expect(-> atom.grammars.selectGrammar(null, null)).not.toThrow()
|
||||
|
||||
describe ".removeGrammar(grammar)", ->
|
||||
it "removes the grammar, so it won't be returned by selectGrammar", ->
|
||||
grammar = atom.syntax.selectGrammar('foo.js')
|
||||
atom.syntax.removeGrammar(grammar)
|
||||
expect(atom.syntax.selectGrammar('foo.js').name).not.toBe grammar.name
|
||||
|
||||
describe ".getProperty(scopeDescriptor)", ->
|
||||
it "returns the property with the most specific scope selector", ->
|
||||
atom.syntax.addProperties(".source.coffee .string.quoted.double.coffee", foo: bar: baz: 42)
|
||||
atom.syntax.addProperties(".source .string.quoted.double", foo: bar: baz: 22)
|
||||
atom.syntax.addProperties(".source", foo: bar: baz: 11)
|
||||
|
||||
expect(atom.syntax.getProperty([".source.coffee", ".string.quoted.double.coffee"], "foo.bar.baz")).toBe 42
|
||||
expect(atom.syntax.getProperty([".source.js", ".string.quoted.double.js"], "foo.bar.baz")).toBe 22
|
||||
expect(atom.syntax.getProperty([".source.js", ".variable.assignment.js"], "foo.bar.baz")).toBe 11
|
||||
expect(atom.syntax.getProperty([".text"], "foo.bar.baz")).toBeUndefined()
|
||||
|
||||
it "favors the most recently added properties in the event of a specificity tie", ->
|
||||
atom.syntax.addProperties(".source.coffee .string.quoted.single", foo: bar: baz: 42)
|
||||
atom.syntax.addProperties(".source.coffee .string.quoted.double", foo: bar: baz: 22)
|
||||
|
||||
expect(atom.syntax.getProperty([".source.coffee", ".string.quoted.single"], "foo.bar.baz")).toBe 42
|
||||
expect(atom.syntax.getProperty([".source.coffee", ".string.quoted.single.double"], "foo.bar.baz")).toBe 22
|
||||
|
||||
describe ".removeProperties(name)", ->
|
||||
it "allows properties to be removed by name", ->
|
||||
atom.syntax.addProperties("a", ".source.coffee .string.quoted.double.coffee", foo: bar: baz: 42)
|
||||
atom.syntax.addProperties("b", ".source .string.quoted.double", foo: bar: baz: 22)
|
||||
|
||||
atom.syntax.removeProperties("b")
|
||||
expect(atom.syntax.getProperty([".source.js", ".string.quoted.double.js"], "foo.bar.baz")).toBeUndefined()
|
||||
expect(atom.syntax.getProperty([".source.coffee", ".string.quoted.double.coffee"], "foo.bar.baz")).toBe 42
|
||||
grammar = atom.grammars.selectGrammar('foo.js')
|
||||
atom.grammars.removeGrammar(grammar)
|
||||
expect(atom.grammars.selectGrammar('foo.js').name).not.toBe grammar.name
|
||||
|
||||
@@ -3,10 +3,12 @@ _ = require 'underscore-plus'
|
||||
|
||||
TextEditorView = require '../src/text-editor-view'
|
||||
TextEditorComponent = require '../src/text-editor-component'
|
||||
ViewRegistry = require '../src/view-registry'
|
||||
|
||||
nbsp = String.fromCharCode(160)
|
||||
|
||||
describe "TextEditorComponent", ->
|
||||
[contentNode, editor, wrapperView, wrapperNode, component, componentNode, verticalScrollbarNode, horizontalScrollbarNode] = []
|
||||
[viewRegistry, contentNode, editor, wrapperView, wrapperNode, component, componentNode, verticalScrollbarNode, horizontalScrollbarNode] = []
|
||||
[lineHeightInPixels, charWidth, nextAnimationFrame, noAnimationFrame, lineOverdrawMargin] = []
|
||||
|
||||
beforeEach ->
|
||||
@@ -31,19 +33,22 @@ describe "TextEditorComponent", ->
|
||||
atom.project.open('sample.js').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
viewRegistry = new ViewRegistry(atom.views)
|
||||
|
||||
contentNode = document.querySelector('#jasmine-content')
|
||||
contentNode.style.width = '1000px'
|
||||
|
||||
wrapperView = new TextEditorView(editor, {lineOverdrawMargin})
|
||||
wrapperView.attachToDom()
|
||||
wrapperNode = wrapperView.element
|
||||
wrapperNode = atom.views.createView(editor, {viewRegistry, lineOverdrawMargin})
|
||||
wrapperNode.setUpdatedSynchronously(false)
|
||||
jasmine.attachToDOM(wrapperNode)
|
||||
|
||||
{component} = wrapperView
|
||||
component.performSyncUpdates = false
|
||||
{component} = wrapperNode
|
||||
component.setFontFamily('monospace')
|
||||
component.setLineHeight(1.3)
|
||||
component.setFontSize(20)
|
||||
|
||||
wrapperView = wrapperNode.__spacePenView
|
||||
|
||||
lineHeightInPixels = editor.getLineHeightInPixels()
|
||||
charWidth = editor.getDefaultCharWidth()
|
||||
componentNode = component.getDOMNode()
|
||||
@@ -302,7 +307,7 @@ describe "TextEditorComponent", ->
|
||||
|
||||
it "interleaves invisible line-ending characters with indent guides on empty lines", ->
|
||||
component.setShowIndentGuide(true)
|
||||
editor.setTextInBufferRange([[10, 0], [11, 0]], "\r\n", false)
|
||||
editor.setTextInBufferRange([[10, 0], [11, 0]], "\r\n", normalizeLineEndings: false)
|
||||
nextAnimationFrame()
|
||||
expect(component.lineNodeForScreenRow(10).innerHTML).toBe '<span class="indent-guide"><span class="invisible-character">C</span><span class="invisible-character">E</span></span>'
|
||||
|
||||
@@ -1247,7 +1252,7 @@ describe "TextEditorComponent", ->
|
||||
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", ->
|
||||
it "renders at the head of the marker by default", ->
|
||||
marker = editor.displayBuffer.markBufferRange([[2, 5], [2, 10]], invalidate: 'never')
|
||||
decoration = editor.decorateMarker(marker, {type: 'overlay', item})
|
||||
nextAnimationFrame()
|
||||
@@ -1269,6 +1274,17 @@ describe "TextEditorComponent", ->
|
||||
expect(overlay.style.left).toBe position.left + '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()
|
||||
|
||||
position = editor.pixelPositionForBufferPosition([2, 5])
|
||||
|
||||
overlay = component.getTopmostDOMNode().querySelector('atom-overlay')
|
||||
expect(overlay.style.left).toBe position.left + 'px'
|
||||
expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px'
|
||||
|
||||
describe "positioning the overlay when near the edge of the editor", ->
|
||||
[itemWidth, itemHeight] = []
|
||||
beforeEach ->
|
||||
@@ -2532,7 +2548,7 @@ describe "TextEditorComponent", ->
|
||||
describe "grammar data attributes", ->
|
||||
it "adds and updates the grammar data attribute based on the current grammar", ->
|
||||
expect(wrapperNode.dataset.grammar).toBe 'source js'
|
||||
editor.setGrammar(atom.syntax.nullGrammar)
|
||||
editor.setGrammar(atom.grammars.nullGrammar)
|
||||
expect(wrapperNode.dataset.grammar).toBe 'text plain null-grammar'
|
||||
|
||||
describe "encoding data attributes", ->
|
||||
|
||||
@@ -98,3 +98,23 @@ describe "TextEditorElement", ->
|
||||
verticalScrollbarNode = element.querySelector(".vertical-scrollbar")
|
||||
scrollbarWidth = verticalScrollbarNode.offsetWidth - verticalScrollbarNode.clientWidth
|
||||
expect(scrollbarWidth).toEqual(8)
|
||||
|
||||
describe "::setUpdatedSynchronously", ->
|
||||
it "controls whether the text editor is updated synchronously", ->
|
||||
element = new TextEditorElement
|
||||
jasmine.attachToDOM(element)
|
||||
|
||||
element.setUpdatedSynchronously(false)
|
||||
expect(element.isUpdatedSynchronously()).toBe false
|
||||
|
||||
element.getModel().setText("hello")
|
||||
expect(element.shadowRoot.textContent).not.toContain "hello"
|
||||
|
||||
waitsForAnimationFrame()
|
||||
|
||||
runs ->
|
||||
expect(element.shadowRoot.textContent).toContain "hello"
|
||||
|
||||
element.setUpdatedSynchronously(true)
|
||||
element.getModel().setText("goodbye")
|
||||
expect(element.shadowRoot.textContent).toContain "goodbye"
|
||||
|
||||
@@ -616,7 +616,7 @@ describe "TextEditor", ->
|
||||
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', false)
|
||||
buffer.setTextInRange([[1, 0], [1, Infinity]], '\t\t\ta', normalizeLineEndings: false)
|
||||
|
||||
editor.setCursorScreenPosition [1,7]
|
||||
editor.moveToFirstCharacterOfLine()
|
||||
@@ -2607,69 +2607,44 @@ describe "TextEditor", ->
|
||||
atom.clipboard.write(" z();")
|
||||
editor.setCursorBufferPosition([1, Infinity])
|
||||
editor.pasteText()
|
||||
|
||||
console.log JSON.stringify(editor.lineTextForBufferRow(1))
|
||||
expect(editor.lineTextForBufferRow(1)).toBe(" y(); z();")
|
||||
|
||||
describe "when `autoIndentOnPaste` is false", ->
|
||||
beforeEach ->
|
||||
atom.config.set('editor.autoIndentOnPaste', false)
|
||||
|
||||
describe "when the inserted text contains no newlines", ->
|
||||
it "does not adjust the indentation level of the text", ->
|
||||
editor.setCursorBufferPosition([5, 2])
|
||||
editor.insertText("foo", indentBasis: 5)
|
||||
expect(editor.lineTextForBufferRow(5)).toBe " foo current = items.shift();"
|
||||
describe "when the cursor is indented further than the original copied text", ->
|
||||
it "increases the indentation of the copied lines to match", ->
|
||||
editor.setSelectedBufferRange([[1, 2], [3, 0]])
|
||||
editor.copySelectedText()
|
||||
|
||||
it "does not adjust the whitespace if there are preceding characters", ->
|
||||
copyText(" foo")
|
||||
editor.setCursorBufferPosition([5, 30])
|
||||
editor.setCursorBufferPosition([5, 6])
|
||||
editor.pasteText()
|
||||
|
||||
expect(editor.lineTextForBufferRow(5)).toBe " current = items.shift(); foo"
|
||||
expect(editor.lineTextForBufferRow(5)).toBe " var sort = function(items) {"
|
||||
expect(editor.lineTextForBufferRow(6)).toBe " if (items.length <= 1) return items;"
|
||||
|
||||
describe "when the inserted text contains newlines", ->
|
||||
describe "when the cursor is preceded only by whitespace characters", ->
|
||||
it "normalizes indented lines to each cursor's current indentation level", ->
|
||||
editor.setSelectedBufferRanges([
|
||||
[[1,2], [3,0]],
|
||||
[[4,4], [6,0]]
|
||||
])
|
||||
editor.copySelectedText()
|
||||
expect(atom.clipboard.read()).toEqual """
|
||||
var sort = function(items) {
|
||||
if (items.length <= 1) return items;
|
||||
describe "when the cursor is indented less far than the original copied text", ->
|
||||
it "decreases the indentation of the copied lines to match", ->
|
||||
editor.setSelectedBufferRange([[6, 6], [8, 0]])
|
||||
editor.copySelectedText()
|
||||
|
||||
while(items.length > 0) {
|
||||
current = items.shift();
|
||||
editor.setCursorBufferPosition([1, 2])
|
||||
editor.pasteText()
|
||||
|
||||
"""
|
||||
expect(editor.lineTextForBufferRow(1)).toBe " current < pivot ? left.push(current) : right.push(current);"
|
||||
expect(editor.lineTextForBufferRow(2)).toBe "}"
|
||||
|
||||
editor.setCursorBufferPosition([0,0])
|
||||
editor.insertNewlineAbove()
|
||||
editor.setSelectedBufferRanges([
|
||||
[[0,0], [0,0]],
|
||||
[[1,0], [1,0]]
|
||||
])
|
||||
editor.pasteText()
|
||||
describe "when the first copied line has leading whitespace", ->
|
||||
it "preserves the line's leading whitespace", ->
|
||||
editor.setSelectedBufferRange([[4, 0], [6, 0]])
|
||||
editor.copySelectedText()
|
||||
|
||||
expect(editor.lineTextForBufferRow(0)).toBe "var sort = function(items) {"
|
||||
console.log JSON.stringify(editor.lineTextForBufferRow(1))
|
||||
expect(editor.lineTextForBufferRow(1)).toBe " if (items.length <= 1) return items;"
|
||||
expect(editor.lineTextForBufferRow(2)).toBe ""
|
||||
expect(editor.lineTextForBufferRow(3)).toBe "while(items.length > 0) {"
|
||||
expect(editor.lineTextForBufferRow(4)).toBe " current = items.shift();"
|
||||
editor.setCursorBufferPosition([0, 0])
|
||||
editor.pasteText()
|
||||
|
||||
describe "when the cursor is preceded by non-whitespace characters", ->
|
||||
it "normalizes the indentation level of all lines based on the level of the existing first line", ->
|
||||
copyText(" while (true) {\n foo();\n }\n", {startColumn: 0})
|
||||
editor.setCursorBufferPosition([1, Infinity])
|
||||
editor.pasteText()
|
||||
|
||||
expect(editor.lineTextForBufferRow(1)).toBe " var sort = function(items) {while (true) {"
|
||||
expect(editor.lineTextForBufferRow(2)).toBe " foo();"
|
||||
expect(editor.lineTextForBufferRow(3)).toBe " }"
|
||||
expect(editor.lineTextForBufferRow(4)).toBe ""
|
||||
expect(editor.lineTextForBufferRow(0)).toBe " while(items.length > 0) {"
|
||||
expect(editor.lineTextForBufferRow(1)).toBe " current = items.shift();"
|
||||
|
||||
describe 'when the clipboard has many selections', ->
|
||||
beforeEach ->
|
||||
@@ -3039,18 +3014,16 @@ describe "TextEditor", ->
|
||||
expect(editor.isFoldedAtBufferRow(1)).toBeFalsy()
|
||||
expect(editor.isFoldedAtBufferRow(2)).toBeTruthy()
|
||||
|
||||
describe "begin/commitTransaction()", ->
|
||||
describe "::transact", ->
|
||||
it "restores the selection when the transaction is undone/redone", ->
|
||||
buffer.setText('1234')
|
||||
editor.setSelectedBufferRange([[0, 1], [0, 3]])
|
||||
editor.beginTransaction()
|
||||
|
||||
editor.delete()
|
||||
editor.moveToEndOfLine()
|
||||
editor.insertText('5')
|
||||
expect(buffer.getText()).toBe '145'
|
||||
|
||||
editor.commitTransaction()
|
||||
editor.transact ->
|
||||
editor.delete()
|
||||
editor.moveToEndOfLine()
|
||||
editor.insertText('5')
|
||||
expect(buffer.getText()).toBe '145'
|
||||
|
||||
editor.undo()
|
||||
expect(buffer.getText()).toBe '1234'
|
||||
@@ -3357,17 +3330,17 @@ describe "TextEditor", ->
|
||||
it "switches to the better-matched grammar and re-tokenizes the buffer", ->
|
||||
editor.destroy()
|
||||
|
||||
jsGrammar = atom.syntax.selectGrammar('a.js')
|
||||
atom.syntax.removeGrammar(jsGrammar)
|
||||
jsGrammar = atom.grammars.selectGrammar('a.js')
|
||||
atom.grammars.removeGrammar(jsGrammar)
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.js', autoIndent: false).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(editor.getGrammar()).toBe atom.syntax.nullGrammar
|
||||
expect(editor.getGrammar()).toBe atom.grammars.nullGrammar
|
||||
expect(editor.tokenizedLineForScreenRow(0).tokens.length).toBe 1
|
||||
|
||||
atom.syntax.addGrammar(jsGrammar)
|
||||
atom.grammars.addGrammar(jsGrammar)
|
||||
expect(editor.getGrammar()).toBe jsGrammar
|
||||
expect(editor.tokenizedLineForScreenRow(0).tokens.length).toBeGreaterThan 1
|
||||
|
||||
@@ -3787,7 +3760,7 @@ describe "TextEditor", ->
|
||||
|
||||
it "updates the grammar based on grammar overrides", ->
|
||||
expect(editor.getGrammar().name).toBe 'JavaScript'
|
||||
atom.syntax.setGrammarOverrideForPath(editor.getPath(), 'source.coffee')
|
||||
atom.grammars.setGrammarOverrideForPath(editor.getPath(), 'source.coffee')
|
||||
editor.reloadGrammar()
|
||||
expect(editor.getGrammar().name).toBe 'CoffeeScript'
|
||||
|
||||
@@ -3805,7 +3778,7 @@ describe "TextEditor", ->
|
||||
atom.packages.activatePackage('language-hyperlink')
|
||||
|
||||
runs ->
|
||||
grammar = atom.syntax.selectGrammar("text.js")
|
||||
grammar = atom.grammars.selectGrammar("text.js")
|
||||
{tokens} = grammar.tokenizeLine("var i; // http://github.com")
|
||||
|
||||
expect(tokens[0].value).toBe "var"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
path = require 'path'
|
||||
|
||||
{$, $$, WorkspaceView} = require 'atom'
|
||||
{$, $$} = require '../src/space-pen-extensions'
|
||||
fs = require 'fs-plus'
|
||||
temp = require 'temp'
|
||||
|
||||
@@ -20,8 +20,12 @@ describe "ThemeManager", ->
|
||||
|
||||
describe "theme getters and setters", ->
|
||||
beforeEach ->
|
||||
jasmine.snapshotDeprecations()
|
||||
atom.packages.loadPackages()
|
||||
|
||||
afterEach ->
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
it 'getLoadedThemes get all the loaded themes', ->
|
||||
themes = themeManager.getLoadedThemes()
|
||||
expect(themes.length).toBeGreaterThan(2)
|
||||
@@ -130,15 +134,24 @@ describe "ThemeManager", ->
|
||||
expect(-> atom.packages.activatePackage('a-theme-that-will-not-be-found')).toThrow()
|
||||
|
||||
describe "::requireStylesheet(path)", ->
|
||||
beforeEach ->
|
||||
jasmine.snapshotDeprecations()
|
||||
|
||||
afterEach ->
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
it "synchronously loads css at the given path and installs a style tag for it in the head", ->
|
||||
atom.styles.onDidAddStyleElement styleElementAddedHandler = jasmine.createSpy("styleElementAddedHandler")
|
||||
themeManager.onDidChangeStylesheets stylesheetsChangedHandler = jasmine.createSpy("stylesheetsChangedHandler")
|
||||
themeManager.onDidAddStylesheet stylesheetAddedHandler = jasmine.createSpy("stylesheetAddedHandler")
|
||||
|
||||
cssPath = atom.project.resolve('css.css')
|
||||
lengthBefore = $('head style').length
|
||||
|
||||
themeManager.requireStylesheet(cssPath)
|
||||
expect($('head style').length).toBe lengthBefore + 1
|
||||
|
||||
expect(styleElementAddedHandler).toHaveBeenCalled()
|
||||
expect(stylesheetAddedHandler).toHaveBeenCalled()
|
||||
expect(stylesheetsChangedHandler).toHaveBeenCalled()
|
||||
|
||||
@@ -148,8 +161,10 @@ describe "ThemeManager", ->
|
||||
expect(element[0].sheet).toBe stylesheetAddedHandler.argsForCall[0][0]
|
||||
|
||||
# doesn't append twice
|
||||
styleElementAddedHandler.reset()
|
||||
themeManager.requireStylesheet(cssPath)
|
||||
expect($('head style').length).toBe lengthBefore + 1
|
||||
expect(styleElementAddedHandler).not.toHaveBeenCalled()
|
||||
|
||||
$('head style[id*="css.css"]').remove()
|
||||
|
||||
@@ -192,6 +207,7 @@ describe "ThemeManager", ->
|
||||
disposable = themeManager.requireStylesheet(cssPath)
|
||||
expect($(document.body).css('font-weight')).toBe("bold")
|
||||
|
||||
atom.styles.onDidRemoveStyleElement styleElementRemovedHandler = jasmine.createSpy("styleElementRemovedHandler")
|
||||
themeManager.onDidRemoveStylesheet stylesheetRemovedHandler = jasmine.createSpy("stylesheetRemovedHandler")
|
||||
themeManager.onDidChangeStylesheets stylesheetsChangedHandler = jasmine.createSpy("stylesheetsChangedHandler")
|
||||
|
||||
@@ -199,6 +215,7 @@ describe "ThemeManager", ->
|
||||
|
||||
expect($(document.body).css('font-weight')).not.toBe("bold")
|
||||
|
||||
expect(styleElementRemovedHandler).toHaveBeenCalled()
|
||||
expect(stylesheetRemovedHandler).toHaveBeenCalled()
|
||||
stylesheet = stylesheetRemovedHandler.argsForCall[0][0]
|
||||
expect(stylesheet instanceof CSSStyleSheet).toBe true
|
||||
@@ -209,13 +226,18 @@ describe "ThemeManager", ->
|
||||
describe "base stylesheet loading", ->
|
||||
workspaceElement = null
|
||||
beforeEach ->
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
jasmine.snapshotDeprecations()
|
||||
|
||||
workspaceElement = atom.views.createView(atom.workspace)
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
workspaceElement.appendChild document.createElement('atom-text-editor')
|
||||
|
||||
waitsForPromise ->
|
||||
themeManager.activateThemes()
|
||||
|
||||
beforeEach ->
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
it "loads the correct values from the theme's ui-variables file", ->
|
||||
themeManager.onDidReloadAll reloadHandler = jasmine.createSpy()
|
||||
atom.config.set('core.themes', ['theme-with-ui-variables', 'theme-with-syntax-variables'])
|
||||
@@ -265,7 +287,14 @@ describe "ThemeManager", ->
|
||||
expect(workspaceElement).not.toHaveClass 'theme-atom-dark-syntax'
|
||||
|
||||
describe "when the user stylesheet changes", ->
|
||||
beforeEach ->
|
||||
jasmine.snapshotDeprecations()
|
||||
|
||||
afterEach ->
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
it "reloads it", ->
|
||||
[styleElementAddedHandler, styleElementRemovedHandler] = []
|
||||
[stylesheetRemovedHandler, stylesheetAddedHandler, stylesheetsChangedHandler] = []
|
||||
userStylesheetPath = path.join(temp.mkdirSync("atom"), 'styles.less')
|
||||
fs.writeFileSync(userStylesheetPath, 'body {border-style: dotted !important;}')
|
||||
@@ -275,6 +304,9 @@ describe "ThemeManager", ->
|
||||
themeManager.activateThemes()
|
||||
|
||||
runs ->
|
||||
atom.styles.onDidRemoveStyleElement styleElementRemovedHandler = jasmine.createSpy("styleElementRemovedHandler")
|
||||
atom.styles.onDidAddStyleElement styleElementAddedHandler = jasmine.createSpy("styleElementAddedHandler")
|
||||
|
||||
themeManager.onDidChangeStylesheets stylesheetsChangedHandler = jasmine.createSpy("stylesheetsChangedHandler")
|
||||
themeManager.onDidRemoveStylesheet stylesheetRemovedHandler = jasmine.createSpy("stylesheetRemovedHandler")
|
||||
themeManager.onDidAddStylesheet stylesheetAddedHandler = jasmine.createSpy("stylesheetAddedHandler")
|
||||
@@ -289,14 +321,19 @@ describe "ThemeManager", ->
|
||||
runs ->
|
||||
expect($(document.body).css('border-style')).toBe 'dashed'
|
||||
|
||||
expect(styleElementRemovedHandler).toHaveBeenCalled()
|
||||
expect(styleElementRemovedHandler.argsForCall[0][0].textContent).toContain 'dotted'
|
||||
expect(stylesheetRemovedHandler).toHaveBeenCalled()
|
||||
expect(stylesheetRemovedHandler.argsForCall[0][0].cssRules[0].style.border).toBe 'dotted'
|
||||
|
||||
expect(styleElementAddedHandler).toHaveBeenCalled()
|
||||
expect(styleElementAddedHandler.argsForCall[0][0].textContent).toContain 'dashed'
|
||||
expect(stylesheetAddedHandler).toHaveBeenCalled()
|
||||
expect(stylesheetAddedHandler.argsForCall[0][0].cssRules[0].style.border).toBe 'dashed'
|
||||
|
||||
expect(stylesheetsChangedHandler).toHaveBeenCalled()
|
||||
|
||||
styleElementRemovedHandler.reset()
|
||||
stylesheetRemovedHandler.reset()
|
||||
stylesheetsChangedHandler.reset()
|
||||
fs.removeSync(userStylesheetPath)
|
||||
@@ -305,6 +342,8 @@ describe "ThemeManager", ->
|
||||
themeManager.loadUserStylesheet.callCount is 2
|
||||
|
||||
runs ->
|
||||
expect(styleElementRemovedHandler).toHaveBeenCalled()
|
||||
expect(styleElementRemovedHandler.argsForCall[0][0].textContent).toContain 'dashed'
|
||||
expect(stylesheetRemovedHandler).toHaveBeenCalled()
|
||||
expect(stylesheetRemovedHandler.argsForCall[0][0].cssRules[0].style.border).toBe 'dashed'
|
||||
expect($(document.body).css('border-style')).toBe 'none'
|
||||
|
||||
@@ -522,7 +522,7 @@ describe "TokenizedBuffer", ->
|
||||
buffer = atom.project.bufferForPathSync()
|
||||
buffer.setText "<div class='name'><%= User.find(2).full_name %></div>"
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
tokenizedBuffer.setGrammar(atom.syntax.selectGrammar('test.erb'))
|
||||
tokenizedBuffer.setGrammar(atom.grammars.selectGrammar('test.erb'))
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
|
||||
{tokens} = tokenizedBuffer.tokenizedLineForRow(0)
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
ViewRegistry = require '../src/view-registry'
|
||||
ViewFactory = require '../src/view-factory'
|
||||
{View} = require '../src/space-pen-extensions'
|
||||
|
||||
describe "ViewRegistry", ->
|
||||
registry = null
|
||||
describe "ViewFactory", ->
|
||||
factory = null
|
||||
|
||||
beforeEach ->
|
||||
registry = new ViewRegistry
|
||||
factory = new ViewFactory
|
||||
|
||||
describe "::getView(object)", ->
|
||||
describe "::createView(object, params)", ->
|
||||
describe "when passed a DOM node", ->
|
||||
it "returns the given DOM node", ->
|
||||
node = document.createElement('div')
|
||||
expect(registry.getView(node)).toBe node
|
||||
expect(factory.createView(node)).toBe node
|
||||
|
||||
describe "when passed a SpacePen view", ->
|
||||
it "returns the root node of the view with a __spacePenView property pointing at the SpacePen view", ->
|
||||
@@ -19,56 +19,65 @@ describe "ViewRegistry", ->
|
||||
@content: -> @div "Hello"
|
||||
|
||||
view = new TestView
|
||||
node = registry.getView(view)
|
||||
node = factory.createView(view)
|
||||
expect(node.textContent).toBe "Hello"
|
||||
expect(node.__spacePenView).toBe view
|
||||
|
||||
describe "when passed a model object", ->
|
||||
describe "when a view provider is registered matching the object's constructor", ->
|
||||
describe "when the provider has a viewConstructor property", ->
|
||||
it "constructs a view element and assigns the model on it", ->
|
||||
it "constructs a view element and calls initialize on it with the creation params", ->
|
||||
class TestModel
|
||||
|
||||
class TestModelSubclass extends TestModel
|
||||
|
||||
class TestView
|
||||
setModel: (@model) ->
|
||||
initialize: (@params) ->
|
||||
|
||||
model = new TestModel
|
||||
|
||||
registry.addViewProvider
|
||||
factory.addViewProvider
|
||||
modelConstructor: TestModel
|
||||
viewConstructor: TestView
|
||||
|
||||
view = registry.getView(model)
|
||||
view = factory.createView(model, a: 1)
|
||||
expect(view instanceof TestView).toBe true
|
||||
expect(view.model).toBe model
|
||||
expect(view.params.a).toBe 1
|
||||
expect(view.params.model).toBe model
|
||||
expect(view.params.viewFactory).toBe factory
|
||||
|
||||
subclassModel = new TestModelSubclass
|
||||
view2 = registry.getView(subclassModel)
|
||||
view2 = factory.createView(subclassModel)
|
||||
expect(view2 instanceof TestView).toBe true
|
||||
expect(view2.model).toBe subclassModel
|
||||
expect(view2.params.model).toBe subclassModel
|
||||
|
||||
describe "when the provider has a createView method", ->
|
||||
it "constructs a view element by calling the createView method with the model", ->
|
||||
it "constructs a view element by calling the createView method with the creation params", ->
|
||||
class TestModel
|
||||
class TestView
|
||||
setModel: (@model) ->
|
||||
initialize: (@params) ->
|
||||
|
||||
registry.addViewProvider
|
||||
factory.addViewProvider
|
||||
modelConstructor: TestModel
|
||||
createView: (model) ->
|
||||
createView: (params) ->
|
||||
view = new TestView
|
||||
view.setModel(model)
|
||||
view.initialize(params)
|
||||
view
|
||||
|
||||
model = new TestModel
|
||||
view = registry.getView(model)
|
||||
view = factory.createView(model, a: 1)
|
||||
expect(view instanceof TestView).toBe true
|
||||
expect(view.model).toBe model
|
||||
expect(view.params.a).toBe 1
|
||||
expect(view.params.model).toBe model
|
||||
|
||||
describe "when no view provider is registered for the object's constructor", ->
|
||||
describe "when the object has a .getViewClass() method", ->
|
||||
describe "when the object has a .createViewClass() method", ->
|
||||
beforeEach ->
|
||||
jasmine.snapshotDeprecations()
|
||||
|
||||
afterEach ->
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
it "builds an instance of the view class with the model, then returns its root node with a __spacePenView property pointing at the view", ->
|
||||
class TestView extends View
|
||||
@content: (model) -> @div model.name
|
||||
@@ -79,29 +88,26 @@ describe "ViewRegistry", ->
|
||||
getViewClass: -> TestView
|
||||
|
||||
model = new TestModel("hello")
|
||||
node = registry.getView(model)
|
||||
node = factory.createView(model)
|
||||
|
||||
expect(node.textContent).toBe "hello"
|
||||
view = node.__spacePenView
|
||||
expect(view instanceof TestView).toBe true
|
||||
expect(view.model).toBe model
|
||||
|
||||
# returns the same DOM node for repeated calls
|
||||
expect(registry.getView(model)).toBe node
|
||||
|
||||
describe "when the object has no .getViewClass() method", ->
|
||||
describe "when the object has no .createViewClass() method", ->
|
||||
it "throws an exception", ->
|
||||
expect(-> registry.getView(new Object)).toThrow()
|
||||
expect(-> factory.createView(new Object)).toThrow()
|
||||
|
||||
describe "::addViewProvider(providerSpec)", ->
|
||||
it "returns a disposable that can be used to remove the provider", ->
|
||||
class TestModel
|
||||
class TestView
|
||||
setModel: (@model) ->
|
||||
disposable = registry.addViewProvider
|
||||
initialize: ->
|
||||
disposable = factory.addViewProvider
|
||||
modelConstructor: TestModel
|
||||
viewConstructor: TestView
|
||||
|
||||
expect(registry.getView(new TestModel) instanceof TestView).toBe true
|
||||
expect(factory.createView(new TestModel) instanceof TestView).toBe true
|
||||
disposable.dispose()
|
||||
expect(-> registry.getView(new TestModel)).toThrow()
|
||||
expect(-> factory.createView(new TestModel)).toThrow()
|
||||
@@ -1,4 +1,4 @@
|
||||
{$, $$} = require 'atom'
|
||||
{$, $$} = require '../src/space-pen-extensions'
|
||||
path = require 'path'
|
||||
TextEditor = require '../src/text-editor'
|
||||
WindowEventHandler = require '../src/window-event-handler'
|
||||
@@ -95,13 +95,13 @@ describe "Window", ->
|
||||
describe ".unloadEditorWindow()", ->
|
||||
it "saves the serialized state of the window so it can be deserialized after reload", ->
|
||||
workspaceState = atom.workspace.serialize()
|
||||
syntaxState = atom.syntax.serialize()
|
||||
syntaxState = atom.grammars.serialize()
|
||||
projectState = atom.project.serialize()
|
||||
|
||||
atom.unloadEditorWindow()
|
||||
|
||||
expect(atom.state.workspace).toEqual workspaceState
|
||||
expect(atom.state.syntax).toEqual syntaxState
|
||||
expect(atom.state.grammars).toEqual syntaxState
|
||||
expect(atom.state.project).toEqual projectState
|
||||
expect(atom.saveSync).toHaveBeenCalled()
|
||||
|
||||
@@ -259,24 +259,23 @@ describe "Window", ->
|
||||
|
||||
describe "when the opened path exists", ->
|
||||
it "sets the project path to the opened path", ->
|
||||
$(window).trigger('window:open-path', [{pathToOpen: __filename}])
|
||||
|
||||
atom.getCurrentWindow().send 'message', 'open-path', pathToOpen: __filename
|
||||
expect(atom.project.getPaths()[0]).toBe __dirname
|
||||
|
||||
describe "when the opened path does not exist but its parent directory does", ->
|
||||
it "sets the project path to the opened path's parent directory", ->
|
||||
$(window).trigger('window:open-path', [{pathToOpen: path.join(__dirname, 'this-path-does-not-exist.txt')}])
|
||||
|
||||
pathToOpen = path.join(__dirname, 'this-path-does-not-exist.txt')
|
||||
atom.getCurrentWindow().send 'message', 'open-path', {pathToOpen}
|
||||
expect(atom.project.getPaths()[0]).toBe __dirname
|
||||
|
||||
describe "when the opened path is a file", ->
|
||||
it "opens it in the workspace", ->
|
||||
$(window).trigger('window:open-path', [{pathToOpen: __filename}])
|
||||
atom.getCurrentWindow().send 'message', 'open-path', pathToOpen: __filename
|
||||
|
||||
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", ->
|
||||
$(window).trigger('window:open-path', [{pathToOpen: __dirname}])
|
||||
atom.getCurrentWindow().send 'message', 'open-path', pathToOpen: __dirname
|
||||
|
||||
expect(atom.workspace.open.callCount).toBe 0
|
||||
|
||||
@@ -375,7 +375,7 @@ describe "Workspace", ->
|
||||
describe "document.title", ->
|
||||
describe "when the project has no path", ->
|
||||
it "sets the title to 'untitled'", ->
|
||||
atom.project.setPath(undefined)
|
||||
atom.project.setPaths([])
|
||||
expect(document.title).toBe 'untitled - Atom'
|
||||
|
||||
describe "when the project has a path", ->
|
||||
@@ -458,46 +458,59 @@ describe "Workspace", ->
|
||||
expect(atom.setDocumentEdited).toHaveBeenCalledWith(false)
|
||||
|
||||
describe "adding panels", ->
|
||||
class TestPanel
|
||||
constructior: ->
|
||||
class TestItem
|
||||
|
||||
describe '::addLeftPanel(model)', ->
|
||||
it 'adds a panel to the correct panel container', ->
|
||||
expect(atom.workspace.getLeftPanels().length).toBe(0)
|
||||
atom.workspace.panelContainers.left.onDidAddPanel addPanelSpy = jasmine.createSpy()
|
||||
panel = atom.workspace.addLeftPanel(item: new TestPanel())
|
||||
|
||||
model = new TestItem
|
||||
panel = atom.workspace.addLeftPanel(item: model)
|
||||
|
||||
expect(panel).toBeDefined()
|
||||
expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 0})
|
||||
|
||||
describe '::addRightPanel(model)', ->
|
||||
it 'adds a panel to the correct panel container', ->
|
||||
expect(atom.workspace.getRightPanels().length).toBe(0)
|
||||
atom.workspace.panelContainers.right.onDidAddPanel addPanelSpy = jasmine.createSpy()
|
||||
panel = atom.workspace.addRightPanel(item: new TestPanel())
|
||||
|
||||
model = new TestItem
|
||||
panel = atom.workspace.addRightPanel(item: model)
|
||||
|
||||
expect(panel).toBeDefined()
|
||||
expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 0})
|
||||
|
||||
describe '::addTopPanel(model)', ->
|
||||
it 'adds a panel to the correct panel container', ->
|
||||
expect(atom.workspace.getTopPanels().length).toBe(0)
|
||||
atom.workspace.panelContainers.top.onDidAddPanel addPanelSpy = jasmine.createSpy()
|
||||
panel = atom.workspace.addTopPanel(item: new TestPanel())
|
||||
|
||||
model = new TestItem
|
||||
panel = atom.workspace.addTopPanel(item: model)
|
||||
|
||||
expect(panel).toBeDefined()
|
||||
expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 0})
|
||||
|
||||
describe '::addBottomPanel(model)', ->
|
||||
it 'adds a panel to the correct panel container', ->
|
||||
expect(atom.workspace.getBottomPanels().length).toBe(0)
|
||||
atom.workspace.panelContainers.bottom.onDidAddPanel addPanelSpy = jasmine.createSpy()
|
||||
panel = atom.workspace.addBottomPanel(item: new TestPanel())
|
||||
|
||||
model = new TestItem
|
||||
panel = atom.workspace.addBottomPanel(item: model)
|
||||
|
||||
expect(panel).toBeDefined()
|
||||
expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 0})
|
||||
|
||||
describe '::addModalPanel(model)', ->
|
||||
it 'adds a panel to the correct panel container', ->
|
||||
expect(atom.workspace.getModalPanels().length).toBe(0)
|
||||
atom.workspace.panelContainers.modal.onDidAddPanel addPanelSpy = jasmine.createSpy()
|
||||
panel = atom.workspace.addModalPanel(item: new TestPanel())
|
||||
|
||||
model = new TestItem
|
||||
panel = atom.workspace.addModalPanel(item: model)
|
||||
|
||||
expect(panel).toBeDefined()
|
||||
expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 0})
|
||||
expect(panel.getClassName()).toBe 'overlay from-top' # the default
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{$, $$, WorkspaceView, View} = require 'atom'
|
||||
{$, $$, View} = require '../src/space-pen-extensions'
|
||||
Q = require 'q'
|
||||
path = require 'path'
|
||||
temp = require 'temp'
|
||||
@@ -10,16 +10,21 @@ describe "WorkspaceView", ->
|
||||
pathToOpen = null
|
||||
|
||||
beforeEach ->
|
||||
jasmine.snapshotDeprecations()
|
||||
|
||||
atom.project.setPaths([atom.project.resolve('dir')])
|
||||
pathToOpen = atom.project.resolve('a')
|
||||
atom.workspace = new Workspace
|
||||
atom.workspaceView = atom.views.getView(atom.workspace).__spacePenView
|
||||
atom.workspaceView = atom.views.createView(atom.workspace).__spacePenView
|
||||
atom.workspaceView.enableKeymap()
|
||||
atom.workspaceView.focus()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(pathToOpen)
|
||||
|
||||
afterEach ->
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
describe "@deserialize()", ->
|
||||
viewState = null
|
||||
|
||||
@@ -29,7 +34,7 @@ describe "WorkspaceView", ->
|
||||
atom.workspaceView.remove()
|
||||
atom.project = atom.deserializers.deserialize(projectState)
|
||||
atom.workspace = Workspace.deserialize(workspaceState)
|
||||
atom.workspaceView = atom.views.getView(atom.workspace).__spacePenView
|
||||
atom.workspaceView = atom.views.createView(atom.workspace).__spacePenView
|
||||
atom.workspaceView.attachToDom()
|
||||
|
||||
describe "when the serialized WorkspaceView has an unsaved buffer", ->
|
||||
@@ -274,7 +279,7 @@ describe "WorkspaceView", ->
|
||||
describe 'panel containers', ->
|
||||
workspaceElement = null
|
||||
beforeEach ->
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
workspaceElement = atom.views.createView(atom.workspace)
|
||||
|
||||
it 'inserts panel container elements in the correct places in the DOM', ->
|
||||
leftContainer = workspaceElement.querySelector('atom-panel-container.left')
|
||||
|
||||
+26
-10
@@ -39,7 +39,7 @@ class Atom extends Model
|
||||
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)`,
|
||||
If you do need the view, please use `document.querySelector('atom-workspace')`,
|
||||
which returns an HTMLElement.
|
||||
"""
|
||||
|
||||
@@ -146,11 +146,14 @@ class Atom extends Model
|
||||
# Public: A {TooltipManager} instance
|
||||
tooltips: null
|
||||
|
||||
# Experimental: A {NotificationManager} instance
|
||||
notifications: null
|
||||
|
||||
# Public: A {Project} instance
|
||||
project: null
|
||||
|
||||
# Public: A {Syntax} instance
|
||||
syntax: null
|
||||
# Public: A {GrammarRegistry} instance
|
||||
grammars: null
|
||||
|
||||
# Public: A {PackageManager} instance
|
||||
packages: null
|
||||
@@ -164,7 +167,7 @@ class Atom extends Model
|
||||
# Public: A {DeserializerManager} instance
|
||||
deserializers: null
|
||||
|
||||
# Public: A {ViewRegistry} instance
|
||||
# Public: A {ViewFactory} instance
|
||||
views: null
|
||||
|
||||
# Public: A {Workspace} instance
|
||||
@@ -217,12 +220,13 @@ class Atom extends Model
|
||||
|
||||
Config = require './config'
|
||||
KeymapManager = require './keymap-extensions'
|
||||
ViewRegistry = require './view-registry'
|
||||
ViewFactory = require './view-factory'
|
||||
CommandRegistry = require './command-registry'
|
||||
TooltipManager = require './tooltip-manager'
|
||||
NotificationManager = require './notification-manager'
|
||||
PackageManager = require './package-manager'
|
||||
Clipboard = require './clipboard'
|
||||
Syntax = require './syntax'
|
||||
GrammarRegistry = require './grammar-registry'
|
||||
ThemeManager = require './theme-manager'
|
||||
StyleManager = require './style-manager'
|
||||
ContextMenuManager = require './context-menu-manager'
|
||||
@@ -245,9 +249,11 @@ class Atom extends Model
|
||||
@config = new Config({configDirPath, resourcePath})
|
||||
@keymaps = new KeymapManager({configDirPath, resourcePath})
|
||||
@keymap = @keymaps # Deprecated
|
||||
@keymaps.subscribeToFileReadFailure()
|
||||
@tooltips = new TooltipManager
|
||||
@notifications = new NotificationManager
|
||||
@commands = new CommandRegistry
|
||||
@views = new ViewRegistry
|
||||
@views = new ViewFactory
|
||||
@packages = new PackageManager({devMode, configDirPath, resourcePath, safeMode})
|
||||
@styles = new StyleManager
|
||||
document.head.appendChild(new StylesElement)
|
||||
@@ -256,7 +262,11 @@ class Atom extends Model
|
||||
@menu = new MenuManager({resourcePath})
|
||||
@clipboard = new Clipboard()
|
||||
|
||||
@syntax = @deserializers.deserialize(@state.syntax) ? new Syntax()
|
||||
@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
|
||||
|
||||
@subscribe @packages.onDidActivateAll => @watchThemes()
|
||||
|
||||
@@ -569,7 +579,7 @@ class Atom extends Model
|
||||
unloadEditorWindow: ->
|
||||
return if not @project
|
||||
|
||||
@state.syntax = @syntax.serialize()
|
||||
@state.grammars = @grammars.serialize()
|
||||
@state.project = @project.serialize()
|
||||
@state.workspace = @workspace.serialize()
|
||||
@packages.deactivatePackages()
|
||||
@@ -671,7 +681,7 @@ class Atom extends Model
|
||||
startTime = Date.now()
|
||||
@workspace = Workspace.deserialize(@state.workspace) ? new Workspace
|
||||
|
||||
workspaceElement = @views.getView(@workspace)
|
||||
workspaceElement = @views.createView(@workspace)
|
||||
@__workspaceView = workspaceElement.__spacePenView
|
||||
@deserializeTimings.workspace = Date.now() - startTime
|
||||
|
||||
@@ -773,6 +783,12 @@ class Atom extends Model
|
||||
else
|
||||
window[key] = value
|
||||
|
||||
onUpdateAvailable: (callback) ->
|
||||
@emitter.on 'update-available', callback
|
||||
|
||||
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")
|
||||
|
||||
@@ -58,7 +58,7 @@ class AtomWindow
|
||||
@browserWindow.loadUrl @getUrl(loadSettings)
|
||||
@browserWindow.focusOnWebView() if @isSpec
|
||||
|
||||
@openPath(pathToOpen, initialLine, initialColumn)
|
||||
@openPath(pathToOpen, initialLine, initialColumn) unless @isSpecWindow()
|
||||
|
||||
getUrl: (loadSettingsObj) ->
|
||||
# Ignore the windowState when passing loadSettings via URL, since it could
|
||||
@@ -143,10 +143,13 @@ class AtomWindow
|
||||
openPath: (pathToOpen, initialLine, initialColumn) ->
|
||||
if @loaded
|
||||
@focus()
|
||||
@sendCommand('window:open-path', {pathToOpen, initialLine, initialColumn})
|
||||
@sendMessage 'open-path', {pathToOpen, initialLine, initialColumn}
|
||||
else
|
||||
@browserWindow.once 'window:loaded', => @openPath(pathToOpen, initialLine, initialColumn)
|
||||
|
||||
sendMessage: (message, detail) ->
|
||||
@browserWindow.webContents.send 'message', message, detail
|
||||
|
||||
sendCommand: (command, args...) ->
|
||||
if @isSpecWindow()
|
||||
unless global.atomApplication.sendCommandToFirstResponder(command)
|
||||
@@ -154,7 +157,6 @@ class AtomWindow
|
||||
when 'window:reload' then @reload()
|
||||
when 'window:toggle-dev-tools' then @toggleDevTools()
|
||||
when 'window:close' then @close()
|
||||
when 'window:update-available' then @sendCommandToBrowserWindow(command, args...) # For spec testing
|
||||
else if @isWebViewFocused()
|
||||
@sendCommandToBrowserWindow(command, args...)
|
||||
else
|
||||
|
||||
@@ -56,7 +56,7 @@ class AutoUpdateManager
|
||||
emitUpdateAvailableEvent: (windows...) ->
|
||||
return unless @releaseVersion? and @releaseNotes
|
||||
for atomWindow in windows
|
||||
atomWindow.sendCommand('window:update-available', [@releaseVersion, @releaseNotes])
|
||||
atomWindow.sendMessage('update-available', {@releaseVersion, @releaseNotes})
|
||||
|
||||
setState: (state) ->
|
||||
return if @state is state
|
||||
|
||||
@@ -8,7 +8,7 @@ class ContextMenu
|
||||
menu.popup(@atomWindow.browserWindow)
|
||||
|
||||
# It's necessary to build the event handlers in this process, otherwise
|
||||
# closures are drug across processes and failed to be garbage collected
|
||||
# closures are dragged across processes and failed to be garbage collected
|
||||
# appropriately.
|
||||
createClickHandlers: (template) ->
|
||||
for item in template
|
||||
|
||||
@@ -119,9 +119,6 @@ module.exports =
|
||||
autoIndentOnPaste:
|
||||
type: 'boolean'
|
||||
default: true
|
||||
normalizeIndentOnPaste:
|
||||
type: 'boolean'
|
||||
default: true
|
||||
nonWordCharacters:
|
||||
type: 'string'
|
||||
default: "/\\()\"':,.;<>~!@#$%^&*|+=[]{}`?-"
|
||||
|
||||
+12
-4
@@ -526,6 +526,9 @@ class Config
|
||||
|
||||
# Extended: Restore the global setting at `keyPath` to its default value.
|
||||
#
|
||||
# * `scopeSelector` (optional) {String}. eg. '.source.ruby'
|
||||
# See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors)
|
||||
# for more information.
|
||||
# * `keyPath` The {String} name of the key.
|
||||
#
|
||||
# Returns the new value.
|
||||
@@ -721,21 +724,26 @@ class Config
|
||||
@configFileHasErrors = false
|
||||
catch error
|
||||
@configFileHasErrors = true
|
||||
console.error "Failed to load user config '#{@configFilePath}'", error.message
|
||||
console.error error.stack
|
||||
@notifyFailure('Failed to load config.cson', error)
|
||||
|
||||
observeUserConfig: ->
|
||||
try
|
||||
@watchSubscription ?= pathWatcher.watch @configFilePath, (eventType) =>
|
||||
@loadUserConfig() if eventType is 'change' and @watchSubscription?
|
||||
catch error
|
||||
console.error "Failed to watch user config '#{@configFilePath}'", error.message
|
||||
console.error error.stack
|
||||
@notifyFailure('Failed to watch user config', error)
|
||||
|
||||
unobserveUserConfig: ->
|
||||
@watchSubscription?.close()
|
||||
@watchSubscription = null
|
||||
|
||||
notifyFailure: (errorMessage, error) ->
|
||||
message = "#{errorMessage}"
|
||||
detail = error.stack
|
||||
atom.notifications.addError(message, {detail, closable: true})
|
||||
console.error message
|
||||
console.error detail
|
||||
|
||||
save: ->
|
||||
allSettings = global: @settings
|
||||
allSettings = _.extend allSettings, @scopedSettingsStore.propertiesForSource('user-config')
|
||||
|
||||
@@ -889,6 +889,9 @@ class DisplayBuffer extends Model
|
||||
allDecorations = allDecorations.concat(decorations) if decorations?
|
||||
allDecorations
|
||||
|
||||
getOverlayDecorations: ->
|
||||
@getDecorations().filter (decoration) -> decoration.isType('overlay')
|
||||
|
||||
decorationsForScreenRowRange: (startScreenRow, endScreenRow) ->
|
||||
decorationsByMarkerId = {}
|
||||
for marker in @findMarkers(intersectsScreenRowRange: [startScreenRow, endScreenRow])
|
||||
|
||||
@@ -2,7 +2,8 @@ _ = require 'underscore-plus'
|
||||
{deprecate} = require 'grim'
|
||||
{specificity} = require 'clear-cut'
|
||||
{Subscriber} = require 'emissary'
|
||||
{GrammarRegistry, ScopeSelector} = require 'first-mate'
|
||||
FirstMate = require 'first-mate'
|
||||
{ScopeSelector} = FirstMate
|
||||
ScopedPropertyStore = require 'scoped-property-store'
|
||||
PropertyAccessors = require 'property-accessors'
|
||||
|
||||
@@ -11,20 +12,22 @@ Token = require './token'
|
||||
|
||||
# Extended: Syntax class holding the grammars used for tokenizing.
|
||||
#
|
||||
# An instance of this class is always available as the `atom.syntax` global.
|
||||
# An instance of this class is always available as the `atom.grammars` global.
|
||||
#
|
||||
# The Syntax class also contains properties for things such as the
|
||||
# language-specific comment regexes. See {::getProperty} for more details.
|
||||
module.exports =
|
||||
class Syntax extends GrammarRegistry
|
||||
class GrammarRegistry extends FirstMate.GrammarRegistry
|
||||
PropertyAccessors.includeInto(this)
|
||||
Subscriber.includeInto(this)
|
||||
atom.deserializers.add(this)
|
||||
|
||||
@deserialize: ({grammarOverridesByPath}) ->
|
||||
syntax = new Syntax()
|
||||
syntax.grammarOverridesByPath = grammarOverridesByPath
|
||||
syntax
|
||||
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)
|
||||
@@ -34,6 +37,17 @@ class Syntax extends GrammarRegistry
|
||||
|
||||
createToken: (value, scopes) -> new Token({value, scopes})
|
||||
|
||||
# Extended: Select a grammar for the given file path and file contents.
|
||||
#
|
||||
# This picks the best match by checking the file path and contents against
|
||||
# each grammar.
|
||||
#
|
||||
# * `filePath` A {String} file path.
|
||||
# * `fileContents` A {String} of text for the file path.
|
||||
#
|
||||
# Returns a {Grammar}, never null.
|
||||
selectGrammar: (filePath, fileContents) -> super
|
||||
|
||||
# Deprecated: Used by settings-view to display snippets for packages
|
||||
@::accessor 'propertyStore', ->
|
||||
deprecate("Do not use this. Use a public method on Config")
|
||||
@@ -23,6 +23,10 @@ KeymapManager::loadUserKeymap = ->
|
||||
if fs.isFileSync(userKeymapPath)
|
||||
@loadKeymap(userKeymapPath, watch: true, suppressErrors: true)
|
||||
|
||||
KeymapManager::subscribeToFileReadFailure = ->
|
||||
this.onDidFailToReadFile (error) ->
|
||||
atom.notifications.addError('Failed to load keymap.cson', {detail: error.stack, closable: true})
|
||||
|
||||
# This enables command handlers registered via jQuery to call
|
||||
# `.abortKeyBinding()` on the `jQuery.Event` object passed to the handler.
|
||||
jQuery.Event::abortKeyBinding = ->
|
||||
|
||||
@@ -66,10 +66,10 @@ LinesComponent = React.createClass
|
||||
|
||||
insertionPoint = document.createElement('content')
|
||||
insertionPoint.setAttribute('select', 'atom-overlay')
|
||||
@overlayManager = new OverlayManager(@props.hostElement)
|
||||
@overlayManager = new OverlayManager(@props.hostElement, @props.hostElement.viewRegistry)
|
||||
@getDOMNode().appendChild(insertionPoint)
|
||||
else
|
||||
@overlayManager = new OverlayManager(@getDOMNode())
|
||||
@overlayManager = new OverlayManager(@getDOMNode(), @props.hostElement.viewRegistry)
|
||||
|
||||
shouldComponentUpdate: (newProps) ->
|
||||
return true unless isEqualForProperties(newProps, @props,
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
{Emitter, Disposable} = require 'event-kit'
|
||||
Notification = require '../src/notification'
|
||||
|
||||
# Experimental: Allows messaging the user. This will likely change, dont use
|
||||
# quite yet!
|
||||
module.exports =
|
||||
class NotificationManager
|
||||
constructor: ->
|
||||
@notifications = []
|
||||
@emitter = new Emitter
|
||||
|
||||
###
|
||||
Section: Events
|
||||
###
|
||||
|
||||
onDidAddNotification: (callback) ->
|
||||
@emitter.on 'did-add-notification', callback
|
||||
|
||||
###
|
||||
Section: Adding Notifications
|
||||
###
|
||||
|
||||
addSuccess: (message, options) ->
|
||||
@addNotification(new Notification('success', message, options))
|
||||
|
||||
addInfo: (message, options) ->
|
||||
@addNotification(new Notification('info', message, options))
|
||||
|
||||
addWarning: (message, options) ->
|
||||
@addNotification(new Notification('warning', message, options))
|
||||
|
||||
addError: (message, options) ->
|
||||
@addNotification(new Notification('error', message, options))
|
||||
|
||||
addFatalError: (message, options) ->
|
||||
@addNotification(new Notification('fatal', message, options))
|
||||
|
||||
add: (type, message, options) ->
|
||||
@addNotification(new Notification(type, message, options))
|
||||
|
||||
addNotification: (notification) ->
|
||||
@notifications.push(notification)
|
||||
@emitter.emit('did-add-notification', notification)
|
||||
notification
|
||||
@@ -0,0 +1,33 @@
|
||||
|
||||
# Experimental: This will likely change, do not use.
|
||||
module.exports =
|
||||
class Notification
|
||||
constructor: (@type, @message, @options={}) ->
|
||||
@timestamp = new Date()
|
||||
|
||||
getOptions: -> @options
|
||||
|
||||
getType: -> @type
|
||||
|
||||
getMessage: -> @message
|
||||
|
||||
getTimestamp: -> @timestamp
|
||||
|
||||
getDetail: -> @options.detail
|
||||
|
||||
isEqual: (other) ->
|
||||
@getMessage() == other.getMessage() \
|
||||
and @getType() == other.getType() \
|
||||
and @getDetail() == other.getDetail()
|
||||
|
||||
isClosable: ->
|
||||
!!@options.closable
|
||||
|
||||
getIcon: ->
|
||||
return @options.icon if @options.icon?
|
||||
switch @type
|
||||
when 'fatal' then 'bug'
|
||||
when 'error' then 'flame'
|
||||
when 'warning' then 'alert'
|
||||
when 'info' then 'info'
|
||||
when 'success' then 'check'
|
||||
@@ -1,15 +1,18 @@
|
||||
module.exports =
|
||||
class OverlayManager
|
||||
constructor: (@container) ->
|
||||
constructor: (@container, @viewRegistry) ->
|
||||
@overlays = {}
|
||||
|
||||
render: (props) ->
|
||||
{editor, overlayDecorations, lineHeightInPixels} = props
|
||||
|
||||
existingDecorations = null
|
||||
for markerId, {isMarkerReversed, headPixelPosition, decorations} of overlayDecorations
|
||||
for markerId, {headPixelPosition, tailPixelPosition, decorations} of overlayDecorations
|
||||
for decoration in decorations
|
||||
@renderOverlay(editor, decoration, headPixelPosition, lineHeightInPixels)
|
||||
pixelPosition =
|
||||
if decoration.position is 'tail' then tailPixelPosition else headPixelPosition
|
||||
|
||||
@renderOverlay(editor, decoration, pixelPosition, lineHeightInPixels)
|
||||
|
||||
existingDecorations ?= {}
|
||||
existingDecorations[decoration.id] = true
|
||||
@@ -22,7 +25,7 @@ class OverlayManager
|
||||
return
|
||||
|
||||
renderOverlay: (editor, decoration, pixelPosition, lineHeightInPixels) ->
|
||||
item = atom.views.getView(decoration.item)
|
||||
item = @viewRegistry.getView(decoration.item)
|
||||
unless overlay = @overlays[decoration.id]
|
||||
overlay = @overlays[decoration.id] = document.createElement('atom-overlay')
|
||||
overlay.appendChild(item)
|
||||
|
||||
@@ -254,7 +254,7 @@ class Package
|
||||
grammarPaths = fs.listSync(grammarsDirPath, ['json', 'cson'])
|
||||
for grammarPath in grammarPaths
|
||||
try
|
||||
grammar = atom.syntax.readGrammarSync(grammarPath)
|
||||
grammar = atom.grammars.readGrammarSync(grammarPath)
|
||||
grammar.packageName = @name
|
||||
@grammars.push(grammar)
|
||||
grammar.activate()
|
||||
@@ -268,7 +268,7 @@ class Package
|
||||
return Q() if @grammarsLoaded
|
||||
|
||||
loadGrammar = (grammarPath, callback) =>
|
||||
atom.syntax.readGrammar grammarPath, (error, grammar) =>
|
||||
atom.grammars.readGrammar grammarPath, (error, grammar) =>
|
||||
if error?
|
||||
console.warn("Failed to load grammar: #{grammarPath}", error.stack ? error)
|
||||
else
|
||||
|
||||
@@ -8,7 +8,7 @@ class PaneAxisElement extends HTMLElement
|
||||
detachedCallback: ->
|
||||
@subscriptions.dispose()
|
||||
|
||||
setModel: (@model) ->
|
||||
initialize: ({@viewRegistry, @model}) ->
|
||||
@subscriptions.add @model.onDidAddChild(@childAdded.bind(this))
|
||||
@subscriptions.add @model.onDidRemoveChild(@childRemoved.bind(this))
|
||||
@subscriptions.add @model.onDidReplaceChild(@childReplaced.bind(this))
|
||||
@@ -22,12 +22,12 @@ class PaneAxisElement extends HTMLElement
|
||||
@classList.add('vertical', 'pane-column')
|
||||
|
||||
childAdded: ({child, index}) ->
|
||||
view = @model.getView(child)
|
||||
view = @viewRegistry.getView(child)
|
||||
@insertBefore(view, @children[index])
|
||||
callAttachHooks(view) # for backward compatibility with SpacePen views
|
||||
|
||||
childRemoved: ({child}) ->
|
||||
view = @model.getView(child)
|
||||
view = @viewRegistry.getView(child)
|
||||
view.remove()
|
||||
|
||||
childReplaced: ({index, oldChild, newChild}) ->
|
||||
|
||||
@@ -39,9 +39,6 @@ class PaneAxis extends Model
|
||||
|
||||
getOrientation: -> @orientation
|
||||
|
||||
getView: (object) ->
|
||||
@container.getView(object)
|
||||
|
||||
getChildren: -> @children.slice()
|
||||
|
||||
getPanes: ->
|
||||
|
||||
@@ -11,7 +11,7 @@ class PaneContainerElement extends HTMLElement
|
||||
PaneContainerView ?= require './pane-container-view'
|
||||
@__spacePenView = new PaneContainerView(this)
|
||||
|
||||
setModel: (@model) ->
|
||||
initialize: ({@viewRegistry, @model}) ->
|
||||
@subscriptions.add @model.observeRoot(@rootChanged.bind(this))
|
||||
@__spacePenView.setModel(@model)
|
||||
|
||||
@@ -19,7 +19,7 @@ class PaneContainerElement extends HTMLElement
|
||||
focusedElement = document.activeElement if @hasFocus()
|
||||
@firstChild?.remove()
|
||||
if root?
|
||||
view = @model.getView(root)
|
||||
view = @viewRegistry.getView(root)
|
||||
@appendChild(view)
|
||||
callAttachHooks(view)
|
||||
focusedElement?.focus()
|
||||
@@ -45,7 +45,7 @@ class PaneContainerElement extends HTMLElement
|
||||
y = pointB.y - pointA.y
|
||||
Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2))
|
||||
|
||||
paneView = @model.getView(@model.getActivePane())
|
||||
paneView = @viewRegistry.getView(@model.getActivePane())
|
||||
box = @boundingBoxForPaneView(paneView)
|
||||
|
||||
paneViews = _.toArray(@querySelectorAll('atom-pane'))
|
||||
|
||||
@@ -23,7 +23,7 @@ class PaneContainerView extends View
|
||||
@subscriptions.add @model.onDidChangeActivePaneItem(@onActivePaneItemChanged)
|
||||
|
||||
getRoot: ->
|
||||
view = @model.getView(@model.getRoot())
|
||||
view = @element.viewRegistry.getView(@model.getRoot())
|
||||
view.__spacePenView ? view
|
||||
|
||||
onActivePaneItemChanged: (activeItem) =>
|
||||
@@ -55,7 +55,7 @@ class PaneContainerView extends View
|
||||
@getActivePaneView()
|
||||
|
||||
getActivePaneView: ->
|
||||
@model.getView(@model.getActivePane()).__spacePenView
|
||||
@element.viewRegistry.getView(@model.getActivePane()).__spacePenView
|
||||
|
||||
getActivePaneItem: ->
|
||||
@model.getActivePaneItem()
|
||||
@@ -64,7 +64,7 @@ class PaneContainerView extends View
|
||||
@getActivePaneView()?.activeView
|
||||
|
||||
paneForUri: (uri) ->
|
||||
@model.getView(@model.paneForUri(uri)).__spacePenView
|
||||
@element.viewRegistry.getView(@model.paneForUri(uri)).__spacePenView
|
||||
|
||||
focusNextPaneView: ->
|
||||
@model.activateNextPane()
|
||||
|
||||
@@ -9,7 +9,6 @@ PaneAxisElement = require './pane-axis-element'
|
||||
PaneAxis = require './pane-axis'
|
||||
TextEditor = require './text-editor'
|
||||
TextEditorElement = require './text-editor-element'
|
||||
ViewRegistry = require './view-registry'
|
||||
ItemRegistry = require './item-registry'
|
||||
|
||||
module.exports =
|
||||
@@ -36,7 +35,6 @@ class PaneContainer extends Model
|
||||
@subscriptions = new CompositeDisposable
|
||||
|
||||
@itemRegistry = new ItemRegistry
|
||||
@viewRegistry = params?.viewRegistry ? new ViewRegistry
|
||||
@registerViewProviders()
|
||||
|
||||
@setRoot(params?.root ? new Pane)
|
||||
@@ -58,25 +56,22 @@ class PaneContainer extends Model
|
||||
activePaneId: @activePane.id
|
||||
|
||||
registerViewProviders: ->
|
||||
@viewRegistry.addViewProvider
|
||||
atom.views.addViewProvider
|
||||
modelConstructor: PaneContainer
|
||||
viewConstructor: PaneContainerElement
|
||||
|
||||
@viewRegistry.addViewProvider
|
||||
atom.views.addViewProvider
|
||||
modelConstructor: PaneAxis
|
||||
viewConstructor: PaneAxisElement
|
||||
|
||||
@viewRegistry.addViewProvider
|
||||
atom.views.addViewProvider
|
||||
modelConstructor: Pane
|
||||
viewConstructor: PaneElement
|
||||
|
||||
@viewRegistry.addViewProvider
|
||||
atom.views.addViewProvider
|
||||
modelConstructor: TextEditor
|
||||
viewConstructor: TextEditorElement
|
||||
|
||||
getView: (object) ->
|
||||
@viewRegistry.getView(object)
|
||||
|
||||
onDidChangeRoot: (fn) ->
|
||||
@emitter.on 'did-change-root', fn
|
||||
|
||||
|
||||
@@ -43,9 +43,7 @@ class PaneElement extends HTMLElement
|
||||
createSpacePenShim: ->
|
||||
@__spacePenView = new PaneView(this)
|
||||
|
||||
getModel: -> @model
|
||||
|
||||
setModel: (@model) ->
|
||||
initialize: ({@viewRegistry, @model}) ->
|
||||
@subscriptions.add @model.onDidActivate(@activated.bind(this))
|
||||
@subscriptions.add @model.observeActive(@activeStatusChanged.bind(this))
|
||||
@subscriptions.add @model.observeActiveItem(@activeItemChanged.bind(this))
|
||||
@@ -53,8 +51,10 @@ class PaneElement extends HTMLElement
|
||||
@subscriptions.add @model.onDidDestroy(@paneDestroyed.bind(this))
|
||||
@__spacePenView.setModel(@model)
|
||||
|
||||
getModel: -> @model
|
||||
|
||||
activated: ->
|
||||
@focus() unless @hasFocus()
|
||||
@focus()
|
||||
|
||||
activeStatusChanged: (active) ->
|
||||
if active
|
||||
@@ -66,7 +66,7 @@ class PaneElement extends HTMLElement
|
||||
return unless item?
|
||||
|
||||
hasFocus = @hasFocus()
|
||||
itemView = @model.getView(item)
|
||||
itemView = @viewRegistry.getView(item)
|
||||
|
||||
unless @itemViews.contains(itemView)
|
||||
@itemViews.appendChild(itemView)
|
||||
@@ -94,14 +94,14 @@ class PaneElement extends HTMLElement
|
||||
itemView.style.display = 'none'
|
||||
|
||||
itemRemoved: ({item, index, destroyed}) ->
|
||||
if viewToRemove = @model.getView(item)
|
||||
if viewToRemove = @viewRegistry.getView(item)
|
||||
callRemoveHooks(viewToRemove) if destroyed
|
||||
viewToRemove.remove()
|
||||
|
||||
paneDestroyed: ->
|
||||
@subscriptions.dispose()
|
||||
|
||||
getActiveView: -> @model.getView(@model.getActiveItem())
|
||||
getActiveView: -> @viewRegistry.getView(@model.getActiveItem())
|
||||
|
||||
hasFocus: ->
|
||||
this is document.activeElement or @contains(document.activeElement)
|
||||
|
||||
@@ -153,15 +153,15 @@ class PaneView extends View
|
||||
activeItemModifiedChanged: =>
|
||||
@trigger 'pane:active-item-modified-status-changed'
|
||||
|
||||
@::accessor 'activeView', -> @model.getView(@activeItem)?.__spacePenView
|
||||
@::accessor 'activeView', -> @element.viewRegistry.getView(@activeItem)?.__spacePenView
|
||||
|
||||
splitLeft: (items...) -> @model.getView(@model.splitLeft({items})).__spacePenView
|
||||
splitLeft: (items...) -> @element.viewRegistry.getView(@model.splitLeft({items})).__spacePenView
|
||||
|
||||
splitRight: (items...) -> @model.getView(@model.splitRight({items})).__spacePenView
|
||||
splitRight: (items...) -> @element.viewRegistry.getView(@model.splitRight({items})).__spacePenView
|
||||
|
||||
splitUp: (items...) -> @model.getView(@model.splitUp({items})).__spacePenView
|
||||
splitUp: (items...) -> @element.viewRegistry.getView(@model.splitUp({items})).__spacePenView
|
||||
|
||||
splitDown: (items...) -> @model.getView(@model.splitDown({items})).__spacePenView
|
||||
splitDown: (items...) -> @element.viewRegistry.getView(@model.splitDown({items})).__spacePenView
|
||||
|
||||
getContainer: -> @closest('atom-pane-container').view()
|
||||
|
||||
|
||||
@@ -53,9 +53,6 @@ class Pane extends Model
|
||||
params.activeItem = find params.items, (item) -> item.getUri?() is activeItemUri
|
||||
params
|
||||
|
||||
getView: (object) ->
|
||||
@container.getView(object)
|
||||
|
||||
getParent: -> @parent
|
||||
|
||||
setParent: (@parent) -> @parent
|
||||
|
||||
@@ -6,19 +6,24 @@ class PanelContainerElement extends HTMLElement
|
||||
|
||||
getModel: -> @model
|
||||
|
||||
setModel: (@model) ->
|
||||
initialize: ({@viewRegistry, @model}) ->
|
||||
@subscriptions.add @model.onDidAddPanel(@panelAdded.bind(this))
|
||||
@subscriptions.add @model.onDidRemovePanel(@panelRemoved.bind(this))
|
||||
@subscriptions.add @model.onDidDestroy(@destroyed.bind(this))
|
||||
@classList.add(@model.getLocation())
|
||||
|
||||
panelAdded: ({panel, index}) ->
|
||||
panelElement = panel.getView()
|
||||
panelElement = @viewRegistry.getView(panel)
|
||||
panelElement.classList.add(@model.getLocation())
|
||||
if @model.isModal()
|
||||
panelElement.classList.add("overlay", "from-top")
|
||||
else
|
||||
panelElement.classList.add("tool-panel", "panel-#{@model.getLocation()}")
|
||||
|
||||
if index >= @childNodes.length
|
||||
@appendChild(panelElement)
|
||||
else
|
||||
referenceItem = @childNodes[index + 1]
|
||||
referenceItem = @childNodes[index]
|
||||
@insertBefore(panelElement, referenceItem)
|
||||
|
||||
if @model.isModal()
|
||||
@@ -27,7 +32,7 @@ class PanelContainerElement extends HTMLElement
|
||||
@hideAllPanelsExcept(panel) if visible
|
||||
|
||||
panelRemoved: ({panel, index}) ->
|
||||
@removeChild(panel.getView())
|
||||
@removeChild(@viewRegistry.getView(panel))
|
||||
|
||||
destroyed: ->
|
||||
@subscriptions.dispose()
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
module.exports =
|
||||
class PanelContainer
|
||||
constructor: ({@viewRegistry, @location}) ->
|
||||
constructor: ({@location}={}) ->
|
||||
@emitter = new Emitter
|
||||
@subscriptions = new CompositeDisposable
|
||||
@panels = []
|
||||
@@ -30,8 +30,6 @@ class PanelContainer
|
||||
Section: Panels
|
||||
###
|
||||
|
||||
getView: -> @viewRegistry.getView(this)
|
||||
|
||||
getLocation: -> @location
|
||||
|
||||
isModal: -> @location is 'modal'
|
||||
|
||||
@@ -7,16 +7,18 @@ class PanelElement extends HTMLElement
|
||||
|
||||
getModel: -> @model
|
||||
|
||||
setModel: (@model) ->
|
||||
view = @model.getItemView()
|
||||
@appendChild(view)
|
||||
callAttachHooks(view) # for backward compatibility with SpacePen views
|
||||
initialize: ({@viewRegistry, @model}) ->
|
||||
@appendChild(@getItemView())
|
||||
|
||||
@classList.add(@model.getClassName().split(' ')...) if @model.getClassName()?
|
||||
@subscriptions.add @model.onDidChangeVisible(@visibleChanged.bind(this))
|
||||
@subscriptions.add @model.onDidDestroy(@destroyed.bind(this))
|
||||
|
||||
getItemView: ->
|
||||
@viewRegistry.getView(@model.getItem())
|
||||
|
||||
attachedCallback: ->
|
||||
callAttachHooks(@getItemView()) # for backward compatibility with SpacePen views
|
||||
@visibleChanged(@model.isVisible())
|
||||
|
||||
visibleChanged: (visible) ->
|
||||
|
||||
+3
-10
@@ -14,7 +14,7 @@ class Panel
|
||||
Section: Construction and Destruction
|
||||
###
|
||||
|
||||
constructor: ({@viewRegistry, @item, @visible, @priority, @className}) ->
|
||||
constructor: ({@item, @visible, @priority, @className}) ->
|
||||
@emitter = new Emitter
|
||||
@visible ?= true
|
||||
@priority ?= 100
|
||||
@@ -50,15 +50,8 @@ class Panel
|
||||
Section: Panel Details
|
||||
###
|
||||
|
||||
# Public: Gets this panel model's view DOM node.
|
||||
#
|
||||
# Returns an `<atom-panel>` {Element}
|
||||
getView: -> @viewRegistry.getView(this)
|
||||
|
||||
# Public: Gets your panel contents view.
|
||||
#
|
||||
# Returns an {Element} or jQuery element, depeneding on how you created the panel.
|
||||
getItemView: -> @viewRegistry.getView(@item)
|
||||
# Public: Returns the panel's item.
|
||||
getItem: -> @item
|
||||
|
||||
# Public: Returns a {Number} indicating this panel's priority.
|
||||
getPriority: -> @priority
|
||||
|
||||
@@ -64,7 +64,7 @@ class Project extends Model
|
||||
###
|
||||
|
||||
serializeParams: ->
|
||||
path: @path
|
||||
paths: @getPaths()
|
||||
buffers: _.compact(@buffers.map (buffer) -> buffer.serialize() if buffer.isRetained())
|
||||
|
||||
deserializeParams: (params) ->
|
||||
|
||||
+23
-34
@@ -359,8 +359,11 @@ class Selection extends Model
|
||||
@clear()
|
||||
@cursor.needsAutoscroll = @cursor.isLastCursor()
|
||||
|
||||
precedingText = @editor.getTextInRange([[oldBufferRange.start.row, 0], oldBufferRange.start])
|
||||
startLevel = @editor.indentLevelForLine(precedingText)
|
||||
|
||||
if options.indentBasis? and not options.autoIndent
|
||||
text = @normalizeIndents(text, options.indentBasis)
|
||||
text = @adjustIndent(text, startLevel - options.indentBasis)
|
||||
|
||||
newBufferRange = @editor.buffer.setTextInRange(oldBufferRange, text, pick(options, 'undo', 'normalizeLineEndings'))
|
||||
|
||||
@@ -562,8 +565,10 @@ class Selection extends Model
|
||||
# cursor's horizontal position. (default: false)
|
||||
copy: (maintainClipboard=false, fullLine=false) ->
|
||||
return if @isEmpty()
|
||||
selectionText = @editor.buffer.getTextInRange(@getBufferRange())
|
||||
selectionIndentation = @editor.indentationForBufferRow(@getBufferRange().start.row)
|
||||
{start, end} = @getBufferRange()
|
||||
selectionText = @editor.getTextInRange([start, end])
|
||||
precedingText = @editor.getTextInRange([[start.row, 0], start])
|
||||
startLevel = @editor.indentLevelForLine(precedingText)
|
||||
|
||||
if maintainClipboard
|
||||
{text: clipboardText, metadata} = atom.clipboard.readWithMetadata()
|
||||
@@ -572,16 +577,17 @@ class Selection extends Model
|
||||
metadata.selections = [{
|
||||
text: clipboardText,
|
||||
indentBasis: metadata.indentBasis,
|
||||
fullLine: metadata.fullLine,
|
||||
}]
|
||||
metadata.selections.push({
|
||||
text: selectionText,
|
||||
indentBasis: selectionIndentation,
|
||||
indentBasis: startLevel,
|
||||
fullLine: fullLine
|
||||
})
|
||||
atom.clipboard.write([clipboardText, selectionText].join("\n"), metadata)
|
||||
else
|
||||
atom.clipboard.write(selectionText, {
|
||||
indentBasis: selectionIndentation,
|
||||
indentBasis: startLevel,
|
||||
fullLine: fullLine
|
||||
})
|
||||
|
||||
@@ -591,34 +597,22 @@ class Selection extends Model
|
||||
@editor.createFold(range.start.row, range.end.row)
|
||||
@cursor.setBufferPosition([range.end.row + 1, 0])
|
||||
|
||||
# Public: Indents the given text to the suggested level based on the grammar.
|
||||
# Public: Increases the indentation level of
|
||||
#
|
||||
# * `text` The {String} to indent within the selection.
|
||||
# * `indentBasis` The beginning indent level.
|
||||
normalizeIndents: (text, indentBasis) ->
|
||||
textPrecedingCursor = @cursor.getCurrentBufferLine()[0...@cursor.getBufferColumn()]
|
||||
isCursorInsideExistingLine = /\S/.test(textPrecedingCursor)
|
||||
|
||||
# * `indentIncrease` The beginning indent level.
|
||||
adjustIndent: (text, indentIncrease) ->
|
||||
lines = text.split('\n')
|
||||
firstLineIndentLevel = @editor.indentLevelForLine(lines[0])
|
||||
if isCursorInsideExistingLine
|
||||
minimumIndentLevel = @editor.indentationForBufferRow(@cursor.getBufferRow())
|
||||
else
|
||||
minimumIndentLevel = @cursor.getIndentLevel()
|
||||
|
||||
normalizedLines = []
|
||||
for line, i in lines
|
||||
if i == 0
|
||||
indentLevel = 0
|
||||
else if line == '' # remove all indentation from empty lines
|
||||
indentLevel = 0
|
||||
for line, i in lines when i > 0
|
||||
if indentIncrease == 0
|
||||
continue
|
||||
else if indentIncrease > 0
|
||||
lines[i] = @editor.buildIndentString(indentIncrease) + line
|
||||
else
|
||||
lineIndentLevel = @editor.indentLevelForLine(lines[i])
|
||||
indentLevel = minimumIndentLevel + (lineIndentLevel - indentBasis)
|
||||
|
||||
normalizedLines.push(@setIndentationForLine(line, indentLevel))
|
||||
|
||||
normalizedLines.join('\n')
|
||||
currentIndentLevel = @editor.indentLevelForLine(lines[i])
|
||||
indentLevel = Math.max(0, currentIndentLevel + indentIncrease)
|
||||
lines[i] = line.replace(/^[\t ]+/, @editor.buildIndentString(indentLevel))
|
||||
lines.join('\n')
|
||||
|
||||
# Indent the current line(s).
|
||||
#
|
||||
@@ -651,11 +645,6 @@ class Selection extends Model
|
||||
for row in [start..end]
|
||||
@editor.buffer.insert([row, 0], @editor.getTabText()) unless @editor.buffer.lineLengthForRow(row) == 0
|
||||
|
||||
setIndentationForLine: (line, indentLevel) ->
|
||||
desiredIndentLevel = Math.max(0, indentLevel)
|
||||
desiredIndentString = @editor.buildIndentString(desiredIndentLevel)
|
||||
line.replace(/^[\t ]*/, desiredIndentString)
|
||||
|
||||
###
|
||||
Section: Managing multiple selections
|
||||
###
|
||||
|
||||
@@ -12,7 +12,7 @@ jQuery.cleanData = (elements) ->
|
||||
|
||||
SpacePenCallRemoveHooks = SpacePen.callRemoveHooks
|
||||
SpacePen.callRemoveHooks = (element) ->
|
||||
view.unsubscribe() for view in SpacePen.viewsForElement(element)
|
||||
view.unsubscribe?() for view in SpacePen.viewsForElement(element)
|
||||
SpacePenCallRemoveHooks(element)
|
||||
|
||||
NativeEventNames = new Set
|
||||
|
||||
@@ -20,9 +20,6 @@ TextEditorComponent = React.createClass
|
||||
displayName: 'TextEditorComponent'
|
||||
mixins: [SubscriberMixin]
|
||||
|
||||
statics:
|
||||
performSyncUpdates: false
|
||||
|
||||
visible: false
|
||||
autoHeight: false
|
||||
backgroundColor: null
|
||||
@@ -242,7 +239,7 @@ TextEditorComponent = React.createClass
|
||||
@updateRequestedWhilePaused = true
|
||||
return
|
||||
|
||||
if @performSyncUpdates ? TextEditorComponent.performSyncUpdates
|
||||
if @props.hostElement.isUpdatedSynchronously()
|
||||
@forceUpdate()
|
||||
else unless @updateRequested
|
||||
@updateRequested = true
|
||||
@@ -363,14 +360,16 @@ TextEditorComponent = React.createClass
|
||||
filteredDecorations = {}
|
||||
for markerId, decorations of decorationsByMarkerId
|
||||
marker = editor.getMarker(markerId)
|
||||
headBufferPosition = marker.getHeadBufferPosition()
|
||||
headScreenPosition = marker.getHeadScreenPosition()
|
||||
tailScreenPosition = marker.getTailScreenPosition()
|
||||
if marker.isValid()
|
||||
for decoration in decorations
|
||||
if decoration.isType('overlay')
|
||||
decorationParams = decoration.getProperties()
|
||||
filteredDecorations[markerId] ?=
|
||||
id: markerId
|
||||
headPixelPosition: editor.pixelPositionForScreenPosition(headBufferPosition)
|
||||
headPixelPosition: editor.pixelPositionForScreenPosition(headScreenPosition)
|
||||
tailPixelPosition: editor.pixelPositionForScreenPosition(tailScreenPosition)
|
||||
decorations: []
|
||||
filteredDecorations[markerId].decorations.push decorationParams
|
||||
filteredDecorations
|
||||
|
||||
@@ -63,6 +63,9 @@ class TextEditorElement extends HTMLElement
|
||||
@component.checkForVisibilityChange()
|
||||
@focus() if @focusOnAttach
|
||||
|
||||
initialize: ({@viewRegistry, @lineOverdrawMargin, model}) ->
|
||||
@setModel(model)
|
||||
|
||||
setModel: (model) ->
|
||||
throw new Error("Model already assigned on TextEditorElement") if @model?
|
||||
return if model.isDestroyed()
|
||||
@@ -103,7 +106,9 @@ class TextEditorElement extends HTMLElement
|
||||
)
|
||||
@component = React.renderComponent(@componentDescriptor, @rootElement)
|
||||
|
||||
unless @useShadowDOM
|
||||
if @useShadowDOM
|
||||
@shadowRoot.addEventListener('blur', @shadowRootBlurred.bind(this), true)
|
||||
else
|
||||
inputNode = @component.refs.input.getDOMNode()
|
||||
inputNode.addEventListener 'focus', @focused.bind(this)
|
||||
inputNode.addEventListener 'blur', => @dispatchEvent(new FocusEvent('blur', bubbles: false))
|
||||
@@ -128,6 +133,16 @@ class TextEditorElement extends HTMLElement
|
||||
|
||||
@component?.blurred()
|
||||
|
||||
# Work around what seems to be a bug in Chromium. Focus can be stolen from the
|
||||
# hidden input when clicking on the gutter and transferred to the
|
||||
# already-focused host element. The host element never gets a 'focus' event
|
||||
# however, which leaves us in a limbo state where the text editor element is
|
||||
# focused but the hidden input isn't focused. This always refocuses the hidden
|
||||
# input if a blur event occurs in the shadow DOM that is transferring focus
|
||||
# back to the host element.
|
||||
shadowRootBlurred: (event) ->
|
||||
@component.focused() if event.relatedTarget is this
|
||||
|
||||
addGrammarScopeAttribute: ->
|
||||
grammarScope = @model.getGrammar()?.scopeName?.replace(/\./g, ' ')
|
||||
@dataset.grammar = grammarScope
|
||||
@@ -141,6 +156,10 @@ class TextEditorElement extends HTMLElement
|
||||
hasFocus: ->
|
||||
this is document.activeElement or @contains(document.activeElement)
|
||||
|
||||
setUpdatedSynchronously: (@updatedSynchronously) -> @updatedSynchronously
|
||||
|
||||
isUpdatedSynchronously: -> @updatedSynchronously
|
||||
|
||||
stopEventPropagation = (commandListeners) ->
|
||||
newCommandListeners = {}
|
||||
for commandName, commandListener of commandListeners
|
||||
|
||||
@@ -63,7 +63,7 @@ class TextEditorView extends View
|
||||
element = new TextEditorElement
|
||||
element.lineOverdrawMargin = props?.lineOverdrawMargin
|
||||
element.setAttribute(name, value) for name, value of attributes if attributes?
|
||||
element.setModel(model)
|
||||
element.initialize({model})
|
||||
return element.__spacePenView
|
||||
|
||||
# Handle construction with an element
|
||||
|
||||
+67
-25
@@ -1098,34 +1098,49 @@ class TextEditor extends Model
|
||||
# abort the transaction, call {::abortTransaction} to terminate the function's
|
||||
# execution and revert any changes performed up to the abortion.
|
||||
#
|
||||
# * `groupingInterval` (optional) This is the sames as the `groupingInterval`
|
||||
# parameter in {::beginTransaction}
|
||||
# * `fn` A {Function} to call inside the transaction.
|
||||
transact: (groupingInterval, fn) -> @buffer.transact(groupingInterval, fn)
|
||||
|
||||
# Extended: Start an open-ended transaction.
|
||||
#
|
||||
# Call {::commitTransaction} or {::abortTransaction} to terminate the
|
||||
# transaction. If you nest calls to transactions, only the outermost
|
||||
# transaction is considered. You must match every begin with a matching
|
||||
# commit, but a single call to abort will cancel all nested transactions.
|
||||
#
|
||||
# * `groupingInterval` (optional) The {Number} of milliseconds for which this
|
||||
# transaction should be considered 'groupable' after it begins. If a transaction
|
||||
# with a positive `groupingInterval` is committed while the previous transaction is
|
||||
# still 'groupable', the two transactions are merged with respect to undo and redo.
|
||||
# * `fn` A {Function} to call inside the transaction.
|
||||
transact: (groupingInterval, fn) -> @buffer.transact(groupingInterval, fn)
|
||||
|
||||
# Deprecated: Start an open-ended transaction.
|
||||
beginTransaction: (groupingInterval) -> @buffer.beginTransaction(groupingInterval)
|
||||
|
||||
# Extended: Commit an open-ended transaction started with {::beginTransaction}
|
||||
# and push it to the undo stack.
|
||||
#
|
||||
# If transactions are nested, only the outermost commit takes effect.
|
||||
# Deprecated: Commit an open-ended transaction started with {::beginTransaction}.
|
||||
commitTransaction: -> @buffer.commitTransaction()
|
||||
|
||||
# Extended: Abort an open transaction, undoing any operations performed so far
|
||||
# within the transaction.
|
||||
abortTransaction: -> @buffer.abortTransaction()
|
||||
|
||||
# Extended: Create a pointer to the current state of the buffer for use
|
||||
# with {::revertToCheckpoint} and {::groupChangesSinceCheckpoint}.
|
||||
#
|
||||
# Returns a checkpoint value.
|
||||
createCheckpoint: -> @buffer.createCheckpoint()
|
||||
|
||||
# Extended: Revert the buffer to the state it was in when the given
|
||||
# checkpoint was created.
|
||||
#
|
||||
# The redo stack will be empty following this operation, so changes since the
|
||||
# checkpoint will be lost. If the given checkpoint is no longer present in the
|
||||
# undo history, no changes will be made to the buffer and this method will
|
||||
# return `false`.
|
||||
#
|
||||
# Returns a {Boolean} indicating whether the operation succeeded.
|
||||
revertToCheckpoint: (checkpoint) -> @buffer.revertToCheckpoint(checkpoint)
|
||||
|
||||
# Extended: Group all changes since the given checkpoint into a single
|
||||
# transaction for purposes of undo/redo.
|
||||
#
|
||||
# If the given checkpoint is no longer present in the undo history, no
|
||||
# grouping will be performed and this method will return `false`.
|
||||
#
|
||||
# Returns a {Boolean} indicating whether the operation succeeded.
|
||||
groupChangesSinceCheckpoint: (checkpoint) -> @buffer.groupChangesSinceCheckpoint(checkpoint)
|
||||
|
||||
###
|
||||
Section: TextEditor Coordinates
|
||||
###
|
||||
@@ -1248,18 +1263,33 @@ class TextEditor extends Model
|
||||
# ## Arguments
|
||||
#
|
||||
# * `marker` A {Marker} you want this decoration to follow.
|
||||
# * `decorationParams` An {Object} representing the decoration e.g. `{type: 'gutter', class: 'linter-error'}`
|
||||
# * `type` There are a few supported decoration types: `gutter`, `line`, and `highlight`
|
||||
# * `decorationParams` An {Object} representing the decoration e.g.
|
||||
# `{type: 'gutter', class: 'linter-error'}`
|
||||
# * `type` There are a few supported decoration types: `gutter`, `line`,
|
||||
# `highlight`, and `overlay`. The behavior of the types are as follows:
|
||||
# * `gutter` Adds the given `class` to the line numbers overlapping the
|
||||
# rows spanned by the marker.
|
||||
# * `line` Adds the given `class` to the lines overlapping the rows
|
||||
# spanned by the marker.
|
||||
# * `highlight` Creates a `.highlight` div with the nested class with up
|
||||
# to 3 nested regions that fill the area spanned by the marker.
|
||||
# * `overlay` Positions the view associated with the given item at the
|
||||
# head or tail of the given marker, depending on the `position`
|
||||
# property.
|
||||
# * `class` This CSS class will be applied to the decorated line number,
|
||||
# line, or highlight.
|
||||
# * `onlyHead` (optional) If `true`, the decoration will only be applied to the head
|
||||
# of the marker. Only applicable to the `line` and `gutter` types.
|
||||
# * `onlyEmpty` (optional) If `true`, the decoration will only be applied if the
|
||||
# associated marker is empty. Only applicable to the `line` and
|
||||
# * `onlyHead` (optional) If `true`, the decoration will only be applied to
|
||||
# the head of the marker. Only applicable to the `line` and `gutter`
|
||||
# types.
|
||||
# * `onlyEmpty` (optional) If `true`, the decoration will only be applied if
|
||||
# the associated marker is empty. Only applicable to the `line` and
|
||||
# `gutter` types.
|
||||
# * `onlyNonEmpty` (optional) If `true`, the decoration will only be applied if the
|
||||
# associated marker is non-empty. Only applicable to the `line` and
|
||||
# gutter types.
|
||||
# * `onlyNonEmpty` (optional) If `true`, the decoration will only be applied
|
||||
# if the associated marker is non-empty. Only applicable to the `line`
|
||||
# and gutter types.
|
||||
# * `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'`.
|
||||
#
|
||||
# Returns a {Decoration} object
|
||||
decorateMarker: (marker, decorationParams) ->
|
||||
@@ -1278,6 +1308,18 @@ class TextEditor extends Model
|
||||
decorationsForScreenRowRange: (startScreenRow, endScreenRow) ->
|
||||
@displayBuffer.decorationsForScreenRowRange(startScreenRow, endScreenRow)
|
||||
|
||||
# Extended: Get all decorations.
|
||||
#
|
||||
# Returns an {Array} of {Decoration}s.
|
||||
getDecorations: ->
|
||||
@displayBuffer.getDecorations()
|
||||
|
||||
# Extended: Get all decorations of type 'overlay'.
|
||||
#
|
||||
# Returns an {Array} of {Decoration}s.
|
||||
getOverlayDecorations: ->
|
||||
@displayBuffer.getOverlayDecorations()
|
||||
|
||||
decorationForId: (id) ->
|
||||
@displayBuffer.decorationForId(id)
|
||||
|
||||
|
||||
@@ -333,16 +333,18 @@ class ThemeManager
|
||||
|
||||
isInitialLoadComplete: -> @initialLoadComplete
|
||||
|
||||
# FIXME: This should be moved to WorkspaceElement
|
||||
addActiveThemeClasses: ->
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
for pack in @getActiveThemes()
|
||||
workspaceElement.classList.add("theme-#{pack.name}")
|
||||
if workspaceElement = document.querySelector('atom-workspace')
|
||||
for pack in @getActiveThemes()
|
||||
workspaceElement.classList.add("theme-#{pack.name}")
|
||||
return
|
||||
|
||||
# FIXME: This should be moved to WorkspaceElement
|
||||
removeActiveThemeClasses: ->
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
for pack in @getActiveThemes()
|
||||
workspaceElement.classList.remove("theme-#{pack.name}")
|
||||
if workspaceElement = document.querySelector('atom-workspace')
|
||||
for pack in @getActiveThemes()
|
||||
workspaceElement.classList.remove("theme-#{pack.name}")
|
||||
return
|
||||
|
||||
refreshLessCache: ->
|
||||
|
||||
@@ -26,8 +26,8 @@ class TokenizedBuffer extends Model
|
||||
constructor: ({@buffer, @tabLength, @invisibles}) ->
|
||||
@emitter = new Emitter
|
||||
|
||||
@subscribe atom.syntax.onDidAddGrammar(@grammarAddedOrUpdated)
|
||||
@subscribe atom.syntax.onDidUpdateGrammar(@grammarAddedOrUpdated)
|
||||
@subscribe atom.grammars.onDidAddGrammar(@grammarAddedOrUpdated)
|
||||
@subscribe atom.grammars.onDidUpdateGrammar(@grammarAddedOrUpdated)
|
||||
|
||||
@subscribe @buffer.preemptDidChange (e) => @handleBufferChange(e)
|
||||
@subscribe @buffer.onDidChangePath (@bufferPath) => @reloadGrammar()
|
||||
@@ -98,7 +98,7 @@ class TokenizedBuffer extends Model
|
||||
@emitter.emit 'did-change-grammar', grammar
|
||||
|
||||
reloadGrammar: ->
|
||||
if grammar = atom.syntax.selectGrammar(@buffer.getPath(), @buffer.getText())
|
||||
if grammar = atom.grammars.selectGrammar(@buffer.getPath(), @buffer.getText())
|
||||
@setGrammar(grammar)
|
||||
else
|
||||
throw new Error("No grammar found for path: #{path}")
|
||||
|
||||
@@ -19,6 +19,7 @@ class TooltipManager
|
||||
# * `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.
|
||||
# * `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.
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
{Disposable} = require 'event-kit'
|
||||
Grim = require 'grim'
|
||||
ViewRegistry = require './view-registry'
|
||||
|
||||
# Essential: The `ViewFactory` can creates the appropriate views for a given
|
||||
# model object based on recipes registered via {::addViewProvider}. It is
|
||||
# available via `atom.views` as a singleton object.
|
||||
module.exports =
|
||||
class ViewFactory
|
||||
constructor: ->
|
||||
@providers = []
|
||||
@deprecatedViewRegistry = new ViewRegistry(this)
|
||||
|
||||
# Essential: Add a provider that will be used by {::createView} to construct
|
||||
# an element based on the constructor of the given model object.
|
||||
#
|
||||
# ## Examples
|
||||
#
|
||||
# Text editors are divided into a model and a view layer, so when you interact
|
||||
# with methods like `atom.workspace.getActiveTextEditor()` you're only going
|
||||
# to get the model object. We display text editors on screen by teaching the
|
||||
# workspace what view constructor it should use to represent them:
|
||||
#
|
||||
# ```coffee
|
||||
# atom.views.addViewProvider
|
||||
# modelConstructor: TextEditor
|
||||
# viewConstructor: TextEditorElement
|
||||
# ```
|
||||
#
|
||||
# * `providerSpec` {Object} containing the following keys:
|
||||
# * `modelConstructor` Constructor {Function} for your model.
|
||||
# * `viewConstructor` (Optional) Constructor {Function} for your view. It
|
||||
# should be a subclass of `HTMLElement` (that is, your view should be a
|
||||
# DOM node) and have a `::setModel()` method which will be called
|
||||
# immediately after construction. If you don't supply this property, you
|
||||
# must supply the `createView` property with a function that never returns
|
||||
# `undefined`.
|
||||
# * `createView` (Optional) Factory {Function} that must return a subclass
|
||||
# of `HTMLElement` or `undefined`. If this property is not present or the
|
||||
# function returns `undefined`, the view provider will fall back to the
|
||||
# `viewConstructor` property. If you don't provide this property, you must
|
||||
# provider a `viewConstructor` property.
|
||||
#
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to remove the
|
||||
# added provider.
|
||||
addViewProvider: (providerSpec) ->
|
||||
@providers.push(providerSpec)
|
||||
new Disposable =>
|
||||
@providers = @providers.filter (provider) -> provider isnt providerSpec
|
||||
|
||||
getView: (object, suppressDeprecationWarning) ->
|
||||
unless suppressDeprecationWarning
|
||||
Grim.deprecate("Call ::getView on the workspace element instead. The atom.views global is only intended to create views.")
|
||||
@deprecatedViewRegistry.getView(object)
|
||||
|
||||
# Essential: Create an element for the given model object based on providers
|
||||
# registered via {::addViewProvider}.
|
||||
#
|
||||
# ## Examples
|
||||
#
|
||||
# ### Creating a workspace element in specs
|
||||
# ```coffee
|
||||
# workspaceElement = atom.views.createView(atom.workspace)
|
||||
# ```
|
||||
#
|
||||
# * `object` The model for which to create the view. A view provider matching
|
||||
# its constructor must be registered.
|
||||
# * `params` (optional) An {Object} with which to initialize the view. If the
|
||||
# selected view provider has a `createView` method, the params will be
|
||||
# passed to it. If the view provider has a `viewConstructor` method,
|
||||
# `initialize` will be called on the element after creation with the
|
||||
# given params.
|
||||
#
|
||||
# Returns a DOM element.
|
||||
createView: (object, params) ->
|
||||
view =
|
||||
if object instanceof HTMLElement
|
||||
object
|
||||
else if object?.jquery
|
||||
object[0]?.__spacePenView ?= object
|
||||
object[0]
|
||||
else if provider = @findProvider(object)
|
||||
params ?= {}
|
||||
params.viewFactory = this
|
||||
params.model = object
|
||||
element = provider.createView?(params)
|
||||
unless element?
|
||||
element = new provider.viewConstructor
|
||||
if not (typeof element.initialize is 'function') and (typeof element.setModel is 'function')
|
||||
Grim.deprecate("Define `::initialize` instead of `::setModel` in your view. It will be passed a params hash including the model.")
|
||||
element.setModel(object)
|
||||
else
|
||||
element.initialize(params)
|
||||
element
|
||||
else if viewConstructor = object?.getViewClass?()
|
||||
Grim.deprecate("Add a view provider for your object on atom.views instead of implementing `::getViewClass`.")
|
||||
view = new viewConstructor(object)
|
||||
view[0].__spacePenView ?= view
|
||||
view[0]
|
||||
else
|
||||
throw new Error("Can't create a view for #{object.constructor.name} instance. Please register a view provider.")
|
||||
@deprecatedViewRegistry.views.set(object, view)
|
||||
view
|
||||
|
||||
findProvider: (object) ->
|
||||
@providers.find ({modelConstructor}) -> object instanceof modelConstructor
|
||||
+2
-132
@@ -1,144 +1,14 @@
|
||||
{Disposable} = require 'event-kit'
|
||||
|
||||
# Essential: `ViewRegistry` handles the association between model and view
|
||||
# types in Atom. We call this association a View Provider. As in, for a given
|
||||
# model, this class can provide a view via {::getView}, as long as the
|
||||
# model/view association was registered via {::addViewProvider}
|
||||
#
|
||||
# If you're adding your own kind of pane item, a good strategy for all but the
|
||||
# simplest items is to separate the model and the view. The model handles
|
||||
# application logic and is the primary point of API interaction. The view
|
||||
# just handles presentation.
|
||||
#
|
||||
# View providers to inform the workspace how your model objects should be
|
||||
# presented in the DOM. A view provider must always return a DOM node, which
|
||||
# makes [HTML 5 custom elements](http://www.html5rocks.com/en/tutorials/webcomponents/customelements/)
|
||||
# an ideal tool for implementing views in Atom.
|
||||
#
|
||||
# You can access the `ViewRegistry` object via `atom.views`.
|
||||
#
|
||||
# ## Examples
|
||||
#
|
||||
# ### Getting the workspace element
|
||||
#
|
||||
# ```coffee
|
||||
# workspaceElement = atom.views.getView(atom.workspace)
|
||||
# ```
|
||||
#
|
||||
# ### Getting An Editor Element
|
||||
#
|
||||
# ```coffee
|
||||
# textEditor = atom.workspace.getActiveTextEditor()
|
||||
# textEditorElement = atom.views.getView(textEditor)
|
||||
# ```
|
||||
#
|
||||
# ### Getting A Pane Element
|
||||
#
|
||||
# ```coffee
|
||||
# pane = atom.workspace.getActivePane()
|
||||
# paneElement = atom.views.getView(pane)
|
||||
# ```
|
||||
module.exports =
|
||||
class ViewRegistry
|
||||
constructor: ->
|
||||
constructor: (@viewFactory) ->
|
||||
@views = new WeakMap
|
||||
@providers = []
|
||||
|
||||
# Essential: Add a provider that will be used to construct views in the
|
||||
# workspace's view layer based on model objects in its model layer.
|
||||
#
|
||||
# ## Examples
|
||||
#
|
||||
# Text editors are divided into a model and a view layer, so when you interact
|
||||
# with methods like `atom.workspace.getActiveTextEditor()` you're only going
|
||||
# to get the model object. We display text editors on screen by teaching the
|
||||
# workspace what view constructor it should use to represent them:
|
||||
#
|
||||
# ```coffee
|
||||
# atom.views.addViewProvider
|
||||
# modelConstructor: TextEditor
|
||||
# viewConstructor: TextEditorElement
|
||||
# ```
|
||||
#
|
||||
# * `providerSpec` {Object} containing the following keys:
|
||||
# * `modelConstructor` Constructor {Function} for your model.
|
||||
# * `viewConstructor` (Optional) Constructor {Function} for your view. It
|
||||
# should be a subclass of `HTMLElement` (that is, your view should be a
|
||||
# DOM node) and have a `::setModel()` method which will be called
|
||||
# immediately after construction. If you don't supply this property, you
|
||||
# must supply the `createView` property with a function that never returns
|
||||
# `undefined`.
|
||||
# * `createView` (Optional) Factory {Function} that must return a subclass
|
||||
# of `HTMLElement` or `undefined`. If this property is not present or the
|
||||
# function returns `undefined`, the view provider will fall back to the
|
||||
# `viewConstructor` property. If you don't provide this property, you must
|
||||
# provider a `viewConstructor` property.
|
||||
#
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to remove the
|
||||
# added provider.
|
||||
addViewProvider: (providerSpec) ->
|
||||
@providers.push(providerSpec)
|
||||
new Disposable =>
|
||||
@providers = @providers.filter (provider) -> provider isnt providerSpec
|
||||
|
||||
# Essential: Get the view associated with an object in the workspace.
|
||||
#
|
||||
# If you're just *using* the workspace, you shouldn't need to access the view
|
||||
# layer, but view layer access may be necessary if you want to perform DOM
|
||||
# manipulation that isn't supported via the model API.
|
||||
#
|
||||
# ## Examples
|
||||
#
|
||||
# ### Getting An Editor Element
|
||||
# ```coffee
|
||||
# textEditor = atom.workspace.getActiveTextEditor()
|
||||
# textEditorElement = atom.views.getView(textEditor)
|
||||
# ```
|
||||
#
|
||||
# ### Getting A Pane Element
|
||||
# ```coffee
|
||||
# pane = atom.workspace.getActivePane()
|
||||
# paneElement = atom.views.getView(pane)
|
||||
# ```
|
||||
#
|
||||
# ### Getting The Workspace Element
|
||||
#
|
||||
# ```coffee
|
||||
# workspaceElement = atom.views.getView(atom.workspace)
|
||||
# ```
|
||||
#
|
||||
# * `object` The object for which you want to retrieve a view. This can be a
|
||||
# pane item, a pane, or the workspace itself.
|
||||
#
|
||||
# Returns a DOM element.
|
||||
getView: (object) ->
|
||||
return unless object?
|
||||
|
||||
if view = @views.get(object)
|
||||
view
|
||||
else
|
||||
view = @createView(object)
|
||||
view = @viewFactory.createView(object, viewRegistry: this)
|
||||
@views.set(object, view)
|
||||
view
|
||||
|
||||
createView: (object) ->
|
||||
if object instanceof HTMLElement
|
||||
object
|
||||
else if object?.jquery
|
||||
object[0]?.__spacePenView ?= object
|
||||
object[0]
|
||||
else if provider = @findProvider(object)
|
||||
element = provider.createView?(object)
|
||||
unless element?
|
||||
element = new provider.viewConstructor
|
||||
element.setModel(object)
|
||||
element
|
||||
else if viewConstructor = object?.getViewClass?()
|
||||
view = new viewConstructor(object)
|
||||
view[0].__spacePenView ?= view
|
||||
view[0]
|
||||
else
|
||||
throw new Error("Can't create a view for #{object.constructor.name} instance. Please register a view provider.")
|
||||
|
||||
findProvider: (object) ->
|
||||
@providers.find ({modelConstructor}) -> object instanceof modelConstructor
|
||||
|
||||
@@ -14,11 +14,32 @@ class WindowEventHandler
|
||||
constructor: ->
|
||||
@reloadRequested = false
|
||||
|
||||
@subscribe ipc, 'command', (command, args...) ->
|
||||
@subscribe ipc, 'message', (message, detail) ->
|
||||
switch message
|
||||
when 'open-path'
|
||||
{pathToOpen, initialLine, initialColumn} = detail
|
||||
|
||||
unless atom.project?.getPaths().length
|
||||
if fs.existsSync(pathToOpen) or fs.existsSync(path.dirname(pathToOpen))
|
||||
atom.project?.setPaths([pathToOpen])
|
||||
|
||||
unless fs.isDirectorySync(pathToOpen)
|
||||
atom.workspace?.open(pathToOpen, {initialLine, initialColumn})
|
||||
|
||||
when 'update-available'
|
||||
atom.updateAvailable(detail)
|
||||
|
||||
# FIXME: Remove this when deprecations are removed
|
||||
{releaseVersion, releaseNotes} = detail
|
||||
detail = [releaseVersion, releaseNotes]
|
||||
|
||||
if workspaceElement = document.querySelector('atom-workspace')
|
||||
atom.commands.dispatch workspaceElement, "window:update-available", detail
|
||||
|
||||
@subscribe ipc, 'command', (command, args...) ->
|
||||
activeElement = document.activeElement
|
||||
# Use the workspace element view if body has focus
|
||||
if activeElement is document.body and workspaceElement = atom.views.getView(atom.workspace)
|
||||
if activeElement is document.body and workspaceElement = document.querySelector('atom-workspace')
|
||||
activeElement = workspaceElement
|
||||
|
||||
atom.commands.dispatch(activeElement, command, args[0])
|
||||
@@ -30,14 +51,6 @@ class WindowEventHandler
|
||||
|
||||
@subscribe $(window), 'blur', -> document.body.classList.add('is-blurred')
|
||||
|
||||
@subscribeToCommand $(window), 'window:open-path', (event, {pathToOpen, initialLine, initialColumn}) ->
|
||||
unless atom.project?.getPath()
|
||||
if fs.existsSync(pathToOpen) or fs.existsSync(path.dirname(pathToOpen))
|
||||
atom.project?.setPath(pathToOpen)
|
||||
|
||||
unless fs.isDirectorySync(pathToOpen)
|
||||
atom.workspace?.open(pathToOpen, {initialLine, initialColumn})
|
||||
|
||||
@subscribe $(window), 'beforeunload', =>
|
||||
confirmed = atom.workspace?.confirmClose()
|
||||
atom.hide() if confirmed and not @reloadRequested and atom.getCurrentWindow().isWebViewFocused()
|
||||
|
||||
@@ -6,9 +6,37 @@ scrollbarStyle = require 'scrollbar-style'
|
||||
{callAttachHooks} = require 'space-pen'
|
||||
WorkspaceView = null
|
||||
|
||||
# Essential: The on-screen representation of the workspace. Unless you have
|
||||
# an explicit need access the view layer, you should prefer using the
|
||||
# {Workspace} model object via `atom.workspace`.
|
||||
#
|
||||
# ## Examples
|
||||
#
|
||||
# In specs, you can create a workspace element via the view factory and attach
|
||||
# it to the DOM:
|
||||
#
|
||||
# ```coffee
|
||||
# workspaceElement = atom.views.createElement(atom.workspace)
|
||||
# jasmine.attachToDOM(workspaceElement)
|
||||
#
|
||||
# # Get a reference to a nested element corresponding to a model object...
|
||||
# editorElement = workspaceElement.getView(atom.workspace.getActiveTextEditor)
|
||||
# ```
|
||||
#
|
||||
# In production, you can access the singleton instance of the workspace element
|
||||
# by pulling it directly from the DOM:
|
||||
#
|
||||
# ```coffee
|
||||
# workspaceElement = document.querySelector('atom-workspace')
|
||||
#
|
||||
# # Careful! Direct DOM manipulation is more likely to break as Atom changes
|
||||
# workspaceElement.addClass("foo")
|
||||
# ```
|
||||
module.exports =
|
||||
class WorkspaceElement extends HTMLElement
|
||||
globalTextEditorStyleSheet: null
|
||||
viewRegistry: null
|
||||
model: null
|
||||
|
||||
createdCallback: ->
|
||||
@subscriptions = new CompositeDisposable
|
||||
@@ -62,19 +90,20 @@ class WorkspaceElement extends HTMLElement
|
||||
WorkspaceView ?= require './workspace-view'
|
||||
@__spacePenView = new WorkspaceView(this)
|
||||
|
||||
getModel: -> @model
|
||||
initialize: ({@viewFactory, @model}) ->
|
||||
@viewRegistry = @viewFactory.deprecatedViewRegistry
|
||||
atom.views.deprecatedViewRegistry = @viewRegistry
|
||||
|
||||
setModel: (@model) ->
|
||||
@paneContainer = atom.views.getView(@model.paneContainer)
|
||||
@paneContainer = @viewRegistry.getView(@model.paneContainer)
|
||||
@verticalAxis.appendChild(@paneContainer)
|
||||
@addEventListener 'focus', @handleFocus.bind(this)
|
||||
|
||||
@panelContainers =
|
||||
top: @model.panelContainers.top.getView()
|
||||
left: @model.panelContainers.left.getView()
|
||||
right: @model.panelContainers.right.getView()
|
||||
bottom: @model.panelContainers.bottom.getView()
|
||||
modal: @model.panelContainers.modal.getView()
|
||||
top: @viewRegistry.getView(@model.panelContainers.top)
|
||||
left: @viewRegistry.getView(@model.panelContainers.left)
|
||||
right: @viewRegistry.getView(@model.panelContainers.right)
|
||||
bottom: @viewRegistry.getView(@model.panelContainers.bottom)
|
||||
modal: @viewRegistry.getView(@model.panelContainers.modal)
|
||||
|
||||
@horizontalAxis.insertBefore(@panelContainers.left, @verticalAxis)
|
||||
@horizontalAxis.appendChild(@panelContainers.right)
|
||||
@@ -86,6 +115,32 @@ class WorkspaceElement extends HTMLElement
|
||||
|
||||
@__spacePenView.setModel(@model)
|
||||
|
||||
getModel: -> @model
|
||||
|
||||
# Essential: Get the view associated with a model in the workspace.
|
||||
#
|
||||
# ## Examples
|
||||
#
|
||||
# ### Get the active text editor's view element
|
||||
# ```coffee
|
||||
# # At the model level...
|
||||
# activeTextEditor = atom.workspace.getActiveTextEditor()
|
||||
#
|
||||
# # At the view level...
|
||||
# workspaceElement = document.querySelector('atom-workspace')
|
||||
# textEditorElement = workspaceElement.getView(activeTextEditor)
|
||||
#
|
||||
# # Now manipulate the text editor's DOM at your own risk...
|
||||
# ```
|
||||
#
|
||||
# * `model` A model object that's present in the workspace. It could be a
|
||||
# workspace model object such as a {Pane} or a {Panel}, or it could be a
|
||||
# third-party model such as a pane or panel's *item*.
|
||||
#
|
||||
# Returns a DOM element.
|
||||
getView: (model) ->
|
||||
@viewRegistry.getView(model)
|
||||
|
||||
setTextEditorFontSize: (fontSize) ->
|
||||
@updateGlobalEditorStyle('font-size', fontSize + 'px')
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ class WorkspaceView extends View
|
||||
|
||||
constructor: (@element) ->
|
||||
unless @element?
|
||||
return atom.views.getView(atom.workspace).__spacePenView
|
||||
return atom.views.getView(atom.workspace, true).__spacePenView
|
||||
super
|
||||
@deprecateViewEvents()
|
||||
|
||||
|
||||
+56
-30
@@ -14,7 +14,6 @@ Panel = require './panel'
|
||||
PanelElement = require './panel-element'
|
||||
PanelContainer = require './panel-container'
|
||||
PanelContainerElement = require './panel-container-element'
|
||||
ViewRegistry = require './view-registry'
|
||||
WorkspaceElement = require './workspace-element'
|
||||
|
||||
# Essential: Represents the state of the user interface for the entire window.
|
||||
@@ -34,7 +33,6 @@ class Workspace extends Model
|
||||
@delegatesProperty 'activePane', 'activePaneItem', toProperty: 'paneContainer'
|
||||
|
||||
@properties
|
||||
viewRegistry: null
|
||||
paneContainer: null
|
||||
fullScreen: false
|
||||
destroyedItemUris: -> []
|
||||
@@ -45,16 +43,15 @@ class Workspace extends Model
|
||||
@emitter = new Emitter
|
||||
@openers = []
|
||||
|
||||
viewRegistry = atom.views
|
||||
@paneContainer ?= new PaneContainer({viewRegistry})
|
||||
@paneContainer ?= new PaneContainer()
|
||||
@paneContainer.onDidDestroyPaneItem(@onPaneItemDestroyed)
|
||||
|
||||
@panelContainers =
|
||||
top: new PanelContainer({viewRegistry, location: 'top'})
|
||||
left: new PanelContainer({viewRegistry, location: 'left'})
|
||||
right: new PanelContainer({viewRegistry, location: 'right'})
|
||||
bottom: new PanelContainer({viewRegistry, location: 'bottom'})
|
||||
modal: new PanelContainer({viewRegistry, location: 'modal'})
|
||||
top: new PanelContainer({location: 'top'})
|
||||
left: new PanelContainer({location: 'left'})
|
||||
right: new PanelContainer({location: 'right'})
|
||||
bottom: new PanelContainer({location: 'bottom'})
|
||||
modal: new PanelContainer({location: 'modal'})
|
||||
|
||||
@subscribeToActiveItem()
|
||||
|
||||
@@ -86,7 +83,6 @@ class Workspace extends Model
|
||||
for packageName in params.packagesWithActiveGrammars ? []
|
||||
atom.packages.getLoadedPackage(packageName)?.loadGrammarsSync()
|
||||
|
||||
params.paneContainer.viewRegistry = atom.views
|
||||
params.paneContainer = PaneContainer.deserialize(params.paneContainer)
|
||||
params
|
||||
|
||||
@@ -105,13 +101,13 @@ class Workspace extends Model
|
||||
|
||||
packageNames.push(packageName)
|
||||
for scopeName in includedGrammarScopes ? []
|
||||
addGrammar(atom.syntax.grammarForScopeName(scopeName))
|
||||
addGrammar(atom.grammars.grammarForScopeName(scopeName))
|
||||
|
||||
editors = @getTextEditors()
|
||||
addGrammar(editor.getGrammar()) for editor in editors
|
||||
|
||||
if editors.length > 0
|
||||
for grammar in atom.syntax.getGrammars() when grammar.injectionSelector
|
||||
for grammar in atom.grammars.getGrammars() when grammar.injectionSelector
|
||||
addGrammar(grammar)
|
||||
|
||||
_.uniq(packageNames)
|
||||
@@ -377,11 +373,15 @@ class Workspace extends Model
|
||||
# * `activatePane` A {Boolean} indicating whether to call {Pane::activate} on
|
||||
# the containing pane. Defaults to `true`.
|
||||
openSync: (uri='', options={}) ->
|
||||
deprecate("Don't use the `changeFocus` option") if options.changeFocus?
|
||||
# TODO: Remove deprecated changeFocus option
|
||||
if options.changeFocus?
|
||||
deprecate("The `changeFocus` option has been renamed to `activatePane`")
|
||||
options.activatePane = options.changeFocus
|
||||
delete options.changeFocus
|
||||
|
||||
{initialLine, initialColumn} = options
|
||||
# TODO: Remove deprecated changeFocus option
|
||||
activatePane = options.activatePane ? options.changeFocus ? true
|
||||
activatePane = options.activatePane ? true
|
||||
|
||||
uri = atom.project.resolve(uri)
|
||||
|
||||
item = @activePane.itemForUri(uri)
|
||||
@@ -395,7 +395,13 @@ class Workspace extends Model
|
||||
item
|
||||
|
||||
openUriInPane: (uri, pane, options={}) ->
|
||||
changeFocus = options.changeFocus ? true
|
||||
# TODO: Remove deprecated changeFocus option
|
||||
if options.changeFocus?
|
||||
deprecate("The `changeFocus` option has been renamed to `activatePane`")
|
||||
options.activatePane = options.changeFocus
|
||||
delete options.changeFocus
|
||||
|
||||
activatePane = options.activatePane ? true
|
||||
|
||||
if uri?
|
||||
item = pane.itemForUri(uri)
|
||||
@@ -409,7 +415,7 @@ class Workspace extends Model
|
||||
@paneContainer.root = pane
|
||||
@itemOpened(item)
|
||||
pane.activateItem(item)
|
||||
pane.activate() if changeFocus
|
||||
pane.activate() if activatePane
|
||||
index = pane.getActiveItemIndex()
|
||||
@emit "uri-opened"
|
||||
@emitter.emit 'did-open', {uri, pane, item, index}
|
||||
@@ -609,12 +615,16 @@ class Workspace extends Model
|
||||
Section: Panels
|
||||
###
|
||||
|
||||
# Essential: Get an {Array} of all the panel items at the bottom of the editor window.
|
||||
getBottomPanels: ->
|
||||
@getPanels('bottom')
|
||||
|
||||
# Essential: Adds a panel item to the bottom of the editor window.
|
||||
#
|
||||
# * `options` {Object}
|
||||
# * `item` Your panel content. It can be DOM element, a jQuery element, or
|
||||
# a model with a view registered via {ViewRegistry::addViewProvider}. We recommend the
|
||||
# latter. See {ViewRegistry::addViewProvider} for more information.
|
||||
# a model with a view registered via {ViewFactory::addViewProvider}. We recommend the
|
||||
# latter. See {ViewFactory::addViewProvider} for more information.
|
||||
# * `visible` (optional) {Boolean} false if you want the panel to initially be hidden
|
||||
# (default: true)
|
||||
# * `priority` (optional) {Number} Determines stacking order. Lower priority items are
|
||||
@@ -624,12 +634,16 @@ class Workspace extends Model
|
||||
addBottomPanel: (options) ->
|
||||
@addPanel('bottom', options)
|
||||
|
||||
# Essential: Get an {Array} of all the panel items to the left of the editor window.
|
||||
getLeftPanels: ->
|
||||
@getPanels('left')
|
||||
|
||||
# Essential: Adds a panel item to the left of the editor window.
|
||||
#
|
||||
# * `options` {Object}
|
||||
# * `item` Your panel content. It can be DOM element, a jQuery element, or
|
||||
# a model with a view registered via {ViewRegistry::addViewProvider}. We recommend the
|
||||
# latter. See {ViewRegistry::addViewProvider} for more information.
|
||||
# a model with a view registered via {ViewFactory::addViewProvider}. We recommend the
|
||||
# latter. See {ViewFactory::addViewProvider} for more information.
|
||||
# * `visible` (optional) {Boolean} false if you want the panel to initially be hidden
|
||||
# (default: true)
|
||||
# * `priority` (optional) {Number} Determines stacking order. Lower priority items are
|
||||
@@ -639,12 +653,16 @@ class Workspace extends Model
|
||||
addLeftPanel: (options) ->
|
||||
@addPanel('left', options)
|
||||
|
||||
# Essential: Get an {Array} of all the panel items to the right of the editor window.
|
||||
getRightPanels: ->
|
||||
@getPanels('right')
|
||||
|
||||
# Essential: Adds a panel item to the right of the editor window.
|
||||
#
|
||||
# * `options` {Object}
|
||||
# * `item` Your panel content. It can be DOM element, a jQuery element, or
|
||||
# a model with a view registered via {ViewRegistry::addViewProvider}. We recommend the
|
||||
# latter. See {ViewRegistry::addViewProvider} for more information.
|
||||
# a model with a view registered via {ViewFactory::addViewProvider}. We recommend the
|
||||
# latter. See {ViewFactory::addViewProvider} for more information.
|
||||
# * `visible` (optional) {Boolean} false if you want the panel to initially be hidden
|
||||
# (default: true)
|
||||
# * `priority` (optional) {Number} Determines stacking order. Lower priority items are
|
||||
@@ -654,12 +672,16 @@ class Workspace extends Model
|
||||
addRightPanel: (options) ->
|
||||
@addPanel('right', options)
|
||||
|
||||
# Essential: Get an {Array} of all the panel items at the top of the editor window.
|
||||
getTopPanels: ->
|
||||
@getPanels('top')
|
||||
|
||||
# Essential: Adds a panel item to the top of the editor window above the tabs.
|
||||
#
|
||||
# * `options` {Object}
|
||||
# * `item` Your panel content. It can be DOM element, a jQuery element, or
|
||||
# a model with a view registered via {ViewRegistry::addViewProvider}. We recommend the
|
||||
# latter. See {ViewRegistry::addViewProvider} for more information.
|
||||
# a model with a view registered via {ViewFactory::addViewProvider}. We recommend the
|
||||
# latter. See {ViewFactory::addViewProvider} for more information.
|
||||
# * `visible` (optional) {Boolean} false if you want the panel to initially be hidden
|
||||
# (default: true)
|
||||
# * `priority` (optional) {Number} Determines stacking order. Lower priority items are
|
||||
@@ -669,12 +691,16 @@ class Workspace extends Model
|
||||
addTopPanel: (options) ->
|
||||
@addPanel('top', options)
|
||||
|
||||
# Essential: Get an {Array} of all the modal panel items
|
||||
getModalPanels: ->
|
||||
@getPanels('modal')
|
||||
|
||||
# Essential: Adds a panel item as a modal dialog.
|
||||
#
|
||||
# * `options` {Object}
|
||||
# * `item` Your panel content. It can be DOM element, a jQuery element, or
|
||||
# a model with a view registered via {ViewRegistry::addViewProvider}. We recommend the
|
||||
# latter. See {ViewRegistry::addViewProvider} for more information.
|
||||
# a model with a view registered via {ViewFactory::addViewProvider}. We recommend the
|
||||
# latter. See {ViewFactory::addViewProvider} for more information.
|
||||
# * `visible` (optional) {Boolean} false if you want the panel to initially be hidden
|
||||
# (default: true)
|
||||
# * `priority` (optional) {Number} Determines stacking order. Lower priority items are
|
||||
@@ -682,11 +708,11 @@ class Workspace extends Model
|
||||
#
|
||||
# Returns a {Panel}
|
||||
addModalPanel: (options={}) ->
|
||||
# TODO: remove these default classes. They are to supoprt existing themes.
|
||||
options.className ?= 'overlay from-top'
|
||||
@addPanel('modal', options)
|
||||
|
||||
getPanels: (location) ->
|
||||
@panelContainers[location].getPanels()
|
||||
|
||||
addPanel: (location, options) ->
|
||||
options ?= {}
|
||||
options.viewRegistry = atom.views
|
||||
@panelContainers[location].addPanel(new Panel(options))
|
||||
|
||||
@@ -140,6 +140,10 @@ body {
|
||||
color: darken(#f0ad4e, 20%);
|
||||
line-height: 1.4;
|
||||
|
||||
a {
|
||||
color: darken(#f0ad4e, 15%);
|
||||
}
|
||||
|
||||
code {
|
||||
color: darken(#f0ad4e, 20%);
|
||||
background: lighten(#f0ad4e, 35%);
|
||||
|
||||
@@ -64,13 +64,3 @@ div > .inline-block-tight:last-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.error {
|
||||
-webkit-animation: flash-error 0.3s ease-in;
|
||||
}
|
||||
|
||||
@-webkit-keyframes flash-error {
|
||||
0% { background: @background-color-error; }
|
||||
|
||||
100% { background: auto; }
|
||||
}
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário