Comparar commits
884 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| e0af2122d2 | |||
| 1bd1121d50 | |||
| 54e2a2af9d | |||
| 90a0b31cf8 | |||
| 1b257df5cf | |||
| b73acc88a7 | |||
| c6bb6b48b6 | |||
| cb95c3050d | |||
| 3434a68ac0 | |||
| 9a941b97cb | |||
| 9074219145 | |||
| e8d9512f02 | |||
| 764e4ac7dd | |||
| 9350b9dc7b | |||
| fb4e16250a | |||
| 32a1d0c134 | |||
| d471d60bfa | |||
| 75d6aab811 | |||
| a80fcff81c | |||
| 42bce0d438 | |||
| 168e1d7c58 | |||
| bdf0f7d10a | |||
| d21060fd87 | |||
| ddc7ebb576 | |||
| 4ad45a1955 | |||
| 6c5b7cbd1e | |||
| b1492037d5 | |||
| 7a5537d01e | |||
| 91fbb10fd3 | |||
| 684687e412 | |||
| 4612d42fb3 | |||
| 026a0672df | |||
| fe4b60d6b0 | |||
| 040d76e3bf | |||
| 1885d50374 | |||
| f9e508e958 | |||
| de695e31d2 | |||
| 4eabb5bec6 | |||
| f3ec868af6 | |||
| 4e96d24d78 | |||
| b5c3c01cc1 | |||
| 13aa29b485 | |||
| be5342fb51 | |||
| 50dc82d074 | |||
| 4358ff9183 | |||
| 336f0382b5 | |||
| 0307c0e6c9 | |||
| fc1e62471f | |||
| 137e9aacab | |||
| 4ddc6c1c1d | |||
| ef12913422 | |||
| 29c36836fe | |||
| 5c2614544d | |||
| 4c1d85e2bf | |||
| 2dd04c449c | |||
| 55f4a7b63e | |||
| a651254e38 | |||
| 1131952a54 | |||
| 189ebc4476 | |||
| 0688ddf083 | |||
| de2e59ddcb | |||
| 41632f2d95 | |||
| d21e8f0aa8 | |||
| 5521d3765a | |||
| d8b4e00fa8 | |||
| e1906ec9ba | |||
| 35fce94025 | |||
| 4708ffa8f6 | |||
| 8a858a1836 | |||
| f8ce0be095 | |||
| cb17078c48 | |||
| 28ed117db8 | |||
| 67d505fc7e | |||
| dba2ab55e0 | |||
| 119bf1a879 | |||
| 30dd202f33 | |||
| 4a4285b18f | |||
| 37b5a00df3 | |||
| 45fff99967 | |||
| c319329b23 | |||
| e280aa7f40 | |||
| f06a976052 | |||
| 77b8b51c16 | |||
| 3b86bb528c | |||
| d55acdd67b | |||
| de8d0197ff | |||
| 1fb9697229 | |||
| 5f8fe698ba | |||
| ed41ba49f9 | |||
| b500b23a69 | |||
| 27099392f4 | |||
| 19e63996ac | |||
| 87a4f3fc20 | |||
| 1dfed85f37 | |||
| cac2599b55 | |||
| d765e7f115 | |||
| 552af032f4 | |||
| 9bd82b201c | |||
| 662e8b8a11 | |||
| eda4e53b2c | |||
| b8cbc3b5af | |||
| f6309ec489 | |||
| be30cce41a | |||
| a6efeb7a19 | |||
| bc3791f738 | |||
| a8cc73c5e6 | |||
| 2a8dce75cd | |||
| e7200fb938 | |||
| 8c60207fde | |||
| 1ca86d36fd | |||
| 6f971901d7 | |||
| 6f353b6c54 | |||
| a7ebdbb361 | |||
| d84a0337b4 | |||
| 0d1f980940 | |||
| cf382ea2f8 | |||
| a674950ce1 | |||
| 2b7bd8a9d7 | |||
| d98fef52f2 | |||
| c2d1a10684 | |||
| 2580c3e29f | |||
| d2a340c8d0 | |||
| 8ec01b1583 | |||
| 1e3dc14729 | |||
| 253593431d | |||
| 730fbec9ce | |||
| ec70b71511 | |||
| 0b33709c69 | |||
| 7db3f7fefb | |||
| 9bb81b3db9 | |||
| dc1ee10aa4 | |||
| 18214be4f7 | |||
| 1dd4e5bb87 | |||
| 5c17e20a23 | |||
| b040aed702 | |||
| b68b075b1e | |||
| df5f2c4f81 | |||
| 281eb99d88 | |||
| b03694efff | |||
| 2d9a805d8f | |||
| ee110dfd91 | |||
| 6a0fee406e | |||
| b8d2473c6a | |||
| ec4469aebb | |||
| 209adda958 | |||
| 1f74ae1206 | |||
| 04b0d6d930 | |||
| 5b6fcca58a | |||
| cfb785705b | |||
| 80460850d4 | |||
| 116b920703 | |||
| 89b683d9d3 | |||
| 5ac8611a2c | |||
| 52051837c9 | |||
| 1ed3767f0c | |||
| 7f0e6fd86c | |||
| 03610f01d4 | |||
| 5f548627b3 | |||
| 80497be71b | |||
| 952b5e84f7 | |||
| 25eb38ff60 | |||
| b4517c5393 | |||
| 67a1112ced | |||
| 6f38a40b94 | |||
| 5a20066d2e | |||
| 37be8fab30 | |||
| 91fffc08b9 | |||
| 458dea9780 | |||
| ea43384244 | |||
| 65a8c8d946 | |||
| 0e93a11850 | |||
| ce34f758bd | |||
| 0eaf3b6336 | |||
| 4700eeb7e2 | |||
| d7d2a6f1f0 | |||
| 878831bfc7 | |||
| 324ae3fe3a | |||
| bc22130938 | |||
| 461b95b1ac | |||
| d14396e2d3 | |||
| 1e0fd948a5 | |||
| 9d9e33f245 | |||
| f612a85599 | |||
| 136e7d3491 | |||
| 00b913d363 | |||
| 3fd11b7aaf | |||
| c1cf4efb31 | |||
| 4c65d711b0 | |||
| 090f737647 | |||
| 224294d00f | |||
| 8c145168ef | |||
| 4660ed5745 | |||
| c515cf880c | |||
| eb58ce7736 | |||
| 08ede33b66 | |||
| ff519d52b2 | |||
| 6c5a5c49da | |||
| b5a799c997 | |||
| ca7d2695ea | |||
| 81c2374c87 | |||
| e5200d5414 | |||
| f4fdbbc307 | |||
| c6a7e84640 | |||
| fac70d080d | |||
| 5e2a641861 | |||
| 9cf79730ea | |||
| 737d41ad16 | |||
| a49ae766ae | |||
| 239e6ce156 | |||
| fb42086a6f | |||
| 3f53b8d2cb | |||
| 53fb36d0e2 | |||
| 545b375bb5 | |||
| 383d8f6940 | |||
| 280fc9af85 | |||
| 029e4336bc | |||
| aebca38ae6 | |||
| 01f6ca3cae | |||
| 2275a6d2d1 | |||
| 893493960f | |||
| 26121489be | |||
| f0dc88e33c | |||
| 99f6b89b6e | |||
| ff42526199 | |||
| dea7fafee7 | |||
| 357f158f8a | |||
| c18fa805f9 | |||
| 5fd0850f5b | |||
| 66225736fe | |||
| a87036b538 | |||
| 62b8ef7bb3 | |||
| 546351dd46 | |||
| 69f0572f2a | |||
| a6ffaff2a2 | |||
| 4e62540a9b | |||
| bb03d6b83d | |||
| 8aaa34b8fa | |||
| a8f4019693 | |||
| 03a60561b7 | |||
| 761e96429d | |||
| 3e685d91a5 | |||
| 668d3d3672 | |||
| ad1fe5f5f0 | |||
| 23308625f6 | |||
| abc6386ad6 | |||
| 91a1ce84d0 | |||
| 5695a209da | |||
| 97782de8d3 | |||
| a056f44a66 | |||
| a8f57ed276 | |||
| dbd20bcd31 | |||
| e6d63656b7 | |||
| 49fdd24af3 | |||
| db6018d847 | |||
| d87393f21e | |||
| 857c467497 | |||
| 33a207d57c | |||
| 02e3754dd9 | |||
| 70ab01d376 | |||
| 6a34d58ff4 | |||
| 2c5ae6e553 | |||
| 1988ed9e92 | |||
| 7a04a414f7 | |||
| c16435a604 | |||
| a9b2661d3c | |||
| 43220fb189 | |||
| 43f272d1e7 | |||
| 8900d9efdd | |||
| 4cc18cd936 | |||
| ae060fb450 | |||
| affaf9007a | |||
| 54e35a5014 | |||
| 9fa72c0841 | |||
| cfaa5ac3cb | |||
| 76903a0b91 | |||
| d316b14c4d | |||
| 523f965791 | |||
| 9f2d6fd8b5 | |||
| b176a246b3 | |||
| fac844c255 | |||
| 59bd424e89 | |||
| 12bc2a0a39 | |||
| dca5fadeec | |||
| 0872db3780 | |||
| 6134d95bfd | |||
| 1bf98f5b8d | |||
| f468420a29 | |||
| 459c11b602 | |||
| 6f8cb24e5a | |||
| b8d8ae68a3 | |||
| 63eb032472 | |||
| 69396922db | |||
| 99774d7417 | |||
| e67fb86084 | |||
| 98a25ca5e3 | |||
| 245ad7a356 | |||
| b042dffc2c | |||
| ef263580df | |||
| c0010789bc | |||
| 77453ff989 | |||
| da945de5f5 | |||
| 7a7521d810 | |||
| 31811ea4ae | |||
| 512a14d2ed | |||
| cdeb5d1a3d | |||
| 72b120cfe1 | |||
| 14424abe08 | |||
| 254730dc9f | |||
| ba3ae00b76 | |||
| ea2793a746 | |||
| e5fe583a3c | |||
| fe19798af9 | |||
| ce6751859c | |||
| b7aa88f9a1 | |||
| 0c01df5d29 | |||
| 24403ef0b0 | |||
| 56cb847633 | |||
| a7a0ecd019 | |||
| 0dce31e02d | |||
| ad36db61c6 | |||
| 69fe67d6e1 | |||
| 57ed5d7d57 | |||
| 320acab126 | |||
| a91285c754 | |||
| 313fb79fdc | |||
| 3571d1e60e | |||
| 3d89f76abf | |||
| 9e19f62b47 | |||
| e439847b59 | |||
| ce6d5b3b2a | |||
| b4e8d5480c | |||
| 04290ebbbb | |||
| 366684f3d7 | |||
| 5f9549e279 | |||
| a149056408 | |||
| fb60a3189a | |||
| 94f26b99cc | |||
| 3f8d9a4c47 | |||
| 50a27e99bb | |||
| eb885357e6 | |||
| 9b3463ef64 | |||
| 39762081b1 | |||
| 0dd96a0732 | |||
| 70d8777db6 | |||
| bb0a31228d | |||
| cec35ed7c8 | |||
| 95e68c8c2b | |||
| 3f5cd19ddc | |||
| d0dd0a9882 | |||
| 2d52f3deac | |||
| fa376d9543 | |||
| 31480f92ce | |||
| 7d725d5597 | |||
| dbfcd0c4d1 | |||
| 55eff7cd69 | |||
| 97951e38ad | |||
| 68f190ab9a | |||
| a7edf10f1f | |||
| bd050a817d | |||
| 0c267f35ef | |||
| 4437255f65 | |||
| 85af8a2225 | |||
| db64dd5426 | |||
| 34732d059e | |||
| 8888de0256 | |||
| 87b7d9d5e3 | |||
| 67de3ceb5e | |||
| 60b4554cb3 | |||
| f7ae280760 | |||
| 42320c5227 | |||
| 7f090fdac8 | |||
| 4c69abc7db | |||
| 3406b5ee1f | |||
| 2af12a7b7a | |||
| b3c3b55131 | |||
| 74aceb02fc | |||
| 4a36d2ee89 | |||
| de24128009 | |||
| 415c871b83 | |||
| 7f826dd005 | |||
| 408901360f | |||
| ec6accbc8b | |||
| 523460166f | |||
| df996695c8 | |||
| 86a9279743 | |||
| 53b423496f | |||
| ead21bfc33 | |||
| ee14214c7a | |||
| 8f26feadb5 | |||
| 760d8c60ad | |||
| bec5c9c9c9 | |||
| 02a8a41427 | |||
| d5f7e2a6e2 | |||
| 3e6e530b44 | |||
| c277a19781 | |||
| 3191697a38 | |||
| 0cead13df7 | |||
| 59872889db | |||
| da14629826 | |||
| 3bf551cefd | |||
| 85543888b4 | |||
| 37cd047c46 | |||
| e2dc48456d | |||
| bf2a3d3ca4 | |||
| 63f7f01169 | |||
| 6d68c4eeea | |||
| d91dd2f6ea | |||
| c91443825b | |||
| c31e981479 | |||
| 2cefd4f4d6 | |||
| 2a9b1260c2 | |||
| e53feba1fd | |||
| 24752ff006 | |||
| 29ef6366ca | |||
| 06e782e920 | |||
| 6e29f08469 | |||
| 52c1747aaf | |||
| b2973556d6 | |||
| d0c2dfffb1 | |||
| f3af21c5d2 | |||
| e5b4302407 | |||
| fc6aa2aa12 | |||
| 883f6dd50b | |||
| 8ac197074d | |||
| d045bc9836 | |||
| d31c0f81d2 | |||
| 5bad4c95c1 | |||
| dc11573862 | |||
| 4d42cb908d | |||
| db2bb9274d | |||
| 0e3b6628f3 | |||
| 65dafd58c1 | |||
| 0c0b082604 | |||
| 906fcf0929 | |||
| 36458331f8 | |||
| 4b1e44a967 | |||
| c7855dbcd3 | |||
| 950a0ce153 | |||
| d64fefd96c | |||
| 7f903bc6e7 | |||
| d4dfdd17ff | |||
| 2e8bf53a04 | |||
| d9262a8415 | |||
| 504ec58d93 | |||
| 3de158bbdd | |||
| 6cd3ef4a6c | |||
| d5c8b052c6 | |||
| ffdbefc0f4 | |||
| fccddd9200 | |||
| bdb37c4dee | |||
| 4b28cc78b1 | |||
| 28032cb257 | |||
| 75c3197a62 | |||
| e0459fa069 | |||
| 8f9d845683 | |||
| 7caece7c77 | |||
| e279c75653 | |||
| f678d836fa | |||
| 131a457da8 | |||
| df4e791f47 | |||
| 752d028581 | |||
| 543a2ad266 | |||
| c2fe0b7aa1 | |||
| 9e0436d10e | |||
| b3550c6526 | |||
| 75745bccc7 | |||
| 93bd0c8412 | |||
| f473bfdb95 | |||
| 9300ee0f47 | |||
| c7bd1f0a87 | |||
| 763c5053ad | |||
| 3053760880 | |||
| a428b03db5 | |||
| 0153bb538b | |||
| 1f47e7ae64 | |||
| a78dff15c4 | |||
| def39f94df | |||
| 382afba835 | |||
| 0358e9ad54 | |||
| 8f4bf6d897 | |||
| 6428d1cb60 | |||
| 6b4e68f127 | |||
| 9e9cdaecc0 | |||
| 410f573095 | |||
| 41761ffbcf | |||
| ee09eee374 | |||
| a57c58d5d9 | |||
| 1d3163cda1 | |||
| e3505fd45b | |||
| 5461de5856 | |||
| 88b214067f | |||
| 5304afd69a | |||
| a99c404a78 | |||
| 6b971e36b0 | |||
| e550d8a3bc | |||
| f3ff802aa4 | |||
| 52241a45df | |||
| 86b19c1ffc | |||
| 680e1cc80a | |||
| 017cc23bbf | |||
| d49bb2416b | |||
| 1d2c3bce20 | |||
| 48f69880e0 | |||
| ed7de42ba0 | |||
| 95c4e2170b | |||
| 4e2218b005 | |||
| 8b83918a24 | |||
| a1ce1c9ef6 | |||
| 0419ae8712 | |||
| d8737ba4a1 | |||
| 9bd1835ea1 | |||
| 823a79610f | |||
| 3929189e7a | |||
| fb73240654 | |||
| cc890ebdc0 | |||
| 7708d645c9 | |||
| 29cbea4d50 | |||
| 8b1b3d237d | |||
| 7d7f208fc5 | |||
| 1302a38ddf | |||
| f9d70e5623 | |||
| 0e60d73b10 | |||
| 136928f36e | |||
| d6fc3e6d01 | |||
| 04d8584742 | |||
| de88d6b624 | |||
| 32a15796c1 | |||
| 905e456a15 | |||
| 04c59952d5 | |||
| a93bfb5f8c | |||
| 2579f2993b | |||
| f9cdc4883e | |||
| d8da977b20 | |||
| 4d230a0517 | |||
| 258218b166 | |||
| 211d222291 | |||
| dda412d5ec | |||
| d7fabc5a58 | |||
| 16ab2031fa | |||
| 0ea03bc389 | |||
| 1bc38c191f | |||
| c6baed045d | |||
| 71ae6b28dd | |||
| 57e7335907 | |||
| 15442c3dba | |||
| d5c4b74608 | |||
| a2fcc7aa7a | |||
| de0aba6165 | |||
| 4b529ae167 | |||
| 848d77d3eb | |||
| 069ead6b1c | |||
| aef3332a09 | |||
| 4bfc0e8ea1 | |||
| c19c4a5e27 | |||
| 750e3565fd | |||
| 0eb874864c | |||
| 4c60c40eb8 | |||
| 830a8ddc03 | |||
| d9b14dc492 | |||
| 4743cf89dc | |||
| b6710b54cf | |||
| d9e4b9d199 | |||
| 6a408a3a55 | |||
| 4b2e8f8713 | |||
| c882d73527 | |||
| fd005380b0 | |||
| 6776fa4f0d | |||
| 8be5f7d6c8 | |||
| 1c51f512ea | |||
| 0d724bb00d | |||
| 8b94fef806 | |||
| 919fafc7a4 | |||
| 89b240cd4f | |||
| 91bd852812 | |||
| 99c2c32e1e | |||
| ecf4dbefe3 | |||
| cf73dd467a | |||
| 05769f8a49 | |||
| 51fbb1be07 | |||
| af1f57048b | |||
| 0e62841320 | |||
| d9ddf516f8 | |||
| 1436b8eb5e | |||
| 1645efa2ce | |||
| d0fe2c9a5b | |||
| 84ee94dfd1 | |||
| f585f53144 | |||
| 9b3cdd00c8 | |||
| b650043191 | |||
| 6f422ce56b | |||
| abe630937e | |||
| 7cccd5f920 | |||
| e4f6eb17a0 | |||
| 3951c45519 | |||
| 2a2858554a | |||
| 5b6e0b769d | |||
| c189dc22d7 | |||
| d2abbb3681 | |||
| 8df791c949 | |||
| 1d4cab404d | |||
| 1f3ea76379 | |||
| e01be5d41a | |||
| 13e435a4f9 | |||
| 3592ec19df | |||
| b49bd6fd10 | |||
| 2d16d3a459 | |||
| 72f2824588 | |||
| a229c28e62 | |||
| b6576545ba | |||
| e8c0793874 | |||
| 508636c06e | |||
| ca49ac1730 | |||
| 44c4bc8434 | |||
| a2fb288745 | |||
| c00c5c97f1 | |||
| 2248bbf8fb | |||
| 256a9bf08a | |||
| 4d3b4529f1 | |||
| 723ebff69a | |||
| ffb7093cf3 | |||
| d415ec9a00 | |||
| 2e8962501d | |||
| 8425c15cd7 | |||
| f9f2688468 | |||
| ad0bb5098f | |||
| 81e86c1467 | |||
| 0724dd7a7c | |||
| 92b76e61c4 | |||
| 8eee4d87be | |||
| e6d7413af1 | |||
| 6685464229 | |||
| 20772d045c | |||
| 33b7c915eb | |||
| 31a154d7eb | |||
| f0197632a3 | |||
| ae7306572b | |||
| 1a81248c88 | |||
| 8d40e4df10 | |||
| 431688e44c | |||
| f10a70eaf4 | |||
| 282fb66e75 | |||
| a131a03f28 | |||
| 713d7332b3 | |||
| 00f30eaf6c | |||
| f01a2a91f9 | |||
| e51c94b940 | |||
| fe5640df4b | |||
| 42a777e822 | |||
| 73cc1dadae | |||
| 4b9aa18628 | |||
| 163150dc87 | |||
| f3be876065 | |||
| e499e32c24 | |||
| 3534ac0f32 | |||
| ac6675380c | |||
| c1e8505ebf | |||
| e567702e3f | |||
| 5d2c6ea4b4 | |||
| df1a792675 | |||
| 9c1fa74d2f | |||
| 009cbfd418 | |||
| 81fd2bbf2e | |||
| d5222f22ea | |||
| 69545cba61 | |||
| 625a61a18f | |||
| 2d93402858 | |||
| efbf961c4b | |||
| d64ff4d598 | |||
| c81fcac108 | |||
| 01f3f88c6c | |||
| fa45af588e | |||
| 802ec9d8c2 | |||
| cce64cb9e8 | |||
| b38702d754 | |||
| 6a9268cb38 | |||
| 246bbc7862 | |||
| 7428431609 | |||
| f9308fd9fc | |||
| 504a55304e | |||
| 651177bc0c | |||
| d9a47f256c | |||
| 9a51c24937 | |||
| 28f0bf645f | |||
| 0f68f095f1 | |||
| 7686b348b1 | |||
| fc67aa016a | |||
| 422c0e36cb | |||
| 0bbc631607 | |||
| fbdf16a8fa | |||
| 23af7b4072 | |||
| 4219d06bd9 | |||
| e6e43f6884 | |||
| e52a4c1588 | |||
| efac59be9b | |||
| c2199e9c21 | |||
| 8a9d4d8eea | |||
| 837d91c220 | |||
| a49340dd6c | |||
| dfdab3d006 | |||
| 25a9ca4224 | |||
| f4873646c9 | |||
| da9a7a18dd | |||
| f213389db8 | |||
| bca9f81be1 | |||
| e5c31495cb | |||
| 1e69ede779 | |||
| f24389a45b | |||
| 695fd441fb | |||
| 8cd164ef5e | |||
| dbbfb9ae7d | |||
| 18348b8738 | |||
| c4cb6abef1 | |||
| c9ee68651d | |||
| 709c70c4c4 | |||
| fd7c2e92c5 | |||
| bbce381e16 | |||
| a46fcc1985 | |||
| de914193ff | |||
| b80c43db7b | |||
| 83cc6a76de | |||
| d21b5ae75b | |||
| 406743f0fb | |||
| acc5c18ba3 | |||
| f0ca685a16 | |||
| b001e7e28f | |||
| 1ab12b436a | |||
| 9f67978513 | |||
| ff1440be26 | |||
| 7a9a1ca213 | |||
| 35beaf44a9 | |||
| 63c24cd6e9 | |||
| 6d6f41b212 | |||
| af52ad9124 | |||
| 8cf498e7e3 | |||
| 2bbae7090e | |||
| cb6ba3c418 | |||
| ec4cf8b497 | |||
| 967db1f7b8 | |||
| 5b453290ad | |||
| 972fa41528 | |||
| 5ca0864753 | |||
| ee3d928b5b | |||
| b1b541f903 | |||
| a9e4bd4aaf | |||
| 2f908c171d | |||
| 227454e27e | |||
| 1d9fed2464 | |||
| 4298733db6 | |||
| cee0b951fb | |||
| 932a792289 | |||
| 64a57635e9 | |||
| eefa85e8ec | |||
| 5a400f1bb2 | |||
| 65ec0a2f0a | |||
| ed8b8f005f | |||
| 7166937b13 | |||
| 5481e5d664 | |||
| 2ccab9d182 | |||
| a646ab5bb8 | |||
| f10e55b4d5 | |||
| e769a8e4d5 | |||
| 3ac03c9ae0 | |||
| 8b2533e721 | |||
| bc29ddb9b6 | |||
| 1b455a990e | |||
| 69fa5cb3f7 | |||
| eb05e804b1 | |||
| ab456131cc | |||
| a7267d93ad | |||
| 3047152fb0 | |||
| 220fe36167 | |||
| e52fd3925c | |||
| 8713153f01 | |||
| 4237916759 | |||
| bcf1456df7 | |||
| 147db97d4d | |||
| b462a1ffa9 | |||
| e2e838c4ec | |||
| 6b88ce8d19 | |||
| 4141e1060a | |||
| e66e75593d | |||
| c765d069d1 | |||
| faf1a1565e | |||
| 71cae3c937 | |||
| d5b809a194 | |||
| 36427dae9f | |||
| 2fb0f796c4 | |||
| f473d46cf1 | |||
| 061599554e | |||
| a03aad6f5e | |||
| 0a62277cfa | |||
| 9d045d1d43 | |||
| 6e4c4f43b3 | |||
| 099f632a6c | |||
| 0dc0883531 | |||
| 6d6f4671d8 | |||
| ef942ef1c8 | |||
| 2a75836ca2 | |||
| b845086e63 | |||
| ba45dbaa6a | |||
| 3c90007199 | |||
| 1023c421c7 | |||
| ece269f158 | |||
| 43ba0b9529 | |||
| b28f3f29ec | |||
| 92aeb9f3cb | |||
| 89cade2d22 | |||
| 53529dab1f | |||
| 35dd435397 | |||
| 93aec682de | |||
| c64b84750a | |||
| 01876c4004 | |||
| 9680ad7bb5 | |||
| bc5a79564a | |||
| 88a65358b4 | |||
| dcbd2a2102 | |||
| 11e727e3fa | |||
| ce63aee338 | |||
| d3e11a6183 | |||
| 88798fca7e | |||
| 3c9204e464 | |||
| 48417338b0 | |||
| faf523f698 | |||
| 8a85f488f3 | |||
| f75b4aa117 | |||
| e4a65ca810 | |||
| a36cc3a609 | |||
| cb8075206b | |||
| a04f77b400 | |||
| 0e0ae17cd3 | |||
| 02f0c49d0e | |||
| ca6521b711 | |||
| f0c200f233 | |||
| 84e69db268 | |||
| fbdb5b59ea | |||
| 66530eb69a | |||
| 70a7514f9e | |||
| 55ca32f7b3 | |||
| 569ab416b8 | |||
| b1e99d9927 | |||
| caeb70cf4a | |||
| cc233fb7f6 | |||
| c730910f7c | |||
| fc2be08b60 | |||
| e6565f6561 | |||
| 638aaa2e62 | |||
| e23fb98a41 | |||
| 8d0ddc0513 | |||
| c225d180ba | |||
| 217fd8e271 | |||
| b82c808bad | |||
| 25f97b5ef3 | |||
| 86f1a484a8 | |||
| 49313b65b9 | |||
| c0d564b635 | |||
| b9c14379be | |||
| adb3b390bb | |||
| a192b70406 | |||
| 28e6be8baf | |||
| f5fa89418c | |||
| 3d27cd662a | |||
| 0c8744f7a7 | |||
| 272ce92201 | |||
| c30f74ef9e | |||
| 5912ac1d1b | |||
| a1171f39df | |||
| 69c9172e49 | |||
| c1f3aa14cd | |||
| 5017f1473c | |||
| 12ec3f69d6 | |||
| f4e43b96c2 | |||
| f958322cef | |||
| 7061ea5d23 | |||
| c3f995b165 | |||
| 99f25267a0 | |||
| 9176e12f58 | |||
| 97330d19f3 | |||
| e3f0e11aa8 | |||
| 32cd0ee972 | |||
| fc5bc1632d | |||
| 8772e45a39 | |||
| 8c75f425e7 | |||
| f322143272 | |||
| dd5c65b5f9 |
+32
-2
@@ -15,7 +15,7 @@ to propose changes to this document in a pull request.
|
||||
|
||||
This is the repository for the core Atom editor only. Atom comes bundled with
|
||||
many packages and themes that are stored in other repos under the
|
||||
[atom org](https://github.com/atom) such as [tabs](https://github.com/atom/tabs),
|
||||
[atom organization](https://github.com/atom) such as [tabs](https://github.com/atom/tabs),
|
||||
[find-and-replace](https://github.com/atom/find-and-replace),
|
||||
[language-javascript](https://github.com/atom/language-javascript),
|
||||
and [atom-light-ui](http://github.com/atom/atom-light-ui).
|
||||
@@ -30,7 +30,7 @@ in the proper package's repository.
|
||||
* Follow the [CoffeeScript](#coffeescript-styleguide),
|
||||
[JavaScript](https://github.com/styleguide/javascript),
|
||||
and [CSS](https://github.com/styleguide/css) styleguides
|
||||
* Include thoughtfully worded [Jasmine](http://pivotal.github.com/jasmine/)
|
||||
* Include thoughtfully worded [Jasmine](http://pivotal.github.com/jasmine)
|
||||
specs
|
||||
* Avoid placing files in `vendor`. 3rd-party packages should be added as a
|
||||
`package.json` dependency.
|
||||
@@ -61,3 +61,33 @@ in the proper package's repository.
|
||||
|
||||
* Set parameter defaults without spaces around the equal sign
|
||||
* `clear = (count=1) ->` instead of `clear = (count = 1) ->`
|
||||
|
||||
## Documentation Styleguide
|
||||
|
||||
* Use [TomDoc](http://tomdoc.org).
|
||||
* Use [Markdown](https://daringfireball.net/projects/markdown).
|
||||
* Reference classes with `{ClassName}`.
|
||||
* Reference instance methods with `{ClassName::methodName}`.
|
||||
* Reference class methods with `{ClassName.methodName}`.
|
||||
* Delegate to comments elsewhere with `{Delegates to: ClassName.methodName}`
|
||||
style notation.
|
||||
|
||||
### Example
|
||||
|
||||
```coffee
|
||||
# Public: Disable the package with the given name.
|
||||
#
|
||||
# This method emits multiple events:
|
||||
#
|
||||
# * `package-will-be-disabled` - before the package is disabled.
|
||||
# * `package-disabled` - after the package is disabled.
|
||||
#
|
||||
# name - The {String} name of the package to disable.
|
||||
# options - The {Object} with disable options (default: {}):
|
||||
# :trackTime - `true` to track the amount of time disabling took.
|
||||
# :ignoreErrors - `true` to catch and ignore errors thrown.
|
||||
# callback - The {Function} to call after the package has been disabled.
|
||||
#
|
||||
# Returns `undefined`.
|
||||
disablePackage: (name, options, callback) ->
|
||||
```
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Copyright 2014 GitHub, Inc.
|
||||
@@ -1,13 +0,0 @@
|
||||
Copyright 2013 GitHub Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||

|
||||
|
||||
Check out our [guides and API documentation](https://www.atom.io/docs/latest/).
|
||||
Check out our [guides and API documentation](https://atom.io/docs/latest).
|
||||
|
||||
## Installing
|
||||
|
||||
|
||||
@@ -11,10 +11,6 @@ _ = require 'underscore-plus'
|
||||
|
||||
packageJson = require '../package.json'
|
||||
|
||||
# OAuth token for atom-bot
|
||||
# TODO Remove once all repositories are public
|
||||
process.env.ATOM_ACCESS_TOKEN ?= '362295be4c5258d3f7b967bbabae662a455ca2a7'
|
||||
|
||||
# Shim harmony collections in case grunt was invoked without harmony
|
||||
# collections enabled
|
||||
_.extend(global, require('harmony-collections')) unless global.WeakMap?
|
||||
@@ -227,6 +223,6 @@ module.exports = (grunt) ->
|
||||
grunt.registerTask('compile', ['coffee', 'prebuild-less', 'cson', 'peg'])
|
||||
grunt.registerTask('lint', ['coffeelint', 'csslint', 'lesslint'])
|
||||
grunt.registerTask('test', ['shell:kill-atom', 'run-specs'])
|
||||
grunt.registerTask('ci', ['output-disk-space', 'download-atom-shell', 'build', 'set-version', 'lint', 'test', 'codesign', 'publish-build'])
|
||||
grunt.registerTask('ci', ['output-disk-space', 'download-atom-shell', 'build', 'set-version', 'check-licenses', 'lint', 'test', 'codesign', 'publish-build'])
|
||||
grunt.registerTask('docs', ['markdown:guides', 'build-docs'])
|
||||
grunt.registerTask('default', ['download-atom-shell', 'build', 'set-version', 'install'])
|
||||
|
||||
@@ -7,10 +7,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"async": "~0.2.9",
|
||||
"biscotto": "git://github.com/atom/biscotto.git#12188bfbe5f7303fa9f1aa3c4f8662d40ce3c3be",
|
||||
"first-mate": "1.x",
|
||||
"biscotto": ">=2.1.1 <3.0",
|
||||
"formidable": "~1.0.14",
|
||||
"fs-plus": "1.x",
|
||||
"fs-plus": "2.x",
|
||||
"github-releases": "~0.2.0",
|
||||
"grunt": "~0.4.1",
|
||||
"grunt-cli": "~0.1.9",
|
||||
@@ -19,21 +18,20 @@
|
||||
"grunt-contrib-coffee": "~0.9.0",
|
||||
"grunt-contrib-less": "~0.8.0",
|
||||
"grunt-cson": "0.6.0",
|
||||
"grunt-download-atom-shell": "git+https://atom-bot:362295be4c5258d3f7b967bbabae662a455ca2a7@github.com/atom/grunt-download-atom-shell#v0.6.0",
|
||||
"grunt-download-atom-shell": "git+https://atom-bot:467bac80a0017b96fb5be5cfc686f5e0cc607b10@github.com/atom/grunt-download-atom-shell#v0.6.0",
|
||||
"grunt-lesslint": "0.13.0",
|
||||
"grunt-markdown": "~0.4.0",
|
||||
"grunt-peg": "~1.1.0",
|
||||
"grunt-shell": "~0.3.1",
|
||||
"harmony-collections": "~0.3.8",
|
||||
"js-yaml": "~2.1.0",
|
||||
"json-front-matter": "~0.1.3",
|
||||
"legal-eagle": "~0.3.0",
|
||||
"rcedit": "~0.1.2",
|
||||
"request": "~2.27.0",
|
||||
"rimraf": "~2.2.2",
|
||||
"runas": "~0.3.0",
|
||||
"runas": "0.5.x",
|
||||
"underscore-plus": "1.x",
|
||||
"unzip": "~0.1.9",
|
||||
"vm-compatibility-layer": "~0.1.0",
|
||||
"walkdir": "0.0.7"
|
||||
"vm-compatibility-layer": "~0.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ module.exports = (grunt) ->
|
||||
|
||||
cp 'atom.sh', path.join(appDir, 'atom.sh')
|
||||
cp 'package.json', path.join(appDir, 'package.json')
|
||||
cp 'apm', path.join(appDir, 'apm')
|
||||
|
||||
packageDirectories = []
|
||||
nonPackageDirectories = [
|
||||
@@ -47,8 +46,12 @@ module.exports = (grunt) ->
|
||||
path.join('less', 'dist')
|
||||
path.join('less', 'test')
|
||||
path.join('bootstrap', 'docs')
|
||||
path.join('bootstrap', 'examples')
|
||||
path.join('spellchecker', 'vendor')
|
||||
path.join('xmldom', 'test')
|
||||
path.join('jasmine-reporters', 'ext')
|
||||
path.join('build', 'Release', 'obj.target')
|
||||
path.join('build', 'Release', '.deps')
|
||||
path.join('vendor', 'apm')
|
||||
path.join('resources', 'mac')
|
||||
path.join('resources', 'win')
|
||||
@@ -64,13 +67,14 @@ module.exports = (grunt) ->
|
||||
cp 'spec', path.join(appDir, 'spec')
|
||||
cp 'src', path.join(appDir, 'src'), filter: /.+\.(cson|coffee)$/
|
||||
cp 'static', path.join(appDir, 'static')
|
||||
cp 'apm', path.join(appDir, 'apm'), filter: nodeModulesFilter
|
||||
|
||||
if process.platform is 'darwin'
|
||||
grunt.file.recurse path.join('resources', 'mac'), (sourcePath, rootDirectory, subDirectory='', filename) ->
|
||||
unless /.+\.plist/.test(sourcePath)
|
||||
grunt.file.copy(sourcePath, path.resolve(appDir, '..', subDirectory, filename))
|
||||
|
||||
dependencies = ['compile']
|
||||
dependencies = ['compile', "generate-license:save"]
|
||||
dependencies.push('copy-info-plist') if process.platform is 'darwin'
|
||||
dependencies.push('set-exe-icon') if process.platform is 'win32'
|
||||
grunt.task.run(dependencies...)
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
module.exports = (grunt) ->
|
||||
grunt.registerTask 'check-licenses', 'Report the licenses of all dependencies', ->
|
||||
legalEagle = require 'legal-eagle'
|
||||
{size, keys} = require 'underscore-plus'
|
||||
done = @async()
|
||||
|
||||
options =
|
||||
path: process.cwd()
|
||||
omitPermissive: true
|
||||
overrides: require './license-overrides'
|
||||
|
||||
legalEagle options, (err, summary) ->
|
||||
if err?
|
||||
console.error(err)
|
||||
exit 1
|
||||
|
||||
if size(summary)
|
||||
console.error "Found dependencies without permissive licenses:"
|
||||
for name in keys(summary).sort()
|
||||
console.error "#{name}"
|
||||
console.error " License: #{summary[name].license}"
|
||||
console.error " Repository: #{summary[name].repository}"
|
||||
process.exit 1
|
||||
done()
|
||||
@@ -1,102 +0,0 @@
|
||||
path = require 'path'
|
||||
|
||||
_ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
{ScopeSelector} = require 'first-mate'
|
||||
|
||||
module.exports = (grunt) ->
|
||||
grunt.registerTask 'convert-theme', 'Convert a TextMate theme to an Atom theme', ->
|
||||
if textMateThemePath = grunt.option('path')
|
||||
textMateThemePath = path.resolve(textMateThemePath)
|
||||
if grunt.file.isFile(textMateThemePath)
|
||||
textMateTheme = new TextMateTheme(textMateThemePath)
|
||||
themeName = path.basename(textMateThemePath, path.extname(textMateThemePath))
|
||||
atomThemePath = path.join(path.dirname(textMateThemePath), "#{themeName.toLowerCase()}-syntax.css")
|
||||
grunt.file.write(atomThemePath, textMateTheme.getStylesheet())
|
||||
grunt.log.ok("Atom theme written to: #{atomThemePath}")
|
||||
else
|
||||
grunt.log.error("No theme file found at: #{textMateThemePath}")
|
||||
false
|
||||
else
|
||||
grunt.log.error('Must specify --path=<path to TextMate theme>')
|
||||
false
|
||||
|
||||
class TextMateTheme
|
||||
constructor: (@path) ->
|
||||
@rulesets = []
|
||||
@buildRulesets()
|
||||
|
||||
buildRulesets: ->
|
||||
{settings} = fs.readPlistSync(@path)
|
||||
@buildGlobalSettingsRulesets(settings[0])
|
||||
@buildScopeSelectorRulesets(settings[1..])
|
||||
|
||||
getStylesheet: ->
|
||||
lines = []
|
||||
for {selector, properties} in @getRulesets()
|
||||
lines.push("#{selector} {")
|
||||
lines.push " #{name}: #{value};" for name, value of properties
|
||||
lines.push("}\n")
|
||||
lines.join('\n')
|
||||
|
||||
getRulesets: -> @rulesets
|
||||
|
||||
buildGlobalSettingsRulesets: ({settings}) ->
|
||||
{ background, foreground, caret, selection, lineHighlight } = settings
|
||||
|
||||
@rulesets.push
|
||||
selector: '.editor, .editor .gutter'
|
||||
properties:
|
||||
'background-color': @translateColor(background)
|
||||
'color': @translateColor(foreground)
|
||||
|
||||
@rulesets.push
|
||||
selector: '.editor.is-focused .cursor'
|
||||
properties:
|
||||
'border-color': @translateColor(caret)
|
||||
|
||||
@rulesets.push
|
||||
selector: '.editor.is-focused .selection .region'
|
||||
properties:
|
||||
'background-color': @translateColor(selection)
|
||||
|
||||
@rulesets.push
|
||||
selector: '.editor.is-focused .line-number.cursor-line-no-selection, .editor.is-focused .line.cursor-line'
|
||||
properties:
|
||||
'background-color': @translateColor(lineHighlight)
|
||||
|
||||
buildScopeSelectorRulesets: (scopeSelectorSettings) ->
|
||||
for { name, scope, settings } in scopeSelectorSettings
|
||||
continue unless scope
|
||||
@rulesets.push
|
||||
comment: name
|
||||
selector: @translateScopeSelector(scope)
|
||||
properties: @translateScopeSelectorSettings(settings)
|
||||
|
||||
translateScopeSelector: (textmateScopeSelector) ->
|
||||
new ScopeSelector(textmateScopeSelector).toCssSelector()
|
||||
|
||||
translateScopeSelectorSettings: ({ foreground, background, fontStyle }) ->
|
||||
properties = {}
|
||||
|
||||
if fontStyle
|
||||
fontStyles = fontStyle.split(/\s+/)
|
||||
properties['font-weight'] = 'bold' if _.contains(fontStyles, 'bold')
|
||||
properties['font-style'] = 'italic' if _.contains(fontStyles, 'italic')
|
||||
properties['text-decoration'] = 'underline' if _.contains(fontStyles, 'underline')
|
||||
|
||||
properties['color'] = @translateColor(foreground) if foreground
|
||||
properties['background-color'] = @translateColor(background) if background
|
||||
properties
|
||||
|
||||
translateColor: (textmateColor) ->
|
||||
if textmateColor.length <= 7
|
||||
textmateColor
|
||||
else
|
||||
r = parseInt(textmateColor[1..2], 16)
|
||||
g = parseInt(textmateColor[3..4], 16)
|
||||
b = parseInt(textmateColor[5..6], 16)
|
||||
a = parseInt(textmateColor[7..8], 16)
|
||||
a = Math.round((a / 255.0) * 100) / 100
|
||||
|
||||
"rgba(#{r}, #{g}, #{b}, #{a})"
|
||||
@@ -15,24 +15,7 @@ module.exports = (grunt) ->
|
||||
grunt.registerTask 'build-docs', 'Builds the API docs in src', ->
|
||||
done = @async()
|
||||
|
||||
downloadFileFromRepo = ({repo, file}, callback) ->
|
||||
uri = "https://raw2.github.com/atom/#{repo}/master/#{file}"
|
||||
request uri, (error, response, contents) ->
|
||||
return callback(error) if error?
|
||||
downloadPath = path.join('docs', 'includes', repo, file)
|
||||
fs.writeFile downloadPath, contents, (error) ->
|
||||
callback(error, downloadPath)
|
||||
|
||||
includes = [
|
||||
{repo: 'first-mate', file: 'src/grammar-registry.coffee'}
|
||||
{repo: 'space-pen', file: 'src/space-pen.coffee'}
|
||||
{repo: 'text-buffer', file: 'src/marker.coffee'}
|
||||
{repo: 'text-buffer', file: 'src/point.coffee'}
|
||||
{repo: 'text-buffer', file: 'src/range.coffee'}
|
||||
{repo: 'theorist', file: 'src/model.coffee'}
|
||||
]
|
||||
|
||||
async.map includes, downloadFileFromRepo, (error, includePaths) ->
|
||||
downloadIncludes (error, includePaths) ->
|
||||
if error?
|
||||
done(error)
|
||||
else
|
||||
@@ -42,6 +25,7 @@ module.exports = (grunt) ->
|
||||
'--title', 'Atom API Documentation'
|
||||
'-o', 'docs/output/api'
|
||||
'-r', 'docs/README.md'
|
||||
'--stability', '1'
|
||||
'src/'
|
||||
includePaths...
|
||||
]
|
||||
@@ -49,13 +33,32 @@ module.exports = (grunt) ->
|
||||
|
||||
grunt.registerTask 'lint-docs', 'Generate stats about the doc coverage', ->
|
||||
done = @async()
|
||||
args = [commonArgs..., '--noOutput', 'src/']
|
||||
grunt.util.spawn({cmd, args, opts}, done)
|
||||
downloadIncludes (error, includePaths) ->
|
||||
if error?
|
||||
done(error)
|
||||
else
|
||||
args = [
|
||||
commonArgs...
|
||||
'--noOutput'
|
||||
'src/'
|
||||
includePaths...
|
||||
]
|
||||
grunt.util.spawn({cmd, args, opts}, done)
|
||||
|
||||
grunt.registerTask 'missing-docs', 'Generate stats about the doc coverage', ->
|
||||
done = @async()
|
||||
args = [commonArgs..., '--noOutput', '--missing', 'src/']
|
||||
grunt.util.spawn({cmd, args, opts}, done)
|
||||
downloadIncludes (error, includePaths) ->
|
||||
if error?
|
||||
done(error)
|
||||
else
|
||||
args = [
|
||||
commonArgs...
|
||||
'--noOutput'
|
||||
'--missing'
|
||||
'src/'
|
||||
includePaths...
|
||||
]
|
||||
grunt.util.spawn({cmd, args, opts}, done)
|
||||
|
||||
grunt.registerTask 'copy-docs', 'Copies over latest API docs to atom-docs', ->
|
||||
done = @async()
|
||||
@@ -129,3 +132,27 @@ module.exports = (grunt) ->
|
||||
grunt.util.spawn({cmd, args, opts}, callback)
|
||||
|
||||
grunt.util.async.waterfall [fetchTag, stageDocs, fetchSha, commitChanges, pushOrigin, pushHeroku], done
|
||||
|
||||
downloadFileFromRepo = ({repo, file}, callback) ->
|
||||
uri = "https://raw.github.com/atom/#{repo}/master/#{file}"
|
||||
request uri, (error, response, contents) ->
|
||||
return callback(error) if error?
|
||||
downloadPath = path.join('docs', 'includes', repo, file)
|
||||
fs.writeFile downloadPath, contents, (error) ->
|
||||
callback(error, downloadPath)
|
||||
|
||||
downloadIncludes = (callback) ->
|
||||
includes = [
|
||||
{repo: 'first-mate', file: 'src/grammar.coffee'}
|
||||
{repo: 'first-mate', file: 'src/grammar-registry.coffee'}
|
||||
{repo: 'node-pathwatcher', file: 'src/directory.coffee'}
|
||||
{repo: 'node-pathwatcher', file: 'src/file.coffee'}
|
||||
{repo: 'space-pen', file: 'src/space-pen.coffee'}
|
||||
{repo: 'text-buffer', file: 'src/marker.coffee'}
|
||||
{repo: 'text-buffer', file: 'src/point.coffee'}
|
||||
{repo: 'text-buffer', file: 'src/range.coffee'}
|
||||
{repo: 'text-buffer', file: 'src/text-buffer.coffee'}
|
||||
{repo: 'theorist', file: 'src/model.coffee'}
|
||||
]
|
||||
|
||||
async.map(includes, downloadFileFromRepo, callback)
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
|
||||
module.exports = (grunt) ->
|
||||
grunt.registerTask 'generate-license', 'Generate the license, including the licenses of all dependencies', (mode) ->
|
||||
legalEagle = require 'legal-eagle'
|
||||
done = @async()
|
||||
|
||||
options =
|
||||
path: process.cwd()
|
||||
overrides: require './license-overrides'
|
||||
|
||||
legalEagle options, (err, dependencyLicenses) ->
|
||||
if err?
|
||||
console.error(err)
|
||||
exit 1
|
||||
|
||||
licenseText = getLicenseText(dependencyLicenses)
|
||||
if mode is 'save'
|
||||
targetPath = path.join(grunt.config.get('atom.appDir'), 'LICENSE')
|
||||
fs.writeFileSync(targetPath, licenseText)
|
||||
else
|
||||
console.log licenseText
|
||||
done()
|
||||
|
||||
getLicenseText = (dependencyLicenses) ->
|
||||
{keys} = require 'underscore-plus'
|
||||
text = """
|
||||
Copyright 2014 GitHub, Inc.
|
||||
|
||||
This application bundles the following third-party packages in accordance
|
||||
with the following licenses:\n\n
|
||||
"""
|
||||
names = keys(dependencyLicenses).sort()
|
||||
for name in names
|
||||
{license, source, sourceText} = dependencyLicenses[name]
|
||||
|
||||
text += "-------------------------------------------------------------------------\n\n"
|
||||
text += "Package: #{name}\n"
|
||||
text += "License: #{license}\n"
|
||||
text += "License Source: #{source}\n" if source?
|
||||
if sourceText?
|
||||
text += "Source Text:\n\n"
|
||||
text += sourceText
|
||||
text += '\n'
|
||||
text
|
||||
@@ -1,24 +1,20 @@
|
||||
path = require 'path'
|
||||
runas = null
|
||||
|
||||
module.exports = (grunt) ->
|
||||
{cp, mkdir, rm, spawn} = require('./task-helpers')(grunt)
|
||||
{cp, mkdir, rm} = require('./task-helpers')(grunt)
|
||||
|
||||
grunt.registerTask 'install', 'Install the built application', ->
|
||||
installDir = grunt.config.get('atom.installDir')
|
||||
shellAppDir = grunt.config.get('atom.shellAppDir')
|
||||
if process.platform is 'win32'
|
||||
done = @async()
|
||||
|
||||
runas = require 'runas'
|
||||
runas ?= require 'runas'
|
||||
copyFolder = path.resolve 'script', 'copy-folder.cmd'
|
||||
# cmd /c ""script" "source" "destination""
|
||||
arg = "/c \"\"#{copyFolder}\" \"#{shellAppDir}\" \"#{installDir}\"\""
|
||||
if runas('cmd', [arg], hide: true) isnt 0
|
||||
done("Failed to copy #{shellAppDir} to #{installDir}")
|
||||
if runas('cmd', ['/c', copyFolder, shellAppDir, installDir], admin: true) isnt 0
|
||||
grunt.log.error("Failed to copy #{shellAppDir} to #{installDir}")
|
||||
|
||||
createShortcut = path.resolve 'script', 'create-shortcut.cmd'
|
||||
args = ['/c', createShortcut, path.join(installDir, 'atom.exe'), 'Atom']
|
||||
spawn {cmd: 'cmd', args}, done
|
||||
runas('cmd', ['/c', createShortcut, path.join(installDir, 'atom.exe'), 'Atom'])
|
||||
else
|
||||
rm installDir
|
||||
mkdir path.dirname(installDir)
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
module.exports =
|
||||
'aws-sign@0.3.0':
|
||||
repository: 'https://github.com/mikeal/aws-sign'
|
||||
license: 'MIT'
|
||||
source: 'index.js'
|
||||
sourceText: """
|
||||
/*!
|
||||
* knox - auth
|
||||
* Copyright(c) 2010 LearnBoost <dev@learnboost.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
<content omitted>
|
||||
"""
|
||||
'bufferjs@2.0.0':
|
||||
repository: 'https://github.com/coolaj86/node-bufferjs'
|
||||
license: 'MIT'
|
||||
source: 'LICENSE.MIT'
|
||||
sourceText: """
|
||||
Copyright (c) 2010 AJ ONeal (and Contributors)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
"""
|
||||
'buffers@0.1.1':
|
||||
repository: "http://github.com/substack/node-buffers"
|
||||
license: 'MIT'
|
||||
source: 'README.markdown'
|
||||
sourceText: """
|
||||
<content omitted>
|
||||
license
|
||||
=======
|
||||
|
||||
MIT/X11
|
||||
"""
|
||||
'specificity@0.1.3':
|
||||
repository: 'https://github.com/keeganstreet/specificity'
|
||||
license: 'MIT'
|
||||
source: 'package.json in repository'
|
||||
|
||||
'promzard@0.2.0':
|
||||
license: 'ISC'
|
||||
source: 'LICENSE in the repository'
|
||||
sourceText: """
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
"""
|
||||
@@ -8,7 +8,7 @@ request = require 'request'
|
||||
module.exports = (grunt) ->
|
||||
{spawn} = require('./task-helpers')(grunt)
|
||||
|
||||
baseUrl = "https://www.atom.io/api/packages"
|
||||
baseUrl = "https://atom.io/api/packages"
|
||||
|
||||
packageExists = (packageName, token, callback) ->
|
||||
requestSettings =
|
||||
|
||||
@@ -1,27 +1,41 @@
|
||||
fs = require 'fs'
|
||||
fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
walkdir = require 'walkdir'
|
||||
|
||||
module.exports = (grunt) ->
|
||||
cp: (source, destination, {filter}={}) ->
|
||||
unless grunt.file.exists(source)
|
||||
grunt.fatal("Cannot copy non-existent #{source.cyan} to #{destination.cyan}")
|
||||
|
||||
try
|
||||
walkdir.sync source, (sourcePath, stats) ->
|
||||
return if filter?.test(sourcePath)
|
||||
copyFile = (sourcePath, destinationPath) ->
|
||||
return if filter?.test(sourcePath)
|
||||
|
||||
destinationPath = path.join(destination, path.relative(source, sourcePath))
|
||||
if stats.isSymbolicLink()
|
||||
grunt.file.mkdir(path.dirname(destinationPath))
|
||||
fs.symlinkSync(fs.readlinkSync(sourcePath), destinationPath)
|
||||
else if stats.isFile()
|
||||
grunt.file.copy(sourcePath, destinationPath)
|
||||
stats = fs.lstatSync(sourcePath)
|
||||
if stats.isSymbolicLink()
|
||||
grunt.file.mkdir(path.dirname(destinationPath))
|
||||
fs.symlinkSync(fs.readlinkSync(sourcePath), destinationPath)
|
||||
else if stats.isFile()
|
||||
grunt.file.copy(sourcePath, destinationPath)
|
||||
|
||||
if grunt.file.exists(destinationPath)
|
||||
fs.chmodSync(destinationPath, fs.statSync(sourcePath).mode)
|
||||
catch error
|
||||
grunt.fatal(error)
|
||||
if grunt.file.exists(destinationPath)
|
||||
fs.chmodSync(destinationPath, fs.statSync(sourcePath).mode)
|
||||
|
||||
if grunt.file.isFile(source)
|
||||
copyFile(source, destination)
|
||||
else
|
||||
try
|
||||
onFile = (sourcePath) ->
|
||||
destinationPath = path.join(destination, path.relative(source, sourcePath))
|
||||
copyFile(sourcePath, destinationPath)
|
||||
onDirectory = (sourcePath) ->
|
||||
if fs.isSymbolicLinkSync(sourcePath)
|
||||
destinationPath = path.join(destination, path.relative(source, sourcePath))
|
||||
copyFile(sourcePath, destinationPath)
|
||||
false
|
||||
else
|
||||
true
|
||||
fs.traverseTreeSync source, onFile, onDirectory
|
||||
catch error
|
||||
grunt.fatal(error)
|
||||
|
||||
grunt.verbose.writeln("Copied #{source.cyan} to #{destination.cyan}.")
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
path = require 'path'
|
||||
|
||||
module.exports = (grunt) ->
|
||||
grunt.registerTask 'update-octicons', 'Update octicon font and LESS variables', ->
|
||||
pathToOcticons = path.resolve('..', 'octicons')
|
||||
if grunt.file.isDir(pathToOcticons)
|
||||
# Copy font-file
|
||||
fontSrc = path.join(pathToOcticons, 'octicons', 'octicons.woff')
|
||||
fontDest = path.resolve('static', 'octicons.woff')
|
||||
grunt.file.copy(fontSrc, fontDest)
|
||||
|
||||
# Update Octicon UTF codes
|
||||
glyphsSrc = path.join(pathToOcticons, 'data', 'glyphs.yml')
|
||||
output = []
|
||||
for {css, code} in grunt.file.readYAML(glyphsSrc)
|
||||
output.push "@#{css}: \"\\#{code}\";"
|
||||
|
||||
octiconUtfDest = path.resolve('static', 'variables', 'octicon-utf-codes.less')
|
||||
grunt.file.write(octiconUtfDest, "#{output.join('\n')}\n")
|
||||
else
|
||||
grunt.log.error("octicons repo must be cloned to #{pathToOcticons}")
|
||||
false
|
||||
+1
-5
@@ -23,9 +23,7 @@ You can also require many of these classes in your package via:
|
||||
The classes available from `require 'atom'` are:
|
||||
* [BufferedProcess][BufferedProcess]
|
||||
* [BufferedNodeProcess][BufferedNodeProcess]
|
||||
* [Directory][Directory]
|
||||
* [EditorView][EditorView]
|
||||
* [File][File]
|
||||
* [Git][Git]
|
||||
* [Point][Point]
|
||||
* [Range][Range]
|
||||
@@ -47,10 +45,8 @@ Atom ships with node 0.11.10 and the comprehensive node API docs are available
|
||||
[Atom]: ../classes/Atom.html
|
||||
[BufferedProcess]: ../classes/BufferedProcess.html
|
||||
[BufferedNodeProcess]: ../classes/BufferedNodeProcess.html
|
||||
[Directory]: ../classes/Directory.html
|
||||
[Editor]: ../classes/Editor.html
|
||||
[EditorView]: ../classes/EditorView.html
|
||||
[File]: ../classes/File.html
|
||||
[Git]: ../classes/Git.html
|
||||
[Point]: ../classes/Point.html
|
||||
[Range]: ../classes/Range.html
|
||||
@@ -58,5 +54,5 @@ Atom ships with node 0.11.10 and the comprehensive node API docs are available
|
||||
[SelectListView]: ../classes/SelectListView.html
|
||||
[View]: ../classes/View.html
|
||||
[WorkspaceView]: ../classes/WorkspaceView.html
|
||||
[creating-a-package]: https://www.atom.io/docs/latest/creating-a-package
|
||||
[creating-a-package]: https://atom.io/docs/latest/creating-a-package
|
||||
[node-docs]: http://nodejs.org/docs/v0.11.10/api
|
||||
|
||||
@@ -71,27 +71,3 @@ will only attempt to call deserialize if the two versions match, and otherwise
|
||||
return undefined. We plan on implementing a migration system in the future, but
|
||||
this at least protects you from improperly deserializing old state. If you find
|
||||
yourself in dire need of the migration system, let us know.
|
||||
|
||||
### Deferred Package Deserializers
|
||||
|
||||
If your package defers loading on startup with an `activationEvents` property in
|
||||
its `package.cson`, your deserializers won't be loaded until your package is
|
||||
activated. If you want to deserialize an object from your package on startup,
|
||||
this could be a problem.
|
||||
|
||||
The solution is to also supply a `deferredDeserializers` array in your
|
||||
`package.cson` with the names of all your deserializers. When Atom attempts to
|
||||
deserialize some state whose `deserializer` matches one of these names, it will
|
||||
load your package first so it can register any necessary deserializers before
|
||||
proceeding.
|
||||
|
||||
For example, the markdown preview package doesn't fully load until a preview is
|
||||
triggered. But if you refresh a window with a preview pane, it loads the
|
||||
markdown package early so Atom can deserialize the view correctly.
|
||||
|
||||
```coffee-script
|
||||
# markdown-preview/package.cson
|
||||
'activationEvents': 'markdown-preview:toggle': '.editor'
|
||||
'deferredDeserializers': ['MarkdownPreviewView']
|
||||
...
|
||||
```
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
# Contributing to Atom Packages
|
||||
|
||||
The following is a set of guidelines for contributing to Atom packages, which
|
||||
are hosted in the [Atom Organization](https://github.com/atom) on GitHub. If
|
||||
you're unsure which package is causing your problem or if you're having an issue
|
||||
with Atom core, please use the feedback form in the application or email
|
||||
[atom@github.com](mailto:atom@github.com).
|
||||
|
||||
## Submitting Issues
|
||||
|
||||
* Include screenshots and animated GIFs whenever possible; they are immensely
|
||||
helpful.
|
||||
* Include the behavior you expected and other places you've seen that behavior
|
||||
such as Emacs, vi, Xcode, etc.
|
||||
* Check the dev tools (`alt-cmd-i`) for errors and stack traces to include.
|
||||
* Check Console.app for stack traces to include if reporting a crash.
|
||||
* Perform a cursory search to see if a similar issue has already been submitted.
|
||||
|
||||
## Hacking on Packages
|
||||
|
||||
### Cloning
|
||||
|
||||
The first step is creating your own clone. You can of course do this manually
|
||||
with git, or you can use the `apm develop` command to create a clone based on
|
||||
the package's `repository` field in the `package.json`.
|
||||
|
||||
For example, if you want to make changes to the `tree-view` package, run the
|
||||
following command:
|
||||
|
||||
```
|
||||
> apm develop tree-view
|
||||
Cloning https://github.com/atom/tree-view ✓
|
||||
Installing modules ✓
|
||||
~/.atom/dev/packages/tree-view -> ~/github/tree-view
|
||||
```
|
||||
|
||||
This clones the `tree-view` repository to `~/github`. If you prefer a different
|
||||
path, specify it via the `ATOM_REPOS_HOME` environment variable.
|
||||
|
||||
### Running in Development Mode
|
||||
|
||||
Editing a package in Atom is a bit of a circular experience: you're using Atom
|
||||
to modify itself. What happens if you temporarily break something? You don't
|
||||
want the version of Atom you're using to edit to become useless in the process.
|
||||
For this reason, you'll only want to load packages in **development mode** while
|
||||
you are working on them. You'll perform your editing in **stable mode**, only
|
||||
switching to development mode to test your changes.
|
||||
|
||||
To open a development mode window, use the "Application: Open Dev" command,
|
||||
which is normally bound to `cmd-shift-o`. You can also run dev mode from the
|
||||
command line with `atom --dev`.
|
||||
|
||||
To load your package in development mode, create a symlink to it in
|
||||
`~/.atom/dev/packages`. This occurs automatically when you clone the package
|
||||
with `apm develop`. You can also run `apm link --dev` and `apm unlink --dev`
|
||||
from the package directory to create and remove dev-mode symlinks.
|
||||
|
||||
### Installing Dependencies
|
||||
|
||||
Finally, you need to install the cloned package's dependencies by running
|
||||
`apm install` within the package directory. This step is also performed
|
||||
automatically the first time you run `apm develop`, but you'll want to keep
|
||||
dependencies up to date by running `apm update` after pulling upstream changes.
|
||||
|
||||
## Submitting Pull Requests
|
||||
|
||||
### Code Guidelines
|
||||
|
||||
* Include screenshots and animated GIFs in your pull request whenever possible.
|
||||
* Follow the [CoffeeScript](#coffeescript-styleguide),
|
||||
[JavaScript](https://github.com/styleguide/javascript),
|
||||
and [CSS](https://github.com/styleguide/css) styleguides.
|
||||
* Include thoughtfully-worded, well-structured
|
||||
[Jasmine](http://pivotal.github.com/jasmine) specs.
|
||||
* Document new code based on the
|
||||
[Documentation Styleguide](#documentation-styleguide)
|
||||
* End files with a newline.
|
||||
* Place requires in the following order:
|
||||
* Built in Node Modules (such as `path`)
|
||||
* Built in Atom and Atom Shell Modules (such as `atom`, `shell`)
|
||||
* Local Modules (using relative paths)
|
||||
* Place class properties in the following order:
|
||||
* Class methods and properties (methods starting with a `@`)
|
||||
* Instance methods and properties
|
||||
* Avoid platform-dependent code:
|
||||
* Use `require('atom').fs.getHomeDirectory()` to get the home directory.
|
||||
* Use `path.join()` to concatenate filenames.
|
||||
* Use `os.tmpdir()` rather than `/tmp` when you need to reference the
|
||||
temporary directory.
|
||||
|
||||
### Commit Message Guidelines
|
||||
* Use the present tense ("Add feature" not "Added feature")
|
||||
* Use the imperative mood ("Move cursor to..." not "Moves cursor to...")
|
||||
* Limit the first line to 72 characters or less
|
||||
* Reference issues and pull requests liberally
|
||||
* Consider starting the commit message with an applicable emoji:
|
||||
* :lipstick: when improving the format/structure of the code
|
||||
* :racehorse: when improving performance
|
||||
* :non-potable_water: when plugging memory leaks
|
||||
* :memo: when writing docs
|
||||
* :bulb: Check out the [Emoji Cheat Sheet](http://www.emoji-cheat-sheet.com)
|
||||
for more ideas.
|
||||
|
||||
## CoffeeScript Styleguide
|
||||
|
||||
* Use parentheses if it improves code clarity.
|
||||
* Prefer alphabetic keywords to symbolic keywords:
|
||||
* `a is b` instead of `a == b`
|
||||
* Avoid spaces inside the curly-braces of hash literals:
|
||||
* `{a: 1, b: 2}` instead of `{ a: 1, b: 2 }`
|
||||
* Set parameter defaults without spaces around the equal sign:
|
||||
* `clear = (count=1) ->` instead of `clear = (count = 1) ->`
|
||||
* Include a single line of whitespace between methods.
|
||||
|
||||
## Documentation Styleguide
|
||||
|
||||
* Use [TomDoc](http://tomdoc.org).
|
||||
* Use [Markdown](https://daringfireball.net/projects/markdown).
|
||||
* Reference methods and classes in markdown with the custom `{}` notation:
|
||||
* Reference classes with `{ClassName}`
|
||||
* Reference instance methods with `{ClassName::methodName}`
|
||||
* Reference class methods with `{ClassName.methodName}`
|
||||
|
||||
### Example
|
||||
|
||||
```coffee
|
||||
# Public: Disable the package with the given name.
|
||||
#
|
||||
# This method emits multiple events:
|
||||
#
|
||||
# * `package-will-be-disabled` - before the package is disabled.
|
||||
# * `package-disabled` - after the package is disabled.
|
||||
#
|
||||
# name - The {String} name of the package to disable.
|
||||
# options - The {Object} with disable options (default: {}):
|
||||
# :trackTime - `true` to track the amount of time disabling took.
|
||||
# :ignoreErrors - `true` to catch and ignore errors thrown.
|
||||
# callback - The {Function} to call after the package has been disabled.
|
||||
#
|
||||
# Returns `undefined`.
|
||||
disablePackage: (name, options, callback) ->
|
||||
```
|
||||
@@ -0,0 +1,52 @@
|
||||
## Converting a TextMate Bundle
|
||||
|
||||
This guide will show you how to convert a [TextMate][TextMate] bundle to an
|
||||
Atom package.
|
||||
|
||||
Converting a TextMate bundle will allow you to use its editor preferences,
|
||||
snippets, and colorization inside Atom.
|
||||
|
||||
### Install apm
|
||||
|
||||
The `apm` command line utility that ships with Atom supports converting
|
||||
a TextMate bundle to an Atom package.
|
||||
|
||||
Check that you have `apm` installed by running the following command in your
|
||||
terminal:
|
||||
|
||||
```sh
|
||||
apm help init
|
||||
```
|
||||
|
||||
You should see a message print out with details about the `apm init` command.
|
||||
|
||||
If you do not, launch Atom and run the _Atom > Install Shell Commmands_ menu
|
||||
to install the `apm` and `atom` commands.
|
||||
|
||||
### Convert the Package
|
||||
|
||||
Let's convert the TextMate bundle for the [R][R] programming language. You can find other existing TextMate bundles [here][TextMateOrg].
|
||||
|
||||
You can convert the R bundle with the following command:
|
||||
|
||||
```sh
|
||||
apm init --package ~/.atom/packages/language-r --convert https://github.com/textmate/r.tmbundle
|
||||
```
|
||||
|
||||
You can now browse to `~/.atom/packages/language-r` to see the converted bundle.
|
||||
|
||||
:tada: Your new package is now ready to use, launch Atom and open a `.r` file in
|
||||
the editor to see it in action!
|
||||
|
||||
### Further Reading
|
||||
|
||||
* Check out [Publishing a Package](publish-a-package.html) for more information
|
||||
on publishing the package you just created to [atom.io][atomio].
|
||||
|
||||
[atomio]: https://atom.io
|
||||
[CSS]: http://en.wikipedia.org/wiki/Cascading_Style_Sheets
|
||||
[LESS]: http://lesscss.org
|
||||
[plist]: http://en.wikipedia.org/wiki/Property_list
|
||||
[R]: http://en.wikipedia.org/wiki/R_(programming_language)
|
||||
[TextMate]: http://macromates.com
|
||||
[TextMateOrg]: https://github.com/textmate/r.tmbundle
|
||||
@@ -0,0 +1,68 @@
|
||||
## Converting a TextMate Theme
|
||||
|
||||
This guide will show you how to convert a [TextMate][TextMate] theme to an Atom
|
||||
theme.
|
||||
|
||||
### Differences
|
||||
|
||||
TextMate themes use [plist][plist] files while Atom themes use [CSS][CSS] or
|
||||
[LESS][LESS] to style the UI and syntax in the editor.
|
||||
|
||||
The utility that converts the theme first parses the theme's plist file and
|
||||
then creates comparable CSS rules and properties that will style Atom similarly.
|
||||
|
||||
### Install apm
|
||||
|
||||
The `apm` command line utility that ships with Atom supports converting
|
||||
a TextMate theme to an Atom theme.
|
||||
|
||||
Check that you have `apm` installed by running the following command in your
|
||||
terminal:
|
||||
|
||||
```sh
|
||||
apm help init
|
||||
```
|
||||
|
||||
You should see a message print out with details about the `apm init` command.
|
||||
|
||||
If you do not, launch Atom and run the _Atom > Install Shell Commmands_ menu
|
||||
to install the `apm` and `atom` commands.
|
||||
|
||||
You can now run `apm help init` to see all the options for initializing new
|
||||
packages and themes.
|
||||
|
||||
### Convert the Theme
|
||||
|
||||
Download the theme you wish to convert, you can browse existing TextMate themes
|
||||
[here][TextMateThemes].
|
||||
|
||||
Now, let's say you've downloaded the theme to `~/Downloads/MyTheme.tmTheme`,
|
||||
you can convert the theme with the following command:
|
||||
|
||||
```sh
|
||||
apm init --theme ~/.atom/packages/my-theme --convert ~/Downloads/MyTheme.tmTheme
|
||||
```
|
||||
|
||||
You can browse to `~/.atom/packages/my-theme` to see the converted theme.
|
||||
|
||||
### Activate the Theme
|
||||
|
||||
Now that your theme is installed to `~/.atom/packages` you can enable it
|
||||
by launching Atom and selecting the _Atom > Preferences..._ menu.
|
||||
|
||||
Select the _Themes_ link on the left side and choose _My Theme_ from the
|
||||
__Syntax Theme__ dropdown menu to enable your new theme.
|
||||
|
||||
:tada: Your theme is now enabled, open an editor to see it in action!
|
||||
|
||||
### Further Reading
|
||||
|
||||
* Check out [Publishing a Package](publish-a-package.html) for more information
|
||||
on publishing the theme you just created to [atom.io][atomio].
|
||||
|
||||
[atomio]: https://atom.io
|
||||
[CSS]: http://en.wikipedia.org/wiki/Cascading_Style_Sheets
|
||||
[LESS]: http://lesscss.org
|
||||
[plist]: http://en.wikipedia.org/wiki/Property_list
|
||||
[TextMate]: http://macromates.com
|
||||
[TextMateThemes]: http://wiki.macromates.com/Themes/UserSubmittedThemes
|
||||
+58
-55
@@ -1,124 +1,127 @@
|
||||
# Creating a Theme
|
||||
|
||||
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.
|
||||
of CSS). Don't worry if you haven't heard of LESS before; it's just like CSS,
|
||||
but with a few handy extensions.
|
||||
|
||||
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.
|
||||
Atom supports two types of themes: _UI_ and _syntax_. UI themes style
|
||||
elements such as the tree view, the tabs, drop-down lists, and the status bar.
|
||||
Syntax themes style the code inside the editor.
|
||||
|
||||
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.
|
||||
Themes can be installed and changed from the settings view which you can open
|
||||
by selecting the _Atom > Preferences..._ menu and navigating to the _Themes_
|
||||
section on the left hand side.
|
||||
|
||||
## Getting Started
|
||||
|
||||
Themes are pretty straight forward but it's still helpful to be familiar with
|
||||
Themes are pretty straightforward but it's still helpful to be familiar with
|
||||
a few things before starting:
|
||||
|
||||
* LESS is a superset of CSS, but it has some really handy features like
|
||||
variables. If you aren't familiar with its syntax take a few minutes
|
||||
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.
|
||||
|
||||
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.
|
||||
is used to help distribute your theme to Atom users.
|
||||
* Your theme's _package.json_ must contain a `"theme"` key with a value
|
||||
of `"ui"` or `"syntax"` for Atom to recognize and load it as a theme.
|
||||
* You can find existing themes to install or fork on [atom.io](atomio).
|
||||
|
||||
## Creating a Syntax Theme
|
||||
|
||||
Let's create your first theme.
|
||||
|
||||
To get started, hit `cmd-shift-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_.
|
||||
To get started, hit `cmd-shift-P`, and start typing "Generate Syntax Theme" to
|
||||
generate a new theme package. Select "Generate Syntax Theme," and you'll be
|
||||
asked for the path where your theme will be created. Let's call ours _motif_.
|
||||
|
||||
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."
|
||||
Atom will pop open a new window, showing the _motif_ theme, with a default set
|
||||
of folders and files created for us. If you open the settings view (`cmd-,`)
|
||||
and navigate to the _Themes_ section on the left, you'll see the _Motif_ theme
|
||||
listed in the _Syntax Theme_ drop-down. Select it from the menu to activate it,
|
||||
now when you open an editor you should see that your new _motif_ theme in
|
||||
action.
|
||||
|
||||
Open up _stylesheets/colors.less_ to change the various colors variables which
|
||||
have been already been defined. For example, turn `@red` into `#f4c2c1`.
|
||||
|
||||
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.
|
||||
Then open _stylesheets/base.less_ and modify the various selectors that have
|
||||
been already been defined. These selectors style different parts of code in the
|
||||
editor such as comments, strings and the line numbers in the gutter.
|
||||
|
||||
As an example, let's make the `.gutter` `background-color` into `@red`.
|
||||
|
||||
Reload Atom by hitting `cmd-r` to see the changes you made reflected in your Atom
|
||||
window. Pretty neat!
|
||||
Reload Atom by pressing `cmd-alt-option-L` to see the changes you made reflected
|
||||
in your Atom window. Pretty neat!
|
||||
|
||||
## Creating an Interface Theme
|
||||
|
||||
Interface themes **must** provide a `ui-variables.less` file which contains all
|
||||
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
|
||||
1. Fork one of the following repositories:
|
||||
* [atom-dark-ui]
|
||||
* [atom-light-ui]
|
||||
2. Clone the forked repository to the local filesystem
|
||||
3. Open a terminal in the forked theme's directory
|
||||
4. Open your new theme in a Dev Mode Atom window run `atom --dev .` in the
|
||||
terminal or use the _View > Developer > Open in Dev Mode_ menu)
|
||||
5. Change the name of the theme in the theme's `package.json` file
|
||||
6. Run `apm link` to symlink your repository to `~/.atom/packages`
|
||||
7. Reload Atom using `cmd-alt-ctrl-L`
|
||||
8. Enable the theme via _UI Theme_ drop-down in the _Themes_ section of the
|
||||
settings view
|
||||
9. 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.
|
||||
There are a few of tools to help make theme development faster and easier.
|
||||
|
||||
### 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.
|
||||
Reloading by hitting `cmd-alt-ctrl-L` 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!
|
||||
__View > Developer > Open in Dev Mode__ menu or by hitting the `cmd-shift-o`
|
||||
shortcut
|
||||
2. 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`.
|
||||
`cmd-ctrl-shift-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.
|
||||
can open them by selecting the _View > Toggle Developer Tools_ menu, or by
|
||||
using the `cmd-alt-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.
|
||||
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.
|
||||
changes affect all the components in the system. The [styleguide] is a page that
|
||||
renders every component Atom supports.
|
||||
|
||||
To open the styleguide, open the command palette (`cmd-shift-P`) and search for
|
||||
_styleguide_, or use the shortcut `cmd-ctrl-shift-g`.
|
||||
|
||||
![styleguide-img]
|
||||
|
||||
[atomio]: http://atom.io/packages
|
||||
[less]: http://lesscss.org/
|
||||
[git]: http://git-scm.com/
|
||||
[atom]: https://atom.io/
|
||||
|
||||
+69
-35
@@ -1,34 +1,57 @@
|
||||
# Customizing Atom
|
||||
|
||||
To change a setting, configure a theme, or install a package just open the
|
||||
Settings pane in the current window by pressing `cmd+,`.
|
||||
Settings view in the current window by pressing `cmd+,`.
|
||||
|
||||
## Changing The Theme
|
||||
|
||||
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 comes with both light and dark UI themes as well as several syntax themes.
|
||||
You are also encouraged to [create or fork][create-theme] your own theme.
|
||||
|
||||
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.
|
||||
To change the active theme just open the Settings view (`cmd-,`) and select the
|
||||
`Themes` section from the left hand side. You will see a drop-down menu to
|
||||
change the active _Syntax_ and _UI_ themes.
|
||||
|
||||
You can also install more themes from here by browsing the featured themes or
|
||||
searching for a specific theme.
|
||||
|
||||
## Installing Packages
|
||||
|
||||
You can install non-bundled packages by going to the `Available Packages`
|
||||
section on the `Packages` tab within the Settings panel (`cmd-,`).
|
||||
You can install non-bundled packages by going to the `Packages` section on left
|
||||
hand side of the Settings view (`cmd-,`). You will see several featured packages
|
||||
and you can also search for packages from here. The packages listed here have
|
||||
been published to [atom.io](http://atom.io/packages) which is the official
|
||||
registry for Atom packages.
|
||||
|
||||
You can also install packages from the command line using the
|
||||
[apm](https://github.com/atom/apm) command:
|
||||
You can also install packages from the command line using `apm`.
|
||||
|
||||
`apm install <package_name>` to install the latest version.
|
||||
Check that you have `apm` installed by running the following command in your
|
||||
terminal:
|
||||
|
||||
`apm install <package_name>@<package_version>` to install a specific version.
|
||||
```sh
|
||||
apm help install
|
||||
```
|
||||
|
||||
You should see a message print out with details about the `apm install` command.
|
||||
|
||||
If you do not, launch Atom and run the _Atom > Install Shell Commmands_ menu
|
||||
to install the `apm` and `atom` commands.
|
||||
|
||||
You can also install packages by using the `apm install` command:
|
||||
|
||||
* `apm install <package_name>` to install the latest version.
|
||||
|
||||
* `apm install <package_name>@<package_version>` to install a specific version.
|
||||
|
||||
For example `apm install emmet@0.1.5` installs the `0.1.5` release of the
|
||||
[Emmet](https://github.com/atom/emmet) package into `~/.atom/packages`.
|
||||
|
||||
You can also use `apm` to find new packages to install:
|
||||
|
||||
* `apm search coffee` to search for CoffeeScript packages.
|
||||
|
||||
* `apm view emmet` to see more information about a specific package.
|
||||
|
||||
## Customizing Key Bindings
|
||||
|
||||
Atom keymaps work similarly to stylesheets. Just as stylesheets use selectors
|
||||
@@ -36,13 +59,13 @@ 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:
|
||||
|
||||
```coffee-script
|
||||
```coffee
|
||||
'.editor':
|
||||
'enter': 'editor:newline'
|
||||
|
||||
'body':
|
||||
'ctrl-P': 'core:move-up'
|
||||
'ctrl-p': 'core:move-down'
|
||||
'ctrl-b': 'core:move-left'
|
||||
'ctrl-f': 'core:move-right'
|
||||
```
|
||||
|
||||
This keymap defines the meaning of `enter` in two different contexts. In a
|
||||
@@ -55,6 +78,8 @@ 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.
|
||||
|
||||
You can open this file in an editor from the _Atom > Open Your Keymap_ menu.
|
||||
|
||||
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.
|
||||
@@ -64,16 +89,18 @@ currently in use.
|
||||
Atom loads configuration settings from the `config.cson` file in your _~/.atom_
|
||||
directory, which contains CoffeeScript-style JSON:
|
||||
|
||||
```coffeescript
|
||||
core:
|
||||
excludeVcsIgnoredPaths: true
|
||||
editor:
|
||||
fontSize: 18
|
||||
```coffee
|
||||
'core':
|
||||
'excludeVcsIgnoredPaths': true
|
||||
'editor':
|
||||
'fontSize': 18
|
||||
```
|
||||
|
||||
The configuration itself is grouped by the package name or one of the two core
|
||||
namespaces: `core` and `editor`.
|
||||
|
||||
You can open this file in an editor from the _Atom > Open Your Config_ menu.
|
||||
|
||||
### Configuration Key Reference
|
||||
|
||||
- `core`
|
||||
@@ -108,35 +135,42 @@ namespaces: `core` and `editor`.
|
||||
- `removeTrailingWhitespace`: Enable/disable striping of whitespace at the end of lines (defaults to `true`)
|
||||
- `wrap-guide`
|
||||
- `columns`: Array of hashes with a `pattern` and `column` key to match the
|
||||
the path of the current editor to a column position.
|
||||
the path of the current editor to a column position.
|
||||
|
||||
### Quick Personal Hacks
|
||||
|
||||
### user.coffee
|
||||
### init.coffee
|
||||
|
||||
When Atom finishes loading, it will evaluate _user.coffee_ in your _~/.atom_
|
||||
When Atom finishes loading, it will evaluate _init.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.
|
||||
If customizations become extensive, consider [creating a
|
||||
package][create-a-package].
|
||||
If customizations become extensive, consider [creating a package][create-a-package].
|
||||
|
||||
### styles.css
|
||||
You can open this file in an editor from the _Atom > Open Your Init Script_
|
||||
menu.
|
||||
|
||||
This file can also be named _init.js_ and contain JavaScript code.
|
||||
|
||||
### styles.less
|
||||
|
||||
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
|
||||
_styles.css_ in your _~/.atom_ directory.
|
||||
an entire theme that you intend to publish, you can add styles to the
|
||||
_styles.less_ file 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 _styles.css_:
|
||||
You can open this file in an editor from the _Atom > Open Your Stylesheet_ menu.
|
||||
|
||||
```css
|
||||
For example, to change the color of the cursor, you could add the following
|
||||
rule to your _~/.atom/styles.less_ file:
|
||||
|
||||
```less
|
||||
.editor .cursor {
|
||||
border-color: pink;
|
||||
}
|
||||
```
|
||||
|
||||
You can also name the file _styles.less_ if you want to style Atom using
|
||||
[LESS][LESS].
|
||||
Unfamiliar with LESS? Read more about it [here][LESS].
|
||||
|
||||
This file can also be named _styles.css_ and contain CSS.
|
||||
|
||||
[create-a-package]: creating-packages.md
|
||||
[create-theme]: creating-a-theme.md
|
||||
|
||||
+20
-15
@@ -22,7 +22,7 @@ bindings][key-bindings] section.
|
||||
Atom windows are scoped to a single directory on disk. If you launch Atom from
|
||||
the command line via the `atom` command and don't specify a path, Atom opens a
|
||||
window for the current working directory. The current window's directory will be
|
||||
visible as the root of the tree view at the left, and also serve as the context
|
||||
visible as the root of the tree view on the left, and also serve as the context
|
||||
for all file-related operations.
|
||||
|
||||
#### Finding Files
|
||||
@@ -30,7 +30,8 @@ for all file-related operations.
|
||||
The fastest way to find a file is to use the fuzzy finder. Press `cmd-t` and
|
||||
begin typing the name of the file you're looking for. If you are looking for a
|
||||
file that is already open press `cmd-b` to bring up a searchable list of open
|
||||
files.
|
||||
files. If you are using Git you can use `cmd-shift-b` to search the list of
|
||||
files modified and untracked in your project's repository.
|
||||
|
||||
You can also use the tree view to navigate to a file. To open and focus the
|
||||
the tree view, press `ctrl-0`. The tree view can be toggled open and closed with
|
||||
@@ -38,11 +39,10 @@ the tree view, press `ctrl-0`. The tree view can be toggled open and closed with
|
||||
|
||||
#### Adding, Moving, Deleting Files
|
||||
|
||||
Currently, all file modification is performed via the tree view. Add, move, or
|
||||
delete a file by right-clicking in the tree view and selecting the desired
|
||||
operation from the context menu. You can also perform these operations from the
|
||||
keyboard by selecting a file or directory and using `a` to add, `m` to move, and
|
||||
`delete` to delete.
|
||||
You can add, move, and delete files and folders by right-clicking them in the
|
||||
tree view and selecting the desired operation from the context menu. You can
|
||||
also perform these operations from the keyboard by selecting a file or folder
|
||||
and using `a` to add, `m` to move, and `delete` to delete.
|
||||
|
||||
### Searching
|
||||
|
||||
@@ -58,9 +58,15 @@ list of all symbols in the current file, which you can fuzzy filter similarly to
|
||||
`cmd-t`.
|
||||
|
||||
To search for symbols across your project, use `cmd-shift-r`. First you'll need
|
||||
to make sure you have ctags installed and a tags file generated for your
|
||||
project. Also, if you're editing CoffeeScript, it's a good idea to update your
|
||||
`~/.ctags` file to understand the language. Here is [a good example][ctags].
|
||||
to make sure you have `tags` (or `TAGS`) file generated for your project.
|
||||
This can be done by installing [ctags](http://ctags.sourceforge.net/) and
|
||||
running a command such as `ctags -R src/` from the command line in your
|
||||
project's root directory. Using [Homebrew](http://brew.sh/)? Just run
|
||||
`brew install ctags`.
|
||||
|
||||
You can customize how tags are generated by creating your own `.ctags` file
|
||||
in your home directory (`~/.ctags`). Here is [a good example][ctags] to start
|
||||
from.
|
||||
|
||||
### Split Panes
|
||||
|
||||
@@ -68,7 +74,7 @@ You can split any editor pane horizontally or vertically by using `cmd-k right`
|
||||
or `cmd-k down`. Once you have a split pane, you can move focus between them
|
||||
with `cmd-k cmd-right` or `cmd-k cmd-down`. To close a pane, close all its
|
||||
editors with `meta-w`, then press `meta-w` one more time to close the pane. You
|
||||
can configure panes to auto-close with empty in the preferences.
|
||||
can configure panes to auto-close when empty in the Settings view.
|
||||
|
||||
### Folding
|
||||
|
||||
@@ -89,9 +95,8 @@ in preferences.
|
||||
|
||||
## Configuration
|
||||
|
||||
Press `cmd-,` to display the preferences pane. This serves as the primary
|
||||
interface for adjusting config settings, installing packages and changing
|
||||
themes.
|
||||
Press `cmd-,` to open the Settings view. This is the place to change settings,
|
||||
install packages, and change the theme.
|
||||
|
||||
For more advanced configuration see the [customization guide][customization].
|
||||
|
||||
@@ -101,4 +106,4 @@ For more advanced configuration see the [customization guide][customization].
|
||||
[customization]: customizing-atom.md
|
||||
[key-bindings]: customizing-atom.md#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
|
||||
[ctags]: https://github.com/atom/symbols-view/blob/master/lib/.ctags
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* [Customizing Atom](customizing-atom.md)
|
||||
* [Creating a Package](creating-a-package.md)
|
||||
* [Creating a Theme](creating-a-theme.md)
|
||||
* [Publishing a Package](publishing-a-package.md)
|
||||
* [Contributing](contributing.md)
|
||||
|
||||
### Advanced Topics
|
||||
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
## 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.
|
||||
@@ -0,0 +1,97 @@
|
||||
## Publishing a Package
|
||||
|
||||
This guide will show you how to publish a package or theme to the
|
||||
[atom.io][atomio] package registry.
|
||||
|
||||
Publishing a package allows other people to install it and use it in Atom. It
|
||||
is a great way to share what you've made and get feedback and contributions from
|
||||
others.
|
||||
|
||||
This guide assumes your package's name is `my-package` and but you should pick a
|
||||
better name.
|
||||
|
||||
### Install apm
|
||||
|
||||
The `apm` command line utility that ships with Atom supports publishing packages
|
||||
to the atom.io registry.
|
||||
|
||||
Check that you have `apm` installed by running the following command in your
|
||||
terminal:
|
||||
|
||||
```sh
|
||||
apm help publish
|
||||
```
|
||||
|
||||
You should see a message print out with details about the `apm publish` command.
|
||||
|
||||
If you do not, launch Atom and run the _Atom > Install Shell Commmands_ menu
|
||||
to install the `apm` and `atom` commands.
|
||||
|
||||
### Prepare Your Package
|
||||
|
||||
If you've followed the steps in the [your first package][your-first-package]
|
||||
doc then you should be ready to publish and you can skip to the next step.
|
||||
|
||||
If not, there are a few things you should check before publishing:
|
||||
|
||||
* Your *package.json* file has `name`, `description`, and `repository` fields.
|
||||
* Your *package.json* file has a `version` field with a value of `"0.0.0"`.
|
||||
* Your *package.json* file has an `engines` field that contains an entry
|
||||
for Atom such as: `"engines": {"atom": ">=0.50.0"}`.
|
||||
* Your package has a `README.md` file at the root.
|
||||
* Your package is in a Git repository that has been pushed to
|
||||
[GitHub][github]. Follow [this guide][repo-guide] if your package isn't
|
||||
already on GitHub.
|
||||
|
||||
### Publish Your Package
|
||||
|
||||
Before you publish a package it is a good idea to check ahead of time if
|
||||
a package with the same name has already been published to atom.io. You can do
|
||||
that by visiting `http://atom.io/packages/my-package` to see if the package
|
||||
already exists. If it does, update your package's name to something that is
|
||||
available before proceeding.
|
||||
|
||||
Now let's review what the `apm publish` command does:
|
||||
|
||||
1. Registers the package name on atom.io if it is being published for the
|
||||
first time.
|
||||
2. Updates the `version` field in the *package.json* file and commits it.
|
||||
3. Creates a new [Git tag][git-tag] for the version being published.
|
||||
4. Pushes the tag and current branch up to GitHub.
|
||||
5. Updates atom.io with the new version being published.
|
||||
|
||||
Now run the following commands to publish your package:
|
||||
|
||||
```sh
|
||||
cd ~/github/my-package
|
||||
apm publish minor
|
||||
```
|
||||
|
||||
If this is the first package you are publishing, the `apm publish` command may
|
||||
prompt you for your GitHub username and password. This is required to publish
|
||||
and you only need to enter this information the first time you publish. The
|
||||
credentials are stored securely in your [keychain][keychain] once you login.
|
||||
|
||||
:tada: Your package is now published and available on atom.io. Head on over to
|
||||
`http://atom.io/packages/my-package` to see your package's page.
|
||||
|
||||
The `minor` option to the publish command tells apm to increment the second
|
||||
digit of the version before publishing so the published version will be `0.1.0`
|
||||
and the Git tag created will be `v0.1.0`.
|
||||
|
||||
In the future you can run `apm publish major` to publish the `1.0.0` version but
|
||||
since this was the first version being published it is a good idead to start
|
||||
with a minor release.
|
||||
|
||||
### Further Reading
|
||||
|
||||
* Check out [semantic versioning][semver] to learn more about versioning your
|
||||
package releases.
|
||||
|
||||
[atomio]: https://atom.io
|
||||
[github]: https://github.com
|
||||
[git-tag]: http://git-scm.com/book/en/Git-Basics-Tagging
|
||||
[keychain]: http://en.wikipedia.org/wiki/Keychain_(Apple)
|
||||
[repo-guide]: http://guides.github.com/overviews/desktop
|
||||
[semver]: http://semver.org
|
||||
[your-first-package]: your-first-package.html
|
||||
@@ -5,6 +5,7 @@ selected text with [ascii art](http://en.wikipedia.org/wiki/ASCII_art). When you
|
||||
run our new command with the word "cool" selected, it will be replaced with:
|
||||
|
||||
```
|
||||
___
|
||||
/\_ \
|
||||
___ ___ ___\//\ \
|
||||
/'___\ / __`\ / __`\\ \ \
|
||||
@@ -25,17 +26,17 @@ Atom will open a new window with the contents of our new _ascii-art_ package
|
||||
displayed in the Tree View. Because this window is opened **after** the package
|
||||
is created, the ASCII Art package will be loaded and available in our new
|
||||
window. To verify this, toggle the Command Palette (`cmd-shift-P`) and type
|
||||
"ASCII Art" you'll see a new `ASCII Art: Toggle` command. When triggered, this
|
||||
"ASCII Art". You'll see a new `ASCII Art: Toggle` command. When triggered, this
|
||||
command displays a default message.
|
||||
|
||||
Now let's edit the package files to make our ascii art package do something
|
||||
Now let's edit the package files to make our ASCII Art package do something
|
||||
interesting. Since this package doesn't need any UI, we can remove all
|
||||
view-related code. Start by opening up _lib/ascii-art.coffee_. Remove all view
|
||||
code, so the file looks like this:
|
||||
code, so the `module.exports` section looks like this:
|
||||
|
||||
```coffeescript
|
||||
module.exports =
|
||||
activate: ->
|
||||
module.exports =
|
||||
activate: ->
|
||||
```
|
||||
|
||||
## Create a Command
|
||||
@@ -69,23 +70,24 @@ command palette or by pressing `ctrl-alt-cmd-l`.
|
||||
## Trigger the Command
|
||||
|
||||
Now open the command panel and search for the `ascii-art:convert` command. But
|
||||
its not there! To fix this open _package.json_ and find the property called
|
||||
`activationEvents`. Activation Events speed up load time by allowing an Atom to
|
||||
delay a package's activation until it's needed. So add the `ascii-art:convert`
|
||||
to the activationEvents array:
|
||||
it's not there! To fix this, open _package.json_ and find the property called
|
||||
`activationEvents`. Activation Events speed up load time by allowing Atom to
|
||||
delay a package's activation until it's needed. So remove the existing command
|
||||
and add `ascii-art:convert` to the `activationEvents` array:
|
||||
|
||||
```json
|
||||
"activationEvents": ["ascii-art:convert"],
|
||||
```
|
||||
|
||||
First, run reload the window by running the command `window:reload`. Now when
|
||||
you run the `ascii-art:convert` command it will output 'Hello, World!'
|
||||
First, reload the window by running the command `window:reload`. Now when you
|
||||
run the `ascii-art:convert` command it will output 'Hello, World!'
|
||||
|
||||
## Add A Key Binding
|
||||
## Add a Key Binding
|
||||
|
||||
Now let's add a key binding to trigger the `ascii-art:convert` command. Open
|
||||
_keymaps/ascii-art.cson_ and add a key binding linking `ctrl-alt-a` to the
|
||||
`ascii-art:convert` command. When finished, the file will look like this:
|
||||
`ascii-art:convert` command. You can delete the pre-existing key binding since
|
||||
you don't need it anymore. When finished, the file will look like this:
|
||||
|
||||
```coffeescript
|
||||
'.editor':
|
||||
@@ -105,25 +107,25 @@ that it **doesn't** work when the Tree View is focused.
|
||||
|
||||
## Add the ASCII Art
|
||||
|
||||
Now we need to convert the selected text to ascii art. To do this we will use
|
||||
Now we need to convert the selected text to ASCII art. To do this we will use
|
||||
the [figlet](https://npmjs.org/package/figlet) [node](http://nodejs.org/) module
|
||||
from [npm](https://npmjs.org/). Open _package.json_ and add the latest version of
|
||||
figlet to the dependencies:
|
||||
|
||||
```json
|
||||
"dependencies": {
|
||||
"figlet": "1.0.8"
|
||||
}
|
||||
"dependencies": {
|
||||
"figlet": "1.0.8"
|
||||
}
|
||||
```
|
||||
|
||||
After saving the file run the command 'update-package-dependencies:update' from
|
||||
the Command Palette. This will install the packages node module dependencies,
|
||||
After saving the file, run the command 'update-package-dependencies:update' from
|
||||
the Command Palette. This will install the package's node module dependencies,
|
||||
only figlet in this case. You will need to run
|
||||
'update-package-dependencies:update' whenever you update the dependencies field
|
||||
in your _package.json_ file.
|
||||
|
||||
Now require the figlet node module in _lib/ascii-art.coffee_ and instead of
|
||||
inserting 'Hello, World!' convert the selected text to ascii art!
|
||||
inserting 'Hello, World!' convert the selected text to ASCII art.
|
||||
|
||||
```coffeescript
|
||||
convert: ->
|
||||
@@ -139,7 +141,15 @@ convert: ->
|
||||
selection.insertText("\n#{asciiArt}\n")
|
||||
```
|
||||
|
||||
Select some text in an editor window and hit `cmd-alt-a`. :tada: You're now an
|
||||
ASCII art professional!
|
||||
|
||||
## Further reading
|
||||
|
||||
For more information on the mechanics of packages, check out [Creating a
|
||||
Package](creating-a-package.html)
|
||||
* [Getting your project on GitHub guide](http://guides.github.com/overviews/desktop)
|
||||
|
||||
* [Creating a package guide](creating-a-package.html) for more information
|
||||
on the mechanics of packages
|
||||
|
||||
* [Publishing a package guide](publish-a-package.html) for more information
|
||||
on publishing your package to [atom.io](https://atom.io)
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# Your init script
|
||||
#
|
||||
# Atom will evaluate this file each time a new window is opened. It is run
|
||||
# after packages are loaded/activated and after the previous editor state
|
||||
# has been restored.
|
||||
#
|
||||
# An example hack to make opened Markdown files always be soft wrapped:
|
||||
#
|
||||
# path = require 'path'
|
||||
#
|
||||
# atom.workspaceView.eachEditorView (editorView) ->
|
||||
# editor = editorView.getEditor()
|
||||
# if path.extname(editor.getPath()) is '.md'
|
||||
# editor.setSoftWrap(true)
|
||||
@@ -1,9 +1,13 @@
|
||||
# User keymap
|
||||
# Your 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:
|
||||
# keystrokes with events in specific contexts.
|
||||
#
|
||||
# You can create a new keybinding in this file by typing "key" and then hitting
|
||||
# tab.
|
||||
#
|
||||
# Here's an example taken from Atom's built-in keymap:
|
||||
#
|
||||
# '.editor':
|
||||
# 'enter': 'editor:newline'
|
||||
@@ -11,3 +15,4 @@
|
||||
# 'body':
|
||||
# 'ctrl-P': 'core:move-up'
|
||||
# 'ctrl-p': 'core:move-down'
|
||||
#
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Atom snippets allow you to enter a simple prefix in the editor and hit tab to
|
||||
# expand the prefix into a larger code block with templated values.
|
||||
#
|
||||
# You can create a new snippet in this file by typing `snip` and then hitting
|
||||
# You can create a new snippet in this file by typing "snip" and then hitting
|
||||
# tab.
|
||||
#
|
||||
# An example CoffeeScript snippet to expand log to console.log:
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
*
|
||||
* This stylesheet is loaded when Atom starts up and is reloaded automatically
|
||||
* when it is changed.
|
||||
*
|
||||
* If you are unfamiliar with LESS, you can read more about it here:
|
||||
* http://www.lesscss.org
|
||||
*/
|
||||
|
||||
.tree-view {
|
||||
@@ -1 +0,0 @@
|
||||
# For more on how to configure atom open `~/github/atom/docs/configuring-and-extending.md`
|
||||
@@ -1,13 +1,8 @@
|
||||
{Point, Range} = require 'text-buffer'
|
||||
|
||||
module.exports =
|
||||
_: require 'underscore-plus'
|
||||
BufferedNodeProcess: require '../src/buffered-node-process'
|
||||
BufferedProcess: require '../src/buffered-process'
|
||||
ConfigObserver: require '../src/config-observer'
|
||||
Directory: require '../src/directory'
|
||||
File: require '../src/file'
|
||||
fs: require 'fs-plus'
|
||||
Git: require '../src/git'
|
||||
Point: Point
|
||||
Range: Range
|
||||
|
||||
@@ -68,6 +68,8 @@
|
||||
'cmd-=': 'window:increase-font-size'
|
||||
'cmd-+': 'window:increase-font-size'
|
||||
'cmd--': 'window:decrease-font-size'
|
||||
'cmd-_': 'window:decrease-font-size'
|
||||
'cmd-0': 'window:reset-font-size'
|
||||
|
||||
'cmd-k up': 'pane:split-up' # Atom Specific
|
||||
'cmd-k down': 'pane:split-down' # Atom Specific
|
||||
@@ -75,8 +77,12 @@
|
||||
'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-k cmd-p': 'window:focus-previous-pane'
|
||||
'cmd-k cmd-n': 'window:focus-next-pane'
|
||||
'cmd-k cmd-up': 'window:focus-pane-above'
|
||||
'cmd-k cmd-down': 'window:focus-pane-below'
|
||||
'cmd-k cmd-left': 'window:focus-pane-on-left'
|
||||
'cmd-k cmd-right': 'window:focus-pane-on-right'
|
||||
'cmd-1': 'pane:show-item-1'
|
||||
'cmd-2': 'pane:show-item-2'
|
||||
'cmd-3': 'pane:show-item-3'
|
||||
@@ -118,7 +124,6 @@
|
||||
'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'
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
'ctrl-=': 'window:increase-font-size'
|
||||
'ctrl-+': 'window:increase-font-size'
|
||||
'ctrl--': 'window:decrease-font-size'
|
||||
'ctrl-_': 'window:decrease-font-size'
|
||||
'ctrl-0': 'window:reset-font-size'
|
||||
|
||||
'ctrl-k up': 'pane:split-up' # Atom Specific
|
||||
'ctrl-k down': 'pane:split-down' # Atom Specific
|
||||
@@ -47,8 +49,12 @@
|
||||
'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'
|
||||
'ctrl-k ctrl-p': 'window:focus-previous-pane'
|
||||
'ctrl-k ctrl-n': 'window:focus-next-pane'
|
||||
'ctrl-k ctrl-up': 'window:focus-pane-above'
|
||||
'ctrl-k ctrl-down': 'window:focus-pane-below'
|
||||
'ctrl-k ctrl-left': 'window:focus-pane-on-left'
|
||||
'ctrl-k ctrl-right': 'window:focus-pane-on-right'
|
||||
|
||||
'.workspace .editor':
|
||||
# Windows specific
|
||||
@@ -65,7 +71,6 @@
|
||||
'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'
|
||||
|
||||
+4
-2
@@ -3,11 +3,14 @@
|
||||
label: 'Atom'
|
||||
submenu: [
|
||||
{ label: 'About Atom', command: 'application:about' }
|
||||
{ label: 'View License', command: 'application:open-license' }
|
||||
{ label: "VERSION", enabled: false }
|
||||
{ label: "Install update", command: 'application:install-update', visible: false }
|
||||
{ label: "Restart and Install Update", command: 'application:install-update', visible: false}
|
||||
{ label: "Check for Update", command: 'application:check-for-update', visible: false}
|
||||
{ type: 'separator' }
|
||||
{ label: 'Preferences...', command: 'application:show-settings' }
|
||||
{ label: 'Open Your Config', command: 'application:open-your-config' }
|
||||
{ label: 'Open Your Init Script', command: 'application:open-your-init-script' }
|
||||
{ label: 'Open Your Keymap', command: 'application:open-your-keymap' }
|
||||
{ label: 'Open Your Snippets', command: 'application:open-your-snippets' }
|
||||
{ label: 'Open Your Stylesheet', command: 'application:open-your-stylesheet' }
|
||||
@@ -163,7 +166,6 @@
|
||||
label: 'Help'
|
||||
submenu: [
|
||||
{ label: 'Documentation', command: 'application:open-documentation' }
|
||||
{ label: 'Report an Issue', command: 'application:report-issue' }
|
||||
{ type: 'separator' }
|
||||
]
|
||||
}
|
||||
|
||||
@@ -145,6 +145,7 @@
|
||||
label: '&Help'
|
||||
submenu: [
|
||||
{ label: '&About Atom...', command: 'application:about' }
|
||||
{ label: 'View &License', command: 'application:open-license' }
|
||||
{ label: "VERSION", enabled: false }
|
||||
{ label: "Install &update", command: 'application:install-update', visible: false }
|
||||
{ type: 'separator' }
|
||||
|
||||
+89
-97
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "atom",
|
||||
"productName": "Atom",
|
||||
"version": "0.49.0",
|
||||
"version": "0.56.0",
|
||||
"main": "./src/browser/main.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -16,128 +16,120 @@
|
||||
"url": "http://github.com/atom/atom/raw/master/LICENSE.md"
|
||||
}
|
||||
],
|
||||
"atomShellVersion": "0.8.7",
|
||||
"atomShellVersion": "0.10.1",
|
||||
"dependencies": {
|
||||
"async": "0.2.6",
|
||||
"bootstrap": "git://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372",
|
||||
"clear-cut": "0.2.0",
|
||||
"clear-cut": "0.4.0",
|
||||
"coffee-script": "1.7.0",
|
||||
"coffeestack": "0.7.0",
|
||||
"delegato": "1.x",
|
||||
"emissary": "1.x",
|
||||
"first-mate": ">=1.1 <2.0",
|
||||
"fs-plus": "1.x",
|
||||
"first-mate": ">=1.1.5 <2.0",
|
||||
"fs-plus": "2.x",
|
||||
"fstream": "0.1.24",
|
||||
"fuzzaldrin": "1.x",
|
||||
"git-utils": "0.34.0",
|
||||
"git-utils": "1.x",
|
||||
"guid": "0.0.10",
|
||||
"jasmine-tagged": "1.x",
|
||||
"jasmine-tagged": ">=1.1.1 <2.0",
|
||||
"mkdirp": "0.3.5",
|
||||
"keytar": "0.15.1",
|
||||
"less-cache": "0.11.0",
|
||||
"less-cache": "0.12.0",
|
||||
"mixto": "1.x",
|
||||
"nslog": "0.4.0",
|
||||
"nslog": "0.5.0",
|
||||
"oniguruma": "1.x",
|
||||
"optimist": "0.4.0",
|
||||
"pathwatcher": "0.14.2",
|
||||
"pathwatcher": "0.16.0",
|
||||
"pegjs": "0.8.0",
|
||||
"property-accessors": "1.x",
|
||||
"q": "0.9.7",
|
||||
"scandal": "0.13.0",
|
||||
"season": "1.x",
|
||||
"q": "1.0.x",
|
||||
"random-words": "0.0.1",
|
||||
"runas": "0.5.x",
|
||||
"scandal": "0.15.0",
|
||||
"season": ">=1.0.2 <2.0",
|
||||
"semver": "1.1.4",
|
||||
"serializable": "1.x",
|
||||
"space-pen": "3.1.1",
|
||||
"temp": "0.5.0",
|
||||
"text-buffer": "0.16.0",
|
||||
"text-buffer": ">=1.1.2 <2.0",
|
||||
"theorist": "1.x",
|
||||
"underscore-plus": "1.x",
|
||||
"vm-compatibility-layer": "0.1.0"
|
||||
},
|
||||
"packageDependencies": {
|
||||
"atom-dark-syntax": "0.12.0",
|
||||
"atom-dark-ui": "0.21.0",
|
||||
"atom-light-syntax": "0.12.0",
|
||||
"atom-light-ui": "0.20.0",
|
||||
"base16-tomorrow-dark-theme": "0.10.0",
|
||||
"solarized-dark-syntax": "0.8.0",
|
||||
"solarized-light-syntax": "0.4.0",
|
||||
"archive-view": "0.21.0",
|
||||
"autocomplete": "0.21.0",
|
||||
"autoflow": "0.12.0",
|
||||
"autosave": "0.10.0",
|
||||
"background-tips": "0.5.0",
|
||||
"bookmarks": "0.18.0",
|
||||
"bracket-matcher": "0.19.0",
|
||||
"command-logger": "0.10.0",
|
||||
"command-palette": "0.15.0",
|
||||
"dev-live-reload": "0.23.0",
|
||||
"editor-stats": "0.12.0",
|
||||
"exception-reporting": "0.13.0",
|
||||
"feedback": "0.22.0",
|
||||
"find-and-replace": "0.81.0",
|
||||
"fuzzy-finder": "0.32.0",
|
||||
"gists": "0.15.0",
|
||||
"git-diff": "0.23.0",
|
||||
"github-sign-in": "0.18.0",
|
||||
"go-to-line": "0.16.0",
|
||||
"grammar-selector": "0.18.0",
|
||||
"image-view": "0.17.0",
|
||||
"keybinding-resolver": "0.9.0",
|
||||
"link": "0.15.0",
|
||||
"markdown-preview": "0.25.1",
|
||||
"metrics": "0.24.0",
|
||||
"package-generator": "0.25.0",
|
||||
"release-notes": "0.17.0",
|
||||
"settings-view": "0.63.0",
|
||||
"snippets": "0.24.0",
|
||||
"spell-check": "0.21.0",
|
||||
"status-bar": "0.32.0",
|
||||
"styleguide": "0.22.0",
|
||||
"symbols-view": "0.30.0",
|
||||
"tabs": "0.18.0",
|
||||
"terminal": "0.27.0",
|
||||
"timecop": "0.13.0",
|
||||
"to-the-hubs": "0.18.0",
|
||||
"tree-view": "0.65.0",
|
||||
"update-package-dependencies": "0.2.0",
|
||||
"visual-bell": "0.6.0",
|
||||
"welcome": "0.4.0",
|
||||
"whitespace": "0.10.0",
|
||||
"wrap-guide": "0.12.0",
|
||||
"language-c": "0.2.0",
|
||||
"language-clojure": "0.1.0",
|
||||
"language-coffee-script": "0.6.0",
|
||||
"language-css": "0.2.0",
|
||||
"language-gfm": "0.12.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.5.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.3.0",
|
||||
"language-property-list": "0.2.0",
|
||||
"language-puppet": "0.2.0",
|
||||
"language-python": "0.2.0",
|
||||
"language-ruby": "0.8.0",
|
||||
"language-ruby-on-rails": "0.4.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"
|
||||
"atom-dark-syntax": "0.14.0",
|
||||
"atom-dark-ui": "0.23.0",
|
||||
"atom-light-syntax": "0.14.0",
|
||||
"atom-light-ui": "0.22.0",
|
||||
"base16-tomorrow-dark-theme": "0.12.0",
|
||||
"solarized-dark-syntax": "0.10.0",
|
||||
"solarized-light-syntax": "0.6.0",
|
||||
"archive-view": "0.24.0",
|
||||
"autocomplete": "0.24.0",
|
||||
"autoflow": "0.15.0",
|
||||
"autosave": "0.12.0",
|
||||
"background-tips": "0.8.0",
|
||||
"bookmarks": "0.21.0",
|
||||
"bracket-matcher": "0.22.0",
|
||||
"command-palette": "0.18.0",
|
||||
"dev-live-reload": "0.28.0",
|
||||
"exception-reporting": "0.15.0",
|
||||
"feedback": "0.27.0",
|
||||
"find-and-replace": "0.85.0",
|
||||
"fuzzy-finder": "0.37.0",
|
||||
"git-diff": "0.25.0",
|
||||
"go-to-line": "0.17.0",
|
||||
"grammar-selector": "0.21.0",
|
||||
"image-view": "0.25.0",
|
||||
"keybinding-resolver": "0.11.0",
|
||||
"link": "0.18.0",
|
||||
"markdown-preview": "0.37.0",
|
||||
"metrics": "0.28.0",
|
||||
"open-on-github": "0.21.0",
|
||||
"package-generator": "0.28.0",
|
||||
"release-notes": "0.24.0",
|
||||
"settings-view": "0.82.0",
|
||||
"snippets": "0.32.0",
|
||||
"spell-check": "0.26.0",
|
||||
"status-bar": "0.33.0",
|
||||
"styleguide": "0.25.0",
|
||||
"symbols-view": "0.38.0",
|
||||
"tabs": "0.24.0",
|
||||
"timecop": "0.15.0",
|
||||
"tree-view": "0.71.0",
|
||||
"update-package-dependencies": "0.4.0",
|
||||
"welcome": "0.8.0",
|
||||
"whitespace": "0.15.0",
|
||||
"wrap-guide": "0.15.0",
|
||||
"language-c": "0.12.0",
|
||||
"language-coffee-script": "0.13.0",
|
||||
"language-css": "0.10.0",
|
||||
"language-gfm": "0.18.0",
|
||||
"language-git": "0.9.0",
|
||||
"language-go": "0.6.0",
|
||||
"language-html": "0.8.0",
|
||||
"language-hyperlink": "0.8.0",
|
||||
"language-java": "0.8.0",
|
||||
"language-javascript": "0.11.0",
|
||||
"language-json": "0.8.0",
|
||||
"language-less": "0.5.0",
|
||||
"language-make": "0.8.0",
|
||||
"language-objective-c": "0.9.0",
|
||||
"language-perl": "0.8.0",
|
||||
"language-php": "0.8.0",
|
||||
"language-property-list": "0.7.0",
|
||||
"language-python": "0.8.0",
|
||||
"language-ruby": "0.13.0",
|
||||
"language-ruby-on-rails": "0.7.0",
|
||||
"language-sass": "0.8.0",
|
||||
"language-shellscript": "0.7.0",
|
||||
"language-source": "0.7.0",
|
||||
"language-sql": "0.7.0",
|
||||
"language-text": "0.6.0",
|
||||
"language-todo": "0.6.0",
|
||||
"language-toml": "0.11.0",
|
||||
"language-xml": "0.7.0",
|
||||
"language-yaml": "0.6.0"
|
||||
},
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
Arquivo binário não exibido.
Arquivo binário não exibido.
Arquivo binário não exibido.
|
Antes Largura: | Altura: | Tamanho: 345 KiB Depois Largura: | Altura: | Tamanho: 361 KiB |
+1
-6
@@ -3,11 +3,6 @@ var safeExec = require('./utils/child-process-wrapper.js').safeExec;
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
// OAuth token for atom-bot
|
||||
// TODO Remove once all repositories are public
|
||||
if (!process.env.ATOM_ACCESS_TOKEN)
|
||||
process.env.ATOM_ACCESS_TOKEN = '362295be4c5258d3f7b967bbabae662a455ca2a7';
|
||||
|
||||
// Executes an array of commands one by one.
|
||||
function executeCommands(commands, done, index) {
|
||||
index = (index == undefined ? 0 : index);
|
||||
@@ -31,7 +26,7 @@ if (!fs.existsSync(path.join(apmInstallPath, 'node_modules')))
|
||||
fs.mkdirSync(path.join(apmInstallPath, 'node_modules'));
|
||||
|
||||
var apmFlags = process.env.JANKY_SHA1 || process.argv.indexOf('--no-color') !== -1 ? '--no-color' : '';
|
||||
var packagesToDedupe = ['fs-plus', 'humanize-plus', 'nan', 'oniguruma', 'roaster', 'season'];
|
||||
var packagesToDedupe = ['fs-plus', 'humanize-plus', 'oniguruma', 'roaster', 'season'];
|
||||
var echoNewLine = process.platform == 'win32' ? 'echo.' : 'echo';
|
||||
var commands = [
|
||||
'git submodule --quiet sync',
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
#!/usr/bin/env coffee
|
||||
|
||||
usage = """
|
||||
Usage:
|
||||
update-octicons PATH-TO-OCTICONS
|
||||
"""
|
||||
|
||||
path = require 'path'
|
||||
fs = require 'fs'
|
||||
YAML = require 'js-yaml'
|
||||
|
||||
scriptPath = process.argv[1]
|
||||
pathToOcticons = process.argv[2] ? path.join(process.env.HOME, 'github', 'octicons')
|
||||
atomDir = path.resolve(scriptPath, "../../..")
|
||||
|
||||
unless fs.existsSync(pathToOcticons)
|
||||
console.error(usage)
|
||||
process.exit(1)
|
||||
|
||||
# Copy font-file
|
||||
fontSrc = path.join(pathToOcticons, 'octicons', 'octicons.woff')
|
||||
fontDest = path.join(atomDir, 'static', 'octicons.woff')
|
||||
fs.createReadStream(fontSrc).pipe(fs.createWriteStream(fontDest))
|
||||
|
||||
# Update Octicon UTF codes
|
||||
glyphsSrc = path.join(pathToOcticons, 'data', 'glyphs.yml')
|
||||
octiconUtfDest = path.join atomDir, 'static', 'variables', 'octicon-utf-codes.less'
|
||||
output = []
|
||||
for {css, code} in YAML.load(fs.readFileSync(glyphsSrc).toString())
|
||||
output.push "@#{css}: \"\\#{code}\";"
|
||||
|
||||
fs.writeFileSync octiconUtfDest, "#{output.join('\n')}\n"
|
||||
+63
-67
@@ -1,35 +1,52 @@
|
||||
{View, $, $$} = require '../src/space-pen-extensions'
|
||||
path = require 'path'
|
||||
_ = require 'underscore-plus'
|
||||
{convertStackTrace} = require 'coffeestack'
|
||||
{View, $, $$} = require '../src/space-pen-extensions'
|
||||
|
||||
sourceMaps = {}
|
||||
formatStackTrace = (stackTrace) ->
|
||||
formatStackTrace = (spec, message='', stackTrace) ->
|
||||
return stackTrace unless stackTrace
|
||||
|
||||
jasminePath = require.resolve('../vendor/jasmine')
|
||||
jasminePattern = new RegExp("\\(#{_.escapeRegExp(jasminePath)}:\\d+:\\d+\\)\\s*$")
|
||||
jasminePattern = /^\s*at\s+.*\(?.*\/jasmine(-[^\/]*)?\.js:\d+:\d+\)?\s*$/
|
||||
firstJasmineLinePattern = /^\s*at \/.*\/jasmine(-[^\/]*)?\.js:\d+:\d+\)?\s*$/
|
||||
convertedLines = []
|
||||
for line in stackTrace.split('\n')
|
||||
convertedLines.push(line) unless jasminePattern.test(line)
|
||||
break if firstJasmineLinePattern.test(line)
|
||||
|
||||
convertStackTrace(convertedLines.join('\n'), sourceMaps)
|
||||
stackTrace = convertStackTrace(convertedLines.join('\n'), sourceMaps)
|
||||
lines = stackTrace.split('\n')
|
||||
|
||||
# Remove first line of stack when it is the same as the error message
|
||||
errorMatch = lines[0]?.match(/^Error: (.*)/)
|
||||
lines.shift() if message.trim() is errorMatch?[1]?.trim()
|
||||
|
||||
for line, index in lines
|
||||
# Remove prefix of lines matching: at [object Object].<anonymous> (path:1:2)
|
||||
prefixMatch = line.match(/at \[object Object\]\.<anonymous> \(([^\)]+)\)/)
|
||||
line = "at #{prefixMatch[1]}" if prefixMatch
|
||||
|
||||
# Relativize locations to spec directory
|
||||
lines[index] = line.replace("at #{spec.specDirectory}#{path.sep}", 'at ')
|
||||
|
||||
lines = lines.map (line) -> line.trim()
|
||||
lines.join('\n').trim()
|
||||
|
||||
module.exports =
|
||||
class AtomReporter extends View
|
||||
@content: ->
|
||||
@div id: 'HTMLReporter', class: 'jasmine_reporter', =>
|
||||
@div outlet: 'specPopup', class: "spec-popup"
|
||||
@div class: 'spec-reporter', =>
|
||||
@div outlet: "suites"
|
||||
@div outlet: 'coreArea', =>
|
||||
@div outlet: 'coreHeader', class: 'symbolHeader'
|
||||
@ul outlet: 'coreSummary', class: 'symbolSummary list-unstyled'
|
||||
@div outlet: 'bundledArea', =>
|
||||
@div outlet: 'bundledHeader', class: 'symbolHeader'
|
||||
@ul outlet: 'bundledSummary', class: 'symbolSummary list-unstyled'
|
||||
@div outlet: 'userArea', =>
|
||||
@div outlet: 'userHeader', class: 'symbolHeader'
|
||||
@ul outlet: 'userSummary', class: 'symbolSummary list-unstyled'
|
||||
@div outlet: "status", class: 'status', =>
|
||||
@div outlet: 'coreArea', class: 'symbol-area', =>
|
||||
@div outlet: 'coreHeader', class: 'symbol-header'
|
||||
@ul outlet: 'coreSummary', class: 'symbol-summary list-unstyled'
|
||||
@div outlet: 'bundledArea', class: 'symbol-area', =>
|
||||
@div outlet: 'bundledHeader', class: 'symbol-header'
|
||||
@ul outlet: 'bundledSummary', class: 'symbol-summary list-unstyled'
|
||||
@div outlet: 'userArea', class: 'symbol-area', =>
|
||||
@div outlet: 'userHeader', class: 'symbol-header'
|
||||
@ul outlet: 'userSummary', class: 'symbol-summary list-unstyled'
|
||||
@div outlet: "status", class: 'status alert alert-info', =>
|
||||
@div outlet: "time", class: 'time'
|
||||
@div outlet: "specCount", class: 'spec-count'
|
||||
@div outlet: "message", class: 'message'
|
||||
@@ -46,7 +63,7 @@ class AtomReporter extends View
|
||||
|
||||
reportRunnerStarting: (runner) ->
|
||||
@handleEvents()
|
||||
@startedAt = new Date()
|
||||
@startedAt = Date.now()
|
||||
specs = runner.specs()
|
||||
@totalSpecCount = specs.length
|
||||
@addSpecs(specs)
|
||||
@@ -54,57 +71,29 @@ class AtomReporter extends View
|
||||
|
||||
reportRunnerResults: (runner) ->
|
||||
@updateSpecCounts()
|
||||
if @failedCount == 0
|
||||
@message.text "Success!"
|
||||
@status.addClass('alert-success').removeClass('alert-info') if @failedCount is 0
|
||||
if @failedCount is 1
|
||||
@message.text "#{@failedCount} failure"
|
||||
else
|
||||
@message.text "Game Over"
|
||||
@message.text "#{@failedCount} failures"
|
||||
|
||||
reportSuiteResults: (suite) ->
|
||||
|
||||
reportSpecResults: (spec) ->
|
||||
@completeSpecCount++
|
||||
spec.endedAt = new Date().getTime()
|
||||
spec.endedAt = Date.now()
|
||||
@specComplete(spec)
|
||||
@updateStatusView(spec)
|
||||
|
||||
reportSpecStarting: (spec) ->
|
||||
@specStarted(spec)
|
||||
|
||||
specFilter: (spec) ->
|
||||
globalFocusPriority = jasmine.getEnv().focusPriority
|
||||
parent = spec.parentSuite ? spec.suite
|
||||
|
||||
if !globalFocusPriority
|
||||
true
|
||||
else if spec.focusPriority >= globalFocusPriority
|
||||
true
|
||||
else if not parent
|
||||
false
|
||||
else
|
||||
@specFilter(parent)
|
||||
|
||||
handleEvents: ->
|
||||
$(document).on "mouseover", ".spec-summary", ({currentTarget}) =>
|
||||
element = $(currentTarget)
|
||||
description = element.data("description")
|
||||
return unless description
|
||||
|
||||
clearTimeout @timeoutId if @timeoutId?
|
||||
@specPopup.show()
|
||||
spec = _.find(window.timedSpecs, ({fullName}) -> description is fullName)
|
||||
description = "#{description} #{spec.time}ms" if spec
|
||||
@specPopup.text description
|
||||
{left, top} = element.offset()
|
||||
left += 20
|
||||
top += 20
|
||||
@specPopup.offset({left, top})
|
||||
@timeoutId = setTimeout((=> @specPopup.hide()), 3000)
|
||||
|
||||
$(document).on "click", ".spec-toggle", ({currentTarget}) =>
|
||||
element = $(currentTarget)
|
||||
specFailures = element.parent().find('.spec-failures')
|
||||
specFailures.toggle()
|
||||
if specFailures.is(":visible") then element.text "\uf03d" else element.html "\uf03f"
|
||||
element.toggleClass('folded')
|
||||
false
|
||||
|
||||
updateSpecCounts: ->
|
||||
@@ -116,7 +105,7 @@ class AtomReporter extends View
|
||||
|
||||
updateStatusView: (spec) ->
|
||||
if @failedCount > 0
|
||||
@status.addClass('failed') unless @status.hasClass('failed')
|
||||
@status.addClass('alert-danger').removeClass('alert-info')
|
||||
|
||||
@updateSpecCounts()
|
||||
|
||||
@@ -124,7 +113,7 @@ class AtomReporter extends View
|
||||
rootSuite = rootSuite.parentSuite while rootSuite.parentSuite
|
||||
@message.text rootSuite.description
|
||||
|
||||
time = "#{Math.round((spec.endedAt - @startedAt.getTime()) / 10)}"
|
||||
time = "#{Math.round((spec.endedAt - @startedAt) / 10)}"
|
||||
time = "0#{time}" if time.length < 3
|
||||
@time[0].textContent = "#{time[0...-2]}.#{time[-2..]}s"
|
||||
|
||||
@@ -146,15 +135,22 @@ class AtomReporter extends View
|
||||
@userSummary.append symbol
|
||||
|
||||
if coreSpecs > 0
|
||||
@coreHeader.text("Core Specs (#{coreSpecs}):")
|
||||
@coreHeader.text("Core Specs (#{coreSpecs})")
|
||||
else
|
||||
@coreArea.hide()
|
||||
if bundledPackageSpecs > 0
|
||||
@bundledHeader.text("Bundled Package Specs (#{bundledPackageSpecs}):")
|
||||
@bundledHeader.text("Bundled Package Specs (#{bundledPackageSpecs})")
|
||||
else
|
||||
@bundledArea.hide()
|
||||
if userPackageSpecs > 0
|
||||
@userHeader.text("User Package Specs (#{userPackageSpecs}):")
|
||||
if coreSpecs is 0 and bundledPackageSpecs is 0
|
||||
# Package specs being run, show a more descriptive label
|
||||
{specDirectory} = specs[0]
|
||||
packageFolderName = path.basename(path.dirname(specDirectory))
|
||||
packageName = _.undasherize(_.uncamelcase(packageFolderName))
|
||||
@userHeader.text("#{packageName} Specs")
|
||||
else
|
||||
@userHeader.text("User Package Specs (#{userPackageSpecs})")
|
||||
else
|
||||
@userArea.hide()
|
||||
|
||||
@@ -164,7 +160,7 @@ class AtomReporter extends View
|
||||
specComplete: (spec) ->
|
||||
specSummaryElement = $("#spec-summary-#{spec.id}")
|
||||
specSummaryElement.removeClass('pending')
|
||||
specSummaryElement.data("description", spec.getFullName())
|
||||
specSummaryElement.setTooltip(title: spec.getFullName(), container: '.spec-reporter')
|
||||
|
||||
results = spec.results()
|
||||
if results.skipped
|
||||
@@ -185,11 +181,9 @@ class SuiteResultView extends View
|
||||
@div class: 'suite', =>
|
||||
@div outlet: 'description', class: 'description'
|
||||
|
||||
suite: null
|
||||
|
||||
initialize: (@suite) ->
|
||||
@attr('id', "suite-view-#{@suite.id}")
|
||||
@description.html @suite.description
|
||||
@description.text(@suite.description)
|
||||
|
||||
attach: ->
|
||||
(@parentSuiteView() or $('.results')).append this
|
||||
@@ -206,20 +200,22 @@ class SuiteResultView extends View
|
||||
class SpecResultView extends View
|
||||
@content: ->
|
||||
@div class: 'spec', =>
|
||||
@div "\uf03d", class: 'spec-toggle'
|
||||
@div class: 'spec-toggle'
|
||||
@div outlet: 'description', class: 'description'
|
||||
@div outlet: 'specFailures', class: 'spec-failures'
|
||||
spec: null
|
||||
|
||||
initialize: (@spec) ->
|
||||
@addClass("spec-view-#{@spec.id}")
|
||||
@description.html @spec.description
|
||||
|
||||
description = @spec.description
|
||||
description = "it #{description}" if description.indexOf('it ') isnt 0
|
||||
@description.text(description)
|
||||
|
||||
for result in @spec.results().getItems() when not result.passed()
|
||||
stackTrace = formatStackTrace(result.trace.stack)
|
||||
stackTrace = formatStackTrace(@spec, result.message, result.trace.stack)
|
||||
@specFailures.append $$ ->
|
||||
@div result.message, class: 'resultMessage fail'
|
||||
@div stackTrace, class: 'stackTrace' if stackTrace
|
||||
@div result.message, class: 'result-message fail'
|
||||
@pre stackTrace, class: 'stack-trace padded' if stackTrace
|
||||
|
||||
attach: ->
|
||||
@parentSuiteView().append this
|
||||
|
||||
+226
-150
@@ -1,6 +1,7 @@
|
||||
{$, $$, fs, WorkspaceView} = require 'atom'
|
||||
{$, $$, WorkspaceView} = require 'atom'
|
||||
Exec = require('child_process').exec
|
||||
path = require 'path'
|
||||
Package = require '../src/package'
|
||||
ThemeManager = require '../src/theme-manager'
|
||||
|
||||
describe "the `atom` global", ->
|
||||
@@ -9,35 +10,28 @@ describe "the `atom` global", ->
|
||||
|
||||
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.packages.loadPackage('package-with-activation-events')
|
||||
spyOn(pack, 'activateStylesheets').andCallThrough()
|
||||
expect(pack.mainModule).toBeNull()
|
||||
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 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()
|
||||
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.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()
|
||||
pack = null
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-main').then (p) -> pack = p
|
||||
|
||||
runs ->
|
||||
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", ->
|
||||
@@ -54,44 +48,69 @@ describe "the `atom` global", ->
|
||||
|
||||
describe ".activatePackage(id)", ->
|
||||
describe "atom packages", ->
|
||||
describe "when called multiple times", ->
|
||||
it "it only calls activate on the package once", ->
|
||||
spyOn(Package.prototype, 'activateNow').andCallThrough()
|
||||
atom.packages.activatePackage('package-with-index')
|
||||
atom.packages.activatePackage('package-with-index')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-index')
|
||||
|
||||
runs ->
|
||||
expect(Package.prototype.activateNow.callCount).toBe 1
|
||||
|
||||
describe "when the package has a main module", ->
|
||||
describe "when the metadata specifies a main module path˜", ->
|
||||
it "requires the module at the specified path", ->
|
||||
mainModule = require('./fixtures/packages/package-with-main/main-module')
|
||||
spyOn(mainModule, 'activate')
|
||||
pack = atom.packages.activatePackage('package-with-main')
|
||||
expect(mainModule.activate).toHaveBeenCalled()
|
||||
expect(pack.mainModule).toBe mainModule
|
||||
pack = null
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-main').then (p) -> pack = p
|
||||
|
||||
runs ->
|
||||
expect(mainModule.activate).toHaveBeenCalled()
|
||||
expect(pack.mainModule).toBe mainModule
|
||||
|
||||
describe "when the metadata does not specify a main module", ->
|
||||
it "requires index.coffee", ->
|
||||
indexModule = require('./fixtures/packages/package-with-index/index')
|
||||
spyOn(indexModule, 'activate')
|
||||
pack = atom.packages.activatePackage('package-with-index')
|
||||
expect(indexModule.activate).toHaveBeenCalled()
|
||||
expect(pack.mainModule).toBe indexModule
|
||||
pack = null
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-index').then (p) -> pack = p
|
||||
|
||||
runs ->
|
||||
expect(indexModule.activate).toHaveBeenCalled()
|
||||
expect(pack.mainModule).toBe indexModule
|
||||
|
||||
it "assigns config defaults from the module", ->
|
||||
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
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-config-defaults')
|
||||
|
||||
runs ->
|
||||
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] = []
|
||||
[mainModule, promise] = []
|
||||
|
||||
beforeEach ->
|
||||
mainModule = require './fixtures/packages/package-with-activation-events/index'
|
||||
spyOn(mainModule, 'activate').andCallThrough()
|
||||
AtomPackage = require '../src/atom-package'
|
||||
spyOn(AtomPackage.prototype, 'requireMainModule').andCallThrough()
|
||||
pack = atom.packages.activatePackage('package-with-activation-events')
|
||||
spyOn(Package.prototype, 'requireMainModule').andCallThrough()
|
||||
|
||||
promise = 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()
|
||||
expect(promise.isFulfilled()).not.toBeTruthy()
|
||||
atom.workspaceView.trigger 'activation-event'
|
||||
expect(mainModule.activate).toHaveBeenCalled()
|
||||
|
||||
waitsForPromise ->
|
||||
promise
|
||||
|
||||
it "triggers the activation event on all handlers registered during activation", ->
|
||||
atom.workspaceView.openSync()
|
||||
@@ -116,13 +135,17 @@ describe "the `atom` global", ->
|
||||
expect(console.warn).not.toHaveBeenCalled()
|
||||
|
||||
it "passes the activate method the package's previously serialized state if it exists", ->
|
||||
pack = atom.packages.activatePackage("package-with-serialization")
|
||||
expect(pack.mainModule.someNumber).not.toBe 77
|
||||
pack.mainModule.someNumber = 77
|
||||
atom.packages.deactivatePackage("package-with-serialization")
|
||||
spyOn(pack.mainModule, 'activate').andCallThrough()
|
||||
atom.packages.activatePackage("package-with-serialization")
|
||||
expect(pack.mainModule.activate).toHaveBeenCalledWith({someNumber: 77})
|
||||
pack = null
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-with-serialization").then (p) -> pack = p
|
||||
|
||||
runs ->
|
||||
expect(pack.mainModule.someNumber).not.toBe 77
|
||||
pack.mainModule.someNumber = 77
|
||||
atom.packages.deactivatePackage("package-with-serialization")
|
||||
spyOn(pack.mainModule, 'activate').andCallThrough()
|
||||
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", ->
|
||||
atom.config.set("core.disabledPackages", [])
|
||||
@@ -239,116 +262,155 @@ describe "the `atom` global", ->
|
||||
|
||||
describe "grammar loading", ->
|
||||
it "loads the package's grammars", ->
|
||||
atom.packages.activatePackage('package-with-grammars')
|
||||
expect(atom.syntax.selectGrammar('a.alot').name).toBe 'Alot'
|
||||
expect(atom.syntax.selectGrammar('a.alittle').name).toBe 'Alittle'
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-grammars')
|
||||
|
||||
runs ->
|
||||
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.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(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(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(atom.syntax, 'addProperties').andCallThrough()
|
||||
|
||||
atom.packages.activatePackage('package-with-preferences-tmbundle')
|
||||
|
||||
waitsFor ->
|
||||
atom.syntax.addProperties.callCount > 0
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-with-scoped-properties")
|
||||
|
||||
runs ->
|
||||
expect(atom.syntax.getProperty(['.source.pref'], 'editor.increaseIndentPattern')).toBe '^abc$'
|
||||
expect(atom.syntax.getProperty ['.source.omg'], 'editor.increaseIndentPattern').toBe '^a'
|
||||
|
||||
describe "converted textmate packages", ->
|
||||
it "loads the package's grammars", ->
|
||||
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Null Grammar"
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-ruby')
|
||||
|
||||
runs ->
|
||||
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Ruby"
|
||||
|
||||
it "loads the translated scoped properties", ->
|
||||
expect(atom.syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-ruby')
|
||||
|
||||
runs ->
|
||||
expect(atom.syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBe '# '
|
||||
|
||||
describe ".deactivatePackage(id)", ->
|
||||
describe "atom packages", ->
|
||||
it "calls `deactivate` on the package's main module if activate was successful", ->
|
||||
pack = atom.packages.activatePackage("package-with-deactivate")
|
||||
expect(atom.packages.isPackageActive("package-with-deactivate")).toBeTruthy()
|
||||
spyOn(pack.mainModule, 'deactivate').andCallThrough()
|
||||
pack = null
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-with-deactivate").then (p) -> pack = p
|
||||
|
||||
atom.packages.deactivatePackage("package-with-deactivate")
|
||||
expect(pack.mainModule.deactivate).toHaveBeenCalled()
|
||||
expect(atom.packages.isPackageActive("package-with-module")).toBeFalsy()
|
||||
runs ->
|
||||
expect(atom.packages.isPackageActive("package-with-deactivate")).toBeTruthy()
|
||||
spyOn(pack.mainModule, 'deactivate').andCallThrough()
|
||||
|
||||
spyOn(console, 'warn')
|
||||
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.packages.deactivatePackage("package-with-deactivate")
|
||||
expect(pack.mainModule.deactivate).toHaveBeenCalled()
|
||||
expect(atom.packages.isPackageActive("package-with-module")).toBeFalsy()
|
||||
|
||||
atom.packages.deactivatePackage("package-that-throws-on-activate")
|
||||
expect(badPack.mainModule.deactivate).not.toHaveBeenCalled()
|
||||
expect(atom.packages.isPackageActive("package-that-throws-on-activate")).toBeFalsy()
|
||||
spyOn(console, 'warn')
|
||||
|
||||
badPack = null
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-that-throws-on-activate").then (p) -> badPack = p
|
||||
|
||||
runs ->
|
||||
expect(atom.packages.isPackageActive("package-that-throws-on-activate")).toBeTruthy()
|
||||
spyOn(badPack.mainModule, 'deactivate').andCallThrough()
|
||||
|
||||
atom.packages.deactivatePackage("package-that-throws-on-activate")
|
||||
expect(badPack.mainModule.deactivate).not.toHaveBeenCalled()
|
||||
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.packages.activatePackage("package-that-throws-on-activate")
|
||||
spyOn(badPack.mainModule, 'serialize').andCallThrough()
|
||||
badPack = null
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-that-throws-on-activate").then (p) -> badPack = p
|
||||
|
||||
atom.packages.deactivatePackage("package-that-throws-on-activate")
|
||||
expect(badPack.mainModule.serialize).not.toHaveBeenCalled()
|
||||
runs ->
|
||||
spyOn(badPack.mainModule, 'serialize').andCallThrough()
|
||||
|
||||
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.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()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-serialize-error')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-serialization')
|
||||
|
||||
runs ->
|
||||
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.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'
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-grammars')
|
||||
|
||||
runs ->
|
||||
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.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
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-keymaps')
|
||||
|
||||
runs ->
|
||||
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.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")
|
||||
expect(atom.themes.stylesheetElementForId(one)).not.toExist()
|
||||
expect(atom.themes.stylesheetElementForId(two)).not.toExist()
|
||||
expect(atom.themes.stylesheetElementForId(three)).not.toExist()
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-stylesheets')
|
||||
|
||||
runs ->
|
||||
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")
|
||||
expect(atom.themes.stylesheetElementForId(one)).not.toExist()
|
||||
expect(atom.themes.stylesheetElementForId(two)).not.toExist()
|
||||
expect(atom.themes.stylesheetElementForId(three)).not.toExist()
|
||||
|
||||
it "removes the package's scoped-properties", ->
|
||||
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()
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-with-scoped-properties")
|
||||
|
||||
runs ->
|
||||
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(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"
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-ruby')
|
||||
|
||||
runs ->
|
||||
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.packages.activatePackage('language-ruby', sync: true)
|
||||
atom.packages.deactivatePackage('language-ruby')
|
||||
expect(atom.syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-ruby')
|
||||
|
||||
runs ->
|
||||
atom.packages.deactivatePackage('language-ruby')
|
||||
expect(atom.syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
|
||||
|
||||
describe ".activate()", ->
|
||||
packageActivator = null
|
||||
@@ -382,7 +444,7 @@ describe "the `atom` global", ->
|
||||
themes = themeActivator.mostRecentCall.args[0]
|
||||
expect(['theme']).toContain(theme.getType()) for theme in themes
|
||||
|
||||
describe ".en/disablePackage()", ->
|
||||
describe ".enablePackage() and disablePackage()", ->
|
||||
describe "with packages", ->
|
||||
it ".enablePackage() enables a disabled package", ->
|
||||
packageName = 'package-with-main'
|
||||
@@ -391,28 +453,36 @@ describe "the `atom` global", ->
|
||||
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
|
||||
activatedPackages = null
|
||||
waitsFor ->
|
||||
activatedPackages = atom.packages.getActivePackages()
|
||||
activatedPackages.length > 0
|
||||
|
||||
runs ->
|
||||
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
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage(packageName)
|
||||
|
||||
pack = atom.packages.disablePackage(packageName)
|
||||
runs ->
|
||||
atom.packages.observeDisabledPackages()
|
||||
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
|
||||
|
||||
activatedPackages = atom.packages.getActivePackages()
|
||||
expect(activatedPackages).not.toContain(pack)
|
||||
expect(atom.config.get('core.disabledPackages')).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()
|
||||
waitsForPromise ->
|
||||
atom.themes.activateThemes()
|
||||
|
||||
afterEach ->
|
||||
atom.themes.deactivateThemes()
|
||||
@@ -426,18 +496,24 @@ describe "the `atom` global", ->
|
||||
|
||||
# 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
|
||||
activatedPackages = null
|
||||
waitsFor ->
|
||||
activatedPackages = atom.packages.getActivePackages()
|
||||
activatedPackages.length > 0
|
||||
|
||||
runs ->
|
||||
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
|
||||
|
||||
describe ".isReleasedVersion()", ->
|
||||
it "returns false if the version is a SHA and true otherwise", ->
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
describe "Clipboard", ->
|
||||
describe "write(text, metadata) and read()", ->
|
||||
it "writes and reads text to/from the native clipboard", ->
|
||||
expect(atom.clipboard.read()).toBe 'initial clipboard content'
|
||||
atom.clipboard.write('next')
|
||||
expect(atom.clipboard.read()).toBe 'next'
|
||||
|
||||
it "returns metadata if the item on the native clipboard matches the last written item", ->
|
||||
atom.clipboard.write('next', {meta: 'data'})
|
||||
expect(atom.clipboard.read()).toBe 'next'
|
||||
expect(atom.clipboard.readWithMetadata().text).toBe 'next'
|
||||
expect(atom.clipboard.readWithMetadata().metadata).toEqual {meta: 'data'}
|
||||
@@ -1,5 +1,5 @@
|
||||
{fs} = require 'atom'
|
||||
path = require 'path'
|
||||
fs = require 'fs-plus'
|
||||
temp = require 'temp'
|
||||
installer = require '../src/command-installer'
|
||||
|
||||
@@ -10,17 +10,17 @@ describe "install(commandPath, callback)", ->
|
||||
installationFilePath = path.join(installationPath, commandName)
|
||||
|
||||
beforeEach ->
|
||||
fs.chmodSync(commandFilePath, '755')
|
||||
spyOn(installer, 'getInstallDirectory').andReturn installationPath
|
||||
|
||||
describe "on #darwin", ->
|
||||
it "symlinks the command and makes it executable", ->
|
||||
expect(fs.isFileSync(commandFilePath)).toBeTruthy()
|
||||
expect(fs.isExecutableSync(commandFilePath)).toBeFalsy()
|
||||
expect(fs.isFileSync(installationFilePath)).toBeFalsy()
|
||||
|
||||
installDone = false
|
||||
installError = null
|
||||
installer.install commandFilePath, (error) ->
|
||||
installer.install commandFilePath, false, (error) ->
|
||||
installDone = true
|
||||
installError = error
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{fs} = require 'atom'
|
||||
path = require 'path'
|
||||
temp = require 'temp'
|
||||
CSON = require 'season'
|
||||
fs = require 'fs-plus'
|
||||
|
||||
describe "Config", ->
|
||||
dotAtomPath = path.join(temp.dir, 'dot-atom-dir')
|
||||
@@ -63,6 +63,19 @@ describe "Config", ->
|
||||
atom.config.toggle('foo.a')
|
||||
expect(atom.config.get('foo.a')).toBe false
|
||||
|
||||
describe ".restoreDefault(keyPath)", ->
|
||||
it "sets the value of the key path to its default", ->
|
||||
atom.config.setDefaults('a', b: 3)
|
||||
atom.config.set('a.b', 4)
|
||||
expect(atom.config.get('a.b')).toBe 4
|
||||
atom.config.restoreDefault('a.b')
|
||||
expect(atom.config.get('a.b')).toBe 3
|
||||
|
||||
atom.config.set('a.c', 5)
|
||||
expect(atom.config.get('a.c')).toBe 5
|
||||
atom.config.restoreDefault('a.c')
|
||||
expect(atom.config.get('a.c')).toBeUndefined()
|
||||
|
||||
describe ".pushAtKeyPath(keyPath, value)", ->
|
||||
it "pushes the given value to the array at the key path and updates observers", ->
|
||||
atom.config.set("foo.bar.baz", ["a"])
|
||||
@@ -204,7 +217,7 @@ describe "Config", ->
|
||||
expect(fs.existsSync(atom.config.configDirPath)).toBeFalsy()
|
||||
|
||||
afterEach ->
|
||||
fs.removeSync(dotAtomPath) if fs.existsSync(dotAtomPath)
|
||||
fs.removeSync(dotAtomPath)
|
||||
|
||||
describe "when the configDirPath doesn't exist", ->
|
||||
it "copies the contents of dot-atom to ~/.atom", ->
|
||||
@@ -220,6 +233,8 @@ describe "Config", ->
|
||||
expect(fs.existsSync(path.join(atom.config.configDirPath, 'packages'))).toBeTruthy()
|
||||
expect(fs.isFileSync(path.join(atom.config.configDirPath, 'snippets.cson'))).toBeTruthy()
|
||||
expect(fs.isFileSync(path.join(atom.config.configDirPath, 'config.cson'))).toBeTruthy()
|
||||
expect(fs.isFileSync(path.join(atom.config.configDirPath, 'init.coffee'))).toBeTruthy()
|
||||
expect(fs.isFileSync(path.join(atom.config.configDirPath, 'styles.less'))).toBeTruthy()
|
||||
|
||||
describe ".loadUserConfig()", ->
|
||||
beforeEach ->
|
||||
@@ -228,7 +243,7 @@ describe "Config", ->
|
||||
expect(fs.existsSync(atom.config.configDirPath)).toBeFalsy()
|
||||
|
||||
afterEach ->
|
||||
fs.removeSync(dotAtomPath) if fs.existsSync(dotAtomPath)
|
||||
fs.removeSync(dotAtomPath)
|
||||
|
||||
describe "when the config file contains valid cson", ->
|
||||
beforeEach ->
|
||||
@@ -271,7 +286,7 @@ describe "Config", ->
|
||||
|
||||
afterEach ->
|
||||
atom.config.unobserveUserConfig()
|
||||
fs.removeSync(dotAtomPath) if fs.existsSync(dotAtomPath)
|
||||
fs.removeSync(dotAtomPath)
|
||||
|
||||
describe "when the config file changes to contain valid cson", ->
|
||||
it "updates the config data", ->
|
||||
|
||||
@@ -1,138 +0,0 @@
|
||||
Directory = require '../src/directory'
|
||||
{fs} = require 'atom'
|
||||
path = require 'path'
|
||||
|
||||
describe "Directory", ->
|
||||
directory = null
|
||||
|
||||
beforeEach ->
|
||||
directory = new Directory(path.join(__dirname, 'fixtures'))
|
||||
|
||||
afterEach ->
|
||||
directory.off()
|
||||
|
||||
describe "when the contents of the directory change on disk", ->
|
||||
temporaryFilePath = null
|
||||
|
||||
beforeEach ->
|
||||
temporaryFilePath = path.join(__dirname, 'fixtures', 'temporary')
|
||||
fs.removeSync(temporaryFilePath) if fs.existsSync(temporaryFilePath)
|
||||
|
||||
afterEach ->
|
||||
fs.removeSync(temporaryFilePath) if fs.existsSync(temporaryFilePath)
|
||||
|
||||
it "triggers 'contents-changed' event handlers", ->
|
||||
changeHandler = null
|
||||
|
||||
runs ->
|
||||
changeHandler = jasmine.createSpy('changeHandler')
|
||||
directory.on 'contents-changed', changeHandler
|
||||
fs.writeFileSync(temporaryFilePath, '')
|
||||
|
||||
waitsFor "first change", -> changeHandler.callCount > 0
|
||||
|
||||
runs ->
|
||||
changeHandler.reset()
|
||||
fs.removeSync(temporaryFilePath)
|
||||
|
||||
waitsFor "second change", -> changeHandler.callCount > 0
|
||||
|
||||
describe "when the directory unsubscribes from events", ->
|
||||
temporaryFilePath = null
|
||||
|
||||
beforeEach ->
|
||||
temporaryFilePath = path.join(directory.path, 'temporary')
|
||||
fs.removeSync(temporaryFilePath) if fs.existsSync(temporaryFilePath)
|
||||
|
||||
afterEach ->
|
||||
fs.removeSync(temporaryFilePath) if fs.existsSync(temporaryFilePath)
|
||||
|
||||
it "no longer triggers events", ->
|
||||
changeHandler = null
|
||||
|
||||
runs ->
|
||||
changeHandler = jasmine.createSpy('changeHandler')
|
||||
directory.on 'contents-changed', changeHandler
|
||||
fs.writeFileSync(temporaryFilePath, '')
|
||||
|
||||
waitsFor "change event", -> changeHandler.callCount > 0
|
||||
|
||||
runs ->
|
||||
changeHandler.reset()
|
||||
directory.off()
|
||||
waits 20
|
||||
|
||||
runs -> fs.removeSync(temporaryFilePath)
|
||||
waits 20
|
||||
runs -> expect(changeHandler.callCount).toBe 0
|
||||
|
||||
describe "on #darwin or #linux", ->
|
||||
it "includes symlink information about entries", ->
|
||||
entries = directory.getEntriesSync()
|
||||
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()
|
||||
|
||||
callback = jasmine.createSpy('getEntries')
|
||||
directory.getEntries(callback)
|
||||
|
||||
waitsFor -> callback.callCount is 1
|
||||
|
||||
runs ->
|
||||
entries = callback.mostRecentCall.args[1]
|
||||
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)", ->
|
||||
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 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", ->
|
||||
absolutePath = directory.getPath()
|
||||
expect(directory.contains(path.join(absolutePath, "b"))).toBe true
|
||||
expect(directory.contains(path.join(absolutePath, "b", "file.coffee"))).toBe true
|
||||
expect(directory.contains(path.join(absolutePath, "file.coffee"))).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
|
||||
@@ -1,16 +1,19 @@
|
||||
DisplayBuffer = require '../src/display-buffer'
|
||||
{_} = require 'atom'
|
||||
_ = require 'underscore-plus'
|
||||
|
||||
describe "DisplayBuffer", ->
|
||||
[displayBuffer, buffer, changeHandler, tabLength] = []
|
||||
beforeEach ->
|
||||
tabLength = 2
|
||||
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
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-javascript')
|
||||
|
||||
afterEach ->
|
||||
displayBuffer.destroy()
|
||||
buffer.release()
|
||||
|
||||
+42
-27
@@ -16,11 +16,13 @@ describe "Editor", ->
|
||||
|
||||
describe "with default options", ->
|
||||
beforeEach ->
|
||||
atom.packages.activatePackage('language-javascript', sync: true)
|
||||
editor = atom.project.openSync('sample.js', autoIndent: false)
|
||||
buffer = editor.buffer
|
||||
lineLengths = buffer.getLines().map (line) -> line.length
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-javascript')
|
||||
|
||||
describe "when the editor is deserialized", ->
|
||||
it "restores selections and folds based on markers in the buffer", ->
|
||||
editor.setSelectedBufferRange([[1, 2], [3, 4]])
|
||||
@@ -1856,12 +1858,12 @@ describe "Editor", ->
|
||||
expect(editor.getCursorBufferPosition()).toEqual [0, 2]
|
||||
expect(editor.getCursorScreenPosition()).toEqual [0, editor.getTabLength() * 2]
|
||||
|
||||
describe "pasteboard operations", ->
|
||||
describe "clipboard operations", ->
|
||||
beforeEach ->
|
||||
editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[1, 6], [1, 10]]])
|
||||
|
||||
describe ".cutSelectedText()", ->
|
||||
it "removes the selected text from the buffer and places it on the pasteboard", ->
|
||||
it "removes the selected text from the buffer and places it on the clipboard", ->
|
||||
editor.cutSelectedText()
|
||||
expect(buffer.lineForRow(0)).toBe "var = function () {"
|
||||
expect(buffer.lineForRow(1)).toBe " var = function(items) {"
|
||||
@@ -1885,7 +1887,7 @@ describe "Editor", ->
|
||||
editor.cutToEndOfLine()
|
||||
expect(buffer.lineForRow(2)).toBe ' if (items.length'
|
||||
expect(buffer.lineForRow(3)).toBe ' var pivot = item'
|
||||
expect(atom.pasteboard.read()[0]).toBe ' <= 1) return items;\ns.shift(), current, left = [], right = [];'
|
||||
expect(atom.clipboard.read()).toBe ' <= 1) return items;\ns.shift(), current, left = [], right = [];'
|
||||
|
||||
describe "when text is selected", ->
|
||||
it "only cuts the selected text, not to the end of the line", ->
|
||||
@@ -1895,7 +1897,7 @@ describe "Editor", ->
|
||||
|
||||
expect(buffer.lineForRow(2)).toBe ' if (items.lengthurn items;'
|
||||
expect(buffer.lineForRow(3)).toBe ' var pivot = item'
|
||||
expect(atom.pasteboard.read()[0]).toBe ' <= 1) ret\ns.shift(), current, left = [], right = [];'
|
||||
expect(atom.clipboard.read()).toBe ' <= 1) ret\ns.shift(), current, left = [], right = [];'
|
||||
|
||||
describe ".copySelectedText()", ->
|
||||
it "copies selected text onto the clipboard", ->
|
||||
@@ -1906,7 +1908,7 @@ describe "Editor", ->
|
||||
|
||||
describe ".pasteText()", ->
|
||||
it "pastes text into the buffer", ->
|
||||
atom.pasteboard.write('first')
|
||||
atom.clipboard.write('first')
|
||||
editor.pasteText()
|
||||
expect(editor.buffer.lineForRow(0)).toBe "var first = function () {"
|
||||
expect(buffer.lineForRow(1)).toBe " var first = function(items) {"
|
||||
@@ -2733,19 +2735,26 @@ describe "Editor", ->
|
||||
|
||||
describe "when the editor's grammar has an injection selector", ->
|
||||
beforeEach ->
|
||||
atom.packages.activatePackage('language-text', sync: true)
|
||||
atom.packages.activatePackage('language-javascript', sync: true)
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-text')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-javascript')
|
||||
|
||||
it "includes the grammar's patterns when the selector matches the current scope in other grammars", ->
|
||||
atom.packages.activatePackage('language-hyperlink', sync: true)
|
||||
grammar = atom.syntax.selectGrammar("text.js")
|
||||
{tokens} = grammar.tokenizeLine("var i; // http://github.com")
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-hyperlink')
|
||||
|
||||
expect(tokens[0].value).toBe "var"
|
||||
expect(tokens[0].scopes).toEqual ["source.js", "storage.modifier.js"]
|
||||
runs ->
|
||||
grammar = atom.syntax.selectGrammar("text.js")
|
||||
{tokens} = grammar.tokenizeLine("var i; // http://github.com")
|
||||
|
||||
expect(tokens[6].value).toBe "http://github.com"
|
||||
expect(tokens[6].scopes).toEqual ["source.js", "comment.line.double-slash.js", "markup.underline.link.http.hyperlink"]
|
||||
expect(tokens[0].value).toBe "var"
|
||||
expect(tokens[0].scopes).toEqual ["source.js", "storage.modifier.js"]
|
||||
|
||||
expect(tokens[6].value).toBe "http://github.com"
|
||||
expect(tokens[6].scopes).toEqual ["source.js", "comment.line.double-slash.js", "markup.underline.link.http.hyperlink"]
|
||||
|
||||
describe "when the grammar is added", ->
|
||||
it "retokenizes existing buffers that contain tokens that match the injection selector", ->
|
||||
@@ -2756,11 +2765,13 @@ describe "Editor", ->
|
||||
expect(tokens[1].value).toBe " http://github.com"
|
||||
expect(tokens[1].scopes).toEqual ["source.js", "comment.line.double-slash.js"]
|
||||
|
||||
atom.packages.activatePackage('language-hyperlink', sync: true)
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-hyperlink')
|
||||
|
||||
{tokens} = editor.lineForScreenRow(0)
|
||||
expect(tokens[2].value).toBe "http://github.com"
|
||||
expect(tokens[2].scopes).toEqual ["source.js", "comment.line.double-slash.js", "markup.underline.link.http.hyperlink"]
|
||||
runs ->
|
||||
{tokens} = editor.lineForScreenRow(0)
|
||||
expect(tokens[2].value).toBe "http://github.com"
|
||||
expect(tokens[2].scopes).toEqual ["source.js", "comment.line.double-slash.js", "markup.underline.link.http.hyperlink"]
|
||||
|
||||
describe "when the grammar is updated", ->
|
||||
it "retokenizes existing buffers that contain tokens that match the injection selector", ->
|
||||
@@ -2771,14 +2782,18 @@ describe "Editor", ->
|
||||
expect(tokens[1].value).toBe " SELECT * FROM OCTOCATS"
|
||||
expect(tokens[1].scopes).toEqual ["source.js", "comment.line.double-slash.js"]
|
||||
|
||||
atom.packages.activatePackage('package-with-injection-selector', sync: true)
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-injection-selector')
|
||||
|
||||
{tokens} = editor.lineForScreenRow(0)
|
||||
expect(tokens[1].value).toBe " SELECT * FROM OCTOCATS"
|
||||
expect(tokens[1].scopes).toEqual ["source.js", "comment.line.double-slash.js"]
|
||||
runs ->
|
||||
{tokens} = editor.lineForScreenRow(0)
|
||||
expect(tokens[1].value).toBe " SELECT * FROM OCTOCATS"
|
||||
expect(tokens[1].scopes).toEqual ["source.js", "comment.line.double-slash.js"]
|
||||
|
||||
atom.packages.activatePackage('language-sql', sync: true)
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-sql')
|
||||
|
||||
{tokens} = editor.lineForScreenRow(0)
|
||||
expect(tokens[2].value).toBe "SELECT"
|
||||
expect(tokens[2].scopes).toEqual ["source.js", "comment.line.double-slash.js", "keyword.other.DML.sql"]
|
||||
runs ->
|
||||
{tokens} = editor.lineForScreenRow(0)
|
||||
expect(tokens[2].value).toBe "SELECT"
|
||||
expect(tokens[2].scopes).toEqual ["source.js", "comment.line.double-slash.js", "keyword.other.DML.sql"]
|
||||
|
||||
@@ -10,8 +10,6 @@ describe "EditorView", ->
|
||||
[buffer, editorView, editor, cachedLineHeight, cachedCharWidth] = []
|
||||
|
||||
beforeEach ->
|
||||
atom.packages.activatePackage('language-text', sync: true)
|
||||
atom.packages.activatePackage('language-javascript', sync: true)
|
||||
editor = atom.project.openSync('sample.js')
|
||||
buffer = editor.buffer
|
||||
editorView = new EditorView(editor)
|
||||
@@ -26,6 +24,12 @@ describe "EditorView", ->
|
||||
@width(getCharWidth() * widthInChars) if widthInChars
|
||||
$('#jasmine-content').append(this)
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-text', sync: true)
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-javascript', sync: true)
|
||||
|
||||
getLineHeight = ->
|
||||
return cachedLineHeight if cachedLineHeight?
|
||||
calcDimensions()
|
||||
@@ -2515,9 +2519,9 @@ describe "EditorView", ->
|
||||
expect(edited).toBe false
|
||||
|
||||
describe "when editor:copy-path is triggered", ->
|
||||
it "copies the absolute path to the editor view's file to the pasteboard", ->
|
||||
it "copies the absolute path to the editor view's file to the clipboard", ->
|
||||
editorView.trigger 'editor:copy-path'
|
||||
expect(atom.pasteboard.read()[0]).toBe editor.getPath()
|
||||
expect(atom.clipboard.read()).toBe editor.getPath()
|
||||
|
||||
describe "when editor:move-line-up is triggered", ->
|
||||
describe "when there is no selection", ->
|
||||
@@ -2532,6 +2536,52 @@ describe "EditorView", ->
|
||||
editorView.trigger 'editor:move-line-up'
|
||||
expect(editor.getCursorBufferPosition()).toEqual [0,2]
|
||||
|
||||
describe "when the line above is folded", ->
|
||||
it "moves the line around the fold", ->
|
||||
editor.foldBufferRow(1)
|
||||
editor.setCursorBufferPosition([10, 0])
|
||||
editorView.trigger 'editor:move-line-up'
|
||||
|
||||
expect(editor.getCursorBufferPosition()).toEqual [1, 0]
|
||||
expect(buffer.lineForRow(1)).toBe ''
|
||||
expect(buffer.lineForRow(2)).toBe ' var sort = function(items) {'
|
||||
expect(editor.isFoldedAtBufferRow(1)).toBe false
|
||||
expect(editor.isFoldedAtBufferRow(2)).toBe true
|
||||
|
||||
describe "when the line being moved is folded", ->
|
||||
it "moves the fold around the fold above it", ->
|
||||
editor.setCursorBufferPosition([0, 0])
|
||||
editor.insertText """
|
||||
var a = function() {
|
||||
b = 3;
|
||||
};
|
||||
|
||||
"""
|
||||
editor.foldBufferRow(0)
|
||||
editor.foldBufferRow(3)
|
||||
editor.setCursorBufferPosition([3, 0])
|
||||
editorView.trigger 'editor:move-line-up'
|
||||
|
||||
expect(editor.getCursorBufferPosition()).toEqual [0, 0]
|
||||
expect(buffer.lineForRow(0)).toBe 'var quicksort = function () {'
|
||||
expect(buffer.lineForRow(13)).toBe 'var a = function() {'
|
||||
editor.logScreenLines()
|
||||
expect(editor.isFoldedAtBufferRow(0)).toBe true
|
||||
expect(editor.isFoldedAtBufferRow(13)).toBe true
|
||||
|
||||
describe "when the line above is empty and the line above that is folded", ->
|
||||
it "moves the line to the empty line", ->
|
||||
editor.foldBufferRow(2)
|
||||
editor.setCursorBufferPosition([11, 0])
|
||||
editorView.trigger 'editor:move-line-up'
|
||||
|
||||
expect(editor.getCursorBufferPosition()).toEqual [10, 0]
|
||||
expect(buffer.lineForRow(9)).toBe ' };'
|
||||
expect(buffer.lineForRow(10)).toBe ' return sort(Array.apply(this, arguments));'
|
||||
expect(buffer.lineForRow(11)).toBe ''
|
||||
expect(editor.isFoldedAtBufferRow(2)).toBe true
|
||||
expect(editor.isFoldedAtBufferRow(10)).toBe false
|
||||
|
||||
describe "where there is a selection", ->
|
||||
describe "when the selection falls inside the line", ->
|
||||
it "maintains the selection", ->
|
||||
@@ -2631,6 +2681,54 @@ describe "EditorView", ->
|
||||
editorView.trigger 'editor:move-line-down'
|
||||
expect(editor.getCursorBufferPosition()).toEqual [1, 2]
|
||||
|
||||
describe "when the line below is folded", ->
|
||||
it "moves the line around the fold", ->
|
||||
editor.setCursorBufferPosition([0, 0])
|
||||
editor.foldBufferRow(1)
|
||||
editorView.trigger 'editor:move-line-down'
|
||||
|
||||
expect(editor.getCursorBufferPosition()).toEqual [9, 0]
|
||||
expect(buffer.lineForRow(0)).toBe ' var sort = function(items) {'
|
||||
expect(buffer.lineForRow(9)).toBe 'var quicksort = function () {'
|
||||
expect(editor.isFoldedAtBufferRow(0)).toBe true
|
||||
expect(editor.isFoldedAtBufferRow(9)).toBe false
|
||||
|
||||
describe "when the line being moved is folded", ->
|
||||
it "moves the fold around the fold below it", ->
|
||||
editor.setCursorBufferPosition([0, 0])
|
||||
editor.insertText """
|
||||
var a = function() {
|
||||
b = 3;
|
||||
};
|
||||
|
||||
"""
|
||||
editor.foldBufferRow(0)
|
||||
editor.foldBufferRow(3)
|
||||
editor.setCursorBufferPosition([0, 0])
|
||||
editorView.trigger 'editor:move-line-down'
|
||||
|
||||
expect(editor.getCursorBufferPosition()).toEqual [13, 0]
|
||||
expect(buffer.lineForRow(0)).toBe 'var quicksort = function () {'
|
||||
expect(buffer.lineForRow(13)).toBe 'var a = function() {'
|
||||
expect(editor.isFoldedAtBufferRow(0)).toBe true
|
||||
expect(editor.isFoldedAtBufferRow(13)).toBe true
|
||||
|
||||
describe "when the line below is empty and the line below that is folded", ->
|
||||
it "moves the line to the empty line", ->
|
||||
editor.setCursorBufferPosition([0, Infinity])
|
||||
editor.insertText('\n')
|
||||
editor.setCursorBufferPosition([0, 0])
|
||||
editor.foldBufferRow(2)
|
||||
editorView.trigger 'editor:move-line-down'
|
||||
|
||||
expect(editor.getCursorBufferPosition()).toEqual [1, 0]
|
||||
expect(buffer.lineForRow(0)).toBe ''
|
||||
expect(buffer.lineForRow(1)).toBe 'var quicksort = function () {'
|
||||
expect(buffer.lineForRow(2)).toBe ' var sort = function(items) {'
|
||||
expect(editor.isFoldedAtBufferRow(0)).toBe false
|
||||
expect(editor.isFoldedAtBufferRow(1)).toBe false
|
||||
expect(editor.isFoldedAtBufferRow(2)).toBe true
|
||||
|
||||
describe "when the cursor is on the last line", ->
|
||||
it "does not move the line", ->
|
||||
editor.moveCursorToBottom()
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
{File, fs} = require 'atom'
|
||||
path = require 'path'
|
||||
|
||||
describe 'File', ->
|
||||
[filePath, 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.removeSync(filePath) if fs.existsSync(filePath)
|
||||
fs.writeFileSync(filePath, "this is old!")
|
||||
file = new File(filePath)
|
||||
|
||||
afterEach ->
|
||||
file.off()
|
||||
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.writeFileSync(file.getPath(), "this is new!")
|
||||
|
||||
waitsFor "change event", ->
|
||||
changeHandler.callCount > 0
|
||||
|
||||
describe "when the file has already been read", ->
|
||||
beforeEach ->
|
||||
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.writeFileSync(file.getPath(), "this is new!")
|
||||
|
||||
waitsFor "change event", ->
|
||||
changeHandler.callCount > 0
|
||||
|
||||
runs ->
|
||||
changeHandler.reset()
|
||||
fs.writeFileSync(file.getPath(), "this is newer!")
|
||||
|
||||
waitsFor "second change event", ->
|
||||
changeHandler.callCount > 0
|
||||
|
||||
describe "when the file is removed", ->
|
||||
it "triggers 'remove' event handlers", ->
|
||||
removeHandler = null
|
||||
removeHandler = jasmine.createSpy('removeHandler')
|
||||
file.on 'removed', removeHandler
|
||||
fs.removeSync(file.getPath())
|
||||
|
||||
waitsFor "remove event", ->
|
||||
removeHandler.callCount > 0
|
||||
|
||||
describe "when a file is moved (via the filesystem)", ->
|
||||
newPath = null
|
||||
|
||||
beforeEach ->
|
||||
newPath = path.join(path.dirname(filePath), "atom-file-was-moved-test.txt")
|
||||
|
||||
afterEach ->
|
||||
if fs.existsSync(newPath)
|
||||
fs.removeSync(newPath)
|
||||
waitsFor "remove event", 30000, (done) -> file.on 'removed', done
|
||||
|
||||
it "it updates its path", ->
|
||||
jasmine.unspy(window, "setTimeout")
|
||||
moveHandler = null
|
||||
moveHandler = jasmine.createSpy('moveHandler')
|
||||
file.on 'moved', moveHandler
|
||||
|
||||
fs.moveSync(filePath, newPath)
|
||||
|
||||
waitsFor "move event", 30000, ->
|
||||
moveHandler.callCount > 0
|
||||
|
||||
runs ->
|
||||
expect(file.getPath()).toBe newPath
|
||||
|
||||
it "maintains 'contents-changed' events set on previous path", ->
|
||||
jasmine.unspy(window, "setTimeout")
|
||||
moveHandler = null
|
||||
moveHandler = jasmine.createSpy('moveHandler')
|
||||
file.on 'moved', moveHandler
|
||||
changeHandler = null
|
||||
changeHandler = jasmine.createSpy('changeHandler')
|
||||
file.on 'contents-changed', changeHandler
|
||||
|
||||
fs.moveSync(filePath, newPath)
|
||||
|
||||
waitsFor "move event", ->
|
||||
moveHandler.callCount > 0
|
||||
|
||||
runs ->
|
||||
expect(changeHandler).not.toHaveBeenCalled()
|
||||
fs.writeFileSync(file.getPath(), "this is new!")
|
||||
|
||||
waitsFor "change event", ->
|
||||
changeHandler.callCount > 0
|
||||
|
||||
describe "when a file is deleted and the recreated within a small amount of time (git sometimes does this)", ->
|
||||
it "triggers a contents change event if the contents change", ->
|
||||
jasmine.unspy(File.prototype, 'detectResurrectionAfterDelay')
|
||||
jasmine.unspy(window, "setTimeout")
|
||||
|
||||
changeHandler = jasmine.createSpy("file changed")
|
||||
removeHandler = jasmine.createSpy("file removed")
|
||||
file.on 'contents-changed', changeHandler
|
||||
file.on 'removed', removeHandler
|
||||
|
||||
expect(changeHandler).not.toHaveBeenCalled()
|
||||
|
||||
fs.removeSync(filePath)
|
||||
|
||||
expect(changeHandler).not.toHaveBeenCalled()
|
||||
waits 20
|
||||
runs ->
|
||||
fs.writeFileSync(filePath, "HE HAS RISEN!")
|
||||
expect(changeHandler).not.toHaveBeenCalled()
|
||||
|
||||
waitsFor "resurrection change event", ->
|
||||
changeHandler.callCount == 1
|
||||
|
||||
runs ->
|
||||
expect(removeHandler).not.toHaveBeenCalled()
|
||||
fs.writeFileSync(filePath, "Hallelujah!")
|
||||
changeHandler.reset()
|
||||
|
||||
waitsFor "post-resurrection change event", ->
|
||||
changeHandler.callCount > 0
|
||||
@@ -1,2 +1 @@
|
||||
'activationEvents': ['activation-event']
|
||||
'deferredDeserializers': ['Foo']
|
||||
|
||||
-1
@@ -1 +0,0 @@
|
||||
I am hidden so I shouldn't be loaded
|
||||
-1
@@ -1 +0,0 @@
|
||||
I am not a valid plist but that shouldn't cause a crisis
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"name": "my preferences",
|
||||
"scope": "source.pref",
|
||||
"settings": {
|
||||
"increaseIndentPattern": "^abc$"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1 @@
|
||||
# This package loads async, otherwise it would log errors when it
|
||||
# is automatically serialized when workspaceView is deactivatated
|
||||
|
||||
'main': 'index.coffee'
|
||||
'activationEvents': ['activation-event']
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"theme": true
|
||||
"theme": "ui"
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"theme": true
|
||||
"theme": "ui"
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"theme": true
|
||||
"theme": "ui"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"theme": true,
|
||||
"theme": "ui",
|
||||
"stylesheets": ["first.css", "second.less", "last.css"]
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"theme": true,
|
||||
"theme": "ui",
|
||||
"stylesheets": ["editor.less"]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
temp = require 'temp'
|
||||
Git = require '../src/git'
|
||||
{fs} = require 'atom'
|
||||
fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
Task = require '../src/task'
|
||||
|
||||
|
||||
@@ -21,10 +21,6 @@ module.exports.runSpecSuite = (specSuite, logFile, logErrors=true) ->
|
||||
print: (str) ->
|
||||
log(str)
|
||||
onComplete: (runner) ->
|
||||
log('\n')
|
||||
timeReporter.logLongestSuites 10, (line) -> log("#{line}\n")
|
||||
log('\n')
|
||||
timeReporter.logLongestSpecs 10, (line) -> log("#{line}\n")
|
||||
fs.closeSync(logStream) if logStream?
|
||||
atom.exit(runner.results().failedCount > 0 ? 1 : 0)
|
||||
else
|
||||
|
||||
@@ -399,3 +399,32 @@ describe "Keymap", ->
|
||||
runs ->
|
||||
keyBinding = keymap.keyBindingsForKeystroke('ctrl-l')[0]
|
||||
expect(keyBinding).toBeUndefined()
|
||||
|
||||
it "logs a warning when it can't be parsed", ->
|
||||
keymapFilePath = path.join(configDirPath, "keymap.json")
|
||||
fs.writeFileSync(keymapFilePath, '')
|
||||
keymap.loadUserKeymap()
|
||||
|
||||
spyOn(keymap, 'loadUserKeymap').andCallThrough()
|
||||
fs.writeFileSync(keymapFilePath, '}{')
|
||||
spyOn(console, 'warn')
|
||||
|
||||
waitsFor ->
|
||||
keymap.loadUserKeymap.callCount > 0
|
||||
|
||||
runs ->
|
||||
expect(console.warn.callCount).toBe 1
|
||||
expect(console.warn.argsForCall[0][0].length).toBeGreaterThan 0
|
||||
|
||||
describe "when adding a binding with an invalid selector", ->
|
||||
it "logs a warning and does not add it", ->
|
||||
spyOn(console, 'warn')
|
||||
keybinding =
|
||||
'##selector':
|
||||
'cmd-a': 'invalid-command'
|
||||
keymap.add('test', keybinding)
|
||||
|
||||
expect(console.warn.callCount).toBe 1
|
||||
expect(console.warn.argsForCall[0][0].length).toBeGreaterThan 0
|
||||
expect(-> keymap.keyBindingsMatchingElement(document.body)).not.toThrow()
|
||||
expect(keymap.keyBindingsForCommand('invalid:command')).toEqual []
|
||||
|
||||
@@ -6,10 +6,12 @@ describe "LanguageMode", ->
|
||||
|
||||
describe "javascript", ->
|
||||
beforeEach ->
|
||||
atom.packages.activatePackage('language-javascript', sync: true)
|
||||
editor = atom.project.openSync('sample.js', autoIndent: false)
|
||||
{buffer, languageMode} = editor
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-javascript')
|
||||
|
||||
describe ".minIndentLevelForRowRange(startRow, endRow)", ->
|
||||
it "returns the minimum indent level for the given row range", ->
|
||||
expect(languageMode.minIndentLevelForRowRange(4, 7)).toBe 2
|
||||
@@ -100,10 +102,12 @@ describe "LanguageMode", ->
|
||||
|
||||
describe "coffeescript", ->
|
||||
beforeEach ->
|
||||
atom.packages.activatePackage('language-coffee-script', sync: true)
|
||||
editor = atom.project.openSync('coffee.coffee', autoIndent: false)
|
||||
{buffer, languageMode} = editor
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-coffee-script')
|
||||
|
||||
describe ".toggleLineCommentsForBufferRows(start, end)", ->
|
||||
it "comments/uncomments lines in the given range", ->
|
||||
languageMode.toggleLineCommentsForBufferRows(4, 6)
|
||||
@@ -147,10 +151,12 @@ describe "LanguageMode", ->
|
||||
|
||||
describe "css", ->
|
||||
beforeEach ->
|
||||
atom.packages.activatePackage('language-css', sync: true)
|
||||
editor = atom.project.openSync('css.css', autoIndent: false)
|
||||
{buffer, languageMode} = editor
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-css')
|
||||
|
||||
describe ".toggleLineCommentsForBufferRows(start, end)", ->
|
||||
it "comments/uncomments lines in the given range", ->
|
||||
languageMode.toggleLineCommentsForBufferRows(0, 1)
|
||||
@@ -188,11 +194,15 @@ describe "LanguageMode", ->
|
||||
|
||||
describe "less", ->
|
||||
beforeEach ->
|
||||
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
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-less')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-css')
|
||||
|
||||
describe "when commenting lines", ->
|
||||
it "only uses the `commentEnd` pattern if it comes from the same grammar as the `commentStart`", ->
|
||||
languageMode.toggleLineCommentsForBufferRows(0, 0)
|
||||
@@ -200,10 +210,12 @@ describe "LanguageMode", ->
|
||||
|
||||
describe "folding", ->
|
||||
beforeEach ->
|
||||
atom.packages.activatePackage('language-javascript', sync: true)
|
||||
editor = atom.project.openSync('sample.js', autoIndent: false)
|
||||
{buffer, languageMode} = editor
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-javascript')
|
||||
|
||||
it "maintains cursor buffer position when a folding/unfolding", ->
|
||||
editor.setCursorBufferPosition([5,5])
|
||||
languageMode.foldAll()
|
||||
@@ -298,10 +310,12 @@ describe "LanguageMode", ->
|
||||
|
||||
describe "folding with comments", ->
|
||||
beforeEach ->
|
||||
atom.packages.activatePackage('language-javascript', sync: true)
|
||||
editor = atom.project.openSync('sample-with-comments.js', autoIndent: false)
|
||||
{buffer, languageMode} = editor
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-javascript')
|
||||
|
||||
describe ".unfoldAll()", ->
|
||||
it "unfolds every folded line", ->
|
||||
initialScreenLineCount = editor.getScreenLineCount()
|
||||
@@ -362,10 +376,12 @@ describe "LanguageMode", ->
|
||||
|
||||
describe "css", ->
|
||||
beforeEach ->
|
||||
atom.packages.activatePackage('language-source', sync: true)
|
||||
atom.packages.activatePackage('language-css', sync: true)
|
||||
editor = atom.project.openSync('css.css', autoIndent: true)
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-source')
|
||||
atom.packages.activatePackage('language-css')
|
||||
|
||||
describe "suggestedIndentForBufferRow", ->
|
||||
it "does not return negative values (regression)", ->
|
||||
editor.setText('.test {\npadding: 0;\n}')
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{$} = require 'atom'
|
||||
path = require 'path'
|
||||
Package = require '../src/package'
|
||||
ThemePackage = require '../src/theme-package'
|
||||
|
||||
describe "AtomPackage", ->
|
||||
describe "Package", ->
|
||||
describe "theme", ->
|
||||
theme = null
|
||||
|
||||
@@ -16,14 +16,14 @@ describe "AtomPackage", ->
|
||||
it "loads and applies css", ->
|
||||
expect($(".editor").css("padding-bottom")).not.toBe "1234px"
|
||||
themePath = atom.project.resolve('packages/theme-with-index-css')
|
||||
theme = Package.load(themePath)
|
||||
theme = new ThemePackage(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 = atom.project.resolve('packages/theme-with-index-less')
|
||||
theme = Package.load(themePath)
|
||||
theme = new ThemePackage(themePath)
|
||||
theme.activate()
|
||||
expect($(".editor").css("padding-top")).toBe "4321px"
|
||||
|
||||
@@ -34,7 +34,7 @@ describe "AtomPackage", ->
|
||||
expect($(".editor").css("padding-bottom")).not.toBe("103px")
|
||||
|
||||
themePath = atom.project.resolve('packages/theme-with-package-file')
|
||||
theme = Package.load(themePath)
|
||||
theme = new ThemePackage(themePath)
|
||||
theme.activate()
|
||||
expect($(".editor").css("padding-top")).toBe("101px")
|
||||
expect($(".editor").css("padding-right")).toBe("102px")
|
||||
@@ -47,7 +47,7 @@ describe "AtomPackage", ->
|
||||
expect($(".editor").css("padding-bottom")).not.toBe "30px"
|
||||
|
||||
themePath = atom.project.resolve('packages/theme-without-package-file')
|
||||
theme = Package.load(themePath)
|
||||
theme = new ThemePackage(themePath)
|
||||
theme.activate()
|
||||
expect($(".editor").css("padding-top")).toBe "10px"
|
||||
expect($(".editor").css("padding-right")).toBe "20px"
|
||||
@@ -56,7 +56,7 @@ describe "AtomPackage", ->
|
||||
describe "reloading a theme", ->
|
||||
beforeEach ->
|
||||
themePath = atom.project.resolve('packages/theme-with-package-file')
|
||||
theme = Package.load(themePath)
|
||||
theme = new ThemePackage(themePath)
|
||||
theme.activate()
|
||||
|
||||
it "reloads without readding to the stylesheets list", ->
|
||||
@@ -67,7 +67,7 @@ describe "AtomPackage", ->
|
||||
describe "events", ->
|
||||
beforeEach ->
|
||||
themePath = atom.project.resolve('packages/theme-with-package-file')
|
||||
theme = Package.load(themePath)
|
||||
theme = new ThemePackage(themePath)
|
||||
theme.activate()
|
||||
|
||||
it "deactivated event fires on .deactivate()", ->
|
||||
@@ -2,7 +2,7 @@ path = require 'path'
|
||||
temp = require 'temp'
|
||||
PaneContainerView = require '../src/pane-container-view'
|
||||
PaneView = require '../src/pane-view'
|
||||
{_, $, View, $$} = require 'atom'
|
||||
{$, View, $$} = require 'atom'
|
||||
|
||||
describe "PaneContainerView", ->
|
||||
[TestView, container, pane1, pane2, pane3] = []
|
||||
@@ -27,32 +27,6 @@ describe "PaneContainerView", ->
|
||||
afterEach ->
|
||||
atom.deserializers.remove(TestView)
|
||||
|
||||
describe ".focusNextPane()", ->
|
||||
it "focuses the pane following the focused pane or the first pane if no pane has focus", ->
|
||||
container.attachToDom()
|
||||
container.focusNextPane()
|
||||
expect(pane1.activeItem).toMatchSelector ':focus'
|
||||
container.focusNextPane()
|
||||
expect(pane2.activeItem).toMatchSelector ':focus'
|
||||
container.focusNextPane()
|
||||
expect(pane3.activeItem).toMatchSelector ':focus'
|
||||
container.focusNextPane()
|
||||
expect(pane1.activeItem).toMatchSelector ':focus'
|
||||
|
||||
describe ".focusPreviousPane()", ->
|
||||
it "focuses the pane preceding the focused pane or the last pane if no pane has focus", ->
|
||||
container.attachToDom()
|
||||
container.getPanes()[0].focus() # activate first pane
|
||||
|
||||
container.focusPreviousPane()
|
||||
expect(pane3.activeItem).toMatchSelector ':focus'
|
||||
container.focusPreviousPane()
|
||||
expect(pane2.activeItem).toMatchSelector ':focus'
|
||||
container.focusPreviousPane()
|
||||
expect(pane1.activeItem).toMatchSelector ':focus'
|
||||
container.focusPreviousPane()
|
||||
expect(pane3.activeItem).toMatchSelector ':focus'
|
||||
|
||||
describe ".getActivePane()", ->
|
||||
it "returns the most-recently focused pane", ->
|
||||
focusStealer = $$ -> @div tabindex: -1, "focus stealer"
|
||||
@@ -71,10 +45,10 @@ describe "PaneContainerView", ->
|
||||
expect(container.getFocusedPane()).toBe pane3
|
||||
expect(container.getActivePane()).toBe pane3
|
||||
|
||||
describe ".eachPane(callback)", ->
|
||||
describe ".eachPaneView(callback)", ->
|
||||
it "runs the callback with all current and future panes until the subscription is cancelled", ->
|
||||
panes = []
|
||||
subscription = container.eachPane (pane) -> panes.push(pane)
|
||||
subscription = container.eachPaneView (pane) -> panes.push(pane)
|
||||
expect(panes).toEqual [pane1, pane2, pane3]
|
||||
|
||||
panes = []
|
||||
@@ -92,7 +66,7 @@ describe "PaneContainerView", ->
|
||||
|
||||
container.saveAll()
|
||||
|
||||
for pane in container.getPanes()
|
||||
for pane in container.getPaneViews()
|
||||
for item in pane.getItems()
|
||||
expect(item.saved).toBeTruthy()
|
||||
|
||||
@@ -265,3 +239,115 @@ describe "PaneContainerView", ->
|
||||
pane1.remove()
|
||||
pane2.remove()
|
||||
expect(activeItemChangedHandler).not.toHaveBeenCalled()
|
||||
|
||||
describe ".focusNextPaneView()", ->
|
||||
it "focuses the pane following the focused pane or the first pane if no pane has focus", ->
|
||||
container.attachToDom()
|
||||
container.focusNextPaneView()
|
||||
expect(pane1.activeItem).toMatchSelector ':focus'
|
||||
container.focusNextPaneView()
|
||||
expect(pane2.activeItem).toMatchSelector ':focus'
|
||||
container.focusNextPaneView()
|
||||
expect(pane3.activeItem).toMatchSelector ':focus'
|
||||
container.focusNextPaneView()
|
||||
expect(pane1.activeItem).toMatchSelector ':focus'
|
||||
|
||||
describe ".focusPreviousPaneView()", ->
|
||||
it "focuses the pane preceding the focused pane or the last pane if no pane has focus", ->
|
||||
container.attachToDom()
|
||||
container.getPaneViews()[0].focus() # activate first pane
|
||||
|
||||
container.focusPreviousPaneView()
|
||||
expect(pane3.activeItem).toMatchSelector ':focus'
|
||||
container.focusPreviousPaneView()
|
||||
expect(pane2.activeItem).toMatchSelector ':focus'
|
||||
container.focusPreviousPaneView()
|
||||
expect(pane1.activeItem).toMatchSelector ':focus'
|
||||
container.focusPreviousPaneView()
|
||||
expect(pane3.activeItem).toMatchSelector ':focus'
|
||||
|
||||
describe "changing focus directionally between panes", ->
|
||||
[pane1, pane2, pane3, pane4, pane5, pane6, pane7, pane8, pane9] = []
|
||||
|
||||
beforeEach ->
|
||||
# Set up a grid of 9 panes, in the following arrangement, where the
|
||||
# numbers correspond to the variable names below.
|
||||
#
|
||||
# -------
|
||||
# |1|2|3|
|
||||
# -------
|
||||
# |4|5|6|
|
||||
# -------
|
||||
# |7|8|9|
|
||||
# -------
|
||||
|
||||
container = new PaneContainerView
|
||||
pane1 = container.getRoot()
|
||||
pane1.activateItem(new TestView('1'))
|
||||
pane4 = pane1.splitDown(new TestView('4'))
|
||||
pane7 = pane4.splitDown(new TestView('7'))
|
||||
|
||||
pane2 = pane1.splitRight(new TestView('2'))
|
||||
pane3 = pane2.splitRight(new TestView('3'))
|
||||
|
||||
pane5 = pane4.splitRight(new TestView('5'))
|
||||
pane6 = pane5.splitRight(new TestView('6'))
|
||||
|
||||
pane8 = pane7.splitRight(new TestView('8'))
|
||||
pane9 = pane8.splitRight(new TestView('9'))
|
||||
|
||||
container.height(400)
|
||||
container.width(400)
|
||||
container.attachToDom()
|
||||
|
||||
describe ".focusPaneViewAbove()", ->
|
||||
describe "when there are multiple rows above the focused pane", ->
|
||||
it "focuses up to the adjacent row", ->
|
||||
pane8.focus()
|
||||
container.focusPaneViewAbove()
|
||||
expect(pane5.activeItem).toMatchSelector ':focus'
|
||||
|
||||
describe "when there are no rows above the focused pane", ->
|
||||
it "keeps the current pane focused", ->
|
||||
pane2.focus()
|
||||
container.focusPaneViewAbove()
|
||||
expect(pane2.activeItem).toMatchSelector ':focus'
|
||||
|
||||
describe ".focusPaneViewBelow()", ->
|
||||
describe "when there are multiple rows below the focused pane", ->
|
||||
it "focuses down to the adjacent row", ->
|
||||
pane2.focus()
|
||||
container.focusPaneViewBelow()
|
||||
expect(pane5.activeItem).toMatchSelector ':focus'
|
||||
|
||||
describe "when there are no rows below the focused pane", ->
|
||||
it "keeps the current pane focused", ->
|
||||
pane8.focus()
|
||||
container.focusPaneViewBelow()
|
||||
expect(pane8.activeItem).toMatchSelector ':focus'
|
||||
|
||||
describe ".focusPaneViewOnLeft()", ->
|
||||
describe "when there are multiple columns to the left of the focused pane", ->
|
||||
it "focuses left to the adjacent column", ->
|
||||
pane6.focus()
|
||||
container.focusPaneViewOnLeft()
|
||||
expect(pane5.activeItem).toMatchSelector ':focus'
|
||||
|
||||
describe "when there are no columns to the left of the focused pane", ->
|
||||
it "keeps the current pane focused", ->
|
||||
pane4.focus()
|
||||
container.focusPaneViewOnLeft()
|
||||
expect(pane4.activeItem).toMatchSelector ':focus'
|
||||
|
||||
describe ".focusPaneViewOnRight()", ->
|
||||
describe "when there are multiple columns to the right of the focused pane", ->
|
||||
it "focuses right to the adjacent column", ->
|
||||
pane4.focus()
|
||||
container.focusPaneViewOnRight()
|
||||
expect(pane5.activeItem).toMatchSelector ':focus'
|
||||
|
||||
describe "when there are no columns to the right of the focused pane", ->
|
||||
it "keeps the current pane focused", ->
|
||||
pane6.focus()
|
||||
container.focusPaneViewOnRight()
|
||||
expect(pane6.activeItem).toMatchSelector ':focus'
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
PaneContainerView = require '../src/pane-container-view'
|
||||
PaneView = require '../src/pane-view'
|
||||
{fs, $, View} = require 'atom'
|
||||
fs = require 'fs-plus'
|
||||
{$, View} = require 'atom'
|
||||
path = require 'path'
|
||||
temp = require 'temp'
|
||||
|
||||
@@ -164,7 +165,7 @@ describe "PaneView", ->
|
||||
expect(pane.items).toHaveLength(5)
|
||||
|
||||
fs.removeSync(filePath)
|
||||
waitsFor ->
|
||||
waitsFor 30000, ->
|
||||
pane.items.length == 4
|
||||
|
||||
describe "when a pane is destroyed", ->
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
describe "Pasteboard", ->
|
||||
describe "write(text, metadata) and read()", ->
|
||||
it "writes and reads text to/from the native pasteboard", ->
|
||||
expect(atom.pasteboard.read()).toEqual ['initial pasteboard content']
|
||||
atom.pasteboard.write('next')
|
||||
expect(atom.pasteboard.read()[0]).toBe 'next'
|
||||
|
||||
it "returns metadata if the item on the native pasteboard matches the last written item", ->
|
||||
atom.pasteboard.write('next', {meta: 'data'})
|
||||
expect(atom.pasteboard.read()).toEqual ['next', {meta: 'data'}]
|
||||
+69
-105
@@ -1,7 +1,8 @@
|
||||
temp = require 'temp'
|
||||
fstream = require 'fstream'
|
||||
Project = require '../src/project'
|
||||
{_, fs} = require 'atom'
|
||||
_ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
platform = require './spec-helper-platform'
|
||||
BufferedProcess = require '../src/buffered-process'
|
||||
@@ -72,7 +73,7 @@ describe "Project", ->
|
||||
expect(atom.project.getEditors()[1]).toBe editor2
|
||||
|
||||
describe ".openSync(path)", ->
|
||||
[fooOpener, barOpener, absolutePath, newBufferHandler, newEditorHandler] = []
|
||||
[absolutePath, newBufferHandler, newEditorHandler] = []
|
||||
beforeEach ->
|
||||
absolutePath = require.resolve('./fixtures/dir/a')
|
||||
newBufferHandler = jasmine.createSpy('newBufferHandler')
|
||||
@@ -80,129 +81,92 @@ describe "Project", ->
|
||||
newEditorHandler = jasmine.createSpy('newEditorHandler')
|
||||
atom.project.on 'editor-created', newEditorHandler
|
||||
|
||||
fooOpener = (pathToOpen, options) -> { foo: pathToOpen, options } if pathToOpen?.match(/\.foo/)
|
||||
barOpener = (pathToOpen) -> { bar: pathToOpen } if pathToOpen?.match(/^bar:\/\//)
|
||||
atom.project.registerOpener(fooOpener)
|
||||
atom.project.registerOpener(barOpener)
|
||||
describe "when given an absolute path that hasn't been opened previously", ->
|
||||
it "returns a new edit session for the given path and emits 'buffer-created' and 'editor-created' events", ->
|
||||
editor = atom.project.openSync(absolutePath)
|
||||
expect(editor.buffer.getPath()).toBe absolutePath
|
||||
expect(newBufferHandler).toHaveBeenCalledWith editor.buffer
|
||||
expect(newEditorHandler).toHaveBeenCalledWith editor
|
||||
|
||||
afterEach ->
|
||||
atom.project.unregisterOpener(fooOpener)
|
||||
atom.project.unregisterOpener(barOpener)
|
||||
describe "when given a relative path that hasn't been opened previously", ->
|
||||
it "returns a new edit session for the given path (relative to the project root) and emits 'buffer-created' and 'editor-created' events", ->
|
||||
editor = atom.project.openSync('a')
|
||||
expect(editor.buffer.getPath()).toBe absolutePath
|
||||
expect(newBufferHandler).toHaveBeenCalledWith editor.buffer
|
||||
expect(newEditorHandler).toHaveBeenCalledWith editor
|
||||
|
||||
describe "when passed a path that doesn't match a custom opener", ->
|
||||
describe "when given an absolute path that hasn't been opened previously", ->
|
||||
it "returns a new edit session for the given path and emits 'buffer-created' and 'editor-created' events", ->
|
||||
editor = atom.project.openSync(absolutePath)
|
||||
describe "when passed the path to a buffer that has already been opened", ->
|
||||
it "returns a new edit session containing previously opened buffer and emits a 'editor-created' event", ->
|
||||
editor = atom.project.openSync(absolutePath)
|
||||
newBufferHandler.reset()
|
||||
expect(atom.project.openSync(absolutePath).buffer).toBe editor.buffer
|
||||
expect(atom.project.openSync('a').buffer).toBe editor.buffer
|
||||
expect(newBufferHandler).not.toHaveBeenCalled()
|
||||
expect(newEditorHandler).toHaveBeenCalledWith editor
|
||||
|
||||
describe "when not passed a path", ->
|
||||
it "returns a new edit session and emits 'buffer-created' and 'editor-created' events", ->
|
||||
editor = atom.project.openSync()
|
||||
expect(editor.buffer.getPath()).toBeUndefined()
|
||||
expect(newBufferHandler).toHaveBeenCalledWith(editor.buffer)
|
||||
expect(newEditorHandler).toHaveBeenCalledWith editor
|
||||
|
||||
describe ".open(path)", ->
|
||||
[absolutePath, newBufferHandler, newEditorHandler] = []
|
||||
|
||||
beforeEach ->
|
||||
absolutePath = require.resolve('./fixtures/dir/a')
|
||||
newBufferHandler = jasmine.createSpy('newBufferHandler')
|
||||
atom.project.on 'buffer-created', newBufferHandler
|
||||
newEditorHandler = jasmine.createSpy('newEditorHandler')
|
||||
atom.project.on 'editor-created', newEditorHandler
|
||||
|
||||
describe "when given an absolute path that isn't currently open", ->
|
||||
it "returns a new edit session for the given path and emits 'buffer-created' and 'editor-created' events", ->
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
atom.project.open(absolutePath).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(editor.buffer.getPath()).toBe absolutePath
|
||||
expect(newBufferHandler).toHaveBeenCalledWith editor.buffer
|
||||
expect(newEditorHandler).toHaveBeenCalledWith editor
|
||||
|
||||
describe "when given a relative path that hasn't been opened previously", ->
|
||||
it "returns a new edit session for the given path (relative to the project root) and emits 'buffer-created' and 'editor-created' events", ->
|
||||
editor = atom.project.openSync('a')
|
||||
describe "when given a relative path that isn't currently opened", ->
|
||||
it "returns a new edit session for the given path (relative to the project root) and emits 'buffer-created' and 'editor-created' events", ->
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
atom.project.open(absolutePath).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(editor.buffer.getPath()).toBe absolutePath
|
||||
expect(newBufferHandler).toHaveBeenCalledWith editor.buffer
|
||||
expect(newEditorHandler).toHaveBeenCalledWith editor
|
||||
|
||||
describe "when passed the path to a buffer that has already been opened", ->
|
||||
it "returns a new edit session containing previously opened buffer and emits a 'editor-created' event", ->
|
||||
editor = atom.project.openSync(absolutePath)
|
||||
describe "when passed the path to a buffer that is currently opened", ->
|
||||
it "returns a new edit session containing currently opened buffer and emits a 'editor-created' event", ->
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
atom.project.open(absolutePath).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
newBufferHandler.reset()
|
||||
expect(atom.project.openSync(absolutePath).buffer).toBe editor.buffer
|
||||
expect(atom.project.openSync('a').buffer).toBe editor.buffer
|
||||
expect(newBufferHandler).not.toHaveBeenCalled()
|
||||
expect(newEditorHandler).toHaveBeenCalledWith editor
|
||||
|
||||
describe "when not passed a path", ->
|
||||
it "returns a new edit session and emits 'buffer-created' and 'editor-created' events", ->
|
||||
editor = atom.project.openSync()
|
||||
describe "when not passed a path", ->
|
||||
it "returns a new edit session and emits 'buffer-created' and 'editor-created' events", ->
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
atom.project.open().then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(editor.buffer.getPath()).toBeUndefined()
|
||||
expect(newBufferHandler).toHaveBeenCalledWith(editor.buffer)
|
||||
expect(newEditorHandler).toHaveBeenCalledWith editor
|
||||
|
||||
describe "when passed a path that matches a custom opener", ->
|
||||
it "returns the resource returned by the custom opener", ->
|
||||
pathToOpen = atom.project.resolve('a.foo')
|
||||
expect(atom.project.openSync(pathToOpen, hey: "there")).toEqual { foo: pathToOpen, options: {hey: "there"} }
|
||||
expect(atom.project.openSync("bar://baz")).toEqual { bar: "bar://baz" }
|
||||
|
||||
describe ".open(path)", ->
|
||||
[fooOpener, barOpener, absolutePath, newBufferHandler, newEditorHandler] = []
|
||||
|
||||
beforeEach ->
|
||||
absolutePath = require.resolve('./fixtures/dir/a')
|
||||
newBufferHandler = jasmine.createSpy('newBufferHandler')
|
||||
atom.project.on 'buffer-created', newBufferHandler
|
||||
newEditorHandler = jasmine.createSpy('newEditorHandler')
|
||||
atom.project.on 'editor-created', newEditorHandler
|
||||
|
||||
fooOpener = (pathToOpen, options) -> { foo: pathToOpen, options } if pathToOpen?.match(/\.foo/)
|
||||
barOpener = (pathToOpen) -> { bar: pathToOpen } if pathToOpen?.match(/^bar:\/\//)
|
||||
atom.project.registerOpener(fooOpener)
|
||||
atom.project.registerOpener(barOpener)
|
||||
|
||||
afterEach ->
|
||||
atom.project.unregisterOpener(fooOpener)
|
||||
atom.project.unregisterOpener(barOpener)
|
||||
|
||||
describe "when passed a path that doesn't match a custom opener", ->
|
||||
describe "when given an absolute path that isn't currently open", ->
|
||||
it "returns a new edit session for the given path and emits 'buffer-created' and 'editor-created' events", ->
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
atom.project.open(absolutePath).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(editor.buffer.getPath()).toBe absolutePath
|
||||
expect(newBufferHandler).toHaveBeenCalledWith editor.buffer
|
||||
expect(newEditorHandler).toHaveBeenCalledWith editor
|
||||
|
||||
describe "when given a relative path that isn't currently opened", ->
|
||||
it "returns a new edit session for the given path (relative to the project root) and emits 'buffer-created' and 'editor-created' events", ->
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
atom.project.open(absolutePath).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(editor.buffer.getPath()).toBe absolutePath
|
||||
expect(newBufferHandler).toHaveBeenCalledWith editor.buffer
|
||||
expect(newEditorHandler).toHaveBeenCalledWith editor
|
||||
|
||||
describe "when passed the path to a buffer that is currently opened", ->
|
||||
it "returns a new edit session containing currently opened buffer and emits a 'editor-created' event", ->
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
atom.project.open(absolutePath).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
newBufferHandler.reset()
|
||||
expect(atom.project.openSync(absolutePath).buffer).toBe editor.buffer
|
||||
expect(atom.project.openSync('a').buffer).toBe editor.buffer
|
||||
expect(newBufferHandler).not.toHaveBeenCalled()
|
||||
expect(newEditorHandler).toHaveBeenCalledWith editor
|
||||
|
||||
describe "when not passed a path", ->
|
||||
it "returns a new edit session and emits 'buffer-created' and 'editor-created' events", ->
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
atom.project.open().then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(editor.buffer.getPath()).toBeUndefined()
|
||||
expect(newBufferHandler).toHaveBeenCalledWith(editor.buffer)
|
||||
expect(newEditorHandler).toHaveBeenCalledWith editor
|
||||
|
||||
describe "when passed a path that matches a custom opener", ->
|
||||
it "returns the resource returned by the custom opener", ->
|
||||
waitsForPromise ->
|
||||
pathToOpen = atom.project.resolve('a.foo')
|
||||
atom.project.open(pathToOpen, hey: "there").then (item) ->
|
||||
expect(item).toEqual { foo: pathToOpen, options: {hey: "there"} }
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open("bar://baz").then (item) ->
|
||||
expect(item).toEqual { bar: "bar://baz" }
|
||||
|
||||
it "returns number of read bytes as progress indicator", ->
|
||||
filePath = atom.project.resolve 'a'
|
||||
totalBytes = 0
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
{times, random} = require 'underscore-plus'
|
||||
randomWords = require 'random-words'
|
||||
TextBuffer = require 'text-buffer'
|
||||
Editor = require '../src/editor'
|
||||
|
||||
describe "Editor", ->
|
||||
[editor, tokenizedBuffer, buffer, steps, previousSteps] = []
|
||||
|
||||
softWrapColumn = 80
|
||||
|
||||
beforeEach ->
|
||||
atom.config.set('editor.softWrapAtPreferredLineLength', true)
|
||||
atom.config.set('editor.preferredLineLength', softWrapColumn)
|
||||
|
||||
it "properly renders soft-wrapped lines when randomly mutated", ->
|
||||
previousSteps = JSON.parse(localStorage.steps ? '[]')
|
||||
|
||||
times 10, (i) ->
|
||||
buffer = new TextBuffer
|
||||
editor = new Editor({buffer})
|
||||
editor.setEditorWidthInChars(80)
|
||||
tokenizedBuffer = editor.displayBuffer.tokenizedBuffer
|
||||
steps = []
|
||||
|
||||
times 30, ->
|
||||
randomlyMutateEditor()
|
||||
verifyLines()
|
||||
|
||||
verifyLines = ->
|
||||
{bufferRows, screenLines} = getReferenceScreenLines()
|
||||
for referenceBufferRow, screenRow in bufferRows
|
||||
referenceScreenLine = screenLines[screenRow]
|
||||
actualBufferRow = editor.bufferRowForScreenRow(screenRow)
|
||||
unless actualBufferRow is referenceBufferRow
|
||||
logLines()
|
||||
throw new Error("Invalid buffer row #{actualBufferRow} for screen row #{screenRow}", )
|
||||
|
||||
actualScreenLine = editor.lineForScreenRow(screenRow)
|
||||
unless actualScreenLine.text is referenceScreenLine.text
|
||||
logLines()
|
||||
throw new Error("Invalid line text at screen row #{screenRow}")
|
||||
|
||||
logLines = ->
|
||||
console.log "==== screen lines ===="
|
||||
editor.logScreenLines()
|
||||
console.log "==== reference lines ===="
|
||||
{bufferRows, screenLines} = getReferenceScreenLines()
|
||||
for bufferRow, screenRow in bufferRows
|
||||
console.log screenRow, bufferRow, screenLines[screenRow].text
|
||||
|
||||
randomlyMutateEditor = ->
|
||||
if Math.random() < .2
|
||||
softWrap = not editor.getSoftWrap()
|
||||
steps.push(['setSoftWrap', softWrap])
|
||||
editor.setSoftWrap(softWrap)
|
||||
else
|
||||
range = getRandomRange()
|
||||
text = getRandomText()
|
||||
steps.push(['setTextInBufferRange', range, text])
|
||||
editor.setTextInBufferRange(range, text)
|
||||
|
||||
getRandomRange = ->
|
||||
startRow = random(0, buffer.getLastRow())
|
||||
startColumn = random(0, buffer.lineForRow(startRow).length)
|
||||
endRow = random(startRow, buffer.getLastRow())
|
||||
endColumn = random(0, buffer.lineForRow(endRow).length)
|
||||
[[startRow, startColumn], [endRow, endColumn]]
|
||||
|
||||
getRandomText = ->
|
||||
text = []
|
||||
max = buffer.getText().split(/\s/).length * 0.75
|
||||
|
||||
times random(5, max), ->
|
||||
if Math.random() < .1
|
||||
text += '\n'
|
||||
else
|
||||
text += " " if /\w$/.test(text)
|
||||
text += randomWords(exactly: 1)
|
||||
text
|
||||
|
||||
getReferenceScreenLines = ->
|
||||
if editor.getSoftWrap()
|
||||
screenLines = []
|
||||
bufferRows = []
|
||||
for bufferRow in [0..tokenizedBuffer.getLastRow()]
|
||||
for screenLine in softWrapLine(tokenizedBuffer.lineForScreenRow(bufferRow))
|
||||
screenLines.push(screenLine)
|
||||
bufferRows.push(bufferRow)
|
||||
else
|
||||
screenLines = tokenizedBuffer.tokenizedLines.slice()
|
||||
bufferRows = [0..tokenizedBuffer.getLastRow()]
|
||||
{screenLines, bufferRows}
|
||||
|
||||
softWrapLine = (tokenizedLine) ->
|
||||
wrappedLines = []
|
||||
while tokenizedLine.text.length > softWrapColumn and wrapScreenColumn = findWrapColumn(tokenizedLine.text)
|
||||
[wrappedLine, tokenizedLine] = tokenizedLine.softWrapAt(wrapScreenColumn)
|
||||
wrappedLines.push(wrappedLine)
|
||||
wrappedLines.push(tokenizedLine)
|
||||
wrappedLines
|
||||
|
||||
findWrapColumn = (line) ->
|
||||
if /\s/.test(line[softWrapColumn])
|
||||
# search forward for the start of a word past the boundary
|
||||
for column in [softWrapColumn..line.length]
|
||||
return column if /\S/.test(line[column])
|
||||
return line.length
|
||||
else
|
||||
# search backward for the start of the word on the boundary
|
||||
for column in [softWrapColumn..0]
|
||||
return column + 1 if /\s/.test(line[column])
|
||||
return softWrapColumn
|
||||
+86
-243
@@ -6,256 +6,99 @@ describe "RowMap", ->
|
||||
beforeEach ->
|
||||
map = new RowMap
|
||||
|
||||
describe "when no mappings have been recorded", ->
|
||||
it "maps buffer rows to screen rows 1:1", ->
|
||||
describe "::screenRowRangeForBufferRow(bufferRow)", ->
|
||||
it "returns the range of screen rows corresponding to the given buffer row", ->
|
||||
map.spliceRegions(0, 0, [
|
||||
{bufferRows: 5, screenRows: 5}
|
||||
{bufferRows: 1, screenRows: 5}
|
||||
{bufferRows: 5, screenRows: 5}
|
||||
{bufferRows: 5, screenRows: 1}
|
||||
])
|
||||
|
||||
expect(map.screenRowRangeForBufferRow(0)).toEqual [0, 1]
|
||||
expect(map.screenRowRangeForBufferRow(100)).toEqual [100, 101]
|
||||
expect(map.screenRowRangeForBufferRow(5)).toEqual [5, 10]
|
||||
expect(map.screenRowRangeForBufferRow(6)).toEqual [10, 11]
|
||||
expect(map.screenRowRangeForBufferRow(11)).toEqual [15, 16]
|
||||
expect(map.screenRowRangeForBufferRow(12)).toEqual [15, 16]
|
||||
expect(map.screenRowRangeForBufferRow(16)).toEqual [16, 17]
|
||||
|
||||
describe ".mapBufferRowRange(startBufferRow, endBufferRow, screenRows)", ->
|
||||
describe "when mapping to a single screen row (like a visible fold)", ->
|
||||
beforeEach ->
|
||||
map.mapBufferRowRange(5, 10, 1)
|
||||
map.mapBufferRowRange(15, 20, 1)
|
||||
map.mapBufferRowRange(25, 30, 1)
|
||||
describe "::bufferRowRangeForScreenRow(screenRow)", ->
|
||||
it "returns the range of buffer rows corresponding to the given screen row", ->
|
||||
map.spliceRegions(0, 0, [
|
||||
{bufferRows: 5, screenRows: 5}
|
||||
{bufferRows: 1, screenRows: 5}
|
||||
{bufferRows: 5, screenRows: 5}
|
||||
{bufferRows: 5, screenRows: 1}
|
||||
])
|
||||
|
||||
it "accounts for the mapping when translating buffer rows to screen row ranges", ->
|
||||
expect(map.screenRowRangeForBufferRow(0)).toEqual [0, 1]
|
||||
expect(map.bufferRowRangeForScreenRow(0)).toEqual [0, 1]
|
||||
expect(map.bufferRowRangeForScreenRow(5)).toEqual [5, 6]
|
||||
expect(map.bufferRowRangeForScreenRow(6)).toEqual [5, 6]
|
||||
expect(map.bufferRowRangeForScreenRow(10)).toEqual [6, 7]
|
||||
expect(map.bufferRowRangeForScreenRow(14)).toEqual [10, 11]
|
||||
expect(map.bufferRowRangeForScreenRow(15)).toEqual [11, 16]
|
||||
expect(map.bufferRowRangeForScreenRow(16)).toEqual [16, 17]
|
||||
|
||||
expect(map.screenRowRangeForBufferRow(4)).toEqual [4, 5]
|
||||
expect(map.screenRowRangeForBufferRow(5)).toEqual [5, 6]
|
||||
expect(map.screenRowRangeForBufferRow(9)).toEqual [5, 6]
|
||||
expect(map.screenRowRangeForBufferRow(10)).toEqual [6, 7]
|
||||
describe "::spliceRegions(startBufferRow, bufferRowCount, regions)", ->
|
||||
it "can insert regions when empty", ->
|
||||
regions = [
|
||||
{bufferRows: 5, screenRows: 5}
|
||||
{bufferRows: 1, screenRows: 5}
|
||||
{bufferRows: 5, screenRows: 5}
|
||||
{bufferRows: 5, screenRows: 1}
|
||||
]
|
||||
map.spliceRegions(0, 0, regions)
|
||||
expect(map.getRegions()).toEqual regions
|
||||
|
||||
expect(map.screenRowRangeForBufferRow(14)).toEqual [10, 11]
|
||||
expect(map.screenRowRangeForBufferRow(15)).toEqual [11, 12]
|
||||
expect(map.screenRowRangeForBufferRow(19)).toEqual [11, 12]
|
||||
expect(map.screenRowRangeForBufferRow(20)).toEqual [12, 13]
|
||||
it "can insert wrapped lines into rectangular regions", ->
|
||||
map.spliceRegions(0, 0, [{bufferRows: 10, screenRows: 10}])
|
||||
map.spliceRegions(5, 0, [{bufferRows: 1, screenRows: 3}])
|
||||
expect(map.getRegions()).toEqual [
|
||||
{bufferRows: 5, screenRows: 5}
|
||||
{bufferRows: 1, screenRows: 3}
|
||||
{bufferRows: 5, screenRows: 5}
|
||||
]
|
||||
|
||||
expect(map.screenRowRangeForBufferRow(24)).toEqual [16, 17]
|
||||
expect(map.screenRowRangeForBufferRow(25)).toEqual [17, 18]
|
||||
expect(map.screenRowRangeForBufferRow(29)).toEqual [17, 18]
|
||||
expect(map.screenRowRangeForBufferRow(30)).toEqual [18, 19]
|
||||
it "can splice wrapped lines into rectangular regions", ->
|
||||
map.spliceRegions(0, 0, [{bufferRows: 10, screenRows: 10}])
|
||||
map.spliceRegions(5, 1, [{bufferRows: 1, screenRows: 3}])
|
||||
expect(map.getRegions()).toEqual [
|
||||
{bufferRows: 5, screenRows: 5}
|
||||
{bufferRows: 1, screenRows: 3}
|
||||
{bufferRows: 4, screenRows: 4}
|
||||
]
|
||||
|
||||
it "accounts for the mapping when translating screen rows to buffer row ranges", ->
|
||||
expect(map.bufferRowRangeForScreenRow(0)).toEqual [0, 1]
|
||||
it "can splice folded lines into rectangular regions", ->
|
||||
map.spliceRegions(0, 0, [{bufferRows: 10, screenRows: 10}])
|
||||
map.spliceRegions(5, 3, [{bufferRows: 3, screenRows: 1}])
|
||||
expect(map.getRegions()).toEqual [
|
||||
{bufferRows: 5, screenRows: 5}
|
||||
{bufferRows: 3, screenRows: 1}
|
||||
{bufferRows: 2, screenRows: 2}
|
||||
]
|
||||
|
||||
expect(map.bufferRowRangeForScreenRow(4)).toEqual [4, 5]
|
||||
expect(map.bufferRowRangeForScreenRow(5)).toEqual [5, 10]
|
||||
expect(map.bufferRowRangeForScreenRow(6)).toEqual [10, 11]
|
||||
it "can replace folded regions with a folded region that surrounds them", ->
|
||||
map.spliceRegions(0, 0, [
|
||||
{bufferRows: 3, screenRows: 3}
|
||||
{bufferRows: 3, screenRows: 1}
|
||||
{bufferRows: 1, screenRows: 1}
|
||||
{bufferRows: 3, screenRows: 1}
|
||||
{bufferRows: 3, screenRows: 3}
|
||||
])
|
||||
map.spliceRegions(2, 8, [{bufferRows: 8, screenRows: 1}])
|
||||
expect(map.getRegions()).toEqual [
|
||||
{bufferRows: 2, screenRows: 2}
|
||||
{bufferRows: 8, screenRows: 1}
|
||||
{bufferRows: 3, screenRows: 3}
|
||||
]
|
||||
|
||||
expect(map.bufferRowRangeForScreenRow(10)).toEqual [14, 15]
|
||||
expect(map.bufferRowRangeForScreenRow(11)).toEqual [15, 20]
|
||||
expect(map.bufferRowRangeForScreenRow(12)).toEqual [20, 21]
|
||||
it "merges adjacent rectangular regions", ->
|
||||
map.spliceRegions(0, 0, [
|
||||
{bufferRows: 3, screenRows: 3}
|
||||
{bufferRows: 3, screenRows: 1}
|
||||
{bufferRows: 1, screenRows: 1}
|
||||
{bufferRows: 3, screenRows: 1}
|
||||
{bufferRows: 3, screenRows: 3}
|
||||
])
|
||||
|
||||
expect(map.bufferRowRangeForScreenRow(16)).toEqual [24, 25]
|
||||
expect(map.bufferRowRangeForScreenRow(17)).toEqual [25, 30]
|
||||
expect(map.bufferRowRangeForScreenRow(18)).toEqual [30, 31]
|
||||
|
||||
describe "when mapping to zero screen rows (like an invisible fold)", ->
|
||||
beforeEach ->
|
||||
map.mapBufferRowRange(5, 10, 0)
|
||||
map.mapBufferRowRange(15, 20, 0)
|
||||
map.mapBufferRowRange(25, 30, 0)
|
||||
|
||||
it "accounts for the mapping when translating buffer rows to screen row ranges", ->
|
||||
expect(map.screenRowRangeForBufferRow(0)).toEqual [0, 1]
|
||||
|
||||
expect(map.screenRowRangeForBufferRow(4)).toEqual [4, 5]
|
||||
expect(map.screenRowRangeForBufferRow(5)).toEqual [5, 5]
|
||||
expect(map.screenRowRangeForBufferRow(9)).toEqual [5, 5]
|
||||
expect(map.screenRowRangeForBufferRow(10)).toEqual [5, 6]
|
||||
|
||||
expect(map.screenRowRangeForBufferRow(14)).toEqual [9, 10]
|
||||
expect(map.screenRowRangeForBufferRow(15)).toEqual [10, 10]
|
||||
expect(map.screenRowRangeForBufferRow(19)).toEqual [10, 10]
|
||||
expect(map.screenRowRangeForBufferRow(20)).toEqual [10, 11]
|
||||
|
||||
expect(map.screenRowRangeForBufferRow(24)).toEqual [14, 15]
|
||||
expect(map.screenRowRangeForBufferRow(25)).toEqual [15, 15]
|
||||
expect(map.screenRowRangeForBufferRow(29)).toEqual [15, 15]
|
||||
expect(map.screenRowRangeForBufferRow(30)).toEqual [15, 16]
|
||||
|
||||
it "accounts for the mapping when translating screen rows to buffer row ranges", ->
|
||||
expect(map.bufferRowRangeForScreenRow(0)).toEqual [0, 1]
|
||||
|
||||
expect(map.bufferRowRangeForScreenRow(4)).toEqual [4, 5]
|
||||
expect(map.bufferRowRangeForScreenRow(5)).toEqual [10, 11]
|
||||
|
||||
expect(map.bufferRowRangeForScreenRow(9)).toEqual [14, 15]
|
||||
expect(map.bufferRowRangeForScreenRow(10)).toEqual [20, 21]
|
||||
|
||||
expect(map.bufferRowRangeForScreenRow(14)).toEqual [24, 25]
|
||||
expect(map.bufferRowRangeForScreenRow(15)).toEqual [30, 31]
|
||||
|
||||
describe "when mapping a single buffer row to multiple screen rows (like a wrapped line)", ->
|
||||
beforeEach ->
|
||||
map.mapBufferRowRange(5, 6, 3)
|
||||
map.mapBufferRowRange(10, 11, 2)
|
||||
map.mapBufferRowRange(20, 21, 5)
|
||||
|
||||
it "accounts for the mapping when translating buffer rows to screen row ranges", ->
|
||||
expect(map.screenRowRangeForBufferRow(0)).toEqual [0, 1]
|
||||
|
||||
expect(map.screenRowRangeForBufferRow(4)).toEqual [4, 5]
|
||||
expect(map.screenRowRangeForBufferRow(5)).toEqual [5, 8]
|
||||
expect(map.screenRowRangeForBufferRow(6)).toEqual [8, 9]
|
||||
|
||||
expect(map.screenRowRangeForBufferRow(9)).toEqual [11, 12]
|
||||
expect(map.screenRowRangeForBufferRow(10)).toEqual [12, 14]
|
||||
expect(map.screenRowRangeForBufferRow(11)).toEqual [14, 15]
|
||||
|
||||
expect(map.screenRowRangeForBufferRow(19)).toEqual [22, 23]
|
||||
expect(map.screenRowRangeForBufferRow(20)).toEqual [23, 28]
|
||||
expect(map.screenRowRangeForBufferRow(21)).toEqual [28, 29]
|
||||
|
||||
it "accounts for the mapping when translating screen rows to buffer row ranges", ->
|
||||
expect(map.bufferRowRangeForScreenRow(0)).toEqual [0, 1]
|
||||
|
||||
expect(map.bufferRowRangeForScreenRow(4)).toEqual [4, 5]
|
||||
expect(map.bufferRowRangeForScreenRow(5)).toEqual [5, 6]
|
||||
expect(map.bufferRowRangeForScreenRow(7)).toEqual [5, 6]
|
||||
expect(map.bufferRowRangeForScreenRow(8)).toEqual [6, 7]
|
||||
|
||||
expect(map.bufferRowRangeForScreenRow(11)).toEqual [9, 10]
|
||||
expect(map.bufferRowRangeForScreenRow(12)).toEqual [10, 11]
|
||||
expect(map.bufferRowRangeForScreenRow(13)).toEqual [10, 11]
|
||||
expect(map.bufferRowRangeForScreenRow(14)).toEqual [11, 12]
|
||||
|
||||
expect(map.bufferRowRangeForScreenRow(22)).toEqual [19, 20]
|
||||
expect(map.bufferRowRangeForScreenRow(23)).toEqual [20, 21]
|
||||
expect(map.bufferRowRangeForScreenRow(27)).toEqual [20, 21]
|
||||
expect(map.bufferRowRangeForScreenRow(28)).toEqual [21, 22]
|
||||
|
||||
describe "after re-mapping a row range to a new number of screen rows", ->
|
||||
beforeEach ->
|
||||
map.applyScreenDelta(12, 2) # simulate adding 2 more soft wraps
|
||||
map.mapBufferRowRange(10, 11, 4)
|
||||
|
||||
it "updates translation accordingly", ->
|
||||
expect(map.screenRowRangeForBufferRow(4)).toEqual [4, 5]
|
||||
expect(map.screenRowRangeForBufferRow(5)).toEqual [5, 8]
|
||||
expect(map.screenRowRangeForBufferRow(6)).toEqual [8, 9]
|
||||
|
||||
expect(map.screenRowRangeForBufferRow(9)).toEqual [11, 12]
|
||||
expect(map.screenRowRangeForBufferRow(10)).toEqual [12, 16]
|
||||
expect(map.screenRowRangeForBufferRow(11)).toEqual [16, 17]
|
||||
|
||||
expect(map.screenRowRangeForBufferRow(19)).toEqual [24, 25]
|
||||
expect(map.screenRowRangeForBufferRow(20)).toEqual [25, 30]
|
||||
expect(map.screenRowRangeForBufferRow(21)).toEqual [30, 31]
|
||||
|
||||
describe "when the row range is inside an existing 1:1 region", ->
|
||||
it "preserves the starting screen row of subsequent 1:N regions", ->
|
||||
map.mapBufferRowRange(5, 10, 1)
|
||||
map.mapBufferRowRange(25, 30, 1)
|
||||
|
||||
expect(map.bufferRowRangeForScreenRow(5)).toEqual [5, 10]
|
||||
expect(map.bufferRowRangeForScreenRow(21)).toEqual [25, 30]
|
||||
|
||||
map.mapBufferRowRange(15, 20, 1)
|
||||
|
||||
expect(map.bufferRowRangeForScreenRow(11)).toEqual [15, 20]
|
||||
expect(map.bufferRowRangeForScreenRow(5)).toEqual [5, 10]
|
||||
expect(map.bufferRowRangeForScreenRow(21)).toEqual [25, 30]
|
||||
|
||||
describe "when the row range surrounds existing regions", ->
|
||||
it "replaces the regions inside the given buffer row range with a single region", ->
|
||||
map.mapBufferRowRange(5, 10, 1) # inner fold 1
|
||||
map.mapBufferRowRange(11, 13, 1) # inner fold 2
|
||||
map.mapBufferRowRange(15, 20, 1) # inner fold 3
|
||||
map.mapBufferRowRange(22, 27, 1) # following fold
|
||||
|
||||
map.mapBufferRowRange(5, 20, 1)
|
||||
|
||||
expect(map.bufferRowRangeForScreenRow(5)).toEqual [5, 20]
|
||||
expect(map.bufferRowRangeForScreenRow(6)).toEqual [20, 21]
|
||||
expect(map.bufferRowRangeForScreenRow(7)).toEqual [21, 22]
|
||||
expect(map.bufferRowRangeForScreenRow(8)).toEqual [22, 27]
|
||||
|
||||
it "replaces regions that cover 0 buffer rows at the start or end of the buffer row range", ->
|
||||
map.mapBufferRowRange(0, 0, 1)
|
||||
map.mapBufferRowRange(0, 1, 1)
|
||||
map.mapBufferRowRange(1, 1, 1)
|
||||
map.mapBufferRowRange(0, 1, 3)
|
||||
expect(map.screenRowRangeForBufferRow(0)).toEqual [0, 3]
|
||||
|
||||
describe "when the row range straddles existing regions", ->
|
||||
it "splits the straddled regions and places the new region between them", ->
|
||||
# filler region 0
|
||||
map.mapBufferRowRange(4, 7, 1) # region 1
|
||||
# filler region 2
|
||||
map.mapBufferRowRange(13, 15, 1) # region 3
|
||||
|
||||
# create region straddling region 0 and region 2
|
||||
map.mapBufferRowRange(2, 10, 1)
|
||||
|
||||
expect(map.regions[0]).toEqual(bufferRows: 2, screenRows: 2)
|
||||
expect(map.regions[1]).toEqual(bufferRows: 8, screenRows: 1)
|
||||
expect(map.regions[2]).toEqual(bufferRows: 3, screenRows: 8)
|
||||
expect(map.regions[3]).toEqual(bufferRows: 2, screenRows: 1)
|
||||
|
||||
it "merges adjacent isomorphic mappings", ->
|
||||
map.mapBufferRowRange(2, 4, 1)
|
||||
map.mapBufferRowRange(4, 5, 2)
|
||||
|
||||
map.mapBufferRowRange(1, 4, 3)
|
||||
expect(map.regions).toEqual [{bufferRows: 5, screenRows: 5}]
|
||||
|
||||
describe ".applyBufferDelta(startBufferRow, delta)", ->
|
||||
describe "when applying a positive delta", ->
|
||||
it "expands the region containing the given start row by the given delta", ->
|
||||
map.mapBufferRowRange(4, 8, 1)
|
||||
|
||||
map.applyBufferDelta(5, 4)
|
||||
|
||||
expect(map.regions[0]).toEqual(bufferRows: 4, screenRows: 4)
|
||||
expect(map.regions[1]).toEqual(bufferRows: 8, screenRows: 1)
|
||||
|
||||
describe "when applying a negative delta", ->
|
||||
it "shrinks regions starting at the start row until the entire delta is consumed", ->
|
||||
map.mapBufferRowRange(4, 8, 1)
|
||||
map.mapBufferRowRange(10, 14, 1)
|
||||
|
||||
map.applyBufferDelta(3, -6)
|
||||
|
||||
expect(map.regions[0]).toEqual(bufferRows: 3, screenRows: 4)
|
||||
expect(map.regions[1]).toEqual(bufferRows: 0, screenRows: 1)
|
||||
expect(map.regions[2]).toEqual(bufferRows: 1, screenRows: 2)
|
||||
expect(map.regions[3]).toEqual(bufferRows: 4, screenRows: 1)
|
||||
|
||||
describe ".applyScreenDelta(startScreenRow, delta)", ->
|
||||
describe "when applying a positive delta", ->
|
||||
it "can enlarge the screen side of existing regions", ->
|
||||
map.mapBufferRowRange(5, 6, 3) # wrapped line
|
||||
map.applyScreenDelta(5, 2) # wrap it twice more
|
||||
expect(map.screenRowRangeForBufferRow(5)).toEqual [5, 10]
|
||||
|
||||
describe "when applying a negative delta", ->
|
||||
it "can collapse the screen side of multiple regions to 0 until the entire delta has been applied", ->
|
||||
map.mapBufferRowRange(5, 10, 1) # inner fold 1
|
||||
map.mapBufferRowRange(11, 13, 1) # inner fold 2
|
||||
map.mapBufferRowRange(15, 20, 1) # inner fold 3
|
||||
map.mapBufferRowRange(22, 27, 1) # following fold
|
||||
|
||||
map.applyScreenDelta(6, -5)
|
||||
|
||||
expect(map.screenRowRangeForBufferRow(5)).toEqual [5, 6]
|
||||
expect(map.screenRowRangeForBufferRow(9)).toEqual [5, 6]
|
||||
expect(map.screenRowRangeForBufferRow(10)).toEqual [6, 6]
|
||||
expect(map.screenRowRangeForBufferRow(19)).toEqual [6, 6]
|
||||
expect(map.screenRowRangeForBufferRow(22)).toEqual [8, 9]
|
||||
expect(map.screenRowRangeForBufferRow(26)).toEqual [8, 9]
|
||||
|
||||
it "starts collapsing the first region at the start row, not before", ->
|
||||
map.mapBufferRowRange(5, 6, 4)
|
||||
map.mapBufferRowRange(11, 13, 1)
|
||||
|
||||
map.applyScreenDelta(7, -5)
|
||||
|
||||
expect(map.regions[0]).toEqual(bufferRows: 5, screenRows: 5)
|
||||
expect(map.regions[1]).toEqual(bufferRows: 1, screenRows: 2)
|
||||
expect(map.regions[2]).toEqual(bufferRows: 5, screenRows: 2)
|
||||
|
||||
it "does not throw an exception when applying a delta beyond the last region", ->
|
||||
map.mapBufferRowRange(5, 10, 1) # inner fold 1
|
||||
map.applyScreenDelta(15, 10)
|
||||
map.spliceRegions(3, 7, [{bufferRows: 5, screenRows: 5}])
|
||||
|
||||
@@ -2,25 +2,25 @@ SelectListView = require '../src/select-list-view'
|
||||
{$, $$} = require 'atom'
|
||||
|
||||
describe "SelectListView", ->
|
||||
[selectList, array, list, miniEditor] = []
|
||||
[selectList, items, list, filterEditorView] = []
|
||||
|
||||
beforeEach ->
|
||||
array = [
|
||||
items = [
|
||||
["A", "Alpha"], ["B", "Bravo"], ["C", "Charlie"],
|
||||
["D", "Delta"], ["E", "Echo"], ["F", "Foxtrot"]
|
||||
]
|
||||
|
||||
selectList = new SelectListView
|
||||
selectList.maxItems = 4
|
||||
selectList.filterKey = 1
|
||||
selectList.itemForElement = (element) ->
|
||||
$$ -> @li element[1], class: element[0]
|
||||
selectList.setMaxItems(4)
|
||||
selectList.getFilterKey = -> 1
|
||||
selectList.viewForItem = (item) ->
|
||||
$$ -> @li item[1], class: item[0]
|
||||
|
||||
selectList.confirmed = jasmine.createSpy('confirmed hook')
|
||||
selectList.cancelled = jasmine.createSpy('cancelled hook')
|
||||
|
||||
selectList.setArray(array)
|
||||
{list, miniEditor} = selectList
|
||||
selectList.setItems(items)
|
||||
{list, filterEditorView} = selectList
|
||||
|
||||
describe "when an array is assigned", ->
|
||||
it "populates the list with up to maxItems items, based on the liForElement function", ->
|
||||
@@ -28,12 +28,27 @@ describe "SelectListView", ->
|
||||
expect(list.find('li:eq(0)')).toHaveText 'Alpha'
|
||||
expect(list.find('li:eq(0)')).toHaveClass 'A'
|
||||
|
||||
describe "viewForItem(item)", ->
|
||||
it "allows raw DOM elements to be returned", ->
|
||||
selectList.viewForItem = (item) ->
|
||||
li = document.createElement('li')
|
||||
li.classList.add(item[0])
|
||||
li.innerText = item[1]
|
||||
li
|
||||
|
||||
selectList.setItems(items)
|
||||
|
||||
expect(list.find('li').length).toBe selectList.maxItems
|
||||
expect(list.find('li:eq(0)')).toHaveText 'Alpha'
|
||||
expect(list.find('li:eq(0)')).toHaveClass 'A'
|
||||
expect(selectList.getSelectedItem()).toBe items[0]
|
||||
|
||||
describe "when the text of the mini editor changes", ->
|
||||
beforeEach ->
|
||||
selectList.attachToDom()
|
||||
|
||||
it "filters the elements in the list based on the scoreElement function and selects the first item", ->
|
||||
miniEditor.getEditor().insertText('la')
|
||||
filterEditorView.getEditor().insertText('la')
|
||||
window.advanceClock(selectList.inputThrottle)
|
||||
|
||||
expect(list.find('li').length).toBe 2
|
||||
@@ -43,54 +58,54 @@ describe "SelectListView", ->
|
||||
expect(selectList.error).not.toBeVisible()
|
||||
|
||||
it "displays an error if there are no matches, removes error when there are matches", ->
|
||||
miniEditor.getEditor().insertText('nothing will match this')
|
||||
filterEditorView.getEditor().insertText('nothing will match this')
|
||||
window.advanceClock(selectList.inputThrottle)
|
||||
|
||||
expect(list.find('li').length).toBe 0
|
||||
expect(selectList.error).not.toBeHidden()
|
||||
|
||||
miniEditor.getEditor().setText('la')
|
||||
filterEditorView.getEditor().setText('la')
|
||||
window.advanceClock(selectList.inputThrottle)
|
||||
|
||||
expect(list.find('li').length).toBe 2
|
||||
expect(selectList.error).not.toBeVisible()
|
||||
|
||||
it "displays no elements until the array has been set on the list", ->
|
||||
selectList.array = null
|
||||
selectList.items = null
|
||||
selectList.list.empty()
|
||||
miniEditor.getEditor().insertText('la')
|
||||
filterEditorView.getEditor().insertText('la')
|
||||
window.advanceClock(selectList.inputThrottle)
|
||||
|
||||
expect(list.find('li').length).toBe 0
|
||||
expect(selectList.error).toBeHidden()
|
||||
selectList.setArray(array)
|
||||
selectList.setItems(items)
|
||||
expect(list.find('li').length).toBe 2
|
||||
|
||||
describe "when core:move-up / core:move-down are triggered on the miniEditor", ->
|
||||
describe "when core:move-up / core:move-down are triggered on the filterEditorView", ->
|
||||
it "selects the previous / next item in the list, or wraps around to the other side", ->
|
||||
expect(list.find('li:first')).toHaveClass 'selected'
|
||||
|
||||
miniEditor.trigger 'core:move-up'
|
||||
filterEditorView.trigger 'core:move-up'
|
||||
|
||||
expect(list.find('li:first')).not.toHaveClass 'selected'
|
||||
expect(list.find('li:last')).toHaveClass 'selected'
|
||||
|
||||
miniEditor.trigger 'core:move-down'
|
||||
filterEditorView.trigger 'core:move-down'
|
||||
|
||||
expect(list.find('li:first')).toHaveClass 'selected'
|
||||
expect(list.find('li:last')).not.toHaveClass 'selected'
|
||||
|
||||
miniEditor.trigger 'core:move-down'
|
||||
filterEditorView.trigger 'core:move-down'
|
||||
|
||||
expect(list.find('li:eq(0)')).not.toHaveClass 'selected'
|
||||
expect(list.find('li:eq(1)')).toHaveClass 'selected'
|
||||
|
||||
miniEditor.trigger 'core:move-down'
|
||||
filterEditorView.trigger 'core:move-down'
|
||||
|
||||
expect(list.find('li:eq(1)')).not.toHaveClass 'selected'
|
||||
expect(list.find('li:eq(2)')).toHaveClass 'selected'
|
||||
|
||||
miniEditor.trigger 'core:move-up'
|
||||
filterEditorView.trigger 'core:move-up'
|
||||
|
||||
expect(list.find('li:eq(2)')).not.toHaveClass 'selected'
|
||||
expect(list.find('li:eq(1)')).toHaveClass 'selected'
|
||||
@@ -100,43 +115,43 @@ describe "SelectListView", ->
|
||||
itemHeight = list.find('li').outerHeight()
|
||||
list.height(itemHeight * 2)
|
||||
|
||||
miniEditor.trigger 'core:move-down'
|
||||
miniEditor.trigger 'core:move-down'
|
||||
filterEditorView.trigger 'core:move-down'
|
||||
filterEditorView.trigger 'core:move-down'
|
||||
expect(list.scrollBottom()).toBe itemHeight * 3
|
||||
|
||||
miniEditor.trigger 'core:move-down'
|
||||
filterEditorView.trigger 'core:move-down'
|
||||
expect(list.scrollBottom()).toBe itemHeight * 4
|
||||
|
||||
miniEditor.trigger 'core:move-up'
|
||||
miniEditor.trigger 'core:move-up'
|
||||
filterEditorView.trigger 'core:move-up'
|
||||
filterEditorView.trigger 'core:move-up'
|
||||
expect(list.scrollTop()).toBe itemHeight
|
||||
|
||||
describe "the core:confirm event", ->
|
||||
describe "when there is an item selected (because the list in not empty)", ->
|
||||
it "triggers the selected hook with the selected array element", ->
|
||||
miniEditor.trigger 'core:move-down'
|
||||
miniEditor.trigger 'core:move-down'
|
||||
miniEditor.trigger 'core:confirm'
|
||||
expect(selectList.confirmed).toHaveBeenCalledWith(array[2])
|
||||
filterEditorView.trigger 'core:move-down'
|
||||
filterEditorView.trigger 'core:move-down'
|
||||
filterEditorView.trigger 'core:confirm'
|
||||
expect(selectList.confirmed).toHaveBeenCalledWith(items[2])
|
||||
|
||||
describe "when there is no item selected (because the list is empty)", ->
|
||||
beforeEach ->
|
||||
selectList.attachToDom()
|
||||
|
||||
it "does not trigger the confirmed hook", ->
|
||||
miniEditor.getEditor().insertText("i will never match anything")
|
||||
filterEditorView.getEditor().insertText("i will never match anything")
|
||||
window.advanceClock(selectList.inputThrottle)
|
||||
|
||||
expect(list.find('li')).not.toExist()
|
||||
miniEditor.trigger 'core:confirm'
|
||||
filterEditorView.trigger 'core:confirm'
|
||||
expect(selectList.confirmed).not.toHaveBeenCalled()
|
||||
|
||||
it "does trigger the cancelled hook", ->
|
||||
miniEditor.getEditor().insertText("i will never match anything")
|
||||
filterEditorView.getEditor().insertText("i will never match anything")
|
||||
window.advanceClock(selectList.inputThrottle)
|
||||
|
||||
expect(list.find('li')).not.toExist()
|
||||
miniEditor.trigger 'core:confirm'
|
||||
filterEditorView.trigger 'core:confirm'
|
||||
expect(selectList.cancelled).toHaveBeenCalled()
|
||||
|
||||
describe "when a list item is clicked", ->
|
||||
@@ -147,12 +162,12 @@ describe "SelectListView", ->
|
||||
expect(item).toHaveClass 'selected'
|
||||
item.mouseup()
|
||||
|
||||
expect(selectList.confirmed).toHaveBeenCalledWith(array[1])
|
||||
expect(selectList.confirmed).toHaveBeenCalledWith(items[1])
|
||||
|
||||
describe "the core:cancel event", ->
|
||||
it "triggers the cancelled hook and detaches and empties the select list", ->
|
||||
spyOn(selectList, 'detach')
|
||||
miniEditor.trigger 'core:cancel'
|
||||
filterEditorView.trigger 'core:cancel'
|
||||
expect(selectList.cancelled).toHaveBeenCalled()
|
||||
expect(selectList.detach).toHaveBeenCalled()
|
||||
expect(selectList.list).toBeEmpty()
|
||||
@@ -160,7 +175,7 @@ describe "SelectListView", ->
|
||||
describe "when the mini editor loses focus", ->
|
||||
it "triggers the cancelled hook and detaches the select list", ->
|
||||
spyOn(selectList, 'detach')
|
||||
miniEditor.hiddenInput.trigger 'focusout'
|
||||
filterEditorView.hiddenInput.trigger 'focusout'
|
||||
expect(selectList.cancelled).toHaveBeenCalled()
|
||||
expect(selectList.detach).toHaveBeenCalled()
|
||||
|
||||
|
||||
@@ -11,35 +11,6 @@ describe "SpacePen extensions", ->
|
||||
parent = $$ -> @div()
|
||||
parent.append(view)
|
||||
|
||||
describe "View.observeConfig(keyPath, callback)", ->
|
||||
observeHandler = null
|
||||
|
||||
beforeEach ->
|
||||
observeHandler = jasmine.createSpy("observeHandler")
|
||||
view.observeConfig "foo.bar", observeHandler
|
||||
expect(view.hasParent()).toBeTruthy()
|
||||
|
||||
it "observes the keyPath and cancels the subscription when `.unobserveConfig()` is called", ->
|
||||
expect(observeHandler).toHaveBeenCalledWith(undefined)
|
||||
observeHandler.reset()
|
||||
|
||||
atom.config.set("foo.bar", "hello")
|
||||
|
||||
expect(observeHandler).toHaveBeenCalledWith("hello", previous: undefined)
|
||||
observeHandler.reset()
|
||||
|
||||
view.unobserveConfig()
|
||||
|
||||
atom.config.set("foo.bar", "goodbye")
|
||||
|
||||
expect(observeHandler).not.toHaveBeenCalled()
|
||||
|
||||
it "unobserves when the view is removed", ->
|
||||
observeHandler.reset()
|
||||
parent.remove()
|
||||
atom.config.set("foo.bar", "hello")
|
||||
expect(observeHandler).not.toHaveBeenCalled()
|
||||
|
||||
describe "View.subscribe(eventEmitter, eventName, callback)", ->
|
||||
[emitter, eventHandler] = []
|
||||
|
||||
|
||||
@@ -5,7 +5,11 @@ try
|
||||
require '../src/window'
|
||||
Atom = require '../src/atom'
|
||||
window.atom = Atom.loadOrCreate('spec')
|
||||
window.atom.show() unless atom.getLoadSettings().exitWhenDone
|
||||
|
||||
# Show window synchronously so a focusout doesn't fire on input elements
|
||||
# that are focused in the very first spec run.
|
||||
atom.getCurrentWindow().show() unless atom.getLoadSettings().exitWhenDone
|
||||
|
||||
{runSpecSuite} = require './jasmine-helper'
|
||||
|
||||
document.title = "Spec Suite"
|
||||
|
||||
@@ -4,7 +4,9 @@ atom.restoreWindowDimensions()
|
||||
|
||||
require '../vendor/jasmine-jquery'
|
||||
path = require 'path'
|
||||
{_, $, File, WorkspaceView, fs} = require 'atom'
|
||||
_ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
{$, WorkspaceView} = require 'atom'
|
||||
Keymap = require '../src/keymap'
|
||||
Config = require '../src/config'
|
||||
{Point} = require 'text-buffer'
|
||||
@@ -41,7 +43,7 @@ specProjectPath = null
|
||||
if specDirectory
|
||||
specPackagePath = path.resolve(specDirectory, '..')
|
||||
try
|
||||
specPackageName = fs.readObjectSync(path.join(specPackagePath, 'package.json'))?.name
|
||||
specPackageName = JSON.parse(fs.readFileSync(path.join(specPackagePath, 'package.json')))?.name
|
||||
specProjectPath = path.join(specDirectory, 'fixtures')
|
||||
|
||||
beforeEach ->
|
||||
@@ -75,6 +77,7 @@ beforeEach ->
|
||||
spyOn(config, 'save')
|
||||
config.setDefaults('core', WorkspaceView.configDefaults)
|
||||
config.setDefaults('editor', EditorView.configDefaults)
|
||||
config.set "core.destroyEmptyPanes", false
|
||||
config.set "editor.fontFamily", "Courier"
|
||||
config.set "editor.fontSize", 16
|
||||
config.set "editor.autoIndent", false
|
||||
@@ -88,16 +91,16 @@ beforeEach ->
|
||||
spyOn(WorkspaceView.prototype, 'setTitle').andCallFake (@title) ->
|
||||
spyOn(window, "setTimeout").andCallFake window.fakeSetTimeout
|
||||
spyOn(window, "clearTimeout").andCallFake window.fakeClearTimeout
|
||||
spyOn(File.prototype, "detectResurrectionAfterDelay").andCallFake -> @detectResurrection()
|
||||
spyOn(pathwatcher.File.prototype, "detectResurrectionAfterDelay").andCallFake -> @detectResurrection()
|
||||
spyOn(Editor.prototype, "shouldPromptToSave").andReturn false
|
||||
|
||||
# make tokenization synchronous
|
||||
TokenizedBuffer.prototype.chunkSize = Infinity
|
||||
spyOn(TokenizedBuffer.prototype, "tokenizeInBackground").andCallFake -> @tokenizeNextChunk()
|
||||
|
||||
pasteboardContent = 'initial pasteboard content'
|
||||
spyOn(clipboard, 'writeText').andCallFake (text) -> pasteboardContent = text
|
||||
spyOn(clipboard, 'readText').andCallFake -> pasteboardContent
|
||||
clipboardContent = 'initial clipboard content'
|
||||
spyOn(clipboard, 'writeText').andCallFake (text) -> clipboardContent = text
|
||||
spyOn(clipboard, 'readText').andCallFake -> clipboardContent
|
||||
|
||||
addCustomMatchers(this)
|
||||
|
||||
@@ -159,6 +162,16 @@ addCustomMatchers = (spec) ->
|
||||
@message = -> return "Expected path '" + @actual + "'" + notText + " to exist."
|
||||
fs.existsSync(@actual)
|
||||
|
||||
toHaveFocus: ->
|
||||
notText = this.isNot and " not" or ""
|
||||
if not document.hasFocus()
|
||||
console.error "Specs will fail because the Dev Tools have focus. To fix this close the Dev Tools or click the spec runner."
|
||||
|
||||
@message = -> return "Expected element '" + @actual + "' or its descendants" + notText + " to have focus."
|
||||
element = @actual
|
||||
element = element.get(0) if element.jquery
|
||||
element.webkitMatchesSelector(":focus") or element.querySelector(":focus")
|
||||
|
||||
window.keyIdentifierForKey = (key) ->
|
||||
if key.length > 1 # named key
|
||||
key
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{_, fs, Git} = require 'atom'
|
||||
_ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
{Git} = require 'atom'
|
||||
path = require 'path'
|
||||
require './spec-helper'
|
||||
|
||||
|
||||
+30
-18
@@ -1,13 +1,21 @@
|
||||
{fs} = require 'atom'
|
||||
path = require 'path'
|
||||
fs = require 'fs-plus'
|
||||
temp = require 'temp'
|
||||
|
||||
describe "the `syntax` global", ->
|
||||
beforeEach ->
|
||||
atom.packages.activatePackage('language-text', sync: true)
|
||||
atom.packages.activatePackage('language-javascript', sync: true)
|
||||
atom.packages.activatePackage('language-coffee-script', sync: true)
|
||||
atom.packages.activatePackage('language-ruby', sync: true)
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-text')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-javascript')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-coffee-script')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-ruby')
|
||||
|
||||
describe "serialization", ->
|
||||
it "remembers grammar overrides by path", ->
|
||||
@@ -20,29 +28,33 @@ describe "the `syntax` global", ->
|
||||
|
||||
describe ".selectGrammar(filePath)", ->
|
||||
it "can use the filePath to load the correct grammar based on the grammar's filetype", ->
|
||||
atom.packages.activatePackage('language-git', sync: true)
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-git')
|
||||
|
||||
expect(atom.syntax.selectGrammar("file.js").name).toBe "JavaScript" # based on extension (.js)
|
||||
expect(atom.syntax.selectGrammar(path.join(temp.dir, '.git', 'config')).name).toBe "Git Config" # based on end of the path (.git/config)
|
||||
expect(atom.syntax.selectGrammar("Rakefile").name).toBe "Ruby" # based on the file's basename (Rakefile)
|
||||
expect(atom.syntax.selectGrammar("curb").name).toBe "Null Grammar"
|
||||
expect(atom.syntax.selectGrammar("/hu.git/config").name).toBe "Null Grammar"
|
||||
runs ->
|
||||
expect(atom.syntax.selectGrammar("file.js").name).toBe "JavaScript" # based on extension (.js)
|
||||
expect(atom.syntax.selectGrammar(path.join(temp.dir, '.git', 'config')).name).toBe "Git Config" # based on end of the path (.git/config)
|
||||
expect(atom.syntax.selectGrammar("Rakefile").name).toBe "Ruby" # based on the file's basename (Rakefile)
|
||||
expect(atom.syntax.selectGrammar("curb").name).toBe "Null Grammar"
|
||||
expect(atom.syntax.selectGrammar("/hu.git/config").name).toBe "Null Grammar"
|
||||
|
||||
it "uses the filePath's shebang line if the grammar cannot be determined by the extension or basename", ->
|
||||
filePath = require.resolve("./fixtures/shebang")
|
||||
expect(atom.syntax.selectGrammar(filePath).name).toBe "Ruby"
|
||||
|
||||
it "uses the number of newlines in the first line regex to determine the number of lines to test against", ->
|
||||
atom.packages.activatePackage('language-property-list', sync: true)
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-property-list')
|
||||
|
||||
fileContent = "first-line\n<html>"
|
||||
expect(atom.syntax.selectGrammar("dummy.coffee", fileContent).name).toBe "CoffeeScript"
|
||||
runs ->
|
||||
fileContent = "first-line\n<html>"
|
||||
expect(atom.syntax.selectGrammar("dummy.coffee", fileContent).name).toBe "CoffeeScript"
|
||||
|
||||
fileContent = '<?xml version="1.0" encoding="UTF-8"?>'
|
||||
expect(atom.syntax.selectGrammar("grammar.tmLanguage", fileContent).name).toBe "Null Grammar"
|
||||
fileContent = '<?xml version="1.0" encoding="UTF-8"?>'
|
||||
expect(atom.syntax.selectGrammar("grammar.tmLanguage", fileContent).name).toBe "Null Grammar"
|
||||
|
||||
fileContent += '\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">'
|
||||
expect(atom.syntax.selectGrammar("grammar.tmLanguage", fileContent).name).toBe "Property List (XML)"
|
||||
fileContent += '\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">'
|
||||
expect(atom.syntax.selectGrammar("grammar.tmLanguage", fileContent).name).toBe "Property List (XML)"
|
||||
|
||||
it "doesn't read the file when the file contents are specified", ->
|
||||
filePath = require.resolve("./fixtures/shebang")
|
||||
|
||||
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -1,10 +1,11 @@
|
||||
path = require 'path'
|
||||
|
||||
{$, $$, fs, WorkspaceView} = require 'atom'
|
||||
{$, $$, WorkspaceView} = require 'atom'
|
||||
fs = require 'fs-plus'
|
||||
temp = require 'temp'
|
||||
|
||||
ThemeManager = require '../src/theme-manager'
|
||||
AtomPackage = require '../src/atom-package'
|
||||
Package = require '../src/package'
|
||||
|
||||
describe "ThemeManager", ->
|
||||
themeManager = null
|
||||
@@ -26,11 +27,14 @@ describe "ThemeManager", ->
|
||||
expect(themes.length).toBeGreaterThan(2)
|
||||
|
||||
it 'getActiveThemes get all the active themes', ->
|
||||
themeManager.activateThemes()
|
||||
names = atom.config.get('core.themes')
|
||||
expect(names.length).toBeGreaterThan(0)
|
||||
themes = themeManager.getActiveThemes()
|
||||
expect(themes).toHaveLength(names.length)
|
||||
waitsForPromise ->
|
||||
themeManager.activateThemes()
|
||||
|
||||
runs ->
|
||||
names = atom.config.get('core.themes')
|
||||
expect(names.length).toBeGreaterThan(0)
|
||||
themes = themeManager.getActiveThemes()
|
||||
expect(themes).toHaveLength(names.length)
|
||||
|
||||
describe "getImportPaths()", ->
|
||||
it "returns the theme directories before the themes are loaded", ->
|
||||
@@ -51,29 +55,58 @@ describe "ThemeManager", ->
|
||||
it "add/removes stylesheets to reflect the new config value", ->
|
||||
themeManager.on 'reloaded', reloadHandler = jasmine.createSpy()
|
||||
spyOn(themeManager, 'getUserStylesheetPath').andCallFake -> null
|
||||
themeManager.activateThemes()
|
||||
|
||||
atom.config.set('core.themes', [])
|
||||
expect($('style.theme').length).toBe 0
|
||||
expect(reloadHandler).toHaveBeenCalled()
|
||||
waitsForPromise ->
|
||||
themeManager.activateThemes()
|
||||
|
||||
atom.config.set('core.themes', ['atom-dark-syntax'])
|
||||
expect($('style.theme').length).toBe 1
|
||||
expect($('style.theme:eq(0)').attr('id')).toMatch /atom-dark-syntax/
|
||||
runs ->
|
||||
reloadHandler.reset()
|
||||
atom.config.set('core.themes', [])
|
||||
|
||||
atom.config.set('core.themes', ['atom-light-syntax', 'atom-dark-syntax'])
|
||||
expect($('style.theme').length).toBe 2
|
||||
expect($('style.theme:eq(0)').attr('id')).toMatch /atom-dark-syntax/
|
||||
expect($('style.theme:eq(1)').attr('id')).toMatch /atom-light-syntax/
|
||||
waitsFor ->
|
||||
reloadHandler.callCount == 1
|
||||
|
||||
atom.config.set('core.themes', [])
|
||||
expect($('style.theme').length).toBe 0
|
||||
runs ->
|
||||
reloadHandler.reset()
|
||||
expect($('style.theme')).toHaveLength 0
|
||||
atom.config.set('core.themes', ['atom-dark-syntax'])
|
||||
|
||||
# atom-dark-ui has an directory path, the syntax one doesn't
|
||||
atom.config.set('core.themes', ['theme-with-index-less', 'atom-dark-ui'])
|
||||
importPaths = themeManager.getImportPaths()
|
||||
expect(importPaths.length).toBe 1
|
||||
expect(importPaths[0]).toContain 'atom-dark-ui'
|
||||
waitsFor ->
|
||||
reloadHandler.callCount == 1
|
||||
|
||||
runs ->
|
||||
reloadHandler.reset()
|
||||
expect($('style.theme')).toHaveLength 1
|
||||
expect($('style.theme:eq(0)').attr('id')).toMatch /atom-dark-syntax/
|
||||
atom.config.set('core.themes', ['atom-light-syntax', 'atom-dark-syntax'])
|
||||
|
||||
waitsFor ->
|
||||
reloadHandler.callCount == 1
|
||||
|
||||
runs ->
|
||||
reloadHandler.reset()
|
||||
expect($('style.theme')).toHaveLength 2
|
||||
expect($('style.theme:eq(0)').attr('id')).toMatch /atom-dark-syntax/
|
||||
expect($('style.theme:eq(1)').attr('id')).toMatch /atom-light-syntax/
|
||||
atom.config.set('core.themes', [])
|
||||
|
||||
waitsFor ->
|
||||
reloadHandler.callCount == 1
|
||||
|
||||
runs ->
|
||||
reloadHandler.reset()
|
||||
expect($('style.theme')).toHaveLength 0
|
||||
# atom-dark-ui has an directory path, the syntax one doesn't
|
||||
atom.config.set('core.themes', ['theme-with-index-less', 'atom-dark-ui'])
|
||||
|
||||
waitsFor ->
|
||||
reloadHandler.callCount == 1
|
||||
|
||||
runs ->
|
||||
expect($('style.theme')).toHaveLength 2
|
||||
importPaths = themeManager.getImportPaths()
|
||||
expect(importPaths.length).toBe 1
|
||||
expect(importPaths[0]).toContain 'atom-dark-ui'
|
||||
|
||||
describe "when a theme fails to load", ->
|
||||
it "logs a warning", ->
|
||||
@@ -145,31 +178,40 @@ describe "ThemeManager", ->
|
||||
atom.workspaceView = new WorkspaceView
|
||||
atom.workspaceView.append $$ -> @div class: 'editor'
|
||||
atom.workspaceView.attachToDom()
|
||||
themeManager.activateThemes()
|
||||
|
||||
waitsForPromise ->
|
||||
themeManager.activateThemes()
|
||||
|
||||
it "loads the correct values from the theme's ui-variables file", ->
|
||||
themeManager.on 'reloaded', reloadHandler = jasmine.createSpy()
|
||||
atom.config.set('core.themes', ['theme-with-ui-variables'])
|
||||
|
||||
# an override loaded in the base css
|
||||
expect(atom.workspaceView.css("background-color")).toBe "rgb(0, 0, 255)"
|
||||
waitsFor ->
|
||||
reloadHandler.callCount > 0
|
||||
|
||||
# from within the theme itself
|
||||
expect($(".editor").css("padding-top")).toBe "150px"
|
||||
expect($(".editor").css("padding-right")).toBe "150px"
|
||||
expect($(".editor").css("padding-bottom")).toBe "150px"
|
||||
runs ->
|
||||
# an override loaded in the base css
|
||||
expect(atom.workspaceView.css("background-color")).toBe "rgb(0, 0, 255)"
|
||||
|
||||
# from within the theme itself
|
||||
expect($(".editor").css("padding-top")).toBe "150px"
|
||||
expect($(".editor").css("padding-right")).toBe "150px"
|
||||
expect($(".editor").css("padding-bottom")).toBe "150px"
|
||||
|
||||
describe "when the user stylesheet changes", ->
|
||||
it "reloads it", ->
|
||||
userStylesheetPath = path.join(temp.mkdirSync("atom"), 'styles.css')
|
||||
userStylesheetPath = path.join(temp.mkdirSync("atom"), 'styles.less')
|
||||
fs.writeFileSync(userStylesheetPath, 'body {border-style: dotted !important;}')
|
||||
|
||||
spyOn(themeManager, 'getUserStylesheetPath').andReturn userStylesheetPath
|
||||
themeManager.activateThemes()
|
||||
|
||||
expect($(document.body).css('border-style')).toBe 'dotted'
|
||||
spyOn(themeManager, 'loadUserStylesheet').andCallThrough()
|
||||
waitsForPromise ->
|
||||
themeManager.activateThemes()
|
||||
|
||||
fs.writeFileSync(userStylesheetPath, 'body {border-style: dashed}')
|
||||
runs ->
|
||||
expect($(document.body).css('border-style')).toBe 'dotted'
|
||||
spyOn(themeManager, 'loadUserStylesheet').andCallThrough()
|
||||
fs.writeFileSync(userStylesheetPath, 'body {border-style: dashed}')
|
||||
|
||||
waitsFor ->
|
||||
themeManager.loadUserStylesheet.callCount is 1
|
||||
@@ -183,3 +225,14 @@ describe "ThemeManager", ->
|
||||
|
||||
runs ->
|
||||
expect($(document.body).css('border-style')).toBe 'none'
|
||||
|
||||
describe "when a non-existent theme is present in the config", ->
|
||||
it "logs a warning but does not throw an exception (regression)", ->
|
||||
waitsForPromise ->
|
||||
themeManager.activateThemes()
|
||||
|
||||
runs ->
|
||||
spyOn(console, 'warn')
|
||||
expect(-> atom.config.set('core.themes', ['atom-light-ui', 'theme-really-does-not-exist'])).not.toThrow()
|
||||
expect(console.warn.callCount).toBe 1
|
||||
expect(console.warn.argsForCall[0][0].length).toBeGreaterThan 0
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{_} = require 'atom'
|
||||
_ = require 'underscore-plus'
|
||||
|
||||
module.exports =
|
||||
class TimeReporter extends jasmine.Reporter
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
TokenizedBuffer = require '../src/tokenized-buffer'
|
||||
{_} = require 'atom'
|
||||
_ = require 'underscore-plus'
|
||||
|
||||
describe "TokenizedBuffer", ->
|
||||
[tokenizedBuffer, buffer, changeHandler] = []
|
||||
|
||||
beforeEach ->
|
||||
atom.packages.activatePackage('language-javascript', sync: true)
|
||||
# enable async tokenization
|
||||
TokenizedBuffer.prototype.chunkSize = 5
|
||||
jasmine.unspy(TokenizedBuffer.prototype, 'tokenizeInBackground')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-javascript')
|
||||
|
||||
startTokenizing = (tokenizedBuffer) ->
|
||||
tokenizedBuffer.setVisible(true)
|
||||
|
||||
@@ -311,10 +313,13 @@ describe "TokenizedBuffer", ->
|
||||
|
||||
describe "when the buffer contains hard-tabs", ->
|
||||
beforeEach ->
|
||||
atom.packages.activatePackage('language-coffee-script', sync: true)
|
||||
buffer = atom.project.bufferForPathSync('sample-with-tabs.coffee')
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
startTokenizing(tokenizedBuffer)
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-coffee-script')
|
||||
|
||||
runs ->
|
||||
buffer = atom.project.bufferForPathSync('sample-with-tabs.coffee')
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
startTokenizing(tokenizedBuffer)
|
||||
|
||||
afterEach ->
|
||||
tokenizedBuffer.destroy()
|
||||
@@ -341,14 +346,17 @@ describe "TokenizedBuffer", ->
|
||||
|
||||
describe "when the buffer contains surrogate pairs", ->
|
||||
beforeEach ->
|
||||
atom.packages.activatePackage('language-javascript', sync: true)
|
||||
buffer = atom.project.bufferForPathSync 'sample-with-pairs.js'
|
||||
buffer.setText """
|
||||
'abc\uD835\uDF97def'
|
||||
//\uD835\uDF97xyz
|
||||
"""
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-javascript')
|
||||
|
||||
runs ->
|
||||
buffer = atom.project.bufferForPathSync 'sample-with-pairs.js'
|
||||
buffer.setText """
|
||||
'abc\uD835\uDF97def'
|
||||
//\uD835\uDF97xyz
|
||||
"""
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
|
||||
afterEach ->
|
||||
tokenizedBuffer.destroy()
|
||||
@@ -379,22 +387,30 @@ describe "TokenizedBuffer", ->
|
||||
|
||||
describe "when the grammar is updated because a grammar it includes is activated", ->
|
||||
it "retokenizes the buffer", ->
|
||||
atom.packages.activatePackage('language-ruby-on-rails', sync: true)
|
||||
atom.packages.activatePackage('language-ruby', sync: true)
|
||||
|
||||
buffer = atom.project.bufferForPathSync()
|
||||
buffer.setText "<div class='name'><%= User.find(2).full_name %></div>"
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
tokenizedBuffer.setGrammar(atom.syntax.selectGrammar('test.erb'))
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-ruby-on-rails')
|
||||
|
||||
{tokens} = tokenizedBuffer.lineForScreenRow(0)
|
||||
expect(tokens[0]).toEqual value: "<div class='name'>", scopes: ["text.html.ruby"]
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-ruby')
|
||||
|
||||
atom.packages.activatePackage('language-html', sync: true)
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
{tokens} = tokenizedBuffer.lineForScreenRow(0)
|
||||
expect(tokens[0]).toEqual value: '<', scopes: ["text.html.ruby","meta.tag.block.any.html","punctuation.definition.tag.begin.html"]
|
||||
runs ->
|
||||
buffer = atom.project.bufferForPathSync()
|
||||
buffer.setText "<div class='name'><%= User.find(2).full_name %></div>"
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
tokenizedBuffer.setGrammar(atom.syntax.selectGrammar('test.erb'))
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
|
||||
{tokens} = tokenizedBuffer.lineForScreenRow(0)
|
||||
expect(tokens[0]).toEqual value: "<div class='name'>", scopes: ["text.html.ruby"]
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-html')
|
||||
|
||||
runs ->
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
{tokens} = tokenizedBuffer.lineForScreenRow(0)
|
||||
expect(tokens[0]).toEqual value: '<', scopes: ["text.html.ruby","meta.tag.block.any.html","punctuation.definition.tag.begin.html"]
|
||||
|
||||
describe ".tokenForPosition(position)", ->
|
||||
afterEach ->
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{$, $$, fs} = require 'atom'
|
||||
{$, $$} = require 'atom'
|
||||
path = require 'path'
|
||||
Editor = require '../src/editor'
|
||||
WindowEventHandler = require '../src/window-event-handler'
|
||||
|
||||
+137
-95
@@ -7,49 +7,141 @@ describe "Workspace", ->
|
||||
atom.project.setPath(atom.project.resolve('dir'))
|
||||
workspace = new Workspace
|
||||
|
||||
describe "::open(uri)", ->
|
||||
describe "::open(uri, options)", ->
|
||||
beforeEach ->
|
||||
spyOn(workspace.activePane, 'activate')
|
||||
|
||||
describe "when called without a uri", ->
|
||||
it "adds and activates an empty editor on the active pane", ->
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
workspace.open().then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(editor.getPath()).toBeUndefined()
|
||||
expect(workspace.activePane.items).toEqual [editor]
|
||||
expect(workspace.activePaneItem).toBe editor
|
||||
expect(workspace.activePane.activate).toHaveBeenCalled()
|
||||
|
||||
describe "when called with a uri", ->
|
||||
describe "when the active pane already has an editor for the given uri", ->
|
||||
it "activates the existing editor on the active pane", ->
|
||||
editor1 = workspace.openSync('a')
|
||||
editor2 = workspace.openSync('b')
|
||||
spyOn(workspace.activePane, 'activate').andCallThrough()
|
||||
|
||||
describe "when the 'searchAllPanes' option is false (default)", ->
|
||||
describe "when called without a uri", ->
|
||||
it "adds and activates an empty editor on the active pane", ->
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
workspace.open('a').then (o) -> editor = o
|
||||
workspace.open().then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(editor).toBe editor1
|
||||
expect(workspace.activePaneItem).toBe editor
|
||||
expect(workspace.activePane.activate).toHaveBeenCalled()
|
||||
|
||||
describe "when the active pane does not have an editor for the given uri", ->
|
||||
it "adds and activates a new editor for the given path on the active pane", ->
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
workspace.open('a').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(editor.getUri()).toBe 'a'
|
||||
expect(workspace.activePaneItem).toBe editor
|
||||
expect(editor.getPath()).toBeUndefined()
|
||||
expect(workspace.activePane.items).toEqual [editor]
|
||||
expect(workspace.activePaneItem).toBe editor
|
||||
expect(workspace.activePane.activate).toHaveBeenCalled()
|
||||
|
||||
describe "when called with a uri", ->
|
||||
describe "when the active pane already has an editor for the given uri", ->
|
||||
it "activates the existing editor on the active pane", ->
|
||||
editor1 = workspace.openSync('a')
|
||||
editor2 = workspace.openSync('b')
|
||||
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
workspace.open('a').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(editor).toBe editor1
|
||||
expect(workspace.activePaneItem).toBe editor
|
||||
expect(workspace.activePane.activate).toHaveBeenCalled()
|
||||
|
||||
describe "when the active pane does not have an editor for the given uri", ->
|
||||
it "adds and activates a new editor for the given path on the active pane", ->
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
workspace.open('a').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(editor.getUri()).toBe atom.project.resolve('a')
|
||||
expect(workspace.activePaneItem).toBe editor
|
||||
expect(workspace.activePane.items).toEqual [editor]
|
||||
expect(workspace.activePane.activate).toHaveBeenCalled()
|
||||
|
||||
describe "when the 'searchAllPanes' option is true", ->
|
||||
describe "when an editor for the given uri is already open on an inactive pane", ->
|
||||
it "activates the existing editor on the inactive pane, then activates that pane", ->
|
||||
editor1 = workspace.openSync('a')
|
||||
pane1 = workspace.activePane
|
||||
pane2 = workspace.activePane.splitRight()
|
||||
editor2 = workspace.openSync('b')
|
||||
expect(workspace.activePaneItem).toBe editor2
|
||||
|
||||
waitsForPromise ->
|
||||
workspace.open('a', searchAllPanes: true)
|
||||
|
||||
runs ->
|
||||
expect(workspace.activePane).toBe pane1
|
||||
expect(workspace.activePaneItem).toBe editor1
|
||||
|
||||
describe "when no editor for the given uri is open in any pane", ->
|
||||
it "opens an editor for the given uri in the active pane", ->
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
workspace.open('a', searchAllPanes: true).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(workspace.activePaneItem).toBe editor
|
||||
|
||||
describe "when the 'split' option is set", ->
|
||||
describe "when the 'split' option is 'left'", ->
|
||||
it "opens the editor in the leftmost pane of the current pane axis", ->
|
||||
pane1 = workspace.activePane
|
||||
pane2 = pane1.splitRight()
|
||||
expect(workspace.activePane).toBe pane2
|
||||
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
workspace.open('a', split: 'left').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(workspace.activePane).toBe pane1
|
||||
expect(pane1.items).toEqual [editor]
|
||||
expect(pane2.items).toEqual []
|
||||
|
||||
# Focus right pane and reopen the file on the left
|
||||
waitsForPromise ->
|
||||
pane2.focus()
|
||||
workspace.open('a', split: 'left').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(workspace.activePane).toBe pane1
|
||||
expect(pane1.items).toEqual [editor]
|
||||
expect(pane2.items).toEqual []
|
||||
|
||||
describe "when the 'split' option is 'right'", ->
|
||||
it "opens the editor in the rightmost pane of the current pane axis", ->
|
||||
editor = null
|
||||
pane1 = workspace.activePane
|
||||
pane2 = null
|
||||
waitsForPromise ->
|
||||
workspace.open('a', split: 'right').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
pane2 = workspace.getPanes().filter((p) -> p != pane1)[0]
|
||||
expect(workspace.activePane).toBe pane2
|
||||
expect(pane1.items).toEqual []
|
||||
expect(pane2.items).toEqual [editor]
|
||||
|
||||
# Focus right pane and reopen the file on the right
|
||||
waitsForPromise ->
|
||||
pane1.focus()
|
||||
workspace.open('a', split: 'right').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(workspace.activePane).toBe pane2
|
||||
expect(pane1.items).toEqual []
|
||||
expect(pane2.items).toEqual [editor]
|
||||
|
||||
describe "when passed a path that matches a custom opener", ->
|
||||
it "returns the resource returned by the custom opener", ->
|
||||
fooOpener = (pathToOpen, options) -> { foo: pathToOpen, options } if pathToOpen?.match(/\.foo/)
|
||||
barOpener = (pathToOpen) -> { bar: pathToOpen } if pathToOpen?.match(/^bar:\/\//)
|
||||
workspace.registerOpener(fooOpener)
|
||||
workspace.registerOpener(barOpener)
|
||||
|
||||
waitsForPromise ->
|
||||
pathToOpen = atom.project.resolve('a.foo')
|
||||
workspace.open(pathToOpen, hey: "there").then (item) ->
|
||||
expect(item).toEqual { foo: pathToOpen, options: {hey: "there"} }
|
||||
|
||||
waitsForPromise ->
|
||||
workspace.open("bar://baz").then (item) ->
|
||||
expect(item).toEqual { bar: "bar://baz" }
|
||||
|
||||
describe "::openSync(uri, options)", ->
|
||||
[activePane, initialItemCount] = []
|
||||
|
||||
@@ -92,61 +184,6 @@ describe "Workspace", ->
|
||||
workspace.openSync('b', activatePane: false)
|
||||
expect(activePane.activate).not.toHaveBeenCalled()
|
||||
|
||||
describe "::openSingletonSync(uri, options)", ->
|
||||
describe "when an editor for the given uri is already open on the active pane", ->
|
||||
it "activates the existing editor", ->
|
||||
editor1 = workspace.openSync('a')
|
||||
editor2 = workspace.openSync('b')
|
||||
expect(workspace.activePaneItem).toBe editor2
|
||||
workspace.openSingletonSync('a')
|
||||
expect(workspace.activePaneItem).toBe editor1
|
||||
|
||||
describe "when an editor for the given uri is already open on an inactive pane", ->
|
||||
it "activates the existing editor on the inactive pane, then activates that pane", ->
|
||||
editor1 = workspace.openSync('a')
|
||||
pane1 = workspace.activePane
|
||||
pane2 = workspace.activePane.splitRight()
|
||||
editor2 = workspace.openSync('b')
|
||||
expect(workspace.activePaneItem).toBe editor2
|
||||
workspace.openSingletonSync('a')
|
||||
expect(workspace.activePane).toBe pane1
|
||||
expect(workspace.activePaneItem).toBe editor1
|
||||
|
||||
describe "when no editor for the given uri is open in any pane", ->
|
||||
it "opens an editor for the given uri in the active pane", ->
|
||||
editor1 = workspace.openSingletonSync('a')
|
||||
expect(workspace.activePaneItem).toBe editor1
|
||||
|
||||
describe "when the 'split' option is 'left'", ->
|
||||
it "opens the editor in the leftmost pane of the current pane axis", ->
|
||||
pane1 = workspace.activePane
|
||||
pane2 = pane1.splitRight()
|
||||
expect(workspace.activePane).toBe pane2
|
||||
editor1 = workspace.openSingletonSync('a', split: 'left')
|
||||
expect(workspace.activePane).toBe pane1
|
||||
expect(pane1.items).toEqual [editor1]
|
||||
expect(pane2.items).toEqual []
|
||||
|
||||
describe "when the 'split' option is 'right'", ->
|
||||
describe "when the active pane is in a horizontal pane axis", ->
|
||||
it "activates the editor on the rightmost pane of the current pane axis", ->
|
||||
pane1 = workspace.activePane
|
||||
pane2 = pane1.splitRight()
|
||||
pane1.activate()
|
||||
editor1 = workspace.openSingletonSync('a', split: 'right')
|
||||
expect(workspace.activePane).toBe pane2
|
||||
expect(pane2.items).toEqual [editor1]
|
||||
expect(pane1.items).toEqual []
|
||||
|
||||
describe "when the active pane is not in a horizontal pane axis", ->
|
||||
it "splits the current pane to the right, then activates the editor on the right pane", ->
|
||||
pane1 = workspace.activePane
|
||||
editor1 = workspace.openSingletonSync('a', split: 'right')
|
||||
pane2 = workspace.activePane
|
||||
expect(workspace.paneContainer.root.children).toEqual [pane1, pane2]
|
||||
expect(pane2.items).toEqual [editor1]
|
||||
expect(pane1.items).toEqual []
|
||||
|
||||
describe "::reopenItemSync()", ->
|
||||
it "opens the uri associated with the last closed pane that isn't currently open", ->
|
||||
pane = workspace.activePane
|
||||
@@ -162,23 +199,23 @@ describe "Workspace", ->
|
||||
expect(workspace.activePaneItem.getUri()).not.toBeUndefined()
|
||||
|
||||
# destroy all items
|
||||
expect(workspace.activePaneItem.getUri()).toBe 'file1'
|
||||
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('file1')
|
||||
pane.destroyActiveItem()
|
||||
expect(workspace.activePaneItem.getUri()).toBe 'b'
|
||||
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('b')
|
||||
pane.destroyActiveItem()
|
||||
expect(workspace.activePaneItem.getUri()).toBe 'a'
|
||||
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('a')
|
||||
pane.destroyActiveItem()
|
||||
|
||||
# reopens items with uris
|
||||
expect(workspace.activePaneItem).toBeUndefined()
|
||||
workspace.reopenItemSync()
|
||||
expect(workspace.activePaneItem.getUri()).toBe 'a'
|
||||
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('a')
|
||||
|
||||
# does not reopen items that are already open
|
||||
workspace.openSync('b')
|
||||
expect(workspace.activePaneItem.getUri()).toBe 'b'
|
||||
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('b')
|
||||
workspace.reopenItemSync()
|
||||
expect(workspace.activePaneItem.getUri()).toBe 'file1'
|
||||
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('file1')
|
||||
|
||||
describe "::increase/decreaseFontSize()", ->
|
||||
it "increases/decreases the font size without going below 1", ->
|
||||
@@ -193,3 +230,8 @@ describe "Workspace", ->
|
||||
expect(atom.config.get('editor.fontSize')).toBe 1
|
||||
workspace.decreaseFontSize()
|
||||
expect(atom.config.get('editor.fontSize')).toBe 1
|
||||
|
||||
describe "::openLicense()", ->
|
||||
it "opens the license as plain-text in a buffer", ->
|
||||
waitsForPromise -> workspace.openLicense()
|
||||
runs -> expect(workspace.activePaneItem.getText()).toMatch /Copyright/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{$, $$, fs, WorkspaceView, View} = require 'atom'
|
||||
{$, $$, WorkspaceView, View} = require 'atom'
|
||||
Q = require 'q'
|
||||
path = require 'path'
|
||||
temp = require 'temp'
|
||||
@@ -36,12 +36,12 @@ describe "WorkspaceView", ->
|
||||
editorView1 = atom.workspaceView.getActiveView()
|
||||
buffer = editorView1.getEditor().getBuffer()
|
||||
editorView1.splitRight()
|
||||
expect(atom.workspaceView.getActivePane()).toBe atom.workspaceView.getPanes()[1]
|
||||
expect(atom.workspaceView.getActivePane()).toBe atom.workspaceView.getPaneViews()[1]
|
||||
|
||||
simulateReload()
|
||||
|
||||
expect(atom.workspaceView.getEditorViews().length).toBe 2
|
||||
expect(atom.workspaceView.getActivePane()).toBe atom.workspaceView.getPanes()[1]
|
||||
expect(atom.workspaceView.getActivePane()).toBe atom.workspaceView.getPaneViews()[1]
|
||||
expect(atom.workspaceView.title).toBe "untitled - #{atom.project.getPath()}"
|
||||
|
||||
describe "when there are open editors", ->
|
||||
|
||||
@@ -1,252 +0,0 @@
|
||||
Package = require './package'
|
||||
fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
_ = require 'underscore-plus'
|
||||
{$} = require './space-pen-extensions'
|
||||
CSON = require 'season'
|
||||
{Emitter} = require 'emissary'
|
||||
|
||||
### Internal: Loads and resolves packages. ###
|
||||
|
||||
module.exports =
|
||||
class AtomPackage extends Package
|
||||
Emitter.includeInto(this)
|
||||
|
||||
@stylesheetsDir: 'stylesheets'
|
||||
|
||||
metadata: null
|
||||
keymaps: null
|
||||
menus: null
|
||||
stylesheets: null
|
||||
grammars: null
|
||||
scopedProperties: null
|
||||
mainModulePath: null
|
||||
resolvedMainModulePath: false
|
||||
mainModule: null
|
||||
|
||||
constructor: (path, {@metadata}) ->
|
||||
super(path)
|
||||
@reset()
|
||||
|
||||
getType: -> 'atom'
|
||||
|
||||
getStylesheetType: -> 'bundled'
|
||||
|
||||
load: ->
|
||||
@measure 'loadTime', =>
|
||||
try
|
||||
@metadata ?= Package.loadMetadata(@path)
|
||||
|
||||
@loadKeymaps()
|
||||
@loadMenus()
|
||||
@loadStylesheets()
|
||||
@loadGrammars()
|
||||
@loadScopedProperties()
|
||||
|
||||
if @metadata.activationEvents?
|
||||
@registerDeferredDeserializers()
|
||||
else
|
||||
@requireMainModule()
|
||||
|
||||
catch e
|
||||
console.warn "Failed to load package named '#{@name}'", e.stack ? e
|
||||
this
|
||||
|
||||
reset: ->
|
||||
@stylesheets = []
|
||||
@keymaps = []
|
||||
@menus = []
|
||||
@grammars = []
|
||||
@scopedProperties = []
|
||||
|
||||
activate: ({immediate}={}) ->
|
||||
@measure 'activateTime', =>
|
||||
@activateResources()
|
||||
if @metadata.activationEvents? and not immediate
|
||||
@subscribeToActivationEvents()
|
||||
else
|
||||
@activateNow()
|
||||
|
||||
activateNow: ->
|
||||
try
|
||||
@activateConfig()
|
||||
@activateStylesheets()
|
||||
if @requireMainModule()
|
||||
@mainModule.activate(atom.packages.getPackageState(@name) ? {})
|
||||
@mainActivated = true
|
||||
catch e
|
||||
console.warn "Failed to activate package named '#{@name}'", e.stack
|
||||
|
||||
activateConfig: ->
|
||||
return if @configActivated
|
||||
|
||||
@requireMainModule()
|
||||
if @mainModule?
|
||||
atom.config.setDefaults(@name, @mainModule.configDefaults)
|
||||
@mainModule.activateConfig?()
|
||||
@configActivated = true
|
||||
|
||||
activateStylesheets: ->
|
||||
return if @stylesheetsActivated
|
||||
|
||||
type = @getStylesheetType()
|
||||
for [stylesheetPath, content] in @stylesheets
|
||||
atom.themes.applyStylesheet(stylesheetPath, content, type)
|
||||
@stylesheetsActivated = true
|
||||
|
||||
activateResources: ->
|
||||
atom.keymap.add(keymapPath, map) for [keymapPath, map] in @keymaps
|
||||
atom.contextMenu.add(menuPath, map['context-menu']) for [menuPath, map] in @menus
|
||||
atom.menu.add(map.menu) for [menuPath, map] in @menus when map.menu
|
||||
grammar.activate() for grammar in @grammars
|
||||
for [scopedPropertiesPath, selector, properties] in @scopedProperties
|
||||
atom.syntax.addProperties(scopedPropertiesPath, selector, properties)
|
||||
|
||||
loadKeymaps: ->
|
||||
@keymaps = @getKeymapPaths().map (keymapPath) -> [keymapPath, CSON.readFileSync(keymapPath)]
|
||||
|
||||
loadMenus: ->
|
||||
@menus = @getMenuPaths().map (menuPath) -> [menuPath, CSON.readFileSync(menuPath)]
|
||||
|
||||
getKeymapPaths: ->
|
||||
keymapsDirPath = path.join(@path, 'keymaps')
|
||||
if @metadata.keymaps
|
||||
@metadata.keymaps.map (name) -> fs.resolve(keymapsDirPath, name, ['json', 'cson', ''])
|
||||
else
|
||||
fs.listSync(keymapsDirPath, ['cson', 'json'])
|
||||
|
||||
getMenuPaths: ->
|
||||
menusDirPath = path.join(@path, 'menus')
|
||||
if @metadata.menus
|
||||
@metadata.menus.map (name) -> fs.resolve(menusDirPath, name, ['json', 'cson', ''])
|
||||
else
|
||||
fs.listSync(menusDirPath, ['cson', 'json'])
|
||||
|
||||
loadStylesheets: ->
|
||||
@stylesheets = @getStylesheetPaths().map (stylesheetPath) ->
|
||||
[stylesheetPath, atom.themes.loadStylesheet(stylesheetPath)]
|
||||
|
||||
getStylesheetsPath: ->
|
||||
path.join(@path, @constructor.stylesheetsDir)
|
||||
|
||||
getStylesheetPaths: ->
|
||||
stylesheetDirPath = @getStylesheetsPath()
|
||||
|
||||
if @metadata.stylesheetMain
|
||||
[fs.resolve(@path, @metadata.stylesheetMain)]
|
||||
else if @metadata.stylesheets
|
||||
@metadata.stylesheets.map (name) -> fs.resolve(stylesheetDirPath, name, ['css', 'less', ''])
|
||||
else if indexStylesheet = fs.resolve(@path, 'index', ['css', 'less'])
|
||||
[indexStylesheet]
|
||||
else
|
||||
fs.listSync(stylesheetDirPath, ['css', 'less'])
|
||||
|
||||
loadGrammars: ->
|
||||
@grammars = []
|
||||
grammarsDirPath = path.join(@path, 'grammars')
|
||||
for grammarPath in fs.listSync(grammarsDirPath, ['.json', '.cson'])
|
||||
@grammars.push(atom.syntax.readGrammarSync(grammarPath))
|
||||
|
||||
loadScopedProperties: ->
|
||||
@scopedProperties = []
|
||||
scopedPropertiessDirPath = path.join(@path, 'scoped-properties')
|
||||
for scopedPropertiesPath in fs.listSync(scopedPropertiessDirPath, ['.json', '.cson'])
|
||||
for selector, properties of fs.readObjectSync(scopedPropertiesPath)
|
||||
@scopedProperties.push([scopedPropertiesPath, selector, properties])
|
||||
|
||||
serialize: ->
|
||||
if @mainActivated
|
||||
try
|
||||
@mainModule?.serialize?()
|
||||
catch e
|
||||
console.error "Error serializing package '#{@name}'", e.stack
|
||||
|
||||
deactivate: ->
|
||||
@unsubscribeFromActivationEvents()
|
||||
@deactivateResources()
|
||||
@deactivateConfig()
|
||||
@mainModule?.deactivate?() if @mainActivated
|
||||
@emit('deactivated')
|
||||
|
||||
deactivateConfig: ->
|
||||
@mainModule?.deactivateConfig?()
|
||||
@configActivated = false
|
||||
|
||||
deactivateResources: ->
|
||||
grammar.deactivate() for grammar in @grammars
|
||||
atom.syntax.removeProperties(scopedPropertiesPath) for [scopedPropertiesPath] in @scopedProperties
|
||||
atom.keymap.remove(keymapPath) for [keymapPath] in @keymaps
|
||||
atom.themes.removeStylesheet(stylesheetPath) for [stylesheetPath] in @stylesheets
|
||||
@stylesheetsActivated = false
|
||||
|
||||
reloadStylesheets: ->
|
||||
oldSheets = _.clone(@stylesheets)
|
||||
@loadStylesheets()
|
||||
atom.themes.removeStylesheet(stylesheetPath) for [stylesheetPath] in oldSheets
|
||||
@reloadStylesheet(stylesheetPath, content) for [stylesheetPath, content] in @stylesheets
|
||||
|
||||
reloadStylesheet: (stylesheetPath, content) ->
|
||||
atom.themes.applyStylesheet(stylesheetPath, content, @getStylesheetType())
|
||||
|
||||
requireMainModule: ->
|
||||
return @mainModule if @mainModule?
|
||||
mainModulePath = @getMainModulePath()
|
||||
@mainModule = require(mainModulePath) if fs.isFileSync(mainModulePath)
|
||||
|
||||
getMainModulePath: ->
|
||||
return @mainModulePath if @resolvedMainModulePath
|
||||
@resolvedMainModulePath = true
|
||||
mainModulePath =
|
||||
if @metadata.main
|
||||
path.join(@path, @metadata.main)
|
||||
else
|
||||
path.join(@path, 'index')
|
||||
@mainModulePath = fs.resolveExtension(mainModulePath, ["", _.keys(require.extensions)...])
|
||||
|
||||
registerDeferredDeserializers: ->
|
||||
for deserializerName in @metadata.deferredDeserializers ? []
|
||||
atom.deserializers.addDeferred deserializerName, =>
|
||||
@activateStylesheets()
|
||||
@requireMainModule()
|
||||
|
||||
subscribeToActivationEvents: ->
|
||||
return unless @metadata.activationEvents?
|
||||
if _.isArray(@metadata.activationEvents)
|
||||
atom.workspaceView.command(event, @handleActivationEvent) for event in @metadata.activationEvents
|
||||
else if _.isString(@metadata.activationEvents)
|
||||
atom.workspaceView.command(@metadata.activationEvents, @handleActivationEvent)
|
||||
else
|
||||
atom.workspaceView.command(event, selector, @handleActivationEvent) for event, selector of @metadata.activationEvents
|
||||
|
||||
handleActivationEvent: (event) =>
|
||||
bubblePathEventHandlers = @disableEventHandlersOnBubblePath(event)
|
||||
@activateNow()
|
||||
$(event.target).trigger(event)
|
||||
@restoreEventHandlersOnBubblePath(bubblePathEventHandlers)
|
||||
@unsubscribeFromActivationEvents()
|
||||
|
||||
unsubscribeFromActivationEvents: ->
|
||||
if _.isArray(@metadata.activationEvents)
|
||||
atom.workspaceView.off(event, @handleActivationEvent) for event in @metadata.activationEvents
|
||||
else if _.isString(@metadata.activationEvents)
|
||||
atom.workspaceView.off(@metadata.activationEvents, @handleActivationEvent)
|
||||
else
|
||||
atom.workspaceView.off(event, selector, @handleActivationEvent) for event, selector of @metadata.activationEvents
|
||||
|
||||
disableEventHandlersOnBubblePath: (event) ->
|
||||
bubblePathEventHandlers = []
|
||||
disabledHandler = ->
|
||||
element = $(event.target)
|
||||
while element.length
|
||||
if eventHandlers = element.handlers()?[event.type]
|
||||
for eventHandler in eventHandlers
|
||||
eventHandler.disabledHandler = eventHandler.handler
|
||||
eventHandler.handler = disabledHandler
|
||||
bubblePathEventHandlers.push(eventHandler)
|
||||
element = element.parent()
|
||||
bubblePathEventHandlers
|
||||
|
||||
restoreEventHandlersOnBubblePath: (eventHandlers) ->
|
||||
for eventHandler in eventHandlers
|
||||
eventHandler.handler = eventHandler.disabledHandler
|
||||
delete eventHandler.disabledHandler
|
||||
+100
-79
@@ -6,8 +6,6 @@ path = require 'path'
|
||||
remote = require 'remote'
|
||||
screen = require 'screen'
|
||||
shell = require 'shell'
|
||||
dialog = remote.require 'dialog'
|
||||
app = remote.require 'app'
|
||||
|
||||
_ = require 'underscore-plus'
|
||||
{Model} = require 'theorist'
|
||||
@@ -22,16 +20,18 @@ WindowEventHandler = require './window-event-handler'
|
||||
#
|
||||
# ## Useful properties available:
|
||||
#
|
||||
# * `atom.config` - A {Config} instance
|
||||
# * `atom.contextMenu` - A {ContextMenuManager} instance
|
||||
# * `atom.keymap` - A {Keymap} instance
|
||||
# * `atom.menu` - A {MenuManager} instance
|
||||
# * `atom.workspaceView` - A {WorkspaceView} instance
|
||||
# * `atom.packages` - A {PackageManager} instance
|
||||
# * `atom.pasteboard` - A {Pasteboard} instance
|
||||
# * `atom.project` - A {Project} instance
|
||||
# * `atom.syntax` - A {Syntax} instance
|
||||
# * `atom.themes` - A {ThemeManager} instance
|
||||
# * `atom.clipboard` - A {Clipboard} instance
|
||||
# * `atom.config` - A {Config} instance
|
||||
# * `atom.contextMenu` - A {ContextMenuManager} instance
|
||||
# * `atom.deserializers` - A {DeserializerManager} instance
|
||||
# * `atom.keymap` - A {Keymap} instance
|
||||
# * `atom.menu` - A {MenuManager} instance
|
||||
# * `atom.packages` - A {PackageManager} instance
|
||||
# * `atom.project` - A {Project} instance
|
||||
# * `atom.syntax` - A {Syntax} instance
|
||||
# * `atom.themes` - A {ThemeManager} instance
|
||||
# * `atom.workspace` - A {Workspace} instance
|
||||
# * `atom.workspaceView` - A {WorkspaceView} instance
|
||||
module.exports =
|
||||
class Atom extends Model
|
||||
# Public: Load or create the Atom environment in the given mode.
|
||||
@@ -43,11 +43,11 @@ class Atom extends Model
|
||||
@loadOrCreate: (mode) ->
|
||||
@deserialize(@loadState(mode)) ? new this({mode, version: @getVersion()})
|
||||
|
||||
# Private: Deserializes the Atom environment from a state object
|
||||
# Deserializes the Atom environment from a state object
|
||||
@deserialize: (state) ->
|
||||
new this(state) if state?.version is @getVersion()
|
||||
|
||||
# Private: Loads and returns the serialized state corresponding to this window
|
||||
# Loads and returns the serialized state corresponding to this window
|
||||
# if it exists; otherwise returns undefined.
|
||||
@loadState: (mode) ->
|
||||
statePath = @getStatePath(mode)
|
||||
@@ -65,7 +65,7 @@ class Atom extends Model
|
||||
catch error
|
||||
console.warn "Error parsing window state: #{statePath} #{error.stack}", error
|
||||
|
||||
# Private: Returns the path where the state for the current window will be
|
||||
# Returns the path where the state for the current window will be
|
||||
# located if it exists.
|
||||
@getStatePath: (mode) ->
|
||||
switch mode
|
||||
@@ -82,41 +82,47 @@ class Atom extends Model
|
||||
else
|
||||
null
|
||||
|
||||
# Private: Get the directory path to Atom's configuration area.
|
||||
# Get the directory path to Atom's configuration area.
|
||||
#
|
||||
# Returns the absolute path to ~/.atom
|
||||
@getConfigDirPath: ->
|
||||
@configDirPath ?= fs.absolute('~/.atom')
|
||||
|
||||
# Private: Get the path to Atom's storage directory.
|
||||
# Get the path to Atom's storage directory.
|
||||
#
|
||||
# Returns the absolute path to ~/.atom/storage
|
||||
@getStorageDirPath: ->
|
||||
@storageDirPath ?= path.join(@getConfigDirPath(), 'storage')
|
||||
|
||||
# Private: Returns the load settings hash associated with the current window.
|
||||
# Returns the load settings hash associated with the current window.
|
||||
@getLoadSettings: ->
|
||||
_.deepClone(@loadSettings ?= _.deepClone(@getCurrentWindow().loadSettings))
|
||||
@loadSettings ?= JSON.parse(decodeURIComponent(location.search.substr(14)))
|
||||
cloned = _.deepClone(@loadSettings)
|
||||
# The loadSettings.windowState could be large, request it only when needed.
|
||||
cloned.__defineGetter__ 'windowState', =>
|
||||
@getCurrentWindow().loadSettings.windowState
|
||||
cloned.__defineSetter__ 'windowState', (value) =>
|
||||
@getCurrentWindow().loadSettings.windowState = value
|
||||
cloned
|
||||
|
||||
# Private:
|
||||
@getCurrentWindow: ->
|
||||
remote.getCurrentWindow()
|
||||
|
||||
# Private: Get the version of the Atom application.
|
||||
# Get the version of the Atom application.
|
||||
@getVersion: ->
|
||||
@version ?= app.getVersion()
|
||||
@version ?= @getLoadSettings().appVersion
|
||||
|
||||
# Private: Determine whether the current version is an official release.
|
||||
# Determine whether the current version is an official release.
|
||||
@isReleasedVersion: ->
|
||||
not /\w{7}/.test(@getVersion()) # Check if the release is a 7-character SHA prefix
|
||||
|
||||
workspaceViewParentSelector: 'body'
|
||||
|
||||
# Private: Call .loadOrCreate instead
|
||||
# Call .loadOrCreate instead
|
||||
constructor: (@state) ->
|
||||
{@mode} = @state
|
||||
DeserializerManager = require './deserializer-manager'
|
||||
@deserializers = new DeserializerManager(this)
|
||||
@deserializers = new DeserializerManager()
|
||||
|
||||
# Public: Sets up the basic services that should be available in all modes
|
||||
# (both spec and application). Call after this instance has been assigned to
|
||||
@@ -134,7 +140,7 @@ class Atom extends Model
|
||||
Config = require './config'
|
||||
Keymap = require './keymap'
|
||||
PackageManager = require './package-manager'
|
||||
Pasteboard = require './pasteboard'
|
||||
Clipboard = require './clipboard'
|
||||
Syntax = require './syntax'
|
||||
ThemeManager = require './theme-manager'
|
||||
ContextMenuManager = require './context-menu-manager'
|
||||
@@ -148,13 +154,15 @@ class Atom extends Model
|
||||
@themes = new ThemeManager({packageManager: @packages, configDirPath, resourcePath})
|
||||
@contextMenu = new ContextMenuManager(devMode)
|
||||
@menu = new MenuManager({resourcePath})
|
||||
@pasteboard = new Pasteboard()
|
||||
@clipboard = new Clipboard()
|
||||
|
||||
@syntax = @deserializers.deserialize(@state.syntax) ? new Syntax()
|
||||
|
||||
@subscribe @packages, 'activated', => @watchThemes()
|
||||
|
||||
Project = require './project'
|
||||
TextBuffer = require './text-buffer'
|
||||
TextBuffer = require 'text-buffer'
|
||||
@deserializers.add(TextBuffer)
|
||||
TokenizedBuffer = require './tokenized-buffer'
|
||||
DisplayBuffer = require './display-buffer'
|
||||
Editor = require './editor'
|
||||
@@ -167,7 +175,6 @@ class Atom extends Model
|
||||
# Deprecated: Callers should be converted to use atom.deserializers
|
||||
registerRepresentationClasses: ->
|
||||
|
||||
# Private:
|
||||
setBodyPlatformClass: ->
|
||||
document.body.classList.add("platform-#{process.platform}")
|
||||
|
||||
@@ -196,15 +203,13 @@ class Atom extends Model
|
||||
# + width: The new width.
|
||||
# + height: The new height.
|
||||
setWindowDimensions: ({x, y, width, height}) ->
|
||||
browserWindow = @getCurrentWindow()
|
||||
if width? and height?
|
||||
browserWindow.setSize(width, height)
|
||||
@setSize(width, height)
|
||||
if x? and y?
|
||||
browserWindow.setPosition(x, y)
|
||||
@setPosition(x, y)
|
||||
else
|
||||
browserWindow.center()
|
||||
@center()
|
||||
|
||||
# Private:
|
||||
restoreWindowDimensions: ->
|
||||
workAreaSize = screen.getPrimaryDisplay().workAreaSize
|
||||
windowDimensions = @state.windowDimensions ? {}
|
||||
@@ -213,7 +218,6 @@ class Atom extends Model
|
||||
windowDimensions.width ?= initialSize?.width ? Math.min(workAreaSize.width, 1024)
|
||||
@setWindowDimensions(windowDimensions)
|
||||
|
||||
# Private:
|
||||
storeWindowDimensions: ->
|
||||
@state.windowDimensions = @getWindowDimensions()
|
||||
|
||||
@@ -223,12 +227,10 @@ class Atom extends Model
|
||||
getLoadSettings: ->
|
||||
@constructor.getLoadSettings()
|
||||
|
||||
# Private:
|
||||
deserializeProject: ->
|
||||
Project = require './project'
|
||||
@project ?= @deserializers.deserialize(@project) ? new Project(path: @getLoadSettings().initialPath)
|
||||
|
||||
# Private:
|
||||
deserializeWorkspaceView: ->
|
||||
Workspace = require './workspace'
|
||||
WorkspaceView = require './workspace-view'
|
||||
@@ -236,24 +238,22 @@ class Atom extends Model
|
||||
@workspaceView = new WorkspaceView(@workspace)
|
||||
$(@workspaceViewParentSelector).append(@workspaceView)
|
||||
|
||||
# Private:
|
||||
deserializePackageStates: ->
|
||||
@packages.packageStates = @state.packageStates ? {}
|
||||
delete @state.packageStates
|
||||
|
||||
# Private:
|
||||
deserializeEditorWindow: ->
|
||||
@deserializePackageStates()
|
||||
@deserializeProject()
|
||||
@deserializeWorkspaceView()
|
||||
|
||||
# Private: Call this method when establishing a real application window.
|
||||
# Call this method when establishing a real application window.
|
||||
startEditorWindow: ->
|
||||
CommandInstaller = require './command-installer'
|
||||
resourcePath = atom.getLoadSettings().resourcePath
|
||||
CommandInstaller.installAtomCommand resourcePath, (error) ->
|
||||
CommandInstaller.installAtomCommand resourcePath, false, (error) ->
|
||||
console.warn error.message if error?
|
||||
CommandInstaller.installApmCommand resourcePath, (error) ->
|
||||
CommandInstaller.installApmCommand resourcePath, false, (error) ->
|
||||
console.warn error.message if error?
|
||||
|
||||
@restoreWindowDimensions()
|
||||
@@ -276,7 +276,6 @@ class Atom extends Model
|
||||
|
||||
@displayWindow()
|
||||
|
||||
# Private:
|
||||
unloadEditorWindow: ->
|
||||
return if not @project and not @workspaceView
|
||||
|
||||
@@ -292,11 +291,9 @@ class Atom extends Model
|
||||
@keymap.destroy()
|
||||
@windowState = null
|
||||
|
||||
# Private:
|
||||
loadThemes: ->
|
||||
@themes.load()
|
||||
|
||||
# Private:
|
||||
watchThemes: ->
|
||||
@themes.on 'reloaded', =>
|
||||
# Only reload stylesheets from non-theme packages
|
||||
@@ -309,31 +306,32 @@ class Atom extends Model
|
||||
# Calling this method without an options parameter will open a prompt to pick
|
||||
# a file/folder to open in the new window.
|
||||
#
|
||||
# * options
|
||||
# * pathsToOpen: A string array of paths to open
|
||||
# options - An {Object} with the following keys:
|
||||
# :pathsToOpen - An {Array} of {String} paths to open.
|
||||
open: (options) ->
|
||||
ipc.sendChannel('open', options)
|
||||
|
||||
# Public: Open a confirm dialog.
|
||||
#
|
||||
# ## Example:
|
||||
# ```coffeescript
|
||||
# ## Example
|
||||
#
|
||||
# ```coffee
|
||||
# atom.confirm
|
||||
# message: 'How you feeling?'
|
||||
# detailedMessage: 'Be honest.'
|
||||
# buttons:
|
||||
# Good: -> window.alert('good to hear')
|
||||
# Bad: -> window.alert('bummer')
|
||||
# message: 'How you feeling?'
|
||||
# detailedMessage: 'Be honest.'
|
||||
# buttons:
|
||||
# Good: -> window.alert('good to hear')
|
||||
# Bad: -> window.alert('bummer')
|
||||
# ```
|
||||
#
|
||||
# * options:
|
||||
# + message: The string message to display.
|
||||
# + detailedMessage: The string detailed message to display.
|
||||
# + buttons: Either an array of strings or an object where the values
|
||||
# are callbacks to invoke when clicked.
|
||||
# options - An {Object} with the following keys:
|
||||
# :message - The {String} message to display.
|
||||
# :detailedMessage - The {String} detailed message to display.
|
||||
# :buttons - Either an array of strings or an object where keys are
|
||||
# button names and the values are callbacks to invoke when
|
||||
# clicked.
|
||||
#
|
||||
# Returns the chosen index if buttons was an array or the return of the
|
||||
# callback if buttons was an object.
|
||||
# Returns the chosen button index {Number} if the buttons option was an array.
|
||||
confirm: ({message, detailedMessage, buttons}={}) ->
|
||||
buttons ?= {}
|
||||
if _.isArray(buttons)
|
||||
@@ -341,6 +339,7 @@ class Atom extends Model
|
||||
else
|
||||
buttonLabels = Object.keys(buttons)
|
||||
|
||||
dialog = remote.require('dialog')
|
||||
chosen = dialog.showMessageBox @getCurrentWindow(),
|
||||
type: 'info'
|
||||
message: message
|
||||
@@ -353,42 +352,59 @@ class Atom extends Model
|
||||
callback = buttons[buttonLabels[chosen]]
|
||||
callback?()
|
||||
|
||||
# Private:
|
||||
showSaveDialog: (callback) ->
|
||||
callback(showSaveDialogSync())
|
||||
|
||||
# Private:
|
||||
showSaveDialogSync: (defaultPath) ->
|
||||
defaultPath ?= @project?.getPath()
|
||||
currentWindow = @getCurrentWindow()
|
||||
dialog = remote.require('dialog')
|
||||
dialog.showSaveDialog currentWindow, {title: 'Save File', defaultPath}
|
||||
|
||||
# Public: Open the dev tools for the current window.
|
||||
openDevTools: ->
|
||||
@getCurrentWindow().openDevTools()
|
||||
ipc.sendChannel('call-window-method', 'openDevTools')
|
||||
|
||||
# Public: Toggle the visibility of the dev tools for the current window.
|
||||
toggleDevTools: ->
|
||||
@getCurrentWindow().toggleDevTools()
|
||||
ipc.sendChannel('call-window-method', 'toggleDevTools')
|
||||
|
||||
# Public: Reload the current window.
|
||||
reload: ->
|
||||
@getCurrentWindow().restart()
|
||||
ipc.sendChannel('call-window-method', 'restart')
|
||||
|
||||
# Public: Focus the current window.
|
||||
focus: ->
|
||||
@getCurrentWindow().focus()
|
||||
ipc.sendChannel('call-window-method', 'focus')
|
||||
$(window).focus()
|
||||
|
||||
# Public: Show the current window.
|
||||
show: ->
|
||||
@getCurrentWindow().show()
|
||||
ipc.sendChannel('call-window-method', 'show')
|
||||
|
||||
# Public: Hide the current window.
|
||||
hide: ->
|
||||
@getCurrentWindow().hide()
|
||||
ipc.sendChannel('call-window-method', 'hide')
|
||||
|
||||
# Private: Schedule the window to be shown and focused on the next tick.
|
||||
# Public: Set the size of current window.
|
||||
#
|
||||
# width - The {Number} of pixels.
|
||||
# height - The {Number} of pixels.
|
||||
setSize: (width, height) ->
|
||||
ipc.sendChannel('call-window-method', 'setSize', width, height)
|
||||
|
||||
# Public: Set the position of current window.
|
||||
#
|
||||
# x - The {Number} of pixels.
|
||||
# y - The {Number} of pixels.
|
||||
setPosition: (x, y) ->
|
||||
ipc.sendChannel('call-window-method', 'setPosition', x, y)
|
||||
|
||||
# Public: Move current window to the center of the screen.
|
||||
center: ->
|
||||
ipc.sendChannel('call-window-method', 'center')
|
||||
|
||||
# Schedule the window to be shown and focused on the next tick.
|
||||
#
|
||||
# This is done in a next tick to prevent a white flicker from occurring
|
||||
# if called synchronously.
|
||||
@@ -402,8 +418,10 @@ class Atom extends Model
|
||||
close: ->
|
||||
@getCurrentWindow().close()
|
||||
|
||||
# Private:
|
||||
exit: (status) -> app.exit(status)
|
||||
exit: (status) ->
|
||||
app = remote.require('app')
|
||||
app.emit('will-exit')
|
||||
app.exit(status)
|
||||
|
||||
# Public: Is the current window in development mode?
|
||||
inDevMode: ->
|
||||
@@ -419,7 +437,7 @@ class Atom extends Model
|
||||
|
||||
# Public: Set the full screen state of the current window.
|
||||
setFullScreen: (fullScreen=false) ->
|
||||
@getCurrentWindow().setFullScreen(fullScreen)
|
||||
ipc.sendChannel('call-window-method', 'setFullScreen', fullScreen)
|
||||
|
||||
# Public: Is the current window in full screen mode?
|
||||
isFullScreen: ->
|
||||
@@ -450,7 +468,6 @@ class Atom extends Model
|
||||
getConfigDirPath: ->
|
||||
@constructor.getConfigDirPath()
|
||||
|
||||
# Private:
|
||||
saveSync: ->
|
||||
stateString = JSON.stringify(@state)
|
||||
if statePath = @constructor.getStatePath(@mode)
|
||||
@@ -468,11 +485,9 @@ class Atom extends Model
|
||||
getWindowLoadTime: ->
|
||||
@loadTime
|
||||
|
||||
# Private:
|
||||
crashMainProcess: ->
|
||||
remote.process.crash()
|
||||
|
||||
# Private:
|
||||
crashRenderProcess: ->
|
||||
process.crash()
|
||||
|
||||
@@ -481,11 +496,14 @@ class Atom extends Model
|
||||
shell.beep() if @config.get('core.audioBeep')
|
||||
@workspaceView.trigger 'beep'
|
||||
|
||||
# Private:
|
||||
getUserInitScriptPath: ->
|
||||
initScriptPath = fs.resolve(@getConfigDirPath(), 'init', ['js', 'coffee'])
|
||||
initScriptPath ? path.join(@getConfigDirPath(), 'init.coffee')
|
||||
|
||||
requireUserInitScript: ->
|
||||
if userInitScriptPath = fs.resolve(@getConfigDirPath(), 'user', ['js', 'coffee'])
|
||||
if userInitScriptPath = @getUserInitScriptPath()
|
||||
try
|
||||
require userInitScriptPath
|
||||
require(userInitScriptPath) if fs.isFileSync(userInitScriptPath)
|
||||
catch error
|
||||
console.error "Failed to load `#{userInitScriptPath}`", error.stack, error
|
||||
|
||||
@@ -493,6 +511,9 @@ class Atom extends Model
|
||||
#
|
||||
# The globals will be set on the `window` object and removed after the
|
||||
# require completes.
|
||||
#
|
||||
# id - The {String} module name or path.
|
||||
# globals - An {Object} to set as globals during require (default: {})
|
||||
requireWithGlobals: (id, globals={}) ->
|
||||
existingGlobals = {}
|
||||
for key, value of globals
|
||||
|
||||
@@ -3,7 +3,7 @@ ipc = require 'ipc'
|
||||
Menu = require 'menu'
|
||||
_ = require 'underscore-plus'
|
||||
|
||||
# Private: Used to manage the global application menu.
|
||||
# Used to manage the global application menu.
|
||||
#
|
||||
# It's created by {AtomApplication} upon instantiation and used to add, remove
|
||||
# and maintain the state of all menu items.
|
||||
@@ -29,7 +29,7 @@ class ApplicationMenu
|
||||
@menu = Menu.buildFromTemplate(template)
|
||||
Menu.setApplicationMenu(@menu)
|
||||
|
||||
# Private: Flattens the given menu and submenu items into an single Array.
|
||||
# Flattens the given menu and submenu items into an single Array.
|
||||
#
|
||||
# * menu:
|
||||
# A complete menu configuration object for atom-shell's menu API.
|
||||
@@ -42,7 +42,7 @@ class ApplicationMenu
|
||||
items = items.concat(@flattenMenuItems(item.submenu)) if item.submenu
|
||||
items
|
||||
|
||||
# Private: Flattens the given menu template into an single Array.
|
||||
# Flattens the given menu template into an single Array.
|
||||
#
|
||||
# * template:
|
||||
# An object describing the menu item.
|
||||
@@ -64,26 +64,22 @@ class ApplicationMenu
|
||||
for item in @flattenMenuItems(@menu)
|
||||
item.enabled = enable if item.metadata?['windowSpecific']
|
||||
|
||||
# Private: Replaces VERSION with the current version.
|
||||
# Replaces VERSION with the current version.
|
||||
substituteVersion: (template) ->
|
||||
if (item = _.find(@flattenMenuTemplate(template), (i) -> i.label == 'VERSION'))
|
||||
item.label = "Version #{@version}"
|
||||
|
||||
# Public: Makes the download menu item visible if available.
|
||||
#
|
||||
# Note: The update menu item's must match 'Install update' exactly otherwise
|
||||
# this function will fail to work.
|
||||
#
|
||||
# * newVersion:
|
||||
# FIXME: Unused.
|
||||
# * quitAndUpdateCallback:
|
||||
# Function to call when the install menu item has been clicked.
|
||||
showDownloadUpdateItem: (newVersion, quitAndUpdateCallback) ->
|
||||
if (item = _.find(@flattenMenuItems(@menu), (i) -> i.label == 'Install update'))
|
||||
item.visible = true
|
||||
item.click = quitAndUpdateCallback
|
||||
# Toggles Install Update Item
|
||||
showInstallUpdateItem: (visible=true) ->
|
||||
if (item = _.find(@flattenMenuItems(@menu), (i) -> i.label == 'Restart and Install Update'))
|
||||
item.visible = visible
|
||||
|
||||
# Private: Default list of menu items.
|
||||
# Toggles Check For Update Item
|
||||
showCheckForUpdateItem: (visible=true) ->
|
||||
if (item = _.find(@flattenMenuItems(@menu), (i) -> i.label == 'Check for Update'))
|
||||
item.visible = visible
|
||||
|
||||
# Default list of menu items.
|
||||
#
|
||||
# Returns an Array of menu item Objects.
|
||||
getDefaultTemplate: ->
|
||||
@@ -97,7 +93,7 @@ class ApplicationMenu
|
||||
]
|
||||
]
|
||||
|
||||
# Private: Combines a menu template with the appropriate keystroke.
|
||||
# Combines a menu template with the appropriate keystroke.
|
||||
#
|
||||
# * template:
|
||||
# An Object conforming to atom-shell's menu api but lacking accelerator and
|
||||
@@ -117,7 +113,7 @@ class ApplicationMenu
|
||||
@translateTemplate(item.submenu, keystrokesByCommand) if item.submenu
|
||||
template
|
||||
|
||||
# Private: Determine the accelerator for a given command.
|
||||
# Determine the accelerator for a given command.
|
||||
#
|
||||
# * command:
|
||||
# The name of the command.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
AtomWindow = require './atom-window'
|
||||
ApplicationMenu = require './application-menu'
|
||||
AtomProtocolHandler = require './atom-protocol-handler'
|
||||
BrowserWindow = require 'browser-window'
|
||||
Menu = require 'menu'
|
||||
autoUpdater = require 'auto-updater'
|
||||
app = require 'app'
|
||||
@@ -21,7 +22,7 @@ socketPath =
|
||||
else
|
||||
path.join(os.tmpdir(), 'atom.sock')
|
||||
|
||||
# Private: The application's singleton class.
|
||||
# The application's singleton class.
|
||||
#
|
||||
# It's the entry point into the Atom application and maintains the global state
|
||||
# of the application.
|
||||
@@ -72,11 +73,11 @@ class AtomApplication
|
||||
@listenForArgumentsFromNewProcess()
|
||||
@setupJavaScriptArguments()
|
||||
@handleEvents()
|
||||
@checkForUpdates()
|
||||
@setupAutoUpdater()
|
||||
|
||||
@openWithOptions(options)
|
||||
|
||||
# Private: Opens a new window based on the options provided.
|
||||
# Opens a new window based on the options provided.
|
||||
openWithOptions: ({pathsToOpen, urlsToOpen, test, pidToKillWhenClosed, devMode, newWindow, specDirectory, logFile}) ->
|
||||
if test
|
||||
@runSpecs({exitWhenDone: true, @resourcePath, specDirectory, logFile})
|
||||
@@ -97,14 +98,13 @@ class AtomApplication
|
||||
@windows.push window
|
||||
@applicationMenu?.enableWindowSpecificItems(true)
|
||||
|
||||
# Private: Creates server to listen for additional atom application launches.
|
||||
# Creates server to listen for additional atom application launches.
|
||||
#
|
||||
# You can run the atom command multiple times, but after the first launch
|
||||
# the other launches will just pass their information to this server and then
|
||||
# close immediately.
|
||||
listenForArgumentsFromNewProcess: ->
|
||||
if process.platform isnt 'win32' and fs.existsSync(socketPath)
|
||||
fs.unlinkSync socketPath
|
||||
@deleteSocketFile()
|
||||
server = net.createServer (connection) =>
|
||||
connection.on 'data', (data) =>
|
||||
@openWithOptions(JSON.parse(data))
|
||||
@@ -112,23 +112,72 @@ class AtomApplication
|
||||
server.listen socketPath
|
||||
server.on 'error', (error) -> console.error 'Application server failed', error
|
||||
|
||||
# Private: Configures required javascript environment flags.
|
||||
deleteSocketFile: ->
|
||||
return if process.platform is 'win32'
|
||||
|
||||
if fs.existsSync(socketPath)
|
||||
try
|
||||
fs.unlinkSync(socketPath)
|
||||
catch error
|
||||
# Ignore ENOENT errors in case the file was deleted between the exists
|
||||
# check and the call to unlink sync. This occurred occasionally on CI
|
||||
# which is why this check is here.
|
||||
throw error unless error.code is 'ENOENT'
|
||||
|
||||
# Configures required javascript environment flags.
|
||||
setupJavaScriptArguments: ->
|
||||
app.commandLine.appendSwitch 'js-flags', '--harmony_collections --harmony-proxies'
|
||||
|
||||
# Private: Enable updates unless running from a local build of Atom.
|
||||
checkForUpdates: ->
|
||||
versionIsSha = /\w{7}/.test @version
|
||||
# Enable updates unless running from a local build of Atom.
|
||||
setupAutoUpdater: ->
|
||||
autoUpdater.setFeedUrl "https://atom.io/api/updates?version=#{@version}"
|
||||
|
||||
if versionIsSha
|
||||
autoUpdater.setAutomaticallyDownloadsUpdates false
|
||||
autoUpdater.setAutomaticallyChecksForUpdates false
|
||||
else
|
||||
autoUpdater.setAutomaticallyDownloadsUpdates true
|
||||
autoUpdater.setAutomaticallyChecksForUpdates true
|
||||
autoUpdater.checkForUpdatesInBackground()
|
||||
autoUpdater.on 'checking-for-update', =>
|
||||
@applicationMenu.showInstallUpdateItem(false)
|
||||
@applicationMenu.showCheckForUpdateItem(false)
|
||||
|
||||
# Private: Registers basic application commands, non-idempotent.
|
||||
autoUpdater.on 'update-not-available', =>
|
||||
@applicationMenu.showInstallUpdateItem(false)
|
||||
@applicationMenu.showCheckForUpdateItem(true)
|
||||
|
||||
autoUpdater.on 'update-downloaded', (event, releaseNotes, releaseName, releaseDate, releaseURL) =>
|
||||
atomWindow.sendCommand('window:update-available', [releaseName, releaseNotes]) for atomWindow in @windows
|
||||
@applicationMenu.showInstallUpdateItem(true)
|
||||
@applicationMenu.showCheckForUpdateItem(false)
|
||||
@updateVersion = releaseName
|
||||
|
||||
autoUpdater.on 'error', (event, message) =>
|
||||
@applicationMenu.showInstallUpdateItem(false)
|
||||
@applicationMenu.showCheckForUpdateItem(true)
|
||||
|
||||
# Check for update after Atom has fully started and the menus are created
|
||||
setTimeout((-> autoUpdater.checkForUpdates()), 5000)
|
||||
|
||||
checkForUpdate: ->
|
||||
autoUpdater.once 'update-available', ->
|
||||
dialog.showMessageBox
|
||||
type: 'info'
|
||||
buttons: ['OK']
|
||||
message: 'Update available.'
|
||||
detail: 'A new update is being downloaded.'
|
||||
|
||||
autoUpdater.once 'update-not-available', =>
|
||||
dialog.showMessageBox
|
||||
type: 'info'
|
||||
buttons: ['OK']
|
||||
message: 'No update available.'
|
||||
detail: "Version #{@version} is the latest version."
|
||||
|
||||
autoUpdater.once 'error', (event, message)->
|
||||
dialog.showMessageBox
|
||||
type: 'warning'
|
||||
buttons: ['OK']
|
||||
message: 'There was an error checking for updates.'
|
||||
detail: message
|
||||
|
||||
autoUpdater.checkForUpdates()
|
||||
|
||||
# Registers basic application commands, non-idempotent.
|
||||
handleEvents: ->
|
||||
@on 'application:about', -> Menu.sendActionToFirstResponder('orderFrontStandardAboutPanel:')
|
||||
@on 'application:run-all-specs', -> @runSpecs(exitWhenDone: false, resourcePath: global.devResourcePath)
|
||||
@@ -145,11 +194,13 @@ class AtomApplication
|
||||
@on 'application:zoom', -> Menu.sendActionToFirstResponder('zoom:')
|
||||
@on 'application:bring-all-windows-to-front', -> Menu.sendActionToFirstResponder('arrangeInFront:')
|
||||
@on 'application:inspect', ({x,y}) -> @focusedWindow().browserWindow.inspectElement(x, y)
|
||||
@on 'application:open-documentation', -> shell.openExternal('https://www.atom.io/docs/latest/?app')
|
||||
@on 'application:report-issue', -> shell.openExternal('https://github.com/atom/atom/issues/new')
|
||||
@on 'application:open-documentation', -> shell.openExternal('https://atom.io/docs/latest/?app')
|
||||
@on 'application:install-update', -> autoUpdater.quitAndInstall()
|
||||
@on 'application:check-for-update', => @checkForUpdate()
|
||||
|
||||
@openPathOnEvent('application:show-settings', 'atom://config')
|
||||
@openPathOnEvent('application:open-your-config', 'atom://.atom/config')
|
||||
@openPathOnEvent('application:open-your-init-script', 'atom://.atom/init-script')
|
||||
@openPathOnEvent('application:open-your-keymap', 'atom://.atom/keymap')
|
||||
@openPathOnEvent('application:open-your-snippets', 'atom://.atom/snippets')
|
||||
@openPathOnEvent('application:open-your-stylesheet', 'atom://.atom/stylesheet')
|
||||
@@ -157,10 +208,8 @@ class AtomApplication
|
||||
app.on 'window-all-closed', ->
|
||||
app.quit() if process.platform is 'win32'
|
||||
|
||||
app.on 'will-quit', =>
|
||||
# Clean the socket file when quit normally.
|
||||
if process.platform isnt 'win32' and fs.existsSync(socketPath)
|
||||
fs.unlinkSync socketPath
|
||||
app.on 'will-quit', => @deleteSocketFile()
|
||||
app.on 'will-exit', => @deleteSocketFile()
|
||||
|
||||
app.on 'open-file', (event, pathToOpen) =>
|
||||
event.preventDefault()
|
||||
@@ -170,12 +219,6 @@ class AtomApplication
|
||||
event.preventDefault()
|
||||
@openUrl({urlToOpen, @devMode})
|
||||
|
||||
autoUpdater.on 'ready-for-update-on-quit', (event, version, quitAndUpdateCallback) =>
|
||||
event.preventDefault()
|
||||
@updateVersion = version
|
||||
@applicationMenu.showDownloadUpdateItem(version, quitAndUpdateCallback)
|
||||
atomWindow.sendCommand('window:update-available', version) for atomWindow in @windows
|
||||
|
||||
# A request from the associated render process to open a new render process.
|
||||
ipc.on 'open', (processId, routingId, options) =>
|
||||
if options?
|
||||
@@ -195,6 +238,14 @@ class AtomApplication
|
||||
ipc.on 'command', (processId, routingId, command) =>
|
||||
@emit(command)
|
||||
|
||||
ipc.on 'window-command', (processId, routingId, command, args...) ->
|
||||
win = BrowserWindow.fromProcessIdAndRoutingId(processId, routingId)
|
||||
win.emit(command, args...)
|
||||
|
||||
ipc.on 'call-window-method', (processId, routingId, method, args...) ->
|
||||
win = BrowserWindow.fromProcessIdAndRoutingId(processId, routingId)
|
||||
win[method](args...)
|
||||
|
||||
# Public: Executes the given command.
|
||||
#
|
||||
# If it isn't handled globally, delegate to the currently focused window.
|
||||
@@ -221,7 +272,7 @@ class AtomApplication
|
||||
else
|
||||
@openPath({pathToOpen})
|
||||
|
||||
# Private: Returns the {AtomWindow} for the given path.
|
||||
# Returns the {AtomWindow} for the given path.
|
||||
windowForPath: (pathToOpen) ->
|
||||
for atomWindow in @windows
|
||||
return atomWindow if atomWindow.containsPath(pathToOpen)
|
||||
@@ -269,14 +320,6 @@ class AtomApplication
|
||||
# + initialSize:
|
||||
# Object with height and width keys.
|
||||
openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, initialSize}={}) ->
|
||||
if devMode and not fs.existsSync(global.devResourcePath)
|
||||
dialog.showMessageBox
|
||||
type: 'warning'
|
||||
buttons: ['OK']
|
||||
message: 'Atom source directory not found.'
|
||||
detail: 'To run a window in dev mode you need to have the atom/atom repo cloned to ~/github/atom'
|
||||
return
|
||||
|
||||
if pathToOpen
|
||||
[basename, initialLine] = path.basename(pathToOpen).split(':')
|
||||
if initialLine
|
||||
@@ -290,11 +333,12 @@ class AtomApplication
|
||||
openedWindow.openPath(pathToOpen, initialLine)
|
||||
else
|
||||
if devMode
|
||||
resourcePath = global.devResourcePath
|
||||
bootstrapScript = require.resolve(path.join(global.devResourcePath, 'src', 'window-bootstrap'))
|
||||
else
|
||||
resourcePath = @resourcePath
|
||||
bootstrapScript = require.resolve('../window-bootstrap')
|
||||
try
|
||||
bootstrapScript = require.resolve(path.join(global.devResourcePath, 'src', 'window-bootstrap'))
|
||||
resourcePath = global.devResourcePath
|
||||
|
||||
bootstrapScript ?= require.resolve('../window-bootstrap')
|
||||
resourcePath ?= @resourcePath
|
||||
openedWindow = new AtomWindow({pathToOpen, initialLine, bootstrapScript, resourcePath, devMode, initialSize})
|
||||
|
||||
if pidToKillWhenClosed?
|
||||
@@ -309,7 +353,7 @@ class AtomApplication
|
||||
console.log("Killing process #{pid} failed: #{error.code}")
|
||||
delete @pidsToOpenWindows[pid]
|
||||
|
||||
# Private: Open an atom:// url.
|
||||
# Open an atom:// url.
|
||||
#
|
||||
# The host of the URL being opened is assumed to be the package name
|
||||
# responsible for opening the URL. A new window will be created with
|
||||
@@ -341,7 +385,7 @@ class AtomApplication
|
||||
else
|
||||
console.log "Opening unknown url: #{urlToOpen}"
|
||||
|
||||
# Private: Opens up a new {AtomWindow} to run specs within.
|
||||
# Opens up a new {AtomWindow} to run specs within.
|
||||
#
|
||||
# * options
|
||||
# + exitWhenDone:
|
||||
@@ -372,7 +416,7 @@ class AtomApplication
|
||||
isSpec = true
|
||||
new AtomWindow({bootstrapScript, @resourcePath, isSpec})
|
||||
|
||||
# Private: Opens a native dialog to prompt the user for a path.
|
||||
# Opens a native dialog to prompt the user for a path.
|
||||
#
|
||||
# Once paths are selected, they're opened in a new or existing {AtomWindow}s.
|
||||
#
|
||||
|
||||
@@ -3,7 +3,7 @@ fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
protocol = require 'protocol'
|
||||
|
||||
# Private: Handles requests with 'atom' protocol.
|
||||
# Handles requests with 'atom' protocol.
|
||||
#
|
||||
# It's created by {AtomApplication} upon instantiation, and is used to create a
|
||||
# custom resource loader by adding the 'atom' custom protocol.
|
||||
@@ -18,7 +18,7 @@ class AtomProtocolHandler
|
||||
|
||||
@registerAtomProtocol()
|
||||
|
||||
# Private: Creates the 'atom' custom protocol handler.
|
||||
# Creates the 'atom' custom protocol handler.
|
||||
registerAtomProtocol: ->
|
||||
protocol.registerProtocol 'atom', (request) =>
|
||||
relativePath = path.normalize(request.url.substr(7))
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
BrowserWindow = require 'browser-window'
|
||||
Menu = require 'menu'
|
||||
ContextMenu = require './context-menu'
|
||||
app = require 'app'
|
||||
dialog = require 'dialog'
|
||||
ipc = require 'ipc'
|
||||
path = require 'path'
|
||||
fs = require 'fs'
|
||||
url = require 'url'
|
||||
_ = require 'underscore-plus'
|
||||
|
||||
# Private:
|
||||
module.exports =
|
||||
class AtomWindow
|
||||
@iconPath: path.resolve(__dirname, '..', '..', 'resources', 'atom.png')
|
||||
@@ -31,6 +32,7 @@ class AtomWindow
|
||||
|
||||
loadSettings = _.extend({}, settings)
|
||||
loadSettings.windowState ?= '{}'
|
||||
loadSettings.appVersion = app.getVersion()
|
||||
|
||||
# Only send to the first non-spec window created
|
||||
if @constructor.includeShellLoadTime and not @isSpec
|
||||
@@ -43,7 +45,7 @@ class AtomWindow
|
||||
|
||||
@browserWindow.loadSettings = loadSettings
|
||||
@browserWindow.once 'window:loaded', => @loaded = true
|
||||
@browserWindow.loadUrl "file://#{@resourcePath}/static/index.html"
|
||||
@browserWindow.loadUrl @getUrl(loadSettings)
|
||||
@browserWindow.focusOnWebView() if @isSpec
|
||||
|
||||
@openPath(pathToOpen, initialLine)
|
||||
@@ -51,6 +53,18 @@ class AtomWindow
|
||||
setupNodePath: (resourcePath) ->
|
||||
process.env['NODE_PATH'] = path.resolve(resourcePath, 'exports')
|
||||
|
||||
getUrl: (loadSettingsObj) ->
|
||||
# Ignore the windowState when passing loadSettings via URL, since it could
|
||||
# be quite large.
|
||||
loadSettings = _.clone(loadSettingsObj)
|
||||
delete loadSettings['windowState']
|
||||
|
||||
url.format
|
||||
protocol: 'file'
|
||||
pathname: "#{@resourcePath}/static/index.html"
|
||||
slashes: true
|
||||
query: {loadSettings: JSON.stringify(loadSettings)}
|
||||
|
||||
getInitialPath: ->
|
||||
@browserWindow.loadSettings.initialPath
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
Menu = require 'menu'
|
||||
|
||||
# Private:
|
||||
module.exports =
|
||||
class ContextMenu
|
||||
constructor: (template, browserWindow) ->
|
||||
@@ -8,7 +7,7 @@ class ContextMenu
|
||||
menu = Menu.buildFromTemplate(template)
|
||||
menu.popup(browserWindow)
|
||||
|
||||
# Private: It's necessary to build the event handlers in this process, otherwise
|
||||
# It's necessary to build the event handlers in this process, otherwise
|
||||
# closures are drug across processes and failed to be garbage collected
|
||||
# appropriately.
|
||||
createClickHandlers: (template) ->
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
global.shellStartTime = Date.now()
|
||||
|
||||
autoUpdater = require 'auto-updater'
|
||||
crashReporter = require 'crash-reporter'
|
||||
app = require 'app'
|
||||
fs = require 'fs'
|
||||
@@ -42,7 +41,6 @@ start = ->
|
||||
|
||||
app.on 'will-finish-launching', ->
|
||||
setupCrashReporter()
|
||||
setupAutoUpdater()
|
||||
|
||||
app.on 'finish-launching', ->
|
||||
app.removeListener 'open-file', addPathToOpen
|
||||
@@ -66,14 +64,11 @@ global.devResourcePath = path.join(app.getHomeDir(), 'github', 'atom')
|
||||
setupCrashReporter = ->
|
||||
crashReporter.start(productName: 'Atom', companyName: 'GitHub')
|
||||
|
||||
setupAutoUpdater = ->
|
||||
autoUpdater.setFeedUrl 'https://speakeasy.githubapp.com/apps/27/appcast.xml'
|
||||
|
||||
parseCommandLine = ->
|
||||
version = app.getVersion()
|
||||
options = optimist(process.argv[1..])
|
||||
options.usage """
|
||||
Atom #{version}
|
||||
Atom Editor v#{version}
|
||||
|
||||
Usage: atom [options] [file ...]
|
||||
"""
|
||||
@@ -114,8 +109,7 @@ parseCommandLine = ->
|
||||
|
||||
try
|
||||
fs.statSync resourcePath
|
||||
catch e
|
||||
devMode = false
|
||||
catch
|
||||
resourcePath = path.dirname(path.dirname(__dirname))
|
||||
|
||||
{resourcePath, pathsToOpen, executedFrom, test, version, pidToKillWhenClosed, devMode, newWindow, specDirectory, logFile}
|
||||
|
||||
@@ -1,43 +1,39 @@
|
||||
BufferedProcess = require './buffered-process'
|
||||
path = require 'path'
|
||||
|
||||
# Public: Like {BufferedProcess}, but accepts a Node script instead of an
|
||||
# executable.
|
||||
# Public: Like {BufferedProcess}, but accepts a Node script as the command
|
||||
# to run.
|
||||
#
|
||||
# This may seem unnecessary but on Windows we have to have separate executables
|
||||
# for each script without this since Windows doesn't support shebang strings.
|
||||
# This is necessary on Windows since it doesn't support shebang `#!` lines.
|
||||
#
|
||||
# ## Requiring in packages
|
||||
#
|
||||
# ```coffee
|
||||
# {BufferedNodeProcess} = require 'atom'
|
||||
# {BufferedNodeProcess} = require 'atom'
|
||||
# ```
|
||||
module.exports =
|
||||
class BufferedNodeProcess extends BufferedProcess
|
||||
# Executes the given Node script.
|
||||
# Public: Runs the given Node script by spawning a new child process.
|
||||
#
|
||||
# * options
|
||||
# + command:
|
||||
# The path to the Javascript script to execute.
|
||||
# + args:
|
||||
# The array of arguments to pass to the script (optional).
|
||||
# + options:
|
||||
# The options Object to pass to Node's `ChildProcess.spawn` (optional).
|
||||
# + stdout:
|
||||
# The callback that receives a single argument which contains the
|
||||
# standard output of the script. The callback is called as data is
|
||||
# received but it's buffered to ensure only complete lines are passed
|
||||
# until the source stream closes. After the source stream has closed
|
||||
# all remaining data is sent in a final call (optional).
|
||||
# + stderr:
|
||||
# The callback that receives a single argument which contains the
|
||||
# standard error of the script. The callback is called as data is
|
||||
# received but it's buffered to ensure only complete lines are passed
|
||||
# until the source stream closes. After the source stream has closed
|
||||
# all remaining data is sent in a final call (optional).
|
||||
# + exit:
|
||||
# The callback which receives a single argument containing the exit
|
||||
# status (optional).
|
||||
# options - An {Object} with the following keys:
|
||||
# :command - The {String} path to the JavaScript script to execute.
|
||||
# :args - The {Array} of arguments to pass to the script (optional).
|
||||
# :options - The options {Object} to pass to Node's `ChildProcess.spawn`
|
||||
# method (optional).
|
||||
# :stdout - The callback {Function} that receives a single argument which
|
||||
# contains the standard output from the command. The callback is
|
||||
# called as data is received but it's buffered to ensure only
|
||||
# complete lines are passed until the source stream closes. After
|
||||
# the source stream has closed all remaining data is sent in a
|
||||
# final call (optional).
|
||||
# :stderr - The callback {Function} that receives a single argument which
|
||||
# contains the standard error output from the command. The
|
||||
# callback is called as data is received but it's buffered to
|
||||
# ensure only complete lines are passed until the source stream
|
||||
# closes. After the source stream has closed all remaining data
|
||||
# is sent in a final call (optional).
|
||||
# :exit - The callback {Function} which receives a single argument
|
||||
# containing the exit status (optional).
|
||||
constructor: ({command, args, options, stdout, stderr, exit}) ->
|
||||
node =
|
||||
if process.platform is 'darwin'
|
||||
|
||||
@@ -1,44 +1,46 @@
|
||||
ChildProcess = require 'child_process'
|
||||
|
||||
# Public: A wrapper which provides line buffering for Node's ChildProcess.
|
||||
# Public: A wrapper which provides standard error/output line buffering for
|
||||
# Node's ChildProcess.
|
||||
#
|
||||
# ## Requiring in packages
|
||||
#
|
||||
# ```coffee
|
||||
# {BufferedProcess} = require 'atom'
|
||||
# {BufferedProcess} = require 'atom'
|
||||
#
|
||||
# command = 'ps'
|
||||
# args = ['-ef']
|
||||
# stdout = (output) -> console.log(output)
|
||||
# exit = (code) -> console.log("ps -ef exited with #{code}")
|
||||
# process = new BufferredProcess({command, args, stdout, exit})
|
||||
# ```
|
||||
module.exports =
|
||||
class BufferedProcess
|
||||
process: null
|
||||
killed: false
|
||||
|
||||
# Executes the given executable.
|
||||
# Public: Runs the given command by spawning a new child process.
|
||||
#
|
||||
# * options
|
||||
# + command:
|
||||
# The path to the executable to execute.
|
||||
# + args:
|
||||
# The array of arguments to pass to the script (optional).
|
||||
# + options:
|
||||
# The options Object to pass to Node's `ChildProcess.spawn` (optional).
|
||||
# + stdout:
|
||||
# The callback that receives a single argument which contains the
|
||||
# standard output of the script. The callback is called as data is
|
||||
# received but it's buffered to ensure only complete lines are passed
|
||||
# until the source stream closes. After the source stream has closed
|
||||
# all remaining data is sent in a final call (optional).
|
||||
# + stderr:
|
||||
# The callback that receives a single argument which contains the
|
||||
# standard error of the script. The callback is called as data is
|
||||
# received but it's buffered to ensure only complete lines are passed
|
||||
# until the source stream closes. After the source stream has closed
|
||||
# all remaining data is sent in a final call (optional).
|
||||
# + exit:
|
||||
# The callback which receives a single argument containing the exit
|
||||
# status (optional).
|
||||
# options - An {Object} with the following keys:
|
||||
# :command - The {String} command to execute.
|
||||
# :args - The {Array} of arguments to pass to the command (optional).
|
||||
# :options - The options {Object} to pass to Node's `ChildProcess.spawn`
|
||||
# method (optional).
|
||||
# :stdout - The callback {Function} that receives a single argument which
|
||||
# contains the standard output from the command. The callback is
|
||||
# called as data is received but it's buffered to ensure only
|
||||
# complete lines are passed until the source stream closes. After
|
||||
# the source stream has closed all remaining data is sent in a
|
||||
# final call (optional).
|
||||
# :stderr - The callback {Function} that receives a single argument which
|
||||
# contains the standard error output from the command. The
|
||||
# callback is called as data is received but it's buffered to
|
||||
# ensure only complete lines are passed until the source stream
|
||||
# closes. After the source stream has closed all remaining data
|
||||
# is sent in a final call (optional).
|
||||
# :exit - The callback {Function} which receives a single argument
|
||||
# containing the exit status (optional).
|
||||
constructor: ({command, args, options, stdout, stderr, exit}={}) ->
|
||||
options ?= {}
|
||||
@process = ChildProcess.spawn(command, args, options)
|
||||
@killed = false
|
||||
|
||||
stdoutClosed = true
|
||||
stderrClosed = true
|
||||
@@ -68,14 +70,11 @@ class BufferedProcess
|
||||
processExited = true
|
||||
triggerExitCallback()
|
||||
|
||||
# Private: Helper method to pass data line by line.
|
||||
# Helper method to pass data line by line.
|
||||
#
|
||||
# * stream:
|
||||
# The Stream to read from.
|
||||
# * onLines:
|
||||
# The callback to call with each line of data.
|
||||
# * onDone:
|
||||
# The callback to call when the stream has closed.
|
||||
# stream - The Stream to read from.
|
||||
# onLines - The callback to call with each line of data.
|
||||
# onDone - The callback to call when the stream has closed.
|
||||
bufferStream: (stream, onLines, onDone) ->
|
||||
stream.setEncoding('utf8')
|
||||
buffered = ''
|
||||
@@ -93,7 +92,7 @@ class BufferedProcess
|
||||
onLines(buffered) if buffered.length > 0
|
||||
onDone()
|
||||
|
||||
# Public: Terminates the process.
|
||||
# Public: Terminate the process.
|
||||
kill: ->
|
||||
@killed = true
|
||||
@process.kill()
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
clipboard = require 'clipboard'
|
||||
crypto = require 'crypto'
|
||||
|
||||
# Public: Represents the clipboard used for copying and pasting in Atom.
|
||||
#
|
||||
# An instance of this class is always available as the `atom.clipboard` global.
|
||||
module.exports =
|
||||
class Clipboard
|
||||
metadata: null
|
||||
signatureForMetadata: null
|
||||
|
||||
# Creates an `md5` hash of some text.
|
||||
#
|
||||
# text - A {String} to hash.
|
||||
#
|
||||
# Returns a hashed {String}.
|
||||
md5: (text) ->
|
||||
crypto.createHash('md5').update(text, 'utf8').digest('hex')
|
||||
|
||||
# Public: Write the given text to the clipboard.
|
||||
#
|
||||
# The metadata associated with the text is available by calling
|
||||
# {::readWithMetadata}.
|
||||
#
|
||||
# text - The {String} to store.
|
||||
# metadata - The additional info to associate with the text.
|
||||
write: (text, metadata) ->
|
||||
@signatureForMetadata = @md5(text)
|
||||
@metadata = metadata
|
||||
clipboard.writeText(text)
|
||||
|
||||
# Public: Read the text from the clipboard.
|
||||
#
|
||||
# Returns a {String}.
|
||||
read: ->
|
||||
clipboard.readText()
|
||||
|
||||
# Public: Read the text from the clipboard and return both the text and the
|
||||
# associated metadata.
|
||||
#
|
||||
# Returns an {Object} with the following keys:
|
||||
# :text - The {String} clipboard text.
|
||||
# :metadata - The metadata stored by an earlier call to {::write}.
|
||||
readWithMetadata: ->
|
||||
text = @read()
|
||||
if @signatureForMetadata is @md5(text)
|
||||
{text, @metadata}
|
||||
else
|
||||
{text}
|
||||
@@ -3,52 +3,57 @@ _ = require 'underscore-plus'
|
||||
async = require 'async'
|
||||
fs = require 'fs-plus'
|
||||
mkdirp = require 'mkdirp'
|
||||
runas = require 'runas'
|
||||
|
||||
symlinkCommand = (sourcePath, destinationPath, callback) ->
|
||||
mkdirp path.dirname(destinationPath), (error) ->
|
||||
if error?
|
||||
fs.unlink destinationPath, (error) ->
|
||||
if error? and error?.code != 'ENOENT'
|
||||
callback(error)
|
||||
else
|
||||
fs.symlink sourcePath, destinationPath, (error) ->
|
||||
mkdirp path.dirname(destinationPath), (error) ->
|
||||
if error?
|
||||
callback(error)
|
||||
else
|
||||
fs.chmod(destinationPath, 0o755, callback)
|
||||
fs.symlink sourcePath, destinationPath, callback
|
||||
|
||||
unlinkCommand = (destinationPath, callback) ->
|
||||
fs.unlink destinationPath, (error) ->
|
||||
if error? and error.code isnt 'ENOENT'
|
||||
callback(error)
|
||||
else
|
||||
callback()
|
||||
symlinkCommandWithPrivilegeSync = (sourcePath, destinationPath) ->
|
||||
if runas('/bin/rm', ['-f', destinationPath], admin: true) != 0
|
||||
throw new Error("Failed to remove '#{destinationPath}'")
|
||||
|
||||
if runas('/bin/mkdir', ['-p', path.dirname(destinationPath)], admin: true) != 0
|
||||
throw new Error("Failed to create directory '#{destinationPath}'")
|
||||
|
||||
if runas('/bin/ln', ['-s', sourcePath, destinationPath], admin: true) != 0
|
||||
throw new Error("Failed to symlink '#{sourcePath}' to '#{destinationPath}'")
|
||||
|
||||
module.exports =
|
||||
getInstallDirectory: ->
|
||||
"/usr/local/bin"
|
||||
|
||||
install: (commandPath, callback) ->
|
||||
install: (commandPath, askForPrivilege, callback) ->
|
||||
return unless process.platform is 'darwin'
|
||||
|
||||
commandName = path.basename(commandPath, path.extname(commandPath))
|
||||
directory = @getInstallDirectory()
|
||||
if fs.existsSync(directory)
|
||||
destinationPath = path.join(directory, commandName)
|
||||
unlinkCommand destinationPath, (error) =>
|
||||
if error?
|
||||
error = new Error "Could not remove file at #{destinationPath}." if error
|
||||
callback?(error)
|
||||
else
|
||||
symlinkCommand commandPath, destinationPath, (error) =>
|
||||
error = new Error "Failed to symlink #{commandPath} to #{destinationPath}." if error
|
||||
callback?(error)
|
||||
else
|
||||
error = new Error "Directory '#{directory} doesn't exist."
|
||||
callback?(error)
|
||||
destinationPath = path.join(@getInstallDirectory(), commandName)
|
||||
|
||||
installAtomCommand: (resourcePath, callback) ->
|
||||
fs.readlink destinationPath, (error, realpath) ->
|
||||
if realpath == commandPath
|
||||
callback()
|
||||
return
|
||||
|
||||
symlinkCommand commandPath, destinationPath, (error) =>
|
||||
if askForPrivilege and error?.code is 'EACCES'
|
||||
try
|
||||
error = null
|
||||
symlinkCommandWithPrivilegeSync(commandPath, destinationPath)
|
||||
catch error
|
||||
|
||||
callback?(error)
|
||||
|
||||
installAtomCommand: (resourcePath, askForPrivilege, callback) ->
|
||||
commandPath = path.join(resourcePath, 'atom.sh')
|
||||
@install commandPath, callback
|
||||
@install commandPath, askForPrivilege, callback
|
||||
|
||||
installApmCommand: (resourcePath, callback) ->
|
||||
installApmCommand: (resourcePath, askForPrivilege, callback) ->
|
||||
commandPath = path.join(resourcePath, 'apm', 'node_modules', '.bin', 'apm')
|
||||
@install commandPath, callback
|
||||
@install commandPath, askForPrivilege, callback
|
||||
|
||||
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