Comparar commits
1463 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 79c6badce8 | |||
| a48ef934eb | |||
| 85d5968318 | |||
| 9b4dd602be | |||
| 62d84e5d4b | |||
| 61ed5da1dc | |||
| 32e25d4bb2 | |||
| aae9614839 | |||
| 7fa4121227 | |||
| 1d783826a2 | |||
| bdb6e193de | |||
| 3f75512de2 | |||
| 5910b05344 | |||
| 7f039b3383 | |||
| ca35ced587 | |||
| 734ef19f48 | |||
| ef9ce1bf70 | |||
| c754b73b71 | |||
| 21565332a4 | |||
| 8871d9cd2d | |||
| 64f0fcc839 | |||
| 581d12b04f | |||
| 05a9ace3e6 | |||
| 03eac362f6 | |||
| 8a05b0f51d | |||
| 4069d23d86 | |||
| 78b48345ac | |||
| 139e2f6de0 | |||
| ed86b4a478 | |||
| f2352131cc | |||
| 56df435fb8 | |||
| 595ff19b5b | |||
| 33eb0bae8f | |||
| fde1560377 | |||
| a640d07599 | |||
| 45b65cd3aa | |||
| f217278001 | |||
| 3320176a0a | |||
| 754b5a6004 | |||
| 79b84b2433 | |||
| 17be036ff8 | |||
| 23deec833f | |||
| 6a8d0bef4a | |||
| d5ce1a0312 | |||
| 74decbd18a | |||
| 085806f97f | |||
| ca8be83903 | |||
| da713da311 | |||
| 7a6c75a83e | |||
| 3e7a517c25 | |||
| e623ef4232 | |||
| 18399aa264 | |||
| 2a5f393712 | |||
| 27f779ec03 | |||
| 5d717eb7bd | |||
| 0b457fd80a | |||
| dd9aa2d02f | |||
| 87b530140b | |||
| 2f46fee1ca | |||
| fbb48e7807 | |||
| 01c141eec6 | |||
| 7d9d0c715c | |||
| a9887b5007 | |||
| c4dec72dcd | |||
| d093d5cc06 | |||
| 27c9e54538 | |||
| 3bbe6ee98c | |||
| 524d8e8e21 | |||
| c31211dc21 | |||
| 6c1b63d352 | |||
| 6fa7da79eb | |||
| c2371f3054 | |||
| 2349627e3c | |||
| 90d92a4c92 | |||
| 66171e0301 | |||
| cdc7f70b22 | |||
| e225dbe93d | |||
| 7dc18765ad | |||
| c1d379fd6c | |||
| a754ac4da0 | |||
| 21560df2f0 | |||
| f0aa408b70 | |||
| 161c9a62b5 | |||
| 2c5bbcbc22 | |||
| eee72f7664 | |||
| 073d398e6f | |||
| 2310e263a7 | |||
| de7b212d99 | |||
| 75873ef6b3 | |||
| 73855a49fc | |||
| cae055fd3f | |||
| 2aad31c4dc | |||
| 93052ad611 | |||
| 67733b8b05 | |||
| 21543569ef | |||
| 7371ebbf20 | |||
| 73470cc294 | |||
| 1e60b5fa3b | |||
| 172ecbd897 | |||
| 289cc24b56 | |||
| a20483ccdb | |||
| b2ceaf3b8b | |||
| 1c3c508985 | |||
| 645f4ad907 | |||
| 05dd6f8f17 | |||
| b19390b519 | |||
| a3f339e0c3 | |||
| 42040e14b3 | |||
| 91640f0886 | |||
| 0377d64788 | |||
| cd37caae96 | |||
| aab63c26e7 | |||
| 6da6101a52 | |||
| 87b33648dc | |||
| d0b380e535 | |||
| 99480901e2 | |||
| 6852720408 | |||
| f9498732a5 | |||
| e4aa82fda1 | |||
| bc1a743b2f | |||
| 3fe22aa5c8 | |||
| fe035d4d7c | |||
| e8bfb7ca09 | |||
| 4bfd48b983 | |||
| 5a1fadf7ce | |||
| 819ac9ea68 | |||
| 6384841134 | |||
| a0fbec29c3 | |||
| 238fca2004 | |||
| 014beda455 | |||
| 777df644ce | |||
| f3ea3a3395 | |||
| b82fdace61 | |||
| 7195102a04 | |||
| 5ec6a4a189 | |||
| e330b1a2e8 | |||
| 5334433bc2 | |||
| 366a12903a | |||
| 063cb04fb5 | |||
| d9c2f07fbe | |||
| 5c1fa8e53d | |||
| a1f3540cb4 | |||
| 2eeb399cf1 | |||
| 71e8e865f2 | |||
| 9f080be6e1 | |||
| 56f66f8578 | |||
| 0b1dc704ea | |||
| 578d823118 | |||
| 0196f2a2eb | |||
| 1e68a7266f | |||
| 093143f7a9 | |||
| 4eeef9cfbd | |||
| ce3ec75c55 | |||
| bb09de9703 | |||
| e64ba18fe3 | |||
| 3908f81fc6 | |||
| fac46a295c | |||
| b01470a738 | |||
| f3be613662 | |||
| ede29d99c1 | |||
| d2369e94c8 | |||
| dbe3399016 | |||
| 3952423d99 | |||
| ffdcecc0f2 | |||
| 0069eb4d0d | |||
| 5fa55026d5 | |||
| 6d04d57e74 | |||
| 3f0dca5a40 | |||
| 8b14a66e2c | |||
| 1607411df1 | |||
| dade9f6309 | |||
| 568aa1d396 | |||
| 9febe179fa | |||
| c9e68ab044 | |||
| 285186567a | |||
| 1c136f16e3 | |||
| 534a2d4565 | |||
| 9e814de969 | |||
| 7202ba274a | |||
| 46e85fac87 | |||
| d1f1b494cf | |||
| f11803df60 | |||
| f094a86ae7 | |||
| a6c791ce39 | |||
| dfa870f514 | |||
| a98377b899 | |||
| c3de3d8eea | |||
| 2d15f5e49a | |||
| 56386cb06a | |||
| 986a7ad5c3 | |||
| 9a01b5a6bf | |||
| ccafda6f7f | |||
| 33538a5ed7 | |||
| aae85cd7c1 | |||
| ce098e587f | |||
| 233d819e04 | |||
| fbbf3d177a | |||
| c33bd34996 | |||
| 34cdb23d71 | |||
| fcedcd117d | |||
| 3d7de21d6c | |||
| 2278ee742a | |||
| 55e90f8ae1 | |||
| 2ca738453b | |||
| 31a9bb83cf | |||
| 1e4504e7f3 | |||
| bf05ddb958 | |||
| 756c2be64a | |||
| 6fdd4f775b | |||
| 625fcaffc8 | |||
| 955d379e0e | |||
| 0d71f20073 | |||
| 42c40e8c7a | |||
| 89212e599f | |||
| 95e4ac903c | |||
| 311155ac0d | |||
| aaa82e23da | |||
| 8e46bc5241 | |||
| 37a5a6f501 | |||
| 83f14c137c | |||
| b0b458b1f6 | |||
| f4de124aa6 | |||
| 4b0eaf05a5 | |||
| 03e8bc6f19 | |||
| 13186fcf7a | |||
| fea0f1f90a | |||
| b449bb4444 | |||
| fe6b40fc5d | |||
| 82e3935ae3 | |||
| 32a3b6302c | |||
| 6157fcaf73 | |||
| ab74d8be38 | |||
| 886a2aa867 | |||
| aeaa76a9e1 | |||
| 6a7bcb6f52 | |||
| ee1ec4670d | |||
| 7e0af4c575 | |||
| f55a200591 | |||
| 89d8eac091 | |||
| 5011b6e78f | |||
| d6e67c5b32 | |||
| de547e20c2 | |||
| 2b79b19330 | |||
| 2b234545b5 | |||
| a66543048b | |||
| ca96aa2804 | |||
| 316571308a | |||
| b323d9ce18 | |||
| 0e1c757cd0 | |||
| 084bbb1578 | |||
| 7c348ee478 | |||
| a0c6a94409 | |||
| 80cdf61fa4 | |||
| 29c3fadb6f | |||
| 1ae3806c69 | |||
| 98b509441c | |||
| 02f40688e2 | |||
| cb8e378af6 | |||
| babc4732b8 | |||
| dcccde8f3f | |||
| 8ed4923e58 | |||
| 529c829438 | |||
| 809a02ca10 | |||
| b9902cb6f2 | |||
| de4d3dbbe9 | |||
| 3fe88c4df1 | |||
| 20811a9f52 | |||
| b137f1a3e3 | |||
| 0b12f01206 | |||
| 1d7b4c5f9a | |||
| e2d4b58d5f | |||
| 1c8df2c0b5 | |||
| 9067c65a41 | |||
| 1d4f2fba8b | |||
| 12dd412439 | |||
| 19d680544b | |||
| a45dd3fe37 | |||
| f6c8a435ae | |||
| 93bfe0edf6 | |||
| d3fed57cb3 | |||
| 8372adb38a | |||
| e4b3d3a83c | |||
| 11f1ef9d8b | |||
| 7d87ae00ff | |||
| 3ec2378242 | |||
| 28943a35da | |||
| 7b43c8a860 | |||
| 8b17b7eca9 | |||
| 6432cda691 | |||
| cf0bdb9c94 | |||
| 34f1472653 | |||
| a475e27cd4 | |||
| abc1f23516 | |||
| dc7e7f9ed0 | |||
| 5fdec4dc7b | |||
| 618d281d6c | |||
| 055ec8cb9c | |||
| df3fe90c89 | |||
| 21e0e95a7a | |||
| 6caed6e918 | |||
| 7dd84636ba | |||
| b12954760d | |||
| 4bb21fd9ec | |||
| 11787e5a5d | |||
| 276e63611a | |||
| 957374eb40 | |||
| fe9f1373c1 | |||
| 6290c19264 | |||
| 913bb82d6e | |||
| ffc936ca4d | |||
| 1808e5f991 | |||
| 62feefd28d | |||
| ada992be4d | |||
| f8933cfeab | |||
| 0878d7ab6a | |||
| bd8e19bce7 | |||
| 4852ba6d95 | |||
| caffcafe2e | |||
| c7a1205ca6 | |||
| 2c4f94c319 | |||
| 941fc97e79 | |||
| 8788b2a51c | |||
| ca8ae9ad61 | |||
| 2fb00af255 | |||
| f6ce0f038f | |||
| 94a8d16664 | |||
| fc0a46d6b2 | |||
| fd443a8b68 | |||
| c43f277c5b | |||
| dd0938dca6 | |||
| e90f19da97 | |||
| c3aea1d149 | |||
| 569c3116a8 | |||
| 8bdc1d2418 | |||
| fa1600c53d | |||
| 6a1e83205f | |||
| 33891b51f2 | |||
| 1ef821f4e7 | |||
| ed030a54c3 | |||
| 6bb3a69410 | |||
| 53f5e9fbc6 | |||
| 1dac1f375c | |||
| cfab5c619d | |||
| b6afc415f8 | |||
| 5454e93168 | |||
| 389b2bd8d6 | |||
| 8ea011597c | |||
| 21060ae85a | |||
| fe0cc7d273 | |||
| f67e9b6e03 | |||
| 64f2cdb795 | |||
| a996597d49 | |||
| 52680bd63f | |||
| b8f0f1c683 | |||
| 0840de95dc | |||
| fe1b2c6d9d | |||
| 7b307a17ea | |||
| 097571a83d | |||
| 0673ce8e71 | |||
| 967b022fa6 | |||
| e330b8940a | |||
| 526e5311b9 | |||
| 3720f0fb8f | |||
| 46b108f1cc | |||
| aa59002922 | |||
| 6af125bd33 | |||
| d5d2ae63fe | |||
| 08f774e57a | |||
| 513a964732 | |||
| 8f9f5ed0ed | |||
| 001fe5931e | |||
| c7541f89da | |||
| cb0f3ce2ec | |||
| d71e58ec33 | |||
| 5aacccb03b | |||
| 8f63e40ba0 | |||
| 6c09a42545 | |||
| 1cb1387abd | |||
| fe426000d0 | |||
| 3617a61ea2 | |||
| c7b5753814 | |||
| 4ce23e4b51 | |||
| c8aeb8ec2d | |||
| 0d75bcae48 | |||
| 81c56ca4f1 | |||
| fb02917adf | |||
| 8c8f1bc048 | |||
| 94bc4ce737 | |||
| 9914085ead | |||
| b801c3ce56 | |||
| e31dbfd7d6 | |||
| d4b5303983 | |||
| ad0d0473b3 | |||
| 0db23c3e96 | |||
| 0b78450917 | |||
| 4b15b98bdd | |||
| 572157124e | |||
| d0e1d32ae9 | |||
| 33cb42a3f7 | |||
| 055109a708 | |||
| 3539288a1e | |||
| 88d80918a7 | |||
| 0897007662 | |||
| 1c4e38c867 | |||
| 78617e31bc | |||
| a377a49004 | |||
| 5756ec45ba | |||
| 23c8db09b7 | |||
| 9f8a8139e0 | |||
| d793d114d4 | |||
| 9b3edc89a6 | |||
| 58b2a4f98e | |||
| f356190b42 | |||
| 08a81b61a3 | |||
| bff47e10f4 | |||
| 6dbe86b063 | |||
| 21edc61384 | |||
| ef0022f4da | |||
| cbee5efee6 | |||
| 55da08c69e | |||
| df7c3d066a | |||
| ba627c005e | |||
| b3efe00757 | |||
| 5f8e757f57 | |||
| 5f6f09fc45 | |||
| f9e7d64131 | |||
| eefeb2ab2a | |||
| ee896846bb | |||
| ddd560b785 | |||
| 59d8beb935 | |||
| c4de03d5c4 | |||
| 53f7592815 | |||
| 86a1f43196 | |||
| 177f3b9d53 | |||
| affcb5ff4a | |||
| a168692eea | |||
| 80db09f47b | |||
| 1ef1f60556 | |||
| 7934043646 | |||
| ae6b4547e1 | |||
| aaa654de39 | |||
| 1d3f33e740 | |||
| 19e6c632ea | |||
| 0d014c6257 | |||
| 445421f961 | |||
| 778ed06272 | |||
| e16481d6e0 | |||
| f34af85ad3 | |||
| 9118a70592 | |||
| 43419fdef2 | |||
| 11f3686832 | |||
| 455321c4a8 | |||
| dfa5ac11a2 | |||
| 8754a0cbaf | |||
| 6485e4f540 | |||
| 4ca66a535c | |||
| 56c88820d6 | |||
| 5d56365c26 | |||
| 55c5ae926c | |||
| ef68fd24d5 | |||
| 4497ec9733 | |||
| 38a3c0dbd3 | |||
| b69bc8ce71 | |||
| fe6cf8ec01 | |||
| b4f8387053 | |||
| 6b63f5db9e | |||
| 291f4fbb90 | |||
| dba7687470 | |||
| e6a7678fd6 | |||
| 4b6867831a | |||
| 28d7160c3b | |||
| c4ab4364ba | |||
| 98db48eae6 | |||
| d6cb848503 | |||
| 3119ed9dfe | |||
| 3f0f3267c1 | |||
| 2cc32e1faf | |||
| a8fe8ab982 | |||
| 4bee197e01 | |||
| 01f41207d4 | |||
| ce2e123cc8 | |||
| 16b64b03f7 | |||
| 2adcc9709c | |||
| 0f1d701646 | |||
| 6e049dd173 | |||
| face4a3f76 | |||
| 015f4f7542 | |||
| 9f5e913804 | |||
| 383a724144 | |||
| 90c21906a4 | |||
| 0686efc429 | |||
| 2058d5a431 | |||
| 6c9f037cd9 | |||
| 5033fac8eb | |||
| 0aa0dc01d5 | |||
| 994756f8c1 | |||
| 47bab20363 | |||
| efb87237e2 | |||
| 2be5790311 | |||
| 60fa937ed7 | |||
| 867a6ecd95 | |||
| 36c9d68009 | |||
| 4dda2f93ae | |||
| fcdc341981 | |||
| 5b187e7a8c | |||
| 740085e561 | |||
| 5a2730c8c0 | |||
| 08ee9c08b7 | |||
| 103f602c9c | |||
| fb6b8029be | |||
| edc789173b | |||
| 7ba4782ceb | |||
| 9863386644 | |||
| 1fe6a2974d | |||
| 6bd7dd8841 | |||
| 3db786953c | |||
| b9b9b7df91 | |||
| da2d37408f | |||
| 8739dfe739 | |||
| cd2e78f04f | |||
| 8851120db2 | |||
| c59404b2b0 | |||
| 151a4290d4 | |||
| 1ef5809b24 | |||
| 8cca42a6b8 | |||
| aad23d4760 | |||
| d20bff473b | |||
| 287f1984db | |||
| 1cb5d16a60 | |||
| 105f8d0baf | |||
| 7e9a1d8ffe | |||
| ee280d87f9 | |||
| e312050163 | |||
| 717626fbaf | |||
| ec761d00ef | |||
| 3d99e580b9 | |||
| b0da17701b | |||
| 8443db6630 | |||
| 2333b53d05 | |||
| f05eb67125 | |||
| 4c5fdbce93 | |||
| 9482e9b397 | |||
| 0eb4704f5e | |||
| 13c374845f | |||
| 0c87f0edf8 | |||
| c9db0f14ed | |||
| 875e9c886c | |||
| 05867bc889 | |||
| 621058aa9e | |||
| 3b52a6a040 | |||
| e70f87dfc7 | |||
| 0695aafe80 | |||
| c9eebcf00a | |||
| f26110a81b | |||
| 651b40f360 | |||
| 456c27475b | |||
| bc0a268841 | |||
| 9d9ff97995 | |||
| a03a89d359 | |||
| 7e043f5bc6 | |||
| e8f8cd2dcd | |||
| 132c6f7414 | |||
| a458f7581d | |||
| 64565cc510 | |||
| 7de8b4c2f4 | |||
| 01e40bd866 | |||
| 6e47135ba7 | |||
| b041c0176c | |||
| b22d64745f | |||
| cbf55f38f9 | |||
| 9e8b1fb661 | |||
| 6d4285f180 | |||
| 7d3c272909 | |||
| 6677b2ccdf | |||
| bf48195752 | |||
| b8680be6c6 | |||
| 0264fd6be5 | |||
| 9c79e39401 | |||
| e06100fe25 | |||
| f7686a5485 | |||
| 01610a3fb8 | |||
| d8766b9aba | |||
| ebb7a2637a | |||
| a143ca551b | |||
| 3cfefc03ff | |||
| 1646cdc349 | |||
| bc289cc0cb | |||
| ef97dadea1 | |||
| 83dcf79bcf | |||
| 60563f46c9 | |||
| 70925263f7 | |||
| 166faf1af2 | |||
| aab2937a48 | |||
| 1b9f86d13a | |||
| 88802ef4c5 | |||
| e8e3e3224f | |||
| 1b6c34673e | |||
| aa6f2187d8 | |||
| 7d64cd179e | |||
| 56ff3b79e4 | |||
| ba654f15cb | |||
| 62ccf92a5d | |||
| ca073fb7c2 | |||
| 94b5d08b63 | |||
| 678dc82d50 | |||
| 5b5f0af6b5 | |||
| 695c8d97f2 | |||
| 5ac3a74bf0 | |||
| d150170e5b | |||
| d14e5a6992 | |||
| b419cdf193 | |||
| a57f1e4727 | |||
| 34499d87ab | |||
| 4e18e7a67c | |||
| aef9a12910 | |||
| b501758bf7 | |||
| 993cc75c15 | |||
| 64e02d007c | |||
| a39255fa77 | |||
| ddfd1842d1 | |||
| 3e71dcfcd0 | |||
| 2629345df2 | |||
| 8c3fbc3437 | |||
| c30f63fa0c | |||
| 5685eb9263 | |||
| e3fd999964 | |||
| e8109adeee | |||
| b150191263 | |||
| 4dc909de03 | |||
| c029f8eb95 | |||
| 31e75884be | |||
| 82e5545f6e | |||
| febd845876 | |||
| 61021b6a13 | |||
| b9274412c5 | |||
| d6457152f0 | |||
| 49e48a0895 | |||
| eae7a7065e | |||
| 696355f6dd | |||
| ab0c60bd45 | |||
| 83005deae6 | |||
| d486a55b4c | |||
| e6b3f400c0 | |||
| 86cba12457 | |||
| 1d6e3c73cf | |||
| 8fb06a5b11 | |||
| 8afb3fb6b9 | |||
| ff9356bc2c | |||
| b523decc7e | |||
| e7a14bf17f | |||
| a593d3b152 | |||
| 9781565df8 | |||
| a595378850 | |||
| b2e2a2cdda | |||
| eb8d9214b7 | |||
| 8ac8b3748f | |||
| b4a28d7418 | |||
| c6ee5699e7 | |||
| 19220aa9f3 | |||
| 0a10603eb3 | |||
| 0700732495 | |||
| c3b270dc80 | |||
| 2baa5ba678 | |||
| 0bd701b4a6 | |||
| 1be8d5e618 | |||
| a212a7c259 | |||
| 76a041cfe1 | |||
| 46eb6df61e | |||
| 93c7531cf9 | |||
| 8bf726d3e1 | |||
| 412cb602a4 | |||
| f10abfe630 | |||
| 14664625d5 | |||
| 9e12c4610d | |||
| c1d09f5229 | |||
| d486522cde | |||
| e3ff39bf4f | |||
| 74a48e58dc | |||
| e63bf75f96 | |||
| 8b9595f1bd | |||
| 53954c236c | |||
| 3de18ae9f6 | |||
| 9c7ce22abe | |||
| bfab56247f | |||
| e4400c648d | |||
| 271f23083e | |||
| e3f4a72ab3 | |||
| ee3b7cee76 | |||
| 5a357a54dc | |||
| d07bf338c8 | |||
| 516ddec854 | |||
| 0ab2b89c1a | |||
| 2c2c7e67d7 | |||
| e1f8b042ed | |||
| f7ce6a015d | |||
| 4775783ba3 | |||
| d0bf4c1d2e | |||
| 4f1d862bc0 | |||
| 059671c454 | |||
| 1f16cd3912 | |||
| 2d16fc33a3 | |||
| 6ad8062d45 | |||
| 8f0c0362e8 | |||
| 91436bec25 | |||
| e93d83dcdf | |||
| 62f44e64f4 | |||
| c571d6a9d4 | |||
| bdd4ac63f4 | |||
| 0c77712a77 | |||
| a00db81765 | |||
| c91bca44cb | |||
| dbf4ba099b | |||
| e67324dcc9 | |||
| 1528d6ea49 | |||
| a49fd569e3 | |||
| 44213aff96 | |||
| 22589bf2dd | |||
| 28a2b48688 | |||
| 668ef0b3a1 | |||
| 9a4db9d95d | |||
| e457600f38 | |||
| 2f62123a75 | |||
| e7e28b568b | |||
| b70df78041 | |||
| c4b24fe738 | |||
| b1f5d1e276 | |||
| cd9d6ca6ee | |||
| d6159a38d4 | |||
| a828f389f4 | |||
| 91c8371752 | |||
| 05c70aceec | |||
| 002fc570e7 | |||
| f81c64f068 | |||
| e9bcb4637e | |||
| e21f1c1394 | |||
| eae5a25872 | |||
| 6364589630 | |||
| 41f6d6b0dd | |||
| c581135029 | |||
| af92c96a73 | |||
| cdd4c9669a | |||
| 1368b60f16 | |||
| cc42db3bff | |||
| cc3a2ab2d5 | |||
| f9837aadaa | |||
| 20c7f298a9 | |||
| 86506752a7 | |||
| 83206ac3a7 | |||
| dc54ebf416 | |||
| d5b960f32b | |||
| ffaaa21b37 | |||
| ef2a322229 | |||
| 1931cb6dff | |||
| 6040221d26 | |||
| 7c70c43c1c | |||
| cde0fae1f3 | |||
| 95107052d0 | |||
| 650915724b | |||
| ad67abc2a2 | |||
| 50d2d5b1cd | |||
| 010905db0b | |||
| 232bc8be8e | |||
| 57577966e7 | |||
| 08d5231d28 | |||
| 05c3d89381 | |||
| 7a3dc2c3b8 | |||
| 8eecc56d08 | |||
| e009ff6c59 | |||
| f500e2e9fc | |||
| 2a98ccec8d | |||
| 8742f6c06c | |||
| 9605da9d56 | |||
| 1cdb87fdce | |||
| 330bb1df4b | |||
| 45ceb3f9f9 | |||
| 3fa7c8fb48 | |||
| 97c183d6df | |||
| 42362e6ce9 | |||
| 2266ea25e8 | |||
| 970d7654cb | |||
| 82cbfb3829 | |||
| c2c6b5f868 | |||
| 0dd0c39918 | |||
| 7002b4e5f6 | |||
| 78f1865bcf | |||
| bb281ce5af | |||
| b02d906cfb | |||
| b5b07c1052 | |||
| c77b44d5ef | |||
| eba1e474f8 | |||
| 6fa580f543 | |||
| feed72b68e | |||
| 5cee47c207 | |||
| 1d1a14b8e9 | |||
| 18421465c0 | |||
| ea9930db70 | |||
| 2d40cb09d1 | |||
| 8956881192 | |||
| 32bc8a6258 | |||
| 30c1124e5e | |||
| 63cb53b169 | |||
| 17ebb079eb | |||
| 9f4f3d26e5 | |||
| 8bc9c9aba3 | |||
| 2e20c7696e | |||
| 78bb8b473b | |||
| a0fb4333d5 | |||
| 197291e453 | |||
| bafea9b95b | |||
| 23b635db1e | |||
| 7aa57c44f8 | |||
| ece0ea2a54 | |||
| f22732b109 | |||
| 71b9188ece | |||
| a2017628bc | |||
| cf025639bd | |||
| df6ebddc69 | |||
| aa2734f3bf | |||
| b9e3a8bd40 | |||
| 2a3a38a5f8 | |||
| 0254812446 | |||
| 11186f627e | |||
| db44df040e | |||
| cdf439b556 | |||
| e4fc15deec | |||
| 53547b5a8d | |||
| 6460cbe288 | |||
| 29646cdff8 | |||
| feff67457d | |||
| 1f30231d5c | |||
| 3e584f29b1 | |||
| c424f7bafa | |||
| 48fbdc69fb | |||
| c1b0ba2773 | |||
| d4949c872b | |||
| a8a28c8635 | |||
| 6f47010a72 | |||
| 0a3f64a3df | |||
| f21e8e3aa4 | |||
| 39fb929af6 | |||
| ca26d53db1 | |||
| 1b8f8cd914 | |||
| 2d30ec84bb | |||
| 378a7135b7 | |||
| b288a5c68f | |||
| 265e4ff43c | |||
| 4ad38eed87 | |||
| 427a26c99b | |||
| 069e0bed9a | |||
| f7dfd60014 | |||
| d5f92ef59d | |||
| 76b68ae1f8 | |||
| b79068ea65 | |||
| 9ae078f405 | |||
| 2dd1b161cf | |||
| e6e7d389cd | |||
| 6aa6706d86 | |||
| 2b2677ae18 | |||
| 42e269a7ce | |||
| 0c6c2e2d84 | |||
| c513c55f7a | |||
| e873a0977c | |||
| 8bcf40111d | |||
| 224bc56d4e | |||
| 5d35f52174 | |||
| afb2ec86b7 | |||
| 8f870544b9 | |||
| 29f6833807 | |||
| ffcd948362 | |||
| 3b525302b0 | |||
| 3ae5213ebf | |||
| d2f33dcf39 | |||
| 80f4e7eb7f | |||
| cbb82b1dcc | |||
| 7a81a84393 | |||
| f2f915c0d0 | |||
| 72bd408722 | |||
| e38f7259e5 | |||
| 48335bd4ac | |||
| cdebc2306c | |||
| a37b029ad9 | |||
| ba9be0c07a | |||
| 4a48e1a228 | |||
| 43dae4e9eb | |||
| 8503a53fec | |||
| d0ed2a87cd | |||
| fa36ab1a5c | |||
| 141da61301 | |||
| 59ef210624 | |||
| 2ddcfb60cf | |||
| e003b478f3 | |||
| de69446e1e | |||
| 5e253378e2 | |||
| 9da395c0aa | |||
| fd0bed4248 | |||
| 1f86c62dc9 | |||
| 161a87b8e1 | |||
| 74cb91a6a1 | |||
| 3eab78bc23 | |||
| 2574e4b6ee | |||
| fd177d7171 | |||
| eeb24e1d5c | |||
| b13c633775 | |||
| b14ca90362 | |||
| 997891f298 | |||
| 967c04fb19 | |||
| 2a7908a196 | |||
| ecbb7cad23 | |||
| 8ac84359b1 | |||
| 71a24ec49b | |||
| c614519529 | |||
| 2624cf6e75 | |||
| f2c1ea9b5a | |||
| 7b1b73e8eb | |||
| e8b50755cb | |||
| dd3b20f7de | |||
| 73c1fb23da | |||
| d5b07088cd | |||
| d2864f1d0c | |||
| b330ce6722 | |||
| 81e6150fde | |||
| 16128b0d90 | |||
| 0788905eb5 | |||
| abe36765b5 | |||
| eaea8753f5 | |||
| 0b74dfc67a | |||
| 9f753cd3b9 | |||
| 4440210d9a | |||
| 56832b11fc | |||
| 23cc82e0ef | |||
| 077cb9ddb7 | |||
| b416116e0c | |||
| 9cc52e7882 | |||
| 79e90b313f | |||
| 9093690511 | |||
| c8a45b7b74 | |||
| f1e862252b | |||
| c3b79778ba | |||
| 37fec2e2bf | |||
| d805b6f6ac | |||
| f88e7e99ee | |||
| 3c1734c8f3 | |||
| efdcf5a40f | |||
| 06960f5c10 | |||
| 047b875ce9 | |||
| 2b266da3e3 | |||
| d430aafb7c | |||
| 4132cddb8a | |||
| d38067ec1a | |||
| beda703001 | |||
| 71ede6b97f | |||
| fa5f88cf05 | |||
| 069ae17f9d | |||
| 1e4041d7cf | |||
| a7d2c14364 | |||
| abf570ebf5 | |||
| 3c08ae2de6 | |||
| c1fae082b4 | |||
| 40ab5938f2 | |||
| b2dae8be6c | |||
| c71e9cf618 | |||
| 931ac5d029 | |||
| 620b939a46 | |||
| 73f0f2930f | |||
| c66b478c63 | |||
| 2254a6e33b | |||
| bb19821c5c | |||
| 0aae15e4c1 | |||
| 4d035b148d | |||
| 7bee816c19 | |||
| 927279cd9d | |||
| 91f33de04e | |||
| 351035e540 | |||
| 656bee7f56 | |||
| e7fc879a57 | |||
| 575a13957b | |||
| ee2e5bb2b0 | |||
| efbddc7339 | |||
| 1c16f4fb73 | |||
| 23158261b2 | |||
| dd51a08d54 | |||
| 03f6461dec | |||
| 4fae98d049 | |||
| eeebaba350 | |||
| 3b05b40d66 | |||
| f01d006e25 | |||
| d765880f74 | |||
| ceffb23431 | |||
| 755abaf2b7 | |||
| 35ff4b8677 | |||
| d16fb6fc8f | |||
| 5d701d899e | |||
| 12ca6f86ef | |||
| 58ef0f4176 | |||
| 4dada919ba | |||
| 9b318c1317 | |||
| 6ed3bb48f2 | |||
| 814ab4e980 | |||
| ffbce2020e | |||
| 0fc2f70dc5 | |||
| 5277277683 | |||
| 3ec33de3b7 | |||
| 0d49f2a3d0 | |||
| d21a5a6836 | |||
| 5e3d52927a | |||
| 0bc470c6d9 | |||
| 2aa3a7c332 | |||
| 948a2a47a3 | |||
| df2727d926 | |||
| 1129ff7436 | |||
| 89f72c36f8 | |||
| 017c3315d2 | |||
| 0a561643a9 | |||
| 640b6feb49 | |||
| 94f441e123 | |||
| 459309aa78 | |||
| 558778b4d4 | |||
| 05550717e2 | |||
| a92e5c00ea | |||
| dbd1438cf7 | |||
| 082686bba8 | |||
| f6fee9d04f | |||
| 02dd79feeb | |||
| ff5ee45dc7 | |||
| 702eaea483 | |||
| fc6b6d9760 | |||
| 3e5f204f08 | |||
| eced0a3208 | |||
| f3aec0dfee | |||
| fd062a7c4f | |||
| d9c946cafa | |||
| 2502d48544 | |||
| 9ea2bfa920 | |||
| 2ec6d578f6 | |||
| ff22046f54 | |||
| 5541875965 | |||
| 9c877c7f0b | |||
| 4061011609 | |||
| e8b5bf5402 | |||
| 069208975c | |||
| 60dcef26b0 | |||
| 217f182579 | |||
| ccdd17c0d8 | |||
| d6452c37d8 | |||
| c9ab78ee53 | |||
| 5a1e72cd81 | |||
| bd674764e8 | |||
| 3cce3c5202 | |||
| c809df6762 | |||
| 9c3a8e5c7a | |||
| 9f0064f903 | |||
| 35399d93a9 | |||
| 5619f81c89 | |||
| 26d9d7a8fd | |||
| 590a03b8e3 | |||
| 9c9e1164b1 | |||
| 708d3fb08f | |||
| e07fb89ec7 | |||
| 3c13f41b7c | |||
| 49756e6846 | |||
| 142f5cf754 | |||
| acbb521532 | |||
| 1e6302b060 | |||
| c7afa8d682 | |||
| 30e20884d9 | |||
| 3e71e8a2be | |||
| 0e601737e7 | |||
| 0653eed275 | |||
| 0d131e7253 | |||
| a0c5e38cdd | |||
| b1d474fd5c | |||
| 0dc6302c38 | |||
| 89ea353d99 | |||
| 766634c428 | |||
| 1262073853 | |||
| 686b88fe60 | |||
| 875dfa61cb | |||
| 2000e43053 | |||
| 450eba0d54 | |||
| 5be444c4ed | |||
| 238399adb6 | |||
| 747b79cced | |||
| 6e93c37ce1 | |||
| b3b3e5fa3c | |||
| 3251362400 | |||
| 9b84271fee | |||
| 5e5375528b | |||
| 514ca3a9c2 | |||
| 436ffd90d4 | |||
| 201677eb1d | |||
| 887dadd589 | |||
| 538f66d9cf | |||
| 53b0ac22cc | |||
| 84dc0df925 | |||
| d49e419191 | |||
| d33e3e4071 | |||
| 02b9e79888 | |||
| 820b870f82 | |||
| 6171e357c1 | |||
| b07b024602 | |||
| c37d5124d9 | |||
| caadec6e62 | |||
| 7b9ff7d0f7 | |||
| 08e5c42f0c | |||
| 2d9c2ec939 | |||
| ee6b2b0776 | |||
| 607ed972c1 | |||
| 7149ade43c | |||
| d989aeb592 | |||
| cded70c48a | |||
| ede64f65c8 | |||
| 80a3e0c9c9 | |||
| 5883dd4f16 | |||
| 0254e64762 | |||
| d0f6e83726 | |||
| 9d51d1a143 | |||
| 565f5fb304 | |||
| 835088676d | |||
| 43c54a93e5 | |||
| 8bd87ac4f2 | |||
| 76c152b97d | |||
| aa57414547 | |||
| 0ee4956109 | |||
| 28a45c0fcd | |||
| 719616aa3a | |||
| dbef7a26ce | |||
| f7a30845f8 | |||
| 492d7bc69a | |||
| 60aca173ce | |||
| 9a839045e5 | |||
| ee495575a2 | |||
| 8ce72bedea | |||
| 5c36a98bb0 | |||
| 3f8eb361c0 | |||
| 26039653b2 | |||
| fc4750bcd5 | |||
| 541d25787b | |||
| 697c96921f | |||
| 913f20333d | |||
| e2ecff22c2 | |||
| 71f7e20eeb | |||
| 6a3638c7d3 | |||
| 5b6e8a1b20 | |||
| 216a5e61fd | |||
| 8dbc0259c1 | |||
| 4d4551987f | |||
| 4fa15d3fce | |||
| f066887fd8 | |||
| e3250d73a8 | |||
| 72a89231f8 | |||
| 57d9aa6019 | |||
| af8ecef30d | |||
| 7b3101778b | |||
| d292579376 | |||
| 2c8854ce8b | |||
| 03964ff568 | |||
| 1c357f9b65 | |||
| 6e313dc0e4 | |||
| bf1457e557 | |||
| 3d9bb68007 | |||
| eaed08a5cc | |||
| f05bba6a6f | |||
| 07f370df2a | |||
| 672fb8ecaf | |||
| f47ad4f16b | |||
| b8597ab384 | |||
| d10bc2c06c | |||
| 0db962b94f | |||
| 667e0929b6 | |||
| ff30a8e14b | |||
| 11dbcfecaf | |||
| 6318571fed | |||
| 7f1f2bccd5 | |||
| c797995597 | |||
| 6030edcf0a | |||
| 9fe32954dc | |||
| 320b4a49b4 | |||
| e5ac73e0db | |||
| 0b0c3229d3 | |||
| a0486bc9b0 | |||
| f9a0e038a5 | |||
| ffa83e6356 | |||
| 4b566d1ce3 | |||
| 09e7a5af6b | |||
| a31862a32d | |||
| c44b04e47a | |||
| 3589fcc107 | |||
| 30ea10cfb8 | |||
| d062cdda84 | |||
| ea93c21a92 | |||
| c0cc002134 | |||
| 417ea030ef | |||
| 3145e9b53b | |||
| a7bd04de36 | |||
| ec37b8abd9 | |||
| 0b22d99fad | |||
| f60ead03d2 | |||
| cd3ec7d156 | |||
| eadee9f15c | |||
| 8001942283 | |||
| f506130d3b | |||
| 4549ea2058 | |||
| 01380c307e | |||
| 024785fa4f | |||
| afa03b6379 | |||
| a55847b03b | |||
| 57769f4328 | |||
| 538b938a71 | |||
| 714a1327ce | |||
| 3ff0b3cfe2 | |||
| 69a247294c | |||
| b73798bd03 | |||
| 8ecc353999 | |||
| 118625f002 | |||
| c50632bd82 | |||
| 1e6cca0969 | |||
| 64c5732e51 | |||
| e8c399428c | |||
| 5b239938a9 | |||
| c1f8b1e941 | |||
| aed15766fb | |||
| 0f1c1715dd | |||
| 091189ee79 | |||
| a79f36cbf2 | |||
| 483f63ab05 | |||
| 1ed01c5155 | |||
| 87408f689f | |||
| 5d1b88493e | |||
| 551bb72756 | |||
| a0fd9098ad | |||
| b6a0763419 | |||
| 9994cbbd6e | |||
| b05a3fa4b6 | |||
| fd51392a2d | |||
| 83e7c59aba | |||
| 8d6ffe9daa | |||
| bb99a8e586 | |||
| 63f39d84a3 | |||
| d31fe2ee91 | |||
| 83581bc6d2 | |||
| 47cf00751f | |||
| 002e3898fa | |||
| 38f50d60f5 | |||
| 7be57deef6 | |||
| d0decbb7e5 | |||
| 68c7b2dab0 | |||
| 8e73258168 | |||
| 53b4b1c349 | |||
| fae1f500eb | |||
| 4308e428d3 | |||
| 1d343dd483 | |||
| e17c9ced57 | |||
| 8edd6ad5d5 | |||
| fba1d486e3 | |||
| cdfad1218b | |||
| 4d415d3ca9 | |||
| 6a37f9dad4 | |||
| 0255faded1 | |||
| 12b42bf459 | |||
| abd8bd1253 | |||
| cd633ede92 | |||
| e4c87b2d0b | |||
| c1c46cfb94 | |||
| 942695d582 | |||
| 8682bad958 | |||
| 3d9598a99a | |||
| 0221f7d263 | |||
| 92c6ad66eb | |||
| 894cae7c9c | |||
| b0e9b4b81f | |||
| 9b7bc34d44 | |||
| ff8577b7d6 | |||
| 317365e41f | |||
| e4219cae45 | |||
| ed3bb509fa | |||
| 8d27369afc | |||
| 63fb5b1fe5 | |||
| 891200d658 | |||
| d815147df6 | |||
| d7836f6082 | |||
| 1538afee05 | |||
| db64e8c0b3 | |||
| 31c1241ce8 | |||
| 7875386498 | |||
| c766ddf5e6 | |||
| 940df94081 | |||
| 018ee0deb0 | |||
| dafa1ab0a8 | |||
| 730cd8680e | |||
| 338eb5a871 | |||
| 142654b77c | |||
| 7db7234fb1 | |||
| 78f600a7f6 | |||
| 187895a893 | |||
| 1120a14351 | |||
| 192df9c496 | |||
| 45ae59b1fb | |||
| 0ac683284d | |||
| 23af63b76c | |||
| 080b52de8d | |||
| 53773274df | |||
| 3ed0f7bde4 | |||
| 5b214bdfd7 | |||
| d883834626 | |||
| 818fc10ba5 | |||
| b95b3148c9 | |||
| 29a9a9d2ed | |||
| 22411b3c87 | |||
| 7c6f9b1a81 | |||
| 4f8bb00af2 | |||
| 6abb5a2390 | |||
| 6d29d8de48 | |||
| 23620e158b | |||
| 0c811ec703 | |||
| b114545dd2 | |||
| 2e71043657 | |||
| c614ec6beb | |||
| 7a1874d1b9 | |||
| 14a7202df2 | |||
| b7e7b83bdf | |||
| 5fc14e0c37 | |||
| d004d94f3f | |||
| 6faef08592 | |||
| 017030fd60 | |||
| 1b38118cc3 | |||
| 2c2661da11 | |||
| b17c8ced84 | |||
| 02f13d6a06 | |||
| 8061101bbd | |||
| 662262ab82 | |||
| 349ba86b92 | |||
| d93633a837 | |||
| 93742f933b | |||
| 4b70147b3b | |||
| 0be5d1f3fd | |||
| ffdfe63a4e | |||
| adc8618823 | |||
| 2f2a634c2a | |||
| 36c58e9132 | |||
| 33cf5dda15 | |||
| 5acf1150a4 | |||
| 4c9059d445 | |||
| ff1ab93652 | |||
| 43d5c3f66d | |||
| 250af9191a | |||
| 7365be7d88 | |||
| 6d15fbb114 | |||
| 37ec1abc25 | |||
| 41cfa2892b | |||
| caae18c552 | |||
| 380bad2129 | |||
| 8e60db65a3 | |||
| 8caed2081b | |||
| 1ed6733ab5 | |||
| d2d77012c5 | |||
| 6c55fc102d | |||
| 9a61c545f4 | |||
| 2029895f0b | |||
| 7f0150c6b8 | |||
| 124b1ebd33 | |||
| d3e2d9b5f9 | |||
| f8e61f5c48 | |||
| e95e8a22c3 | |||
| 0033c9659f | |||
| 9db3f9b5d9 | |||
| 55b71405c9 | |||
| db47d02c3c | |||
| ad577d6315 | |||
| 19a8626c21 | |||
| 87bfcf5683 | |||
| 722be2267d | |||
| a3559d1289 | |||
| b4fb526d75 | |||
| 122b209ad7 | |||
| 53da1db3d8 | |||
| 34d7913505 | |||
| 0c54f6254d | |||
| 9c6353977f | |||
| 2cee400547 | |||
| ba8707dfd9 | |||
| 64e8c978e4 | |||
| 1ff97fc21a | |||
| 964e88f131 | |||
| f5c9dc7362 | |||
| 32329070c2 | |||
| 9f7b430c02 | |||
| 26ab49306e | |||
| 13232de4b9 | |||
| f9250e3dd1 | |||
| a878d9e3da | |||
| 3aae7bb77e | |||
| 8825be937e | |||
| b3324b49b0 | |||
| 785c71daf8 | |||
| 7f9ce094c7 | |||
| 89b0e4d159 | |||
| 98928dd99f | |||
| 4df546a19e | |||
| 04cdad680b | |||
| 87687036cb | |||
| 4f1bdee2d7 | |||
| 5942f2997f | |||
| 26a3a77fed | |||
| a50e948a90 | |||
| bd8c14355c | |||
| 1a6884ff71 | |||
| 156b6a9490 | |||
| 407ccc4819 | |||
| 5516dadffe | |||
| f1cf8496f8 | |||
| b4afc24ee8 | |||
| d0be7fbf8e | |||
| 8463c759b5 | |||
| 5a772d7078 | |||
| 8ab8201020 | |||
| 6eb72ac2a1 | |||
| 8a3f137519 | |||
| a57c86f4ea | |||
| 8cd04b5178 | |||
| d351938702 | |||
| c2bb5a998b | |||
| 303124f1dd | |||
| 875f0ca1e5 | |||
| 6a494f65a5 | |||
| aa404a316d | |||
| 45d3fea3d0 | |||
| 0ab382133b | |||
| 98a3bb475b | |||
| 2394f25b92 | |||
| 914288ab86 | |||
| aba5eb5b41 | |||
| 5c46bff4c1 | |||
| 8f68d62420 | |||
| a8c008767f | |||
| 64e4cd3db1 | |||
| bde0a3dff0 | |||
| 66635a19d1 | |||
| 1deba49722 | |||
| 0b3a00056f | |||
| 7b7c9abdeb | |||
| 141c4f48bf | |||
| 73796a27e5 | |||
| 32101c57bf | |||
| b63a33c7bb | |||
| d8e857efc9 | |||
| c0b8b0a443 | |||
| 6cf41eea0a | |||
| b468a6f375 | |||
| 6e17755c1a | |||
| b921dc3a1d | |||
| cc68925ab7 | |||
| 9147419ed3 | |||
| ed09e4e33f | |||
| e9fd6f0c32 | |||
| b315e62a43 | |||
| 716fe8cfe7 | |||
| c825b1d9bb | |||
| a1c39c9f38 | |||
| dc245184c1 | |||
| 8b73224fe3 | |||
| 903a1b9bf0 | |||
| 459e4d5523 | |||
| 3e933ee81b |
@@ -0,0 +1,8 @@
|
||||
# Specs depend on character counts, if we don't specify the line endings the
|
||||
# fixtures will vary depending on platform
|
||||
spec/fixtures/**/*.js text eol=lf
|
||||
spec/fixtures/**/*.coffee text eol=lf
|
||||
spec/fixtures/**/*.less text eol=lf
|
||||
spec/fixtures/**/*.css text eol=lf
|
||||
spec/fixtures/**/*.txt text eol=lf
|
||||
spec/fixtures/dir/**/* text eol=lf
|
||||
@@ -5,6 +5,8 @@
|
||||
.nvm-version
|
||||
node_modules
|
||||
npm-debug.log
|
||||
debug.log
|
||||
/tags
|
||||
/atom-shell/
|
||||
docs/output
|
||||
spec/fixtures/evil-files/
|
||||
|
||||
-101
@@ -1,101 +0,0 @@
|
||||
* Improved: Faster and better looking find and replace
|
||||
* Improved: Double-click selection behavior between word/non-word
|
||||
* Added: Solarized theme now bundled by default
|
||||
* Added: Base16 Tomorrow Dark theme now bundled by default
|
||||
|
||||
* Fixed: Make Atom's version the same as Speakeasy's version
|
||||
|
||||
* Fixed: Package generator package not opening window to generated package
|
||||
|
||||
* Fixed: Precompile bootstrap.less for faster startup
|
||||
|
||||
* Fixed: Save sometimes failing from an editor that was split
|
||||
* Fixed: Search results not appearing when set to exclude ignores
|
||||
|
||||
* Fixed: Status bar and gutter displaying incorrect Git status information
|
||||
* Fixed: Packages not installing from the Settings view
|
||||
* Fixed: Spec runner now works from a released build
|
||||
* Fixed: Literate CoffeeScript not syntax highlighting correctly
|
||||
|
||||
* Added: Soft wrap and tab length can now be set in the settings view
|
||||
* Fixed: Python import statements not syntax highlighting correctly
|
||||
|
||||
* Added: Terminal package now bundled by default, open with ctrl-`
|
||||
* Fixed: Fuzzy finder not showing results for files at a certain depth
|
||||
* Fixed: Atom > Preferences... menu not opening settings in focused window
|
||||
|
||||
* Fixed: Atom failing to launch if the theme being used was not found
|
||||
|
||||
* Improved: Theme changes now immediately take effect
|
||||
* Fixed: Wrap in quotes/parens now works in split panes
|
||||
* Improved: Autocomplete now includes CSS property names and values
|
||||
* Improved: Settings GUI is now a pane item
|
||||
* Added: Support package filtering in Settings GUI
|
||||
* Added: Dynamically load all config options in the Settings GUI
|
||||
* Added: Ability to bookmark lines and navigate bookmarks
|
||||
* Fixed: Error when inserting newlines in CSS
|
||||
* Fixed: Folding all will fold comments as well
|
||||
* Added: Ability to fold all code at a given indentation level
|
||||
|
||||
* Improved: cmd-n now opens a new tab and cmd-shift-n now opens a new window.
|
||||
* Added: Inspect Element context menu
|
||||
* Fixed: Save As dialog now defaults to directory path of current editor
|
||||
* Fixed: Using toggle comment shortcut respects indentation level
|
||||
|
||||
* Fixed: Search never completing in the command panel
|
||||
|
||||
* Fixed: cmd-n now works when no windows are open
|
||||
|
||||
* Fixed: Error selecting a grammar for an untitled editor
|
||||
|
||||
* Added: j/k now can be used to navigate the tree view and archive editor
|
||||
|
||||
* Fixed: Atom can now be launched when ~/.atom/config.cson doesn't exist
|
||||
* Added: Initial collaboration sessions
|
||||
* Fixed: Empty lines being deleted via uppercase/downcase command
|
||||
* Fixed: Keybindings not working when using non-English keyboard language
|
||||
* Fixed: cmd-shift-p and cmd-alt-w not doing anything when pressed
|
||||
|
||||
* Improved: Use grunt (instead of rake) for build system
|
||||
* Fixed: Java files not syntax highlighting correctly.
|
||||
* Fixed: LESS/CSS now indents properly after hitting enter.
|
||||
* Added: Support for browsing .tar.gz and .zip files in the editor
|
||||
* Added: TODO/FIXME/CHANGED are now highlighted in comments.
|
||||
* Fixed: Full screen state of windows is now persisted across restarts.
|
||||
* Added: Makefile syntax highlighting now included.
|
||||
* Added: Open fuzzy finder to specific line using colon suffix (i.e ':25')
|
||||
* Fixed: Issues deleting and moving over certain UTF-8 characters
|
||||
* Fixed: Tree view not properly highlighting or revealing for open images.
|
||||
* Added: Packages can now be installed from the configuration UI.
|
||||
* Fixed: .git folder now ignored by default when searching
|
||||
|
||||
* Fixed: Not being able to disable packages from configuration UI.
|
||||
* Fixed: Fuzzy finder showing poor results for entered text
|
||||
* Improved: App icon
|
||||
|
||||
* Fixed: Fuzzy finder being empty sometimes
|
||||
|
||||
* Improved: App icon
|
||||
* Fixed: End of line invisibles rendering incorrectly with the indent guide
|
||||
* Fixed: Updates not installing automatically on restart
|
||||
* Fixed: Wrap guide not displaying
|
||||
* Fixed: Error when saving with the markdown preview focused
|
||||
|
||||
* Fixed: Atom always running in dev mode
|
||||
* Fixed: Crash when running in dev mode without a path to the Atom source
|
||||
|
||||
* Fixed: Freeze when editing a RoR class
|
||||
* Added: meta-N to open a new untitled editor in the current window
|
||||
|
||||
* Fixed: Styling in command logger
|
||||
* Added: XML and Ruby syntax highlighting in Markdown files
|
||||
* Fixed: Error when editing files in a HEAD-less Git repository
|
||||
|
||||
* Fixed: Invisible characters not being visible when enabled
|
||||
* Added: Editor gutter now displays Git status for lines
|
||||
|
||||
* Improved: Startup time
|
||||
* Added: SQL bundle now included
|
||||
* Added: PEG.js bundle now included
|
||||
* Added: Hyperlinks can now be opened with ctrl-O
|
||||
* Fixed: PHP syntax highlighting
|
||||
+9
-4
@@ -10,10 +10,8 @@
|
||||
* Check the Dev tools (`alt-cmd-i`) for errors and stack traces to include
|
||||
|
||||
## Code
|
||||
* Follow the [JavaScript](https://github.com/styleguide/javascript),
|
||||
[CSS](https://github.com/styleguide/css),
|
||||
and [Objective-C](https://github.com/github/objective-c-conventions)
|
||||
styleguides
|
||||
* Follow the [JavaScript](https://github.com/styleguide/javascript) and
|
||||
[CSS](https://github.com/styleguide/css) styleguides
|
||||
* Include thoughtfully worded [Jasmine](http://pivotal.github.com/jasmine/)
|
||||
specs
|
||||
* Add 3rd-party packages as a `package.json` dependency
|
||||
@@ -28,6 +26,13 @@
|
||||
* Class methods (methods starting with a `@`)
|
||||
* Instance variables
|
||||
* Instance methods
|
||||
* Beware of platform differences
|
||||
* The home directory is `process.env.USERPROFILE` on Windows, while on OS X
|
||||
and Linux it's `process.env.HOME`
|
||||
* Path separator is `\` on Windows, and is `/` on OS X and Linux, so use
|
||||
`path.join` to concatenate filenames
|
||||
* Temporary directory is not `/tmp` on Windows, use `os.tmpdir()` when
|
||||
possible
|
||||
|
||||
## Philosophy
|
||||
|
||||
|
||||
+28
-18
@@ -1,19 +1,35 @@
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
os = require 'os'
|
||||
|
||||
fm = require 'json-front-matter'
|
||||
_ = require 'underscore'
|
||||
_ = require 'underscore-plus'
|
||||
|
||||
packageJson = require './package.json'
|
||||
|
||||
module.exports = (grunt) ->
|
||||
appName = 'Atom.app'
|
||||
if not grunt.option('verbose')
|
||||
grunt.log.writeln = (args...) -> grunt.log
|
||||
grunt.log.write = (args...) -> grunt.log
|
||||
|
||||
[major, minor, patch] = packageJson.version.split('.')
|
||||
buildDir = grunt.option('build-dir') ? '/tmp/atom-build'
|
||||
shellAppDir = path.join(buildDir, appName)
|
||||
contentsDir = path.join(shellAppDir, 'Contents')
|
||||
appDir = path.join(contentsDir, 'Resources', 'app')
|
||||
installDir = path.join('/Applications', appName)
|
||||
if process.platform is 'win32'
|
||||
appName = 'Atom'
|
||||
tmpDir = os.tmpdir()
|
||||
installRoot = process.env.ProgramFiles
|
||||
buildDir = grunt.option('build-dir') ? path.join(tmpDir, 'atom-build')
|
||||
shellAppDir = path.join(buildDir, appName)
|
||||
appDir = path.join(shellAppDir, 'resources', 'app')
|
||||
else
|
||||
appName = 'Atom.app'
|
||||
tmpDir = '/tmp'
|
||||
installRoot = '/Applications'
|
||||
buildDir = grunt.option('build-dir') ? path.join(tmpDir, 'atom-build')
|
||||
shellAppDir = path.join(buildDir, appName)
|
||||
contentsDir = path.join(shellAppDir, 'Contents')
|
||||
appDir = path.join(contentsDir, 'Resources', 'app')
|
||||
|
||||
installDir = path.join(installRoot, appName)
|
||||
|
||||
coffeeConfig =
|
||||
options:
|
||||
@@ -54,6 +70,7 @@ module.exports = (grunt) ->
|
||||
glob_to_multiple:
|
||||
expand: true
|
||||
src: [
|
||||
'menus/*.cson'
|
||||
'keymaps/*.cson'
|
||||
'static/**/*.cson'
|
||||
]
|
||||
@@ -88,6 +105,8 @@ module.exports = (grunt) ->
|
||||
level: 'error'
|
||||
max_line_length:
|
||||
level: 'ignore'
|
||||
indentation:
|
||||
level: 'ignore'
|
||||
src: [
|
||||
'dot-atom/**/*.coffee'
|
||||
'exports/**/*.coffee'
|
||||
@@ -157,15 +176,6 @@ module.exports = (grunt) ->
|
||||
stderr: false
|
||||
failOnError: false
|
||||
|
||||
test:
|
||||
command: "#{path.join(contentsDir, 'MacOS', 'Atom')} --test --resource-path=#{__dirname}"
|
||||
options:
|
||||
stdout: true
|
||||
stderr: true
|
||||
callback: (error, stdout, stderr, callback) ->
|
||||
grunt.warn('Specs failed') if error?
|
||||
callback()
|
||||
|
||||
grunt.loadNpmTasks('grunt-coffeelint')
|
||||
grunt.loadNpmTasks('grunt-lesslint')
|
||||
grunt.loadNpmTasks('grunt-cson')
|
||||
@@ -178,8 +188,8 @@ module.exports = (grunt) ->
|
||||
|
||||
grunt.registerTask('compile', ['coffee', 'prebuild-less', 'cson'])
|
||||
grunt.registerTask('lint', ['coffeelint', 'csslint', 'lesslint'])
|
||||
grunt.registerTask('test', ['shell:kill-atom', 'shell:test'])
|
||||
grunt.registerTask('ci', ['lint', 'update-atom-shell', 'build', 'set-development-version', 'test'])
|
||||
grunt.registerTask('test', ['shell:kill-atom', 'run-specs'])
|
||||
grunt.registerTask('ci', ['update-atom-shell', 'build', 'set-development-version', 'lint', 'test'])
|
||||
grunt.registerTask('deploy', ['partial-clean', 'update-atom-shell', 'build', 'codesign'])
|
||||
grunt.registerTask('docs', ['markdown:guides', 'build-docs'])
|
||||
grunt.registerTask('default', ['update-atom-shell', 'build', 'set-development-version', 'install'])
|
||||
|
||||
+5
-1
@@ -2,7 +2,7 @@
|
||||
|
||||

|
||||
|
||||
Check out our [guides](https://atom-docs.githubapp.com/v26.0/index.html) and [API documentation](https://atom-docs.githubapp.com/v26.0/api/index.html).
|
||||
Check out our [guides](https://www.atom.io/docs/latest/) and [API documentation](https://www.atom.io/docs/api/v34.0.0/api/)
|
||||
|
||||
## Installing
|
||||
|
||||
@@ -15,6 +15,7 @@ It will automatically update when a new release is available.
|
||||
### Requirements
|
||||
|
||||
* Mountain Lion
|
||||
* Looking for Windows support? Read [here][building].
|
||||
* Boxen (Obviously Atom won't release with this requirement)
|
||||
|
||||
### Installation
|
||||
@@ -24,3 +25,6 @@ It will automatically update when a new release is available.
|
||||
2. `cd ~/github/atom`
|
||||
|
||||
3. `script/build`
|
||||
|
||||
|
||||
[building]: https://github.com/atom/atom/blob/master/docs/building-atom.md
|
||||
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
#!/bin/sh
|
||||
ATOM_PATH=/Applications/Atom.app
|
||||
ATOM_PATH=${ATOM_PATH-/Applications/Atom.app}
|
||||
ATOM_BINARY=$ATOM_PATH/Contents/MacOS/Atom
|
||||
|
||||
if [ ! -d $ATOM_PATH ]; then sleep 5; fi # Wait for Atom to reappear, Sparkle may be replacing it.
|
||||
@@ -32,6 +32,7 @@ done
|
||||
|
||||
if [ $EXPECT_OUTPUT ]; then
|
||||
$ATOM_BINARY --executed-from="$(pwd)" --pid=$$ $@
|
||||
exit $?
|
||||
else
|
||||
open -a $ATOM_PATH -n --args --executed-from="$(pwd)" --pid=$$ $@
|
||||
fi
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
require '../src/window'
|
||||
Atom = require '../src/atom'
|
||||
window.atom = new Atom()
|
||||
atom = new Atom()
|
||||
atom.show() unless atom.getLoadSettings().exitWhenDone
|
||||
window.atom = atom
|
||||
|
||||
{runSpecSuite} = require '../spec/jasmine-helper'
|
||||
|
||||
atom.openDevTools()
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
require '../spec/spec-helper'
|
||||
|
||||
$ = require 'jquery'
|
||||
_ = require 'underscore'
|
||||
{Point} = require 'telepath'
|
||||
Project = require 'project'
|
||||
fsUtils = require 'fs-utils'
|
||||
TokenizedBuffer = require 'tokenized-buffer'
|
||||
path = require 'path'
|
||||
{$, _, Point, fs} = require 'atom'
|
||||
Project = require '../src/project'
|
||||
TokenizedBuffer = require '../src/tokenized-buffer'
|
||||
|
||||
defaultCount = 100
|
||||
window.pbenchmark = (args...) -> window.benchmark(args..., profile: true)
|
||||
@@ -13,7 +11,7 @@ window.fbenchmark = (args...) -> window.benchmark(args..., focused: true)
|
||||
window.fpbenchmark = (args...) -> window.benchmark(args..., profile: true, focused: true)
|
||||
window.pfbenchmark = window.fpbenchmark
|
||||
|
||||
window.benchmarkFixturesProject = new Project(fsUtils.resolveOnLoadPath('benchmark/fixtures'))
|
||||
window.benchmarkFixturesProject = new Project(path.join(__dirname, 'fixtures'))
|
||||
|
||||
beforeEach ->
|
||||
window.project = window.benchmarkFixturesProject
|
||||
@@ -75,8 +73,8 @@ window.clickEvent = (properties={}) ->
|
||||
|
||||
window.mouseEvent = (type, properties) ->
|
||||
if properties.point
|
||||
{point, editor} = properties
|
||||
{top, left} = @pagePixelPositionForPoint(editor, point)
|
||||
{point, editorView} = properties
|
||||
{top, left} = @pagePixelPositionForPoint(editorView, point)
|
||||
properties.pageX = left + 1
|
||||
properties.pageY = top + 1
|
||||
properties.originalEvent ?= {detail: 1}
|
||||
@@ -88,14 +86,14 @@ window.mousedownEvent = (properties={}) ->
|
||||
window.mousemoveEvent = (properties={}) ->
|
||||
window.mouseEvent('mousemove', properties)
|
||||
|
||||
window.pagePixelPositionForPoint = (editor, point) ->
|
||||
window.pagePixelPositionForPoint = (editorView, point) ->
|
||||
point = Point.fromObject point
|
||||
top = editor.lines.offset().top + point.row * editor.lineHeight
|
||||
left = editor.lines.offset().left + point.column * editor.charWidth - editor.lines.scrollLeft()
|
||||
top = editorView.lines.offset().top + point.row * editorView.lineHeight
|
||||
left = editorView.lines.offset().left + point.column * editorView.charWidth - editorView.lines.scrollLeft()
|
||||
{ top, left }
|
||||
|
||||
window.setEditorWidthInChars = (editor, widthInChars, charWidth=editor.charWidth) ->
|
||||
editor.width(charWidth * widthInChars + editor.lines.position().left)
|
||||
window.seteditorViewWidthInChars = (editorView, widthInChars, charWidth=editorView.charWidth) ->
|
||||
editorView.width(charWidth * widthInChars + editorView.lines.position().left)
|
||||
|
||||
$.fn.resultOfTrigger = (type) ->
|
||||
event = $.Event(type)
|
||||
|
||||
@@ -1,110 +1,217 @@
|
||||
require './benchmark-helper'
|
||||
$ = require 'jquery'
|
||||
_ = require 'underscore'
|
||||
TokenizedBuffer = require 'tokenized-buffer'
|
||||
RootView = require 'root-view'
|
||||
{$, _, RootView} = require 'atom'
|
||||
TokenizedBuffer = require '../src/tokenized-buffer'
|
||||
|
||||
describe "editor.", ->
|
||||
editor = null
|
||||
describe "editorView.", ->
|
||||
editorView = null
|
||||
|
||||
beforeEach ->
|
||||
window.rootViewParentSelector = '#jasmine-content'
|
||||
window.rootView = new RootView
|
||||
window.rootView.attachToDom()
|
||||
|
||||
|
||||
rootView.width(1024)
|
||||
rootView.height(768)
|
||||
rootView.open() # open blank editor
|
||||
editor = rootView.getActiveView()
|
||||
rootView.openSync()
|
||||
editorView = rootView.getActiveView()
|
||||
|
||||
afterEach ->
|
||||
if editor.pendingDisplayUpdate
|
||||
if editorView.pendingDisplayUpdate
|
||||
waitsFor "editor to finish rendering", (done) ->
|
||||
editor.on 'editor:display-updated', done
|
||||
editorView.on 'editor:display-updated', done
|
||||
|
||||
describe "keymap.", ->
|
||||
event = null
|
||||
|
||||
beforeEach ->
|
||||
event = keydownEvent('x', target: editor.hiddenInput[0])
|
||||
event = keydownEvent('x', target: editorView.hiddenInput[0])
|
||||
|
||||
benchmark "keydown-event-with-no-binding", 10, ->
|
||||
keymap.handleKeyEvent(event)
|
||||
|
||||
describe "opening-buffers.", ->
|
||||
benchmark "300-line-file.", ->
|
||||
buffer = project.bufferForPath('medium.coffee')
|
||||
buffer = project.bufferForPathSync('medium.coffee')
|
||||
|
||||
describe "empty-file.", ->
|
||||
benchmark "insert-delete", ->
|
||||
editor.insertText('x')
|
||||
editor.backspace()
|
||||
editorView.insertText('x')
|
||||
editorView.backspace()
|
||||
|
||||
describe "300-line-file.", ->
|
||||
beforeEach ->
|
||||
rootView.open('medium.coffee')
|
||||
rootView.openSync('medium.coffee')
|
||||
|
||||
describe "at-begining.", ->
|
||||
benchmark "insert-delete", ->
|
||||
editor.insertText('x')
|
||||
editor.backspace()
|
||||
editorView.insertText('x')
|
||||
editorView.backspace()
|
||||
|
||||
benchmark "insert-delete-rehighlight", ->
|
||||
editor.insertText('"')
|
||||
editor.backspace()
|
||||
editorView.insertText('"')
|
||||
editorView.backspace()
|
||||
|
||||
describe "at-end.", ->
|
||||
beforeEach ->
|
||||
editor.moveCursorToBottom()
|
||||
editorView.moveCursorToBottom()
|
||||
|
||||
benchmark "insert-delete", ->
|
||||
editor.insertText('"')
|
||||
editor.backspace()
|
||||
editorView.insertText('"')
|
||||
editorView.backspace()
|
||||
|
||||
describe "empty-vs-set-innerHTML.", ->
|
||||
[firstRow, lastRow] = []
|
||||
beforeEach ->
|
||||
firstRow = editorView.getFirstVisibleScreenRow()
|
||||
lastRow = editorView.getLastVisibleScreenRow()
|
||||
|
||||
benchmark "build-gutter-html.", 1000, ->
|
||||
editorView.gutter.renderLineNumbers(null, firstRow, lastRow)
|
||||
|
||||
benchmark "set-innerHTML.", 1000, ->
|
||||
editorView.gutter.renderLineNumbers(null, firstRow, lastRow)
|
||||
editorView.gutter.lineNumbers[0].innerHtml = ''
|
||||
|
||||
benchmark "empty.", 1000, ->
|
||||
editorView.gutter.renderLineNumbers(null, firstRow, lastRow)
|
||||
editorView.gutter.lineNumbers.empty()
|
||||
|
||||
describe "positionLeftForLineAndColumn.", ->
|
||||
line = null
|
||||
beforeEach ->
|
||||
editorView.scrollTop(2000)
|
||||
editorView.resetDisplay()
|
||||
line = editorView.lineElementForScreenRow(106)[0]
|
||||
|
||||
describe "one-line.", ->
|
||||
beforeEach ->
|
||||
editorView.clearCharacterWidthCache()
|
||||
|
||||
benchmark "uncached", 5000, ->
|
||||
editorView.positionLeftForLineAndColumn(line, 106, 82)
|
||||
editorView.clearCharacterWidthCache()
|
||||
|
||||
benchmark "cached", 5000, ->
|
||||
editorView.positionLeftForLineAndColumn(line, 106, 82)
|
||||
|
||||
describe "multiple-lines.", ->
|
||||
[firstRow, lastRow] = []
|
||||
beforeEach ->
|
||||
firstRow = editorView.getFirstVisibleScreenRow()
|
||||
lastRow = editorView.getLastVisibleScreenRow()
|
||||
|
||||
benchmark "cache-entire-visible-area", 100, ->
|
||||
for i in [firstRow..lastRow]
|
||||
line = editorView.lineElementForScreenRow(i)[0]
|
||||
editorView.positionLeftForLineAndColumn(line, i, Math.max(0, editorView.lineLengthForBufferRow(i)))
|
||||
|
||||
describe "text-rendering.", ->
|
||||
beforeEach ->
|
||||
editorView.scrollTop(2000)
|
||||
|
||||
benchmark "resetDisplay", 50, ->
|
||||
editorView.resetDisplay()
|
||||
|
||||
benchmark "htmlForScreenRows", 1000, ->
|
||||
lastRow = editorView.getLastScreenRow()
|
||||
editorView.htmlForScreenRows(0, lastRow)
|
||||
|
||||
benchmark "htmlForScreenRows.htmlParsing", 50, ->
|
||||
lastRow = editorView.getLastScreenRow()
|
||||
html = editorView.htmlForScreenRows(0, lastRow)
|
||||
|
||||
div = document.createElement('div')
|
||||
div.innerHTML = html
|
||||
|
||||
describe "gutter-api.", ->
|
||||
describe "getLineNumberElementsForClass.", ->
|
||||
beforeEach ->
|
||||
editorView.gutter.addClassToLine(20, 'omgwow')
|
||||
editorView.gutter.addClassToLine(40, 'omgwow')
|
||||
|
||||
benchmark "DOM", 20000, ->
|
||||
editorView.gutter.getLineNumberElementsForClass('omgwow')
|
||||
|
||||
benchmark "getLineNumberElement.DOM", 20000, ->
|
||||
editorView.gutter.getLineNumberElement(12)
|
||||
|
||||
benchmark "toggle-class", 2000, ->
|
||||
editorView.gutter.addClassToLine(40, 'omgwow')
|
||||
editorView.gutter.removeClassFromLine(40, 'omgwow')
|
||||
|
||||
describe "find-then-unset.", ->
|
||||
classes = ['one', 'two', 'three', 'four']
|
||||
|
||||
benchmark "single-class", 200, ->
|
||||
editorView.gutter.addClassToLine(30, 'omgwow')
|
||||
editorView.gutter.addClassToLine(40, 'omgwow')
|
||||
editorView.gutter.removeClassFromAllLines('omgwow')
|
||||
|
||||
benchmark "multiple-class", 200, ->
|
||||
editorView.gutter.addClassToLine(30, 'one')
|
||||
editorView.gutter.addClassToLine(30, 'two')
|
||||
|
||||
editorView.gutter.addClassToLine(40, 'two')
|
||||
editorView.gutter.addClassToLine(40, 'three')
|
||||
editorView.gutter.addClassToLine(40, 'four')
|
||||
|
||||
for klass in classes
|
||||
editorView.gutter.removeClassFromAllLines(klass)
|
||||
|
||||
describe "line-htmlification.", ->
|
||||
div = null
|
||||
html = null
|
||||
beforeEach ->
|
||||
lastRow = editorView.getLastScreenRow()
|
||||
html = editorView.htmlForScreenRows(0, lastRow)
|
||||
div = document.createElement('div')
|
||||
|
||||
benchmark "setInnerHTML", 1, ->
|
||||
div.innerHTML = html
|
||||
|
||||
describe "9000-line-file.", ->
|
||||
benchmark "opening.", 5, ->
|
||||
rootView.open('huge.js')
|
||||
rootView.openSync('huge.js')
|
||||
|
||||
describe "after-opening.", ->
|
||||
beforeEach ->
|
||||
rootView.open('huge.js')
|
||||
rootView.openSync('huge.js')
|
||||
|
||||
benchmark "moving-to-eof.", 1, ->
|
||||
editor.moveCursorToBottom()
|
||||
editorView.moveCursorToBottom()
|
||||
|
||||
describe "on-first-line.", ->
|
||||
benchmark "inserting-newline", 5, ->
|
||||
editor.insertNewline()
|
||||
editorView.insertNewline()
|
||||
|
||||
describe "on-last-visible-line.", ->
|
||||
beforeEach ->
|
||||
editor.setCursorScreenPosition([editor.getLastVisibleScreenRow(), 0])
|
||||
editorView.setCursorScreenPosition([editorView.getLastVisibleScreenRow(), 0])
|
||||
|
||||
benchmark "move-down-and-scroll", 300, ->
|
||||
editor.trigger 'move-down'
|
||||
editorView.trigger 'move-down'
|
||||
|
||||
describe "at-eof.", ->
|
||||
endPosition = null
|
||||
|
||||
beforeEach ->
|
||||
editor.moveCursorToBottom()
|
||||
endPosition = editor.getCursorScreenPosition()
|
||||
editorView.moveCursorToBottom()
|
||||
endPosition = editorView.getCursorScreenPosition()
|
||||
|
||||
benchmark "move-to-beginning-of-word", ->
|
||||
editor.moveCursorToBeginningOfWord()
|
||||
editor.setCursorScreenPosition(endPosition)
|
||||
editorView.moveCursorToBeginningOfWord()
|
||||
editorView.setCursorScreenPosition(endPosition)
|
||||
|
||||
benchmark "insert", ->
|
||||
editor.insertText('x')
|
||||
editorView.insertText('x')
|
||||
|
||||
describe "TokenizedBuffer.", ->
|
||||
describe "coffee-script-grammar.", ->
|
||||
[languageMode, buffer] = []
|
||||
|
||||
beforeEach ->
|
||||
editSession = benchmarkFixturesProject.open('medium.coffee')
|
||||
{ languageMode, buffer } = editSession
|
||||
editor = benchmarkFixturesProject.openSync('medium.coffee')
|
||||
{ languageMode, buffer } = editor
|
||||
|
||||
benchmark "construction", 20, ->
|
||||
new TokenizedBuffer(buffer, { languageMode, tabLength: 2})
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
## Building Atom
|
||||
|
||||
These guide is meant only for users who wish to help develop atom core,
|
||||
if you're just interested in using atom you should just [download
|
||||
atom][download].
|
||||
|
||||
## OSX
|
||||
|
||||
* Use Mountain Lion
|
||||
* Install the latest node 0.10.x release (32bit preferable)
|
||||
* Clone [atom][atom-git] to `~/github/atom`
|
||||
* Run `~/github/atom/script/bootstrap`
|
||||
|
||||
## Windows
|
||||
|
||||
* Install [Visual C++ 2010 Express][win-vs2010]
|
||||
* Install the [latest 32bit Node 0.10.x][win-node]
|
||||
* Install the [latest Python 2.7.x][win-python]
|
||||
* Install [GitHub for Windows][win-github]
|
||||
* Clone [atom/atom][atom-git] to `C:\Users\<user>\github\atom\`
|
||||
* Add `C:\Python27;C:\Program Files\nodejs;C:\Users\<user>\github\atom\node_modules\`
|
||||
to your PATH
|
||||
* Set ATOM_ACCESS_TOKEN to your oauth2 credentials (run `security -q
|
||||
find-generic-password -ws 'GitHub API Token'` on OSX to get your
|
||||
credentials).
|
||||
* Use the Windows GitHub shell and cd into `C:\Users\<user>\github\atom`
|
||||
* Run `script\bootstrap`
|
||||
|
||||
[download]: http://www.atom.io
|
||||
[win-node]: http://nodejs.org/download/
|
||||
[win-python]: http://www.python.org/download/
|
||||
[win-github]: http://windows.github.com/
|
||||
[win-vs2010]: http://www.microsoft.com/visualstudio/eng/products/visual-studio-2010-express
|
||||
[atom-git]: https://github.com/atom/atom/
|
||||
+195
-356
@@ -1,76 +1,56 @@
|
||||
{{{
|
||||
"title": "Creating a Package"
|
||||
}}}
|
||||
# Creating Packages
|
||||
|
||||
# Authoring Packages
|
||||
|
||||
Packages are at the core of Atom. Nearly everything outside of the main editor manipulation
|
||||
is handled by a package. That includes "core" pieces like the command panel, status bar,
|
||||
file tree, and more.
|
||||
Packages are at the core of Atom. Nearly everything outside of the main editor
|
||||
is handled by a package. That includes "core" pieces like the [file tree][file-tree],
|
||||
[status bar][status-bar], [syntax highlighting][cs-syntax], and more.
|
||||
|
||||
A package can contain a variety of different resource types to change Atom's
|
||||
behavior. The basic package layout is as follows (though not every package will
|
||||
have all of these directories):
|
||||
behavior. The basic package layout is as follows:
|
||||
|
||||
```text
|
||||
my-package/
|
||||
lib/
|
||||
stylesheets/
|
||||
keymaps/
|
||||
snippets/
|
||||
grammars/
|
||||
keymaps/
|
||||
lib/
|
||||
menus/
|
||||
spec/
|
||||
package.json
|
||||
snippets/
|
||||
stylesheets/
|
||||
index.coffee
|
||||
package.json
|
||||
```
|
||||
|
||||
## Publishing
|
||||
Not every package will have (or need) all of these directories.
|
||||
|
||||
Atom bundles a command line utility called [apm](http://github.com/atom/apm)
|
||||
which can be used to publish Atom packages to the public registry.
|
||||
|
||||
Once your package is written and ready for distribution you can run the
|
||||
following to publish your package:
|
||||
|
||||
```sh
|
||||
cd my-package
|
||||
apm publish minor
|
||||
```
|
||||
|
||||
This will update your `package.json` to have a new minor `version`, commit
|
||||
the change, create a new [Git tag](http://git-scm.com/book/en/Git-Basics-Tagging),
|
||||
and then upload the package to the registry.
|
||||
|
||||
Run `apm help publish` to see all the available options and `apm help` to see
|
||||
all the other available commands.
|
||||
We have [a tutorial on creating your first package][first-package].
|
||||
|
||||
## package.json
|
||||
|
||||
Similar to [npm packages][npm], Atom packages
|
||||
can contain a _package.json_ file in their top-level directory. This file contains metadata
|
||||
about the package, such as the path to its "main" module, library dependencies,
|
||||
and manifests specifying the order in which its resources should be loaded.
|
||||
Similar to [npm packages][npm], Atom packages contain a _package.json_ file
|
||||
in their top-level directory. This file contains metadata about the package,
|
||||
such as the path to its "main" module, library dependencies, and manifests
|
||||
specifying the order in which its resources should be loaded.
|
||||
|
||||
In addition to the regular [npm package.json keys](https://npmjs.org/doc/json.html)
|
||||
available, Atom package.json files have their own additions.
|
||||
In addition to the regular [npm package.json keys][npm-keys] available, Atom
|
||||
package.json files have their own additions.
|
||||
|
||||
- `main` (**Required**): the path to the CoffeeScript file that's the entry point
|
||||
to your package
|
||||
- `stylesheets` (**Optional**): an Array of Strings identifying the order of the
|
||||
stylesheets your package needs to load. If not specified, stylesheets in the _stylesheets_
|
||||
directory are added alphabetically.
|
||||
stylesheets your package needs to load. If not specified, stylesheets in the
|
||||
_stylesheets_ directory are added alphabetically.
|
||||
- `keymaps`(**Optional**): an Array of Strings identifying the order of the
|
||||
key mappings your package needs to load. If not specified, mappings in the _keymaps_
|
||||
directory are added alphabetically.
|
||||
key mappings your package needs to load. If not specified, mappings in the
|
||||
_keymaps_ directory are added alphabetically.
|
||||
- `menus`(**Optional**): an Array of Strings identifying the order of
|
||||
the menu mappings your package needs to load. If not specified, mappings
|
||||
in the _keymap_ directory are added alphabetically.
|
||||
- `snippets` (**Optional**): an Array of Strings identifying the order of the
|
||||
snippets your package needs to load. If not specified, snippets in the _snippets_
|
||||
directory are added alphabetically.
|
||||
snippets your package needs to load. If not specified, snippets in the
|
||||
_snippets_ directory are added alphabetically.
|
||||
- `activationEvents` (**Optional**): an Array of Strings identifying events that
|
||||
trigger your package's activation. You can delay the loading of your package until
|
||||
one of these events is trigged.
|
||||
trigger your package's activation. You can delay the loading of your package
|
||||
until one of these events is trigged.
|
||||
|
||||
## Source Code
|
||||
|
||||
@@ -106,20 +86,22 @@ you don't need to worry because that's getting torn down anyway.
|
||||
|
||||
### Simple Package Code
|
||||
|
||||
Your directory would look like this:
|
||||
|
||||
```text
|
||||
my-package/
|
||||
package.json # optional
|
||||
package.json
|
||||
index.coffee
|
||||
lib/
|
||||
my-package.coffee
|
||||
```
|
||||
|
||||
`index.coffee`:
|
||||
`index.coffee` might be:
|
||||
```coffeescript
|
||||
module.exports = require "./lib/my-package"
|
||||
```
|
||||
|
||||
`my-package/my-package.coffee`:
|
||||
`my-package/my-package.coffee` might start:
|
||||
```coffeescript
|
||||
module.exports =
|
||||
activate: (rootView, state) -> # ...
|
||||
@@ -127,57 +109,100 @@ module.exports =
|
||||
serialize: -> # ...
|
||||
```
|
||||
|
||||
Beyond this simple contract, your package has full access to Atom's internal
|
||||
API. Anything we call internally, you can call as well. Be aware that since we
|
||||
are early in development, APIs are subject to change and we have not yet
|
||||
established clear boundaries between what is public and what is private. Also,
|
||||
please collaborate with us if you need an API that doesn't exist. Our goal is
|
||||
to build out Atom's API organically based on the needs of package authors like
|
||||
you.
|
||||
|
||||
See [Atom's built-in packages](https://github.com/atom/atom/)
|
||||
for examples of Atom's API in action.
|
||||
Beyond this simple contract, your package has access to Atom's API. Be aware
|
||||
that since we are early in development, APIs are subject to change and we have
|
||||
not yet established clear boundaries between what is public and what is private.
|
||||
Also, please collaborate with us if you need an API that doesn't exist. Our goal
|
||||
is to build out Atom's API organically based on the needs of package authors
|
||||
like you.
|
||||
|
||||
## Stylesheets
|
||||
|
||||
Stylesheets for your package should be placed in the _stylesheets_ directory.
|
||||
Any stylesheets in this directory will be loaded and attached to the DOM when
|
||||
your package is activated. Stylesheets can be written as CSS or LESS.
|
||||
your package is activated. Stylesheets can be written as CSS or [LESS] (but LESS
|
||||
is recommended).
|
||||
|
||||
An optional `stylesheets` array in your _package.json_ can list the stylesheets by
|
||||
name to specify a loading order; otherwise, stylesheets are loaded alphabetically.
|
||||
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-p`) and search for _styleguide_,
|
||||
or just type `cmd-ctrl-G`.
|
||||
|
||||
If you _do_ need special styling, try to keep only structural styles in the package
|
||||
stylesheets. If you _must_ specify colors and sizing, these should be taken from
|
||||
the active theme's [ui-variables.less][ui-variables]. For more information, see the
|
||||
[theme variables docs][theme-variables]. If you follow this guideline, your package
|
||||
will look good out of the box with any theme!
|
||||
|
||||
An optional `stylesheets` array in your _package.json_ can list the stylesheets
|
||||
by name to specify a loading order; otherwise, stylesheets are loaded
|
||||
alphabetically.
|
||||
|
||||
## Keymaps
|
||||
|
||||
Keymaps are placed in the _keymaps_ subdirectory. It's a good idea to provide
|
||||
default keymaps for your extension, especially if you're also adding a new command.
|
||||
It's recommended that you provide key bindings for commonly used actions for
|
||||
your extension, especially if you're also adding a new command:
|
||||
|
||||
By default, all keymaps are loaded in alphabetical order. An optional `keymaps`
|
||||
array in your _package.json_ can specify which keymaps to load and in what order.
|
||||
```coffeescript
|
||||
'.tree-view-scroller':
|
||||
'ctrl-V': 'changer:magic'
|
||||
```
|
||||
|
||||
See the [main keymaps documentation](../internals/keymaps.md) for more information on
|
||||
Keymaps are placed in the _keymaps_ subdirectory. By default, all keymaps are
|
||||
loaded in alphabetical order. An optional `keymaps` array in your _package.json_
|
||||
can specify which keymaps to load and in what order.
|
||||
|
||||
|
||||
Keybindings are executed by determining which element the keypress occured on. In
|
||||
the example above, `changer:magic` command is executed when pressing `ctrl-V` on
|
||||
the `.tree-view-scroller` element.
|
||||
|
||||
See the [main keymaps documentation][keymaps] for more detailed information on
|
||||
how keymaps work.
|
||||
|
||||
## Menus
|
||||
|
||||
Menus are placed in the _menus_ subdirectory. It's useful to specify a
|
||||
context menu items if if commands are linked to a specific part of the
|
||||
interface, say for example adding a file in the tree-view.
|
||||
Menus are placed in the _menus_ subdirectory. By default, all menus are loaded
|
||||
in alphabetical order. An optional `menus` array in your _package.json_ can
|
||||
specify which menus to load and in what order.
|
||||
|
||||
By default, all menus are loaded in alphabetical order. An optional
|
||||
`menus` array in your _package.json_ can specify which menus to load
|
||||
and in what order.
|
||||
### Application Menu
|
||||
|
||||
Context menus are created by determining which element was selected and
|
||||
then adding all of the menu items whose selectors match that element (in
|
||||
the order which they were loaded). The process is then repeated for the
|
||||
elements until reaching the top of the dom tree.
|
||||
|
||||
NOTE: Currently you can only specify items to be added to the context
|
||||
menu, the menu which appears when you right click. There are plans to
|
||||
add support for adding to global menu.
|
||||
It's recommended that you create an application menu item for common actions
|
||||
with your package that aren't tied to a specific element:
|
||||
|
||||
```coffee-script
|
||||
'menu': [
|
||||
{
|
||||
'label': 'Packages'
|
||||
'submenu': [
|
||||
{
|
||||
'label': 'My Package'
|
||||
'submenu': [
|
||||
{
|
||||
'label': 'Toggle'
|
||||
'command': 'my-package:toggle'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
To add your own item to the application menu, simply create a top level `menu`
|
||||
key in any menu configuration file in _menus_. This can be a JSON or [CSON] file.
|
||||
|
||||
The menu templates you specify are merged with all other templates provided
|
||||
by other packages in the order which they were loaded.
|
||||
|
||||
### Context Menu
|
||||
|
||||
It's recommended to specify a context menu item for commands that are linked to
|
||||
specific parts of the interface, like adding a file in the tree-view:
|
||||
|
||||
```coffee-script
|
||||
'context-menu':
|
||||
'.tree-view':
|
||||
'Add file': 'tree-view:add-file'
|
||||
@@ -185,10 +210,22 @@ add support for adding to global menu.
|
||||
'Inspect Element': 'core:inspect'
|
||||
```
|
||||
|
||||
To add your own item to the application menu simply create a top level
|
||||
`context-menu` key in any menu configuration file in _menus_. This can be a
|
||||
JSON or [CSON] file.
|
||||
|
||||
Context menus are created by determining which element was selected and
|
||||
then adding all of the menu items whose selectors match that element (in
|
||||
the order which they were loaded). The process is then repeated for the
|
||||
elements until reaching the top of the DOM tree.
|
||||
|
||||
In the example above, the `Add file` item will only appear when the focused item
|
||||
or one of its parents has the `tree-view` class applied to it.
|
||||
|
||||
## Snippets
|
||||
|
||||
An extension can supply language snippets in the _snippets_ directory. These can
|
||||
be `.cson` or `.json` files. Here's an example:
|
||||
An extension can supply language snippets in the _snippets_ directory which
|
||||
allows the user to enter repetitive text quickly:
|
||||
|
||||
```coffeescript
|
||||
".source.coffee .specs":
|
||||
@@ -203,24 +240,26 @@ be `.cson` or `.json` files. Here's an example:
|
||||
"""
|
||||
```
|
||||
|
||||
A snippets file contains scope selectors at its top level (`.source.coffee .spec`).
|
||||
Each scope selector contains a hash of snippets keyed by their name (`Expect`, `Describe`).
|
||||
Each snippet also specifies a `prefix` and a `body` key. The `prefix` represents
|
||||
the first few letters to type before hitting the `tab` key to autocomplete. The
|
||||
`body` defines the autofilled text. You can use placeholders like `$1`, `$2`, to indicate
|
||||
regions in the body the user can navigate to every time they hit `tab`.
|
||||
A snippets file contains scope selectors at its top level (`.source.coffee
|
||||
.spec`). Each scope selector contains a hash of snippets keyed by their name
|
||||
(`Expect`, `Describe`). Each snippet also specifies a `prefix` and a `body` key.
|
||||
The `prefix` represents the first few letters to type before hitting the `tab`
|
||||
key to autocomplete. The `body` defines the autofilled text. You can use
|
||||
placeholders like `$1`, `$2`, to indicate regions in the body the user can
|
||||
navigate to every time they hit `tab`.
|
||||
|
||||
All files in the directory are automatically loaded, unless the
|
||||
_package.json_ supplies a `snippets` key. As with all scoped
|
||||
items, snippets loaded later take precedence over earlier snippets when two
|
||||
snippets match a scope with the same specificity.
|
||||
All files in the directory are automatically loaded, unless the _package.json_
|
||||
supplies a `snippets` key. As with all scoped items, snippets loaded later take
|
||||
precedence over earlier snippets when two snippets match a scope with the same
|
||||
specificity.
|
||||
|
||||
## Language Grammars
|
||||
|
||||
If you're developing a new language grammar, you'll want to place your file in
|
||||
the _grammars_ directory. Each grammar is a pairing of two keys, `match` and
|
||||
`captures`. `match` is a regular expression identifying the pattern to highlight,
|
||||
while `captures` is an object representing what to do with each matching group.
|
||||
`captures`. `match` is a regular expression identifying the pattern to
|
||||
highlight, while `captures` is an object representing what to do with each
|
||||
matching group.
|
||||
|
||||
For example:
|
||||
|
||||
@@ -245,14 +284,14 @@ To capture a single group, simply use the `name` key instead:
|
||||
}
|
||||
```
|
||||
|
||||
This indicates that Markdown header lines (`#`, `##`, `###`) should be applied with
|
||||
the `markup.heading.gfm` token.
|
||||
This indicates that Markdown header lines (`#`, `##`, `###`) should be applied
|
||||
with the `markup.heading.gfm` token.
|
||||
|
||||
More information about the significance of these tokens can be found in
|
||||
[section 12.4 of the TextMate Manual](http://manual.macromates.com/en/language_grammars.html).
|
||||
[section 12.4 of the TextMate Manual][tm-tokens].
|
||||
|
||||
Your grammar should also include a `filetypes` array, which is a list of file extensions
|
||||
your grammar supports:
|
||||
Your grammar should also include a `filetypes` array, which is a list of file
|
||||
extensions your grammar supports:
|
||||
|
||||
```coffeescript
|
||||
'fileTypes': [
|
||||
@@ -279,278 +318,78 @@ You can also use the `atom` protocol URLs in themes.
|
||||
|
||||
## Writing Tests
|
||||
|
||||
Your package **should** have tests, and if they're placed in the _spec_ directory,
|
||||
they can be run by Atom.
|
||||
Your package **should** have tests, and if they're placed in the _spec_
|
||||
directory, they can be run by Atom.
|
||||
|
||||
Under the hood, [Jasmine](https://github.com/pivotal/jasmine) is being used to
|
||||
execute the tests, so you can assume that any DSL available there is available
|
||||
to your package as well.
|
||||
Under the hood, [Jasmine] executes your tests, so you can assume that any DSL
|
||||
available there is available to your package as well.
|
||||
|
||||
# Full Example
|
||||
**FIXME: Explain the following**
|
||||
|
||||
Let's take a look at creating our first package.
|
||||
* jasmine
|
||||
* jasmine-focused
|
||||
* `spec/fixtures` and global.project
|
||||
* setTimeout
|
||||
* whatever else is different in spec-helper
|
||||
|
||||
Atom has a command you can enter that'll create a package for you:
|
||||
`package-generator:generate`. Otherwise, you can hit `cmd-p`, and start typing
|
||||
"Package Generator." Once you activate this package, it'll ask you for a name for
|
||||
your new package. Let's call ours _changer_.
|
||||
## Running Tests
|
||||
|
||||
Now, _changer_ is going to have a default set of folders and files created for us.
|
||||
Hit `cmd-r` to reload Atom, then hit `cmd-p` and start typing "Changer." You'll
|
||||
see a new `Changer:Toggle` command which, if selected, pops up a new message. So
|
||||
far, so good!
|
||||
TODO: Probably use the menu option now.
|
||||
|
||||
In order to demonstrate the capabilities of Atom and its API, our Changer plugin
|
||||
is going to do two things:
|
||||
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.
|
||||
|
||||
1. It'll show only modified files in the file tree
|
||||
2. It'll append a new pane to the editor with some information about the modified
|
||||
files
|
||||
## Publishing
|
||||
|
||||
Let's get started!
|
||||
Atom bundles a command line utility called [apm] which can be used to publish
|
||||
Atom packages to the public registry.
|
||||
|
||||
## Changing Keybindings and Commands
|
||||
Once your package is written and ready for distribution you can run the
|
||||
following to publish your package:
|
||||
|
||||
Since Changer is primarily concerned with the file tree, let's write a keybinding
|
||||
that works only when the tree is focused. Instead of using the default `toggle`,
|
||||
our keybinding executes a new command called `magic`.
|
||||
|
||||
_keymaps/changer.cson_ can easily become this:
|
||||
|
||||
```coffeescript
|
||||
'.tree-view-scroller':
|
||||
'ctrl-V': 'changer:magic'
|
||||
```sh
|
||||
cd my-package
|
||||
apm publish minor
|
||||
```
|
||||
|
||||
Notice that the keybinding is called `ctrl-V`--that's actually `ctrl-shift-v`.
|
||||
You can use capital letters to denote using `shift` for your binding.
|
||||
This will update your `package.json` to have a new minor `version`, commit the
|
||||
change, create a new [Git tag][git-tag], and then upload the package to the
|
||||
registry.
|
||||
|
||||
`.tree-view-scroller` represents the parent container for the tree view. Keybindings
|
||||
only work within the context of where they're entered. For example, hitting `ctrl-V`
|
||||
anywhere other than tree won't do anything. You can map to `body` if you want
|
||||
to scope to anywhere in Atom, or just `.editor` for the editor portion.
|
||||
Run `apm help publish` to see all the available options and `apm help` to see
|
||||
all the other available commands.
|
||||
|
||||
To bind keybindings to a command, we'll use the `rootView.command` method. This
|
||||
takes a command name and executes a function in the code. For example:
|
||||
## Included Libraries
|
||||
|
||||
```coffeescript
|
||||
rootView.command "changer:magic", => @magic()
|
||||
```
|
||||
FIXME: Describe `require 'atom'
|
||||
|
||||
It's common practice to namespace your commands with your package name, and separate
|
||||
it with a colon (`:`). Rename the existing `toggle` method to `magic` to get the
|
||||
binding to work.
|
||||
In addition to core node.js modules, all packages can `require` the following
|
||||
popular libraries into their packages:
|
||||
|
||||
Reload the editor, click on the tree, hit your keybinding, and...nothing happens! What the heck?!
|
||||
|
||||
Open up the _package.json_ file, and notice the key that says `activationEvents`.
|
||||
Basically, this tells Atom to not load a package until it hears a certain event.
|
||||
Let's change the event to `changer:magic` and reload the editor.
|
||||
|
||||
Hitting the key binding on the tree now works!
|
||||
|
||||
## Working with styles
|
||||
|
||||
The next step is to hide elements in the tree that aren't modified. To do that,
|
||||
we'll first try and get a list of files that have not changed.
|
||||
|
||||
All packages are able to use jQuery in their code. In fact, we have [a list of
|
||||
some of the bundled libraries Atom provides by default](#included-libraries).
|
||||
|
||||
Let's bring in jQuery:
|
||||
|
||||
```coffeescript
|
||||
$ = require 'jquery'
|
||||
```
|
||||
|
||||
Now, we can query the tree to get us a list of every file that _wasn't_ modified:
|
||||
|
||||
```coffeescript
|
||||
magic: ->
|
||||
$('ol.entries li').each (i, el) ->
|
||||
if !$(el).hasClass("modified")
|
||||
console.log el
|
||||
```
|
||||
|
||||
You can access the dev console by hitting `alt-cmd-i`. When we execute the
|
||||
`changer:magic` command, the browser console lists the items that are not being
|
||||
modified. Let's add a class to each of these elements called `hide-me`:
|
||||
|
||||
```coffeescript
|
||||
magic: ->
|
||||
$('ol.entries li').each (i, el) ->
|
||||
if !$(el).hasClass("modified")
|
||||
$(el).addClass("hide-me")
|
||||
```
|
||||
|
||||
With our newly added class, we can manipulate the visibility of the elements
|
||||
with a simple stylesheet. Open up _changer.css_ in the _stylesheets_ directory,
|
||||
and add a single entry:
|
||||
|
||||
```css
|
||||
ol.entries .hide-me {
|
||||
display: none;
|
||||
}
|
||||
```
|
||||
|
||||
Refresh atom, and run the `changer` command. You'll see all the non-changed files
|
||||
disappear from the tree. There are a number of ways you can get the list back;
|
||||
let's just naively iterate over the same elements and remove the class:
|
||||
|
||||
```coffeescript
|
||||
magic: ->
|
||||
$('ol.entries li').each (i, el) ->
|
||||
if !$(el).hasClass("modified")
|
||||
if !$(el).hasClass("hide-me")
|
||||
$(el).addClass("hide-me")
|
||||
else
|
||||
$(el).removeClass("hide-me")
|
||||
```
|
||||
|
||||
## Creating a New Pane
|
||||
|
||||
The next goal of this package is to append a pane to the Atom editor that lists
|
||||
some information about the modified files.
|
||||
|
||||
To do that, we're going to first create a new class method called `content`. Every
|
||||
package that extends from the `View` class can provide an optional class method
|
||||
called `content`. The `content` method constructs the DOM that your package uses
|
||||
as its UI. The principals of `content` are built entirely on [SpacePen](https://github.com/nathansobo/space-pen),
|
||||
which we'll touch upon only briefly here.
|
||||
|
||||
Our display will simply be an unordered list of the file names, and their
|
||||
modified times. Let's start by carving out a `div` to hold the filenames:
|
||||
|
||||
```coffeescript
|
||||
@content: ->
|
||||
@div class: 'modified-files-container', =>
|
||||
@ul class: 'modified-files-list', outlet: 'modifiedFilesList', =>
|
||||
@li 'Test'
|
||||
@li 'Test2'
|
||||
```
|
||||
|
||||
You can add any HTML5 attribute you like. `outlet` names the variable
|
||||
your package can uses to manipulate the element directly. The fat pipe (`=>`) indicates
|
||||
that the next set are nested children.
|
||||
|
||||
We'll add one more line to `magic` to make this pane appear:
|
||||
|
||||
```coffeescript
|
||||
rootView.vertical.append(this)
|
||||
```
|
||||
|
||||
If you hit the key command, you'll see a box appear right underneath the editor.
|
||||
Success!
|
||||
|
||||
Before we populate this, let's apply some logic to toggle the pane off and on, just
|
||||
like we did with the tree view:
|
||||
|
||||
```coffeescript
|
||||
# toggles the pane
|
||||
if @hasParent()
|
||||
rootView.vertical.children().last().remove()
|
||||
else
|
||||
rootView.vertical.append(this)
|
||||
```
|
||||
|
||||
There are about a hundred different ways to toggle a pane on and off, and this
|
||||
might not be the most efficient one. If you know your package needs to be toggled
|
||||
on and off more freely, it might be better to draw the UI during the initialization,
|
||||
then immediately call `hide()` on the element to remove it from the view. You can
|
||||
then swap between `show()` and `hide()`, and instead of forcing Atom to add and remove
|
||||
the element as we're doing here, it'll just set a CSS property to control your package's
|
||||
visibility.
|
||||
|
||||
You might have noticed that our two `li` elements aren't showing up. Let's set
|
||||
a color on them so that they pop. Open up `changer.css` and add this CSS:
|
||||
|
||||
```css
|
||||
ul.modified-files-list {
|
||||
color: white;
|
||||
}
|
||||
```
|
||||
|
||||
Refresh Atom, hit the key combo, and see your brilliantly white test list.
|
||||
|
||||
## Calling Node.js Code
|
||||
|
||||
Since Atom is built on top of Node.js, you can call any of its libraries, including
|
||||
other modules that your package requires.
|
||||
|
||||
We'll iterate through our resulting tree, and construct the path to our modified
|
||||
file based on its depth in the tree:
|
||||
|
||||
```coffeescript
|
||||
path = require 'path'
|
||||
|
||||
# ...
|
||||
|
||||
modifiedFiles = []
|
||||
# for each single entry...
|
||||
$('ol.entries li.file.modified span.name').each (i, el) ->
|
||||
filePath = []
|
||||
# ...grab its name...
|
||||
filePath.unshift($(el).text())
|
||||
|
||||
# ... then find its parent directories, and grab their names
|
||||
parents = $(el).parents('.directory.modified')
|
||||
parents.each (i, el) ->
|
||||
filePath.unshift($(el).find('div.header span.name').eq(0).text())
|
||||
|
||||
modifiedFilePath = path.join(project.rootDirectory.path, filePath.join(path.sep))
|
||||
modifiedFiles.push modifiedFilePath
|
||||
```
|
||||
|
||||
`modifiedFiles` is an array containing a list of our modified files. We're also using
|
||||
the node.js [`path` library](http://nodejs.org/docs/latest/api/path.html) to get
|
||||
the proper directory separator for our system.
|
||||
|
||||
Let's remove the two `@li` elements we added in `@content`, so that we can populate
|
||||
our `modifiedFilesList` with real information. We'll do that by iterating over
|
||||
`modifiedFiles`, accessing a file's last modified time, and appending it to
|
||||
`modifiedFilesList`:
|
||||
|
||||
```coffeescript
|
||||
# toggles the pane
|
||||
if @hasParent()
|
||||
rootView.vertical.children().last().remove()
|
||||
else
|
||||
for file in modifiedFiles
|
||||
stat = fs.lstatSync(file)
|
||||
mtime = stat.mtime
|
||||
@modifiedFilesList.append("<li>#{file} - Modified at #{mtime}")
|
||||
rootView.vertical.append(this)
|
||||
```
|
||||
|
||||
When you toggle the modified files list, your pane is now populated with the filenames
|
||||
and modified times of files in your project. You might notice that subsequent calls
|
||||
to this command reduplicate information. We could provide an elegant way of rechecking
|
||||
files already in the list, but for this demonstration, we'll just clear the `modifiedFilesList`
|
||||
each time it's closed:
|
||||
|
||||
```coffeescript
|
||||
# toggles the pane
|
||||
if @hasParent()
|
||||
@modifiedFilesList.empty()
|
||||
rootView.vertical.children().last().remove()
|
||||
else
|
||||
for file in modifiedFiles
|
||||
stat = fs.lstatSync(file)
|
||||
mtime = stat.mtime
|
||||
@modifiedFilesList.append("<li>#{file} - Modified at #{mtime}")
|
||||
rootView.vertical.append(this)
|
||||
```
|
||||
|
||||
# Included Libraries
|
||||
|
||||
In addition to core node.js modules, all packages can `require` the following popular
|
||||
libraries into their packages:
|
||||
|
||||
* [SpacePen](https://github.com/nathansobo/space-pen) (as `require 'space-pen'`)
|
||||
* [jQuery](http://jquery.com/) (as `require 'jquery'`)
|
||||
* [Underscore](http://underscorejs.org/) (as `require 'underscore'`)
|
||||
|
||||
Additional libraries can be found by browsing Atom's _node_modules_ folder.
|
||||
* [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]: internals/keymaps.md
|
||||
[theme-variables]: theme-variables.md
|
||||
[tm-tokens]: http://manual.macromates.com/en/language_grammars.html
|
||||
[spacepen]: https://github.com/nathansobo/space-pen
|
||||
[path]: http://nodejs.org/docs/latest/api/path.html
|
||||
[jquery]: http://jquery.com/
|
||||
[underscore]: http://underscorejs.org/
|
||||
[jasmine]: https://github.com/pivotal/jasmine
|
||||
[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
|
||||
|
||||
+117
-58
@@ -1,76 +1,135 @@
|
||||
{{{
|
||||
"title": "Creating a Theme"
|
||||
}}}
|
||||
|
||||
# Creating a Theme
|
||||
|
||||
## Overview
|
||||
Atom's interface is rendered using HTML, and it's styled via [LESS] (a superset
|
||||
of CSS). Don't worry if you haven't heard of LESS before; it's just like CSS, but
|
||||
with a few handy extensions.
|
||||
|
||||
* Explain the difference between ui themes and syntax themes
|
||||
Since CSS is the basis of the theming system, we can load multiple themes within
|
||||
Atom, and the themes behave just as they would on a website. Themes loaded first
|
||||
are overridden by themes which are loaded later. The order of theme loading is
|
||||
controlled within the Settings/Themes pane.
|
||||
|
||||
This flexibility is helpful for users that prefer a light interface with a dark
|
||||
syntax theme. Atom currently has only interface and syntax themes, but it is
|
||||
possible to create a theme to style something specific — say, changing
|
||||
the colors in the tree view or creating a language specific syntax theme.
|
||||
|
||||
## Getting Started
|
||||
|
||||
* What do I need to install?
|
||||
* Atom - to edit text
|
||||
* Git - to track and distribute your themes
|
||||
* What do I need to know?
|
||||
* CSS/LESS - as that's what themes are written in
|
||||
* Devtools - so you can find the selector you're looking for.
|
||||
* Is there an example I can start from?
|
||||
* Yes, you can clone https://github.com/atom/solarized-dark-syntax
|
||||
Themes are pretty straight forward but it's still helpful to be familiar with
|
||||
a few things before starting:
|
||||
|
||||
# Create a minimal syntax theme
|
||||
* LESS is a superset of CSS, but it has some really handy features like
|
||||
variables. If you aren't familiar with its syntax take a few minutes
|
||||
to [familiarize yourself][less-tutorial].
|
||||
* You may also want to review the concept of a _[package.json]_, too. This file
|
||||
is used to help distribute your theme to Atom users.
|
||||
|
||||
```bash
|
||||
cd ~/.atom/packages
|
||||
mkdir my-theme
|
||||
cd my-theme
|
||||
git init
|
||||
mkdir stylesheets
|
||||
apm init --theme
|
||||
cat > index.less <<END
|
||||
@import "./stylesheets/base.less";
|
||||
@import "./stylesheets/overrides.less";
|
||||
END
|
||||
cat > stylesheets/base.less <<END
|
||||
@import "ui-variables";
|
||||
There are two types of themes you can create: syntax themes and interface themes.
|
||||
The differences between them are simply a matter of what they target and what
|
||||
they provide. Syntax themes focus on the entire editor pane, while interface themes
|
||||
target elements which are outside of the editor.
|
||||
|
||||
.editor {
|
||||
color: fade(@text-color, 20%);
|
||||
}
|
||||
END
|
||||
cat > stylesheets/overrides.less <<END
|
||||
@import "ui-variables";
|
||||
## Creating a Syntax Theme
|
||||
|
||||
.editor {
|
||||
color: fade(@text-color, 80%);
|
||||
}
|
||||
END
|
||||
```
|
||||
Let's create your first theme.
|
||||
|
||||
### Important points
|
||||
To get started, hit `cmd-p`, and start typing "Generate Theme" to generate
|
||||
a package. Select "Generate Theme," and you'll be asked for a theme name. Let's
|
||||
call ours _motif_.
|
||||
|
||||
* Notice the theme attribute in the package.json file (generated by apm). This
|
||||
is specific to Atom and required for all theme packages. Otherwise they won't
|
||||
be displayed in the theme chooser.
|
||||
* Notice the ui-variables require. If you'd like to make your theme adapt to the
|
||||
users choosen ui theme, these variables allow you to create your own colors
|
||||
based on them.
|
||||
Atom will pop open a new window, showing the _motif_ theme, with a default set of
|
||||
folders and files created for us. If you hit `cmd-,` and navigate to the Themes
|
||||
menu option, you'll see the `motif` theme already available. Drag it over from
|
||||
"Enabled Themes" to "Available Themes."
|
||||
|
||||
## How to create a UI theme
|
||||
Open up _stylesheets/colors.less_ to change the various colors variables which
|
||||
have been already been defined. For example, turn `@red` into `#f4c2c1`.
|
||||
|
||||
* Needs to have a file called ui-variables and it must contain the following
|
||||
variables:
|
||||
* A list of variables from @benogle's theme refactor.
|
||||
Then, open _stylesheets/base.less_, and modify the various syntax CSS selectors
|
||||
that have been already been defined. Each of these selectors represents a different
|
||||
part of the Atom window. Themes that don't need to modify a particular region
|
||||
can simply remove the selectors they don't need.
|
||||
|
||||
## How to just override UI colors
|
||||
As an example, let's make the `.gutter` `background-color` into `@red`.
|
||||
|
||||
* Not interested in making an entire theme? Not to worry, you can override just
|
||||
the colors.
|
||||
* Create a theme as above but just include a single file in your `stylesheets`
|
||||
directory called `ui-variables.less`
|
||||
* IMPORTANT: This theme must come before
|
||||
Reload Atom by hitting `cmd-r` to see the changes you made reflected in your Atom
|
||||
window. Pretty neat!
|
||||
|
||||
## How to create a syntax theme
|
||||
## Creating an Interface Theme
|
||||
|
||||
* Explain the idea behind grammars/tokens and classes you'd want to override.
|
||||
Interface themes **must** provide a `ui-variables.less` file which contains all
|
||||
of the variables provided by the [core themes][ui-variables].
|
||||
|
||||
To create an interface UI theme, do the following:
|
||||
|
||||
1. Fork one of the following repos
|
||||
1. [atom-dark-ui]
|
||||
1. [atom-light-ui]
|
||||
1. Open a terminal in the forked theme's directory
|
||||
1. Open your new theme in a Dev Mode Atom window (run `atom -d .` in the terminal or use the __View > Developer > Open in Dev Mode__ menu)
|
||||
1. Change the name of the theme in the theme's `package.json` file
|
||||
1. Run `apm link` to tell Atom about your new theme
|
||||
1. Reload Atom (`cmd-r`)
|
||||
1. Enable the theme via the themes panel in settings
|
||||
1. 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
|
||||
|
||||
There are a few of tools to help make theme development faster.
|
||||
|
||||
### Live Reload
|
||||
|
||||
Reloading by hitting `cmd-r` after you make changes to your theme is less than ideal.
|
||||
Atom supports [live updating][livereload] of styles on Dev Mode Atom windows.
|
||||
|
||||
To enable a Dev Mode window:
|
||||
|
||||
1. Open your theme directory in a dev window by either going to the
|
||||
__View > Developer > Open in Dev Mode__ menu or by hitting the `cmd-shift-o`
|
||||
shortcut
|
||||
1. Make a change to your theme file and save it. Your change should be
|
||||
immediately applied!
|
||||
|
||||
If you'd like to reload all the styles at any time, you can use the shortcut
|
||||
`cmd-ctrl-R`.
|
||||
|
||||
### Developer Tools
|
||||
|
||||
Atom is based on the Chrome browser, and supports Chrome's Developer Tools. You
|
||||
can open them by selecting the __View > Toggle Developer Tools__ menu, or by using
|
||||
the `cmd-option-i` shortcut.
|
||||
|
||||
The dev tools allow you to inspect elements and take a look at their CSS
|
||||
properties.
|
||||
|
||||
![devtools-img]
|
||||
|
||||
Check out Google's [extensive tutorial][devtools-tutorial] for a short introduction.
|
||||
|
||||
### Atom Styleguide
|
||||
|
||||
If you are creating an interface theme, you'll want a way to see how your theme
|
||||
changes affect all the components in the system. The [styleguide] is a page with
|
||||
every component Atom supports rendered.
|
||||
|
||||
To open the styleguide, open the command palette (`cmd-p`) and search for
|
||||
_styleguide_, or use the shortcut `cmd-ctrl-shift-g`.
|
||||
|
||||
![styleguide-img]
|
||||
|
||||
[less]: http://lesscss.org/
|
||||
[git]: http://git-scm.com/
|
||||
[atom]: https://atom.io/
|
||||
[package.json]: ./creating-a-package.html#package-json
|
||||
[less-tutorial]: https://speakerdeck.com/danmatthews/less-css
|
||||
[devtools-tutorial]: https://developers.google.com/chrome-developer-tools/docs/elements
|
||||
[ui-variables]: ./theme-variables.html
|
||||
[livereload]: https://github.com/atom/dev-live-reload
|
||||
[styleguide]: https://github.com/atom/styleguide
|
||||
[atom-dark-ui]: https://github.com/atom/atom-dark-ui
|
||||
[atom-light-ui]: https://github.com/atom/atom-light-ui
|
||||
[styleguide-img]: https://f.cloud.github.com/assets/69169/1347390/2d431d98-36af-11e3-8f8e-3f4ce1e67adb.png
|
||||
[devtools-img]: https://f.cloud.github.com/assets/69169/1347391/2d51f91c-36af-11e3-806f-f7b334af43e9.png
|
||||
[themesettings-img]: https://f.cloud.github.com/assets/69169/1347569/3150bd0c-36b2-11e3-9d69-423503acfe3f.png
|
||||
|
||||
+77
-70
@@ -1,58 +1,23 @@
|
||||
{{{
|
||||
"title": "Customizing Atom"
|
||||
}}}
|
||||
# Customizing Atom
|
||||
|
||||
# Configuration Settings
|
||||
To change a setting, configure a theme, or install a package just open the
|
||||
Settings pane in the current window by pressing `cmd+,`.
|
||||
|
||||
## Your .atom Directory
|
||||
## Changing The Theme
|
||||
|
||||
When you install Atom, an _.atom_ directory is created in your home directory.
|
||||
If you press `cmd-,`, that directory is opened in a new window. For the
|
||||
time being, this serves as the primary interface for adjusting configuration
|
||||
settings, adding and changing key bindings, tweaking styles, etc.
|
||||
Because Atom themes are based on CSS, it's possible (and encouraged) to have
|
||||
multiple themes active at the same time. Atom comes with both light and dark
|
||||
interface themes as well as several syntax themes (you can also [create your
|
||||
own][create-theme]).
|
||||
|
||||
Atom loads configuration settings from the `config.cson` file in your _~/.atom_
|
||||
directory, which contains CoffeeScript-style JSON:
|
||||
To change the active themes just open the Settings pane (`cmd-,`) and select the
|
||||
`Themes` tab. You can install non-bundled themes by going to the `Available
|
||||
Themes` section on the `Packages` tab within the Settings panel.
|
||||
|
||||
```coffeescript
|
||||
core:
|
||||
hideGitIgnoredFiles: true
|
||||
editor:
|
||||
fontSize: 18
|
||||
```
|
||||
## Installing Packages
|
||||
|
||||
Configuration is broken into namespaces, which are defined by the config hash's
|
||||
top-level keys. In addition to Atom's core components, each package may define
|
||||
its own namespace.
|
||||
|
||||
## Glossary of Config Keys
|
||||
|
||||
- `core`
|
||||
- `disablePackages`: An array of package names to disable
|
||||
- `hideGitIgnoredFiles`: Whether files in the _.gitignore_ should be hidden
|
||||
- `ignoredNames`: File names to ignore across all of Atom (not fully implemented)
|
||||
- `themes`: An array of theme names to load, in cascading order
|
||||
- `autosave`: Save a buffer when its view loses focus
|
||||
- `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
|
||||
- `invisibles`: Specify characters that Atom renders for invisibles in this hash
|
||||
- `tab`: Hard tab characters
|
||||
- `cr`: Carriage return (for Microsoft-style line endings)
|
||||
- `eol`: `\n` characters
|
||||
- `space`: Leading and trailing space characters
|
||||
- `preferredLineLength`: Identifies the length of a line (defaults to `80`)
|
||||
- `showInvisibles`: Whether to render placeholders for invisible characters (defaults to `false`)
|
||||
- `fuzzyFinder`
|
||||
- `ignoredNames`: Files to ignore *only* in the fuzzy-finder
|
||||
- `whitespace`
|
||||
- `ensureSingleTrailingNewline`: Whether to reduce multiple newlines to one at the end of files
|
||||
- `wrapGuide`
|
||||
- `columns`: Array of hashes with a `pattern` and `column` key to match the
|
||||
the path of the current editor to a column position.
|
||||
You can install non-bundled packages by going to the `Available Packages`
|
||||
section on the `Packages` tab within the Settings panel (`cmd-,`).
|
||||
|
||||
## Customizing Key Bindings
|
||||
|
||||
@@ -65,8 +30,9 @@ built-in keymaps:
|
||||
'.editor':
|
||||
'enter': 'editor:newline'
|
||||
|
||||
".select-list .editor.mini":
|
||||
'enter': 'core:confirm',
|
||||
'body':
|
||||
'ctrl-P': 'core:move-up'
|
||||
'ctrl-p': 'core:move-down'
|
||||
```
|
||||
|
||||
This keymap defines the meaning of `enter` in two different contexts. In a
|
||||
@@ -75,37 +41,75 @@ the editor to insert a newline. But if the same keystroke occurs inside of a
|
||||
select list's mini-editor, it instead emits the `core:confirm` event based on
|
||||
the binding in the more-specific selector.
|
||||
|
||||
By default, any keymap files in your `~/.atom/keymaps` directory are loaded
|
||||
in alphabetical order when Atom is started. They will always be loaded last,
|
||||
giving you the chance to override bindings that are defined by Atom's core
|
||||
keymaps or third-party packages.
|
||||
By default, `~/.atom/keymap.cson` is loaded when Atom is started. It will always
|
||||
be loaded last, giving you the chance to override bindings that are defined by
|
||||
Atom's core keymaps or third-party packages.
|
||||
|
||||
## Changing The Theme
|
||||
You'll want to know all the commands available to you. Open the Settings panel
|
||||
(`cmd-,`) and select the _Keybindings_ tab. It will show you all the keybindings
|
||||
currently in use.
|
||||
|
||||
Atom comes bundled with two themes `atom-dark-*` and `atom-light-*`.
|
||||
## Advanced Configuration
|
||||
|
||||
Because Atom themes are based on CSS, it's possible to have multiple themes
|
||||
active at the same time.
|
||||
Atom loads configuration settings from the `config.cson` file in your _~/.atom_
|
||||
directory, which contains CoffeeScript-style JSON:
|
||||
|
||||
For example, you'll usually select a theme for the UI and another theme for
|
||||
syntax highlighting. You can change themes from the preferences pane.
|
||||
```coffeescript
|
||||
core:
|
||||
hideGitIgnoredFiles: true
|
||||
editor:
|
||||
fontSize: 18
|
||||
```
|
||||
|
||||
You install new themes by placing them in the _~/.atom/themes_ directory. A
|
||||
theme can be a single LESS file or a directory containing multiple LESS files.
|
||||
The configuration itself is grouped by the package name or one of the two core
|
||||
namespaces: `core` and `editor`.
|
||||
|
||||
## Installing Packages
|
||||
### Configuration Key Reference
|
||||
|
||||
FIXME: Rewrite for the new dialog.
|
||||
- `core`
|
||||
- `disabledPackages`: An array of package names to disable
|
||||
- `excludeVcsIgnoredPaths`: Don't search within files specified by _.gitignore_
|
||||
- `hideGitIgnoredFiles`: Whether files in the _.gitignore_ should be hidden
|
||||
- `ignoredNames`: File names to ignore across all of Atom
|
||||
- `projectHome`: The directory where projects are assumed to be located
|
||||
- `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
|
||||
- `invisibles`: Specify characters that Atom renders for invisibles in this hash
|
||||
- `tab`: Hard tab characters
|
||||
- `cr`: Carriage return (for Microsoft-style line endings)
|
||||
- `eol`: `\n` characters
|
||||
- `space`: Leading and trailing space characters
|
||||
- `normalizeIndentOnPaste`: Enable/disable conversion of pasted tabs to spaces
|
||||
- `preferredLineLength`: Identifies the length of a line (defaults to `80`)
|
||||
- `showInvisibles`: Whether to render placeholders for invisible characters (defaults to `false`)
|
||||
- `showIndentGuide`: Show/hide indent indicators within the editor
|
||||
- `showLineNumbers`: Show/hide line numbers within the gutter
|
||||
- `softWrap`: Enable/disable soft wrapping of text within the editor
|
||||
- `softWrapAtPreferredLineLength`: Enable/disable soft line wrapping at `preferredLineLength`
|
||||
- `tabLength`: Number of spaces within a tab (defaults to `2`)
|
||||
- `fuzzyFinder`
|
||||
- `ignoredNames`: Files to ignore *only* in the fuzzy-finder
|
||||
- `whitespace`
|
||||
- `ensureSingleTrailingNewline`: Whether to reduce multiple newlines to one at the end of files
|
||||
- `removeTrailingWhitespace`: Enable/disable striping of whitespace at the end of lines (defaults to `true`)
|
||||
- `wrapGuide`
|
||||
- `columns`: Array of hashes with a `pattern` and `column` key to match the
|
||||
the path of the current editor to a column position.
|
||||
|
||||
## Quick Personal Hacks
|
||||
### Quick Personal Hacks
|
||||
|
||||
### user.coffee
|
||||
|
||||
When Atom finishes loading, it will evaluate _user.coffee_ in your _~/.atom_
|
||||
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.
|
||||
Please refer to the [Atom Internals Guide](./internals/intro,md) for more information. If your
|
||||
customizations become extensive, consider [creating a package](./packages/creating_packages.md).
|
||||
If customizations become extensive, consider [creating a
|
||||
package][create-a-package].
|
||||
|
||||
### user.less
|
||||
|
||||
@@ -113,8 +117,8 @@ If you want to apply quick-and-dirty personal styling changes without creating
|
||||
an entire theme that you intend to distribute, you can add styles to
|
||||
_user.less_ in your _~/.atom_ directory.
|
||||
|
||||
For example, to change the color of the highlighted line number for the line that
|
||||
contains the cursor, you could add the following style to _user.less_:
|
||||
For example, to change the color of the highlighted line number for the line
|
||||
that contains the cursor, you could add the following style to _user.less_:
|
||||
|
||||
```less
|
||||
@highlight-color: pink;
|
||||
@@ -123,3 +127,6 @@ contains the cursor, you could add the following style to _user.less_:
|
||||
color: @highlight-color;
|
||||
}
|
||||
```
|
||||
|
||||
[create-a-package]: creating-packages.md
|
||||
[create-theme]: creating-a-theme.md
|
||||
|
||||
+25
-31
@@ -1,32 +1,28 @@
|
||||
{{{
|
||||
"title": "Getting Started"
|
||||
}}}
|
||||
|
||||
# Getting Started
|
||||
|
||||
Welcome to Atom! This guide provides a quick introduction so you can be
|
||||
productive as quickly as possible. There are also guides which cover
|
||||
[configuring][configuring], [theming][theming], and [extending][extending] Atom.
|
||||
[configuring], [theming], and [extending] Atom.
|
||||
|
||||
## The Command Palette
|
||||
|
||||
If there's one key-command you must remember in Atom, it should be `cmd-p`. You
|
||||
can always hit `cmd-p` to bring up a list of commands that are relevant to the
|
||||
currently focused UI element. If there is a key binding for a given command, it
|
||||
is also displayed. This is a great way to explore the system and get to know the
|
||||
key commands interactively. If you'd like to learn about adding or changing a
|
||||
binding for a command, refer to the [key bindings](#customizing-key-bindings)
|
||||
currently focused interface element. If there is a key binding for a given
|
||||
command, it is also displayed. This is a great way to explore the system and get
|
||||
to know the key commands interactively. If you'd like to learn about adding or
|
||||
changing a binding for a command, refer to the [key bindings][key-bindings]
|
||||
section below.
|
||||
|
||||

|
||||
![Command Palette]
|
||||
|
||||
## The Basics
|
||||
|
||||
### Working With Files
|
||||
|
||||
Atom windows are scoped to the directory in which they're opened from. So if
|
||||
you launch Atom from the command line, everything will be relative to the
|
||||
current directory. This means that the tree view on the left will only show files
|
||||
Atom windows are scoped to the directory in which they're opened from. So if you
|
||||
launch Atom from the command line, everything will be relative to the current
|
||||
directory. This means that the tree view on the left will only show files
|
||||
contained within that directory.
|
||||
|
||||
This can be a useful way to organize multiple projects, as each project will be
|
||||
@@ -57,21 +53,23 @@ To delete a file, select it in the tree view and hit `delete`.
|
||||
|
||||
#### Find and Replace
|
||||
|
||||
FIXME: Describe https://github.com/atom/find-and-replace
|
||||
To search within a buffer use `cmd-f`. To search the entire project use
|
||||
`cmd-shift-f`. To find and replace within the current buffer use `cmd-alt-f`.
|
||||
|
||||
#### Navigating By Symbols
|
||||
|
||||
If you want to jump to a method, the `cmd-j` binding opens a list of all symbols
|
||||
in the current file. `cmd-.` jumps to the tag for the word currently under the cursor.
|
||||
in the current file. `cmd-.` jumps to the tag for the word currently under the
|
||||
cursor.
|
||||
|
||||
To search for symbols across your project use `cmd-shift-j`, but you'll need to
|
||||
make sure you have a tags file generated for the project Also, if you're editing
|
||||
CoffeeScript, it's a good idea to update your `~/.ctags` file to understand the
|
||||
language. Here is [a good example](https://github.com/kevinsawicki/dotfiles/blob/master/.ctags).
|
||||
language. Here is [a good example][ctags].
|
||||
|
||||
### Split Panes
|
||||
|
||||
You can split any editor pane horizontally or vertically by using `ctrl-\` or
|
||||
You can split any editor pane horizontally or vertically by using `ctrl-w s` or
|
||||
`ctrl-w v`. Once you have a split pane, you can move focus between them with
|
||||
`ctrl-tab` or `ctrl-w w`. To close a pane, close all tabs inside it.
|
||||
|
||||
@@ -79,8 +77,7 @@ You can split any editor pane horizontally or vertically by using `ctrl-\` or
|
||||
|
||||
You can fold everything with `ctrl-{` and unfold everything with
|
||||
`ctrl-}`. Or, you can fold / unfold by a single level with `ctrl-[` and
|
||||
`ctrl-]`. The user interaction around folds is still a bit rough, but we're
|
||||
planning to improve it soon.
|
||||
`ctrl-]`.
|
||||
|
||||
### Soft-Wrap
|
||||
|
||||
@@ -91,18 +88,15 @@ command.
|
||||
## Configuration
|
||||
|
||||
If you press `cmd-,`, a configuration panel will appear in the currently focused
|
||||
pane. This will serve as the primary interface for adjusting configuration
|
||||
settings, adding and changing key bindings, tweaking styles, etc.
|
||||
pane. This serves as the primary interface for adjusting settings, installing
|
||||
packages and changing themes.
|
||||
|
||||
For more advanced configuration see the [customization guide][customization].
|
||||
|
||||
## Installing Packages
|
||||
|
||||
To install a package, open the configuration panel and select the packages tab.
|
||||
|
||||
FIXME: Needs more details.
|
||||
|
||||
[configuring]: customizing-atom.html
|
||||
[theming]: creating-a-theme.html
|
||||
[extending]: creating-a-package.html
|
||||
[customization]: customizing-atom.html
|
||||
[configuring]: customizing-atom.md
|
||||
[theming]: creating-a-theme.md
|
||||
[extending]: creating-a-package.md
|
||||
[customization]: customizing-atom.md
|
||||
[key-bindings]: #customizing-key-bindings
|
||||
[command palette]: https://f.cloud.github.com/assets/1424/1091618/ee7c3554-166a-11e3-9955-aaa61bb5509c.png
|
||||
[ctags]: https://github.com/kevinsawicki/dotfiles/blob/master/.ctags
|
||||
|
||||
+9
-12
@@ -1,16 +1,13 @@
|
||||
{{{
|
||||
"title": "Guides"
|
||||
}}}
|
||||
|
||||
## Guides
|
||||
|
||||
* [Getting Started](getting-started.html)
|
||||
* [Customizing Atom](customizing-atom.html)
|
||||
* [Creating a Package](creating-a-package.html)
|
||||
* [Creating a Theme](creating-a-theme.html)
|
||||
* [Getting Started](getting-started.md)
|
||||
* [Customizing Atom](customizing-atom.md)
|
||||
* [Creating a Package](creating-a-package.md)
|
||||
* [Creating a Theme](creating-a-theme.md)
|
||||
|
||||
### Advanced Topics
|
||||
* [Configuration](internals/configuration.html)
|
||||
* [Keymaps](internals/keymaps.html)
|
||||
* [Serialization](internals/serialization.html)
|
||||
* [View System](internals/view-system.html)
|
||||
|
||||
* [Configuration](internals/configuration.md)
|
||||
* [Keymaps](internals/keymaps.md)
|
||||
* [Serialization](internals/serialization.md)
|
||||
* [View System](internals/view-system.md)
|
||||
|
||||
@@ -7,7 +7,7 @@ read config settings. You can read a value from `config` with `config.get`:
|
||||
|
||||
```coffeescript
|
||||
# read a value with `config.get`
|
||||
@autosave() if config.get "core.autosave"
|
||||
@showInvisibles() if config.get "edtior.showInvisibles"
|
||||
```
|
||||
|
||||
Or you can use `observeConfig` to track changes from a view object.
|
||||
@@ -47,7 +47,7 @@ the following way:
|
||||
|
||||
```coffeescript
|
||||
# basic key update
|
||||
config.set("core.autosave", true)
|
||||
config.set("core.showInvisibles", true)
|
||||
|
||||
config.pushAtKeyPath("core.disabledPackages", "wrap-guide")
|
||||
```
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
|
||||
### SpacePen Basics
|
||||
|
||||
Atom's view system is built around the [SpacePen](http://github.com/nathansobo/space-pen)
|
||||
view framework. SpacePen view objects inherit from the jQuery prototype, and
|
||||
wrap DOM nodes
|
||||
Atom's view system is built around the [SpacePen] view framework. SpacePen
|
||||
view objects inherit from the jQuery prototype, and wrap DOM nodes
|
||||
|
||||
View objects are actually jQuery wrappers around DOM fragments, supporting all
|
||||
the typical jQuery traversal and manipulation methods. In addition, view objects
|
||||
@@ -28,8 +27,7 @@ editorView = editorElement.view()
|
||||
editorView.setCursorBufferPosition([1, 2])
|
||||
```
|
||||
|
||||
Refer to the [SpacePen](http://github.com/nathansobo/space-pen) documentation
|
||||
for more details.
|
||||
Refer to the [SpacePen] documentation for more details.
|
||||
|
||||
### RootView
|
||||
|
||||
@@ -38,7 +36,7 @@ singleton instance of the `RootView` view class. The root view fills the entire
|
||||
window, and contains every other view. If you open Atom's inspector with
|
||||
`alt-cmd-i`, you can see the internal structure of `RootView`:
|
||||
|
||||

|
||||
![RootView in the inspector][rootview-inspector]
|
||||
|
||||
#### Panes
|
||||
|
||||
@@ -62,3 +60,6 @@ rootView.horizontal.prepend(new MyView)
|
||||
# place a view below the panes (or use .prepend() to place it above)
|
||||
rootView.vertical.append(new MyOtherView)
|
||||
```
|
||||
|
||||
[spacepen]: http://github.com/nathansobo/space-pen
|
||||
[rootview-inspector]: https://f.cloud.github.com/assets/1424/1091631/1932c2d6-166b-11e3-8adf-9690fe82d3b8.png
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
## Atom Documentation Format
|
||||
|
||||
This document describes our documentation format, which is markdown with
|
||||
a few rules.
|
||||
|
||||
### Philosophy
|
||||
|
||||
1. Method and argument names **should** clearly communicate its use.
|
||||
1. Use documentation to enhance and not correct method/argument names.
|
||||
|
||||
#### Basic
|
||||
|
||||
In some cases all that's required is a single line. **Do not** feel
|
||||
obligated to write more because we have a format.
|
||||
|
||||
```markdown
|
||||
# Private: Returns the number of pixels from the top of the screen.
|
||||
```
|
||||
|
||||
* **Each method should declare whether it's public or private by using `Public:`
|
||||
or `Private:`** prefix.
|
||||
* Following the colon, there should be a short description (that isn't redundant with the
|
||||
method name).
|
||||
* Documentation should be hard wrapped to 80 columns.
|
||||
|
||||
### Public vs Private
|
||||
|
||||
If a method is public it can be used by other classes (and possibly by
|
||||
the public API). The appropriate steps should be taken to minimize the impact
|
||||
when changing public methods. In some cases that might mean adding an
|
||||
appropriate release note. In other cases it might mean doing the legwork to
|
||||
ensure all affected packages are updated.
|
||||
|
||||
#### Complex
|
||||
|
||||
For complex methods it's necessary to explain exactly what arguments
|
||||
are required and how different inputs effect the operation of the
|
||||
function.
|
||||
|
||||
The idea is to communicate things that the API user might not know about,
|
||||
so repeating information that can be gleaned from the method or argument names
|
||||
is not useful.
|
||||
|
||||
```markdown
|
||||
# Private: Determine the accelerator for a given command.
|
||||
#
|
||||
# * command:
|
||||
# The name of the command.
|
||||
# * keystrokesByCommand:
|
||||
# An {Object} whose keys are commands and the values are Arrays containing
|
||||
# the keystrokes.
|
||||
# * options:
|
||||
# + accelerators:
|
||||
# Boolean to determine whether accelerators should be shown.
|
||||
#
|
||||
# Returns a String containing the keystroke in a format that can be interpreted
|
||||
# by atom shell to provide nice icons where available.
|
||||
#
|
||||
# Raises an Exception if no window is available.
|
||||
```
|
||||
|
||||
* Use curly brackets `{}` to provide links to other classes.
|
||||
* Use `+` for the options list.
|
||||
+1
-2
@@ -137,8 +137,7 @@
|
||||
</div>
|
||||
<div class="collapse navbar-collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a href="/<%= tag %>/index.html">Guides</a></li>
|
||||
<li><a href="/<%= tag %>/api/index.html">API</a></li>
|
||||
<li><a href="/docs/api/<%= tag %>/api/index.html">API</a></li>
|
||||
</ul>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
# Style variables
|
||||
|
||||
Atom's UI provides a set of variables you can use in your own themes and packages.
|
||||
|
||||
## Use in Themes
|
||||
|
||||
Each custom theme must specify a `ui-variables.less` file with all of the
|
||||
following variables defined. The top-most theme specified in the theme settings
|
||||
will be loaded and available for import.
|
||||
|
||||
## Use in Packages
|
||||
|
||||
In any of your package's `.less` files, you can access the theme variables
|
||||
by importing the `ui-variables` file from Atom.
|
||||
|
||||
Your package should generally only specify structural styling, and these should
|
||||
come from [the style guide][styleguide]. Your package shouldn't specify colors,
|
||||
padding sizes, or anything in absolute pixels. You should instead use the theme
|
||||
variables. If you follow this guideline, your package will look good out of the
|
||||
box with any theme!
|
||||
|
||||
Here's an example `.less` file that a package can define using theme variables:
|
||||
|
||||
```css
|
||||
@import "ui-variables";
|
||||
|
||||
.my-selector{
|
||||
background-color: @base-background-color;
|
||||
padding: @component-padding;
|
||||
}
|
||||
```
|
||||
|
||||
## Variables
|
||||
|
||||
### Text colors
|
||||
|
||||
* `@text-color`
|
||||
* `@text-color-subtle`
|
||||
* `@text-color-highlight`
|
||||
* `@text-color-selected`
|
||||
* `@text-color-info` - A blue
|
||||
* `@text-color-success`- A green
|
||||
* `@text-color-warning`- An orange or yellow
|
||||
* `@text-color-error` - A red
|
||||
|
||||
### Background colors
|
||||
|
||||
* `@background-color-info` - A blue
|
||||
* `@background-color-success` - A green
|
||||
* `@background-color-warning` - An orange or yellow
|
||||
* `@background-color-error` - A red
|
||||
* `@background-color-highlight`
|
||||
* `@background-color-selected`
|
||||
* `@app-background-color` - The app's background under all the editor components
|
||||
|
||||
### Component colors
|
||||
|
||||
* `@base-background-color` -
|
||||
* `@base-border-color` -
|
||||
|
||||
* `@pane-item-background-color` -
|
||||
* `@pane-item-border-color` -
|
||||
|
||||
* `@input-background-color` -
|
||||
* `@input-border-color` -
|
||||
|
||||
* `@tool-panel-background-color` -
|
||||
* `@tool-panel-border-color` -
|
||||
|
||||
* `@inset-panel-background-color` -
|
||||
* `@inset-panel-border-color` -
|
||||
|
||||
* `@panel-heading-background-color` -
|
||||
* `@panel-heading-border-color` -
|
||||
|
||||
* `@overlay-background-color` -
|
||||
* `@overlay-border-color` -
|
||||
|
||||
* `@button-background-color` -
|
||||
* `@button-background-color-hover` -
|
||||
* `@button-background-color-selected` -
|
||||
* `@button-border-color` -
|
||||
|
||||
* `@tab-bar-background-color` -
|
||||
* `@tab-bar-border-color` -
|
||||
* `@tab-background-color` -
|
||||
* `@tab-background-color-active` -
|
||||
* `@tab-border-color` -
|
||||
|
||||
* `@tree-view-background-color` -
|
||||
* `@tree-view-border-color` -
|
||||
|
||||
* `@ui-site-color-1` -
|
||||
* `@ui-site-color-2` -
|
||||
* `@ui-site-color-3` -
|
||||
* `@ui-site-color-4` -
|
||||
* `@ui-site-color-5` -
|
||||
|
||||
### Component sizes
|
||||
|
||||
* `@disclosure-arrow-size` -
|
||||
|
||||
* `@component-padding` -
|
||||
* `@component-icon-padding` -
|
||||
* `@component-icon-size` -
|
||||
* `@component-line-height` -
|
||||
* `@component-border-radius` -
|
||||
|
||||
* `@tab-height` -
|
||||
|
||||
### Fonts
|
||||
|
||||
* `@font-size` -
|
||||
* `@font-family` -
|
||||
|
||||
[styleguide]: https://github.com/atom/styleguide
|
||||
@@ -0,0 +1,334 @@
|
||||
# Creating Your First Package
|
||||
|
||||
Let's take a look at creating your first package.
|
||||
|
||||
To get started, hit `cmd-p`, and start typing "Generate Package" to generate
|
||||
a package. Once you select the "Generate Package" command, it'll ask you for a
|
||||
name for your new package. Let's call ours _changer_.
|
||||
|
||||
Atom will pop open a new window, showing the _changer_ package with a default set of
|
||||
folders and files created for us. Hit `cmd-p` and start typing "Changer." You'll
|
||||
see a new `Changer:Toggle` command which, if selected, pops up a greeting. So far,
|
||||
so good!
|
||||
|
||||
In order to demonstrate the capabilities of Atom and its API, our Changer plugin
|
||||
is going to do two things:
|
||||
|
||||
1. It'll show only modified files in the file tree
|
||||
2. It'll append a new pane to the editor with some information about the modified
|
||||
files
|
||||
|
||||
Let's get started!
|
||||
|
||||
## Changing Keybindings and Commands
|
||||
|
||||
Since Changer is primarily concerned with the file tree, let's write a
|
||||
key binding that works only when the tree is focused. Instead of using the
|
||||
default `toggle`, our keybinding executes a new command called `magic`.
|
||||
|
||||
_keymaps/changer.cson_ should change to look like this:
|
||||
|
||||
```coffeescript
|
||||
'.tree-view':
|
||||
'ctrl-V': 'changer:magic'
|
||||
```
|
||||
|
||||
Notice that the keybinding is called `ctrl-V` — that's actually `ctrl-shift-v`.
|
||||
You can use capital letters to denote using `shift` for your binding.
|
||||
|
||||
`.tree-view` represents the parent container for the tree view.
|
||||
Keybindings only work within the context of where they're entered. In this case,
|
||||
hitting `ctrl-V` anywhere other than tree won't do anything. Obviously, you can
|
||||
bind to any part of the editor using element, id, or class names. For example,
|
||||
you can map to `body` if you want to scope to anywhere in Atom, or just `.editor`
|
||||
for the editor portion.
|
||||
|
||||
To bind keybindings to a command, we'll need to do a bit of association in our
|
||||
CoffeeScript code using the `rootView.command` method. This method takes a command
|
||||
name and executes a callback function. Open up _lib/changer-view.coffee_, and
|
||||
change `rootView.command "changer:toggle"` to look like this:
|
||||
|
||||
```coffeescript
|
||||
rootView.command "changer:magic", => @magic()
|
||||
```
|
||||
|
||||
It's common practice to namespace your commands with your package name, separated
|
||||
with a colon (`:`). Make sure to rename your `toggle` method to `magic` as well.
|
||||
|
||||
Every time you reload the Atom editor, changes to your package code will be reevaluated,
|
||||
just as if you were writing a script for the browser. Reload the editor, click on
|
||||
the tree, hit your keybinding, and...nothing happens! What the heck?!
|
||||
|
||||
Open up the _package.json_ file, and find the property called `activationEvents`.
|
||||
Basically, this key tells Atom to not load a package until it hears a certain event.
|
||||
Change the event to `changer:magic` and reload the editor:
|
||||
|
||||
```json
|
||||
"activationEvents": ["changer:magic"]
|
||||
```
|
||||
|
||||
Hitting the key binding on the tree now works!
|
||||
|
||||
## Working with Styles
|
||||
|
||||
The next step is to hide elements in the tree that aren't modified. To do that,
|
||||
we'll first try and get a list of files that have not changed.
|
||||
|
||||
All packages are able to use jQuery in their code. In fact, there's [a list of
|
||||
the bundled libraries Atom provides by default][bundled-libs].
|
||||
|
||||
We bring in jQuery by requiring the `atom` package and binding it to the `$` variable:
|
||||
|
||||
```coffeescript
|
||||
{$, View} = require 'atom'
|
||||
```
|
||||
|
||||
Now, we can define the `magic` method to query the tree to get us a list of every
|
||||
file that _wasn't_ modified:
|
||||
|
||||
```coffeescript
|
||||
magic: ->
|
||||
$('ol.entries li').each (i, el) ->
|
||||
if !$(el).hasClass("status-modified")
|
||||
console.log el
|
||||
```
|
||||
|
||||
You can access the dev console by hitting `alt-cmd-i`. Here, you'll see all the
|
||||
statements from `console` calls. When we execute the `changer:magic` command, the
|
||||
browser console lists items that are not being modified (_i.e._, those without the
|
||||
`status-modified` class). Let's add a class to each of these elements called `hide-me`:
|
||||
|
||||
```coffeescript
|
||||
magic: ->
|
||||
$('ol.entries li').each (i, el) ->
|
||||
if !$(el).hasClass("status-modified")
|
||||
$(el).addClass("hide-me")
|
||||
```
|
||||
|
||||
With our newly added class, we can manipulate the visibility of the elements
|
||||
with a simple stylesheet. Open up _changer.css_ in the _stylesheets_ directory,
|
||||
and add a single entry:
|
||||
|
||||
```css
|
||||
ol.entries .hide-me {
|
||||
display: none;
|
||||
}
|
||||
```
|
||||
|
||||
Refresh Atom, and run the `changer` command. You'll see all the non-changed
|
||||
files disappear from the tree. Success!
|
||||
|
||||
![Changer_File_View]
|
||||
|
||||
There are a number of ways you can get the list back; let's just naively iterate
|
||||
over the same elements and remove the class:
|
||||
|
||||
```coffeescript
|
||||
magic: ->
|
||||
$('ol.entries li').each (i, el) ->
|
||||
if !$(el).hasClass("status-modified")
|
||||
if !$(el).hasClass("hide-me")
|
||||
$(el).addClass("hide-me")
|
||||
else
|
||||
$(el).removeClass("hide-me")
|
||||
```
|
||||
|
||||
## Creating a New Panel
|
||||
|
||||
The next goal of this package is to append a panel to the Atom editor that lists
|
||||
some information about the modified files.
|
||||
|
||||
To do that, we're going to first open up [the style guide][styleguide]. The Style
|
||||
Guide lists every type of UI element that can be created by an Atom package. Aside
|
||||
from helping you avoid writing fresh code from scratch, it ensures that packages
|
||||
have the same look and feel no matter how they're built.
|
||||
|
||||
Every package that extends from the `View` class can provide an optional class
|
||||
method called `content`. The `content` method constructs the DOM that your
|
||||
package uses as its UI. The principals of `content` are built entirely on
|
||||
[SpacePen][space-pen], which we'll touch upon only briefly here.
|
||||
|
||||
Our display will simply be an unordered list of the file names, and their
|
||||
modified times. We'll append this list to a panel on the bottom of the editor. A
|
||||
basic `panel` element inside a `tool-panel` will work well for us. Let's start by carving out a
|
||||
`div` to hold the filenames:
|
||||
|
||||
```coffeescript
|
||||
@content: ->
|
||||
@div class: "changer tool-panel panel-bottom", =>
|
||||
@div class: "panel", =>
|
||||
@div class: "panel-heading", "Modified Files"
|
||||
@div class: "panel-body padded", outlet: 'modifiedFilesContainer', =>
|
||||
@ul class: 'modified-files-list', outlet: 'modifiedFilesList', =>
|
||||
@li 'Modified File Test'
|
||||
@li 'Modified File Test'
|
||||
```
|
||||
|
||||
You can add any HTML attribute you like. `outlet` names the variable your
|
||||
package can use to manipulate the element directly. The fat arrow (`=>`)
|
||||
indicates that the next DOM set are nested children.
|
||||
|
||||
Once again, you can style `li` elements using your stylesheets. Let's test that
|
||||
out by adding these lines to the _changer.css_ file:
|
||||
|
||||
```css
|
||||
ul.modified-files-list {
|
||||
color: white;
|
||||
}
|
||||
```
|
||||
|
||||
We'll add one more line to the end of the `magic` method to make this pane appear:
|
||||
|
||||
```coffeescript
|
||||
rootView.vertical.append(this)
|
||||
```
|
||||
|
||||
If you refresh Atom and hit the key command, you'll see a box appear right underneath
|
||||
the editor:
|
||||
|
||||
![Changer_Panel_Append]
|
||||
|
||||
As you might have guessed, `rootView.vertical.append` tells Atom to append `this`
|
||||
item (_i.e._, whatever is defined by`@content`) _vertically_ to the editor. If
|
||||
we had called `rootView.horizontal.append`, the pane would be attached to the
|
||||
right-hand side of the editor.
|
||||
|
||||
Before we populate this panel for real, let's apply some logic to toggle the pane
|
||||
off and on, just like we did with the tree view. Replace the `rootView.vertical.append`
|
||||
call with this code:
|
||||
|
||||
```coffeescript
|
||||
# toggles the pane
|
||||
if @hasParent()
|
||||
rootView.vertical.children().last().remove()
|
||||
else
|
||||
rootView.vertical.append(this)
|
||||
```
|
||||
|
||||
There are about a hundred different ways to toggle a pane on and off, and this
|
||||
might not be the most efficient one. If you know your package needs to be
|
||||
toggled on and off more freely, it might be better to draw the interface during the
|
||||
initialization, then immediately call `hide()` on the element to remove it from
|
||||
the view. You can then swap between `show()` and `hide()`, and instead of
|
||||
forcing Atom to add and remove the element as we're doing here, it'll just set a
|
||||
CSS property to control your package's visibility.
|
||||
|
||||
Refresh Atom, hit the key combo, and watch your test list appear and disappear.
|
||||
|
||||
## Calling Node.js Code
|
||||
|
||||
Since Atom is built on top of [Node.js][node], you can call any of its libraries,
|
||||
including other modules that your package requires.
|
||||
|
||||
We'll iterate through our resulting tree, and construct the path to our modified
|
||||
file based on its depth in the tree. We'll use Node to handle path joining for
|
||||
directories.
|
||||
|
||||
Add the following Node module to the top of your file:
|
||||
|
||||
```coffeescript
|
||||
path = require 'path'
|
||||
```
|
||||
|
||||
Then, add these lines to your `magic` method, _before_ your pane drawing code:
|
||||
|
||||
```coffeescript
|
||||
modifiedFiles = []
|
||||
# for each single entry...
|
||||
$('ol.entries li.file.status-modified span.name').each (i, el) ->
|
||||
filePath = []
|
||||
# ...grab its name...
|
||||
filePath.unshift($(el).text())
|
||||
|
||||
# ... then find its parent directories, and grab their names
|
||||
parents = $(el).parents('.directory.status-modified')
|
||||
parents.each (i, el) ->
|
||||
filePath.unshift($(el).find('div.header span.name').eq(0).text())
|
||||
|
||||
modifiedFilePath = path.join(atom.project.rootDirectory.path, filePath.join(path.sep))
|
||||
modifiedFiles.push modifiedFilePath
|
||||
```
|
||||
|
||||
`modifiedFiles` is an array containing a list of our modified files. We're also
|
||||
using the node.js [`path` library][path] to get the proper directory separator
|
||||
for our system.
|
||||
|
||||
Remove the two `@li` elements we added in `@content`, so that we can
|
||||
populate our `modifiedFilesList` with real information. We'll do that by
|
||||
iterating over `modifiedFiles`, accessing a file's last modified time, and
|
||||
appending it to `modifiedFilesList`:
|
||||
|
||||
```coffeescript
|
||||
# toggles the pane
|
||||
if @hasParent()
|
||||
rootView.vertical.children().last().remove()
|
||||
else
|
||||
for file in modifiedFiles
|
||||
stat = fs.lstatSync(file)
|
||||
mtime = stat.mtime
|
||||
@modifiedFilesList.append("<li>#{file} - Modified at #{mtime}")
|
||||
rootView.vertical.append(this)
|
||||
```
|
||||
|
||||
When you toggle the modified files list, your pane is now populated with the
|
||||
filenames and modified times of files in your project:
|
||||
|
||||
![Changer_Panel_Timestamps]
|
||||
|
||||
You might notice that subsequent calls to this command reduplicate information.
|
||||
We could provide an elegant way of rechecking files already in the list, but for
|
||||
this demonstration, we'll just clear the `modifiedFilesList` each time it's closed:
|
||||
|
||||
```coffeescript
|
||||
# toggles the pane
|
||||
if @hasParent()
|
||||
@modifiedFilesList.empty() # added this to clear the list on close
|
||||
rootView.vertical.children().last().remove()
|
||||
else
|
||||
for file in modifiedFiles
|
||||
stat = fs.lstatSync(file)
|
||||
mtime = stat.mtime
|
||||
@modifiedFilesList.append("<li>#{file} - Modified at #{mtime}")
|
||||
rootView.vertical.append(this)
|
||||
```
|
||||
|
||||
## Coloring UI Elements
|
||||
|
||||
For packages that create new UI elements, adhering to the style guide is just one
|
||||
part to keeping visual consistency. Packages dealing with color, fonts, padding,
|
||||
margins, and other visual cues should rely on [Theme Variables][theme-vars], instead
|
||||
of developing individual styles. Theme variables are variables defined by Atom
|
||||
for use in packages and themes. They're only available in [`LESS`](http://lesscss.org/)
|
||||
stylesheets.
|
||||
|
||||
For our package, let's remove the style defined by `ul.modified-files-list` in
|
||||
_changer.css_. Create a new file under the _stylesheets_ directory called _text-colors.less_.
|
||||
Here, we'll import the _ui-variables.less_ file, and define some Atom-specific
|
||||
styles:
|
||||
|
||||
```less
|
||||
@import "ui-variables";
|
||||
|
||||
ul.modified-files-list {
|
||||
color: @text-color;
|
||||
background-color: @background-color-info;
|
||||
}
|
||||
```
|
||||
|
||||
Using theme variables ensures that packages look great alongside any theme.
|
||||
|
||||
## Further reading
|
||||
|
||||
For more information on the mechanics of packages, check out
|
||||
[Creating a Package][creating-a-package].
|
||||
|
||||
[bundled-libs]: creating-a-package.html#included-libraries
|
||||
[styleguide]: https://github.com/atom/styleguide
|
||||
[space-pen]: https://github.com/atom/space-pen
|
||||
[node]: http://nodejs.org/
|
||||
[path]: http://nodejs.org/docs/latest/api/path.html
|
||||
[changer_file_view]: https://f.cloud.github.com/assets/69169/1441187/d7a7cb46-41a7-11e3-8128-d93f70a5d5c1.png
|
||||
[changer_panel_append]: https://f.cloud.github.com/assets/69169/1441189/db0c74da-41a7-11e3-8286-b82dd9190c34.png
|
||||
[changer_panel_timestamps]: https://f.cloud.github.com/assets/69169/1441190/dcc8eeb6-41a7-11e3-830f-1f1b33072fcd.png
|
||||
[theme-vars]: theme-variables.html
|
||||
[creating-a-package]: creating-a-package.html
|
||||
@@ -0,0 +1,13 @@
|
||||
# User keymap
|
||||
#
|
||||
# Atom keymaps work similarly to stylesheets. Just as stylesheets use selectors
|
||||
# to apply styles to elements, Atom keymaps use selectors to associate
|
||||
# keystrokes with events in specific contexts. Here's a small example, excerpted
|
||||
# from Atom's built-in keymaps:
|
||||
#
|
||||
# '.editor':
|
||||
# 'enter': 'editor:newline'
|
||||
#
|
||||
# 'body':
|
||||
# 'ctrl-P': 'core:move-up'
|
||||
# 'ctrl-p': 'core:move-down'
|
||||
+11
-15
@@ -1,32 +1,28 @@
|
||||
{View, $$, $$$} = require '../src/space-pen-extensions'
|
||||
{Document, Point, Range, Site} = require 'telepath'
|
||||
{Document, Point, Range} = require 'telepath'
|
||||
|
||||
module.exports =
|
||||
_: require '../src/underscore-extensions'
|
||||
$: require '../src/jquery-extensions'
|
||||
$$: $$
|
||||
$$$: $$$
|
||||
_: require 'underscore-plus'
|
||||
BufferedNodeProcess: require '../src/buffered-node-process'
|
||||
BufferedProcess: require '../src/buffered-process'
|
||||
Directory: require '../src/directory'
|
||||
Document: Document
|
||||
EventEmitter: require '../src/event-emitter'
|
||||
File: require '../src/file'
|
||||
fs: require '../src/fs-utils'
|
||||
fs: require 'fs-plus'
|
||||
Git: require '../src/git'
|
||||
Point: Point
|
||||
Range: Range
|
||||
ScrollView: require '../src/scroll-view'
|
||||
Site: Site
|
||||
stringscore: require '../vendor/stringscore'
|
||||
Subscriber: require '../src/subscriber'
|
||||
View: View
|
||||
|
||||
# The following classes can't be used from a Task handler and should therefore
|
||||
# only be exported when not running as a child node process
|
||||
unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
|
||||
module.exports.Editor = require '../src/editor'
|
||||
module.exports.pathForRepositoryUrl = require('../src/project').pathForRepositoryUrl
|
||||
{$, $$, $$$, View} = require '../src/space-pen-extensions'
|
||||
|
||||
module.exports.$ = $
|
||||
module.exports.$$ = $$
|
||||
module.exports.$$$ = $$$
|
||||
module.exports.Editor = require '../src/editor-view'
|
||||
module.exports.RootView = require '../src/root-view'
|
||||
module.exports.SelectList = require '../src/select-list'
|
||||
module.exports.ScrollView = require '../src/scroll-view'
|
||||
module.exports.Task = require '../src/task'
|
||||
module.exports.View = View
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# FIXME Make jquery a package.json dependency
|
||||
# This is needed so that space-pen can be require it as 'jquery'
|
||||
module.exports = require '../vendor/jquery'
|
||||
@@ -1,21 +0,0 @@
|
||||
'body':
|
||||
'meta-up': 'core:move-to-top'
|
||||
'meta-down': 'core:move-to-bottom'
|
||||
'meta-shift-up': 'core:select-to-top'
|
||||
'meta-shift-down': 'core:select-to-bottom'
|
||||
|
||||
'.editor':
|
||||
'meta-right': 'editor:move-to-end-of-line'
|
||||
'meta-left': 'editor:move-to-beginning-of-line'
|
||||
'alt-left': 'editor:move-to-beginning-of-word'
|
||||
'alt-right': 'editor:move-to-end-of-word'
|
||||
'meta-shift-left': 'editor:select-to-beginning-of-line'
|
||||
'meta-shift-right': 'editor:select-to-end-of-line'
|
||||
'alt-shift-left': 'editor:select-to-beginning-of-word'
|
||||
'alt-shift-right': 'editor:select-to-end-of-word'
|
||||
'alt-backspace': 'editor:backspace-to-beginning-of-word'
|
||||
'meta-backspace': 'editor:backspace-to-beginning-of-line'
|
||||
'alt-delete': 'editor:delete-to-end-of-word'
|
||||
'ctrl-t': 'editor:transpose'
|
||||
'ctrl-A': 'editor:select-to-first-character-of-line'
|
||||
'ctrl-E': 'editor:select-to-end-of-line'
|
||||
@@ -1,96 +0,0 @@
|
||||
'body':
|
||||
'meta-q': 'application:quit'
|
||||
'meta-h': 'application:hide'
|
||||
'meta-H': 'application:hide-other-applications'
|
||||
'meta-n': 'application:new-file'
|
||||
'meta-N': 'application:new-window'
|
||||
'meta-o': 'application:open'
|
||||
'meta-O': 'application:open-dev'
|
||||
'meta-m': 'application:minimize'
|
||||
'meta-,': 'application:show-settings'
|
||||
'alt-meta-ctrl-m': 'application:zoom'
|
||||
'meta-alt-ctrl-s': 'application:run-all-specs'
|
||||
|
||||
'meta-s': 'core:save'
|
||||
'meta-S': 'core:save-as'
|
||||
'enter': 'core:confirm'
|
||||
'escape': 'core:cancel'
|
||||
'meta-w': 'core:close'
|
||||
'up': 'core:move-up'
|
||||
'down': 'core:move-down'
|
||||
'left': 'core:move-left'
|
||||
'right': 'core:move-right'
|
||||
'shift-up': 'core:select-up'
|
||||
'shift-down': 'core:select-down'
|
||||
'shift-left': 'core:select-left'
|
||||
'shift-right': 'core:select-right'
|
||||
'meta-a': 'core:select-all'
|
||||
'backspace': 'core:backspace'
|
||||
'shift-backspace': 'core:backspace'
|
||||
'delete': 'core:delete'
|
||||
'meta-z': 'core:undo'
|
||||
'meta-Z': 'core:redo'
|
||||
'meta-x': 'core:cut'
|
||||
'meta-c': 'core:copy'
|
||||
'meta-v': 'core:paste'
|
||||
'pageup': 'core:page-up'
|
||||
'pagedown': 'core:page-down'
|
||||
|
||||
'meta-alt-s': 'window:save-all'
|
||||
'meta-W': 'window:close'
|
||||
'meta-+': 'window:increase-font-size'
|
||||
'meta--': 'window:decrease-font-size'
|
||||
'ctrl-w w': 'window:focus-next-pane'
|
||||
'ctrl-tab': 'window:focus-next-pane'
|
||||
'ctrl-meta-f': 'window:toggle-full-screen'
|
||||
'meta-r': 'window:reload'
|
||||
'alt-meta-i': 'window:toggle-dev-tools'
|
||||
'meta-alt-ctrl-p': 'window:run-package-specs'
|
||||
|
||||
'ctrl-|': 'pane:split-right'
|
||||
'ctrl-w v': 'pane:split-right'
|
||||
'ctrl--': 'pane:split-down'
|
||||
'ctrl-w s': 'pane:split-down'
|
||||
|
||||
'meta-{': 'pane:show-previous-item'
|
||||
'meta-}': 'pane:show-next-item'
|
||||
'alt-meta-left': 'pane:show-previous-item'
|
||||
'alt-meta-right': 'pane:show-next-item'
|
||||
'meta-1': 'pane:show-item-1'
|
||||
'meta-2': 'pane:show-item-2'
|
||||
'meta-3': 'pane:show-item-3'
|
||||
'meta-4': 'pane:show-item-4'
|
||||
'meta-5': 'pane:show-item-5'
|
||||
'meta-6': 'pane:show-item-6'
|
||||
'meta-7': 'pane:show-item-7'
|
||||
'meta-8': 'pane:show-item-8'
|
||||
'meta-9': 'pane:show-item-9'
|
||||
'meta-T': 'pane:reopen-closed-item'
|
||||
'alt-meta-w': 'pane:close-other-items'
|
||||
'meta-P': 'pane:close'
|
||||
|
||||
'.tool-panel':
|
||||
'meta-escape': 'tool-panel:unfocus'
|
||||
'escape': 'core:close'
|
||||
'meta-w': 'noop'
|
||||
|
||||
# allow standard input fields to work correctly
|
||||
'input:not(.hidden-input)':
|
||||
'tab': 'core:focus-next'
|
||||
'shift-tab': 'core:focus-previous'
|
||||
'left': 'native!'
|
||||
'right': 'native!'
|
||||
'shift-left': 'native!'
|
||||
'shift-right': 'native!'
|
||||
'backspace': 'native!'
|
||||
'shift-backspace': 'native!'
|
||||
'delete': 'native!'
|
||||
'meta-z': 'native!'
|
||||
'meta-Z': 'native!'
|
||||
'meta-x': 'native!'
|
||||
'meta-c': 'native!'
|
||||
'meta-v': 'native!'
|
||||
|
||||
'button':
|
||||
'tab': 'core:focus-next'
|
||||
'shift-tab': 'core:focus-previous'
|
||||
@@ -0,0 +1,52 @@
|
||||
'.editor':
|
||||
# Platform Bindings
|
||||
'alt-left': 'editor:move-to-previous-word-boundary'
|
||||
'alt-right': 'editor:move-to-next-word-boundary'
|
||||
'alt-shift-left': 'editor:select-to-previous-word-boundary'
|
||||
'alt-shift-right': 'editor:select-to-next-word-boundary'
|
||||
'home': 'editor:move-to-first-character-of-line'
|
||||
'end': 'editor:move-to-end-of-line'
|
||||
'shift-home': 'editor:select-to-first-character-of-line'
|
||||
'shift-end': 'editor:select-to-end-of-line'
|
||||
|
||||
# Sublime Parity
|
||||
'ctrl-t': 'editor:transpose'
|
||||
|
||||
'.editor:not(.mini)':
|
||||
# Atom Specific
|
||||
'ctrl-C': 'editor:copy-path'
|
||||
|
||||
# Sublime Parity
|
||||
'tab': 'editor:indent'
|
||||
'enter': 'editor:newline'
|
||||
'shift-tab': 'editor:outdent-selected-rows'
|
||||
'ctrl-K': 'editor:delete-line'
|
||||
'ctrl-shift-up': 'editor:add-selection-above'
|
||||
'ctrl-shift-down': 'editor:add-selection-below'
|
||||
|
||||
'.tool-panel':
|
||||
'escape': 'core:close'
|
||||
|
||||
'.tool-panel.panel-left, .tool-panel.panel-right':
|
||||
'escape': 'tool-panel:unfocus'
|
||||
|
||||
'.editor !important, .editor.mini !important':
|
||||
'escape': 'editor:consolidate-selections'
|
||||
|
||||
# allow standard input fields to work correctly
|
||||
'input:not(.hidden-input), .native-key-bindings':
|
||||
'tab': 'core:focus-next'
|
||||
'shift-tab': 'core:focus-previous'
|
||||
'left': 'native!'
|
||||
'right': 'native!'
|
||||
'shift-left': 'native!'
|
||||
'shift-right': 'native!'
|
||||
'backspace': 'native!'
|
||||
'shift-backspace': 'native!'
|
||||
'delete': 'native!'
|
||||
'ctrl-b': 'native!'
|
||||
'ctrl-f': 'native!'
|
||||
'ctrl-F': 'native!'
|
||||
'ctrl-B': 'native!'
|
||||
'ctrl-h': 'native!'
|
||||
'ctrl-d': 'native!'
|
||||
@@ -0,0 +1,154 @@
|
||||
'.platform-darwin':
|
||||
# Apple specific
|
||||
'cmd-q': 'application:quit'
|
||||
'cmd-h': 'application:hide'
|
||||
'cmd-H': 'application:hide-other-applications'
|
||||
'cmd-m': 'application:minimize'
|
||||
'alt-cmd-ctrl-m': 'application:zoom'
|
||||
|
||||
'ctrl-p': 'core:move-up'
|
||||
'ctrl-n': 'core:move-down'
|
||||
'ctrl-b': 'core:move-left'
|
||||
'ctrl-f': 'core:move-right'
|
||||
'ctrl-P': 'core:select-up'
|
||||
'ctrl-N': 'core:select-down'
|
||||
'ctrl-F': 'core:select-right'
|
||||
'ctrl-B': 'core:select-left'
|
||||
'ctrl-h': 'core:backspace'
|
||||
'ctrl-d': 'core:delete'
|
||||
|
||||
# Atom Specific
|
||||
'cmd-O': 'application:open-dev'
|
||||
'cmd-alt-ctrl-s': 'application:run-all-specs'
|
||||
'enter': 'core:confirm'
|
||||
'escape': 'core:cancel'
|
||||
'up': 'core:move-up'
|
||||
'down': 'core:move-down'
|
||||
'left': 'core:move-left'
|
||||
'right': 'core:move-right'
|
||||
'ctrl-alt-cmd-r': 'window:reload'
|
||||
'alt-cmd-i': 'window:toggle-dev-tools'
|
||||
'cmd-alt-ctrl-p': 'window:run-package-specs'
|
||||
|
||||
# Sublime Parity
|
||||
'cmd-,': 'application:show-settings'
|
||||
'cmd-N': 'application:new-window'
|
||||
'cmd-W': 'window:close'
|
||||
'cmd-o': 'application:open'
|
||||
'cmd-T': 'pane:reopen-closed-item'
|
||||
'cmd-n': 'application:new-file'
|
||||
'cmd-s': 'core:save'
|
||||
'cmd-S': 'core:save-as'
|
||||
'cmd-alt-s': 'window:save-all'
|
||||
'cmd-w': 'core:close'
|
||||
'cmd-ctrl-f': 'window:toggle-full-screen'
|
||||
'cmd-z': 'core:undo'
|
||||
'cmd-Z': 'core:redo'
|
||||
'cmd-y': 'core:redo'
|
||||
'cmd-x': 'core:cut'
|
||||
'cmd-c': 'core:copy'
|
||||
'cmd-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'
|
||||
'shift-backspace': 'core:backspace'
|
||||
'cmd-up': 'core:move-to-top'
|
||||
'cmd-down': 'core:move-to-bottom'
|
||||
'cmd-shift-up': 'core:select-to-top'
|
||||
'cmd-shift-down': 'core:select-to-bottom'
|
||||
'cmd-{': 'pane:show-previous-item'
|
||||
'cmd-}': 'pane:show-next-item'
|
||||
'cmd-alt-left': 'pane:show-previous-item'
|
||||
'cmd-alt-right': 'pane:show-next-item'
|
||||
'cmd-=': 'window:increase-font-size'
|
||||
'cmd-+': 'window:increase-font-size'
|
||||
'cmd--': 'window:decrease-font-size'
|
||||
|
||||
'cmd-k up': 'pane:split-up' # Atom Specific
|
||||
'cmd-k down': 'pane:split-down' # Atom Specific
|
||||
'cmd-k left': 'pane:split-left' # Atom Specific
|
||||
'cmd-k right': 'pane:split-right' # Atom Specific
|
||||
'cmd-k cmd-w': 'pane:close' # Atom Specific
|
||||
'cmd-k alt-cmd-w': 'pane:close-other-items' # Atom Specific
|
||||
'cmd-k cmd-left': 'window:focus-previous-pane'
|
||||
'cmd-k cmd-right': 'window:focus-next-pane'
|
||||
'cmd-1': 'pane:show-item-1'
|
||||
'cmd-2': 'pane:show-item-2'
|
||||
'cmd-3': 'pane:show-item-3'
|
||||
'cmd-4': 'pane:show-item-4'
|
||||
'cmd-5': 'pane:show-item-5'
|
||||
'cmd-6': 'pane:show-item-6'
|
||||
'cmd-7': 'pane:show-item-7'
|
||||
'cmd-8': 'pane:show-item-8'
|
||||
'cmd-9': 'pane:show-item-9'
|
||||
|
||||
'.platform-darwin .editor':
|
||||
# Apple Specific
|
||||
'cmd-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'
|
||||
'cmd-left': 'editor:move-to-first-character-of-line'
|
||||
'cmd-right': 'editor:move-to-end-of-line'
|
||||
'cmd-shift-left': 'editor:select-to-first-character-of-line'
|
||||
'cmd-shift-right': 'editor:select-to-end-of-line'
|
||||
'alt-backspace': 'editor:backspace-to-beginning-of-word'
|
||||
'alt-delete': 'editor:delete-to-end-of-word'
|
||||
'ctrl-a': 'editor:move-to-first-character-of-line'
|
||||
'ctrl-e': 'editor:move-to-end-of-line'
|
||||
'ctrl-k': 'editor:cut-to-end-of-line'
|
||||
|
||||
# Atom Specific
|
||||
'ctrl-W': 'editor:select-word'
|
||||
|
||||
# Sublime Parity
|
||||
'cmd-a': 'core:select-all'
|
||||
'cmd-alt-p': 'editor:log-cursor-scope'
|
||||
'cmd-k cmd-u': 'editor:upper-case'
|
||||
'cmd-k cmd-l': 'editor:lower-case'
|
||||
|
||||
'body.platform-darwin .editor:not(.mini)':
|
||||
# Atom specific
|
||||
'alt-cmd-z': 'editor:checkout-head-revision'
|
||||
'cmd-<': 'editor:scroll-to-cursor'
|
||||
'alt-cmd-ctrl-f': 'editor:fold-selection'
|
||||
'cmd-=': 'editor:auto-indent'
|
||||
|
||||
# Sublime Parity
|
||||
'cmd-enter': 'editor:newline-below'
|
||||
'cmd-shift-enter': 'editor:newline-above'
|
||||
'cmd-]': 'editor:indent-selected-rows'
|
||||
'cmd-[': 'editor:outdent-selected-rows'
|
||||
'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-alt-[': 'editor:fold-current-row'
|
||||
'cmd-alt-]': 'editor:unfold-current-row'
|
||||
'cmd-alt-{': 'editor:fold-all' # Atom Specific
|
||||
'cmd-alt-}': 'editor:unfold-all' # Atom Specific
|
||||
'cmd-k cmd-0': 'editor:unfold-all'
|
||||
'cmd-k cmd-1': 'editor:fold-at-indent-level-1'
|
||||
'cmd-k cmd-2': 'editor:fold-at-indent-level-2'
|
||||
'cmd-k cmd-3': 'editor:fold-at-indent-level-3'
|
||||
'cmd-k cmd-4': 'editor:fold-at-indent-level-4'
|
||||
'cmd-k cmd-5': 'editor:fold-at-indent-level-5'
|
||||
'cmd-k cmd-6': 'editor:fold-at-indent-level-6'
|
||||
'cmd-k cmd-7': 'editor:fold-at-indent-level-7'
|
||||
'cmd-k cmd-8': 'editor:fold-at-indent-level-8'
|
||||
'cmd-k cmd-9': 'editor:fold-at-indent-level-9'
|
||||
|
||||
# allow standard input fields to work correctly
|
||||
'body.platform-darwin input:not(.hidden-input), body.platform-darwin .native-key-bindings':
|
||||
'cmd-z': 'native!'
|
||||
'cmd-Z': 'native!'
|
||||
'cmd-x': 'native!'
|
||||
'cmd-c': 'native!'
|
||||
'cmd-v': 'native!'
|
||||
@@ -1,50 +0,0 @@
|
||||
'.editor':
|
||||
'meta-d': 'editor:delete-line'
|
||||
'ctrl-W': 'editor:select-word'
|
||||
'meta-alt-p': 'editor:log-cursor-scope'
|
||||
'meta-u': 'editor:upper-case'
|
||||
'meta-U': 'editor:lower-case'
|
||||
|
||||
'.editor:not(.mini)':
|
||||
'enter': 'editor:newline'
|
||||
'meta-enter': 'editor:newline-below'
|
||||
'meta-shift-enter': 'editor:newline-above'
|
||||
'tab': 'editor:indent'
|
||||
'meta-=': 'editor:auto-indent'
|
||||
|
||||
'ctrl-[': 'editor:fold-current-row'
|
||||
'ctrl-]': 'editor:unfold-current-row'
|
||||
'ctrl-{': 'editor:fold-all'
|
||||
'ctrl-}': 'editor:unfold-all'
|
||||
'ctrl-meta-1': 'editor:fold-at-indent-level-1'
|
||||
'ctrl-meta-2': 'editor:fold-at-indent-level-2'
|
||||
'ctrl-meta-3': 'editor:fold-at-indent-level-3'
|
||||
'ctrl-meta-4': 'editor:fold-at-indent-level-4'
|
||||
'ctrl-meta-5': 'editor:fold-at-indent-level-5'
|
||||
'ctrl-meta-6': 'editor:fold-at-indent-level-6'
|
||||
'ctrl-meta-7': 'editor:fold-at-indent-level-7'
|
||||
'ctrl-meta-8': 'editor:fold-at-indent-level-8'
|
||||
'ctrl-meta-9': 'editor:fold-at-indent-level-9'
|
||||
|
||||
'alt-shift-down': 'editor:add-selection-below'
|
||||
'alt-shift-up': 'editor:add-selection-above'
|
||||
'alt-meta-ctrl-f': 'editor:fold-selection'
|
||||
'shift-tab': 'editor:outdent-selected-rows'
|
||||
'meta-[': 'editor:outdent-selected-rows'
|
||||
'meta-]': 'editor:indent-selected-rows'
|
||||
|
||||
'meta-/': 'editor:toggle-line-comments'
|
||||
'ctrl-C': 'editor:copy-path'
|
||||
'ctrl-meta-up': 'editor:move-line-up'
|
||||
'ctrl-meta-down': 'editor:move-line-down'
|
||||
'meta-D': 'editor:duplicate-line'
|
||||
'ctrl-J': 'editor:join-line'
|
||||
'meta-<': 'editor:scroll-to-cursor'
|
||||
|
||||
'.editor.mini':
|
||||
'enter': 'core:confirm',
|
||||
'escape': 'core:cancel'
|
||||
'meta-w': 'core:cancel'
|
||||
|
||||
'.editor !important, .editor.mini !important':
|
||||
'escape': 'editor:consolidate-selections'
|
||||
@@ -1,33 +1,7 @@
|
||||
'body':
|
||||
'ctrl-p': 'core:move-up'
|
||||
'ctrl-n': 'core:move-down'
|
||||
'ctrl-b': 'core:move-left'
|
||||
'ctrl-f': 'core:move-right'
|
||||
'ctrl-P': 'core:select-up'
|
||||
'ctrl-N': 'core:select-down'
|
||||
'ctrl-F': 'core:select-right'
|
||||
'ctrl-B': 'core:select-left'
|
||||
'alt-ctrl-n': 'editor:add-selection-below'
|
||||
'alt-ctrl-p': 'editor:add-selection-above'
|
||||
'ctrl-h': 'core:backspace'
|
||||
'ctrl-d': 'core:delete'
|
||||
|
||||
'.editor':
|
||||
'alt-f': 'editor:move-to-end-of-word'
|
||||
'alt-F': 'editor:select-to-end-of-word'
|
||||
'alt-b': 'editor:move-to-beginning-of-word'
|
||||
'alt-B': 'editor:select-to-beginning-of-word'
|
||||
'ctrl-a': 'editor:move-to-first-character-of-line'
|
||||
'ctrl-e': 'editor:move-to-end-of-line'
|
||||
'alt-h': 'editor:backspace-to-beginning-of-word'
|
||||
'alt-d': 'editor:delete-to-end-of-word'
|
||||
'ctrl-k': 'editor:cut-to-end-of-line'
|
||||
|
||||
# allow standard input fields to work correctly
|
||||
'input:not(.hidden-input)':
|
||||
'ctrl-b': 'native!'
|
||||
'ctrl-f': 'native!'
|
||||
'ctrl-F': 'native!'
|
||||
'ctrl-B': 'native!'
|
||||
'ctrl-h': 'native!'
|
||||
'ctrl-d': 'native!'
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
'.editor':
|
||||
'alt-meta-z': 'editor:checkout-head-revision'
|
||||
@@ -1,4 +0,0 @@
|
||||
'.select-list .mini.editor':
|
||||
'enter': 'core:confirm'
|
||||
'escape': 'core:cancel'
|
||||
'meta-w': 'core:cancel'
|
||||
@@ -0,0 +1,102 @@
|
||||
'.platform-win32':
|
||||
# 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-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-left': 'window:focus-previous-pane'
|
||||
'ctrl-k ctrl-right': 'window:focus-next-pane'
|
||||
|
||||
'.platform-win32 .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'
|
||||
|
||||
'.platform-win32 .editor:not(.mini)':
|
||||
# Atom specific
|
||||
'alt-ctrl-z': 'editor:checkout-head-revision'
|
||||
'ctrl-<': 'editor:scroll-to-cursor'
|
||||
'alt-ctrl-f': 'editor:fold-selection'
|
||||
'ctrl-=': 'editor:auto-indent'
|
||||
|
||||
# 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-line'
|
||||
'ctrl-D': 'editor:duplicate-line'
|
||||
|
||||
'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
|
||||
'.platform-win32 input:not(.hidden-input), .platform-win32 .native-key-bindings':
|
||||
'ctrl-z': 'native!'
|
||||
'ctrl-Z': 'native!'
|
||||
'ctrl-x': 'native!'
|
||||
'ctrl-c': 'native!'
|
||||
'ctrl-v': 'native!'
|
||||
@@ -0,0 +1,180 @@
|
||||
'menu': [
|
||||
{
|
||||
label: 'Atom'
|
||||
submenu: [
|
||||
{ label: 'About Atom', command: 'application:about' }
|
||||
{ label: "VERSION", enabled: false }
|
||||
{ label: "Install update", command: 'application:install-update', visible: false }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Preferences...', command: 'application:show-settings' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Hide Atom', command: 'application:hide' }
|
||||
{ label: 'Hide Others', command: 'application:hide-other-applications' }
|
||||
{ label: 'Show All', command: 'application:unhide-all-applications' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Quit', command: 'application:quit' }
|
||||
]
|
||||
}
|
||||
{
|
||||
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: 'Save', command: 'core:save' }
|
||||
{ label: 'Save As...', command: 'core:save-as' }
|
||||
{ label: 'Save All', command: 'window:save-all' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Close Buffer', command: 'core:close' }
|
||||
{ label: 'Close All Buffers', command: 'pane:close' }
|
||||
{ label: 'Close Window', command: 'window:close' }
|
||||
]
|
||||
}
|
||||
|
||||
{
|
||||
label: 'Edit'
|
||||
submenu: [
|
||||
{ label: 'Undo', command: 'core:undo' }
|
||||
{ label: 'Redo', command: 'core:redo' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Cut', command: 'core:cut' }
|
||||
{ label: 'Copy', command: 'core:copy' }
|
||||
{ label: 'Copy Path', 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: 'Duplicate Line', command: 'editor:duplicate-line' }
|
||||
{ label: 'Delete Line', command: 'editor:delete-line' }
|
||||
{ label: 'Join Lines', command: 'editor:join-line' }
|
||||
]
|
||||
}
|
||||
{
|
||||
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: 'Fold 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: 'Selection'
|
||||
submenu: [
|
||||
{ label: 'Add Selection Above', command: 'editor:add-selection-above' }
|
||||
{ label: 'Add Selection Below', command: 'editor:add-selection-below' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Select to Top', command: 'core:select-to-top' }
|
||||
{ label: 'Select to Bottom', 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 Word', command: 'editor:select-to-beginning-of-word' }
|
||||
{ label: 'Select to Beginning of Line', 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 Word', command: 'editor:select-to-end-of-word' }
|
||||
{ label: 'Select to End of Line', command: 'editor:select-to-end-of-line' }
|
||||
]
|
||||
}
|
||||
|
||||
{
|
||||
label: 'Movement'
|
||||
submenu: [
|
||||
{ label: 'Move to Top', command: 'core:move-to-top' }
|
||||
{ label: 'Move to Bottom', command: 'core:move-to-bottom' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Move to Beginning of Line', command: 'editor:move-to-beginning-of-line' }
|
||||
{ label: 'Move to First Character of Line', command: 'editor:move-to-first-character-of-line' }
|
||||
{ label: 'Move to End of Line', command: 'editor:move-to-end-of-line' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Move to Beginning of Word', command: 'editor:move-to-beginning-of-word' }
|
||||
{ label: 'Move to End of Word', command: 'editor:move-to-end-of-word' }
|
||||
{ label: 'Move to Next Word', command: 'editor:move-to-next-word-boundary' }
|
||||
{ label: 'Move to Previous Word', command: 'editor:move-to-previous-word-boundary' }
|
||||
]
|
||||
}
|
||||
|
||||
{
|
||||
label: 'Find'
|
||||
submenu: []
|
||||
}
|
||||
|
||||
{
|
||||
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: 'Packages'
|
||||
submenu: []
|
||||
}
|
||||
|
||||
{
|
||||
label: 'Window'
|
||||
submenu: [
|
||||
{ label: 'Minimize', command: 'application:minimize' }
|
||||
{ label: 'Zoom', command: 'application:zoom' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Bring All to Front', command: 'application:bring-all-windows-to-front' }
|
||||
]
|
||||
}
|
||||
|
||||
{
|
||||
label: 'Help'
|
||||
submenu: [
|
||||
{ label: 'Documentation', command: 'application:open-documentation' }
|
||||
{ label: 'Report an Issue', command: 'application:report-issue' }
|
||||
{ type: 'separator' }
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,172 @@
|
||||
'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 Line', command: 'editor:duplicate-line' }
|
||||
{ label: 'D&elete Line', command: 'editor:delete-line' }
|
||||
{ label: '&Join Lines', command: 'editor:join-line' }
|
||||
]
|
||||
}
|
||||
{
|
||||
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' }
|
||||
{ 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: '&Movement'
|
||||
submenu: [
|
||||
{ label: 'Move to &Top', command: 'core:move-to-top' }
|
||||
{ label: 'Move to &Bottom', command: 'core:move-to-bottom' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Move to Beginning of &Line', command: 'editor:move-to-beginning-of-line' }
|
||||
{ label: 'Move to &First Character of Line', command: 'editor:move-to-first-character-of-line' }
|
||||
{ label: 'Move to &End of Line', command: 'editor:move-to-end-of-line' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Move to Beginning of &Word', command: 'editor:move-to-beginning-of-word' }
|
||||
{ label: 'Move to End of Wor&d', command: 'editor:move-to-end-of-word' }
|
||||
{ label: 'Move to &Next Word', command: 'editor:move-to-next-word-boundary' }
|
||||
{ label: 'Move to &Previous Word', command: 'editor:move-to-previous-word-boundary' }
|
||||
]
|
||||
}
|
||||
|
||||
{
|
||||
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: "VERSION", enabled: false }
|
||||
{ label: "Install &update", command: 'application:install-update', visible: false }
|
||||
{ type: 'separator' }
|
||||
{ label: '&Documentation', command: 'application:open-documentation' }
|
||||
{ label: 'Report an &Issue', command: 'application:report-issue' }
|
||||
{ type: 'separator' }
|
||||
]
|
||||
}
|
||||
]
|
||||
+110
-101
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "atom",
|
||||
"version": "31.0.0",
|
||||
"main": "./src/main.js",
|
||||
"version": "39.0.0",
|
||||
"main": "./src/browser/main.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/atom/atom.git"
|
||||
@@ -9,109 +9,35 @@
|
||||
"bugs": {
|
||||
"url": "https://github.com/atom/atom/issues"
|
||||
},
|
||||
"atomShellVersion": "0.5.4",
|
||||
"atomShellVersion": "0.6.11",
|
||||
"dependencies": {
|
||||
"async": "0.2.6",
|
||||
"bootstrap": "git://github.com/twbs/bootstrap.git#v3.0.0",
|
||||
"coffee-script": "1.6.2",
|
||||
"bootstrap": "git://github.com/benogle/bootstrap.git",
|
||||
"clear-cut": "0.2.0",
|
||||
"coffee-script": "1.6.3",
|
||||
"coffeestack": "0.6.0",
|
||||
"first-mate": "0.2.0",
|
||||
"git-utils": "0.25.0",
|
||||
"emissary": "0.19.0",
|
||||
"first-mate": "0.5.0",
|
||||
"fs-plus": "0.9.0",
|
||||
"fuzzaldrin": "0.1.0",
|
||||
"git-utils": "0.29.0",
|
||||
"guid": "0.0.10",
|
||||
"jasmine-focused": "~0.14.0",
|
||||
"jasmine-focused": "~0.15.0",
|
||||
"mkdirp": "0.3.5",
|
||||
"less": "git://github.com/nathansobo/less.js.git",
|
||||
"less-cache": "0.8.0",
|
||||
"less-cache": "0.10.0",
|
||||
"nslog": "0.1.0",
|
||||
"oniguruma": "0.20.0",
|
||||
"oniguruma": "0.24.0",
|
||||
"optimist": "0.4.0",
|
||||
"pathwatcher": "0.5.0",
|
||||
"pathwatcher": "0.10.0",
|
||||
"pegjs": "0.7.0",
|
||||
"plist": "git://github.com/nathansobo/node-plist.git",
|
||||
"rimraf": "2.1.4",
|
||||
"scandal": "0.5.0",
|
||||
"season": "0.13.0",
|
||||
"q": "0.9.7",
|
||||
"scandal": "0.8.0",
|
||||
"season": "0.14.0",
|
||||
"semver": "1.1.4",
|
||||
"space-pen": "1.3.0",
|
||||
"tantamount": "0.5.0",
|
||||
"telepath": "0.8.1",
|
||||
"space-pen": "2.0.0",
|
||||
"telepath": "0.45.0",
|
||||
"temp": "0.5.0",
|
||||
"underscore": "1.4.4",
|
||||
"atom-light-ui": "0.4.0",
|
||||
"atom-light-syntax": "0.4.0",
|
||||
"atom-dark-ui": "0.4.0",
|
||||
"atom-dark-syntax": "0.4.0",
|
||||
"base16-tomorrow-dark-theme": "0.2.0",
|
||||
"solarized-dark-syntax": "0.3.0",
|
||||
"archive-view": "0.8.0",
|
||||
"autocomplete": "0.6.0",
|
||||
"autoflow": "0.3.0",
|
||||
"bookmarks": "0.4.0",
|
||||
"bracket-matcher": "0.5.0",
|
||||
"collaboration": "0.20.0",
|
||||
"command-logger": "0.4.0",
|
||||
"command-palette": "0.4.0",
|
||||
"editor-stats": "0.3.0",
|
||||
"exception-reporting": "0.3.0",
|
||||
"find-and-replace": "0.24.0",
|
||||
"fuzzy-finder": "0.7.0",
|
||||
"gfm": "0.5.0",
|
||||
"git-diff": "0.4.0",
|
||||
"gists": "0.3.0",
|
||||
"github-sign-in": "0.7.0",
|
||||
"go-to-line": "0.4.0",
|
||||
"grammar-selector": "0.5.0",
|
||||
"image-view": "0.6.0",
|
||||
"link": "0.4.0",
|
||||
"markdown-preview": "0.6.0",
|
||||
"metrics": "0.8.0",
|
||||
"package-generator": "0.10.0",
|
||||
"release-notes": "0.2.0",
|
||||
"settings-view": "0.27.0",
|
||||
"snippets": "0.6.0",
|
||||
"spell-check": "0.6.0",
|
||||
"status-bar": "0.8.0",
|
||||
"symbols-view": "0.8.0",
|
||||
"tabs": "0.5.0",
|
||||
"terminal": "0.10.0",
|
||||
"timecop": "0.5.0",
|
||||
"to-the-hubs": "0.6.0",
|
||||
"toml": "0.3.0",
|
||||
"tree-view": "0.8.0",
|
||||
"ui-demo": "0.8.0",
|
||||
"whitespace": "0.5.0",
|
||||
"wrap-guide": "0.3.0",
|
||||
"c-tmbundle": "1.0.0",
|
||||
"coffee-script-tmbundle": "1.0.0",
|
||||
"css-tmbundle": "1.0.0",
|
||||
"git-tmbundle": "1.0.0",
|
||||
"go-tmbundle": "1.0.0",
|
||||
"html-tmbundle": "1.0.0",
|
||||
"hyperlink-helper-tmbundle": "1.0.0",
|
||||
"java-tmbundle": "1.0.0",
|
||||
"javascript-tmbundle": "2.0.0",
|
||||
"json-tmbundle": "1.0.0",
|
||||
"less-tmbundle": "1.0.0",
|
||||
"make-tmbundle": "1.0.0",
|
||||
"mustache-tmbundle": "1.0.0",
|
||||
"objective-c-tmbundle": "1.0.0",
|
||||
"pegjs-tmbundle": "1.0.0",
|
||||
"perl-tmbundle": "1.0.0",
|
||||
"php-tmbundle": "1.0.0",
|
||||
"property-list-tmbundle": "1.0.0",
|
||||
"puppet-textmate-tmbundle": "1.0.0",
|
||||
"python-tmbundle": "1.0.0",
|
||||
"ruby-on-rails-tmbundle": "1.0.0",
|
||||
"ruby-tmbundle": "1.0.0",
|
||||
"sass-tmbundle": "1.0.0",
|
||||
"shellscript-tmbundle": "1.0.0",
|
||||
"source-tmbundle": "1.0.0",
|
||||
"sql-tmbundle": "1.0.0",
|
||||
"text-tmbundle": "1.0.0",
|
||||
"textmate-clojure": "1.0.0",
|
||||
"todo-tmbundle": "1.0.0",
|
||||
"xml-tmbundle": "1.0.0",
|
||||
"yaml-tmbundle": "1.0.0"
|
||||
"underscore-plus": "0.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"biscotto": "0.0.17",
|
||||
@@ -119,24 +45,107 @@
|
||||
"fstream": "0.1.24",
|
||||
"grunt": "~0.4.1",
|
||||
"grunt-cli": "~0.1.9",
|
||||
"grunt-coffeelint": "0.0.6",
|
||||
"grunt-coffeelint": "git://github.com/atom/grunt-coffeelint.git",
|
||||
"grunt-lesslint": "0.13.0",
|
||||
"grunt-cson": "0.5.0",
|
||||
"grunt-contrib-csslint": "~0.1.2",
|
||||
"grunt-contrib-coffee": "~0.7.0",
|
||||
"grunt-contrib-less": "~0.6.4",
|
||||
"grunt-contrib-less": "~0.8.0",
|
||||
"walkdir": "0.0.7",
|
||||
"ws": "0.4.27",
|
||||
"js-yaml": "~2.1.0",
|
||||
"grunt-markdown": "~0.4.0",
|
||||
"json-front-matter": "~0.1.3",
|
||||
"grunt-shell": "~0.3.1",
|
||||
"jasmine-node": "git://github.com/kevinsawicki/jasmine-node.git#short-stacks",
|
||||
"request": "~2.27.0"
|
||||
"jasmine-tagged": "0.2.0",
|
||||
"request": "~2.27.0",
|
||||
"unzip": "~0.1.9",
|
||||
"rcedit": "~0.1.2",
|
||||
"rimraf": "~2.2.2"
|
||||
},
|
||||
"packageDependencies": {
|
||||
"atom-light-ui": "0.8.0",
|
||||
"atom-light-syntax": "0.6.0",
|
||||
"atom-dark-ui": "0.8.0",
|
||||
"atom-dark-syntax": "0.6.0",
|
||||
"base16-tomorrow-dark-theme": "0.6.0",
|
||||
"solarized-dark-syntax": "0.4.0",
|
||||
"archive-view": "0.14.0",
|
||||
"autocomplete": "0.15.0",
|
||||
"autoflow": "0.9.0",
|
||||
"autosave": "0.7.0",
|
||||
"bookmarks": "0.13.0",
|
||||
"bracket-matcher": "0.12.0",
|
||||
"command-logger": "0.7.0",
|
||||
"command-palette": "0.10.0",
|
||||
"dev-live-reload": "0.17.0",
|
||||
"editor-stats": "0.7.0",
|
||||
"exception-reporting": "0.8.0",
|
||||
"find-and-replace": "0.49.0",
|
||||
"fuzzy-finder": "0.25.0",
|
||||
"gists": "0.11.0",
|
||||
"git-diff": "0.16.0",
|
||||
"github-sign-in": "0.11.0",
|
||||
"go-to-line": "0.10.0",
|
||||
"grammar-selector": "0.11.0",
|
||||
"image-view": "0.9.0",
|
||||
"keybinding-resolver": "0.5.0",
|
||||
"link": "0.9.0",
|
||||
"markdown-preview": "0.19.0",
|
||||
"metrics": "0.12.0",
|
||||
"package-generator": "0.21.0",
|
||||
"release-notes": "0.12.0",
|
||||
"settings-view": "0.47.0",
|
||||
"snippets": "0.15.0",
|
||||
"spell-check": "0.15.0",
|
||||
"status-bar": "0.22.0",
|
||||
"styleguide": "0.15.0",
|
||||
"symbols-view": "0.24.0",
|
||||
"tabs": "0.12.0",
|
||||
"terminal": "0.22.0",
|
||||
"timecop": "0.10.0",
|
||||
"to-the-hubs": "0.13.0",
|
||||
"tree-view": "0.39.0",
|
||||
"visual-bell": "0.4.0",
|
||||
"whitespace": "0.9.0",
|
||||
"wrap-guide": "0.6.0",
|
||||
"language-c": "0.2.0",
|
||||
"language-clojure": "0.1.0",
|
||||
"language-coffee-script": "0.3.0",
|
||||
"language-css": "0.2.0",
|
||||
"language-gfm": "0.9.0",
|
||||
"language-git": "0.3.0",
|
||||
"language-go": "0.2.0",
|
||||
"language-html": "0.2.0",
|
||||
"language-hyperlink": "0.3.0",
|
||||
"language-java": "0.2.0",
|
||||
"language-javascript": "0.3.0",
|
||||
"language-json": "0.2.0",
|
||||
"language-less": "0.1.0",
|
||||
"language-make": "0.1.0",
|
||||
"language-mustache": "0.1.0",
|
||||
"language-objective-c": "0.2.0",
|
||||
"language-pegjs": "0.1.0",
|
||||
"language-perl": "0.2.0",
|
||||
"language-php": "0.2.0",
|
||||
"language-property-list": "0.2.0",
|
||||
"language-puppet": "0.2.0",
|
||||
"language-python": "0.2.0",
|
||||
"language-ruby": "0.4.0",
|
||||
"language-ruby-on-rails": "0.3.0",
|
||||
"language-sass": "0.3.0",
|
||||
"language-shellscript": "0.2.0",
|
||||
"language-source": "0.2.0",
|
||||
"language-sql": "0.2.0",
|
||||
"language-text": "0.2.0",
|
||||
"language-todo": "0.2.0",
|
||||
"language-toml": "0.7.0",
|
||||
"language-xml": "0.2.0",
|
||||
"language-yaml": "0.1.0"
|
||||
},
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"preinstall": "true",
|
||||
"test": "script/test"
|
||||
"preinstall": "node -e 'process.exit(0)'",
|
||||
"test": "node script/test"
|
||||
}
|
||||
}
|
||||
|
||||
Arquivo executável
BIN
Arquivo binário não exibido.
|
Depois Largura: | Altura: | Tamanho: 52 KiB |
Arquivo binário não exibido.
|
Depois Largura: | Altura: | Tamanho: 345 KiB |
+33
-17
@@ -1,22 +1,38 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env node
|
||||
var safeExec = require('./utils/child-process-wrapper.js').safeExec;
|
||||
var path = require('path');
|
||||
|
||||
# exit on subprocess errors
|
||||
set -o errexit
|
||||
|
||||
exit_unless_npm_exists() {
|
||||
if ! hash npm 2> /dev/null; then
|
||||
echo "ERROR: Atom requires npm"
|
||||
exit 1
|
||||
fi
|
||||
// Executes an array of commands one by one.
|
||||
function executeCommands(commands, done, index) {
|
||||
index = (index == undefined ? 0 : index);
|
||||
if (index < commands.length) {
|
||||
var command = commands[index];
|
||||
var options = null;
|
||||
if (typeof command !== 'string') {
|
||||
options = command.options;
|
||||
command = command.command;
|
||||
}
|
||||
safeExec(command, options, executeCommands.bind(this, commands, done, index + 1));
|
||||
} else
|
||||
done(null);
|
||||
}
|
||||
|
||||
exit_unless_npm_exists
|
||||
// Join multiple commands into one line.
|
||||
function joinCommands() {
|
||||
var commandSeparator = process.platform == 'win32' ? '&' : ';';
|
||||
return Array.prototype.slice.call(arguments, 0).join(commandSeparator);
|
||||
}
|
||||
|
||||
git submodule --quiet sync
|
||||
git submodule --quiet update --recursive --init
|
||||
var echoNewLine = process.platform == 'win32' ? 'echo.' : 'echo';
|
||||
var commands = [
|
||||
'git submodule --quiet sync',
|
||||
'git submodule --quiet update --recursive --init',
|
||||
{command: joinCommands('cd vendor/apm', 'npm install --silent .'), options: {ignoreStdout: true}},
|
||||
{command: 'npm install --silent vendor/apm', options: {ignoreStdout: true}},
|
||||
echoNewLine,
|
||||
'node node_modules/atom-package-manager/bin/apm clean',
|
||||
'node node_modules/atom-package-manager/bin/apm install --silent',
|
||||
];
|
||||
|
||||
(cd vendor/apm && npm install --silent .)
|
||||
|
||||
npm install --silent vendor/apm
|
||||
echo ""
|
||||
./node_modules/.bin/apm install --silent
|
||||
process.chdir(path.dirname(__dirname));
|
||||
executeCommands(commands, process.exit);
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
@IF EXIST "%~dp0\node.exe" (
|
||||
"%~dp0\node.exe" "%~dp0\bootstrap" %*
|
||||
) ELSE (
|
||||
node "%~dp0\bootstrap" %*
|
||||
)
|
||||
|
||||
+10
-6
@@ -1,8 +1,12 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env node
|
||||
var cp = require('./utils/child-process-wrapper.js');
|
||||
var path = require('path');
|
||||
|
||||
set -e
|
||||
process.chdir(path.dirname(__dirname));
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
./script/bootstrap
|
||||
./node_modules/.bin/grunt "$@"
|
||||
cp.safeExec('node script/bootstrap', function() {
|
||||
// node node_modules/grunt-cli/bin/grunt "$@"
|
||||
var gruntPath = path.join('node_modules', 'grunt-cli', 'bin', 'grunt');
|
||||
var args = [gruntPath].concat(process.argv.slice(2));
|
||||
cp.safeSpawn(process.execPath, args, process.exit);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
@IF EXIST "%~dp0\node.exe" (
|
||||
"%~dp0\node.exe" "%~dp0\build" %*
|
||||
) ELSE (
|
||||
node "%~dp0\build" %*
|
||||
)
|
||||
+34
-13
@@ -1,18 +1,39 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env node
|
||||
var cp = require('./utils/child-process-wrapper.js');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
set -e
|
||||
process.chdir(path.dirname(__dirname));
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
if (process.platform != 'darwin')
|
||||
throw new Error('cibuild can not run on ' + process.platform + ' yet!');
|
||||
|
||||
rm -rf ~/.atom
|
||||
git clean -dff
|
||||
var homeDir = process.platform == 'win32' ? process.env.USERPROFILE : process.env.HOME;
|
||||
|
||||
ATOM_CREDENTIALS_FILE=/var/lib/jenkins/config/atomcredentials
|
||||
if [ -f $ATOM_CREDENTIALS_FILE ]; then
|
||||
. $ATOM_CREDENTIALS_FILE
|
||||
export ATOM_ACCESS_TOKEN=$ATOM_ACCESS_TOKEN # make it visibile to grunt.
|
||||
fi
|
||||
function readEnvironmentVariables() {
|
||||
var credentialsPath = '/var/lib/jenkins/config/atomcredentials';
|
||||
try {
|
||||
var credentials = fs.readFileSync(credentialsPath, 'utf8');
|
||||
var lines = credentials.trim().split('\n');
|
||||
for (i in lines) {
|
||||
var parts = lines[i].split('=');
|
||||
var key = parts[0].trim();
|
||||
var value = parts[1].trim().substr(1, parts[1].length - 2);
|
||||
process.env[key] = value;
|
||||
}
|
||||
} catch(error) { }
|
||||
}
|
||||
|
||||
./script/bootstrap
|
||||
./node_modules/.bin/apm clean
|
||||
./node_modules/.bin/grunt ci --stack --no-color
|
||||
readEnvironmentVariables();
|
||||
cp.safeExec.bind(global, 'node script/bootstrap', function(error) {
|
||||
if (error)
|
||||
process.exit(1);
|
||||
var async = require('async');
|
||||
async.series([
|
||||
require('rimraf').bind(global, path.join(homeDir, '.atom')),
|
||||
cp.safeExec.bind(global, 'git clean -dff'),
|
||||
cp.safeExec.bind(global, 'node node_modules/grunt-cli/bin/grunt ci --stack --no-color'),
|
||||
], function(error) {
|
||||
process.exit(error ? 1 : 0);
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -8,7 +8,7 @@ set -ex
|
||||
cd "$(dirname "$0")/../.."
|
||||
rm -fr node_modules
|
||||
./script/bootstrap
|
||||
./node_modules/.bin/grunt --build-dir="$BUILT_PRODUCTS_DIR" deploy
|
||||
./node_modules/.bin/grunt --no-color --build-dir="$BUILT_PRODUCTS_DIR" deploy
|
||||
|
||||
echo "TARGET_BUILD_DIR=$BUILT_PRODUCTS_DIR"
|
||||
echo "FULL_PRODUCT_NAME=Atom.app"
|
||||
|
||||
+7
-6
@@ -1,8 +1,9 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env node
|
||||
var safeExec = require('./utils/child-process-wrapper.js').safeExec;
|
||||
var path = require('path');
|
||||
|
||||
set -e
|
||||
process.chdir(path.dirname(__dirname));
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
./script/bootstrap
|
||||
./node_modules/.bin/grunt ci --stack --no-color
|
||||
safeExec('node script/bootstrap', function() {
|
||||
safeExec('node node_modules/grunt-cli/bin/grunt ci --stack --no-color', process.exit);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
var childProcess = require('child_process');
|
||||
|
||||
// Exit the process if the command failed and only call the callback if the
|
||||
// command succeed, output of the command would also be piped.
|
||||
exports.safeExec = function(command, options, callback) {
|
||||
if (!callback) {
|
||||
callback = options;
|
||||
options = {};
|
||||
}
|
||||
if (!options)
|
||||
options = {};
|
||||
|
||||
// This needed to be increased for `apm test` runs that generate many failures
|
||||
// The default is 200KB.
|
||||
options.maxBuffer = 1024 * 1024;
|
||||
|
||||
var child = childProcess.exec(command, options, function(error, stdout, stderr) {
|
||||
if (error)
|
||||
process.exit(error.code || 1);
|
||||
else
|
||||
callback(null);
|
||||
});
|
||||
child.stderr.pipe(process.stderr);
|
||||
if (!options.ignoreStdout)
|
||||
child.stdout.pipe(process.stdout);
|
||||
}
|
||||
|
||||
// Same with safeExec but call child_process.spawn instead.
|
||||
exports.safeSpawn = function(command, args, options, callback) {
|
||||
if (!callback) {
|
||||
callback = options;
|
||||
options = {};
|
||||
}
|
||||
var child = childProcess.spawn(command, args, options);
|
||||
child.stderr.pipe(process.stderr);
|
||||
child.stdout.pipe(process.stdout);
|
||||
child.on('exit', function(code) {
|
||||
if (code != 0)
|
||||
process.exit(code);
|
||||
else
|
||||
callback(null);
|
||||
});
|
||||
}
|
||||
@@ -15,14 +15,14 @@ describe "AtomPackage", ->
|
||||
describe "when the theme contains a single style file", ->
|
||||
it "loads and applies css", ->
|
||||
expect($(".editor").css("padding-bottom")).not.toBe "1234px"
|
||||
themePath = project.resolve('packages/theme-with-index-css')
|
||||
themePath = atom.project.resolve('packages/theme-with-index-css')
|
||||
theme = Package.load(themePath)
|
||||
theme.activate()
|
||||
expect($(".editor").css("padding-top")).toBe "1234px"
|
||||
|
||||
it "parses, loads and applies less", ->
|
||||
expect($(".editor").css("padding-bottom")).not.toBe "1234px"
|
||||
themePath = project.resolve('packages/theme-with-index-less')
|
||||
themePath = atom.project.resolve('packages/theme-with-index-less')
|
||||
theme = Package.load(themePath)
|
||||
theme.activate()
|
||||
expect($(".editor").css("padding-top")).toBe "4321px"
|
||||
@@ -33,7 +33,7 @@ describe "AtomPackage", ->
|
||||
expect($(".editor").css("padding-right")).not.toBe("102px")
|
||||
expect($(".editor").css("padding-bottom")).not.toBe("103px")
|
||||
|
||||
themePath = project.resolve('packages/theme-with-package-file')
|
||||
themePath = atom.project.resolve('packages/theme-with-package-file')
|
||||
theme = Package.load(themePath)
|
||||
theme.activate()
|
||||
expect($(".editor").css("padding-top")).toBe("101px")
|
||||
@@ -46,7 +46,7 @@ describe "AtomPackage", ->
|
||||
expect($(".editor").css("padding-right")).not.toBe "20px"
|
||||
expect($(".editor").css("padding-bottom")).not.toBe "30px"
|
||||
|
||||
themePath = project.resolve('packages/theme-without-package-file')
|
||||
themePath = atom.project.resolve('packages/theme-without-package-file')
|
||||
theme = Package.load(themePath)
|
||||
theme.activate()
|
||||
expect($(".editor").css("padding-top")).toBe "10px"
|
||||
@@ -55,7 +55,7 @@ describe "AtomPackage", ->
|
||||
|
||||
describe "reloading a theme", ->
|
||||
beforeEach ->
|
||||
themePath = project.resolve('packages/theme-with-package-file')
|
||||
themePath = atom.project.resolve('packages/theme-with-package-file')
|
||||
theme = Package.load(themePath)
|
||||
theme.activate()
|
||||
|
||||
@@ -66,7 +66,7 @@ describe "AtomPackage", ->
|
||||
|
||||
describe "events", ->
|
||||
beforeEach ->
|
||||
themePath = project.resolve('packages/theme-with-package-file')
|
||||
themePath = atom.project.resolve('packages/theme-with-package-file')
|
||||
theme = Package.load(themePath)
|
||||
theme.activate()
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
$ = require 'jquery'
|
||||
{View, $$} = require 'space-pen'
|
||||
_ = require 'underscore'
|
||||
{View, $, $$} = require '../src/space-pen-extensions'
|
||||
_ = require 'underscore-plus'
|
||||
{convertStackTrace} = require 'coffeestack'
|
||||
|
||||
sourceMaps = {}
|
||||
|
||||
+220
-103
@@ -1,46 +1,56 @@
|
||||
{$, $$, fs, RootView} = require 'atom'
|
||||
Exec = require('child_process').exec
|
||||
path = require 'path'
|
||||
ThemeManager = require '../src/theme-manager'
|
||||
|
||||
describe "the `atom` global", ->
|
||||
beforeEach ->
|
||||
window.rootView = new RootView
|
||||
atom.rootView = new RootView
|
||||
|
||||
describe "package lifecycle methods", ->
|
||||
describe ".loadPackage(name)", ->
|
||||
describe "when the package has deferred deserializers", ->
|
||||
it "requires the package's main module if one of its deferred deserializers is referenced", ->
|
||||
pack = atom.loadPackage('package-with-activation-events')
|
||||
pack = atom.packages.loadPackage('package-with-activation-events')
|
||||
spyOn(pack, 'activateStylesheets').andCallThrough()
|
||||
expect(pack.mainModule).toBeNull()
|
||||
object = deserialize({deserializer: 'Foo', data: 5})
|
||||
object = atom.deserializers.deserialize({deserializer: 'Foo', data: 5})
|
||||
expect(pack.mainModule).toBeDefined()
|
||||
expect(object.constructor.name).toBe 'Foo'
|
||||
expect(object.data).toBe 5
|
||||
expect(pack.activateStylesheets).toHaveBeenCalled()
|
||||
|
||||
it "continues if the package has an invalid package.json", ->
|
||||
spyOn(console, 'warn')
|
||||
atom.config.set("core.disabledPackages", [])
|
||||
expect(-> atom.packages.loadPackage("package-with-broken-package-json")).not.toThrow()
|
||||
|
||||
it "continues if the package has an invalid keymap", ->
|
||||
atom.config.set("core.disabledPackages", [])
|
||||
expect(-> atom.packages.loadPackage("package-with-broken-keymap")).not.toThrow()
|
||||
|
||||
describe ".unloadPackage(name)", ->
|
||||
describe "when the package is active", ->
|
||||
it "throws an error", ->
|
||||
pack = atom.activatePackage('package-with-main')
|
||||
expect(atom.isPackageLoaded(pack.name)).toBeTruthy()
|
||||
expect(atom.isPackageActive(pack.name)).toBeTruthy()
|
||||
expect( -> atom.unloadPackage(pack.name)).toThrow()
|
||||
expect(atom.isPackageLoaded(pack.name)).toBeTruthy()
|
||||
expect(atom.isPackageActive(pack.name)).toBeTruthy()
|
||||
pack = atom.packages.activatePackage('package-with-main')
|
||||
expect(atom.packages.isPackageLoaded(pack.name)).toBeTruthy()
|
||||
expect(atom.packages.isPackageActive(pack.name)).toBeTruthy()
|
||||
expect( -> atom.packages.unloadPackage(pack.name)).toThrow()
|
||||
expect(atom.packages.isPackageLoaded(pack.name)).toBeTruthy()
|
||||
expect(atom.packages.isPackageActive(pack.name)).toBeTruthy()
|
||||
|
||||
describe "when the package is not loaded", ->
|
||||
it "throws an error", ->
|
||||
expect(atom.isPackageLoaded('unloaded')).toBeFalsy()
|
||||
expect( -> atom.unloadPackage('unloaded')).toThrow()
|
||||
expect(atom.isPackageLoaded('unloaded')).toBeFalsy()
|
||||
expect(atom.packages.isPackageLoaded('unloaded')).toBeFalsy()
|
||||
expect( -> atom.packages.unloadPackage('unloaded')).toThrow()
|
||||
expect(atom.packages.isPackageLoaded('unloaded')).toBeFalsy()
|
||||
|
||||
describe "when the package is loaded", ->
|
||||
it "no longers reports it as being loaded", ->
|
||||
pack = atom.loadPackage('package-with-main')
|
||||
expect(atom.isPackageLoaded(pack.name)).toBeTruthy()
|
||||
atom.unloadPackage(pack.name)
|
||||
expect(atom.isPackageLoaded(pack.name)).toBeFalsy()
|
||||
pack = atom.packages.loadPackage('package-with-main')
|
||||
expect(atom.packages.isPackageLoaded(pack.name)).toBeTruthy()
|
||||
atom.packages.unloadPackage(pack.name)
|
||||
expect(atom.packages.isPackageLoaded(pack.name)).toBeFalsy()
|
||||
|
||||
describe ".activatePackage(id)", ->
|
||||
describe "atom packages", ->
|
||||
@@ -49,7 +59,7 @@ describe "the `atom` global", ->
|
||||
it "requires the module at the specified path", ->
|
||||
mainModule = require('./fixtures/packages/package-with-main/main-module')
|
||||
spyOn(mainModule, 'activate')
|
||||
pack = atom.activatePackage('package-with-main')
|
||||
pack = atom.packages.activatePackage('package-with-main')
|
||||
expect(mainModule.activate).toHaveBeenCalled()
|
||||
expect(pack.mainModule).toBe mainModule
|
||||
|
||||
@@ -57,15 +67,15 @@ describe "the `atom` global", ->
|
||||
it "requires index.coffee", ->
|
||||
indexModule = require('./fixtures/packages/package-with-index/index')
|
||||
spyOn(indexModule, 'activate')
|
||||
pack = atom.activatePackage('package-with-index')
|
||||
pack = atom.packages.activatePackage('package-with-index')
|
||||
expect(indexModule.activate).toHaveBeenCalled()
|
||||
expect(pack.mainModule).toBe indexModule
|
||||
|
||||
it "assigns config defaults from the module", ->
|
||||
expect(config.get('package-with-config-defaults.numbers.one')).toBeUndefined()
|
||||
atom.activatePackage('package-with-config-defaults')
|
||||
expect(config.get('package-with-config-defaults.numbers.one')).toBe 1
|
||||
expect(config.get('package-with-config-defaults.numbers.two')).toBe 2
|
||||
expect(atom.config.get('package-with-config-defaults.numbers.one')).toBeUndefined()
|
||||
atom.packages.activatePackage('package-with-config-defaults')
|
||||
expect(atom.config.get('package-with-config-defaults.numbers.one')).toBe 1
|
||||
expect(atom.config.get('package-with-config-defaults.numbers.two')).toBe 2
|
||||
|
||||
describe "when the package metadata includes activation events", ->
|
||||
[mainModule, pack] = []
|
||||
@@ -75,24 +85,24 @@ describe "the `atom` global", ->
|
||||
spyOn(mainModule, 'activate').andCallThrough()
|
||||
AtomPackage = require '../src/atom-package'
|
||||
spyOn(AtomPackage.prototype, 'requireMainModule').andCallThrough()
|
||||
pack = atom.activatePackage('package-with-activation-events')
|
||||
pack = atom.packages.activatePackage('package-with-activation-events')
|
||||
|
||||
it "defers requiring/activating the main module until an activation event bubbles to the root view", ->
|
||||
expect(pack.requireMainModule).not.toHaveBeenCalled()
|
||||
expect(mainModule.activate).not.toHaveBeenCalled()
|
||||
rootView.trigger 'activation-event'
|
||||
atom.rootView.trigger 'activation-event'
|
||||
expect(mainModule.activate).toHaveBeenCalled()
|
||||
|
||||
it "triggers the activation event on all handlers registered during activation", ->
|
||||
rootView.open()
|
||||
editor = rootView.getActiveView()
|
||||
atom.rootView.openSync()
|
||||
editorView = atom.rootView.getActiveView()
|
||||
eventHandler = jasmine.createSpy("activation-event")
|
||||
editor.command 'activation-event', eventHandler
|
||||
editor.trigger 'activation-event'
|
||||
editorView.command 'activation-event', eventHandler
|
||||
editorView.trigger 'activation-event'
|
||||
expect(mainModule.activate.callCount).toBe 1
|
||||
expect(mainModule.activationEventCallCount).toBe 1
|
||||
expect(eventHandler.callCount).toBe 1
|
||||
editor.trigger 'activation-event'
|
||||
editorView.trigger 'activation-event'
|
||||
expect(mainModule.activationEventCallCount).toBe 2
|
||||
expect(eventHandler.callCount).toBe 2
|
||||
expect(mainModule.activate.callCount).toBe 1
|
||||
@@ -101,23 +111,23 @@ describe "the `atom` global", ->
|
||||
it "does not throw an exception", ->
|
||||
spyOn(console, "error")
|
||||
spyOn(console, "warn").andCallThrough()
|
||||
expect(-> atom.activatePackage('package-without-module')).not.toThrow()
|
||||
expect(-> atom.packages.activatePackage('package-without-module')).not.toThrow()
|
||||
expect(console.error).not.toHaveBeenCalled()
|
||||
expect(console.warn).not.toHaveBeenCalled()
|
||||
|
||||
it "passes the activate method the package's previously serialized state if it exists", ->
|
||||
pack = atom.activatePackage("package-with-serialization")
|
||||
pack = atom.packages.activatePackage("package-with-serialization")
|
||||
expect(pack.mainModule.someNumber).not.toBe 77
|
||||
pack.mainModule.someNumber = 77
|
||||
atom.deactivatePackage("package-with-serialization")
|
||||
atom.packages.deactivatePackage("package-with-serialization")
|
||||
spyOn(pack.mainModule, 'activate').andCallThrough()
|
||||
atom.activatePackage("package-with-serialization")
|
||||
atom.packages.activatePackage("package-with-serialization")
|
||||
expect(pack.mainModule.activate).toHaveBeenCalledWith({someNumber: 77})
|
||||
|
||||
it "logs warning instead of throwing an exception if the package fails to load", ->
|
||||
config.set("core.disabledPackages", [])
|
||||
atom.config.set("core.disabledPackages", [])
|
||||
spyOn(console, "warn")
|
||||
expect(-> atom.activatePackage("package-that-throws-an-exception")).not.toThrow()
|
||||
expect(-> atom.packages.activatePackage("package-that-throws-an-exception")).not.toThrow()
|
||||
expect(console.warn).toHaveBeenCalled()
|
||||
|
||||
describe "keymap loading", ->
|
||||
@@ -127,31 +137,33 @@ describe "the `atom` global", ->
|
||||
element2 = $$ -> @div class: 'test-2'
|
||||
element3 = $$ -> @div class: 'test-3'
|
||||
|
||||
expect(keymap.bindingsForElement(element1)['ctrl-z']).toBeUndefined()
|
||||
expect(keymap.bindingsForElement(element2)['ctrl-z']).toBeUndefined()
|
||||
expect(keymap.bindingsForElement(element3)['ctrl-z']).toBeUndefined()
|
||||
expect(atom.keymap.keyBindingsForKeystrokeMatchingElement('ctrl-z', element1)).toHaveLength 0
|
||||
expect(atom.keymap.keyBindingsForKeystrokeMatchingElement('ctrl-z', element2)).toHaveLength 0
|
||||
expect(atom.keymap.keyBindingsForKeystrokeMatchingElement('ctrl-z', element3)).toHaveLength 0
|
||||
|
||||
atom.activatePackage("package-with-keymaps")
|
||||
atom.packages.activatePackage("package-with-keymaps")
|
||||
|
||||
expect(keymap.bindingsForElement(element1)['ctrl-z']).toBe "test-1"
|
||||
expect(keymap.bindingsForElement(element2)['ctrl-z']).toBe "test-2"
|
||||
expect(keymap.bindingsForElement(element3)['ctrl-z']).toBeUndefined()
|
||||
expect(atom.keymap.keyBindingsForKeystrokeMatchingElement('ctrl-z', element1)[0].command).toBe "test-1"
|
||||
expect(atom.keymap.keyBindingsForKeystrokeMatchingElement('ctrl-z', element2)[0].command).toBe "test-2"
|
||||
expect(atom.keymap.keyBindingsForKeystrokeMatchingElement('ctrl-z', element3)).toHaveLength 0
|
||||
|
||||
describe "when the metadata contains a 'keymaps' manifest", ->
|
||||
it "loads only the keymaps specified by the manifest, in the specified order", ->
|
||||
element1 = $$ -> @div class: 'test-1'
|
||||
element3 = $$ -> @div class: 'test-3'
|
||||
|
||||
expect(keymap.bindingsForElement(element1)['ctrl-z']).toBeUndefined()
|
||||
expect(atom.keymap.keyBindingsForKeystrokeMatchingElement('ctrl-z', element1)).toHaveLength 0
|
||||
|
||||
atom.activatePackage("package-with-keymaps-manifest")
|
||||
atom.packages.activatePackage("package-with-keymaps-manifest")
|
||||
|
||||
expect(keymap.bindingsForElement(element1)['ctrl-z']).toBe 'keymap-1'
|
||||
expect(keymap.bindingsForElement(element1)['ctrl-n']).toBe 'keymap-2'
|
||||
expect(keymap.bindingsForElement(element3)['ctrl-y']).toBeUndefined()
|
||||
expect(atom.keymap.keyBindingsForKeystrokeMatchingElement('ctrl-z', element1)[0].command).toBe 'keymap-1'
|
||||
expect(atom.keymap.keyBindingsForKeystrokeMatchingElement('ctrl-n', element1)[0].command).toBe 'keymap-2'
|
||||
expect(atom.keymap.keyBindingsForKeystrokeMatchingElement('ctrl-y', element3)).toHaveLength 0
|
||||
|
||||
describe "menu loading", ->
|
||||
beforeEach -> atom.contextMenu.definitions = []
|
||||
beforeEach ->
|
||||
atom.contextMenu.definitions = []
|
||||
atom.menu.template = []
|
||||
|
||||
describe "when the metadata does not contain a 'menus' manifest", ->
|
||||
it "loads all the .cson/.json files in the menus directory", ->
|
||||
@@ -159,8 +171,11 @@ describe "the `atom` global", ->
|
||||
|
||||
expect(atom.contextMenu.definitionsForElement(element)).toEqual []
|
||||
|
||||
atom.activatePackage("package-with-menus")
|
||||
atom.packages.activatePackage("package-with-menus")
|
||||
|
||||
expect(atom.menu.template.length).toBe 2
|
||||
expect(atom.menu.template[0].label).toBe "Second to Last"
|
||||
expect(atom.menu.template[1].label).toBe "Last"
|
||||
expect(atom.contextMenu.definitionsForElement(element)[0].label).toBe "Menu item 1"
|
||||
expect(atom.contextMenu.definitionsForElement(element)[1].label).toBe "Menu item 2"
|
||||
expect(atom.contextMenu.definitionsForElement(element)[2].label).toBe "Menu item 3"
|
||||
@@ -171,24 +186,30 @@ describe "the `atom` global", ->
|
||||
|
||||
expect(atom.contextMenu.definitionsForElement(element)).toEqual []
|
||||
|
||||
atom.activatePackage("package-with-menus-manifest")
|
||||
atom.packages.activatePackage("package-with-menus-manifest")
|
||||
|
||||
expect(atom.menu.template[0].label).toBe "Second to Last"
|
||||
expect(atom.menu.template[1].label).toBe "Last"
|
||||
expect(atom.contextMenu.definitionsForElement(element)[0].label).toBe "Menu item 2"
|
||||
expect(atom.contextMenu.definitionsForElement(element)[1].label).toBe "Menu item 1"
|
||||
expect(atom.contextMenu.definitionsForElement(element)[2]).toBeUndefined()
|
||||
|
||||
|
||||
describe "stylesheet loading", ->
|
||||
describe "when the metadata contains a 'stylesheets' manifest", ->
|
||||
it "loads stylesheets from the stylesheets directory as specified by the manifest", ->
|
||||
one = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/1.css")
|
||||
two = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/2.less")
|
||||
three = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/3.css")
|
||||
|
||||
one = atom.themes.stringToId(one)
|
||||
two = atom.themes.stringToId(two)
|
||||
three = atom.themes.stringToId(three)
|
||||
|
||||
expect(atom.themes.stylesheetElementForId(one)).not.toExist()
|
||||
expect(atom.themes.stylesheetElementForId(two)).not.toExist()
|
||||
expect(atom.themes.stylesheetElementForId(three)).not.toExist()
|
||||
|
||||
atom.activatePackage("package-with-stylesheets-manifest")
|
||||
atom.packages.activatePackage("package-with-stylesheets-manifest")
|
||||
|
||||
expect(atom.themes.stylesheetElementForId(one)).toExist()
|
||||
expect(atom.themes.stylesheetElementForId(two)).toExist()
|
||||
@@ -200,11 +221,17 @@ describe "the `atom` global", ->
|
||||
one = require.resolve("./fixtures/packages/package-with-stylesheets/stylesheets/1.css")
|
||||
two = require.resolve("./fixtures/packages/package-with-stylesheets/stylesheets/2.less")
|
||||
three = require.resolve("./fixtures/packages/package-with-stylesheets/stylesheets/3.css")
|
||||
|
||||
|
||||
one = atom.themes.stringToId(one)
|
||||
two = atom.themes.stringToId(two)
|
||||
three = atom.themes.stringToId(three)
|
||||
|
||||
expect(atom.themes.stylesheetElementForId(one)).not.toExist()
|
||||
expect(atom.themes.stylesheetElementForId(two)).not.toExist()
|
||||
expect(atom.themes.stylesheetElementForId(three)).not.toExist()
|
||||
|
||||
atom.activatePackage("package-with-stylesheets")
|
||||
atom.packages.activatePackage("package-with-stylesheets")
|
||||
expect(atom.themes.stylesheetElementForId(one)).toExist()
|
||||
expect(atom.themes.stylesheetElementForId(two)).toExist()
|
||||
expect(atom.themes.stylesheetElementForId(three)).toExist()
|
||||
@@ -212,90 +239,91 @@ describe "the `atom` global", ->
|
||||
|
||||
describe "grammar loading", ->
|
||||
it "loads the package's grammars", ->
|
||||
atom.activatePackage('package-with-grammars')
|
||||
expect(syntax.selectGrammar('a.alot').name).toBe 'Alot'
|
||||
expect(syntax.selectGrammar('a.alittle').name).toBe 'Alittle'
|
||||
atom.packages.activatePackage('package-with-grammars')
|
||||
expect(atom.syntax.selectGrammar('a.alot').name).toBe 'Alot'
|
||||
expect(atom.syntax.selectGrammar('a.alittle').name).toBe 'Alittle'
|
||||
|
||||
describe "scoped-property loading", ->
|
||||
it "loads the scoped properties", ->
|
||||
atom.activatePackage("package-with-scoped-properties")
|
||||
expect(syntax.getProperty ['.source.omg'], 'editor.increaseIndentPattern').toBe '^a'
|
||||
atom.packages.activatePackage("package-with-scoped-properties")
|
||||
expect(atom.syntax.getProperty ['.source.omg'], 'editor.increaseIndentPattern').toBe '^a'
|
||||
|
||||
describe "textmate packages", ->
|
||||
it "loads the package's grammars", ->
|
||||
expect(syntax.selectGrammar("file.rb").name).toBe "Null Grammar"
|
||||
atom.activatePackage('ruby-tmbundle', sync: true)
|
||||
expect(syntax.selectGrammar("file.rb").name).toBe "Ruby"
|
||||
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Null Grammar"
|
||||
atom.packages.activatePackage('language-ruby', sync: true)
|
||||
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Ruby"
|
||||
|
||||
it "translates the package's scoped properties to Atom terms", ->
|
||||
expect(syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
|
||||
atom.activatePackage('ruby-tmbundle', sync: true)
|
||||
expect(syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBe '# '
|
||||
expect(atom.syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
|
||||
atom.packages.activatePackage('language-ruby', sync: true)
|
||||
expect(atom.syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBe '# '
|
||||
|
||||
describe "when the package has no grammars but does have preferences", ->
|
||||
it "loads the package's preferences as scoped properties", ->
|
||||
jasmine.unspy(window, 'setTimeout')
|
||||
spyOn(syntax, 'addProperties').andCallThrough()
|
||||
spyOn(atom.syntax, 'addProperties').andCallThrough()
|
||||
|
||||
atom.activatePackage('package-with-preferences-tmbundle')
|
||||
atom.packages.activatePackage('package-with-preferences-tmbundle')
|
||||
|
||||
waitsFor ->
|
||||
syntax.addProperties.callCount > 0
|
||||
atom.syntax.addProperties.callCount > 0
|
||||
|
||||
runs ->
|
||||
expect(syntax.getProperty(['.source.pref'], 'editor.increaseIndentPattern')).toBe '^abc$'
|
||||
expect(atom.syntax.getProperty(['.source.pref'], 'editor.increaseIndentPattern')).toBe '^abc$'
|
||||
|
||||
describe ".deactivatePackage(id)", ->
|
||||
describe "atom packages", ->
|
||||
it "calls `deactivate` on the package's main module if activate was successful", ->
|
||||
pack = atom.activatePackage("package-with-deactivate")
|
||||
expect(atom.isPackageActive("package-with-deactivate")).toBeTruthy()
|
||||
pack = atom.packages.activatePackage("package-with-deactivate")
|
||||
expect(atom.packages.isPackageActive("package-with-deactivate")).toBeTruthy()
|
||||
spyOn(pack.mainModule, 'deactivate').andCallThrough()
|
||||
|
||||
atom.deactivatePackage("package-with-deactivate")
|
||||
atom.packages.deactivatePackage("package-with-deactivate")
|
||||
expect(pack.mainModule.deactivate).toHaveBeenCalled()
|
||||
expect(atom.isPackageActive("package-with-module")).toBeFalsy()
|
||||
expect(atom.packages.isPackageActive("package-with-module")).toBeFalsy()
|
||||
|
||||
spyOn(console, 'warn')
|
||||
badPack = atom.activatePackage("package-that-throws-on-activate")
|
||||
expect(atom.isPackageActive("package-that-throws-on-activate")).toBeTruthy()
|
||||
badPack = atom.packages.activatePackage("package-that-throws-on-activate")
|
||||
expect(atom.packages.isPackageActive("package-that-throws-on-activate")).toBeTruthy()
|
||||
spyOn(badPack.mainModule, 'deactivate').andCallThrough()
|
||||
|
||||
atom.deactivatePackage("package-that-throws-on-activate")
|
||||
atom.packages.deactivatePackage("package-that-throws-on-activate")
|
||||
expect(badPack.mainModule.deactivate).not.toHaveBeenCalled()
|
||||
expect(atom.isPackageActive("package-that-throws-on-activate")).toBeFalsy()
|
||||
expect(atom.packages.isPackageActive("package-that-throws-on-activate")).toBeFalsy()
|
||||
|
||||
it "does not serialize packages that have not been activated called on their main module", ->
|
||||
spyOn(console, 'warn')
|
||||
badPack = atom.activatePackage("package-that-throws-on-activate")
|
||||
badPack = atom.packages.activatePackage("package-that-throws-on-activate")
|
||||
spyOn(badPack.mainModule, 'serialize').andCallThrough()
|
||||
|
||||
atom.deactivatePackage("package-that-throws-on-activate")
|
||||
atom.packages.deactivatePackage("package-that-throws-on-activate")
|
||||
expect(badPack.mainModule.serialize).not.toHaveBeenCalled()
|
||||
|
||||
it "absorbs exceptions that are thrown by the package module's serialize methods", ->
|
||||
spyOn(console, 'error')
|
||||
atom.activatePackage('package-with-serialize-error', immediate: true)
|
||||
atom.activatePackage('package-with-serialization', immediate: true)
|
||||
atom.deactivatePackages()
|
||||
atom.packages.activatePackage('package-with-serialize-error', immediate: true)
|
||||
atom.packages.activatePackage('package-with-serialization', immediate: true)
|
||||
atom.packages.deactivatePackages()
|
||||
expect(atom.packages.packageStates['package-with-serialize-error']).toBeUndefined()
|
||||
expect(atom.packages.packageStates['package-with-serialization']).toEqual someNumber: 1
|
||||
expect(console.error).toHaveBeenCalled()
|
||||
|
||||
it "removes the package's grammars", ->
|
||||
atom.activatePackage('package-with-grammars')
|
||||
atom.deactivatePackage('package-with-grammars')
|
||||
expect(syntax.selectGrammar('a.alot').name).toBe 'Null Grammar'
|
||||
expect(syntax.selectGrammar('a.alittle').name).toBe 'Null Grammar'
|
||||
atom.packages.activatePackage('package-with-grammars')
|
||||
atom.packages.deactivatePackage('package-with-grammars')
|
||||
expect(atom.syntax.selectGrammar('a.alot').name).toBe 'Null Grammar'
|
||||
expect(atom.syntax.selectGrammar('a.alittle').name).toBe 'Null Grammar'
|
||||
|
||||
it "removes the package's keymaps", ->
|
||||
atom.activatePackage('package-with-keymaps')
|
||||
atom.deactivatePackage('package-with-keymaps')
|
||||
expect(keymap.bindingsForElement($$ -> @div class: 'test-1')['ctrl-z']).toBeUndefined()
|
||||
expect(keymap.bindingsForElement($$ -> @div class: 'test-2')['ctrl-z']).toBeUndefined()
|
||||
atom.packages.activatePackage('package-with-keymaps')
|
||||
atom.packages.deactivatePackage('package-with-keymaps')
|
||||
expect(atom.keymap.keyBindingsForKeystrokeMatchingElement('ctrl-z', $$ -> @div class: 'test-1')).toHaveLength 0
|
||||
expect(atom.keymap.keyBindingsForKeystrokeMatchingElement('ctrl-z', $$ -> @div class: 'test-2')).toHaveLength 0
|
||||
|
||||
it "removes the package's stylesheets", ->
|
||||
atom.activatePackage('package-with-stylesheets')
|
||||
atom.deactivatePackage('package-with-stylesheets')
|
||||
atom.packages.activatePackage('package-with-stylesheets')
|
||||
atom.packages.deactivatePackage('package-with-stylesheets')
|
||||
one = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/1.css")
|
||||
two = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/2.less")
|
||||
three = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/3.css")
|
||||
@@ -304,20 +332,109 @@ describe "the `atom` global", ->
|
||||
expect(atom.themes.stylesheetElementForId(three)).not.toExist()
|
||||
|
||||
it "removes the package's scoped-properties", ->
|
||||
atom.activatePackage("package-with-scoped-properties")
|
||||
expect(syntax.getProperty ['.source.omg'], 'editor.increaseIndentPattern').toBe '^a'
|
||||
atom.deactivatePackage("package-with-scoped-properties")
|
||||
expect(syntax.getProperty ['.source.omg'], 'editor.increaseIndentPattern').toBeUndefined()
|
||||
atom.packages.activatePackage("package-with-scoped-properties")
|
||||
expect(atom.syntax.getProperty ['.source.omg'], 'editor.increaseIndentPattern').toBe '^a'
|
||||
atom.packages.deactivatePackage("package-with-scoped-properties")
|
||||
expect(atom.syntax.getProperty ['.source.omg'], 'editor.increaseIndentPattern').toBeUndefined()
|
||||
|
||||
describe "textmate packages", ->
|
||||
it "removes the package's grammars", ->
|
||||
expect(syntax.selectGrammar("file.rb").name).toBe "Null Grammar"
|
||||
atom.activatePackage('ruby-tmbundle', sync: true)
|
||||
expect(syntax.selectGrammar("file.rb").name).toBe "Ruby"
|
||||
atom.deactivatePackage('ruby-tmbundle')
|
||||
expect(syntax.selectGrammar("file.rb").name).toBe "Null Grammar"
|
||||
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Null Grammar"
|
||||
atom.packages.activatePackage('language-ruby', sync: true)
|
||||
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Ruby"
|
||||
atom.packages.deactivatePackage('language-ruby')
|
||||
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Null Grammar"
|
||||
|
||||
it "removes the package's scoped properties", ->
|
||||
atom.activatePackage('ruby-tmbundle', sync: true)
|
||||
atom.deactivatePackage('ruby-tmbundle')
|
||||
expect(syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
|
||||
atom.packages.activatePackage('language-ruby', sync: true)
|
||||
atom.packages.deactivatePackage('language-ruby')
|
||||
expect(atom.syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
|
||||
|
||||
describe ".activate()", ->
|
||||
packageActivator = null
|
||||
themeActivator = null
|
||||
|
||||
beforeEach ->
|
||||
spyOn(console, 'warn')
|
||||
atom.packages.loadPackages()
|
||||
|
||||
loadedPackages = atom.packages.getLoadedPackages()
|
||||
expect(loadedPackages.length).toBeGreaterThan 0
|
||||
|
||||
packageActivator = spyOn(atom.packages, 'activatePackages')
|
||||
themeActivator = spyOn(atom.themes, 'activatePackages')
|
||||
|
||||
afterEach ->
|
||||
atom.packages.unloadPackages()
|
||||
|
||||
Syntax = require '../src/syntax'
|
||||
atom.syntax = window.syntax = new Syntax()
|
||||
|
||||
it "activates all the packages, and none of the themes", ->
|
||||
atom.packages.activate()
|
||||
|
||||
expect(packageActivator).toHaveBeenCalled()
|
||||
expect(themeActivator).toHaveBeenCalled()
|
||||
|
||||
packages = packageActivator.mostRecentCall.args[0]
|
||||
expect(['atom', 'textmate']).toContain(pack.getType()) for pack in packages
|
||||
|
||||
themes = themeActivator.mostRecentCall.args[0]
|
||||
expect(['theme']).toContain(theme.getType()) for theme in themes
|
||||
|
||||
describe ".en/disablePackage()", ->
|
||||
describe "with packages", ->
|
||||
it ".enablePackage() enables a disabled package", ->
|
||||
packageName = 'package-with-main'
|
||||
atom.config.pushAtKeyPath('core.disabledPackages', packageName)
|
||||
atom.packages.observeDisabledPackages()
|
||||
expect(atom.config.get('core.disabledPackages')).toContain packageName
|
||||
|
||||
pack = atom.packages.enablePackage(packageName)
|
||||
|
||||
loadedPackages = atom.packages.getLoadedPackages()
|
||||
activatedPackages = atom.packages.getActivePackages()
|
||||
expect(loadedPackages).toContain(pack)
|
||||
expect(activatedPackages).toContain(pack)
|
||||
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
|
||||
|
||||
it ".disablePackage() disables an enabled package", ->
|
||||
packageName = 'package-with-main'
|
||||
atom.packages.activatePackage(packageName)
|
||||
atom.packages.observeDisabledPackages()
|
||||
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
|
||||
|
||||
pack = atom.packages.disablePackage(packageName)
|
||||
|
||||
activatedPackages = atom.packages.getActivePackages()
|
||||
expect(activatedPackages).not.toContain(pack)
|
||||
expect(atom.config.get('core.disabledPackages')).toContain packageName
|
||||
|
||||
describe "with themes", ->
|
||||
beforeEach ->
|
||||
atom.themes.activateThemes()
|
||||
|
||||
afterEach ->
|
||||
atom.themes.deactivateThemes()
|
||||
atom.config.unobserve('core.themes')
|
||||
|
||||
it ".enablePackage() and .disablePackage() enables and disables a theme", ->
|
||||
packageName = 'theme-with-package-file'
|
||||
|
||||
expect(atom.config.get('core.themes')).not.toContain packageName
|
||||
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
|
||||
|
||||
# enabling of theme
|
||||
pack = atom.packages.enablePackage(packageName)
|
||||
activatedPackages = atom.packages.getActivePackages()
|
||||
expect(activatedPackages).toContain(pack)
|
||||
expect(atom.config.get('core.themes')).toContain packageName
|
||||
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
|
||||
|
||||
# disabling of theme
|
||||
pack = atom.packages.disablePackage(packageName)
|
||||
activatedPackages = atom.packages.getActivePackages()
|
||||
expect(activatedPackages).not.toContain(pack)
|
||||
expect(atom.config.get('core.themes')).not.toContain packageName
|
||||
expect(atom.config.get('core.themes')).not.toContain packageName
|
||||
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
|
||||
|
||||
@@ -1,33 +1,36 @@
|
||||
{fs} = require 'atom'
|
||||
path = require 'path'
|
||||
temp = require 'temp'
|
||||
installer = require '../src/command-installer'
|
||||
|
||||
describe "install(commandPath, callback)", ->
|
||||
directory = '/tmp/install-atom-command/atom'
|
||||
commandPath = "#{directory}/source"
|
||||
destinationPath = "#{directory}/bin/source"
|
||||
directory = path.join(temp.dir, 'install-atom-command', 'atom')
|
||||
commandPath = path.join(directory, 'source')
|
||||
destinationPath = path.join(directory, 'bin', 'source')
|
||||
|
||||
beforeEach ->
|
||||
spyOn(installer, 'findInstallDirectory').andCallFake (callback) ->
|
||||
callback(directory)
|
||||
|
||||
fs.remove(directory) if fs.exists(directory)
|
||||
fs.removeSync(directory) if fs.existsSync(directory)
|
||||
|
||||
it "symlinks the command and makes it executable", ->
|
||||
fs.writeSync(commandPath, 'test')
|
||||
expect(fs.isFileSync(commandPath)).toBeTruthy()
|
||||
expect(fs.isExecutableSync(commandPath)).toBeFalsy()
|
||||
expect(fs.isFileSync(destinationPath)).toBeFalsy()
|
||||
describe "on #darwin", ->
|
||||
it "symlinks the command and makes it executable", ->
|
||||
fs.writeFileSync(commandPath, 'test')
|
||||
expect(fs.isFileSync(commandPath)).toBeTruthy()
|
||||
expect(fs.isExecutableSync(commandPath)).toBeFalsy()
|
||||
expect(fs.isFileSync(destinationPath)).toBeFalsy()
|
||||
|
||||
installDone = false
|
||||
installError = null
|
||||
installer.install commandPath, (error) ->
|
||||
installDone = true
|
||||
installError = error
|
||||
installDone = false
|
||||
installError = null
|
||||
installer.install commandPath, (error) ->
|
||||
installDone = true
|
||||
installError = error
|
||||
|
||||
waitsFor -> installDone
|
||||
waitsFor -> installDone
|
||||
|
||||
runs ->
|
||||
expect(installError).toBeNull()
|
||||
expect(fs.isFileSync(destinationPath)).toBeTruthy()
|
||||
expect(fs.realpathSync(destinationPath)).toBe fs.realpathSync(commandPath)
|
||||
expect(fs.isExecutableSync(destinationPath)).toBeTruthy()
|
||||
runs ->
|
||||
expect(installError).toBeNull()
|
||||
expect(fs.isFileSync(destinationPath)).toBeTruthy()
|
||||
expect(fs.realpathSync(destinationPath)).toBe fs.realpathSync(commandPath)
|
||||
expect(fs.isExecutableSync(destinationPath)).toBeTruthy()
|
||||
|
||||
+155
-117
@@ -1,265 +1,303 @@
|
||||
{fs} = require 'atom'
|
||||
path = require 'path'
|
||||
temp = require 'temp'
|
||||
CSON = require 'season'
|
||||
|
||||
describe "Config", ->
|
||||
dotAtomPath = path.join(temp.dir, 'dot-atom-dir')
|
||||
|
||||
describe ".get(keyPath)", ->
|
||||
it "allows a key path's value to be read", ->
|
||||
expect(config.set("foo.bar.baz", 42)).toBe 42
|
||||
expect(config.get("foo.bar.baz")).toBe 42
|
||||
expect(config.get("bogus.key.path")).toBeUndefined()
|
||||
expect(atom.config.set("foo.bar.baz", 42)).toBe 42
|
||||
expect(atom.config.get("foo.bar.baz")).toBe 42
|
||||
expect(atom.config.get("bogus.key.path")).toBeUndefined()
|
||||
|
||||
it "returns a deep clone of the key path's value", ->
|
||||
config.set('value', array: [1, b: 2, 3])
|
||||
retrievedValue = config.get('value')
|
||||
atom.config.set('value', array: [1, b: 2, 3])
|
||||
retrievedValue = atom.config.get('value')
|
||||
retrievedValue.array[0] = 4
|
||||
retrievedValue.array[1].b = 2.1
|
||||
expect(config.get('value')).toEqual(array: [1, b: 2, 3])
|
||||
expect(atom.config.get('value')).toEqual(array: [1, b: 2, 3])
|
||||
|
||||
describe ".set(keyPath, value)", ->
|
||||
it "allows a key path's value to be written", ->
|
||||
expect(config.set("foo.bar.baz", 42)).toBe 42
|
||||
expect(config.get("foo.bar.baz")).toBe 42
|
||||
expect(atom.config.set("foo.bar.baz", 42)).toBe 42
|
||||
expect(atom.config.get("foo.bar.baz")).toBe 42
|
||||
|
||||
it "updates observers and saves when a key path is set", ->
|
||||
observeHandler = jasmine.createSpy "observeHandler"
|
||||
config.observe "foo.bar.baz", observeHandler
|
||||
atom.config.observe "foo.bar.baz", observeHandler
|
||||
observeHandler.reset()
|
||||
|
||||
config.set("foo.bar.baz", 42)
|
||||
atom.config.set("foo.bar.baz", 42)
|
||||
|
||||
expect(config.save).toHaveBeenCalled()
|
||||
expect(observeHandler).toHaveBeenCalledWith 42
|
||||
expect(atom.config.save).toHaveBeenCalled()
|
||||
expect(observeHandler).toHaveBeenCalledWith 42, {previous: undefined}
|
||||
|
||||
describe "when the value equals the default value", ->
|
||||
it "does not store the value", ->
|
||||
config.setDefaults("foo", same: 1, changes: 1)
|
||||
expect(config.settings.foo).toBeUndefined()
|
||||
config.set('foo.same', 1)
|
||||
config.set('foo.changes', 2)
|
||||
expect(config.settings.foo).toEqual {changes: 2}
|
||||
atom.config.setDefaults("foo", same: 1, changes: 1)
|
||||
expect(atom.config.settings.foo).toBeUndefined()
|
||||
atom.config.set('foo.same', 1)
|
||||
atom.config.set('foo.changes', 2)
|
||||
expect(atom.config.settings.foo).toEqual {changes: 2}
|
||||
|
||||
config.set('foo.changes', 1)
|
||||
expect(config.settings.foo).toEqual {}
|
||||
atom.config.set('foo.changes', 1)
|
||||
expect(atom.config.settings.foo).toEqual {}
|
||||
|
||||
describe ".toggle(keyPath)", ->
|
||||
it "negates the boolean value of the current key path value", ->
|
||||
atom.config.set('foo.a', 1)
|
||||
atom.config.toggle('foo.a')
|
||||
expect(atom.config.get('foo.a')).toBe false
|
||||
|
||||
atom.config.set('foo.a', '')
|
||||
atom.config.toggle('foo.a')
|
||||
expect(atom.config.get('foo.a')).toBe true
|
||||
|
||||
atom.config.set('foo.a', null)
|
||||
atom.config.toggle('foo.a')
|
||||
expect(atom.config.get('foo.a')).toBe true
|
||||
|
||||
atom.config.set('foo.a', true)
|
||||
atom.config.toggle('foo.a')
|
||||
expect(atom.config.get('foo.a')).toBe false
|
||||
|
||||
describe ".pushAtKeyPath(keyPath, value)", ->
|
||||
it "pushes the given value to the array at the key path and updates observers", ->
|
||||
config.set("foo.bar.baz", ["a"])
|
||||
atom.config.set("foo.bar.baz", ["a"])
|
||||
observeHandler = jasmine.createSpy "observeHandler"
|
||||
config.observe "foo.bar.baz", observeHandler
|
||||
atom.config.observe "foo.bar.baz", observeHandler
|
||||
observeHandler.reset()
|
||||
|
||||
expect(config.pushAtKeyPath("foo.bar.baz", "b")).toBe 2
|
||||
expect(config.get("foo.bar.baz")).toEqual ["a", "b"]
|
||||
expect(observeHandler).toHaveBeenCalledWith config.get("foo.bar.baz")
|
||||
expect(atom.config.pushAtKeyPath("foo.bar.baz", "b")).toBe 2
|
||||
expect(atom.config.get("foo.bar.baz")).toEqual ["a", "b"]
|
||||
expect(observeHandler).toHaveBeenCalledWith atom.config.get("foo.bar.baz"), {previous: ['a']}
|
||||
|
||||
describe ".unshiftAtKeyPath(keyPath, value)", ->
|
||||
it "unshifts the given value to the array at the key path and updates observers", ->
|
||||
atom.config.set("foo.bar.baz", ["b"])
|
||||
observeHandler = jasmine.createSpy "observeHandler"
|
||||
atom.config.observe "foo.bar.baz", observeHandler
|
||||
observeHandler.reset()
|
||||
|
||||
expect(atom.config.unshiftAtKeyPath("foo.bar.baz", "a")).toBe 2
|
||||
expect(atom.config.get("foo.bar.baz")).toEqual ["a", "b"]
|
||||
expect(observeHandler).toHaveBeenCalledWith atom.config.get("foo.bar.baz"), {previous: ['b']}
|
||||
|
||||
describe ".removeAtKeyPath(keyPath, value)", ->
|
||||
it "removes the given value from the array at the key path and updates observers", ->
|
||||
config.set("foo.bar.baz", ["a", "b", "c"])
|
||||
atom.config.set("foo.bar.baz", ["a", "b", "c"])
|
||||
observeHandler = jasmine.createSpy "observeHandler"
|
||||
config.observe "foo.bar.baz", observeHandler
|
||||
atom.config.observe "foo.bar.baz", observeHandler
|
||||
observeHandler.reset()
|
||||
|
||||
expect(config.removeAtKeyPath("foo.bar.baz", "b")).toEqual ["a", "c"]
|
||||
expect(config.get("foo.bar.baz")).toEqual ["a", "c"]
|
||||
expect(observeHandler).toHaveBeenCalledWith config.get("foo.bar.baz")
|
||||
expect(atom.config.removeAtKeyPath("foo.bar.baz", "b")).toEqual ["a", "c"]
|
||||
expect(atom.config.get("foo.bar.baz")).toEqual ["a", "c"]
|
||||
expect(observeHandler).toHaveBeenCalledWith atom.config.get("foo.bar.baz"), {previous: ['a', 'b', 'c']}
|
||||
|
||||
describe ".getPositiveInt(keyPath, defaultValue)", ->
|
||||
it "returns the proper current or default value", ->
|
||||
config.set('editor.preferredLineLength', 0)
|
||||
expect(config.getPositiveInt('editor.preferredLineLength', 80)).toBe 80
|
||||
config.set('editor.preferredLineLength', -1234)
|
||||
expect(config.getPositiveInt('editor.preferredLineLength', 80)).toBe 80
|
||||
config.set('editor.preferredLineLength', 'abcd')
|
||||
expect(config.getPositiveInt('editor.preferredLineLength', 80)).toBe 80
|
||||
config.set('editor.preferredLineLength', null)
|
||||
expect(config.getPositiveInt('editor.preferredLineLength', 80)).toBe 80
|
||||
atom.config.set('editor.preferredLineLength', 0)
|
||||
expect(atom.config.getPositiveInt('editor.preferredLineLength', 80)).toBe 80
|
||||
atom.config.set('editor.preferredLineLength', -1234)
|
||||
expect(atom.config.getPositiveInt('editor.preferredLineLength', 80)).toBe 80
|
||||
atom.config.set('editor.preferredLineLength', 'abcd')
|
||||
expect(atom.config.getPositiveInt('editor.preferredLineLength', 80)).toBe 80
|
||||
atom.config.set('editor.preferredLineLength', null)
|
||||
expect(atom.config.getPositiveInt('editor.preferredLineLength', 80)).toBe 80
|
||||
|
||||
describe ".save()", ->
|
||||
nodeFs = require 'fs'
|
||||
|
||||
beforeEach ->
|
||||
spyOn(nodeFs, 'writeFileSync')
|
||||
jasmine.unspy config, 'save'
|
||||
jasmine.unspy atom.config, 'save'
|
||||
|
||||
describe "when ~/.atom/config.json exists", ->
|
||||
it "writes any non-default properties to ~/.atom/config.json", ->
|
||||
config.configFilePath = path.join(config.configDirPath, "config.json")
|
||||
config.set("a.b.c", 1)
|
||||
config.set("a.b.d", 2)
|
||||
config.set("x.y.z", 3)
|
||||
config.setDefaults("a.b", e: 4, f: 5)
|
||||
atom.config.configFilePath = path.join(atom.config.configDirPath, "atom.config.json")
|
||||
atom.config.set("a.b.c", 1)
|
||||
atom.config.set("a.b.d", 2)
|
||||
atom.config.set("x.y.z", 3)
|
||||
atom.config.setDefaults("a.b", e: 4, f: 5)
|
||||
|
||||
nodeFs.writeFileSync.reset()
|
||||
config.save()
|
||||
atom.config.save()
|
||||
|
||||
expect(nodeFs.writeFileSync.argsForCall[0][0]).toBe(path.join(config.configDirPath, "config.json"))
|
||||
expect(nodeFs.writeFileSync.argsForCall[0][0]).toBe(path.join(atom.config.configDirPath, "atom.config.json"))
|
||||
writtenConfig = JSON.parse(nodeFs.writeFileSync.argsForCall[0][1])
|
||||
expect(writtenConfig).toEqual config.settings
|
||||
expect(writtenConfig).toEqual atom.config.settings
|
||||
|
||||
describe "when ~/.atom/config.json doesn't exist", ->
|
||||
it "writes any non-default properties to ~/.atom/config.cson", ->
|
||||
config.configFilePath = path.join(config.configDirPath, "config.cson")
|
||||
config.set("a.b.c", 1)
|
||||
config.set("a.b.d", 2)
|
||||
config.set("x.y.z", 3)
|
||||
config.setDefaults("a.b", e: 4, f: 5)
|
||||
atom.config.configFilePath = path.join(atom.config.configDirPath, "atom.config.cson")
|
||||
atom.config.set("a.b.c", 1)
|
||||
atom.config.set("a.b.d", 2)
|
||||
atom.config.set("x.y.z", 3)
|
||||
atom.config.setDefaults("a.b", e: 4, f: 5)
|
||||
|
||||
nodeFs.writeFileSync.reset()
|
||||
config.save()
|
||||
atom.config.save()
|
||||
|
||||
expect(nodeFs.writeFileSync.argsForCall[0][0]).toBe(path.join(config.configDirPath, "config.cson"))
|
||||
expect(nodeFs.writeFileSync.argsForCall[0][0]).toBe(path.join(atom.config.configDirPath, "atom.config.cson"))
|
||||
CoffeeScript = require 'coffee-script'
|
||||
writtenConfig = CoffeeScript.eval(nodeFs.writeFileSync.argsForCall[0][1], bare: true)
|
||||
expect(writtenConfig).toEqual config.settings
|
||||
expect(writtenConfig).toEqual atom.config.settings
|
||||
|
||||
describe ".setDefaults(keyPath, defaults)", ->
|
||||
it "assigns any previously-unassigned keys to the object at the key path", ->
|
||||
config.set("foo.bar.baz", a: 1)
|
||||
config.setDefaults("foo.bar.baz", a: 2, b: 3, c: 4)
|
||||
expect(config.get("foo.bar.baz.a")).toBe 1
|
||||
expect(config.get("foo.bar.baz.b")).toBe 3
|
||||
expect(config.get("foo.bar.baz.c")).toBe 4
|
||||
atom.config.set("foo.bar.baz", a: 1)
|
||||
atom.config.setDefaults("foo.bar.baz", a: 2, b: 3, c: 4)
|
||||
expect(atom.config.get("foo.bar.baz.a")).toBe 1
|
||||
expect(atom.config.get("foo.bar.baz.b")).toBe 3
|
||||
expect(atom.config.get("foo.bar.baz.c")).toBe 4
|
||||
|
||||
config.setDefaults("foo.quux", x: 0, y: 1)
|
||||
expect(config.get("foo.quux.x")).toBe 0
|
||||
expect(config.get("foo.quux.y")).toBe 1
|
||||
atom.config.setDefaults("foo.quux", x: 0, y: 1)
|
||||
expect(atom.config.get("foo.quux.x")).toBe 0
|
||||
expect(atom.config.get("foo.quux.y")).toBe 1
|
||||
|
||||
describe ".observe(keyPath)", ->
|
||||
observeHandler = null
|
||||
[observeHandler, observeSubscription] = []
|
||||
|
||||
beforeEach ->
|
||||
observeHandler = jasmine.createSpy("observeHandler")
|
||||
config.set("foo.bar.baz", "value 1")
|
||||
config.observe "foo.bar.baz", observeHandler
|
||||
atom.config.set("foo.bar.baz", "value 1")
|
||||
observeSubscription = atom.config.observe "foo.bar.baz", observeHandler
|
||||
|
||||
it "fires the given callback with the current value at the keypath", ->
|
||||
expect(observeHandler).toHaveBeenCalledWith("value 1")
|
||||
|
||||
it "fires the callback every time the observed value changes", ->
|
||||
observeHandler.reset() # clear the initial call
|
||||
config.set('foo.bar.baz', "value 2")
|
||||
expect(observeHandler).toHaveBeenCalledWith("value 2")
|
||||
atom.config.set('foo.bar.baz', "value 2")
|
||||
expect(observeHandler).toHaveBeenCalledWith("value 2", {previous: 'value 1'})
|
||||
observeHandler.reset()
|
||||
|
||||
config.set('foo.bar.baz', "value 1")
|
||||
expect(observeHandler).toHaveBeenCalledWith("value 1")
|
||||
atom.config.set('foo.bar.baz', "value 1")
|
||||
expect(observeHandler).toHaveBeenCalledWith("value 1", {previous: 'value 2'})
|
||||
|
||||
it "fires the callback when the observed value is deleted", ->
|
||||
observeHandler.reset() # clear the initial call
|
||||
config.set('foo.bar.baz', undefined)
|
||||
expect(observeHandler).toHaveBeenCalledWith(undefined)
|
||||
atom.config.set('foo.bar.baz', undefined)
|
||||
expect(observeHandler).toHaveBeenCalledWith(undefined, {previous: 'value 1'})
|
||||
|
||||
it "fires the callback when the full key path goes into and out of existence", ->
|
||||
observeHandler.reset() # clear the initial call
|
||||
config.set("foo.bar", undefined)
|
||||
atom.config.set("foo.bar", undefined)
|
||||
|
||||
expect(observeHandler).toHaveBeenCalledWith(undefined)
|
||||
expect(observeHandler).toHaveBeenCalledWith(undefined, {previous: 'value 1'})
|
||||
observeHandler.reset()
|
||||
|
||||
config.set("foo.bar.baz", "i'm back")
|
||||
expect(observeHandler).toHaveBeenCalledWith("i'm back")
|
||||
atom.config.set("foo.bar.baz", "i'm back")
|
||||
expect(observeHandler).toHaveBeenCalledWith("i'm back", {previous: undefined})
|
||||
|
||||
it "does not fire the callback once the observe subscription is off'ed", ->
|
||||
observeHandler.reset() # clear the initial call
|
||||
observeSubscription.off()
|
||||
atom.config.set('foo.bar.baz', "value 2")
|
||||
expect(observeHandler).not.toHaveBeenCalled()
|
||||
|
||||
describe ".initializeConfigDirectory()", ->
|
||||
beforeEach ->
|
||||
config.configDirPath = '/tmp/dot-atom-dir'
|
||||
expect(fs.exists(config.configDirPath)).toBeFalsy()
|
||||
atom.config.configDirPath = dotAtomPath
|
||||
expect(fs.existsSync(atom.config.configDirPath)).toBeFalsy()
|
||||
|
||||
afterEach ->
|
||||
fs.remove('/tmp/dot-atom-dir') if fs.exists('/tmp/dot-atom-dir')
|
||||
fs.removeSync(dotAtomPath) if fs.existsSync(dotAtomPath)
|
||||
|
||||
describe "when the configDirPath doesn't exist", ->
|
||||
it "copies the contents of dot-atom to ~/.atom", ->
|
||||
initializationDone = false
|
||||
jasmine.unspy(window, "setTimeout")
|
||||
config.initializeConfigDirectory ->
|
||||
atom.config.initializeConfigDirectory ->
|
||||
initializationDone = true
|
||||
|
||||
waitsFor -> initializationDone
|
||||
|
||||
runs ->
|
||||
expect(fs.exists(config.configDirPath)).toBeTruthy()
|
||||
expect(fs.exists(path.join(config.configDirPath, 'packages'))).toBeTruthy()
|
||||
expect(fs.exists(path.join(config.configDirPath, 'snippets'))).toBeTruthy()
|
||||
expect(fs.isFileSync(path.join(config.configDirPath, 'config.cson'))).toBeTruthy()
|
||||
expect(fs.existsSync(atom.config.configDirPath)).toBeTruthy()
|
||||
expect(fs.existsSync(path.join(atom.config.configDirPath, 'packages'))).toBeTruthy()
|
||||
expect(fs.existsSync(path.join(atom.config.configDirPath, 'snippets'))).toBeTruthy()
|
||||
expect(fs.isFileSync(path.join(atom.config.configDirPath, 'config.cson'))).toBeTruthy()
|
||||
|
||||
describe ".loadUserConfig()", ->
|
||||
beforeEach ->
|
||||
config.configDirPath = '/tmp/dot-atom-dir'
|
||||
config.configFilePath = path.join(config.configDirPath, "config.cson")
|
||||
expect(fs.exists(config.configDirPath)).toBeFalsy()
|
||||
atom.config.configDirPath = dotAtomPath
|
||||
atom.config.configFilePath = path.join(atom.config.configDirPath, "atom.config.cson")
|
||||
expect(fs.existsSync(atom.config.configDirPath)).toBeFalsy()
|
||||
|
||||
afterEach ->
|
||||
fs.remove('/tmp/dot-atom-dir') if fs.exists('/tmp/dot-atom-dir')
|
||||
fs.removeSync(dotAtomPath) if fs.existsSync(dotAtomPath)
|
||||
|
||||
describe "when the config file contains valid cson", ->
|
||||
beforeEach ->
|
||||
fs.writeSync(config.configFilePath, "foo: bar: 'baz'")
|
||||
config.loadUserConfig()
|
||||
fs.writeFileSync(atom.config.configFilePath, "foo: bar: 'baz'")
|
||||
atom.config.loadUserConfig()
|
||||
|
||||
it "updates the config data based on the file contents", ->
|
||||
expect(config.get("foo.bar")).toBe 'baz'
|
||||
expect(atom.config.get("foo.bar")).toBe 'baz'
|
||||
|
||||
describe "when the config file contains invalid cson", ->
|
||||
beforeEach ->
|
||||
spyOn(console, 'error')
|
||||
fs.writeSync(config.configFilePath, "{{{{{")
|
||||
fs.writeFileSync(atom.config.configFilePath, "{{{{{")
|
||||
|
||||
it "logs an error to the console and does not overwrite the config file on a subsequent save", ->
|
||||
config.loadUserConfig()
|
||||
atom.config.loadUserConfig()
|
||||
expect(console.error).toHaveBeenCalled()
|
||||
config.set("hair", "blonde") # trigger a save
|
||||
expect(config.save).not.toHaveBeenCalled()
|
||||
atom.config.set("hair", "blonde") # trigger a save
|
||||
expect(atom.config.save).not.toHaveBeenCalled()
|
||||
|
||||
describe "when the config file does not exist", ->
|
||||
it "creates it with an empty object", ->
|
||||
fs.makeTree(config.configDirPath)
|
||||
config.loadUserConfig()
|
||||
expect(fs.exists(config.configFilePath)).toBe true
|
||||
expect(CSON.readFileSync(config.configFilePath)).toEqual {}
|
||||
fs.makeTreeSync(atom.config.configDirPath)
|
||||
atom.config.loadUserConfig()
|
||||
expect(fs.existsSync(atom.config.configFilePath)).toBe true
|
||||
expect(CSON.readFileSync(atom.config.configFilePath)).toEqual {}
|
||||
|
||||
describe ".observeUserConfig()", ->
|
||||
updatedHandler = null
|
||||
|
||||
beforeEach ->
|
||||
config.configDirPath = '/tmp/dot-atom-dir'
|
||||
config.configFilePath = path.join(config.configDirPath, "config.cson")
|
||||
expect(fs.exists(config.configDirPath)).toBeFalsy()
|
||||
fs.writeSync(config.configFilePath, "foo: bar: 'baz'")
|
||||
config.loadUserConfig()
|
||||
config.observeUserConfig()
|
||||
atom.config.configDirPath = dotAtomPath
|
||||
atom.config.configFilePath = path.join(atom.config.configDirPath, "atom.config.cson")
|
||||
expect(fs.existsSync(atom.config.configDirPath)).toBeFalsy()
|
||||
fs.writeFileSync(atom.config.configFilePath, "foo: bar: 'baz'")
|
||||
atom.config.loadUserConfig()
|
||||
atom.config.observeUserConfig()
|
||||
updatedHandler = jasmine.createSpy("updatedHandler")
|
||||
config.on 'updated', updatedHandler
|
||||
atom.config.on 'updated', updatedHandler
|
||||
|
||||
afterEach ->
|
||||
config.unobserveUserConfig()
|
||||
fs.remove('/tmp/dot-atom-dir') if fs.exists('/tmp/dot-atom-dir')
|
||||
atom.config.unobserveUserConfig()
|
||||
fs.removeSync(dotAtomPath) if fs.existsSync(dotAtomPath)
|
||||
|
||||
describe "when the config file changes to contain valid cson", ->
|
||||
it "updates the config data", ->
|
||||
fs.writeSync(config.configFilePath, "foo: { bar: 'quux', baz: 'bar'}")
|
||||
fs.writeFileSync(atom.config.configFilePath, "foo: { bar: 'quux', baz: 'bar'}")
|
||||
waitsFor 'update event', -> updatedHandler.callCount > 0
|
||||
runs ->
|
||||
expect(config.get('foo.bar')).toBe 'quux'
|
||||
expect(config.get('foo.baz')).toBe 'bar'
|
||||
expect(atom.config.get('foo.bar')).toBe 'quux'
|
||||
expect(atom.config.get('foo.baz')).toBe 'bar'
|
||||
|
||||
describe "when the config file changes to contain invalid cson", ->
|
||||
beforeEach ->
|
||||
spyOn(console, 'error')
|
||||
fs.writeSync(config.configFilePath, "}}}")
|
||||
fs.writeFileSync(atom.config.configFilePath, "}}}")
|
||||
waitsFor "error to be logged", -> console.error.callCount > 0
|
||||
|
||||
it "logs a warning and does not update config data", ->
|
||||
expect(updatedHandler.callCount).toBe 0
|
||||
expect(config.get('foo.bar')).toBe 'baz'
|
||||
config.set("hair", "blonde") # trigger a save
|
||||
expect(config.save).not.toHaveBeenCalled()
|
||||
expect(atom.config.get('foo.bar')).toBe 'baz'
|
||||
atom.config.set("hair", "blonde") # trigger a save
|
||||
expect(atom.config.save).not.toHaveBeenCalled()
|
||||
|
||||
describe "when the config file subsequently changes again to contain valid cson", ->
|
||||
beforeEach ->
|
||||
fs.writeSync(config.configFilePath, "foo: bar: 'baz'")
|
||||
fs.writeFileSync(atom.config.configFilePath, "foo: bar: 'baz'")
|
||||
waitsFor 'update event', -> updatedHandler.callCount > 0
|
||||
|
||||
it "updates the config data and resumes saving", ->
|
||||
config.set("hair", "blonde")
|
||||
expect(config.save).toHaveBeenCalled()
|
||||
atom.config.set("hair", "blonde")
|
||||
expect(atom.config.save).toHaveBeenCalled()
|
||||
|
||||
@@ -16,10 +16,10 @@ describe "Directory", ->
|
||||
|
||||
beforeEach ->
|
||||
temporaryFilePath = path.join(__dirname, 'fixtures', 'temporary')
|
||||
fs.remove(temporaryFilePath) if fs.exists(temporaryFilePath)
|
||||
fs.removeSync(temporaryFilePath) if fs.existsSync(temporaryFilePath)
|
||||
|
||||
afterEach ->
|
||||
fs.remove(temporaryFilePath) if fs.exists(temporaryFilePath)
|
||||
fs.removeSync(temporaryFilePath) if fs.existsSync(temporaryFilePath)
|
||||
|
||||
it "triggers 'contents-changed' event handlers", ->
|
||||
changeHandler = null
|
||||
@@ -27,13 +27,13 @@ describe "Directory", ->
|
||||
runs ->
|
||||
changeHandler = jasmine.createSpy('changeHandler')
|
||||
directory.on 'contents-changed', changeHandler
|
||||
fs.writeSync(temporaryFilePath, '')
|
||||
fs.writeFileSync(temporaryFilePath, '')
|
||||
|
||||
waitsFor "first change", -> changeHandler.callCount > 0
|
||||
|
||||
runs ->
|
||||
changeHandler.reset()
|
||||
fs.remove(temporaryFilePath)
|
||||
fs.removeSync(temporaryFilePath)
|
||||
|
||||
waitsFor "second change", -> changeHandler.callCount > 0
|
||||
|
||||
@@ -42,10 +42,10 @@ describe "Directory", ->
|
||||
|
||||
beforeEach ->
|
||||
temporaryFilePath = path.join(directory.path, 'temporary')
|
||||
fs.remove(temporaryFilePath) if fs.exists(temporaryFilePath)
|
||||
fs.removeSync(temporaryFilePath) if fs.existsSync(temporaryFilePath)
|
||||
|
||||
afterEach ->
|
||||
fs.remove(temporaryFilePath) if fs.exists(temporaryFilePath)
|
||||
fs.removeSync(temporaryFilePath) if fs.existsSync(temporaryFilePath)
|
||||
|
||||
it "no longer triggers events", ->
|
||||
changeHandler = null
|
||||
@@ -53,7 +53,7 @@ describe "Directory", ->
|
||||
runs ->
|
||||
changeHandler = jasmine.createSpy('changeHandler')
|
||||
directory.on 'contents-changed', changeHandler
|
||||
fs.writeSync(temporaryFilePath, '')
|
||||
fs.writeFileSync(temporaryFilePath, '')
|
||||
|
||||
waitsFor "change event", -> changeHandler.callCount > 0
|
||||
|
||||
@@ -62,36 +62,49 @@ describe "Directory", ->
|
||||
directory.off()
|
||||
waits 20
|
||||
|
||||
runs -> fs.remove(temporaryFilePath)
|
||||
runs -> fs.removeSync(temporaryFilePath)
|
||||
waits 20
|
||||
runs -> expect(changeHandler.callCount).toBe 0
|
||||
|
||||
it "includes symlink information about entries", ->
|
||||
entries = directory.getEntries()
|
||||
for entry in entries
|
||||
name = entry.getBaseName()
|
||||
if name is 'symlink-to-dir' or name is 'symlink-to-file'
|
||||
expect(entry.symlink).toBeTruthy()
|
||||
else
|
||||
expect(entry.symlink).toBeFalsy()
|
||||
describe "on #darwin or #linux", ->
|
||||
it "includes symlink information about entries", ->
|
||||
entries = directory.getEntries()
|
||||
for entry in entries
|
||||
name = entry.getBaseName()
|
||||
if name is 'symlink-to-dir' or name is 'symlink-to-file'
|
||||
expect(entry.symlink).toBeTruthy()
|
||||
else
|
||||
expect(entry.symlink).toBeFalsy()
|
||||
|
||||
describe ".relativize(path)", ->
|
||||
it "returns a relative path based on the directory's path", ->
|
||||
absolutePath = directory.getPath()
|
||||
expect(directory.relativize(absolutePath)).toBe ''
|
||||
expect(directory.relativize(path.join(absolutePath, "b"))).toBe "b"
|
||||
expect(directory.relativize(path.join(absolutePath, "b/file.coffee"))).toBe "b/file.coffee"
|
||||
expect(directory.relativize(path.join(absolutePath, "file.coffee"))).toBe "file.coffee"
|
||||
describe "on #darwin or #linux", ->
|
||||
it "returns a relative path based on the directory's path", ->
|
||||
absolutePath = directory.getPath()
|
||||
expect(directory.relativize(absolutePath)).toBe ''
|
||||
expect(directory.relativize(path.join(absolutePath, "b"))).toBe "b"
|
||||
expect(directory.relativize(path.join(absolutePath, "b/file.coffee"))).toBe "b/file.coffee"
|
||||
expect(directory.relativize(path.join(absolutePath, "file.coffee"))).toBe "file.coffee"
|
||||
|
||||
it "returns a relative path based on the directory's symlinked source path", ->
|
||||
symlinkPath = path.join(__dirname, 'fixtures', 'symlink-to-dir')
|
||||
symlinkDirectory = new Directory(symlinkPath)
|
||||
realFilePath = require.resolve('./fixtures/dir/a')
|
||||
expect(symlinkDirectory.relativize(symlinkPath)).toBe ''
|
||||
expect(symlinkDirectory.relativize(realFilePath)).toBe 'a'
|
||||
it "returns a relative path based on the directory's symlinked source path", ->
|
||||
symlinkPath = path.join(__dirname, 'fixtures', 'symlink-to-dir')
|
||||
symlinkDirectory = new Directory(symlinkPath)
|
||||
realFilePath = require.resolve('./fixtures/dir/a')
|
||||
expect(symlinkDirectory.relativize(symlinkPath)).toBe ''
|
||||
expect(symlinkDirectory.relativize(realFilePath)).toBe 'a'
|
||||
|
||||
it "returns the full path if the directory's path is not a prefix of the path", ->
|
||||
expect(directory.relativize('/not/relative')).toBe '/not/relative'
|
||||
it "returns the full path if the directory's path is not a prefix of the path", ->
|
||||
expect(directory.relativize('/not/relative')).toBe '/not/relative'
|
||||
|
||||
describe "on #win32", ->
|
||||
it "returns a relative path based on the directory's path", ->
|
||||
absolutePath = directory.getPath()
|
||||
expect(directory.relativize(absolutePath)).toBe ''
|
||||
expect(directory.relativize(path.join(absolutePath, "b"))).toBe "b"
|
||||
expect(directory.relativize(path.join(absolutePath, "b/file.coffee"))).toBe "b\\file.coffee"
|
||||
expect(directory.relativize(path.join(absolutePath, "file.coffee"))).toBe "file.coffee"
|
||||
|
||||
it "returns the full path if the directory's path is not a prefix of the path", ->
|
||||
expect(directory.relativize('/not/relative')).toBe "\\not\\relative"
|
||||
|
||||
describe ".contains(path)", ->
|
||||
it "returns true if the path is a child of the directory's path", ->
|
||||
@@ -100,11 +113,12 @@ describe "Directory", ->
|
||||
expect(directory.contains(path.join(absolutePath, "b", "file.coffee"))).toBe true
|
||||
expect(directory.contains(path.join(absolutePath, "file.coffee"))).toBe true
|
||||
|
||||
it "returns true if the path is a child of the directory's symlinked source path", ->
|
||||
symlinkPath = path.join(__dirname, 'fixtures', 'symlink-to-dir')
|
||||
symlinkDirectory = new Directory(symlinkPath)
|
||||
realFilePath = require.resolve('./fixtures/dir/a')
|
||||
expect(symlinkDirectory.contains(realFilePath)).toBe true
|
||||
|
||||
it "returns false if the directory's path is not a prefix of the path", ->
|
||||
expect(directory.contains('/not/relative')).toBe false
|
||||
|
||||
describe "on #darwin or #linux", ->
|
||||
it "returns true if the path is a child of the directory's symlinked source path", ->
|
||||
symlinkPath = path.join(__dirname, 'fixtures', 'symlink-to-dir')
|
||||
symlinkDirectory = new Directory(symlinkPath)
|
||||
realFilePath = require.resolve('./fixtures/dir/a')
|
||||
expect(symlinkDirectory.contains(realFilePath)).toBe true
|
||||
|
||||
@@ -5,8 +5,8 @@ describe "DisplayBuffer", ->
|
||||
[displayBuffer, buffer, changeHandler, tabLength] = []
|
||||
beforeEach ->
|
||||
tabLength = 2
|
||||
atom.activatePackage('javascript-tmbundle', sync: true)
|
||||
buffer = project.bufferForPath('sample.js')
|
||||
atom.packages.activatePackage('language-javascript', sync: true)
|
||||
buffer = atom.project.bufferForPathSync('sample.js')
|
||||
displayBuffer = new DisplayBuffer({buffer, tabLength})
|
||||
changeHandler = jasmine.createSpy 'changeHandler'
|
||||
displayBuffer.on 'changed', changeHandler
|
||||
@@ -20,7 +20,7 @@ describe "DisplayBuffer", ->
|
||||
displayBuffer.setTabLength(4)
|
||||
displayBuffer.setEditorWidthInChars(64)
|
||||
displayBuffer.createFold(2, 4)
|
||||
displayBuffer2 = deserialize(displayBuffer.serialize())
|
||||
displayBuffer2 = atom.deserializers.deserialize(displayBuffer.serialize())
|
||||
expect(displayBuffer2.id).toBe displayBuffer.id
|
||||
expect(displayBuffer2.buffer).toBe displayBuffer.buffer
|
||||
expect(displayBuffer2.tokenizedBuffer.buffer).toBe displayBuffer.tokenizedBuffer.buffer
|
||||
@@ -66,14 +66,14 @@ describe "DisplayBuffer", ->
|
||||
describe "rendering of soft-wrapped lines", ->
|
||||
describe "when editor.softWrapAtPreferredLineLength is set", ->
|
||||
it "uses the preferred line length as the soft wrap column when it is less than the configured soft wrap column", ->
|
||||
config.set('editor.preferredLineLength', 100)
|
||||
config.set('editor.softWrapAtPreferredLineLength', true)
|
||||
atom.config.set('editor.preferredLineLength', 100)
|
||||
atom.config.set('editor.softWrapAtPreferredLineLength', true)
|
||||
expect(displayBuffer.lineForRow(10).text).toBe ' return '
|
||||
|
||||
config.set('editor.preferredLineLength', 5)
|
||||
atom.config.set('editor.preferredLineLength', 5)
|
||||
expect(displayBuffer.lineForRow(10).text).toBe 'funct'
|
||||
|
||||
config.set('editor.softWrapAtPreferredLineLength', false)
|
||||
atom.config.set('editor.softWrapAtPreferredLineLength', false)
|
||||
expect(displayBuffer.lineForRow(10).text).toBe ' return '
|
||||
|
||||
describe "when the line is shorter than the max line length", ->
|
||||
@@ -154,7 +154,7 @@ describe "DisplayBuffer", ->
|
||||
|
||||
describe "when a newline is inserted, deleted, and re-inserted at the end of a wrapped line (regression)", ->
|
||||
it "correctly renders the original wrapped line", ->
|
||||
buffer = project.buildBuffer(null, '')
|
||||
buffer = atom.project.buildBufferSync(null, '')
|
||||
displayBuffer = new DisplayBuffer({buffer, tabLength, editorWidthInChars: 30, softWrap: true})
|
||||
|
||||
buffer.insert([0, 0], "the quick brown fox jumps over the lazy dog.")
|
||||
@@ -206,7 +206,7 @@ describe "DisplayBuffer", ->
|
||||
beforeEach ->
|
||||
displayBuffer.destroy()
|
||||
buffer.release()
|
||||
buffer = project.bufferForPath('two-hundred.txt')
|
||||
buffer = atom.project.bufferForPathSync('two-hundred.txt')
|
||||
displayBuffer = new DisplayBuffer({buffer, tabLength})
|
||||
displayBuffer.on 'changed', changeHandler
|
||||
|
||||
@@ -600,7 +600,7 @@ describe "DisplayBuffer", ->
|
||||
it "unsubscribes all display buffer markers from their underlying buffer marker (regression)", ->
|
||||
marker = displayBuffer.markBufferPosition([12, 2])
|
||||
displayBuffer.destroy()
|
||||
expect(marker.bufferMarker.subscriptionCount()).toBe 0
|
||||
expect(marker.bufferMarker.getSubscriptionCount()).toBe 0
|
||||
expect( -> buffer.insert([12, 2], '\n')).not.toThrow()
|
||||
|
||||
describe "markers", ->
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
{Site} = require 'telepath'
|
||||
Environment = require './environment'
|
||||
|
||||
describe "EditSession replication", ->
|
||||
[env1, env2, editSession1, editSession2] = []
|
||||
beforeEach ->
|
||||
env1 = new Environment(siteId: 1)
|
||||
env2 = env1.clone(siteId: 2)
|
||||
envConnection = env1.connect(env2)
|
||||
doc2 = null
|
||||
|
||||
env1.run ->
|
||||
editSession1 = project.open('sample.js')
|
||||
editSession1.setScrollTop(5)
|
||||
editSession1.setScrollLeft(5)
|
||||
editSession1.setCursorScreenPosition([0, 5])
|
||||
editSession1.addSelectionForBufferRange([[1, 2], [3, 4]])
|
||||
doc1 = editSession1.getState()
|
||||
doc2 = doc1.clone(env2.site)
|
||||
envConnection.connect(doc1, doc2)
|
||||
|
||||
env2.run ->
|
||||
editSession2 = deserialize(doc2)
|
||||
|
||||
afterEach ->
|
||||
env1.destroy()
|
||||
env2.destroy()
|
||||
|
||||
it "replicates the selections of existing replicas", ->
|
||||
expect(editSession2.getRemoteSelectedBufferRanges()).toEqual editSession1.getSelectedBufferRanges()
|
||||
|
||||
editSession1.getLastSelection().setBufferRange([[2, 3], [4, 5]])
|
||||
expect(editSession2.getRemoteSelectedBufferRanges()).toEqual editSession1.getSelectedBufferRanges()
|
||||
|
||||
editSession1.addCursorAtBufferPosition([5, 6])
|
||||
expect(editSession2.getRemoteSelectedBufferRanges()).toEqual editSession1.getSelectedBufferRanges()
|
||||
|
||||
editSession1.consolidateSelections()
|
||||
expect(editSession2.getRemoteSelectedBufferRanges()).toEqual editSession1.getSelectedBufferRanges()
|
||||
|
||||
it "introduces a local cursor for a new replica at the position of the last remote cursor", ->
|
||||
expect(editSession2.getCursors().length).toBe 1
|
||||
expect(editSession2.getSelections().length).toBe 1
|
||||
expect(editSession2.getCursorBufferPosition()).toEqual [3, 4]
|
||||
expect(editSession2.getSelectedBufferRanges()).toEqual [[[3, 4], [3, 4]]]
|
||||
|
||||
expect(editSession1.getRemoteCursors().length).toBe 1
|
||||
expect(editSession1.getRemoteSelections().length).toBe 1
|
||||
[cursor] = editSession1.getRemoteCursors()
|
||||
[selection] = editSession1.getRemoteSelections()
|
||||
expect(cursor.getBufferPosition()).toEqual [3, 4]
|
||||
expect(selection.getBufferRange()).toEqual [[3, 4], [3, 4]]
|
||||
|
||||
it "replicates the scroll position", ->
|
||||
expect(editSession2.getScrollTop()).toBe editSession1.getScrollTop()
|
||||
expect(editSession2.getScrollLeft()).toBe editSession1.getScrollLeft()
|
||||
|
||||
editSession1.setScrollTop(10)
|
||||
expect(editSession2.getScrollTop()).toBe 10
|
||||
|
||||
editSession2.setScrollLeft(20)
|
||||
expect(editSession1.getScrollLeft()).toBe 20
|
||||
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -1,37 +0,0 @@
|
||||
{Site} = require 'telepath'
|
||||
Editor = require '../src/editor'
|
||||
Environment = require './environment'
|
||||
|
||||
describe "Editor replication", ->
|
||||
[env1, env2, editSession1, editSession2, editor1, editor2] = []
|
||||
|
||||
beforeEach ->
|
||||
env1 = new Environment(siteId: 1)
|
||||
env2 = env1.clone(siteId: 2)
|
||||
envConnection = env1.connect(env2)
|
||||
doc2 = null
|
||||
|
||||
env1.run ->
|
||||
editSession1 = project.open('sample.js')
|
||||
editSession1.setSelectedBufferRange([[1, 2], [3, 4]])
|
||||
doc1 = editSession1.getState()
|
||||
doc2 = doc1.clone(env2.site)
|
||||
envConnection.connect(doc1, doc2)
|
||||
editor1 = new Editor(editSession1)
|
||||
editor1.attachToDom()
|
||||
|
||||
env2.run ->
|
||||
editSession2 = deserialize(doc2)
|
||||
editor2 = new Editor(editSession2)
|
||||
editor2.attachToDom()
|
||||
|
||||
afterEach ->
|
||||
env1.destroy()
|
||||
env2.destroy()
|
||||
|
||||
it "displays the cursors and selections from all replicas", ->
|
||||
expect(editor1.getSelectionViews().length).toBe 2
|
||||
expect(editor2.getSelectionViews().length).toBe 2
|
||||
|
||||
expect(editor1.getCursorViews().length).toBe 2
|
||||
expect(editor2.getCursorViews().length).toBe 2
|
||||
+2613
-2654
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -1,59 +0,0 @@
|
||||
path = require 'path'
|
||||
{Site} = require 'telepath'
|
||||
{fs} = require 'atom'
|
||||
Project = require '../src/project'
|
||||
|
||||
module.exports =
|
||||
class Environment
|
||||
constructor: ({@site, @state, siteId, projectPath}={}) ->
|
||||
@site ?= new Site(siteId ? 1)
|
||||
if @state?
|
||||
@run => @project = deserialize(@state.get('project'))
|
||||
else
|
||||
@state = @site.createDocument({})
|
||||
@project = new Project(projectPath ? path.join(__dirname, 'fixtures'))
|
||||
@state.set(project: @project.getState())
|
||||
|
||||
clone: (params) ->
|
||||
site = new Site(params.siteId)
|
||||
new Environment(site: site, state: @state.clone(site))
|
||||
|
||||
destroy: ->
|
||||
@project.destroy()
|
||||
|
||||
getState: -> @state
|
||||
|
||||
run: (fn) ->
|
||||
uninstall = @install()
|
||||
fn()
|
||||
uninstall()
|
||||
|
||||
install: ->
|
||||
oldSite = window.site
|
||||
oldProject = window.project
|
||||
window.site = @site
|
||||
window.project = @project
|
||||
->
|
||||
window.site = oldSite
|
||||
window.project = oldProject
|
||||
|
||||
connect: (otherEnv) ->
|
||||
new EnvironmentConnection(this, otherEnv)
|
||||
|
||||
|
||||
connectDocuments: (docA, docB, envB) ->
|
||||
|
||||
class EnvironmentConnection
|
||||
constructor: (@envA, @envB) ->
|
||||
@envA.getState().connect(@envB.getState())
|
||||
|
||||
connect: (docA, docB) ->
|
||||
unless docA.site is @envA.site
|
||||
throw new Error("Document and environment sites do not match (doc: site #{docA.site.id}, env: site #{@envA.site.id})")
|
||||
unless docB.site is @envB.site
|
||||
throw new Error("Document and environment sites do not match (doc: site #{docB.site.id}, env: site #{@envB.site.id})")
|
||||
|
||||
connection = docA.connect(docB)
|
||||
connection.abFilter = (fn) => @envB.run(fn)
|
||||
connection.baFilter = (fn) => @envA.run(fn)
|
||||
connection
|
||||
@@ -1,208 +0,0 @@
|
||||
{_} = require 'atom'
|
||||
EventEmitter = require '../src/event-emitter'
|
||||
|
||||
describe "EventEmitter mixin", ->
|
||||
[object, fooHandler1, fooHandler2, barHandler] = []
|
||||
|
||||
beforeEach ->
|
||||
object = {}
|
||||
_.extend(object, EventEmitter)
|
||||
|
||||
fooHandler1 = jasmine.createSpy('fooHandler1')
|
||||
fooHandler2 = jasmine.createSpy('fooHandler2')
|
||||
barHandler = jasmine.createSpy('barHandler')
|
||||
|
||||
object.on 'foo', fooHandler1
|
||||
object.on 'foo', fooHandler2
|
||||
object.on 'bar', barHandler
|
||||
|
||||
describe ".on", ->
|
||||
describe "when called with multiple space-separated event names", ->
|
||||
it "subscribes to each event names", ->
|
||||
object.on ' a.b c.d\te ', fooHandler1
|
||||
|
||||
object.trigger 'a'
|
||||
expect(fooHandler1).toHaveBeenCalled()
|
||||
|
||||
fooHandler1.reset()
|
||||
object.trigger 'c'
|
||||
expect(fooHandler1).toHaveBeenCalled()
|
||||
|
||||
fooHandler1.reset()
|
||||
object.trigger 'e'
|
||||
expect(fooHandler1).toHaveBeenCalled()
|
||||
|
||||
fooHandler1.reset()
|
||||
object.trigger ''
|
||||
expect(fooHandler1).not.toHaveBeenCalled()
|
||||
|
||||
describe ".trigger", ->
|
||||
describe "when called with a non-namespaced event name", ->
|
||||
it "triggers all handlers registered for the given event name", ->
|
||||
object.trigger 'foo', 'data'
|
||||
expect(fooHandler1).toHaveBeenCalledWith('data')
|
||||
expect(fooHandler2).toHaveBeenCalledWith('data')
|
||||
expect(barHandler).not.toHaveBeenCalled()
|
||||
|
||||
fooHandler1.reset()
|
||||
fooHandler2.reset()
|
||||
|
||||
object.trigger 'bar', 'stuff'
|
||||
expect(barHandler).toHaveBeenCalledWith('stuff')
|
||||
|
||||
describe "when there are namespaced handlers", ->
|
||||
it "triggers only handlers registered with the given namespace / event combination", ->
|
||||
barHandler2 = jasmine.createSpy('barHandler2')
|
||||
object.on('bar.ns1', barHandler2)
|
||||
|
||||
object.trigger('bar')
|
||||
|
||||
expect(barHandler).toHaveBeenCalled()
|
||||
expect(barHandler2).toHaveBeenCalled()
|
||||
barHandler.reset()
|
||||
barHandler2.reset()
|
||||
|
||||
object.trigger('bar.ns1')
|
||||
|
||||
expect(barHandler).not.toHaveBeenCalled()
|
||||
expect(barHandler2).toHaveBeenCalled()
|
||||
|
||||
it "does not raise exceptions when called with non-existent events / namespaces", ->
|
||||
object.trigger('junk')
|
||||
object.trigger('junk.garbage')
|
||||
|
||||
describe ".off", ->
|
||||
describe "when called with no arguments", ->
|
||||
it "removes all subscriptions", ->
|
||||
object.off()
|
||||
object.trigger 'foo'
|
||||
expect(fooHandler1).not.toHaveBeenCalled()
|
||||
expect(fooHandler2).not.toHaveBeenCalled()
|
||||
|
||||
describe "when called with multiple space-separated event names", ->
|
||||
it "unsubscribes from each event name", ->
|
||||
object.on 'a.b c.d e', fooHandler1
|
||||
object.off ' a.b\te '
|
||||
|
||||
object.trigger 'a'
|
||||
expect(fooHandler1).not.toHaveBeenCalled()
|
||||
|
||||
fooHandler1.reset()
|
||||
object.trigger 'e'
|
||||
expect(fooHandler1).not.toHaveBeenCalled()
|
||||
|
||||
fooHandler1.reset()
|
||||
object.trigger 'c.d'
|
||||
expect(fooHandler1).toHaveBeenCalled()
|
||||
|
||||
describe "when called with a non-namespaced event name", ->
|
||||
it "removes all handlers for that event name", ->
|
||||
object.off 'foo'
|
||||
object.trigger 'foo'
|
||||
expect(fooHandler1).not.toHaveBeenCalled()
|
||||
expect(fooHandler2).not.toHaveBeenCalled()
|
||||
|
||||
describe "when called with a non-namespaced event name and a handler function", ->
|
||||
it "removes the specific handler", ->
|
||||
object.off 'foo', fooHandler1
|
||||
object.trigger 'foo'
|
||||
expect(fooHandler1).not.toHaveBeenCalled()
|
||||
expect(fooHandler2).toHaveBeenCalled()
|
||||
|
||||
it "does not throw an exception if there was not matching `on` call", ->
|
||||
expect(-> object.off 'marco', -> "nothing").not.toThrow()
|
||||
|
||||
describe "when there are namespaced event handlers", ->
|
||||
[barHandler2, bazHandler1, bazHandler2, bazHandler3] = []
|
||||
|
||||
beforeEach ->
|
||||
barHandler2 = jasmine.createSpy('barHandler2')
|
||||
bazHandler1 = jasmine.createSpy('bazHandler1')
|
||||
bazHandler2 = jasmine.createSpy('bazHandler2')
|
||||
bazHandler3 = jasmine.createSpy('bazHandler3')
|
||||
|
||||
object.on 'bar.ns1', barHandler2
|
||||
object.on 'baz.ns1', bazHandler1
|
||||
object.on 'baz.ns1', bazHandler2
|
||||
object.on 'baz.ns2', bazHandler3
|
||||
|
||||
describe "when called with a namespaced event name", ->
|
||||
it "removes all handlers in that namespace", ->
|
||||
object.trigger 'baz'
|
||||
|
||||
expect(bazHandler1).toHaveBeenCalled()
|
||||
expect(bazHandler2).toHaveBeenCalled()
|
||||
expect(bazHandler3).toHaveBeenCalled()
|
||||
|
||||
bazHandler1.reset()
|
||||
bazHandler2.reset()
|
||||
bazHandler3.reset()
|
||||
|
||||
object.off 'baz.ns1'
|
||||
object.trigger 'baz'
|
||||
object.trigger 'baz.ns1'
|
||||
|
||||
expect(bazHandler1).not.toHaveBeenCalled()
|
||||
expect(bazHandler2).not.toHaveBeenCalled()
|
||||
expect(bazHandler3).toHaveBeenCalled()
|
||||
|
||||
describe "when called with just a namespace", ->
|
||||
it "removes all handlers for all events on that namespace", ->
|
||||
object.trigger 'bar'
|
||||
expect(barHandler).toHaveBeenCalled()
|
||||
expect(barHandler2).toHaveBeenCalled()
|
||||
|
||||
barHandler.reset()
|
||||
barHandler2.reset()
|
||||
|
||||
object.trigger 'baz'
|
||||
expect(bazHandler1).toHaveBeenCalled()
|
||||
expect(bazHandler2).toHaveBeenCalled()
|
||||
expect(bazHandler3).toHaveBeenCalled()
|
||||
|
||||
bazHandler1.reset()
|
||||
bazHandler2.reset()
|
||||
bazHandler3.reset()
|
||||
|
||||
object.off '.ns1'
|
||||
|
||||
object.trigger 'bar'
|
||||
object.trigger 'bar.ns1'
|
||||
expect(barHandler).toHaveBeenCalled()
|
||||
expect(barHandler2).not.toHaveBeenCalled()
|
||||
|
||||
object.trigger 'baz'
|
||||
object.trigger 'baz.ns1'
|
||||
|
||||
expect(bazHandler1).not.toHaveBeenCalled()
|
||||
expect(bazHandler2).not.toHaveBeenCalled()
|
||||
expect(bazHandler3).toHaveBeenCalled()
|
||||
|
||||
describe "when called with event names and namespaces that don't exist", ->
|
||||
it "does not raise an exception", ->
|
||||
object.off 'junk'
|
||||
object.off '.garbage'
|
||||
object.off 'junk.garbage'
|
||||
|
||||
|
||||
describe ".one(event, callback)", ->
|
||||
it "triggers the given callback once, then removes the subscription", ->
|
||||
oneHandler = jasmine.createSpy('oneHandler')
|
||||
object.one 'event', oneHandler
|
||||
|
||||
object.trigger('event')
|
||||
expect(oneHandler).toHaveBeenCalled()
|
||||
oneHandler.reset()
|
||||
|
||||
object.trigger('event')
|
||||
expect(oneHandler).not.toHaveBeenCalled()
|
||||
|
||||
describe ".subscriptionCount()", ->
|
||||
it "returns the total number of subscriptions on the object", ->
|
||||
expect(object.subscriptionCount()).toBe 3
|
||||
|
||||
object.on 'baz', ->
|
||||
expect(object.subscriptionCount()).toBe 4
|
||||
|
||||
object.off 'foo'
|
||||
expect(object.subscriptionCount()).toBe 2
|
||||
+16
-16
@@ -6,40 +6,40 @@ describe 'File', ->
|
||||
|
||||
beforeEach ->
|
||||
filePath = path.join(__dirname, 'fixtures', 'atom-file-test.txt') # Don't put in /tmp because /tmp symlinks to /private/tmp and screws up the rename test
|
||||
fs.remove(filePath) if fs.exists(filePath)
|
||||
fs.writeSync(filePath, "this is old!")
|
||||
fs.removeSync(filePath) if fs.existsSync(filePath)
|
||||
fs.writeFileSync(filePath, "this is old!")
|
||||
file = new File(filePath)
|
||||
|
||||
afterEach ->
|
||||
file.off()
|
||||
fs.remove(filePath) if fs.exists(filePath)
|
||||
fs.removeSync(filePath) if fs.existsSync(filePath)
|
||||
|
||||
describe "when the file has not been read", ->
|
||||
describe "when the contents of the file change", ->
|
||||
it "triggers 'contents-changed' event handlers", ->
|
||||
file.on 'contents-changed', changeHandler = jasmine.createSpy('changeHandler')
|
||||
fs.writeSync(file.getPath(), "this is new!")
|
||||
fs.writeFileSync(file.getPath(), "this is new!")
|
||||
|
||||
waitsFor "change event", ->
|
||||
changeHandler.callCount > 0
|
||||
|
||||
describe "when the file has already been read", ->
|
||||
beforeEach ->
|
||||
file.read()
|
||||
file.readSync()
|
||||
|
||||
describe "when the contents of the file change", ->
|
||||
it "triggers 'contents-changed' event handlers", ->
|
||||
changeHandler = null
|
||||
changeHandler = jasmine.createSpy('changeHandler')
|
||||
file.on 'contents-changed', changeHandler
|
||||
fs.writeSync(file.getPath(), "this is new!")
|
||||
fs.writeFileSync(file.getPath(), "this is new!")
|
||||
|
||||
waitsFor "change event", ->
|
||||
changeHandler.callCount > 0
|
||||
|
||||
runs ->
|
||||
changeHandler.reset()
|
||||
fs.writeSync(file.getPath(), "this is newer!")
|
||||
fs.writeFileSync(file.getPath(), "this is newer!")
|
||||
|
||||
waitsFor "second change event", ->
|
||||
changeHandler.callCount > 0
|
||||
@@ -49,7 +49,7 @@ describe 'File', ->
|
||||
removeHandler = null
|
||||
removeHandler = jasmine.createSpy('removeHandler')
|
||||
file.on 'removed', removeHandler
|
||||
fs.remove(file.getPath())
|
||||
fs.removeSync(file.getPath())
|
||||
|
||||
waitsFor "remove event", ->
|
||||
removeHandler.callCount > 0
|
||||
@@ -61,8 +61,8 @@ describe 'File', ->
|
||||
newPath = path.join(path.dirname(filePath), "atom-file-was-moved-test.txt")
|
||||
|
||||
afterEach ->
|
||||
if fs.exists(newPath)
|
||||
fs.remove(newPath)
|
||||
if fs.existsSync(newPath)
|
||||
fs.removeSync(newPath)
|
||||
waitsFor "remove event", (done) -> file.on 'removed', done
|
||||
|
||||
it "it updates its path", ->
|
||||
@@ -71,7 +71,7 @@ describe 'File', ->
|
||||
moveHandler = jasmine.createSpy('moveHandler')
|
||||
file.on 'moved', moveHandler
|
||||
|
||||
fs.move(filePath, newPath)
|
||||
fs.moveSync(filePath, newPath)
|
||||
|
||||
waitsFor "move event", ->
|
||||
moveHandler.callCount > 0
|
||||
@@ -88,14 +88,14 @@ describe 'File', ->
|
||||
changeHandler = jasmine.createSpy('changeHandler')
|
||||
file.on 'contents-changed', changeHandler
|
||||
|
||||
fs.move(filePath, newPath)
|
||||
fs.moveSync(filePath, newPath)
|
||||
|
||||
waitsFor "move event", ->
|
||||
moveHandler.callCount > 0
|
||||
|
||||
runs ->
|
||||
expect(changeHandler).not.toHaveBeenCalled()
|
||||
fs.writeSync(file.getPath(), "this is new!")
|
||||
fs.writeFileSync(file.getPath(), "this is new!")
|
||||
|
||||
waitsFor "change event", ->
|
||||
changeHandler.callCount > 0
|
||||
@@ -112,12 +112,12 @@ describe 'File', ->
|
||||
|
||||
expect(changeHandler).not.toHaveBeenCalled()
|
||||
|
||||
fs.remove(filePath)
|
||||
fs.removeSync(filePath)
|
||||
|
||||
expect(changeHandler).not.toHaveBeenCalled()
|
||||
waits 20
|
||||
runs ->
|
||||
fs.writeSync(filePath, "HE HAS RISEN!")
|
||||
fs.writeFileSync(filePath, "HE HAS RISEN!")
|
||||
expect(changeHandler).not.toHaveBeenCalled()
|
||||
|
||||
waitsFor "resurrection change event", ->
|
||||
@@ -125,7 +125,7 @@ describe 'File', ->
|
||||
|
||||
runs ->
|
||||
expect(removeHandler).not.toHaveBeenCalled()
|
||||
fs.writeSync(filePath, "Hallelujah!")
|
||||
fs.writeFileSync(filePath, "Hallelujah!")
|
||||
changeHandler.reset()
|
||||
|
||||
waitsFor "post-resurrection change event", ->
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
I am evil because there's a UTF-8 character right here: ă
|
||||
@@ -1 +0,0 @@
|
||||
I am evil because there are spaces in my name
|
||||
@@ -1 +0,0 @@
|
||||
I am evil because there's a newline in my name
|
||||
-1
@@ -1 +0,0 @@
|
||||
I am evil because there's a " in my filename. Why you do that!?
|
||||
-1
@@ -1 +0,0 @@
|
||||
I am evil because there's a UTF-8 character in my name
|
||||
externo
-1
@@ -1 +0,0 @@
|
||||
* First list item
|
||||
@@ -1,6 +0,0 @@
|
||||
module.exports = ->
|
||||
try
|
||||
require 'jquery'
|
||||
true
|
||||
catch e
|
||||
false
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
## File.markdown
|
||||
|
||||
:cool:
|
||||
|
||||
```ruby
|
||||
def func
|
||||
x = 1
|
||||
end
|
||||
```
|
||||
|
||||
```
|
||||
function f(x) {
|
||||
return x++;
|
||||
}
|
||||
```
|
||||
|
||||
```kombucha
|
||||
drink-that-stuff:
|
||||
tastes-weird~
|
||||
```
|
||||
externo
BIN
Arquivo binário não exibido.
@@ -1,5 +1,5 @@
|
||||
class Foo
|
||||
registerDeserializer(this)
|
||||
atom.deserializers.add(this)
|
||||
@deserialize: ({data}) -> new Foo(data)
|
||||
constructor: (@data) ->
|
||||
|
||||
@@ -9,5 +9,5 @@ module.exports =
|
||||
|
||||
activate: ->
|
||||
@activateCallCount++
|
||||
rootView.getActiveView()?.command 'activation-event', =>
|
||||
atom.rootView.getActiveView()?.command 'activation-event', =>
|
||||
@activationEventCallCount++
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
INVALID
|
||||
@@ -0,0 +1 @@
|
||||
INVALID
|
||||
@@ -1,3 +1,7 @@
|
||||
"context-menu":
|
||||
".test-1":
|
||||
"Menu item 1": "command-1"
|
||||
'menu': [
|
||||
{ 'label': 'Last' }
|
||||
]
|
||||
|
||||
'context-menu':
|
||||
'.test-1':
|
||||
'Menu item 1': 'command-1'
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
"context-menu":
|
||||
".test-1":
|
||||
"Menu item 2": "command-2"
|
||||
'menu': [
|
||||
{ 'label': 'Second to Last' }
|
||||
]
|
||||
|
||||
'context-menu':
|
||||
'.test-1':
|
||||
'Menu item 2': 'command-2'
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
"context-menu":
|
||||
".test-1":
|
||||
"Menu item 3": "command-3"
|
||||
'context-menu':
|
||||
'.test-1':
|
||||
'Menu item 3': 'command-3'
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
"context-menu":
|
||||
".test-1":
|
||||
"Menu item 1": "command-1"
|
||||
'menu': [
|
||||
{ 'label': 'Second to Last' }
|
||||
]
|
||||
|
||||
'context-menu':
|
||||
'.test-1':
|
||||
'Menu item 1': 'command-1'
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
"context-menu":
|
||||
".test-1":
|
||||
"Menu item 2": "command-2"
|
||||
'menu': [
|
||||
{ 'label': 'Last' }
|
||||
]
|
||||
|
||||
'context-menu':
|
||||
'.test-1':
|
||||
'Menu item 2': 'command-2'
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
"context-menu":
|
||||
".test-1":
|
||||
"Menu item 3": "command-3"
|
||||
'menu': [
|
||||
{ 'label': 'Second to Last' }
|
||||
]
|
||||
|
||||
'context-menu':
|
||||
'.test-1':
|
||||
'Menu item 3': 'command-3'
|
||||
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
function duplicate() {
|
||||
return false;
|
||||
}
|
||||
externo
-11
@@ -1,11 +0,0 @@
|
||||
var thisIsCrazy = true;
|
||||
|
||||
function callMeMaybe() {
|
||||
return "here's my number";
|
||||
}
|
||||
|
||||
var iJustMetYou = callMeMaybe();
|
||||
|
||||
function duplicate() {
|
||||
return true;
|
||||
}
|
||||
externo
-10
@@ -1,10 +0,0 @@
|
||||
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
|
||||
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
|
||||
!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/
|
||||
!_TAG_PROGRAM_NAME Exuberant Ctags //
|
||||
!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/
|
||||
!_TAG_PROGRAM_VERSION 5.8 //
|
||||
callMeMaybe tagged.js /^function callMeMaybe() {$/;" f
|
||||
duplicate tagged-duplicate.js /^function duplicate() {$/;" f
|
||||
duplicate tagged.js /^function duplicate() {$/;" f
|
||||
thisIsCrazy tagged.js /^var thisIsCrazy = true;$/;" v
|
||||
externo
-514
@@ -1,514 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>author</key>
|
||||
<string>Michael Sheets</string>
|
||||
<key>name</key>
|
||||
<string>Twilight</string>
|
||||
<key>settings</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
<string>#141414</string>
|
||||
<key>caret</key>
|
||||
<string>#A7A7A7</string>
|
||||
<key>foreground</key>
|
||||
<string>#F8F8F8</string>
|
||||
<key>invisibles</key>
|
||||
<string>#FFFFFF40</string>
|
||||
<key>lineHighlight</key>
|
||||
<string>#FFFFFF08</string>
|
||||
<key>selection</key>
|
||||
<string>#DDF0FF33</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Comment</string>
|
||||
<key>scope</key>
|
||||
<string>comment</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>italic</string>
|
||||
<key>foreground</key>
|
||||
<string>#5F5A60</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Constant</string>
|
||||
<key>scope</key>
|
||||
<string>constant</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#CF6A4C</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Entity</string>
|
||||
<key>scope</key>
|
||||
<string>entity</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#9B703F</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Keyword</string>
|
||||
<key>scope</key>
|
||||
<string>keyword</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#CDA869</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Storage</string>
|
||||
<key>scope</key>
|
||||
<string>storage</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#F9EE98</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>String</string>
|
||||
<key>scope</key>
|
||||
<string>string</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#8F9D6A</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Support</string>
|
||||
<key>scope</key>
|
||||
<string>support</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#9B859D</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Variable</string>
|
||||
<key>scope</key>
|
||||
<string>variable</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#7587A6</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Invalid – Deprecated</string>
|
||||
<key>scope</key>
|
||||
<string>invalid.deprecated</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>italic underline</string>
|
||||
<key>foreground</key>
|
||||
<string>#D2A8A1</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Invalid – Illegal</string>
|
||||
<key>scope</key>
|
||||
<string>invalid.illegal</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
<string>#562D56BF</string>
|
||||
<key>foreground</key>
|
||||
<string>#F8F8F8</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>-----------------------------------</string>
|
||||
<key>settings</key>
|
||||
<dict/>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>♦ Embedded Source</string>
|
||||
<key>scope</key>
|
||||
<string>text source</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
<string>#B0B3BA14</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>♦ Embedded Source (Bright)</string>
|
||||
<key>scope</key>
|
||||
<string>text.html.ruby source</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
<string>#B1B3BA21</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>♦ Entity inherited-class</string>
|
||||
<key>scope</key>
|
||||
<string>entity.other.inherited-class</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>italic</string>
|
||||
<key>foreground</key>
|
||||
<string>#9B5C2E</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>♦ String embedded-source</string>
|
||||
<key>scope</key>
|
||||
<string>string source</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#DAEFA3</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>♦ String constant</string>
|
||||
<key>scope</key>
|
||||
<string>string constant</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#DDF2A4</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>♦ String.regexp</string>
|
||||
<key>scope</key>
|
||||
<string>string.regexp</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#E9C062</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>♦ String.regexp.«special»</string>
|
||||
<key>scope</key>
|
||||
<string>string.regexp constant.character.escape, string.regexp source.ruby.embedded, string.regexp string.regexp.arbitrary-repitition</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#CF7D34</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>♦ String variable</string>
|
||||
<key>scope</key>
|
||||
<string>string variable</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#8A9A95</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>♦ Support.function</string>
|
||||
<key>scope</key>
|
||||
<string>support.function</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#DAD085</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>♦ Support.constant</string>
|
||||
<key>scope</key>
|
||||
<string>support.constant</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#CF6A4C</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>c C/C++ Preprocessor Line</string>
|
||||
<key>scope</key>
|
||||
<string>meta.preprocessor.c</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#8996A8</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>c C/C++ Preprocessor Directive</string>
|
||||
<key>scope</key>
|
||||
<string>meta.preprocessor.c keyword</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#AFC4DB</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>✘ Doctype/XML Processing</string>
|
||||
<key>scope</key>
|
||||
<string>meta.tag.sgml.doctype, meta.tag.sgml.doctype entity, meta.tag.sgml.doctype string, meta.tag.preprocessor.xml, meta.tag.preprocessor.xml entity, meta.tag.preprocessor.xml string</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#494949</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>✘ Meta.tag.«all»</string>
|
||||
<key>scope</key>
|
||||
<string>declaration.tag, declaration.tag entity, meta.tag, meta.tag entity</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#AC885B</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>✘ Meta.tag.inline</string>
|
||||
<key>scope</key>
|
||||
<string>declaration.tag.inline, declaration.tag.inline entity, source entity.name.tag, source entity.other.attribute-name, meta.tag.inline, meta.tag.inline entity</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#E0C589</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>§ css tag-name</string>
|
||||
<key>scope</key>
|
||||
<string>meta.selector.css entity.name.tag</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#CDA869</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>§ css:pseudo-class</string>
|
||||
<key>scope</key>
|
||||
<string>meta.selector.css entity.other.attribute-name.tag.pseudo-class</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#8F9D6A</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>§ css#id</string>
|
||||
<key>scope</key>
|
||||
<string>meta.selector.css entity.other.attribute-name.id</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#8B98AB</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>§ css.class</string>
|
||||
<key>scope</key>
|
||||
<string>meta.selector.css entity.other.attribute-name.class</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#9B703F</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>§ css property-name:</string>
|
||||
<key>scope</key>
|
||||
<string>support.type.property-name.css</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#C5AF75</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>§ css property-value;</string>
|
||||
<key>scope</key>
|
||||
<string>meta.property-group support.constant.property-value.css, meta.property-value support.constant.property-value.css</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#F9EE98</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>§ css @at-rule</string>
|
||||
<key>scope</key>
|
||||
<string>meta.preprocessor.at-rule keyword.control.at-rule</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#8693A5</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>§ css additional-constants</string>
|
||||
<key>scope</key>
|
||||
<string>meta.property-value support.constant.named-color.css, meta.property-value constant</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#CA7840</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>§ css constructor.argument</string>
|
||||
<key>scope</key>
|
||||
<string>meta.constructor.argument.css</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#8F9D6A</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>⎇ diff.header</string>
|
||||
<key>scope</key>
|
||||
<string>meta.diff, meta.diff.header, meta.separator</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
<string>#0E2231</string>
|
||||
<key>fontStyle</key>
|
||||
<string>italic</string>
|
||||
<key>foreground</key>
|
||||
<string>#F8F8F8</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>⎇ diff.deleted</string>
|
||||
<key>scope</key>
|
||||
<string>markup.deleted</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
<string>#420E09</string>
|
||||
<key>foreground</key>
|
||||
<string>#F8F8F8</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>⎇ diff.changed</string>
|
||||
<key>scope</key>
|
||||
<string>markup.changed</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
<string>#4A410D</string>
|
||||
<key>foreground</key>
|
||||
<string>#F8F8F8</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>⎇ diff.inserted</string>
|
||||
<key>scope</key>
|
||||
<string>markup.inserted</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
<string>#253B22</string>
|
||||
<key>foreground</key>
|
||||
<string>#F8F8F8</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Markup: List</string>
|
||||
<key>scope</key>
|
||||
<string>markup.list</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#F9EE98</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Markup: Heading</string>
|
||||
<key>scope</key>
|
||||
<string>markup.heading</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#CF6A4C</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</array>
|
||||
<key>uuid</key>
|
||||
<string>766026CB-703D-4610-B070-8DE07D967C5F</string>
|
||||
</dict>
|
||||
</plist>
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
var quicksort = function () {
|
||||
var sort = function(items) {
|
||||
if (items.length <= 1) return items;
|
||||
var pivot = items.shift(), current, left = [], right = [];
|
||||
while(items.length > 0) {
|
||||
current = items.shift();
|
||||
current < pivot ? left.push(current) : right.push(current);
|
||||
}
|
||||
return sort(left).concat(pivot).concat(sort(right));
|
||||
};
|
||||
|
||||
return sort(Array.apply(this, arguments));
|
||||
};
|
||||
-1
@@ -1 +0,0 @@
|
||||
Some text.
|
||||
@@ -1,136 +0,0 @@
|
||||
{fs} = require 'atom'
|
||||
path = require 'path'
|
||||
temp = require 'temp'
|
||||
|
||||
describe "fs", ->
|
||||
fixturesDir = path.join(__dirname, 'fixtures')
|
||||
|
||||
describe ".read(path)", ->
|
||||
it "return contents of file", ->
|
||||
expect(fs.read(require.resolve("./fixtures/sample.txt"))).toBe "Some text.\n"
|
||||
|
||||
it "does not through an exception when the path is a binary file", ->
|
||||
expect(-> fs.read(require.resolve("./fixtures/binary-file.png"))).not.toThrow()
|
||||
|
||||
describe ".isFileSync(path)", ->
|
||||
it "returns true with a file path", ->
|
||||
expect(fs.isFileSync(path.join(fixturesDir, 'sample.js'))).toBe true
|
||||
|
||||
it "returns false with a directory path", ->
|
||||
expect(fs.isFileSync(fixturesDir)).toBe false
|
||||
|
||||
it "returns false with a non-existent path", ->
|
||||
expect(fs.isFileSync(path.join(fixturesDir, 'non-existent'))).toBe false
|
||||
expect(fs.isFileSync(null)).toBe false
|
||||
|
||||
describe ".exists(path)", ->
|
||||
it "returns true when path exsits", ->
|
||||
expect(fs.exists(fixturesDir)).toBe true
|
||||
|
||||
it "returns false when path doesn't exsit", ->
|
||||
expect(fs.exists(path.join(fixturesDir, "-nope-does-not-exist"))).toBe false
|
||||
expect(fs.exists("")).toBe false
|
||||
expect(fs.exists(null)).toBe false
|
||||
|
||||
describe ".makeTree(path)", ->
|
||||
beforeEach ->
|
||||
fs.remove("/tmp/a") if fs.exists("/tmp/a")
|
||||
|
||||
it "creates all directories in path including any missing parent directories", ->
|
||||
fs.makeTree("/tmp/a/b/c")
|
||||
expect(fs.exists("/tmp/a/b/c")).toBeTruthy()
|
||||
|
||||
describe ".traverseTreeSync(path, onFile, onDirectory)", ->
|
||||
it "calls fn for every path in the tree at the given path", ->
|
||||
paths = []
|
||||
onPath = (childPath) ->
|
||||
paths.push(childPath)
|
||||
true
|
||||
fs.traverseTreeSync fixturesDir, onPath, onPath
|
||||
expect(paths).toEqual fs.listTreeSync(fixturesDir)
|
||||
|
||||
it "does not recurse into a directory if it is pruned", ->
|
||||
paths = []
|
||||
onPath = (childPath) ->
|
||||
if childPath.match(/\/dir$/)
|
||||
false
|
||||
else
|
||||
paths.push(childPath)
|
||||
true
|
||||
fs.traverseTreeSync fixturesDir, onPath, onPath
|
||||
|
||||
expect(paths.length).toBeGreaterThan 0
|
||||
for filePath in paths
|
||||
expect(filePath).not.toMatch /\/dir\//
|
||||
|
||||
it "returns entries if path is a symlink", ->
|
||||
symlinkPath = path.join(fixturesDir, 'symlink-to-dir')
|
||||
symlinkPaths = []
|
||||
onSymlinkPath = (path) -> symlinkPaths.push(path.substring(symlinkPath.length + 1))
|
||||
|
||||
regularPath = path.join(fixturesDir, 'dir')
|
||||
paths = []
|
||||
onPath = (path) -> paths.push(path.substring(regularPath.length + 1))
|
||||
|
||||
fs.traverseTreeSync(symlinkPath, onSymlinkPath, onSymlinkPath)
|
||||
fs.traverseTreeSync(regularPath, onPath, onPath)
|
||||
|
||||
expect(symlinkPaths).toEqual(paths)
|
||||
|
||||
it "ignores missing symlinks", ->
|
||||
directory = temp.mkdirSync('symlink-in-here')
|
||||
paths = []
|
||||
onPath = (childPath) -> paths.push(childPath)
|
||||
fs.symlinkSync(path.join(directory, 'source'), path.join(directory, 'destination'))
|
||||
fs.traverseTreeSync(directory, onPath)
|
||||
expect(paths.length).toBe 0
|
||||
|
||||
describe ".md5ForPath(path)", ->
|
||||
it "returns the MD5 hash of the file at the given path", ->
|
||||
expect(fs.md5ForPath(require.resolve('./fixtures/sample.js'))).toBe 'dd38087d0d7e3e4802a6d3f9b9745f2b'
|
||||
|
||||
describe ".list(path, extensions)", ->
|
||||
it "returns the absolute paths of entries within the given directory", ->
|
||||
paths = fs.listSync(project.getPath())
|
||||
expect(paths).toContain project.resolve('css.css')
|
||||
expect(paths).toContain project.resolve('coffee.coffee')
|
||||
expect(paths).toContain project.resolve('two-hundred.txt')
|
||||
|
||||
it "returns an empty array for paths that aren't directories or don't exist", ->
|
||||
expect(fs.listSync(project.resolve('sample.js'))).toEqual []
|
||||
expect(fs.listSync('/non/existent/directory')).toEqual []
|
||||
|
||||
it "can filter the paths by an optional array of file extensions", ->
|
||||
paths = fs.listSync(project.getPath(), ['.css', 'coffee'])
|
||||
expect(paths).toContain project.resolve('css.css')
|
||||
expect(paths).toContain project.resolve('coffee.coffee')
|
||||
expect(listedPath).toMatch /(css|coffee)$/ for listedPath in paths
|
||||
|
||||
describe ".list(path, [extensions,] callback)", ->
|
||||
paths = null
|
||||
|
||||
it "calls the callback with the absolute paths of entries within the given directory", ->
|
||||
waitsFor (done) ->
|
||||
fs.list project.getPath(), (err, result) ->
|
||||
paths = result
|
||||
done()
|
||||
runs ->
|
||||
expect(paths).toContain project.resolve('css.css')
|
||||
expect(paths).toContain project.resolve('coffee.coffee')
|
||||
expect(paths).toContain project.resolve('two-hundred.txt')
|
||||
|
||||
it "can filter the paths by an optional array of file extensions", ->
|
||||
waitsFor (done) ->
|
||||
fs.list project.getPath(), ['css', '.coffee'], (err, result) ->
|
||||
paths = result
|
||||
done()
|
||||
runs ->
|
||||
expect(paths).toContain project.resolve('css.css')
|
||||
expect(paths).toContain project.resolve('coffee.coffee')
|
||||
expect(listedPath).toMatch /(css|coffee)$/ for listedPath in paths
|
||||
|
||||
describe ".absolute(relativePath)", ->
|
||||
it "converts a leading ~ segment to the HOME directory", ->
|
||||
expect(fs.absolute('~')).toBe fs.realpathSync(process.env.HOME)
|
||||
expect(fs.absolute(path.join('~', 'does', 'not', 'exist'))).toBe path.join(process.env.HOME, 'does', 'not', 'exist')
|
||||
expect(fs.absolute('~test')).toBe '~test'
|
||||
+81
-69
@@ -8,18 +8,19 @@ describe "Git", ->
|
||||
repo = null
|
||||
|
||||
beforeEach ->
|
||||
fs.remove('/tmp/.git') if fs.isDirectorySync('/tmp/.git')
|
||||
gitPath = path.join(temp.dir, '.git')
|
||||
fs.removeSync(gitPath) if fs.isDirectorySync(gitPath)
|
||||
|
||||
afterEach ->
|
||||
repo.destroy() if repo?.repo?
|
||||
|
||||
describe "@open(path)", ->
|
||||
it "returns null when no repository is found", ->
|
||||
expect(Git.open('/tmp/nogit.txt')).toBeNull()
|
||||
expect(Git.open(path.join(temp.dir, 'nogit.txt'))).toBeNull()
|
||||
|
||||
describe "new Git(path)", ->
|
||||
it "throws an exception when no repository is found", ->
|
||||
expect(-> new Git('/tmp/nogit.txt')).toThrow()
|
||||
expect(-> new Git(path.join(temp.dir, 'nogit.txt'))).toThrow()
|
||||
|
||||
describe ".getPath()", ->
|
||||
it "returns the repository path for a .git directory path", ->
|
||||
@@ -46,22 +47,22 @@ describe "Git", ->
|
||||
repo = new Git(path.join(__dirname, 'fixtures', 'git', 'working-dir'))
|
||||
filePath = require.resolve('./fixtures/git/working-dir/file.txt')
|
||||
newPath = path.join(__dirname, 'fixtures', 'git', 'working-dir', 'new-path.txt')
|
||||
originalPathText = fs.read(filePath)
|
||||
originalPathText = fs.readFileSync(filePath, 'utf8')
|
||||
|
||||
afterEach ->
|
||||
fs.writeSync(filePath, originalPathText)
|
||||
fs.remove(newPath) if fs.exists(newPath)
|
||||
fs.writeFileSync(filePath, originalPathText)
|
||||
fs.removeSync(newPath) if fs.existsSync(newPath)
|
||||
|
||||
describe "when the path is unstaged", ->
|
||||
it "returns false if the path has not been modified", ->
|
||||
expect(repo.isPathModified(filePath)).toBeFalsy()
|
||||
|
||||
it "returns true if the path is modified", ->
|
||||
fs.writeSync(filePath, "change")
|
||||
fs.writeFileSync(filePath, "change")
|
||||
expect(repo.isPathModified(filePath)).toBeTruthy()
|
||||
|
||||
it "returns true if the path is deleted", ->
|
||||
fs.remove(filePath)
|
||||
fs.removeSync(filePath)
|
||||
expect(repo.isPathModified(filePath)).toBeTruthy()
|
||||
|
||||
it "returns false if the path is new", ->
|
||||
@@ -74,10 +75,10 @@ describe "Git", ->
|
||||
repo = new Git(path.join(__dirname, 'fixtures', 'git', 'working-dir'))
|
||||
filePath = require.resolve('./fixtures/git/working-dir/file.txt')
|
||||
newPath = path.join(__dirname, 'fixtures', 'git', 'working-dir', 'new-path.txt')
|
||||
fs.writeSync(newPath, "i'm new here")
|
||||
fs.writeFileSync(newPath, "i'm new here")
|
||||
|
||||
afterEach ->
|
||||
fs.remove(newPath) if fs.exists(newPath)
|
||||
fs.removeSync(newPath) if fs.existsSync(newPath)
|
||||
|
||||
describe "when the path is unstaged", ->
|
||||
it "returns true if the path is new", ->
|
||||
@@ -92,35 +93,35 @@ describe "Git", ->
|
||||
beforeEach ->
|
||||
repo = new Git(path.join(__dirname, 'fixtures', 'git', 'working-dir'))
|
||||
path1 = require.resolve('./fixtures/git/working-dir/file.txt')
|
||||
originalPath1Text = fs.read(path1)
|
||||
originalPath1Text = fs.readFileSync(path1, 'utf8')
|
||||
path2 = require.resolve('./fixtures/git/working-dir/other.txt')
|
||||
originalPath2Text = fs.read(path2)
|
||||
originalPath2Text = fs.readFileSync(path2, 'utf8')
|
||||
|
||||
afterEach ->
|
||||
fs.writeSync(path1, originalPath1Text)
|
||||
fs.writeSync(path2, originalPath2Text)
|
||||
fs.writeFileSync(path1, originalPath1Text)
|
||||
fs.writeFileSync(path2, originalPath2Text)
|
||||
|
||||
it "no longer reports a path as modified after checkout", ->
|
||||
expect(repo.isPathModified(path1)).toBeFalsy()
|
||||
fs.writeSync(path1, '')
|
||||
fs.writeFileSync(path1, '')
|
||||
expect(repo.isPathModified(path1)).toBeTruthy()
|
||||
expect(repo.checkoutHead(path1)).toBeTruthy()
|
||||
expect(repo.isPathModified(path1)).toBeFalsy()
|
||||
|
||||
it "restores the contents of the path to the original text", ->
|
||||
fs.writeSync(path1, '')
|
||||
fs.writeFileSync(path1, '')
|
||||
expect(repo.checkoutHead(path1)).toBeTruthy()
|
||||
expect(fs.read(path1)).toBe(originalPath1Text)
|
||||
expect(fs.readFileSync(path1, 'utf8')).toBe(originalPath1Text)
|
||||
|
||||
it "only restores the path specified", ->
|
||||
fs.writeSync(path2, 'path 2 is edited')
|
||||
fs.writeFileSync(path2, 'path 2 is edited')
|
||||
expect(repo.isPathModified(path2)).toBeTruthy()
|
||||
expect(repo.checkoutHead(path1)).toBeTruthy()
|
||||
expect(fs.read(path2)).toBe('path 2 is edited')
|
||||
expect(fs.readFileSync(path2, 'utf8')).toBe('path 2 is edited')
|
||||
expect(repo.isPathModified(path2)).toBeTruthy()
|
||||
|
||||
it "fires a status-changed event if the checkout completes successfully", ->
|
||||
fs.writeSync(path1, '')
|
||||
fs.writeFileSync(path1, '')
|
||||
repo.getPathStatus(path1)
|
||||
statusHandler = jasmine.createSpy('statusHandler')
|
||||
repo.on 'status-changed', statusHandler
|
||||
@@ -143,14 +144,14 @@ describe "Git", ->
|
||||
beforeEach ->
|
||||
repo = new Git(path.join(__dirname, 'fixtures', 'git', 'working-dir'))
|
||||
filePath = require.resolve('./fixtures/git/working-dir/file.txt')
|
||||
originalPathText = fs.read(filePath)
|
||||
originalPathText = fs.readFileSync(filePath, 'utf8')
|
||||
|
||||
afterEach ->
|
||||
fs.writeSync(filePath, originalPathText)
|
||||
fs.writeFileSync(filePath, originalPathText)
|
||||
|
||||
it "returns the number of lines added and deleted", ->
|
||||
expect(repo.getDiffStats(filePath)).toEqual {added: 0, deleted: 0}
|
||||
fs.writeSync(filePath, "#{originalPathText} edited line")
|
||||
fs.writeFileSync(filePath, "#{originalPathText} edited line")
|
||||
expect(repo.getDiffStats(filePath)).toEqual {added: 1, deleted: 1}
|
||||
|
||||
describe ".getPathStatus(path)", ->
|
||||
@@ -159,20 +160,20 @@ describe "Git", ->
|
||||
beforeEach ->
|
||||
repo = new Git(path.join(__dirname, 'fixtures', 'git', 'working-dir'))
|
||||
filePath = require.resolve('./fixtures/git/working-dir/file.txt')
|
||||
originalPathText = fs.read(filePath)
|
||||
originalPathText = fs.readFileSync(filePath, 'utf8')
|
||||
|
||||
afterEach ->
|
||||
fs.writeSync(filePath, originalPathText)
|
||||
fs.writeFileSync(filePath, originalPathText)
|
||||
|
||||
it "trigger a status-changed event when the new status differs from the last cached one", ->
|
||||
statusHandler = jasmine.createSpy("statusHandler")
|
||||
repo.on 'status-changed', statusHandler
|
||||
fs.writeSync(filePath, '')
|
||||
fs.writeFileSync(filePath, '')
|
||||
status = repo.getPathStatus(filePath)
|
||||
expect(statusHandler.callCount).toBe 1
|
||||
expect(statusHandler.argsForCall[0][0..1]).toEqual [filePath, status]
|
||||
|
||||
fs.writeSync(filePath, 'abc')
|
||||
fs.writeFileSync(filePath, 'abc')
|
||||
status = repo.getPathStatus(filePath)
|
||||
expect(statusHandler.callCount).toBe 1
|
||||
|
||||
@@ -181,18 +182,18 @@ describe "Git", ->
|
||||
|
||||
beforeEach ->
|
||||
repo = new Git(path.join(__dirname, 'fixtures', 'git', 'working-dir'))
|
||||
modifiedPath = project.resolve('git/working-dir/file.txt')
|
||||
originalModifiedPathText = fs.read(modifiedPath)
|
||||
newPath = project.resolve('git/working-dir/untracked.txt')
|
||||
cleanPath = project.resolve('git/working-dir/other.txt')
|
||||
fs.writeSync(newPath, '')
|
||||
modifiedPath = atom.project.resolve('git/working-dir/file.txt')
|
||||
originalModifiedPathText = fs.readFileSync(modifiedPath, 'utf8')
|
||||
newPath = atom.project.resolve('git/working-dir/untracked.txt')
|
||||
cleanPath = atom.project.resolve('git/working-dir/other.txt')
|
||||
fs.writeFileSync(newPath, '')
|
||||
|
||||
afterEach ->
|
||||
fs.writeSync(modifiedPath, originalModifiedPathText)
|
||||
fs.remove(newPath) if fs.exists(newPath)
|
||||
fs.writeFileSync(modifiedPath, originalModifiedPathText)
|
||||
fs.removeSync(newPath) if fs.existsSync(newPath)
|
||||
|
||||
it "returns status information for all new and modified files", ->
|
||||
fs.writeSync(modifiedPath, 'making this path modified')
|
||||
fs.writeFileSync(modifiedPath, 'making this path modified')
|
||||
statusHandler = jasmine.createSpy('statusHandler')
|
||||
repo.on 'statuses-changed', statusHandler
|
||||
repo.refreshStatus()
|
||||
@@ -206,58 +207,69 @@ describe "Git", ->
|
||||
expect(repo.isStatusNew(statuses[newPath])).toBeTruthy()
|
||||
expect(repo.isStatusModified(statuses[modifiedPath])).toBeTruthy()
|
||||
|
||||
describe "when a buffer is changed and then saved", ->
|
||||
[originalContent, editSession] = []
|
||||
describe "buffer events", ->
|
||||
[originalContent, editor] = []
|
||||
|
||||
beforeEach ->
|
||||
editor = atom.project.openSync('sample.js')
|
||||
originalContent = editor.getText()
|
||||
|
||||
afterEach ->
|
||||
fs.writeSync(editSession.getPath(), originalContent)
|
||||
fs.writeFileSync(editor.getPath(), originalContent)
|
||||
|
||||
it "emits a status-changed event", ->
|
||||
editSession = project.open('sample.js')
|
||||
originalContent = editSession.getText()
|
||||
editSession.insertNewline()
|
||||
it "emits a status-changed event when a buffer is saved", ->
|
||||
editor.insertNewline()
|
||||
|
||||
statusHandler = jasmine.createSpy('statusHandler')
|
||||
project.getRepo().on 'status-changed', statusHandler
|
||||
editSession.save()
|
||||
atom.project.getRepo().on 'status-changed', statusHandler
|
||||
editor.save()
|
||||
expect(statusHandler.callCount).toBe 1
|
||||
expect(statusHandler).toHaveBeenCalledWith editSession.getPath(), 256
|
||||
expect(statusHandler).toHaveBeenCalledWith editor.getPath(), 256
|
||||
|
||||
describe "when a buffer is reloaded and has been changed", ->
|
||||
[originalContent, editSession] = []
|
||||
|
||||
afterEach ->
|
||||
fs.writeSync(editSession.getPath(), originalContent)
|
||||
|
||||
it "emits a status-changed event", ->
|
||||
editSession = project.open('sample.js')
|
||||
originalContent = editSession.getText()
|
||||
fs.writeSync(editSession.getPath(), 'changed')
|
||||
it "emits a status-changed event when a buffer is reloaded", ->
|
||||
fs.writeFileSync(editor.getPath(), 'changed')
|
||||
|
||||
statusHandler = jasmine.createSpy('statusHandler')
|
||||
project.getRepo().on 'status-changed', statusHandler
|
||||
editSession.getBuffer().reload()
|
||||
atom.project.getRepo().on 'status-changed', statusHandler
|
||||
editor.getBuffer().reload()
|
||||
expect(statusHandler.callCount).toBe 1
|
||||
expect(statusHandler).toHaveBeenCalledWith editSession.getPath(), 256
|
||||
editSession.getBuffer().reload()
|
||||
expect(statusHandler).toHaveBeenCalledWith editor.getPath(), 256
|
||||
editor.getBuffer().reload()
|
||||
expect(statusHandler.callCount).toBe 1
|
||||
|
||||
it "emits a status-changed event when a buffer's path changes", ->
|
||||
fs.writeFileSync(editor.getPath(), 'changed')
|
||||
|
||||
statusHandler = jasmine.createSpy('statusHandler')
|
||||
atom.project.getRepo().on 'status-changed', statusHandler
|
||||
editor.getBuffer().emit 'path-changed'
|
||||
expect(statusHandler.callCount).toBe 1
|
||||
expect(statusHandler).toHaveBeenCalledWith editor.getPath(), 256
|
||||
editor.getBuffer().emit 'path-changed'
|
||||
expect(statusHandler.callCount).toBe 1
|
||||
|
||||
describe "when a project is deserialized", ->
|
||||
[originalContent, buffer, project2] = []
|
||||
|
||||
afterEach ->
|
||||
fs.writeSync(buffer.getPath(), originalContent)
|
||||
fs.writeFileSync(buffer.getPath(), originalContent)
|
||||
project2?.destroy()
|
||||
|
||||
it "subscribes to all the serialized buffers in the project", ->
|
||||
project.open('sample.js')
|
||||
project2 = deserialize(project.serialize())
|
||||
atom.project.openSync('sample.js')
|
||||
#TODO Replace with atom.replicate().project when Atom is a telepath model
|
||||
project2 = atom.replicate().get('project')
|
||||
buffer = project2.getBuffers()[0]
|
||||
originalContent = buffer.getText()
|
||||
buffer.append('changes')
|
||||
|
||||
statusHandler = jasmine.createSpy('statusHandler')
|
||||
project2.getRepo().on 'status-changed', statusHandler
|
||||
buffer.save()
|
||||
expect(statusHandler.callCount).toBe 1
|
||||
expect(statusHandler).toHaveBeenCalledWith buffer.getPath(), 256
|
||||
waitsFor ->
|
||||
buffer.loaded
|
||||
|
||||
runs ->
|
||||
originalContent = buffer.getText()
|
||||
buffer.append('changes')
|
||||
|
||||
statusHandler = jasmine.createSpy('statusHandler')
|
||||
project2.getRepo().on 'status-changed', statusHandler
|
||||
buffer.save()
|
||||
expect(statusHandler.callCount).toBe 1
|
||||
expect(statusHandler).toHaveBeenCalledWith buffer.getPath(), 256
|
||||
|
||||
@@ -3,6 +3,7 @@ module.exports.runSpecSuite = (specSuite, logErrors=true) ->
|
||||
window[key] = value for key, value of require '../vendor/jasmine'
|
||||
|
||||
require 'jasmine-focused'
|
||||
require 'jasmine-tagged'
|
||||
|
||||
TimeReporter = require './time-reporter'
|
||||
timeReporter = new TimeReporter()
|
||||
@@ -27,6 +28,7 @@ module.exports.runSpecSuite = (specSuite, logErrors=true) ->
|
||||
jasmineEnv = jasmine.getEnv()
|
||||
jasmineEnv.addReporter(reporter)
|
||||
jasmineEnv.addReporter(timeReporter)
|
||||
jasmineEnv.setIncludedTags([process.platform])
|
||||
|
||||
$('body').append $$ -> @div id: 'jasmine-content'
|
||||
|
||||
|
||||
@@ -1,178 +0,0 @@
|
||||
{_, $, $$, View} = require 'atom'
|
||||
|
||||
describe 'jQuery extensions', ->
|
||||
describe '$.fn.preempt(eventName, handler)', ->
|
||||
[returnValue, element, events] = []
|
||||
|
||||
beforeEach ->
|
||||
returnValue = undefined
|
||||
element = $("<div>")
|
||||
events = []
|
||||
|
||||
element.on 'foo', -> events.push(1)
|
||||
element.preempt 'foo', ->
|
||||
events.push(2)
|
||||
returnValue
|
||||
element.on 'foo', -> events.push(3)
|
||||
|
||||
it 'calls the preempting handler before all others', ->
|
||||
element.trigger 'foo'
|
||||
expect(events).toEqual [2,1,3]
|
||||
|
||||
describe 'when handler returns false', ->
|
||||
it 'does not call subsequent handlers', ->
|
||||
returnValue = false
|
||||
element.trigger 'foo'
|
||||
expect(events).toEqual [2]
|
||||
|
||||
describe 'when the event is namespaced', ->
|
||||
it 'calls handler', ->
|
||||
element.preempt 'foo.bar', -> events.push(4)
|
||||
element.trigger 'foo'
|
||||
expect(events).toEqual [4,2,1,3]
|
||||
|
||||
events = []
|
||||
element.trigger 'foo.bar'
|
||||
expect(events).toEqual [4]
|
||||
|
||||
events = []
|
||||
element.off('.bar')
|
||||
element.trigger 'foo'
|
||||
expect(events).toEqual [2,1,3]
|
||||
|
||||
describe "$.fn.events() and $.fn.document(...)", ->
|
||||
it "returns a list of all events being listened for on the target node or its ancestors, along with their documentation string", ->
|
||||
view = $$ ->
|
||||
@div id: 'a', =>
|
||||
@div id: 'b', =>
|
||||
@div id: 'c'
|
||||
@div id: 'd'
|
||||
|
||||
view.document 'a1', "This is event A2"
|
||||
view.document 'b2', "This is event b2"
|
||||
|
||||
view.document 'a1', "A1: Waste perfectly-good steak"
|
||||
view.on 'a1', ->
|
||||
view.on 'a2', ->
|
||||
view.on 'b1', -> # should not appear as a duplicate
|
||||
|
||||
divB = view.find('#b')
|
||||
|
||||
divB.document 'b1', "B1: Super-sonic bomber"
|
||||
divB.document 'b2', "B2: Looks evil. Kinda is."
|
||||
divB.on 'b1', ->
|
||||
divB.on 'b2', ->
|
||||
|
||||
view.find('#c').on 'c', ->
|
||||
view.find('#d').on 'd', ->
|
||||
|
||||
expect(view.find('#c').events()).toEqual
|
||||
'c': null
|
||||
'b1': "B1: Super-sonic bomber"
|
||||
'b2': "B2: Looks evil. Kinda is."
|
||||
'a1': "A1: Waste perfectly-good steak"
|
||||
'a2': null
|
||||
|
||||
describe "$.fn.command(eventName, [selector, options,] handler)", ->
|
||||
[view, handler] = []
|
||||
|
||||
beforeEach ->
|
||||
view = $$ ->
|
||||
@div class: 'a', =>
|
||||
@div class: 'b'
|
||||
@div class: 'c'
|
||||
handler = jasmine.createSpy("commandHandler")
|
||||
|
||||
it "binds the handler to the given event / selector for all argument combinations", ->
|
||||
view.command 'test:foo', handler
|
||||
view.trigger 'test:foo'
|
||||
expect(handler).toHaveBeenCalled()
|
||||
handler.reset()
|
||||
|
||||
view.command 'test:bar', '.b', handler
|
||||
view.find('.b').trigger 'test:bar'
|
||||
view.find('.c').trigger 'test:bar'
|
||||
expect(handler.callCount).toBe 1
|
||||
handler.reset()
|
||||
|
||||
view.command 'test:baz', doc: 'Spaz', handler
|
||||
view.trigger 'test:baz'
|
||||
expect(handler).toHaveBeenCalled()
|
||||
handler.reset()
|
||||
|
||||
view.command 'test:quux', '.c', doc: 'Lorem', handler
|
||||
view.find('.b').trigger 'test:quux'
|
||||
view.find('.c').trigger 'test:quux'
|
||||
expect(handler.callCount).toBe 1
|
||||
|
||||
it "passes the 'data' option through when binding the event handler", ->
|
||||
view.command 'test:foo', data: "bar", handler
|
||||
view.trigger 'test:foo'
|
||||
expect(handler.argsForCall[0][0].data).toBe 'bar'
|
||||
|
||||
it "sets a custom docstring if the 'doc' option is specified", ->
|
||||
view.command 'test:foo', doc: "Foo!", handler
|
||||
expect(view.events()).toEqual 'test:foo': 'Test: Foo!'
|
||||
|
||||
it "capitalizes the 'github' prefix how we like it", ->
|
||||
view.command 'github:spelling', handler
|
||||
expect(view.events()).toEqual 'github:spelling': 'GitHub: Spelling'
|
||||
|
||||
describe "$.fn.scrollUp/Down/ToTop/ToBottom", ->
|
||||
it "scrolls the element in the specified way if possible", ->
|
||||
view = $$ -> @div => _.times 20, => @div('A')
|
||||
view.css(height: 100, width: 100, overflow: 'scroll')
|
||||
view.attachToDom()
|
||||
|
||||
view.scrollUp()
|
||||
expect(view.scrollTop()).toBe 0
|
||||
|
||||
view.scrollDown()
|
||||
expect(view.scrollTop()).toBeGreaterThan 0
|
||||
previousScrollTop = view.scrollTop()
|
||||
view.scrollDown()
|
||||
expect(view.scrollTop()).toBeGreaterThan previousScrollTop
|
||||
|
||||
view.scrollToBottom()
|
||||
expect(view.scrollTop()).toBe view.prop('scrollHeight') - 100
|
||||
previousScrollTop = view.scrollTop()
|
||||
view.scrollDown()
|
||||
expect(view.scrollTop()).toBe previousScrollTop
|
||||
view.scrollUp()
|
||||
expect(view.scrollTop()).toBeLessThan previousScrollTop
|
||||
previousScrollTop = view.scrollTop()
|
||||
view.scrollUp()
|
||||
expect(view.scrollTop()).toBeLessThan previousScrollTop
|
||||
|
||||
view.scrollToTop()
|
||||
expect(view.scrollTop()).toBe 0
|
||||
|
||||
describe "Event.prototype", ->
|
||||
class GrandchildView extends View
|
||||
@content: -> @div class: 'grandchild'
|
||||
|
||||
class ChildView extends View
|
||||
@content: ->
|
||||
@div class: 'child', =>
|
||||
@subview 'grandchild', new GrandchildView
|
||||
|
||||
class ParentView extends View
|
||||
@content: ->
|
||||
@div class: 'parent', =>
|
||||
@subview 'child', new ChildView
|
||||
|
||||
[parentView, event] = []
|
||||
beforeEach ->
|
||||
parentView = new ParentView
|
||||
eventHandler = jasmine.createSpy('eventHandler')
|
||||
parentView.on 'foo', '.child', eventHandler
|
||||
parentView.child.grandchild.trigger 'foo'
|
||||
event = eventHandler.argsForCall[0][0]
|
||||
|
||||
describe ".currentTargetView()", ->
|
||||
it "returns the current target's space pen view", ->
|
||||
expect(event.currentTargetView()).toBe parentView.child
|
||||
|
||||
describe ".targetView()", ->
|
||||
it "returns the target's space pen view", ->
|
||||
expect(event.targetView()).toBe parentView.child.grandchild
|
||||
+78
-110
@@ -1,12 +1,15 @@
|
||||
path = require 'path'
|
||||
|
||||
Keymap = require '../src/keymap'
|
||||
{$, $$, RootView} = require 'atom'
|
||||
|
||||
describe "Keymap", ->
|
||||
fragment = null
|
||||
keymap = null
|
||||
resourcePath = atom.getLoadSettings().resourcePath
|
||||
|
||||
beforeEach ->
|
||||
keymap = new Keymap
|
||||
keymap = new Keymap({configDirPath: atom.getConfigDirPath(), resourcePath})
|
||||
fragment = $ """
|
||||
<div class="command-mode">
|
||||
<div class="child-node">
|
||||
@@ -18,25 +21,19 @@ describe "Keymap", ->
|
||||
describe ".handleKeyEvent(event)", ->
|
||||
deleteCharHandler = null
|
||||
insertCharHandler = null
|
||||
commandZHandler = null
|
||||
|
||||
beforeEach ->
|
||||
keymap.bindKeys '.command-mode', 'x': 'deleteChar'
|
||||
keymap.bindKeys '.insert-mode', 'x': 'insertChar'
|
||||
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
|
||||
|
||||
it "adds a 'keystrokes' string to the event object", ->
|
||||
event = keydownEvent('x', altKey: true, metaKey: true)
|
||||
keymap.handleKeyEvent(event)
|
||||
expect(event.keystrokes).toBe 'alt-meta-x'
|
||||
|
||||
event = keydownEvent(',', metaKey: true)
|
||||
event.which = 188
|
||||
keymap.handleKeyEvent(event)
|
||||
expect(event.keystrokes).toBe 'meta-,'
|
||||
fragment.on 'commandZPressed', commandZHandler
|
||||
|
||||
describe "when no binding matches the event's keystroke", ->
|
||||
it "does not return false so the event continues to propagate", ->
|
||||
@@ -44,10 +41,11 @@ describe "Keymap", ->
|
||||
|
||||
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) # This is the 'z' key using the Greek keyboard layout
|
||||
event.which = 122
|
||||
keymap.handleKeyEvent(event)
|
||||
expect(event.keystrokes).toBe 'meta-z'
|
||||
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", ->
|
||||
@@ -64,9 +62,6 @@ describe "Keymap", ->
|
||||
keymap.handleKeyEvent(event)
|
||||
expect(deleteCharHandler).not.toHaveBeenCalled()
|
||||
expect(insertCharHandler).toHaveBeenCalled()
|
||||
commandEvent = insertCharHandler.argsForCall[0][0]
|
||||
expect(commandEvent.keyEvent).toBe event
|
||||
expect(event.keystrokes).toBe 'x'
|
||||
|
||||
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", ->
|
||||
@@ -85,7 +80,7 @@ describe "Keymap", ->
|
||||
|
||||
describe "when the event's target node descends from multiple nodes that match selectors with a binding", ->
|
||||
beforeEach ->
|
||||
keymap.bindKeys '.child-node', 'x': 'foo'
|
||||
keymap.bindKeys 'name', '.child-node', 'x': 'foo'
|
||||
|
||||
it "only triggers bindings on selectors associated with the closest ancestor node", ->
|
||||
fooHandler = jasmine.createSpy 'fooHandler'
|
||||
@@ -122,10 +117,10 @@ describe "Keymap", ->
|
||||
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 'div .child-node', 'x': 'foo'
|
||||
keymap.bindKeys '.command-mode .child-node !important', 'x': 'baz'
|
||||
keymap.bindKeys '.command-mode .child-node', 'x': 'quux'
|
||||
keymap.bindKeys '.child-node', 'x': 'bar'
|
||||
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'
|
||||
@@ -143,8 +138,8 @@ describe "Keymap", ->
|
||||
|
||||
describe "when the matching selectors have the same specificity", ->
|
||||
it "triggers the bindings for the most recently declared selector", ->
|
||||
keymap.bindKeys '.child-node', 'x': 'foo', 'y': 'baz'
|
||||
keymap.bindKeys '.child-node', 'x': 'bar'
|
||||
keymap.bindKeys 'name', '.child-node', 'x': 'foo', 'y': 'baz'
|
||||
keymap.bindKeys 'name', '.child-node', 'x': 'bar'
|
||||
|
||||
fooHandler = jasmine.createSpy 'fooHandler'
|
||||
barHandler = jasmine.createSpy 'barHandler'
|
||||
@@ -164,10 +159,11 @@ describe "Keymap", ->
|
||||
|
||||
describe "when the event's target is the document body", ->
|
||||
it "triggers the mapped event on the rootView", ->
|
||||
window.rootView = new RootView
|
||||
keymap.bindKeys 'body', 'x': 'foo'
|
||||
atom.rootView = new RootView
|
||||
atom.rootView.attachToDom()
|
||||
keymap.bindKeys 'name', 'body', 'x': 'foo'
|
||||
fooHandler = jasmine.createSpy("fooHandler")
|
||||
rootView.on 'foo', fooHandler
|
||||
atom.rootView.on 'foo', fooHandler
|
||||
|
||||
result = keymap.handleKeyEvent(keydownEvent('x', target: document.body))
|
||||
expect(result).toBe(false)
|
||||
@@ -177,7 +173,7 @@ describe "Keymap", ->
|
||||
|
||||
describe "when the event matches a 'native!' binding", ->
|
||||
it "returns true, allowing the browser's native key handling to process the event", ->
|
||||
keymap.bindKeys '.grandchild-node', 'x': 'native!'
|
||||
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
|
||||
@@ -187,7 +183,7 @@ describe "Keymap", ->
|
||||
[quitHandler, closeOtherWindowsHandler] = []
|
||||
|
||||
beforeEach ->
|
||||
keymap.bindKeys "*",
|
||||
keymap.bindKeys 'name', "*",
|
||||
'ctrl-x ctrl-c': 'quit'
|
||||
'ctrl-x 1': 'close-other-windows'
|
||||
|
||||
@@ -203,6 +199,7 @@ describe "Keymap", ->
|
||||
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()
|
||||
@@ -216,7 +213,7 @@ describe "Keymap", ->
|
||||
expect(closeOtherWindowsHandler).toHaveBeenCalled()
|
||||
|
||||
describe "when a second keystroke added to the first doesn't match any bindings", ->
|
||||
it "clears the queued keystrokes without triggering any events", ->
|
||||
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()
|
||||
@@ -226,7 +223,7 @@ describe "Keymap", ->
|
||||
|
||||
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 ".grandchild-node", 'ctrl-x ctrl-c': 'more-specific-quit'
|
||||
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
|
||||
@@ -250,39 +247,17 @@ describe "Keymap", ->
|
||||
describe "when there is a complete binding with a more specific selector", ->
|
||||
it "favors the more specific complete match", ->
|
||||
|
||||
describe "when a tab keystroke does not match any bindings", ->
|
||||
it "returns false to prevent the browser from transferring focus", ->
|
||||
expect(keymap.handleKeyEvent(keydownEvent('U+0009', target: fragment[0]))).toBe false
|
||||
|
||||
describe ".keystrokesByCommandForSelector(selector)", ->
|
||||
it "returns a hash of all commands and their keybindings", ->
|
||||
keymap.bindKeys 'body', 'a': 'letter'
|
||||
keymap.bindKeys '.editor', 'b': 'letter'
|
||||
keymap.bindKeys '.editor', '1': 'number'
|
||||
keymap.bindKeys '.editor', 'meta-alt-1': 'number-with-modifiers'
|
||||
|
||||
expect(keymap.keystrokesByCommandForSelector()).toEqual
|
||||
'letter': ['b', 'a']
|
||||
'number': ['1']
|
||||
'number-with-modifiers': ['alt-meta-1']
|
||||
|
||||
expect(keymap.keystrokesByCommandForSelector('.editor')).toEqual
|
||||
'letter': ['b']
|
||||
'number': ['1']
|
||||
'number-with-modifiers': ['alt-meta-1']
|
||||
|
||||
|
||||
describe ".bindKeys(selector, bindings)", ->
|
||||
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 '*', 'ctrl-alt-delete': 'foo'
|
||||
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 '*', 'ctrl-alt--': 'foo'
|
||||
keymap.bindKeys 'name', '*', 'ctrl-alt--': 'foo'
|
||||
result = keymap.handleKeyEvent(keydownEvent('-', ctrlKey: true, altKey: true, target: fragment[0]))
|
||||
expect(result).toBe(false)
|
||||
expect(fooHandler).toHaveBeenCalled()
|
||||
@@ -295,15 +270,17 @@ describe "Keymap", ->
|
||||
'.brown':
|
||||
'ctrl-h': 'harvest'
|
||||
|
||||
expect(keymap.bindingsForElement($$ -> @div class: 'green')).toEqual { 'ctrl-c': 'cultivate' }
|
||||
expect(keymap.bindingsForElement($$ -> @div class: 'brown')).toEqual { '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.bindingsForElement($$ -> @div class: 'green')).toEqual {}
|
||||
expect(keymap.bindingsForElement($$ -> @div class: 'brown')).toEqual {}
|
||||
expect(keymap.bindingSetsByFirstKeystroke['ctrl-c']).toEqual []
|
||||
expect(keymap.bindingSetsByFirstKeystroke['ctrl-h']).toEqual []
|
||||
expect(keymap.keyBindingsMatchingElement($$ -> @div class: 'green')).toHaveLength 1
|
||||
expect(keymap.keyBindingsMatchingElement($$ -> @div class: 'brown')).toEqual []
|
||||
|
||||
describe ".keystrokeStringForEvent(event)", ->
|
||||
describe "when no modifiers are pressed", ->
|
||||
@@ -314,12 +291,12 @@ describe "Keymap", ->
|
||||
expect(keymap.keystrokeStringForEvent(keydownEvent('left'))).toBe 'left'
|
||||
expect(keymap.keystrokeStringForEvent(keydownEvent('\b'))).toBe 'backspace'
|
||||
|
||||
describe "when ctrl, alt or meta is pressed with a non-modifier key", ->
|
||||
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 'meta-['
|
||||
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-ctrl-meta-left'
|
||||
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", ->
|
||||
@@ -328,54 +305,45 @@ describe "Keymap", ->
|
||||
expect(keymap.keystrokeStringForEvent(keydownEvent('left', shiftKey: true))).toBe 'shift-left'
|
||||
expect(keymap.keystrokeStringForEvent(keydownEvent('Left', shiftKey: true))).toBe 'shift-left'
|
||||
|
||||
describe ".bindingsForElement(element)", ->
|
||||
describe ".keyBindingsMatchingElement(element)", ->
|
||||
it "returns the matching bindings for the element", ->
|
||||
keymap.bindKeys '.command-mode', 'c': 'c'
|
||||
keymap.bindKeys '.grandchild-node', 'g': 'g'
|
||||
keymap.bindKeys 'name', '.command-mode', 'c': 'c'
|
||||
keymap.bindKeys 'name', '.grandchild-node', 'g': 'g'
|
||||
|
||||
bindings = keymap.bindingsForElement(fragment.find('.grandchild-node'))
|
||||
expect(Object.keys(bindings).length).toBe 2
|
||||
expect(bindings['c']).toEqual "c"
|
||||
expect(bindings['g']).toEqual "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 '.command-mode', 'g': 'command-mode'
|
||||
keymap.bindKeys '.command-mode .grandchild-node', 'g': 'command-and-grandchild-node'
|
||||
keymap.bindKeys '.grandchild-node', 'g': 'grandchild-node'
|
||||
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.bindingsForElement(fragment.find('.grandchild-node'))
|
||||
expect(Object.keys(bindings).length).toBe 1
|
||||
expect(bindings['g']).toEqual "command-and-grandchild-node"
|
||||
bindings = keymap.keyBindingsMatchingElement(fragment.find('.grandchild-node'))
|
||||
expect(bindings).toHaveLength 3
|
||||
expect(bindings[0].command).toEqual "cmd-and-grandchild-node"
|
||||
|
||||
describe ".getAllKeyMappings", ->
|
||||
it "returns the all bindings", ->
|
||||
keymap.bindKeys '~/.atom/packages/dummy/keymaps/a.cson', '.command-mode', 'k': 'c'
|
||||
describe ".keyBindingsForCommandMatchingElement(element)", ->
|
||||
beforeEach ->
|
||||
keymap.add 'nature',
|
||||
'.green':
|
||||
'ctrl-c': 'cultivate'
|
||||
'.green-2':
|
||||
'ctrl-o': 'cultivate'
|
||||
'.brown':
|
||||
'ctrl-h': 'harvest'
|
||||
'.blue':
|
||||
'ctrl-c': 'fly'
|
||||
|
||||
mappings = keymap.getAllKeyMappings()
|
||||
expect(mappings.length).toBe 1
|
||||
expect(mappings[0].source).toEqual 'dummy'
|
||||
expect(mappings[0].keystrokes).toEqual 'k'
|
||||
expect(mappings[0].command).toEqual 'c'
|
||||
expect(mappings[0].selector).toEqual '.command-mode'
|
||||
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"
|
||||
|
||||
describe ".determineSource", ->
|
||||
describe "for a package", ->
|
||||
it "returns '<package-name>'", ->
|
||||
expect(keymap.determineSource('~/.atom/packages/dummy/keymaps/a.cson')).toEqual 'dummy'
|
||||
|
||||
describe "for a linked package", ->
|
||||
it "returns '<package-name>'", ->
|
||||
expect(keymap.determineSource('/Users/john/github/dummy/keymaps/a.cson')).toEqual 'dummy'
|
||||
|
||||
describe "for a user defined keymap", ->
|
||||
it "returns 'User'", ->
|
||||
expect(keymap.determineSource('~/.atom/keymaps/a.cson')).toEqual 'User'
|
||||
|
||||
describe "for a core keymap", ->
|
||||
it "returns 'Core'", ->
|
||||
expect(keymap.determineSource('/Applications/Atom.app/.../node_modules/dummy/keymaps/a.cson')).toEqual 'Core'
|
||||
|
||||
describe "for a linked core keymap", ->
|
||||
it "returns 'Core'", ->
|
||||
expect(keymap.determineSource('/Users/john/github/atom/keymaps/a.cson')).toEqual 'Core'
|
||||
it "no keymap an element without that map", ->
|
||||
el = $$ -> @div class: 'brown'
|
||||
bindings = keymap.keyBindingsForCommandMatchingElement('cultivate', el)
|
||||
expect(bindings).toHaveLength 0
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
describe "LanguageMode", ->
|
||||
[editSession, buffer, languageMode] = []
|
||||
[editor, buffer, languageMode] = []
|
||||
|
||||
afterEach ->
|
||||
editSession.destroy()
|
||||
editor.destroy()
|
||||
|
||||
describe "javascript", ->
|
||||
beforeEach ->
|
||||
atom.activatePackage('javascript-tmbundle', sync: true)
|
||||
editSession = project.open('sample.js', autoIndent: false)
|
||||
{buffer, languageMode} = editSession
|
||||
atom.packages.activatePackage('language-javascript', sync: true)
|
||||
editor = atom.project.openSync('sample.js', autoIndent: false)
|
||||
{buffer, languageMode} = editor
|
||||
|
||||
describe ".minIndentLevelForRowRange(startRow, endRow)", ->
|
||||
it "returns the minimum indent level for the given row range", ->
|
||||
@@ -32,6 +32,18 @@ describe "LanguageMode", ->
|
||||
expect(buffer.lineForRow(6)).toBe " // current < pivot ? left.push(current) : right.push(current);"
|
||||
expect(buffer.lineForRow(7)).toBe " // }"
|
||||
|
||||
buffer.setText('\tvar i;')
|
||||
languageMode.toggleLineCommentsForBufferRows(0, 0)
|
||||
expect(buffer.lineForRow(0)).toBe "\t// var i;"
|
||||
|
||||
buffer.setText('var i;')
|
||||
languageMode.toggleLineCommentsForBufferRows(0, 0)
|
||||
expect(buffer.lineForRow(0)).toBe "// var i;"
|
||||
|
||||
buffer.setText(' var i;')
|
||||
languageMode.toggleLineCommentsForBufferRows(0, 0)
|
||||
expect(buffer.lineForRow(0)).toBe " // var i;"
|
||||
|
||||
describe "fold suggestion", ->
|
||||
describe ".doesBufferRowStartFold(bufferRow)", ->
|
||||
it "returns true only when the buffer row starts a foldable region", ->
|
||||
@@ -97,9 +109,9 @@ describe "LanguageMode", ->
|
||||
|
||||
describe "coffeescript", ->
|
||||
beforeEach ->
|
||||
atom.activatePackage('coffee-script-tmbundle', sync: true)
|
||||
editSession = project.open('coffee.coffee', autoIndent: false)
|
||||
{buffer, languageMode} = editSession
|
||||
atom.packages.activatePackage('language-coffee-script', sync: true)
|
||||
editor = atom.project.openSync('coffee.coffee', autoIndent: false)
|
||||
{buffer, languageMode} = editor
|
||||
|
||||
describe ".toggleLineCommentsForBufferRows(start, end)", ->
|
||||
it "comments/uncomments lines in the given range", ->
|
||||
@@ -144,9 +156,9 @@ describe "LanguageMode", ->
|
||||
|
||||
describe "css", ->
|
||||
beforeEach ->
|
||||
atom.activatePackage('css-tmbundle', sync: true)
|
||||
editSession = project.open('css.css', autoIndent: false)
|
||||
{buffer, languageMode} = editSession
|
||||
atom.packages.activatePackage('language-css', sync: true)
|
||||
editor = atom.project.openSync('css.css', autoIndent: false)
|
||||
{buffer, languageMode} = editor
|
||||
|
||||
describe ".toggleLineCommentsForBufferRows(start, end)", ->
|
||||
it "comments/uncomments lines in the given range", ->
|
||||
@@ -185,10 +197,10 @@ describe "LanguageMode", ->
|
||||
|
||||
describe "less", ->
|
||||
beforeEach ->
|
||||
atom.activatePackage('less-tmbundle', sync: true)
|
||||
atom.activatePackage('css-tmbundle', sync: true)
|
||||
editSession = project.open('sample.less', autoIndent: false)
|
||||
{buffer, languageMode} = editSession
|
||||
atom.packages.activatePackage('language-less', sync: true)
|
||||
atom.packages.activatePackage('language-css', sync: true)
|
||||
editor = atom.project.openSync('sample.less', autoIndent: false)
|
||||
{buffer, languageMode} = editor
|
||||
|
||||
describe "when commenting lines", ->
|
||||
it "only uses the `commentEnd` pattern if it comes from the same grammar as the `commentStart`", ->
|
||||
@@ -197,68 +209,68 @@ describe "LanguageMode", ->
|
||||
|
||||
describe "folding", ->
|
||||
beforeEach ->
|
||||
atom.activatePackage('javascript-tmbundle', sync: true)
|
||||
editSession = project.open('sample.js', autoIndent: false)
|
||||
{buffer, languageMode} = editSession
|
||||
atom.packages.activatePackage('language-javascript', sync: true)
|
||||
editor = atom.project.openSync('sample.js', autoIndent: false)
|
||||
{buffer, languageMode} = editor
|
||||
|
||||
it "maintains cursor buffer position when a folding/unfolding", ->
|
||||
editSession.setCursorBufferPosition([5,5])
|
||||
editor.setCursorBufferPosition([5,5])
|
||||
languageMode.foldAll()
|
||||
expect(editSession.getCursorBufferPosition()).toEqual([5,5])
|
||||
expect(editor.getCursorBufferPosition()).toEqual([5,5])
|
||||
|
||||
describe ".unfoldAll()", ->
|
||||
it "unfolds every folded line", ->
|
||||
initialScreenLineCount = editSession.getScreenLineCount()
|
||||
initialScreenLineCount = editor.getScreenLineCount()
|
||||
languageMode.foldBufferRow(0)
|
||||
languageMode.foldBufferRow(1)
|
||||
expect(editSession.getScreenLineCount()).toBeLessThan initialScreenLineCount
|
||||
expect(editor.getScreenLineCount()).toBeLessThan initialScreenLineCount
|
||||
languageMode.unfoldAll()
|
||||
expect(editSession.getScreenLineCount()).toBe initialScreenLineCount
|
||||
expect(editor.getScreenLineCount()).toBe initialScreenLineCount
|
||||
|
||||
describe ".foldAll()", ->
|
||||
it "folds every foldable line", ->
|
||||
languageMode.foldAll()
|
||||
|
||||
fold1 = editSession.lineForScreenRow(0).fold
|
||||
fold1 = editor.lineForScreenRow(0).fold
|
||||
expect([fold1.getStartRow(), fold1.getEndRow()]).toEqual [0, 12]
|
||||
fold1.destroy()
|
||||
|
||||
fold2 = editSession.lineForScreenRow(1).fold
|
||||
fold2 = editor.lineForScreenRow(1).fold
|
||||
expect([fold2.getStartRow(), fold2.getEndRow()]).toEqual [1, 9]
|
||||
fold2.destroy()
|
||||
|
||||
fold3 = editSession.lineForScreenRow(4).fold
|
||||
fold3 = editor.lineForScreenRow(4).fold
|
||||
expect([fold3.getStartRow(), fold3.getEndRow()]).toEqual [4, 7]
|
||||
|
||||
describe ".foldBufferRow(bufferRow)", ->
|
||||
describe "when bufferRow can be folded", ->
|
||||
it "creates a fold based on the syntactic region starting at the given row", ->
|
||||
languageMode.foldBufferRow(1)
|
||||
fold = editSession.lineForScreenRow(1).fold
|
||||
fold = editor.lineForScreenRow(1).fold
|
||||
expect(fold.getStartRow()).toBe 1
|
||||
expect(fold.getEndRow()).toBe 9
|
||||
|
||||
describe "when bufferRow can't be folded", ->
|
||||
it "searches upward for the first row that begins a syntatic region containing the given buffer row (and folds it)", ->
|
||||
languageMode.foldBufferRow(8)
|
||||
fold = editSession.lineForScreenRow(1).fold
|
||||
fold = editor.lineForScreenRow(1).fold
|
||||
expect(fold.getStartRow()).toBe 1
|
||||
expect(fold.getEndRow()).toBe 9
|
||||
|
||||
describe "when the bufferRow is already folded", ->
|
||||
it "searches upward for the first row that begins a syntatic region containing the folded row (and folds it)", ->
|
||||
languageMode.foldBufferRow(2)
|
||||
expect(editSession.lineForScreenRow(1).fold).toBeDefined()
|
||||
expect(editSession.lineForScreenRow(0).fold).not.toBeDefined()
|
||||
expect(editor.lineForScreenRow(1).fold).toBeDefined()
|
||||
expect(editor.lineForScreenRow(0).fold).not.toBeDefined()
|
||||
|
||||
languageMode.foldBufferRow(1)
|
||||
expect(editSession.lineForScreenRow(0).fold).toBeDefined()
|
||||
expect(editor.lineForScreenRow(0).fold).toBeDefined()
|
||||
|
||||
describe "when the bufferRow is in a multi-line comment", ->
|
||||
it "searches upward and downward for surrounding comment lines and folds them as a single fold", ->
|
||||
buffer.insert([1,0], " //this is a comment\n // and\n //more docs\n\n//second comment")
|
||||
languageMode.foldBufferRow(1)
|
||||
fold = editSession.lineForScreenRow(1).fold
|
||||
fold = editor.lineForScreenRow(1).fold
|
||||
expect(fold.getStartRow()).toBe 1
|
||||
expect(fold.getEndRow()).toBe 3
|
||||
|
||||
@@ -266,7 +278,7 @@ describe "LanguageMode", ->
|
||||
it "searches upward for the first row that begins a syntatic region containing the folded row (and folds it)", ->
|
||||
buffer.insert([1,0], " //this is a single line comment\n")
|
||||
languageMode.foldBufferRow(1)
|
||||
fold = editSession.lineForScreenRow(0).fold
|
||||
fold = editor.lineForScreenRow(0).fold
|
||||
expect(fold.getStartRow()).toBe 0
|
||||
expect(fold.getEndRow()).toBe 13
|
||||
|
||||
@@ -274,77 +286,77 @@ describe "LanguageMode", ->
|
||||
describe "when bufferRow can be unfolded", ->
|
||||
it "destroys a fold based on the syntactic region starting at the given row", ->
|
||||
languageMode.foldBufferRow(1)
|
||||
expect(editSession.lineForScreenRow(1).fold).toBeDefined()
|
||||
expect(editor.lineForScreenRow(1).fold).toBeDefined()
|
||||
|
||||
languageMode.unfoldBufferRow(1)
|
||||
expect(editSession.lineForScreenRow(1).fold).toBeUndefined()
|
||||
expect(editor.lineForScreenRow(1).fold).toBeUndefined()
|
||||
|
||||
describe "when bufferRow can't be unfolded", ->
|
||||
it "does not throw an error", ->
|
||||
expect(editSession.lineForScreenRow(1).fold).toBeUndefined()
|
||||
expect(editor.lineForScreenRow(1).fold).toBeUndefined()
|
||||
languageMode.unfoldBufferRow(1)
|
||||
expect(editSession.lineForScreenRow(1).fold).toBeUndefined()
|
||||
expect(editor.lineForScreenRow(1).fold).toBeUndefined()
|
||||
|
||||
describe "folding with comments", ->
|
||||
beforeEach ->
|
||||
atom.activatePackage('javascript-tmbundle', sync: true)
|
||||
editSession = project.open('sample-with-comments.js', autoIndent: false)
|
||||
{buffer, languageMode} = editSession
|
||||
atom.packages.activatePackage('language-javascript', sync: true)
|
||||
editor = atom.project.openSync('sample-with-comments.js', autoIndent: false)
|
||||
{buffer, languageMode} = editor
|
||||
|
||||
describe ".unfoldAll()", ->
|
||||
it "unfolds every folded line", ->
|
||||
initialScreenLineCount = editSession.getScreenLineCount()
|
||||
initialScreenLineCount = editor.getScreenLineCount()
|
||||
languageMode.foldBufferRow(0)
|
||||
languageMode.foldBufferRow(5)
|
||||
expect(editSession.getScreenLineCount()).toBeLessThan initialScreenLineCount
|
||||
expect(editor.getScreenLineCount()).toBeLessThan initialScreenLineCount
|
||||
languageMode.unfoldAll()
|
||||
expect(editSession.getScreenLineCount()).toBe initialScreenLineCount
|
||||
expect(editor.getScreenLineCount()).toBe initialScreenLineCount
|
||||
|
||||
describe ".foldAll()", ->
|
||||
it "folds every foldable line", ->
|
||||
languageMode.foldAll()
|
||||
|
||||
fold1 = editSession.lineForScreenRow(0).fold
|
||||
fold1 = editor.lineForScreenRow(0).fold
|
||||
expect([fold1.getStartRow(), fold1.getEndRow()]).toEqual [0, 19]
|
||||
fold1.destroy()
|
||||
|
||||
fold2 = editSession.lineForScreenRow(1).fold
|
||||
fold2 = editor.lineForScreenRow(1).fold
|
||||
expect([fold2.getStartRow(), fold2.getEndRow()]).toEqual [1, 4]
|
||||
|
||||
fold3 = editSession.lineForScreenRow(2).fold.destroy()
|
||||
fold3 = editor.lineForScreenRow(2).fold.destroy()
|
||||
|
||||
fold4 = editSession.lineForScreenRow(3).fold
|
||||
fold4 = editor.lineForScreenRow(3).fold
|
||||
expect([fold4.getStartRow(), fold4.getEndRow()]).toEqual [6, 8]
|
||||
|
||||
describe ".foldAllAtIndentLevel()", ->
|
||||
it "folds every foldable range at a given indentLevel", ->
|
||||
languageMode.foldAllAtIndentLevel(2)
|
||||
|
||||
fold1 = editSession.lineForScreenRow(6).fold
|
||||
fold1 = editor.lineForScreenRow(6).fold
|
||||
expect([fold1.getStartRow(), fold1.getEndRow()]).toEqual [6, 8]
|
||||
fold1.destroy()
|
||||
|
||||
fold2 = editSession.lineForScreenRow(11).fold
|
||||
fold2 = editor.lineForScreenRow(11).fold
|
||||
expect([fold2.getStartRow(), fold2.getEndRow()]).toEqual [11, 14]
|
||||
fold2.destroy()
|
||||
|
||||
it "does not fold anything but the indentLevel", ->
|
||||
languageMode.foldAllAtIndentLevel(0)
|
||||
|
||||
fold1 = editSession.lineForScreenRow(0).fold
|
||||
fold1 = editor.lineForScreenRow(0).fold
|
||||
expect([fold1.getStartRow(), fold1.getEndRow()]).toEqual [0, 19]
|
||||
fold1.destroy()
|
||||
|
||||
fold2 = editSession.lineForScreenRow(5).fold
|
||||
fold2 = editor.lineForScreenRow(5).fold
|
||||
expect(fold2).toBeFalsy()
|
||||
|
||||
describe "css", ->
|
||||
beforeEach ->
|
||||
atom.activatePackage('source-tmbundle', sync: true)
|
||||
atom.activatePackage('css-tmbundle', sync: true)
|
||||
editSession = project.open('css.css', autoIndent: true)
|
||||
atom.packages.activatePackage('language-source', sync: true)
|
||||
atom.packages.activatePackage('language-css', sync: true)
|
||||
editor = atom.project.openSync('css.css', autoIndent: true)
|
||||
|
||||
describe "suggestedIndentForBufferRow", ->
|
||||
it "does not return negative values (regression)", ->
|
||||
editSession.setText('.test {\npadding: 0;\n}')
|
||||
expect(editSession.suggestedIndentForBufferRow(2)).toBe 0
|
||||
editor.setText('.test {\npadding: 0;\n}')
|
||||
expect(editor.suggestedIndentForBufferRow(2)).toBe 0
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
{Site} = require 'telepath'
|
||||
{View} = require 'atom'
|
||||
PaneContainer = require '../src/pane-container'
|
||||
Pane = require '../src/pane'
|
||||
Environment = require './environment'
|
||||
|
||||
describe "PaneContainer replication", ->
|
||||
[env1, env2, envConnection, container1, container2, pane1a, pane1b, pane1c] = []
|
||||
|
||||
class TestView extends View
|
||||
@deserialize: ({name}) -> new TestView(name)
|
||||
@content: -> @div tabindex: -1
|
||||
initialize: (@name) -> @text(@name)
|
||||
serialize: -> { deserializer: 'TestView', @name }
|
||||
getState: -> @serialize()
|
||||
getUri: -> "/tmp/#{@name}"
|
||||
isEqual: (other) -> @name is other.name
|
||||
|
||||
beforeEach ->
|
||||
registerDeserializer(TestView)
|
||||
|
||||
env1 = new Environment(siteId: 1)
|
||||
env2 = env1.clone(siteId: 2)
|
||||
envConnection = env1.connect(env2)
|
||||
doc2 = null
|
||||
|
||||
env1.run ->
|
||||
container1 = new PaneContainer
|
||||
pane1a = new Pane(new TestView('A'))
|
||||
container1.setRoot(pane1a)
|
||||
pane1b = pane1a.splitRight(new TestView('B'))
|
||||
pane1c = pane1b.splitDown(new TestView('C'))
|
||||
|
||||
doc1 = container1.getState()
|
||||
doc2 = doc1.clone(env2.site)
|
||||
envConnection.connect(doc1, doc2)
|
||||
|
||||
env2.run ->
|
||||
container2 = deserialize(doc2)
|
||||
|
||||
afterEach ->
|
||||
env1.destroy()
|
||||
env2.destroy()
|
||||
unregisterDeserializer(TestView)
|
||||
|
||||
it "replicates the inital state of a pane container with splits", ->
|
||||
expect(container1.find('.row > :eq(0):contains(A)')).toExist()
|
||||
expect(container1.find('.row > :eq(1)')).toHaveClass 'column'
|
||||
expect(container1.find('.row > :eq(1) > :eq(0):contains(B)')).toExist()
|
||||
expect(container1.find('.row > :eq(1) > :eq(1):contains(C)')).toExist()
|
||||
|
||||
expect(container2.find('.row > :eq(0):contains(A)')).toExist()
|
||||
expect(container2.find('.row > :eq(1)')).toHaveClass 'column'
|
||||
expect(container2.find('.row > :eq(1) > :eq(0):contains(B)')).toExist()
|
||||
expect(container2.find('.row > :eq(1) > :eq(1):contains(C)')).toExist()
|
||||
|
||||
it "replicates the splitting of panes", ->
|
||||
container1.attachToDom().width(400).height(200)
|
||||
container2.attachToDom().width(400).height(200)
|
||||
|
||||
pane1d = pane1a.splitRight(new TestView('D'))
|
||||
|
||||
expect(container1.find('.row > :eq(1):contains(D)')).toExist()
|
||||
expect(container2.find('.row > :eq(1):contains(D)')).toExist()
|
||||
|
||||
expect(container2.find('.row > :eq(1):contains(D)').outerWidth()).toBe container1.find('.row > :eq(1):contains(D)').outerWidth()
|
||||
|
||||
pane1d.splitDown(new TestView('E'))
|
||||
|
||||
expect(container1.find('.row > :eq(1)')).toHaveClass('column')
|
||||
expect(container1.find('.row > :eq(1) > :eq(0):contains(D)')).toExist()
|
||||
expect(container1.find('.row > :eq(1) > :eq(1):contains(E)')).toExist()
|
||||
|
||||
expect(container2.find('.row > :eq(1)')).toHaveClass('column')
|
||||
expect(container2.find('.row > :eq(1) > :eq(0):contains(D)')).toExist()
|
||||
expect(container2.find('.row > :eq(1) > :eq(1):contains(E)')).toExist()
|
||||
|
||||
it "replicates removal of panes", ->
|
||||
pane1c.remove()
|
||||
|
||||
expect(container1.find('.row > :eq(0):contains(A)')).toExist()
|
||||
expect(container1.find('.row > :eq(1):contains(B)')).toExist()
|
||||
expect(container2.find('.row > :eq(0):contains(A)')).toExist()
|
||||
expect(container2.find('.row > :eq(1):contains(B)')).toExist()
|
||||
|
||||
pane1b.remove()
|
||||
|
||||
expect(container1.find('> :eq(0):contains(A)')).toExist()
|
||||
expect(container2.find('> :eq(0):contains(A)')).toExist()
|
||||
|
||||
pane1a.remove()
|
||||
|
||||
expect(container1.children()).not.toExist()
|
||||
expect(container2.children()).not.toExist()
|
||||
|
||||
# FIXME: We need to get this passing again on master
|
||||
xit "replicates splitting of panes containing edit sessions", ->
|
||||
env1.run ->
|
||||
pane1a.showItem(project.open('dir/a'))
|
||||
pane1a.splitDown()
|
||||
|
||||
expect(project.getBuffers().length).toBe 1
|
||||
expect(container1.find('.row > :eq(0) > :eq(0)').view().activeItem.getRelativePath()).toBe 'dir/a'
|
||||
expect(container1.find('.row > :eq(0) > :eq(1)').view().activeItem.getRelativePath()).toBe 'dir/a'
|
||||
|
||||
env2.run ->
|
||||
expect(container2.find('.row > :eq(0) > :eq(0)').view().activeItem.getRelativePath()).toBe 'dir/a'
|
||||
expect(container2.find('.row > :eq(0) > :eq(1)').view().activeItem.getRelativePath()).toBe 'dir/a'
|
||||
@@ -1,3 +1,5 @@
|
||||
path = require 'path'
|
||||
temp = require 'temp'
|
||||
PaneContainer = require '../src/pane-container'
|
||||
Pane = require '../src/pane'
|
||||
{_, $, View, $$} = require 'atom'
|
||||
@@ -7,12 +9,12 @@ describe "PaneContainer", ->
|
||||
|
||||
beforeEach ->
|
||||
class TestView extends View
|
||||
registerDeserializer(this)
|
||||
atom.deserializers.add(this)
|
||||
@deserialize: ({name}) -> new TestView(name)
|
||||
@content: -> @div tabindex: -1
|
||||
initialize: (@name) -> @text(@name)
|
||||
serialize: -> { deserializer: 'TestView', @name }
|
||||
getUri: -> "/tmp/#{@name}"
|
||||
getUri: -> path.join(temp.dir, @name)
|
||||
save: -> @saved = true
|
||||
isEqual: (other) -> @name is other.name
|
||||
|
||||
@@ -23,7 +25,7 @@ describe "PaneContainer", ->
|
||||
pane3 = pane2.splitDown(new TestView('3'))
|
||||
|
||||
afterEach ->
|
||||
unregisterDeserializer(TestView)
|
||||
atom.deserializers.remove(TestView)
|
||||
|
||||
describe ".focusNextPane()", ->
|
||||
it "focuses the pane following the focused pane or the first pane if no pane has focus", ->
|
||||
@@ -78,11 +80,11 @@ describe "PaneContainer", ->
|
||||
expect(panes).toEqual [pane1, pane2, pane3]
|
||||
|
||||
panes = []
|
||||
pane4 = pane3.splitRight()
|
||||
pane4 = pane3.splitRight(pane3.copyActiveItem())
|
||||
expect(panes).toEqual [pane4]
|
||||
|
||||
panes = []
|
||||
subscription.cancel()
|
||||
subscription.off()
|
||||
pane4.splitDown()
|
||||
expect(panes).toEqual []
|
||||
|
||||
@@ -109,11 +111,11 @@ describe "PaneContainer", ->
|
||||
|
||||
describe "when the last-closed pane item is an edit session", ->
|
||||
it "reopens the edit session (regression)", ->
|
||||
editSession = project.open('sample.js')
|
||||
pane3.showItem(editSession)
|
||||
pane3.destroyItem(editSession)
|
||||
editor = atom.project.openSync('sample.js')
|
||||
pane3.showItem(editor)
|
||||
pane3.destroyItem(editor)
|
||||
expect(container.reopenItem()).toBeTruthy()
|
||||
expect(pane3.activeItem.getPath()).toBe editSession.getPath()
|
||||
expect(pane3.activeItem.getPath()).toBe editor.getPath()
|
||||
expect(container.reopenItem()).toBeFalsy()
|
||||
|
||||
describe "when there is no active pane", ->
|
||||
@@ -165,30 +167,30 @@ describe "PaneContainer", ->
|
||||
|
||||
describe ".confirmClose()", ->
|
||||
it "returns true after modified files are saved", ->
|
||||
pane1.itemAtIndex(0).isModified = -> true
|
||||
pane2.itemAtIndex(0).isModified = -> true
|
||||
spyOn(atom, "confirmSync").andReturn(0)
|
||||
pane1.itemAtIndex(0).shouldPromptToSave = -> true
|
||||
pane2.itemAtIndex(0).shouldPromptToSave = -> true
|
||||
spyOn(atom, "confirm").andReturn(0)
|
||||
|
||||
saved = container.confirmClose()
|
||||
|
||||
runs ->
|
||||
expect(saved).toBeTruthy()
|
||||
expect(atom.confirmSync).toHaveBeenCalled()
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
|
||||
it "returns false if the user cancels saving", ->
|
||||
pane1.itemAtIndex(0).isModified = -> true
|
||||
pane2.itemAtIndex(0).isModified = -> true
|
||||
spyOn(atom, "confirmSync").andReturn(1)
|
||||
pane1.itemAtIndex(0).shouldPromptToSave = -> true
|
||||
pane2.itemAtIndex(0).shouldPromptToSave = -> true
|
||||
spyOn(atom, "confirm").andReturn(1)
|
||||
|
||||
saved = container.confirmClose()
|
||||
|
||||
runs ->
|
||||
expect(saved).toBeFalsy()
|
||||
expect(atom.confirmSync).toHaveBeenCalled()
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
|
||||
describe "serialization", ->
|
||||
it "can be serialized and deserialized, and correctly adjusts dimensions of deserialized panes after attach", ->
|
||||
newContainer = deserialize(container.serialize())
|
||||
newContainer = atom.deserializers.deserialize(container.serialize())
|
||||
expect(newContainer.find('.row > :contains(1)')).toExist()
|
||||
expect(newContainer.find('.row > .column > :contains(2)')).toExist()
|
||||
expect(newContainer.find('.row > .column > :contains(3)')).toExist()
|
||||
@@ -200,7 +202,7 @@ describe "PaneContainer", ->
|
||||
xit "removes empty panes on deserialization", ->
|
||||
# only deserialize pane 1's view successfully
|
||||
TestView.deserialize = ({name}) -> new TestView(name) if name is '1'
|
||||
newContainer = deserialize(container.serialize())
|
||||
newContainer = atom.deserializers.deserialize(container.serialize())
|
||||
expect(newContainer.find('.row, .column')).not.toExist()
|
||||
expect(newContainer.find('> :contains(1)')).toExist()
|
||||
|
||||
|
||||
Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais
Referência em uma Nova Issue
Bloquear um usuário