Comparar commits
484 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 6430bbb460 | |||
| 362ff963fd | |||
| 61ca2e14dc | |||
| 56677e71e4 | |||
| c927101bb2 | |||
| 28f280183e | |||
| f1df254a66 | |||
| af28083a6f | |||
| 495caa7316 | |||
| d0757c87c8 | |||
| c19d99e9e2 | |||
| ab43b08739 | |||
| 01bf346d0f | |||
| c3bd501b84 | |||
| 556bb5b65e | |||
| de1c6d1a5d | |||
| a985942b16 | |||
| 9ba106192d | |||
| 83568a1d85 | |||
| 71333bbc93 | |||
| 4e10ea0b10 | |||
| 888d6dfab5 | |||
| 622b396111 | |||
| 0f2943989f | |||
| 63e618cf74 | |||
| 76f37277d9 | |||
| 745e9c8284 | |||
| 456e511031 | |||
| 390be558e2 | |||
| 4acd5951f5 | |||
| 8cd7d7dc0c | |||
| a127240f4f | |||
| c0ab2c4ac8 | |||
| 4c534606c2 | |||
| f330e207b4 | |||
| d05a3f370e | |||
| 08edcf23c9 | |||
| dc4640eee0 | |||
| 33073ea270 | |||
| 449acc7ced | |||
| dde253160c | |||
| c547039f1d | |||
| afb795d8cc | |||
| ef8a493b9a | |||
| c738145dc7 | |||
| 86991bbec2 | |||
| 973d7ebf13 | |||
| 93c67b670a | |||
| c7315e2be6 | |||
| a4976c32ae | |||
| 37a85bcdd0 | |||
| 47bd093d68 | |||
| a788a7e9b7 | |||
| 9101da11ce | |||
| f7159181ac | |||
| 1784a7f726 | |||
| a28a8447a7 | |||
| 197e74f18d | |||
| 5cae6f20c4 | |||
| 6ad704c1e4 | |||
| 2b0cb11df3 | |||
| 9aee7d4b38 | |||
| b6c86ea217 | |||
| 0d169f0516 | |||
| 740e6de5f3 | |||
| 5dea6e7d12 | |||
| 312e4e0e8a | |||
| 853ad9cee3 | |||
| a5ccfa6299 | |||
| 800ca5a37a | |||
| 23b8b15261 | |||
| 959aa08d62 | |||
| 6eed4e461f | |||
| 00b79e69f1 | |||
| 3739995ddb | |||
| f942bafe54 | |||
| 5fa230e71a | |||
| 9858916c31 | |||
| 18ed76f111 | |||
| feb35e710c | |||
| 2e989b502a | |||
| 434c9e60a8 | |||
| 84453d5441 | |||
| 9e11914b8b | |||
| f9f7cf6d34 | |||
| c7b206f5ca | |||
| 3b8b569d0c | |||
| 8365ccb064 | |||
| fee8e4a75a | |||
| edd8714bbf | |||
| 56adf8cc32 | |||
| d3956da8e5 | |||
| b24b338b2c | |||
| 14969c0522 | |||
| 65f2ffa55e | |||
| 5638c7fb6a | |||
| cb8b254502 | |||
| 027ebc78c4 | |||
| d9fb54ad6f | |||
| 2e72790e72 | |||
| 8fcd71f207 | |||
| 776eedd473 | |||
| 62c515e4e7 | |||
| 223334181b | |||
| a7e18b05d3 | |||
| b92e6f5a2d | |||
| 2170e917bd | |||
| 7add4af585 | |||
| 5076e2c8b3 | |||
| b56d73cd74 | |||
| 6c5a0e3670 | |||
| 791f89216b | |||
| f6067cb629 | |||
| 22158031bf | |||
| 8ac3fada4e | |||
| a03d5bc288 | |||
| cc489e5663 | |||
| cd3f7f73a0 | |||
| 9cb67a6def | |||
| 786e8c558a | |||
| bfeeddea4d | |||
| 1589b8b192 | |||
| b02d0e3df3 | |||
| d3f29c4580 | |||
| 7263ca8faa | |||
| cd812e7a65 | |||
| 4e6e636b8b | |||
| 083bafdb33 | |||
| adbe151c5d | |||
| 26b450fe49 | |||
| 5d273d0ee6 | |||
| b9b2b4bca2 | |||
| 79094ee889 | |||
| 52f2c0ec69 | |||
| d2f485a1ab | |||
| c12002a0ba | |||
| fed2bd6ab8 | |||
| d29b5b20cd | |||
| a0bb9d88e0 | |||
| 32b3c4076f | |||
| acd1d31480 | |||
| 242fce3d79 | |||
| e0bac77fa5 | |||
| c4c13375e4 | |||
| 83f0104c46 | |||
| a0a3c93b1d | |||
| 98a874808e | |||
| e7b790c5b9 | |||
| 4988293400 | |||
| 0d51c3b871 | |||
| 8316183fa0 | |||
| 8e617ff4e2 | |||
| 3ca5495690 | |||
| 5c47ae0cbc | |||
| 6a86a00c66 | |||
| 1abe64e73e | |||
| bb9150340d | |||
| c3f5c43694 | |||
| 1678016ae4 | |||
| f50e402de3 | |||
| e6363150dd | |||
| 5f024bfd69 | |||
| 76adb58fea | |||
| 53d5e61b23 | |||
| 499c09fc25 | |||
| 7891595fed | |||
| 604f2a951f | |||
| c1b6b716b1 | |||
| 4d861a68d1 | |||
| a831688ce1 | |||
| 1cbac24cee | |||
| afa5f73094 | |||
| a142e23f49 | |||
| f1b7536d06 | |||
| 397e61a0d8 | |||
| af22e45f70 | |||
| e6a12530a1 | |||
| 896c98b7a0 | |||
| 3201a05672 | |||
| 93181d8a54 | |||
| 661f1f822a | |||
| 678306317d | |||
| 8dd5f17609 | |||
| 13e069b45d | |||
| e61cc5eb13 | |||
| 9e92952ad0 | |||
| a8d778781c | |||
| da17679ec7 | |||
| 1cf663714e | |||
| 05963c4e57 | |||
| 965a18f7e2 | |||
| 58c45f87e6 | |||
| 21e609ffac | |||
| 93befc986f | |||
| 3321d77264 | |||
| 84761563f0 | |||
| 014cf19723 | |||
| 2a42ed4aaa | |||
| 34b1615782 | |||
| 87db2760b8 | |||
| b4dd0f4f73 | |||
| 9d655fd642 | |||
| 4700edf439 | |||
| 87c2f4496f | |||
| 2741445d95 | |||
| ed90c5e6c2 | |||
| 0bf2a3f480 | |||
| a743e8d058 | |||
| ddc607c760 | |||
| cbc8ad1467 | |||
| 1a1eb4380a | |||
| 535b49f60c | |||
| b5e60f7aa0 | |||
| ce29060d2d | |||
| 7d1c23b561 | |||
| 9e2799db27 | |||
| 040f6deb1e | |||
| 33d2debf5f | |||
| 6de40e21c7 | |||
| 6169caa1fb | |||
| b4e25137a2 | |||
| 05aaace387 | |||
| a32daecf5f | |||
| 6db43d85c4 | |||
| 53e06b8680 | |||
| 9ab2500970 | |||
| 697e70d47c | |||
| ffd1f8520c | |||
| 9132859757 | |||
| 6af2e1649c | |||
| 0962918a82 | |||
| 6b963a562f | |||
| db41b022c2 | |||
| d4084b305b | |||
| b81c1f408f | |||
| 97bdb84122 | |||
| 87e8720269 | |||
| 160c32384c | |||
| 33299ec774 | |||
| d4cc549a01 | |||
| 76a5da8be8 | |||
| 0b0cbe11dc | |||
| 86d730a3a9 | |||
| 99ff482afe | |||
| 84be87324e | |||
| d1ecafc69f | |||
| 235f602002 | |||
| 1ee4240b7e | |||
| a46c4ed30e | |||
| 023b9d18e1 | |||
| 5b992d1397 | |||
| 1ad25f4a56 | |||
| 4baea35c23 | |||
| 63335f6b60 | |||
| f691c20d68 | |||
| 45ca1c6762 | |||
| 528267b7d7 | |||
| 5cdeb7bc18 | |||
| 36d28235fa | |||
| 3b13e4f502 | |||
| f7ecc3e2a3 | |||
| 89a5469151 | |||
| 77e8f5c9ac | |||
| 1fc597ca22 | |||
| 5c62eb0253 | |||
| c378ef0649 | |||
| 12982027f2 | |||
| 36a9e3f76e | |||
| a9d215970f | |||
| 0daee2c2c2 | |||
| f9fe317298 | |||
| ce46991600 | |||
| e1d9838a28 | |||
| 0c057dbbd5 | |||
| aad393618e | |||
| ccaffb1c28 | |||
| 47b1d3e90f | |||
| 9df7ea91db | |||
| 5bf0e53c01 | |||
| c052b03793 | |||
| 22cf142473 | |||
| 1d6db875ff | |||
| b2a71ecd36 | |||
| 432b531c07 | |||
| 3190f7578f | |||
| db49d4da31 | |||
| 9fb1edbc54 | |||
| 5a2365cead | |||
| 3619e6acaf | |||
| 936ab1c898 | |||
| b961ed416e | |||
| 867f920329 | |||
| 6f4107fe5d | |||
| 323ce940f9 | |||
| 1fe452776d | |||
| d263205a9a | |||
| 60970d6cec | |||
| 32f6ab717e | |||
| 4f871f1331 | |||
| c2107fa9b3 | |||
| 96d4c1c41b | |||
| bac10d60c4 | |||
| 828b841f17 | |||
| 11bda1b47a | |||
| 2577843e51 | |||
| e0e821e7a4 | |||
| 93f109fbba | |||
| 97a55ba8c0 | |||
| 0a59d13d56 | |||
| 20dbc4cfd3 | |||
| 6efaf91ff9 | |||
| b6b90c0270 | |||
| d736ebff38 | |||
| 0cf180804c | |||
| c0c5f46097 | |||
| 16cc9f76c4 | |||
| 6ad8aa7e5c | |||
| 67fc2b9af5 | |||
| b8b58b25da | |||
| 696c795b50 | |||
| 97d697f195 | |||
| 57d020ff65 | |||
| 3e56822968 | |||
| d46d797f87 | |||
| fa6a826a37 | |||
| e598856db5 | |||
| 380fee33ef | |||
| d524d25a43 | |||
| 2f765974f8 | |||
| 28868fdb8c | |||
| 4ce785d12c | |||
| 7f8f5203bc | |||
| 77fb8ba15b | |||
| 058005afdf | |||
| 062072ad87 | |||
| a6a9a9e94b | |||
| c024abcc5f | |||
| c69f4baa04 | |||
| 5a4cf01083 | |||
| 49699bddf2 | |||
| 542ed631e8 | |||
| 8c574bfd30 | |||
| f570a417e6 | |||
| ae9e1b0416 | |||
| 08ab5ff650 | |||
| c33288f9bb | |||
| 073f9f2a3e | |||
| b6fc7ff1ac | |||
| 163ee97c73 | |||
| 788b55ee2a | |||
| 3a3a4cd3b2 | |||
| 9d01795335 | |||
| aa0a767e34 | |||
| fb4956dde6 | |||
| 94cee03335 | |||
| 15581c9750 | |||
| 55c8c920f9 | |||
| 0db20c7cbb | |||
| 57e618dec9 | |||
| 206810d5db | |||
| 85a2698f67 | |||
| 04a8a6f784 | |||
| 5d40916b6c | |||
| 9f73a42cf1 | |||
| 75b43b4fa3 | |||
| 19f105e9e7 | |||
| f097f6b4f8 | |||
| 9fa571bf39 | |||
| 5cb18fc7e5 | |||
| 274ae6cd57 | |||
| 7d3fe78eed | |||
| 4ba7182bbf | |||
| 5fe4476114 | |||
| 3dc908c5ff | |||
| 2355862101 | |||
| e51e859631 | |||
| 6211f7330f | |||
| 62eac3f8a5 | |||
| ba40706265 | |||
| 683203a9a1 | |||
| 3ec3c2b69d | |||
| 1bc2248fc2 | |||
| 4be793f465 | |||
| 3454249b58 | |||
| cbd42ac20c | |||
| 02e4482def | |||
| 2306f16b30 | |||
| 9bb6a18d41 | |||
| 85844f03f7 | |||
| 4b8e98af0c | |||
| f30992c5f2 | |||
| 4af007dce3 | |||
| 1e7da34346 | |||
| b8efbedee1 | |||
| 8435826e8a | |||
| 16468eb65d | |||
| d5e04e883e | |||
| 2f3ce50875 | |||
| c20d3a8182 | |||
| ca1f66d197 | |||
| 4138b95146 | |||
| 11d4222c9f | |||
| bc454f14e0 | |||
| bc65322da0 | |||
| 63ad6b1a66 | |||
| 4dd0bf7dab | |||
| aa7482ac28 | |||
| ad1d92d6d9 | |||
| 131e7a021a | |||
| 38e0c39c4a | |||
| c538857cfa | |||
| c964e718b7 | |||
| 2738da2829 | |||
| fe36f5f9de | |||
| c179e562a7 | |||
| e8ad1aa074 | |||
| 3f190d67da | |||
| e60a9e45f7 | |||
| 114b938edf | |||
| 3093a35554 | |||
| 3839432654 | |||
| 0a66e9d21e | |||
| 3dbdfe54ad | |||
| 485fc62d22 | |||
| a0f8405457 | |||
| 56da4f49d4 | |||
| 0d5a707ffb | |||
| 76b7a8cec9 | |||
| de987d3fd2 | |||
| 1a09ec6b92 | |||
| 6716e544f0 | |||
| 2f3a9c9e35 | |||
| 3d1baaf3f3 | |||
| b819f681aa | |||
| 149cfdf0c2 | |||
| d522438876 | |||
| 8fe72cd469 | |||
| e30b2f1c73 | |||
| 51a950c419 | |||
| e693254913 | |||
| 170a71f416 | |||
| e8c19300b5 | |||
| 045850ba06 | |||
| 366ded2f5e | |||
| 716682f072 | |||
| 29ee7cc76b | |||
| ab9cc75f8b | |||
| 9fcac1ab1c | |||
| c172882c15 | |||
| bb6446f7d0 | |||
| e2609ddd06 | |||
| 7f3e0287eb | |||
| 1bba80c2b2 | |||
| 0845610595 | |||
| 2c09321315 | |||
| f2d495eab2 | |||
| 67c193c5ce | |||
| e62485195a | |||
| 1eba8cff39 | |||
| 40b465b0b6 | |||
| 909ec375b1 | |||
| a17b504bdb | |||
| 75857bec01 | |||
| b8fa3a2127 | |||
| 979fad966d | |||
| d523f9e1ec | |||
| f10453ed04 | |||
| 2743c0ab6f | |||
| 2cf5df858f | |||
| dfbb50385d | |||
| e0f6642a9b | |||
| 87c217c3f6 | |||
| 77aa539e70 | |||
| 13fa424ed5 | |||
| 0ea2a9dc9c | |||
| e3eadc310d | |||
| 6520587ba8 | |||
| 3bb62b6651 | |||
| e8ab37c207 | |||
| 612e972ac6 | |||
| 14a20147c6 | |||
| ed9c62f883 | |||
| 0239c7d386 | |||
| 7a0b8c31d4 |
@@ -36,7 +36,7 @@ many packages and themes that are stored in other repos under the
|
||||
[tabs](https://github.com/atom/tabs),
|
||||
[find-and-replace](https://github.com/atom/find-and-replace),
|
||||
[language-javascript](https://github.com/atom/language-javascript), and
|
||||
[atom-light-ui](http://github.com/atom/atom-light-ui).
|
||||
[atom-light-ui](https://github.com/atom/atom-light-ui).
|
||||
|
||||
For more information on how to work with Atom's official packages, see
|
||||
[Contributing to Atom Packages](https://atom.io/docs/latest/contributing-to-packages.html)
|
||||
@@ -74,7 +74,7 @@ For more information on how to work with Atom's official packages, see
|
||||
* Limit the first line to 72 characters or less
|
||||
* Reference issues and pull requests liberally
|
||||
* Consider starting the commit message with an applicable emoji:
|
||||
* :lipstick: `:lipstick:` when improving the format/structure of the code
|
||||
* :art: `:art:` when improving the format/structure of the code
|
||||
* :racehorse: `:racehorse:` when improving performance
|
||||
* :non-potable_water: `:non-potable_water:` when plugging memory leaks
|
||||
* :memo: `:memo:` when writing docs
|
||||
@@ -88,6 +88,7 @@ For more information on how to work with Atom's official packages, see
|
||||
* :lock: `:lock:` when dealing with security
|
||||
* :arrow_up: `:arrow_up:` when upgrading dependencies
|
||||
* :arrow_down: `:arrow_down:` when downgrading dependencies
|
||||
* :shirt: `:shirt:` when removing linter warnings
|
||||
|
||||
## CoffeeScript Styleguide
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||

|
||||
|
||||
Atom is a hackable text editor for the 21st century, built on [atom-shell](http://github.com/atom/atom-shell), and based on everything we love about our favorite editors. We designed it to be deeply customizable, but still approachable using the default configuration.
|
||||
Atom is a hackable text editor for the 21st century, built on [atom-shell](https://github.com/atom/atom-shell), and based on everything we love about our favorite editors. We designed it to be deeply customizable, but still approachable using the default configuration.
|
||||
|
||||
Visit [atom.io](https://atom.io) to learn more or visit the [Atom forum](https://discuss.atom.io).
|
||||
|
||||
@@ -9,7 +9,7 @@ about the Atom 1.0 roadmap.
|
||||
|
||||
## Installing
|
||||
|
||||
### Mac OS X
|
||||
### OS X
|
||||
|
||||
Download the latest [Atom release](https://github.com/atom/atom/releases/latest).
|
||||
|
||||
|
||||
@@ -6,6 +6,6 @@
|
||||
"url": "https://github.com/atom/atom.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"atom-package-manager": "0.119.0"
|
||||
"atom-package-manager": "0.135.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,18 +45,24 @@ if [ $REDIRECT_STDERR ]; then
|
||||
fi
|
||||
|
||||
if [ $OS == 'Mac' ]; then
|
||||
ATOM_PATH="${ATOM_PATH:-/Applications}" # Set ATOM_PATH unless it is already set
|
||||
ATOM_APP_NAME=Atom.app
|
||||
|
||||
# If ATOM_PATH isn't a executable file, use spotlight to search for Atom
|
||||
if [ ! -x "$ATOM_PATH/$ATOM_APP_NAME" ]; then
|
||||
ATOM_PATH="$(mdfind "kMDItemCFBundleIdentifier == 'com.github.atom'" | grep -v ShipIt | head -1 | xargs -0 dirname)"
|
||||
fi
|
||||
if [ -z "${ATOM_PATH}" ]; then
|
||||
# If ATOM_PATH isnt set, check /Applications and then ~/Applications for Atom.app
|
||||
if [ -x "/Applications/$ATOM_APP_NAME" ]; then
|
||||
ATOM_PATH="/Applications"
|
||||
elif [ -x "$HOME/Applications/$ATOM_APP_NAME" ]; then
|
||||
ATOM_PATH="$HOME/Applications"
|
||||
else
|
||||
# We havent found an Atom.app, use spotlight to search for Atom
|
||||
ATOM_PATH="$(mdfind "kMDItemCFBundleIdentifier == 'com.github.atom'" | grep -v ShipIt | head -1 | xargs -0 dirname)"
|
||||
|
||||
# Exit if Atom can't be found
|
||||
if [ -z "$ATOM_PATH" ]; then
|
||||
echo "Cannot locate Atom.app, it is usually located in /Applications. Set the ATOM_PATH environment variable to the directory containing Atom.app."
|
||||
exit 1
|
||||
# Exit if Atom can't be found
|
||||
if [ ! -x "$ATOM_PATH/$ATOM_APP_NAME" ]; then
|
||||
echo "Cannot locate Atom.app, it is usually located in /Applications. Set the ATOM_PATH environment variable to the directory containing Atom.app."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $EXPECT_OUTPUT ]; then
|
||||
@@ -69,9 +75,9 @@ elif [ $OS == 'Linux' ]; then
|
||||
SCRIPT=$(readlink -f "$0")
|
||||
USR_DIRECTORY=$(readlink -f $(dirname $SCRIPT)/..)
|
||||
ATOM_PATH="$USR_DIRECTORY/share/atom/atom"
|
||||
DOT_ATOM_DIR="$HOME/.atom"
|
||||
ATOM_HOME="${ATOM_HOME:-$HOME/.atom}"
|
||||
|
||||
mkdir -p "$DOT_ATOM_DIR"
|
||||
mkdir -p "$ATOM_HOME"
|
||||
|
||||
: ${TMPDIR:=/tmp}
|
||||
|
||||
@@ -82,9 +88,9 @@ elif [ $OS == 'Linux' ]; then
|
||||
exit $?
|
||||
else
|
||||
(
|
||||
nohup "$ATOM_PATH" --executed-from="$(pwd)" --pid=$$ "$@" > "$DOT_ATOM_DIR/nohup.out" 2>&1
|
||||
nohup "$ATOM_PATH" --executed-from="$(pwd)" --pid=$$ "$@" > "$ATOM_HOME/nohup.out" 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
cat "$DOT_ATOM_DIR/nohup.out"
|
||||
cat "$ATOM_HOME/nohup.out"
|
||||
exit $?
|
||||
fi
|
||||
) &
|
||||
|
||||
@@ -198,6 +198,7 @@ module.exports = (grunt) ->
|
||||
outputDir: 'atom-shell'
|
||||
downloadDir: atomShellDownloadDir
|
||||
rebuild: true # rebuild native modules after atom-shell is updated
|
||||
token: process.env.ATOM_ACCESS_TOKEN
|
||||
|
||||
'create-windows-installer':
|
||||
appDirectory: shellAppDir
|
||||
@@ -205,6 +206,8 @@ module.exports = (grunt) ->
|
||||
authors: 'GitHub Inc.'
|
||||
loadingGif: path.resolve(__dirname, '..', 'resources', 'win', 'loading.gif')
|
||||
iconUrl: 'https://raw.githubusercontent.com/atom/atom/master/resources/win/atom.ico'
|
||||
setupIcon: path.resolve(__dirname, '..', 'resources', 'win', 'atom.ico')
|
||||
remoteReleases: 'https://atom.io/api/updates'
|
||||
|
||||
shell:
|
||||
'kill-atom':
|
||||
@@ -219,7 +222,7 @@ module.exports = (grunt) ->
|
||||
grunt.registerTask('test', ['shell:kill-atom', 'run-specs'])
|
||||
grunt.registerTask('docs', ['markdown:guides', 'build-docs'])
|
||||
|
||||
ciTasks = ['output-disk-space', 'download-atom-shell', 'build']
|
||||
ciTasks = ['output-disk-space', 'download-atom-shell', 'download-atom-shell-chromedriver', 'build']
|
||||
ciTasks.push('dump-symbols') if process.platform isnt 'win32'
|
||||
ciTasks.push('set-version', 'check-licenses', 'lint')
|
||||
ciTasks.push('mkdeb') if process.platform is 'linux'
|
||||
@@ -229,6 +232,6 @@ module.exports = (grunt) ->
|
||||
ciTasks.push('publish-build')
|
||||
grunt.registerTask('ci', ciTasks)
|
||||
|
||||
defaultTasks = ['download-atom-shell', 'build', 'set-version']
|
||||
defaultTasks = ['download-atom-shell', 'download-atom-shell-chromedriver', 'build', 'set-version']
|
||||
defaultTasks.push 'install' unless process.platform is 'linux'
|
||||
grunt.registerTask('default', defaultTasks)
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# VERSION: 0.1
|
||||
# DESCRIPTION: Create the atom editor in a container
|
||||
# DESCRIPTION: Create the atom editor in a container
|
||||
# AUTHOR: Jessica Frazelle <jessie@docker.com>
|
||||
# COMMENTS:
|
||||
# This file describes how to build the atom editor
|
||||
# This file describes how to build the atom editor
|
||||
# in a container with all dependencies installed.
|
||||
# Tested on Debian Jessie.
|
||||
# USAGE:
|
||||
# # Download atom Dockerfile
|
||||
# wget http://raw.githubusercontent.com/atom/atom/master/Dockerfile
|
||||
# wget https://raw.githubusercontent.com/atom/atom/master/Dockerfile
|
||||
#
|
||||
# # Build atom image
|
||||
# docker build -t atom .
|
||||
|
||||
@@ -12,25 +12,26 @@
|
||||
"fs-plus": "2.x",
|
||||
"github-releases": "~0.2.0",
|
||||
"grunt": "~0.4.1",
|
||||
"grunt-atom-shell-installer": "^0.16.0",
|
||||
"grunt-atom-shell-installer": "^0.21.0",
|
||||
"grunt-cli": "~0.1.9",
|
||||
"grunt-coffeelint": "git+https://github.com/atom/grunt-coffeelint.git#cfb99aa99811d52687969532bd5a98011ed95bfe",
|
||||
"grunt-contrib-coffee": "~0.12.0",
|
||||
"grunt-contrib-csslint": "~0.1.2",
|
||||
"grunt-contrib-less": "~0.8.0",
|
||||
"grunt-cson": "0.14.0",
|
||||
"grunt-download-atom-shell": "~0.10.0",
|
||||
"grunt-download-atom-shell": "~0.12.0",
|
||||
"grunt-lesslint": "0.13.0",
|
||||
"grunt-peg": "~1.1.0",
|
||||
"grunt-shell": "~0.3.1",
|
||||
"harmony-collections": "~0.3.8",
|
||||
"legal-eagle": "~0.8.0",
|
||||
"legal-eagle": "~0.9.0",
|
||||
"minidump": "~0.8",
|
||||
"npm": "~1.4.5",
|
||||
"rcedit": "~0.3.0",
|
||||
"request": "~2.27.0",
|
||||
"rimraf": "~2.2.2",
|
||||
"runas": "~1.0.1",
|
||||
"selenium-webdriver": "^2.44.0",
|
||||
"tello": "1.0.4",
|
||||
"temp": "~0.8.1",
|
||||
"underscore-plus": "1.x",
|
||||
|
||||
@@ -144,7 +144,10 @@ module.exports = (grunt) ->
|
||||
cp 'spec', path.join(appDir, 'spec')
|
||||
cp 'src', path.join(appDir, 'src'), filter: /.+\.(cson|coffee)$/
|
||||
cp 'static', path.join(appDir, 'static')
|
||||
cp 'apm', path.join(appDir, 'apm'), filter: filterNodeModule
|
||||
|
||||
cp path.join('apm', 'node_modules', 'atom-package-manager'), path.join(appDir, 'apm'), filter: filterNodeModule
|
||||
if process.platform isnt 'win32'
|
||||
fs.symlinkSync(path.join('..', '..', 'bin', 'apm'), path.join(appDir, 'apm', 'node_modules', '.bin', 'apm'))
|
||||
|
||||
if process.platform is 'darwin'
|
||||
grunt.file.recurse path.join('resources', 'mac'), (sourcePath, rootDirectory, subDirectory='', filename) ->
|
||||
|
||||
@@ -35,6 +35,10 @@ module.exports =
|
||||
|
||||
MIT/X11
|
||||
"""
|
||||
'cheerio@0.15.0':
|
||||
repository: "https://github.com/cheeriojs/cheerio"
|
||||
license: 'MIT'
|
||||
source: 'https://github.com/cheeriojs/cheerio/blob/master/package.json'
|
||||
'specificity@0.1.3':
|
||||
repository: 'https://github.com/keeganstreet/specificity'
|
||||
license: 'MIT'
|
||||
@@ -75,3 +79,6 @@ module.exports =
|
||||
|
||||
LGPL
|
||||
"""
|
||||
'core-js@0.4.10':
|
||||
license: 'MIT'
|
||||
source: 'http://rock.mit-license.org linked in source files and bower.json says MIT'
|
||||
|
||||
@@ -36,8 +36,9 @@ module.exports = (grunt) ->
|
||||
maintainer = 'GitHub <atom@github.com>'
|
||||
installDir = '/usr'
|
||||
iconName = 'atom'
|
||||
executable = path.join(installDir, 'share', 'atom', 'atom')
|
||||
getInstalledSize buildDir, (error, installedSize) ->
|
||||
data = {name, version, description, section, arch, maintainer, installDir, iconName, installedSize}
|
||||
data = {name, version, description, section, arch, maintainer, installDir, iconName, installedSize, executable}
|
||||
controlFilePath = fillTemplate(path.join('resources', 'linux', 'debian', 'control'), data)
|
||||
desktopFilePath = fillTemplate(path.join('resources', 'linux', 'atom.desktop'), data)
|
||||
icon = path.join('resources', 'atom.png')
|
||||
|
||||
@@ -33,8 +33,9 @@ module.exports = (grunt) ->
|
||||
installDir = grunt.config.get('atom.installDir')
|
||||
shareDir = path.join(installDir, 'share', 'atom')
|
||||
iconName = path.join(shareDir, 'resources', 'app', 'resources', 'atom.png')
|
||||
executable = 'atom'
|
||||
|
||||
data = {name, version, description, installDir, iconName}
|
||||
data = {name, version, description, installDir, iconName, executable}
|
||||
specFilePath = fillTemplate(path.join('resources', 'linux', 'redhat', 'atom.spec'), data)
|
||||
desktopFilePath = fillTemplate(path.join('resources', 'linux', 'atom.desktop'), data)
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ module.exports = (grunt) ->
|
||||
fullPath = path.join(relativePath, fileName)
|
||||
else
|
||||
fullPath = fileName
|
||||
longPaths.push(fullPath) if fullPath.length >= 200
|
||||
longPaths.push(fullPath) if fullPath.length >= 175
|
||||
|
||||
longPaths.sort (longPath1, longPath2) -> longPath2.length - longPath1.length
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
path = require 'path'
|
||||
fs = require 'fs'
|
||||
|
||||
LessCache = require 'less-cache'
|
||||
|
||||
@@ -7,14 +8,35 @@ module.exports = (grunt) ->
|
||||
prebuiltConfigurations = [
|
||||
['atom-dark-ui', 'atom-dark-syntax']
|
||||
['atom-dark-ui', 'atom-light-syntax']
|
||||
['atom-dark-ui', 'one-dark-syntax']
|
||||
['atom-dark-ui', 'one-light-syntax']
|
||||
['atom-dark-ui', 'solarized-dark-syntax']
|
||||
['atom-dark-ui', 'base16-tomorrow-dark-theme']
|
||||
['atom-dark-ui', 'base16-tomorrow-light-theme']
|
||||
|
||||
['atom-light-ui', 'atom-light-syntax']
|
||||
['atom-light-ui', 'atom-dark-syntax']
|
||||
['atom-light-ui', 'one-dark-syntax']
|
||||
['atom-light-ui', 'one-light-syntax']
|
||||
['atom-light-ui', 'solarized-dark-syntax']
|
||||
['atom-light-ui', 'base16-tomorrow-dark-theme']
|
||||
['atom-light-ui', 'base16-tomorrow-light-theme']
|
||||
|
||||
['one-dark-ui', 'one-dark-syntax']
|
||||
['one-dark-ui', 'one-light-syntax']
|
||||
['one-dark-ui', 'atom-dark-syntax']
|
||||
['one-dark-ui', 'atom-light-syntax']
|
||||
['one-dark-ui', 'solarized-dark-syntax']
|
||||
['one-dark-ui', 'base16-tomorrow-dark-theme']
|
||||
['one-dark-ui', 'base16-tomorrow-light-theme']
|
||||
|
||||
['one-light-ui', 'one-light-syntax']
|
||||
['one-light-ui', 'one-dark-syntax']
|
||||
['one-light-ui', 'atom-light-syntax']
|
||||
['one-light-ui', 'atom-dark-syntax']
|
||||
['one-light-ui', 'solarized-dark-syntax']
|
||||
['one-light-ui', 'base16-tomorrow-dark-theme']
|
||||
['one-light-ui', 'base16-tomorrow-light-theme']
|
||||
]
|
||||
|
||||
directory = path.join(grunt.config.get('atom.appDir'), 'less-compile-cache')
|
||||
@@ -25,7 +47,10 @@ module.exports = (grunt) ->
|
||||
for theme in configuration
|
||||
# TODO Use AtomPackage class once it runs outside of an Atom context
|
||||
themePath = path.resolve('node_modules', theme)
|
||||
stylesheetsDir = path.join(themePath, 'stylesheets')
|
||||
if fs.existsSync(path.join(themePath, 'stylesheets'))
|
||||
stylesheetsDir = path.join(themePath, 'stylesheets')
|
||||
else
|
||||
stylesheetsDir = path.join(themePath, 'styles')
|
||||
{main} = grunt.file.readJSON(path.join(themePath, 'package.json'))
|
||||
main ?= 'index.less'
|
||||
mainPath = path.join(themePath, main)
|
||||
@@ -38,10 +63,18 @@ module.exports = (grunt) ->
|
||||
resourcePath: path.resolve('.')
|
||||
importPaths: importPaths
|
||||
|
||||
cssForFile = (file) ->
|
||||
baseVarImports = """
|
||||
@import "variables/ui-variables";
|
||||
@import "variables/syntax-variables";
|
||||
"""
|
||||
less = fs.readFileSync(file, 'utf8')
|
||||
lessCache.cssForFile(file, [baseVarImports, less].join('\n'))
|
||||
|
||||
for file in @filesSrc
|
||||
grunt.verbose.writeln("File #{file.cyan} created in cache.")
|
||||
lessCache.readFileSync(file)
|
||||
cssForFile(file)
|
||||
|
||||
for file in themeMains
|
||||
grunt.verbose.writeln("File #{file.cyan} created in cache.")
|
||||
lessCache.readFileSync(file)
|
||||
cssForFile(file)
|
||||
|
||||
@@ -68,7 +68,7 @@ getAssets = ->
|
||||
]
|
||||
when 'win32'
|
||||
assets = [{assetName: 'atom-windows.zip', sourcePath: 'Atom'}]
|
||||
for squirrelAsset in ['AtomSetup.exe', 'RELEASES', "atom-#{version}-full.nupkg"]
|
||||
for squirrelAsset in ['AtomSetup.exe', 'RELEASES', "atom-#{version}-full.nupkg", "atom-#{version}-delta.nupkg"]
|
||||
cp path.join(buildDir, 'installer', squirrelAsset), path.join(buildDir, squirrelAsset)
|
||||
assets.push({assetName: squirrelAsset, sourcePath: assetName})
|
||||
assets
|
||||
|
||||
@@ -85,15 +85,27 @@ module.exports = (grunt) ->
|
||||
appPath = getAppPath()
|
||||
resourcePath = process.cwd()
|
||||
coreSpecsPath = path.resolve('spec')
|
||||
chromedriverPath = path.join(resourcePath, "atom-shell", "chromedriver")
|
||||
|
||||
if process.platform in ['darwin', 'linux']
|
||||
options =
|
||||
cmd: appPath
|
||||
args: ['--test', "--resource-path=#{resourcePath}", "--spec-directory=#{coreSpecsPath}"]
|
||||
opts:
|
||||
env: _.extend({}, process.env,
|
||||
ATOM_INTEGRATION_TESTS_ENABLED: true
|
||||
PATH: [process.env.path, chromedriverPath].join(":")
|
||||
)
|
||||
|
||||
else if process.platform is 'win32'
|
||||
options =
|
||||
cmd: process.env.comspec
|
||||
args: ['/c', appPath, '--test', "--resource-path=#{resourcePath}", "--spec-directory=#{coreSpecsPath}", "--log-file=ci.log"]
|
||||
opts:
|
||||
env: _.extend({}, process.env,
|
||||
ATOM_INTEGRATION_TESTS_ENABLED: true
|
||||
PATH: [process.env.path, chromedriverPath].join(";")
|
||||
)
|
||||
|
||||
spawn options, (error, results, code) ->
|
||||
if process.platform is 'win32'
|
||||
|
||||
@@ -49,19 +49,17 @@ can be expressed as keystroke patterns separated by spaces.
|
||||
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:
|
||||
code creates a command to insert the current date in an editor:
|
||||
|
||||
```coffee
|
||||
class EditorView
|
||||
listenForEvents: ->
|
||||
@command 'editor:move-to-first-character-of-line', =>
|
||||
@editor.moveToFirstCharacterOfLine()
|
||||
atom.commands.add 'atom-text-editor',
|
||||
'user:insert-date': (event) ->
|
||||
editor = @getModel()
|
||||
editor.insertText(new Date().toLocaleString())
|
||||
```
|
||||
|
||||
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.
|
||||
`atom.commands` refers to the global {CommandRegistry} instance where all commands
|
||||
are set and consequently picked up by the command palette.
|
||||
|
||||
When you are looking to bind new keys, it is often useful to use the command
|
||||
palette (`ctrl-shift-p`) to discover what commands are being listened for in a
|
||||
@@ -69,6 +67,30 @@ given focus context. Commands are "humanized" following a simple algorithm, so a
|
||||
command like `editor:fold-current-row` would appear as "Editor: Fold Current
|
||||
Row".
|
||||
|
||||
### "Composed" Commands
|
||||
|
||||
A common question is, "How do I make a single keybinding execute two or more
|
||||
commands?" There isn't any direct support for this in Atom, but it can be
|
||||
achieved by creating a custom command that performs the multiple actions
|
||||
you desire and then creating a keybinding for that command. For example, let's
|
||||
say I want to create a "composed" command that performs a Select Line followed
|
||||
by Cut. You could add the following to your `init.coffee`:
|
||||
|
||||
```coffee
|
||||
atom.commands.add 'atom-text-editor', 'custom:cut-line', ->
|
||||
editor = atom.workspace.getActiveTextEditor()
|
||||
editor.selectLinesContainingCursors()
|
||||
editor.cutSelectedText()
|
||||
```
|
||||
|
||||
Then let's say we want to map this custom command to `alt-ctrl-z`, you could
|
||||
add the following to your keymap:
|
||||
|
||||
```coffee
|
||||
'atom-text-editor':
|
||||
'alt-ctrl-z': 'custom:cut-line'
|
||||
```
|
||||
|
||||
### Specificity and Cascade Order
|
||||
|
||||
As is the case with CSS applying styles, when multiple bindings match for a
|
||||
|
||||
@@ -8,7 +8,7 @@ Ubuntu LTS 12.04 64-bit is the recommended platform.
|
||||
* C++ toolchain
|
||||
* [Git](http://git-scm.com/)
|
||||
* [Node.js](http://nodejs.org/download/) v0.10.x
|
||||
* [npm](http://www.npmjs.org/) v1.4.x (bundled with Node.js)
|
||||
* [npm](https://www.npmjs.com/) v1.4.x (bundled with Node.js)
|
||||
* `npm -v` to check the version.
|
||||
* `npm config set python /usr/bin/python2 -g` to ensure that gyp uses python2.
|
||||
* You might need to run this command as `sudo`, depending on how you have set up [npm](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager#ubuntu-mint-elementary-os).
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* For 64-bit builds of node and native modules you **must** have the
|
||||
[Windows 7 64-bit SDK](http://www.microsoft.com/en-us/download/details.aspx?id=8279).
|
||||
You may also need the [compiler update for the Windows SDK 7.1](http://www.microsoft.com/en-us/download/details.aspx?id=4422)
|
||||
* [Python](http://www.python.org/download/) v2.7.
|
||||
* [Python](https://www.python.org/downloads/) v2.7.
|
||||
* The python.exe must be available at `%SystemDrive%\Python27\python.exe`.
|
||||
If it is installed elsewhere, you can create a symbolic link to the
|
||||
directory containing the python.exe using:
|
||||
@@ -19,7 +19,7 @@
|
||||
### On Windows 8
|
||||
* [Visual Studio Express 2013 for Windows Desktop](http://www.visualstudio.com/en-us/downloads/download-visual-studio-vs#DownloadFamilies_2)
|
||||
* [node.js](http://nodejs.org/download/) v0.10.x
|
||||
* [Python](http://www.python.org/download/) v2.7.x (required by [node-gyp](https://github.com/TooTallNate/node-gyp))
|
||||
* [Python](https://www.python.org/downloads/) v2.7.x (required by [node-gyp](https://github.com/TooTallNate/node-gyp))
|
||||
* [GitHub for Windows](http://windows.github.com/)
|
||||
|
||||
## Instructions
|
||||
|
||||
@@ -44,9 +44,9 @@ the editor to see it in action!
|
||||
on publishing the package you just created to [atom.io][atomio].
|
||||
|
||||
[atomio]: https://atom.io
|
||||
[CSS]: http://en.wikipedia.org/wiki/Cascading_Style_Sheets
|
||||
[LESS]: http://lesscss.org
|
||||
[plist]: http://en.wikipedia.org/wiki/Property_list
|
||||
[R]: http://en.wikipedia.org/wiki/R_(programming_language)
|
||||
[CSS]: https://en.wikipedia.org/wiki/Cascading_Style_Sheets
|
||||
[Less]: http://lesscss.org
|
||||
[plist]: https://en.wikipedia.org/wiki/Property_list
|
||||
[R]: https://en.wikipedia.org/wiki/R_(programming_language)
|
||||
[TextMate]: http://macromates.com
|
||||
[TextMateOrg]: https://github.com/textmate
|
||||
|
||||
@@ -6,7 +6,7 @@ theme.
|
||||
### Differences
|
||||
|
||||
TextMate themes use [plist][plist] files while Atom themes use [CSS][CSS] or
|
||||
[LESS][LESS] to style the UI and syntax in the editor.
|
||||
[Less][Less] to style the UI and syntax in the editor.
|
||||
|
||||
The utility that converts the theme first parses the theme's plist file and
|
||||
then creates comparable CSS rules and properties that will style Atom similarly.
|
||||
@@ -61,8 +61,8 @@ __Syntax Theme__ dropdown menu to enable your new theme.
|
||||
on publishing the theme you just created to [atom.io][atomio].
|
||||
|
||||
[atomio]: https://atom.io
|
||||
[CSS]: http://en.wikipedia.org/wiki/Cascading_Style_Sheets
|
||||
[LESS]: http://lesscss.org
|
||||
[plist]: http://en.wikipedia.org/wiki/Property_list
|
||||
[CSS]: https://en.wikipedia.org/wiki/Cascading_Style_Sheets
|
||||
[Less]: http://lesscss.org
|
||||
[plist]: https://en.wikipedia.org/wiki/Property_list
|
||||
[TextMate]: http://macromates.com
|
||||
[TextMateThemes]: http://wiki.macromates.com/Themes/UserSubmittedThemes
|
||||
|
||||
@@ -51,9 +51,24 @@ in the _menus_ directory are added alphabetically.
|
||||
- `snippets` (**Optional**): an Array of Strings identifying the order of the
|
||||
snippets your package needs to load. If not specified, snippets in the
|
||||
_snippets_ directory are added alphabetically.
|
||||
- `activationEvents` (**Optional**): an Array of Strings identifying events that
|
||||
- `activationCommands` (**Optional**): an Array of Strings identifying commands that
|
||||
trigger your package's activation. You can delay the loading of your package
|
||||
until one of these events is triggered.
|
||||
- `providedServices` (**Optional**): an Object describing the services that your
|
||||
package provides, which can be used by other packages. The keys of this object
|
||||
are the names of the services, and the values are Objects with the following
|
||||
keys:
|
||||
- `description` (**Optional**) a String describing the service
|
||||
- `versions` (**Required**) an Object whose keys are Semver version strings,
|
||||
and whose values are names of methods in your package's top-level module
|
||||
that return a value implementing the service.
|
||||
- `consumedServices` (**Optional**): an Object describing the services that your
|
||||
package uses, which can be provided by other packages. The keys of this object
|
||||
are the names of the services, and the values are Objects with the following
|
||||
keys:
|
||||
- `versions` (**Required**) an Object whose keys are Semver version ranges
|
||||
and whose values are names of methods in your package's top-level module
|
||||
that are called with values implementing the service.
|
||||
|
||||
## Source Code
|
||||
|
||||
@@ -83,9 +98,9 @@ module's `activate` method so you can restore your view to where the user left
|
||||
off.
|
||||
|
||||
- `deactivate()`: This **optional** method is called when the window is shutting
|
||||
down. If your package is watching any files or holding external resources in any
|
||||
other way, release them here. If you're just subscribing to things on window,
|
||||
you don't need to worry because that's getting torn down anyway.
|
||||
down, or when your package is being updated or disabled. If your package is
|
||||
watching any files, holding external resources, providing commands or subscribing
|
||||
to events, release them here.
|
||||
|
||||
### Simple Package Code
|
||||
|
||||
@@ -112,19 +127,18 @@ module.exports =
|
||||
serialize: -> # ...
|
||||
```
|
||||
|
||||
Beyond this simple contract, your package has access to Atom's API. Be aware
|
||||
that since we are early in development, APIs are subject to change and we have
|
||||
not yet established clear boundaries between what is public and what is private.
|
||||
Also, please collaborate with us if you need an API that doesn't exist. Our goal
|
||||
is to build out Atom's API organically based on the needs of package authors
|
||||
like you.
|
||||
Beyond this simple contract, your package has access to [Atom's API][api]. Be aware
|
||||
that the Atom 1.0 API is mostly frozen. Refer to the API documentation for what
|
||||
is public. That said, please collaborate with us if you need an API that doesn't
|
||||
exist. Our goal is to build out Atom's API organically based on the needs of
|
||||
package authors like you.
|
||||
|
||||
## Style Sheets
|
||||
|
||||
Style sheets for your package should be placed in the _styles_ directory.
|
||||
Any style sheets in this directory will be loaded and attached to the DOM when
|
||||
your package is activated. Style sheets can be written as CSS or [LESS], but
|
||||
LESS is recommended.
|
||||
your package is activated. Style sheets can be written as CSS or [Less], but
|
||||
Less is recommended.
|
||||
|
||||
Ideally, you won't need much in the way of styling. We've provided a standard
|
||||
set of components which define both the colors and UI elements for any package
|
||||
@@ -352,6 +366,79 @@ to indicate the type your value should be, its default, etc.
|
||||
See the [Config API Docs](https://atom.io/docs/api/latest/Config) for more
|
||||
details specifying your configuration.
|
||||
|
||||
## Interacting With Other Packages Via Services
|
||||
|
||||
Atom packages can interact with each other through versioned APIs called
|
||||
*services*. To provide a service, in your `package.json`, specify one or more
|
||||
version numbers, each paired with the name of a method on your package's main module:
|
||||
|
||||
```json
|
||||
{
|
||||
"providedServices": {
|
||||
"my-service": {
|
||||
"description": "Does a useful thing",
|
||||
"versions": {
|
||||
"1.2.3": "provideMyServiceV1",
|
||||
"2.3.4": "provideMyServiceV2",
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In your package's main module, implement the methods named above. These methods
|
||||
will be called any time a package is activated that consumes their corresponding
|
||||
service. They should return a value that implements the service's API.
|
||||
|
||||
|
||||
```coffeescript
|
||||
module.exports =
|
||||
activate: -> # ...
|
||||
|
||||
provideMyServiceV1: ->
|
||||
adaptToLegacyAPI(myService)
|
||||
|
||||
provideMyServiceV2: ->
|
||||
myService
|
||||
```
|
||||
|
||||
Similarly, to consume a service, specify one or more [version *ranges*][version-ranges],
|
||||
each paired with the name of a method on the package's main module:
|
||||
|
||||
```json
|
||||
{
|
||||
"consumedServices": {
|
||||
"another-service": {
|
||||
"versions": {
|
||||
"^1.2.3": "consumeAnotherServiceV1",
|
||||
">=2.3.4 <2.5": "consumeAnotherServiceV2",
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
These methods will be called any time a package is activated that *provides* their
|
||||
corresponding service. They will receive the service object as an argument. You
|
||||
will usually need to perform some kind of cleanup in the event that the package
|
||||
providing the service is deactivated. To do this, return a `Disposable` from
|
||||
your service-consuming method:
|
||||
|
||||
```coffeescript
|
||||
{Disposable} = require 'atom'
|
||||
|
||||
module.exports =
|
||||
activate: -> # ...
|
||||
|
||||
consumeAnotherServiceV1: (service) ->
|
||||
useService(adaptServiceFromLegacyAPI(service))
|
||||
new Disposable -> stopUsingService(service)
|
||||
|
||||
consumeAnotherServiceV2: (service) ->
|
||||
useService(service)
|
||||
new Disposable -> stopUsingService(service)
|
||||
```
|
||||
|
||||
## Bundle External Resources
|
||||
|
||||
It's common to ship external resources like images and fonts in the package, to
|
||||
@@ -402,11 +489,12 @@ registry.
|
||||
Run `apm help publish` to see all the available options and `apm help` to see
|
||||
all the other available commands.
|
||||
|
||||
[api]: https://atom.io/docs/api/latest
|
||||
[file-tree]: https://github.com/atom/tree-view
|
||||
[status-bar]: https://github.com/atom/status-bar
|
||||
[cs-syntax]: https://github.com/atom/language-coffee-script
|
||||
[npm]: http://en.wikipedia.org/wiki/Npm_(software)
|
||||
[npm-keys]: https://npmjs.org/doc/json.html
|
||||
[npm]: https://en.wikipedia.org/wiki/Npm_(software)
|
||||
[npm-keys]: https://docs.npmjs.com/files/package.json
|
||||
[git-tag]: http://git-scm.com/book/en/Git-Basics-Tagging
|
||||
[wrap-guide]: https://github.com/atom/wrap-guide/
|
||||
[keymaps]: advanced/keymaps.md
|
||||
@@ -418,9 +506,10 @@ all the other available commands.
|
||||
[underscore]: http://underscorejs.org/
|
||||
[jasmine]: http://jasmine.github.io
|
||||
[cson]: https://github.com/atom/season
|
||||
[LESS]: http://lesscss.org
|
||||
[Less]: http://lesscss.org
|
||||
[ui-variables]: https://github.com/atom/atom-dark-ui/blob/master/styles/ui-variables.less
|
||||
[first-package]: your-first-package.html
|
||||
[convert-bundle]: converting-a-text-mate-bundle.html
|
||||
[convert-theme]: converting-a-text-mate-theme.html
|
||||
[json-schema]: http://json-schema.org/
|
||||
[version-ranges]: https://docs.npmjs.com/misc/semver#ranges
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Creating a Theme
|
||||
|
||||
Atom's interface is rendered using HTML, and it's styled via [LESS] which is a
|
||||
superset of CSS. Don't worry if you haven't heard of LESS before; it's just like
|
||||
Atom's interface is rendered using HTML, and it's styled via [Less] which is a
|
||||
superset of CSS. Don't worry if you haven't heard of Less before; it's just like
|
||||
CSS, but with a few handy extensions.
|
||||
|
||||
Atom supports two types of themes: _UI_ and _syntax_. UI themes style
|
||||
@@ -9,22 +9,23 @@ elements such as the tree view, the tabs, drop-down lists, and the status bar.
|
||||
Syntax themes style the code inside the editor.
|
||||
|
||||
Themes can be installed and changed from the settings view which you can open
|
||||
by selecting the _Atom > Preferences..._ menu and navigating to the _Themes_
|
||||
section on the left hand side.
|
||||
by selecting the _Atom > Preferences..._ menu and navigating to the _Install_
|
||||
section and the _Themes_ section on the left hand side.
|
||||
|
||||
## Getting Started
|
||||
|
||||
Themes are pretty straightforward but it's still helpful to be familiar with
|
||||
a few things before starting:
|
||||
|
||||
* LESS is a superset of CSS, but it has some really handy features like
|
||||
* Less is a superset of CSS, but it has some really handy features like
|
||||
variables. If you aren't familiar with its syntax, take a few minutes
|
||||
to [familiarize yourself][less-tutorial].
|
||||
* You may also want to review the concept of a _[package.json]_, too. This file
|
||||
is used to help distribute your theme to Atom users.
|
||||
* Your theme's _package.json_ must contain a `"theme"` key with a value
|
||||
of `"ui"` or `"syntax"` for Atom to recognize and load it as a theme.
|
||||
* You can find existing themes to install or fork on [atom.io](atomio).
|
||||
* You can find existing themes to install or fork on
|
||||
[atom.io][atomio-themes].
|
||||
|
||||
## Creating a Syntax Theme
|
||||
|
||||
@@ -130,13 +131,13 @@ _styleguide_, or use the shortcut `cmd-ctrl-shift-g`.
|
||||
|
||||
![styleguide-img]
|
||||
|
||||
[atomio]: http://atom.io/packages
|
||||
[LESS]: http://lesscss.org/
|
||||
[atomio-themes]: https://atom.io/themes
|
||||
[Less]: http://lesscss.org/
|
||||
[git]: http://git-scm.com/
|
||||
[atom]: https://atom.io/
|
||||
[package.json]: ./creating-a-package.html#package-json
|
||||
[less-tutorial]: https://speakerdeck.com/danmatthews/less-css
|
||||
[devtools-tutorial]: https://developers.google.com/chrome-developer-tools/docs/elements
|
||||
[devtools-tutorial]: https://developer.chrome.com/devtools/docs/dom-and-styles
|
||||
[ui-variables]: ./theme-variables.html
|
||||
[livereload]: https://github.com/atom/dev-live-reload
|
||||
[styleguide]: https://github.com/atom/styleguide
|
||||
|
||||
@@ -100,6 +100,14 @@ namespaces: `core` and `editor`.
|
||||
|
||||
You can open this file in an editor from the _Atom > Open Your Config_ menu.
|
||||
|
||||
### Custom Configuration Location
|
||||
|
||||
You can override the location that Atom stores configuration files and folders
|
||||
in by setting the `ATOM_HOME` environment variable. The `ATOM_HOME` path will be
|
||||
used instead of `~/.atom` when it is set.
|
||||
|
||||
This option can be useful when you want to make Atom portable across machines.
|
||||
|
||||
### Configuration Key Reference
|
||||
|
||||
- `core`
|
||||
@@ -169,17 +177,17 @@ For example, to change the color of the cursor, you could add the following
|
||||
rule to your _~/.atom/styles.less_ file:
|
||||
|
||||
```less
|
||||
atom-text-editor.is-focused .cursor {
|
||||
atom-text-editor::shadow .cursor {
|
||||
border-color: pink;
|
||||
}
|
||||
```
|
||||
|
||||
Unfamiliar with LESS? Read more about it [here][LESS].
|
||||
Unfamiliar with Less? Read more about it [here][Less].
|
||||
|
||||
This file can also be named _styles.css_ and contain CSS.
|
||||
|
||||
[creating-a-package]: creating-a-package.md
|
||||
[create-theme]: creating-a-theme.md
|
||||
[LESS]: http://www.lesscss.org
|
||||
[Less]: http://www.lesscss.org
|
||||
[CSON]: https://github.com/atom/season
|
||||
[CoffeeScript]: http://coffeescript.org/
|
||||
|
||||
@@ -100,6 +100,21 @@ When an error is thrown in Atom, the developer tools are automatically shown wit
|
||||
|
||||
If you can reproduce the error, use this approach to get the full stack trace. The stack trace might point to a problem in your [Init script][init script or stylesheet] or a specific package you installed, which you can then disable and report an issue on its GitHub repository.
|
||||
|
||||
## Check that you have a build toolchain installed
|
||||
|
||||
If you are having issues installing a package using `apm install`, this could be
|
||||
because the package has dependencies on libraries that contain native code
|
||||
and so you will need to have a C++ compiler and Python installed to be able to
|
||||
install it.
|
||||
|
||||
You can run `apm install --check` to see if [apm][apm] can build native code on
|
||||
your machine.
|
||||
|
||||
Check out the pre-requisites in the [build instructions][build-instructions] for
|
||||
your platform for more details.
|
||||
|
||||
[apm]: https://github.com/atom/apm
|
||||
[build-instructions]: https://github.com/atom/atom/tree/master/docs/build-instructions
|
||||
[submitting issues]: https://github.com/atom/atom/blob/master/CONTRIBUTING.md#submitting-issues
|
||||
[building atom]: https://github.com/atom/atom#building
|
||||
[atom releases]: https://github.com/atom/atom/releases
|
||||
|
||||
@@ -34,7 +34,7 @@ files. If you are using Git you can use `cmd-shift-b` to search the list of
|
||||
files modified and untracked in your project's repository.
|
||||
|
||||
You can also use the tree view to navigate to a file. To open and focus the
|
||||
the tree view, press `ctrl-0`. The tree view can be toggled open and closed with
|
||||
tree view, press `ctrl-0`. The tree view can be toggled open and closed with
|
||||
`cmd-\`.
|
||||
|
||||
#### Adding, Moving, Deleting Files
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
* [Contributing](contributing.md)
|
||||
* [Contributing to Core Packages](contributing-to-packages.md)
|
||||
* [Debugging](debugging.md)
|
||||
* [Your First Package](your-first-package.md)
|
||||
|
||||
### Advanced Topics
|
||||
|
||||
@@ -19,6 +20,8 @@
|
||||
* [Keymaps](advanced/keymaps.md)
|
||||
* [Serialization](advanced/serialization.md)
|
||||
* [Scopes and Scope Descriptors](advanced/scopes-and-scope-descriptors.md)
|
||||
* [Theme Variables](theme-variables.md)
|
||||
* [apm REST API](apm-rest-api.md)
|
||||
|
||||
### Upgrading to 1.0 APIs
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ If not, there are a few things you should check before publishing:
|
||||
|
||||
Before you publish a package it is a good idea to check ahead of time if
|
||||
a package with the same name has already been published to atom.io. You can do
|
||||
that by visiting `http://atom.io/packages/my-package` to see if the package
|
||||
that by visiting `https://atom.io/packages/my-package` to see if the package
|
||||
already exists. If it does, update your package's name to something that is
|
||||
available before proceeding.
|
||||
|
||||
@@ -73,7 +73,7 @@ and you only need to enter this information the first time you publish. The
|
||||
credentials are stored securely in your [keychain][keychain] once you login.
|
||||
|
||||
:tada: Your package is now published and available on atom.io. Head on over to
|
||||
`http://atom.io/packages/my-package` to see your package's page.
|
||||
`https://atom.io/packages/my-package` to see your package's page.
|
||||
|
||||
With `apm publish`, you can bump the version and publish by using
|
||||
```sh
|
||||
@@ -107,7 +107,7 @@ Use `patch` when you make a small change like a bug fix that does not add or rem
|
||||
[atomio]: https://atom.io
|
||||
[github]: https://github.com
|
||||
[git-tag]: http://git-scm.com/book/en/Git-Basics-Tagging
|
||||
[keychain]: http://en.wikipedia.org/wiki/Keychain_(Apple)
|
||||
[keychain]: https://en.wikipedia.org/wiki/Keychain_(Apple)
|
||||
[repo-guide]: http://guides.github.com/overviews/desktop
|
||||
[semver]: http://semver.org
|
||||
[your-first-package]: your-first-package.html
|
||||
|
||||
@@ -24,7 +24,7 @@ Here's an example `.less` file that a package can define using theme variables:
|
||||
```css
|
||||
@import "ui-variables";
|
||||
|
||||
.my-selector{
|
||||
.my-selector {
|
||||
background-color: @base-background-color;
|
||||
padding: @component-padding;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,625 @@
|
||||
# Upgrading your package to 1.0 APIs
|
||||
|
||||
Atom is rapidly approaching 1.0. Much of the effort leading up to the 1.0 has been cleaning up APIs in an attempt to future proof, and make a more pleasant experience developing packages.
|
||||
|
||||
This document will guide you through the large bits of upgrading your package to work with 1.0 APIs.
|
||||
|
||||
## TL;DR
|
||||
|
||||
We've set deprecation messages and errors in strategic places to help make sure you don't miss anything. You should be able to get 95% of the way to an updated package just by fixing errors and deprecations. There are a couple of things you can do to get the full effect of all the errors and deprecations.
|
||||
|
||||
### Use atom-space-pen-views
|
||||
|
||||
If you use any class from `require 'atom'` with a `$` or `View` in the name, add the `atom-space-pen-views` module to your package's `package.json` file's dependencies:
|
||||
|
||||
```js
|
||||
{
|
||||
"dependencies": {
|
||||
"atom-space-pen-views": "^2.0.3"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then run `apm install` in your package directory.
|
||||
|
||||
### Require views from atom-space-pen-views
|
||||
|
||||
Anywhere you are requiring one of the following from `atom` you need to require them from `atom-space-pen-views` instead.
|
||||
|
||||
```coffee
|
||||
# require these from 'atom-space-pen-views' rather than 'atom'
|
||||
$
|
||||
$$
|
||||
$$$
|
||||
View
|
||||
TextEditorView
|
||||
ScrollView
|
||||
SelectListView
|
||||
```
|
||||
|
||||
So this:
|
||||
|
||||
```coffee
|
||||
# Old way
|
||||
{$, TextEditorView, View, GitRepository} = require 'atom'
|
||||
```
|
||||
|
||||
Would be replaced by this:
|
||||
|
||||
```coffee
|
||||
# New way
|
||||
{GitRepository} = require 'atom'
|
||||
{$, TextEditorView, View} = require 'atom-space-pen-views'
|
||||
```
|
||||
|
||||
### Run specs and test your package
|
||||
|
||||
You wrote specs, right!? Here's where they shine. Run them with `cmd-shift-P`, and search for `run package specs`. It will show all the deprecation messages and errors.
|
||||
|
||||
### Update the engines field in package.json
|
||||
|
||||
When you are deprecation free and all done converting, upgrade the `engines` field in your package.json:
|
||||
|
||||
```json
|
||||
{
|
||||
"engines": {
|
||||
"atom": ">=0.174.0, <2.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
We have upgraded all the core packages. Please see [this issue](https://github.com/atom/atom/issues/4011) for a link to all the upgrade PRs.
|
||||
|
||||
## Deprecations
|
||||
|
||||
All of the methods in Atom core that have changes will emit deprecation messages when called. These messages are shown in two places: your **package specs**, and in **Deprecation Cop**.
|
||||
|
||||
### Specs
|
||||
|
||||
Just run your specs, and all the deprecations will be displayed in yellow.
|
||||
|
||||

|
||||
|
||||
### Deprecation Cop
|
||||
|
||||
Run an atom window in dev mode (`atom -d`) with your package loaded, and open Deprecation Cop (search for `deprecation` in the command palette). Deprecated methods will be appear in Deprecation Cop only after they have been called.
|
||||
|
||||

|
||||
|
||||
When deprecation cop is open, and deprecated methods are called, a `Refresh` button will appear in the top right of the Deprecation Cop interface. So exercise your package, then come back to Deprecation Cop and click the `Refresh` button.
|
||||
|
||||
## Upgrading your Views
|
||||
|
||||
Previous to 1.0, views were baked into Atom core. These views were based on jQuery and `space-pen`. They looked something like this:
|
||||
|
||||
```coffee
|
||||
# The old way: getting views from atom
|
||||
{$, TextEditorView, View} = require 'atom'
|
||||
|
||||
module.exports =
|
||||
class SomeView extends View
|
||||
@content: ->
|
||||
@div class: 'find-and-replace', =>
|
||||
@div class: 'block', =>
|
||||
@subview 'myEditor', new TextEditorView(mini: true)
|
||||
#...
|
||||
```
|
||||
|
||||
### The New
|
||||
|
||||
`require 'atom'` no longer provides view helpers or jQuery. Atom core is now 'view agnostic'. The preexisting view system is available from a new npm package: `atom-space-pen-views`.
|
||||
|
||||
`atom-space-pen-views` now provides jQuery, `space-pen` views, and Atom specific views:
|
||||
|
||||
|
||||
```coffee
|
||||
# These are now provided by atom-space-pen-views
|
||||
$
|
||||
$$
|
||||
$$$
|
||||
View
|
||||
TextEditorView
|
||||
ScrollView
|
||||
SelectListView
|
||||
```
|
||||
|
||||
### Adding the module dependencies
|
||||
|
||||
To use the new views, you need to specify the `atom-space-pen-views` module in your package's `package.json` file's dependencies:
|
||||
|
||||
```js
|
||||
{
|
||||
"dependencies": {
|
||||
"atom-space-pen-views": "^2.0.3"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`space-pen` bundles jQuery. If you do not need `space-pen` or any of the views, you can require jQuery directly.
|
||||
|
||||
```js
|
||||
{
|
||||
"dependencies": {
|
||||
"jquery": "^2"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Converting your views
|
||||
|
||||
Sometimes it is as simple as converting the requires at the top of each view page. I assume you read the 'TL;DR' section and have updated all of your requires.
|
||||
|
||||
### Upgrading classes extending any space-pen View
|
||||
|
||||
#### `afterAttach` and `beforeRemove` updated
|
||||
|
||||
The `afterAttach` and `beforeRemove` hooks have been replaced with
|
||||
`attached` and `detached` and the semantics have changed.
|
||||
|
||||
`afterAttach` was called whenever the node was attached to another DOM node, even if that parent node wasn't present in the DOM. `afterAttach` also was called with a boolean indicating whether or not the element and its parents were on the DOM. Now the `attached` hook is _only_ called when the node and all of its parents are actually on the DOM, and is not called with a boolean.
|
||||
|
||||
`beforeRemove` was only called when `$.fn.remove` was called, which was typically used when the node was completely removed from the DOM. The new `detached` hook is called whenever the DOM node is _detached_, which could happen if the node is being detached for reattachment later. In short, if `beforeRemove` is called the node is never coming back. With `detached` it might be attached again later.
|
||||
|
||||
```coffee
|
||||
# Old way
|
||||
{View} = require 'atom'
|
||||
class MyView extends View
|
||||
afterAttach: (onDom) ->
|
||||
#...
|
||||
|
||||
beforeRemove: ->
|
||||
#...
|
||||
```
|
||||
|
||||
```coffee
|
||||
# New way
|
||||
{View} = require 'atom-space-pen-views'
|
||||
class MyView extends View
|
||||
attached: ->
|
||||
# Always called with the equivalent of @afterAttach(true)!
|
||||
#...
|
||||
|
||||
detached: ->
|
||||
#...
|
||||
```
|
||||
|
||||
#### `subscribe` and `subscribeToCommand` methods removed
|
||||
|
||||
The `subscribe` and `subscribeToCommand` methods have been removed. See the Eventing and Disposables section for more info.
|
||||
|
||||
### Upgrading to the new TextEditorView
|
||||
|
||||
All of the atom-specific methods available on the `TextEditorView` have been moved to the `TextEditor`, available via `TextEditorView::getModel`. See the [`TextEditorView` docs][TextEditorView] and [`TextEditor` docs][TextEditor] for more info.
|
||||
|
||||
### Upgrading classes extending ScrollView
|
||||
|
||||
The `ScrollView` has very minor changes.
|
||||
|
||||
You can no longer use `@off` to remove default behavior for `core:move-up`, `core:move-down`, etc.
|
||||
|
||||
```coffee
|
||||
# Old way to turn off default behavior
|
||||
class ResultsView extends ScrollView
|
||||
initialize: (@model) ->
|
||||
super()
|
||||
# turn off default scrolling behavior from ScrollView
|
||||
@off 'core:move-up'
|
||||
@off 'core:move-down'
|
||||
@off 'core:move-left'
|
||||
@off 'core:move-right'
|
||||
```
|
||||
|
||||
```coffee
|
||||
# New way to turn off default behavior
|
||||
class ResultsView extends ScrollView
|
||||
initialize: (@model) ->
|
||||
disposable = super()
|
||||
# turn off default scrolling behavior from ScrollView
|
||||
disposable.dispose()
|
||||
```
|
||||
|
||||
* Check out [an example](https://github.com/atom/find-and-replace/pull/311/files#diff-9) from find-and-replace.
|
||||
* See the [docs][ScrollView] for all the options.
|
||||
|
||||
### Upgrading classes extending SelectListView
|
||||
|
||||
Your SelectListView might look something like this:
|
||||
|
||||
```coffee
|
||||
# Old!
|
||||
class CommandPaletteView extends SelectListView
|
||||
initialize: ->
|
||||
super()
|
||||
@addClass('command-palette overlay from-top')
|
||||
atom.workspaceView.command 'command-palette:toggle', => @toggle()
|
||||
|
||||
confirmed: ({name, jQuery}) ->
|
||||
@cancel()
|
||||
# do something with the result
|
||||
|
||||
toggle: ->
|
||||
if @hasParent()
|
||||
@cancel()
|
||||
else
|
||||
@attach()
|
||||
|
||||
attach: ->
|
||||
@storeFocusedElement()
|
||||
|
||||
items = [] # TODO: build items
|
||||
@setItems(items)
|
||||
|
||||
atom.workspaceView.append(this)
|
||||
@focusFilterEditor()
|
||||
|
||||
confirmed: ({name, jQuery}) ->
|
||||
@cancel()
|
||||
```
|
||||
|
||||
This attaches and detaches itself from the dom when toggled, canceling magically detaches it from the DOM, and it uses the classes `overlay` and `from-top`.
|
||||
|
||||
The new SelectListView no longer automatically detaches itself from the DOM when cancelled. It's up to you to implement whatever cancel beahavior you want. Using the new APIs to mimic the sematics of the old class, it should look like this:
|
||||
|
||||
```coffee
|
||||
# New!
|
||||
class CommandPaletteView extends SelectListView
|
||||
initialize: ->
|
||||
super()
|
||||
# no more need for the `overlay` and `from-top` classes
|
||||
@addClass('command-palette')
|
||||
atom.commands.add 'atom-workspace', 'command-palette:toggle', => @toggle()
|
||||
|
||||
# You need to implement the `cancelled` method and hide.
|
||||
cancelled: ->
|
||||
@hide()
|
||||
|
||||
confirmed: ({name, jQuery}) ->
|
||||
@cancel()
|
||||
# do something with the result
|
||||
|
||||
toggle: ->
|
||||
# Toggling now checks panel visibility,
|
||||
# and hides / shows rather than attaching to / detaching from the DOM.
|
||||
if @panel?.isVisible()
|
||||
@cancel()
|
||||
else
|
||||
@show()
|
||||
|
||||
show: ->
|
||||
# Now you will add your select list as a modal panel to the workspace
|
||||
@panel ?= atom.workspace.addModalPanel(item: this)
|
||||
@panel.show()
|
||||
|
||||
@storeFocusedElement()
|
||||
|
||||
items = [] # TODO: build items
|
||||
@setItems(items)
|
||||
|
||||
@focusFilterEditor()
|
||||
|
||||
hide: ->
|
||||
@panel?.hide()
|
||||
```
|
||||
|
||||
* And check out the [conversion of CommandPaletteView][selectlistview-example] as a real-world example.
|
||||
* See the [SelectListView docs][SelectListView] for all options.
|
||||
|
||||
## Using the model layer rather than the view layer
|
||||
|
||||
The API no longer exposes any specialized view objects or view classes. `atom.workspaceView`, and all the view classes: `WorkspaceView`, `EditorView`, `PaneView`, etc. have been globally deprecated.
|
||||
|
||||
Nearly all of the atom-specific actions performed by the old view objects can now be managed via the model layer. For example, here's adding a panel to the interface using the `atom.workspace` model instead of the `workspaceView`:
|
||||
|
||||
```coffee
|
||||
# Old!
|
||||
div = document.createElement('div')
|
||||
atom.workspaceView.appendToTop(div)
|
||||
```
|
||||
|
||||
```coffee
|
||||
# New!
|
||||
div = document.createElement('div')
|
||||
atom.workspace.addTopPanel(item: div)
|
||||
```
|
||||
|
||||
For actions that still require the view, such as dispatching commands or munging css classes, you'll access the view via the `atom.views.getView()` method. This will return a subclass of `HTMLElement` rather than a jQuery object or an instance of a deprecated view class (e.g. `WorkspaceView`).
|
||||
|
||||
```coffee
|
||||
# Old!
|
||||
workspaceView = atom.workspaceView
|
||||
editorView = workspaceView.getActiveEditorView()
|
||||
paneView = editorView.getPaneView()
|
||||
```
|
||||
|
||||
```coffee
|
||||
# New!
|
||||
# Generally, just use the models
|
||||
workspace = atom.workspace
|
||||
editor = workspace.getActiveTextEditor()
|
||||
pane = editor.getPane()
|
||||
|
||||
# If you need views, get them with `getView`
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
editorElement = atom.views.getView(editor)
|
||||
paneElement = atom.views.getView(pane)
|
||||
```
|
||||
|
||||
## Updating Specs
|
||||
|
||||
`atom.workspaceView`, the `WorkspaceView` class and the `EditorView` class have been deprecated. These two objects are used heavily throughout specs, mostly to dispatch events and commands. This section will explain how to remove them while still retaining the ability to dispatch events and commands.
|
||||
|
||||
### Removing WorkspaceView references
|
||||
|
||||
`WorkspaceView` has been deprecated. Everything you could do on the view, you can now do on the `Workspace` model.
|
||||
|
||||
Requiring `WorkspaceView` from `atom` and accessing any methods on it will throw a deprecation warning. Many specs lean heavily on `WorkspaceView` to trigger commands and fetch `EditorView` objects.
|
||||
|
||||
Your specs might contain something like this:
|
||||
|
||||
```coffee
|
||||
# Old!
|
||||
{WorkspaceView} = require 'atom'
|
||||
describe 'FindView', ->
|
||||
beforeEach ->
|
||||
atom.workspaceView = new WorkspaceView()
|
||||
```
|
||||
|
||||
Instead, we will use the `atom.views.getView()` method. This will return a plain `HTMLElement`, not a `WorkspaceView` or jQuery object.
|
||||
|
||||
```coffee
|
||||
# New!
|
||||
describe 'FindView', ->
|
||||
workspaceElement = null
|
||||
beforeEach ->
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
```
|
||||
|
||||
### Attaching the workspace to the DOM
|
||||
|
||||
The workspace needs to be attached to the DOM in some cases. For example, view hooks only work (`attached()` on `View`, `attachedCallback()` on custom elements) when there is a descendant attached to the DOM.
|
||||
|
||||
You might see this in your specs:
|
||||
|
||||
```coffee
|
||||
# Old!
|
||||
atom.workspaceView.attachToDom()
|
||||
```
|
||||
|
||||
Change it to:
|
||||
|
||||
```coffee
|
||||
# New!
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
```
|
||||
|
||||
### Removing EditorView references
|
||||
|
||||
Like `WorkspaceView`, `EditorView` has been deprecated. Everything you needed to do on the view you are now able to do on the `TextEditor` model.
|
||||
|
||||
In many cases, you will not even need to get the editor's view anymore. Any of those instances should be updated to use the `TextEditor` instance instead. You should really only need the editor's view when you plan on triggering a command on the view in a spec.
|
||||
|
||||
Your specs might contain something like this:
|
||||
|
||||
```coffee
|
||||
# Old!
|
||||
describe 'Something', ->
|
||||
[editorView] = []
|
||||
beforeEach ->
|
||||
editorView = atom.workspaceView.getActiveView()
|
||||
```
|
||||
|
||||
We're going to use `atom.views.getView()` again to get the editor element. As in the case of the `workspaceElement`, `getView` will return a subclass of `HTMLElement` rather than an `EditorView` or jQuery object.
|
||||
|
||||
```coffee
|
||||
# New!
|
||||
describe 'Something', ->
|
||||
[editor, editorElement] = []
|
||||
beforeEach ->
|
||||
editor = atom.workspace.getActiveTextEditor()
|
||||
editorElement = atom.views.getView(editor)
|
||||
```
|
||||
|
||||
### Dispatching commands
|
||||
|
||||
Since the `editorElement` objects are no longer `jQuery` objects, they no longer support `trigger()`. Additionally, Atom has a new command dispatcher, `atom.commands`, that we use rather than commandeering jQuery's `trigger` method.
|
||||
|
||||
From this:
|
||||
|
||||
```coffee
|
||||
# Old!
|
||||
workspaceView.trigger 'a-package:toggle'
|
||||
editorView.trigger 'find-and-replace:show'
|
||||
```
|
||||
|
||||
To this:
|
||||
|
||||
```coffee
|
||||
# New!
|
||||
atom.commands.dispatch workspaceElement, 'a-package:toggle'
|
||||
atom.commands.dispatch editorElement, 'find-and-replace:show'
|
||||
```
|
||||
|
||||
## Eventing and Disposables
|
||||
|
||||
A couple large things changed with respect to events:
|
||||
|
||||
1. All model events are now exposed as event subscription methods that return [`Disposable`][disposable] objects
|
||||
1. The `subscribe()` method is no longer available on `space-pen` `View` objects
|
||||
1. An Emitter is now provided from `require 'atom'`
|
||||
|
||||
### Consuming Events
|
||||
|
||||
All events from the Atom API are now methods that return a [`Disposable`][disposable] object, on which you can call `dispose()` to unsubscribe.
|
||||
|
||||
```coffee
|
||||
# Old!
|
||||
editor.on 'changed', ->
|
||||
```
|
||||
|
||||
```coffee
|
||||
# New!
|
||||
disposable = editor.onDidChange ->
|
||||
|
||||
# You can unsubscribe at some point in the future via `dispose()`
|
||||
disposable.dispose()
|
||||
```
|
||||
|
||||
Deprecation warnings will guide you toward the correct methods.
|
||||
|
||||
#### Using a CompositeDisposable
|
||||
|
||||
You can group multiple disposables into a single disposable with a `CompositeDisposable`.
|
||||
|
||||
```coffee
|
||||
{CompositeDisposable} = require 'atom'
|
||||
|
||||
class Something
|
||||
constructor: ->
|
||||
editor = atom.workspace.getActiveTextEditor()
|
||||
@disposables = new CompositeDisposable
|
||||
@disposables.add editor.onDidChange ->
|
||||
@disposables.add editor.onDidChangePath ->
|
||||
|
||||
destroy: ->
|
||||
@disposables.dispose()
|
||||
```
|
||||
|
||||
### Removing View::subscribe and Subscriber::subscribe calls
|
||||
|
||||
There were a couple permutations of `subscribe()`. In these examples, a `CompositeDisposable` is used as it will commonly be useful where conversion is necessary.
|
||||
|
||||
#### subscribe(unsubscribable)
|
||||
|
||||
This one is very straight forward.
|
||||
|
||||
```coffee
|
||||
# Old!
|
||||
@subscribe editor.on 'changed', ->
|
||||
```
|
||||
|
||||
```coffee
|
||||
# New!
|
||||
disposables = new CompositeDisposable
|
||||
disposables.add editor.onDidChange ->
|
||||
```
|
||||
|
||||
#### subscribe(modelObject, event, method)
|
||||
|
||||
When the modelObject is an Atom model object, the change is very simple. Just use the correct event method, and add it to your CompositeDisposable.
|
||||
|
||||
```coffee
|
||||
# Old!
|
||||
@subscribe editor, 'changed', ->
|
||||
```
|
||||
|
||||
```coffee
|
||||
# New!
|
||||
disposables = new CompositeDisposable
|
||||
disposables.add editor.onDidChange ->
|
||||
```
|
||||
|
||||
#### subscribe(jQueryObject, selector(optional), event, method)
|
||||
|
||||
Things are a little more complicated when subscribing to a DOM or jQuery element. Atom no longer provides helpers for subscribing to elements. You can use jQuery or the native DOM APIs, whichever you prefer.
|
||||
|
||||
```coffee
|
||||
# Old!
|
||||
@subscribe $(window), 'focus', ->
|
||||
```
|
||||
|
||||
```coffee
|
||||
# New!
|
||||
{Disposable, CompositeDisposable} = require 'atom'
|
||||
disposables = new CompositeDisposable
|
||||
|
||||
# New with jQuery
|
||||
focusCallback = ->
|
||||
$(window).on 'focus', focusCallback
|
||||
disposables.add new Disposable ->
|
||||
$(window).off 'focus', focusCallback
|
||||
|
||||
# New with native APIs
|
||||
focusCallback = ->
|
||||
window.addEventListener 'focus', focusCallback
|
||||
disposables.add new Disposable ->
|
||||
window.removeEventListener 'focus', focusCallback
|
||||
```
|
||||
|
||||
### Providing Events: Using the Emitter
|
||||
|
||||
You no longer need to require `emissary` to get an emitter. We now provide an `Emitter` class from `require 'atom'`. We have a specific pattern for use of the `Emitter`. Rather than mixing it in, we instantiate a member variable, and create explicit subscription methods. For more information see the [`Emitter` docs][emitter].
|
||||
|
||||
```coffee
|
||||
# New!
|
||||
{Emitter} = require 'atom'
|
||||
|
||||
class Something
|
||||
constructor: ->
|
||||
@emitter = new Emitter
|
||||
|
||||
destroy: ->
|
||||
@emitter.dispose()
|
||||
|
||||
onDidChange: (callback) ->
|
||||
@emitter.on 'did-change', callback
|
||||
|
||||
methodThatFiresAChange: ->
|
||||
@emitter.emit 'did-change', {data: 2}
|
||||
|
||||
# Using the evented class
|
||||
something = new Something
|
||||
something.onDidChange (eventObject) ->
|
||||
console.log eventObject.data # => 2
|
||||
something.methodThatFiresAChange()
|
||||
```
|
||||
|
||||
## Subscribing To Commands
|
||||
|
||||
`$.fn.command` and `View::subscribeToCommand` are no longer available. Now we use `atom.commands.add`, and collect the results in a `CompositeDisposable`. See [the docs][commands-add] for more info.
|
||||
|
||||
```coffee
|
||||
# Old!
|
||||
atom.workspaceView.command 'core:close core:cancel', ->
|
||||
|
||||
# When inside a View class, you might see this
|
||||
@subscribeToCommand 'core:close core:cancel', ->
|
||||
```
|
||||
|
||||
```coffee
|
||||
# New!
|
||||
@disposables.add atom.commands.add 'atom-workspace',
|
||||
'core:close': ->
|
||||
'core:cancel': ->
|
||||
|
||||
# You can register commands directly on individual DOM elements in addition to
|
||||
# using selectors. When in a View class, you should have a `@element` object
|
||||
# available. `@element` is a plain HTMLElement object
|
||||
@disposables.add atom.commands.add @element,
|
||||
'core:close': ->
|
||||
'core:cancel': ->
|
||||
```
|
||||
|
||||
## Upgrading your stylesheet's selectors
|
||||
|
||||
Many selectors have changed, and we have introduced the [Shadow DOM][shadowdom] to the editor. See [Upgrading Your Package Selectors guide][upgrading-selectors] for more information in upgrading your package stylesheets.
|
||||
|
||||
## Help us improve this guide!
|
||||
|
||||
Did you hit something painful that wasn't in here? Want to reword some bit of it? Find something incorrect? Please edit [this file][guide], and send a pull request. Contributions are greatly appreciated.
|
||||
|
||||
|
||||
|
||||
|
||||
[texteditorview]:https://github.com/atom/atom-space-pen-views#texteditorview
|
||||
[scrollview]:https://github.com/atom/atom-space-pen-views#scrollview
|
||||
[selectlistview]:https://github.com/atom/atom-space-pen-views#selectlistview
|
||||
[selectlistview-example]:https://github.com/atom/command-palette/pull/19/files
|
||||
[emitter]:https://atom.io/docs/api/latest/Emitter
|
||||
[texteditor]:https://atom.io/docs/api/latest/TextEditor
|
||||
[disposable]:https://atom.io/docs/api/latest/Disposable
|
||||
[commands-add]:https://atom.io/docs/api/latest/CommandRegistry#instance-add
|
||||
[upgrading-selectors]:upgrading-your-ui-theme
|
||||
[shadowdom]:http://blog.atom.io/2014/11/18/avoiding-style-pollution-with-the-shadow-dom.html
|
||||
[guide]:https://github.com/atom/atom/blob/master/docs/upgrading/upgrading-your-package.md
|
||||
@@ -6,19 +6,16 @@ Syntax themes are specifically intended to style only text editor content, so th
|
||||
|
||||
When theme style sheets are loaded into the text editor's shadow DOM, selectors intended to target the editor from the *outside* no longer make sense. Styles targeting the `.editor` and `.editor-colors` classes instead need to target the `:host` pseudo-element, which matches against the containing `atom-text-editor` node. Check out the [Shadow DOM 201][host-pseudo-element] article for more information about the `:host` pseudo-element.
|
||||
|
||||
Here's an example from Atom's light syntax theme. Note that the previous selectors intended to target the editor from the outside have been retained to allow the theme to keep working during the transition phase when it is possible to disable the shadow DOM.
|
||||
Here's an example from Atom's light syntax theme. Note that the `atom-text-editor` selector intended to target the editor from the outside has been retained to allow the theme to keep working during the transition phase when it is possible to disable the shadow DOM.
|
||||
|
||||
```css
|
||||
.editor-colors, :host { /* :host added */
|
||||
atom-text-editor, :host { /* :host added */
|
||||
background-color: @syntax-background-color;
|
||||
color: @syntax-text-color;
|
||||
}
|
||||
|
||||
.editor, :host { /* :host added */
|
||||
.invisible-character {
|
||||
color: @syntax-invisible-character-color;
|
||||
}
|
||||
|
||||
/* more nested selectors... */
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Writing specs
|
||||
|
||||
Atom uses [Jasmine](http://jasmine.github.io/2.0/introduction.html) as its spec framework. Any new functionality should have specs to guard against regressions.
|
||||
Atom uses [Jasmine](http://jasmine.github.io/1.3/introduction.html) as its spec framework. Any new functionality should have specs to guard against regressions.
|
||||
|
||||
## Create a new spec
|
||||
|
||||
@@ -12,7 +12,7 @@ Atom uses [Jasmine](http://jasmine.github.io/2.0/introduction.html) as its spec
|
||||
|
||||
0. Add one or more `describe` methods
|
||||
|
||||
The `describe` method takes two arguments, a description and a function. If the description explains a behavior it typically begins with `when` if it is more like a unit test it begins with the method name.
|
||||
The `describe` method takes two arguments, a description and a function. If the description explains a behavior it typically begins with `when`; if it is more like a unit test it begins with the method name.
|
||||
|
||||
```coffee
|
||||
describe "when a test is written", ->
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Create 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
|
||||
selected text with [ascii art](https://en.wikipedia.org/wiki/ASCII_art). When you
|
||||
run our new command with the word "cool" selected, it will be replaced with:
|
||||
|
||||
```
|
||||
@@ -72,12 +72,12 @@ command palette or by pressing `ctrl-alt-cmd-l`.
|
||||
|
||||
Now open the command panel and search for the `ascii-art:convert` command. But
|
||||
it's not there! To fix this, open _package.json_ and find the property called
|
||||
`activationEvents`. Activation Events speed up load time by allowing Atom to
|
||||
`activationCommands`. Activation Events speed up load time by allowing Atom to
|
||||
delay a package's activation until it's needed. So remove the existing command
|
||||
and add `ascii-art:convert` to the `activationEvents` array:
|
||||
and add `ascii-art:convert` to the `activationCommands` array:
|
||||
|
||||
```json
|
||||
"activationEvents": ["ascii-art:convert"],
|
||||
"activationCommands": ["ascii-art:convert"],
|
||||
```
|
||||
|
||||
First, reload the window by running the command `window:reload`. Now when you
|
||||
@@ -88,17 +88,17 @@ run the `ascii-art:convert` command it will output 'Hello, World!'
|
||||
Now let's add a key binding to trigger the `ascii-art:convert` command. Open
|
||||
_keymaps/ascii-art.cson_ and add a key binding linking `ctrl-alt-a` to the
|
||||
`ascii-art:convert` command. You can delete the pre-existing key binding since
|
||||
you don't need it anymore. When finished, the file will look like this:
|
||||
you don't need it anymore. When finished, the file will have this:
|
||||
|
||||
```coffeescript
|
||||
'atom-text-editor':
|
||||
'cmd-alt-a': 'ascii-art:convert'
|
||||
'ctrl-alt-a': 'ascii-art:convert'
|
||||
```
|
||||
|
||||
Notice `atom-text-editor` on the first line. Just like CSS, keymap selectors
|
||||
*scope* key bindings so they only apply to specific elements. In this case, our
|
||||
binding is only active for elements matching the `atom-text-editor` selector. If
|
||||
the Tree View has focus, pressing `cmd-alt-a` won't trigger the
|
||||
the Tree View has focus, pressing `ctrl-alt-a` won't trigger the
|
||||
`ascii-art:convert` command. But if the editor has focus, the
|
||||
`ascii-art:convert` method *will* be triggered. More information on key bindings
|
||||
can be found in the [keymaps](advanced/keymaps.html) documentation.
|
||||
@@ -142,7 +142,7 @@ convert: ->
|
||||
selection.insertText("\n#{asciiArt}\n")
|
||||
```
|
||||
|
||||
Select some text in an editor window and hit `cmd-alt-a`. :tada: You're now an
|
||||
Select some text in an editor window and hit `ctrl-alt-a`. :tada: You're now an
|
||||
ASCII art professional!
|
||||
|
||||
## Further reading
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "atom",
|
||||
"productName": "Atom",
|
||||
"version": "0.171.0",
|
||||
"version": "0.178.0",
|
||||
"description": "A hackable text editor for the 21st Century.",
|
||||
"main": "./src/browser/main.js",
|
||||
"repository": {
|
||||
@@ -17,10 +17,11 @@
|
||||
"url": "http://github.com/atom/atom/raw/master/LICENSE.md"
|
||||
}
|
||||
],
|
||||
"atomShellVersion": "0.20.5",
|
||||
"atomShellVersion": "0.21.0",
|
||||
"dependencies": {
|
||||
"6to5-core": "^3.0.14",
|
||||
"async": "0.2.6",
|
||||
"atom-keymap": "^2.5.2",
|
||||
"atom-keymap": "^3.1.0",
|
||||
"bootstrap": "git+https://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372",
|
||||
"clear-cut": "0.4.0",
|
||||
"coffee-script": "1.8.0",
|
||||
@@ -28,106 +29,111 @@
|
||||
"color": "^0.7.3",
|
||||
"delegato": "^1",
|
||||
"emissary": "^1.3.1",
|
||||
"event-kit": "^1.0.1",
|
||||
"first-mate": "^2.2.4",
|
||||
"event-kit": "^1.0.2",
|
||||
"first-mate": "^3.0.0",
|
||||
"fs-plus": "^2.3.2",
|
||||
"fstream": "0.1.24",
|
||||
"fuzzaldrin": "^2.1",
|
||||
"git-utils": "^2.2",
|
||||
"git-utils": "^3.0.0",
|
||||
"grim": "1.1.0",
|
||||
"guid": "0.0.10",
|
||||
"jasmine-json": "~0.0",
|
||||
"jasmine-tagged": "^1.1.2",
|
||||
"jquery": "^2.1.1",
|
||||
"less-cache": "0.19.0",
|
||||
"less-cache": "0.21",
|
||||
"marked": "^0.3",
|
||||
"mixto": "^1",
|
||||
"mkdirp": "0.3.5",
|
||||
"nslog": "^1.0.1",
|
||||
"oniguruma": "^3.0.4",
|
||||
"nslog": "^2.0.0",
|
||||
"oniguruma": "^4.0.0",
|
||||
"optimist": "0.4.0",
|
||||
"pathwatcher": "^2.5.0",
|
||||
"pathwatcher": "^3.1.0",
|
||||
"property-accessors": "^1",
|
||||
"q": "^1.0.1",
|
||||
"random-words": "0.0.1",
|
||||
"react-atom-fork": "^0.11.4",
|
||||
"react-atom-fork": "^0.11.5",
|
||||
"reactionary-atom-fork": "^1.0.0",
|
||||
"runas": "1.0.1",
|
||||
"scandal": "1.0.3",
|
||||
"runas": "2.0.0",
|
||||
"scandal": "2.0.0",
|
||||
"scoped-property-store": "^0.16.2",
|
||||
"scrollbar-style": "^1.0.2",
|
||||
"season": "^5.0.4",
|
||||
"scrollbar-style": "^2.0.0",
|
||||
"season": "^5.1.2",
|
||||
"semver": "2.2.1",
|
||||
"serializable": "^1",
|
||||
"service-hub": "^0.1.0",
|
||||
"service-hub": "^0.2.0",
|
||||
"space-pen": "3.8.2",
|
||||
"stacktrace-parser": "0.1.1",
|
||||
"temp": "0.7.0",
|
||||
"text-buffer": "^3.8.4",
|
||||
"text-buffer": "^4.0.0",
|
||||
"theorist": "^1.0.2",
|
||||
"underscore-plus": "^1.6.6",
|
||||
"vm-compatibility-layer": "0.1.0"
|
||||
},
|
||||
"packageDependencies": {
|
||||
"atom-dark-syntax": "0.23.0",
|
||||
"atom-dark-ui": "0.43.0",
|
||||
"atom-light-syntax": "0.24.0",
|
||||
"atom-light-ui": "0.37.0",
|
||||
"base16-tomorrow-dark-theme": "0.23.0",
|
||||
"base16-tomorrow-light-theme": "0.6.0",
|
||||
"solarized-dark-syntax": "0.30.0",
|
||||
"solarized-light-syntax": "0.17.0",
|
||||
"archive-view": "0.43.0",
|
||||
"autocomplete": "0.42.0",
|
||||
"autoflow": "0.20.0",
|
||||
"autosave": "0.19.0",
|
||||
"background-tips": "0.20.0",
|
||||
"bookmarks": "0.33.0",
|
||||
"bracket-matcher": "0.67.0",
|
||||
"command-palette": "0.32.0",
|
||||
"deprecation-cop": "0.26.0",
|
||||
"dev-live-reload": "0.36.0",
|
||||
"encoding-selector": "0.14.0",
|
||||
"atom-dark-syntax": "0.26.0",
|
||||
"atom-dark-ui": "0.46.0",
|
||||
"atom-light-syntax": "0.26.0",
|
||||
"atom-light-ui": "0.40.0",
|
||||
"base16-tomorrow-dark-theme": "0.25.0",
|
||||
"base16-tomorrow-light-theme": "0.8.0",
|
||||
"one-dark-ui": "0.3.0",
|
||||
"one-dark-syntax": "0.3.0",
|
||||
"one-light-syntax": "0.3.0",
|
||||
"one-light-ui": "0.2.0",
|
||||
"solarized-dark-syntax": "0.32.0",
|
||||
"solarized-light-syntax": "0.19.0",
|
||||
"archive-view": "0.46.0",
|
||||
"autocomplete": "0.44.0",
|
||||
"autoflow": "0.21.0",
|
||||
"autosave": "0.20.0",
|
||||
"background-tips": "0.22.0",
|
||||
"bookmarks": "0.35.0",
|
||||
"bracket-matcher": "0.71.0",
|
||||
"command-palette": "0.34.0",
|
||||
"deprecation-cop": "0.34.0",
|
||||
"dev-live-reload": "0.41.0",
|
||||
"encoding-selector": "0.17.0",
|
||||
"exception-reporting": "0.21.0",
|
||||
"find-and-replace": "0.155.0",
|
||||
"fuzzy-finder": "0.64.0",
|
||||
"git-diff": "0.47.0",
|
||||
"find-and-replace": "0.156.0",
|
||||
"fuzzy-finder": "0.65.0",
|
||||
"git-diff": "0.50.0",
|
||||
"go-to-line": "0.30.0",
|
||||
"grammar-selector": "0.42.0",
|
||||
"image-view": "0.46.0",
|
||||
"incompatible-packages": "0.19.0",
|
||||
"keybinding-resolver": "0.25.0",
|
||||
"link": "0.29.0",
|
||||
"markdown-preview": "0.117.0",
|
||||
"metrics": "0.40.0",
|
||||
"notifications": "0.24.0",
|
||||
"grammar-selector": "0.44.0",
|
||||
"image-view": "0.48.0",
|
||||
"incompatible-packages": "0.21.0",
|
||||
"keybinding-resolver": "0.27.0",
|
||||
"link": "0.30.0",
|
||||
"markdown-preview": "0.133.0",
|
||||
"metrics": "0.42.0",
|
||||
"notifications": "0.26.0",
|
||||
"open-on-github": "0.32.0",
|
||||
"package-generator": "0.36.0",
|
||||
"release-notes": "0.45.0",
|
||||
"settings-view": "0.172.0",
|
||||
"snippets": "0.67.0",
|
||||
"spell-check": "0.49.0",
|
||||
"status-bar": "0.56.0",
|
||||
"styleguide": "0.41.0",
|
||||
"symbols-view": "0.77.0",
|
||||
"tabs": "0.62.0",
|
||||
"timecop": "0.26.0",
|
||||
"tree-view": "0.147.0",
|
||||
"update-package-dependencies": "0.7.0",
|
||||
"package-generator": "0.37.0",
|
||||
"release-notes": "0.47.0",
|
||||
"settings-view": "0.174.0",
|
||||
"snippets": "0.72.0",
|
||||
"spell-check": "0.54.0",
|
||||
"status-bar": "0.57.0",
|
||||
"styleguide": "0.43.0",
|
||||
"symbols-view": "0.81.0",
|
||||
"tabs": "0.64.0",
|
||||
"timecop": "0.28.0",
|
||||
"tree-view": "0.154.0",
|
||||
"update-package-dependencies": "0.8.0",
|
||||
"welcome": "0.21.0",
|
||||
"whitespace": "0.28.0",
|
||||
"wrap-guide": "0.29.0",
|
||||
"language-c": "0.37.0",
|
||||
"wrap-guide": "0.31.0",
|
||||
"language-c": "0.38.0",
|
||||
"language-clojure": "0.10.0",
|
||||
"language-coffee-script": "0.39.0",
|
||||
"language-css": "0.26.0",
|
||||
"language-gfm": "0.62.0",
|
||||
"language-css": "0.27.0",
|
||||
"language-gfm": "0.63.0",
|
||||
"language-git": "0.10.0",
|
||||
"language-go": "0.21.0",
|
||||
"language-html": "0.28.0",
|
||||
"language-hyperlink": "0.12.2",
|
||||
"language-java": "0.14.0",
|
||||
"language-javascript": "0.54.0",
|
||||
"language-json": "0.11.0",
|
||||
"language-javascript": "0.56.0",
|
||||
"language-json": "0.12.0",
|
||||
"language-less": "0.24.0",
|
||||
"language-make": "0.13.0",
|
||||
"language-mustache": "0.11.0",
|
||||
@@ -141,11 +147,11 @@
|
||||
"language-sass": "0.31.0",
|
||||
"language-shellscript": "0.12.0",
|
||||
"language-source": "0.9.0",
|
||||
"language-sql": "0.13.0",
|
||||
"language-sql": "0.14.0",
|
||||
"language-text": "0.6.0",
|
||||
"language-todo": "0.15.0",
|
||||
"language-todo": "0.16.0",
|
||||
"language-toml": "0.15.0",
|
||||
"language-xml": "0.27.0",
|
||||
"language-xml": "0.28.0",
|
||||
"language-yaml": "0.22.0"
|
||||
},
|
||||
"private": true,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
Name=Atom
|
||||
Comment=<%= description %>
|
||||
GenericName=Text Editor
|
||||
Exec=<%= installDir %>/share/atom/atom %U
|
||||
Exec=<%= executable %> %U
|
||||
Icon=<%= iconName %>
|
||||
Type=Application
|
||||
StartupNotify=true
|
||||
|
||||
|
Depois Largura: | Altura: | Tamanho: 628 KiB |
|
Depois Largura: | Altura: | Tamanho: 20 KiB |
|
Depois Largura: | Altura: | Tamanho: 944 B |
|
Depois Largura: | Altura: | Tamanho: 1.6 KiB |
|
Depois Largura: | Altura: | Tamanho: 61 KiB |
|
Depois Largura: | Altura: | Tamanho: 2.4 KiB |
|
Depois Largura: | Altura: | Tamanho: 4.5 KiB |
|
Depois Largura: | Altura: | Tamanho: 192 KiB |
|
Depois Largura: | Altura: | Tamanho: 7.0 KiB |
@@ -1,26 +1,27 @@
|
||||
Name: <%= name %>
|
||||
Version: <%= version %>
|
||||
Release: 0.1%{?dist}
|
||||
Summary: Atom is a hackable text editor for the 21st century
|
||||
Summary: <%= description %>
|
||||
License: MIT
|
||||
URL: https://atom.io/
|
||||
AutoReqProv: no # Avoid libchromiumcontent.so missing dependency
|
||||
Prefix: <%= installDir %>
|
||||
|
||||
%description
|
||||
<%= description %>
|
||||
|
||||
%install
|
||||
mkdir -p %{buildroot}/usr/local/share/atom
|
||||
cp -r /tmp/atom-build/Atom/* %{buildroot}/usr/local/share/atom
|
||||
mkdir -p %{buildroot}/usr/local/bin/
|
||||
ln -sf /usr/local/share/atom/resources/app/apm/node_modules/.bin/apm %{buildroot}/usr/local/bin/apm
|
||||
cp atom.sh %{buildroot}/usr/local/bin/atom
|
||||
chmod 755 atom.sh
|
||||
mkdir -p %{buildroot}/usr/local/share/applications/
|
||||
mv atom.desktop %{buildroot}/usr/local/share/applications/
|
||||
mkdir -p %{buildroot}/<%= installDir %>/share/atom/
|
||||
cp -r Atom/* %{buildroot}/<%= installDir %>/share/atom/
|
||||
mkdir -p %{buildroot}/<%= installDir %>/bin/
|
||||
ln -sf ../share/atom/resources/app/apm/node_modules/.bin/apm %{buildroot}/<%= installDir %>/bin/apm
|
||||
cp atom.sh %{buildroot}/<%= installDir %>/bin/atom
|
||||
chmod 755 %{buildroot}/<%= installDir %>/bin/atom
|
||||
mkdir -p %{buildroot}/<%= installDir %>/share/applications/
|
||||
cp atom.desktop %{buildroot}/<%= installDir %>/share/applications/
|
||||
|
||||
%files
|
||||
/usr/local/bin/atom
|
||||
/usr/local/bin/apm
|
||||
/usr/local/share/atom/
|
||||
/usr/local/share/applications/atom.desktop
|
||||
<%= installDir %>/bin/atom
|
||||
<%= installDir %>/bin/apm
|
||||
<%= installDir %>/share/atom/
|
||||
<%= installDir %>/share/applications/atom.desktop
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
"$0/../../app/apm/node_modules/atom-package-manager/bin/node.exe" "$0/../../app/apm/node_modules/atom-package-manager/lib/cli.js" "$@"
|
||||
"$0/../../app/apm/bin/node.exe" "$0/../../app/apm/lib/cli.js" "$@"
|
||||
|
||||
@@ -18,5 +18,5 @@ FOR %%a IN (%*) DO (
|
||||
IF "%EXPECT_OUTPUT%"=="YES" (
|
||||
"%~dp0\..\..\atom.exe" %*
|
||||
) ELSE (
|
||||
"%~dp0\..\app\apm\node_modules\atom-package-manager\bin\node.exe" "%~dp0\atom.js" %*
|
||||
"%~dp0\..\app\apm\bin\node.exe" "%~dp0\atom.js" %*
|
||||
)
|
||||
|
||||
@@ -18,5 +18,5 @@ done
|
||||
if [ $EXPECT_OUTPUT ]; then
|
||||
"$0/../../../atom.exe" "$@"
|
||||
else
|
||||
"$0/../../app/apm/node_modules/atom-package-manager/bin/node.exe" "$0/../atom.js" "$@"
|
||||
"$0/../../app/apm/bin/node.exe" "$0/../atom.js" "$@"
|
||||
fi
|
||||
|
||||
@@ -48,9 +48,9 @@ function bootstrap() {
|
||||
var dedupeNpmCommand = npmPath + npmFlags + 'dedupe';
|
||||
|
||||
if (process.argv.indexOf('--no-quiet') === -1) {
|
||||
buildInstallCommand += ' --quiet';
|
||||
apmInstallCommand += ' --quiet';
|
||||
moduleInstallCommand += ' --quiet';
|
||||
buildInstallCommand += ' --loglevel error';
|
||||
apmInstallCommand += ' --loglevel error';
|
||||
moduleInstallCommand += ' --loglevel error';
|
||||
dedupeApmCommand += ' --quiet';
|
||||
dedupeNpmCommand += ' --quiet';
|
||||
buildInstallOptions.ignoreStdout = true;
|
||||
|
||||
@@ -11,7 +11,7 @@ ARCH=`uname -m`
|
||||
|
||||
rpmdev-setuptree
|
||||
|
||||
cp -r $BUILD_DIRECTORY/Atom/* $RPM_BUILD_ROOT/BUILD
|
||||
cp -r $BUILD_DIRECTORY/Atom $RPM_BUILD_ROOT/BUILD
|
||||
cp $SPEC_FILE $RPM_BUILD_ROOT/SPECS
|
||||
cp ./atom.sh $RPM_BUILD_ROOT/BUILD
|
||||
cp $DESKTOP_FILE $RPM_BUILD_ROOT/BUILD
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
set -e
|
||||
|
||||
script/build
|
||||
script/grunt mkrpm publish-build --stack
|
||||
script/grunt mkrpm publish-build --stack --install-dir /usr
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
to5 = require '../src/6to5'
|
||||
crypto = require 'crypto'
|
||||
|
||||
describe "6to5 transpiler support", ->
|
||||
describe "::create6to5VersionAndOptionsDigest", ->
|
||||
it "returns a digest for the library version and specified options", ->
|
||||
defaultOptions =
|
||||
blacklist: [
|
||||
'useStrict'
|
||||
]
|
||||
experimental: true
|
||||
optional: [
|
||||
'asyncToGenerator'
|
||||
]
|
||||
reactCompat: true
|
||||
sourceMap: 'inline'
|
||||
version = '3.0.14'
|
||||
shasum = crypto.createHash('sha1')
|
||||
shasum.update('6to5-core', 'utf8')
|
||||
shasum.update('\0', 'utf8')
|
||||
shasum.update(version, 'utf8')
|
||||
shasum.update('\0', 'utf8')
|
||||
shasum.update('{"blacklist": ["useStrict",],"experimental": true,"optional": ["asyncToGenerator",],"reactCompat": true,"sourceMap": "inline",}')
|
||||
expectedDigest = shasum.digest('hex')
|
||||
|
||||
observedDigest = to5.create6to5VersionAndOptionsDigest(version, defaultOptions)
|
||||
expect(observedDigest).toEqual expectedDigest
|
||||
|
||||
describe "when a .js file starts with 'use 6to5';", ->
|
||||
it "transpiles it using 6to5", ->
|
||||
transpiled = require('./fixtures/6to5/single-quotes.js')
|
||||
expect(transpiled(3)).toBe 4
|
||||
|
||||
describe 'when a .js file starts with "use 6to5";', ->
|
||||
it "transpiles it using 6to5", ->
|
||||
transpiled = require('./fixtures/6to5/double-quotes.js')
|
||||
expect(transpiled(3)).toBe 4
|
||||
|
||||
describe "when a .js file does not start with 'use 6to6';", ->
|
||||
it "does not transpile it using 6to5", ->
|
||||
expect(-> require('./fixtures/6to5/invalid.js')).toThrow()
|
||||
@@ -47,9 +47,8 @@ describe "the `atom` global", ->
|
||||
updateAvailableHandler.callCount > 0
|
||||
|
||||
runs ->
|
||||
{releaseVersion, releaseNotes} = updateAvailableHandler.mostRecentCall.args[0]
|
||||
{releaseVersion} = updateAvailableHandler.mostRecentCall.args[0]
|
||||
expect(releaseVersion).toBe 'version'
|
||||
expect(releaseNotes).toBe 'notes'
|
||||
|
||||
describe "loading default config", ->
|
||||
it 'loads the default core config', ->
|
||||
|
||||
@@ -226,14 +226,44 @@ describe "Config", ->
|
||||
advanceClock(500)
|
||||
expect(atom.config.save.callCount).toBe 1
|
||||
|
||||
describe "when a 'source' and no 'scopeSelector' is given", ->
|
||||
it "removes all scoped settings with the given source", ->
|
||||
atom.config.set("foo.bar.baz", 1, scopeSelector: ".a", source: "source-a")
|
||||
atom.config.set("foo.bar.quux", 2, scopeSelector: ".b", source: "source-a")
|
||||
expect(atom.config.get("foo.bar", scope: [".a.b"])).toEqual(baz: 1, quux: 2)
|
||||
describe "when no 'scopeSelector' is given", ->
|
||||
describe "when a 'source' but no key-path is given", ->
|
||||
it "removes all scoped settings with the given source", ->
|
||||
atom.config.set("foo.bar.baz", 1, scopeSelector: ".a", source: "source-a")
|
||||
atom.config.set("foo.bar.quux", 2, scopeSelector: ".b", source: "source-a")
|
||||
expect(atom.config.get("foo.bar", scope: [".a.b"])).toEqual(baz: 1, quux: 2)
|
||||
|
||||
atom.config.unset(null, source: "source-a")
|
||||
expect(atom.config.get("foo.bar", scope: [".a"])).toEqual(baz: 0, ok: 0)
|
||||
atom.config.unset(null, source: "source-a")
|
||||
expect(atom.config.get("foo.bar", scope: [".a"])).toEqual(baz: 0, ok: 0)
|
||||
|
||||
describe "when a 'source' and a key-path is given", ->
|
||||
it "removes all scoped settings with the given source and key-path", ->
|
||||
atom.config.set("foo.bar.baz", 1)
|
||||
atom.config.set("foo.bar.baz", 2, scopeSelector: ".a", source: "source-a")
|
||||
atom.config.set("foo.bar.baz", 3, scopeSelector: ".a.b", source: "source-b")
|
||||
expect(atom.config.get("foo.bar.baz", scope: [".a.b"])).toEqual(3)
|
||||
|
||||
atom.config.unset("foo.bar.baz", source: "source-b")
|
||||
expect(atom.config.get("foo.bar.baz", scope: [".a.b"])).toEqual(2)
|
||||
expect(atom.config.get("foo.bar.baz")).toEqual(1)
|
||||
|
||||
describe "when no 'source' is given", ->
|
||||
it "removes all scoped and unscoped properties for that key-path", ->
|
||||
atom.config.setDefaults("foo.bar", baz: 100)
|
||||
|
||||
atom.config.set("foo.bar", { baz: 1, ok: 2 }, scopeSelector: ".a")
|
||||
atom.config.set("foo.bar", { baz: 11, ok: 12 }, scopeSelector: ".b")
|
||||
atom.config.set("foo.bar", { baz: 21, ok: 22 })
|
||||
|
||||
atom.config.unset("foo.bar.baz")
|
||||
|
||||
expect(atom.config.get("foo.bar.baz", scope: [".a"])).toBe 100
|
||||
expect(atom.config.get("foo.bar.baz", scope: [".b"])).toBe 100
|
||||
expect(atom.config.get("foo.bar.baz")).toBe 100
|
||||
|
||||
expect(atom.config.get("foo.bar.ok", scope: [".a"])).toBe 2
|
||||
expect(atom.config.get("foo.bar.ok", scope: [".b"])).toBe 12
|
||||
expect(atom.config.get("foo.bar.ok")).toBe 22
|
||||
|
||||
describe "when a 'scopeSelector' is given", ->
|
||||
it "restores the global default when no scoped default set", ->
|
||||
@@ -669,6 +699,26 @@ describe "Config", ->
|
||||
expect(atom.config.get("foo.bar")).toBe 'baz'
|
||||
expect(atom.config.get("foo.bar", scope: ['.source.ruby'])).toBe 'more-specific'
|
||||
|
||||
describe "when the config file does not conform to the schema", ->
|
||||
beforeEach ->
|
||||
fs.writeFileSync atom.config.configFilePath, """
|
||||
'*':
|
||||
foo:
|
||||
bar: 'omg'
|
||||
int: 'baz'
|
||||
'.source.ruby':
|
||||
foo:
|
||||
bar: 'scoped'
|
||||
int: 'nope'
|
||||
"""
|
||||
|
||||
it "validates and does not load the incorrect values", ->
|
||||
atom.config.loadUserConfig()
|
||||
expect(atom.config.get("foo.int")).toBe 12
|
||||
expect(atom.config.get("foo.bar")).toBe 'omg'
|
||||
expect(atom.config.get("foo.int", scope: ['.source.ruby'])).toBe 12
|
||||
expect(atom.config.get("foo.bar", scope: ['.source.ruby'])).toBe 'scoped'
|
||||
|
||||
describe "when the config file contains valid cson", ->
|
||||
beforeEach ->
|
||||
fs.writeFileSync(atom.config.configFilePath, "foo: bar: 'baz'")
|
||||
@@ -686,15 +736,14 @@ describe "Config", ->
|
||||
expect(observeHandler).toHaveBeenCalledWith 'baz'
|
||||
|
||||
describe "when the config file contains invalid cson", ->
|
||||
addErrorHandler = null
|
||||
beforeEach ->
|
||||
spyOn(console, 'error')
|
||||
spyOn(atom.notifications, 'addError')
|
||||
atom.notifications.onDidAddNotification addErrorHandler = jasmine.createSpy()
|
||||
fs.writeFileSync(atom.config.configFilePath, "{{{{{")
|
||||
|
||||
it "logs an error to the console and does not overwrite the config file on a subsequent save", ->
|
||||
atom.config.loadUserConfig()
|
||||
expect(console.error).toHaveBeenCalled()
|
||||
expect(atom.notifications.addError.callCount).toBe 1
|
||||
expect(addErrorHandler.callCount).toBe 1
|
||||
atom.config.set("hair", "blonde") # trigger a save
|
||||
expect(atom.config.save).not.toHaveBeenCalled()
|
||||
|
||||
@@ -876,10 +925,11 @@ describe "Config", ->
|
||||
expect(atom.config.get('foo.bar')).toBe 'newVal'
|
||||
|
||||
describe "when the config file changes to contain invalid cson", ->
|
||||
addErrorHandler = null
|
||||
beforeEach ->
|
||||
spyOn(console, 'error')
|
||||
atom.notifications.onDidAddNotification addErrorHandler = jasmine.createSpy()
|
||||
writeConfigFile("}}}")
|
||||
waitsFor "error to be logged", -> console.error.callCount > 0
|
||||
waitsFor "error to be logged", -> addErrorHandler.callCount > 0
|
||||
|
||||
it "logs a warning and does not update config data", ->
|
||||
expect(updatedHandler.callCount).toBe 0
|
||||
@@ -1076,6 +1126,62 @@ describe "Config", ->
|
||||
expect(atom.config.get('foo.bar.str', scope: ['.source.js'])).toBe 'omg'
|
||||
expect(atom.config.get('foo.bar.str', scope: ['.source.coffee'])).toBe 'ok'
|
||||
|
||||
describe 'when a schema is added after config values have been set', ->
|
||||
schema = null
|
||||
beforeEach ->
|
||||
schema =
|
||||
type: 'object'
|
||||
properties:
|
||||
int:
|
||||
type: 'integer'
|
||||
default: 2
|
||||
str:
|
||||
type: 'string'
|
||||
default: 'def'
|
||||
|
||||
it "respects the new schema when values are set", ->
|
||||
expect(atom.config.set('foo.bar.str', 'global')).toBe true
|
||||
expect(atom.config.set('foo.bar.str', 'scoped', scopeSelector: '.source.js')).toBe true
|
||||
expect(atom.config.get('foo.bar.str')).toBe 'global'
|
||||
expect(atom.config.get('foo.bar.str', scope: ['.source.js'])).toBe 'scoped'
|
||||
|
||||
expect(atom.config.set('foo.bar.noschema', 'nsGlobal')).toBe true
|
||||
expect(atom.config.set('foo.bar.noschema', 'nsScoped', scopeSelector: '.source.js')).toBe true
|
||||
expect(atom.config.get('foo.bar.noschema')).toBe 'nsGlobal'
|
||||
expect(atom.config.get('foo.bar.noschema', scope: ['.source.js'])).toBe 'nsScoped'
|
||||
|
||||
expect(atom.config.set('foo.bar.int', 'nope')).toBe true
|
||||
expect(atom.config.set('foo.bar.int', 'notanint', scopeSelector: '.source.js')).toBe true
|
||||
expect(atom.config.set('foo.bar.int', 23, scopeSelector: '.source.coffee')).toBe true
|
||||
expect(atom.config.get('foo.bar.int')).toBe 'nope'
|
||||
expect(atom.config.get('foo.bar.int', scope: ['.source.js'])).toBe 'notanint'
|
||||
expect(atom.config.get('foo.bar.int', scope: ['.source.coffee'])).toBe 23
|
||||
|
||||
atom.config.setSchema('foo.bar', schema)
|
||||
|
||||
expect(atom.config.get('foo.bar.str')).toBe 'global'
|
||||
expect(atom.config.get('foo.bar.str', scope: ['.source.js'])).toBe 'scoped'
|
||||
expect(atom.config.get('foo.bar.noschema')).toBe 'nsGlobal'
|
||||
expect(atom.config.get('foo.bar.noschema', scope: ['.source.js'])).toBe 'nsScoped'
|
||||
|
||||
expect(atom.config.get('foo.bar.int')).toBe 2
|
||||
expect(atom.config.get('foo.bar.int', scope: ['.source.js'])).toBe 2
|
||||
expect(atom.config.get('foo.bar.int', scope: ['.source.coffee'])).toBe 23
|
||||
|
||||
it "sets all values that adhere to the schema", ->
|
||||
expect(atom.config.set('foo.bar.int', 10)).toBe true
|
||||
expect(atom.config.set('foo.bar.int', 15, scopeSelector: '.source.js')).toBe true
|
||||
expect(atom.config.set('foo.bar.int', 23, scopeSelector: '.source.coffee')).toBe true
|
||||
expect(atom.config.get('foo.bar.int')).toBe 10
|
||||
expect(atom.config.get('foo.bar.int', scope: ['.source.js'])).toBe 15
|
||||
expect(atom.config.get('foo.bar.int', scope: ['.source.coffee'])).toBe 23
|
||||
|
||||
atom.config.setSchema('foo.bar', schema)
|
||||
|
||||
expect(atom.config.get('foo.bar.int')).toBe 10
|
||||
expect(atom.config.get('foo.bar.int', scope: ['.source.js'])).toBe 15
|
||||
expect(atom.config.get('foo.bar.int', scope: ['.source.coffee'])).toBe 23
|
||||
|
||||
describe 'when the value has an "integer" type', ->
|
||||
beforeEach ->
|
||||
schema =
|
||||
@@ -1363,6 +1469,14 @@ describe "Config", ->
|
||||
atom.config.set('foo.bar.aColor', false)
|
||||
expect(atom.config.get('foo.bar.aColor')).toEqual {red: 255, green: 255, blue: 255, alpha: 1}
|
||||
|
||||
it "returns a clone of the Color when returned in a parent object", ->
|
||||
color1 = atom.config.get('foo.bar').aColor
|
||||
color2 = atom.config.get('foo.bar').aColor
|
||||
expect(color1.toRGBAString()).toBe 'rgba(255, 255, 255, 1)'
|
||||
expect(color2.toRGBAString()).toBe 'rgba(255, 255, 255, 1)'
|
||||
expect(color1).not.toBe color2
|
||||
expect(color1).toEqual color2
|
||||
|
||||
describe 'when the `enum` key is used', ->
|
||||
beforeEach ->
|
||||
schema =
|
||||
|
||||
@@ -351,11 +351,16 @@ describe "DisplayBuffer", ->
|
||||
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toMatch /^10/
|
||||
|
||||
describe "when there is another display buffer pointing to the same buffer", ->
|
||||
it "does not create folds in the other display buffer", ->
|
||||
it "does not consider folds to be nested inside of folds from the other display buffer", ->
|
||||
otherDisplayBuffer = new DisplayBuffer({buffer, tabLength})
|
||||
otherDisplayBuffer.createFold(1, 5)
|
||||
|
||||
displayBuffer.createFold(2, 4)
|
||||
expect(otherDisplayBuffer.foldsStartingAtBufferRow(2).length).toBe 0
|
||||
|
||||
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe '2'
|
||||
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toBe '5'
|
||||
|
||||
describe "when the buffer changes", ->
|
||||
[fold1, fold2] = []
|
||||
beforeEach ->
|
||||
@@ -1058,7 +1063,7 @@ describe "DisplayBuffer", ->
|
||||
[marker, decoration, decorationProperties] = []
|
||||
beforeEach ->
|
||||
marker = displayBuffer.markBufferRange([[2, 13], [3, 15]])
|
||||
decorationProperties = {type: 'gutter', class: 'one'}
|
||||
decorationProperties = {type: 'line-number', class: 'one'}
|
||||
decoration = displayBuffer.decorateMarker(marker, decorationProperties)
|
||||
|
||||
it "can add decorations associated with markers and remove them", ->
|
||||
@@ -1079,11 +1084,11 @@ describe "DisplayBuffer", ->
|
||||
describe "when a decoration is updated via Decoration::update()", ->
|
||||
it "emits an 'updated' event containing the new and old params", ->
|
||||
decoration.onDidChangeProperties updatedSpy = jasmine.createSpy()
|
||||
decoration.setProperties type: 'gutter', class: 'two'
|
||||
decoration.setProperties type: 'line-number', class: 'two'
|
||||
|
||||
{oldProperties, newProperties} = updatedSpy.mostRecentCall.args[0]
|
||||
expect(oldProperties).toEqual decorationProperties
|
||||
expect(newProperties).toEqual type: 'gutter', class: 'two', id: decoration.id
|
||||
expect(newProperties).toEqual type: 'line-number', class: 'two', id: decoration.id
|
||||
|
||||
describe "::getDecorations(properties)", ->
|
||||
it "returns decorations matching the given optional properties", ->
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
"use 6to5";
|
||||
|
||||
module.exports = v => v + 1
|
||||
@@ -0,0 +1,3 @@
|
||||
'use 6to6';
|
||||
|
||||
module.exports = v => v + 1
|
||||
@@ -0,0 +1,3 @@
|
||||
'use 6to5';
|
||||
|
||||
module.exports = v => v + 1
|
||||
@@ -0,0 +1,10 @@
|
||||
module.exports =
|
||||
activate: ->
|
||||
|
||||
deactivate: ->
|
||||
|
||||
consumeFirstServiceV3: ->
|
||||
|
||||
consumeFirstServiceV4: ->
|
||||
|
||||
consumeSecondService: ->
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "package-with-consumed-services",
|
||||
|
||||
"consumedServices": {
|
||||
"service-1": {
|
||||
"versions": {
|
||||
">=0.2 <=0.3.6": "consumeFirstServiceV3",
|
||||
"^0.4.1": "consumeFirstServiceV4"
|
||||
}
|
||||
},
|
||||
"service-2": {
|
||||
"versions": {
|
||||
"0.2.1 || 0.2.2": "consumeSecondService"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
class TestItem
|
||||
getUri: -> "test"
|
||||
|
||||
exports.activate = ->
|
||||
atom.workspace.addOpener -> new TestItem
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "package-with-invalid-styles",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{
|
||||
@@ -0,0 +1,13 @@
|
||||
module.exports =
|
||||
activate: ->
|
||||
|
||||
deactivate: ->
|
||||
|
||||
provideFirstServiceV3: ->
|
||||
'first-service-v3'
|
||||
|
||||
provideFirstServiceV4: ->
|
||||
'first-service-v4'
|
||||
|
||||
provideSecondService: ->
|
||||
'second-service'
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "package-with-provided-services",
|
||||
|
||||
"providedServices": {
|
||||
"service-1": {
|
||||
"description": "The first service",
|
||||
"versions": {
|
||||
"0.3.1": "provideFirstServiceV3",
|
||||
"0.4.1": "provideFirstServiceV4"
|
||||
}
|
||||
},
|
||||
"service-2": {
|
||||
"description": "The second service",
|
||||
"versions": {
|
||||
"0.2.1": "provideSecondService"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"theme": "ui",
|
||||
"stylesheets": ["editor.less"]
|
||||
"styleSheets": ["editor.less"]
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"theme": "syntax",
|
||||
"stylesheets": ["editor.less"]
|
||||
"styleSheets": ["editor.less"]
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"theme": "ui",
|
||||
"stylesheets": ["editor.less"]
|
||||
"styleSheets": ["editor.less"]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script wraps the `Atom` binary, allowing the `chromedriver` server to
|
||||
# execute it with positional arguments. `chromedriver` only allows 'switches'
|
||||
# to be specified when starting a browser, not positional arguments, so this
|
||||
# script accepts two special switches:
|
||||
#
|
||||
# * `atom-path` The path to the `Atom` binary
|
||||
# * `atom-args` A space-separated list of positional arguments to pass to Atom.
|
||||
#
|
||||
# Any other switches will be passed through to `Atom`.
|
||||
|
||||
atom_path=""
|
||||
atom_switches=()
|
||||
atom_args=()
|
||||
|
||||
for arg in "$@"; do
|
||||
case $arg in
|
||||
--atom-path=*)
|
||||
atom_path="${arg#*=}"
|
||||
;;
|
||||
|
||||
--atom-args=*)
|
||||
atom_args_string="${arg#*=}"
|
||||
for atom_arg in $atom_args_string; do
|
||||
atom_args+=($atom_arg)
|
||||
done
|
||||
;;
|
||||
|
||||
*)
|
||||
atom_switches+=($arg)
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
exec $atom_path "${atom_switches[@]}" "${atom_args[@]}"
|
||||
@@ -0,0 +1,107 @@
|
||||
# These tests are excluded by default. To run them from the command line:
|
||||
#
|
||||
# ATOM_INTEGRATION_TESTS_ENABLED=true apm test
|
||||
return unless process.env.ATOM_INTEGRATION_TESTS_ENABLED
|
||||
|
||||
os = require "os"
|
||||
fs = require "fs"
|
||||
path = require "path"
|
||||
remote = require "remote"
|
||||
temp = require("temp").track()
|
||||
{spawn, spawnSync} = require "child_process"
|
||||
{Builder, By} = require "../../build/node_modules/selenium-webdriver"
|
||||
|
||||
AtomPath = remote.process.argv[0]
|
||||
AtomLauncherPath = path.join(__dirname, "helpers", "atom-launcher.sh")
|
||||
SocketPath = path.join(os.tmpdir(), "atom-integration-test.sock")
|
||||
ChromeDriverPort = 9515
|
||||
|
||||
describe "Starting Atom", ->
|
||||
[chromeDriver, driver, tempDirPath] = []
|
||||
|
||||
beforeEach ->
|
||||
tempDirPath = temp.mkdirSync("empty-dir")
|
||||
|
||||
waitsFor "chromedriver to start", (done) ->
|
||||
chromeDriver = spawn "chromedriver", ["--verbose", "--port=#{ChromeDriverPort}"]
|
||||
chromeDriver.on "error", (error) ->
|
||||
throw new Error("chromedriver failed to start: #{error.message}")
|
||||
chromeDriver.stdout.on "data", -> done()
|
||||
|
||||
afterEach ->
|
||||
waitsForPromise -> driver.quit().thenFinally(-> chromeDriver.kill())
|
||||
|
||||
startAtom = (args...) ->
|
||||
driver = new Builder()
|
||||
.usingServer("http://localhost:#{ChromeDriverPort}")
|
||||
.withCapabilities(
|
||||
chromeOptions:
|
||||
binary: AtomLauncherPath
|
||||
args: [
|
||||
"atom-path=#{AtomPath}"
|
||||
"atom-args=#{args.join(" ")}"
|
||||
"dev"
|
||||
"safe"
|
||||
"user-data-dir=#{temp.mkdirSync('integration-spec-')}"
|
||||
"socket-path=#{SocketPath}"
|
||||
]
|
||||
)
|
||||
.forBrowser('atom')
|
||||
.build()
|
||||
|
||||
waitsForPromise ->
|
||||
driver.wait ->
|
||||
driver.getTitle().then (title) -> title.indexOf("Atom") >= 0
|
||||
|
||||
startAnotherAtom = (args...) ->
|
||||
spawnSync(AtomPath, args.concat([
|
||||
"--dev",
|
||||
"--safe",
|
||||
"--socket-path=#{SocketPath}"
|
||||
]))
|
||||
|
||||
describe "when given the name of a file that doesn't exist", ->
|
||||
tempFilePath = null
|
||||
|
||||
beforeEach ->
|
||||
tempFilePath = path.join(tempDirPath, "an-existing-file")
|
||||
fs.writeFileSync(tempFilePath, "This was already here.")
|
||||
startAtom(path.join(tempDirPath, "new-file"))
|
||||
|
||||
it "opens a new window with an empty text editor", ->
|
||||
waitsForPromise ->
|
||||
driver.getAllWindowHandles().then (handles) ->
|
||||
expect(handles.length).toBe 1
|
||||
driver.executeScript(-> atom.workspace.getActivePane().getItems().length).then (length) ->
|
||||
expect(length).toBe 1
|
||||
driver.executeScript(-> atom.workspace.getActiveTextEditor().getText()).then (text) ->
|
||||
expect(text).toBe("")
|
||||
driver.findElement(By.tagName("atom-text-editor")).sendKeys("Hello world!")
|
||||
driver.executeScript(-> atom.workspace.getActiveTextEditor().getText()).then (text) ->
|
||||
expect(text).toBe "Hello world!"
|
||||
|
||||
# Opening another existing file in the same directory reuses the window,
|
||||
# and opens a new tab for the file.
|
||||
waitsForPromise ->
|
||||
startAnotherAtom(tempFilePath)
|
||||
driver.wait ->
|
||||
driver.executeScript(-> atom.workspace.getActivePane().getItems().length).then (length) ->
|
||||
length is 2
|
||||
driver.executeScript(-> atom.workspace.getActiveTextEditor().getText()).then (text) ->
|
||||
expect(text).toBe "This was already here."
|
||||
|
||||
# Opening a different directory creates a new window.
|
||||
waitsForPromise ->
|
||||
startAnotherAtom(temp.mkdirSync("another-empty-dir"))
|
||||
driver.wait ->
|
||||
driver.getAllWindowHandles().then (handles) ->
|
||||
handles.length is 2
|
||||
|
||||
describe "when given the name of a directory that exists", ->
|
||||
beforeEach ->
|
||||
startAtom(tempDirPath)
|
||||
|
||||
it "opens a new window no text editors open", ->
|
||||
waitsForPromise ->
|
||||
driver.executeScript(-> atom.workspace.getActiveTextEditor()).then (editor) ->
|
||||
expect(editor).toBeNull()
|
||||
@@ -1,5 +1,6 @@
|
||||
{$, $$} = require '../src/space-pen-extensions'
|
||||
Package = require '../src/package'
|
||||
{Disposable} = require 'atom'
|
||||
|
||||
describe "PackageManager", ->
|
||||
workspaceElement = null
|
||||
@@ -22,6 +23,12 @@ describe "PackageManager", ->
|
||||
expect(pack instanceof Package).toBe true
|
||||
expect(pack.metadata.name).toBe "package-with-broken-keymap"
|
||||
|
||||
it "returns the package if it has an invalid stylesheet", ->
|
||||
pack = atom.packages.loadPackage("package-with-invalid-styles")
|
||||
expect(pack instanceof Package).toBe true
|
||||
expect(pack.metadata.name).toBe "package-with-invalid-styles"
|
||||
expect(pack.stylesheets.length).toBe 0
|
||||
|
||||
it "returns null if the package has an invalid package.json", ->
|
||||
spyOn(console, 'warn')
|
||||
expect(atom.packages.loadPackage("package-with-broken-package-json")).toBeNull()
|
||||
@@ -445,6 +452,47 @@ describe "PackageManager", ->
|
||||
runs ->
|
||||
expect(atom.config.get 'editor.increaseIndentPattern', scope: ['.source.omg']).toBe '^a'
|
||||
|
||||
describe "service registration", ->
|
||||
it "registers the package's provided and consumed services", ->
|
||||
consumerModule = require "./fixtures/packages/package-with-consumed-services"
|
||||
firstServiceV3Disposed = false
|
||||
firstServiceV4Disposed = false
|
||||
secondServiceDisposed = false
|
||||
spyOn(consumerModule, 'consumeFirstServiceV3').andReturn(new Disposable -> firstServiceV3Disposed = true)
|
||||
spyOn(consumerModule, 'consumeFirstServiceV4').andReturn(new Disposable -> firstServiceV4Disposed = true)
|
||||
spyOn(consumerModule, 'consumeSecondService').andReturn(new Disposable -> secondServiceDisposed = true)
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-with-consumed-services")
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-with-provided-services")
|
||||
|
||||
runs ->
|
||||
expect(consumerModule.consumeFirstServiceV3).toHaveBeenCalledWith('first-service-v3')
|
||||
expect(consumerModule.consumeFirstServiceV4).toHaveBeenCalledWith('first-service-v4')
|
||||
expect(consumerModule.consumeSecondService).toHaveBeenCalledWith('second-service')
|
||||
|
||||
consumerModule.consumeFirstServiceV3.reset()
|
||||
consumerModule.consumeFirstServiceV4.reset()
|
||||
consumerModule.consumeSecondService.reset()
|
||||
|
||||
atom.packages.deactivatePackage("package-with-provided-services")
|
||||
|
||||
expect(firstServiceV3Disposed).toBe true
|
||||
expect(firstServiceV4Disposed).toBe true
|
||||
expect(secondServiceDisposed).toBe true
|
||||
|
||||
atom.packages.deactivatePackage("package-with-consumed-services")
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-with-provided-services")
|
||||
|
||||
runs ->
|
||||
expect(consumerModule.consumeFirstServiceV3).not.toHaveBeenCalled()
|
||||
expect(consumerModule.consumeFirstServiceV4).not.toHaveBeenCalled()
|
||||
expect(consumerModule.consumeSecondService).not.toHaveBeenCalled()
|
||||
|
||||
describe "::deactivatePackage(id)", ->
|
||||
afterEach ->
|
||||
atom.packages.unloadPackages()
|
||||
|
||||
@@ -37,6 +37,32 @@ describe "Project", ->
|
||||
deserializedProject.getBuffers()[0].destroy()
|
||||
expect(deserializedProject.getBuffers().length).toBe 0
|
||||
|
||||
|
||||
it "does not deserialize buffers when their path is a directory that exists", ->
|
||||
pathToOpen = path.join(temp.mkdirSync(), 'file.txt')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open(pathToOpen)
|
||||
|
||||
runs ->
|
||||
expect(atom.project.getBuffers().length).toBe 1
|
||||
fs.mkdirSync(pathToOpen)
|
||||
deserializedProject = atom.project.testSerialization()
|
||||
expect(deserializedProject.getBuffers().length).toBe 0
|
||||
|
||||
it "does not deserialize buffers when their path is inaccessible", ->
|
||||
pathToOpen = path.join(temp.mkdirSync(), 'file.txt')
|
||||
fs.writeFileSync(pathToOpen, '')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open(pathToOpen)
|
||||
|
||||
runs ->
|
||||
expect(atom.project.getBuffers().length).toBe 1
|
||||
fs.chmodSync(pathToOpen, '000')
|
||||
deserializedProject = atom.project.testSerialization()
|
||||
expect(deserializedProject.getBuffers().length).toBe 0
|
||||
|
||||
describe "when an editor is saved and the project has no path", ->
|
||||
it "sets the project's path to the saved file's parent directory", ->
|
||||
tempFile = temp.openSync().path
|
||||
@@ -51,6 +77,29 @@ describe "Project", ->
|
||||
editor.saveAs(tempFile)
|
||||
expect(atom.project.getPaths()[0]).toBe path.dirname(tempFile)
|
||||
|
||||
describe "when a watch error is thrown from the TextBuffer", ->
|
||||
editor = null
|
||||
beforeEach ->
|
||||
waitsForPromise ->
|
||||
atom.project.open(require.resolve('./fixtures/dir/a')).then (o) -> editor = o
|
||||
|
||||
it "creates a warning notification", ->
|
||||
atom.notifications.onDidAddNotification noteSpy = jasmine.createSpy()
|
||||
|
||||
error = new Error('SomeError')
|
||||
error.eventType = 'resurrect'
|
||||
editor.buffer.emitter.emit 'will-throw-watch-error',
|
||||
handle: jasmine.createSpy()
|
||||
error: error
|
||||
|
||||
expect(noteSpy).toHaveBeenCalled()
|
||||
|
||||
notification = noteSpy.mostRecentCall.args[0]
|
||||
expect(notification.getType()).toBe 'warning'
|
||||
expect(notification.getDetail()).toBe 'SomeError'
|
||||
expect(notification.getMessage()).toContain '`resurrect`'
|
||||
expect(notification.getMessage()).toContain 'fixtures/dir/a'
|
||||
|
||||
describe ".open(path)", ->
|
||||
[absolutePath, newBufferHandler] = []
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ Config = require '../src/config'
|
||||
{Point} = require 'text-buffer'
|
||||
Project = require '../src/project'
|
||||
Workspace = require '../src/workspace'
|
||||
ServiceHub = require 'service-hub'
|
||||
TextEditor = require '../src/text-editor'
|
||||
TextEditorView = require '../src/text-editor-view'
|
||||
TextEditorElement = require '../src/text-editor-element'
|
||||
@@ -77,6 +78,7 @@ beforeEach ->
|
||||
projectPath = specProjectPath ? path.join(@specDirectory, 'fixtures')
|
||||
atom.project = new Project(paths: [projectPath])
|
||||
atom.workspace = new Workspace()
|
||||
atom.packages.serviceHub = new ServiceHub
|
||||
atom.keymaps.keyBindings = _.clone(keyBindingsToRestore)
|
||||
atom.commands.restoreSnapshot(commandsToRestore)
|
||||
atom.styles.restoreSnapshot(styleElementsToRestore)
|
||||
@@ -213,6 +215,11 @@ jasmine.snapshotDeprecations = ->
|
||||
jasmine.restoreDeprecationsSnapshot = ->
|
||||
Grim.deprecations = deprecationsSnapshot
|
||||
|
||||
jasmine.useRealClock = ->
|
||||
jasmine.unspy(window, 'setTimeout')
|
||||
jasmine.unspy(window, 'clearTimeout')
|
||||
jasmine.unspy(_._, 'now')
|
||||
|
||||
addCustomMatchers = (spec) ->
|
||||
spec.addMatchers
|
||||
toBeInstanceOf: (expected) ->
|
||||
@@ -298,13 +305,13 @@ window.waitsForPromise = (args...) ->
|
||||
window.waitsFor timeout, (moveOn) ->
|
||||
promise = fn()
|
||||
if shouldReject
|
||||
promise.fail(moveOn)
|
||||
promise.done ->
|
||||
(promise.catch ? promise.thenCatch).call(promise, moveOn)
|
||||
promise.then ->
|
||||
jasmine.getEnv().currentSpec.fail("Expected promise to be rejected, but it was resolved")
|
||||
moveOn()
|
||||
else
|
||||
promise.done(moveOn)
|
||||
promise.fail (error) ->
|
||||
promise.then(moveOn)
|
||||
(promise.catch ? promise.thenCatch).call promise, (error) ->
|
||||
jasmine.getEnv().currentSpec.fail("Expected promise to be resolved, but it was rejected with #{jasmine.pp(error)}")
|
||||
moveOn()
|
||||
|
||||
|
||||
@@ -374,6 +374,22 @@ describe "TextEditorComponent", ->
|
||||
expect(line2LeafNodes[2].textContent).toBe ' '
|
||||
expect(line2LeafNodes[2].classList.contains('indent-guide')).toBe true
|
||||
|
||||
it "renders indent guides correctly on lines containing only whitespace when invisibles are enabled", ->
|
||||
atom.config.set 'editor.showInvisibles', true
|
||||
atom.config.set 'editor.invisibles', space: '-', eol: 'x'
|
||||
editor.getBuffer().insert([1, Infinity], '\n ')
|
||||
nextAnimationFrame()
|
||||
|
||||
line2LeafNodes = getLeafNodes(component.lineNodeForScreenRow(2))
|
||||
expect(line2LeafNodes.length).toBe 4
|
||||
expect(line2LeafNodes[0].textContent).toBe '--'
|
||||
expect(line2LeafNodes[0].classList.contains('indent-guide')).toBe true
|
||||
expect(line2LeafNodes[1].textContent).toBe '--'
|
||||
expect(line2LeafNodes[1].classList.contains('indent-guide')).toBe true
|
||||
expect(line2LeafNodes[2].textContent).toBe '--'
|
||||
expect(line2LeafNodes[2].classList.contains('indent-guide')).toBe true
|
||||
expect(line2LeafNodes[3].textContent).toBe 'x'
|
||||
|
||||
it "does not render indent guides in trailing whitespace for lines containing non whitespace characters", ->
|
||||
editor.getBuffer().setText " hi "
|
||||
nextAnimationFrame()
|
||||
@@ -931,7 +947,7 @@ describe "TextEditorComponent", ->
|
||||
|
||||
beforeEach ->
|
||||
marker = editor.displayBuffer.markBufferRange([[2, 13], [3, 15]], invalidate: 'inside')
|
||||
decorationParams = {type: ['gutter', 'line'], class: 'a'}
|
||||
decorationParams = {type: ['line-number', 'line'], class: 'a'}
|
||||
decoration = editor.decorateMarker(marker, decorationParams)
|
||||
nextAnimationFrame()
|
||||
|
||||
@@ -946,7 +962,7 @@ describe "TextEditorComponent", ->
|
||||
|
||||
# Add decorations that are out of range
|
||||
marker2 = editor.displayBuffer.markBufferRange([[9, 0], [9, 0]])
|
||||
editor.decorateMarker(marker2, type: ['gutter', 'line'], class: 'b')
|
||||
editor.decorateMarker(marker2, type: ['line-number', 'line'], class: 'b')
|
||||
nextAnimationFrame()
|
||||
|
||||
# Scroll decorations into view
|
||||
@@ -970,7 +986,7 @@ describe "TextEditorComponent", ->
|
||||
|
||||
marker.destroy()
|
||||
marker = editor.markBufferRange([[0, 0], [0, 2]])
|
||||
editor.decorateMarker(marker, type: ['gutter', 'line'], class: 'b')
|
||||
editor.decorateMarker(marker, type: ['line-number', 'line'], class: 'b')
|
||||
nextAnimationFrame()
|
||||
expect(lineNumberHasClass(0, 'b')).toBe true
|
||||
expect(lineNumberHasClass(1, 'b')).toBe false
|
||||
@@ -1039,7 +1055,7 @@ describe "TextEditorComponent", ->
|
||||
|
||||
describe "when the decoration's 'onlyHead' property is true", ->
|
||||
it "only applies the decoration's class to lines containing the marker's head", ->
|
||||
editor.decorateMarker(marker, type: ['gutter', 'line'], class: 'only-head', onlyHead: true)
|
||||
editor.decorateMarker(marker, type: ['line-number', 'line'], class: 'only-head', onlyHead: true)
|
||||
nextAnimationFrame()
|
||||
expect(lineAndLineNumberHaveClass(1, 'only-head')).toBe false
|
||||
expect(lineAndLineNumberHaveClass(2, 'only-head')).toBe false
|
||||
@@ -1048,7 +1064,7 @@ describe "TextEditorComponent", ->
|
||||
|
||||
describe "when the decoration's 'onlyEmpty' property is true", ->
|
||||
it "only applies the decoration when its marker is empty", ->
|
||||
editor.decorateMarker(marker, type: ['gutter', 'line'], class: 'only-empty', onlyEmpty: true)
|
||||
editor.decorateMarker(marker, type: ['line-number', 'line'], class: 'only-empty', onlyEmpty: true)
|
||||
nextAnimationFrame()
|
||||
expect(lineAndLineNumberHaveClass(2, 'only-empty')).toBe false
|
||||
expect(lineAndLineNumberHaveClass(3, 'only-empty')).toBe false
|
||||
@@ -1060,7 +1076,7 @@ describe "TextEditorComponent", ->
|
||||
|
||||
describe "when the decoration's 'onlyNonEmpty' property is true", ->
|
||||
it "only applies the decoration when its marker is non-empty", ->
|
||||
editor.decorateMarker(marker, type: ['gutter', 'line'], class: 'only-non-empty', onlyNonEmpty: true)
|
||||
editor.decorateMarker(marker, type: ['line-number', 'line'], class: 'only-non-empty', onlyNonEmpty: true)
|
||||
nextAnimationFrame()
|
||||
expect(lineAndLineNumberHaveClass(2, 'only-non-empty')).toBe true
|
||||
expect(lineAndLineNumberHaveClass(3, 'only-non-empty')).toBe true
|
||||
|
||||
@@ -155,6 +155,25 @@ describe "TextEditor", ->
|
||||
expect(editor2.getSoftTabs()).toBe true
|
||||
expect(editor2.getEncoding()).toBe 'macroman'
|
||||
|
||||
it "uses scoped `core.fileEncoding` values", ->
|
||||
editor1 = null
|
||||
editor2 = null
|
||||
|
||||
atom.config.set('core.fileEncoding', 'utf16le')
|
||||
atom.config.set('core.fileEncoding', 'macroman', scopeSelector: '.js')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('a').then (o) -> editor1 = o
|
||||
|
||||
runs ->
|
||||
expect(editor1.getEncoding()).toBe 'utf16le'
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('test.js').then (o) -> editor2 = o
|
||||
|
||||
runs ->
|
||||
expect(editor2.getEncoding()).toBe 'macroman'
|
||||
|
||||
describe "title", ->
|
||||
describe ".getTitle()", ->
|
||||
it "uses the basename of the buffer's path as its title, or 'untitled' if the path is undefined", ->
|
||||
@@ -2630,12 +2649,20 @@ describe "TextEditor", ->
|
||||
atom.config.set("editor.autoIndentOnPaste", true)
|
||||
|
||||
describe "when only whitespace precedes the cursor", ->
|
||||
it "auto-indents the lines spanned by the pasted text", ->
|
||||
atom.clipboard.write("console.log(x);\nconsole.log(y);\n")
|
||||
editor.setCursorBufferPosition([5, 2])
|
||||
it "auto-indents the lines spanned by the pasted text, based on the first pasted line", ->
|
||||
expect(editor.indentationForBufferRow(5)).toBe(3)
|
||||
|
||||
atom.clipboard.write("a(x);\n b(x);\n c(x);\n", indentBasis: 0)
|
||||
editor.setCursorBufferPosition([5, 0])
|
||||
editor.pasteText()
|
||||
expect(editor.lineTextForBufferRow(5)).toBe(" console.log(x);")
|
||||
expect(editor.lineTextForBufferRow(6)).toBe(" console.log(y);")
|
||||
|
||||
# Adjust the indentation of the pasted block
|
||||
expect(editor.indentationForBufferRow(5)).toBe(3)
|
||||
expect(editor.indentationForBufferRow(6)).toBe(4)
|
||||
expect(editor.indentationForBufferRow(7)).toBe(5)
|
||||
|
||||
# Preserve the indentation of the next row
|
||||
expect(editor.indentationForBufferRow(8)).toBe(3)
|
||||
|
||||
describe "when non-whitespace characters precede the cursor", ->
|
||||
it "does not auto-indent the first line being pasted", ->
|
||||
@@ -2732,9 +2759,9 @@ describe "TextEditor", ->
|
||||
editor.setSelectedBufferRange([[1, 2], [1, Infinity]])
|
||||
editor.pasteText()
|
||||
expect(editor.lineTextForBufferRow(1)).toBe(" if (items.length <= 1) return items;")
|
||||
expect(editor.lineTextForBufferRow(2)).toBe(" ")
|
||||
expect(editor.lineTextForBufferRow(2)).toBe("")
|
||||
expect(editor.lineTextForBufferRow(3)).toBe(" if (items.length <= 1) return items;")
|
||||
expect(editor.getCursorBufferPosition()).toEqual([2, 2])
|
||||
expect(editor.getCursorBufferPosition()).toEqual([2, 0])
|
||||
|
||||
describe "when there is no selection", ->
|
||||
it "pastes the line above the cursor and retains the cursor's column", ->
|
||||
|
||||
@@ -289,69 +289,105 @@ describe "ThemeManager", ->
|
||||
# from within the theme itself
|
||||
expect($("atom-text-editor").css("background-color")).toBe "rgb(0, 152, 255)"
|
||||
|
||||
|
||||
describe "when the user stylesheet changes", ->
|
||||
describe "user stylesheet", ->
|
||||
userStylesheetPath = null
|
||||
beforeEach ->
|
||||
jasmine.snapshotDeprecations()
|
||||
|
||||
afterEach ->
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
it "reloads it", ->
|
||||
[styleElementAddedHandler, styleElementRemovedHandler] = []
|
||||
[stylesheetRemovedHandler, stylesheetAddedHandler, stylesheetsChangedHandler] = []
|
||||
userStylesheetPath = path.join(temp.mkdirSync("atom"), 'styles.less')
|
||||
fs.writeFileSync(userStylesheetPath, 'body {border-style: dotted !important;}')
|
||||
spyOn(atom.styles, 'getUserStyleSheetPath').andReturn userStylesheetPath
|
||||
|
||||
waitsForPromise ->
|
||||
themeManager.activateThemes()
|
||||
describe "when the user stylesheet changes", ->
|
||||
beforeEach ->
|
||||
jasmine.snapshotDeprecations()
|
||||
|
||||
runs ->
|
||||
atom.styles.onDidRemoveStyleElement styleElementRemovedHandler = jasmine.createSpy("styleElementRemovedHandler")
|
||||
atom.styles.onDidAddStyleElement styleElementAddedHandler = jasmine.createSpy("styleElementAddedHandler")
|
||||
afterEach ->
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
themeManager.onDidChangeStylesheets stylesheetsChangedHandler = jasmine.createSpy("stylesheetsChangedHandler")
|
||||
themeManager.onDidRemoveStylesheet stylesheetRemovedHandler = jasmine.createSpy("stylesheetRemovedHandler")
|
||||
themeManager.onDidAddStylesheet stylesheetAddedHandler = jasmine.createSpy("stylesheetAddedHandler")
|
||||
spyOn(themeManager, 'loadUserStylesheet').andCallThrough()
|
||||
it "reloads it", ->
|
||||
[styleElementAddedHandler, styleElementRemovedHandler] = []
|
||||
[stylesheetRemovedHandler, stylesheetAddedHandler, stylesheetsChangedHandler] = []
|
||||
|
||||
expect($(document.body).css('border-style')).toBe 'dotted'
|
||||
fs.writeFileSync(userStylesheetPath, 'body {border-style: dashed}')
|
||||
waitsForPromise ->
|
||||
themeManager.activateThemes()
|
||||
|
||||
waitsFor ->
|
||||
themeManager.loadUserStylesheet.callCount is 1
|
||||
runs ->
|
||||
atom.styles.onDidRemoveStyleElement styleElementRemovedHandler = jasmine.createSpy("styleElementRemovedHandler")
|
||||
atom.styles.onDidAddStyleElement styleElementAddedHandler = jasmine.createSpy("styleElementAddedHandler")
|
||||
|
||||
runs ->
|
||||
expect($(document.body).css('border-style')).toBe 'dashed'
|
||||
themeManager.onDidChangeStylesheets stylesheetsChangedHandler = jasmine.createSpy("stylesheetsChangedHandler")
|
||||
themeManager.onDidRemoveStylesheet stylesheetRemovedHandler = jasmine.createSpy("stylesheetRemovedHandler")
|
||||
themeManager.onDidAddStylesheet stylesheetAddedHandler = jasmine.createSpy("stylesheetAddedHandler")
|
||||
spyOn(themeManager, 'loadUserStylesheet').andCallThrough()
|
||||
|
||||
expect(styleElementRemovedHandler).toHaveBeenCalled()
|
||||
expect(styleElementRemovedHandler.argsForCall[0][0].textContent).toContain 'dotted'
|
||||
expect(stylesheetRemovedHandler).toHaveBeenCalled()
|
||||
expect(stylesheetRemovedHandler.argsForCall[0][0].cssRules[0].style.border).toBe 'dotted'
|
||||
expect($(document.body).css('border-style')).toBe 'dotted'
|
||||
fs.writeFileSync(userStylesheetPath, 'body {border-style: dashed}')
|
||||
|
||||
expect(styleElementAddedHandler).toHaveBeenCalled()
|
||||
expect(styleElementAddedHandler.argsForCall[0][0].textContent).toContain 'dashed'
|
||||
expect(stylesheetAddedHandler).toHaveBeenCalled()
|
||||
expect(stylesheetAddedHandler.argsForCall[0][0].cssRules[0].style.border).toBe 'dashed'
|
||||
waitsFor ->
|
||||
themeManager.loadUserStylesheet.callCount is 1
|
||||
|
||||
expect(stylesheetsChangedHandler).toHaveBeenCalled()
|
||||
runs ->
|
||||
expect($(document.body).css('border-style')).toBe 'dashed'
|
||||
|
||||
styleElementRemovedHandler.reset()
|
||||
stylesheetRemovedHandler.reset()
|
||||
stylesheetsChangedHandler.reset()
|
||||
fs.removeSync(userStylesheetPath)
|
||||
expect(styleElementRemovedHandler).toHaveBeenCalled()
|
||||
expect(styleElementRemovedHandler.argsForCall[0][0].textContent).toContain 'dotted'
|
||||
expect(stylesheetRemovedHandler).toHaveBeenCalled()
|
||||
expect(stylesheetRemovedHandler.argsForCall[0][0].cssRules[0].style.border).toBe 'dotted'
|
||||
|
||||
waitsFor ->
|
||||
themeManager.loadUserStylesheet.callCount is 2
|
||||
expect(styleElementAddedHandler).toHaveBeenCalled()
|
||||
expect(styleElementAddedHandler.argsForCall[0][0].textContent).toContain 'dashed'
|
||||
expect(stylesheetAddedHandler).toHaveBeenCalled()
|
||||
expect(stylesheetAddedHandler.argsForCall[0][0].cssRules[0].style.border).toBe 'dashed'
|
||||
|
||||
runs ->
|
||||
expect(styleElementRemovedHandler).toHaveBeenCalled()
|
||||
expect(styleElementRemovedHandler.argsForCall[0][0].textContent).toContain 'dashed'
|
||||
expect(stylesheetRemovedHandler).toHaveBeenCalled()
|
||||
expect(stylesheetRemovedHandler.argsForCall[0][0].cssRules[0].style.border).toBe 'dashed'
|
||||
expect($(document.body).css('border-style')).toBe 'none'
|
||||
expect(stylesheetsChangedHandler).toHaveBeenCalled()
|
||||
expect(stylesheetsChangedHandler).toHaveBeenCalled()
|
||||
|
||||
styleElementRemovedHandler.reset()
|
||||
stylesheetRemovedHandler.reset()
|
||||
stylesheetsChangedHandler.reset()
|
||||
fs.removeSync(userStylesheetPath)
|
||||
|
||||
waitsFor ->
|
||||
themeManager.loadUserStylesheet.callCount is 2
|
||||
|
||||
runs ->
|
||||
expect(styleElementRemovedHandler).toHaveBeenCalled()
|
||||
expect(styleElementRemovedHandler.argsForCall[0][0].textContent).toContain 'dashed'
|
||||
expect(stylesheetRemovedHandler).toHaveBeenCalled()
|
||||
expect(stylesheetRemovedHandler.argsForCall[0][0].cssRules[0].style.border).toBe 'dashed'
|
||||
expect($(document.body).css('border-style')).toBe 'none'
|
||||
expect(stylesheetsChangedHandler).toHaveBeenCalled()
|
||||
|
||||
describe "when there is an error reading the stylesheet", ->
|
||||
addErrorHandler = null
|
||||
beforeEach ->
|
||||
themeManager.loadUserStylesheet()
|
||||
spyOn(themeManager.lessCache, 'cssForFile').andCallFake ->
|
||||
throw new Error('EACCES permission denied "styles.less"')
|
||||
atom.notifications.onDidAddNotification addErrorHandler = jasmine.createSpy()
|
||||
|
||||
it "creates an error notification and does not add the stylesheet", ->
|
||||
themeManager.loadUserStylesheet()
|
||||
expect(addErrorHandler).toHaveBeenCalled()
|
||||
note = addErrorHandler.mostRecentCall.args[0]
|
||||
expect(note.getType()).toBe 'error'
|
||||
expect(note.getMessage()).toContain 'Error loading'
|
||||
expect(atom.styles.styleElementsBySourcePath[atom.styles.getUserStyleSheetPath()]).toBeUndefined()
|
||||
|
||||
describe "when there is an error watching the user stylesheet", ->
|
||||
addErrorHandler = null
|
||||
beforeEach ->
|
||||
{File} = require 'pathwatcher'
|
||||
spyOn(File::, 'on').andCallFake (event) ->
|
||||
if event.indexOf('contents-changed') > -1
|
||||
throw new Error('Unable to watch path')
|
||||
spyOn(themeManager, 'loadStylesheet').andReturn ''
|
||||
atom.notifications.onDidAddNotification addErrorHandler = jasmine.createSpy()
|
||||
|
||||
it "creates an error notification", ->
|
||||
themeManager.loadUserStylesheet()
|
||||
expect(addErrorHandler).toHaveBeenCalled()
|
||||
note = addErrorHandler.mostRecentCall.args[0]
|
||||
expect(note.getType()).toBe 'error'
|
||||
expect(note.getMessage()).toContain 'Unable to watch path'
|
||||
|
||||
describe "when a non-existent theme is present in the config", ->
|
||||
beforeEach ->
|
||||
|
||||
@@ -169,6 +169,14 @@ describe "Window", ->
|
||||
$("<a href='#scroll-me'>link</a>").appendTo(document.body).click().remove()
|
||||
expect(shell.openExternal).not.toHaveBeenCalled()
|
||||
|
||||
describe "when a form is submitted", ->
|
||||
it "prevents the default so that the window's URL isn't changed", ->
|
||||
submitSpy = jasmine.createSpy('submit')
|
||||
$(document).on('submit', 'form', submitSpy)
|
||||
$("<form>foo</form>").appendTo(document.body).submit().remove()
|
||||
expect(submitSpy.callCount).toBe 1
|
||||
expect(submitSpy.argsForCall[0][0].isDefaultPrevented()).toBe true
|
||||
|
||||
describe "core:focus-next and core:focus-previous", ->
|
||||
describe "when there is no currently focused element", ->
|
||||
it "focuses the element with the lowest/highest tabindex", ->
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
path = require 'path'
|
||||
temp = require 'temp'
|
||||
Workspace = require '../src/workspace'
|
||||
Pane = require '../src/pane'
|
||||
{View} = require '../src/space-pen-extensions'
|
||||
platform = require './spec-helper-platform'
|
||||
_ = require 'underscore-plus'
|
||||
fstream = require 'fstream'
|
||||
fs = require 'fs-plus'
|
||||
Grim = require 'grim'
|
||||
|
||||
describe "Workspace", ->
|
||||
workspace = null
|
||||
@@ -250,6 +252,116 @@ describe "Workspace", ->
|
||||
runs ->
|
||||
expect(newEditorHandler.argsForCall[0][0].textEditor).toBe editor
|
||||
|
||||
it "records a deprecation warning on the appropriate package if the item has a ::getUri method instead of ::getURI", ->
|
||||
jasmine.snapshotDeprecations()
|
||||
|
||||
waitsForPromise -> atom.packages.activatePackage('package-with-deprecated-pane-item-method')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open("test")
|
||||
|
||||
runs ->
|
||||
deprecations = Grim.getDeprecations()
|
||||
expect(deprecations.length).toBe 1
|
||||
expect(deprecations[0].message).toBe "Pane item with class `TestItem` should implement `::getURI` instead of `::getUri`."
|
||||
expect(deprecations[0].getStacks()[0].metadata.packageName).toBe "package-with-deprecated-pane-item-method"
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
describe "when there is an error opening the file", ->
|
||||
notificationSpy = null
|
||||
beforeEach ->
|
||||
atom.notifications.onDidAddNotification notificationSpy = jasmine.createSpy()
|
||||
|
||||
describe "when a large file is opened", ->
|
||||
beforeEach ->
|
||||
spyOn(fs, 'getSizeSync').andReturn 2 * 1048577 # 2MB
|
||||
|
||||
it "creates a notification", ->
|
||||
waitsForPromise ->
|
||||
workspace.open('file1')
|
||||
|
||||
runs ->
|
||||
expect(notificationSpy).toHaveBeenCalled()
|
||||
notification = notificationSpy.mostRecentCall.args[0]
|
||||
expect(notification.getType()).toBe 'warning'
|
||||
expect(notification.getMessage()).toContain '< 2MB'
|
||||
|
||||
describe "when a file does not exist", ->
|
||||
it "creates an empty buffer for the specified path", ->
|
||||
waitsForPromise ->
|
||||
workspace.open('not-a-file.md')
|
||||
|
||||
runs ->
|
||||
editor = workspace.getActiveTextEditor()
|
||||
expect(notificationSpy).not.toHaveBeenCalled()
|
||||
expect(editor.getPath()).toContain 'not-a-file.md'
|
||||
|
||||
describe "when the user does not have access to the file", ->
|
||||
beforeEach ->
|
||||
spyOn(fs, 'openSync').andCallFake (path) ->
|
||||
error = new Error("EACCES, permission denied '#{path}'")
|
||||
error.path = path
|
||||
error.code = 'EACCES'
|
||||
throw error
|
||||
|
||||
it "creates a notification", ->
|
||||
waitsForPromise ->
|
||||
workspace.open('file1')
|
||||
|
||||
runs ->
|
||||
expect(notificationSpy).toHaveBeenCalled()
|
||||
notification = notificationSpy.mostRecentCall.args[0]
|
||||
expect(notification.getType()).toBe 'warning'
|
||||
expect(notification.getMessage()).toContain 'Permission denied'
|
||||
expect(notification.getMessage()).toContain 'file1'
|
||||
|
||||
describe "when the the operation is not permitted", ->
|
||||
beforeEach ->
|
||||
spyOn(fs, 'openSync').andCallFake (path) ->
|
||||
error = new Error("EPERM, operation not permitted '#{path}'")
|
||||
error.path = path
|
||||
error.code = 'EPERM'
|
||||
throw error
|
||||
|
||||
it "creates a notification", ->
|
||||
waitsForPromise ->
|
||||
workspace.open('file1')
|
||||
|
||||
runs ->
|
||||
expect(notificationSpy).toHaveBeenCalled()
|
||||
notification = notificationSpy.mostRecentCall.args[0]
|
||||
expect(notification.getType()).toBe 'warning'
|
||||
expect(notification.getMessage()).toContain 'Unable to open'
|
||||
expect(notification.getMessage()).toContain 'file1'
|
||||
|
||||
describe "when the the file is already open in windows", ->
|
||||
beforeEach ->
|
||||
spyOn(fs, 'openSync').andCallFake (path) ->
|
||||
error = new Error("EBUSY, resource busy or locked '#{path}'")
|
||||
error.path = path
|
||||
error.code = 'EBUSY'
|
||||
throw error
|
||||
|
||||
it "creates a notification", ->
|
||||
waitsForPromise ->
|
||||
workspace.open('file1')
|
||||
|
||||
runs ->
|
||||
expect(notificationSpy).toHaveBeenCalled()
|
||||
notification = notificationSpy.mostRecentCall.args[0]
|
||||
expect(notification.getType()).toBe 'warning'
|
||||
expect(notification.getMessage()).toContain 'Unable to open'
|
||||
expect(notification.getMessage()).toContain 'file1'
|
||||
|
||||
describe "when there is an unhandled error", ->
|
||||
beforeEach ->
|
||||
spyOn(fs, 'openSync').andCallFake (path) ->
|
||||
throw new Error("I dont even know what is happening right now!!")
|
||||
|
||||
it "creates a notification", ->
|
||||
open = -> workspace.open('file1', workspace.getActivePane())
|
||||
expect(open).toThrow()
|
||||
|
||||
describe "::reopenItem()", ->
|
||||
it "opens the uri associated with the last closed pane that isn't currently open", ->
|
||||
pane = workspace.getActivePane()
|
||||
@@ -841,3 +953,79 @@ describe "Workspace", ->
|
||||
expect(results[0].replacements).toBe 6
|
||||
|
||||
expect(editor.isModified()).toBeTruthy()
|
||||
|
||||
describe "::saveActivePaneItem()", ->
|
||||
describe "when there is an error", ->
|
||||
it "emits a warning notification when the file cannot be saved", ->
|
||||
spyOn(Pane::, 'saveActiveItem').andCallFake ->
|
||||
throw new Error("'/some/file' is a directory")
|
||||
|
||||
atom.notifications.onDidAddNotification addedSpy = jasmine.createSpy()
|
||||
atom.workspace.saveActivePaneItem()
|
||||
expect(addedSpy).toHaveBeenCalled()
|
||||
expect(addedSpy.mostRecentCall.args[0].getType()).toBe 'warning'
|
||||
|
||||
it "emits a warning notification when the directory cannot be written to", ->
|
||||
spyOn(Pane::, 'saveActiveItem').andCallFake ->
|
||||
throw new Error("ENOTDIR, not a directory '/Some/dir/and-a-file.js'")
|
||||
|
||||
atom.notifications.onDidAddNotification addedSpy = jasmine.createSpy()
|
||||
atom.workspace.saveActivePaneItem()
|
||||
expect(addedSpy).toHaveBeenCalled()
|
||||
expect(addedSpy.mostRecentCall.args[0].getType()).toBe 'warning'
|
||||
|
||||
it "emits a warning notification when the user does not have permission", ->
|
||||
spyOn(Pane::, 'saveActiveItem').andCallFake ->
|
||||
error = new Error("EACCES, permission denied '/Some/dir/and-a-file.js'")
|
||||
error.code = 'EACCES'
|
||||
error.path = '/Some/dir/and-a-file.js'
|
||||
throw error
|
||||
|
||||
atom.notifications.onDidAddNotification addedSpy = jasmine.createSpy()
|
||||
atom.workspace.saveActivePaneItem()
|
||||
expect(addedSpy).toHaveBeenCalled()
|
||||
expect(addedSpy.mostRecentCall.args[0].getType()).toBe 'warning'
|
||||
|
||||
it "emits a warning notification when the operation is not permitted", ->
|
||||
spyOn(Pane::, 'saveActiveItem').andCallFake ->
|
||||
error = new Error("EPERM, operation not permitted '/Some/dir/and-a-file.js'")
|
||||
error.code = 'EPERM'
|
||||
error.path = '/Some/dir/and-a-file.js'
|
||||
throw error
|
||||
|
||||
it "emits a warning notification when the file is already open by another app", ->
|
||||
spyOn(Pane::, 'saveActiveItem').andCallFake ->
|
||||
error = new Error("EBUSY, resource busy or locked '/Some/dir/and-a-file.js'")
|
||||
error.code = 'EBUSY'
|
||||
error.path = '/Some/dir/and-a-file.js'
|
||||
throw error
|
||||
|
||||
atom.notifications.onDidAddNotification addedSpy = jasmine.createSpy()
|
||||
atom.workspace.saveActivePaneItem()
|
||||
expect(addedSpy).toHaveBeenCalled()
|
||||
|
||||
notificaiton = addedSpy.mostRecentCall.args[0]
|
||||
expect(notificaiton.getType()).toBe 'warning'
|
||||
expect(notificaiton.getMessage()).toContain 'Unable to save'
|
||||
|
||||
it "emits a warning notification when the file system is read-only", ->
|
||||
spyOn(Pane::, 'saveActiveItem').andCallFake ->
|
||||
error = new Error("EROFS, read-only file system '/Some/dir/and-a-file.js'")
|
||||
error.code = 'EROFS'
|
||||
error.path = '/Some/dir/and-a-file.js'
|
||||
throw error
|
||||
|
||||
atom.notifications.onDidAddNotification addedSpy = jasmine.createSpy()
|
||||
atom.workspace.saveActivePaneItem()
|
||||
expect(addedSpy).toHaveBeenCalled()
|
||||
|
||||
notification = addedSpy.mostRecentCall.args[0]
|
||||
expect(notification.getType()).toBe 'warning'
|
||||
expect(notification.getMessage()).toContain 'Unable to save'
|
||||
|
||||
it "emits a warning notification when the file cannot be saved", ->
|
||||
spyOn(Pane::, 'saveActiveItem').andCallFake ->
|
||||
throw new Error("no one knows")
|
||||
|
||||
save = -> atom.workspace.saveActivePaneItem()
|
||||
expect(save).toThrow()
|
||||
|
||||
@@ -3,7 +3,6 @@ Q = require 'q'
|
||||
path = require 'path'
|
||||
temp = require 'temp'
|
||||
TextEditorView = require '../src/text-editor-view'
|
||||
Pane = require '../src/pane'
|
||||
PaneView = require '../src/pane-view'
|
||||
Workspace = require '../src/workspace'
|
||||
|
||||
@@ -295,39 +294,3 @@ describe "WorkspaceView", ->
|
||||
|
||||
modalContainer = workspaceElement.querySelector('atom-panel-container.modal')
|
||||
expect(modalContainer.parentNode).toBe workspaceElement
|
||||
|
||||
describe "::saveActivePaneItem()", ->
|
||||
describe "when there is an error", ->
|
||||
it "emits a warning notification when the file cannot be saved", ->
|
||||
spyOn(Pane::, 'saveActiveItem').andCallFake ->
|
||||
throw new Error("'/some/file' is a directory")
|
||||
|
||||
atom.notifications.onDidAddNotification addedSpy = jasmine.createSpy()
|
||||
atom.workspace.saveActivePaneItem()
|
||||
expect(addedSpy).toHaveBeenCalled()
|
||||
expect(addedSpy.mostRecentCall.args[0].getType()).toBe 'warning'
|
||||
|
||||
it "emits a warning notification when the directory cannot be written to", ->
|
||||
spyOn(Pane::, 'saveActiveItem').andCallFake ->
|
||||
throw new Error("ENOTDIR, not a directory '/Some/dir/and-a-file.js'")
|
||||
|
||||
atom.notifications.onDidAddNotification addedSpy = jasmine.createSpy()
|
||||
atom.workspace.saveActivePaneItem()
|
||||
expect(addedSpy).toHaveBeenCalled()
|
||||
expect(addedSpy.mostRecentCall.args[0].getType()).toBe 'warning'
|
||||
|
||||
it "emits a warning notification when the user does not have permission", ->
|
||||
spyOn(Pane::, 'saveActiveItem').andCallFake ->
|
||||
throw new Error("EACCES, permission denied '/Some/dir/and-a-file.js'")
|
||||
|
||||
atom.notifications.onDidAddNotification addedSpy = jasmine.createSpy()
|
||||
atom.workspace.saveActivePaneItem()
|
||||
expect(addedSpy).toHaveBeenCalled()
|
||||
expect(addedSpy.mostRecentCall.args[0].getType()).toBe 'warning'
|
||||
|
||||
it "emits a warning notification when the file cannot be saved", ->
|
||||
spyOn(Pane::, 'saveActiveItem').andCallFake ->
|
||||
throw new Error("no one knows")
|
||||
|
||||
save = -> atom.workspace.saveActivePaneItem()
|
||||
expect(save).toThrow()
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
###
|
||||
Cache for source code transpiled by 6to5.
|
||||
|
||||
Inspired by https://github.com/atom/atom/blob/6b963a562f8d495fbebe6abdbafbc7caf705f2c3/src/coffee-cache.coffee.
|
||||
###
|
||||
|
||||
crypto = require 'crypto'
|
||||
fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
to5 = null # Defer until used
|
||||
|
||||
stats =
|
||||
hits: 0
|
||||
misses: 0
|
||||
|
||||
defaultOptions =
|
||||
# The Chrome dev tools will show the original version of the file
|
||||
# when the source map is inlined.
|
||||
sourceMap: 'inline'
|
||||
|
||||
# Because Atom is currently packaged with a fork of React v0.11,
|
||||
# it makes sense to use the --react-compat option so the React
|
||||
# JSX transformer produces pre-v0.12 code.
|
||||
reactCompat: true
|
||||
|
||||
# Blacklisted features do not get transpiled. Features that are
|
||||
# natively supported in the target environment should be listed
|
||||
# here. Because Atom uses a bleeding edge version of Node/io.js,
|
||||
# I think this can include es6.arrowFunctions, es6.classes, and
|
||||
# possibly others, but I want to be conservative.
|
||||
blacklist: [
|
||||
'useStrict'
|
||||
]
|
||||
|
||||
# Includes support for es7 features listed at:
|
||||
# http://6to5.org/docs/usage/transformers/#es7-experimental-.
|
||||
experimental: true
|
||||
|
||||
optional: [
|
||||
# Target a version of the regenerator runtime that
|
||||
# supports yield so the transpiled code is cleaner/smaller.
|
||||
'asyncToGenerator'
|
||||
]
|
||||
|
||||
###
|
||||
shasum - Hash with an update() method.
|
||||
value - Must be a value that could be returned by JSON.parse().
|
||||
###
|
||||
updateDigestForJsonValue = (shasum, value) ->
|
||||
# Implmentation is similar to that of pretty-printing a JSON object, except:
|
||||
# * Strings are not escaped.
|
||||
# * No effort is made to avoid trailing commas.
|
||||
# These shortcuts should not affect the correctness of this function.
|
||||
type = typeof value
|
||||
if type is 'string'
|
||||
shasum.update('"', 'utf8')
|
||||
shasum.update(value, 'utf8')
|
||||
shasum.update('"', 'utf8')
|
||||
else if type in ['boolean', 'number']
|
||||
shasum.update(value.toString(), 'utf8')
|
||||
else if value is null
|
||||
shasum.update('null', 'utf8')
|
||||
else if Array.isArray value
|
||||
shasum.update('[', 'utf8')
|
||||
for item in value
|
||||
updateDigestForJsonValue(shasum, item)
|
||||
shasum.update(',', 'utf8')
|
||||
shasum.update(']', 'utf8')
|
||||
else
|
||||
# value must be an object: be sure to sort the keys.
|
||||
keys = Object.keys value
|
||||
keys.sort()
|
||||
|
||||
shasum.update('{', 'utf8')
|
||||
for key in keys
|
||||
updateDigestForJsonValue(shasum, key)
|
||||
shasum.update(': ', 'utf8')
|
||||
updateDigestForJsonValue(shasum, value[key])
|
||||
shasum.update(',', 'utf8')
|
||||
shasum.update('}', 'utf8')
|
||||
|
||||
create6to5VersionAndOptionsDigest = (version, options) ->
|
||||
shasum = crypto.createHash('sha1')
|
||||
# Include the version of 6to5 in the hash.
|
||||
shasum.update('6to5-core', 'utf8')
|
||||
shasum.update('\0', 'utf8')
|
||||
shasum.update(version, 'utf8')
|
||||
shasum.update('\0', 'utf8')
|
||||
updateDigestForJsonValue(shasum, options)
|
||||
shasum.digest('hex')
|
||||
|
||||
jsCacheDir = null
|
||||
|
||||
getCachePath = (sourceCode) ->
|
||||
digest = crypto.createHash('sha1').update(sourceCode, 'utf8').digest('hex')
|
||||
|
||||
unless jsCacheDir?
|
||||
to5Version = require('6to5-core/package.json').version
|
||||
cacheDir = path.join(process.env.ATOM_HOME, 'compile-cache')
|
||||
jsCacheDir = path.join(cacheDir, 'js', '6to5', create6to5VersionAndOptionsDigest(to5Version, defaultOptions))
|
||||
|
||||
path.join(jsCacheDir, "#{digest}.js")
|
||||
|
||||
getCachedJavaScript = (cachePath) ->
|
||||
if fs.isFileSync(cachePath)
|
||||
try
|
||||
cachedJavaScript = fs.readFileSync(cachePath, 'utf8')
|
||||
stats.hits++
|
||||
return cachedJavaScript
|
||||
null
|
||||
|
||||
# Returns the 6to5 options that should be used to transpile filePath.
|
||||
createOptions = (filePath) ->
|
||||
options = filename: filePath
|
||||
for key, value of defaultOptions
|
||||
options[key] = value
|
||||
options
|
||||
|
||||
transpile = (sourceCode, filePath, cachePath) ->
|
||||
options = createOptions(filePath)
|
||||
to5 ?= require '6to5-core'
|
||||
js = to5.transform(sourceCode, options).code
|
||||
stats.misses++
|
||||
|
||||
try
|
||||
fs.writeFileSync(cachePath, js)
|
||||
|
||||
js
|
||||
|
||||
# Function that obeys the contract of an entry in the require.extensions map.
|
||||
# Returns the transpiled version of the JavaScript code at filePath, which is
|
||||
# either generated on the fly or pulled from cache.
|
||||
loadFile = (module, filePath) ->
|
||||
sourceCode = fs.readFileSync(filePath, 'utf8')
|
||||
unless sourceCode.startsWith('"use 6to5"') or sourceCode.startsWith("'use 6to5'")
|
||||
return module._compile(sourceCode, filePath)
|
||||
|
||||
cachePath = getCachePath(sourceCode)
|
||||
js = getCachedJavaScript(cachePath) ? transpile(sourceCode, filePath, cachePath)
|
||||
module._compile(js, filePath)
|
||||
|
||||
register = ->
|
||||
Object.defineProperty(require.extensions, '.js', {
|
||||
writable: false
|
||||
value: loadFile
|
||||
})
|
||||
|
||||
module.exports =
|
||||
register: register
|
||||
getCacheMisses: -> stats.misses
|
||||
getCacheHits: -> stats.hits
|
||||
|
||||
# Visible for testing.
|
||||
create6to5VersionAndOptionsDigest: create6to5VersionAndOptionsDigest
|
||||
|
||||
addPathToCache: (filePath) ->
|
||||
return if path.extname(filePath) isnt '.js'
|
||||
|
||||
sourceCode = fs.readFileSync(filePath, 'utf8')
|
||||
cachePath = getCachePath(sourceCode)
|
||||
transpile(sourceCode, filePath, cachePath)
|
||||
@@ -3,7 +3,6 @@ ipc = require 'ipc'
|
||||
os = require 'os'
|
||||
path = require 'path'
|
||||
remote = require 'remote'
|
||||
screen = require 'screen'
|
||||
shell = require 'shell'
|
||||
|
||||
_ = require 'underscore-plus'
|
||||
@@ -43,6 +42,12 @@ class Atom extends Model
|
||||
which returns an HTMLElement.
|
||||
"""
|
||||
|
||||
serviceHubDeprecationMessage = """
|
||||
atom.services is no longer available. To register service providers and
|
||||
consumers, use the `providedServices` and `consumedServices` fields in
|
||||
your package's package.json.
|
||||
"""
|
||||
|
||||
Object.defineProperty atom, 'workspaceView',
|
||||
get: ->
|
||||
deprecate(workspaceViewDeprecationMessage)
|
||||
@@ -51,6 +56,14 @@ class Atom extends Model
|
||||
deprecate(workspaceViewDeprecationMessage)
|
||||
atom.__workspaceView = newValue
|
||||
|
||||
Object.defineProperty atom, 'services',
|
||||
get: ->
|
||||
deprecate(serviceHubDeprecationMessage)
|
||||
atom.packages.serviceHub
|
||||
set: (newValue) ->
|
||||
deprecate(serviceHubDeprecationMessage)
|
||||
atom.packages.serviceHub = newValue
|
||||
|
||||
atom
|
||||
|
||||
# Deserializes the Atom environment from a state object
|
||||
@@ -96,7 +109,7 @@ class Atom extends Model
|
||||
#
|
||||
# Returns the absolute path to ~/.atom
|
||||
@getConfigDirPath: ->
|
||||
@configDirPath ?= fs.absolute('~/.atom')
|
||||
@configDirPath ?= process.env.ATOM_HOME
|
||||
|
||||
# Get the path to Atom's storage directory.
|
||||
#
|
||||
@@ -134,9 +147,6 @@ class Atom extends Model
|
||||
# Public: A {Clipboard} instance
|
||||
clipboard: null
|
||||
|
||||
# A {ServiceHub} instance
|
||||
services: null
|
||||
|
||||
# Public: A {ContextMenuManager} instance
|
||||
contextMenu: null
|
||||
|
||||
@@ -236,7 +246,6 @@ class Atom extends Model
|
||||
NotificationManager = require './notification-manager'
|
||||
PackageManager = require './package-manager'
|
||||
Clipboard = require './clipboard'
|
||||
ServiceHub = require './service-hub'
|
||||
GrammarRegistry = require './grammar-registry'
|
||||
ThemeManager = require './theme-manager'
|
||||
StyleManager = require './style-manager'
|
||||
@@ -254,9 +263,6 @@ class Atom extends Model
|
||||
# Make react.js faster
|
||||
process.env.NODE_ENV ?= 'production' unless devMode
|
||||
|
||||
# Set Atom's home so packages don't have to guess it
|
||||
process.env.ATOM_HOME = configDirPath
|
||||
|
||||
@config = new Config({configDirPath, resourcePath})
|
||||
@keymaps = new KeymapManager({configDirPath, resourcePath})
|
||||
@keymap = @keymaps # Deprecated
|
||||
@@ -272,7 +278,6 @@ class Atom extends Model
|
||||
@contextMenu = new ContextMenuManager({resourcePath, devMode})
|
||||
@menu = new MenuManager({resourcePath})
|
||||
@clipboard = new Clipboard()
|
||||
@services = new ServiceHub
|
||||
|
||||
@grammars = @deserializers.deserialize(@state.grammars ? @state.syntax) ? new GrammarRegistry()
|
||||
|
||||
@@ -547,6 +552,7 @@ class Atom extends Model
|
||||
if @isValidDimensions(dimensions)
|
||||
dimensions
|
||||
else
|
||||
screen = remote.require 'screen'
|
||||
{width, height} = screen.getPrimaryDisplay().workAreaSize
|
||||
{x: 0, y: 0, width: Math.min(1024, width), height}
|
||||
|
||||
@@ -776,7 +782,9 @@ class Atom extends Model
|
||||
try
|
||||
require(userInitScriptPath) if fs.isFileSync(userInitScriptPath)
|
||||
catch error
|
||||
console.error "Failed to load `#{userInitScriptPath}`", error.stack, error
|
||||
atom.notifications.addError "Failed to load `#{userInitScriptPath}`",
|
||||
detail: error.message
|
||||
dismissable: true
|
||||
|
||||
# Require the module with the given globals.
|
||||
#
|
||||
|
||||
@@ -14,7 +14,7 @@ url = require 'url'
|
||||
{EventEmitter} = require 'events'
|
||||
_ = require 'underscore-plus'
|
||||
|
||||
socketPath =
|
||||
DefaultSocketPath =
|
||||
if process.platform is 'win32'
|
||||
'\\\\.\\pipe\\atom-sock'
|
||||
else
|
||||
@@ -31,17 +31,20 @@ class AtomApplication
|
||||
|
||||
# Public: The entry point into the Atom application.
|
||||
@open: (options) ->
|
||||
options.socketPath ?= DefaultSocketPath
|
||||
|
||||
createAtomApplication = -> new AtomApplication(options)
|
||||
|
||||
# FIXME: Sometimes when socketPath doesn't exist, net.connect would strangely
|
||||
# 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 (process.platform isnt 'win32' and not fs.existsSync socketPath) or options.test
|
||||
if (process.platform isnt 'win32' and not fs.existsSync options.socketPath) or options.test
|
||||
createAtomApplication()
|
||||
return
|
||||
|
||||
client = net.connect {path: socketPath}, ->
|
||||
|
||||
client = net.connect {path: options.socketPath}, ->
|
||||
client.write JSON.stringify(options), ->
|
||||
client.end()
|
||||
app.terminate()
|
||||
@@ -57,7 +60,7 @@ class AtomApplication
|
||||
exit: (status) -> app.exit(status)
|
||||
|
||||
constructor: (options) ->
|
||||
{@resourcePath, @version, @devMode, @safeMode} = options
|
||||
{@resourcePath, @version, @devMode, @safeMode, @socketPath} = options
|
||||
|
||||
# Normalize to make sure drive letter case is consistent on Windows
|
||||
@resourcePath = path.normalize(@resourcePath) if @resourcePath
|
||||
@@ -119,15 +122,15 @@ class AtomApplication
|
||||
connection.on 'data', (data) =>
|
||||
@openWithOptions(JSON.parse(data))
|
||||
|
||||
server.listen socketPath
|
||||
server.listen @socketPath
|
||||
server.on 'error', (error) -> console.error 'Application server failed', error
|
||||
|
||||
deleteSocketFile: ->
|
||||
return if process.platform is 'win32'
|
||||
|
||||
if fs.existsSync(socketPath)
|
||||
if fs.existsSync(@socketPath)
|
||||
try
|
||||
fs.unlinkSync(socketPath)
|
||||
fs.unlinkSync(@socketPath)
|
||||
catch error
|
||||
# Ignore ENOENT errors in case the file was deleted between the exists
|
||||
# check and the call to unlink sync. This occurred occasionally on CI
|
||||
@@ -216,6 +219,8 @@ class AtomApplication
|
||||
ipc.on 'open', (event, options) =>
|
||||
window = @windowForEvent(event)
|
||||
if options?
|
||||
if typeof options.pathsToOpen is 'string'
|
||||
options.pathsToOpen = [options.pathsToOpen]
|
||||
if options.pathsToOpen?.length > 0
|
||||
options.window = window
|
||||
@openPaths(options)
|
||||
@@ -414,7 +419,7 @@ class AtomApplication
|
||||
PackageManager = require '../package-manager'
|
||||
fs = require 'fs-plus'
|
||||
@packages = new PackageManager
|
||||
configDirPath: fs.absolute('~/.atom')
|
||||
configDirPath: process.env.ATOM_HOME
|
||||
devMode: devMode
|
||||
resourcePath: @resourcePath
|
||||
|
||||
|
||||
@@ -23,13 +23,18 @@ class AtomWindow
|
||||
# Normalize to make sure drive letter case is consistent on Windows
|
||||
@resourcePath = path.normalize(@resourcePath) if @resourcePath
|
||||
|
||||
@browserWindow = new BrowserWindow
|
||||
options =
|
||||
show: false
|
||||
title: 'Atom'
|
||||
icon: @constructor.iconPath
|
||||
'web-preferences':
|
||||
'direct-write': false
|
||||
'direct-write': true
|
||||
'subpixel-font-scaling': false
|
||||
# Don't set icon on Windows so the exe's ico will be used as window and
|
||||
# taskbar's icon. See https://github.com/atom/atom/issues/4811 for more.
|
||||
if process.platform is 'linux'
|
||||
options.icon = @constructor.iconPath
|
||||
|
||||
@browserWindow = new BrowserWindow options
|
||||
global.atomApplication.addWindow(this)
|
||||
|
||||
@handleEvents()
|
||||
|
||||
@@ -47,7 +47,7 @@ class AutoUpdateManager
|
||||
@setState(ErrorState)
|
||||
console.error "Error Downloading Update: #{message}"
|
||||
|
||||
autoUpdater.on 'update-downloaded', (event, @releaseNotes, @releaseVersion) =>
|
||||
autoUpdater.on 'update-downloaded', (event, releaseNotes, @releaseVersion) =>
|
||||
@setState(UpdateAvailableState)
|
||||
@emitUpdateAvailableEvent(@getWindows()...)
|
||||
|
||||
@@ -61,9 +61,9 @@ class AutoUpdateManager
|
||||
@setState(UnsupportedState)
|
||||
|
||||
emitUpdateAvailableEvent: (windows...) ->
|
||||
return unless @releaseVersion? and @releaseNotes
|
||||
return unless @releaseVersion?
|
||||
for atomWindow in windows
|
||||
atomWindow.sendMessage('update-available', {@releaseVersion, @releaseNotes})
|
||||
atomWindow.sendMessage('update-available', {@releaseVersion})
|
||||
|
||||
setState: (state) ->
|
||||
return if @state is state
|
||||
|
||||
@@ -13,17 +13,8 @@ process.on 'uncaughtException', (error={}) ->
|
||||
nslog(error.message) if error.message?
|
||||
nslog(error.stack) if error.stack?
|
||||
|
||||
# Patch fs.statSyncNoException/fs.lstatSyncNoException to fail for non-strings
|
||||
# https://github.com/atom/atom-shell/issues/843
|
||||
{lstatSyncNoException, statSyncNoException} = fs
|
||||
fs.statSyncNoException = (pathToStat) ->
|
||||
return false unless pathToStat and typeof pathToStat is 'string'
|
||||
statSyncNoException(pathToStat)
|
||||
fs.lstatSyncNoException = (pathToStat) ->
|
||||
return false unless pathToStat and typeof pathToStat is 'string'
|
||||
lstatSyncNoException(pathToStat)
|
||||
|
||||
start = ->
|
||||
setupAtomHome()
|
||||
if process.platform is 'win32'
|
||||
SquirrelUpdate = require './squirrel-update'
|
||||
squirrelCommand = process.argv[1]
|
||||
@@ -50,8 +41,12 @@ start = ->
|
||||
app.removeListener 'open-file', addPathToOpen
|
||||
app.removeListener 'open-url', addUrlToOpen
|
||||
|
||||
cwd = args.executedFrom?.toString() or process.cwd()
|
||||
args.pathsToOpen = args.pathsToOpen.map (pathToOpen) ->
|
||||
path.resolve(args.executedFrom ? process.cwd(), pathToOpen.toString())
|
||||
if cwd
|
||||
path.resolve(cwd, pathToOpen.toString())
|
||||
else
|
||||
path.resolve(pathToOpen.toString())
|
||||
|
||||
setupCoffeeScript()
|
||||
if args.devMode
|
||||
@@ -79,6 +74,18 @@ setupCoffeeScript = ->
|
||||
js = CoffeeScript.compile(coffee, filename: filePath)
|
||||
module._compile(js, filePath)
|
||||
|
||||
setupAtomHome = ->
|
||||
return if process.env.ATOM_HOME
|
||||
|
||||
if process.platform is 'win32'
|
||||
home = process.env.USERPROFILE
|
||||
else
|
||||
home = process.env.HOME
|
||||
atomHome = path.join(home, '.atom')
|
||||
try
|
||||
atomHome = fs.realpathSync(atomHome)
|
||||
process.env.ATOM_HOME = atomHome
|
||||
|
||||
parseCommandLine = ->
|
||||
version = app.getVersion()
|
||||
options = optimist(process.argv[1..])
|
||||
@@ -95,8 +102,12 @@ parseCommandLine = ->
|
||||
opened or a new window if it hasn't.
|
||||
|
||||
Environment Variables:
|
||||
ATOM_DEV_RESOURCE_PATH The path from which Atom loads source code in dev mode.
|
||||
Defaults to `~/github/atom`.
|
||||
|
||||
ATOM_DEV_RESOURCE_PATH The path from which Atom loads source code in dev mode.
|
||||
Defaults to `~/github/atom`.
|
||||
|
||||
ATOM_HOME The root path for all configuration files and folders.
|
||||
Defaults to `~/.atom`.
|
||||
"""
|
||||
options.alias('d', 'dev').boolean('d').describe('d', 'Run in development mode.')
|
||||
options.alias('f', 'foreground').boolean('f').describe('f', 'Keep the browser process in the foreground.')
|
||||
@@ -109,6 +120,7 @@ parseCommandLine = ->
|
||||
options.alias('t', 'test').boolean('t').describe('t', 'Run the specified specs and exit with error code on failures.')
|
||||
options.alias('v', 'version').boolean('v').describe('v', 'Print the version.')
|
||||
options.alias('w', 'wait').boolean('w').describe('w', 'Wait for window to be closed before returning.')
|
||||
options.string('socket-path')
|
||||
args = options.argv
|
||||
|
||||
if args.help
|
||||
@@ -129,6 +141,7 @@ parseCommandLine = ->
|
||||
newWindow = args['new-window']
|
||||
pidToKillWhenClosed = args['pid'] if args['wait']
|
||||
logFile = args['log-file']
|
||||
socketPath = args['socket-path']
|
||||
|
||||
if args['resource-path']
|
||||
devMode = true
|
||||
@@ -153,6 +166,6 @@ parseCommandLine = ->
|
||||
# explicitly pass it by command line, see http://git.io/YC8_Ew.
|
||||
process.env.PATH = args['path-environment'] if args['path-environment']
|
||||
|
||||
{resourcePath, pathsToOpen, executedFrom, test, version, pidToKillWhenClosed, devMode, safeMode, newWindow, specDirectory, logFile}
|
||||
{resourcePath, pathsToOpen, executedFrom, test, version, pidToKillWhenClosed, devMode, safeMode, newWindow, specDirectory, logFile, socketPath}
|
||||
|
||||
start()
|
||||
|
||||
@@ -125,7 +125,7 @@ addCommandsToPath = (callback) ->
|
||||
atomShCommand = "#!/bin/sh\r\n\"$0/../#{relativeAtomShPath.replace(/\\/g, '/')}\" \"$@\""
|
||||
|
||||
apmCommandPath = path.join(binFolder, 'apm.cmd')
|
||||
relativeApmPath = path.relative(binFolder, path.join(process.resourcesPath, 'app', 'apm', 'node_modules', 'atom-package-manager', 'bin', 'apm.cmd'))
|
||||
relativeApmPath = path.relative(binFolder, path.join(process.resourcesPath, 'app', 'apm', 'bin', 'apm.cmd'))
|
||||
apmCommand = "@echo off\r\n\"%~dp0\\#{relativeApmPath}\" %*"
|
||||
|
||||
apmShCommandPath = path.join(binFolder, 'apm')
|
||||
|
||||
@@ -28,22 +28,23 @@ class BufferedProcess
|
||||
# * `options` An {Object} with the following keys:
|
||||
# * `command` The {String} command to execute.
|
||||
# * `args` The {Array} of arguments to pass to the command (optional).
|
||||
# * `options` The options {Object} to pass to Node's `ChildProcess.spawn`
|
||||
# method (optional).
|
||||
# * `stdout` The callback {Function} that receives a single argument which
|
||||
# contains the standard output from the command. The callback is
|
||||
# called as data is received but it's buffered to ensure only
|
||||
# complete lines are passed until the source stream closes. After
|
||||
# the source stream has closed all remaining data is sent in a
|
||||
# final call (optional).
|
||||
# * `stderr` The callback {Function} that receives a single argument which
|
||||
# contains the standard error output from the command. The
|
||||
# callback is called as data is received but it's buffered to
|
||||
# ensure only complete lines are passed until the source stream
|
||||
# closes. After the source stream has closed all remaining data
|
||||
# is sent in a final call (optional).
|
||||
# * `exit` The callback {Function} which receives a single argument
|
||||
# containing the exit status (optional).
|
||||
# * `options` {Object} (optional) The options {Object} to pass to Node's
|
||||
# `ChildProcess.spawn` method.
|
||||
# * `stdout` {Function} (optional) The callback that receives a single
|
||||
# argument which contains the standard output from the command. The
|
||||
# callback is called as data is received but it's buffered to ensure only
|
||||
# complete lines are passed until the source stream closes. After the
|
||||
# source stream has closed all remaining data is sent in a final call.
|
||||
# * `data` {String}
|
||||
# * `stderr` {Function} (optional) The callback that receives a single
|
||||
# argument which contains the standard error output from the command. The
|
||||
# callback is called as data is received but it's buffered to ensure only
|
||||
# complete lines are passed until the source stream closes. After the
|
||||
# source stream has closed all remaining data is sent in a final call.
|
||||
# * `data` {String}
|
||||
# * `exit` {Function} (optional) The callback which receives a single
|
||||
# argument containing the exit status.
|
||||
# * `code` {Number}
|
||||
constructor: ({command, args, options, stdout, stderr, exit}={}) ->
|
||||
@emitter = new Emitter
|
||||
options ?= {}
|
||||
|
||||
@@ -5,7 +5,11 @@ CoffeeScript = require 'coffee-script'
|
||||
CSON = require 'season'
|
||||
fs = require 'fs-plus'
|
||||
|
||||
cacheDir = path.join(fs.absolute('~/.atom'), 'compile-cache')
|
||||
cacheDir = path.join(process.env.ATOM_HOME, 'compile-cache')
|
||||
|
||||
stats =
|
||||
hits: 0
|
||||
misses: 0
|
||||
|
||||
# Use separate compile cache when sudo'ing as root to avoid permission issues
|
||||
if process.env.USER is 'root' and process.env.SUDO_USER and process.env.SUDO_USER isnt process.env.USER
|
||||
@@ -21,7 +25,10 @@ getCachePath = (coffee) ->
|
||||
getCachedJavaScript = (cachePath) ->
|
||||
if fs.isFileSync(cachePath)
|
||||
try
|
||||
fs.readFileSync(cachePath, 'utf8')
|
||||
cachedJavaScript = fs.readFileSync(cachePath, 'utf8')
|
||||
stats.hits++
|
||||
return cachedJavaScript
|
||||
return
|
||||
|
||||
convertFilePath = (filePath) ->
|
||||
if process.platform is 'win32'
|
||||
@@ -30,6 +37,7 @@ convertFilePath = (filePath) ->
|
||||
|
||||
compileCoffeeScript = (coffee, filePath, cachePath) ->
|
||||
{js, v3SourceMap} = CoffeeScript.compile(coffee, filename: filePath, sourceMap: true)
|
||||
stats.misses++
|
||||
# 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=#{convertFilePath(filePath)}"
|
||||
@@ -53,10 +61,16 @@ module.exports =
|
||||
})
|
||||
|
||||
addPathToCache: (filePath) ->
|
||||
extension = path.extname(filePath)
|
||||
if extension is '.coffee'
|
||||
content = fs.readFileSync(filePath, 'utf8')
|
||||
cachePath = getCachePath(coffee)
|
||||
compileCoffeeScript(coffee, filePath, cachePath)
|
||||
else if extension is '.cson'
|
||||
CSON.readFileSync(filePath)
|
||||
switch path.extname(filePath)
|
||||
when '.coffee'
|
||||
content = fs.readFileSync(filePath, 'utf8')
|
||||
cachePath = getCachePath(coffee)
|
||||
compileCoffeeScript(coffee, filePath, cachePath)
|
||||
when '.cson'
|
||||
CSON.readFileSync(filePath)
|
||||
when '.js'
|
||||
require('./6to5').addPathToCache(filePath)
|
||||
|
||||
getCacheMisses: -> stats.misses
|
||||
|
||||
getCacheHits: -> stats.hits
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
_ = require 'underscore-plus'
|
||||
ParsedColor = require 'color'
|
||||
ParsedColor = null
|
||||
|
||||
# Essential: A simple color class returned from {Config::get} when the value
|
||||
# at the key path is of type 'color'.
|
||||
@@ -7,15 +7,17 @@ module.exports =
|
||||
class Color
|
||||
# Essential: Parse a {String} or {Object} into a {Color}.
|
||||
#
|
||||
# * `value` - A {String} such as `'white'`, `#ff00ff`, or
|
||||
# `'rgba(255, 15, 60, .75)'` or an {Object} with `red`, `green`,
|
||||
# `blue`, and `alpha` properties.
|
||||
# * `value` A {String} such as `'white'`, `#ff00ff`, or
|
||||
# `'rgba(255, 15, 60, .75)'` or an {Object} with `red`, `green`, `blue`,
|
||||
# and `alpha` properties.
|
||||
#
|
||||
# Returns a {Color} or `null` if it cannot be parsed.
|
||||
@parse: (value) ->
|
||||
return null if _.isArray(value) or _.isFunction(value)
|
||||
return null unless _.isObject(value) or _.isString(value)
|
||||
|
||||
ParsedColor ?= require 'color'
|
||||
|
||||
try
|
||||
parsedColor = new ParsedColor(value)
|
||||
catch error
|
||||
@@ -51,11 +53,11 @@ class Color
|
||||
@blue = blue
|
||||
@alpha = alpha
|
||||
|
||||
# Esssential: Returns a {String} in the form `'#abcdef'`.
|
||||
# Essential: Returns a {String} in the form `'#abcdef'`.
|
||||
toHexString: ->
|
||||
"##{numberToHexString(@red)}#{numberToHexString(@green)}#{numberToHexString(@blue)}"
|
||||
|
||||
# Esssential: Returns a {String} in the form `'rgba(25, 50, 75, .9)'`.
|
||||
# Essential: Returns a {String} in the form `'rgba(25, 50, 75, .9)'`.
|
||||
toRGBAString: ->
|
||||
"rgba(#{@red}, #{@green}, #{@blue}, #{@alpha})"
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ ScopeDescriptor = require './scope-descriptor'
|
||||
#
|
||||
# ## Config Schemas
|
||||
#
|
||||
# We use [json schema](json-schema.org) which allows you to define your value's
|
||||
# We use [json schema](http://json-schema.org) which allows you to define your value's
|
||||
# default, the type it should be, etc. A simple example:
|
||||
#
|
||||
# ```coffee
|
||||
@@ -519,7 +519,7 @@ class Config
|
||||
# * `options` (optional) {Object} see the `options` argument to {::get}
|
||||
#
|
||||
# Returns an {Array} of {Object}s with the following keys:
|
||||
# * `scopeSelector` The scope-selector {String} with which the value is associated
|
||||
# * `scopeDescriptor` The {ScopeDescriptor} with which the value is associated
|
||||
# * `value` The value for the key-path
|
||||
getAll: (keyPath, options) ->
|
||||
{scope, sources} = options if options?
|
||||
@@ -583,6 +583,7 @@ class Config
|
||||
Pass a `scopeSelector` in an options hash as the final argument instead.
|
||||
"""
|
||||
[scopeSelector, keyPath, value] = arguments
|
||||
shouldSave = true
|
||||
else
|
||||
[keyPath, value, options] = arguments
|
||||
scopeSelector = options?.scopeSelector
|
||||
@@ -601,7 +602,7 @@ class Config
|
||||
return false
|
||||
|
||||
if scopeSelector?
|
||||
@setRawScopedValue(source, scopeSelector, keyPath, value)
|
||||
@setRawScopedValue(keyPath, value, source, scopeSelector)
|
||||
else
|
||||
@setRawValue(keyPath, value)
|
||||
|
||||
@@ -640,8 +641,9 @@ class Config
|
||||
@scopedSettingsStore.removePropertiesForSourceAndSelector(source, scopeSelector)
|
||||
@emitChangeEvent()
|
||||
else
|
||||
@scopedSettingsStore.removePropertiesForSource(source)
|
||||
if keyPath?
|
||||
for scopeSelector of @scopedSettingsStore.propertiesForSource(source)
|
||||
@unset(keyPath, {scopeSelector, source})
|
||||
if keyPath? and source is @getUserConfigPath()
|
||||
@set(keyPath, _.valueForKeyPath(@defaultSettings, keyPath))
|
||||
|
||||
# Extended: Get an {Array} of all of the `source` {String}s with which
|
||||
@@ -795,6 +797,7 @@ class Config
|
||||
_.extend rootSchema, schema
|
||||
@setDefaults(keyPath, @extractDefaultsFromSchema(schema))
|
||||
@setScopedDefaultsFromSchema(keyPath, schema)
|
||||
@resetSettingsForSchemaChange()
|
||||
|
||||
load: ->
|
||||
@initializeConfigDirectory()
|
||||
@@ -832,25 +835,35 @@ class Config
|
||||
@configFileHasErrors = false
|
||||
catch error
|
||||
@configFileHasErrors = true
|
||||
@notifyFailure('Failed to load config.cson', error)
|
||||
message = "Failed to load `#{path.basename(@configFilePath)}`"
|
||||
|
||||
detail = if error.location?
|
||||
# stack is the output from CSON in this case
|
||||
error.stack
|
||||
else
|
||||
# message will be EACCES permission denied, et al
|
||||
error.message
|
||||
|
||||
@notifyFailure(message, detail)
|
||||
|
||||
observeUserConfig: ->
|
||||
try
|
||||
@watchSubscription ?= pathWatcher.watch @configFilePath, (eventType) =>
|
||||
@debouncedLoad() if eventType is 'change' and @watchSubscription?
|
||||
catch error
|
||||
@notifyFailure('Failed to watch user config', error)
|
||||
@notifyFailure """
|
||||
Unable to watch path: `#{path.basename(@configFilePath)}`. Make sure you have permissions to
|
||||
`#{@configFilePath}`. On linux there are currently problems with watch
|
||||
sizes. See [this document][watches] for more info.
|
||||
[watches]:https://github.com/atom/atom/blob/master/docs/build-instructions/linux.md#typeerror-unable-to-watch-path
|
||||
"""
|
||||
|
||||
unobserveUserConfig: ->
|
||||
@watchSubscription?.close()
|
||||
@watchSubscription = null
|
||||
|
||||
notifyFailure: (errorMessage, error) ->
|
||||
message = "#{errorMessage}"
|
||||
detail = error.stack
|
||||
atom.notifications.addError(message, {detail, dismissable: true})
|
||||
console.error message
|
||||
console.error detail
|
||||
notifyFailure: (errorMessage, detail) ->
|
||||
atom.notifications.addError(errorMessage, {detail, dismissable: true})
|
||||
|
||||
save: ->
|
||||
allSettings = {'*': @settings}
|
||||
@@ -888,16 +901,10 @@ class Config
|
||||
defaultValue = _.valueForKeyPath(@defaultSettings, keyPath)
|
||||
|
||||
if value?
|
||||
if value instanceof Color
|
||||
value = value.clone()
|
||||
else
|
||||
value = _.deepClone(value)
|
||||
_.defaults(value, defaultValue) if isPlainObject(value) and isPlainObject(defaultValue)
|
||||
value = @deepClone(value)
|
||||
_.defaults(value, defaultValue) if isPlainObject(value) and isPlainObject(defaultValue)
|
||||
else
|
||||
if defaultValue instanceof Color
|
||||
value = defaultValue.clone()
|
||||
else
|
||||
value = _.deepClone(defaultValue)
|
||||
value = @deepClone(defaultValue)
|
||||
|
||||
value
|
||||
|
||||
@@ -947,6 +954,16 @@ class Config
|
||||
catch e
|
||||
console.warn("'#{keyPath}' could not set the default. Attempted default: #{JSON.stringify(defaults)}; Schema: #{JSON.stringify(@getSchema(keyPath))}")
|
||||
|
||||
deepClone: (object) ->
|
||||
if object instanceof Color
|
||||
object.clone()
|
||||
else if _.isArray(object)
|
||||
object.map (value) => @deepClone(value)
|
||||
else if isPlainObject(object)
|
||||
_.mapObject object, (key, value) => [key, @deepClone(value)]
|
||||
else
|
||||
object
|
||||
|
||||
# `schema` will look something like this
|
||||
#
|
||||
# ```coffee
|
||||
@@ -982,9 +999,28 @@ class Config
|
||||
defaults[key] = @extractDefaultsFromSchema(value) for key, value of properties
|
||||
defaults
|
||||
|
||||
makeValueConformToSchema: (keyPath, value) ->
|
||||
value = @constructor.executeSchemaEnforcers(keyPath, value, schema) if schema = @getSchema(keyPath)
|
||||
value
|
||||
makeValueConformToSchema: (keyPath, value, options) ->
|
||||
if options?.suppressException
|
||||
try
|
||||
@makeValueConformToSchema(keyPath, value)
|
||||
catch e
|
||||
undefined
|
||||
else
|
||||
value = @constructor.executeSchemaEnforcers(keyPath, value, schema) if schema = @getSchema(keyPath)
|
||||
value
|
||||
|
||||
# When the schema is changed / added, there may be values set in the config
|
||||
# that do not conform to the schema. This will reset make them conform.
|
||||
resetSettingsForSchemaChange: (source=@getUserConfigPath()) ->
|
||||
@transact =>
|
||||
@settings = @makeValueConformToSchema(null, @settings, suppressException: true)
|
||||
priority = @priorityForSource(source)
|
||||
selectorsAndSettings = @scopedSettingsStore.propertiesForSource(source)
|
||||
@scopedSettingsStore.removePropertiesForSource(source)
|
||||
for scopeSelector, settings of selectorsAndSettings
|
||||
settings = @makeValueConformToSchema(null, settings, suppressException: true)
|
||||
@setRawScopedValue(null, settings, source, scopeSelector)
|
||||
return
|
||||
|
||||
###
|
||||
Section: Private Scoped Settings
|
||||
@@ -1001,8 +1037,15 @@ class Config
|
||||
|
||||
resetUserScopedSettings: (newScopedSettings) ->
|
||||
source = @getUserConfigPath()
|
||||
priority = @priorityForSource(source)
|
||||
@scopedSettingsStore.removePropertiesForSource(source)
|
||||
@scopedSettingsStore.addProperties(source, newScopedSettings, priority: @priorityForSource(source))
|
||||
|
||||
for scopeSelector, settings of newScopedSettings
|
||||
settings = @makeValueConformToSchema(null, settings, suppressException: true)
|
||||
validatedSettings = {}
|
||||
validatedSettings[scopeSelector] = withoutEmptyObjects(settings)
|
||||
@scopedSettingsStore.addProperties(source, validatedSettings, {priority}) if validatedSettings[scopeSelector]?
|
||||
|
||||
@emitChangeEvent()
|
||||
|
||||
addScopedSettings: (source, selector, value, options) ->
|
||||
@@ -1015,7 +1058,7 @@ class Config
|
||||
disposable.dispose()
|
||||
@emitChangeEvent()
|
||||
|
||||
setRawScopedValue: (source, selector, keyPath, value) ->
|
||||
setRawScopedValue: (keyPath, value, source, selector, options) ->
|
||||
if keyPath?
|
||||
newValue = {}
|
||||
_.setValueForKeyPath(newValue, keyPath, value)
|
||||
@@ -1102,12 +1145,17 @@ Config.addSchemaEnforcers
|
||||
return value unless schema.properties?
|
||||
|
||||
newValue = {}
|
||||
for prop, childSchema of schema.properties
|
||||
continue unless value.hasOwnProperty(prop)
|
||||
try
|
||||
newValue[prop] = @executeSchemaEnforcers("#{keyPath}.#{prop}", value[prop], childSchema)
|
||||
catch error
|
||||
console.warn "Error setting item in object: #{error.message}"
|
||||
for prop, propValue of value
|
||||
childSchema = schema.properties[prop]
|
||||
if childSchema?
|
||||
try
|
||||
newValue[prop] = @executeSchemaEnforcers("#{keyPath}.#{prop}", propValue, childSchema)
|
||||
catch error
|
||||
console.warn "Error setting item in object: #{error.message}"
|
||||
else
|
||||
# Just pass through un-schema'd values
|
||||
newValue[prop] = propValue
|
||||
|
||||
newValue
|
||||
|
||||
'array':
|
||||
@@ -1152,7 +1200,7 @@ Config.addSchemaEnforcers
|
||||
throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} is not one of #{JSON.stringify(possibleValues)}")
|
||||
|
||||
isPlainObject = (value) ->
|
||||
_.isObject(value) and not _.isArray(value) and not _.isFunction(value) and not _.isString(value)
|
||||
_.isObject(value) and not _.isArray(value) and not _.isFunction(value) and not _.isString(value) and not (value instanceof Color)
|
||||
|
||||
splitKeyPath = (keyPath) ->
|
||||
return [] unless keyPath?
|
||||
|
||||
@@ -34,8 +34,8 @@ class Decoration
|
||||
|
||||
# Private: Check if the `decorationProperties.type` matches `type`
|
||||
#
|
||||
# * `decorationProperties` {Object} eg. `{type: 'gutter', class: 'my-new-class'}`
|
||||
# * `type` {String} type like `'gutter'`, `'line'`, etc. `type` can also
|
||||
# * `decorationProperties` {Object} eg. `{type: 'line-number', class: 'my-new-class'}`
|
||||
# * `type` {String} type like `'line-number'`, `'line'`, etc. `type` can also
|
||||
# be an {Array} of {String}s, where it will return true if the decoration's
|
||||
# type matches any in the array.
|
||||
#
|
||||
@@ -107,7 +107,7 @@ class Decoration
|
||||
|
||||
# Public: Check if this decoration is of type `type`
|
||||
#
|
||||
# * `type` {String} type like `'gutter'`, `'line'`, etc. `type` can also
|
||||
# * `type` {String} type like `'line-number'`, `'line'`, etc. `type` can also
|
||||
# be an {Array} of {String}s, where it will return true if the decoration's
|
||||
# type matches any in the array.
|
||||
#
|
||||
@@ -131,10 +131,10 @@ class Decoration
|
||||
# ## Examples
|
||||
#
|
||||
# ```coffee
|
||||
# decoration.update({type: 'gutter', class: 'my-new-class'})
|
||||
# decoration.update({type: 'line-number', class: 'my-new-class'})
|
||||
# ```
|
||||
#
|
||||
# * `newProperties` {Object} eg. `{type: 'gutter', class: 'my-new-class'}`
|
||||
# * `newProperties` {Object} eg. `{type: 'line-number', class: 'my-new-class'}`
|
||||
setProperties: (newProperties) ->
|
||||
return if @destroyed
|
||||
oldProperties = @properties
|
||||
|
||||
@@ -898,7 +898,7 @@ class DisplayBuffer extends Model
|
||||
@getDecorations(propertyFilter).filter (decoration) -> decoration.isType('line')
|
||||
|
||||
getGutterDecorations: (propertyFilter) ->
|
||||
@getDecorations(propertyFilter).filter (decoration) -> decoration.isType('gutter')
|
||||
@getDecorations(propertyFilter).filter (decoration) -> decoration.isType('line-number')
|
||||
|
||||
getHighlightDecorations: (propertyFilter) ->
|
||||
@getDecorations(propertyFilter).filter (decoration) -> decoration.isType('highlight')
|
||||
@@ -1222,7 +1222,7 @@ class DisplayBuffer extends Model
|
||||
@emitter.emit 'did-create-marker', marker
|
||||
|
||||
createFoldForMarker: (marker) ->
|
||||
@decorateMarker(marker, type: 'gutter', class: 'folded')
|
||||
@decorateMarker(marker, type: 'line-number', class: 'folded')
|
||||
new Fold(this, marker)
|
||||
|
||||
foldForMarker: (marker) ->
|
||||
|
||||
@@ -19,10 +19,9 @@ class Fold
|
||||
|
||||
# Returns whether this fold is contained within another fold
|
||||
isInsideLargerFold: ->
|
||||
if largestContainingFoldMarker = @displayBuffer.findMarker(class: 'fold', containsBufferRange: @getBufferRange())
|
||||
not largestContainingFoldMarker.getBufferRange().isEqual(@getBufferRange())
|
||||
else
|
||||
false
|
||||
largestContainingFoldMarker = @displayBuffer.findFoldMarker(containsRange: @getBufferRange())
|
||||
largestContainingFoldMarker and
|
||||
not largestContainingFoldMarker.getRange().isEqual(@getBufferRange())
|
||||
|
||||
# Destroys this fold
|
||||
destroy: ->
|
||||
|
||||
@@ -33,7 +33,7 @@ Task = require './task'
|
||||
#
|
||||
# ```coffee
|
||||
# git = atom.project.getRepo()
|
||||
# console.log git.getOriginUrl()
|
||||
# console.log git.getOriginURL()
|
||||
# ```
|
||||
#
|
||||
# ### Requiring in packages
|
||||
@@ -234,8 +234,8 @@ class GitRepository
|
||||
# for, only needed if the repository has submodules.
|
||||
getOriginURL: (path) -> @getConfigValue('remote.origin.url', path)
|
||||
getOriginUrl: (path) ->
|
||||
deprecate("Use ::getOriginURL instead.")
|
||||
@getOriginUrl()
|
||||
deprecate 'Use ::getOriginURL instead.'
|
||||
@getOriginURL(path)
|
||||
|
||||
# Public: Returns the upstream branch for the current HEAD, or null if there
|
||||
# is no upstream branch for the current HEAD.
|
||||
|
||||
@@ -163,7 +163,7 @@ GutterComponent = React.createClass
|
||||
classes = ''
|
||||
if lineDecorations? and decorations = lineDecorations[screenRow]
|
||||
for id, decoration of decorations
|
||||
if Decoration.isType(decoration, 'gutter')
|
||||
if Decoration.isType(decoration, 'line-number')
|
||||
classes += decoration.class + ' '
|
||||
|
||||
classes += "foldable " if bufferRow >= 0 and editor.isFoldableAtBufferRow(bufferRow)
|
||||
@@ -195,12 +195,12 @@ GutterComponent = React.createClass
|
||||
|
||||
if previousDecorations?
|
||||
for id, decoration of previousDecorations
|
||||
if Decoration.isType(decoration, 'gutter') and not @hasDecoration(decorations, decoration)
|
||||
if Decoration.isType(decoration, 'line-number') and not @hasDecoration(decorations, decoration)
|
||||
node.classList.remove(decoration.class)
|
||||
|
||||
if decorations?
|
||||
for id, decoration of decorations
|
||||
if Decoration.isType(decoration, 'gutter') and not @hasDecoration(previousDecorations, decoration)
|
||||
if Decoration.isType(decoration, 'line-number') and not @hasDecoration(previousDecorations, decoration)
|
||||
node.classList.add(decoration.class)
|
||||
|
||||
unless @screenRowsByLineNumberId[lineNumberId] is screenRow
|
||||
|
||||
@@ -20,12 +20,37 @@ KeymapManager::getUserKeymapPath = ->
|
||||
|
||||
KeymapManager::loadUserKeymap = ->
|
||||
userKeymapPath = @getUserKeymapPath()
|
||||
if fs.isFileSync(userKeymapPath)
|
||||
return unless fs.isFileSync(userKeymapPath)
|
||||
|
||||
try
|
||||
@loadKeymap(userKeymapPath, watch: true, suppressErrors: true)
|
||||
catch error
|
||||
if error.message.indexOf('Unable to watch path') > -1
|
||||
message = """
|
||||
Unable to watch path: `#{path.basename(userKeymapPath)}`. Make sure you
|
||||
have permission to read `#{userKeymapPath}`.
|
||||
|
||||
On linux there are currently problems with watch sizes. See
|
||||
[this document][watches] for more info.
|
||||
[watches]:https://github.com/atom/atom/blob/master/docs/build-instructions/linux.md#typeerror-unable-to-watch-path
|
||||
"""
|
||||
atom.notifications.addError(message, {dismissable: true})
|
||||
else
|
||||
detail = error.path
|
||||
stack = error.stack
|
||||
atom.notifications.addFatalError(error.message, {detail, stack, dismissable: true})
|
||||
|
||||
KeymapManager::subscribeToFileReadFailure = ->
|
||||
this.onDidFailToReadFile (error) ->
|
||||
atom.notifications.addError('Failed to load keymap.cson', {detail: error.stack, dismissable: true})
|
||||
@onDidFailToReadFile (error) =>
|
||||
userKeymapPath = @getUserKeymapPath()
|
||||
message = "Failed to load `#{userKeymapPath}`"
|
||||
|
||||
detail = if error.location?
|
||||
error.stack
|
||||
else
|
||||
error.message
|
||||
|
||||
atom.notifications.addError(message, {detail: detail, dismissable: true})
|
||||
|
||||
# This enables command handlers registered via jQuery to call
|
||||
# `.abortKeyBinding()` on the `jQuery.Event` object passed to the handler.
|
||||
|
||||
@@ -32,7 +32,7 @@ class LanguageMode
|
||||
|
||||
return unless commentStartEntry?
|
||||
|
||||
commentEndEntry = atom.config.getAll('editor.commentEnd', {scope}).find (entry) ->
|
||||
commentEndEntry = _.find atom.config.getAll('editor.commentEnd', {scope}), (entry) ->
|
||||
entry.scopeSelector is commentStartEntry.scopeSelector
|
||||
commentStartString = commentStartEntry?.value
|
||||
commentEndString = commentEndEntry?.value
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
path = require 'path'
|
||||
fs = require 'fs-plus'
|
||||
LessCache = require 'less-cache'
|
||||
{Subscriber} = require 'emissary'
|
||||
|
||||
# {LessCache} wrapper used by {ThemeManager} to read stylesheets.
|
||||
module.exports =
|
||||
class LessCompileCache
|
||||
Subscriber.includeInto(this)
|
||||
|
||||
@cacheDir: path.join(require('./coffee-cache').cacheDir, 'less')
|
||||
@cacheDir: path.join(process.env.ATOM_HOME, 'compile-cache', 'less')
|
||||
|
||||
constructor: ({resourcePath, importPaths}) ->
|
||||
@lessSearchPaths = [
|
||||
@@ -35,5 +31,3 @@ class LessCompileCache
|
||||
|
||||
cssForFile: (stylesheetPath, lessContent) ->
|
||||
@cache.cssForFile(stylesheetPath, lessContent)
|
||||
|
||||
destroy: -> @unsubscribe()
|
||||
|
||||
@@ -213,8 +213,7 @@ LinesComponent = React.createClass
|
||||
innerHTML = ""
|
||||
|
||||
scopeStack = []
|
||||
firstTrailingWhitespacePosition = text.search(/\s*$/)
|
||||
lineIsWhitespaceOnly = firstTrailingWhitespacePosition is 0
|
||||
lineIsWhitespaceOnly = line.isOnlyWhitespace()
|
||||
for token in tokens
|
||||
innerHTML += @updateScopeStack(scopeStack, token.scopes)
|
||||
hasIndentGuide = not editor.isMini() and showIndentGuide and (token.hasLeadingWhitespace() or (token.hasTrailingWhitespace() and lineIsWhitespaceOnly))
|
||||
|
||||
@@ -268,7 +268,7 @@ class Marker
|
||||
|
||||
# Extended: Sets the buffer position of the marker's head.
|
||||
#
|
||||
# * `screenRange` The new {Point} to use
|
||||
# * `bufferPosition` The new {Point} to use
|
||||
# * `properties` (optional) {Object} properties to associate with the marker.
|
||||
setHeadBufferPosition: (bufferPosition, properties) ->
|
||||
@bufferMarker.setHeadPosition(bufferPosition, properties)
|
||||
@@ -281,7 +281,7 @@ class Marker
|
||||
|
||||
# Extended: Sets the screen position of the marker's head.
|
||||
#
|
||||
# * `screenRange` The new {Point} to use
|
||||
# * `screenPosition` The new {Point} to use
|
||||
# * `properties` (optional) {Object} properties to associate with the marker.
|
||||
setHeadScreenPosition: (screenPosition, properties) ->
|
||||
screenPosition = @displayBuffer.clipScreenPosition(screenPosition, properties)
|
||||
@@ -295,7 +295,7 @@ class Marker
|
||||
|
||||
# Extended: Sets the buffer position of the marker's tail.
|
||||
#
|
||||
# * `screenRange` The new {Point} to use
|
||||
# * `bufferPosition` The new {Point} to use
|
||||
# * `properties` (optional) {Object} properties to associate with the marker.
|
||||
setTailBufferPosition: (bufferPosition) ->
|
||||
@bufferMarker.setTailPosition(bufferPosition)
|
||||
@@ -308,7 +308,7 @@ class Marker
|
||||
|
||||
# Extended: Sets the screen position of the marker's tail.
|
||||
#
|
||||
# * `screenRange` The new {Point} to use
|
||||
# * `screenPosition` The new {Point} to use
|
||||
# * `properties` (optional) {Object} properties to associate with the marker.
|
||||
setTailScreenPosition: (screenPosition, options) ->
|
||||
screenPosition = @displayBuffer.clipScreenPosition(screenPosition, options)
|
||||
|
||||
@@ -176,7 +176,7 @@ class MenuManager
|
||||
element?.classList.toString().split(' ') ? []
|
||||
|
||||
sortPackagesMenu: ->
|
||||
packagesMenu = @template.find ({label}) -> MenuHelpers.normalizeLabel(label) is 'Packages'
|
||||
packagesMenu = _.find @template, ({label}) -> MenuHelpers.normalizeLabel(label) is 'Packages'
|
||||
return unless packagesMenu?.submenu?
|
||||
|
||||
packagesMenu.submenu.sort (item1, item2) ->
|
||||
|
||||