Comparar commits
560 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 98ea42d808 | |||
| 4e3a46ee71 | |||
| 9ebc5fa30e | |||
| 810ca750cd | |||
| 424652e27c | |||
| 831beceaac | |||
| 2daf026967 | |||
| dbd6a98bbe | |||
| a4ffdeb842 | |||
| 9b6194c5a4 | |||
| 8e4573677d | |||
| 61e9befbe7 | |||
| 0f50c40a93 | |||
| 907f8c34ac | |||
| c178d4c874 | |||
| 233fd44b01 | |||
| ab88edaa02 | |||
| 50c25d9e44 | |||
| 9be593d390 | |||
| 318c43931c | |||
| 244fc33f49 | |||
| f83f5263a9 | |||
| 3266dde2e3 | |||
| 3428ee335a | |||
| db6b4d7b81 | |||
| 1c195987c1 | |||
| 4913714a61 | |||
| 8e2856465c | |||
| 868c7a3908 | |||
| afaf91ebde | |||
| c92fe1452b | |||
| 2bde128fed | |||
| 89461505b5 | |||
| 85df5e61e5 | |||
| 5e477ff984 | |||
| 2baf9eda61 | |||
| 7d6d8175b9 | |||
| 0fdda032cc | |||
| c82d0f8c1c | |||
| 65ff108615 | |||
| 075611eb65 | |||
| b82537b020 | |||
| 06fee4636a | |||
| 5fe1af3239 | |||
| bf6cc3d384 | |||
| b4a4ba91b0 | |||
| 271776944a | |||
| b1d5a3d75f | |||
| bd68790a10 | |||
| f0a7663447 | |||
| db627d65c7 | |||
| a9f581797a | |||
| 763291230d | |||
| 55a77a34bd | |||
| f4f975c6b7 | |||
| 2d26382510 | |||
| c5cd56a99e | |||
| 24943dd526 | |||
| 8b32e30ee7 | |||
| 72c99be0f2 | |||
| 10ac1f6ae8 | |||
| 524170534c | |||
| d542f35336 | |||
| 697ba53c6b | |||
| 148a8bad2e | |||
| 7a344b91aa | |||
| 5783350484 | |||
| 9fce23d5ac | |||
| 7c17c99b9e | |||
| ff560bc3a3 | |||
| 61f01f4713 | |||
| 2e8c0234bb | |||
| 8e62d772b3 | |||
| 532cfb5775 | |||
| f912eb805d | |||
| 6838ff8ea2 | |||
| 8aa2c40bbf | |||
| c2d603769e | |||
| 3710d85e63 | |||
| 12a72302d9 | |||
| 2c70f0dc27 | |||
| 6165c65a51 | |||
| 3ea3f64214 | |||
| 08601d32a3 | |||
| 0ae1f6858c | |||
| f2e5b480e1 | |||
| 19ab197bc1 | |||
| 8bf1464b64 | |||
| 0ee3421cbc | |||
| a18536e8a4 | |||
| cc2e1eecd3 | |||
| 87b95128f9 | |||
| 344a56b47a | |||
| da8d055817 | |||
| c07272633f | |||
| b26e0d42d5 | |||
| 8ee4e927a1 | |||
| 7eaa3cb2b6 | |||
| 696928540c | |||
| b33f36d30a | |||
| 179b392a49 | |||
| 857f19c382 | |||
| 8a333208a2 | |||
| ff23f62c3e | |||
| dcdc9d6b90 | |||
| 3d28f957c7 | |||
| 2eb2aa5bef | |||
| 371820fd59 | |||
| 596c584ef1 | |||
| 27a1577021 | |||
| 8f2745c248 | |||
| 1c964d05f8 | |||
| 2dcbf7f751 | |||
| 067f73da38 | |||
| ae324c13a6 | |||
| 9a488adbb9 | |||
| 4c0f1efec6 | |||
| 8974cb5f34 | |||
| cb303a3149 | |||
| c44628a5b1 | |||
| fb1effc654 | |||
| 5ab213b854 | |||
| bbf738635c | |||
| 705d3e9fbc | |||
| 6bd3728548 | |||
| 7d997f6d9a | |||
| e919eb3eba | |||
| c2b2096c8c | |||
| 46638d2ea1 | |||
| fdb08517d3 | |||
| f272962562 | |||
| 9e661d8a99 | |||
| 43c0b79273 | |||
| 96e96c3c7f | |||
| 15c51b4417 | |||
| 6c93ca0e42 | |||
| a3cb98a3d3 | |||
| 31ecd39f08 | |||
| 4d986b8417 | |||
| 2d14c06089 | |||
| 7746ad0b13 | |||
| 1cbaf8d1f5 | |||
| cb41e2c41a | |||
| 2fd71f2fa8 | |||
| 37d67e8a83 | |||
| 2f8e67d679 | |||
| 22dc165a25 | |||
| ebfe50aafc | |||
| de58936ed1 | |||
| eba2abd5d9 | |||
| 864ab0c095 | |||
| de3d424f51 | |||
| 68c2c18d83 | |||
| 54907455fe | |||
| ba8ab21a0d | |||
| f272d9abde | |||
| 972f194388 | |||
| adb2f31e7f | |||
| ccfd239ad1 | |||
| 6fc56b9372 | |||
| 9072a6da7a | |||
| d39547097c | |||
| 3b2f58fa22 | |||
| cbddc4eb6f | |||
| 96a0c1039a | |||
| 1390bef626 | |||
| e70a2ab3de | |||
| e0d1bdc072 | |||
| 79c60d3884 | |||
| 1e85bc66b4 | |||
| 0d633a1e27 | |||
| 0759f6a1fd | |||
| 99b5675c4e | |||
| 4f7957183c | |||
| 2de18d3c4d | |||
| fecf13e2df | |||
| 31e44d50e4 | |||
| c28aeeac4a | |||
| 5649de6cd1 | |||
| 26a649abda | |||
| 3b02ae1ce9 | |||
| 13278c3d40 | |||
| 17760a458a | |||
| 282814fe59 | |||
| 35fb02fce9 | |||
| 7286c339c8 | |||
| b956fa4d1f | |||
| 8cb66895f0 | |||
| 3a9584b840 | |||
| 5d20a518ae | |||
| bd3dc453ef | |||
| 151d22c325 | |||
| d6433a67c8 | |||
| be561f0e5e | |||
| 1f6d90319b | |||
| eca63364a6 | |||
| 38f25160d6 | |||
| 28ce023164 | |||
| 10b3d56682 | |||
| 945011f9e3 | |||
| d7c6cd68b9 | |||
| ed4c3fde2d | |||
| c5db1c33a0 | |||
| d719ea74dd | |||
| 996defaadb | |||
| 86cd7f7a01 | |||
| a79090c65a | |||
| 86c720af81 | |||
| a9becd5cc8 | |||
| 1e327699b8 | |||
| 0ba9425bb6 | |||
| 7d19b839d9 | |||
| e1a9f0a533 | |||
| f6d0051446 | |||
| 126df1fa03 | |||
| 0a72d9539f | |||
| 60ecbe054e | |||
| 5a3fa18863 | |||
| bea4f2abde | |||
| 3fc2ca3d77 | |||
| 29fcc4727a | |||
| ddb973b03a | |||
| c2b05f9956 | |||
| 7fd452102f | |||
| c80d3eea47 | |||
| 8421edbb72 | |||
| 03587f54be | |||
| dac7760018 | |||
| bd28d5d7b1 | |||
| 34df19b204 | |||
| 6e824dadf2 | |||
| c50cfc1714 | |||
| d0fcd573bd | |||
| 79089ced97 | |||
| aa6811a088 | |||
| dd27a35039 | |||
| f3b696c5ec | |||
| 8405041f64 | |||
| a372993c44 | |||
| 909e0d7312 | |||
| e8503f7ddc | |||
| 42a6caf7dc | |||
| eaffb12ffb | |||
| 105e0d3c82 | |||
| 534a36c7e1 | |||
| b5b8f757b2 | |||
| 10e3dfbfdb | |||
| bfdcbbe9f1 | |||
| 5d49839236 | |||
| e6508237e7 | |||
| 2d4797c84e | |||
| 392516e60f | |||
| d09a2d0772 | |||
| 2bd5c10f09 | |||
| 5c910113a3 | |||
| c591a2e098 | |||
| b5acc9b093 | |||
| 5b6f8ff0f6 | |||
| d530d0a4d5 | |||
| 211ce4b2d3 | |||
| 1800438a77 | |||
| 1eda9a839a | |||
| e3cc400ac2 | |||
| b9b3d021cc | |||
| 6e202e18d8 | |||
| 750b57859a | |||
| 7ba520fea1 | |||
| da85a07dae | |||
| 01851523a0 | |||
| eda744f07f | |||
| 4acfe11af1 | |||
| 85824c5df6 | |||
| 20a0c27111 | |||
| 76200884d5 | |||
| ce4ce55b29 | |||
| 66f6e38788 | |||
| d97a0a3324 | |||
| 63f5a0a324 | |||
| f0837bb98b | |||
| 0f98a72876 | |||
| 1dd59204e9 | |||
| decae725a6 | |||
| 6c92d45ff3 | |||
| 272dd4a076 | |||
| 626ebe380e | |||
| f86ce48d65 | |||
| ef92cca9db | |||
| aa71810bfb | |||
| 22c47ac648 | |||
| e592528937 | |||
| 1fdb49f314 | |||
| aff37d1ae4 | |||
| a0234d0cc6 | |||
| 8a77acb51e | |||
| 690bbbd14c | |||
| 9c9bb2f192 | |||
| 23a40fe051 | |||
| 5d9cd662fc | |||
| 6c01589d3b | |||
| 820dde8ad2 | |||
| 3de4d63f44 | |||
| e1df82e0c3 | |||
| c1985b4a10 | |||
| 1ca9ce4db3 | |||
| 636705bd70 | |||
| 153dcd8ad3 | |||
| f2c2fe11b4 | |||
| 7a2c4fa5cc | |||
| 923816ca8e | |||
| 23d0b7b89e | |||
| a6b35f3a22 | |||
| 87fb39c8a5 | |||
| 4d188a79fb | |||
| a02b807dad | |||
| e0fa9d0213 | |||
| 35ad8abf4c | |||
| 372ca374cc | |||
| 75b6e94be1 | |||
| f912d0ef88 | |||
| 1bf8a01d0b | |||
| 5e8213d45f | |||
| 8b093122ac | |||
| bc14ad5b15 | |||
| fc543fc5a6 | |||
| 2e3aec81e7 | |||
| 9b04578d3e | |||
| 6654d32229 | |||
| 7c2c9448a3 | |||
| 6531128647 | |||
| fd1b895ff9 | |||
| f4e88bbcc0 | |||
| 7993f98166 | |||
| e11b775a31 | |||
| b999494154 | |||
| 6a7ed1a948 | |||
| d0889cca31 | |||
| 8b673c7adf | |||
| f1b0390b9b | |||
| b43d767a26 | |||
| bd4f642045 | |||
| 3bdfc7d785 | |||
| 4aa73968f0 | |||
| 06bc09951d | |||
| 9d59043788 | |||
| 33f0ca3042 | |||
| e1bc62dae3 | |||
| 77dbe9ccac | |||
| 150d8c2119 | |||
| b16f6adf76 | |||
| 834dd963ef | |||
| 01e0f9c2b7 | |||
| b4c0bb1f18 | |||
| f70fc683d1 | |||
| 956d4bd5bf | |||
| 8b45f89a75 | |||
| def6b67c8f | |||
| e8136853db | |||
| 084b41e33b | |||
| 6242bd7eb7 | |||
| 5fbe298f9c | |||
| b1c2c645df | |||
| d2a6aa5462 | |||
| 71abe66b8f | |||
| 01eb6e31ba | |||
| 071e6f885f | |||
| 5fcde96f88 | |||
| a1ad10b3ee | |||
| 6d26732208 | |||
| 20a396f190 | |||
| 4b7e5ca9fc | |||
| 8522707bd2 | |||
| a1505736d7 | |||
| 5cd17028d6 | |||
| 3089dd8688 | |||
| 044c45225b | |||
| 0c1ade82b2 | |||
| 7fdf5ed7dc | |||
| 6fb956688a | |||
| 28b362f8ff | |||
| 7035ccdcd2 | |||
| ba5ac8d872 | |||
| ea16ecc81f | |||
| 0eac9d3e6f | |||
| 68a8b6d437 | |||
| e136ba9f3e | |||
| 9ee6bea772 | |||
| 79bdde4f08 | |||
| 2a5f0e3c9f | |||
| 3c42f3de47 | |||
| 7cd15d408e | |||
| 5228b778dc | |||
| 49eaf7afeb | |||
| b2f02232f2 | |||
| 2f2d7da20b | |||
| 168043d422 | |||
| 101e1f6b50 | |||
| 323b6cec9d | |||
| 019a04c488 | |||
| e566bbc5e7 | |||
| d2140672fd | |||
| 667df80d35 | |||
| 0d8ad2d8b0 | |||
| 1796ff6871 | |||
| 49c54ee69a | |||
| d8e314b0a0 | |||
| 65acfe61ce | |||
| 2f067de10a | |||
| acecb50f7e | |||
| 9b27932d2c | |||
| 4aa8c0a76a | |||
| 246e43217a | |||
| 6925a5f3a4 | |||
| 81a92a9f13 | |||
| 8440d66d33 | |||
| 63ce978afe | |||
| b4e6386496 | |||
| f524a96add | |||
| 1d0f3bb831 | |||
| 2e0ef27570 | |||
| ebbb8fcef1 | |||
| 1d89d3dbe9 | |||
| 18512f5b99 | |||
| 5d4906b4d1 | |||
| 5e83a0eea6 | |||
| 3f43856145 | |||
| bb16ca6394 | |||
| 3f83aaf32d | |||
| e8ec565273 | |||
| 8ab6460571 | |||
| 19f7abf0f8 | |||
| ce2ad727c6 | |||
| fe213d1e13 | |||
| 35b78af446 | |||
| a72d4ccded | |||
| 1babf4ba55 | |||
| 18ab2477a8 | |||
| 9d56392cbc | |||
| 7cc68f59a7 | |||
| d6a9a0b15f | |||
| 766471f4b9 | |||
| 143a6a9cca | |||
| 7ad41a3ff2 | |||
| 12fadffb00 | |||
| ef97128fe6 | |||
| 1b0bc366e4 | |||
| 89c87f99e8 | |||
| 0e0b6a4978 | |||
| 7fe3caf841 | |||
| 2799892f1d | |||
| 7ecd839310 | |||
| 11a2628ed2 | |||
| a24b9cf9b9 | |||
| 705f77f5ba | |||
| c71cbf2e09 | |||
| 33aba7b721 | |||
| 58f4e5bf76 | |||
| 2095c7546a | |||
| 6005444fda | |||
| 658ccaf78f | |||
| 3112b2b071 | |||
| 32f746b918 | |||
| 5145a0260d | |||
| acc782b754 | |||
| e6508e6978 | |||
| 4e45fbbc04 | |||
| 81c2d70fbb | |||
| d2ec20bd10 | |||
| 6e3a7f8fa0 | |||
| 8e83acbafd | |||
| 40a8522460 | |||
| dfa9ca733e | |||
| 4681098e8c | |||
| 4f81d53d11 | |||
| dc5dc608ba | |||
| 83dc1c76ef | |||
| d660e9a066 | |||
| abcaaa3264 | |||
| 7f2b871885 | |||
| e51dd05989 | |||
| 51da7732f4 | |||
| 1b7dc2f147 | |||
| 63aedb65d9 | |||
| 9c503fe8d6 | |||
| 83e59bf5b0 | |||
| 4ef5c374ef | |||
| 764b31fdcd | |||
| 7fe2b41209 | |||
| 25a14bf44f | |||
| bde3606757 | |||
| 84f7af7e58 | |||
| bf0a448bff | |||
| be148574e3 | |||
| 235e00c19a | |||
| 87035eb4a9 | |||
| e67a9c9664 | |||
| 719dfd91ab | |||
| 5f97c46e5f | |||
| 739d171462 | |||
| f105602da5 | |||
| 01f4ebde54 | |||
| 97f3d1662e | |||
| aa04589dd2 | |||
| 9473039a0b | |||
| 574cc098c6 | |||
| f17c490768 | |||
| 6d246f5244 | |||
| bec30ae833 | |||
| feb501c76f | |||
| b32f4ad80a | |||
| 4b12228b15 | |||
| afd576697e | |||
| 6a24360ffd | |||
| 5faa69b66c | |||
| 833498011c | |||
| 4f6cc659c4 | |||
| 5cef77e52c | |||
| 712ab734dd | |||
| 0f0a57af1c | |||
| ce5eef2605 | |||
| 6d6960badb | |||
| 54269aa92a | |||
| ec65a71d6d | |||
| 761fcde654 | |||
| 3346ddac38 | |||
| f20c55f849 | |||
| 37c5c35a12 | |||
| e541ccb197 | |||
| 1f7027d825 | |||
| 0d9e7a5e08 | |||
| c4ac96e669 | |||
| 74f65b978e | |||
| eab874b3ef | |||
| 54d9361dad | |||
| e8cd130ad6 | |||
| 2f70f4ba25 | |||
| 1548167b94 | |||
| 91a320127a | |||
| 7a0a4dc3b3 | |||
| ba9c006cb4 | |||
| 2f92160e9c | |||
| 8f0063465c | |||
| 0c8bb089b9 | |||
| 746b99508b | |||
| 05ce497f29 | |||
| 5bfb382209 | |||
| 32efa7b112 | |||
| e4fcd589db | |||
| 8da5a99196 | |||
| d5cb79027a | |||
| fea1a001ee | |||
| 3ae6f0a93d | |||
| 28d7db2371 | |||
| 02b582a60d | |||
| 83a40e1b33 | |||
| ca0a875e6b | |||
| 9932d4789e | |||
| 2c68dfd8cf | |||
| 64f66fad4d | |||
| 5a8e3100b9 | |||
| 87dedc3dd2 |
@@ -0,0 +1,2 @@
|
||||
ca =
|
||||
cache = ~/.atom/.npm
|
||||
+1
-1
@@ -10,7 +10,7 @@ to propose changes to this document in a pull request.
|
||||
that behavior such as Emacs, vi, Xcode, etc.
|
||||
* Check the Console app for stack traces to include if reporting a crash.
|
||||
* Check the Dev tools (`alt-cmd-i`) for errors and stack traces to include.
|
||||
|
||||
|
||||
### Package Repositories
|
||||
|
||||
This is the repository for the core Atom editor only. Atom comes bundled with
|
||||
|
||||
+56
-15
@@ -1,11 +1,13 @@
|
||||
#!/bin/sh
|
||||
ATOM_PATH=${ATOM_PATH-/Applications/Atom.app}
|
||||
ATOM_BINARY=$ATOM_PATH/Contents/MacOS/Atom
|
||||
#!/bin/bash
|
||||
|
||||
if [ ! -d $ATOM_PATH ]; then sleep 5; fi # Wait for Atom to reappear, Sparkle may be replacing it.
|
||||
|
||||
if [ ! -d $ATOM_PATH ]; then
|
||||
echo "Atom application not found at '$ATOM_PATH'" >&2
|
||||
if [ "`uname`" == 'Darwin' ]; then
|
||||
OS='Mac'
|
||||
elif [ "`expr substr $(uname -s) 1 5`" == 'Linux' ]; then
|
||||
OS='Linux'
|
||||
elif [ "`expr substr $(uname -s) 1 10`" == 'MINGW32_NT' ]; then
|
||||
OS='Cygwin'
|
||||
else
|
||||
echo "Your platform (`uname -a`) is not supported."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -16,7 +18,11 @@ while getopts ":wtfvhs-:" opt; do
|
||||
wait)
|
||||
WAIT=1
|
||||
;;
|
||||
help|version|foreground|test)
|
||||
help|version)
|
||||
REDIRECT_STDERR=1
|
||||
EXPECT_OUTPUT=1
|
||||
;;
|
||||
foreground|test)
|
||||
EXPECT_OUTPUT=1
|
||||
;;
|
||||
esac
|
||||
@@ -24,25 +30,60 @@ while getopts ":wtfvhs-:" opt; do
|
||||
w)
|
||||
WAIT=1
|
||||
;;
|
||||
h|v|f|t)
|
||||
h|v)
|
||||
REDIRECT_STDERR=1
|
||||
EXPECT_OUTPUT=1
|
||||
;;
|
||||
f|t)
|
||||
EXPECT_OUTPUT=1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ $EXPECT_OUTPUT ]; then
|
||||
$ATOM_BINARY --executed-from="$(pwd)" --pid=$$ $@
|
||||
exit $?
|
||||
else
|
||||
open -a $ATOM_PATH -n --args --executed-from="$(pwd)" --pid=$$ $@
|
||||
if [ $REDIRECT_STDERR ]; then
|
||||
exec 2> /dev/null
|
||||
fi
|
||||
|
||||
# Used to exit process when atom is used as $EDITOR
|
||||
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'" | head -1 | xargs dirname)
|
||||
fi
|
||||
|
||||
# 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
|
||||
fi
|
||||
|
||||
if [ $EXPECT_OUTPUT ]; then
|
||||
"$ATOM_PATH/$ATOM_APP_NAME/Contents/MacOS/Atom" --executed-from="$(pwd)" --pid=$$ "$@"
|
||||
exit $?
|
||||
else
|
||||
open -a "$ATOM_PATH/$ATOM_APP_NAME" -n --args --executed-from="$(pwd)" --pid=$$ "$@"
|
||||
fi
|
||||
elif [ $OS == 'Linux' ]; then
|
||||
ATOM_PATH='/opt/Atom/atom'
|
||||
[ -x "$ATOM_PATH" ] || ATOM_PATH='/tmp/atom-build/Atom/atom'
|
||||
|
||||
if [ $EXPECT_OUTPUT ]; then
|
||||
"$ATOM_PATH" --executed-from="$(pwd)" --pid=$$ "$@"
|
||||
exit $?
|
||||
else
|
||||
nohup "$ATOM_PATH" --executed-from="$(pwd)" --pid=$$ "$@" > /dev/null &
|
||||
fi
|
||||
fi
|
||||
|
||||
# Exits this process when Atom is used as $EDITOR
|
||||
on_die() {
|
||||
exit 0
|
||||
}
|
||||
trap 'on_die' SIGQUIT SIGTERM
|
||||
|
||||
# If the wait flag is set, don't exit this process until Atom tells it to.
|
||||
if [ $WAIT ]; then
|
||||
while true; do
|
||||
sleep 1
|
||||
|
||||
@@ -41,19 +41,31 @@ module.exports = (grunt) ->
|
||||
tmpDir = os.tmpdir()
|
||||
installRoot = process.env.ProgramFiles
|
||||
buildDir = grunt.option('build-dir') ? path.join(tmpDir, 'atom-build')
|
||||
symbolsDir = path.join(buildDir, 'Atom.breakpad.syms')
|
||||
shellAppDir = path.join(buildDir, appName)
|
||||
contentsDir = shellAppDir
|
||||
appDir = path.join(shellAppDir, 'resources', 'app')
|
||||
atomShellDownloadDir = path.join(os.tmpdir(), 'atom-cached-atom-shells')
|
||||
else
|
||||
else if process.platform is 'darwin'
|
||||
appName = 'Atom.app'
|
||||
tmpDir = '/tmp'
|
||||
installRoot = '/Applications'
|
||||
buildDir = grunt.option('build-dir') ? path.join(tmpDir, 'atom-build')
|
||||
symbolsDir = path.join(buildDir, 'Atom.breakpad.syms')
|
||||
shellAppDir = path.join(buildDir, appName)
|
||||
contentsDir = path.join(shellAppDir, 'Contents')
|
||||
appDir = path.join(contentsDir, 'Resources', 'app')
|
||||
atomShellDownloadDir = '/tmp/atom-cached-atom-shells'
|
||||
else
|
||||
appName = 'Atom'
|
||||
tmpDir = '/tmp'
|
||||
installRoot = '/opt'
|
||||
buildDir = grunt.option('build-dir') ? path.join(tmpDir, 'atom-build')
|
||||
symbolsDir = path.join(buildDir, 'Atom.breakpad.syms')
|
||||
shellAppDir = path.join(buildDir, appName)
|
||||
contentsDir = shellAppDir
|
||||
appDir = path.join(shellAppDir, 'resources', 'app')
|
||||
atomShellDownloadDir = '/tmp/atom-cached-atom-shells'
|
||||
|
||||
installDir = path.join(installRoot, appName)
|
||||
|
||||
@@ -123,7 +135,7 @@ module.exports = (grunt) ->
|
||||
grunt.initConfig
|
||||
pkg: grunt.file.readJSON('package.json')
|
||||
|
||||
atom: {appDir, appName, buildDir, contentsDir, installDir, shellAppDir}
|
||||
atom: {appDir, appName, symbolsDir, buildDir, contentsDir, installDir, shellAppDir}
|
||||
|
||||
coffee: coffeeConfig
|
||||
|
||||
@@ -223,6 +235,9 @@ module.exports = (grunt) ->
|
||||
grunt.registerTask('compile', ['coffee', 'prebuild-less', 'cson', 'peg'])
|
||||
grunt.registerTask('lint', ['coffeelint', 'csslint', 'lesslint'])
|
||||
grunt.registerTask('test', ['shell:kill-atom', 'run-specs'])
|
||||
grunt.registerTask('ci', ['output-disk-space', 'download-atom-shell', 'build', 'set-version', 'check-licenses', 'lint', 'test', 'codesign', 'publish-build'])
|
||||
grunt.registerTask('ci', ['output-disk-space', 'download-atom-shell', 'build', 'dump-symbols', 'set-version', 'check-licenses', 'lint', 'test', 'codesign', 'publish-build'])
|
||||
grunt.registerTask('docs', ['markdown:guides', 'build-docs'])
|
||||
grunt.registerTask('default', ['download-atom-shell', 'build', 'set-version', 'install'])
|
||||
|
||||
defaultTasks = ['download-atom-shell', 'build', 'set-version']
|
||||
defaultTasks.push 'install' unless process.platform is 'linux'
|
||||
grunt.registerTask('default', defaultTasks)
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
"grunt-contrib-csslint": "~0.1.2",
|
||||
"grunt-contrib-coffee": "~0.9.0",
|
||||
"grunt-contrib-less": "~0.8.0",
|
||||
"grunt-cson": "0.6.0",
|
||||
"grunt-download-atom-shell": "git+https://atom-bot:467bac80a0017b96fb5be5cfc686f5e0cc607b10@github.com/atom/grunt-download-atom-shell#v0.6.0",
|
||||
"grunt-cson": "0.8.0",
|
||||
"grunt-download-atom-shell": "git+https://atom-bot:467bac80a0017b96fb5be5cfc686f5e0cc607b10@github.com/atom/grunt-download-atom-shell#v0.6.1",
|
||||
"grunt-lesslint": "0.13.0",
|
||||
"grunt-markdown": "~0.4.0",
|
||||
"grunt-peg": "~1.1.0",
|
||||
@@ -26,12 +26,14 @@
|
||||
"harmony-collections": "~0.3.8",
|
||||
"json-front-matter": "~0.1.3",
|
||||
"legal-eagle": "~0.3.0",
|
||||
"minidump": "0.5.x",
|
||||
"rcedit": "~0.1.2",
|
||||
"request": "~2.27.0",
|
||||
"rimraf": "~2.2.2",
|
||||
"runas": "0.5.x",
|
||||
"underscore-plus": "1.x",
|
||||
"unzip": "~0.1.9",
|
||||
"vm-compatibility-layer": "~0.1.0"
|
||||
"vm-compatibility-layer": "~0.1.0",
|
||||
"npm": "~1.4.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ module.exports = (grunt) ->
|
||||
|
||||
if process.platform is 'darwin'
|
||||
cp 'atom-shell/Atom.app', shellAppDir
|
||||
else if process.platform is 'win32'
|
||||
else
|
||||
cp 'atom-shell', shellAppDir
|
||||
|
||||
mkdir appDir
|
||||
|
||||
@@ -15,6 +15,9 @@ module.exports = (grunt) ->
|
||||
console.error(err)
|
||||
exit 1
|
||||
|
||||
for key of summary
|
||||
delete summary[key] if key.match /^atom@/
|
||||
|
||||
if size(summary)
|
||||
console.error "Found dependencies without permissive licenses:"
|
||||
for name in keys(summary).sort()
|
||||
|
||||
@@ -143,6 +143,8 @@ downloadFileFromRepo = ({repo, file}, callback) ->
|
||||
|
||||
downloadIncludes = (callback) ->
|
||||
includes = [
|
||||
{repo: 'atom-keymap', file: 'src/keymap.coffee'}
|
||||
{repo: 'atom-keymap', file: 'src/key-binding.coffee'}
|
||||
{repo: 'first-mate', file: 'src/grammar.coffee'}
|
||||
{repo: 'first-mate', file: 'src/grammar-registry.coffee'}
|
||||
{repo: 'node-pathwatcher', file: 'src/directory.coffee'}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
async = require 'async'
|
||||
fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
minidump = require 'minidump'
|
||||
|
||||
module.exports = (grunt) ->
|
||||
{mkdir, rm} = require('./task-helpers')(grunt)
|
||||
|
||||
dumpSymbolTo = (binaryPath, targetDirectory, callback) ->
|
||||
minidump.dumpSymbol binaryPath, (error, content) ->
|
||||
return callback(error) if error?
|
||||
|
||||
moduleLine = /MODULE [^ ]+ [^ ]+ ([0-9A-F]+) (.*)\n/.exec(content)
|
||||
if moduleLine.length isnt 3
|
||||
return callback("Invalid output when dumping symbol for #{binaryPath}")
|
||||
|
||||
filename = moduleLine[2]
|
||||
targetPathDirname = path.join(targetDirectory, filename, moduleLine[1])
|
||||
mkdir targetPathDirname
|
||||
|
||||
targetPath = path.join(targetPathDirname, "#{filename}.sym")
|
||||
fs.writeFile(targetPath, content, callback)
|
||||
|
||||
grunt.registerTask 'dump-symbols', 'Dump symbols for native modules', ->
|
||||
done = @async()
|
||||
|
||||
symbolsDir = grunt.config.get('atom.symbolsDir')
|
||||
rm symbolsDir
|
||||
mkdir symbolsDir
|
||||
|
||||
tasks = []
|
||||
onFile = (binaryPath) ->
|
||||
if /.*\.node$/.test(binaryPath)
|
||||
tasks.push(dumpSymbolTo.bind(this, binaryPath, symbolsDir))
|
||||
onDirectory = ->
|
||||
true
|
||||
fs.traverseTreeSync 'node_modules', onFile, onDirectory
|
||||
|
||||
async.parallel tasks, done
|
||||
@@ -2,14 +2,17 @@ child_process = require 'child_process'
|
||||
path = require 'path'
|
||||
|
||||
_ = require 'underscore-plus'
|
||||
async = require 'async'
|
||||
fs = require 'fs-plus'
|
||||
GitHub = require 'github-releases'
|
||||
request = require 'request'
|
||||
|
||||
grunt = null
|
||||
maxReleases = 10
|
||||
assetName = 'atom-mac.zip'
|
||||
assetPath = "/tmp/atom-build/#{assetName}"
|
||||
assets = [
|
||||
{assetName: 'atom-mac.zip', sourceName: 'Atom.app'}
|
||||
{assetName: 'atom-mac-symbols.zip', sourceName: 'Atom.breakpad.syms'}
|
||||
]
|
||||
commitSha = process.env.JANKY_SHA1
|
||||
token = process.env.ATOM_ACCESS_TOKEN
|
||||
defaultHeaders =
|
||||
@@ -18,39 +21,48 @@ defaultHeaders =
|
||||
|
||||
module.exports = (gruntObject) ->
|
||||
grunt = gruntObject
|
||||
|
||||
grunt.registerTask 'publish-build', 'Publish the built app', ->
|
||||
return unless process.platform is 'darwin'
|
||||
return if process.env.JANKY_SHA1 and process.env.JANKY_BRANCH isnt 'master'
|
||||
|
||||
done = @async()
|
||||
buildDir = grunt.config.get('atom.buildDir')
|
||||
|
||||
createBuildRelease (error, release) ->
|
||||
return done(error) if error?
|
||||
zipApp (error) ->
|
||||
|
||||
zipApps buildDir, assets, (error) ->
|
||||
return done(error) if error?
|
||||
uploadAsset release, (error) ->
|
||||
uploadAssets release, buildDir, assets, (error) ->
|
||||
return done(error) if error?
|
||||
publishRelease release, (error) ->
|
||||
return done(error) if error?
|
||||
getAtomDraftRelease (error, release) ->
|
||||
return done(error) if error?
|
||||
deleteExistingAsset release, (error) ->
|
||||
assetNames = (asset.assetName for asset in assets)
|
||||
deleteExistingAssets release, assetNames, (error) ->
|
||||
return done(error) if error?
|
||||
uploadAsset(release, done)
|
||||
uploadAssets(release, buildDir, assets, done)
|
||||
|
||||
logError = (message, error, details) ->
|
||||
grunt.log.error(message)
|
||||
grunt.log.error(error.message ? error) if error?
|
||||
grunt.log.error(details) if details
|
||||
|
||||
zipApp = (callback) ->
|
||||
fs.removeSync(assetPath)
|
||||
zipApps = (buildDir, assets, callback) ->
|
||||
zip = (directory, sourceName, assetName, callback) ->
|
||||
options = {cwd: directory, maxBuffer: Infinity}
|
||||
child_process.exec "zip -r --symlinks #{assetName} #{sourceName}", options, (error, stdout, stderr) ->
|
||||
if error?
|
||||
logError("Zipping #{sourceName} failed", error, stderr)
|
||||
callback(error)
|
||||
|
||||
options = {cwd: path.dirname(assetPath), maxBuffer: Infinity}
|
||||
child_process.exec "zip -r --symlinks #{assetName} Atom.app", options, (error, stdout, stderr) ->
|
||||
if error?
|
||||
logError('Zipping Atom.app failed', error, stderr)
|
||||
callback(error)
|
||||
tasks = []
|
||||
for {assetName, sourceName} in assets
|
||||
fs.removeSync(path.join(buildDir, assetName))
|
||||
tasks.push(zip.bind(this, buildDir, sourceName, assetName))
|
||||
async.parallel(tasks, callback)
|
||||
|
||||
getRelease = (callback) ->
|
||||
options =
|
||||
@@ -93,10 +105,12 @@ deleteRelease = (release) ->
|
||||
if error? or response.statusCode isnt 204
|
||||
logError('Deleting release failed', error, body)
|
||||
|
||||
deleteExistingAsset = (release, callback) ->
|
||||
for asset in release.assets when asset.name is assetName
|
||||
deleteExistingAssets = (release, assetNames, callback) ->
|
||||
[callback, assetNames] = [assetNames, callback] if not callback?
|
||||
|
||||
deleteAsset = (url, callback) ->
|
||||
options =
|
||||
uri: asset.url
|
||||
uri: url
|
||||
method: 'DELETE'
|
||||
headers: defaultHeaders
|
||||
request options, (error, response, body='') ->
|
||||
@@ -106,9 +120,10 @@ deleteExistingAsset = (release, callback) ->
|
||||
else
|
||||
callback()
|
||||
|
||||
return
|
||||
|
||||
callback()
|
||||
tasks = []
|
||||
for asset in release.assets when not assetNames? or asset.name in assetNames
|
||||
tasks.push(deleteAsset.bind(this, asset.url))
|
||||
async.parallel(tasks, callback)
|
||||
|
||||
createBuildRelease = (callback) ->
|
||||
getRelease (error, release) ->
|
||||
@@ -117,7 +132,7 @@ createBuildRelease = (callback) ->
|
||||
return
|
||||
|
||||
if release?
|
||||
deleteExistingAsset release, (error) ->
|
||||
deleteExistingAssets release, (error) ->
|
||||
callback(error, release)
|
||||
return
|
||||
|
||||
@@ -139,23 +154,30 @@ createBuildRelease = (callback) ->
|
||||
else
|
||||
callback(null, release)
|
||||
|
||||
uploadAsset = (release, callback) ->
|
||||
options =
|
||||
uri: release.upload_url.replace(/\{.*$/, "?name=#{assetName}")
|
||||
method: 'POST'
|
||||
headers: _.extend({
|
||||
'Content-Type': 'application/zip'
|
||||
'Content-Length': fs.getSizeSync(assetPath)
|
||||
}, defaultHeaders)
|
||||
uploadAssets = (release, buildDir, assets, callback) ->
|
||||
upload = (release, assetName, assetPath, callback) ->
|
||||
options =
|
||||
uri: release.upload_url.replace(/\{.*$/, "?name=#{assetName}")
|
||||
method: 'POST'
|
||||
headers: _.extend({
|
||||
'Content-Type': 'application/zip'
|
||||
'Content-Length': fs.getSizeSync(assetPath)
|
||||
}, defaultHeaders)
|
||||
|
||||
assetRequest = request options, (error, response, body='') ->
|
||||
if error? or response.statusCode >= 400
|
||||
logError('Upload release asset failed', error, body)
|
||||
callback(error ? new Error(response.statusCode))
|
||||
else
|
||||
callback(null, release)
|
||||
assetRequest = request options, (error, response, body='') ->
|
||||
if error? or response.statusCode >= 400
|
||||
logError("Upload release asset #{assetName} failed", error, body)
|
||||
callback(error ? new Error(response.statusCode))
|
||||
else
|
||||
callback(null, release)
|
||||
|
||||
fs.createReadStream(assetPath).pipe(assetRequest)
|
||||
fs.createReadStream(assetPath).pipe(assetRequest)
|
||||
|
||||
tasks = []
|
||||
for {assetName, sourceName} in assets
|
||||
assetPath = path.join(buildDir, assetName)
|
||||
tasks.push(upload.bind(this, release, assetName, assetPath))
|
||||
async.parallel(tasks, callback)
|
||||
|
||||
publishRelease = (release, callback) ->
|
||||
options =
|
||||
|
||||
@@ -48,3 +48,5 @@ module.exports = (grunt) ->
|
||||
|
||||
rcedit = require('rcedit')
|
||||
rcedit(shellExePath, {'version-string': strings}, done)
|
||||
else
|
||||
done()
|
||||
|
||||
@@ -31,6 +31,7 @@ The classes available from `require 'atom'` are:
|
||||
* [SelectListView][SelectListView]
|
||||
* [View][View]
|
||||
* [WorkspaceView][WorkspaceView]
|
||||
* [Workspace][Workspace]
|
||||
|
||||
### How do I create a package?
|
||||
|
||||
@@ -54,5 +55,6 @@ Atom ships with node 0.11.10 and the comprehensive node API docs are available
|
||||
[SelectListView]: ../classes/SelectListView.html
|
||||
[View]: ../classes/View.html
|
||||
[WorkspaceView]: ../classes/WorkspaceView.html
|
||||
[Workspace]: ../classes/Workspace.html
|
||||
[creating-a-package]: https://atom.io/docs/latest/creating-a-package
|
||||
[node-docs]: http://nodejs.org/docs/v0.11.10/api
|
||||
|
||||
@@ -40,7 +40,7 @@ the editor to see it in action!
|
||||
|
||||
### Further Reading
|
||||
|
||||
* Check out [Publishing a Package](publish-a-package.html) for more information
|
||||
* Check out [Publishing a Package](publishing-a-package.html) for more information
|
||||
on publishing the package you just created to [atom.io][atomio].
|
||||
|
||||
[atomio]: https://atom.io
|
||||
|
||||
@@ -57,7 +57,7 @@ __Syntax Theme__ dropdown menu to enable your new theme.
|
||||
|
||||
### Further Reading
|
||||
|
||||
* Check out [Publishing a Package](publish-a-package.html) for more information
|
||||
* Check out [Publishing a Package](publishing-a-package.html) for more information
|
||||
on publishing the theme you just created to [atom.io][atomio].
|
||||
|
||||
[atomio]: https://atom.io
|
||||
|
||||
@@ -24,6 +24,9 @@ Not every package will have (or need) all of these directories.
|
||||
|
||||
We have [a tutorial on creating your first package][first-package].
|
||||
|
||||
There are also guides for converting [TextMate bundles][convert-bundle] and
|
||||
[TextMate themes][convert-theme] so they work in Atom.
|
||||
|
||||
## package.json
|
||||
|
||||
Similar to [npm packages][npm], Atom packages contain a _package.json_ file
|
||||
@@ -127,7 +130,7 @@ Ideally, you won't need much in the way of styling. We've provided a standard
|
||||
set of components which define both the colors and UI elements for any package
|
||||
that fits into Atom seamlessly. You can view all of Atom's UI components by opening
|
||||
the styleguide: open the command palette (`cmd-shift-P`) and search for _styleguide_,
|
||||
or just type `cmd-ctrl-G`.
|
||||
or just type `cmd-ctrl-shift-G`.
|
||||
|
||||
If you _do_ need special styling, try to keep only structural styles in the package
|
||||
stylesheets. If you _must_ specify colors and sizing, these should be taken from
|
||||
@@ -322,27 +325,20 @@ Your package **should** have tests, and if they're placed in the _spec_
|
||||
directory, they can be run by Atom.
|
||||
|
||||
Under the hood, [Jasmine] executes your tests, so you can assume that any DSL
|
||||
available there is available to your package as well.
|
||||
|
||||
**FIXME: Explain the following**
|
||||
|
||||
* jasmine
|
||||
* jasmine-focused
|
||||
* `spec/fixtures` and global.project
|
||||
* setTimeout
|
||||
* whatever else is different in spec-helper
|
||||
available there is also available to your package.
|
||||
|
||||
## Running Tests
|
||||
|
||||
TODO: Probably use the menu option now.
|
||||
Once you've got your test suite written, you can run it by pressing
|
||||
`cmd-alt-ctrl-p` or via the _Developer > Run Package Specs_ menu.
|
||||
|
||||
Once you've got your test suite written, the recommended way to run it is `apm
|
||||
test`. `apm test` prints its output to the console and returns the proper status
|
||||
code depending on whether tests passed or failed.
|
||||
You can also use the `apm test` command to run them from the command line. It
|
||||
prints the test output and results to the console and returns the proper status
|
||||
code depending on whether the tests passed or failed.
|
||||
|
||||
## Publishing
|
||||
|
||||
Atom bundles a command line utility called [apm] which can be used to publish
|
||||
Atom bundles a command line utility called apm which can be used to publish
|
||||
Atom packages to the public registry.
|
||||
|
||||
Once your package is written and ready for distribution you can run the
|
||||
@@ -360,25 +356,11 @@ registry.
|
||||
Run `apm help publish` to see all the available options and `apm help` to see
|
||||
all the other available commands.
|
||||
|
||||
## Included Libraries
|
||||
|
||||
FIXME: Describe `require 'atom'
|
||||
|
||||
In addition to core node.js modules, all packages can `require` the following
|
||||
popular libraries into their packages:
|
||||
|
||||
* [SpacePen] (as `require 'space-pen'`)
|
||||
* [jQuery] (as `require 'jquery'`)
|
||||
* [Underscore] (as `require 'underscore'`)
|
||||
|
||||
Additional libraries can be found by browsing Atom's *node_modules* folder.
|
||||
|
||||
[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
|
||||
[apm]: https://github.com/atom/apm
|
||||
[git-tag]: http://git-scm.com/book/en/Git-Basics-Tagging
|
||||
[wrap-guide]: https://github.com/atom/wrap-guide/
|
||||
[keymaps]: advanced/keymaps.md
|
||||
@@ -388,8 +370,10 @@ Additional libraries can be found by browsing Atom's *node_modules* folder.
|
||||
[path]: http://nodejs.org/docs/latest/api/path.html
|
||||
[jquery]: http://jquery.com/
|
||||
[underscore]: http://underscorejs.org/
|
||||
[jasmine]: https://github.com/pivotal/jasmine
|
||||
[jasmine]: http://jasmine.github.io
|
||||
[cson]: https://github.com/atom/season
|
||||
[less]: http://lesscss.org
|
||||
[ui-variables]: https://github.com/atom/atom-dark-ui/blob/master/stylesheets/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
|
||||
|
||||
+20
-13
@@ -32,14 +32,15 @@ Let's create your first theme.
|
||||
|
||||
To get started, hit `cmd-shift-P`, and start typing "Generate Syntax Theme" to
|
||||
generate a new theme package. Select "Generate Syntax Theme," and you'll be
|
||||
asked for the path where your theme will be created. Let's call ours _motif_.
|
||||
asked for the path where your theme will be created. Let's call ours
|
||||
_motif-syntax_. __Tip:__ syntax themes should end with _-syntax_.
|
||||
|
||||
Atom will pop open a new window, showing the _motif_ theme, with a default set
|
||||
of folders and files created for us. If you open the settings view (`cmd-,`)
|
||||
and navigate to the _Themes_ section on the left, you'll see the _Motif_ theme
|
||||
listed in the _Syntax Theme_ drop-down. Select it from the menu to activate it,
|
||||
now when you open an editor you should see that your new _motif_ theme in
|
||||
action.
|
||||
Atom will pop open a new window, showing the _motif-syntax_ theme, with a
|
||||
default set of folders and files created for us. If you open the settings view
|
||||
(`cmd-,`) and navigate to the _Themes_ section on the left, you'll see the
|
||||
_Motif_ theme listed in the _Syntax Theme_ drop-down. Select it from the menu to
|
||||
activate it, now when you open an editor you should see that your new
|
||||
_motif-syntax_ theme in action.
|
||||
|
||||
Open up _stylesheets/colors.less_ to change the various colors variables which
|
||||
have been already been defined. For example, turn `@red` into `#f4c2c1`.
|
||||
@@ -50,9 +51,14 @@ editor such as comments, strings and the line numbers in the gutter.
|
||||
|
||||
As an example, let's make the `.gutter` `background-color` into `@red`.
|
||||
|
||||
Reload Atom by pressing `cmd-alt-option-L` to see the changes you made reflected
|
||||
Reload Atom by pressing `cmd-alt-ctrl-l` to see the changes you made reflected
|
||||
in your Atom window. Pretty neat!
|
||||
|
||||
__Tip:__ You can avoid reloading to see changes you make by opening an atom
|
||||
window in dev mode. To open a Dev Mode Atom window run `atom --dev .` in the
|
||||
terminal, use `cmd-shift-o` or use the _View > Developer > Open in Dev Mode_
|
||||
menu. When you edit your theme, changes will instantly be reflected!
|
||||
|
||||
## Creating an Interface Theme
|
||||
|
||||
Interface themes **must** provide a `ui-variables.less` file which contains all
|
||||
@@ -66,13 +72,14 @@ To create an interface UI theme, do the following:
|
||||
2. Clone the forked repository to the local filesystem
|
||||
3. Open a terminal in the forked theme's directory
|
||||
4. Open your new theme in a Dev Mode Atom window run `atom --dev .` in the
|
||||
terminal or use the _View > Developer > Open in Dev Mode_ menu)
|
||||
terminal or use the _View > Developer > Open in Dev Mode_ menu
|
||||
5. Change the name of the theme in the theme's `package.json` file
|
||||
6. Run `apm link` to symlink your repository to `~/.atom/packages`
|
||||
7. Reload Atom using `cmd-alt-ctrl-L`
|
||||
8. Enable the theme via _UI Theme_ drop-down in the _Themes_ section of the
|
||||
6. Name your theme end with a `-ui`. i.e. `super-white-ui`
|
||||
7. Run `apm link` to symlink your repository to `~/.atom/packages`
|
||||
8. Reload Atom using `cmd-alt-ctrl-L`
|
||||
9. Enable the theme via _UI Theme_ drop-down in the _Themes_ section of the
|
||||
settings view
|
||||
9. Make changes! Since you opened the theme in a Dev Mode window, changes will
|
||||
10. Make changes! Since you opened the theme in a Dev Mode window, changes will
|
||||
be instantly reflected in the editor without having to reload.
|
||||
|
||||
## Development workflow
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Customizing Atom
|
||||
|
||||
To change a setting, configure a theme, or install a package just open the
|
||||
Settings view in the current window by pressing `cmd+,`.
|
||||
Settings view in the current window by pressing `cmd-,`.
|
||||
|
||||
## Changing The Theme
|
||||
|
||||
@@ -63,9 +63,8 @@ built-in keymaps:
|
||||
'.editor':
|
||||
'enter': 'editor:newline'
|
||||
|
||||
'body':
|
||||
'ctrl-b': 'core:move-left'
|
||||
'ctrl-f': 'core:move-right'
|
||||
'.mini.editor input':
|
||||
'enter': 'core:confirm'
|
||||
```
|
||||
|
||||
This keymap defines the meaning of `enter` in two different contexts. In a
|
||||
@@ -87,7 +86,7 @@ currently in use.
|
||||
## Advanced Configuration
|
||||
|
||||
Atom loads configuration settings from the `config.cson` file in your _~/.atom_
|
||||
directory, which contains CoffeeScript-style JSON:
|
||||
directory, which contains [CoffeeScript-style JSON][CSON] (CSON):
|
||||
|
||||
```coffee
|
||||
'core':
|
||||
@@ -111,7 +110,6 @@ You can open this file in an editor from the _Atom > Open Your Config_ menu.
|
||||
- `themes`: An array of theme names to load, in cascading order
|
||||
- `editor`
|
||||
- `autoIndent`: Enable/disable basic auto-indent (defaults to `true`)
|
||||
- `autoIndentOnPaste`: Enable/disable auto-indented pasted text (defaults to `false`)
|
||||
- `nonWordCharacters`: A string of non-word characters to define word boundaries
|
||||
- `fontSize`: The editor font size
|
||||
- `fontFamily`: The editor font family
|
||||
@@ -142,13 +140,21 @@ You can open this file in an editor from the _Atom > Open Your Config_ menu.
|
||||
### init.coffee
|
||||
|
||||
When Atom finishes loading, it will evaluate _init.coffee_ in your _~/.atom_
|
||||
directory, giving you a chance to run arbitrary personal CoffeeScript code to
|
||||
directory, giving you a chance to run arbitrary personal [CoffeeScript][] code to
|
||||
make customizations. You have full access to Atom's API from code in this file.
|
||||
If customizations become extensive, consider [creating a package][create-a-package].
|
||||
If customizations become extensive, consider [creating a package][creating-a-package].
|
||||
|
||||
You can open this file in an editor from the _Atom > Open Your Init Script_
|
||||
menu.
|
||||
|
||||
For example, if you have the Audio Beep configuration setting enabled, you
|
||||
could add the following code to your _~/.atom/init.coffee_ file to have Atom
|
||||
greet you with an audio beep every time it loads:
|
||||
|
||||
```coffee
|
||||
atom.beep()
|
||||
```
|
||||
|
||||
This file can also be named _init.js_ and contain JavaScript code.
|
||||
|
||||
### styles.less
|
||||
@@ -172,6 +178,8 @@ Unfamiliar with LESS? Read more about it [here][LESS].
|
||||
|
||||
This file can also be named _styles.css_ and contain CSS.
|
||||
|
||||
[create-a-package]: creating-packages.md
|
||||
[creating-a-package]: creating-a-package.md
|
||||
[create-theme]: creating-a-theme.md
|
||||
[LESS]: http://www.lesscss.org
|
||||
[CSON]: https://github.com/atom/season
|
||||
[CoffeeScript]: http://coffeescript.org/
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
* [Creating a Package](creating-a-package.md)
|
||||
* [Creating a Theme](creating-a-theme.md)
|
||||
* [Publishing a Package](publishing-a-package.md)
|
||||
* [Converting a TextMate Bundle](converting-a-text-mate-bundle.md)
|
||||
* [Converting a TextMate Theme](converting-a-text-mate-theme.md)
|
||||
* [Contributing](contributing.md)
|
||||
|
||||
### Advanced Topics
|
||||
|
||||
@@ -20,7 +20,8 @@ The final package can be viewed at
|
||||
To begin, press `cmd-shift-P` to bring up the [Command
|
||||
Palette](https://github.com/atom/command-palette). Type "generate package" and
|
||||
select the "Package Generator: Generate Package" command. Now we need to name
|
||||
the package. Let's call it _ascii-art_.
|
||||
the package. Try to avoid naming your package with the *atom-* prefix, for
|
||||
example we are going to call this package _ascii-art_.
|
||||
|
||||
Atom will open a new window with the contents of our new _ascii-art_ package
|
||||
displayed in the Tree View. Because this window is opened **after** the package
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
# '.editor':
|
||||
# 'enter': 'editor:newline'
|
||||
#
|
||||
# 'body':
|
||||
# '.workspace':
|
||||
# 'ctrl-P': 'core:move-up'
|
||||
# 'ctrl-p': 'core:move-down'
|
||||
#
|
||||
|
||||
@@ -21,3 +21,4 @@ unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
|
||||
module.exports.Task = require '../src/task'
|
||||
module.exports.View = View
|
||||
module.exports.WorkspaceView = require '../src/workspace-view'
|
||||
module.exports.Workspace = require '../src/workspace'
|
||||
|
||||
@@ -96,6 +96,7 @@
|
||||
'.editor':
|
||||
# Apple Specific
|
||||
'cmd-backspace': 'editor:backspace-to-beginning-of-line'
|
||||
'cmd-shift-backspace': 'editor:backspace-to-beginning-of-line'
|
||||
'cmd-delete': 'editor:backspace-to-beginning-of-line'
|
||||
'ctrl-A': 'editor:select-to-first-character-of-line'
|
||||
'ctrl-E': 'editor:select-to-end-of-line'
|
||||
@@ -133,8 +134,8 @@
|
||||
'ctrl-cmd-up': 'editor:move-line-up'
|
||||
'ctrl-cmd-down': 'editor:move-line-down'
|
||||
'cmd-/': 'editor:toggle-line-comments'
|
||||
'cmd-j': 'editor:join-line'
|
||||
'cmd-D': 'editor:duplicate-line'
|
||||
'cmd-j': 'editor:join-lines'
|
||||
'cmd-D': 'editor:duplicate-lines'
|
||||
'cmd-L': 'editor:split-selections-into-lines'
|
||||
|
||||
'cmd-alt-[': 'editor:fold-current-row'
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
'body':
|
||||
# Atom Specific
|
||||
'enter': 'core:confirm'
|
||||
'escape': 'core:cancel'
|
||||
'up': 'core:move-up'
|
||||
'down': 'core:move-down'
|
||||
'left': 'core:move-left'
|
||||
'right': 'core:move-right'
|
||||
'ctrl-alt-r': 'window:reload'
|
||||
'ctrl-alt-i': 'window:toggle-dev-tools'
|
||||
'ctrl-alt-p': 'window:run-package-specs'
|
||||
'ctrl-alt-s': 'application:run-all-specs'
|
||||
|
||||
# Sublime Parity
|
||||
'ctrl-N': 'application:new-window'
|
||||
'ctrl-W': 'window:close'
|
||||
'ctrl-o': 'application:open'
|
||||
'ctrl-T': 'pane:reopen-closed-item'
|
||||
'ctrl-n': 'application:new-file'
|
||||
'ctrl-s': 'core:save'
|
||||
'ctrl-S': 'core:save-as'
|
||||
'ctrl-w': 'core:close'
|
||||
'ctrl-z': 'core:undo'
|
||||
'ctrl-y': 'core:redo'
|
||||
'ctrl-x': 'core:cut'
|
||||
'ctrl-c': 'core:copy'
|
||||
'ctrl-v': 'core:paste'
|
||||
'shift-up': 'core:select-up'
|
||||
'shift-down': 'core:select-down'
|
||||
'shift-left': 'core:select-left'
|
||||
'shift-right': 'core:select-right'
|
||||
'delete': 'core:delete'
|
||||
'pageup': 'core:page-up'
|
||||
'pagedown': 'core:page-down'
|
||||
'backspace': 'core:backspace'
|
||||
'ctrl-tab': 'pane:show-next-item'
|
||||
'ctrl-shift-tab': 'pane:show-previous-item'
|
||||
'ctrl-shift-up': 'core:move-up'
|
||||
'ctrl-shift-down': 'core:move-down'
|
||||
'ctrl-=': 'window:increase-font-size'
|
||||
'ctrl-+': 'window:increase-font-size'
|
||||
'ctrl--': 'window:decrease-font-size'
|
||||
'ctrl-_': 'window:decrease-font-size'
|
||||
'ctrl-0': 'window:reset-font-size'
|
||||
|
||||
'ctrl-k up': 'pane:split-up' # Atom Specific
|
||||
'ctrl-k down': 'pane:split-down' # Atom Specific
|
||||
'ctrl-k left': 'pane:split-left' # Atom Specific
|
||||
'ctrl-k right': 'pane:split-right' # Atom Specific
|
||||
'ctrl-k ctrl-w': 'pane:close' # Atom Specific
|
||||
'ctrl-k alt-ctrl-w': 'pane:close-other-items' # Atom Specific
|
||||
'ctrl-k ctrl-p': 'window:focus-previous-pane'
|
||||
'ctrl-k ctrl-n': 'window:focus-next-pane'
|
||||
'ctrl-k ctrl-up': 'window:focus-pane-above'
|
||||
'ctrl-k ctrl-down': 'window:focus-pane-below'
|
||||
'ctrl-k ctrl-left': 'window:focus-pane-on-left'
|
||||
'ctrl-k ctrl-right': 'window:focus-pane-on-right'
|
||||
|
||||
'.workspace .editor':
|
||||
# Windows specific
|
||||
'ctrl-delete': 'editor:backspace-to-beginning-of-word'
|
||||
|
||||
# Sublime Parity
|
||||
'ctrl-a': 'core:select-all'
|
||||
'ctrl-alt-p': 'editor:log-cursor-scope'
|
||||
'ctrl-k ctrl-u': 'editor:upper-case'
|
||||
'ctrl-k ctrl-l': 'editor:lower-case'
|
||||
|
||||
'.workspace .editor:not(.mini)':
|
||||
# Atom specific
|
||||
'alt-ctrl-z': 'editor:checkout-head-revision'
|
||||
'ctrl-<': 'editor:scroll-to-cursor'
|
||||
'alt-ctrl-f': 'editor:fold-selection'
|
||||
|
||||
# Sublime Parity
|
||||
'ctrl-enter': 'editor:newline-below'
|
||||
'ctrl-shift-enter': 'editor:newline-above'
|
||||
'ctrl-]': 'editor:indent-selected-rows'
|
||||
'ctrl-[': 'editor:outdent-selected-rows'
|
||||
'ctrl-up': 'editor:move-line-up'
|
||||
'ctrl-down': 'editor:move-line-down'
|
||||
'ctrl-/': 'editor:toggle-line-comments'
|
||||
'ctrl-j': 'editor:join-lines'
|
||||
'ctrl-D': 'editor:duplicate-lines'
|
||||
|
||||
'ctrl-alt-[': 'editor:fold-current-row'
|
||||
'ctrl-alt-]': 'editor:unfold-current-row'
|
||||
'ctrl-alt-{': 'editor:fold-all' # Atom Specific
|
||||
'ctrl-alt-}': 'editor:unfold-all' # Atom Specific
|
||||
'ctrl-k ctrl-0': 'editor:unfold-all'
|
||||
'ctrl-k ctrl-1': 'editor:fold-at-indent-level-1'
|
||||
'ctrl-k ctrl-2': 'editor:fold-at-indent-level-2'
|
||||
'ctrl-k ctrl-3': 'editor:fold-at-indent-level-3'
|
||||
'ctrl-k ctrl-4': 'editor:fold-at-indent-level-4'
|
||||
'ctrl-k ctrl-5': 'editor:fold-at-indent-level-5'
|
||||
'ctrl-k ctrl-6': 'editor:fold-at-indent-level-6'
|
||||
'ctrl-k ctrl-7': 'editor:fold-at-indent-level-7'
|
||||
'ctrl-k ctrl-8': 'editor:fold-at-indent-level-8'
|
||||
'ctrl-k ctrl-9': 'editor:fold-at-indent-level-9'
|
||||
|
||||
# allow standard input fields to work correctly
|
||||
'body .native-key-bindings':
|
||||
'ctrl-z': 'native!'
|
||||
'ctrl-Z': 'native!'
|
||||
'ctrl-x': 'native!'
|
||||
'ctrl-c': 'native!'
|
||||
'ctrl-v': 'native!'
|
||||
@@ -80,8 +80,8 @@
|
||||
'ctrl-up': 'editor:move-line-up'
|
||||
'ctrl-down': 'editor:move-line-down'
|
||||
'ctrl-/': 'editor:toggle-line-comments'
|
||||
'ctrl-j': 'editor:join-line'
|
||||
'ctrl-D': 'editor:duplicate-line'
|
||||
'ctrl-j': 'editor:join-lines'
|
||||
'ctrl-D': 'editor:duplicate-lines'
|
||||
|
||||
'ctrl-alt-[': 'editor:fold-current-row'
|
||||
'ctrl-alt-]': 'editor:unfold-current-row'
|
||||
|
||||
+4
-3
@@ -7,6 +7,7 @@
|
||||
{ label: "VERSION", enabled: false }
|
||||
{ label: "Restart and Install Update", command: 'application:install-update', visible: false}
|
||||
{ label: "Check for Update", command: 'application:check-for-update', visible: false}
|
||||
{ label: "Downloading Update", command: 'application:check-for-update', enabled: false, visible: false}
|
||||
{ type: 'separator' }
|
||||
{ label: 'Preferences...', command: 'application:show-settings' }
|
||||
{ label: 'Open Your Config', command: 'application:open-your-config' }
|
||||
@@ -37,7 +38,7 @@
|
||||
{ label: 'Save All', command: 'window:save-all' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Close Buffer', command: 'core:close' }
|
||||
{ label: 'Close All Buffers', command: 'pane:close' }
|
||||
{ label: 'Close Pane', command: 'pane:close' }
|
||||
{ label: 'Close Window', command: 'window:close' }
|
||||
]
|
||||
}
|
||||
@@ -64,9 +65,9 @@
|
||||
{ type: 'separator' }
|
||||
{ label: 'Move Line Up', command: 'editor:move-line-up' }
|
||||
{ label: 'Move Line Down', command: 'editor:move-line-down' }
|
||||
{ label: 'Duplicate Line', command: 'editor:duplicate-line' }
|
||||
{ label: 'Duplicate Lines', command: 'editor:duplicate-lines' }
|
||||
{ label: 'Delete Line', command: 'editor:delete-line' }
|
||||
{ label: 'Join Lines', command: 'editor:join-line' }
|
||||
{ label: 'Join Lines', command: 'editor:join-lines' }
|
||||
]
|
||||
}
|
||||
{
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
'menu': [
|
||||
{
|
||||
label: '&File'
|
||||
submenu: [
|
||||
{ label: 'New &Window', command: 'application:new-window' }
|
||||
{ label: '&New File', command: 'application:new-file' }
|
||||
{ label: '&Open...', command: 'application:open' }
|
||||
{ label: 'Reopen Last &Item', command: 'pane:reopen-closed-item' }
|
||||
{ type: 'separator' }
|
||||
{ label: '&Preferences...', command: 'application:show-settings' }
|
||||
{ type: 'separator' }
|
||||
{ label: '&Save', command: 'core:save' }
|
||||
{ label: 'Save &As...', command: 'core:save-as' }
|
||||
{ label: 'Save A&ll', command: 'window:save-all' }
|
||||
{ type: 'separator' }
|
||||
{ label: '&Close Buffer', command: 'core:close' }
|
||||
{ label: 'Close All &Buffers', command: 'pane:close' }
|
||||
{ label: 'Clos&e Window', command: 'window:close' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'E&xit', command: 'application:quit' }
|
||||
]
|
||||
}
|
||||
|
||||
{
|
||||
label: '&Edit'
|
||||
submenu: [
|
||||
{ label: '&Undo', command: 'core:undo' }
|
||||
{ label: '&Redo', command: 'core:redo' }
|
||||
{ type: 'separator' }
|
||||
{ label: '&Cut', command: 'core:cut' }
|
||||
{ label: 'C&opy', command: 'core:copy' }
|
||||
{ label: 'Copy Pat&h', command: 'editor:copy-path' }
|
||||
{ label: '&Paste', command: 'core:paste' }
|
||||
{ label: 'Select &All', command: 'core:select-all' }
|
||||
{ type: 'separator' }
|
||||
{ label: '&Toggle Comments', command: 'editor:toggle-line-comments' }
|
||||
{
|
||||
label: 'Lines',
|
||||
submenu: [
|
||||
{ label: '&Indent', command: 'editor:indent-selected-rows' }
|
||||
{ label: '&Outdent', command: 'editor:outdent-selected-rows' }
|
||||
{ label: '&Auto Indent', command: 'editor:auto-indent' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Move Line &Up', command: 'editor:move-line-up' }
|
||||
{ label: 'Move Line &Down', command: 'editor:move-line-down' }
|
||||
{ label: 'Du&plicate Lines', command: 'editor:duplicate-lines' }
|
||||
{ label: 'D&elete Line', command: 'editor:delete-line' }
|
||||
{ label: '&Join Lines', command: 'editor:join-lines' }
|
||||
]
|
||||
}
|
||||
{
|
||||
label: 'Text',
|
||||
submenu: [
|
||||
{ label: '&Upper Case', command: 'editor:upper-case' }
|
||||
{ label: '&Lower Case', command: 'editor:lower-case' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Delete to End of &Word', command: 'editor:delete-to-end-of-word' }
|
||||
{ label: '&Delete Line', command: 'editor:delete-line' }
|
||||
{ type: 'separator' }
|
||||
{ label: '&Transpose', command: 'editor:transpose' }
|
||||
]
|
||||
}
|
||||
{
|
||||
label: 'Folding',
|
||||
submenu: [
|
||||
{ label: '&Fold', command: 'editor:fold-current-row' }
|
||||
{ label: '&Unfold', command: 'editor:unfold-current-row' }
|
||||
{ label: 'Unfold &All', command: 'editor:unfold-all' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Fol&d All', command: 'editor:fold-all' }
|
||||
{ label: 'Fold Level 1', command: 'editor:fold-at-indent-level-1' }
|
||||
{ label: 'Fold Level 2', command: 'editor:fold-at-indent-level-2' }
|
||||
{ label: 'Fold Level 3', command: 'editor:fold-at-indent-level-3' }
|
||||
{ label: 'Fold Level 4', command: 'editor:fold-at-indent-level-4' }
|
||||
{ label: 'Fold Level 5', command: 'editor:fold-at-indent-level-5' }
|
||||
{ label: 'Fold Level 6', command: 'editor:fold-at-indent-level-6' }
|
||||
{ label: 'Fold Level 7', command: 'editor:fold-at-indent-level-7' }
|
||||
{ label: 'Fold Level 8', command: 'editor:fold-at-indent-level-8' }
|
||||
{ label: 'Fold Level 9', command: 'editor:fold-at-indent-level-9' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
{
|
||||
label: '&View'
|
||||
submenu: [
|
||||
{ label: '&Reload', command: 'window:reload' }
|
||||
{ label: 'Toggle &Full Screen', command: 'window:toggle-full-screen' }
|
||||
{
|
||||
label: 'Developer'
|
||||
submenu: [
|
||||
{ label: 'Open In &Dev Mode...', command: 'application:open-dev' }
|
||||
{ label: 'Run &Atom Specs', command: 'application:run-all-specs' }
|
||||
{ label: 'Run Package &Specs', command: 'window:run-package-specs' }
|
||||
{ label: 'Toggle Developer &Tools', command: 'window:toggle-dev-tools' }
|
||||
]
|
||||
}
|
||||
{ type: 'separator' }
|
||||
{ label: 'Toggle Soft &Wrap', command: 'editor:toggle-soft-wrap' }
|
||||
]
|
||||
}
|
||||
|
||||
{
|
||||
label: '&Selection'
|
||||
submenu: [
|
||||
{ label: 'Add Selection &Above', command: 'editor:add-selection-above' }
|
||||
{ label: 'Add Selection &Below', command: 'editor:add-selection-below' }
|
||||
{ label: 'S&plit into Lines', command: 'editor:split-selections-into-lines'}
|
||||
{ type: 'separator' }
|
||||
{ label: 'Select to &Top', command: 'core:select-to-top' }
|
||||
{ label: 'Select to Botto&m', command: 'core:select-to-bottom' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Select &Line', command: 'editor:select-line' }
|
||||
{ label: 'Select &Word', command: 'editor:select-word' }
|
||||
{ label: 'Select to Beginning of W&ord', command: 'editor:select-to-beginning-of-word' }
|
||||
{ label: 'Select to Beginning of L&ine', command: 'editor:select-to-beginning-of-line' }
|
||||
{ label: 'Select to First &Character of Line', command: 'editor:select-to-first-character-of-line' }
|
||||
{ label: 'Select to End of Wor&d', command: 'editor:select-to-end-of-word' }
|
||||
{ label: 'Select to End of Lin&e', command: 'editor:select-to-end-of-line' }
|
||||
]
|
||||
}
|
||||
|
||||
{
|
||||
label: 'F&ind'
|
||||
submenu: []
|
||||
}
|
||||
|
||||
{
|
||||
label: '&Packages'
|
||||
submenu: []
|
||||
}
|
||||
|
||||
{
|
||||
label: '&Window'
|
||||
submenu: [
|
||||
{ label: 'Mi&nimize', command: 'application:minimize' }
|
||||
{ label: 'Ma&ximize', command: 'application:zoom' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Bring &All to Front', command: 'application:bring-all-windows-to-front' }
|
||||
]
|
||||
}
|
||||
|
||||
{
|
||||
label: '&Help'
|
||||
submenu: [
|
||||
{ label: '&About Atom...', command: 'application:about' }
|
||||
{ label: 'View &License', command: 'application:open-license' }
|
||||
{ label: "VERSION", enabled: false }
|
||||
{ label: "Install &update", command: 'application:install-update', visible: false }
|
||||
{ type: 'separator' }
|
||||
{ label: '&Documentation', command: 'application:open-documentation' }
|
||||
{ type: 'separator' }
|
||||
]
|
||||
}
|
||||
]
|
||||
+2
-2
@@ -43,9 +43,9 @@
|
||||
{ type: 'separator' }
|
||||
{ label: 'Move Line &Up', command: 'editor:move-line-up' }
|
||||
{ label: 'Move Line &Down', command: 'editor:move-line-down' }
|
||||
{ label: 'Du&plicate Line', command: 'editor:duplicate-line' }
|
||||
{ label: 'Du&plicate Lines', command: 'editor:duplicate-lines' }
|
||||
{ label: 'D&elete Line', command: 'editor:delete-line' }
|
||||
{ label: '&Join Lines', command: 'editor:join-line' }
|
||||
{ label: '&Join Lines', command: 'editor:join-lines' }
|
||||
]
|
||||
}
|
||||
{
|
||||
|
||||
+77
-81
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "atom",
|
||||
"productName": "Atom",
|
||||
"version": "0.59.0",
|
||||
"version": "0.76.0",
|
||||
"main": "./src/browser/main.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -10,125 +10,121 @@
|
||||
"bugs": {
|
||||
"url": "https://github.com/atom/atom/issues"
|
||||
},
|
||||
"licenses": [
|
||||
{
|
||||
"type": "Apache",
|
||||
"url": "http://github.com/atom/atom/raw/master/LICENSE.md"
|
||||
}
|
||||
],
|
||||
"atomShellVersion": "0.10.1",
|
||||
"license": "All Rights Reserved",
|
||||
"atomShellVersion": "0.11.2",
|
||||
"dependencies": {
|
||||
"async": "0.2.6",
|
||||
"atom-keymap": "^0.10.0",
|
||||
"bootstrap": "git://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372",
|
||||
"clear-cut": "0.4.0",
|
||||
"coffee-script": "1.7.0",
|
||||
"coffeestack": "0.7.0",
|
||||
"delegato": "1.x",
|
||||
"emissary": "1.x",
|
||||
"first-mate": ">=1.1.5 <2.0",
|
||||
"fs-plus": "2.x",
|
||||
"first-mate": ">=1.4.2 <2.0",
|
||||
"fs-plus": ">=2.0.4 < 3.0",
|
||||
"fstream": "0.1.24",
|
||||
"fuzzaldrin": "1.x",
|
||||
"git-utils": "1.x",
|
||||
"fuzzaldrin": "~1.1",
|
||||
"git-utils": "^1.1.1",
|
||||
"guid": "0.0.10",
|
||||
"jasmine-tagged": ">=1.1.1 <2.0",
|
||||
"mkdirp": "0.3.5",
|
||||
"keytar": "0.15.1",
|
||||
"keytar": "1.x",
|
||||
"less-cache": "0.12.0",
|
||||
"mixto": "1.x",
|
||||
"nslog": "0.5.0",
|
||||
"oniguruma": "1.x",
|
||||
"oniguruma": "^1.0.4",
|
||||
"optimist": "0.4.0",
|
||||
"pathwatcher": "0.16.0",
|
||||
"pegjs": "0.8.0",
|
||||
"pathwatcher": "^1.0.0",
|
||||
"property-accessors": "1.x",
|
||||
"q": "1.0.x",
|
||||
"q": "^1.0.1",
|
||||
"random-words": "0.0.1",
|
||||
"runas": "0.5.x",
|
||||
"scandal": "0.15.0",
|
||||
"scrollbar-style": "^0.1.0",
|
||||
"season": ">=1.0.2 <2.0",
|
||||
"semver": "1.1.4",
|
||||
"serializable": "1.x",
|
||||
"space-pen": "3.1.1",
|
||||
"temp": "0.5.0",
|
||||
"text-buffer": ">=1.1.2 <2.0",
|
||||
"text-buffer": "^1.4.4",
|
||||
"theorist": "1.x",
|
||||
"underscore-plus": "1.x",
|
||||
"underscore-plus": ">=1.0.5 <2.0",
|
||||
"vm-compatibility-layer": "0.1.0"
|
||||
},
|
||||
"packageDependencies": {
|
||||
"atom-dark-syntax": "0.14.0",
|
||||
"atom-dark-ui": "0.23.0",
|
||||
"atom-light-syntax": "0.14.0",
|
||||
"atom-light-ui": "0.22.0",
|
||||
"base16-tomorrow-dark-theme": "0.12.0",
|
||||
"solarized-dark-syntax": "0.10.0",
|
||||
"solarized-light-syntax": "0.6.0",
|
||||
"archive-view": "0.24.0",
|
||||
"autocomplete": "0.24.0",
|
||||
"atom-dark-syntax": "0.15.0",
|
||||
"atom-dark-ui": "0.26.0",
|
||||
"atom-light-syntax": "0.16.0",
|
||||
"atom-light-ui": "0.23.0",
|
||||
"base16-tomorrow-dark-theme": "0.13.0",
|
||||
"solarized-dark-syntax": "0.14.0",
|
||||
"solarized-light-syntax": "0.7.0",
|
||||
"archive-view": "0.29.0",
|
||||
"autocomplete": "0.27.0",
|
||||
"autoflow": "0.15.0",
|
||||
"autosave": "0.12.0",
|
||||
"background-tips": "0.8.0",
|
||||
"bookmarks": "0.21.0",
|
||||
"bracket-matcher": "0.22.0",
|
||||
"command-palette": "0.18.0",
|
||||
"dev-live-reload": "0.28.0",
|
||||
"exception-reporting": "0.15.0",
|
||||
"feedback": "0.27.0",
|
||||
"find-and-replace": "0.85.0",
|
||||
"fuzzy-finder": "0.37.0",
|
||||
"autosave": "0.13.0",
|
||||
"background-tips": "0.9.0",
|
||||
"bookmarks": "0.22.0",
|
||||
"bracket-matcher": "0.26.0",
|
||||
"command-palette": "0.19.0",
|
||||
"dev-live-reload": "0.29.0",
|
||||
"exception-reporting": "0.17.0",
|
||||
"feedback": "0.28.0",
|
||||
"find-and-replace": "0.92.0",
|
||||
"fuzzy-finder": "0.42.0",
|
||||
"git-diff": "0.25.0",
|
||||
"go-to-line": "0.17.0",
|
||||
"grammar-selector": "0.21.0",
|
||||
"image-view": "0.25.0",
|
||||
"keybinding-resolver": "0.11.0",
|
||||
"link": "0.18.0",
|
||||
"markdown-preview": "0.37.0",
|
||||
"metrics": "0.30.0",
|
||||
"open-on-github": "0.21.0",
|
||||
"package-generator": "0.28.0",
|
||||
"release-notes": "0.24.0",
|
||||
"settings-view": "0.82.0",
|
||||
"snippets": "0.32.0",
|
||||
"spell-check": "0.26.0",
|
||||
"status-bar": "0.33.0",
|
||||
"styleguide": "0.25.0",
|
||||
"symbols-view": "0.38.0",
|
||||
"tabs": "0.24.0",
|
||||
"timecop": "0.15.0",
|
||||
"tree-view": "0.71.0",
|
||||
"update-package-dependencies": "0.4.0",
|
||||
"welcome": "0.9.0",
|
||||
"whitespace": "0.15.0",
|
||||
"wrap-guide": "0.15.0",
|
||||
"language-c": "0.12.0",
|
||||
"language-coffee-script": "0.13.0",
|
||||
"language-css": "0.10.0",
|
||||
"language-gfm": "0.18.0",
|
||||
"go-to-line": "0.18.0",
|
||||
"grammar-selector": "0.23.0",
|
||||
"image-view": "0.32.0",
|
||||
"keybinding-resolver": "0.12.0",
|
||||
"link": "0.20.0",
|
||||
"markdown-preview": "0.50.0",
|
||||
"metrics": "0.32.0",
|
||||
"open-on-github": "0.23.0",
|
||||
"package-generator": "0.30.0",
|
||||
"release-notes": "0.26.0",
|
||||
"settings-view": "0.97.0",
|
||||
"snippets": "0.37.0",
|
||||
"spell-check": "0.28.0",
|
||||
"status-bar": "0.36.0",
|
||||
"styleguide": "0.26.0",
|
||||
"symbols-view": "0.44.0",
|
||||
"tabs": "0.31.0",
|
||||
"timecop": "0.17.0",
|
||||
"tree-view": "0.83.0",
|
||||
"update-package-dependencies": "0.6.0",
|
||||
"welcome": "0.11.0",
|
||||
"whitespace": "0.21.0",
|
||||
"wrap-guide": "0.18.0",
|
||||
"language-c": "0.13.0",
|
||||
"language-coffee-script": "0.16.0",
|
||||
"language-css": "0.13.0",
|
||||
"language-gfm": "0.24.0",
|
||||
"language-git": "0.9.0",
|
||||
"language-go": "0.6.0",
|
||||
"language-html": "0.8.0",
|
||||
"language-hyperlink": "0.8.0",
|
||||
"language-java": "0.8.0",
|
||||
"language-javascript": "0.11.0",
|
||||
"language-go": "0.7.0",
|
||||
"language-html": "0.15.0",
|
||||
"language-hyperlink": "0.9.0",
|
||||
"language-java": "0.9.0",
|
||||
"language-javascript": "0.21.0",
|
||||
"language-json": "0.8.0",
|
||||
"language-less": "0.5.0",
|
||||
"language-make": "0.8.0",
|
||||
"language-objective-c": "0.9.0",
|
||||
"language-less": "0.6.0",
|
||||
"language-make": "0.9.0",
|
||||
"language-objective-c": "0.10.0",
|
||||
"language-perl": "0.8.0",
|
||||
"language-php": "0.8.0",
|
||||
"language-php": "0.13.0",
|
||||
"language-property-list": "0.7.0",
|
||||
"language-python": "0.8.0",
|
||||
"language-ruby": "0.13.0",
|
||||
"language-ruby-on-rails": "0.7.0",
|
||||
"language-python": "0.12.0",
|
||||
"language-ruby": "0.16.0",
|
||||
"language-ruby-on-rails": "0.12.0",
|
||||
"language-sass": "0.8.0",
|
||||
"language-shellscript": "0.7.0",
|
||||
"language-shellscript": "0.8.0",
|
||||
"language-source": "0.7.0",
|
||||
"language-sql": "0.7.0",
|
||||
"language-text": "0.6.0",
|
||||
"language-todo": "0.6.0",
|
||||
"language-toml": "0.11.0",
|
||||
"language-xml": "0.7.0",
|
||||
"language-todo": "0.9.0",
|
||||
"language-toml": "0.12.0",
|
||||
"language-xml": "0.8.0",
|
||||
"language-yaml": "0.6.0"
|
||||
},
|
||||
"private": true,
|
||||
|
||||
@@ -25,13 +25,15 @@
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.developer-tools</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.7</string>
|
||||
<string>10.8</string>
|
||||
<key>NSAppleScriptEnabled</key>
|
||||
<string>YES</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>AtomApplication</string>
|
||||
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
||||
<true/>
|
||||
<key>SUPublicDSAKeyFile</key>
|
||||
<string>speakeasy.pem</string>
|
||||
<key>SUScheduledCheckInterval</key>
|
||||
|
||||
+19
-8
@@ -1,4 +1,11 @@
|
||||
#!/usr/bin/env node --harmony_collections
|
||||
|
||||
var nodeMinorVersion = process.versions.node.split('.')[1]
|
||||
if (nodeMinorVersion !== '10') {
|
||||
console.warn("You must run script/bootstrap and script/build with node v0.10.x");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var safeExec = require('./utils/child-process-wrapper.js').safeExec;
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
@@ -25,21 +32,25 @@ if (!fs.existsSync(apmInstallPath))
|
||||
if (!fs.existsSync(path.join(apmInstallPath, 'node_modules')))
|
||||
fs.mkdirSync(path.join(apmInstallPath, 'node_modules'));
|
||||
|
||||
var apmPath = 'apm/node_modules/atom-package-manager/bin/apm'
|
||||
var apmFlags = process.env.JANKY_SHA1 || process.argv.indexOf('--no-color') !== -1 ? '--no-color' : '';
|
||||
|
||||
var npmPath = path.resolve(__dirname, '..', 'build', 'node_modules', '.bin', 'npm');
|
||||
var npmFlags = ' --userconfig=' + path.resolve('.npmrc') + ' ';
|
||||
|
||||
var packagesToDedupe = ['fs-plus', 'humanize-plus', 'oniguruma', 'roaster', 'season'];
|
||||
var echoNewLine = process.platform == 'win32' ? 'echo.' : 'echo';
|
||||
|
||||
var commands = [
|
||||
'git submodule --quiet sync',
|
||||
'git submodule --quiet update --recursive --init',
|
||||
{command: 'npm install --quiet', options: {cwd: path.resolve(__dirname, '..', 'build'), ignoreStdout: true}},
|
||||
{command: 'npm install --quiet', options: {cwd: apmVendorPath, ignoreStdout: true}},
|
||||
{command: 'npm install --quiet ' + apmVendorPath, options: {cwd: apmInstallPath, ignoreStdout: true}},
|
||||
{command: 'npm install --quiet ' + apmVendorPath, options: {ignoreStdout: true}},
|
||||
{command: 'node ../../apm/node_modules/atom-package-manager/bin/apm rebuild', options: {cwd: path.resolve('node_modules', 'atom-package-manager'), ignoreStdout: true}},
|
||||
{command: 'npm' + npmFlags + 'install --quiet', options: {cwd: path.resolve(__dirname, '..', 'build'), ignoreStdout: true}},
|
||||
{command: npmPath + npmFlags + 'install --quiet', options: {cwd: apmVendorPath, ignoreStdout: true}},
|
||||
{command: npmPath + npmFlags + 'install --quiet ' + apmVendorPath, options: {cwd: apmInstallPath, ignoreStdout: true}},
|
||||
echoNewLine,
|
||||
'node apm/node_modules/atom-package-manager/bin/apm clean ' + apmFlags,
|
||||
'node apm/node_modules/atom-package-manager/bin/apm install --quiet ' + apmFlags,
|
||||
'node apm/node_modules/atom-package-manager/bin/apm dedupe --quiet ' + apmFlags + ' ' + packagesToDedupe.join(' '),
|
||||
apmPath + ' clean ' + apmFlags,
|
||||
apmPath + ' install --quiet ' + apmFlags,
|
||||
apmPath + ' dedupe --quiet ' + apmFlags + ' ' + packagesToDedupe.join(' '),
|
||||
];
|
||||
|
||||
process.chdir(path.dirname(__dirname));
|
||||
|
||||
@@ -22,6 +22,7 @@ var commands = [
|
||||
[__dirname, '..', 'atom-shell'],
|
||||
[home, '.atom', '.node-gyp'],
|
||||
[home, '.atom', 'storage'],
|
||||
[home, '.atom', '.npm'],
|
||||
[tmpdir, 'atom-build'],
|
||||
[tmpdir, 'atom-cached-atom-shells'],
|
||||
[tmpdir, 'atom-compile-cache'],
|
||||
|
||||
@@ -126,6 +126,16 @@ describe "the `atom` global", ->
|
||||
expect(eventHandler.callCount).toBe 2
|
||||
expect(mainModule.activate.callCount).toBe 1
|
||||
|
||||
it "activates the package immediately when the events are empty", ->
|
||||
mainModule = require './fixtures/packages/package-with-empty-activation-events/index'
|
||||
spyOn(mainModule, 'activate').andCallThrough()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-empty-activation-events')
|
||||
|
||||
runs ->
|
||||
expect(mainModule.activate.callCount).toBe 1
|
||||
|
||||
describe "when the package has no main module", ->
|
||||
it "does not throw an exception", ->
|
||||
spyOn(console, "error")
|
||||
|
||||
@@ -37,7 +37,7 @@ describe "DisplayBuffer", ->
|
||||
expect(displayBuffer2.isFoldedAtBufferRow(3)).toBeTruthy()
|
||||
|
||||
# can diverge from origin
|
||||
displayBuffer2.destroyFoldsContainingBufferRow(3)
|
||||
displayBuffer2.unfoldBufferRow(3)
|
||||
expect(displayBuffer2.isFoldedAtBufferRow(3)).not.toBe displayBuffer.isFoldedAtBufferRow(3)
|
||||
|
||||
describe "when the buffer changes", ->
|
||||
@@ -200,6 +200,12 @@ describe "DisplayBuffer", ->
|
||||
expect(tokensText displayBuffer.lineForRow(12).tokens).toBe 'sort(left).concat(pivot).concat(sort(rig'
|
||||
expect(changeHandler).toHaveBeenCalledWith(start: 0, end: 15, screenDelta: 3, bufferDelta: 0)
|
||||
|
||||
it "only allows positive widths to be assigned", ->
|
||||
displayBuffer.setEditorWidthInChars(0)
|
||||
expect(displayBuffer.editorWidthInChars).not.toBe 0
|
||||
displayBuffer.setEditorWidthInChars(-1)
|
||||
expect(displayBuffer.editorWidthInChars).not.toBe -1
|
||||
|
||||
describe "primitive folding", ->
|
||||
beforeEach ->
|
||||
displayBuffer.destroy()
|
||||
@@ -460,6 +466,12 @@ describe "DisplayBuffer", ->
|
||||
|
||||
expect(changeHandler).toHaveBeenCalledWith(start: 3, end: 3, screenDelta: 1, bufferDelta: 1)
|
||||
|
||||
describe "when the change starts at the beginning of a fold but does not extend to the end (regression)", ->
|
||||
it "preserves a proper mapping between buffer and screen coordinates", ->
|
||||
expect(displayBuffer.screenPositionForBufferPosition([8, 0])).toEqual [4, 0]
|
||||
buffer.setTextInRange([[2, 0], [3, 0]], "\n")
|
||||
expect(displayBuffer.screenPositionForBufferPosition([8, 0])).toEqual [4, 0]
|
||||
|
||||
describe "position translation", ->
|
||||
it "translates positions to account for folded lines and characters and the placeholder", ->
|
||||
fold = displayBuffer.createFold(4, 7)
|
||||
@@ -495,7 +507,7 @@ describe "DisplayBuffer", ->
|
||||
expect(displayBuffer.bufferPositionForScreenPosition([5, 0])).toEqual [5, 0]
|
||||
expect(displayBuffer.bufferPositionForScreenPosition([9, 2])).toEqual [9, 2]
|
||||
|
||||
describe ".destroyFoldsContainingBufferRow(row)", ->
|
||||
describe ".unfoldBufferRow(row)", ->
|
||||
it "destroys all folds containing the given row", ->
|
||||
displayBuffer.createFold(2, 4)
|
||||
displayBuffer.createFold(2, 6)
|
||||
@@ -506,13 +518,24 @@ describe "DisplayBuffer", ->
|
||||
expect(displayBuffer.lineForRow(1).text).toBe '1'
|
||||
expect(displayBuffer.lineForRow(2).text).toBe '10'
|
||||
|
||||
displayBuffer.destroyFoldsContainingBufferRow(2)
|
||||
displayBuffer.unfoldBufferRow(2)
|
||||
expect(displayBuffer.lineForRow(1).text).toBe '1'
|
||||
expect(displayBuffer.lineForRow(2).text).toBe '2'
|
||||
expect(displayBuffer.lineForRow(7).fold).toBeDefined()
|
||||
expect(displayBuffer.lineForRow(8).text).toMatch /^9-+/
|
||||
expect(displayBuffer.lineForRow(10).fold).toBeDefined()
|
||||
|
||||
describe ".outermostFoldsInBufferRowRange(startRow, endRow)", ->
|
||||
it "returns the outermost folds entirely contained in the given row range, exclusive of end row", ->
|
||||
fold1 = displayBuffer.createFold(4, 7)
|
||||
fold2 = displayBuffer.createFold(5, 6)
|
||||
fold3 = displayBuffer.createFold(11, 15)
|
||||
fold4 = displayBuffer.createFold(12, 13)
|
||||
fold5 = displayBuffer.createFold(16, 17)
|
||||
|
||||
expect(displayBuffer.outermostFoldsInBufferRowRange(3, 18)).toEqual [fold1, fold3, fold5]
|
||||
expect(displayBuffer.outermostFoldsInBufferRowRange(5, 16)).toEqual [fold3]
|
||||
|
||||
describe ".clipScreenPosition(screenPosition, wrapBeyondNewlines: false, wrapAtSoftNewlines: false, skipAtomicTokens: false)", ->
|
||||
beforeEach ->
|
||||
displayBuffer.setSoftWrap(true)
|
||||
@@ -588,6 +611,13 @@ describe "DisplayBuffer", ->
|
||||
expect(displayBuffer.screenPositionForBufferPosition([0, 1])).toEqual [0, 2]
|
||||
expect(displayBuffer.bufferPositionForScreenPosition([0, 2])).toEqual [0, 1]
|
||||
|
||||
it "correctly translates positions on soft wrapped lines containing tabs", ->
|
||||
buffer.setText('\t\taa bb cc dd ee ff gg')
|
||||
displayBuffer.setSoftWrap(true)
|
||||
displayBuffer.setEditorWidthInChars(10)
|
||||
expect(displayBuffer.screenPositionForBufferPosition([0, 10], wrapAtSoftNewlines: true)).toEqual [1, 0]
|
||||
expect(displayBuffer.bufferPositionForScreenPosition([1, 0])).toEqual [0, 10]
|
||||
|
||||
describe ".getMaxLineLength()", ->
|
||||
it "returns the length of the longest screen line", ->
|
||||
expect(displayBuffer.getMaxLineLength()).toBe 65
|
||||
@@ -684,7 +714,7 @@ describe "DisplayBuffer", ->
|
||||
}
|
||||
markerChangedHandler.reset()
|
||||
|
||||
displayBuffer.destroyFoldsContainingBufferRow(4)
|
||||
displayBuffer.unfoldBufferRow(4)
|
||||
expect(markerChangedHandler).toHaveBeenCalled()
|
||||
expect(markerChangedHandler.argsForCall[0][0]).toEqual {
|
||||
oldHeadScreenPosition: [8, 23]
|
||||
@@ -867,7 +897,7 @@ describe "DisplayBuffer", ->
|
||||
expect(marker.getHeadScreenPosition()).toEqual [8, 10]
|
||||
expect(marker.getTailScreenPosition()).toEqual [8, 4]
|
||||
|
||||
displayBuffer.destroyFoldsContainingBufferRow(4)
|
||||
displayBuffer.unfoldBufferRow(4)
|
||||
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
expect(markerChangedHandler).toHaveBeenCalled()
|
||||
|
||||
+2523
-2420
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+67
-108
@@ -587,7 +587,7 @@ describe "EditorView", ->
|
||||
editorView.renderedLines.trigger mousedownEvent(editorView: editorView, point: [4, 10])
|
||||
|
||||
# moving changes selection
|
||||
$(document).trigger mousemoveEvent(editorView: editorView, point: [5, 27])
|
||||
$(document).trigger mousemoveEvent(editorView: editorView, point: [5, 27], which: 1)
|
||||
|
||||
range = editor.getSelection().getScreenRange()
|
||||
expect(range.start).toEqual({row: 4, column: 10})
|
||||
@@ -617,12 +617,12 @@ describe "EditorView", ->
|
||||
originalScrollTop = editorView.scrollTop()
|
||||
|
||||
# moving changes selection
|
||||
$(document).trigger mousemoveEvent(editorView: editorView, pageX: 0, pageY: -1)
|
||||
$(document).trigger mousemoveEvent(editorView: editorView, pageX: 0, pageY: -1, which: 1)
|
||||
expect(editorView.scrollTop()).toBe originalScrollTop - editorView.lineHeight
|
||||
|
||||
# every mouse move selects more text
|
||||
for x in [0..10]
|
||||
$(document).trigger mousemoveEvent(editorView: editorView, pageX: 0, pageY: -1)
|
||||
$(document).trigger mousemoveEvent(editorView: editorView, pageX: 0, pageY: -1, which: 1)
|
||||
|
||||
expect(editorView.scrollTop()).toBe 0
|
||||
|
||||
@@ -633,7 +633,7 @@ describe "EditorView", ->
|
||||
event = mousedownEvent(editorView: editorView, point: [4, 10])
|
||||
event.originalEvent.which = 2
|
||||
editorView.renderedLines.trigger(event)
|
||||
$(document).trigger mousemoveEvent(editorView: editorView, point: [5, 27])
|
||||
$(document).trigger mousemoveEvent(editorView: editorView, point: [5, 27], which: 1)
|
||||
$(document).trigger 'mouseup'
|
||||
|
||||
range = editor.getSelection().getScreenRange()
|
||||
@@ -654,6 +654,25 @@ describe "EditorView", ->
|
||||
expect(range.start).toEqual({row: 4, column: 10})
|
||||
expect(range.end).toEqual({row: 4, column: 10})
|
||||
|
||||
describe "when the editor is hidden", ->
|
||||
it "stops scrolling the editor", ->
|
||||
editorView.vScrollMargin = 0
|
||||
editorView.attachToDom(heightInLines: 5)
|
||||
editorView.scrollToBottom()
|
||||
|
||||
spyOn(window, 'setInterval').andCallFake ->
|
||||
|
||||
editorView.renderedLines.trigger mousedownEvent(editorView: editorView, point: [12, 0])
|
||||
originalScrollTop = editorView.scrollTop()
|
||||
|
||||
$(document).trigger mousemoveEvent(editorView: editorView, pageX: 0, pageY: -1, which: 1)
|
||||
expect(editorView.scrollTop()).toBe originalScrollTop - editorView.lineHeight
|
||||
|
||||
editorView.hide()
|
||||
|
||||
$(document).trigger mousemoveEvent(editorView: editorView, pageX: 100000, pageY: -1, which: 1)
|
||||
expect(editorView.scrollTop()).toBe originalScrollTop - editorView.lineHeight
|
||||
|
||||
describe "double-click and drag", ->
|
||||
it "selects the word under the cursor, then continues to select by word in either direction as the mouse is dragged", ->
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: 0, column: 0)
|
||||
@@ -662,11 +681,11 @@ describe "EditorView", ->
|
||||
editorView.renderedLines.trigger mousedownEvent(editorView: editorView, point: [0, 8], originalEvent: {detail: 2})
|
||||
expect(editor.getSelectedText()).toBe "quicksort"
|
||||
|
||||
editorView.renderedLines.trigger mousemoveEvent(editorView: editorView, point: [1, 8])
|
||||
editorView.renderedLines.trigger mousemoveEvent(editorView: editorView, point: [1, 8], which: 1)
|
||||
expect(editor.getSelectedBufferRange()).toEqual [[0, 4], [1, 10]]
|
||||
expect(editor.getCursorBufferPosition()).toEqual [1, 10]
|
||||
|
||||
editorView.renderedLines.trigger mousemoveEvent(editorView: editorView, point: [0, 1])
|
||||
editorView.renderedLines.trigger mousemoveEvent(editorView: editorView, point: [0, 1], which: 1)
|
||||
expect(editor.getSelectedBufferRange()).toEqual [[0, 0], [0, 13]]
|
||||
expect(editor.getCursorBufferPosition()).toEqual [0, 0]
|
||||
|
||||
@@ -691,12 +710,12 @@ describe "EditorView", ->
|
||||
expect(editor.getSelectedBufferRange()).toEqual [[4, 0], [5, 0]]
|
||||
|
||||
# moving changes selection linewise
|
||||
editorView.renderedLines.trigger mousemoveEvent(editorView: editorView, point: [5, 27])
|
||||
editorView.renderedLines.trigger mousemoveEvent(editorView: editorView, point: [5, 27], which: 1)
|
||||
expect(editor.getSelectedBufferRange()).toEqual [[4, 0], [6, 0]]
|
||||
expect(editor.getCursorBufferPosition()).toEqual [6, 0]
|
||||
|
||||
# moving changes selection linewise
|
||||
editorView.renderedLines.trigger mousemoveEvent(editorView: editorView, point: [2, 27])
|
||||
editorView.renderedLines.trigger mousemoveEvent(editorView: editorView, point: [2, 27], which: 1)
|
||||
expect(editor.getSelectedBufferRange()).toEqual [[2, 0], [5, 0]]
|
||||
expect(editor.getCursorBufferPosition()).toEqual [2, 0]
|
||||
|
||||
@@ -706,11 +725,11 @@ describe "EditorView", ->
|
||||
describe "meta-click and drag", ->
|
||||
it "adds an additional selection", ->
|
||||
editorView.renderedLines.trigger mousedownEvent(editorView: editorView, point: [4, 10])
|
||||
editorView.renderedLines.trigger mousemoveEvent(editorView: editorView, point: [5, 27])
|
||||
editorView.renderedLines.trigger mousemoveEvent(editorView: editorView, point: [5, 27], which: 1)
|
||||
editorView.renderedLines.trigger 'mouseup'
|
||||
|
||||
editorView.renderedLines.trigger mousedownEvent(editorView: editorView, point: [6, 10], metaKey: true)
|
||||
editorView.renderedLines.trigger mousemoveEvent(editorView: editorView, point: [8, 27], metaKey: true)
|
||||
editorView.renderedLines.trigger mousemoveEvent(editorView: editorView, point: [8, 27], metaKey: true, which: 1)
|
||||
editorView.renderedLines.trigger 'mouseup'
|
||||
|
||||
selections = editor.getSelections()
|
||||
@@ -1806,6 +1825,17 @@ describe "EditorView", ->
|
||||
runs ->
|
||||
expect(editor.getSoftWrapColumn()).toBeLessThan previousSoftWrapColumn
|
||||
|
||||
it "accounts for the width of the scrollbar if there is one", ->
|
||||
# force the scrollbar to always be visible, regardless of OS visibility setting
|
||||
$('#jasmine-content').prepend """
|
||||
<style>
|
||||
::-webkit-scrollbar { width: 15px; }
|
||||
</style>
|
||||
"""
|
||||
setEditorHeightInLines(editorView, 5)
|
||||
setEditorWidthInChars(editorView, 40)
|
||||
expect(editor.lineForScreenRow(2).text.length).toBe 34
|
||||
|
||||
describe "gutter rendering", ->
|
||||
beforeEach ->
|
||||
editorView.attachToDom(heightInLines: 5.5)
|
||||
@@ -2419,51 +2449,11 @@ describe "EditorView", ->
|
||||
editorView.underlayer.trigger event
|
||||
expect(editor.getSelection().getScreenRange()).toEqual [[0,0], [12,2]]
|
||||
|
||||
# TODO: Move to editor-spec
|
||||
describe ".reloadGrammar()", ->
|
||||
[filePath] = []
|
||||
|
||||
beforeEach ->
|
||||
tmpdir = fs.absolute(temp.dir)
|
||||
filePath = path.join(tmpdir, "grammar-change.txt")
|
||||
fs.writeFileSync(filePath, "var i;")
|
||||
|
||||
afterEach ->
|
||||
fs.removeSync(filePath) if fs.existsSync(filePath)
|
||||
|
||||
it "updates all the rendered lines when the grammar changes", ->
|
||||
editor = atom.project.openSync(filePath)
|
||||
editorView.edit(editor)
|
||||
expect(editor.getGrammar().name).toBe 'Plain Text'
|
||||
atom.syntax.setGrammarOverrideForPath(filePath, 'source.js')
|
||||
editor.reloadGrammar()
|
||||
expect(editor.getGrammar().name).toBe 'JavaScript'
|
||||
|
||||
tokenizedBuffer = editorView.editor.displayBuffer.tokenizedBuffer
|
||||
line0 = tokenizedBuffer.lineForScreenRow(0)
|
||||
expect(line0.tokens.length).toBe 3
|
||||
expect(line0.tokens[0]).toEqual(value: 'var', scopes: ['source.js', 'storage.modifier.js'])
|
||||
|
||||
it "doesn't update the rendered lines when the grammar doesn't change", ->
|
||||
expect(editor.getGrammar().name).toBe 'JavaScript'
|
||||
spyOn(editorView, 'updateDisplay').andCallThrough()
|
||||
editor.reloadGrammar()
|
||||
expect(editor.reloadGrammar()).toBeFalsy()
|
||||
expect(editorView.updateDisplay).not.toHaveBeenCalled()
|
||||
expect(editor.getGrammar().name).toBe 'JavaScript'
|
||||
|
||||
it "emits an editor:grammar-changed event when updated", ->
|
||||
editor = atom.project.openSync(filePath)
|
||||
editorView.edit(editor)
|
||||
|
||||
describe "when the editor's grammar is changed", ->
|
||||
it "emits an editor:grammar-changed event", ->
|
||||
eventHandler = jasmine.createSpy('eventHandler')
|
||||
editorView.on('editor:grammar-changed', eventHandler)
|
||||
editor.reloadGrammar()
|
||||
|
||||
expect(eventHandler).not.toHaveBeenCalled()
|
||||
|
||||
atom.syntax.setGrammarOverrideForPath(filePath, 'source.js')
|
||||
editor.reloadGrammar()
|
||||
editor.setGrammar(atom.syntax.selectGrammar('.coffee'))
|
||||
expect(eventHandler).toHaveBeenCalled()
|
||||
|
||||
describe ".replaceSelectedText()", ->
|
||||
@@ -2810,61 +2800,6 @@ describe "EditorView", ->
|
||||
expect(buffer.lineForRow(1)).toBe ' if (items.length <= 1) return items;'
|
||||
expect(buffer.lineForRow(2)).toBe ' var sort = function(items) {'
|
||||
|
||||
describe "when editor:duplicate-line is triggered", ->
|
||||
describe "where there is no selection", ->
|
||||
describe "when the cursor isn't on a folded line", ->
|
||||
it "duplicates the current line below and moves the cursor down one row", ->
|
||||
editor.setCursorBufferPosition([0, 5])
|
||||
editorView.trigger 'editor:duplicate-line'
|
||||
expect(buffer.lineForRow(0)).toBe 'var quicksort = function () {'
|
||||
expect(buffer.lineForRow(1)).toBe 'var quicksort = function () {'
|
||||
expect(editor.getCursorBufferPosition()).toEqual [1, 5]
|
||||
|
||||
describe "when the cursor is on a folded line", ->
|
||||
it "duplicates the entire fold before and moves the cursor to the new fold", ->
|
||||
editor.setCursorBufferPosition([4])
|
||||
editor.foldCurrentRow()
|
||||
editorView.trigger 'editor:duplicate-line'
|
||||
expect(editor.getCursorScreenPosition()).toEqual [5]
|
||||
expect(editor.isFoldedAtScreenRow(4)).toBeTruthy()
|
||||
expect(editor.isFoldedAtScreenRow(5)).toBeTruthy()
|
||||
expect(buffer.lineForRow(8)).toBe ' while(items.length > 0) {'
|
||||
expect(buffer.lineForRow(9)).toBe ' current = items.shift();'
|
||||
expect(buffer.lineForRow(10)).toBe ' current < pivot ? left.push(current) : right.push(current);'
|
||||
expect(buffer.lineForRow(11)).toBe ' }'
|
||||
|
||||
describe "when the cursor is on the last line and it doesn't have a trailing newline", ->
|
||||
it "inserts a newline and the duplicated line", ->
|
||||
editor.moveCursorToBottom()
|
||||
editorView.trigger 'editor:duplicate-line'
|
||||
expect(buffer.lineForRow(12)).toBe '};'
|
||||
expect(buffer.lineForRow(13)).toBe '};'
|
||||
expect(buffer.lineForRow(14)).toBeUndefined()
|
||||
expect(editor.getCursorBufferPosition()).toEqual [13, 2]
|
||||
|
||||
describe "when the cursor in on the last line and it is only a newline", ->
|
||||
it "duplicates the current line below and moves the cursor down one row", ->
|
||||
editor.moveCursorToBottom()
|
||||
editor.insertNewline()
|
||||
editor.moveCursorToBottom()
|
||||
editorView.trigger 'editor:duplicate-line'
|
||||
expect(buffer.lineForRow(13)).toBe ''
|
||||
expect(buffer.lineForRow(14)).toBe ''
|
||||
expect(buffer.lineForRow(15)).toBeUndefined()
|
||||
expect(editor.getCursorBufferPosition()).toEqual [14, 0]
|
||||
|
||||
describe "when the cursor is on the second to last line and the last line only a newline", ->
|
||||
it "duplicates the current line below and moves the cursor down one row", ->
|
||||
editor.moveCursorToBottom()
|
||||
editor.insertNewline()
|
||||
editor.setCursorBufferPosition([12])
|
||||
editorView.trigger 'editor:duplicate-line'
|
||||
expect(buffer.lineForRow(12)).toBe '};'
|
||||
expect(buffer.lineForRow(13)).toBe '};'
|
||||
expect(buffer.lineForRow(14)).toBe ''
|
||||
expect(buffer.lineForRow(15)).toBeUndefined()
|
||||
expect(editor.getCursorBufferPosition()).toEqual [13, 0]
|
||||
|
||||
describe "when the escape key is pressed on the editor view", ->
|
||||
it "clears multiple selections if there are any, and otherwise allows other bindings to be handled", ->
|
||||
atom.keymap.bindKeys 'name', '.editor', {'escape': 'test-event'}
|
||||
@@ -2987,6 +2922,30 @@ describe "EditorView", ->
|
||||
editorView.pixelPositionForScreenPosition([1, 5])
|
||||
expect(editorView.measureToColumn.callCount).toBe 0
|
||||
|
||||
describe "when stylesheets are changed", ->
|
||||
afterEach ->
|
||||
atom.themes.removeStylesheet 'line-height'
|
||||
atom.themes.removeStylesheet 'char-width'
|
||||
|
||||
it "updates the editor if the line height or character width changes due to a stylesheet change", ->
|
||||
editorView.attachToDom()
|
||||
editor.setCursorScreenPosition([1, 3])
|
||||
expect(editorView.pixelPositionForScreenPosition([1, 3])).toEqual {top: 20, left: 30}
|
||||
expect(editorView.getCursorView().position()).toEqual {top: 20, left: 30}
|
||||
|
||||
atom.themes.applyStylesheet 'line-height', """
|
||||
.editor { line-height: 2; }
|
||||
"""
|
||||
|
||||
expect(editorView.pixelPositionForScreenPosition([1, 3])).toEqual {top: 32, left: 30}
|
||||
expect(editorView.getCursorView().position()).toEqual {top: 32, left: 30}
|
||||
|
||||
atom.themes.applyStylesheet 'char-width', """
|
||||
.editor { letter-spacing: 2px; }
|
||||
"""
|
||||
expect(editorView.pixelPositionForScreenPosition([1, 3])).toEqual {top: 32, left: 36}
|
||||
expect(editorView.getCursorView().position()).toEqual {top: 32, left: 36}
|
||||
|
||||
describe "when the editor contains hard tabs", ->
|
||||
it "correctly calculates the the position left for a column", ->
|
||||
editor.setText('\ttest')
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
module.exports = activate: ->
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "no events",
|
||||
"version": "0.1.0",
|
||||
"activationEvents": []
|
||||
}
|
||||
@@ -1,430 +0,0 @@
|
||||
fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
temp = require 'temp'
|
||||
Keymap = require '../src/keymap'
|
||||
{$, $$, WorkspaceView} = require 'atom'
|
||||
|
||||
describe "Keymap", ->
|
||||
fragment = null
|
||||
keymap = null
|
||||
resourcePath = atom.getLoadSettings().resourcePath
|
||||
configDirPath = null
|
||||
|
||||
beforeEach ->
|
||||
configDirPath = temp.mkdirSync('atom')
|
||||
keymap = new Keymap({configDirPath, resourcePath})
|
||||
fragment = $ """
|
||||
<div class="command-mode">
|
||||
<div class="child-node">
|
||||
<div class="grandchild-node"/>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
|
||||
afterEach ->
|
||||
keymap.destroy()
|
||||
|
||||
describe ".handleKeyEvent(event)", ->
|
||||
deleteCharHandler = null
|
||||
insertCharHandler = null
|
||||
commandZHandler = null
|
||||
|
||||
beforeEach ->
|
||||
keymap.bindKeys 'name', '.command-mode', 'x': 'deleteChar'
|
||||
keymap.bindKeys 'name', '.insert-mode', 'x': 'insertChar'
|
||||
keymap.bindKeys 'name', '.command-mode', 'cmd-z': 'commandZPressed'
|
||||
|
||||
deleteCharHandler = jasmine.createSpy('deleteCharHandler')
|
||||
insertCharHandler = jasmine.createSpy('insertCharHandler')
|
||||
commandZHandler = jasmine.createSpy('commandZHandler')
|
||||
fragment.on 'deleteChar', deleteCharHandler
|
||||
fragment.on 'insertChar', insertCharHandler
|
||||
fragment.on 'commandZPressed', commandZHandler
|
||||
|
||||
describe "when no binding matches the event's keystroke", ->
|
||||
it "does not return false so the event continues to propagate", ->
|
||||
expect(keymap.handleKeyEvent(keydownEvent('0', target: fragment[0]))).not.toBe false
|
||||
|
||||
describe "when a non-English keyboard language is used", ->
|
||||
it "uses the physical character pressed instead of the character it maps to in the current language", ->
|
||||
event = keydownEvent('U+03B6', metaKey: true, which: 122, target: fragment[0]) # This is the 'z' key using the Greek keyboard layout
|
||||
result = keymap.handleKeyEvent(event)
|
||||
|
||||
expect(result).toBe(false)
|
||||
expect(commandZHandler).toHaveBeenCalled()
|
||||
|
||||
describe "when at least one binding fully matches the event's keystroke", ->
|
||||
describe "when the event's target node matches a selector with a matching binding", ->
|
||||
it "triggers the command event associated with that binding on the target node and returns false", ->
|
||||
result = keymap.handleKeyEvent(keydownEvent('x', target: fragment[0]))
|
||||
expect(result).toBe(false)
|
||||
expect(deleteCharHandler).toHaveBeenCalled()
|
||||
expect(insertCharHandler).not.toHaveBeenCalled()
|
||||
|
||||
deleteCharHandler.reset()
|
||||
fragment.removeClass('command-mode').addClass('insert-mode')
|
||||
|
||||
event = keydownEvent('x', target: fragment[0])
|
||||
keymap.handleKeyEvent(event)
|
||||
expect(deleteCharHandler).not.toHaveBeenCalled()
|
||||
expect(insertCharHandler).toHaveBeenCalled()
|
||||
|
||||
describe "when the event's target node *descends* from a selector with a matching binding", ->
|
||||
it "triggers the command event associated with that binding on the target node and returns false", ->
|
||||
target = fragment.find('.child-node')[0]
|
||||
result = keymap.handleKeyEvent(keydownEvent('x', target: target))
|
||||
expect(result).toBe(false)
|
||||
expect(deleteCharHandler).toHaveBeenCalled()
|
||||
expect(insertCharHandler).not.toHaveBeenCalled()
|
||||
|
||||
deleteCharHandler.reset()
|
||||
fragment.removeClass('command-mode').addClass('insert-mode')
|
||||
|
||||
keymap.handleKeyEvent(keydownEvent('x', target: target))
|
||||
expect(deleteCharHandler).not.toHaveBeenCalled()
|
||||
expect(insertCharHandler).toHaveBeenCalled()
|
||||
|
||||
describe "when the event's target node descends from multiple nodes that match selectors with a binding", ->
|
||||
beforeEach ->
|
||||
keymap.bindKeys 'name', '.child-node', 'x': 'foo'
|
||||
|
||||
it "only triggers bindings on selectors associated with the closest ancestor node", ->
|
||||
fooHandler = jasmine.createSpy 'fooHandler'
|
||||
fragment.on 'foo', fooHandler
|
||||
|
||||
target = fragment.find('.grandchild-node')[0]
|
||||
keymap.handleKeyEvent(keydownEvent('x', target: target))
|
||||
expect(fooHandler).toHaveBeenCalled()
|
||||
expect(deleteCharHandler).not.toHaveBeenCalled()
|
||||
expect(insertCharHandler).not.toHaveBeenCalled()
|
||||
|
||||
describe "when 'abortKeyBinding' is called on the triggered event", ->
|
||||
[fooHandler1, fooHandler2] = []
|
||||
|
||||
beforeEach ->
|
||||
fooHandler1 = jasmine.createSpy('fooHandler1').andCallFake (e) ->
|
||||
expect(deleteCharHandler).not.toHaveBeenCalled()
|
||||
e.abortKeyBinding()
|
||||
fooHandler2 = jasmine.createSpy('fooHandler2')
|
||||
|
||||
fragment.find('.child-node').on 'foo', fooHandler1
|
||||
fragment.on 'foo', fooHandler2
|
||||
|
||||
it "aborts the current event and tries again with the next-most-specific key binding", ->
|
||||
target = fragment.find('.grandchild-node')[0]
|
||||
keymap.handleKeyEvent(keydownEvent('x', target: target))
|
||||
expect(fooHandler1).toHaveBeenCalled()
|
||||
expect(fooHandler2).not.toHaveBeenCalled()
|
||||
expect(deleteCharHandler).toHaveBeenCalled()
|
||||
|
||||
it "does not throw an exception if the event was not triggered by the keymap", ->
|
||||
fragment.find('.grandchild-node').trigger 'foo'
|
||||
|
||||
describe "when the event bubbles to a node that matches multiple selectors", ->
|
||||
describe "when the matching selectors differ in specificity", ->
|
||||
it "triggers the binding for the most specific selector", ->
|
||||
keymap.bindKeys 'name', 'div .child-node', 'x': 'foo'
|
||||
keymap.bindKeys 'name', '.command-mode .child-node !important', 'x': 'baz'
|
||||
keymap.bindKeys 'name', '.command-mode .child-node', 'x': 'quux'
|
||||
keymap.bindKeys 'name', '.child-node', 'x': 'bar'
|
||||
|
||||
fooHandler = jasmine.createSpy 'fooHandler'
|
||||
barHandler = jasmine.createSpy 'barHandler'
|
||||
bazHandler = jasmine.createSpy 'bazHandler'
|
||||
fragment.on 'foo', fooHandler
|
||||
fragment.on 'bar', barHandler
|
||||
fragment.on 'baz', bazHandler
|
||||
|
||||
target = fragment.find('.grandchild-node')[0]
|
||||
keymap.handleKeyEvent(keydownEvent('x', target: target))
|
||||
|
||||
expect(fooHandler).not.toHaveBeenCalled()
|
||||
expect(barHandler).not.toHaveBeenCalled()
|
||||
expect(bazHandler).toHaveBeenCalled()
|
||||
|
||||
describe "when the matching selectors have the same specificity", ->
|
||||
it "triggers the bindings for the most recently declared selector", ->
|
||||
keymap.bindKeys 'name', '.child-node', 'x': 'foo', 'y': 'baz'
|
||||
keymap.bindKeys 'name', '.child-node', 'x': 'bar'
|
||||
|
||||
fooHandler = jasmine.createSpy 'fooHandler'
|
||||
barHandler = jasmine.createSpy 'barHandler'
|
||||
bazHandler = jasmine.createSpy 'bazHandler'
|
||||
fragment.on 'foo', fooHandler
|
||||
fragment.on 'bar', barHandler
|
||||
fragment.on 'baz', bazHandler
|
||||
|
||||
target = fragment.find('.grandchild-node')[0]
|
||||
keymap.handleKeyEvent(keydownEvent('x', target: target))
|
||||
|
||||
expect(barHandler).toHaveBeenCalled()
|
||||
expect(fooHandler).not.toHaveBeenCalled()
|
||||
|
||||
keymap.handleKeyEvent(keydownEvent('y', target: target))
|
||||
expect(bazHandler).toHaveBeenCalled()
|
||||
|
||||
describe "when the event's target is the document body", ->
|
||||
it "triggers the mapped event on the workspaceView", ->
|
||||
atom.workspaceView = new WorkspaceView
|
||||
atom.workspaceView.attachToDom()
|
||||
keymap.bindKeys 'name', 'body', 'x': 'foo'
|
||||
fooHandler = jasmine.createSpy("fooHandler")
|
||||
atom.workspaceView.on 'foo', fooHandler
|
||||
|
||||
result = keymap.handleKeyEvent(keydownEvent('x', target: document.body))
|
||||
expect(result).toBe(false)
|
||||
expect(fooHandler).toHaveBeenCalled()
|
||||
expect(deleteCharHandler).not.toHaveBeenCalled()
|
||||
expect(insertCharHandler).not.toHaveBeenCalled()
|
||||
|
||||
describe "when the event matches a 'native!' binding", ->
|
||||
it "returns true, allowing the browser's native key handling to process the event", ->
|
||||
keymap.bindKeys 'name', '.grandchild-node', 'x': 'native!'
|
||||
nativeHandler = jasmine.createSpy("nativeHandler")
|
||||
fragment.on 'native!', nativeHandler
|
||||
expect(keymap.handleKeyEvent(keydownEvent('x', target: fragment.find('.grandchild-node')[0]))).toBe true
|
||||
expect(nativeHandler).not.toHaveBeenCalled()
|
||||
|
||||
describe "when at least one binding partially matches the event's keystroke", ->
|
||||
[quitHandler, closeOtherWindowsHandler] = []
|
||||
|
||||
beforeEach ->
|
||||
keymap.bindKeys 'name', "*",
|
||||
'ctrl-x ctrl-c': 'quit'
|
||||
'ctrl-x 1': 'close-other-windows'
|
||||
|
||||
quitHandler = jasmine.createSpy('quitHandler')
|
||||
closeOtherWindowsHandler = jasmine.createSpy('closeOtherWindowsHandler')
|
||||
fragment.on 'quit', quitHandler
|
||||
fragment.on 'close-other-windows', closeOtherWindowsHandler
|
||||
|
||||
it "only matches entire keystroke patterns", ->
|
||||
expect(keymap.handleKeyEvent(keydownEvent('c', target: fragment[0]))).not.toBe false
|
||||
|
||||
describe "when the event's target node matches a selector with a partially matching multi-stroke binding", ->
|
||||
describe "when a second keystroke added to the first to match a multi-stroke binding completely", ->
|
||||
it "triggers the event associated with the matched multi-stroke binding", ->
|
||||
expect(keymap.handleKeyEvent(keydownEvent('x', target: fragment[0], ctrlKey: true))).toBeFalsy()
|
||||
expect(keymap.handleKeyEvent(keydownEvent('ctrl', target: fragment[0]))).toBeFalsy() # This simulates actual key event behavior
|
||||
expect(keymap.handleKeyEvent(keydownEvent('c', target: fragment[0], ctrlKey: true))).toBeFalsy()
|
||||
|
||||
expect(quitHandler).toHaveBeenCalled()
|
||||
expect(closeOtherWindowsHandler).not.toHaveBeenCalled()
|
||||
quitHandler.reset()
|
||||
|
||||
expect(keymap.handleKeyEvent(keydownEvent('x', target: fragment[0], ctrlKey: true))).toBeFalsy()
|
||||
expect(keymap.handleKeyEvent(keydownEvent('1', target: fragment[0]))).toBeFalsy()
|
||||
|
||||
expect(quitHandler).not.toHaveBeenCalled()
|
||||
expect(closeOtherWindowsHandler).toHaveBeenCalled()
|
||||
|
||||
describe "when a second keystroke added to the first doesn't match any bindings", ->
|
||||
it "clears the queued keystroke without triggering any events", ->
|
||||
expect(keymap.handleKeyEvent(keydownEvent('x', target: fragment[0], ctrlKey: true))).toBe false
|
||||
expect(keymap.handleKeyEvent(keydownEvent('c', target: fragment[0]))).toBe false
|
||||
expect(quitHandler).not.toHaveBeenCalled()
|
||||
expect(closeOtherWindowsHandler).not.toHaveBeenCalled()
|
||||
|
||||
expect(keymap.handleKeyEvent(keydownEvent('c', target: fragment[0]))).not.toBe false
|
||||
|
||||
describe "when the event's target node descends from multiple nodes that match selectors with a partial binding match", ->
|
||||
it "allows any of the bindings to be triggered upon a second keystroke, favoring the most specific selector", ->
|
||||
keymap.bindKeys 'name', ".grandchild-node", 'ctrl-x ctrl-c': 'more-specific-quit'
|
||||
grandchildNode = fragment.find('.grandchild-node')[0]
|
||||
moreSpecificQuitHandler = jasmine.createSpy('moreSpecificQuitHandler')
|
||||
fragment.on 'more-specific-quit', moreSpecificQuitHandler
|
||||
|
||||
expect(keymap.handleKeyEvent(keydownEvent('x', target: grandchildNode, ctrlKey: true))).toBeFalsy()
|
||||
expect(keymap.handleKeyEvent(keydownEvent('1', target: grandchildNode))).toBeFalsy()
|
||||
expect(quitHandler).not.toHaveBeenCalled()
|
||||
expect(moreSpecificQuitHandler).not.toHaveBeenCalled()
|
||||
expect(closeOtherWindowsHandler).toHaveBeenCalled()
|
||||
closeOtherWindowsHandler.reset()
|
||||
|
||||
expect(keymap.handleKeyEvent(keydownEvent('x', target: grandchildNode, ctrlKey: true))).toBeFalsy()
|
||||
expect(keymap.handleKeyEvent(keydownEvent('c', target: grandchildNode, ctrlKey: true))).toBeFalsy()
|
||||
expect(quitHandler).not.toHaveBeenCalled()
|
||||
expect(closeOtherWindowsHandler).not.toHaveBeenCalled()
|
||||
expect(moreSpecificQuitHandler).toHaveBeenCalled()
|
||||
|
||||
describe "when there is a complete binding with a less specific selector", ->
|
||||
it "favors the more specific partial match", ->
|
||||
|
||||
describe "when there is a complete binding with a more specific selector", ->
|
||||
it "favors the more specific complete match", ->
|
||||
|
||||
describe ".bindKeys(name, selector, bindings)", ->
|
||||
it "normalizes the key patterns in the hash to put the modifiers in alphabetical order", ->
|
||||
fooHandler = jasmine.createSpy('fooHandler')
|
||||
fragment.on 'foo', fooHandler
|
||||
keymap.bindKeys 'name', '*', 'ctrl-alt-delete': 'foo'
|
||||
result = keymap.handleKeyEvent(keydownEvent('delete', ctrlKey: true, altKey: true, target: fragment[0]))
|
||||
expect(result).toBe(false)
|
||||
expect(fooHandler).toHaveBeenCalled()
|
||||
|
||||
fooHandler.reset()
|
||||
keymap.bindKeys 'name', '*', 'ctrl-alt--': 'foo'
|
||||
result = keymap.handleKeyEvent(keydownEvent('-', ctrlKey: true, altKey: true, target: fragment[0]))
|
||||
expect(result).toBe(false)
|
||||
expect(fooHandler).toHaveBeenCalled()
|
||||
|
||||
describe ".remove(name)", ->
|
||||
it "removes the binding set with the given selector and bindings", ->
|
||||
keymap.add 'nature',
|
||||
'.green':
|
||||
'ctrl-c': 'cultivate'
|
||||
'.brown':
|
||||
'ctrl-h': 'harvest'
|
||||
|
||||
keymap.add 'medical',
|
||||
'.green':
|
||||
'ctrl-v': 'vomit'
|
||||
|
||||
expect(keymap.keyBindingsMatchingElement($$ -> @div class: 'green')).toHaveLength 2
|
||||
expect(keymap.keyBindingsMatchingElement($$ -> @div class: 'brown')).toHaveLength 1
|
||||
|
||||
keymap.remove('nature')
|
||||
|
||||
expect(keymap.keyBindingsMatchingElement($$ -> @div class: 'green')).toHaveLength 1
|
||||
expect(keymap.keyBindingsMatchingElement($$ -> @div class: 'brown')).toEqual []
|
||||
|
||||
describe ".keystrokeStringForEvent(event)", ->
|
||||
describe "when no modifiers are pressed", ->
|
||||
it "returns a string that identifies the key pressed", ->
|
||||
expect(keymap.keystrokeStringForEvent(keydownEvent('a'))).toBe 'a'
|
||||
expect(keymap.keystrokeStringForEvent(keydownEvent('['))).toBe '['
|
||||
expect(keymap.keystrokeStringForEvent(keydownEvent('*'))).toBe '*'
|
||||
expect(keymap.keystrokeStringForEvent(keydownEvent('left'))).toBe 'left'
|
||||
expect(keymap.keystrokeStringForEvent(keydownEvent('\b'))).toBe 'backspace'
|
||||
|
||||
describe "when ctrl, alt or command is pressed with a non-modifier key", ->
|
||||
it "returns a string that identifies the key pressed", ->
|
||||
expect(keymap.keystrokeStringForEvent(keydownEvent('a', altKey: true))).toBe 'alt-a'
|
||||
expect(keymap.keystrokeStringForEvent(keydownEvent('[', metaKey: true))).toBe 'cmd-['
|
||||
expect(keymap.keystrokeStringForEvent(keydownEvent('*', ctrlKey: true))).toBe 'ctrl-*'
|
||||
expect(keymap.keystrokeStringForEvent(keydownEvent('left', ctrlKey: true, metaKey: true, altKey: true))).toBe 'alt-cmd-ctrl-left'
|
||||
|
||||
describe "when shift is pressed when a non-modifer key", ->
|
||||
it "returns a string that identifies the key pressed", ->
|
||||
expect(keymap.keystrokeStringForEvent(keydownEvent('A', shiftKey: true))).toBe 'A'
|
||||
expect(keymap.keystrokeStringForEvent(keydownEvent('{', shiftKey: true))).toBe '{'
|
||||
expect(keymap.keystrokeStringForEvent(keydownEvent('left', shiftKey: true))).toBe 'shift-left'
|
||||
expect(keymap.keystrokeStringForEvent(keydownEvent('Left', shiftKey: true))).toBe 'shift-left'
|
||||
|
||||
describe ".keyBindingsMatchingElement(element)", ->
|
||||
it "returns the matching bindings for the element", ->
|
||||
keymap.bindKeys 'name', '.command-mode', 'c': 'c'
|
||||
keymap.bindKeys 'name', '.grandchild-node', 'g': 'g'
|
||||
|
||||
bindings = keymap.keyBindingsMatchingElement(fragment.find('.grandchild-node'))
|
||||
expect(bindings).toHaveLength 2
|
||||
expect(bindings[0].command).toEqual "g"
|
||||
expect(bindings[1].command).toEqual "c"
|
||||
|
||||
describe "when multiple bindings match a keystroke", ->
|
||||
it "only returns bindings that match the most specific selector", ->
|
||||
keymap.bindKeys 'name', '.command-mode', 'g': 'cmd-mode'
|
||||
keymap.bindKeys 'name', '.command-mode .grandchild-node', 'g': 'cmd-and-grandchild-node'
|
||||
keymap.bindKeys 'name', '.grandchild-node', 'g': 'grandchild-node'
|
||||
|
||||
bindings = keymap.keyBindingsMatchingElement(fragment.find('.grandchild-node'))
|
||||
expect(bindings).toHaveLength 3
|
||||
expect(bindings[0].command).toEqual "cmd-and-grandchild-node"
|
||||
|
||||
describe ".keyBindingsForCommandMatchingElement(element)", ->
|
||||
beforeEach ->
|
||||
keymap.add 'nature',
|
||||
'.green':
|
||||
'ctrl-c': 'cultivate'
|
||||
'.green-2':
|
||||
'ctrl-o': 'cultivate'
|
||||
'.brown':
|
||||
'ctrl-h': 'harvest'
|
||||
'.blue':
|
||||
'ctrl-c': 'fly'
|
||||
|
||||
it "finds a keymap for an element", ->
|
||||
el = $$ -> @div class: 'green'
|
||||
bindings = keymap.keyBindingsForCommandMatchingElement('cultivate', el)
|
||||
expect(bindings).toHaveLength 1
|
||||
expect(bindings[0].keystroke).toEqual "ctrl-c"
|
||||
|
||||
it "no keymap an element without that map", ->
|
||||
el = $$ -> @div class: 'brown'
|
||||
bindings = keymap.keyBindingsForCommandMatchingElement('cultivate', el)
|
||||
expect(bindings).toHaveLength 0
|
||||
|
||||
describe "loading platform specific keybindings", ->
|
||||
customKeymap = null
|
||||
|
||||
beforeEach ->
|
||||
resourcePath = temp.mkdirSync('atom')
|
||||
customKeymap = new Keymap({configDirPath, resourcePath})
|
||||
|
||||
afterEach ->
|
||||
customKeymap.destroy()
|
||||
|
||||
it "doesn't load keybindings from other platforms", ->
|
||||
win32FilePath = path.join(resourcePath, "keymaps", "win32.cson")
|
||||
darwinFilePath = path.join(resourcePath, "keymaps", "darwin.cson")
|
||||
fs.writeFileSync(win32FilePath, '"body": "ctrl-l": "core:win32-move-left"')
|
||||
fs.writeFileSync(darwinFilePath, '"body": "ctrl-l": "core:darwin-move-left"')
|
||||
|
||||
customKeymap.loadBundledKeymaps()
|
||||
keyBindings = customKeymap.keyBindingsForKeystroke('ctrl-l')
|
||||
expect(keyBindings).toHaveLength 1
|
||||
expect(keyBindings[0].command).toBe "core:#{process.platform}-move-left"
|
||||
|
||||
describe "when the user keymap file is changed", ->
|
||||
it "is reloaded", ->
|
||||
keymapFilePath = path.join(configDirPath, "keymap.cson")
|
||||
fs.writeFileSync(keymapFilePath, '"body": "ctrl-l": "core:move-left"')
|
||||
keymap.loadUserKeymap()
|
||||
|
||||
spyOn(keymap, 'loadUserKeymap').andCallThrough()
|
||||
fs.writeFileSync(keymapFilePath, "'body': 'ctrl-l': 'core:move-right'")
|
||||
|
||||
waitsFor ->
|
||||
keymap.loadUserKeymap.callCount > 0
|
||||
|
||||
runs ->
|
||||
keyBinding = keymap.keyBindingsForKeystroke('ctrl-l')[0]
|
||||
expect(keyBinding.command).toBe 'core:move-right'
|
||||
keymap.loadUserKeymap.reset()
|
||||
fs.removeSync(keymapFilePath)
|
||||
|
||||
waitsFor ->
|
||||
keymap.loadUserKeymap.callCount > 0
|
||||
|
||||
runs ->
|
||||
keyBinding = keymap.keyBindingsForKeystroke('ctrl-l')[0]
|
||||
expect(keyBinding).toBeUndefined()
|
||||
|
||||
it "logs a warning when it can't be parsed", ->
|
||||
keymapFilePath = path.join(configDirPath, "keymap.json")
|
||||
fs.writeFileSync(keymapFilePath, '')
|
||||
keymap.loadUserKeymap()
|
||||
|
||||
spyOn(keymap, 'loadUserKeymap').andCallThrough()
|
||||
fs.writeFileSync(keymapFilePath, '}{')
|
||||
spyOn(console, 'warn')
|
||||
|
||||
waitsFor ->
|
||||
keymap.loadUserKeymap.callCount > 0
|
||||
|
||||
runs ->
|
||||
expect(console.warn.callCount).toBe 1
|
||||
expect(console.warn.argsForCall[0][0].length).toBeGreaterThan 0
|
||||
|
||||
describe "when adding a binding with an invalid selector", ->
|
||||
it "logs a warning and does not add it", ->
|
||||
spyOn(console, 'warn')
|
||||
keybinding =
|
||||
'##selector':
|
||||
'cmd-a': 'invalid-command'
|
||||
keymap.add('test', keybinding)
|
||||
|
||||
expect(console.warn.callCount).toBe 1
|
||||
expect(console.warn.argsForCall[0][0].length).toBeGreaterThan 0
|
||||
expect(-> keymap.keyBindingsMatchingElement(document.body)).not.toThrow()
|
||||
expect(keymap.keyBindingsForCommand('invalid:command')).toEqual []
|
||||
@@ -208,6 +208,20 @@ describe "LanguageMode", ->
|
||||
languageMode.toggleLineCommentsForBufferRows(0, 0)
|
||||
expect(buffer.lineForRow(0)).toBe "// @color: #4D926F;"
|
||||
|
||||
describe "xml", ->
|
||||
beforeEach ->
|
||||
editor = atom.project.openSync('sample.xml', autoIndent: false)
|
||||
editor.setText("<!-- test -->")
|
||||
{buffer, languageMode} = editor
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-xml')
|
||||
|
||||
describe "when uncommenting lines", ->
|
||||
it "removes the leading whitespace from the comment end pattern match", ->
|
||||
languageMode.toggleLineCommentsForBufferRows(0, 0)
|
||||
expect(buffer.lineForRow(0)).toBe "test"
|
||||
|
||||
describe "folding", ->
|
||||
beforeEach ->
|
||||
editor = atom.project.openSync('sample.js', autoIndent: false)
|
||||
@@ -285,21 +299,6 @@ describe "LanguageMode", ->
|
||||
expect(fold.getStartRow()).toBe 0
|
||||
expect(fold.getEndRow()).toBe 13
|
||||
|
||||
describe ".unfoldBufferRow(bufferRow)", ->
|
||||
describe "when bufferRow can be unfolded", ->
|
||||
it "destroys a fold based on the syntactic region starting at the given row", ->
|
||||
languageMode.foldBufferRow(1)
|
||||
expect(editor.lineForScreenRow(1).fold).toBeDefined()
|
||||
|
||||
languageMode.unfoldBufferRow(1)
|
||||
expect(editor.lineForScreenRow(1).fold).toBeUndefined()
|
||||
|
||||
describe "when bufferRow can't be unfolded", ->
|
||||
it "does not throw an error", ->
|
||||
expect(editor.lineForScreenRow(1).fold).toBeUndefined()
|
||||
languageMode.unfoldBufferRow(1)
|
||||
expect(editor.lineForScreenRow(1).fold).toBeUndefined()
|
||||
|
||||
describe ".isFoldableAtBufferRow(bufferRow)", ->
|
||||
it "returns true if the line starts a foldable row range", ->
|
||||
expect(languageMode.isFoldableAtBufferRow(0)).toBe true
|
||||
|
||||
@@ -292,7 +292,7 @@ describe "Pane", ->
|
||||
pane.activeItem.path = __filename
|
||||
pane.activeItem.saveAs = jasmine.createSpy("saveAs")
|
||||
pane.saveActiveItemAs()
|
||||
expect(atom.showSaveDialogSync).toHaveBeenCalledWith(__dirname)
|
||||
expect(atom.showSaveDialogSync).toHaveBeenCalledWith(__filename)
|
||||
expect(pane.activeItem.saveAs).toHaveBeenCalledWith('/selected/path')
|
||||
|
||||
describe "when the current item does not have a saveAs method", ->
|
||||
|
||||
@@ -159,14 +159,14 @@ describe "PaneView", ->
|
||||
|
||||
describe "when an unmodifed buffer's path is deleted", ->
|
||||
it "removes the pane item", ->
|
||||
jasmine.unspy(window, 'setTimeout')
|
||||
filePath = temp.openSync('atom').path
|
||||
editor = atom.project.openSync(filePath)
|
||||
pane.activateItem(editor)
|
||||
expect(pane.items).toHaveLength(5)
|
||||
|
||||
fs.removeSync(filePath)
|
||||
waitsFor 30000, ->
|
||||
pane.items.length == 4
|
||||
waitsFor -> pane.items.length == 4
|
||||
|
||||
describe "when a pane is destroyed", ->
|
||||
[pane2, pane2Model] = []
|
||||
|
||||
@@ -491,6 +491,16 @@ describe "Project", ->
|
||||
expect(resultForA.matches).toHaveLength 1
|
||||
expect(resultForA.matches[0].matchText).toBe 'Elephant'
|
||||
|
||||
it "ignores buffers outside the project", ->
|
||||
editor = atom.project.openSync(temp.openSync().path)
|
||||
editor.setText("Elephant")
|
||||
results = []
|
||||
waitsForPromise ->
|
||||
atom.project.scan /Elephant/, (result) -> results.push result
|
||||
|
||||
runs ->
|
||||
expect(results).toHaveLength 0
|
||||
|
||||
describe ".eachBuffer(callback)", ->
|
||||
beforeEach ->
|
||||
atom.project.bufferForPathSync('a')
|
||||
|
||||
@@ -43,6 +43,15 @@ describe "SelectListView", ->
|
||||
expect(list.find('li:eq(0)')).toHaveClass 'A'
|
||||
expect(selectList.getSelectedItem()).toBe items[0]
|
||||
|
||||
it "allows raw HTML to be returned", ->
|
||||
selectList.viewForItem = (item) ->
|
||||
"<li>#{item}</li>"
|
||||
|
||||
selectList.setItems(['Bermuda', 'Bahama'])
|
||||
|
||||
expect(list.find('li:eq(0)')).toHaveText 'Bermuda'
|
||||
expect(selectList.getSelectedItem()).toBe 'Bermuda'
|
||||
|
||||
describe "when the text of the mini editor changes", ->
|
||||
beforeEach ->
|
||||
selectList.attachToDom()
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# Start the crash reporter before anything else.
|
||||
require('crash-reporter').start(productName: 'Atom', companyName: 'GitHub')
|
||||
|
||||
path = require 'path'
|
||||
|
||||
try
|
||||
require '../src/window'
|
||||
Atom = require '../src/atom'
|
||||
@@ -12,6 +14,12 @@ try
|
||||
|
||||
{runSpecSuite} = require './jasmine-helper'
|
||||
|
||||
# Add 'src/exports' to module search path.
|
||||
exportsPath = path.resolve(atom.getLoadSettings().resourcePath, 'exports')
|
||||
require('module').globalPaths.push(exportsPath)
|
||||
# Still set NODE_PATH since tasks may need it.
|
||||
process.env.NODE_PATH = exportsPath
|
||||
|
||||
document.title = "Spec Suite"
|
||||
runSpecSuite './spec-suite', atom.getLoadSettings().logFile
|
||||
catch error
|
||||
|
||||
@@ -6,8 +6,8 @@ require '../vendor/jasmine-jquery'
|
||||
path = require 'path'
|
||||
_ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
Keymap = require '../src/keymap-extensions'
|
||||
{$, WorkspaceView} = require 'atom'
|
||||
Keymap = require '../src/keymap'
|
||||
Config = require '../src/config'
|
||||
{Point} = require 'text-buffer'
|
||||
Project = require '../src/project'
|
||||
@@ -180,7 +180,15 @@ window.keyIdentifierForKey = (key) ->
|
||||
"U+00" + charCode.toString(16)
|
||||
|
||||
window.keydownEvent = (key, properties={}) ->
|
||||
properties = $.extend({originalEvent: { keyIdentifier: keyIdentifierForKey(key) }}, properties)
|
||||
originalEventProperties = {}
|
||||
originalEventProperties.ctrl = properties.ctrlKey
|
||||
originalEventProperties.alt = properties.altKey
|
||||
originalEventProperties.shift = properties.shiftKey
|
||||
originalEventProperties.cmd = properties.metaKey
|
||||
originalEventProperties.target = properties.target?[0] ? properties.target
|
||||
originalEventProperties.which = properties.which
|
||||
originalEvent = Keymap.keydownEvent(key, originalEventProperties)
|
||||
properties = $.extend({originalEvent}, properties)
|
||||
$.Event("keydown", properties)
|
||||
|
||||
window.mouseEvent = (type, properties) ->
|
||||
|
||||
@@ -5,7 +5,7 @@ path = require 'path'
|
||||
require './spec-helper'
|
||||
|
||||
requireSpecs = (specDirectory, specType) ->
|
||||
for specFilePath in fs.listTreeSync(specDirectory) when /-spec\.coffee$/.test specFilePath
|
||||
for specFilePath in fs.listTreeSync(specDirectory) when /-spec\.(coffee|js)$/.test specFilePath
|
||||
require specFilePath
|
||||
|
||||
# Set spec directory on spec for setting up the project in spec-helper
|
||||
@@ -26,6 +26,7 @@ setSpecDirectory = (specDirectory) ->
|
||||
|
||||
runAllSpecs = ->
|
||||
{resourcePath} = atom.getLoadSettings()
|
||||
|
||||
# Only run core specs when resource path is the Atom repository
|
||||
if Git.exists(resourcePath)
|
||||
requireSpecs(path.join(resourcePath, 'spec'))
|
||||
|
||||
@@ -170,8 +170,11 @@ describe "ThemeManager", ->
|
||||
expect($(document.body).css('font-weight')).not.toBe("bold")
|
||||
themeManager.requireStylesheet(cssPath)
|
||||
expect($(document.body).css('font-weight')).toBe("bold")
|
||||
|
||||
themeManager.on 'stylesheets-changed', stylesheetsChangedHandler = jasmine.createSpy("stylesheetsChangedHandler")
|
||||
themeManager.removeStylesheet(cssPath)
|
||||
expect($(document.body).css('font-weight')).not.toBe("bold")
|
||||
expect(stylesheetsChangedHandler).toHaveBeenCalled()
|
||||
|
||||
describe "base stylesheet loading", ->
|
||||
beforeEach ->
|
||||
@@ -204,12 +207,15 @@ describe "ThemeManager", ->
|
||||
fs.writeFileSync(userStylesheetPath, 'body {border-style: dotted !important;}')
|
||||
|
||||
spyOn(themeManager, 'getUserStylesheetPath').andReturn userStylesheetPath
|
||||
themeManager.on 'stylesheets-changed', stylesheetsChangedHandler = jasmine.createSpy("stylesheetsChangedHandler")
|
||||
|
||||
waitsForPromise ->
|
||||
themeManager.activateThemes()
|
||||
|
||||
runs ->
|
||||
expect($(document.body).css('border-style')).toBe 'dotted'
|
||||
expect(stylesheetsChangedHandler).toHaveBeenCalled()
|
||||
stylesheetsChangedHandler.reset()
|
||||
spyOn(themeManager, 'loadUserStylesheet').andCallThrough()
|
||||
fs.writeFileSync(userStylesheetPath, 'body {border-style: dashed}')
|
||||
|
||||
@@ -218,6 +224,8 @@ describe "ThemeManager", ->
|
||||
|
||||
runs ->
|
||||
expect($(document.body).css('border-style')).toBe 'dashed'
|
||||
expect(stylesheetsChangedHandler).toHaveBeenCalled()
|
||||
stylesheetsChangedHandler.reset()
|
||||
fs.removeSync(userStylesheetPath)
|
||||
|
||||
waitsFor ->
|
||||
@@ -225,6 +233,7 @@ describe "ThemeManager", ->
|
||||
|
||||
runs ->
|
||||
expect($(document.body).css('border-style')).toBe 'none'
|
||||
expect(stylesheetsChangedHandler).toHaveBeenCalled()
|
||||
|
||||
describe "when a non-existent theme is present in the config", ->
|
||||
it "logs a warning but does not throw an exception (regression)", ->
|
||||
|
||||
@@ -452,3 +452,14 @@ describe "TokenizedBuffer", ->
|
||||
expect(tokenizedBuffer.tokenForPosition([0,0]).value).toBe ' '
|
||||
atom.config.set('editor.tabLength', 6)
|
||||
expect(tokenizedBuffer.tokenForPosition([0,0]).value).toBe ' '
|
||||
|
||||
it "does not allow the tab length to be less than 1", ->
|
||||
buffer = atom.project.bufferForPathSync('sample.js')
|
||||
buffer.setText('\ttest')
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
expect(tokenizedBuffer.tokenForPosition([0,0]).value).toBe ' '
|
||||
atom.config.set('editor.tabLength', 1)
|
||||
expect(tokenizedBuffer.tokenForPosition([0,0]).value).toBe ' '
|
||||
atom.config.set('editor.tabLength', 0)
|
||||
expect(tokenizedBuffer.tokenForPosition([0,0]).value).toBe ' '
|
||||
|
||||
@@ -90,11 +90,13 @@ describe "Window", ->
|
||||
it "saves the serialized state of the window so it can be deserialized after reload", ->
|
||||
workspaceState = atom.workspace.serialize()
|
||||
syntaxState = atom.syntax.serialize()
|
||||
projectState = atom.project.serialize()
|
||||
|
||||
atom.unloadEditorWindow()
|
||||
|
||||
expect(atom.state.workspace).toEqual workspaceState
|
||||
expect(atom.state.syntax).toEqual syntaxState
|
||||
expect(atom.state.project).toEqual projectState
|
||||
expect(atom.saveSync).toHaveBeenCalled()
|
||||
|
||||
it "unsubscribes from all buffers", ->
|
||||
|
||||
@@ -14,14 +14,24 @@ describe "Workspace", ->
|
||||
describe "when the 'searchAllPanes' option is false (default)", ->
|
||||
describe "when called without a uri", ->
|
||||
it "adds and activates an empty editor on the active pane", ->
|
||||
editor = null
|
||||
[editor1, editor2] = []
|
||||
|
||||
waitsForPromise ->
|
||||
workspace.open().then (o) -> editor = o
|
||||
workspace.open().then (editor) -> editor1 = editor
|
||||
|
||||
runs ->
|
||||
expect(editor.getPath()).toBeUndefined()
|
||||
expect(workspace.activePane.items).toEqual [editor]
|
||||
expect(workspace.activePaneItem).toBe editor
|
||||
expect(editor1.getPath()).toBeUndefined()
|
||||
expect(workspace.activePane.items).toEqual [editor1]
|
||||
expect(workspace.activePaneItem).toBe editor1
|
||||
expect(workspace.activePane.activate).toHaveBeenCalled()
|
||||
|
||||
waitsForPromise ->
|
||||
workspace.open().then (editor) -> editor2 = editor
|
||||
|
||||
runs ->
|
||||
expect(editor2.getPath()).toBeUndefined()
|
||||
expect(workspace.activePane.items).toEqual [editor1, editor2]
|
||||
expect(workspace.activePaneItem).toBe editor2
|
||||
expect(workspace.activePane.activate).toHaveBeenCalled()
|
||||
|
||||
describe "when called with a uri", ->
|
||||
|
||||
@@ -241,3 +241,11 @@ describe "WorkspaceView", ->
|
||||
expect(atom.workspaceView.getActivePane().getItems()).toHaveLength 1
|
||||
atom.workspaceView.trigger('core:close')
|
||||
expect(atom.workspaceView.getActivePane().getItems()).toHaveLength 0
|
||||
|
||||
describe "the scrollbar visibility class", ->
|
||||
it "has a class based on the style of the scrollbar", ->
|
||||
scrollbarStyle = require 'scrollbar-style'
|
||||
scrollbarStyle.emitValue 'legacy'
|
||||
expect(atom.workspaceView).toHaveClass 'scrollbars-visible-always'
|
||||
scrollbarStyle.emitValue 'overlay'
|
||||
expect(atom.workspaceView).toHaveClass 'scrollbars-visible-when-scrolling'
|
||||
|
||||
+15
-5
@@ -34,6 +34,8 @@ WindowEventHandler = require './window-event-handler'
|
||||
# * `atom.workspaceView` - A {WorkspaceView} instance
|
||||
module.exports =
|
||||
class Atom extends Model
|
||||
@version: 1 # Increment this when the serialization format changes
|
||||
|
||||
# Public: Load or create the Atom environment in the given mode.
|
||||
#
|
||||
# - mode: Pass 'editor' or 'spec' depending on the kind of environment you
|
||||
@@ -41,11 +43,11 @@ class Atom extends Model
|
||||
#
|
||||
# Returns an Atom instance, fully initialized
|
||||
@loadOrCreate: (mode) ->
|
||||
@deserialize(@loadState(mode)) ? new this({mode, version: @getVersion()})
|
||||
@deserialize(@loadState(mode)) ? new this({mode, @version})
|
||||
|
||||
# Deserializes the Atom environment from a state object
|
||||
@deserialize: (state) ->
|
||||
new this(state) if state?.version is @getVersion()
|
||||
new this(state) if state?.version is @version
|
||||
|
||||
# Loads and returns the serialized state corresponding to this window
|
||||
# if it exists; otherwise returns undefined.
|
||||
@@ -110,7 +112,7 @@ class Atom extends Model
|
||||
|
||||
# Get the version of the Atom application.
|
||||
@getVersion: ->
|
||||
@version ?= @getLoadSettings().appVersion
|
||||
@appVersion ?= @getLoadSettings().appVersion
|
||||
|
||||
# Determine whether the current version is an official release.
|
||||
@isReleasedVersion: ->
|
||||
@@ -138,7 +140,7 @@ class Atom extends Model
|
||||
@loadTime = null
|
||||
|
||||
Config = require './config'
|
||||
Keymap = require './keymap'
|
||||
Keymap = require './keymap-extensions'
|
||||
PackageManager = require './package-manager'
|
||||
Clipboard = require './clipboard'
|
||||
Syntax = require './syntax'
|
||||
@@ -148,6 +150,12 @@ class Atom extends Model
|
||||
{devMode, resourcePath} = @getLoadSettings()
|
||||
configDirPath = @getConfigDirPath()
|
||||
|
||||
# Add 'src/exports' to module search path.
|
||||
exportsPath = path.resolve(resourcePath, 'exports')
|
||||
require('module').globalPaths.push(exportsPath)
|
||||
# Still set NODE_PATH since tasks may need it.
|
||||
process.env.NODE_PATH = exportsPath
|
||||
|
||||
@config = new Config({configDirPath, resourcePath})
|
||||
@keymap = new Keymap({configDirPath, resourcePath})
|
||||
@packages = new PackageManager({devMode, configDirPath, resourcePath})
|
||||
@@ -229,13 +237,14 @@ class Atom extends Model
|
||||
|
||||
deserializeProject: ->
|
||||
Project = require './project'
|
||||
@project ?= @deserializers.deserialize(@project) ? new Project(path: @getLoadSettings().initialPath)
|
||||
@project ?= @deserializers.deserialize(@state.project) ? new Project(path: @getLoadSettings().initialPath)
|
||||
|
||||
deserializeWorkspaceView: ->
|
||||
Workspace = require './workspace'
|
||||
WorkspaceView = require './workspace-view'
|
||||
@workspace = Workspace.deserialize(@state.workspace) ? new Workspace
|
||||
@workspaceView = new WorkspaceView(@workspace)
|
||||
@keymap.defaultTarget = @workspaceView[0]
|
||||
$(@workspaceViewParentSelector).append(@workspaceView)
|
||||
|
||||
deserializePackageStates: ->
|
||||
@@ -280,6 +289,7 @@ class Atom extends Model
|
||||
return if not @project and not @workspaceView
|
||||
|
||||
@state.syntax = @syntax.serialize()
|
||||
@state.project = @project.serialize()
|
||||
@state.workspace = @workspace.serialize()
|
||||
@packages.deactivatePackages()
|
||||
@state.packageStates = @packages.packageStates
|
||||
|
||||
@@ -71,11 +71,28 @@ class ApplicationMenu
|
||||
|
||||
# Toggles Install Update Item
|
||||
showInstallUpdateItem: (visible=true) ->
|
||||
if visible
|
||||
@showDownloadingUpdateItem(false)
|
||||
@showCheckForUpdateItem(false)
|
||||
|
||||
if (item = _.find(@flattenMenuItems(@menu), (i) -> i.label == 'Restart and Install Update'))
|
||||
item.visible = visible
|
||||
|
||||
# Toggles Downloading Update Item
|
||||
showDownloadingUpdateItem: (visible=true) ->
|
||||
if visible
|
||||
@showInstallUpdateItem(false)
|
||||
@showCheckForUpdateItem(false)
|
||||
|
||||
if (item = _.find(@flattenMenuItems(@menu), (i) -> i.label == 'Downloading Update'))
|
||||
item.visible = visible
|
||||
|
||||
# Toggles Check For Update Item
|
||||
showCheckForUpdateItem: (visible=true) ->
|
||||
if visible
|
||||
@showDownloadingUpdateItem(false)
|
||||
@showInstallUpdateItem(false)
|
||||
|
||||
if (item = _.find(@flattenMenuItems(@menu), (i) -> i.label == 'Check for Update'))
|
||||
item.visible = visible
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@ socketPath =
|
||||
module.exports =
|
||||
class AtomApplication
|
||||
_.extend @prototype, EventEmitter.prototype
|
||||
updateVersion: null
|
||||
|
||||
# Public: The entry point into the Atom application.
|
||||
@open: (options) ->
|
||||
@@ -130,51 +129,42 @@ class AtomApplication
|
||||
|
||||
# Enable updates unless running from a local build of Atom.
|
||||
setupAutoUpdater: ->
|
||||
return if /\w{7}/.test(@version) # Only released versions should check for updates.
|
||||
|
||||
autoUpdater.setFeedUrl "https://atom.io/api/updates?version=#{@version}"
|
||||
|
||||
autoUpdater.on 'checking-for-update', =>
|
||||
@applicationMenu.showDownloadingUpdateItem(false)
|
||||
@applicationMenu.showInstallUpdateItem(false)
|
||||
@applicationMenu.showCheckForUpdateItem(false)
|
||||
|
||||
autoUpdater.on 'update-not-available', =>
|
||||
@applicationMenu.showInstallUpdateItem(false)
|
||||
@applicationMenu.showCheckForUpdateItem(true)
|
||||
|
||||
autoUpdater.on 'update-downloaded', (event, releaseNotes, releaseName, releaseDate, releaseURL) =>
|
||||
atomWindow.sendCommand('window:update-available', [releaseName, releaseNotes]) for atomWindow in @windows
|
||||
autoUpdater.on 'update-available', =>
|
||||
@applicationMenu.showDownloadingUpdateItem(true)
|
||||
|
||||
autoUpdater.on 'update-downloaded', (event, releaseNotes, releaseVersion, releaseDate, releaseURL) =>
|
||||
atomWindow.sendCommand('window:update-available', [releaseVersion, releaseNotes]) for atomWindow in @windows
|
||||
@applicationMenu.showInstallUpdateItem(true)
|
||||
@applicationMenu.showCheckForUpdateItem(false)
|
||||
@updateVersion = releaseName
|
||||
|
||||
autoUpdater.on 'error', (event, message) =>
|
||||
@applicationMenu.showInstallUpdateItem(false)
|
||||
@applicationMenu.showCheckForUpdateItem(true)
|
||||
|
||||
# Check for update after Atom has fully started and the menus are created
|
||||
setTimeout((-> autoUpdater.checkForUpdates()), 5000)
|
||||
|
||||
checkForUpdate: ->
|
||||
autoUpdater.once 'update-available', ->
|
||||
dialog.showMessageBox
|
||||
type: 'info'
|
||||
buttons: ['OK']
|
||||
message: 'Update available.'
|
||||
detail: 'A new update is being downloaded.'
|
||||
@onUpdateNotAvailable ?= =>
|
||||
autoUpdater.removeListener 'error', @onUpdateError
|
||||
dialog.showMessageBox type: 'info', buttons: ['OK'], message: 'No update available.', detail: "Version #{@version} is the latest version."
|
||||
|
||||
autoUpdater.once 'update-not-available', =>
|
||||
dialog.showMessageBox
|
||||
type: 'info'
|
||||
buttons: ['OK']
|
||||
message: 'No update available.'
|
||||
detail: "Version #{@version} is the latest version."
|
||||
|
||||
autoUpdater.once 'error', (event, message)->
|
||||
dialog.showMessageBox
|
||||
type: 'warning'
|
||||
buttons: ['OK']
|
||||
message: 'There was an error checking for updates.'
|
||||
detail: message
|
||||
@onUpdateError ?= (event, message) =>
|
||||
autoUpdater.removeListener 'update-not-available', @onUpdateNotAvailable
|
||||
dialog.showMessageBox type: 'warning', buttons: ['OK'], message: 'There was an error checking for updates.', detail: message
|
||||
|
||||
autoUpdater.once 'update-not-available', @onUpdateNotAvailable
|
||||
autoUpdater.once 'error', @onUpdateError
|
||||
autoUpdater.checkForUpdates()
|
||||
|
||||
# Registers basic application commands, non-idempotent.
|
||||
@@ -206,10 +196,15 @@ class AtomApplication
|
||||
@openPathOnEvent('application:open-your-stylesheet', 'atom://.atom/stylesheet')
|
||||
|
||||
app.on 'window-all-closed', ->
|
||||
app.quit() if process.platform is 'win32'
|
||||
app.quit() if process.platform in ['win32', 'linux']
|
||||
|
||||
app.on 'will-quit', => @deleteSocketFile()
|
||||
app.on 'will-exit', => @deleteSocketFile()
|
||||
app.on 'will-quit', =>
|
||||
@killAllProcesses()
|
||||
@deleteSocketFile()
|
||||
|
||||
app.on 'will-exit', =>
|
||||
@killAllProcesses()
|
||||
@deleteSocketFile()
|
||||
|
||||
app.on 'open-file', (event, pathToOpen) =>
|
||||
event.preventDefault()
|
||||
@@ -256,7 +251,26 @@ class AtomApplication
|
||||
# The optional arguments to pass along.
|
||||
sendCommand: (command, args...) ->
|
||||
unless @emit(command, args...)
|
||||
@focusedWindow()?.sendCommand(command, args...)
|
||||
focusedWindow = @focusedWindow()
|
||||
if focusedWindow?
|
||||
focusedWindow.sendCommand(command, args...)
|
||||
else
|
||||
@sendCommandToFirstResponder(command)
|
||||
|
||||
# Translates the command into OS X action and sends it to application's first
|
||||
# responder.
|
||||
sendCommandToFirstResponder: (command) ->
|
||||
return false unless process.platform is 'darwin'
|
||||
|
||||
switch command
|
||||
when 'core:undo' then Menu.sendActionToFirstResponder('undo:')
|
||||
when 'core:redo' then Menu.sendActionToFirstResponder('redo:')
|
||||
when 'core:copy' then Menu.sendActionToFirstResponder('copy:')
|
||||
when 'core:cut' then Menu.sendActionToFirstResponder('cut:')
|
||||
when 'core:paste' then Menu.sendActionToFirstResponder('paste:')
|
||||
when 'core:select-all' then Menu.sendActionToFirstResponder('selectAll:')
|
||||
else return false
|
||||
true
|
||||
|
||||
# Public: Open the given path in the focused window when the event is
|
||||
# triggered.
|
||||
@@ -345,13 +359,25 @@ class AtomApplication
|
||||
@pidsToOpenWindows[pidToKillWhenClosed] = openedWindow
|
||||
|
||||
openedWindow.browserWindow.on 'destroyed', =>
|
||||
for pid, trackedWindow of @pidsToOpenWindows when trackedWindow is openedWindow
|
||||
try
|
||||
process.kill(pid)
|
||||
catch error
|
||||
if error.code isnt 'ESRCH'
|
||||
console.log("Killing process #{pid} failed: #{error.code}")
|
||||
delete @pidsToOpenWindows[pid]
|
||||
@killProcessForWindow(openedWindow)
|
||||
|
||||
# Kill all processes associated with opened windows.
|
||||
killAllProcesses: ->
|
||||
@killProcess(pid) for pid of @pidsToOpenWindows
|
||||
|
||||
# Kill process associated with the given opened window.
|
||||
killProcessForWindow: (openedWindow) ->
|
||||
for pid, trackedWindow of @pidsToOpenWindows
|
||||
@killProcess(pid) if trackedWindow is openedWindow
|
||||
|
||||
# Kill the process with the given pid.
|
||||
killProcess: (pid) ->
|
||||
try
|
||||
process.kill(pid)
|
||||
catch error
|
||||
if error.code isnt 'ESRCH'
|
||||
console.log("Killing process #{pid} failed: #{error.code}")
|
||||
delete @pidsToOpenWindows[pid]
|
||||
|
||||
# Open an atom:// url.
|
||||
#
|
||||
@@ -427,8 +453,3 @@ class AtomApplication
|
||||
promptForPath: ({devMode}={}) ->
|
||||
dialog.showOpenDialog title: 'Open', properties: ['openFile', 'openDirectory', 'multiSelections', 'createDirectory'], (pathsToOpen) =>
|
||||
@openPaths({pathsToOpen, devMode})
|
||||
|
||||
# Public: If an update is available, it returns the new version string
|
||||
# otherwise it returns null.
|
||||
getUpdateVersion: ->
|
||||
@updateVersion
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
BrowserWindow = require 'browser-window'
|
||||
Menu = require 'menu'
|
||||
ContextMenu = require './context-menu'
|
||||
app = require 'app'
|
||||
dialog = require 'dialog'
|
||||
@@ -22,12 +21,7 @@ class AtomWindow
|
||||
{@resourcePath, pathToOpen, initialLine, @isSpec, @exitWhenDone} = settings
|
||||
global.atomApplication.addWindow(this)
|
||||
|
||||
@setupNodePath(@resourcePath)
|
||||
@browserWindow = new BrowserWindow show: false, title: 'Atom', icon: @constructor.iconPath
|
||||
@browserWindow.restart = _.wrap _.bind(@browserWindow.restart, @browserWindow), (restart) =>
|
||||
@setupNodePath(@resourcePath)
|
||||
restart()
|
||||
|
||||
@handleEvents()
|
||||
|
||||
loadSettings = _.extend({}, settings)
|
||||
@@ -50,9 +44,6 @@ class AtomWindow
|
||||
|
||||
@openPath(pathToOpen, initialLine)
|
||||
|
||||
setupNodePath: (resourcePath) ->
|
||||
process.env['NODE_PATH'] = path.resolve(resourcePath, 'exports')
|
||||
|
||||
getUrl: (loadSettingsObj) ->
|
||||
# Ignore the windowState when passing loadSettings via URL, since it could
|
||||
# be quite large.
|
||||
@@ -104,7 +95,7 @@ class AtomWindow
|
||||
type: 'warning'
|
||||
buttons: ['Close Window', 'Reload', 'Keep It Open']
|
||||
message: 'The editor has crashed'
|
||||
detail: 'Please report this issue to https://github.com/atom/atom/issues'
|
||||
detail: 'Please report this issue to atom@github.com'
|
||||
switch chosen
|
||||
when 0 then @browserWindow.destroy()
|
||||
when 1 then @browserWindow.restart()
|
||||
@@ -121,13 +112,12 @@ class AtomWindow
|
||||
if @loaded
|
||||
@focus()
|
||||
@sendCommand('window:open-path', {pathToOpen, initialLine})
|
||||
@sendCommand('window:update-available', global.atomApplication.getUpdateVersion()) if global.atomApplication.getUpdateVersion()
|
||||
else
|
||||
@browserWindow.once 'window:loaded', => @openPath(pathToOpen, initialLine)
|
||||
|
||||
sendCommand: (command, args...) ->
|
||||
if @isSpecWindow()
|
||||
unless @sendCommandToFirstResponder(command)
|
||||
unless global.atomApplication.sendCommandToFirstResponder(command)
|
||||
switch command
|
||||
when 'window:reload' then @reload()
|
||||
when 'window:toggle-dev-tools' then @toggleDevTools()
|
||||
@@ -135,24 +125,13 @@ class AtomWindow
|
||||
else if @isWebViewFocused()
|
||||
@sendCommandToBrowserWindow(command, args...)
|
||||
else
|
||||
unless @sendCommandToFirstResponder(command)
|
||||
unless global.atomApplication.sendCommandToFirstResponder(command)
|
||||
@sendCommandToBrowserWindow(command, args...)
|
||||
|
||||
sendCommandToBrowserWindow: (command, args...) ->
|
||||
action = if args[0]?.contextCommand then 'context-command' else 'command'
|
||||
ipc.sendChannel @browserWindow.getProcessId(), @browserWindow.getRoutingId(), action, command, args...
|
||||
|
||||
sendCommandToFirstResponder: (command) ->
|
||||
switch command
|
||||
when 'core:undo' then Menu.sendActionToFirstResponder('undo:')
|
||||
when 'core:redo' then Menu.sendActionToFirstResponder('redo:')
|
||||
when 'core:copy' then Menu.sendActionToFirstResponder('copy:')
|
||||
when 'core:cut' then Menu.sendActionToFirstResponder('cut:')
|
||||
when 'core:paste' then Menu.sendActionToFirstResponder('paste:')
|
||||
when 'core:select-all' then Menu.sendActionToFirstResponder('selectAll:')
|
||||
else return false
|
||||
true
|
||||
|
||||
close: -> @browserWindow.close()
|
||||
|
||||
focus: -> @browserWindow.focus()
|
||||
|
||||
@@ -77,7 +77,7 @@ parseCommandLine = ->
|
||||
options.alias('h', 'help').boolean('h').describe('h', 'Print this usage message.')
|
||||
options.alias('l', 'log-file').string('l').describe('l', 'Log all output to file.')
|
||||
options.alias('n', 'new-window').boolean('n').describe('n', 'Open a new window.')
|
||||
options.alias('s', 'spec-directory').string('s').describe('s', 'Set the directory from which specs are loaded (default: Atom\'s spec directory).')
|
||||
options.alias('s', 'spec-directory').string('s').describe('s', 'Set the spec directory (default: Atom\'s spec directory).')
|
||||
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.')
|
||||
|
||||
@@ -146,7 +146,7 @@ class DisplayBufferMarker
|
||||
@bufferMarker.setAttributes(attributes)
|
||||
|
||||
matchesAttributes: (attributes) ->
|
||||
attributes = @displayBuffer.translateToBufferMarkerAttributes(attributes)
|
||||
attributes = @displayBuffer.translateToBufferMarkerParams(attributes)
|
||||
@bufferMarker.matchesAttributes(attributes)
|
||||
|
||||
# Destroys the marker
|
||||
|
||||
+55
-27
@@ -10,6 +10,11 @@ Fold = require './fold'
|
||||
Token = require './token'
|
||||
DisplayBufferMarker = require './display-buffer-marker'
|
||||
|
||||
class BufferToScreenConversionError extends Error
|
||||
constructor: (@message, @metadata) ->
|
||||
super
|
||||
Error.captureStackTrace(this, BufferToScreenConversionError)
|
||||
|
||||
module.exports =
|
||||
class DisplayBuffer extends Model
|
||||
Serializable.includeInto(this)
|
||||
@@ -94,10 +99,11 @@ class DisplayBuffer extends Model
|
||||
#
|
||||
# editorWidthInChars - A {Number} of characters.
|
||||
setEditorWidthInChars: (editorWidthInChars) ->
|
||||
previousWidthInChars = @editorWidthInChars
|
||||
@editorWidthInChars = editorWidthInChars
|
||||
if editorWidthInChars isnt previousWidthInChars and @softWrap
|
||||
@updateWrappedScreenLines()
|
||||
if editorWidthInChars > 0
|
||||
previousWidthInChars = @editorWidthInChars
|
||||
@editorWidthInChars = editorWidthInChars
|
||||
if editorWidthInChars isnt previousWidthInChars and @softWrap
|
||||
@updateWrappedScreenLines()
|
||||
|
||||
getSoftWrapColumn: ->
|
||||
if atom.config.get('editor.softWrapAtPreferredLineLength')
|
||||
@@ -164,7 +170,7 @@ class DisplayBuffer extends Model
|
||||
# Removes any folds found that contain the given buffer row.
|
||||
#
|
||||
# bufferRow - The buffer row {Number} to check against
|
||||
destroyFoldsContainingBufferRow: (bufferRow) ->
|
||||
unfoldBufferRow: (bufferRow) ->
|
||||
fold.destroy() for fold in @foldsContainingBufferRow(bufferRow)
|
||||
|
||||
# Given a buffer row, this returns the largest fold that starts there.
|
||||
@@ -209,6 +215,13 @@ class DisplayBuffer extends Model
|
||||
largestFoldContainingBufferRow: (bufferRow) ->
|
||||
@foldsContainingBufferRow(bufferRow)[0]
|
||||
|
||||
# Returns the folds in the given row range (exclusive of end row) that are
|
||||
# not contained by any other folds.
|
||||
outermostFoldsInBufferRowRange: (startRow, endRow) ->
|
||||
@findFoldMarkers(containedInRange: [[startRow, 0], [endRow, 0]])
|
||||
.map (marker) => @foldForMarker(marker)
|
||||
.filter (fold) -> not fold.isInsideLargerFold()
|
||||
|
||||
# Public: Given a buffer row, this returns folds that include it.
|
||||
#
|
||||
#
|
||||
@@ -291,13 +304,15 @@ class DisplayBuffer extends Model
|
||||
{ row, column } = @buffer.clipPosition(bufferPosition)
|
||||
[startScreenRow, endScreenRow] = @rowMap.screenRowRangeForBufferRow(row)
|
||||
for screenRow in [startScreenRow...endScreenRow]
|
||||
unless screenLine = @screenLines[screenRow]
|
||||
throw new Error """
|
||||
No screen line exists for screen row #{screenRow}, converted from buffer position (#{row}, #{column})
|
||||
Soft wrap enabled: #{@getSoftWrap()}
|
||||
Fold count: #{@findFoldMarkers().length}
|
||||
Last buffer row: #{@getLastRow()}
|
||||
"""
|
||||
screenLine = @screenLines[screenRow]
|
||||
|
||||
unless screenLine?
|
||||
throw new BufferToScreenConversionError "No screen line exists when converting buffer row to screen row",
|
||||
softWrapEnabled: @getSoftWrap()
|
||||
foldCount: @findFoldMarkers().length
|
||||
lastBufferRow: @buffer.getLastRow()
|
||||
lastScreenRow: @getLastRow()
|
||||
|
||||
maxBufferColumn = screenLine.getMaxBufferColumn()
|
||||
if screenLine.isSoftWrapped() and column > maxBufferColumn
|
||||
continue
|
||||
@@ -511,24 +526,34 @@ class DisplayBuffer extends Model
|
||||
# Refer to {DisplayBuffer::findMarkers} for details.
|
||||
#
|
||||
# Returns a {DisplayBufferMarker} or null
|
||||
findMarker: (attributes) ->
|
||||
@findMarkers(attributes)[0]
|
||||
findMarker: (params) ->
|
||||
@findMarkers(params)[0]
|
||||
|
||||
# Finds all valid markers satisfying the given attributes
|
||||
# Public: Find all markers satisfying a set of parameters.
|
||||
#
|
||||
# attributes - The attributes against which to compare the markers' attributes
|
||||
# There are some reserved keys that match against derived marker properties:
|
||||
# startBufferRow - The buffer row at which the marker starts
|
||||
# endBufferRow - The buffer row at which the marker ends
|
||||
# params - An {Object} containing parameters that all returned markers must
|
||||
# satisfy. Unreserved keys will be compared against the markers' custom
|
||||
# properties. There are also the following reserved keys with special
|
||||
# meaning for the query:
|
||||
# :startBufferRow - A {Number}. Only returns markers starting at this row in
|
||||
# buffer coordinates.
|
||||
# :endBufferRow - A {Number}. Only returns markers ending at this row in
|
||||
# buffer coordinates.
|
||||
# :containsBufferRange - A {Range} or range-compatible {Array}. Only returns
|
||||
# markers containing this range in buffer coordinates.
|
||||
# :containsBufferPosition - A {Point} or point-compatible {Array}. Only
|
||||
# returns markers containing this position in buffer coordinates.
|
||||
# :containedInBufferRange - A {Range} or range-compatible {Array}. Only
|
||||
# returns markers contained within this range.
|
||||
#
|
||||
# Returns an {Array} of {DisplayBufferMarker}s
|
||||
findMarkers: (attributes) ->
|
||||
attributes = @translateToBufferMarkerAttributes(attributes)
|
||||
@buffer.findMarkers(attributes).map (stringMarker) => @getMarker(stringMarker.id)
|
||||
findMarkers: (params) ->
|
||||
params = @translateToBufferMarkerParams(params)
|
||||
@buffer.findMarkers(params).map (stringMarker) => @getMarker(stringMarker.id)
|
||||
|
||||
translateToBufferMarkerAttributes: (attributes) ->
|
||||
stringMarkerAttributes = {}
|
||||
for key, value of attributes
|
||||
translateToBufferMarkerParams: (params) ->
|
||||
bufferMarkerParams = {}
|
||||
for key, value of params
|
||||
switch key
|
||||
when 'startBufferRow'
|
||||
key = 'startRow'
|
||||
@@ -538,8 +563,10 @@ class DisplayBuffer extends Model
|
||||
key = 'containsRange'
|
||||
when 'containsBufferPosition'
|
||||
key = 'containsPosition'
|
||||
stringMarkerAttributes[key] = value
|
||||
stringMarkerAttributes
|
||||
when 'containedInBufferRange'
|
||||
key = 'containedInRange'
|
||||
bufferMarkerParams[key] = value
|
||||
bufferMarkerParams
|
||||
|
||||
findFoldMarker: (attributes) ->
|
||||
@findFoldMarkers(attributes)[0]
|
||||
@@ -577,6 +604,7 @@ class DisplayBuffer extends Model
|
||||
|
||||
updateScreenLines: (startBufferRow, endBufferRow, bufferDelta=0, options={}) ->
|
||||
startBufferRow = @rowMap.bufferRowRangeForBufferRow(startBufferRow)[0]
|
||||
endBufferRow = @rowMap.bufferRowRangeForBufferRow(endBufferRow - 1)[1]
|
||||
startScreenRow = @rowMap.screenRowRangeForBufferRow(startBufferRow)[0]
|
||||
endScreenRow = @rowMap.screenRowRangeForBufferRow(endBufferRow - 1)[1]
|
||||
|
||||
|
||||
+69
-26
@@ -20,7 +20,23 @@ LongLineLength = 1000
|
||||
# ## Requiring in packages
|
||||
#
|
||||
# ```coffee
|
||||
# {EditorView} = require 'atom'
|
||||
# {EditorView} = require 'atom'
|
||||
#
|
||||
# miniEditorView = new EditorView(mini: true)
|
||||
# ```
|
||||
#
|
||||
# ## Iterating over the open editor views
|
||||
#
|
||||
# ```coffee
|
||||
# for editorView in atom.workspace.getEditorViews()
|
||||
# console.log(editorView.getEditor().getPath())
|
||||
# ```
|
||||
#
|
||||
# ## Subscribing to every current and future editor
|
||||
#
|
||||
# ```coffee
|
||||
# atom.workspace.eachEditorView (editorView) ->
|
||||
# console.log(editorView.getEditor().getPath())
|
||||
# ```
|
||||
module.exports =
|
||||
class EditorView extends View
|
||||
@@ -193,7 +209,7 @@ class EditorView extends View
|
||||
'editor:unfold-all': => @editor.unfoldAll()
|
||||
'editor:fold-current-row': => @editor.foldCurrentRow()
|
||||
'editor:unfold-current-row': => @editor.unfoldCurrentRow()
|
||||
'editor:fold-selection': => @editor.foldSelection()
|
||||
'editor:fold-selection': => @editor.foldSelectedLines()
|
||||
'editor:fold-at-indent-level-1': => @editor.foldAllAtIndentLevel(0)
|
||||
'editor:fold-at-indent-level-2': => @editor.foldAllAtIndentLevel(1)
|
||||
'editor:fold-at-indent-level-3': => @editor.foldAllAtIndentLevel(2)
|
||||
@@ -209,8 +225,8 @@ class EditorView extends View
|
||||
'editor:copy-path': => @copyPathToClipboard()
|
||||
'editor:move-line-up': => @editor.moveLineUp()
|
||||
'editor:move-line-down': => @editor.moveLineDown()
|
||||
'editor:duplicate-line': => @editor.duplicateLine()
|
||||
'editor:join-line': => @editor.joinLine()
|
||||
'editor:duplicate-lines': => @editor.duplicateLines()
|
||||
'editor:join-lines': => @editor.joinLines()
|
||||
'editor:toggle-indent-guide': => atom.config.toggle('editor.showIndentGuide')
|
||||
'editor:toggle-line-numbers': => atom.config.toggle('editor.showLineNumbers')
|
||||
'editor:scroll-to-cursor': => @scrollToCursorPosition()
|
||||
@@ -403,6 +419,8 @@ class EditorView extends View
|
||||
@scrollView.on 'overflowchanged', =>
|
||||
updateWidthInChars() if @[0].classList.contains('soft-wrap')
|
||||
|
||||
@subscribe atom.themes, 'stylesheets-changed', => @recalculateDimensions()
|
||||
|
||||
handleInputEvents: ->
|
||||
@on 'cursor:moved', =>
|
||||
return unless @isFocused
|
||||
@@ -445,20 +463,29 @@ class EditorView extends View
|
||||
|
||||
selectOnMousemoveUntilMouseup: ->
|
||||
lastMoveEvent = null
|
||||
|
||||
finalizeSelections = =>
|
||||
clearInterval(interval)
|
||||
$(document).off 'mousemove', moveHandler
|
||||
$(document).off 'mouseup', finalizeSelections
|
||||
|
||||
unless @editor.isDestroyed()
|
||||
@editor.mergeIntersectingSelections(isReversed: @editor.getLastSelection().isReversed())
|
||||
@editor.finalizeSelections()
|
||||
@syncCursorAnimations()
|
||||
|
||||
moveHandler = (event = lastMoveEvent) =>
|
||||
if event
|
||||
return unless event?
|
||||
|
||||
if event.which is 1 and @[0].style.display isnt 'none'
|
||||
@editor.selectToScreenPosition(@screenPositionFromMouseEvent(event))
|
||||
lastMoveEvent = event
|
||||
else
|
||||
finalizeSelections()
|
||||
|
||||
$(document).on "mousemove.editor-#{@id}", moveHandler
|
||||
interval = setInterval(moveHandler, 20)
|
||||
|
||||
$(document).one "mouseup.editor-#{@id}", =>
|
||||
clearInterval(interval)
|
||||
$(document).off 'mousemove', moveHandler
|
||||
@editor.mergeIntersectingSelections(isReversed: @editor.getLastSelection().isReversed())
|
||||
@editor.finalizeSelections()
|
||||
@syncCursorAnimations()
|
||||
$(document).one "mouseup.editor-#{@id}", finalizeSelections
|
||||
|
||||
afterAttach: (onDom) ->
|
||||
return unless onDom
|
||||
@@ -667,11 +694,15 @@ class EditorView extends View
|
||||
@editor.setSoftWrap(not @editor.getSoftWrap())
|
||||
|
||||
calculateWidthInChars: ->
|
||||
Math.floor(@scrollView.width() / @charWidth)
|
||||
Math.floor((@scrollView.width() - @getScrollbarWidth()) / @charWidth)
|
||||
|
||||
calculateHeightInLines: ->
|
||||
Math.ceil($(window).height() / @lineHeight)
|
||||
|
||||
getScrollbarWidth: ->
|
||||
scrollbarElement = @verticalScrollbar[0]
|
||||
scrollbarElement.offsetWidth - scrollbarElement.clientWidth
|
||||
|
||||
# Public: Enables/disables soft wrap on the editor.
|
||||
#
|
||||
# softWrap - A {Boolean} which, if `true`, enables soft wrap
|
||||
@@ -853,7 +884,19 @@ class EditorView extends View
|
||||
fragment.remove()
|
||||
@setHeightInLines()
|
||||
|
||||
updateLayerDimensions: ->
|
||||
recalculateDimensions: ->
|
||||
return unless @attached and @isVisible()
|
||||
|
||||
oldCharWidth = @charWidth
|
||||
oldLineHeight = @lineHeight
|
||||
|
||||
@calculateDimensions()
|
||||
|
||||
unless @charWidth is oldCharWidth and @lineHeight is oldLineHeight
|
||||
@clearCharacterWidthCache()
|
||||
@requestDisplayUpdate()
|
||||
|
||||
updateLayerDimensions: (scrollViewWidth) ->
|
||||
height = @lineHeight * @editor.getScreenLineCount()
|
||||
unless @layerHeight == height
|
||||
@layerHeight = height
|
||||
@@ -863,7 +906,7 @@ class EditorView extends View
|
||||
@verticalScrollbarContent.height(@layerHeight)
|
||||
@scrollBottom(height) if @scrollBottom() > height
|
||||
|
||||
minWidth = Math.max(@charWidth * @editor.getMaxScreenLineLength() + 20, @scrollView.width())
|
||||
minWidth = Math.max(@charWidth * @editor.getMaxScreenLineLength() + 20, scrollViewWidth)
|
||||
unless @layerMinWidth == minWidth
|
||||
@renderedLines.css('min-width', minWidth)
|
||||
@underlayer.css('min-width', minWidth)
|
||||
@@ -897,7 +940,7 @@ class EditorView extends View
|
||||
@setSoftWrap(@editor.getSoftWrap())
|
||||
@newCursors = @editor.getCursors()
|
||||
@newSelections = @editor.getSelections()
|
||||
@updateDisplay(suppressAutoScroll: true)
|
||||
@updateDisplay(suppressAutoscroll: true)
|
||||
|
||||
requestDisplayUpdate: ->
|
||||
return if @pendingDisplayUpdate
|
||||
@@ -907,19 +950,20 @@ class EditorView extends View
|
||||
@updateDisplay()
|
||||
@pendingDisplayUpdate = false
|
||||
|
||||
updateDisplay: (options={}) ->
|
||||
updateDisplay: (options) ->
|
||||
return unless @attached and @editor
|
||||
return if @editor.isDestroyed()
|
||||
unless @isOnDom() and @isVisible()
|
||||
@redrawOnReattach = true
|
||||
return
|
||||
|
||||
@updateRenderedLines()
|
||||
scrollViewWidth = @scrollView.width()
|
||||
@updateRenderedLines(scrollViewWidth)
|
||||
@updatePlaceholderText()
|
||||
@highlightCursorLine()
|
||||
@updateCursorViews()
|
||||
@updateSelectionViews()
|
||||
@autoscroll(options)
|
||||
@autoscroll(options?.suppressAutoscroll ? false)
|
||||
@trigger 'editor:display-updated'
|
||||
|
||||
updateCursorViews: ->
|
||||
@@ -960,17 +1004,16 @@ class EditorView extends View
|
||||
(startRow <= @firstRenderedScreenRow and endRow >= @lastRenderedScreenRow) # selection surrounds the rendered items
|
||||
|
||||
syncCursorAnimations: ->
|
||||
for cursorView in @getCursorViews()
|
||||
do (cursorView) -> cursorView.resetBlinking()
|
||||
cursorView.resetBlinking() for cursorView in @getCursorViews()
|
||||
|
||||
autoscroll: (options={}) ->
|
||||
autoscroll: (suppressAutoscroll) ->
|
||||
for cursorView in @getCursorViews()
|
||||
if !options.suppressAutoScroll and cursorView.needsAutoscroll()
|
||||
if !suppressAutoscroll and cursorView.needsAutoscroll()
|
||||
@scrollToPixelPosition(cursorView.getPixelPosition())
|
||||
cursorView.clearAutoscroll()
|
||||
|
||||
for selectionView in @getSelectionViews()
|
||||
if !options.suppressAutoScroll and selectionView.needsAutoscroll()
|
||||
if !suppressAutoscroll and selectionView.needsAutoscroll()
|
||||
@scrollToPixelPosition(selectionView.getCenterPixelPosition(), center: true)
|
||||
selectionView.highlight()
|
||||
selectionView.clearAutoscroll()
|
||||
@@ -986,7 +1029,7 @@ class EditorView extends View
|
||||
else
|
||||
@underlayer.append($('<span/>', class: 'placeholder-text', text: @placeholderText))
|
||||
|
||||
updateRenderedLines: ->
|
||||
updateRenderedLines: (scrollViewWidth) ->
|
||||
firstVisibleScreenRow = @getFirstVisibleScreenRow()
|
||||
lastScreenRowToRender = firstVisibleScreenRow + @heightInLines - 1
|
||||
lastScreenRow = @editor.getLastScreenRow()
|
||||
@@ -1010,7 +1053,7 @@ class EditorView extends View
|
||||
@fillDirtyRanges(intactRanges, renderFrom, renderTo)
|
||||
@firstRenderedScreenRow = renderFrom
|
||||
@lastRenderedScreenRow = renderTo
|
||||
@updateLayerDimensions()
|
||||
@updateLayerDimensions(scrollViewWidth)
|
||||
@updatePaddingOfRenderedLines()
|
||||
|
||||
computeSurroundingEmptyLineChanges: (change) ->
|
||||
|
||||
+732
-331
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -41,6 +41,10 @@ class Fold
|
||||
range.end.column = 0
|
||||
range
|
||||
|
||||
getBufferRowRange: ->
|
||||
{start, end} = @getBufferRange()
|
||||
[start.row, end.row]
|
||||
|
||||
# Returns the fold's start row as a {Number}.
|
||||
getStartRow: ->
|
||||
@getBufferRange().start.row
|
||||
|
||||
+88
-17
@@ -10,6 +10,18 @@ GitUtils = require 'git-utils'
|
||||
# `atom.project` global and calling `getRepo()`. Note that this will only be
|
||||
# available when the project is backed by a Git repository.
|
||||
#
|
||||
# This class handles submodules automically by taking a `path` argument to many
|
||||
# of the methods. This `path` argument will determine which underlying
|
||||
# repository is used.
|
||||
#
|
||||
# For a repository with submodules this would have the following outcome:
|
||||
#
|
||||
# ```coffee
|
||||
# repo = atom.project.getRepo()
|
||||
# repo.getShortHead() # 'master'
|
||||
# repo.getShortHead('vendor/path/to/a/submodule') # 'dead1234'
|
||||
# ```
|
||||
#
|
||||
# ## Example
|
||||
#
|
||||
# ```coffeescript
|
||||
@@ -89,10 +101,11 @@ class Git
|
||||
@unsubscribe()
|
||||
|
||||
# Returns the corresponding {Repository}
|
||||
getRepo: ->
|
||||
unless @repo?
|
||||
getRepo: (path) ->
|
||||
if @repo?
|
||||
@repo.submoduleForPath(path) ? @repo
|
||||
else
|
||||
throw new Error("Repository has been destroyed")
|
||||
@repo
|
||||
|
||||
# Reread the index to update any values that have changed since the
|
||||
# last time the index was read.
|
||||
@@ -113,7 +126,8 @@ class Git
|
||||
# {::isStatusModified} or {::isStatusNew} to get more information.
|
||||
getPathStatus: (path) ->
|
||||
currentPathStatus = @statuses[path] ? 0
|
||||
pathStatus = @getRepo().getStatus(@relativize(path)) ? 0
|
||||
repo = @getRepo(path)
|
||||
pathStatus = repo.getStatus(repo.relativize(path)) ? 0
|
||||
if pathStatus > 0
|
||||
@statuses[path] = pathStatus
|
||||
else
|
||||
@@ -153,8 +167,11 @@ class Git
|
||||
# `refs/remotes`. It also shortens the SHA-1 of a detached `HEAD` to 7
|
||||
# characters.
|
||||
#
|
||||
# path - An optional {String} path in the repository to get this information
|
||||
# for, only needed if the repository contains submodules.
|
||||
#
|
||||
# Returns a {String}.
|
||||
getShortHead: -> @getRepo().getShortHead()
|
||||
getShortHead: (path) -> @getRepo(path).getShortHead()
|
||||
|
||||
# Public: Restore the contents of a path in the working directory and index
|
||||
# to the version at `HEAD`.
|
||||
@@ -170,7 +187,8 @@ class Git
|
||||
#
|
||||
# Returns a {Boolean} that's true if the method was successful.
|
||||
checkoutHead: (path) ->
|
||||
headCheckedOut = @getRepo().checkoutHead(@relativize(path))
|
||||
repo = @getRepo(path)
|
||||
headCheckedOut = repo.checkoutHead(repo.relativize(path))
|
||||
@getPathStatus(path) if headCheckedOut
|
||||
headCheckedOut
|
||||
|
||||
@@ -194,14 +212,22 @@ class Git
|
||||
# Returns an {Object} with the following keys:
|
||||
# :added - The {Number} of added lines.
|
||||
# :deleted - The {Number} of deleted lines.
|
||||
getDiffStats: (path) -> @getRepo().getDiffStats(@relativize(path))
|
||||
getDiffStats: (path) ->
|
||||
repo = @getRepo(path)
|
||||
repo.getDiffStats(repo.relativize(path))
|
||||
|
||||
# Public: Is the given path a submodule in the repository?
|
||||
#
|
||||
# path - The {String} path to check.
|
||||
#
|
||||
# Returns a {Boolean}.
|
||||
isSubmodule: (path) -> @getRepo().isSubmodule(@relativize(path))
|
||||
isSubmodule: (path) ->
|
||||
repo = @getRepo(path)
|
||||
if repo.isSubmodule(repo.relativize(path))
|
||||
true
|
||||
else
|
||||
# Check if the path is a working directory in a repo that isn't the root.
|
||||
path is repo.getWorkingDirectory() and repo isnt @getRepo()
|
||||
|
||||
# Public: Get the status of a directory in the repository's working directory.
|
||||
#
|
||||
@@ -232,34 +258,69 @@ class Git
|
||||
# Ignore eol of line differences on windows so that files checked in as
|
||||
# LF don't report every line modified when the text contains CRLF endings.
|
||||
options = ignoreEolWhitespace: process.platform is 'win32'
|
||||
@getRepo().getLineDiffs(@relativize(path), text, options)
|
||||
repo = @getRepo(path)
|
||||
repo.getLineDiffs(repo.relativize(path), text, options)
|
||||
|
||||
# Public: Returns the git configuration value specified by the key.
|
||||
getConfigValue: (key) -> @getRepo().getConfigValue(key)
|
||||
#
|
||||
# path - An optional {String} path in the repository to get this information
|
||||
# for, only needed if the repository has submodules.
|
||||
getConfigValue: (key, path) -> @getRepo(path).getConfigValue(key)
|
||||
|
||||
# Public: Returns the origin url of the repository.
|
||||
getOriginUrl: -> @getConfigValue('remote.origin.url')
|
||||
#
|
||||
# path - An optional {String} path in the repository to get this information
|
||||
# for, only needed if the repository has submodules.
|
||||
getOriginUrl: (path) -> @getConfigValue('remote.origin.url', path)
|
||||
|
||||
# Public: Returns the upstream branch for the current HEAD, or null if there
|
||||
# is no upstream branch for the current HEAD.
|
||||
#
|
||||
# path - An optional {String} path in the repo to get this information for,
|
||||
# only needed if the repository contains submodules.
|
||||
#
|
||||
# Returns a {String} branch name such as `refs/remotes/origin/master`.
|
||||
getUpstreamBranch: -> @getRepo().getUpstreamBranch()
|
||||
getUpstreamBranch: (path) -> @getRepo(path).getUpstreamBranch()
|
||||
|
||||
# Public: Returns the current SHA for the given reference.
|
||||
getReferenceTarget: (reference) -> @getRepo().getReferenceTarget(reference)
|
||||
#
|
||||
# reference - The {String} reference to get the target of.
|
||||
# path - An optional {String} path in the repo to get the reference target
|
||||
# for. Only needed if the repository contains submodules.
|
||||
getReferenceTarget: (reference, path) ->
|
||||
@getRepo(path).getReferenceTarget(reference)
|
||||
|
||||
# Public: Gets all the local and remote references.
|
||||
#
|
||||
# path - An optional {String} path in the repository to get this information
|
||||
# for, only needed if the repository has submodules.
|
||||
#
|
||||
# Returns an {Object} with the following keys:
|
||||
# :heads - An {Array} of head reference names.
|
||||
# :remotes - An {Array} of remote reference names.
|
||||
# :tags - An {Array} of tag reference names.
|
||||
getReferences: -> @getRepo().getReferences()
|
||||
getReferences: (path) -> @getRepo(path).getReferences()
|
||||
|
||||
# Public: Returns the number of commits behind the current branch is from the
|
||||
# its upstream remote branch.
|
||||
getAheadBehindCount: (reference) -> @getRepo().getAheadBehindCount(reference)
|
||||
#
|
||||
# reference - The {String} branch reference name.
|
||||
# path - The {String} path in the repository to get this information for,
|
||||
# only needed if the repository contains submodules.
|
||||
getAheadBehindCount: (reference, path) ->
|
||||
@getRepo(path).getAheadBehindCount(reference)
|
||||
|
||||
# Public: Get the cached ahead/behind commit counts for the current branch's
|
||||
# upstream branch.
|
||||
#
|
||||
# path - An optional {String} path in the repository to get this information
|
||||
# for, only needed if the repository has submodules.
|
||||
#
|
||||
# Returns an {Object} with the following keys:
|
||||
# :ahead - The {Number} of commits ahead.
|
||||
# :behind - The {Number} of commits behind.
|
||||
getCachedUpstreamAheadBehindCount: (path) ->
|
||||
@getRepo(path).upstream ? @upstream
|
||||
|
||||
# Public: Returns true if the given branch exists.
|
||||
hasBranch: (branch) -> @getReferenceTarget("refs/heads/#{branch}")?
|
||||
@@ -267,9 +328,19 @@ class Git
|
||||
# Refreshes the current git status in an outside process and asynchronously
|
||||
# updates the relevant properties.
|
||||
refreshStatus: ->
|
||||
@statusTask = Task.once require.resolve('./repository-status-handler'), @getPath(), ({statuses, upstream, branch}) =>
|
||||
statusesUnchanged = _.isEqual(statuses, @statuses) and _.isEqual(upstream, @upstream) and _.isEqual(branch, @branch)
|
||||
handlerPath = require.resolve('./repository-status-handler')
|
||||
@statusTask = Task.once handlerPath, @getPath(), ({statuses, upstream, branch, submodules}) =>
|
||||
statusesUnchanged = _.isEqual(statuses, @statuses) and
|
||||
_.isEqual(upstream, @upstream) and
|
||||
_.isEqual(branch, @branch) and
|
||||
_.isEqual(submodules, @submodules)
|
||||
|
||||
@statuses = statuses
|
||||
@upstream = upstream
|
||||
@branch = branch
|
||||
@submodules = submodules
|
||||
|
||||
for submodulePath, submoduleRepo of @getRepo().submodules
|
||||
submoduleRepo.upstream = submodules[submodulePath].upstream
|
||||
|
||||
@emit 'statuses-changed' unless statusesUnchanged
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
_ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
{specificity} = require 'clear-cut'
|
||||
|
||||
module.exports =
|
||||
class KeyBinding
|
||||
@parser: null
|
||||
@currentIndex: 1
|
||||
@specificities: null
|
||||
|
||||
@calculateSpecificity: (selector) ->
|
||||
@specificities ?= {}
|
||||
value = @specificities[selector]
|
||||
unless value?
|
||||
value = specificity(selector)
|
||||
@specificities[selector] = value
|
||||
value
|
||||
|
||||
@normalizeKeystroke: (keystroke) ->
|
||||
normalizedKeystroke = keystroke.split(/\s+/).map (keystroke) =>
|
||||
keys = @parseKeystroke(keystroke)
|
||||
modifiers = keys[0...-1]
|
||||
modifiers.sort()
|
||||
[modifiers..., _.last(keys)].join('-')
|
||||
normalizedKeystroke.join(' ')
|
||||
|
||||
@parseKeystroke: (keystroke) ->
|
||||
unless @parser?
|
||||
try
|
||||
@parser = require './keystroke-pattern'
|
||||
catch
|
||||
keystrokePattern = fs.readFileSync(require.resolve('./keystroke-pattern.pegjs'), 'utf8')
|
||||
PEG = require 'pegjs'
|
||||
@parser = PEG.buildParser(keystrokePattern)
|
||||
|
||||
@parser.parse(keystroke)
|
||||
|
||||
constructor: (source, command, keystroke, selector) ->
|
||||
@source = source
|
||||
@command = command
|
||||
@keystroke = KeyBinding.normalizeKeystroke(keystroke)
|
||||
@selector = selector.replace(/!important/g, '')
|
||||
@specificity = KeyBinding.calculateSpecificity(selector)
|
||||
@index = KeyBinding.currentIndex++
|
||||
|
||||
matches: (keystroke) ->
|
||||
multiKeystroke = /\s/.test keystroke
|
||||
if multiKeystroke
|
||||
keystroke == @keystroke
|
||||
else
|
||||
keystroke.split(' ')[0] == @keystroke.split(' ')[0]
|
||||
|
||||
compare: (keyBinding) ->
|
||||
if keyBinding.specificity == @specificity
|
||||
keyBinding.index - @index
|
||||
else
|
||||
keyBinding.specificity - @specificity
|
||||
@@ -0,0 +1,27 @@
|
||||
fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
Keymap = require 'atom-keymap'
|
||||
CSON = require 'season'
|
||||
{jQuery} = require 'space-pen'
|
||||
|
||||
Keymap::loadBundledKeymaps = ->
|
||||
@loadKeyBindings(path.join(@resourcePath, 'keymaps'))
|
||||
@emit('bundled-keymaps-loaded')
|
||||
|
||||
Keymap::getUserKeymapPath = ->
|
||||
if userKeymapPath = CSON.resolve(path.join(@configDirPath, 'keymap'))
|
||||
userKeymapPath
|
||||
else
|
||||
path.join(@configDirPath, 'keymap.cson')
|
||||
|
||||
Keymap::loadUserKeymap = ->
|
||||
userKeymapPath = @getUserKeymapPath()
|
||||
if fs.isFileSync(userKeymapPath)
|
||||
@loadKeyBindings(userKeymapPath, watch: true, suppressErrors: true)
|
||||
|
||||
# This enables command handlers registered via jQuery to call
|
||||
# `.abortKeyBinding()` on the `jQuery.Event` object passed to the handler.
|
||||
jQuery.Event::abortKeyBinding = ->
|
||||
@originalEvent?.abortKeyBinding?()
|
||||
|
||||
module.exports = Keymap
|
||||
@@ -1,221 +0,0 @@
|
||||
{$} = require './space-pen-extensions'
|
||||
_ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
CSON = require 'season'
|
||||
KeyBinding = require './key-binding'
|
||||
{File} = require 'pathwatcher'
|
||||
{Emitter} = require 'emissary'
|
||||
|
||||
Modifiers = ['alt', 'control', 'ctrl', 'shift', 'cmd']
|
||||
|
||||
# Public: Associates keybindings with commands.
|
||||
#
|
||||
# An instance of this class is always available as the `atom.keymap` global.
|
||||
#
|
||||
# Keymaps are defined in a CSON/JSON format. A typical keymap looks something
|
||||
# like this:
|
||||
#
|
||||
# ```cson
|
||||
# 'body':
|
||||
# 'ctrl-l': 'package:do-something'
|
||||
# '.someClass':
|
||||
# 'enter': 'package:confirm'
|
||||
# ```
|
||||
#
|
||||
# As a key, you define the DOM element you want to work on, using CSS notation.
|
||||
# For that key, you define one or more key:value pairs, associating keystrokes
|
||||
# with a command to execute.
|
||||
module.exports =
|
||||
class Keymap
|
||||
Emitter.includeInto(this)
|
||||
|
||||
constructor: ({@resourcePath, @configDirPath})->
|
||||
@keyBindings = []
|
||||
|
||||
destroy: ->
|
||||
@unwatchUserKeymap()
|
||||
|
||||
# Public: Returns an array of all {KeyBinding}s.
|
||||
getKeyBindings: ->
|
||||
_.clone(@keyBindings)
|
||||
|
||||
# Public: Returns a array of {KeyBinding}s (sorted by selector specificity)
|
||||
# that match a keystroke and element.
|
||||
#
|
||||
# keystroke - The {String} representing the keys pressed (e.g. ctrl-P).
|
||||
# element - The DOM node that will match a {KeyBinding}'s selector.
|
||||
keyBindingsForKeystrokeMatchingElement: (keystroke, element) ->
|
||||
keyBindings = @keyBindingsForKeystroke(keystroke)
|
||||
@keyBindingsMatchingElement(element, keyBindings)
|
||||
|
||||
# Public: Returns a array of {KeyBinding}s (sorted by selector specificity)
|
||||
# that match a command.
|
||||
#
|
||||
# command - The {String} representing the command (tree-view:toggle).
|
||||
# element - The DOM node that will match a {KeyBinding}'s selector.
|
||||
keyBindingsForCommandMatchingElement: (command, element) ->
|
||||
keyBindings = @keyBindingsForCommand(command)
|
||||
@keyBindingsMatchingElement(element, keyBindings)
|
||||
|
||||
# Public: Returns an array of {KeyBinding}s that match a keystroke
|
||||
#
|
||||
# keystroke: The {String} representing the keys pressed (e.g. ctrl-P)
|
||||
keyBindingsForKeystroke: (keystroke) ->
|
||||
keystroke = KeyBinding.normalizeKeystroke(keystroke)
|
||||
@keyBindings.filter (keyBinding) -> keyBinding.matches(keystroke)
|
||||
|
||||
# Public: Returns an array of {KeyBinding}s that match a command
|
||||
#
|
||||
# keystroke - The {String} representing the keys pressed (e.g. ctrl-P)
|
||||
keyBindingsForCommand: (command) ->
|
||||
@keyBindings.filter (keyBinding) -> keyBinding.command == command
|
||||
|
||||
# Public: Returns a array of {KeyBinding}s (sorted by selector specificity)
|
||||
# whos selector matches the element.
|
||||
#
|
||||
# element - The DOM node that will match a {KeyBinding}'s selector.
|
||||
keyBindingsMatchingElement: (element, keyBindings=@keyBindings) ->
|
||||
keyBindings = keyBindings.filter ({selector}) -> $(element).closest(selector).length > 0
|
||||
keyBindings.sort (a, b) -> a.compare(b)
|
||||
|
||||
# Public: Returns a keystroke string derived from an event.
|
||||
#
|
||||
# event - A DOM or jQuery event.
|
||||
# previousKeystroke - An optional string used for multiKeystrokes.
|
||||
keystrokeStringForEvent: (event, previousKeystroke) ->
|
||||
if event.originalEvent.keyIdentifier.indexOf('U+') == 0
|
||||
hexCharCode = event.originalEvent.keyIdentifier[2..]
|
||||
charCode = parseInt(hexCharCode, 16)
|
||||
charCode = event.which if !@isAscii(charCode) and @isAscii(event.which)
|
||||
key = @keyFromCharCode(charCode)
|
||||
else
|
||||
key = event.originalEvent.keyIdentifier.toLowerCase()
|
||||
|
||||
modifiers = []
|
||||
if event.altKey and key not in Modifiers
|
||||
modifiers.push 'alt'
|
||||
if event.metaKey and key not in Modifiers
|
||||
modifiers.push 'cmd'
|
||||
if event.ctrlKey and key not in Modifiers
|
||||
modifiers.push 'ctrl'
|
||||
|
||||
if event.shiftKey and key not in Modifiers
|
||||
isNamedKey = key.length > 1
|
||||
modifiers.push 'shift' if isNamedKey
|
||||
else
|
||||
key = key.toLowerCase()
|
||||
|
||||
keystroke = [modifiers..., key].join('-')
|
||||
|
||||
if previousKeystroke
|
||||
if keystroke in Modifiers
|
||||
previousKeystroke
|
||||
else
|
||||
"#{previousKeystroke} #{keystroke}"
|
||||
else
|
||||
keystroke
|
||||
|
||||
loadBundledKeymaps: ->
|
||||
@loadDirectory(path.join(@resourcePath, 'keymaps'))
|
||||
@emit('bundled-keymaps-loaded')
|
||||
|
||||
getUserKeymapPath: ->
|
||||
if userKeymapPath = CSON.resolve(path.join(@configDirPath, 'keymap'))
|
||||
userKeymapPath
|
||||
else
|
||||
path.join(@configDirPath, 'keymap.cson')
|
||||
|
||||
unwatchUserKeymap: ->
|
||||
@userKeymapFile?.off()
|
||||
@remove(@userKeymapPath) if @userKeymapPath?
|
||||
|
||||
loadUserKeymap: ->
|
||||
@unwatchUserKeymap()
|
||||
userKeymapPath = @getUserKeymapPath()
|
||||
if fs.isFileSync(userKeymapPath)
|
||||
@userKeymapPath = userKeymapPath
|
||||
@userKeymapFile = new File(userKeymapPath)
|
||||
@userKeymapFile.on 'contents-changed moved removed', => @loadUserKeymap()
|
||||
@add(@userKeymapPath, @readUserKeymap())
|
||||
|
||||
readUserKeymap: ->
|
||||
try
|
||||
CSON.readFileSync(@userKeymapPath) ? {}
|
||||
catch error
|
||||
console.warn("Failed to load your keymap file: #{@userKeymapPath}", error.stack ? error)
|
||||
{}
|
||||
|
||||
loadDirectory: (directoryPath) ->
|
||||
platforms = ['darwin', 'freebsd', 'linux', 'sunos', 'win32']
|
||||
otherPlatforms = platforms.filter (name) -> name != process.platform
|
||||
|
||||
for filePath in fs.listSync(directoryPath, ['.cson', '.json'])
|
||||
continue if path.basename(filePath, path.extname(filePath)) in otherPlatforms
|
||||
@load(filePath)
|
||||
|
||||
load: (path) ->
|
||||
@add(path, CSON.readFileSync(path))
|
||||
|
||||
add: (source, keyMappingsBySelector) ->
|
||||
for selector, keyMappings of keyMappingsBySelector
|
||||
@bindKeys(source, selector, keyMappings)
|
||||
|
||||
remove: (source) ->
|
||||
@keyBindings = @keyBindings.filter (keyBinding) -> keyBinding.source isnt source
|
||||
|
||||
bindKeys: (source, selector, keyMappings) ->
|
||||
for keystroke, command of keyMappings
|
||||
keyBinding = new KeyBinding(source, command, keystroke, selector)
|
||||
try
|
||||
$(keyBinding.selector) # Verify selector is valid before registering
|
||||
@keyBindings.push(keyBinding)
|
||||
catch
|
||||
console.warn("Keybinding '#{keystroke}': '#{command}' in #{source} has an invalid selector: '#{selector}'")
|
||||
|
||||
handleKeyEvent: (event) ->
|
||||
element = event.target
|
||||
element = atom.workspaceView if element == document.body
|
||||
keystroke = @keystrokeStringForEvent(event, @queuedKeystroke)
|
||||
keyBindings = @keyBindingsForKeystrokeMatchingElement(keystroke, element)
|
||||
|
||||
if keyBindings.length == 0 and @queuedKeystroke
|
||||
@queuedKeystroke = null
|
||||
return false
|
||||
else
|
||||
@queuedKeystroke = null
|
||||
|
||||
for keyBinding in keyBindings
|
||||
partialMatch = keyBinding.keystroke isnt keystroke
|
||||
if partialMatch
|
||||
@queuedKeystroke = keystroke
|
||||
shouldBubble = false
|
||||
else
|
||||
if keyBinding.command is 'native!'
|
||||
shouldBubble = true
|
||||
else if @triggerCommandEvent(element, keyBinding.command, event)
|
||||
shouldBubble = false
|
||||
|
||||
break if shouldBubble?
|
||||
|
||||
shouldBubble ? true
|
||||
|
||||
triggerCommandEvent: (element, commandName, event) ->
|
||||
commandEvent = $.Event(commandName)
|
||||
commandEvent.originalEvent = event
|
||||
commandEvent.abortKeyBinding = -> commandEvent.stopImmediatePropagation()
|
||||
$(element).trigger(commandEvent)
|
||||
not commandEvent.isImmediatePropagationStopped()
|
||||
|
||||
isAscii: (charCode) ->
|
||||
0 <= charCode <= 127
|
||||
|
||||
keyFromCharCode: (charCode) ->
|
||||
switch charCode
|
||||
when 8 then 'backspace'
|
||||
when 9 then 'tab'
|
||||
when 13 then 'enter'
|
||||
when 27 then 'escape'
|
||||
when 32 then 'space'
|
||||
when 127 then 'delete'
|
||||
else String.fromCharCode(charCode)
|
||||
@@ -1,3 +0,0 @@
|
||||
keystrokePattern = key:key additionalKeys:additionalKey* { return [key].concat(additionalKeys); }
|
||||
additionalKey = '-' key:key { return key; }
|
||||
key = '-' / chars:[^-]+ { return chars.join('') }
|
||||
@@ -39,13 +39,13 @@ class LanguageMode
|
||||
return unless commentStartString
|
||||
|
||||
buffer = @editor.buffer
|
||||
commentStartRegexString = _.escapeRegExp(commentStartString).replace(/(\s+)$/, '($1)?')
|
||||
commentStartRegexString = _.escapeRegExp(commentStartString).replace(/(\s+)$/, '(?:$1)?')
|
||||
commentStartRegex = new OnigRegExp("^(\\s*)(#{commentStartRegexString})")
|
||||
shouldUncomment = commentStartRegex.test(buffer.lineForRow(start))
|
||||
|
||||
if commentEndString
|
||||
if shouldUncomment
|
||||
commentEndRegexString = _.escapeRegExp(commentEndString).replace(/^(\s+)/, '($1)?')
|
||||
commentEndRegexString = _.escapeRegExp(commentEndString).replace(/^(\s+)/, '(?:$1)?')
|
||||
commentEndRegex = new OnigRegExp("(#{commentEndRegexString})(\\s*)$")
|
||||
startMatch = commentStartRegex.search(buffer.lineForRow(start))
|
||||
endMatch = commentEndRegex.search(buffer.lineForRow(end))
|
||||
@@ -121,12 +121,6 @@ class LanguageMode
|
||||
fold = @editor.displayBuffer.largestFoldStartingAtBufferRow(startRow)
|
||||
return @editor.createFold(startRow, endRow) unless fold
|
||||
|
||||
# Given a buffer row, this unfolds it.
|
||||
#
|
||||
# bufferRow - A {Number} indicating the buffer row
|
||||
unfoldBufferRow: (bufferRow) ->
|
||||
@editor.displayBuffer.largestFoldContainingBufferRow(bufferRow)?.destroy()
|
||||
|
||||
# Find the row range for a fold at a given bufferRow. Will handle comments
|
||||
# and code.
|
||||
#
|
||||
@@ -271,10 +265,11 @@ class LanguageMode
|
||||
|
||||
# Given a buffer row, this indents it.
|
||||
#
|
||||
# bufferRow - The row {Number}
|
||||
autoIndentBufferRow: (bufferRow) ->
|
||||
# bufferRow - The row {Number}.
|
||||
# options - An options {Object} to pass through to {Editor::setIndentationForBufferRow}.
|
||||
autoIndentBufferRow: (bufferRow, options) ->
|
||||
indentLevel = @suggestedIndentForBufferRow(bufferRow)
|
||||
@editor.setIndentationForBufferRow(bufferRow, indentLevel)
|
||||
@editor.setIndentationForBufferRow(bufferRow, indentLevel, options)
|
||||
|
||||
# Given a buffer row, this decreases the indentation.
|
||||
#
|
||||
|
||||
@@ -77,7 +77,7 @@ class MenuManager
|
||||
keystrokesByCommand = {}
|
||||
for binding in atom.keymap.getKeyBindings() when @includeSelector(binding.selector)
|
||||
keystrokesByCommand[binding.command] ?= []
|
||||
keystrokesByCommand[binding.command].push binding.keystroke
|
||||
keystrokesByCommand[binding.command].unshift binding.keystroke
|
||||
@sendToBrowserProcess(@template, keystrokesByCommand)
|
||||
|
||||
loadPlatformItems: ->
|
||||
|
||||
@@ -41,7 +41,7 @@ class PackageManager
|
||||
|
||||
# Public: Get the path to the apm command
|
||||
getApmPath: ->
|
||||
@apmPath ?= require.resolve('atom-package-manager/bin/apm')
|
||||
@apmPath ?= path.resolve(__dirname, '..', 'apm', 'node_modules', 'atom-package-manager', 'bin', 'apm')
|
||||
|
||||
# Public: Get the paths being used to look for packages.
|
||||
#
|
||||
|
||||
+14
-2
@@ -69,7 +69,7 @@ class Package
|
||||
@loadStylesheets()
|
||||
@grammarsPromise = @loadGrammars()
|
||||
@scopedPropertiesPromise = @loadScopedProperties()
|
||||
@requireMainModule() unless @metadata.activationEvents?
|
||||
@requireMainModule() unless @hasActivationEvents()
|
||||
|
||||
catch error
|
||||
console.warn "Failed to load package named '#{@name}'", error.stack ? error
|
||||
@@ -87,7 +87,7 @@ class Package
|
||||
@activationDeferred = Q.defer()
|
||||
@measure 'activateTime', =>
|
||||
@activateResources()
|
||||
if @metadata.activationEvents?
|
||||
if @hasActivationEvents()
|
||||
@subscribeToActivationEvents()
|
||||
else
|
||||
@activateNow()
|
||||
@@ -262,6 +262,18 @@ class Package
|
||||
path.join(@path, 'index')
|
||||
@mainModulePath = fs.resolveExtension(mainModulePath, ["", _.keys(require.extensions)...])
|
||||
|
||||
hasActivationEvents: ->
|
||||
if _.isArray(@metadata.activationEvents)
|
||||
return @metadata.activationEvents.some (activationEvent) ->
|
||||
activationEvent?.length > 0
|
||||
else if _.isString(@metadata.activationEvents)
|
||||
return @metadata.activationEvents.length > 0
|
||||
else if _.isObject(@metadata.activationEvents)
|
||||
for event, selector of @metadata.activationEvents
|
||||
return true if event.length > 0 and selector.length > 0
|
||||
|
||||
false
|
||||
|
||||
subscribeToActivationEvents: ->
|
||||
return unless @metadata.activationEvents?
|
||||
if _.isArray(@metadata.activationEvents)
|
||||
|
||||
@@ -75,7 +75,9 @@ class PaneView extends View
|
||||
@command 'pane:split-right', => @splitRight(@copyActiveItem())
|
||||
@command 'pane:split-up', => @splitUp(@copyActiveItem())
|
||||
@command 'pane:split-down', => @splitDown(@copyActiveItem())
|
||||
@command 'pane:close', => @model.destroy()
|
||||
@command 'pane:close', =>
|
||||
@model.destroyItems()
|
||||
@model.destroy()
|
||||
@command 'pane:close-other-items', => @destroyInactiveItems()
|
||||
|
||||
# Deprecated: Use ::destroyItem
|
||||
|
||||
+3
-5
@@ -1,5 +1,4 @@
|
||||
{find, compact, extend, last} = require 'underscore-plus'
|
||||
{dirname} = require 'path'
|
||||
{Model, Sequence} = require 'theorist'
|
||||
Serializable = require 'serializable'
|
||||
PaneAxis = require './pane-axis'
|
||||
@@ -265,10 +264,9 @@ class Pane extends Model
|
||||
return unless item?.saveAs?
|
||||
|
||||
itemPath = item.getPath?()
|
||||
itemPath = dirname(itemPath) if itemPath
|
||||
path = atom.showSaveDialogSync(itemPath)
|
||||
if path
|
||||
item.saveAs(path)
|
||||
newItemPath = atom.showSaveDialogSync(itemPath)
|
||||
if newItemPath
|
||||
item.saveAs(newItemPath)
|
||||
nextAction?()
|
||||
|
||||
# Public: Saves all items.
|
||||
|
||||
@@ -189,8 +189,8 @@ class Project extends Model
|
||||
#
|
||||
# Returns a promise that resolves to the {TextBuffer}.
|
||||
buildBuffer: (absoluteFilePath) ->
|
||||
if fs.getSizeSync(absoluteFilePath) >= 1048576 # 1MB
|
||||
throw new Error("Atom can only handle files < 1MB, for now.")
|
||||
if fs.getSizeSync(absoluteFilePath) >= 2 * 1048576 # 2MB
|
||||
throw new Error("Atom can only handle files < 2MB, for now.")
|
||||
|
||||
buffer = new TextBuffer({filePath: absoluteFilePath})
|
||||
@addBuffer(buffer)
|
||||
@@ -251,6 +251,7 @@ class Project extends Model
|
||||
|
||||
for buffer in @getBuffers() when buffer.isModified()
|
||||
filePath = buffer.getPath()
|
||||
continue unless @contains(filePath)
|
||||
matches = []
|
||||
buffer.scan regex, (match) -> matches.push match
|
||||
iterator {filePath, matches} if matches.length > 0
|
||||
|
||||
@@ -3,17 +3,30 @@ path = require 'path'
|
||||
|
||||
module.exports = (repoPath) ->
|
||||
repo = Git.open(repoPath)
|
||||
|
||||
upstream = {}
|
||||
statuses = {}
|
||||
submodules = {}
|
||||
branch = null
|
||||
|
||||
if repo?
|
||||
# Statuses in main repo
|
||||
workingDirectoryPath = repo.getWorkingDirectory()
|
||||
statuses = {}
|
||||
for filePath, status of repo.getStatus()
|
||||
statuses[path.join(workingDirectoryPath, filePath)] = status
|
||||
|
||||
# Statuses in submodules
|
||||
for submodulePath, submoduleRepo of repo.submodules
|
||||
submodules[submodulePath] =
|
||||
branch: submoduleRepo.getHead()
|
||||
upstream: submoduleRepo.getAheadBehindCount()
|
||||
|
||||
workingDirectoryPath = submoduleRepo.getWorkingDirectory()
|
||||
for filePath, status of submoduleRepo.getStatus()
|
||||
statuses[path.join(workingDirectoryPath, filePath)] = status
|
||||
|
||||
upstream = repo.getAheadBehindCount()
|
||||
branch = repo.getHead()
|
||||
repo.release()
|
||||
else
|
||||
upstream = {}
|
||||
statuses = {}
|
||||
branch = null
|
||||
|
||||
{statuses, upstream, branch}
|
||||
{statuses, upstream, branch, submodules}
|
||||
|
||||
@@ -56,6 +56,11 @@ class SelectListView extends View
|
||||
@filterEditorView.hiddenInput.on 'focusout', =>
|
||||
@cancel() unless @cancelling
|
||||
|
||||
# This prevents the focusout event from firing on the filter editor view
|
||||
# when the list is scrolled by clicking the scrollbar and dragging.
|
||||
@list.on 'mousedown', ({target}) =>
|
||||
false if target is @list[0]
|
||||
|
||||
@on 'core:move-up', =>
|
||||
@selectPreviousItemView()
|
||||
@on 'core:move-down', =>
|
||||
@@ -148,8 +153,8 @@ class SelectListView extends View
|
||||
|
||||
for i in [0...Math.min(filteredItems.length, @maxItems)]
|
||||
item = filteredItems[i]
|
||||
itemView = @viewForItem(item)
|
||||
$(itemView).data('select-list-item', item)
|
||||
itemView = $(@viewForItem(item))
|
||||
itemView.data('select-list-item', item)
|
||||
@list.append(itemView)
|
||||
|
||||
@selectItemView(@list.find('li:first'))
|
||||
|
||||
+13
-7
@@ -1,4 +1,4 @@
|
||||
{Range} = require 'text-buffer'
|
||||
{Point, Range} = require 'text-buffer'
|
||||
{Emitter} = require 'emissary'
|
||||
{pick} = require 'underscore-plus'
|
||||
|
||||
@@ -141,6 +141,8 @@ class Selection
|
||||
#
|
||||
# position - An instance of {Point}, with a given `row` and `column`.
|
||||
selectToScreenPosition: (position) ->
|
||||
position = Point.fromObject(position)
|
||||
|
||||
@modifySelection =>
|
||||
if @initialScreenRange
|
||||
if position.isLessThan(@initialScreenRange.start)
|
||||
@@ -282,7 +284,7 @@ class Selection
|
||||
# :undo - if `skip`, skips the undo stack for this operation.
|
||||
insertText: (text, options={}) ->
|
||||
oldBufferRange = @getBufferRange()
|
||||
@editor.destroyFoldsContainingBufferRow(oldBufferRange.end.row)
|
||||
@editor.unfoldBufferRow(oldBufferRange.end.row)
|
||||
wasReversed = @isReversed()
|
||||
@clear()
|
||||
@cursor.needsAutoscroll = @cursor.isLastCursor()
|
||||
@@ -299,7 +301,7 @@ class Selection
|
||||
if options.autoIndent
|
||||
@editor.autoIndentBufferRow(row) for row in newBufferRange.getRows()
|
||||
else if options.autoIndentNewline and text == '\n'
|
||||
@editor.autoIndentBufferRow(newBufferRange.end.row)
|
||||
@editor.autoIndentBufferRow(newBufferRange.end.row, preserveLeadingWhitespace: true)
|
||||
else if options.autoDecreaseIndent and /\S/.test text
|
||||
@editor.autoDecreaseIndentForBufferRow(newBufferRange.start.row)
|
||||
|
||||
@@ -334,11 +336,15 @@ class Selection
|
||||
|
||||
normalizedLines.join('\n')
|
||||
|
||||
# Public: Indents the selection.
|
||||
# Indent the current line(s).
|
||||
#
|
||||
# If the selection is empty, indents the current line if the cursor precedes
|
||||
# non-whitespace characters, and otherwise inserts a tab. If the selection is
|
||||
# non empty, calls {::indentSelectedRows}.
|
||||
#
|
||||
# options - A {Object} with the keys:
|
||||
# :autoIndent - If `true`, the indentation is performed appropriately.
|
||||
# Otherwise, {Editor::getTabText} is used.
|
||||
# :autoIndent - If `true`, the line is indented to an automatically-inferred
|
||||
# level. Otherwise, {Editor::getTabText} is inserted.
|
||||
indent: ({ autoIndent }={})->
|
||||
{ row, column } = @cursor.getBufferPosition()
|
||||
|
||||
@@ -433,7 +439,7 @@ class Selection
|
||||
# Public: Joins the current line with the one below it.
|
||||
#
|
||||
# If there selection spans more than one line, all the lines are joined together.
|
||||
joinLine: ->
|
||||
joinLines: ->
|
||||
selectedRange = @getBufferRange()
|
||||
if selectedRange.isEmpty()
|
||||
return if selectedRange.start.row is @editor.buffer.getLastRow()
|
||||
|
||||
+1
-1
@@ -87,7 +87,7 @@ class Task
|
||||
if _.isFunction(callback)
|
||||
@callback = callback
|
||||
else
|
||||
args = arguments
|
||||
args.push(callback)
|
||||
@send({event: 'start', args})
|
||||
|
||||
# Public: Send message to the task.
|
||||
|
||||
@@ -191,6 +191,7 @@ class ThemeManager
|
||||
removeStylesheet: (stylesheetPath) ->
|
||||
fullPath = @resolveStylesheet(stylesheetPath) ? stylesheetPath
|
||||
@stylesheetElementForId(@stringToId(fullPath)).remove()
|
||||
@emit 'stylesheets-changed'
|
||||
|
||||
applyStylesheet: (path, text, ttype = 'bundled', htmlElement=$('html')) ->
|
||||
styleElement = @stylesheetElementForId(@stringToId(path), htmlElement)
|
||||
@@ -201,3 +202,4 @@ class ThemeManager
|
||||
htmlElement.find("head style.#{ttype}:last").after "<style class='#{ttype}' id='#{@stringToId(path)}'>#{text}</style>"
|
||||
else
|
||||
htmlElement.find("head").append "<style class='#{ttype}' id='#{@stringToId(path)}'>#{text}</style>"
|
||||
@emit 'stylesheets-changed'
|
||||
|
||||
@@ -20,7 +20,7 @@ class TokenizedBuffer extends Model
|
||||
visible: false
|
||||
|
||||
constructor: ({@buffer, @tabLength}) ->
|
||||
@tabLength ?= atom.config.get('editor.tabLength') ? 2
|
||||
@tabLength ?= atom.config.getPositiveInt('editor.tabLength', 2)
|
||||
|
||||
@subscribe atom.syntax, 'grammar-added grammar-updated', (grammar) =>
|
||||
if grammar.injectionSelector?
|
||||
@@ -40,7 +40,7 @@ class TokenizedBuffer extends Model
|
||||
@emit "changed", { start: 0, end: lastRow, delta: 0 }
|
||||
|
||||
@subscribe atom.config.observe 'editor.tabLength', callNow: false, =>
|
||||
@setTabLength(atom.config.getPositiveInt('editor.tabLength'))
|
||||
@setTabLength(atom.config.getPositiveInt('editor.tabLength', 2))
|
||||
|
||||
@reloadGrammar()
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ class TokenizedLine
|
||||
@tokens = @breakOutAtomicTokens(tokens, tabLength)
|
||||
@startBufferColumn ?= 0
|
||||
@text = _.pluck(@tokens, 'value').join('')
|
||||
@bufferDelta = _.sum(_.pluck(@tokens, 'bufferDelta'))
|
||||
|
||||
copy: ->
|
||||
new TokenizedLine({@tokens, @lineEnding, @ruleStack, @startBufferColumn, @fold})
|
||||
@@ -55,7 +56,7 @@ class TokenizedLine
|
||||
@text.length
|
||||
|
||||
getMaxBufferColumn: ->
|
||||
@startBufferColumn + @getMaxScreenColumn()
|
||||
@startBufferColumn + @bufferDelta
|
||||
|
||||
softWrapAt: (column) ->
|
||||
return [new TokenizedLine([], '', [0, 0], [0, 0]), this] if column == 0
|
||||
@@ -78,7 +79,7 @@ class TokenizedLine
|
||||
)
|
||||
rightFragment = new TokenizedLine(
|
||||
tokens: rightTokens
|
||||
startBufferColumn: @startBufferColumn + column
|
||||
startBufferColumn: @bufferColumnForScreenColumn(column)
|
||||
ruleStack: @ruleStack
|
||||
lineEnding: @lineEnding
|
||||
)
|
||||
|
||||
+106
-49
@@ -3,6 +3,7 @@ path = require 'path'
|
||||
Q = require 'q'
|
||||
_ = require 'underscore-plus'
|
||||
Delegator = require 'delegato'
|
||||
scrollbarStyle = require 'scrollbar-style'
|
||||
{$, $$, View} = require './space-pen-extensions'
|
||||
fs = require 'fs-plus'
|
||||
Workspace = require './workspace'
|
||||
@@ -14,38 +15,42 @@ PaneRowView = require './pane-row-view'
|
||||
PaneContainerView = require './pane-container-view'
|
||||
Editor = require './editor'
|
||||
|
||||
# Public: The container for the entire Atom application.
|
||||
# Public: The top-level view for the entire window. An instance of this class is
|
||||
# available via the `atom.workspaceView` global.
|
||||
#
|
||||
# An instance of this class is always available as the `atom.workspaceView`
|
||||
# global.
|
||||
# It is backed by a model object, an instance of {Workspace}, which is available
|
||||
# via the `atom.workspace` global or {::getModel}. You should prefer to interact
|
||||
# with the model object when possible, but it won't always be possible with the
|
||||
# current API.
|
||||
#
|
||||
# ## Commands
|
||||
# ## Adding Perimiter Panels
|
||||
#
|
||||
# * `application:about` - Opens the about dialog.
|
||||
# * `application:show-settings` - Opens the preference pane in the currently
|
||||
# focused editor.
|
||||
# * `application:quit` - Quits the entire application.
|
||||
# * `application:hide` - Hides the entire application.
|
||||
# * `application:hide-other-applications` - Hides other applications
|
||||
# running on the system.
|
||||
# * `application:unhide-other-applications` - Shows other applications
|
||||
# that were previously hidden.
|
||||
# * `application:new-window` - Opens a new {AtomWindow} with no {Project}
|
||||
# path.
|
||||
# * `application:new-file` - Creates a new file within the focused window.
|
||||
# Note: only one new file may exist within an {AtomWindow} at a time.
|
||||
# * `application:open` - Prompts the user for a path to open in a new {AtomWindow}
|
||||
# * `application:minimize` - Minimizes the currently focused {AtomWindow}
|
||||
# * `application:zoom` - Expands the window to fill the screen or returns it to
|
||||
# it's original unzoomed size.
|
||||
# * `application:bring-all-windows-to-front` - Brings all {AtomWindow}s to the
|
||||
# the front.
|
||||
# Use the following methods if possible to attach panels to the perimiter of the
|
||||
# workspace rather than manipulating the DOM directly to better insulate you to
|
||||
# changes in the workspace markup:
|
||||
#
|
||||
# * {::prependToTop}
|
||||
# * {::appendToTop}
|
||||
# * {::prependToBottom}
|
||||
# * {::appendToBottom}
|
||||
# * {::prependToLeft}
|
||||
# * {::appendToLeft}
|
||||
# * {::prependToRight}
|
||||
# * {::appendToRight}
|
||||
#
|
||||
# ## Requiring in package specs
|
||||
#
|
||||
# If you need a `WorkspaceView` instance to test your package, require it via
|
||||
# the built-in `atom` module.
|
||||
#
|
||||
# ```coffee
|
||||
# {WorkspaceView} = require 'atom'
|
||||
# ```
|
||||
#
|
||||
# You can assign it to the `atom.workspaceView` global in the spec or just use
|
||||
# it as a local, depending on what you're trying to accomplish. Building the
|
||||
# `WorkspaceView` is currently expensive, so you should try build a {Workspace}
|
||||
# instead if possible.
|
||||
module.exports =
|
||||
class WorkspaceView extends View
|
||||
Delegator.includeInto(this)
|
||||
@@ -81,6 +86,14 @@ class WorkspaceView extends View
|
||||
|
||||
@subscribe @model, 'uri-opened', => @trigger 'uri-opened'
|
||||
|
||||
@subscribe scrollbarStyle, (style) =>
|
||||
@removeClass('scrollbars-visible-always scrollbars-visible-when-scrolling')
|
||||
switch style
|
||||
when 'legacy'
|
||||
@addClass("scrollbars-visible-always")
|
||||
when 'overlay'
|
||||
@addClass("scrollbars-visible-when-scrolling")
|
||||
|
||||
@updateTitle()
|
||||
|
||||
@on 'focus', (e) => @handleFocus(e)
|
||||
@@ -139,6 +152,12 @@ class WorkspaceView extends View
|
||||
@command 'core:save', => @saveActivePaneItem()
|
||||
@command 'core:save-as', => @saveActivePaneItemAs()
|
||||
|
||||
# Public: Get the underlying model object.
|
||||
#
|
||||
# Returns a {Workspace}.
|
||||
getModel: -> @model
|
||||
|
||||
# Public: Install the Atom shell commands on the user's system.
|
||||
installShellCommands: ->
|
||||
showErrorDialog = (error) ->
|
||||
installDirectory = CommandInstaller.getInstallDirectory()
|
||||
@@ -176,11 +195,11 @@ class WorkspaceView extends View
|
||||
afterAttach: (onDom) ->
|
||||
@focus() if onDom
|
||||
|
||||
# Public: Shows a dialog asking if the pane was _really_ meant to be closed.
|
||||
# Prompts to save all unsaved items
|
||||
confirmClose: ->
|
||||
@panes.confirmClose()
|
||||
|
||||
# Public: Updates the application's title, based on whichever file is open.
|
||||
# Updates the application's title, based on whichever file is open.
|
||||
updateTitle: ->
|
||||
if projectPath = atom.project.getPath()
|
||||
if item = @getActivePaneItem()
|
||||
@@ -190,85 +209,119 @@ class WorkspaceView extends View
|
||||
else
|
||||
@setTitle('untitled')
|
||||
|
||||
# Public: Sets the application's title.
|
||||
# Sets the application's title.
|
||||
setTitle: (title) ->
|
||||
document.title = title
|
||||
|
||||
# Returns an Array of all of the application's {EditorView}s.
|
||||
# Get all editor views.
|
||||
#
|
||||
# You should prefer {Workspace::getEditors} unless you absolutely need access
|
||||
# to the view objects. Also consider using {::eachEditorView}, which will call
|
||||
# a callback for all current and *future* editor views.
|
||||
#
|
||||
# Returns an {Array} of {EditorView}s.
|
||||
getEditorViews: ->
|
||||
@panes.find('.pane > .item-views > .editor').map(-> $(this).view()).toArray()
|
||||
|
||||
# Public: Prepends the element to the top of the window.
|
||||
# Public: Prepend an element or view to the panels at the top of the
|
||||
# workspace.
|
||||
prependToTop: (element) ->
|
||||
@vertical.prepend(element)
|
||||
|
||||
# Public: Appends the element to the top of the window.
|
||||
# Public: Append an element or view to the panels at the top of the workspace.
|
||||
appendToTop: (element) ->
|
||||
@panes.before(element)
|
||||
|
||||
# Public: Prepends the element to the bottom of the window.
|
||||
# Public: Prepend an element or view to the panels at the bottom of the
|
||||
# workspace.
|
||||
prependToBottom: (element) ->
|
||||
@panes.after(element)
|
||||
|
||||
# Public: Appends the element to bottom of the window.
|
||||
# Public: Append an element or view to the panels at the bottom of the
|
||||
# workspace.
|
||||
appendToBottom: (element) ->
|
||||
@vertical.append(element)
|
||||
|
||||
# Public: Prepends the element to the left side of the window.
|
||||
# Public: Prepend an element or view to the panels at the left of the
|
||||
# workspace.
|
||||
prependToLeft: (element) ->
|
||||
@horizontal.prepend(element)
|
||||
|
||||
# Public: Appends the element to the left side of the window.
|
||||
# Public: Append an element or view to the panels at the left of the
|
||||
# workspace.
|
||||
appendToLeft: (element) ->
|
||||
@vertical.before(element)
|
||||
|
||||
# Public: Prepends the element to the right side of the window.
|
||||
# Public: Prepend an element or view to the panels at the right of the
|
||||
# workspace.
|
||||
prependToRight: (element) ->
|
||||
@vertical.after(element)
|
||||
|
||||
# Public: Appends the element to the right side of the window.
|
||||
# Public: Append an element or view to the panels at the right of the
|
||||
# workspace.
|
||||
appendToRight: (element) ->
|
||||
@horizontal.append(element)
|
||||
|
||||
# Public: Returns the currently focused {PaneView}.
|
||||
# Public: Get the active pane view.
|
||||
#
|
||||
# Prefer {Workspace::getActivePane} if you don't actually need access to the
|
||||
# view.
|
||||
#
|
||||
# Returns a {PaneView}.
|
||||
getActivePaneView: ->
|
||||
@panes.getActivePane()
|
||||
|
||||
# Public: Returns the currently focused item from within the focused {PaneView}
|
||||
getActivePaneItem: ->
|
||||
@model.activePaneItem
|
||||
|
||||
# Public: Returns the view of the currently focused item.
|
||||
# Public: Get the view associated with the active pane item.
|
||||
#
|
||||
# Returns a view.
|
||||
getActiveView: ->
|
||||
@panes.getActiveView()
|
||||
|
||||
# Public: Focuses the previous pane by id.
|
||||
# Focus the previous pane by id.
|
||||
focusPreviousPaneView: -> @model.activatePreviousPane()
|
||||
|
||||
# Public: Focuses the next pane by id.
|
||||
# Focus the next pane by id.
|
||||
focusNextPaneView: -> @model.activateNextPane()
|
||||
|
||||
# Public: Focuses the pane directly above the active pane.
|
||||
# Public: Focus the pane directly above the active pane.
|
||||
focusPaneViewAbove: -> @panes.focusPaneViewAbove()
|
||||
|
||||
# Public: Focuses the pane directly below the active pane.
|
||||
# Public: Focus the pane directly below the active pane.
|
||||
focusPaneViewBelow: -> @panes.focusPaneViewBelow()
|
||||
|
||||
# Public: Focuses the pane directly to the left of the active pane.
|
||||
# Public: Focus the pane directly to the left of the active pane.
|
||||
focusPaneViewOnLeft: -> @panes.focusPaneViewOnLeft()
|
||||
|
||||
# Public: Focuses the pane directly to the right of the active pane.
|
||||
# Public: Focus the pane directly to the right of the active pane.
|
||||
focusPaneViewOnRight: -> @panes.focusPaneViewOnRight()
|
||||
|
||||
# Public: Fires a callback on each open {PaneView}.
|
||||
# Public: Register a function to be called for every current and future
|
||||
# pane view in the workspace.
|
||||
#
|
||||
# callback - A {Function} with a {PaneView} as its only argument.
|
||||
#
|
||||
# Returns a subscription object with an `.off` method that you can call to
|
||||
# unregister the callback.
|
||||
eachPaneView: (callback) ->
|
||||
@panes.eachPaneView(callback)
|
||||
|
||||
# Public: Get all existing pane views.
|
||||
#
|
||||
# Prefer {Workspace::getPanes} if you don't need access to the view objects.
|
||||
# Also consider using {::eachPaneView} if you want to register a callback for
|
||||
# all current and *future* pane views.
|
||||
#
|
||||
# Returns an Array of all open {PaneView}s.
|
||||
getPaneViews: ->
|
||||
@panes.getPanes()
|
||||
|
||||
# Public: Fires a callback on each open {EditorView}.
|
||||
# Public: Register a function to be called for every current and future
|
||||
# editor view in the workspace.
|
||||
#
|
||||
# callback - A {Function} with an {EditorView} as its only argument.
|
||||
#
|
||||
# Returns a subscription object with an `.off` method that you can call to
|
||||
# unregister the callback.
|
||||
eachEditorView: (callback) ->
|
||||
callback(editor) for editor in @getEditorViews()
|
||||
attachedCallback = (e, editor) -> callback(editor)
|
||||
@@ -290,3 +343,7 @@ class WorkspaceView extends View
|
||||
# Deprecated
|
||||
getActivePane: ->
|
||||
@getActivePaneView()
|
||||
|
||||
# Deprecated: Call {Workspace::getActivePaneItem} instead.
|
||||
getActivePaneItem: ->
|
||||
@model.activePaneItem
|
||||
|
||||
+93
-34
@@ -7,18 +7,18 @@ Delegator = require 'delegato'
|
||||
PaneContainer = require './pane-container'
|
||||
Pane = require './pane'
|
||||
|
||||
# Public: Represents the view state of the entire window, including the panes at
|
||||
# the center and panels around the periphery.
|
||||
# Public: Represents the state of the user interface for the entire window.
|
||||
# An instance of this class is available via the `atom.workspace` global.
|
||||
#
|
||||
# An instance of this class is always available as the `atom.workspace` global.
|
||||
# Interact with this object to open files, be notified of current and future
|
||||
# editors, and manipulate panes. To add panels, you'll need to use the
|
||||
# {WorkspaceView} class for now until we establish APIs at the model layer.
|
||||
module.exports =
|
||||
class Workspace extends Model
|
||||
atom.deserializers.add(this)
|
||||
Serializable.includeInto(this)
|
||||
|
||||
@delegatesProperty 'activePane', 'activePaneItem', toProperty: 'paneContainer'
|
||||
@delegatesMethod 'getPanes', 'saveAll', 'activateNextPane', 'activatePreviousPane',
|
||||
toProperty: 'paneContainer'
|
||||
|
||||
@properties
|
||||
paneContainer: -> new PaneContainer
|
||||
@@ -49,31 +49,41 @@ class Workspace extends Model
|
||||
paneContainer: @paneContainer.serialize()
|
||||
fullScreen: atom.isFullScreen()
|
||||
|
||||
# Public: Calls callback for every existing {Editor} and for all new {Editor}s.
|
||||
# that are created.
|
||||
# Public: Register a function to be called for every current and future
|
||||
# {Editor} in the workspace.
|
||||
#
|
||||
# callback - A {Function} with an {Editor} as its only argument
|
||||
# callback - A {Function} with an {Editor} as its only argument.
|
||||
#
|
||||
# Returns a subscription object with an `.off` method that you can call to
|
||||
# unregister the callback.
|
||||
eachEditor: (callback) ->
|
||||
atom.project.eachEditor(callback)
|
||||
|
||||
# Public: Returns an {Array} of all open {Editor}s.
|
||||
# Public: Get all current editors in the workspace.
|
||||
#
|
||||
# Returns an {Array} of {Editor}s.
|
||||
getEditors: ->
|
||||
atom.project.getEditors()
|
||||
|
||||
# Public: Asynchronously opens a given a filepath in Atom.
|
||||
# Public: Open a given a URI in Atom asynchronously.
|
||||
#
|
||||
# uri - A {String} uri.
|
||||
# options - An options {Object} (default: {}).
|
||||
# :initialLine - A {Number} indicating which line number to open to.
|
||||
# :split - A {String} ('left' or 'right') that opens the filePath in a new
|
||||
# pane or an existing one if it exists.
|
||||
# :changeFocus - A {Boolean} that allows the filePath to be opened without
|
||||
# changing focus.
|
||||
# :searchAllPanes - A {Boolean} that will open existing editors from any pane
|
||||
# if the uri is already open (default: false)
|
||||
# uri - A {String} containing a URI.
|
||||
# options - An optional options {Object}
|
||||
# :initialLine - A {Number} indicating which row to move the cursor to
|
||||
# initially. Defaults to `0`.
|
||||
# :split - Either 'left' or 'right'. If 'left', the item will be opened in
|
||||
# leftmost pane of the current active pane's row. If 'right', the
|
||||
# item will be opened in the rightmost pane of the current active
|
||||
# pane's row.
|
||||
# :activatePane - A {Boolean} indicating whether to call {Pane::activate} on
|
||||
# the containing pane. Defaults to `true`.
|
||||
# :searchAllPanes - A {Boolean}. If `true`, the workspace will attempt to
|
||||
# activate an existing item for the given URI on any pane.
|
||||
# If `false`, only the active pane will be searched for
|
||||
# an existing item for the same URI. Defaults to `false`.
|
||||
#
|
||||
# Returns a promise that resolves to the {Editor} for the file URI.
|
||||
open: (uri='', options={}) ->
|
||||
open: (uri, options={}) ->
|
||||
searchAllPanes = options.searchAllPanes
|
||||
split = options.split
|
||||
uri = atom.project.resolve(uri)
|
||||
@@ -89,10 +99,20 @@ class Workspace extends Model
|
||||
|
||||
@openUriInPane(uri, pane, options)
|
||||
|
||||
# Public: Open Atom's license in the active pane.
|
||||
openLicense: ->
|
||||
@open(join(atom.getLoadSettings().resourcePath, 'LICENSE'))
|
||||
|
||||
# Only used in specs
|
||||
# Synchronously open the given URI in the active pane. **Only use this method
|
||||
# in specs. Calling this in production code will block the UI thread and
|
||||
# everyone will be mad at you.**
|
||||
#
|
||||
# uri - A {String} containing a URI.
|
||||
# options - An optional options {Object}
|
||||
# :initialLine - A {Number} indicating which row to move the cursor to
|
||||
# initially. Defaults to `0`.
|
||||
# :activatePane - A {Boolean} indicating whether to call {Pane::activate} on
|
||||
# the containing pane. Defaults to `true`.
|
||||
openSync: (uri='', options={}) ->
|
||||
{initialLine} = options
|
||||
# TODO: Remove deprecated changeFocus option
|
||||
@@ -112,8 +132,8 @@ class Workspace extends Model
|
||||
openUriInPane: (uri, pane, options={}) ->
|
||||
changeFocus = options.changeFocus ? true
|
||||
|
||||
item = pane.itemForUri(uri)
|
||||
if uri
|
||||
if uri?
|
||||
item = pane.itemForUri(uri)
|
||||
item ?= opener(atom.project.resolve(uri), options) for opener in @getOpeners() when !item
|
||||
item ?= atom.project.open(uri, options)
|
||||
|
||||
@@ -130,7 +150,8 @@ class Workspace extends Model
|
||||
.catch (error) ->
|
||||
console.error(error.stack ? error)
|
||||
|
||||
# Public: Reopens the last-closed item uri if it hasn't already been reopened.
|
||||
# Public: Reopen the last-closed item's URI if it hasn't already been
|
||||
# reopened.
|
||||
reopenItemSync: ->
|
||||
if uri = @destroyedItemUris.pop()
|
||||
@openSync(uri)
|
||||
@@ -150,50 +171,88 @@ class Workspace extends Model
|
||||
registerOpener: (opener) ->
|
||||
atom.project.registerOpener(opener)
|
||||
|
||||
# Public: Remove a registered opener.
|
||||
# Public: Unregister an opener registered with {::registerOpener}.
|
||||
unregisterOpener: (opener) ->
|
||||
atom.project.unregisterOpener(opener)
|
||||
|
||||
getOpeners: ->
|
||||
atom.project.openers
|
||||
|
||||
# Public: Returns the active {Pane}.
|
||||
# Public: Get the active {Pane}.
|
||||
#
|
||||
# Returns a {Pane}.
|
||||
getActivePane: ->
|
||||
@paneContainer.activePane
|
||||
|
||||
# Public: Returns the first pane {Pane} with an item for the given uri or
|
||||
# undefined if none exists.
|
||||
# Public: Get all {Pane}s.
|
||||
#
|
||||
# Returns an {Array} of {Pane}s.
|
||||
getPanes: ->
|
||||
@paneContainer.getPanes()
|
||||
|
||||
# Public: Save all pane items.
|
||||
saveAll: ->
|
||||
@paneContainer.saveAll()
|
||||
|
||||
# Public: Make the next pane active.
|
||||
activateNextPane: ->
|
||||
@paneContainer.activateNextPane()
|
||||
|
||||
# Public: Make the previous pane active.
|
||||
activatePreviousPane: ->
|
||||
@paneContainer.activatePreviousPane()
|
||||
|
||||
# Public: Get the first pane {Pane} with an item for the given URI.
|
||||
#
|
||||
# Returns a {Pane} or `undefined` if no pane exists for the given URI.
|
||||
paneForUri: (uri) ->
|
||||
@paneContainer.paneForUri(uri)
|
||||
|
||||
# Public: save the active item.
|
||||
# Public: Save the active pane item.
|
||||
#
|
||||
# If the active pane item currently has a URI according to the item's
|
||||
# `.getUri` method, calls `.save` on the item. Otherwise
|
||||
# {::saveActivePaneItemAs} # will be called instead. This method does nothing
|
||||
# if the active item does not implement a `.save` method.
|
||||
saveActivePaneItem: ->
|
||||
@activePane?.saveActiveItem()
|
||||
|
||||
# Public: save the active item as.
|
||||
# Public: Prompt the user for a path and save the active pane item to it.
|
||||
#
|
||||
# Opens a native dialog where the user selects a path on disk, then calls
|
||||
# `.saveAs` on the item with the selected path. This method does nothing if
|
||||
# the active item does not implement a `.saveAs` method.
|
||||
saveActivePaneItemAs: ->
|
||||
@activePane?.saveActiveItemAs()
|
||||
|
||||
# Public: destroy/close the active item.
|
||||
# Public: Destroy (close) the active pane item.
|
||||
#
|
||||
# Removes the active pane item and calls the `.destroy` method on it if one is
|
||||
# defined.
|
||||
destroyActivePaneItem: ->
|
||||
@activePane?.destroyActiveItem()
|
||||
|
||||
# Public: destroy/close the active pane.
|
||||
# Public: Destroy (close) the active pane.
|
||||
destroyActivePane: ->
|
||||
@activePane?.destroy()
|
||||
|
||||
# Public: Returns an {Editor} if the active pane item is an {Editor},
|
||||
# or null otherwise.
|
||||
# Public: Get the active item if it is an {Editor}.
|
||||
#
|
||||
# Returns an {Editor} or `undefined` if the current active item is not an
|
||||
# {Editor}.
|
||||
getActiveEditor: ->
|
||||
@activePane?.getActiveEditor()
|
||||
|
||||
# Public: Increase the editor font size by 1px.
|
||||
increaseFontSize: ->
|
||||
atom.config.set("editor.fontSize", atom.config.get("editor.fontSize") + 1)
|
||||
|
||||
# Public: Decrease the editor font size by 1px.
|
||||
decreaseFontSize: ->
|
||||
fontSize = atom.config.get("editor.fontSize")
|
||||
atom.config.set("editor.fontSize", fontSize - 1) if fontSize > 1
|
||||
|
||||
# Public: Restore to a default editor font size.
|
||||
resetFontSize: ->
|
||||
atom.config.restoreDefault("editor.fontSize")
|
||||
|
||||
|
||||
+2
-32
@@ -3,39 +3,9 @@
|
||||
<head>
|
||||
<title></title>
|
||||
|
||||
<script>
|
||||
window.onload = function() {
|
||||
var path = require('path');
|
||||
var ipc = require('ipc');
|
||||
try {
|
||||
// Skip "?loadSettings=".
|
||||
var loadSettings = JSON.parse(decodeURIComponent(location.search.substr(14)));
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src *; script-src 'self'; style-src 'self' 'unsafe-inline';">
|
||||
|
||||
// Start the crash reporter before anything else.
|
||||
require('crash-reporter').start({
|
||||
productName: 'Atom',
|
||||
companyName: 'GitHub',
|
||||
// By explicitly passing the app version here, we could save the call
|
||||
// of "require('remote').require('app').getVersion()".
|
||||
extra: {_version: loadSettings.appVersion}
|
||||
});
|
||||
|
||||
require('vm-compatibility-layer');
|
||||
require('coffee-script').register();
|
||||
require(path.resolve(__dirname, '..', 'src', 'coffee-cache')).register();
|
||||
require(loadSettings.bootstrapScript);
|
||||
ipc.sendChannel('window-command', 'window:loaded')
|
||||
}
|
||||
catch (error) {
|
||||
var currentWindow = require('remote').getCurrentWindow();
|
||||
currentWindow.setSize(800, 600);
|
||||
currentWindow.center();
|
||||
currentWindow.show();
|
||||
currentWindow.openDevTools();
|
||||
console.error(error.stack || error);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script src="index.js"></script>
|
||||
</head>
|
||||
<body tabindex="-1">
|
||||
</body>
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
window.onload = function() {
|
||||
var path = require('path');
|
||||
var ipc = require('ipc');
|
||||
try {
|
||||
// Skip "?loadSettings=".
|
||||
var loadSettings = JSON.parse(decodeURIComponent(location.search.substr(14)));
|
||||
|
||||
// Start the crash reporter before anything else.
|
||||
require('crash-reporter').start({
|
||||
productName: 'Atom',
|
||||
companyName: 'GitHub',
|
||||
// By explicitly passing the app version here, we could save the call
|
||||
// of "require('remote').require('app').getVersion()".
|
||||
extra: {_version: loadSettings.appVersion}
|
||||
});
|
||||
|
||||
require('vm-compatibility-layer');
|
||||
require('coffee-script').register();
|
||||
require(path.resolve(__dirname, '..', 'src', 'coffee-cache')).register();
|
||||
require(loadSettings.bootstrapScript);
|
||||
ipc.sendChannel('window-command', 'window:loaded')
|
||||
}
|
||||
catch (error) {
|
||||
var currentWindow = require('remote').getCurrentWindow();
|
||||
currentWindow.setSize(800, 600);
|
||||
currentWindow.center();
|
||||
currentWindow.show();
|
||||
currentWindow.openDevTools();
|
||||
console.error(error.stack || error);
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@
|
||||
display: -webkit-flex;
|
||||
-webkit-flex: 1;
|
||||
-webkit-flex-direction: column;
|
||||
overflow: hidden;
|
||||
|
||||
.item-views {
|
||||
-webkit-flex: 1;
|
||||
|
||||
@@ -1,8 +1,29 @@
|
||||
// This file has fallback variables. It specifies the syntax variables that
|
||||
// themes must implement.
|
||||
// This file has fallback variables. It specifies all syntax variables that
|
||||
// themes must implement if they include a syntax-variables.less file.
|
||||
|
||||
// Colors
|
||||
// General colors
|
||||
@syntax-text-color: #333;
|
||||
@syntax-cursor-color: #333;
|
||||
@syntax-selection-color: #69c;
|
||||
@syntax-background-color: #fff;
|
||||
|
||||
@syntax-color-added: #5293d8;
|
||||
@syntax-color-modified: #f78a46;
|
||||
@syntax-color-removed: #c00;
|
||||
// Guide colors
|
||||
@syntax-wrap-guide-color: #ccc;
|
||||
@syntax-indent-guide-color: #ccc;
|
||||
@syntax-invisible-character-color: #ccc;
|
||||
|
||||
// For find and replace markers
|
||||
@syntax-result-marker-color: #444;
|
||||
@syntax-result-marker-color-selected: #000;
|
||||
|
||||
// Gutter colors
|
||||
@syntax-gutter-text-color: #333;
|
||||
@syntax-gutter-text-color-selected: #000;
|
||||
@syntax-gutter-background-color: #ccc;
|
||||
@syntax-gutter-background-color-selected: #eee;
|
||||
|
||||
// For git diff info. i.e. in the gutter
|
||||
@syntax-color-added: green;
|
||||
@syntax-color-modified: orange;
|
||||
@syntax-color-removed: red;
|
||||
@syntax-color-renamed: blue;
|
||||
|
||||
externo
+1
-1
Submodule vendor/apm updated: 1137653592...3f0003c60e
Referência em uma Nova Issue
Bloquear um usuário