2013-10-26 03:07:00 +04:00
|
|
|
# Creating Packages
|
2013-08-21 02:46:47 +04:00
|
|
|
|
2013-10-15 04:00:16 +04:00
|
|
|
Packages are at the core of Atom. Nearly everything outside of the main editor
|
2013-10-26 03:07:00 +04:00
|
|
|
is handled by a package. That includes "core" pieces like the [file tree][file-tree],
|
|
|
|
[status bar][status-bar], [syntax highlighting][cs-syntax], and more.
|
2013-08-21 02:46:47 +04:00
|
|
|
|
|
|
|
A package can contain a variety of different resource types to change Atom's
|
2013-10-26 03:07:00 +04:00
|
|
|
behavior. The basic package layout is as follows:
|
2013-08-21 02:46:47 +04:00
|
|
|
|
|
|
|
```text
|
|
|
|
my-package/
|
|
|
|
grammars/
|
2013-10-16 04:34:19 +04:00
|
|
|
keymaps/
|
|
|
|
lib/
|
|
|
|
menus/
|
2013-08-21 02:46:47 +04:00
|
|
|
spec/
|
2013-10-16 04:34:19 +04:00
|
|
|
snippets/
|
|
|
|
stylesheets/
|
2013-08-21 02:46:47 +04:00
|
|
|
index.coffee
|
2013-10-16 04:34:19 +04:00
|
|
|
package.json
|
2013-08-21 02:46:47 +04:00
|
|
|
```
|
|
|
|
|
2013-10-26 03:07:00 +04:00
|
|
|
Not every package will have (or need) all of these directories.
|
|
|
|
|
2013-10-31 02:21:51 +04:00
|
|
|
We have [a tutorial on creating your first package][first-package].
|
2013-10-31 01:34:50 +04:00
|
|
|
|
2013-08-21 02:46:47 +04:00
|
|
|
## package.json
|
|
|
|
|
2013-10-26 03:07:00 +04:00
|
|
|
Similar to [npm packages][npm], Atom packages contain a _package.json_ file
|
2013-10-15 04:00:16 +04:00
|
|
|
in their top-level directory. This file contains metadata about the package,
|
|
|
|
such as the path to its "main" module, library dependencies, and manifests
|
|
|
|
specifying the order in which its resources should be loaded.
|
2013-08-21 02:46:47 +04:00
|
|
|
|
2013-10-15 04:00:16 +04:00
|
|
|
In addition to the regular [npm package.json keys][npm-keys] available, Atom
|
|
|
|
package.json files have their own additions.
|
2013-08-21 03:48:01 +04:00
|
|
|
|
|
|
|
- `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
|
2013-10-15 04:00:16 +04:00
|
|
|
stylesheets your package needs to load. If not specified, stylesheets in the
|
|
|
|
_stylesheets_ directory are added alphabetically.
|
2013-08-21 03:48:01 +04:00
|
|
|
- `keymaps`(**Optional**): an Array of Strings identifying the order of the
|
2013-10-15 04:00:16 +04:00
|
|
|
key mappings your package needs to load. If not specified, mappings in the
|
|
|
|
_keymaps_ directory are added alphabetically.
|
2013-09-20 01:21:31 +04:00
|
|
|
- `menus`(**Optional**): an Array of Strings identifying the order of
|
|
|
|
the menu mappings your package needs to load. If not specified, mappings
|
|
|
|
in the _keymap_ directory are added alphabetically.
|
2013-08-21 03:48:01 +04:00
|
|
|
- `snippets` (**Optional**): an Array of Strings identifying the order of the
|
2013-10-15 04:00:16 +04:00
|
|
|
snippets your package needs to load. If not specified, snippets in the
|
|
|
|
_snippets_ directory are added alphabetically.
|
2013-08-21 03:48:01 +04:00
|
|
|
- `activationEvents` (**Optional**): an Array of Strings identifying events that
|
2013-10-15 04:00:16 +04:00
|
|
|
trigger your package's activation. You can delay the loading of your package
|
|
|
|
until one of these events is trigged.
|
2013-08-21 02:46:47 +04:00
|
|
|
|
|
|
|
## Source Code
|
|
|
|
|
|
|
|
If you want to extend Atom's behavior, your package should contain a single
|
|
|
|
top-level module, which you export from _index.coffee_ (or whichever file is
|
|
|
|
indicated by the `main` key in your _package.json_ file). The remainder of your
|
|
|
|
code should be placed in the `lib` directory, and required from your top-level
|
|
|
|
file.
|
|
|
|
|
|
|
|
Your package's top-level module is a singleton object that manages the lifecycle
|
|
|
|
of your extensions to Atom. Even if your package creates ten different views and
|
|
|
|
appends them to different parts of the DOM, it's all managed from your top-level
|
|
|
|
object.
|
|
|
|
|
|
|
|
Your package's top-level module should implement the following methods:
|
|
|
|
|
2013-11-26 22:50:30 +04:00
|
|
|
- `activate(state)`: This **required** method is called when your
|
|
|
|
package is activated. It is passed the state data from the last time the window
|
|
|
|
was serialized if your module implements the `serialize()` method. Use this to
|
|
|
|
do initialization work when your package is started (like setting up DOM
|
|
|
|
elements or binding events).
|
2013-08-21 02:46:47 +04:00
|
|
|
|
|
|
|
- `serialize()`: This **optional** method is called when the window is shutting
|
|
|
|
down, allowing you to return JSON to represent the state of your component. When
|
|
|
|
the window is later restored, the data you returned is passed to your
|
|
|
|
module's `activate` method so you can restore your view to where the user left
|
|
|
|
off.
|
|
|
|
|
|
|
|
- `deactivate()`: This **optional** method is called when the window is shutting
|
|
|
|
down. If your package is watching any files or holding external resources in any
|
|
|
|
other way, release them here. If you're just subscribing to things on window,
|
|
|
|
you don't need to worry because that's getting torn down anyway.
|
|
|
|
|
|
|
|
### Simple Package Code
|
|
|
|
|
2013-10-26 03:07:00 +04:00
|
|
|
Your directory would look like this:
|
|
|
|
|
2013-08-21 02:46:47 +04:00
|
|
|
```text
|
|
|
|
my-package/
|
2013-10-26 03:07:00 +04:00
|
|
|
package.json
|
2013-08-21 02:46:47 +04:00
|
|
|
index.coffee
|
|
|
|
lib/
|
|
|
|
my-package.coffee
|
|
|
|
```
|
|
|
|
|
2013-10-26 03:07:00 +04:00
|
|
|
`index.coffee` might be:
|
2013-08-21 02:46:47 +04:00
|
|
|
```coffeescript
|
|
|
|
module.exports = require "./lib/my-package"
|
|
|
|
```
|
|
|
|
|
2013-10-26 03:07:00 +04:00
|
|
|
`my-package/my-package.coffee` might start:
|
2013-08-21 02:46:47 +04:00
|
|
|
```coffeescript
|
|
|
|
module.exports =
|
2013-11-26 22:50:30 +04:00
|
|
|
activate: (state) -> # ...
|
2013-08-21 02:46:47 +04:00
|
|
|
deactivate: -> # ...
|
|
|
|
serialize: -> # ...
|
|
|
|
```
|
|
|
|
|
2013-10-16 04:34:19 +04:00
|
|
|
Beyond this simple contract, your package has access to Atom's API. Be aware
|
|
|
|
that since we are early in development, APIs are subject to change and we have
|
|
|
|
not yet established clear boundaries between what is public and what is private.
|
|
|
|
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.
|
2013-08-21 02:46:47 +04:00
|
|
|
|
|
|
|
## Stylesheets
|
|
|
|
|
|
|
|
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
|
2013-10-16 04:34:19 +04:00
|
|
|
your package is activated. Stylesheets can be written as CSS or [LESS] (but LESS
|
|
|
|
is recommended).
|
2013-08-21 02:46:47 +04:00
|
|
|
|
2013-10-26 03:07:00 +04:00
|
|
|
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
|
2013-12-04 23:33:04 +04:00
|
|
|
the styleguide: open the command palette (`cmd-shift-P`) and search for _styleguide_,
|
2013-10-26 03:07:00 +04:00
|
|
|
or just type `cmd-ctrl-G`.
|
2013-10-16 22:52:00 +04:00
|
|
|
|
2013-10-26 03:07:00 +04:00
|
|
|
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!
|
2013-10-16 22:52:00 +04:00
|
|
|
|
2013-10-15 04:00:16 +04:00
|
|
|
An optional `stylesheets` array in your _package.json_ can list the stylesheets
|
|
|
|
by name to specify a loading order; otherwise, stylesheets are loaded
|
|
|
|
alphabetically.
|
2013-08-21 02:46:47 +04:00
|
|
|
|
|
|
|
## Keymaps
|
|
|
|
|
2013-10-26 03:07:00 +04:00
|
|
|
It's recommended that you provide key bindings for commonly used actions for
|
|
|
|
your extension, especially if you're also adding a new command:
|
|
|
|
|
2013-10-16 04:34:19 +04:00
|
|
|
```coffeescript
|
|
|
|
'.tree-view-scroller':
|
|
|
|
'ctrl-V': 'changer:magic'
|
|
|
|
```
|
|
|
|
|
|
|
|
Keymaps are placed in the _keymaps_ subdirectory. By default, all keymaps are
|
|
|
|
loaded in alphabetical order. An optional `keymaps` array in your _package.json_
|
|
|
|
can specify which keymaps to load and in what order.
|
2013-08-21 02:46:47 +04:00
|
|
|
|
2013-10-26 03:07:00 +04:00
|
|
|
|
|
|
|
Keybindings are executed by determining which element the keypress occured on. In
|
|
|
|
the example above, `changer:magic` command is executed when pressing `ctrl-V` on
|
|
|
|
the `.tree-view-scroller` element.
|
|
|
|
|
2013-10-16 04:34:19 +04:00
|
|
|
See the [main keymaps documentation][keymaps] for more detailed information on
|
|
|
|
how keymaps work.
|
2013-08-21 02:46:47 +04:00
|
|
|
|
2013-09-20 01:21:31 +04:00
|
|
|
## Menus
|
|
|
|
|
2013-10-16 04:34:19 +04:00
|
|
|
Menus are placed in the _menus_ subdirectory. By default, all menus are loaded
|
|
|
|
in alphabetical order. An optional `menus` array in your _package.json_ can
|
|
|
|
specify which menus to load and in what order.
|
|
|
|
|
|
|
|
### Application Menu
|
|
|
|
|
2013-10-26 03:07:00 +04:00
|
|
|
It's recommended that you create an application menu item for common actions
|
|
|
|
with your package that aren't tied to a specific element:
|
|
|
|
|
2013-10-16 04:34:19 +04:00
|
|
|
```coffee-script
|
|
|
|
'menu': [
|
|
|
|
{
|
|
|
|
'label': 'Packages'
|
|
|
|
'submenu': [
|
|
|
|
{
|
|
|
|
'label': 'My Package'
|
|
|
|
'submenu': [
|
|
|
|
{
|
|
|
|
'label': 'Toggle'
|
|
|
|
'command': 'my-package:toggle'
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
```
|
2013-09-20 01:21:31 +04:00
|
|
|
|
2013-10-26 03:07:00 +04:00
|
|
|
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.
|
2013-10-15 04:00:16 +04:00
|
|
|
|
2013-10-16 04:34:19 +04:00
|
|
|
The menu templates you specify are merged with all other templates provided
|
|
|
|
by other packages in the order which they were loaded.
|
2013-09-20 01:21:31 +04:00
|
|
|
|
2013-10-16 04:34:19 +04:00
|
|
|
### Context Menu
|
2013-09-20 01:21:31 +04:00
|
|
|
|
2013-10-26 03:07:00 +04:00
|
|
|
It's recommended to specify a context menu item for commands that are linked to
|
|
|
|
specific parts of the interface, like adding a file in the tree-view:
|
|
|
|
|
2013-10-16 04:34:19 +04:00
|
|
|
```coffee-script
|
2013-09-20 01:21:31 +04:00
|
|
|
'context-menu':
|
|
|
|
'.tree-view':
|
|
|
|
'Add file': 'tree-view:add-file'
|
2013-12-02 20:23:29 +04:00
|
|
|
'.workspace':
|
2013-09-20 01:21:31 +04:00
|
|
|
'Inspect Element': 'core:inspect'
|
|
|
|
```
|
|
|
|
|
2013-10-16 04:34:19 +04:00
|
|
|
To add your own item to the application menu simply create a top level
|
2013-10-26 03:07:00 +04:00
|
|
|
`context-menu` key in any menu configuration file in _menus_. This can be a
|
|
|
|
JSON or [CSON] file.
|
2013-10-16 04:34:19 +04:00
|
|
|
|
|
|
|
Context menus are created by determining which element was selected and
|
|
|
|
then adding all of the menu items whose selectors match that element (in
|
|
|
|
the order which they were loaded). The process is then repeated for the
|
|
|
|
elements until reaching the top of the DOM tree.
|
|
|
|
|
|
|
|
In the example above, the `Add file` item will only appear when the focused item
|
|
|
|
or one of its parents has the `tree-view` class applied to it.
|
|
|
|
|
2013-08-21 02:46:47 +04:00
|
|
|
## Snippets
|
|
|
|
|
2013-10-16 04:34:19 +04:00
|
|
|
An extension can supply language snippets in the _snippets_ directory which
|
2013-10-26 03:07:00 +04:00
|
|
|
allows the user to enter repetitive text quickly:
|
2013-08-21 02:46:47 +04:00
|
|
|
|
|
|
|
```coffeescript
|
|
|
|
".source.coffee .specs":
|
|
|
|
"Expect":
|
|
|
|
prefix: "ex"
|
|
|
|
body: "expect($1).to$2"
|
|
|
|
"Describe":
|
|
|
|
prefix: "de"
|
|
|
|
body: """
|
|
|
|
describe "${1:description}", ->
|
|
|
|
${2:body}
|
|
|
|
"""
|
|
|
|
```
|
|
|
|
|
2013-10-15 04:00:16 +04:00
|
|
|
A snippets file contains scope selectors at its top level (`.source.coffee
|
|
|
|
.spec`). Each scope selector contains a hash of snippets keyed by their name
|
|
|
|
(`Expect`, `Describe`). Each snippet also specifies a `prefix` and a `body` key.
|
|
|
|
The `prefix` represents the first few letters to type before hitting the `tab`
|
|
|
|
key to autocomplete. The `body` defines the autofilled text. You can use
|
|
|
|
placeholders like `$1`, `$2`, to indicate regions in the body the user can
|
|
|
|
navigate to every time they hit `tab`.
|
2013-08-21 02:46:47 +04:00
|
|
|
|
2013-10-15 04:00:16 +04:00
|
|
|
All files in the directory are automatically loaded, unless the _package.json_
|
|
|
|
supplies a `snippets` key. As with all scoped items, snippets loaded later take
|
|
|
|
precedence over earlier snippets when two snippets match a scope with the same
|
|
|
|
specificity.
|
2013-08-21 02:46:47 +04:00
|
|
|
|
|
|
|
## Language Grammars
|
|
|
|
|
|
|
|
If you're developing a new language grammar, you'll want to place your file in
|
|
|
|
the _grammars_ directory. Each grammar is a pairing of two keys, `match` and
|
2013-10-15 04:00:16 +04:00
|
|
|
`captures`. `match` is a regular expression identifying the pattern to
|
|
|
|
highlight, while `captures` is an object representing what to do with each
|
|
|
|
matching group.
|
2013-09-03 21:21:51 +04:00
|
|
|
|
2013-08-21 02:46:47 +04:00
|
|
|
For example:
|
|
|
|
|
|
|
|
|
2013-09-03 21:21:51 +04:00
|
|
|
```coffeescript
|
2013-08-21 02:46:47 +04:00
|
|
|
{
|
|
|
|
'match': '(?:^|\\s)(__[^_]+__)'
|
|
|
|
'captures':
|
|
|
|
'1': 'name': 'markup.bold.gfm'
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
This indicates that the first matching capture (`(__[^_]+__)`) should have the
|
|
|
|
`markup.bold.gfm` token applied to it.
|
|
|
|
|
|
|
|
To capture a single group, simply use the `name` key instead:
|
|
|
|
|
2013-09-03 21:21:51 +04:00
|
|
|
```coffeescript
|
2013-08-21 02:46:47 +04:00
|
|
|
{
|
|
|
|
'match': '^#{1,6}\\s+.+$'
|
|
|
|
'name': 'markup.heading.gfm'
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2013-10-15 04:00:16 +04:00
|
|
|
This indicates that Markdown header lines (`#`, `##`, `###`) should be applied
|
|
|
|
with the `markup.heading.gfm` token.
|
2013-08-21 02:46:47 +04:00
|
|
|
|
|
|
|
More information about the significance of these tokens can be found in
|
2013-10-15 04:00:16 +04:00
|
|
|
[section 12.4 of the TextMate Manual][tm-tokens].
|
2013-08-21 02:46:47 +04:00
|
|
|
|
2013-10-15 04:00:16 +04:00
|
|
|
Your grammar should also include a `filetypes` array, which is a list of file
|
|
|
|
extensions your grammar supports:
|
2013-08-21 02:46:47 +04:00
|
|
|
|
2013-09-03 21:21:51 +04:00
|
|
|
```coffeescript
|
2013-08-21 02:46:47 +04:00
|
|
|
'fileTypes': [
|
|
|
|
'markdown'
|
|
|
|
'md'
|
|
|
|
'mkd'
|
|
|
|
'mkdown'
|
|
|
|
'ron'
|
|
|
|
]
|
|
|
|
```
|
|
|
|
|
2013-09-14 10:34:00 +04:00
|
|
|
## Bundle External Resources
|
|
|
|
|
|
|
|
It's common to ship external resources like images and fonts in the package, to
|
|
|
|
make it easy to reference the resources in HTML or CSS, you can use the `atom`
|
|
|
|
protocol URLs to load resources in the package.
|
|
|
|
|
|
|
|
The URLs should be in the format of
|
|
|
|
`atom://package-name/relative-path-to-package-of-resource`, for example, the
|
2013-12-05 08:40:27 +04:00
|
|
|
`atom://image-view/images/transparent-background.gif` would be equivalent to
|
2013-09-14 10:34:00 +04:00
|
|
|
`~/.atom/packages/image-view/images/transparent-background.gif`.
|
|
|
|
|
|
|
|
You can also use the `atom` protocol URLs in themes.
|
|
|
|
|
2013-08-21 02:46:47 +04:00
|
|
|
## Writing Tests
|
|
|
|
|
2013-10-15 04:00:16 +04:00
|
|
|
Your package **should** have tests, and if they're placed in the _spec_
|
|
|
|
directory, they can be run by Atom.
|
|
|
|
|
2013-10-26 03:07:00 +04:00
|
|
|
Under the hood, [Jasmine] executes your tests, so you can assume that any DSL
|
|
|
|
available there is available to your package as well.
|
2013-08-21 02:46:47 +04:00
|
|
|
|
2013-10-16 04:34:19 +04:00
|
|
|
**FIXME: Explain the following**
|
|
|
|
|
|
|
|
* jasmine
|
|
|
|
* jasmine-focused
|
|
|
|
* `spec/fixtures` and global.project
|
|
|
|
* setTimeout
|
|
|
|
* whatever else is different in spec-helper
|
|
|
|
|
2013-10-26 03:07:00 +04:00
|
|
|
## Running Tests
|
|
|
|
|
|
|
|
TODO: Probably use the menu option now.
|
2013-10-15 04:00:16 +04:00
|
|
|
|
2013-10-16 04:34:19 +04:00
|
|
|
Once you've got your test suite written, the recommended way to run it is `apm
|
|
|
|
test`. `apm test` prints its output to the console and returns the proper status
|
|
|
|
code depending on whether tests passed or failed.
|
|
|
|
|
|
|
|
## Publishing
|
|
|
|
|
|
|
|
Atom bundles a command line utility called [apm] which can be used to publish
|
|
|
|
Atom packages to the public registry.
|
|
|
|
|
|
|
|
Once your package is written and ready for distribution you can run the
|
|
|
|
following to publish your package:
|
|
|
|
|
|
|
|
```sh
|
|
|
|
cd my-package
|
|
|
|
apm publish minor
|
|
|
|
```
|
|
|
|
|
|
|
|
This will update your `package.json` to have a new minor `version`, commit the
|
|
|
|
change, create a new [Git tag][git-tag], and then upload the package to the
|
|
|
|
registry.
|
|
|
|
|
|
|
|
Run `apm help publish` to see all the available options and `apm help` to see
|
|
|
|
all the other available commands.
|
|
|
|
|
2013-10-26 03:07:00 +04:00
|
|
|
## Included Libraries
|
2013-08-21 02:46:47 +04:00
|
|
|
|
2013-10-15 04:00:16 +04:00
|
|
|
FIXME: Describe `require 'atom'
|
|
|
|
|
|
|
|
In addition to core node.js modules, all packages can `require` the following
|
|
|
|
popular libraries into their packages:
|
2013-08-21 02:46:47 +04:00
|
|
|
|
2013-10-15 04:00:16 +04:00
|
|
|
* [SpacePen] (as `require 'space-pen'`)
|
|
|
|
* [jQuery] (as `require 'jquery'`)
|
|
|
|
* [Underscore] (as `require 'underscore'`)
|
2013-08-21 02:46:47 +04:00
|
|
|
|
2013-10-17 04:05:26 +04:00
|
|
|
Additional libraries can be found by browsing Atom's *node_modules* folder.
|
2013-08-21 02:46:47 +04:00
|
|
|
|
2013-10-26 03:07:00 +04:00
|
|
|
[file-tree]: https://github.com/atom/tree-view
|
|
|
|
[status-bar]: https://github.com/atom/status-bar
|
|
|
|
[cs-syntax]: https://github.com/atom/language-coffee-script
|
2013-08-21 03:48:01 +04:00
|
|
|
[npm]: http://en.wikipedia.org/wiki/Npm_(software)
|
2013-10-15 04:00:16 +04:00
|
|
|
[npm-keys]: https://npmjs.org/doc/json.html
|
|
|
|
[apm]: https://github.com/atom/apm
|
|
|
|
[git-tag]: http://git-scm.com/book/en/Git-Basics-Tagging
|
|
|
|
[wrap-guide]: https://github.com/atom/wrap-guide/
|
|
|
|
[keymaps]: internals/keymaps.md
|
2013-10-25 02:13:47 +04:00
|
|
|
[theme-variables]: theme-variables.md
|
2013-10-15 04:00:16 +04:00
|
|
|
[tm-tokens]: http://manual.macromates.com/en/language_grammars.html
|
|
|
|
[spacepen]: https://github.com/nathansobo/space-pen
|
|
|
|
[path]: http://nodejs.org/docs/latest/api/path.html
|
|
|
|
[jquery]: http://jquery.com/
|
|
|
|
[underscore]: http://underscorejs.org/
|
|
|
|
[jasmine]: https://github.com/pivotal/jasmine
|
2013-10-16 04:34:19 +04:00
|
|
|
[cson]: https://github.com/atom/season
|
|
|
|
[less]: http://lesscss.org
|
2013-10-16 22:52:00 +04:00
|
|
|
[ui-variables]: https://github.com/atom/atom-dark-ui/blob/master/stylesheets/ui-variables.less
|
2013-10-31 01:34:50 +04:00
|
|
|
[first-package]: your-first-package.html
|