diff --git a/README.md b/README.md
index 7f0b4807d..4a9e91317 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Atom — The hackable, ~~collaborative~~ editor
+# Atom — The hackable editor

diff --git a/build/package.json b/build/package.json
index 29855c350..14b1437e4 100644
--- a/build/package.json
+++ b/build/package.json
@@ -7,7 +7,7 @@
},
"dependencies": {
"async": "~0.2.9",
- "biscotto": "0.0.17",
+ "biscotto": "git://github.com/atom/biscotto.git#12188bfbe5f7303fa9f1aa3c4f8662d40ce3c3be",
"first-mate": "~0.13.0",
"formidable": "~1.0.14",
"fs-plus": "1.x",
@@ -19,7 +19,7 @@
"grunt-contrib-coffee": "~0.7.0",
"grunt-contrib-less": "~0.8.0",
"grunt-cson": "0.5.0",
- "grunt-download-atom-shell": "git+https://atom-bot:362295be4c5258d3f7b967bbabae662a455ca2a7@github.com/atom/grunt-download-atom-shell#v0.5.0",
+ "grunt-download-atom-shell": "git+https://atom-bot:362295be4c5258d3f7b967bbabae662a455ca2a7@github.com/atom/grunt-download-atom-shell#v0.6.0",
"grunt-lesslint": "0.13.0",
"grunt-markdown": "~0.4.0",
"grunt-peg": "~1.1.0",
@@ -30,6 +30,7 @@
"rcedit": "~0.1.2",
"request": "~2.27.0",
"rimraf": "~2.2.2",
+ "runas": "~0.3.0",
"unzip": "~0.1.9",
"vm-compatibility-layer": "~0.1.0",
"walkdir": "0.0.7"
diff --git a/build/tasks/docs-task.coffee b/build/tasks/docs-task.coffee
index 07367b31d..6f9b3c8b4 100644
--- a/build/tasks/docs-task.coffee
+++ b/build/tasks/docs-task.coffee
@@ -5,12 +5,14 @@ fs = require 'fs-plus'
request = require 'request'
module.exports = (grunt) ->
+ {rm} = require('./task-helpers')(grunt)
+
cmd = path.join('node_modules', '.bin', 'coffee')
commonArgs = [path.join('build', 'node_modules', '.bin', 'biscotto'), '--']
opts =
stdio: 'inherit'
- grunt.registerTask 'build-docs', 'Builds the API docs in src/app', ->
+ grunt.registerTask 'build-docs', 'Builds the API docs in src', ->
done = @async()
downloadFileFromRepo = ({repo, file}, callback) ->
@@ -34,6 +36,7 @@ module.exports = (grunt) ->
if error?
done(error)
else
+ rm('docs/output/api')
args = [
commonArgs...
'--title', 'Atom API Documentation'
diff --git a/build/tasks/install-task.coffee b/build/tasks/install-task.coffee
index 23cae1bb9..a2b591734 100644
--- a/build/tasks/install-task.coffee
+++ b/build/tasks/install-task.coffee
@@ -1,11 +1,25 @@
path = require 'path'
module.exports = (grunt) ->
- {cp, mkdir, rm} = require('./task-helpers')(grunt)
+ {cp, mkdir, rm, spawn} = require('./task-helpers')(grunt)
grunt.registerTask 'install', 'Install the built application', ->
installDir = grunt.config.get('atom.installDir')
shellAppDir = grunt.config.get('atom.shellAppDir')
- rm installDir
- mkdir path.dirname(installDir)
- cp shellAppDir, installDir
+ if process.platform is 'win32'
+ done = @async()
+
+ runas = require 'runas'
+ copyFolder = path.resolve 'script', 'copy-folder.cmd'
+ # cmd /c ""script" "source" "destination""
+ arg = "/c \"\"#{copyFolder}\" \"#{shellAppDir}\" \"#{installDir}\"\""
+ if runas('cmd', [arg], hide: true) isnt 0
+ done("Failed to copy #{shellAppDir} to #{installDir}")
+
+ createShortcut = path.resolve 'script', 'create-shortcut.cmd'
+ args = ['/c', createShortcut, path.join(installDir, 'atom.exe'), 'Atom']
+ spawn {cmd: 'cmd', args}, done
+ else
+ rm installDir
+ mkdir path.dirname(installDir)
+ cp shellAppDir, installDir
diff --git a/build/tasks/set-version-task.coffee b/build/tasks/set-version-task.coffee
index be41866a8..bdf6e0c4d 100644
--- a/build/tasks/set-version-task.coffee
+++ b/build/tasks/set-version-task.coffee
@@ -41,7 +41,7 @@ module.exports = (grunt) ->
strings =
CompanyName: 'GitHub, Inc.'
- FileDescription: 'The hackable, collaborative editor'
+ FileDescription: 'The hackable editor'
LegalCopyright: 'Copyright (C) 2013 GitHub, Inc. All rights reserved'
ProductName: 'Atom'
ProductVersion: version
diff --git a/docs/README.md b/docs/README.md
index 9010e60f1..41be7406f 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -14,12 +14,26 @@ overview of the main editor API.
Check out the [Atom][Atom] class docs to see what globals are available and
what they provide.
-You can also require many of these classes in your packages via:
+You can also require many of these classes in your package via:
```coffee
{EditorView} = require 'atom'
```
+The classes available from `require 'atom'` are:
+ * [BufferedProcess][BufferedProcess]
+ * [BufferedNodeProcess][BufferedNodeProcess]
+ * [Directory][Directory]
+ * [EditorView][EditorView]
+ * [File][File]
+ * [Git][Git]
+ * [Point][Point]
+ * [Range][Range]
+ * [ScrollView][ScrollView]
+ * [SelectList][SelectList]
+ * [View][View]
+ * [WorkspaceView][WorkspaceView]
+
### How do I create a package?
You probably want to read the [creating a package][creating-a-package]
@@ -31,7 +45,18 @@ Atom ships with node 0.11.10 and the comprehensive node API docs are available
[here][node-docs].
[Atom]: ../classes/Atom.html
+[BufferedProcess]: ../classes/BufferedProcess.html
+[BufferedNodeProcess]: ../classes/BufferedNodeProcess.html
+[Directory]: ../classes/Directory.html
[Editor]: ../classes/Editor.html
[EditorView]: ../classes/EditorView.html
+[File]: ../classes/File.html
+[Git]: ../classes/Git.html
+[Point]: ../classes/Point.html
+[Range]: ../classes/Range.html
+[ScrollView]: ../classes/ScrollView.html
+[SelectList]: ../classes/SelectList.html
+[View]: ../classes/View.html
+[WorkspaceView]: ../classes/WorkspaceView.html
[creating-a-package]: https://www.atom.io/docs/latest/creating-a-package
[node-docs]: http://nodejs.org/docs/v0.11.10/api
diff --git a/docs/advanced/configuration.md b/docs/advanced/configuration.md
new file mode 100644
index 000000000..606432804
--- /dev/null
+++ b/docs/advanced/configuration.md
@@ -0,0 +1,76 @@
+## Configuration API
+
+### Reading Config Settings
+
+If you are writing a package that you want to make configurable, you'll need to
+read config settings via the `atom.config` global. You can read the current
+value of a namespaced config key with `atom.config.get`:
+
+```coffeescript
+# read a value with `config.get`
+@showInvisibles() if atom.config.get "editor.showInvisibles"
+```
+
+Or you can use the `::observeConfig` to track changes from any view object.
+
+```coffeescript
+class MyView extends View
+ initialize: ->
+ @observeConfig 'editor.fontSize', () =>
+ @adjustFontSize()
+```
+
+The `::observeConfig` 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.
+
+Subscriptions made with `observeConfig` are automatically canceled when the
+view is removed. You can cancel config subscriptions manually via the
+`unobserveConfig` method.
+
+```coffeescript
+view1.unobserveConfig() # unobserve all properties
+```
+
+You can add the ability to observe config values to non-view classes by
+extending their prototype with the `ConfigObserver` mixin:
+
+```coffeescript
+{ConfigObserver} = require 'atom'
+
+class MyClass
+ ConfigObserver.includeInto(this)
+
+ constructor: ->
+ @observeConfig 'editor.showInvisibles', -> # ...
+
+ destroy: ->
+ @unobserveConfig()
+```
+
+### Writing Config Settings
+
+The `atom.config` database is populated on startup from `~/.atom/config.cson`,
+but you can programmatically write to it with `atom.config.set`:
+
+```coffeescript
+# basic key update
+atom.config.set("core.showInvisibles", true)
+```
+
+You should never mutate the value of a config key, because that would circumvent
+the notification of observers. You can however use methods like `pushAtKeyPath`,
+`unshiftAtKeyPath`, and `removeAtKeyPath` to manipulate mutable config values.
+
+```coffeescript
+atom.config.pushAtKeyPath("core.disabledPackages", "wrap-guide")
+atom.config.removeAtKeyPath("core.disabledPackages", "terminal")
+```
+
+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.
+
+```coffeescript
+atom.config.setDefaults("editor", fontSize: 18, showInvisibles: true)
+```
diff --git a/docs/advanced/globals.md b/docs/advanced/globals.md
new file mode 100644
index 000000000..ba8285975
--- /dev/null
+++ b/docs/advanced/globals.md
@@ -0,0 +1,34 @@
+# 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.
+ * workspaceView:
+ Similar to workspace, but provides access to the root of all views in the
+ current window.
+ * 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.
diff --git a/docs/advanced/keymaps.md b/docs/advanced/keymaps.md
new file mode 100644
index 000000000..aaa5d398b
--- /dev/null
+++ b/docs/advanced/keymaps.md
@@ -0,0 +1,123 @@
+# Keymaps In-Depth
+
+## Structure of a Keymap File
+
+Keymap files are encoded as JSON or CSON files containing nested hashes. They
+work much like stylesheets, but instead of applying style properties to elements
+matching the selector, they specify the meaning of keystrokes on elements
+matching the selector. Here is an example of some bindings that apply when
+keystrokes pass through elements with the class `.editor`:
+
+```coffee
+'.editor':
+ 'cmd-delete': 'editor:backspace-to-beginning-of-line'
+ 'alt-backspace': 'editor:backspace-to-beginning-of-word'
+ 'ctrl-A': 'editor:select-to-first-character-of-line'
+ 'ctrl-shift-e': 'editor:select-to-end-of-line'
+ 'cmd-left': 'editor:move-to-first-character-of-line'
+
+'.editor:not(.mini)'
+ 'cmd-alt-[': 'editor:fold-current-row'
+ 'cmd-alt-]': 'editor:unfold-current-row'
+```
+
+Beneath the first selector are several bindings, mapping specific *keystroke
+patterns* to *commands*. When an element with the `.editor` class is focused and
+`cmd-delete` is pressed, an custom DOM event called
+`editor:backspace-to-beginning-of-line` is emitted on the `.editor` element.
+
+The second selector group also targets editors, but only if they don't have the
+`.mini` class. In this example, the commands for code folding don't really make
+sense on mini-editors, so the selector restricts them to regular editors.
+
+### Keystroke Patterns
+
+Keystroke patterns express one or more keystrokes combined with optional
+modifier keys. For example: `ctrl-w v`, or `cmd-shift-up`. A keystroke is
+composed of the following symbols, separated by a `-`. A multi-keystroke pattern
+can be expressed as keystroke patterns separated by spaces.
+
+
+| Type | Examples
+| --------------------|----------------------------
+| Character literals | `a` `4` `$`
+| Modifier keys | `cmd` `ctrl` `alt` `shift`
+| Special keys | `enter` `escape` `backspace` `delete` `tab` `home` `end` `pageup` `pagedown` `left` `right` `up` `down`
+
+### Commands
+
+Commands are custom DOM events that are triggered when a keystroke matches a
+binding. This allows user interface code to listen for named commands without
+specifying the specific keybinding that triggers it. For example, the following
+code sets up {EditorView} to listen for commands to move the cursor to the first
+character of the current line:
+
+```coffee
+class EditorView
+ listenForEvents: ->
+ @command 'editor:move-to-first-character-of-line', =>
+ @editor.moveCursorToFirstCharacterOfLine()
+```
+
+The `::command` method is basically an enhanced version of jQuery's `::on`
+method that listens for a custom DOM event and adds some metadata to the DOM,
+which is read by the command palette.
+
+When you are looking to bind new keys, it is often useful to use the command
+palette (`ctrl-shift-p`) to discover what commands are being listened for in a
+given focus context. Commands are "humanized" following a simple algorithm, so a
+command like `editor:fold-current-row` would appear as "Editor: Fold Current
+Row".
+
+### Specificity and Cascade Order
+
+As is the case with CSS applying styles, when multiple bindings match for a
+single element, the conflict is resolved by choosing the most *specific*
+selector. If two matching selectors have the same specificity, the binding
+for the selector appearing later in the cascade takes precedence.
+
+Currently, there's no way to specify selector ordering within a single keymap,
+because JSON objects do not preserve order. We eventually plan to introduce a
+custom CSS-like file format for keymaps that allows for ordering within a single
+file. For now, we've opted to handle cases where selector ordering is critical
+by breaking the keymap into two separate files, such as `snippets-1.cson` and
+`snippets-2.cson`.
+
+## Overloading Key Bindings
+
+Occasionally, it makes sense to layer multiple actions on top of the same key
+binding. An example of this is the snippets package. Snippets are inserted by
+typing a snippet prefix such as `for` and then pressing `tab`. Every time `tab`
+is pressed, we want to execute code attempting to expand a snippet if one exists
+for the text preceding the cursor. If a snippet *doesn't* exist, we want `tab`
+to actually insert whitespace.
+
+To achieve this, the snippets package makes use of the `.abortKeyBinding()`
+method on the event object representing the `snippets:expand` command.
+
+```coffee-script
+# pseudo-code
+editor.command 'snippets:expand', (e) =>
+ if @cursorFollowsValidPrefix()
+ @expandSnippet()
+ else
+ e.abortKeyBinding()
+```
+
+When the event handler observes that the cursor does not follow a valid prefix,
+it calls `e.abortKeyBinding()`, telling the keymap system to continue searching
+for another matching binding.
+
+## Step-by-Step: How Keydown Events are Mapped to Commands
+
+* A keydown event occurs on a *focused* element.
+* Starting at the focused element, the keymap walks upward towards the root of
+ the document, searching for the most specific CSS selector that matches the
+ current DOM element and also contains a keystroke pattern matching the keydown
+ event.
+* When a matching keystroke pattern is found, the search is terminated and the
+ pattern's corresponding command is triggered on the current element.
+* If `.abortKeyBinding()` is called on the triggered event object, the search
+ is resumed, triggering a binding on the next-most-specific CSS selector for
+ the same element or continuing upward to parent elements.
+* If no bindings are found, the event is handled by Chromium normally.
diff --git a/docs/internals/serialization.md b/docs/advanced/serialization.md
similarity index 100%
rename from docs/internals/serialization.md
rename to docs/advanced/serialization.md
diff --git a/docs/internals/view-system.md b/docs/advanced/view-system.md
similarity index 100%
rename from docs/internals/view-system.md
rename to docs/advanced/view-system.md
diff --git a/docs/creating-a-package.md b/docs/creating-a-package.md
index 24072d822..183a5d28a 100644
--- a/docs/creating-a-package.md
+++ b/docs/creating-a-package.md
@@ -154,7 +154,7 @@ 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 occured on. In
+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.
@@ -381,7 +381,7 @@ Additional libraries can be found by browsing Atom's *node_modules* folder.
[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
+[keymaps]: advanced/keymaps.md
[theme-variables]: theme-variables.md
[tm-tokens]: http://manual.macromates.com/en/language_grammars.html
[spacepen]: https://github.com/nathansobo/space-pen
diff --git a/docs/getting-started.md b/docs/getting-started.md
index 8d3c5414a..fe6fe86fe 100644
--- a/docs/getting-started.md
+++ b/docs/getting-started.md
@@ -19,13 +19,11 @@ bindings][key-bindings] section.
### Working With Files
-Atom windows are scoped to the directory they're opened from. If you launch Atom
-from the command line everything will be relative to the current directory. This
-means that the tree view on the left will only show files contained within that
-directory.
-
-This can be a useful way to organize multiple projects, as each project will be
-contained within its own window.
+Atom windows are scoped to a single directory on disk. If you launch Atom from
+the command line via the `atom` command and don't specify a path, Atom opens a
+window for the current working directory. The current window's directory will be
+visible as the root of the tree view at the left, and also serve as the context
+for all file-related operations.
#### Finding Files
@@ -34,20 +32,17 @@ begin typing the name of the file you're looking for. If you are looking for a
file that is already open press `cmd-b` to bring up a searchable list of open
files.
-You can also use the tree view to navigate to a file. To open or move focus to
-the tree view, press `cmd-\`. You can then navigate to a file using the arrow
-keys and select it with `return`.
+You can also use the tree view to navigate to a file. To open and focus the
+the tree view, press `ctrl-0`. The tree view can be toggled open and closed with
+`cmd-\`.
#### Adding, Moving, Deleting Files
-Currently, all file modification is performed via the tree view. To add a file,
-select a directory in the tree view and press `a`. Then type the name of the
-file. Any intermediate directories you type will be created automatically if
-needed.
-
-To move or rename a file or directory, select it in the tree view and press `m`.
-
-To delete a file, select it in the tree view and press `delete`.
+Currently, all file modification is performed via the tree view. Add, move, or
+delete a file by right-clicking in the tree view and selecting the desired
+operation from the context menu. You can also perform these operations from the
+keyboard by selecting a file or directory and using `a` to add, `m` to move, and
+`delete` to delete.
### Searching
@@ -58,35 +53,43 @@ To search within a buffer use `cmd-f`. To search the entire project use
#### Navigating By Symbols
-If you want to jump to a method press `cmd-r`. It opens a list of all symbols
-in the current file.
+To jump to a symbol such as a method definition, press `cmd-r`. This opens a
+list of all symbols in the current file, which you can fuzzy filter similarly to
+`cmd-t`.
-To search for symbols across your project use `cmd-shift-r`, but you'll need to
-make sure you have a ctags installed and a tags file generated for your project.
-Also, if you're editing CoffeeScript, it's a good idea to update your `~/.ctags`
-file to understand the language. Here is [a good example][ctags].
+To search for symbols across your project, use `cmd-shift-r`. First you'll need
+to make sure you have ctags installed and a tags file generated for your
+project. Also, if you're editing CoffeeScript, it's a good idea to update your
+`~/.ctags` file to understand the language. Here is [a good example][ctags].
### Split Panes
-You can split any editor pane horizontally or vertically by using `cmd-k right` or
-`cmd-k down`. Once you have a split pane, you can move focus between them with
-`cmd-k cmd-right` or `cmd-k cmd-down`. To close a pane, close all tabs inside it.
+You can split any editor pane horizontally or vertically by using `cmd-k right`
+or `cmd-k down`. Once you have a split pane, you can move focus between them
+with `cmd-k cmd-right` or `cmd-k cmd-down`. To close a pane, close all its
+editors with `meta-w`, then press `meta-w` one more time to close the pane. You
+can configure panes to auto-close with empty in the preferences.
### Folding
-You can fold everything with `alt-cmd-{` and unfold everything with
-`alt-cmd-}`. Or, you can fold / unfold by a single level with `alt-cmd-[` and
-`alt-cmd-]`.
+You can fold blocks of code by clicking the arrows that appear when you hover
+your mouse cursor over the gutter. You can also fold and unfold from the
+keyboard with `alt-cmd-[` and `alt-cmd-]`. To fold everything, use
+`alt-cmd-shift-{` and to unfold everything use `alt-cmd-shift-}`. You can also
+fold at a specific indentation level with `cmd-k cmd-N` where N is the
+indentation depth.
### Soft-Wrap
If you want to toggle soft wrap, trigger the command from the command palette.
Press `cmd-shift-P` to open the palette, then type "wrap" to find the correct
-command.
+command. By default, lines will wrap based on the size of the editor. If you
+prefer to wrap at a specific line length, toggle "Wrap at preferred line length"
+in preferences.
## Configuration
-Press `cmd-,` to display the a settings pane. This serves as the primary
+Press `cmd-,` to display the preferences pane. This serves as the primary
interface for adjusting config settings, installing packages and changing
themes.
diff --git a/docs/index.md b/docs/index.md
index a27dc1d9d..001836228 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -7,7 +7,7 @@
### Advanced Topics
-* [Configuration](internals/configuration.md)
-* [Keymaps](internals/keymaps.md)
-* [Serialization](internals/serialization.md)
-* [View System](internals/view-system.md)
+* [Configuration](advanced/configuration.md)
+* [Keymaps](advanced/keymaps.md)
+* [Serialization](advanced/serialization.md)
+* [View System](advanced/view-system.md)
diff --git a/docs/internals/configuration.md b/docs/internals/configuration.md
deleted file mode 100644
index b70493dc1..000000000
--- a/docs/internals/configuration.md
+++ /dev/null
@@ -1,61 +0,0 @@
-## Configuration API
-
-### Reading Config Settings
-
-If you are writing a package that you want to make configurable, you'll need to
-read config settings. You can read a value from `config` with `config.get`:
-
-```coffeescript
-# read a value with `config.get`
-@showInvisibles() if config.get "edtior.showInvisibles"
-```
-
-Or you can use `observeConfig` to track changes from a view object.
-
-```coffeescript
-class MyView extends View
- initialize: ->
- @observeConfig 'editor.fontSize', () =>
- @adjustFontSize()
-```
-
-The `observeConfig` 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.
-
-Subscriptions made with `observeConfig` are automatically canceled when the
-view is removed. You can cancel config subscriptions manually via the
-`unobserveConfig` method.
-
-```coffeescript
-view1.unobserveConfig() # unobserve all properties
-```
-
-You can add the ability to observe config values to non-view classes by
-extending their prototype with the `ConfigObserver` mixin:
-
-```coffeescript
-ConfigObserver = require 'config-observer'
-_.extend MyClass.prototype, ConfigObserver
-```
-
-### Writing Config Settings
-
-As discussed above, the config database is automatically populated from
-`config.cson` when Atom is started, but you can programmatically write to it in
-the following way:
-
-```coffeescript
-# basic key update
-config.set("core.showInvisibles", true)
-
-config.pushAtKeyPath("core.disabledPackages", "wrap-guide")
-```
-
-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.
-
-```coffeescript
-config.setDefaults("editor", fontSize: 18, showInvisibles: true)
-```
diff --git a/docs/internals/keymaps.md b/docs/internals/keymaps.md
deleted file mode 100644
index c346ff7dd..000000000
--- a/docs/internals/keymaps.md
+++ /dev/null
@@ -1,69 +0,0 @@
-## Keymaps In-Depth
-
-### Structure of a Keymap File
-
-Keymap files are encoded as JSON or CSON files containing nested hashes. The
-top-level keys of a keymap are **CSS 3 selectors**, which specify a particular
-context in Atom's interface. Common selectors are `.editor`, which scopes
-bindings to just work when an editor is focused, and `body`, which scopes
-bindings globally.
-
-Beneath the selectors are hashes mapping **keystroke patterns** to
-**semantic events**. A keystroke pattern looks like the following examples.
-Note that the last example describes multiple keystrokes in succession:
-
-- `p`
-- `2`
-- `ctrl-p`
-- `ctrl-alt-cmd-p`
-- `tab`
-- `escape`
-- `enter`
-- `ctrl-w w`
-
-A semantic event is the name of the custom event that will be triggered on the
-target of the keydown event when a key binding matches. You can use the command
-palette (bound to `cmd-shift-P`), to get a list of relevant events and their bindings
-in any focused context in Atom.
-
-### Rules for Mapping A Keydown Event to A Semantic Event
-
-A keymap's job is to translate a physical keystroke event (like `cmd-D`) into a
-semantic event (like `editor:duplicate-line`). Whenever a keydown event occurs
-on a focused element, it bubbles up the DOM as usual. As soon as an element on
-the bubble path matches a key binding for the keystroke, the binding's semantic
-event is triggered on the original target of the keydown event. Just as with
-CSS, if multiple selectors match an element, the most specific selector is
-favored. If two selectors have the same specificity, the selector that occurs
-latest in the cascade is favored.
-
-Currently, there's no way to specify selector ordering within a single keymap,
-because JSON hashes do not preserve order. Rather than making the format more
-awkward in order to preserve order, we've opted to handle cases where order is
-critical by breaking the keymap into two separate files, such as
-`snippets-1.cson` and `snippets-2.cson`.
-
-### Overloading Key Bindings
-
-Occasionally, it makes sense to layer multiple actions on top of the same key
-binding. An example of this is the snippets package. You expand a snippet by
-pressing `tab` immediately following a snippet's prefix. But if the cursor is
-not following a valid snippet prefix, then we want tab to perform its normal
-action (probably inserting a tab character or the appropriate number of spaces).
-
-To achieve this, the snippets package makes use of the `abortKeyBinding` method
-on the event object that's triggered by the binding for `tab`.
-
-```coffee-script
-# pseudo-code
-editor.command 'snippets:expand', (e) =>
- if @cursorFollowsValidPrefix()
- @expandSnippet()
- else
- e.abortKeyBinding()
-```
-
-When the event handler observes that the cursor does not follow a valid prefix,
-it calls `e.abortKeyBinding()`, which tells the keymap system to continue
-searching up the cascade for another matching binding. In this case, the default
-implementation of `tab` ends up getting triggered.
diff --git a/docs/proposals/private-beta-tasks.md b/docs/proposals/private-beta-tasks.md
deleted file mode 100644
index 98db56041..000000000
--- a/docs/proposals/private-beta-tasks.md
+++ /dev/null
@@ -1,70 +0,0 @@
-**Polish the user experience**
-
-First and foremost, Atom is a **product**. Atom needs to feel familiar and
-inviting. This includes a solid introductory experience and parity with the most
-important features of Sublime Text.
-
- * First launch UI and flow (actions below should be easily discoverable)
- * Create a new file
- * Open a project and edit an existing file
- * Install a package
- * Change settings (adjust theme, change key bindings, set config options)
- * How to use command P
- * Use collaboration internally
- * How and where to edit keyBinding should be obvious to new users
- * Finish find and replace in buffer/project
- * Atom should start < 300ms
- * Match Sublime's multiple selection functionality (#523)
- * Fix softwrap bugs
- * Menus & Context menus
- * Track usage/engagement of our users (make this opted in?)
- * Windows support
- * Reliably and securely auto-update and list what's new
- * Secure access to the keychain (don't give every package access to the keychain)
- * Secure access to GitHub (each package can ask to have it's own oauth token)
- * Don't crash when opening/editing large (> 10Mb) files
- * Send js and native crash reports to a remote server
-
-**Lay solid groundwork for a package and theme ecosystem**
-
-Extensibility is one of Atom's key value propositions, so a smooth experience
-for creating and maintaining packages is just as important as the user
-experience. The package development, dependency and publishing workflow needs to
-be solid. We also want to have a mechanism for clearly communicating with
-package authors about breaking API changes.
-
- * Finish APM backend (integrate with GitHub Releases)
- * Streamline Dev workflow
- * `apm create` - create package scaffolding
- * `apm test` - so users can run focused package tests
- * `apm publish` - should integrate release best practices (ie npm version)
- * Determine which classes and methods should be included in the public API
- * Users can find/install/update/fork existing packages and themes
-
-**Tighten up the view layer**
-Our current approach to the view layer need some improvement. We want to
-actively promote the use of the M-V-VM design pattern, provide some declarative
-event binding mechanisms in the view layer, and improve the performance of the
-typical package specs. We don't want the current approach to be used as an
-example in a bunch of new packages, so it's important to improve it now.
-
- * Add marker view API
-
-**Get atom.io online with some exciting articles and documentation**
-We'd love to send our private alpha candidates to a nice site with information
-about what Atom is, the philosophies and technologies behind it, and guidance
-for how to get started.
-
- * Design and create www.atom.io
- * Guides
- * Theme & Package creation guide
- * Full API per release tag
- * Changelog per release
- * Explanation of features
- * Explain Semver and general plans for the future (reassure developers we care about them)
- * General Values/Goals
- * Make docs accessible from Atom
- * Community/contribution guidelines
- * Is all communication to be done through issues?
- * When should you publish a plugin?
- * Do we need to vet plugins from a security perspective?
diff --git a/docs/proposals/private-beta-timeline.md b/docs/proposals/private-beta-timeline.md
deleted file mode 100644
index dfcc93c6f..000000000
--- a/docs/proposals/private-beta-timeline.md
+++ /dev/null
@@ -1,16 +0,0 @@
-## Proposed Timeline
-
-1. **October 30st** - Internal launch - persuade as many githubbers to switch as
-possible.
-
-1. Triage bugs and identify what needs to be fixed before private alpha. Maybe
-talk to @chrissiebrodigan about doing a UX study.
-
-1. **November 22st** - Private alpha launch
-
-1. Trickle out invites as people ask/we need more testers.
-
-1. If our usage metrics/engagement metrics decrease, stop, identify the issue
-and fix it before continuing.
-
-1. Launch
diff --git a/docs/your-first-package.md b/docs/your-first-package.md
index 9f9901229..c1e0b991d 100644
--- a/docs/your-first-package.md
+++ b/docs/your-first-package.md
@@ -1,335 +1,145 @@
-# Creating Your First Package
+# Create Your First Package
-Let's take a look at creating your first package.
+This tutorial will guide you though creating a simple command that replaces the
+selected text with [ascii art](http://en.wikipedia.org/wiki/ASCII_art). When you
+run our new command with the word "cool" selected, it will be replaced with:
-To get started, hit `cmd-shift-P`, and start typing "Generate Package" to generate
-a package. Once you select the "Generate Package" command, it'll ask you for a
-name for your new package. Let's call ours _changer_.
-
-Atom will pop open a new window, showing the _changer_ package with a default set of
-folders and files created for us. Hit `cmd-shift-P` and start typing "Changer." You'll
-see a new `Changer:Toggle` command which, if selected, pops up a greeting. So far,
-so good!
-
-In order to demonstrate the capabilities of Atom and its API, our Changer plugin
-is going to do two things:
-
-1. It'll show only modified files in the file tree
-2. It'll append a new pane to the editor with some information about the modified
-files
-
-Let's get started!
-
-## Changing Keybindings and Commands
-
-Since Changer is primarily concerned with the file tree, let's write a
-key binding that works only when the tree is focused. Instead of using the
-default `toggle`, our keybinding executes a new command called `magic`.
-
-_keymaps/changer.cson_ should change to look like this:
-
-```coffeescript
-'.tree-view':
- 'ctrl-V': 'changer:magic'
+```
+ /\_ \
+ ___ ___ ___\//\ \
+ /'___\ / __`\ / __`\\ \ \
+/\ \__//\ \L\ \/\ \L\ \\_\ \_
+\ \____\ \____/\ \____//\____\
+ \/____/\/___/ \/___/ \/____/
```
-Notice that the keybinding is called `ctrl-V` — that's actually `ctrl-shift-v`.
-You can use capital letters to denote using `shift` for your binding.
+The final package can be viewed at
+[https://github.com/atom/ascii-art](https://github.com/atom/ascii-art).
-`.tree-view` represents the parent container for the tree view.
-Keybindings only work within the context of where they're entered. In this case,
-hitting `ctrl-V` anywhere other than tree won't do anything. Obviously, you can
-bind to any part of the editor using element, id, or class names. For example,
-you can map to `body` if you want to scope to anywhere in Atom, or just `.editor`
-for the editor portion.
+To begin, press `cmd-shift-P` to bring up the [Command
+Palette](https://github.com/atom/command-palette). Type "generate package" and
+select the "Package Generator: Generate Package" command. Now we need to name
+the package. Let's call it _ascii-art_.
-To bind keybindings to a command, we'll need to do a bit of association in our
-CoffeeScript code using the `atom.workspaceView.command` method. This method takes a command
-name and executes a callback function. Open up _lib/changer-view.coffee_, and
-change `atom.workspaceView.command "changer:toggle"` to look like this:
+Atom will open a new window with the contents of our new _ascii-art_ package
+displayed in the Tree View. Because this window is opened **after** the package
+is created, the ASCII Art package will be loaded and available in our new
+window. To verify this, toggle the Command Palette (`cmd-shift-P`) and type
+"ASCII Art" you'll see a new `ASCII Art: Toggle` command. When triggered, this
+command displays a default message.
+
+Now let's edit the package files to make our ascii art package do something
+interesting. Since this package doesn't need any UI, we can remove all
+view-related code. Start by opening up _lib/ascii-art.coffee_. Remove all view
+code, so the file looks like this:
```coffeescript
-atom.workspaceView.command "changer:magic", => @magic()
+ module.exports =
+ activate: ->
```
-It's common practice to namespace your commands with your package name, separated
-with a colon (`:`). Make sure to rename your `toggle` method to `magic` as well.
+## Create a Command
-Every time you reload the Atom editor, changes to your package code will be reevaluated,
-just as if you were writing a script for the browser. Reload the editor, click on
-the tree, hit your keybinding, and...nothing happens! What the heck?!
+Now let's add a command. We recommend that you namespace your commands with the
+package name followed by a `:`, so we'll call our command `ascii-art:convert`.
+Register the command in _lib/ascii-art.coffee_:
-Open up the _package.json_ file, and find the property called `activationEvents`.
-Basically, this key tells Atom to not load a package until it hears a certain event.
-Change the event to `changer:magic` and reload the editor:
+```coffeescript
+module.exports =
+ activate: ->
+ atom.workspaceView.command "ascii-art:convert", => @convert()
+
+ convert: ->
+ # This assumes the active pane item is an editor
+ editor = atom.workspace.activePaneItem
+ editor.insertText('Hello, World!')
+```
+
+The `atom.workspaceView.command` method takes a command name and a callback. The
+callback executes when the command is triggered. In this case, when the command
+is triggered the callback will call the `convert` method and insert 'Hello,
+World!'.
+
+## Reload the Package
+
+Before we can trigger `ascii-art:convert`, we need to load the latest code for
+our package by reloading the window. Run the command `window:reload` from the
+command palette or by pressing `ctrl-alt-cmd-l`.
+
+## Trigger the Command
+
+Now open the command panel and search for the `ascii-art:convert` command. But
+its not there! To fix this open _package.json_ and find the property called
+`activationEvents`. Activation Events speed up load time by allowing an Atom to
+delay a package's activation until it's needed. So add the `ascii-art:convert`
+to the activationEvents array:
```json
-"activationEvents": ["changer:magic"]
+"activationEvents": ["ascii-art:convert"],
```
-Hitting the key binding on the tree now works!
+First, run reload the window by running the command `window:reload`. Now when
+you run the `ascii-art:convert` command it will output 'Hello, World!'
-## Working with Styles
+## Add A Key Binding
-The next step is to hide elements in the tree that aren't modified. To do that,
-we'll first try and get a list of files that have not changed.
-
-All packages are able to use jQuery in their code. In fact, there's [a list of
-the bundled libraries Atom provides by default][bundled-libs].
-
-We bring in jQuery by requiring the `atom` package and binding it to the `$` variable:
+Now let's add a key binding to trigger the `ascii-art:convert` command. Open
+_keymaps/ascii-art.cson_ and add a key binding linking `ctrl-alt-a` to the
+`ascii-art:convert` command. When finished, the file will look like this:
```coffeescript
-{$, View} = require 'atom'
+'.editor':
+ 'cmd-alt-a': 'ascii-art:convert'
```
-Now, we can define the `magic` method to query the tree to get us a list of every
-file that _wasn't_ modified:
+Notice `.editor` on the first line. Just like CSS, keymap selectors *scope* key
+bindings so they only apply to specific elements. In this case, our binding is
+only active for elements matching the `.editor` selector. If the Tree View has
+focus, pressing `cmd-alt-a` won't trigger the `ascii-art:convert` command. But
+if the editor has focus, the `ascii-art:convert` method *will* be triggered.
+More information on key bindings can be found in the
+[keymaps](advanced/keymaps.html) documentation.
+
+Now reload the window and verify that the key binding works! You can also verify
+that it **doesn't** work when the Tree View is focused.
+
+## Add the ASCII Art
+
+Now we need to convert the selected text to ascii art. To do this we will use
+the [figlet](https://npmjs.org/package/figlet) [node](http://nodejs.org/) module
+from [npm](https://npmjs.org/). Open _package.json_ and add the latest version of
+figlet to the dependencies:
+
+```json
+ "dependencies": {
+ "figlet": "1.0.8"
+ }
+```
+
+After saving the file run the command 'update-package-dependencies:update' from
+the Command Palette. This will install the packages node module dependencies,
+only figlet in this case. You will need to run
+'update-package-dependencies:update' whenever you update the dependencies field
+in your _package.json_ file.
+
+Now require the figlet node module in _lib/ascii-art.coffee_ and instead of
+inserting 'Hello, World!' convert the selected text to ascii art!
```coffeescript
-magic: ->
- $('ol.entries li').each (i, el) ->
- if !$(el).hasClass("status-modified")
- console.log el
+convert: ->
+ # This assumes the active pane item is an editor
+ editor = atom.workspace.activePaneItem
+ selection = editor.getSelection()
+
+ figlet = require 'figlet'
+ figlet selection.getText(), {font: "Larry 3D 2"}, (error, asciiArt) ->
+ if error
+ console.error(error)
+ else
+ selection.insertText("\n#{asciiArt}\n")
```
-You can access the dev console by hitting `alt-cmd-i`. Here, you'll see all the
-statements from `console` calls. When we execute the `changer:magic` command, the
-browser console lists items that are not being modified (_i.e._, those without the
-`status-modified` class). Let's add a class to each of these elements called `hide-me`:
-
-```coffeescript
-magic: ->
- $('ol.entries li').each (i, el) ->
- if !$(el).hasClass("status-modified")
- $(el).addClass("hide-me")
-```
-
-With our newly added class, we can manipulate the visibility of the elements
-with a simple stylesheet. Open up _changer.css_ in the _stylesheets_ directory,
-and add a single entry:
-
-```css
-ol.entries .hide-me {
- display: none;
-}
-```
-
-Refresh Atom, and run the `changer` command. You'll see all the non-changed
-files disappear from the tree. Success!
-
-![Changer_File_View]
-
-There are a number of ways you can get the list back; let's just naively iterate
-over the same elements and remove the class:
-
-```coffeescript
-magic: ->
- $('ol.entries li').each (i, el) ->
- if !$(el).hasClass("status-modified")
- if !$(el).hasClass("hide-me")
- $(el).addClass("hide-me")
- else
- $(el).removeClass("hide-me")
-```
-
-## Creating a New Panel
-
-The next goal of this package is to append a panel to the Atom editor that lists
-some information about the modified files.
-
-To do that, we're going to first open up [the style guide][styleguide]. The Style
-Guide lists every type of UI element that can be created by an Atom package. Aside
-from helping you avoid writing fresh code from scratch, it ensures that packages
-have the same look and feel no matter how they're built.
-
-Every package that extends from the `View` class can provide an optional class
-method called `content`. The `content` method constructs the DOM that your
-package uses as its UI. The principals of `content` are built entirely on
-[SpacePen][space-pen], which we'll touch upon only briefly here.
-
-Our display will simply be an unordered list of the file names, and their
-modified times. We'll append this list to a panel on the bottom of the editor. A
-basic `panel` element inside a `tool-panel` will work well for us. Let's start by carving out a
-`div` to hold the filenames:
-
-```coffeescript
-@content: ->
- @div class: "changer tool-panel panel-bottom", =>
- @div class: "panel", =>
- @div class: "panel-heading", "Modified Files"
- @div class: "panel-body padded", outlet: 'modifiedFilesContainer', =>
- @ul class: 'modified-files-list', outlet: 'modifiedFilesList', =>
- @li 'Modified File Test'
- @li 'Modified File Test'
-```
-
-You can add any HTML attribute you like. `outlet` names the variable your
-package can use to manipulate the element directly. The fat arrow (`=>`)
-indicates that the next DOM set are nested children.
-
-Once again, you can style `li` elements using your stylesheets. Let's test that
-out by adding these lines to the _changer.css_ file:
-
-```css
-ul.modified-files-list {
- color: white;
-}
-```
-
-We'll add one more line to the end of the `magic` method to make this pane
-appear:
-
-```coffeescript
-atom.workspaceView.prependToBottom(this)
-```
-
-If you refresh Atom and hit the key command, you'll see a box appear right
-underneath the editor:
-
-![Changer_Panel_Append]
-
-As you might have guessed, `atom.workspaceView.prependToBottom` tells Atom to
-prepend `this` item (_i.e._, whatever is defined by`@content`). If we had called
-`atom.workspaceView.appendToBottom`, the pane would be attached below the status
-bar.
-
-Before we populate this panel for real, let's apply some logic to toggle the
-pane off and on, just like we did with the tree view. Replace the
-`atom.workspaceView.prependToBottom` call with this code:
-
-```coffeescript
-# toggles the pane
-if @hasParent()
- @remove()
-else
- atom.workspaceView.prependToBottom(this)
-```
-
-There are about a hundred different ways to toggle a pane on and off, and this
-might not be the most efficient one. If you know your package needs to be
-toggled on and off more freely, it might be better to draw the interface during the
-initialization, then immediately call `hide()` on the element to remove it from
-the view. You can then swap between `show()` and `hide()`, and instead of
-forcing Atom to add and remove the element as we're doing here, it'll just set a
-CSS property to control your package's visibility.
-
-Refresh Atom, hit the key combo, and watch your test list appear and disappear.
-
-## Calling Node.js Code
-
-Since Atom is built on top of [Node.js][node], you can call any of its libraries,
-including other modules that your package requires.
-
-We'll iterate through our resulting tree, and construct the path to our modified
-file based on its depth in the tree. We'll use Node to handle path joining for
-directories.
-
-Add the following Node module to the top of your file:
-
-```coffeescript
-path = require 'path'
-```
-
-Then, add these lines to your `magic` method, _before_ your pane drawing code:
-
-```coffeescript
-modifiedFiles = []
-# for each single entry...
-$('ol.entries li.file.status-modified span.name').each (i, el) ->
- filePath = []
- # ...grab its name...
- filePath.unshift($(el).text())
-
- # ... then find its parent directories, and grab their names
- parents = $(el).parents('.directory.status-modified')
- parents.each (i, el) ->
- filePath.unshift($(el).find('div.header span.name').eq(0).text())
-
- modifiedFilePath = path.join(atom.project.rootDirectory.path, filePath.join(path.sep))
- modifiedFiles.push modifiedFilePath
-```
-
-`modifiedFiles` is an array containing a list of our modified files. We're also
-using the node.js [`path` library][path] to get the proper directory separator
-for our system.
-
-Remove the two `@li` elements we added in `@content`, so that we can
-populate our `modifiedFilesList` with real information. We'll do that by
-iterating over `modifiedFiles`, accessing a file's last modified time, and
-appending it to `modifiedFilesList`:
-
-```coffeescript
-# toggles the pane
-if @hasParent()
- @remove()
-else
- for file in modifiedFiles
- stat = fs.lstatSync(file)
- mtime = stat.mtime
- @modifiedFilesList.append("
#{file} - Modified at #{mtime}")
- atom.workspaceView.prependToBottom(this)
-```
-
-When you toggle the modified files list, your pane is now populated with the
-filenames and modified times of files in your project:
-
-![Changer_Panel_Timestamps]
-
-You might notice that subsequent calls to this command reduplicate information.
-We could provide an elegant way of rechecking files already in the list, but for
-this demonstration, we'll just clear the `modifiedFilesList` each time it's closed:
-
-```coffeescript
-# toggles the pane
-if @hasParent()
- @modifiedFilesList.empty() # added this to clear the list on close
- @remove()
-else
- for file in modifiedFiles
- stat = fs.lstatSync(file)
- mtime = stat.mtime
- @modifiedFilesList.append("#{file} - Modified at #{mtime}")
- atom.workspaceView.prependToBottom(this)
-```
-
-## Coloring UI Elements
-
-For packages that create new UI elements, adhering to the style guide is just one
-part to keeping visual consistency. Packages dealing with color, fonts, padding,
-margins, and other visual cues should rely on [Theme Variables][theme-vars], instead
-of developing individual styles. Theme variables are variables defined by Atom
-for use in packages and themes. They're only available in [`LESS`](http://lesscss.org/)
-stylesheets.
-
-For our package, let's remove the style defined by `ul.modified-files-list` in
-_changer.css_. Create a new file under the _stylesheets_ directory called _text-colors.less_.
-Here, we'll import the _ui-variables.less_ file, and define some Atom-specific
-styles:
-
-```less
-@import "ui-variables";
-
-ul.modified-files-list {
- color: @text-color;
- background-color: @background-color-info;
-}
-```
-
-Using theme variables ensures that packages look great alongside any theme.
-
## Further reading
-For more information on the mechanics of packages, check out
-[Creating a Package][creating-a-package].
-
-[bundled-libs]: creating-a-package.html#included-libraries
-[styleguide]: https://github.com/atom/styleguide
-[space-pen]: https://github.com/atom/space-pen
-[node]: http://nodejs.org/
-[path]: http://nodejs.org/docs/latest/api/path.html
-[changer_file_view]: https://f.cloud.github.com/assets/69169/1441187/d7a7cb46-41a7-11e3-8128-d93f70a5d5c1.png
-[changer_panel_append]: https://f.cloud.github.com/assets/69169/1441189/db0c74da-41a7-11e3-8286-b82dd9190c34.png
-[changer_panel_timestamps]: https://f.cloud.github.com/assets/69169/1441190/dcc8eeb6-41a7-11e3-830f-1f1b33072fcd.png
-[theme-vars]: theme-variables.html
-[creating-a-package]: creating-a-package.html
+For more information on the mechanics of packages, check out [Creating a
+Package](creating-a-package.html)
diff --git a/dot-atom/snippets.cson b/dot-atom/snippets.cson
new file mode 100644
index 000000000..e9d644de1
--- /dev/null
+++ b/dot-atom/snippets.cson
@@ -0,0 +1,15 @@
+# Your snippets
+#
+# Atom snippets allow you to enter a simple prefix in the editor and hit tab to
+# expand the prefix into a larger code block with templated values.
+#
+# You can create a new snippet in this file by typing `snip` and then hitting
+# tab.
+#
+# An example CoffeeScript snippet to expand log to console.log:
+#
+# '.source.coffee':
+# 'Console log':
+# 'prefix': 'log'
+# 'body': 'console.log $1'
+#
diff --git a/dot-atom/snippets/coffee.cson b/dot-atom/snippets/coffee.cson
deleted file mode 100644
index 5421f12f4..000000000
--- a/dot-atom/snippets/coffee.cson
+++ /dev/null
@@ -1,44 +0,0 @@
-".source.coffee":
- "Describe block":
- prefix: "de"
- body: """
- describe "${1:description}", ->
- ${2:body}
- """
- "It block":
- prefix: "i"
- body: """
- it "$1", ->
- $2
- """
- "Before each":
- prefix: "be"
- body: """
- beforeEach ->
- $1
- """
- "After each":
- prefix: "af"
- body: """
- afterEach ->
- $1
- """
- "Expectation":
- prefix: "ex"
- body: "expect($1).to$2"
- "Console log":
- prefix: "log"
- body: "console.log $1"
- "Range array":
- prefix: "ra"
- body: "[[$1, $2], [$3, $4]]"
- "Point array":
- prefix: "pt"
- body: "[$1, $2]"
-
- "Key-value pair":
- prefix: ":"
- body: '${1:"${2:key}"}: ${3:value}'
- "Create Jasmine spy":
- prefix: "spy"
- body: 'jasmine.createSpy("${1:description}")$2'
diff --git a/exports/atom.coffee b/exports/atom.coffee
index c5a7ffb63..2eb3c6e36 100644
--- a/exports/atom.coffee
+++ b/exports/atom.coffee
@@ -8,6 +8,7 @@ module.exports =
File: require '../src/file'
fs: require 'fs-plus'
Git: require '../src/git'
+ ConfigObserver: require '../src/config-observer'
Point: Point
Range: Range
diff --git a/keymaps/base.cson b/keymaps/base.cson
index 980a42969..4fe2e868c 100644
--- a/keymaps/base.cson
+++ b/keymaps/base.cson
@@ -24,9 +24,6 @@
'ctrl-shift-up': 'editor:add-selection-above'
'ctrl-shift-down': 'editor:add-selection-below'
-'.tool-panel':
- 'escape': 'core:close'
-
'.tool-panel.panel-left, .tool-panel.panel-right':
'escape': 'tool-panel:unfocus'
diff --git a/keymaps/darwin.cson b/keymaps/darwin.cson
index facd6cc8e..a112bfbf7 100644
--- a/keymaps/darwin.cson
+++ b/keymaps/darwin.cson
@@ -1,4 +1,4 @@
-'.platform-darwin':
+'body':
# Apple specific
'cmd-q': 'application:quit'
'cmd-h': 'application:hide'
@@ -87,7 +87,7 @@
'cmd-8': 'pane:show-item-8'
'cmd-9': 'pane:show-item-9'
-'.platform-darwin .editor':
+'.editor':
# Apple Specific
'cmd-backspace': 'editor:backspace-to-beginning-of-line'
'cmd-delete': 'editor:backspace-to-beginning-of-line'
@@ -113,7 +113,7 @@
'cmd-k cmd-l': 'editor:lower-case'
'cmd-l': 'editor:select-line'
-'body.platform-darwin .editor:not(.mini)':
+'.workspace .editor:not(.mini)':
# Atom specific
'alt-cmd-z': 'editor:checkout-head-revision'
'cmd-<': 'editor:scroll-to-cursor'
@@ -148,7 +148,7 @@
'cmd-k cmd-9': 'editor:fold-at-indent-level-9'
# allow standard input fields to work correctly
-'body.platform-darwin .native-key-bindings':
+'body .native-key-bindings':
'cmd-z': 'native!'
'cmd-Z': 'native!'
'cmd-x': 'native!'
diff --git a/keymaps/win32.cson b/keymaps/win32.cson
index 60825bf16..3b6a230a5 100644
--- a/keymaps/win32.cson
+++ b/keymaps/win32.cson
@@ -1,4 +1,4 @@
-'.platform-win32':
+'body':
# Atom Specific
'enter': 'core:confirm'
'escape': 'core:cancel'
@@ -50,7 +50,7 @@
'ctrl-k ctrl-left': 'window:focus-previous-pane'
'ctrl-k ctrl-right': 'window:focus-next-pane'
-'.platform-win32 .editor':
+'.workspace .editor':
# Windows specific
'ctrl-delete': 'editor:backspace-to-beginning-of-word'
@@ -60,7 +60,7 @@
'ctrl-k ctrl-u': 'editor:upper-case'
'ctrl-k ctrl-l': 'editor:lower-case'
-'.platform-win32 .editor:not(.mini)':
+'.workspace .editor:not(.mini)':
# Atom specific
'alt-ctrl-z': 'editor:checkout-head-revision'
'ctrl-<': 'editor:scroll-to-cursor'
@@ -94,7 +94,7 @@
'ctrl-k ctrl-9': 'editor:fold-at-indent-level-9'
# allow standard input fields to work correctly
-'.platform-win32 input:not(.hidden-input), .platform-win32 .native-key-bindings':
+'body .native-key-bindings':
'ctrl-z': 'native!'
'ctrl-Z': 'native!'
'ctrl-x': 'native!'
diff --git a/menus/darwin.cson b/menus/darwin.cson
index de22e7673..44e88dead 100644
--- a/menus/darwin.cson
+++ b/menus/darwin.cson
@@ -9,8 +9,11 @@
{ label: 'Preferences...', command: 'application:show-settings' }
{ label: 'Open Your Config', command: 'application:open-your-config' }
{ label: 'Open Your Keymap', command: 'application:open-your-keymap' }
+ { label: 'Open Your Snippets', command: 'application:open-your-snippets' }
{ label: 'Open Your Stylesheet', command: 'application:open-your-stylesheet' }
{ type: 'separator' }
+ { label: 'Install Shell Commands', command: 'window:install-shell-commands' }
+ { type: 'separator' }
{ label: 'Hide Atom', command: 'application:hide' }
{ label: 'Hide Others', command: 'application:hide-other-applications' }
{ label: 'Show All', command: 'application:unhide-all-applications' }
diff --git a/package.json b/package.json
index 89324d063..9a8b9e760 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "atom",
"productName": "Atom",
- "version": "0.48.0",
+ "version": "0.49.0",
"main": "./src/browser/main.js",
"repository": {
"type": "git",
@@ -16,7 +16,7 @@
"url": "http://github.com/atom/atom/raw/master/LICENSE.md"
}
],
- "atomShellVersion": "0.8.5",
+ "atomShellVersion": "0.8.7",
"dependencies": {
"async": "0.2.6",
"bootstrap": "git://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372",
@@ -28,15 +28,15 @@
"first-mate": "1.x",
"fs-plus": "1.x",
"fstream": "0.1.24",
- "fuzzaldrin": "0.6.0",
- "git-utils": "0.33.1",
+ "fuzzaldrin": "0.7.0",
+ "git-utils": "0.34.0",
"guid": "0.0.10",
"jasmine-tagged": "0.3.0",
"mkdirp": "0.3.5",
"keytar": "0.15.1",
"less-cache": "0.11.0",
"mixto": "1.x",
- "nslog": "0.3.0",
+ "nslog": "0.4.0",
"oniguruma": "1.x",
"optimist": "0.4.0",
"pathwatcher": "0.14.2",
@@ -75,7 +75,7 @@
"editor-stats": "0.12.0",
"exception-reporting": "0.12.0",
"feedback": "0.22.0",
- "find-and-replace": "0.79.0",
+ "find-and-replace": "0.80.0",
"fuzzy-finder": "0.31.0",
"gists": "0.15.0",
"git-diff": "0.23.0",
@@ -86,27 +86,28 @@
"keybinding-resolver": "0.9.0",
"link": "0.15.0",
"markdown-preview": "0.25.1",
- "metrics": "0.21.0",
+ "metrics": "0.24.0",
"package-generator": "0.24.0",
"release-notes": "0.17.0",
"settings-view": "0.57.0",
- "snippets": "0.20.0",
+ "snippets": "0.22.0",
"spell-check": "0.20.0",
"status-bar": "0.32.0",
"styleguide": "0.21.0",
"symbols-view": "0.29.0",
"tabs": "0.18.0",
- "terminal": "0.26.0",
+ "terminal": "0.27.0",
"timecop": "0.13.0",
- "to-the-hubs": "0.17.0",
+ "to-the-hubs": "0.18.0",
"tree-view": "0.65.0",
+ "update-package-dependencies": "0.2.0",
"visual-bell": "0.6.0",
"welcome": "0.4.0",
"whitespace": "0.10.0",
"wrap-guide": "0.12.0",
"language-c": "0.2.0",
"language-clojure": "0.1.0",
- "language-coffee-script": "0.4.0",
+ "language-coffee-script": "0.6.0",
"language-css": "0.2.0",
"language-gfm": "0.12.0",
"language-git": "0.3.0",
diff --git a/script/copy-folder.cmd b/script/copy-folder.cmd
new file mode 100644
index 000000000..b17473992
--- /dev/null
+++ b/script/copy-folder.cmd
@@ -0,0 +1,18 @@
+@echo off
+
+set USAGE=Usage: %0 source destination
+
+if [%1] == [] (
+ echo %USAGE%
+ exit 1
+)
+if [%2] == [] (
+ echo %USAGE%
+ exit 2
+)
+
+:: rm -rf %2
+if exist %2 rmdir %2 /s /q
+
+:: cp -rf %1 %2
+xcopy %1 %2 /e /h /c /i /y /r
diff --git a/script/create-shortcut.cmd b/script/create-shortcut.cmd
new file mode 100644
index 000000000..ca295d434
--- /dev/null
+++ b/script/create-shortcut.cmd
@@ -0,0 +1,23 @@
+@echo off
+
+set USAGE=Usage: %0 source name-on-desktop
+
+if [%1] == [] (
+ echo %USAGE%
+ exit 1
+)
+if [%2] == [] (
+ echo %USAGE%
+ exit 2
+)
+
+set SCRIPT="%TEMP%\%RANDOM%-%RANDOM%-%RANDOM%-%RANDOM%.vbs"
+
+echo Set oWS = WScript.CreateObject("WScript.Shell") >> %SCRIPT%
+echo sLinkFile = "%USERPROFILE%\Desktop\%2.lnk" >> %SCRIPT%
+echo Set oLink = oWS.CreateShortcut(sLinkFile) >> %SCRIPT%
+echo oLink.TargetPath = %1 >> %SCRIPT%
+echo oLink.Save >> %SCRIPT%
+
+cscript /nologo %SCRIPT%
+del %SCRIPT%
diff --git a/script/grunt b/script/grunt
index 3f8516512..1523b2fed 100755
--- a/script/grunt
+++ b/script/grunt
@@ -2,8 +2,8 @@
var cp = require('./utils/child-process-wrapper.js');
var path = require('path');
-// node build/node_modules/grunt-cli/bin/grunt "$@"
-var gruntPath = path.resolve(__dirname, '..', 'build', 'node_modules', 'grunt-cli', 'bin', 'grunt') + (process.platform === 'win32' ? '.cmd' : '');
-var args = [gruntPath, '--gruntfile', path.resolve('build', 'Gruntfile.coffee')];
+// node build/node_modules/.bin/grunt "$@"
+var gruntPath = path.resolve(__dirname, '..', 'build', 'node_modules', '.bin', 'grunt') + (process.platform === 'win32' ? '.cmd' : '');
+var args = ['--gruntfile', path.resolve('build', 'Gruntfile.coffee')];
args = args.concat(process.argv.slice(2));
-cp.safeSpawn(process.execPath, args, process.exit);
+cp.safeSpawn(gruntPath, args, process.exit);
diff --git a/script/install-cli b/script/install-cli
index b1ade33db..c24835852 100755
--- a/script/install-cli
+++ b/script/install-cli
@@ -3,9 +3,8 @@
path = require 'path'
CommandInstaller = require '../src/command-installer'
-callback = (error, sourcePath, destinationPath) ->
- unless error?
- console.log "#{sourcePath} intalled to #{destinationPath}"
+callback = (error) ->
+ console.warn error.message if error?
CommandInstaller.installAtomCommand(path.resolve(__dirname, '..'), callback)
CommandInstaller.installApmCommand(path.resolve(__dirname, '..'), callback)
diff --git a/script/utils/update-octicons b/script/utils/update-octicons
index 30121e19a..b66402d88 100755
--- a/script/utils/update-octicons
+++ b/script/utils/update-octicons
@@ -24,7 +24,7 @@ fs.createReadStream(fontSrc).pipe(fs.createWriteStream(fontDest))
# Update Octicon UTF codes
glyphsSrc = path.join(pathToOcticons, 'data', 'glyphs.yml')
-octiconUtfDest = path.join atomDir, 'static', 'octicon-utf-codes.less'
+octiconUtfDest = path.join atomDir, 'static', 'variables', 'octicon-utf-codes.less'
output = []
for {css, code} in YAML.load(fs.readFileSync(glyphsSrc).toString())
output.push "@#{css}: \"\\#{code}\";"
diff --git a/spec/command-installer-spec.coffee b/spec/command-installer-spec.coffee
index c6b8ee321..6bd66b4d3 100644
--- a/spec/command-installer-spec.coffee
+++ b/spec/command-installer-spec.coffee
@@ -4,33 +4,31 @@ temp = require 'temp'
installer = require '../src/command-installer'
describe "install(commandPath, callback)", ->
- directory = path.join(temp.dir, 'install-atom-command', 'atom')
- commandPath = path.join(directory, 'source')
- destinationPath = path.join(directory, 'bin', 'source')
+ commandFilePath = temp.openSync("atom-command").path
+ commandName = path.basename(commandFilePath)
+ installationPath = temp.mkdirSync("atom-bin")
+ installationFilePath = path.join(installationPath, commandName)
beforeEach ->
- spyOn(installer, 'findInstallDirectory').andCallFake (callback) ->
- callback(directory)
-
- fs.removeSync(directory) if fs.existsSync(directory)
+ spyOn(installer, 'getInstallDirectory').andReturn installationPath
describe "on #darwin", ->
it "symlinks the command and makes it executable", ->
- fs.writeFileSync(commandPath, 'test')
- expect(fs.isFileSync(commandPath)).toBeTruthy()
- expect(fs.isExecutableSync(commandPath)).toBeFalsy()
- expect(fs.isFileSync(destinationPath)).toBeFalsy()
+ expect(fs.isFileSync(commandFilePath)).toBeTruthy()
+ expect(fs.isExecutableSync(commandFilePath)).toBeFalsy()
+ expect(fs.isFileSync(installationFilePath)).toBeFalsy()
installDone = false
installError = null
- installer.install commandPath, (error) ->
+ installer.install commandFilePath, (error) ->
installDone = true
installError = error
- waitsFor -> installDone
+ waitsFor ->
+ installDone
runs ->
expect(installError).toBeNull()
- expect(fs.isFileSync(destinationPath)).toBeTruthy()
- expect(fs.realpathSync(destinationPath)).toBe fs.realpathSync(commandPath)
- expect(fs.isExecutableSync(destinationPath)).toBeTruthy()
+ expect(fs.isFileSync(installationFilePath)).toBeTruthy()
+ expect(fs.realpathSync(installationFilePath)).toBe fs.realpathSync(commandFilePath)
+ expect(fs.isExecutableSync(installationFilePath)).toBeTruthy()
diff --git a/spec/config-spec.coffee b/spec/config-spec.coffee
index 13785568f..77455c5c2 100644
--- a/spec/config-spec.coffee
+++ b/spec/config-spec.coffee
@@ -218,7 +218,7 @@ describe "Config", ->
runs ->
expect(fs.existsSync(atom.config.configDirPath)).toBeTruthy()
expect(fs.existsSync(path.join(atom.config.configDirPath, 'packages'))).toBeTruthy()
- expect(fs.existsSync(path.join(atom.config.configDirPath, 'snippets'))).toBeTruthy()
+ expect(fs.isFileSync(path.join(atom.config.configDirPath, 'snippets.cson'))).toBeTruthy()
expect(fs.isFileSync(path.join(atom.config.configDirPath, 'config.cson'))).toBeTruthy()
describe ".loadUserConfig()", ->
diff --git a/spec/file-spec.coffee b/spec/file-spec.coffee
index c2a93ffad..05ab6fb54 100644
--- a/spec/file-spec.coffee
+++ b/spec/file-spec.coffee
@@ -63,7 +63,7 @@ describe 'File', ->
afterEach ->
if fs.existsSync(newPath)
fs.removeSync(newPath)
- waitsFor "remove event", (done) -> file.on 'removed', done
+ waitsFor "remove event", 30000, (done) -> file.on 'removed', done
it "it updates its path", ->
jasmine.unspy(window, "setTimeout")
diff --git a/spec/keymap-spec.coffee b/spec/keymap-spec.coffee
index d976144ed..064c5b1c7 100644
--- a/spec/keymap-spec.coffee
+++ b/spec/keymap-spec.coffee
@@ -354,6 +354,27 @@ describe "Keymap", ->
bindings = keymap.keyBindingsForCommandMatchingElement('cultivate', el)
expect(bindings).toHaveLength 0
+ describe "loading platform specific keybindings", ->
+ customKeymap = null
+
+ beforeEach ->
+ resourcePath = temp.mkdirSync('atom')
+ customKeymap = new Keymap({configDirPath, resourcePath})
+
+ afterEach ->
+ customKeymap.destroy()
+
+ it "doesn't load keybindings from other platforms", ->
+ win32FilePath = path.join(resourcePath, "keymaps", "win32.cson")
+ darwinFilePath = path.join(resourcePath, "keymaps", "darwin.cson")
+ fs.writeFileSync(win32FilePath, '"body": "ctrl-l": "core:win32-move-left"')
+ fs.writeFileSync(darwinFilePath, '"body": "ctrl-l": "core:darwin-move-left"')
+
+ customKeymap.loadBundledKeymaps()
+ keyBindings = customKeymap.keyBindingsForKeystroke('ctrl-l')
+ expect(keyBindings).toHaveLength 1
+ expect(keyBindings[0].command).toBe "core:#{process.platform}-move-left"
+
describe "when the user keymap file is changed", ->
it "is reloaded", ->
keymapFilePath = path.join(configDirPath, "keymap.cson")
diff --git a/src/atom.coffee b/src/atom.coffee
index 848be9b3b..3cc30c31e 100644
--- a/src/atom.coffee
+++ b/src/atom.coffee
@@ -34,7 +34,7 @@ WindowEventHandler = require './window-event-handler'
# * `atom.themes` - A {ThemeManager} instance
module.exports =
class Atom extends Model
- # Public: Load or create the Atom environment in the given mode
+ # Public: Load or create the Atom environment in the given mode.
#
# - mode: Pass 'editor' or 'spec' depending on the kind of environment you
# want to build.
@@ -249,10 +249,12 @@ class Atom extends Model
# Private: Call this method when establishing a real application window.
startEditorWindow: ->
- if process.platform is 'darwin'
- CommandInstaller = require './command-installer'
- CommandInstaller.installAtomCommand()
- CommandInstaller.installApmCommand()
+ CommandInstaller = require './command-installer'
+ resourcePath = atom.getLoadSettings().resourcePath
+ CommandInstaller.installAtomCommand resourcePath, (error) ->
+ console.warn error.message if error?
+ CommandInstaller.installApmCommand resourcePath, (error) ->
+ console.warn error.message if error?
@restoreWindowDimensions()
@config.load()
diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee
index 149e87241..affabc0ae 100644
--- a/src/browser/atom-application.coffee
+++ b/src/browser/atom-application.coffee
@@ -15,7 +15,11 @@ url = require 'url'
{EventEmitter} = require 'events'
_ = require 'underscore-plus'
-socketPath = path.join(os.tmpdir(), 'atom.sock')
+socketPath =
+ if process.platform is 'win32'
+ '\\\\.\\pipe\\atom-sock'
+ else
+ path.join(os.tmpdir(), 'atom.sock')
# Private: The application's singleton class.
#
@@ -35,14 +39,10 @@ class AtomApplication
# take a few seconds to trigger 'error' event, it could be a bug of node
# or atom-shell, before it's fixed we check the existence of socketPath to
# speedup startup.
- if (not fs.existsSync socketPath) or options.test
+ if (process.platform isnt 'win32' and not fs.existsSync socketPath) or options.test
createAtomApplication()
return
- # The net.connect is slow in atom-shell for now, use this workaround until
- # atom/atom-shell#159 is fixed.
- process.activateUvLoop()
-
client = net.connect {path: socketPath}, ->
client.write JSON.stringify(options), ->
client.end()
@@ -103,7 +103,8 @@ class AtomApplication
# the other launches will just pass their information to this server and then
# close immediately.
listenForArgumentsFromNewProcess: ->
- fs.unlinkSync socketPath if fs.existsSync(socketPath)
+ if process.platform isnt 'win32' and fs.existsSync(socketPath)
+ fs.unlinkSync socketPath
server = net.createServer (connection) =>
connection.on 'data', (data) =>
@openWithOptions(JSON.parse(data))
@@ -148,15 +149,18 @@ class AtomApplication
@on 'application:report-issue', -> shell.openExternal('https://github.com/atom/atom/issues/new')
@openPathOnEvent('application:show-settings', 'atom://config')
- @openPathOnEvent('application:open-your-stylesheet', 'atom://.atom/stylesheet')
- @openPathOnEvent('application:open-your-keymap', 'atom://.atom/keymap')
@openPathOnEvent('application:open-your-config', 'atom://.atom/config')
+ @openPathOnEvent('application:open-your-keymap', 'atom://.atom/keymap')
+ @openPathOnEvent('application:open-your-snippets', 'atom://.atom/snippets')
+ @openPathOnEvent('application:open-your-stylesheet', 'atom://.atom/stylesheet')
app.on 'window-all-closed', ->
app.quit() if process.platform is 'win32'
app.on 'will-quit', =>
- fs.unlinkSync socketPath if fs.existsSync(socketPath) # Clean the socket file when quit normally.
+ # Clean the socket file when quit normally.
+ if process.platform isnt 'win32' and fs.existsSync(socketPath)
+ fs.unlinkSync socketPath
app.on 'open-file', (event, pathToOpen) =>
event.preventDefault()
diff --git a/src/browser/atom-window.coffee b/src/browser/atom-window.coffee
index 0f09bfaa4..4ca0ab3ad 100644
--- a/src/browser/atom-window.coffee
+++ b/src/browser/atom-window.coffee
@@ -74,6 +74,8 @@ class AtomWindow
global.atomApplication.removeWindow(this)
@browserWindow.on 'unresponsive', =>
+ return if @isSpec
+
chosen = dialog.showMessageBox @browserWindow,
type: 'warning'
buttons: ['Close', 'Keep Waiting']
diff --git a/src/browser/main.coffee b/src/browser/main.coffee
index cd3c144f5..bb24a5efa 100644
--- a/src/browser/main.coffee
+++ b/src/browser/main.coffee
@@ -7,16 +7,14 @@ fs = require 'fs'
module = require 'module'
path = require 'path'
optimist = require 'optimist'
-# TODO: NSLog is missing .lib on windows
-nslog = require 'nslog' unless process.platform is 'win32'
+nslog = require 'nslog'
dialog = require 'dialog'
console.log = (args...) ->
# TODO: Make NSLog work as expected
output = args.map((arg) -> JSON.stringify(arg)).join(" ")
- if process.platform == 'darwin'
- nslog(output)
- else
+ nslog(output)
+ if process.platform isnt 'darwin'
fs.writeFileSync('debug.log', output, flag: 'a')
process.on 'uncaughtException', (error={}) ->
diff --git a/src/buffered-node-process.coffee b/src/buffered-node-process.coffee
index a98734506..397c7bb98 100644
--- a/src/buffered-node-process.coffee
+++ b/src/buffered-node-process.coffee
@@ -6,6 +6,12 @@ path = require 'path'
#
# This may seem unnecessary but on Windows we have to have separate executables
# for each script without this since Windows doesn't support shebang strings.
+#
+# ## Requiring in packages
+#
+# ```coffee
+# {BufferedNodeProcess} = require 'atom'
+# ```
module.exports =
class BufferedNodeProcess extends BufferedProcess
# Executes the given Node script.
diff --git a/src/buffered-process.coffee b/src/buffered-process.coffee
index 3a555c3b6..b27c315be 100644
--- a/src/buffered-process.coffee
+++ b/src/buffered-process.coffee
@@ -1,6 +1,12 @@
ChildProcess = require 'child_process'
# Public: A wrapper which provides line buffering for Node's ChildProcess.
+#
+# ## Requiring in packages
+#
+# ```coffee
+# {BufferedProcess} = require 'atom'
+# ```
module.exports =
class BufferedProcess
process: null
diff --git a/src/coffee-cache.coffee b/src/coffee-cache.coffee
index 263cd924c..9653b735d 100644
--- a/src/coffee-cache.coffee
+++ b/src/coffee-cache.coffee
@@ -22,7 +22,10 @@ getCachedJavaScript = (cachePath) ->
fs.readFileSync(cachePath, 'utf8') if stat.isFile()
compileCoffeeScript = (coffee, filePath, cachePath) ->
- js = CoffeeScript.compile(coffee, filename: filePath)
+ {js,v3SourceMap} = CoffeeScript.compile(coffee, filename: filePath, sourceMap: true)
+ # Include source map in the web page environment.
+ if btoa? and JSON? and unescape? and encodeURIComponent?
+ js = "#{js}\n//# sourceMappingURL=data:application/json;base64,#{btoa unescape encodeURIComponent v3SourceMap}\n//# sourceURL=#{filePath}"
try
mkdir(path.dirname(cachePath))
fs.writeFileSync(cachePath, js)
diff --git a/src/command-installer.coffee b/src/command-installer.coffee
index aa6a9e803..a0374bf99 100644
--- a/src/command-installer.coffee
+++ b/src/command-installer.coffee
@@ -23,46 +23,32 @@ unlinkCommand = (destinationPath, callback) ->
callback()
module.exports =
- findInstallDirectory: (callback) ->
- directories = ['/opt/boxen', '/opt/github', '/usr/local']
- async.detect(directories, fs.isDirectory, callback)
+ getInstallDirectory: ->
+ "/usr/local/bin"
- install: (commandPath, commandName, callback) ->
- if not commandName? or _.isFunction(commandName)
- callback = commandName
- commandName = path.basename(commandPath, path.extname(commandPath))
+ install: (commandPath, callback) ->
+ return unless process.platform is 'darwin'
- installCallback = (error, sourcePath, destinationPath) ->
- if error?
- console.warn "Failed to install `#{commandName}` binary", error
- callback?(error, sourcePath, destinationPath)
-
- @findInstallDirectory (directory) ->
- if directory?
- destinationPath = path.join(directory, 'bin', commandName)
- unlinkCommand destinationPath, (error) ->
- if error?
- installCallback(error)
- else
- symlinkCommand commandPath, destinationPath, (error) ->
- installCallback(error, commandPath, destinationPath)
- else
- installCallback(new Error("No destination directory exists to install"))
+ commandName = path.basename(commandPath, path.extname(commandPath))
+ directory = @getInstallDirectory()
+ if fs.existsSync(directory)
+ destinationPath = path.join(directory, commandName)
+ unlinkCommand destinationPath, (error) =>
+ if error?
+ error = new Error "Could not remove file at #{destinationPath}." if error
+ callback?(error)
+ else
+ symlinkCommand commandPath, destinationPath, (error) =>
+ error = new Error "Failed to symlink #{commandPath} to #{destinationPath}." if error
+ callback?(error)
+ else
+ error = new Error "Directory '#{directory} doesn't exist."
+ callback?(error)
installAtomCommand: (resourcePath, callback) ->
- if _.isFunction(resourcePath)
- callback = resourcePath
- resourcePath = null
-
- resourcePath ?= atom.getLoadSettings().resourcePath
commandPath = path.join(resourcePath, 'atom.sh')
- @install(commandPath, callback)
+ @install commandPath, callback
installApmCommand: (resourcePath, callback) ->
- if _.isFunction(resourcePath)
- callback = resourcePath
- resourcePath = null
-
- resourcePath ?= atom.getLoadSettings().resourcePath
commandPath = path.join(resourcePath, 'apm', 'node_modules', '.bin', 'apm')
- @install(commandPath, callback)
+ @install commandPath, callback
diff --git a/src/config-observer.coffee b/src/config-observer.coffee
index ca52945c5..46d3c44dd 100644
--- a/src/config-observer.coffee
+++ b/src/config-observer.coffee
@@ -1,4 +1,7 @@
+Mixin = require 'mixto'
+
module.exports =
+class ConfigObserver extends Mixin
observeConfig: (keyPath, args...) ->
@configSubscriptions ?= {}
@configSubscriptions[keyPath] = atom.config.observe(keyPath, args...)
diff --git a/src/directory.coffee b/src/directory.coffee
index a90dc290d..6404dc5ba 100644
--- a/src/directory.coffee
+++ b/src/directory.coffee
@@ -7,7 +7,13 @@ pathWatcher = require 'pathwatcher'
File = require './file'
-# Public: Represents a directory using {File}s
+# Public: Represents a directory using {File}s.
+#
+# ## Requiring in packages
+#
+# ```coffee
+# {Directory} = require 'atom'
+# ```
module.exports =
class Directory
Emitter.includeInto(this)
diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee
index 6974ad9ba..3c835863b 100644
--- a/src/display-buffer.coffee
+++ b/src/display-buffer.coffee
@@ -15,7 +15,7 @@ ConfigObserver = require './config-observer'
module.exports =
class DisplayBuffer extends Model
Serializable.includeInto(this)
- _.extend @prototype, ConfigObserver
+ ConfigObserver.includeInto(this)
@properties
softWrap: null
@@ -297,8 +297,12 @@ class DisplayBuffer extends Model
[startScreenRow, endScreenRow] = @rowMap.screenRowRangeForBufferRow(row)
for screenRow in [startScreenRow...endScreenRow]
unless screenLine = @screenLines[screenRow]
- throw new Error("No screen line exists for screen row #{screenRow}, converted from buffer position (#{row}, #{column})")
-
+ throw new Error """
+ No screen line exists for screen row #{screenRow}, converted from buffer position (#{row}, #{column})
+ Soft wrap enabled: #{@getSoftWrap()}
+ Fold count: #{@findFoldMarkers().length}
+ Last buffer row: #{@getLastRow()}
+ """
maxBufferColumn = screenLine.getMaxBufferColumn()
if screenLine.isSoftWrapped() and column > maxBufferColumn
continue
diff --git a/src/editor-view.coffee b/src/editor-view.coffee
index 35acb9b33..ea82127d8 100644
--- a/src/editor-view.coffee
+++ b/src/editor-view.coffee
@@ -1,6 +1,6 @@
{View, $, $$$} = require './space-pen-extensions'
TextBuffer = require './text-buffer'
-Gutter = require './gutter'
+GutterView = require './gutter-view'
{Point, Range} = require 'text-buffer'
Editor = require './editor'
CursorView = require './cursor-view'
@@ -16,6 +16,12 @@ LongLineLength = 1000
# Public: Represents the entire visual pane in Atom.
#
# The EditorView manages the {Editor}, which manages the file buffers.
+#
+# ## Requiring in packages
+#
+# ```coffee
+# {EditorView} = require 'atom'
+# ```
module.exports =
class EditorView extends View
@characterWidthCache: {}
@@ -41,7 +47,7 @@ class EditorView extends View
attributes = { class: @classes(params), tabindex: -1 }
_.extend(attributes, params.attributes) if params.attributes
@div attributes, =>
- @subview 'gutter', new Gutter
+ @subview 'gutter', new GutterView
@div class: 'scroll-view', outlet: 'scrollView', =>
@div class: 'overlayer', outlet: 'overlayer'
@div class: 'lines', outlet: 'renderedLines'
@@ -405,7 +411,7 @@ class EditorView extends View
selectedText = null
@hiddenInput.on 'compositionstart', =>
- selectedText = @getSelectedText()
+ selectedText = @editor.getSelectedText()
@hiddenInput.css('width', '100%')
@hiddenInput.on 'compositionupdate', (e) =>
@editor.insertText(e.originalEvent.data, {select: true, undo: 'skip'})
diff --git a/src/editor.coffee b/src/editor.coffee
index a5aede5ed..753754be2 100644
--- a/src/editor.coffee
+++ b/src/editor.coffee
@@ -202,8 +202,8 @@ class Editor extends Model
# Deprecated: Use the ::scrollLeft property directly
getScrollLeft: -> @scrollLeft
- # Set the number of characters that can be displayed horizontally in the
- # editor that contains this edit session.
+ # Public: Set the number of characters that can be displayed horizontally in
+ # the editor.
#
# editorWidthInChars - A {Number} of characters
setEditorWidthInChars: (editorWidthInChars) ->
@@ -765,27 +765,27 @@ class Editor extends Model
findMarkers: (attributes) ->
@displayBuffer.findMarkers(attributes)
- # {Delegates to: DisplayBuffer.markScreenRange}
+ # Public: {Delegates to: DisplayBuffer.markScreenRange}
markScreenRange: (args...) ->
@displayBuffer.markScreenRange(args...)
- # {Delegates to: DisplayBuffer.markBufferRange}
+ # Public: {Delegates to: DisplayBuffer.markBufferRange}
markBufferRange: (args...) ->
@displayBuffer.markBufferRange(args...)
- # {Delegates to: DisplayBuffer.markScreenPosition}
+ # Public: {Delegates to: DisplayBuffer.markScreenPosition}
markScreenPosition: (args...) ->
@displayBuffer.markScreenPosition(args...)
- # {Delegates to: DisplayBuffer.markBufferPosition}
+ # Public: {Delegates to: DisplayBuffer.markBufferPosition}
markBufferPosition: (args...) ->
@displayBuffer.markBufferPosition(args...)
- # {Delegates to: DisplayBuffer.destroyMarker}
+ # Public: {Delegates to: DisplayBuffer.destroyMarker}
destroyMarker: (args...) ->
@displayBuffer.destroyMarker(args...)
- # {Delegates to: DisplayBuffer.getMarkerCount}
+ # Public: {Delegates to: DisplayBuffer.getMarkerCount}
getMarkerCount: ->
@buffer.getMarkerCount()
diff --git a/src/file.coffee b/src/file.coffee
index bc8152d8a..bb09cc4f2 100644
--- a/src/file.coffee
+++ b/src/file.coffee
@@ -10,6 +10,12 @@ fs = require 'fs-plus'
#
# You should probably create a {Directory} and access the {File} objects that
# it creates, rather than instantiating the {File} class directly.
+#
+# ## Requiring in packages
+#
+# ```coffee
+# {File} = require 'atom'
+# ```
module.exports =
class File
Emitter.includeInto(this)
diff --git a/src/git.coffee b/src/git.coffee
index dd795310a..b22466461 100644
--- a/src/git.coffee
+++ b/src/git.coffee
@@ -7,7 +7,8 @@ GitUtils = require 'git-utils'
# Public: Represents the underlying git operations performed by Atom.
#
# This class shouldn't be instantiated directly but instead by accessing the
-# `atom.project` global and calling `getRepo()`.
+# `atom.project` global and calling `getRepo()`. Note that this will only be
+# available when the project is backed by a Git repository.
#
# ## Example
#
@@ -15,6 +16,12 @@ GitUtils = require 'git-utils'
# git = atom.project.getRepo()
# console.log git.getOriginUrl()
# ```
+#
+# ## Requiring in packages
+#
+# ```coffee
+# {Git} = require 'atom'
+# ```
module.exports =
class Git
Emitter.includeInto(this)
@@ -250,12 +257,7 @@ class Git
# Public: Returns the upstream branch for the current HEAD, or null if there
# is no upstream branch for the current HEAD.
#
- # Examples
- #
- # getUpstreamBranch()
- # # => "refs/remotes/origin/master"
- #
- # Returns a String.
+ # Returns a String branch name such as `refs/remotes/origin/master`
getUpstreamBranch: -> @getRepo().getUpstreamBranch()
# Public: Returns the current SHA for the given reference.
diff --git a/src/gutter.coffee b/src/gutter-view.coffee
similarity index 97%
rename from src/gutter.coffee
rename to src/gutter-view.coffee
index ff7926954..cae0d51c0 100644
--- a/src/gutter.coffee
+++ b/src/gutter-view.coffee
@@ -6,7 +6,7 @@ _ = require 'underscore-plus'
#
# The gutter also indicates if rows are folded.
module.exports =
-class Gutter extends View
+class GutterView extends View
### Internal ###
@@ -234,11 +234,11 @@ class Gutter extends View
lastBufferRow = null
for bufferRow in editor.bufferRowsForScreenRows(startScreenRow, endScreenRow) when bufferRow isnt lastBufferRow
lastBufferRow = bufferRow
- lineNumberElement = @getLineNumberElement(bufferRow)[0]
- if editor.isFoldableAtBufferRow(bufferRow)
- lineNumberElement.classList.add('foldable')
- else
- lineNumberElement.classList.remove('foldable')
+ if lineNumberElement = @getLineNumberElement(bufferRow)[0]
+ if editor.isFoldableAtBufferRow(bufferRow)
+ lineNumberElement.classList.add('foldable')
+ else
+ lineNumberElement.classList.remove('foldable')
removeLineHighlights: ->
return unless @highlightedLineNumbers
diff --git a/src/keymap.coffee b/src/keymap.coffee
index e75faf17d..3c3a8ec44 100644
--- a/src/keymap.coffee
+++ b/src/keymap.coffee
@@ -142,7 +142,12 @@ class Keymap
@userKeymapFile.on 'contents-changed moved removed', => @loadUserKeymap()
loadDirectory: (directoryPath) ->
- @load(filePath) for filePath in fs.listSync(directoryPath, ['.cson', '.json'])
+ platforms = ['darwin', 'freebsd', 'linux', 'sunos', 'win32']
+ otherPlatforms = platforms.filter (name) -> name != process.platform
+
+ for filePath in fs.listSync(directoryPath, ['.cson', '.json'])
+ continue if path.basename(filePath, path.extname(filePath)) in otherPlatforms
+ @load(filePath)
load: (path) ->
@add(path, CSON.readFileSync(path))
diff --git a/src/pasteboard.coffee b/src/pasteboard.coffee
index 92d808395..2f97333d8 100644
--- a/src/pasteboard.coffee
+++ b/src/pasteboard.coffee
@@ -1,7 +1,9 @@
clipboard = require 'clipboard'
crypto = require 'crypto'
-# Internal: Represents the clipboard used for copying and pasting in Atom.
+# Public: Represents the clipboard used for copying and pasting in Atom.
+#
+# A pasteboard instance is always available under the `atom.pasteboard` global.
module.exports =
class Pasteboard
signatureForMetadata: null
@@ -14,18 +16,19 @@ class Pasteboard
md5: (text) ->
crypto.createHash('md5').update(text, 'utf8').digest('hex')
- # Saves from the clipboard.
+ # Public: Write the given text to the clipboard.
#
- # text - A {String} to store
- # metadata - An object of additional info to associate with the text
+ # text - A {String} to store.
+ # metadata - An {Object} of additional info to associate with the text.
write: (text, metadata) ->
@signatureForMetadata = @md5(text)
@metadata = metadata
clipboard.writeText(text)
- # Loads from the clipboard.
+ # Public: Read the text from the clipboard.
#
- # Returns an {Array}. The first index is the saved text, and the second is any metadata associated with the text.
+ # Returns an {Array}. The first element is the saved text and the second is
+ # any metadata associated with the text.
read: ->
text = clipboard.readText()
value = [text]
diff --git a/src/project.coffee b/src/project.coffee
index 30c3711ba..62f5f0dbe 100644
--- a/src/project.coffee
+++ b/src/project.coffee
@@ -16,8 +16,7 @@ Git = require './git'
# Public: Represents a project that's opened in Atom.
#
-# Ultimately, a project is a git directory that's been opened. It's a collection
-# of directories and files that you can operate on.
+# There is always a project available under the `atom.project` global.
module.exports =
class Project extends Model
atom.deserializers.add(this)
diff --git a/src/scroll-view.coffee b/src/scroll-view.coffee
index 380669cfa..7f09cf73d 100644
--- a/src/scroll-view.coffee
+++ b/src/scroll-view.coffee
@@ -5,9 +5,11 @@
# This `View` subclass listens to events such as `page-up`, `page-down`,
# `move-to-top`, and `move-to-bottom`.
#
-# FIXME: I don't actually understand if this is useful or not. I think it is
-# a base of package widgets but I don't really understand how the core events
-# work.
+# ## Requiring in packages
+#
+# ```coffee
+# {ScrollView} = require 'atom'
+# ```
module.exports =
class ScrollView extends View
diff --git a/src/select-list.coffee b/src/select-list.coffee
index 415560aed..925d6b56e 100644
--- a/src/select-list.coffee
+++ b/src/select-list.coffee
@@ -4,6 +4,12 @@ fuzzyFilter = require('fuzzaldrin').filter
# Public: Provides a widget for users to make a selection from a list of
# choices.
+#
+# ## Requiring in packages
+#
+# ```coffee
+# {SelectList} = require 'atom'
+# ```
module.exports =
class SelectList extends View
diff --git a/src/space-pen-extensions.coffee b/src/space-pen-extensions.coffee
index c048d803a..11bcc3c1a 100644
--- a/src/space-pen-extensions.coffee
+++ b/src/space-pen-extensions.coffee
@@ -1,9 +1,9 @@
_ = require 'underscore-plus'
spacePen = require 'space-pen'
-ConfigObserver = require './config-observer'
{Subscriber} = require 'emissary'
+ConfigObserver = require './config-observer'
-_.extend spacePen.View.prototype, ConfigObserver
+ConfigObserver.includeInto(spacePen.View)
Subscriber.includeInto(spacePen.View)
jQuery = spacePen.jQuery
diff --git a/src/syntax.coffee b/src/syntax.coffee
index ac5edb3e0..af1a6278a 100644
--- a/src/syntax.coffee
+++ b/src/syntax.coffee
@@ -6,7 +6,12 @@ _ = require 'underscore-plus'
{$, $$} = require './space-pen-extensions'
Token = require './token'
-### Public ###
+# Public: Syntax class holding the grammars used for tokenizing.
+#
+# The Syntax class also contains properties for things such as the
+# language-specific comment regexes.
+#
+# There is always a syntax object available under the `atom.syntax` global.
module.exports =
class Syntax extends GrammarRegistry
Subscriber.includeInto(this)
@@ -49,6 +54,18 @@ class Syntax extends GrammarRegistry
@scopedProperties = []
@scopedPropertiesIndex = 0
+ # Public: Get a property for the given scope and key path.
+ #
+ # ## Example
+ # ```coffee
+ # comment = atom.syntax.getProperty(['.source.ruby'], 'editor.commentStart')
+ # console.log(comment) # '# '
+ # ```
+ #
+ # * scope: An {Array} of {String} scopes.
+ # * keyPath: A {String} key path.
+ #
+ # Returns a {String} property value or undefined.
getProperty: (scope, keyPath) ->
for object in @propertiesForScope(scope, keyPath)
value = _.valueForKeyPath(object, keyPath)
diff --git a/src/task.coffee b/src/task.coffee
index 80eaa81b8..03f80cc56 100644
--- a/src/task.coffee
+++ b/src/task.coffee
@@ -12,6 +12,12 @@ child_process = require 'child_process'
# * task:warn - Emitted when console.warn is called within the task.
# * task:error - Emitted when console.error is called within the task.
# * task:completed - Emitted when the task has succeeded or failed.
+#
+# ## Requiring in packages
+#
+# ```coffee
+# {Task} = require 'atom'
+# ```
module.exports =
class Task
Emitter.includeInto(this)
diff --git a/src/text-utils.coffee b/src/text-utils.coffee
index 4577ae321..a043d7c73 100644
--- a/src/text-utils.coffee
+++ b/src/text-utils.coffee
@@ -1,13 +1,9 @@
-### Internal ###
-
isHighSurrogate = (string, index) ->
0xD800 <= string.charCodeAt(index) <= 0xDBFF
isLowSurrogate = (string, index) ->
0xDC00 <= string.charCodeAt(index) <= 0xDFFF
-### Public ###
-
# Is the character at the given index the start of a high/low surrogate pair?
#
# string - The {String} to check for a surrogate pair.
diff --git a/src/theme-manager.coffee b/src/theme-manager.coffee
index b073a9b45..a1d9caa89 100644
--- a/src/theme-manager.coffee
+++ b/src/theme-manager.coffee
@@ -8,9 +8,9 @@ fs = require 'fs-plus'
AtomPackage = require './atom-package'
File = require './file'
-# Private: Handles discovering and loading available themes.
+# Public: Handles loading and activating available themes.
#
-# Themes are a subset of packages
+# A ThemeManager instance is always available under the `atom.themes` global.
module.exports =
class ThemeManager
Emitter.includeInto(this)
@@ -19,27 +19,26 @@ class ThemeManager
@lessCache = null
@packageManager.registerPackageActivator(this, ['theme'])
- # Internal-only:
getAvailableNames: ->
# TODO: Maybe should change to list all the available themes out there?
@getLoadedNames()
+ # Public: Get an array of all the loaded theme names.
getLoadedNames: ->
theme.name for theme in @getLoadedThemes()
- # Internal-only:
+ # Public: Get an array of all the active theme names.
getActiveNames: ->
theme.name for theme in @getActiveThemes()
- # Internal-only:
+ # Public: Get an array of all the active themes.
getActiveThemes: ->
pack for pack in @packageManager.getActivePackages() when pack.isTheme()
- # Internal-only:
+ # Public: Get an array of all the loaded themes.
getLoadedThemes: ->
pack for pack in @packageManager.getLoadedPackages() when pack.isTheme()
- # Internal-only: adhere to the PackageActivator interface
activatePackages: (themePackages) -> @activateThemes()
# Private: Get the enabled theme names from the config.
@@ -53,7 +52,6 @@ class ThemeManager
# the first/top theme to override later themes in the stack.
themeNames.reverse()
- # Internal-only:
activateThemes: ->
# atom.config.observe runs the callback once, then on subsequent changes.
atom.config.observe 'core.themes', =>
@@ -69,13 +67,11 @@ class ThemeManager
@emit('reloaded')
- # Internal-only:
deactivateThemes: ->
@unwatchUserStylesheet()
@packageManager.deactivatePackage(pack.name) for pack in @getActiveThemes()
null
- # Internal-only:
refreshLessCache: ->
@lessCache?.setImportPaths(@getImportPaths())
@@ -85,7 +81,6 @@ class ThemeManager
setEnabledThemes: (enabledThemeNames) ->
atom.config.set('core.themes', enabledThemeNames)
- # Public:
getImportPaths: ->
activeThemes = @getActiveThemes()
if activeThemes.length > 0
@@ -98,7 +93,7 @@ class ThemeManager
themePath for themePath in themePaths when fs.isDirectorySync(themePath)
- # Public:
+ # Public: Returns the {String} path to the user's stylesheet under ~/.atom
getUserStylesheetPath: ->
stylesheetPath = fs.resolve(path.join(@configDirPath, 'user'), ['css', 'less'])
if fs.isFileSync(stylesheetPath)
@@ -106,13 +101,11 @@ class ThemeManager
else
path.join(@configDirPath, 'user.less')
- #Private:
unwatchUserStylesheet: ->
@userStylesheetFile?.off()
@userStylesheetFile = null
@removeStylesheet(@userStylesheetPath) if @userStylesheetPath?
- # Private:
loadUserStylesheet: ->
@unwatchUserStylesheet()
userStylesheetPath = @getUserStylesheetPath()
@@ -125,34 +118,32 @@ class ThemeManager
userStylesheetContents = @loadStylesheet(userStylesheetPath)
@applyStylesheet(userStylesheetPath, userStylesheetContents, 'userTheme')
- # Internal-only:
loadBaseStylesheets: ->
@requireStylesheet('bootstrap/less/bootstrap')
@reloadBaseStylesheets()
- # Internal-only:
reloadBaseStylesheets: ->
@requireStylesheet('../static/atom')
if nativeStylesheetPath = fs.resolveOnLoadPath(process.platform, ['css', 'less'])
@requireStylesheet(nativeStylesheetPath)
- # Internal-only:
stylesheetElementForId: (id, htmlElement=$('html')) ->
htmlElement.find("""head style[id="#{id}"]""")
- # Internal-only:
resolveStylesheet: (stylesheetPath) ->
if path.extname(stylesheetPath).length > 0
fs.resolveOnLoadPath(stylesheetPath)
else
fs.resolveOnLoadPath(stylesheetPath, ['css', 'less'])
- # Public: resolves and applies the stylesheet specified by the path.
+ # Public: Resolve and apply the stylesheet specified by the path.
#
- # * stylesheetPath: String. Can be an absolute path or the name of a CSS or
- # LESS file in the stylesheets path.
+ # This supports both CSS and LESS stylsheets.
#
- # Returns the absolute path to the stylesheet
+ # * stylesheetPath: A {String} path to the stylesheet that can be an absolute
+ # path or a relative path that will be resolved against the load path.
+ #
+ # Returns the absolute path to the required stylesheet.
requireStylesheet: (stylesheetPath, ttype = 'bundled', htmlElement) ->
if fullPath = @resolveStylesheet(stylesheetPath)
content = @loadStylesheet(fullPath)
@@ -162,14 +153,12 @@ class ThemeManager
fullPath
- # Internal-only:
loadStylesheet: (stylesheetPath) ->
if path.extname(stylesheetPath) is '.less'
@loadLessStylesheet(stylesheetPath)
else
fs.readFileSync(stylesheetPath, 'utf8')
- # Internal-only:
loadLessStylesheet: (lessStylesheetPath) ->
unless @lessCache?
LessCompileCache = require './less-compile-cache'
@@ -184,16 +173,13 @@ class ThemeManager
#{e.message}
"""
- # Internal-only:
stringToId: (string) ->
string.replace(/\\/g, '/')
- # Internal-only:
removeStylesheet: (stylesheetPath) ->
fullPath = @resolveStylesheet(stylesheetPath) ? stylesheetPath
@stylesheetElementForId(@stringToId(fullPath)).remove()
- # Internal-only:
applyStylesheet: (path, text, ttype = 'bundled', htmlElement=$('html')) ->
styleElement = @stylesheetElementForId(@stringToId(path), htmlElement)
if styleElement.length
diff --git a/src/window.coffee b/src/window.coffee
index d9767fe3d..891515ed9 100644
--- a/src/window.coffee
+++ b/src/window.coffee
@@ -1,9 +1,9 @@
# Public: Measure how long a function takes to run.
#
# * description:
-# A String description that will be logged to the console.
+# A {String} description that will be logged to the console.
# * fn:
-# A Function to measure the duration of.
+# A {Function} to measure the duration of.
#
# Returns the value returned by the given function.
window.measure = (description, fn) ->
@@ -16,10 +16,10 @@ window.measure = (description, fn) ->
# Public: Create a dev tools profile for a function.
#
# * description:
-# A String descrption that will be available in the Profiles tab of the dev
+# A {String} descrption that will be available in the Profiles tab of the dev
# tools.
# * fn:
-# A Function to profile.
+# A {Function} to profile.
#
# Return the value returned by the given function.
window.profile = (description, fn) ->
diff --git a/src/workspace-view.coffee b/src/workspace-view.coffee
index f0a819cf4..a45b86b04 100644
--- a/src/workspace-view.coffee
+++ b/src/workspace-view.coffee
@@ -6,6 +6,7 @@ Delegator = require 'delegato'
{$, $$, View} = require './space-pen-extensions'
fs = require 'fs-plus'
Workspace = require './workspace'
+CommandInstaller = require './command-installer'
EditorView = require './editor-view'
PaneView = require './pane-view'
PaneColumnView = require './pane-column-view'
@@ -37,6 +38,11 @@ Editor = require './editor'
# * `application:bring-all-windows-to-front` - Brings all {AtomWindow}s to the
# the front.
#
+# ## Requiring in package specs
+#
+# ```coffee
+# {WorkspaceView} = require 'atom'
+# ```
module.exports =
class WorkspaceView extends View
Delegator.includeInto(this)
@@ -101,8 +107,11 @@ class WorkspaceView extends View
@command 'application:bring-all-windows-to-front', -> ipc.sendChannel('command', 'application:bring-all-windows-to-front')
@command 'application:open-your-config', -> ipc.sendChannel('command', 'application:open-your-config')
@command 'application:open-your-keymap', -> ipc.sendChannel('command', 'application:open-your-keymap')
+ @command 'application:open-your-snippets', -> ipc.sendChannel('command', 'application:open-your-snippets')
@command 'application:open-your-stylesheet', -> ipc.sendChannel('command', 'application:open-your-stylesheet')
+ @command 'window:install-shell-commands', => @installShellCommands()
+
@command 'window:run-package-specs', => ipc.sendChannel('run-package-specs', path.join(atom.project.getPath(), 'spec'))
@command 'window:increase-font-size', => @increaseFontSize()
@command 'window:decrease-font-size', => @decreaseFontSize()
@@ -122,6 +131,26 @@ class WorkspaceView extends View
@command 'core:save', => @saveActivePaneItem()
@command 'core:save-as', => @saveActivePaneItemAs()
+ installShellCommands: ->
+ showErrorDialog = (error) ->
+ installDirectory = CommandInstaller.getInstallDirectory()
+ atom.confirm
+ message: error.message
+ detailedMessage: "Make sure #{installDirectory} exists and is writable. Run 'sudo mkdir -p #{installDirectory} && sudo chown $USER #{installDirectory}' to fix this problem."
+
+ resourcePath = atom.getLoadSettings().resourcePath
+ CommandInstaller.installAtomCommand resourcePath, (error) =>
+ if error?
+ showDialog(error)
+ else
+ CommandInstaller.installApmCommand resourcePath, (error) =>
+ if error?
+ showDialog(error)
+ else
+ atom.confirm
+ message: "Commands installed."
+ detailedMessage: "The shell commands `atom` and `apm` are installed."
+
# Private:
handleFocus: (e) ->
if @getActivePane()
diff --git a/static/octicons.less b/static/octicons.less
index 267d8a675..32147c0fd 100644
--- a/static/octicons.less
+++ b/static/octicons.less
@@ -27,6 +27,7 @@
.make-icon(book);
.make-icon(bookmark);
.make-icon(broadcast);
+.make-icon(browser);
.make-icon(bug);
.make-icon(calendar);
.make-icon(check);
@@ -46,6 +47,7 @@
.make-icon(comment-add);
.make-icon(comment-discussion);
.make-icon(credit-card);
+.make-icon(dash);
.make-icon(dashboard);
.make-icon(database);
.make-icon(device-camera);
@@ -74,6 +76,7 @@
.make-icon(file-symlink-file);
.make-icon(file-text);
.make-icon(file-zip);
+.make-icon(fold);
.make-icon(gear);
.make-icon(gift);
.make-icon(gist);
@@ -92,6 +95,7 @@
.make-icon(git-pull-request-abandoned);
.make-icon(globe);
.make-icon(graph);
+.make-icon(heart);
.make-icon(history);
.make-icon(home);
.make-icon(horizontal-rule);
@@ -127,10 +131,14 @@
.make-icon(mail);
.make-icon(mail-read);
.make-icon(mail-reply);
+.make-icon(mark-facebook);
.make-icon(mark-github);
.make-icon(mark-github-detail);
+.make-icon(mark-google);
.make-icon(mark-twitter);
+.make-icon(markdown);
.make-icon(megaphone);
+.make-icon(mention);
.make-icon(microscope);
.make-icon(milestone);
.make-icon(mirror-private);
@@ -142,6 +150,7 @@
.make-icon(mute);
.make-icon(mute-video);
.make-icon(no-newline);
+.make-icon(node-js);
.make-icon(octoface);
.make-icon(organization);
.make-icon(pencil);
@@ -150,11 +159,16 @@
.make-icon(person-follow);
.make-icon(person-remove);
.make-icon(pin);
+.make-icon(playback-fast-forward);
+.make-icon(playback-pause);
+.make-icon(playback-play);
+.make-icon(playback-rewind);
.make-icon(plus);
.make-icon(podium);
.make-icon(primitive-dot);
.make-icon(primitive-square);
.make-icon(pulse);
+.make-icon(puzzle);
.make-icon(question);
.make-icon(quote);
.make-icon(radio-tower);
@@ -175,18 +189,22 @@
.make-icon(screen-full);
.make-icon(screen-normal);
.make-icon(search);
+.make-icon(search-save);
.make-icon(server);
.make-icon(settings);
+.make-icon(split);
.make-icon(squirrel);
.make-icon(star);
.make-icon(star-add);
.make-icon(star-delete);
+.make-icon(steps);
.make-icon(stop);
.make-icon(sync);
.make-icon(tag);
.make-icon(tag-add);
.make-icon(tag-remove);
.make-icon(telescope);
+.make-icon(terminal);
.make-icon(three-bars);
.make-icon(tools);
.make-icon(triangle-down);
diff --git a/static/octicons.woff b/static/octicons.woff
index 34a7f90f5..bf0b57bdd 100644
Binary files a/static/octicons.woff and b/static/octicons.woff differ
diff --git a/static/variables/octicon-utf-codes.less b/static/variables/octicon-utf-codes.less
index 0f9dc7202..fc90117be 100644
--- a/static/variables/octicon-utf-codes.less
+++ b/static/variables/octicon-utf-codes.less
@@ -14,6 +14,7 @@
@book: "\f007";
@bookmark: "\f07b";
@broadcast: "\f048";
+@browser: "\f0c5";
@bug: "\f091";
@calendar: "\f068";
@check: "\f03a";
@@ -33,6 +34,7 @@
@comment-add: "\f06f";
@comment-discussion: "\f04f";
@credit-card: "\f045";
+@dash: "\f0ca";
@dashboard: "\f07d";
@database: "\f096";
@device-camera: "\f056";
@@ -61,6 +63,7 @@
@file-symlink-file: "\f0b0";
@file-text: "\f011";
@file-zip: "\f013";
+@fold: "\f0cc";
@gear: "\f02f";
@gift: "\f042";
@gist: "\f00e";
@@ -79,6 +82,7 @@
@git-pull-request-abandoned: "\f090";
@globe: "\f0b6";
@graph: "\f043";
+@heart: "\2665";
@history: "\f07e";
@home: "\f08d";
@horizontal-rule: "\f070";
@@ -114,10 +118,14 @@
@mail: "\f03b";
@mail-read: "\f03c";
@mail-reply: "\f051";
+@mark-facebook: "\f0ce";
@mark-github: "\f00a";
@mark-github-detail: "\f093";
+@mark-google: "\f0cd";
@mark-twitter: "\f0ae";
+@markdown: "\f0c9";
@megaphone: "\f077";
+@mention: "\f0be";
@microscope: "\f089";
@milestone: "\f075";
@mirror-private: "\f025";
@@ -129,19 +137,26 @@
@mute: "\f080";
@mute-video: "\f0b8";
@no-newline: "\f09c";
+@node-js: "\f0c3";
@octoface: "\f008";
@organization: "\f037";
+@package: "\f0c4";
@pencil: "\f058";
@person: "\f018";
@person-add: "\f01a";
@person-follow: "\f01c";
@person-remove: "\f01b";
@pin: "\f041";
+@playback-fast-forward: "\f0bd";
+@playback-pause: "\f0bb";
+@playback-play: "\f0bf";
+@playback-rewind: "\f0bc";
@plus: "\f05d";
@podium: "\f0af";
@primitive-dot: "\f052";
@primitive-square: "\f053";
@pulse: "\f085";
+@puzzle: "\f0c0";
@question: "\f02c";
@quote: "\f063";
@radio-tower: "\f030";
@@ -162,18 +177,22 @@
@screen-full: "\f066";
@screen-normal: "\f067";
@search: "\f02e";
+@search-save: "\f0cb";
@server: "\f097";
@settings: "\f07c";
+@split: "\f0c6";
@squirrel: "\f0b2";
@star: "\f02a";
@star-add: "\f082";
@star-delete: "\f083";
+@steps: "\f0c7";
@stop: "\f08f";
@sync: "\f087";
@tag: "\f015";
@tag-add: "\f054";
@tag-remove: "\f055";
@telescope: "\f088";
+@terminal: "\f0c8";
@three-bars: "\f05e";
@tools: "\f031";
@triangle-down: "\f05b";
diff --git a/vendor/apm b/vendor/apm
index b80ef23ce..3f8701bfe 160000
--- a/vendor/apm
+++ b/vendor/apm
@@ -1 +1 @@
-Subproject commit b80ef23ce8d2a1e8b4f40eb0f89c87f32dcc3415
+Subproject commit 3f8701bfe624de844641863391c04def9cca5c86