Comparar commits
937 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 0a0e848e7b | |||
| 5348b912cc | |||
| 3fd4e57162 | |||
| 7c356d2592 | |||
| e49414d2ec | |||
| 1361424673 | |||
| e084bebb54 | |||
| df8d014e3c | |||
| d839ea9aa5 | |||
| 6cdb1a188a | |||
| 4218e0a037 | |||
| 36a0da01cc | |||
| ef2bdf6365 | |||
| ef1ec9b693 | |||
| 68d0a99c6e | |||
| 64f3938f5c | |||
| 3faecb5988 | |||
| bf50b4a128 | |||
| 88df4d2f3e | |||
| 4136ff566b | |||
| 2fe523a664 | |||
| 148180adda | |||
| 01a4032895 | |||
| 2b2b65ec82 | |||
| 5ffc063f0c | |||
| dee0771dd7 | |||
| aef6991ca8 | |||
| e8db3e97ce | |||
| b1dd4f2e8e | |||
| 633b08b9de | |||
| 1228435f9b | |||
| 02b5280587 | |||
| 2e47207701 | |||
| 593b5b4e36 | |||
| 1896c94775 | |||
| 4dc20e2027 | |||
| 238e291888 | |||
| 5ccac143aa | |||
| ae97244664 | |||
| 859e3cd038 | |||
| 07577ff944 | |||
| 72b1821828 | |||
| 781a51ac53 | |||
| 9055e650c6 | |||
| 5195a4aaa7 | |||
| 5e4f34f92c | |||
| dc7b549017 | |||
| 29d5f63cd9 | |||
| 33b4ec8e25 | |||
| 85abed2406 | |||
| 520ece4b13 | |||
| 184068dc55 | |||
| f27b897e91 | |||
| 6e201104bc | |||
| 908a2978ae | |||
| 2eb5ef0816 | |||
| 0c5f2cd067 | |||
| d1e60fb2a5 | |||
| bee7be1d1a | |||
| bee4c9df8a | |||
| c5815d2af9 | |||
| 77717d3eff | |||
| d3e0005b33 | |||
| 8295019891 | |||
| 2edcc517b1 | |||
| 9083103bb3 | |||
| bc391094df | |||
| ffba81a962 | |||
| 1e1f4cf173 | |||
| 7f04149f8d | |||
| cd1fb99142 | |||
| 388763e7cd | |||
| f22e4225c3 | |||
| db4b99d27b | |||
| 17f9cc49f2 | |||
| 609855af3c | |||
| 8410d8587b | |||
| 33c9d5ae24 | |||
| 0c48821465 | |||
| 43259f5c51 | |||
| fe2cb046c3 | |||
| de132d79a4 | |||
| 5af181ffb5 | |||
| 355f54ba00 | |||
| b56d4c6181 | |||
| ad9e2ab869 | |||
| a497b0f90f | |||
| e4fd80399d | |||
| c4c5d72bf1 | |||
| 0504244066 | |||
| 8560526158 | |||
| ec8805e99e | |||
| f8ec2e6da4 | |||
| 2a28eafd04 | |||
| a6bf1af2d5 | |||
| 8eae66fc49 | |||
| 02757fc2de | |||
| fc37ac37bd | |||
| 63587abe97 | |||
| d5ea766541 | |||
| bd0643eda4 | |||
| 7a9710b8c3 | |||
| 468c6598db | |||
| ddb3cdc76f | |||
| 1c8e716cfd | |||
| f1f83a7d36 | |||
| 8d87eb2ed6 | |||
| 29d26a4fae | |||
| 5c6f711bf3 | |||
| 53c363b853 | |||
| bacd612c71 | |||
| 2cded15c4c | |||
| 2e73a46cbc | |||
| 64ae7bcdcc | |||
| abca7f778c | |||
| b7197145c8 | |||
| 7f53bb5753 | |||
| 8d38fc77d6 | |||
| 1975882b9e | |||
| 0bd4d31ab0 | |||
| 4192c121e5 | |||
| e89e2141d7 | |||
| 25c5458bd2 | |||
| ff0cddfd1d | |||
| a7ec7497e2 | |||
| 3790cdb262 | |||
| 4308ce7bb0 | |||
| b302fdc553 | |||
| 2fffbba503 | |||
| 9be1427891 | |||
| 4564a39392 | |||
| 068c1e6249 | |||
| 06a55250b9 | |||
| d8240628a7 | |||
| eaa7593b27 | |||
| 72e4be60c0 | |||
| f3a4d32a32 | |||
| edadedce7b | |||
| 89be77b0a9 | |||
| 99ba20ae0d | |||
| 0255e44f00 | |||
| 4832d36ac1 | |||
| 5d15af943e | |||
| 0a671fc386 | |||
| c06f5911c6 | |||
| 2af8404ea9 | |||
| 345d20dc4a | |||
| 34b93554c3 | |||
| 3de926a1af | |||
| bc85bd2e74 | |||
| 3601aac136 | |||
| de8b498402 | |||
| ef09fbbfb2 | |||
| a3784500ec | |||
| 1bd00f1d0a | |||
| ef7f0ed9ed | |||
| 65e80cd65e | |||
| 14bed8a3c8 | |||
| d0513cb95d | |||
| 6a08618821 | |||
| 72c87bfbc9 | |||
| 54c7c1e98d | |||
| 4e73fe3f24 | |||
| 359793c0b0 | |||
| 34ec15862f | |||
| 04bbe393d4 | |||
| 5b84aa7b18 | |||
| 7ba498a170 | |||
| c21f8a5a6c | |||
| 5788e30269 | |||
| 0312609e19 | |||
| 32fba97c3a | |||
| 5259d5b750 | |||
| dff27eba18 | |||
| d2908c75fc | |||
| 2c04bff0fa | |||
| 4f2f158d0d | |||
| 351dc58354 | |||
| 2867dd98e5 | |||
| 32a0804b9a | |||
| 408e62a993 | |||
| d4057d21c7 | |||
| 031ec9798a | |||
| 1ebdd801f5 | |||
| 084632a985 | |||
| 002e14990b | |||
| 3a3fc4b614 | |||
| b028673b5d | |||
| 6394814142 | |||
| e128212410 | |||
| 2d4360dcf0 | |||
| 120e2a3bdb | |||
| 7142022f05 | |||
| 25520a4cad | |||
| 56da6399b8 | |||
| a7379b067a | |||
| de6fb2802b | |||
| 2bfd7d093a | |||
| 416266b815 | |||
| bcc888bfb4 | |||
| e9bcb851c3 | |||
| 8411d41621 | |||
| a66f81d70a | |||
| 72d1eb24a3 | |||
| ba18c65dac | |||
| 0c94298ea4 | |||
| 9bf374d4e5 | |||
| 9344e3fc98 | |||
| ede6a081a4 | |||
| d83547b9f4 | |||
| ef2337359b | |||
| bc8a5f4b23 | |||
| 261421b609 | |||
| 07eb2585d6 | |||
| bec3d4effc | |||
| 422c4d41d1 | |||
| 7aa233d9d6 | |||
| 6c9df6d91a | |||
| 520e478447 | |||
| fc462fcd21 | |||
| 69b34b7377 | |||
| 3180bd2e3c | |||
| 286c7e8f18 | |||
| 1c6e2f06ed | |||
| 527a18fedc | |||
| 46e1a9254d | |||
| ae46f1a3e1 | |||
| 573c7f9621 | |||
| dbed45c68e | |||
| 9e6756ed6d | |||
| 95818ab21f | |||
| 9cf50960a2 | |||
| f555af0b88 | |||
| 853ee3eec5 | |||
| bb9e052c90 | |||
| 4bade1c976 | |||
| 058d55c829 | |||
| dc323348b7 | |||
| 858e7b62a3 | |||
| 28015339d9 | |||
| ca86e0258f | |||
| 87fcc39045 | |||
| b78ff8c3a9 | |||
| 01fdf016a9 | |||
| 655cce9fd4 | |||
| f3ea2cd9e0 | |||
| ebcae85f1a | |||
| 0b79c31d45 | |||
| d5ec8551e1 | |||
| cd376c2d1d | |||
| 8d84a97b2b | |||
| 0104d7e264 | |||
| 019cccc978 | |||
| 7f1d88a05d | |||
| ec754e5cd9 | |||
| e046bb52d7 | |||
| 34be92b5b0 | |||
| fb0a15b1b3 | |||
| e96d2dbd17 | |||
| 025370b9f8 | |||
| e26ab5513f | |||
| f623a4f2b5 | |||
| 4186a4943b | |||
| e179860519 | |||
| 43f8596fb1 | |||
| 2c7d01e398 | |||
| 1bdf45f7d6 | |||
| 7e6e61905b | |||
| 01b4ff24b9 | |||
| 47e2cb4645 | |||
| 236f4c5342 | |||
| 911390aba8 | |||
| 4569b76dd5 | |||
| 1c410cbf5a | |||
| 5f602ad86e | |||
| 9da9c77e61 | |||
| 8ed05a4201 | |||
| a8533c1010 | |||
| 87915f70e2 | |||
| ec07cb9524 | |||
| d4ae3ac548 | |||
| 1b4426e3ba | |||
| 32245b1d92 | |||
| 030bcd6d4f | |||
| f1628fb1e0 | |||
| 7c1a4a9e08 | |||
| 3b1c70911f | |||
| 70fc084864 | |||
| d9152e856b | |||
| 10dba4b9a0 | |||
| 5e51445118 | |||
| f4b7f86eb0 | |||
| 07308a4e04 | |||
| 8cca198af1 | |||
| efea4c6d05 | |||
| 588d9b97eb | |||
| 4f77a371f4 | |||
| 94dd1eed54 | |||
| 09b91974a7 | |||
| 99611fad34 | |||
| 1b026cc805 | |||
| 4c0d87080a | |||
| a09eb96982 | |||
| 5531d54554 | |||
| b73d267a5f | |||
| 5add0e4f70 | |||
| 7040906473 | |||
| 131aad24c0 | |||
| 64870c733b | |||
| 68ca6a0a0d | |||
| 376010722e | |||
| 31cf907b48 | |||
| 28af52dfab | |||
| 9e7e77bdf8 | |||
| d0385a90ea | |||
| f9c4af301d | |||
| 3cf4b7b3e4 | |||
| 8523df58b0 | |||
| bd2c2bfe46 | |||
| f5a70da6f0 | |||
| a8186b15cf | |||
| fe088ba16a | |||
| 562a047b9e | |||
| 634c995a71 | |||
| 153faefaf9 | |||
| 636a8a8286 | |||
| faada2de30 | |||
| e762efa97e | |||
| a2c9c21cfb | |||
| ea4f99e5ac | |||
| b46ac9080c | |||
| 24a463b18d | |||
| 3d28a04ffa | |||
| 326542644d | |||
| 45f70bb783 | |||
| a227ed7586 | |||
| 5288666bfc | |||
| 0396aac11f | |||
| 5db163a328 | |||
| 4d12e025e4 | |||
| be20148518 | |||
| 756347a716 | |||
| 7379627fcb | |||
| 4b02d3ff61 | |||
| dc6836dc2d | |||
| a2c4caf7ad | |||
| e8b6fb919e | |||
| 2087426afc | |||
| b703ca0ebf | |||
| 601c877136 | |||
| 6c609cb7d2 | |||
| 31d7110bba | |||
| ad522e6ab1 | |||
| e59f242f19 | |||
| bae625a894 | |||
| b5532ee4a3 | |||
| 31b4b7a372 | |||
| 1a1ed56419 | |||
| 13be8d5139 | |||
| 312901ff68 | |||
| 346b6007ca | |||
| a8df77243c | |||
| f30641da44 | |||
| 049531e495 | |||
| e8594ccec4 | |||
| 65ab436da2 | |||
| e7bd8026d2 | |||
| d9e731c84a | |||
| 8e1e5a3760 | |||
| 02594e3f7a | |||
| da5bf6c74c | |||
| 5cd8f5952f | |||
| 1b8be75a76 | |||
| 235180cf03 | |||
| a13990155f | |||
| a72f11594d | |||
| 86d7a45a78 | |||
| a229d696d5 | |||
| ef6ca3853d | |||
| 9e86d5f5f1 | |||
| 3ef91c61d9 | |||
| 5bae58eeb1 | |||
| 6ce859774a | |||
| fa4a6e2d71 | |||
| 9ee54801a2 | |||
| 79578e08ab | |||
| 732e23b8ea | |||
| d51894103d | |||
| eb59196c02 | |||
| 142eedd705 | |||
| 77d269c6d9 | |||
| b23009a8f3 | |||
| 84de8c1bfd | |||
| 6a9faee109 | |||
| 4d6737230a | |||
| 362f696e3e | |||
| 677d3abe0e | |||
| c78f9137cc | |||
| d8d378e083 | |||
| 8cf9e1990b | |||
| e9f116a14e | |||
| b2253ab7ce | |||
| fc5dc46e73 | |||
| cb9d488a1e | |||
| 389b5c7891 | |||
| 6bf97f7a1a | |||
| d0639393ca | |||
| 7ae6cba337 | |||
| a3e85d6758 | |||
| decce0e3a1 | |||
| aa2868efbf | |||
| 8521114c08 | |||
| 43b5a9cfd0 | |||
| 4387e16496 | |||
| 6f3ebe8d0c | |||
| c972d9b022 | |||
| b1563fdfc0 | |||
| a2c41a2ae3 | |||
| 21623b9c37 | |||
| 7dcafb44f1 | |||
| f9c975bba7 | |||
| 1c6f7b00eb | |||
| fc1709f113 | |||
| 35c2ef09a0 | |||
| dbbf310e36 | |||
| ee1c17d787 | |||
| fe3ea229a2 | |||
| 381ebe1a38 | |||
| 965a65d6f8 | |||
| 25b641125d | |||
| 53aff00218 | |||
| 9f8e1fbb80 | |||
| 5e7a26dc9d | |||
| 7ca6277403 | |||
| 774e86da8d | |||
| 893d349594 | |||
| f7d18154e7 | |||
| 4f5098f0a3 | |||
| e04c6b4732 | |||
| f31cc1b0da | |||
| 3b6711d83d | |||
| 776e8a308c | |||
| d62ac36062 | |||
| 1734182191 | |||
| e0b54d8501 | |||
| 2f3d74c047 | |||
| 66661f2d10 | |||
| cae5cdc81c | |||
| 2f45685a06 | |||
| 8577bf9a4c | |||
| 8e6dcf43b0 | |||
| 15bb3ee31d | |||
| 2234ff78c7 | |||
| fca6a7758b | |||
| 7dae04b8d4 | |||
| 7afb25cead | |||
| b0ddab842b | |||
| a2d08547b6 | |||
| a6aa94110c | |||
| 8f5018f925 | |||
| a47feb9dd8 | |||
| 9ef4ea180b | |||
| 24be115cf6 | |||
| d61504873a | |||
| ae7047571f | |||
| 40fdce9c00 | |||
| d3ede06cad | |||
| 31d25209a0 | |||
| d7ee81418d | |||
| 1d2ce26b81 | |||
| 56095187e6 | |||
| 04e4b917b0 | |||
| 58af226359 | |||
| 88cb7e2f96 | |||
| 728aacd3fb | |||
| 4f56bc32dc | |||
| d16bd0d7eb | |||
| b6fc17e363 | |||
| b6056a44e2 | |||
| 6ce4efa3ce | |||
| 0c0f143f91 | |||
| 2a5ac13e4c | |||
| 6cc6c81493 | |||
| a215cd77ed | |||
| ddad8ef45c | |||
| c1ce1e624d | |||
| d611dbb36a | |||
| 2ee2efeb84 | |||
| 367e429162 | |||
| 8417dfd10e | |||
| 15d1c5f992 | |||
| e0b1a0cfa7 | |||
| cfd9baa0d6 | |||
| 1d80c35708 | |||
| ad88ace448 | |||
| a6d870bf4c | |||
| 646d8a5966 | |||
| 7be8bd7118 | |||
| e98b43e479 | |||
| c167166add | |||
| 68964f1ca1 | |||
| fbcb152107 | |||
| c51ede98fc | |||
| 51183f4be5 | |||
| bf16527aa6 | |||
| 2cce36694d | |||
| 11fbb33a24 | |||
| 2e5c844d46 | |||
| 0b088e8b72 | |||
| 1479197ffb | |||
| c79c7b7a98 | |||
| dfb72c287b | |||
| 1db983a0a0 | |||
| 3ead596a5d | |||
| b8a2139c05 | |||
| 99af9e2c33 | |||
| b7bd11a883 | |||
| 1ac40b2673 | |||
| 5434a26636 | |||
| 50445a73bd | |||
| ff9c031f57 | |||
| c1ebbf36be | |||
| 8717547db4 | |||
| e99996d5b4 | |||
| 7c4a32fffa | |||
| 196729e6d2 | |||
| db94aa94eb | |||
| f670673baf | |||
| f5bd6a6baf | |||
| 9e20cefd4b | |||
| fa66689c07 | |||
| 905b28975e | |||
| 7e5f667b31 | |||
| f103e72c01 | |||
| 6cba6af743 | |||
| eeb44407e3 | |||
| 68df603512 | |||
| 3f8d7d54cf | |||
| b5703ff57a | |||
| f97db691c3 | |||
| 41ab48bc6e | |||
| 087b52c9b4 | |||
| 18f7297968 | |||
| 3cd34e0b4d | |||
| ae1b640725 | |||
| 25e3e46166 | |||
| dc49875af9 | |||
| a36454c86c | |||
| 8fa68c488d | |||
| 2c84d69ff2 | |||
| 3fb28803b5 | |||
| a25cf0a899 | |||
| 6e1efdf2ee | |||
| 8e095d7b5b | |||
| 9899e7f2e3 | |||
| a62a0f4bb7 | |||
| dac792a243 | |||
| 31b3d8f967 | |||
| 55fb816998 | |||
| ce527aea10 | |||
| a7a9301f25 | |||
| 0f551d4b11 | |||
| 35a7bb115d | |||
| 553abc2009 | |||
| 0ad1aeea43 | |||
| 7e52c86095 | |||
| 950338ed22 | |||
| 8ed3b7a250 | |||
| 390c36ca15 | |||
| 1df2e50bbf | |||
| 749dba1ac7 | |||
| a28566a559 | |||
| 64f1c8b80e | |||
| b47f6265c7 | |||
| 9511c952af | |||
| be0877327e | |||
| 3134bfda95 | |||
| 1c177aa206 | |||
| ec65def5d3 | |||
| 3aefa53b33 | |||
| 4fd07a4cf3 | |||
| 03463da729 | |||
| 1cc5ef3479 | |||
| 77f78d0a11 | |||
| 8f98f2368b | |||
| f467e3eed4 | |||
| 3052fe3f3b | |||
| 1bce626324 | |||
| e222998f82 | |||
| 2aca16dc6b | |||
| 653a2623bf | |||
| 03ce9e0ec8 | |||
| 0245ec28eb | |||
| 94f86cb461 | |||
| b4871fddfb | |||
| a598dcc259 | |||
| 918c86476c | |||
| 4d65a220e2 | |||
| 7697f19c3d | |||
| 6ad6409efe | |||
| b6fcc35131 | |||
| bd873dc851 | |||
| 4c2931f6b5 | |||
| 1704c78eea | |||
| bcad8c1b3e | |||
| 81d9193bf4 | |||
| 7514f70434 | |||
| 12a8688a9b | |||
| 0524a724e1 | |||
| 805c7ae301 | |||
| 3f3dabed41 | |||
| 516035a82c | |||
| 08686ee769 | |||
| 5b479ad5f5 | |||
| d4366aa09e | |||
| 3f549bbada | |||
| 1187d50b81 | |||
| a1d4c2a4c7 | |||
| afe386ce40 | |||
| d31669c67f | |||
| 5259a1ced4 | |||
| 437b0decab | |||
| 61ee1be2cb | |||
| 2548891b99 | |||
| 115a7e1dfb | |||
| 5d2be8d5c5 | |||
| 6d08ade20c | |||
| 0043072ecf | |||
| 89c57b6d52 | |||
| f2a08cd178 | |||
| df524e4803 | |||
| b8c4b83653 | |||
| 2df2254227 | |||
| f4d256eef2 | |||
| cb109dc09f | |||
| 919181067a | |||
| 48d252e118 | |||
| 75a07ac722 | |||
| e06bbfac6b | |||
| 4265cfc61e | |||
| 57531d75fe | |||
| 5c1d9a6a2e | |||
| 883009a3bd | |||
| 3ed5e64a01 | |||
| 0fdceb8474 | |||
| 041ec8c7cf | |||
| 07e64152be | |||
| 87d2e51adb | |||
| 30582c69e8 | |||
| 6e34562d94 | |||
| 3da933372f | |||
| 3601baeb80 | |||
| 64b4adf6c8 | |||
| d2d63d3241 | |||
| 4840987082 | |||
| 249a14704b | |||
| cf64d80abe | |||
| 5e511ca6c6 | |||
| c4a547a9ea | |||
| b936e126da | |||
| 5418e74fb9 | |||
| 40a2ed3703 | |||
| 67c8de623d | |||
| bf7c14e6f3 | |||
| 512a50814b | |||
| 3c251dbe56 | |||
| eae33be515 | |||
| a343e4b9f7 | |||
| 5f359a4271 | |||
| ae1dd6e876 | |||
| d1bd2113bf | |||
| c9ae9e11c1 | |||
| b10b8d80ae | |||
| 7f57a094f6 | |||
| b7df08cbdd | |||
| 89dc5f26ad | |||
| 2c60b0463e | |||
| 3093198662 | |||
| 7b8ef2f6e3 | |||
| c56ac70181 | |||
| d77c914fd8 | |||
| 8e91e503c9 | |||
| 97c9f05447 | |||
| 2715bec4c8 | |||
| 45717d7431 | |||
| afd61a369b | |||
| 86082d19e1 | |||
| b7d6825287 | |||
| 1fe13fbad8 | |||
| 1f21e4178d | |||
| aef75238ec | |||
| 419b1ec348 | |||
| bb31af5e8c | |||
| befedac546 | |||
| be0dcb840e | |||
| b521af9b4a | |||
| 61cb22840e | |||
| eaeb5b3b13 | |||
| 466a50ff37 | |||
| 4f2d935a1d | |||
| b19126024a | |||
| 56eb1fc6e4 | |||
| 07a2a6710d | |||
| cbedd221f3 | |||
| d684911fce | |||
| b625965982 | |||
| 9688469501 | |||
| f9cb9b7ea2 | |||
| 6448258f4e | |||
| 9f1a3c6eff | |||
| 21c2bf4861 | |||
| b9753a0785 | |||
| ff27ac5670 | |||
| 720679b41b | |||
| 248843583e | |||
| 1f3ef99390 | |||
| e74b56c50e | |||
| c924d55a26 | |||
| 4964a067d0 | |||
| 264196a11f | |||
| bfa70b4ba6 | |||
| 7e5d554bd8 | |||
| a90039baab | |||
| 55228f9667 | |||
| 6295c2ddc4 | |||
| 5ca6d01911 | |||
| 6d9fed6644 | |||
| 3c8bfb8bc8 | |||
| 00987f3642 | |||
| 6e070ae057 | |||
| ac70bfc456 | |||
| fd0f323666 | |||
| 0e31557abf | |||
| e7c1d20d8e | |||
| e8c8f0de0d | |||
| ea0773e8fc | |||
| 037306a30c | |||
| 9ea94cb6cc | |||
| 97fe09f157 | |||
| 5b149bd41a | |||
| 8a899f2116 | |||
| dfa2f46ced | |||
| 2b2d1d87f7 | |||
| 3784b77b95 | |||
| 7f418e2de4 | |||
| 78da19f479 | |||
| 4e18ebe843 | |||
| 152a8b311f | |||
| 64470a3c7d | |||
| fae035731f | |||
| 446a48ca00 | |||
| ce9b34c9eb | |||
| d1ed176550 | |||
| 652219b8cf | |||
| e6229f6145 | |||
| 9c066d93fa | |||
| e754689014 | |||
| de96de2de1 | |||
| 6d89c893b7 | |||
| 16df6a32d6 | |||
| a337384e7b | |||
| cdb6de05b3 | |||
| 1b262eadaa | |||
| fd5ea8a0b1 | |||
| fe31d2d28a | |||
| 40b66e8eb3 | |||
| 71e83962ac | |||
| 5316d586d1 | |||
| f79039e4f7 | |||
| f4d6b69002 | |||
| 08e6dc20e1 | |||
| 4f14d8a64f | |||
| da53dfc903 | |||
| 875cfefd36 | |||
| b6fb996ceb | |||
| 316559ae09 | |||
| 08d28d7ed4 | |||
| 3a3adf43a4 | |||
| 0951305962 | |||
| 481935c880 | |||
| 8ffcdad89a | |||
| 9e3ce09658 | |||
| 8c5d0775bc | |||
| 36e8b10917 | |||
| b2b048994c | |||
| 6db23e67e8 | |||
| 7872e95561 | |||
| 45eeee9aea | |||
| 9cbc693c77 | |||
| ee9d4ab70e | |||
| 68c3113b75 | |||
| 3a71b0470b | |||
| 421cdb41b9 | |||
| a8538a1361 | |||
| c3cedd2dc9 | |||
| da38218941 | |||
| c700ca0430 | |||
| 0fe3f2d03c | |||
| 65b1e13b83 | |||
| 2acb387446 | |||
| 746273a2ef | |||
| 778beba901 | |||
| 9278920093 | |||
| ece868c9de | |||
| 651ed9b91e | |||
| ac993680db | |||
| 48b33ed07d | |||
| 724953206f | |||
| c4e3b90201 | |||
| a722d1aa36 | |||
| 25e3ae0325 | |||
| e26da5887d | |||
| 31037797e4 | |||
| 2ae7cba452 | |||
| fa3ebc8c0f | |||
| ff36781c98 | |||
| 2f038cbe66 | |||
| f962888b35 | |||
| 6880368a79 | |||
| 13ba6883b4 | |||
| 1e6e804ebb | |||
| 5690d9fe81 | |||
| 6fef8de63e | |||
| e29185ef11 | |||
| c999a6e0e4 | |||
| 2bbf5c7800 | |||
| 273203e4c9 | |||
| 1211680998 | |||
| 84e76556da | |||
| 55881d594b | |||
| 6f0882a098 | |||
| dda465d08a | |||
| 124c517056 | |||
| 6fa6863244 | |||
| 0ad26c337a | |||
| 353eb27d2e | |||
| 6edb0b7a3d | |||
| cd5f0c0047 | |||
| 5716c7c574 | |||
| ce30299122 | |||
| 9b5593d020 | |||
| 4d642b91ef | |||
| 8b4cff474f | |||
| 73ce81d597 | |||
| 09e4c585aa | |||
| 2c5af98cca | |||
| cbe07b49aa | |||
| aa557a7bdf | |||
| 65cafdda03 | |||
| 9a18ff5954 | |||
| d2bc7ab192 | |||
| bf7d2defd6 | |||
| c4e4429744 | |||
| bfc382c398 | |||
| 795399e184 | |||
| 37bdfb716b | |||
| 405afca1c6 | |||
| 7627e0b0f0 | |||
| 25d2206471 | |||
| 2d96444e21 | |||
| f5c3bdb845 | |||
| 22b932ebee | |||
| ad157fe423 | |||
| 50a6d251d6 | |||
| f3d36a9726 | |||
| c2b8cedef1 | |||
| 21fd2b8f1d | |||
| c7461f476e | |||
| 8e65d30a84 | |||
| 626964f15b | |||
| c058483422 | |||
| 57e6419d1d | |||
| 9b7547cbe0 | |||
| e74dfe3438 | |||
| fe82e3e30f | |||
| b000e8e4a2 | |||
| 64c82f1c87 | |||
| 0ad2730353 | |||
| 6017b73acf | |||
| 0334177696 | |||
| 54cec0a5ff | |||
| c5fa2bf12d | |||
| bc8a1756f3 | |||
| 3f01e2f748 | |||
| 7dfe829fc8 | |||
| c87bc57f9e | |||
| 89bd241a78 | |||
| d15fd34f7a | |||
| a118cdd32b | |||
| 3a2de9c698 | |||
| c60e5d90fd | |||
| e9bff37e06 | |||
| 695f8da3c3 | |||
| ea5c5c9e84 | |||
| 4f9108980f | |||
| 8148e4e50d | |||
| f07a832c83 | |||
| 070d239f41 | |||
| 9b02055db9 | |||
| 0162247bd7 | |||
| 9001d34ddf | |||
| cbcc30b384 | |||
| ce9fe90217 | |||
| 7a9278e6a7 | |||
| 01622140e3 | |||
| e44027b186 | |||
| d53f97ecfe | |||
| f3efd7d60b | |||
| 8d25da9474 | |||
| 1aee276b45 | |||
| 191bc115cf | |||
| 63488997ee | |||
| a22480d857 | |||
| 757ae6de39 | |||
| cfc08e8b98 | |||
| c8e9282557 | |||
| a36163ce86 | |||
| e3d1a6aef8 | |||
| 7d8256d343 | |||
| bf9f8597a7 | |||
| 9f2c8c1756 | |||
| 0ae8765a8a | |||
| 308960309d | |||
| b8ac8516fe | |||
| 38a347ddab | |||
| f30c56c237 | |||
| bb9d67a1b1 | |||
| 58c55cdf81 | |||
| 50a616d91c | |||
| a2be86d15a | |||
| 73f8c28add | |||
| d015793851 | |||
| 0b5b741db4 | |||
| aeac32ae47 | |||
| fab60e7faa | |||
| 6296665f46 | |||
| 1fe6c498ac |
@@ -6,3 +6,9 @@ spec/fixtures/**/*.less text eol=lf
|
||||
spec/fixtures/**/*.css text eol=lf
|
||||
spec/fixtures/**/*.txt text eol=lf
|
||||
spec/fixtures/dir/**/* text eol=lf
|
||||
|
||||
# Git 1.7 does not support **/* patterns
|
||||
spec/fixtures/css.css text eol=lf
|
||||
spec/fixtures/sample.js text eol=lf
|
||||
spec/fixtures/sample.less text eol=lf
|
||||
spec/fixtures/sample.txt text eol=lf
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
ca =
|
||||
cache = ~/.atom/.npm
|
||||
|
||||
+69
-43
@@ -1,64 +1,83 @@
|
||||
# :tada: Contributing to Atom :tada:
|
||||
# Contributing to Atom
|
||||
|
||||
These are just guidelines, not rules, use your best judgement and feel free
|
||||
to propose changes to this document in a pull request.
|
||||
:+1::tada: First off, thanks for taking the time to contribute! :tada::+1:
|
||||
|
||||
## Issues
|
||||
* Include screenshots and animated GIFs whenever possible, they are immensely
|
||||
helpful.
|
||||
* Include the behavior you expected to happen and other places you've seen
|
||||
that behavior such as Emacs, vi, Xcode, etc.
|
||||
* Check the Console app for stack traces to include if reporting a crash.
|
||||
* Check the Dev tools (`alt-cmd-i`) for errors and stack traces to include.
|
||||
The following is a set of guidelines for contributing to Atom and its 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 open an issue on the [main atom repository](https://github.com/atom/atom/issues).
|
||||
These are just guidelines, not rules, use your best judgement and feel free to
|
||||
propose changes to this document in a pull request.
|
||||
|
||||
## Submitting Issues
|
||||
|
||||
* Check the [debugging guide](https://atom.io/docs/latest/debugging) for tips
|
||||
on debugging. You might be able to find the cause of the problem and fix
|
||||
things yourself.
|
||||
* Include the version of Atom you are using and the OS.
|
||||
* 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 to include. If the dev tools
|
||||
are open _before_ the error is triggered, a full stack trace for the error
|
||||
will be logged. If you can reproduce the error, use this approach to get the
|
||||
full stack trace and include it in the issue.
|
||||
* On Mac, 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.
|
||||
|
||||
### Package Repositories
|
||||
|
||||
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 organization](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).
|
||||
[language-javascript](https://github.com/atom/language-javascript), and
|
||||
[atom-light-ui](http://github.com/atom/atom-light-ui).
|
||||
|
||||
If you think you know which package is causing the issue you are reporting, feel
|
||||
free to open up the issue in that specific repository instead. When in doubt
|
||||
just open the issue here but be aware that it may get closed here and reopened
|
||||
in the proper package's repository.
|
||||
For more information on how to work with Atom's official packages, see
|
||||
[Contributing to Atom Packages](https://atom.io/docs/latest/contributing-to-packages.html)
|
||||
|
||||
## Pull Requests
|
||||
* Include screenshots and animated GIFs whenever possible.
|
||||
* Follow the [CoffeeScript](#coffeescript-styleguide),
|
||||
[JavaScript](https://github.com/styleguide/javascript),
|
||||
and [CSS](https://github.com/styleguide/css) styleguides
|
||||
* Include thoughtfully worded [Jasmine](http://jasmine.github.io/)
|
||||
specs
|
||||
* Avoid placing files in `vendor`. 3rd-party packages should be added as a
|
||||
`package.json` dependency.
|
||||
* Files end with a newline.
|
||||
* Requires should be in the following order:
|
||||
|
||||
* 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://jasmine.github.io/) 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)
|
||||
* Class variables and methods should be in the following order:
|
||||
* Class methods (methods starting with a `@`)
|
||||
* Instance methods
|
||||
* Beware of platform differences
|
||||
* 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.
|
||||
* Temporary directory is not `/tmp` on Windows, use `os.tmpdir()` when
|
||||
possible
|
||||
* Use `os.tmpdir()` rather than `/tmp` when you need to reference the
|
||||
temporary directory.
|
||||
|
||||
## Git Commit Messages
|
||||
* Use the present tense
|
||||
* Reference issues and pull requests liberally
|
||||
* Consider starting the commit message with an applicable emoji:
|
||||
|
||||
* 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: `:lipstick:` when improving the format/structure of the code
|
||||
* :racehorse: `:racehorse:` when improving performance
|
||||
* :non-potable_water: `:non-potable_water:` when plugging memory leaks
|
||||
* :memo: `:memo:` when writing docs
|
||||
* :penguin: `:penguin:` when fixing something on Linux
|
||||
* :apple: `:apple:` when fixing something on Mac OS
|
||||
* :bug: `:bug:` when fixing a bug
|
||||
* :checkered_flag: `:checkered_flag:` when fixing something on Windows
|
||||
* :bug: `:bug:` when fixing a bug
|
||||
* :fire: `:fire:` when removing code or files
|
||||
* :green_heart: `:green_heart:` when fixing the CI build
|
||||
* :white_check_mark: `:white_check_mark:` when adding tests
|
||||
@@ -67,17 +86,24 @@ in the proper package's repository.
|
||||
## CoffeeScript Styleguide
|
||||
|
||||
* Set parameter defaults without spaces around the equal sign
|
||||
* `clear = (count=1) ->` instead of `clear = (count = 1) ->`
|
||||
* `clear = (count=1) ->` instead of `clear = (count = 1) ->`
|
||||
* 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 }`
|
||||
* Include a single line of whitespace between methods.
|
||||
|
||||
## 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.
|
||||
* 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}`
|
||||
* Delegate to comments elsewhere with `{Delegates to: ClassName.methodName}`
|
||||
style notation.
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
+1
-1
@@ -6,6 +6,6 @@
|
||||
"url": "https://github.com/atom/atom.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"atom-package-manager": "0.54.0"
|
||||
"atom-package-manager": "0.69.0"
|
||||
}
|
||||
}
|
||||
|
||||
+5
-3
@@ -70,16 +70,18 @@ elif [ $OS == 'Linux' ]; then
|
||||
USR_DIRECTORY=$(readlink -f $(dirname $SCRIPT)/..)
|
||||
ATOM_PATH="$USR_DIRECTORY/share/atom/atom"
|
||||
|
||||
[ -x "$ATOM_PATH" ] || ATOM_PATH='/tmp/atom-build/Atom/atom'
|
||||
: ${TMPDIR:=/tmp}
|
||||
|
||||
[ -x "$ATOM_PATH" ] || ATOM_PATH="$TMPDIR/atom-build/Atom/atom"
|
||||
|
||||
if [ $EXPECT_OUTPUT ]; then
|
||||
"$ATOM_PATH" --executed-from="$(pwd)" --pid=$$ "$@"
|
||||
exit $?
|
||||
else
|
||||
(
|
||||
nohup "$ATOM_PATH" --executed-from="$(pwd)" --pid=$$ "$@" > /tmp/atom-nohup.out 2>&1
|
||||
nohup "$ATOM_PATH" --executed-from="$(pwd)" --pid=$$ "$@" > "$TMPDIR/atom-nohup.out" 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
cat /tmp/atom-nohup.out
|
||||
cat "$TMPDIR/atom-nohup.out"
|
||||
exit $?
|
||||
fi
|
||||
) &
|
||||
|
||||
@@ -36,35 +36,23 @@ module.exports = (grunt) ->
|
||||
grunt.log.write = (args...) -> grunt.log
|
||||
|
||||
[major, minor, patch] = packageJson.version.split('.')
|
||||
tmpDir = os.tmpdir()
|
||||
appName = if process.platform is 'darwin' then 'Atom.app' else 'Atom'
|
||||
buildDir = grunt.option('build-dir') ? path.join(tmpDir, 'atom-build')
|
||||
atomShellDownloadDir = path.join(os.tmpdir(), 'atom-cached-atom-shells')
|
||||
symbolsDir = path.join(buildDir, 'Atom.breakpad.syms')
|
||||
shellAppDir = path.join(buildDir, appName)
|
||||
if process.platform is 'win32'
|
||||
appName = 'Atom'
|
||||
tmpDir = os.tmpdir()
|
||||
buildDir = grunt.option('build-dir') ? path.join(tmpDir, 'atom-build')
|
||||
symbolsDir = path.join(buildDir, 'Atom.breakpad.syms')
|
||||
shellAppDir = path.join(buildDir, appName)
|
||||
contentsDir = shellAppDir
|
||||
appDir = path.join(shellAppDir, 'resources', 'app')
|
||||
atomShellDownloadDir = path.join(os.tmpdir(), 'atom-cached-atom-shells')
|
||||
installDir = path.join(process.env.ProgramFiles, appName)
|
||||
else if process.platform is 'darwin'
|
||||
appName = 'Atom.app'
|
||||
tmpDir = '/tmp'
|
||||
buildDir = grunt.option('build-dir') ? path.join(tmpDir, 'atom-build')
|
||||
symbolsDir = path.join(buildDir, 'Atom.breakpad.syms')
|
||||
shellAppDir = path.join(buildDir, appName)
|
||||
contentsDir = path.join(shellAppDir, 'Contents')
|
||||
appDir = path.join(contentsDir, 'Resources', 'app')
|
||||
atomShellDownloadDir = '/tmp/atom-cached-atom-shells'
|
||||
installDir = path.join('/Applications', appName)
|
||||
else
|
||||
appName = 'Atom'
|
||||
tmpDir = '/tmp'
|
||||
buildDir = grunt.option('build-dir') ? path.join(tmpDir, 'atom-build')
|
||||
symbolsDir = path.join(buildDir, 'Atom.breakpad.syms')
|
||||
shellAppDir = path.join(buildDir, appName)
|
||||
contentsDir = shellAppDir
|
||||
appDir = path.join(shellAppDir, 'resources', 'app')
|
||||
atomShellDownloadDir = '/tmp/atom-cached-atom-shells'
|
||||
installDir = process.env.INSTALL_PREFIX ? '/usr/local'
|
||||
|
||||
coffeeConfig =
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"grunt-contrib-coffee": "~0.9.0",
|
||||
"grunt-contrib-less": "~0.8.0",
|
||||
"grunt-cson": "0.8.0",
|
||||
"grunt-download-atom-shell": "~0.7.0",
|
||||
"grunt-download-atom-shell": "~0.8.0",
|
||||
"grunt-lesslint": "0.13.0",
|
||||
"grunt-markdown": "~0.4.0",
|
||||
"grunt-peg": "~1.1.0",
|
||||
@@ -26,7 +26,7 @@
|
||||
"harmony-collections": "~0.3.8",
|
||||
"json-front-matter": "~0.1.3",
|
||||
"legal-eagle": "~0.4.0",
|
||||
"minidump": "0.5.x",
|
||||
"minidump": "~0.7",
|
||||
"read-package-json": "1.1.8",
|
||||
"normalize-package-data": "0.2.12",
|
||||
"rcedit": "~0.1.2",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
_ = require 'underscore-plus'
|
||||
|
||||
module.exports = (grunt) ->
|
||||
{cp, isAtomPackage, mkdir, rm} = require('./task-helpers')(grunt)
|
||||
@@ -48,16 +49,22 @@ module.exports = (grunt) ->
|
||||
path.join('bootstrap', 'docs')
|
||||
path.join('bootstrap', 'examples')
|
||||
path.join('pegjs', 'examples')
|
||||
# Add .* to avoid matching hunspell_dictionaries.
|
||||
path.join('spellchecker', 'vendor', 'hunspell', '.*')
|
||||
path.join('plist', 'tests')
|
||||
path.join('xmldom', 'test')
|
||||
path.join('jasmine-reporters', 'ext')
|
||||
path.join('build', 'Release', 'obj.target')
|
||||
path.join('build', 'Release', 'obj')
|
||||
path.join('build', 'Release', '.deps')
|
||||
path.join('vendor', 'apm')
|
||||
path.join('resources', 'mac')
|
||||
path.join('resources', 'win')
|
||||
]
|
||||
ignoredPaths = ignoredPaths.map (ignoredPath) -> _.escapeRegExp(ignoredPath)
|
||||
|
||||
# Add .* to avoid matching hunspell_dictionaries.
|
||||
ignoredPaths.push "#{_.escapeRegExp(path.join('spellchecker', 'vendor', 'hunspell') + path.sep)}.*"
|
||||
ignoredPaths.push "#{_.escapeRegExp(path.join('build', 'Release') + path.sep)}.*\\.pdb"
|
||||
|
||||
# Hunspell dictionaries are only not needed on OS X.
|
||||
if process.platform is 'darwin'
|
||||
ignoredPaths.push path.join('spellchecker', 'vendor', 'hunspell_dictionaries')
|
||||
@@ -79,6 +86,10 @@ module.exports = (grunt) ->
|
||||
unless /.+\.plist/.test(sourcePath)
|
||||
grunt.file.copy(sourcePath, path.resolve(appDir, '..', subDirectory, filename))
|
||||
|
||||
if process.platform is 'win32'
|
||||
cp path.join('resources', 'win', 'msvcp100.dll'), path.join(shellAppDir, 'msvcp100.dll')
|
||||
cp path.join('resources', 'win', 'msvcr100.dll'), path.join(shellAppDir, 'msvcr100.dll')
|
||||
|
||||
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'
|
||||
|
||||
@@ -5,7 +5,7 @@ module.exports = (grunt) ->
|
||||
{rm} = require('./task-helpers')(grunt)
|
||||
|
||||
grunt.registerTask 'partial-clean', 'Delete some of the build files', ->
|
||||
tmpdir = if process.platform is 'win32' then os.tmpdir() else '/tmp'
|
||||
tmpdir = os.tmpdir()
|
||||
|
||||
rm grunt.config.get('atom.buildDir')
|
||||
rm require('../src/coffee-cache').cacheDir
|
||||
|
||||
@@ -2,6 +2,8 @@ module.exports = (grunt) ->
|
||||
{spawn} = require('./task-helpers')(grunt)
|
||||
|
||||
grunt.registerTask 'codesign', 'Codesign the app', ->
|
||||
return unless process.platform is 'darwin'
|
||||
|
||||
done = @async()
|
||||
|
||||
if process.env.XCODE_KEYCHAIN
|
||||
|
||||
@@ -143,7 +143,7 @@ downloadFileFromRepo = ({repo, file}, callback) ->
|
||||
|
||||
downloadIncludes = (callback) ->
|
||||
includes = [
|
||||
{repo: 'atom-keymap', file: 'src/keymap.coffee'}
|
||||
{repo: 'atom-keymap', file: 'src/keymap-manager.coffee'}
|
||||
{repo: 'atom-keymap', file: 'src/key-binding.coffee'}
|
||||
{repo: 'first-mate', file: 'src/grammar.coffee'}
|
||||
{repo: 'first-mate', file: 'src/grammar-registry.coffee'}
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
_ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
runas = null
|
||||
|
||||
fillTemplate = (filePath, data) ->
|
||||
template = _.template(String(fs.readFileSync(filePath + '.in')))
|
||||
filled = template(data)
|
||||
fs.writeFileSync(filePath, filled)
|
||||
|
||||
module.exports = (grunt) ->
|
||||
{cp, mkdir, rm} = require('./task-helpers')(grunt)
|
||||
|
||||
@@ -25,12 +31,23 @@ module.exports = (grunt) ->
|
||||
binDir = path.join(installDir, 'bin')
|
||||
shareDir = path.join(installDir, 'share', 'atom')
|
||||
|
||||
iconName = path.join(shareDir,'resources','app','resources','atom.png')
|
||||
desktopFile = path.join('resources', 'linux', 'Atom.desktop')
|
||||
|
||||
mkdir binDir
|
||||
cp 'atom.sh', path.join(binDir, 'atom')
|
||||
rm shareDir
|
||||
mkdir path.dirname(shareDir)
|
||||
cp shellAppDir, shareDir
|
||||
|
||||
# Create Atom.desktop if installation in '/usr/local'
|
||||
applicationsDir = path.join('/usr','share','applications')
|
||||
tmpDir = if process.env.TMPDIR? then process.env.TMPDIR else '/tmp'
|
||||
if installDir.indexOf(tmpDir) isnt 0 and fs.isDirectorySync(applicationsDir)
|
||||
{description} = grunt.file.readJSON('package.json')
|
||||
fillTemplate(desktopFile, {description, installDir, iconName})
|
||||
cp desktopFile, path.join(applicationsDir,'Atom.desktop')
|
||||
|
||||
# Create relative symbol link for apm.
|
||||
process.chdir(binDir)
|
||||
rm('apm')
|
||||
|
||||
@@ -13,11 +13,19 @@ module.exports = (grunt) ->
|
||||
grunt.registerTask 'mkdeb', 'Create debian package', ->
|
||||
done = @async()
|
||||
|
||||
if process.arch is 'ia32'
|
||||
arch = 'i386'
|
||||
else if process.arch is 'x64'
|
||||
arch = 'amd64'
|
||||
else
|
||||
return done("Unsupported arch #{process.arch}")
|
||||
|
||||
{name, version, description} = grunt.file.readJSON('package.json')
|
||||
section = 'devel'
|
||||
arch = 'amd64'
|
||||
maintainer = 'GitHub <atom@github.com>'
|
||||
data = {name, version, description, section, arch, maintainer}
|
||||
installDir = '/usr'
|
||||
iconName = 'atom'
|
||||
data = {name, version, description, section, arch, maintainer, installDir, iconName}
|
||||
|
||||
control = path.join('resources', 'linux', 'debian', 'control')
|
||||
fillTemplate(control, data)
|
||||
@@ -27,5 +35,5 @@ module.exports = (grunt) ->
|
||||
buildDir = grunt.config.get('atom.buildDir')
|
||||
|
||||
cmd = path.join('script', 'mkdeb')
|
||||
args = [version, control, desktop, icon, buildDir]
|
||||
args = [version, arch, control, desktop, icon, buildDir]
|
||||
spawn({cmd, args}, done)
|
||||
|
||||
@@ -8,11 +8,17 @@ GitHub = require 'github-releases'
|
||||
request = require 'request'
|
||||
|
||||
grunt = null
|
||||
maxReleases = 10
|
||||
assets = [
|
||||
{assetName: 'atom-mac.zip', sourceName: 'Atom.app'}
|
||||
{assetName: 'atom-mac-symbols.zip', sourceName: 'Atom.breakpad.syms'}
|
||||
]
|
||||
|
||||
if process.platform is 'darwin'
|
||||
assets = [
|
||||
{assetName: 'atom-mac.zip', sourceName: 'Atom.app'}
|
||||
{assetName: 'atom-mac-symbols.zip', sourceName: 'Atom.breakpad.syms'}
|
||||
]
|
||||
else
|
||||
assets = [
|
||||
{assetName: 'atom-windows.zip', sourceName: 'Atom'}
|
||||
]
|
||||
|
||||
commitSha = process.env.JANKY_SHA1
|
||||
token = process.env.ATOM_ACCESS_TOKEN
|
||||
defaultHeaders =
|
||||
@@ -23,7 +29,6 @@ module.exports = (gruntObject) ->
|
||||
grunt = gruntObject
|
||||
|
||||
grunt.registerTask 'publish-build', 'Publish the built app', ->
|
||||
return unless process.platform is 'darwin'
|
||||
return if process.env.JANKY_SHA1 and process.env.JANKY_BRANCH isnt 'master'
|
||||
|
||||
done = @async()
|
||||
@@ -45,10 +50,13 @@ logError = (message, error, details) ->
|
||||
|
||||
zipApps = (buildDir, assets, callback) ->
|
||||
zip = (directory, sourceName, assetName, callback) ->
|
||||
if process.platform is 'win32'
|
||||
zipCommand = "C:/psmodules/7z.exe a -r #{assetName} #{sourceName}"
|
||||
else
|
||||
zipCommand = "zip -r --symlinks #{assetName} #{sourceName}"
|
||||
options = {cwd: directory, maxBuffer: Infinity}
|
||||
child_process.exec "zip -r --symlinks #{assetName} #{sourceName}", options, (error, stdout, stderr) ->
|
||||
if error?
|
||||
logError("Zipping #{sourceName} failed", error, stderr)
|
||||
child_process.exec zipCommand, options, (error, stdout, stderr) ->
|
||||
logError("Zipping #{sourceName} failed", error, stderr) if error?
|
||||
callback(error)
|
||||
|
||||
tasks = []
|
||||
|
||||
@@ -39,7 +39,8 @@ module.exports = (grunt) ->
|
||||
grunt.verbose.writeln "Launching #{path.basename(packagePath)} specs."
|
||||
spawn options, (error, results, code) ->
|
||||
if process.platform is 'win32'
|
||||
process.stderr.write(fs.readFileSync(path.join(packagePath, 'ci.log')))
|
||||
if error
|
||||
process.stderr.write(fs.readFileSync(path.join(packagePath, 'ci.log')))
|
||||
fs.unlinkSync(path.join(packagePath, 'ci.log'))
|
||||
|
||||
failedPackages.push path.basename(packagePath) if error
|
||||
@@ -77,7 +78,7 @@ module.exports = (grunt) ->
|
||||
|
||||
spawn options, (error, results, code) ->
|
||||
if process.platform is 'win32'
|
||||
process.stderr.write(fs.readFileSync('ci.log'))
|
||||
process.stderr.write(fs.readFileSync('ci.log')) if error
|
||||
fs.unlinkSync('ci.log')
|
||||
else
|
||||
# TODO: Restore concurrency on Windows
|
||||
@@ -104,9 +105,4 @@ module.exports = (grunt) ->
|
||||
failures.push "atom core" if coreSpecFailed
|
||||
|
||||
grunt.log.error("[Error]".red + " #{failures.join(', ')} spec(s) failed") if failures.length > 0
|
||||
|
||||
# TODO: Mark the build as green on Windows until specs pass.
|
||||
if process.platform is 'darwin'
|
||||
done(!coreSpecFailed and failedPackages.length == 0)
|
||||
else if process.platform is 'win32'
|
||||
done(true)
|
||||
done(!coreSpecFailed and failedPackages.length == 0)
|
||||
|
||||
@@ -91,6 +91,16 @@ the current keystroke sequence and continue searching from its parent. If you
|
||||
want to remove a binding from a keymap you don't control, such as keymaps in
|
||||
Atom core or in packages, use the `unset!` directive.
|
||||
|
||||
For example, the following code removes the keybinding for `a` in the Tree View,
|
||||
which is normally used to trigger the `tree-view:add-file` command:
|
||||
|
||||
```coffee
|
||||
'.tree-view':
|
||||
'a': 'unset!'
|
||||
```
|
||||
|
||||

|
||||
|
||||
## Forcing Chromium's Native Keystroke Handling
|
||||
|
||||
If you want to force the native browser behavior for a given keystroke, use the
|
||||
|
||||
@@ -0,0 +1,216 @@
|
||||
## Atom.io package and update API
|
||||
|
||||
This guide describes the web API used by [apm](https://github.com/atom/apm) and
|
||||
Atom. The vast majority of use cases are met by the `apm` command-line tool,
|
||||
which does other useful things like incrementing your version in `package.json`
|
||||
and making sure you have pushed your git tag. In fact, Atom itself shells out to
|
||||
`apm` rather than hitting the API directly. If you're curious about how Atom
|
||||
uses `apm`, see the [PackageManager class](https://github.com/atom/settings-view/blob/master/lib/package-manager.coffee)
|
||||
in the `settings-view` package.
|
||||
|
||||
### Authorization
|
||||
|
||||
For calls to the API that require authentication, provide a valid token from your
|
||||
[Atom.io account page](https://atom.io/account) in the `Authorization` header.
|
||||
|
||||
### Media type
|
||||
|
||||
All requests that take parameters require `application/json`.
|
||||
|
||||
## Resources
|
||||
|
||||
### Packages
|
||||
|
||||
#### GET /api/packages
|
||||
|
||||
Returns a list of all packages in the following format:
|
||||
```json
|
||||
[
|
||||
{
|
||||
"releases": {
|
||||
"latest": "0.6.0"
|
||||
},
|
||||
"name": "thedaniel-test-package",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thedaniel/test-package"
|
||||
}
|
||||
},
|
||||
...
|
||||
]
|
||||
```
|
||||
|
||||
#### GET /api/packages/:package_name
|
||||
|
||||
Returns package details and versions for a single package
|
||||
|
||||
Parameters:
|
||||
|
||||
- **engine** (optional) - Only show packages with versions compatible with this
|
||||
Atom version. Must be valid [SemVer](http://semver.org).
|
||||
|
||||
Returns:
|
||||
|
||||
```json
|
||||
{
|
||||
"releases": {
|
||||
"latest": "0.6.0"
|
||||
},
|
||||
"name": "thedaniel-test-package",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thedaniel/test-package"
|
||||
},
|
||||
"versions": [
|
||||
(see single version output below)
|
||||
...,
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### POST /api/packages
|
||||
|
||||
Create a new package; requires authentication.
|
||||
|
||||
The name and version will be fetched from the `package.json`
|
||||
file in the specified repository. The authenticating user *must* have access
|
||||
to the indicated repository.
|
||||
|
||||
When a package is created, a release hook is registered with GitHub for package
|
||||
version creation.
|
||||
|
||||
Parameters:
|
||||
|
||||
- **repository** - String. The repository containing the plugin, in the form "owner/repo"
|
||||
|
||||
Returns:
|
||||
|
||||
- **201** - Successfully created, returns created package.
|
||||
- **400** - Repository is inaccessible, nonexistent, not an atom package. Possible
|
||||
error messages include:
|
||||
- That repo does not exist, isn't an atom package, or atombot does not have access
|
||||
- The package.json at owner/repo isn't valid
|
||||
- **409** - A package by that name already exists
|
||||
|
||||
|
||||
#### DELETE /api/packages/:package_name
|
||||
|
||||
Delete a package; requires authentication.
|
||||
|
||||
Returns:
|
||||
|
||||
- **204** - Success
|
||||
- **400** - Repository is inaccessible
|
||||
- **401** - Unauthorized
|
||||
|
||||
### Package Versions
|
||||
|
||||
#### GET /api/packages/:package_name/versions/:version_name
|
||||
|
||||
Returns `package.json` with `dist` key added for e.g. tarball download:
|
||||
|
||||
```json
|
||||
{
|
||||
"bugs": {
|
||||
"url": "https://github.com/thedaniel/test-package/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"async": "~0.2.6",
|
||||
"pegjs": "~0.7.0",
|
||||
"season": "~0.13.0"
|
||||
},
|
||||
"description": "Expand snippets matching the current prefix with `tab`.",
|
||||
"dist": {
|
||||
"tarball": "https://codeload.github.com/..."
|
||||
},
|
||||
"engines": {
|
||||
"atom": "*"
|
||||
},
|
||||
"main": "./lib/snippets",
|
||||
"name": "thedaniel-test-package",
|
||||
"publishConfig": {
|
||||
"registry": "https://...",
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thedaniel/test-package.git"
|
||||
},
|
||||
"version": "0.6.0"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Creating a new package version
|
||||
|
||||
#### POST /api/packages/:package_name/versions
|
||||
|
||||
Creates a new package version from a git tag; requires authentication.
|
||||
|
||||
#### Parameters
|
||||
|
||||
- **tag** - A git tag for the version you'd like to create. It's important to note
|
||||
that the version name will not be taken from the tag, but from the `version`
|
||||
key in the `package.json` file at that ref. The authenticating user *must* have
|
||||
access to the package repository.
|
||||
|
||||
#### Returns
|
||||
|
||||
- **201** - Successfully created. Returns created version.
|
||||
- **400** - Git tag not found / Repository inaccessible
|
||||
- **409** - Version exists
|
||||
|
||||
### Delete a version
|
||||
|
||||
#### DELETE /api/packages/:package_name/versions/:version_name
|
||||
|
||||
Deletes a package version; requires authentication.
|
||||
|
||||
Note that a version cannot be republished with a different tag if it is deleted.
|
||||
If you need to delete the latest version of a package for e.g. security reasons,
|
||||
you'll need to increment the version when republishing.
|
||||
|
||||
Returns 204 No Content
|
||||
|
||||
|
||||
### Stars
|
||||
|
||||
#### GET /api/users/:login/stars
|
||||
|
||||
List a user's starred packages.
|
||||
|
||||
Return value is similar to **GET /api/packages**
|
||||
|
||||
#### GET /api/stars
|
||||
|
||||
List the authenticated user's starred packages; requires authentication.
|
||||
|
||||
Return value is similar to **GET /api/packages**
|
||||
|
||||
#### POST /api/packages/:name/star
|
||||
|
||||
Star a package; requires authentication.
|
||||
|
||||
Returns a package.
|
||||
|
||||
#### DELETE /api/packages/:name/star
|
||||
|
||||
Unstar a package; requires authentication.
|
||||
|
||||
Returns 204 No Content.
|
||||
|
||||
### Atom updates
|
||||
|
||||
#### GET /api/updates
|
||||
|
||||
Atom update feed, following the format expected by [Squirrel](https://github.com/Squirrel/).
|
||||
|
||||
Returns:
|
||||
|
||||
```
|
||||
{
|
||||
"name": "0.96.0",
|
||||
"notes": "[HTML release notes]"
|
||||
"pub_date": "2014-05-19T15:52:06.000Z",
|
||||
"url": "https://www.atom.io/api/updates/download"
|
||||
}
|
||||
```
|
||||
@@ -15,7 +15,7 @@ FreeBSD -RELEASE 64-bit is the recommended platform.
|
||||
```sh
|
||||
git clone https://github.com/atom/atom
|
||||
cd atom
|
||||
script/build # Creates application at /tmp/atom-build/Atom
|
||||
script/build # Creates application at $TMPDIR/atom-build/Atom
|
||||
sudo script/grunt install # Installs command to /usr/local/bin/atom
|
||||
```
|
||||
|
||||
|
||||
@@ -4,20 +4,63 @@ Ubuntu LTS 12.04 64-bit is the recommended platform.
|
||||
|
||||
## Requirements
|
||||
|
||||
* OS with 64-bit architecture
|
||||
* OS with 64-bit or 32-bit architecture
|
||||
* C++ toolchain
|
||||
* on Ubuntu/Debian: `sudo apt-get install build-essential`
|
||||
* on Fedora: `sudo yum --assumeyes install make gcc gcc-c++ glibc-devel`
|
||||
* [node.js](http://nodejs.org/download/) v0.10.x
|
||||
* [npm](http://www.npmjs.org/) v1.4.x
|
||||
* libgnome-keyring-dev `sudo apt-get install libgnome-keyring-dev` (refer to your distribution's manual on how to install packages if you are not on Debian or Ubuntu-based systems)
|
||||
* [Ubuntu/Debian/Mint instructions](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager#ubuntu-mint-elementary-os)
|
||||
* [Fedora instructions](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager#fedora)
|
||||
* [npm](http://www.npmjs.org/) v1.4.x
|
||||
* `npm` comes with node.js so no explicit installation is needed here.
|
||||
* You can check `npm` 1.4 or above is installed by running `npm -v`.
|
||||
* libgnome-keyring-dev
|
||||
* on Ubuntu/Debian: `sudo apt-get install libgnome-keyring-dev`
|
||||
* on Fedora: `sudo yum --assumeyes install libgnome-keyring-devel`
|
||||
* on other distributions refer to the manual on how to install packages
|
||||
* `npm config set python /usr/bin/python2 -g` to ensure that gyp uses Python 2
|
||||
* This command may require `sudo` depending on how you have
|
||||
[configured npm](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager#ubuntu-mint-elementary-os).
|
||||
* Git
|
||||
* on Ubuntu/Debian: `sudo apt-get install git`
|
||||
* on Fedora: `sudo yum install git-core`
|
||||
|
||||
## Instructions
|
||||
|
||||
```sh
|
||||
git clone https://github.com/atom/atom
|
||||
cd atom
|
||||
script/build # Creates application at /tmp/atom-build/Atom
|
||||
script/build # Creates application at $TMPDIR/atom-build/Atom
|
||||
sudo script/grunt install # Installs command to /usr/local/bin/atom
|
||||
script/grunt mkdeb # Generates a .deb package at /tmp/atom-build
|
||||
script/grunt mkdeb # Generates a .deb package at $TMPDIR/atom-build
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
|
||||
### Exception: "TypeError: Unable to watch path"
|
||||
|
||||
If you get following error with a big traceback right after Atom starts:
|
||||
|
||||
```
|
||||
TypeError: Unable to watch path
|
||||
```
|
||||
|
||||
you have to increase number of watched files by inotify. For testing if
|
||||
this is the reason for this error you can issue
|
||||
|
||||
```sh
|
||||
sudo sysctl fs.inotify.max_user_watches=32768
|
||||
```
|
||||
|
||||
and restart Atom. If Atom now works fine, you can make this setting permanent:
|
||||
|
||||
```sh
|
||||
echo 32768 > /proc/sys/fs/inotify/max_user_watches
|
||||
```
|
||||
|
||||
See also https://github.com/atom/atom/issues/2082.
|
||||
|
||||
### Linux build error reports in atom/atom
|
||||
* Use [this search](https://github.com/atom/atom/search?q=label%3Abuild-error+label%3Alinux&type=Issues)
|
||||
to get a list of reports about build errors on Linux.
|
||||
|
||||
@@ -9,9 +9,12 @@
|
||||
## Instructions
|
||||
|
||||
```sh
|
||||
git clone https://github.com/atom/atom
|
||||
git clone https://github.com/atom/atom.git
|
||||
cd atom
|
||||
script/build # Creates application at /Applications/Atom.app
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### OSX build error reports in atom/atom
|
||||
* Use [this search](https://github.com/atom/atom/search?q=label%3Abuild-error+label%3Aos-x&type=Issues) to get a list of reports about build errors on OSX.
|
||||
|
||||
@@ -2,41 +2,65 @@
|
||||
|
||||
## Requirements
|
||||
|
||||
* Windows 7 or later
|
||||
* [Visual C++ 2010 SP1 Express](http://www.visualstudio.com/en-us/downloads/download-visual-studio-vs#DownloadFamilies_4)
|
||||
* [node.js - 32bit](http://nodejs.org/download/) v0.10.x
|
||||
* [Python 2.7.x](http://www.python.org/download/)
|
||||
### On Windows 7
|
||||
* [Visual C++ 2010 Express](http://www.visualstudio.com/en-us/downloads/download-visual-studio-vs#DownloadFamilies_4)
|
||||
* [Visual Studio 2010 Service Pack 1](http://www.microsoft.com/en-us/download/details.aspx?id=23691)
|
||||
* [node.js](http://nodejs.org/download/) v0.10.x
|
||||
* For 64-bit builds of node and native modules you **must** have the
|
||||
[Windows 7 64-bit SDK](http://www.microsoft.com/en-us/download/details.aspx?id=8279).
|
||||
You may also need the [compiler update for the Windows SDK 7.1](http://www.microsoft.com/en-us/download/details.aspx?id=4422)
|
||||
* [Python](http://www.python.org/download/) v2.7.
|
||||
* The python.exe must be available at `%SystemDrive%\Python27\python.exe`.
|
||||
If it is installed elsewhere, you can create a symbolic link to the
|
||||
directory containing the python.exe using:
|
||||
`mklink /d %SystemDrive%\Python27 D:\elsewhere\Python27`
|
||||
* [GitHub for Windows](http://windows.github.com/)
|
||||
|
||||
### On Windows 8
|
||||
* [Visual Studio Express 2013 for Windows Desktop](http://www.visualstudio.com/en-us/downloads/download-visual-studio-vs#DownloadFamilies_2)
|
||||
* [node.js](http://nodejs.org/download/) v0.10.x
|
||||
* [Python](http://www.python.org/download/) v2.7.x (required by [node-gyp](https://github.com/TooTallNate/node-gyp))
|
||||
* [GitHub for Windows](http://windows.github.com/)
|
||||
to your PATH
|
||||
* Open the Windows GitHub shell (NOT the Standard PowerShell, the shortcut labeled 'Git Shell' - make sure you have logged in at least once to the GitHub for Windows GUI App)
|
||||
* `$env:Path = $env:Path + ";C:\path\to\atom\repo\node_modules"`
|
||||
|
||||
## Instructions
|
||||
|
||||
```bat
|
||||
# Use the `Git Shell` app which was installed by GitHub for Windows. Also Make
|
||||
# sure you have logged into the GitHub for Windows GUI App.
|
||||
cd C:\
|
||||
git clone https://github.com/atom/atom
|
||||
git clone https://github.com/atom/atom/
|
||||
cd atom
|
||||
script\build
|
||||
script/build # Creates application in the `Program Files` directory
|
||||
```
|
||||
|
||||
## Why do I have to use GitHub for Windows? Can't I just use my existing Git?
|
||||
## Why do I have to use GitHub for Windows?
|
||||
|
||||
You totally can! GitHub for Windows's Git Shell just takes less work to set up. You need to have Posix tools in your `%PATH%` (i.e. `grep`, `sed`, et al.), which isn't the default configuration when you install Git. To fix this, you probably need to fiddle with your system PATH.
|
||||
You don't, You can use your existing Git! GitHub for Windows's Git Shell is just
|
||||
easier to set up. You need to have Posix tools in your `%PATH%` (i.e. `grep`,
|
||||
`sed`, et al.), which isn't the default configuration when you install Git. To
|
||||
fix this, you probably need to fiddle with your system PATH.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
Some of the most common errors include:
|
||||
### Common Errors
|
||||
* `node is not recognized`
|
||||
|
||||
gyp WARN install got an error, rolling back install
|
||||
and
|
||||
* If you just installed node you need to restart your computer before node is
|
||||
available on your Path.
|
||||
|
||||
>> The system cannot find the path specified.
|
||||
|
||||
These two error messages can usually be ignored. The solution to these errors is to re-run `script\build`, possibly several times.
|
||||
* `script/build` outputs only the Node and Python versions before returning
|
||||
|
||||
If your Visual Studio is in a non-standard location, and you get the error `You must have Visual Studio 2010 or 2012 installed`, you need to modify `apm\node_modules\atom-package-manager\lib\config.js` around line 90 and replace the variable with your Visual Studio directory plus Common7/IDE.
|
||||
* Try moving the repository to `C:\atom`. Most likely, the path is too long.
|
||||
See [issue #2200](https://github.com/atom/atom/issues/2200).
|
||||
|
||||
Example:
|
||||
* `error MSB4025: The project file could not be loaded. Invalid character in the given encoding.`
|
||||
|
||||
vs2010Path = "H:/VS2010/Common7/IDE"
|
||||
* These can occur because your home directory (`%USERPROFILE%`) has non-ASCII
|
||||
characters in it. This is a bug in [gyp](https://code.google.com/p/gyp/)
|
||||
which is used to build native node modules and there is no known workaround.
|
||||
* https://github.com/TooTallNate/node-gyp/issues/297
|
||||
* https://code.google.com/p/gyp/issues/detail?id=393
|
||||
|
||||
### Windows build error reports in atom/atom
|
||||
* Use [this search](https://github.com/atom/atom/search?q=label%3Abuild-error+label%3Awindows&type=Issues) to get a list of reports about build errors on Windows.
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# Contributing to Official Atom Packages
|
||||
|
||||
If you think you know which package is causing the issue you are reporting, feel
|
||||
free to open up the issue in that specific repository instead. When in doubt
|
||||
just open the issue here but be aware that it may get closed here and reopened
|
||||
in the proper package's repository.
|
||||
|
||||
## 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.
|
||||
@@ -1,142 +0,0 @@
|
||||
# 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) ->
|
||||
```
|
||||
Link simbólico
+1
@@ -0,0 +1 @@
|
||||
../CONTRIBUTING.md
|
||||
@@ -225,6 +225,20 @@ elements until reaching the top of the DOM tree.
|
||||
In the example above, the `Add file` item will only appear when the focused item
|
||||
or one of its parents has the `tree-view` class applied to it.
|
||||
|
||||
You can also add separators and submenus to your context menus. To add a
|
||||
submenu, pass in another object instead of a command. To add a separator, use
|
||||
`-` for the name and command of the item.
|
||||
|
||||
```coffeescript
|
||||
'context-menu':
|
||||
'.workspace':
|
||||
'Inspect Element': 'core:inspect'
|
||||
'-': '-'
|
||||
'Text':
|
||||
'Select All': 'core:select-all'
|
||||
'Deleted Selected Text': 'core:delete'
|
||||
```
|
||||
|
||||
## Snippets
|
||||
|
||||
An extension can supply language snippets in the _snippets_ directory which
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
# Debugging
|
||||
|
||||
Atom provides several tools to help you understand unexpected behavior and debug problems. This guide describes some of those tools and a few approaches to help you debug and provide more helpful information when [submitting issues]:
|
||||
|
||||
* [Update to the latest version](#update-to-the-latest-version)
|
||||
* [Check Atom and package settings](#check-atom-and-package-settings)
|
||||
* [Check the keybindings](#check-the-keybindings)
|
||||
* [Check if the problem shows up in safe mode](#check-if-the-problem-shows-up-in-safe-mode)
|
||||
* [Check your config files](#check-your-config-files)
|
||||
* [Check for errors in the developer tools](#check-for-errors-in-the-developer-tools)
|
||||
|
||||
## Update to the latest version
|
||||
|
||||
You might be running into an issue which was already fixed in a more recent version of Atom than the one you're using.
|
||||
|
||||
If you're building Atom from source, pull down the latest version of master and [re-build][building atom].
|
||||
|
||||
If you're using released version, check which version of Atom you're using:
|
||||
|
||||
```shell
|
||||
$ atom --version
|
||||
0.99.0
|
||||
```
|
||||
|
||||
Head on over to the [list of releases][atom releases] and see if there's a more recent release. You can update to the most recent release by downloading Atom from the releases page, or with the in-app auto-updater. The in-app auto-updater checks for and downloads a new version after you restart Atom, or if you use the Atom > Check for Update menu option.
|
||||
|
||||
## Check Atom and package settings
|
||||
|
||||
In some cases, unexpected behavior might be caused by misconfigured or unconfigured settings in Atom or in one of the packages.
|
||||
|
||||
Open Atom's Settings View with `cmd-,` or the Atom > Preferences menu option.
|
||||
|
||||
![Settings View]
|
||||
|
||||
Check Atom's settings in the Settings pane, there's a description of each configuration option [here][customizing guide]. For example, if you want Atom to use hard tabs (real tabs) and not soft tabs (spaces), disable the "Soft Tabs" option.
|
||||
|
||||
Since Atom ships with a set of packages and you can install additional packages yourself, check the list of packages and their settings. For example, if you'd like to get rid of the vertical line in the middle of the editor, disable the [Wrap Guide package]. And if you don't like it when Atom strips trailing whitespace or ensures that there's a single trailing newline in the file, you can configure that in the [Whitespace packages'][whitespace package] settings.
|
||||
|
||||
![Package Settings]
|
||||
|
||||
## Check the keybindings
|
||||
|
||||
If a command is not executing when you hit a keystroke or the wrong command is executing, there might be an issue with the keybindings for that keystroke. Atom ships with the [Keybinding resolver][keybinding resolver package], a neat package which helps you understand which keybindings are executed.
|
||||
|
||||
Show the keybinding resolver with <code>cmd-.</code> or with "Key Binding Resolver: Show" from the Command palette. With the keybinding resolver shown, hit a keystroke:
|
||||
|
||||
![Keybinding Resolver]
|
||||
|
||||
The keybinding resolver shows you a list of keybindings that exist for the keystroke, where each item in the list has the following:
|
||||
* the command for the keybinding,
|
||||
* the CSS selector used to define the context in which the keybinding is valid, and
|
||||
* the file in which the keybinding is defined.
|
||||
|
||||
Of all the keybinding that are listed (grey color), at most one keybinding is matched and executed (green color). If the command you wanted to trigger isn't listed, then a keybinding for that command hasn't been defined. More keybindings are provided by [packages] and you can [define your own keybindings][customizing keybindings].
|
||||
|
||||
If multiple keybindings are matched, Atom determines which keybinding will be executed based on the [specificity of the selectors and the order in which they were loaded][specificity and order]. If the command you wanted to trigger is listed in the Keybinding resolver, but wasn't the one that was executed, this is normally explained by one of two causes:
|
||||
* the keystroke was not used in the context defined by the keybinding's selector. For example, you can't trigger the "Tree View: Add File" command if the Tree View is not focused, or
|
||||
* there is another keybinding that took precedence. This often happens when you install a package which defines keybinding that conflict with existing keybindings. If the package's keybindings have selectors with higher specificity or were loaded later, they'll have priority over existing ones.
|
||||
|
||||
Atom loads core Atom keybindings and package keybindings first, and user-defined keybindings after last. Since user-defined keybindings are loaded last, you can use your `keymap.cson` file to tweak the keybindings and sort out problems like these. For example, you can remove keybindings with [the `unset!` directive][unset directive].
|
||||
|
||||
If you notice that a package's keybindings are taking precedence over core Atom keybindings, it might be a good idea to report the issue on the package's GitHub repository.
|
||||
|
||||
## Check if the problem shows up in safe mode
|
||||
|
||||
A large part of Atom's functionality comes from packages you can install. In some cases, these packages might be causing unexpected behavior, problems, or performance issues.
|
||||
|
||||
To determine if a package you installed is causing problems, start Atom from the terminal in safe mode:
|
||||
|
||||
```
|
||||
$ atom --safe
|
||||
```
|
||||
|
||||
This starts Atom, but does not load packages from `~/.atom/packages` or `~/.atom/dev/packages`. If you can no longer reproduce the problem in safe mode, it's likely it was caused by one of the packages.
|
||||
|
||||
To figure out which package is causing trouble, start Atom normally again and open Settings (`cmd-,`). Since Settings allow you to disable each installed package, you can disable packages one by one until you can no longer reproduce the issue. Restart (`cmd-q`) or reload (`cmd-ctrl-alt-l`) Atom after you disable each package to make sure it's completely gone.
|
||||
|
||||
When you find the problematic package, you can disable or uninstall the package, and consider creating an issue on the package's GitHub repository.
|
||||
|
||||
## Check your config files
|
||||
|
||||
You might have defined some custom functionality or styles in Atom's [Init script or Stylesheet]. In some situations, these personal hacks might be causing problems so try clearing those files and restarting Atom.
|
||||
|
||||
## Check for errors in the developer tools
|
||||
|
||||
When an error is thrown in Atom, the developer tools are automatically shown with the error logged in the Console tab. However, if the dev tools are open before the error is triggered, a full stack trace for the error will be logged:
|
||||
|
||||
![devtools error]
|
||||
|
||||
If you can reproduce the error, use this approach to get the full stack trace. The stack trace might point to a problem in your [Init script][init script or stylesheet] or a specific package you installed, which you can then disable and report an issue on its GitHub repository.
|
||||
|
||||
[submitting issues]: https://github.com/atom/atom/blob/master/CONTRIBUTING.md#submitting-issues
|
||||
[building atom]: https://github.com/atom/atom#building
|
||||
[atom releases]: https://github.com/atom/atom/releases
|
||||
[customizing guide]: https://atom.io/docs/latest/customizing-atom#configuration-key-reference
|
||||
[settings view]: https://f.cloud.github.com/assets/671378/2241795/ba4827d8-9ce4-11e3-93a8-6666ee100917.png
|
||||
[package settings]: https://cloud.githubusercontent.com/assets/38924/3173588/7e5f6b0c-ebe8-11e3-9ec3-e8d140967e79.png
|
||||
[wrap guide package]: https://atom.io/packages/wrap-guide
|
||||
[whitespace package]: https://atom.io/packages/whitespace
|
||||
[keybinding resolver package]: https://atom.io/packages/keybinding-resolver
|
||||
[keybinding resolver]: https://f.cloud.github.com/assets/671378/2241702/5dd5a102-9cde-11e3-9e3f-1d999930492f.png
|
||||
[customizing keybindings]: https://atom.io/docs/latest/customizing-atom#customizing-key-bindings
|
||||
[packages]: https://atom.io/packages
|
||||
[specificity and order]: https://atom.io/docs/latest/advanced/keymaps#specificity-and-cascade-order
|
||||
[unset directive]: https://atom.io/docs/latest/advanced/keymaps#removing-bindings
|
||||
[init script or stylesheet]: https://atom.io/docs/latest/customizing-atom#quick-personal-hacks
|
||||
[devtools error]: https://cloud.githubusercontent.com/assets/38924/3177710/11b4e510-ec13-11e3-96db-a2e8a7891773.png
|
||||
@@ -5,9 +5,11 @@
|
||||
* [Creating a Package](creating-a-package.md)
|
||||
* [Creating a Theme](creating-a-theme.md)
|
||||
* [Publishing a Package](publishing-a-package.md)
|
||||
* [Writing Specs](writing-specs.md)
|
||||
* [Converting a TextMate Bundle](converting-a-text-mate-bundle.md)
|
||||
* [Converting a TextMate Theme](converting-a-text-mate-theme.md)
|
||||
* [Contributing](contributing.md)
|
||||
* [Debugging](debugging.md)
|
||||
|
||||
### Advanced Topics
|
||||
|
||||
|
||||
@@ -75,18 +75,34 @@ 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.
|
||||
|
||||
With `apm publish`, you can bump the version and publish by using
|
||||
```sh
|
||||
apm publish <version-type>
|
||||
```
|
||||
where `<version-type>` can be `major`, `minor` and `patch`.
|
||||
|
||||
The `major` option to the publish command tells apm to increment the first
|
||||
digit of the version before publishing so the published version will be `1.0.0`
|
||||
and the Git tag created will be `v1.0.0`.
|
||||
|
||||
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 idea to start
|
||||
with a minor release.
|
||||
The `patch` option to the publish command tells apm to increment the third
|
||||
digit of the version before publishing so the published version will be `0.0.1`
|
||||
and the Git tag created will be `v0.0.1`.
|
||||
|
||||
Use `major` when you make a huge change, like a rewrite, or a large change to the functionality or interface.
|
||||
Use `minor` when adding or removing a feature.
|
||||
Use `patch` when you make a small change like a bug fix that does not add or remove features.
|
||||
|
||||
### Further Reading
|
||||
|
||||
* Check out [semantic versioning][semver] to learn more about versioning your
|
||||
package releases.
|
||||
* Consult the [Atom.io package API docs][apm-rest-api] to learn more about how
|
||||
`apm` works.
|
||||
|
||||
[atomio]: https://atom.io
|
||||
[github]: https://github.com
|
||||
@@ -95,3 +111,4 @@ with a minor release.
|
||||
[repo-guide]: http://guides.github.com/overviews/desktop
|
||||
[semver]: http://semver.org
|
||||
[your-first-package]: your-first-package.html
|
||||
[apm-rest-api]: apm-rest-api.md
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
# Writing specs
|
||||
|
||||
Atom uses [Jasmine](http://jasmine.github.io/2.0/introduction.html) as its spec framework. Any new functionality should have specs to guard against regressions.
|
||||
|
||||
## Create a new spec
|
||||
|
||||
[Atom specs](https://github.com/atom/atom/tree/master/spec) and [package specs](https://github.com/atom/markdown-preview/tree/master/spec) are added to their respective `spec` directory. The example below creates a spec for Atom core.
|
||||
|
||||
0. Create a spec file
|
||||
|
||||
Spec files **must** end with `-spec` so add `sample-spec.coffee` to `atom/spec`.
|
||||
|
||||
0. Add one or more `describe` methods
|
||||
|
||||
The `describe` method takes two arguments, a description and a function. If the description explains a behavior it typically begins with `when` if it is more like a unit test it begins with the method name.
|
||||
|
||||
```coffee
|
||||
describe "when a test is written", ->
|
||||
# contents
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```coffee
|
||||
describe "Editor::moveUp", ->
|
||||
# contents
|
||||
```
|
||||
|
||||
0. Add one or more `it` method
|
||||
|
||||
The `it` method also takes two arguments, a description and a function. Try and make the description flow with the `it` method. For example, a description of `this should work` doesn't read well as `it this should work`. But a description of `should work` sounds great as `it should work`.
|
||||
|
||||
```coffee
|
||||
describe "when a test is written", ->
|
||||
it "has some expectations that should pass", ->
|
||||
# Expectations
|
||||
```
|
||||
|
||||
0. Add one or more expectations
|
||||
|
||||
The best way to learn about expectations is to read the [jasmine documentation](http://jasmine.github.io/2.0/introduction.html#section-Expectations) about them. Below is a simple example.
|
||||
|
||||
```coffee
|
||||
describe "when a test is written", ->
|
||||
it "has some expectations that should pass", ->
|
||||
expect("apples").toEqual("apples")
|
||||
expect("oranges").not.toEqual("apples")
|
||||
```
|
||||
|
||||
## Running specs
|
||||
|
||||
Most of the time you'll want to run specs by triggering the `window:run-package-specs` command. This command is not only to run package specs, it is also for Atom core specs. This will run all the specs in the current project's spec directory. If you want to run the Atom core specs and **all** the default package specs trigger the `window:run-all-specs` command.
|
||||
|
||||
To run a limited subset of specs use the `fdescribe` or `fit` methods. You can use those to focus a single spec or several specs. In the example above, focusing an individual spec looks like this:
|
||||
|
||||
```coffee
|
||||
describe "when a test is written", ->
|
||||
fit "has some expectations that should pass", ->
|
||||
expect("apples").toEqual("apples")
|
||||
expect("oranges").not.toEqual("apples")
|
||||
```
|
||||
@@ -149,6 +149,8 @@ ASCII art professional!
|
||||
|
||||
* [Getting your project on GitHub guide](http://guides.github.com/overviews/desktop)
|
||||
|
||||
* [Writing specs](writing-specs.md) for your package
|
||||
|
||||
* [Creating a package guide](creating-a-package.html) for more information
|
||||
on the mechanics of packages
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
# Sublime Parity
|
||||
'tab': 'editor:indent'
|
||||
'enter': 'editor:newline'
|
||||
'num-enter': 'editor:newline'
|
||||
'shift-tab': 'editor:outdent-selected-rows'
|
||||
'ctrl-K': 'editor:delete-line'
|
||||
|
||||
@@ -26,6 +27,7 @@
|
||||
'tab': 'core:focus-next'
|
||||
'shift-tab': 'core:focus-previous'
|
||||
'enter': 'native!'
|
||||
'num-enter': 'native!'
|
||||
'backspace': 'native!'
|
||||
'shift-backspace': 'native!'
|
||||
'delete': 'native!'
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
'cmd-O': 'application:open-dev'
|
||||
'cmd-alt-ctrl-s': 'application:run-all-specs'
|
||||
'enter': 'core:confirm'
|
||||
'num-enter': 'core:confirm'
|
||||
'escape': 'core:cancel'
|
||||
'up': 'core:move-up'
|
||||
'down': 'core:move-down'
|
||||
@@ -52,7 +53,10 @@
|
||||
'shift-down': 'core:select-down'
|
||||
'shift-left': 'core:select-left'
|
||||
'shift-right': 'core:select-right'
|
||||
'shift-pageup': 'core:select-page-up'
|
||||
'shift-pagedown': 'core:select-page-down'
|
||||
'delete': 'core:delete'
|
||||
'shift-delete': 'core:delete'
|
||||
'pageup': 'core:page-up'
|
||||
'pagedown': 'core:page-down'
|
||||
'backspace': 'core:backspace'
|
||||
|
||||
+18
-2
@@ -1,13 +1,14 @@
|
||||
'body':
|
||||
# Atom Specific
|
||||
'enter': 'core:confirm'
|
||||
'num-enter': 'core:confirm'
|
||||
'escape': 'core:cancel'
|
||||
'up': 'core:move-up'
|
||||
'down': 'core:move-down'
|
||||
'left': 'core:move-left'
|
||||
'right': 'core:move-right'
|
||||
'ctrl-alt-r': 'window:reload'
|
||||
'ctrl-alt-i': 'window:toggle-dev-tools'
|
||||
'ctrl-shift-i': 'window:toggle-dev-tools'
|
||||
'ctrl-alt-p': 'window:run-package-specs'
|
||||
'ctrl-alt-s': 'application:run-all-specs'
|
||||
'ctrl-shift-o': 'application:open-dev'
|
||||
@@ -28,14 +29,20 @@
|
||||
'ctrl-x': 'core:cut'
|
||||
'ctrl-c': 'core:copy'
|
||||
'ctrl-v': 'core:paste'
|
||||
'ctrl-insert': 'core:copy'
|
||||
'shift-insert': 'core:paste'
|
||||
'shift-up': 'core:select-up'
|
||||
'shift-down': 'core:select-down'
|
||||
'shift-left': 'core:select-left'
|
||||
'shift-right': 'core:select-right'
|
||||
'shift-pageup': 'core:select-page-up'
|
||||
'shift-pagedown': 'core:select-page-down'
|
||||
'delete': 'core:delete'
|
||||
'shift-delete': 'core:delete'
|
||||
'pageup': 'core:page-up'
|
||||
'pagedown': 'core:page-down'
|
||||
'backspace': 'core:backspace'
|
||||
'shift-backspace': 'core:backspace'
|
||||
'ctrl-tab': 'pane:show-next-item'
|
||||
'ctrl-shift-tab': 'pane:show-previous-item'
|
||||
'ctrl-shift-up': 'core:move-up'
|
||||
@@ -58,6 +65,15 @@
|
||||
'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'
|
||||
'alt-1': 'pane:show-item-1'
|
||||
'alt-2': 'pane:show-item-2'
|
||||
'alt-3': 'pane:show-item-3'
|
||||
'alt-4': 'pane:show-item-4'
|
||||
'alt-5': 'pane:show-item-5'
|
||||
'alt-6': 'pane:show-item-6'
|
||||
'alt-7': 'pane:show-item-7'
|
||||
'alt-8': 'pane:show-item-8'
|
||||
'alt-9': 'pane:show-item-9'
|
||||
|
||||
'.workspace .editor':
|
||||
# Platform Bindings
|
||||
@@ -74,7 +90,7 @@
|
||||
|
||||
# Sublime Parity
|
||||
'ctrl-a': 'core:select-all'
|
||||
'ctrl-alt-p': 'editor:log-cursor-scope'
|
||||
'ctrl-alt-shift-p': 'editor:log-cursor-scope'
|
||||
'ctrl-k ctrl-u': 'editor:upper-case'
|
||||
'ctrl-k ctrl-l': 'editor:lower-case'
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
# Atom Specific
|
||||
'enter': 'core:confirm'
|
||||
'num-enter': 'core:confirm'
|
||||
'escape': 'core:cancel'
|
||||
'up': 'core:move-up'
|
||||
'down': 'core:move-down'
|
||||
@@ -30,11 +31,16 @@
|
||||
'ctrl-x': 'core:cut'
|
||||
'ctrl-c': 'core:copy'
|
||||
'ctrl-v': 'core:paste'
|
||||
'ctrl-insert': 'core:copy'
|
||||
'shift-insert': 'core:paste'
|
||||
'shift-up': 'core:select-up'
|
||||
'shift-down': 'core:select-down'
|
||||
'shift-left': 'core:select-left'
|
||||
'shift-right': 'core:select-right'
|
||||
'shift-pageup': 'core:select-page-up'
|
||||
'shift-pagedown': 'core:select-page-down'
|
||||
'delete': 'core:delete'
|
||||
'shift-delete': 'core:delete'
|
||||
'pageup': 'core:page-up'
|
||||
'pagedown': 'core:page-down'
|
||||
'backspace': 'core:backspace'
|
||||
@@ -43,6 +49,8 @@
|
||||
'ctrl-shift-tab': 'pane:show-previous-item'
|
||||
'ctrl-shift-up': 'core:move-up'
|
||||
'ctrl-shift-down': 'core:move-down'
|
||||
'ctrl-alt-up': 'editor:add-selection-above'
|
||||
'ctrl-alt-down': 'editor:add-selection-below'
|
||||
'ctrl-=': 'window:increase-font-size'
|
||||
'ctrl-+': 'window:increase-font-size'
|
||||
'ctrl--': 'window:decrease-font-size'
|
||||
@@ -75,7 +83,7 @@
|
||||
|
||||
# Sublime Parity
|
||||
'ctrl-a': 'core:select-all'
|
||||
'ctrl-alt-p': 'editor:log-cursor-scope'
|
||||
'ctrl-alt-shift-p': 'editor:log-cursor-scope'
|
||||
'ctrl-k ctrl-u': 'editor:upper-case'
|
||||
'ctrl-k ctrl-l': 'editor:lower-case'
|
||||
|
||||
|
||||
@@ -109,6 +109,7 @@
|
||||
submenu: [
|
||||
{ label: 'Add Selection Above', command: 'editor:add-selection-above' }
|
||||
{ label: 'Add Selection Below', command: 'editor:add-selection-below' }
|
||||
{ label: 'Single Selection', command: 'editor:consolidate-selections'}
|
||||
{ label: 'Split into Lines', command: 'editor:split-selections-into-lines'}
|
||||
{ type: 'separator' }
|
||||
{ label: 'Select to Top', command: 'core:select-to-top' }
|
||||
|
||||
@@ -108,6 +108,7 @@
|
||||
{ label: 'Add Selection &Above', command: 'editor:add-selection-above' }
|
||||
{ label: 'Add Selection &Below', command: 'editor:add-selection-below' }
|
||||
{ label: 'S&plit into Lines', command: 'editor:split-selections-into-lines'}
|
||||
{ label: 'Single Selection', command: 'editor:consolidate-selections'}
|
||||
{ type: 'separator' }
|
||||
{ label: 'Select to &Top', command: 'core:select-to-top' }
|
||||
{ label: 'Select to Botto&m', command: 'core:select-to-bottom' }
|
||||
|
||||
+2
-3
@@ -8,7 +8,7 @@
|
||||
{ label: 'Open Folder...', command: 'application:open-folder' }
|
||||
{ label: 'Reopen Last &Item', command: 'pane:reopen-closed-item' }
|
||||
{ type: 'separator' }
|
||||
{ label: '&Preferences...', command: 'application:show-settings' }
|
||||
{ label: 'Se&ttings', command: 'application:show-settings' }
|
||||
{ type: 'separator' }
|
||||
{ label: '&Save', command: 'core:save' }
|
||||
{ label: 'Save &As...', command: 'core:save-as' }
|
||||
@@ -127,6 +127,7 @@
|
||||
{ label: 'Add Selection &Above', command: 'editor:add-selection-above' }
|
||||
{ label: 'Add Selection &Below', command: 'editor:add-selection-below' }
|
||||
{ label: 'S&plit into Lines', command: 'editor:split-selections-into-lines'}
|
||||
{ label: 'Single Selection', command: 'editor:consolidate-selections'}
|
||||
{ type: 'separator' }
|
||||
{ label: 'Select to &Top', command: 'core:select-to-top' }
|
||||
{ label: 'Select to Botto&m', command: 'core:select-to-bottom' }
|
||||
@@ -164,11 +165,9 @@
|
||||
{
|
||||
label: '&Help'
|
||||
submenu: [
|
||||
{ label: '&About Atom...', command: 'application:about' }
|
||||
{ label: 'View &Terms of Use', command: 'application:open-terms-of-use' }
|
||||
{ label: 'View &License', command: 'application:open-license' }
|
||||
{ label: "VERSION", enabled: false }
|
||||
{ label: "Install &update", command: 'application:install-update', visible: false }
|
||||
{ type: 'separator' }
|
||||
{ label: '&Documentation', command: 'application:open-documentation' }
|
||||
{ type: 'separator' }
|
||||
|
||||
+63
-63
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "atom",
|
||||
"productName": "Atom",
|
||||
"version": "0.96.0",
|
||||
"version": "0.107.0",
|
||||
"description": "A hackable text editor for the 21st Century.",
|
||||
"main": "./src/browser/main.js",
|
||||
"repository": {
|
||||
@@ -17,125 +17,125 @@
|
||||
"url": "http://github.com/atom/atom/raw/master/LICENSE.md"
|
||||
}
|
||||
],
|
||||
"atomShellVersion": "0.12.5",
|
||||
"atomShellVersion": "0.13.2",
|
||||
"dependencies": {
|
||||
"async": "0.2.6",
|
||||
"atom-keymap": "^0.19.0",
|
||||
"atom-keymap": "^0.27.0",
|
||||
"bootstrap": "git+https://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372",
|
||||
"clear-cut": "0.4.0",
|
||||
"coffee-script": "1.7.0",
|
||||
"coffeestack": "0.7.0",
|
||||
"delegato": "^1",
|
||||
"emissary": "^1.2.1",
|
||||
"first-mate": "^1.5.3",
|
||||
"first-mate": "^1.7",
|
||||
"fs-plus": "^2.2.3",
|
||||
"fstream": "0.1.24",
|
||||
"fuzzaldrin": "^1.1",
|
||||
"git-utils": "^1.3",
|
||||
"grim": "0.10.0",
|
||||
"grim": "0.11.0",
|
||||
"guid": "0.0.10",
|
||||
"jasmine-tagged": "^1.1.1",
|
||||
"jasmine-tagged": "^1.1.2",
|
||||
"less-cache": "0.12.0",
|
||||
"mixto": "^1",
|
||||
"mkdirp": "0.3.5",
|
||||
"nslog": "0.5.0",
|
||||
"oniguruma": "^1.0.6",
|
||||
"optimist": "0.4.0",
|
||||
"pathwatcher": "^1.3.1",
|
||||
"pathwatcher": "^1.3.2",
|
||||
"property-accessors": "^1",
|
||||
"q": "^1.0.1",
|
||||
"random-words": "0.0.1",
|
||||
"react": "^0.10.0",
|
||||
"reactionary": "^0.9.0",
|
||||
"react-atom-fork": "^0.10.0",
|
||||
"reactionary-atom-fork": "^0.9.0",
|
||||
"runas": "^0.5",
|
||||
"scandal": "0.15.2",
|
||||
"scandal": "0.15.3",
|
||||
"scoped-property-store": "^0.9.0",
|
||||
"scrollbar-style": "^0.4.0",
|
||||
"season": "^1.0.2",
|
||||
"semver": "1.1.4",
|
||||
"serializable": "^1",
|
||||
"space-pen": "3.1.1",
|
||||
"temp": "0.5.0",
|
||||
"text-buffer": "^2.2.2",
|
||||
"space-pen": "3.2.0",
|
||||
"temp": "0.7.0",
|
||||
"text-buffer": "^2.4.2",
|
||||
"theorist": "^1",
|
||||
"underscore-plus": "^1.2.1",
|
||||
"underscore-plus": "^1.5.0",
|
||||
"vm-compatibility-layer": "0.1.0"
|
||||
},
|
||||
"packageDependencies": {
|
||||
"atom-dark-syntax": "0.15.0",
|
||||
"atom-dark-ui": "0.26.0",
|
||||
"atom-light-syntax": "0.17.0",
|
||||
"atom-light-ui": "0.24.0",
|
||||
"base16-tomorrow-dark-theme": "0.15.0",
|
||||
"solarized-dark-syntax": "0.14.0",
|
||||
"solarized-light-syntax": "0.7.0",
|
||||
"archive-view": "0.31.0",
|
||||
"atom-dark-syntax": "0.17.0",
|
||||
"atom-dark-ui": "0.29.0",
|
||||
"atom-light-syntax": "0.18.0",
|
||||
"atom-light-ui": "0.25.0",
|
||||
"base16-tomorrow-dark-theme": "0.17.0",
|
||||
"solarized-dark-syntax": "0.18.0",
|
||||
"solarized-light-syntax": "0.9.0",
|
||||
"archive-view": "0.33.0",
|
||||
"autocomplete": "0.28.0",
|
||||
"autoflow": "0.17.0",
|
||||
"autosave": "0.13.0",
|
||||
"background-tips": "0.13.0",
|
||||
"bookmarks": "0.22.0",
|
||||
"bracket-matcher": "0.34.0",
|
||||
"command-palette": "0.21.0",
|
||||
"deprecation-cop": "0.5.0",
|
||||
"dev-live-reload": "0.30.0",
|
||||
"exception-reporting": "0.17.0",
|
||||
"autosave": "0.14.0",
|
||||
"background-tips": "0.14.0",
|
||||
"bookmarks": "0.25.0",
|
||||
"bracket-matcher": "0.47.0",
|
||||
"command-palette": "0.23.0",
|
||||
"deprecation-cop": "0.7.0",
|
||||
"dev-live-reload": "0.31.0",
|
||||
"exception-reporting": "0.18.0",
|
||||
"feedback": "0.33.0",
|
||||
"find-and-replace": "0.105.0",
|
||||
"fuzzy-finder": "0.51.0",
|
||||
"git-diff": "0.28.0",
|
||||
"go-to-line": "0.20.0",
|
||||
"grammar-selector": "0.26.0",
|
||||
"image-view": "0.33.0",
|
||||
"keybinding-resolver": "0.17.0",
|
||||
"link": "0.22.0",
|
||||
"markdown-preview": "0.71.0",
|
||||
"find-and-replace": "0.120.0",
|
||||
"fuzzy-finder": "0.55.0",
|
||||
"git-diff": "0.34.0",
|
||||
"go-to-line": "0.23.0",
|
||||
"grammar-selector": "0.27.0",
|
||||
"image-view": "0.35.0",
|
||||
"keybinding-resolver": "0.18.0",
|
||||
"link": "0.24.0",
|
||||
"markdown-preview": "0.83.0",
|
||||
"metrics": "0.32.0",
|
||||
"open-on-github": "0.28.0",
|
||||
"package-generator": "0.30.0",
|
||||
"release-notes": "0.31.0",
|
||||
"settings-view": "0.115.0",
|
||||
"snippets": "0.43.0",
|
||||
"spell-check": "0.35.0",
|
||||
"status-bar": "0.40.0",
|
||||
"package-generator": "0.31.0",
|
||||
"release-notes": "0.32.0",
|
||||
"settings-view": "0.128.0",
|
||||
"snippets": "0.46.0",
|
||||
"spell-check": "0.38.0",
|
||||
"status-bar": "0.41.0",
|
||||
"styleguide": "0.29.0",
|
||||
"symbols-view": "0.52.0",
|
||||
"tabs": "0.40.0",
|
||||
"timecop": "0.18.0",
|
||||
"tree-view": "0.93.0",
|
||||
"symbols-view": "0.56.0",
|
||||
"tabs": "0.42.0",
|
||||
"timecop": "0.19.0",
|
||||
"tree-view": "0.104.0",
|
||||
"update-package-dependencies": "0.6.0",
|
||||
"welcome": "0.14.0",
|
||||
"welcome": "0.16.0",
|
||||
"whitespace": "0.22.0",
|
||||
"wrap-guide": "0.18.0",
|
||||
"language-c": "0.15.0",
|
||||
"wrap-guide": "0.19.0",
|
||||
"language-c": "0.21.0",
|
||||
"language-coffee-script": "0.22.0",
|
||||
"language-css": "0.16.0",
|
||||
"language-gfm": "0.37.0",
|
||||
"language-css": "0.17.0",
|
||||
"language-gfm": "0.40.0",
|
||||
"language-git": "0.9.0",
|
||||
"language-go": "0.12.0",
|
||||
"language-html": "0.22.0",
|
||||
"language-hyperlink": "0.9.0",
|
||||
"language-hyperlink": "0.10.0",
|
||||
"language-java": "0.10.0",
|
||||
"language-javascript": "0.26.0",
|
||||
"language-javascript": "0.28.0",
|
||||
"language-json": "0.8.0",
|
||||
"language-less": "0.9.0",
|
||||
"language-make": "0.10.0",
|
||||
"language-objective-c": "0.11.0",
|
||||
"language-perl": "0.8.0",
|
||||
"language-php": "0.14.0",
|
||||
"language-perl": "0.9.0",
|
||||
"language-php": "0.15.0",
|
||||
"language-property-list": "0.7.0",
|
||||
"language-python": "0.16.0",
|
||||
"language-ruby": "0.24.0",
|
||||
"language-python": "0.18.0",
|
||||
"language-ruby": "0.30.0",
|
||||
"language-ruby-on-rails": "0.14.0",
|
||||
"language-sass": "0.11.0",
|
||||
"language-sass": "0.13.0",
|
||||
"language-shellscript": "0.8.0",
|
||||
"language-source": "0.7.0",
|
||||
"language-sql": "0.8.0",
|
||||
"language-text": "0.6.0",
|
||||
"language-todo": "0.10.0",
|
||||
"language-toml": "0.12.0",
|
||||
"language-xml": "0.13.0",
|
||||
"language-yaml": "0.6.0"
|
||||
"language-xml": "0.15.0",
|
||||
"language-yaml": "0.7.0"
|
||||
},
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
[Desktop Entry]
|
||||
Name=Atom
|
||||
Comment=<%= description %>
|
||||
Exec=/usr/share/atom/atom %U
|
||||
Icon=atom
|
||||
Exec=<%= installDir %>/share/atom/atom %U
|
||||
Icon=<%= iconName %>
|
||||
Type=Application
|
||||
StartupNotify=true
|
||||
Categories=GNOME;GTK;Utility;TextEditor;
|
||||
|
||||
Arquivo binário não exibido.
|
Antes Largura: | Altura: | Tamanho: 361 KiB Depois Largura: | Altura: | Tamanho: 141 KiB |
Arquivo binário não exibido.
Arquivo binário não exibido.
+38
-31
@@ -1,15 +1,8 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
var nodeVersion = process.versions.node.split('.')
|
||||
var nodeMajorVersion = +nodeVersion[0]
|
||||
var nodeMinorVersion = +nodeVersion[1]
|
||||
if (nodeMajorVersion === 0 && nodeMinorVersion < 10) {
|
||||
console.warn("You must run script/bootstrap and script/build with node v0.10 or above");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var safeExec = require('./utils/child-process-wrapper.js').safeExec;
|
||||
var fs = require('fs');
|
||||
var verifyRequirements = require('./utils/verify-requirements');
|
||||
var safeExec = require('./utils/child-process-wrapper.js').safeExec;
|
||||
var path = require('path');
|
||||
|
||||
// Executes an array of commands one by one.
|
||||
@@ -17,39 +10,53 @@ function executeCommands(commands, done, index) {
|
||||
index = (index == undefined ? 0 : index);
|
||||
if (index < commands.length) {
|
||||
var command = commands[index];
|
||||
if (command.message)
|
||||
console.log(command.message);
|
||||
var options = null;
|
||||
if (typeof command !== 'string') {
|
||||
options = command.options;
|
||||
command = command.command;
|
||||
}
|
||||
safeExec(command, options, executeCommands.bind(this, commands, done, index + 1));
|
||||
} else
|
||||
}
|
||||
else
|
||||
done(null);
|
||||
}
|
||||
|
||||
var apmInstallPath = path.resolve(__dirname, '..', 'apm');
|
||||
if (!fs.existsSync(apmInstallPath))
|
||||
fs.mkdirSync(apmInstallPath);
|
||||
if (!fs.existsSync(path.join(apmInstallPath, 'node_modules')))
|
||||
fs.mkdirSync(path.join(apmInstallPath, 'node_modules'));
|
||||
function bootstrap() {
|
||||
var apmInstallPath = path.resolve(__dirname, '..', 'apm');
|
||||
if (!fs.existsSync(apmInstallPath))
|
||||
fs.mkdirSync(apmInstallPath);
|
||||
if (!fs.existsSync(path.join(apmInstallPath, 'node_modules')))
|
||||
fs.mkdirSync(path.join(apmInstallPath, 'node_modules'));
|
||||
|
||||
var apmPath = path.resolve(__dirname, '..', 'apm', 'node_modules', 'atom-package-manager', 'bin', 'apm')
|
||||
var apmFlags = process.env.JANKY_SHA1 || process.argv.indexOf('--no-color') !== -1 ? '--no-color' : '';
|
||||
var apmPath = path.resolve(__dirname, '..', 'apm', 'node_modules', 'atom-package-manager', 'bin', 'apm')
|
||||
var apmFlags = process.env.JANKY_SHA1 || process.argv.indexOf('--no-color') !== -1 ? '--no-color' : '';
|
||||
|
||||
var npmPath = path.resolve(__dirname, '..', 'build', 'node_modules', '.bin', 'npm');
|
||||
var npmFlags = ' --userconfig=' + path.resolve('.npmrc') + ' ';
|
||||
var npmPath = path.resolve(__dirname, '..', 'build', 'node_modules', '.bin', 'npm');
|
||||
var initialNpmCommand = fs.existsSync(npmPath) ? npmPath : 'npm';
|
||||
var npmFlags = ' --userconfig=' + path.resolve('.npmrc') + ' ';
|
||||
|
||||
var packagesToDedupe = ['fs-plus', 'humanize-plus', 'oniguruma', 'roaster', 'season'];
|
||||
var echoNewLine = process.platform == 'win32' ? 'echo.' : 'echo';
|
||||
var packagesToDedupe = ['fs-plus', 'humanize-plus', 'oniguruma', 'roaster', 'season', 'grim'];
|
||||
|
||||
var commands = [
|
||||
{command: 'npm' + npmFlags + 'install --quiet', options: {cwd: path.resolve(__dirname, '..', 'build'), ignoreStdout: true}},
|
||||
{command: npmPath + npmFlags + 'install --quiet', options: {cwd: apmInstallPath, ignoreStdout: true}},
|
||||
echoNewLine,
|
||||
apmPath + ' clean ' + apmFlags,
|
||||
apmPath + ' install --quiet ' + apmFlags,
|
||||
apmPath + ' dedupe --quiet ' + apmFlags + ' ' + packagesToDedupe.join(' '),
|
||||
];
|
||||
var commands = [
|
||||
{command: initialNpmCommand + npmFlags + 'install --quiet', message: 'Installing build modules...', options: {cwd: path.resolve(__dirname, '..', 'build'), ignoreStdout: true}},
|
||||
{command: npmPath + npmFlags + 'install --quiet', message: 'Installing apm...', options: {cwd: apmInstallPath, ignoreStdout: true}},
|
||||
apmPath + ' clean ' + apmFlags,
|
||||
apmPath + ' install --quiet ' + apmFlags,
|
||||
apmPath + ' dedupe --quiet ' + apmFlags + ' ' + packagesToDedupe.join(' '),
|
||||
];
|
||||
|
||||
process.chdir(path.dirname(__dirname));
|
||||
executeCommands(commands, process.exit);
|
||||
process.chdir(path.dirname(__dirname));
|
||||
executeCommands(commands, process.exit);
|
||||
}
|
||||
|
||||
verifyRequirements(function(error, successMessage) {
|
||||
if (error) {
|
||||
console.log(error);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(successMessage);
|
||||
bootstrap();
|
||||
});
|
||||
|
||||
+24
-16
@@ -19,26 +19,34 @@ function loadEnvironmentVariables(filePath) {
|
||||
var value = parts[1].trim().substr(1, parts[1].length - 2);
|
||||
process.env[key] = value;
|
||||
}
|
||||
} catch(error) { }
|
||||
} catch(error) {
|
||||
console.error("Failed to load environment variables: " + filePath, error.code);
|
||||
}
|
||||
}
|
||||
|
||||
function readEnvironmentVariables() {
|
||||
loadEnvironmentVariables('/var/lib/jenkins/config/atomcredentials')
|
||||
loadEnvironmentVariables('/var/lib/jenkins/config/xcodekeychain')
|
||||
if (process.platform === 'win32')
|
||||
loadEnvironmentVariables(path.resolve('/jenkins/config/atomcredentials'));
|
||||
else {
|
||||
loadEnvironmentVariables('/var/lib/jenkins/config/atomcredentials');
|
||||
loadEnvironmentVariables('/var/lib/jenkins/config/xcodekeychain');
|
||||
}
|
||||
}
|
||||
|
||||
readEnvironmentVariables();
|
||||
cp.safeExec.bind(global, 'node script/bootstrap', function(error) {
|
||||
if (error)
|
||||
process.exit(1);
|
||||
require('fs-plus').removeSync.bind(global, path.join(homeDir, '.atom'))
|
||||
var async = require('async');
|
||||
var gruntPath = path.join('build', 'node_modules', '.bin', 'grunt') + (process.platform === 'win32' ? '.cmd' : '');
|
||||
var tasks = [
|
||||
cp.safeExec.bind(global, 'git clean -dff'),
|
||||
cp.safeExec.bind(global, gruntPath + ' ci --gruntfile build/Gruntfile.coffee --stack --no-color'),
|
||||
]
|
||||
async.series(tasks, function(error) {
|
||||
process.exit(error ? 1 : 0);
|
||||
});
|
||||
cp.safeExec.bind(global, 'npm install npm', {cwd: path.resolve(__dirname, '..', 'build')}, function() {
|
||||
cp.safeExec.bind(global, 'node script/bootstrap', function(error) {
|
||||
if (error)
|
||||
process.exit(1);
|
||||
require('fs-plus').removeSync.bind(global, path.join(homeDir, '.atom'))
|
||||
var async = require('async');
|
||||
var gruntPath = path.join('build', 'node_modules', '.bin', 'grunt') + (process.platform === 'win32' ? '.cmd' : '');
|
||||
var tasks = [
|
||||
cp.safeExec.bind(global, 'git clean -dff'),
|
||||
cp.safeExec.bind(global, gruntPath + ' ci --gruntfile build/Gruntfile.coffee --stack --no-color'),
|
||||
]
|
||||
async.series(tasks, function(error) {
|
||||
process.exit(error ? 1 : 0);
|
||||
});
|
||||
})();
|
||||
})();
|
||||
|
||||
+12
-4
@@ -1,14 +1,15 @@
|
||||
#!/usr/bin/env node
|
||||
var cp = require('./utils/child-process-wrapper.js');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var os = require('os');
|
||||
|
||||
var removeCommand = process.platform === 'win32' ? 'del /F /Q /S ' : 'rm -rf ';
|
||||
var removeCommand = process.platform === 'win32' ? 'rmdir /S /Q ' : 'rm -rf ';
|
||||
var productName = require('../package.json').productName;
|
||||
|
||||
process.chdir(path.dirname(__dirname));
|
||||
var home = process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'];
|
||||
var tmpdir = process.platform === 'win32' ? os.tmpdir() : '/tmp';
|
||||
var tmpdir = os.tmpdir();
|
||||
|
||||
// Windows: Use START as a way to ignore error if Atom.exe isnt running
|
||||
var killatom = process.platform === 'win32' ? 'START taskkill /F /IM ' + productName + '.exe' : 'pkill -9 ' + productName + ' || true';
|
||||
@@ -30,8 +31,15 @@ var run = function() {
|
||||
var next = commands.shift();
|
||||
if (!next)
|
||||
process.exit(0);
|
||||
if (Array.isArray(next))
|
||||
next = removeCommand + path.resolve.apply(path.resolve, next);
|
||||
|
||||
if (Array.isArray(next)) {
|
||||
var pathToRemove = path.resolve.apply(path.resolve, next);
|
||||
if (fs.existsSync(pathToRemove))
|
||||
next = removeCommand + pathToRemove;
|
||||
else
|
||||
return run();
|
||||
}
|
||||
|
||||
cp.safeExec(next, run);
|
||||
};
|
||||
run();
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
#!/usr/bin/env node
|
||||
var cp = require('./utils/child-process-wrapper.js');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
// node build/node_modules/.bin/grunt "$@"
|
||||
var gruntPath = path.resolve(__dirname, '..', 'build', 'node_modules', '.bin', 'grunt') + (process.platform === 'win32' ? '.cmd' : '');
|
||||
|
||||
if (!fs.existsSync(gruntPath)) {
|
||||
console.error('Grunt command does not exist at: ' + gruntPath);
|
||||
console.error('Run script/bootstrap to install Grunt');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var args = ['--gruntfile', path.resolve('build', 'Gruntfile.coffee')];
|
||||
args = args.concat(process.argv.slice(2));
|
||||
cp.safeSpawn(gruntPath, args, process.exit);
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/usr/bin/env coffee
|
||||
|
||||
path = require 'path'
|
||||
CommandInstaller = require '../src/command-installer'
|
||||
|
||||
callback = (error) ->
|
||||
console.warn error.message if error?
|
||||
|
||||
CommandInstaller.installAtomCommand(path.resolve(__dirname, '..'), callback)
|
||||
CommandInstaller.installApmCommand(path.resolve(__dirname, '..'), callback)
|
||||
+9
-8
@@ -8,27 +8,28 @@ ROOT=`readlink -f $(dirname $SCRIPT)/..`
|
||||
cd $ROOT
|
||||
|
||||
VERSION="$1"
|
||||
CONTROL_FILE="$2"
|
||||
DESKTOP_FILE="$3"
|
||||
ICON_FILE="$4"
|
||||
DEB_PATH="$5"
|
||||
ARCH="$2"
|
||||
CONTROL_FILE="$3"
|
||||
DESKTOP_FILE="$4"
|
||||
ICON_FILE="$5"
|
||||
DEB_PATH="$6"
|
||||
|
||||
TARGET_ROOT="`mktemp -d`"
|
||||
chmod 755 "$TARGET_ROOT"
|
||||
TARGET="$TARGET_ROOT/atom-$VERSION-amd64"
|
||||
TARGET="$TARGET_ROOT/atom-$VERSION-$ARCH"
|
||||
|
||||
mkdir -p "$TARGET/usr"
|
||||
env INSTALL_PREFIX="$TARGET/usr" script/grunt install
|
||||
|
||||
mkdir -p "$TARGET/DEBIAN"
|
||||
mv "$CONTROL_FILE" "$TARGET/DEBIAN/control"
|
||||
cp "$CONTROL_FILE" "$TARGET/DEBIAN/control"
|
||||
|
||||
mkdir -p "$TARGET/usr/share/applications"
|
||||
mv "$DESKTOP_FILE" "$TARGET/usr/share/applications"
|
||||
cp "$DESKTOP_FILE" "$TARGET/usr/share/applications"
|
||||
|
||||
mkdir -p "$TARGET/usr/share/pixmaps"
|
||||
cp "$ICON_FILE" "$TARGET/usr/share/pixmaps"
|
||||
|
||||
dpkg-deb -b "$TARGET"
|
||||
mv "$TARGET_ROOT/atom-$VERSION-amd64.deb" "$DEB_PATH"
|
||||
mv "$TARGET_ROOT/atom-$VERSION-$ARCH.deb" "$DEB_PATH"
|
||||
rm -rf $TARGET_ROOT
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var childProcess = require('child_process');
|
||||
|
||||
var pythonExecutable = process.env.PYTHON;
|
||||
|
||||
module.exports = function(cb) {
|
||||
verifyNode(function(error, nodeSuccessMessage) {
|
||||
if (error) {
|
||||
cb(error);
|
||||
return;
|
||||
}
|
||||
|
||||
verifyNpm(function(error, npmSuccessMessage) {
|
||||
if (error) {
|
||||
cb(error);
|
||||
return;
|
||||
}
|
||||
|
||||
verifyPython27(function(error, pythonSuccessMessage) {
|
||||
cb(error, (nodeSuccessMessage + "\n" + npmSuccessMessage + "\n" + pythonSuccessMessage).trim());
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
function verifyNode(cb) {
|
||||
var nodeVersion = process.versions.node;
|
||||
var versionArray = nodeVersion.split('.');
|
||||
var nodeMajorVersion = +versionArray[0];
|
||||
var nodeMinorVersion = +versionArray[1];
|
||||
if (nodeMajorVersion === 0 && nodeMinorVersion < 10) {
|
||||
error = "node v0.10 is required to build Atom.";
|
||||
cb(error);
|
||||
}
|
||||
else {
|
||||
cb(null, "Node: v" + nodeVersion);
|
||||
}
|
||||
}
|
||||
|
||||
function verifyNpm(cb) {
|
||||
var localNpmPath = path.resolve(__dirname, '..', '..', 'build', 'node_modules', '.bin', 'npm');
|
||||
if (process.platform === 'win32')
|
||||
localNpmPath += ".cmd";
|
||||
|
||||
var npmCommand = fs.existsSync(localNpmPath) ? localNpmPath : 'npm';
|
||||
if (npmCommand === 'npm' && process.platform === 'win32')
|
||||
npmCommand += ".cmd";
|
||||
|
||||
childProcess.execFile(npmCommand, ['-v'], { env: process.env }, function(err, stdout) {
|
||||
if (err)
|
||||
return cb("npm 1.4 is required to build Atom. An error (" + err + ") occured when checking the version.");
|
||||
|
||||
var npmVersion = stdout ? stdout.trim() : '';
|
||||
var versionArray = npmVersion.split('.');
|
||||
var npmMajorVersion = +versionArray[0] || 0;
|
||||
var npmMinorVersion = +versionArray[1] || 0;
|
||||
if (npmMajorVersion === 1 && npmMinorVersion < 4)
|
||||
cb("npm v1.4+ is required to build Atom.");
|
||||
else
|
||||
cb(null, "npm: v" + npmVersion);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function verifyPython27(cb) {
|
||||
if (process.platform == 'win32') {
|
||||
if (!pythonExecutable) {
|
||||
var systemDrive = process.env.SystemDrive || 'C:\\';
|
||||
pythonExecutable = path.join(systemDrive, 'Python27', 'python.exe');
|
||||
|
||||
if (!fs.existsSync(pythonExecutable)) {
|
||||
pythonExecutable = 'python';
|
||||
}
|
||||
}
|
||||
|
||||
checkPythonVersion(pythonExecutable, cb);
|
||||
}
|
||||
else {
|
||||
cb(null, '');
|
||||
}
|
||||
}
|
||||
|
||||
function checkPythonVersion (python, cb) {
|
||||
var pythonHelpMessage = "Set the PYTHON env var to '/path/to/Python27/python.exe' if your python is installed in a non-default location.";
|
||||
|
||||
childProcess.execFile(python, ['-c', 'import platform; print(platform.python_version());'], { env: process.env }, function (err, stdout) {
|
||||
if (err) {
|
||||
error = "Python 2.7 is required to build Atom. An error (" + err + ") occured when checking the version of '" + python + "'. ";
|
||||
error += pythonHelpMessage;
|
||||
cb(error);
|
||||
return;
|
||||
}
|
||||
|
||||
var version = stdout.trim();
|
||||
if (~version.indexOf('+')) {
|
||||
version = version.replace(/\+/g, '');
|
||||
}
|
||||
if (~version.indexOf('rc')) {
|
||||
version = version.replace(/rc(.*)$/ig, '');
|
||||
}
|
||||
|
||||
// Atom requires python 2.7 or higher (but not python 3) for node-gyp
|
||||
var versionArray = version.split('.').map(function(num) { return +num; });
|
||||
var goodPythonVersion = (versionArray[0] === 2 && versionArray[1] >= 7);
|
||||
if (!goodPythonVersion) {
|
||||
error = "Python 2.7 is required to build Atom. '" + python + "' returns version " + version + ". ";
|
||||
error += pythonHelpMessage;
|
||||
cb(error);
|
||||
return;
|
||||
}
|
||||
|
||||
// Finally, if we've gotten this far, callback to resume the install process.
|
||||
cb(null, "Python: v" + version);
|
||||
});
|
||||
}
|
||||
@@ -2,13 +2,14 @@ path = require 'path'
|
||||
_ = require 'underscore-plus'
|
||||
{convertStackTrace} = require 'coffeestack'
|
||||
{View, $, $$} = require '../src/space-pen-extensions'
|
||||
grim = require 'grim'
|
||||
|
||||
sourceMaps = {}
|
||||
formatStackTrace = (spec, message='', stackTrace) ->
|
||||
return stackTrace unless stackTrace
|
||||
|
||||
jasminePattern = /^\s*at\s+.*\(?.*\/jasmine(-[^\/]*)?\.js:\d+:\d+\)?\s*$/
|
||||
firstJasmineLinePattern = /^\s*at \/.*\/jasmine(-[^\/]*)?\.js:\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)
|
||||
@@ -23,7 +24,7 @@ formatStackTrace = (spec, message='', stackTrace) ->
|
||||
|
||||
for line, index in lines
|
||||
# Remove prefix of lines matching: at [object Object].<anonymous> (path:1:2)
|
||||
prefixMatch = line.match(/at \[object Object\]\.<anonymous> \(([^\)]+)\)/)
|
||||
prefixMatch = line.match(/at \[object Object\]\.<anonymous> \(([^)]+)\)/)
|
||||
line = "at #{prefixMatch[1]}" if prefixMatch
|
||||
|
||||
# Relativize locations to spec directory
|
||||
@@ -52,6 +53,11 @@ class AtomReporter extends View
|
||||
@div outlet: "message", class: 'message'
|
||||
@div outlet: "results", class: 'results'
|
||||
|
||||
@div outlet: "deprecations", class: 'status alert alert-warning', style: 'display: none', =>
|
||||
@span outlet: 'deprecationStatus', '0 deprecations'
|
||||
@div class: 'deprecation-toggle'
|
||||
@div outlet: 'deprecationList', class: 'deprecation-list'
|
||||
|
||||
startedAt: null
|
||||
runningSpecCount: 0
|
||||
completeSpecCount: 0
|
||||
@@ -59,6 +65,7 @@ class AtomReporter extends View
|
||||
failedCount: 0
|
||||
skippedCount: 0
|
||||
totalSpecCount: 0
|
||||
deprecationCount: 0
|
||||
@timeoutId: 0
|
||||
|
||||
reportRunnerStarting: (runner) ->
|
||||
@@ -88,6 +95,29 @@ class AtomReporter extends View
|
||||
reportSpecStarting: (spec) ->
|
||||
@specStarted(spec)
|
||||
|
||||
addDeprecations: (spec) ->
|
||||
deprecations = grim.getDeprecations()
|
||||
@deprecationCount += deprecations.length
|
||||
@deprecations.show() if @deprecationCount > 0
|
||||
if @deprecationCount is 1
|
||||
@deprecationStatus.text("1 deprecation")
|
||||
else
|
||||
@deprecationStatus.text("#{@deprecationCount} deprecations")
|
||||
|
||||
for deprecation in deprecations
|
||||
@deprecationList.append $$ ->
|
||||
@div class: 'padded', =>
|
||||
@div class: 'result-message fail deprecation-message', deprecation.message
|
||||
|
||||
for stack in deprecation.stacks
|
||||
fullStack = stack.map ({functionName, location}) ->
|
||||
if functionName is '<unknown>'
|
||||
" at #{location}"
|
||||
else
|
||||
" at #{functionName} (#{location})"
|
||||
@pre class: 'stack-trace padded', formatStackTrace(spec, deprecation.message, fullStack.join('\n'))
|
||||
grim.clearDeprecations()
|
||||
|
||||
handleEvents: ->
|
||||
$(document).on "click", ".spec-toggle", ({currentTarget}) =>
|
||||
element = $(currentTarget)
|
||||
@@ -96,6 +126,13 @@ class AtomReporter extends View
|
||||
element.toggleClass('folded')
|
||||
false
|
||||
|
||||
$(document).on "click", ".deprecation-toggle", ({currentTarget}) =>
|
||||
element = $(currentTarget)
|
||||
deprecationList = $(document).find('.deprecation-list')
|
||||
deprecationList.toggle()
|
||||
element.toggleClass('folded')
|
||||
false
|
||||
|
||||
updateSpecCounts: ->
|
||||
if @skippedCount
|
||||
specCount = "#{@completeSpecCount - @skippedCount}/#{@totalSpecCount - @skippedCount} (#{@skippedCount} skipped)"
|
||||
@@ -175,6 +212,7 @@ class AtomReporter extends View
|
||||
specView = new SpecResultView(spec)
|
||||
specView.attach()
|
||||
@failedCount++
|
||||
@addDeprecations(spec)
|
||||
|
||||
class SuiteResultView extends View
|
||||
@content: ->
|
||||
|
||||
@@ -380,8 +380,8 @@ describe "the `atom` global", ->
|
||||
|
||||
runs ->
|
||||
atom.packages.deactivatePackage('package-with-keymaps')
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:$$ -> @div class: 'test-1'[0])).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:$$ -> @div class: 'test-2'[0])).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target: ($$ -> @div class: 'test-1')[0])).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target: ($$ -> @div class: 'test-2')[0])).toHaveLength 0
|
||||
|
||||
it "removes the package's stylesheets", ->
|
||||
waitsForPromise ->
|
||||
|
||||
@@ -17,6 +17,22 @@ describe "ContextMenuManager", ->
|
||||
expect(contextMenu.definitions['.selector'][0].label).toEqual 'label'
|
||||
expect(contextMenu.definitions['.selector'][0].command).toEqual 'command'
|
||||
|
||||
it "loads submenus", ->
|
||||
contextMenu.add 'file-path',
|
||||
'.selector':
|
||||
'parent':
|
||||
'child-1': 'child-1:trigger'
|
||||
'child-2': 'child-2:trigger'
|
||||
'parent-2': 'parent-2:trigger'
|
||||
|
||||
expect(contextMenu.definitions['.selector'].length).toBe 2
|
||||
expect(contextMenu.definitions['.selector'][0].label).toEqual 'parent'
|
||||
expect(contextMenu.definitions['.selector'][0].submenu.length).toBe 2
|
||||
expect(contextMenu.definitions['.selector'][0].submenu[0].label).toBe 'child-1'
|
||||
expect(contextMenu.definitions['.selector'][0].submenu[0].command).toBe 'child-1:trigger'
|
||||
expect(contextMenu.definitions['.selector'][0].submenu[1].label).toBe 'child-2'
|
||||
expect(contextMenu.definitions['.selector'][0].submenu[1].command).toBe 'child-2:trigger'
|
||||
|
||||
describe 'dev mode', ->
|
||||
it 'loads', ->
|
||||
contextMenu.add 'file-path',
|
||||
@@ -105,7 +121,7 @@ describe "ContextMenuManager", ->
|
||||
expect(menu[2].command).toEqual 'dev-command'
|
||||
expect(menu[3]).toBeUndefined()
|
||||
|
||||
describe "#executeBuildHandlers", ->
|
||||
describe "executeBuildHandlers", ->
|
||||
menuTemplate = [
|
||||
label: 'label'
|
||||
executeAtBuild: ->
|
||||
@@ -119,4 +135,3 @@ describe "ContextMenuManager", ->
|
||||
|
||||
expect(buildFn).toHaveBeenCalled()
|
||||
expect(buildFn.mostRecentCall.args[0]).toBe event
|
||||
|
||||
|
||||
@@ -912,6 +912,42 @@ describe "DisplayBuffer", ->
|
||||
expect(displayBuffer.findMarkers(class: 'a', startBufferRow: 0, endBufferRow: 3)).toEqual [marker1]
|
||||
expect(displayBuffer.findMarkers(endBufferRow: 10)).toEqual [marker3]
|
||||
|
||||
it "allows the startScreenRow and endScreenRow to be specified", ->
|
||||
marker1 = displayBuffer.markBufferRange([[6, 0], [7, 0]], class: 'a')
|
||||
marker2 = displayBuffer.markBufferRange([[9, 0], [10, 0]], class: 'a')
|
||||
displayBuffer.createFold(4, 7)
|
||||
expect(displayBuffer.findMarkers(class: 'a', startScreenRow: 6, endScreenRow: 7)).toEqual [marker2]
|
||||
|
||||
it "allows intersectsBufferRowRange to be specified", ->
|
||||
marker1 = displayBuffer.markBufferRange([[5, 0], [5, 0]], class: 'a')
|
||||
marker2 = displayBuffer.markBufferRange([[8, 0], [8, 0]], class: 'a')
|
||||
displayBuffer.createFold(4, 7)
|
||||
expect(displayBuffer.findMarkers(class: 'a', intersectsBufferRowRange: [5, 6])).toEqual [marker1]
|
||||
|
||||
it "allows intersectsScreenRowRange to be specified", ->
|
||||
marker1 = displayBuffer.markBufferRange([[5, 0], [5, 0]], class: 'a')
|
||||
marker2 = displayBuffer.markBufferRange([[8, 0], [8, 0]], class: 'a')
|
||||
displayBuffer.createFold(4, 7)
|
||||
expect(displayBuffer.findMarkers(class: 'a', intersectsScreenRowRange: [5, 10])).toEqual [marker2]
|
||||
|
||||
it "allows containedInScreenRange to be specified", ->
|
||||
marker1 = displayBuffer.markBufferRange([[5, 0], [5, 0]], class: 'a')
|
||||
marker2 = displayBuffer.markBufferRange([[8, 0], [8, 0]], class: 'a')
|
||||
displayBuffer.createFold(4, 7)
|
||||
expect(displayBuffer.findMarkers(class: 'a', containedInScreenRange: [[5, 0], [7, 0]])).toEqual [marker2]
|
||||
|
||||
it "allows intersectsBufferRange to be specified", ->
|
||||
marker1 = displayBuffer.markBufferRange([[5, 0], [5, 0]], class: 'a')
|
||||
marker2 = displayBuffer.markBufferRange([[8, 0], [8, 0]], class: 'a')
|
||||
displayBuffer.createFold(4, 7)
|
||||
expect(displayBuffer.findMarkers(class: 'a', intersectsBufferRange: [[5, 0], [6, 0]])).toEqual [marker1]
|
||||
|
||||
it "allows intersectsScreenRange to be specified", ->
|
||||
marker1 = displayBuffer.markBufferRange([[5, 0], [5, 0]], class: 'a')
|
||||
marker2 = displayBuffer.markBufferRange([[8, 0], [8, 0]], class: 'a')
|
||||
displayBuffer.createFold(4, 7)
|
||||
expect(displayBuffer.findMarkers(class: 'a', intersectsScreenRange: [[5, 0], [10, 0]])).toEqual [marker2]
|
||||
|
||||
describe "marker destruction", ->
|
||||
it "allows markers to be destroyed", ->
|
||||
marker = displayBuffer.markScreenRange([[5, 4], [5, 10]])
|
||||
@@ -948,7 +984,7 @@ describe "DisplayBuffer", ->
|
||||
it "returns the start and end positions of the marker based on the line height and character widths assigned to the DisplayBuffer", ->
|
||||
marker = displayBuffer.markScreenRange([[5, 10], [6, 4]])
|
||||
|
||||
displayBuffer.setLineHeight(20)
|
||||
displayBuffer.setLineHeightInPixels(20)
|
||||
displayBuffer.setDefaultCharWidth(10)
|
||||
displayBuffer.setScopedCharWidths(["source.js", "keyword.control.js"], r: 11, e: 11, t: 11, u: 11, n: 11)
|
||||
|
||||
@@ -956,10 +992,21 @@ describe "DisplayBuffer", ->
|
||||
expect(start.top).toBe 5 * 20
|
||||
expect(start.left).toBe (4 * 10) + (6 * 11)
|
||||
|
||||
describe "decorations", ->
|
||||
it "can add decorations associated with markers and remove them", ->
|
||||
decoration = {type: 'gutter', class: 'one'}
|
||||
marker = displayBuffer.markBufferRange([[2, 13], [3, 15]])
|
||||
|
||||
displayBuffer.addDecorationForMarker(marker, decoration)
|
||||
expect(displayBuffer.decorationsForScreenRowRange(2, 3)[marker.id][0]).toBe decoration
|
||||
|
||||
displayBuffer.removeDecorationForMarker(marker, decoration)
|
||||
expect(displayBuffer.decorationsForScreenRowRange(2, 3)[marker.id]).not.toBeDefined()
|
||||
|
||||
describe "::setScrollTop", ->
|
||||
beforeEach ->
|
||||
displayBuffer.manageScrollPosition = true
|
||||
displayBuffer.setLineHeight(10)
|
||||
displayBuffer.setLineHeightInPixels(10)
|
||||
|
||||
it "disallows negative values", ->
|
||||
displayBuffer.setHeight(displayBuffer.getScrollHeight() + 100)
|
||||
@@ -979,7 +1026,7 @@ describe "DisplayBuffer", ->
|
||||
describe "::setScrollLeft", ->
|
||||
beforeEach ->
|
||||
displayBuffer.manageScrollPosition = true
|
||||
displayBuffer.setLineHeight(10)
|
||||
displayBuffer.setLineHeightInPixels(10)
|
||||
displayBuffer.setDefaultCharWidth(10)
|
||||
|
||||
it "disallows negative values", ->
|
||||
@@ -997,17 +1044,26 @@ describe "DisplayBuffer", ->
|
||||
expect(displayBuffer.setScrollLeft(maxScrollLeft + 50)).toBe maxScrollLeft
|
||||
expect(displayBuffer.getScrollLeft()).toBe maxScrollLeft
|
||||
|
||||
describe "::scrollToScreenPosition(position)", ->
|
||||
it "sets the scroll top and scroll left so the given screen position is in view", ->
|
||||
describe "::scrollToScreenPosition(position, [options])", ->
|
||||
beforeEach ->
|
||||
displayBuffer.manageScrollPosition = true
|
||||
displayBuffer.setLineHeight(10)
|
||||
displayBuffer.setLineHeightInPixels(10)
|
||||
displayBuffer.setDefaultCharWidth(10)
|
||||
displayBuffer.setHorizontalScrollbarHeight(0)
|
||||
|
||||
displayBuffer.setHeight(50)
|
||||
displayBuffer.setWidth(50)
|
||||
maxScrollTop = displayBuffer.getScrollHeight() - displayBuffer.getHeight()
|
||||
|
||||
it "sets the scroll top and scroll left so the given screen position is in view", ->
|
||||
displayBuffer.scrollToScreenPosition([8, 20])
|
||||
expect(displayBuffer.getScrollBottom()).toBe (9 + displayBuffer.getVerticalScrollMargin()) * 10
|
||||
expect(displayBuffer.getScrollRight()).toBe (20 + displayBuffer.getHorizontalScrollMargin()) * 10
|
||||
|
||||
describe "when the 'center' option is true", ->
|
||||
it "vertically scrolls to center the given position vertically", ->
|
||||
displayBuffer.scrollToScreenPosition([8, 20], center: true)
|
||||
expect(displayBuffer.getScrollTop()).toBe (8 * 10) + 5 - (50 / 2)
|
||||
expect(displayBuffer.getScrollRight()).toBe (20 + displayBuffer.getHorizontalScrollMargin()) * 10
|
||||
|
||||
it "does not scroll vertically if the position is already in view", ->
|
||||
displayBuffer.scrollToScreenPosition([4, 20], center: true)
|
||||
expect(displayBuffer.getScrollTop()).toBe 0
|
||||
|
||||
+1296
-202
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+169
-5
@@ -622,6 +622,38 @@ describe "Editor", ->
|
||||
editor.moveCursorToBeginningOfNextWord()
|
||||
expect(editor.getCursorBufferPosition()).toEqual [11, 9]
|
||||
|
||||
describe ".moveCursorToBeginningOfNextParagraph()", ->
|
||||
it "moves the cursor before the first line of the next paragraph", ->
|
||||
editor.setCursorBufferPosition [0,6]
|
||||
cursor = editor.getCursor()
|
||||
|
||||
editor.moveCursorToBeginningOfNextParagraph()
|
||||
|
||||
expect(cursor.getBufferPosition()).toEqual { row : 10, column : 0 }
|
||||
|
||||
editor.setText("")
|
||||
editor.setCursorBufferPosition [0,0]
|
||||
cursor = editor.getCursor()
|
||||
editor.moveCursorToBeginningOfNextParagraph()
|
||||
|
||||
expect(cursor.getBufferPosition()).toEqual [0, 0]
|
||||
|
||||
describe ".moveCursorToBeginningOfPreviousParagraph()", ->
|
||||
it "moves the cursor before the first line of the pevious paragraph", ->
|
||||
editor.setCursorBufferPosition [10,0]
|
||||
cursor = editor.getCursor()
|
||||
|
||||
editor.moveCursorToBeginningOfPreviousParagraph()
|
||||
|
||||
expect(cursor.getBufferPosition()).toEqual { row : 0, column : 0 }
|
||||
|
||||
editor.setText("")
|
||||
editor.setCursorBufferPosition [0,0]
|
||||
cursor = editor.getCursor()
|
||||
editor.moveCursorToBeginningOfPreviousParagraph()
|
||||
|
||||
expect(cursor.getBufferPosition()).toEqual [0, 0]
|
||||
|
||||
describe ".getCurrentParagraphBufferRange()", ->
|
||||
it "returns the buffer range of the current paragraph, delimited by blank lines or the beginning / end of the file", ->
|
||||
buffer.setText """
|
||||
@@ -696,7 +728,7 @@ describe "Editor", ->
|
||||
editor.manageScrollPosition = true
|
||||
editor.setVerticalScrollMargin(2)
|
||||
editor.setHorizontalScrollMargin(2)
|
||||
editor.setLineHeight(10)
|
||||
editor.setLineHeightInPixels(10)
|
||||
editor.setDefaultCharWidth(10)
|
||||
editor.setHorizontalScrollbarHeight(0)
|
||||
editor.setHeight(5.5 * 10)
|
||||
@@ -831,6 +863,30 @@ describe "Editor", ->
|
||||
expect(selection1.getScreenRange()).toEqual [[3, 0], [4, 5]]
|
||||
expect(selection2.getScreenRange()).toEqual [[5, 6], [6, 2]]
|
||||
|
||||
describe ".selectToBeginningOfNextParagraph()", ->
|
||||
it "selects from the cursor to first line of the next paragraph", ->
|
||||
editor.setSelectedBufferRange([[3, 0], [4, 5]])
|
||||
editor.addCursorAtScreenPosition([5, 6])
|
||||
editor.selectToScreenPosition([6, 2])
|
||||
|
||||
editor.selectToBeginningOfNextParagraph()
|
||||
|
||||
selections = editor.getSelections()
|
||||
expect(selections.length).toBe 1
|
||||
expect(selections[0].getScreenRange()).toEqual [[3, 0], [10, 0]]
|
||||
|
||||
describe ".selectToBeginningOfPreviousParagraph()", ->
|
||||
it "selects from the cursor to the first line of the pevious paragraph", ->
|
||||
editor.setSelectedBufferRange([[3, 0], [4, 5]])
|
||||
editor.addCursorAtScreenPosition([5, 6])
|
||||
editor.selectToScreenPosition([6, 2])
|
||||
|
||||
editor.selectToBeginningOfPreviousParagraph()
|
||||
|
||||
selections = editor.getSelections()
|
||||
expect(selections.length).toBe 1
|
||||
expect(selections[0].getScreenRange()).toEqual [[0, 0], [5, 6]]
|
||||
|
||||
it "merges selections if they intersect, maintaining the directionality of the last selection", ->
|
||||
editor.setCursorScreenPosition([4, 10])
|
||||
editor.selectToScreenPosition([5, 27])
|
||||
@@ -1135,7 +1191,7 @@ describe "Editor", ->
|
||||
describe "when the 'autoscroll' option is true", ->
|
||||
it "autoscrolls to the selection", ->
|
||||
editor.manageScrollPosition = true
|
||||
editor.setLineHeight(10)
|
||||
editor.setLineHeightInPixels(10)
|
||||
editor.setDefaultCharWidth(10)
|
||||
editor.setHeight(50)
|
||||
editor.setWidth(50)
|
||||
@@ -1164,6 +1220,21 @@ describe "Editor", ->
|
||||
expect(editor.selectMarker(marker)).toBeFalsy()
|
||||
expect(editor.getSelectedBufferRange()).toEqual [[0, 0], [0, 0]]
|
||||
|
||||
describe ".addSelectionForBufferRange(bufferRange)", ->
|
||||
it "adds a selection for the specified buffer range", ->
|
||||
editor.addSelectionForBufferRange([[3, 4], [5, 6]])
|
||||
expect(editor.getSelectedBufferRanges()).toEqual [[[0, 0], [0, 0]], [[3, 4], [5, 6]]]
|
||||
|
||||
it "autoscrolls to the added selection if needed", ->
|
||||
editor.setLineHeightInPixels(10)
|
||||
editor.setDefaultCharWidth(10)
|
||||
editor.setHeight(50)
|
||||
editor.setWidth(50)
|
||||
|
||||
editor.addSelectionForBufferRange([[8, 10], [8, 15]])
|
||||
expect(editor.getScrollTop()).toBe 75
|
||||
expect(editor.getScrollLeft()).toBe 160
|
||||
|
||||
describe ".addSelectionBelow()", ->
|
||||
describe "when the selection is non-empty", ->
|
||||
it "selects the same region of the line below current selections if possible", ->
|
||||
@@ -1584,6 +1655,13 @@ describe "Editor", ->
|
||||
expect(editor.lineForBufferRow(1)).toBe ' '
|
||||
expect(editor.lineForBufferRow(2)).toBe '}'
|
||||
|
||||
describe "when a new line is appended before a closing tag (e.g. by pressing enter before a selection)", ->
|
||||
it "moves the line down and keeps the indentation level the same when editor.autoIndent is true", ->
|
||||
atom.config.set('editor.autoIndent', true)
|
||||
editor.setCursorBufferPosition([9,2])
|
||||
editor.insertNewline()
|
||||
expect(editor.lineForBufferRow(10)).toBe ' };'
|
||||
|
||||
describe ".backspace()", ->
|
||||
describe "when there is a single cursor", ->
|
||||
changeScreenRangeHandler = null
|
||||
@@ -1768,6 +1846,32 @@ describe "Editor", ->
|
||||
expect(buffer.lineForRow(1)).toBe ' var sort = function(it) {'
|
||||
expect(buffer.lineForRow(2)).toBe 'if (items.length <= 1) return items;'
|
||||
|
||||
describe '.deleteToEndOfLine()', ->
|
||||
describe 'when no text is selected', ->
|
||||
it 'deletes all text between the cursor and the end of the line', ->
|
||||
editor.setCursorBufferPosition([1, 24])
|
||||
editor.addCursorAtBufferPosition([2, 5])
|
||||
[cursor1, cursor2] = editor.getCursors()
|
||||
|
||||
editor.deleteToEndOfLine()
|
||||
expect(buffer.lineForRow(1)).toBe ' var sort = function(it'
|
||||
expect(buffer.lineForRow(2)).toBe ' i'
|
||||
expect(cursor1.getBufferPosition()).toEqual [1, 24]
|
||||
expect(cursor2.getBufferPosition()).toEqual [2, 5]
|
||||
|
||||
describe 'when at the end of the line', ->
|
||||
it 'deletes the next newline', ->
|
||||
editor.setCursorBufferPosition([1, 30])
|
||||
editor.deleteToEndOfLine()
|
||||
expect(buffer.lineForRow(1)).toBe ' var sort = function(items) { if (items.length <= 1) return items;'
|
||||
|
||||
describe 'when text is selected', ->
|
||||
it 'deletes only the text in the selection', ->
|
||||
editor.setSelectedBufferRanges([[[1, 24], [1, 27]], [[2, 0], [2, 4]]])
|
||||
editor.deleteToEndOfLine()
|
||||
expect(buffer.lineForRow(1)).toBe ' var sort = function(it) {'
|
||||
expect(buffer.lineForRow(2)).toBe 'if (items.length <= 1) return items;'
|
||||
|
||||
describe ".deleteToBeginningOfLine()", ->
|
||||
describe "when no text is selected", ->
|
||||
it "deletes all text between the cursor and the beginning of the line", ->
|
||||
@@ -2195,6 +2299,15 @@ describe "Editor", ->
|
||||
editor.outdentSelectedRows()
|
||||
expect(buffer.lineForRow(0)).toBe "var quicksort = function () {"
|
||||
|
||||
it "outdents only up to the first non-space non-tab character", ->
|
||||
editor.insertText(' \tfoo\t ')
|
||||
editor.outdentSelectedRows()
|
||||
expect(buffer.lineForRow(0)).toBe "\tfoo\t var quicksort = function () {"
|
||||
editor.outdentSelectedRows()
|
||||
expect(buffer.lineForRow(0)).toBe "foo\t var quicksort = function () {"
|
||||
editor.outdentSelectedRows()
|
||||
expect(buffer.lineForRow(0)).toBe "foo\t var quicksort = function () {"
|
||||
|
||||
describe "when one line is selected", ->
|
||||
it "outdents line and retains editor", ->
|
||||
editor.setSelectedBufferRange([[1,4], [1,14]])
|
||||
@@ -2844,6 +2957,18 @@ describe "Editor", ->
|
||||
expect(editor.lineForBufferRow(4)).toBe " }"
|
||||
expect(editor.lineForBufferRow(5)).toBe " i=1"
|
||||
|
||||
describe "soft and hard tabs", ->
|
||||
it "resets the tab style when tokenization is complete", ->
|
||||
editor.destroy()
|
||||
atom.project.open('sample-with-tabs-and-leading-comment.coffee').then (o) -> editor = o
|
||||
expect(editor.softTabs).toBe true
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-coffee-script')
|
||||
|
||||
runs ->
|
||||
expect(editor.softTabs).toBe false
|
||||
|
||||
describe ".destroy()", ->
|
||||
it "destroys all markers associated with the edit session", ->
|
||||
expect(buffer.getMarkerCount()).toBeGreaterThan 0
|
||||
@@ -3123,7 +3248,7 @@ describe "Editor", ->
|
||||
describe ".scrollToCursorPosition()", ->
|
||||
it "scrolls the last cursor into view", ->
|
||||
editor.setCursorScreenPosition([8, 8])
|
||||
editor.setLineHeight(10)
|
||||
editor.setLineHeightInPixels(10)
|
||||
editor.setDefaultCharWidth(10)
|
||||
editor.setHeight(50)
|
||||
editor.setWidth(50)
|
||||
@@ -3136,21 +3261,60 @@ describe "Editor", ->
|
||||
expect(editor.getScrollRight()).toBe (9 + editor.getHorizontalScrollMargin()) * 10
|
||||
|
||||
describe ".pageUp/Down()", ->
|
||||
it "scrolls one screen height up or down", ->
|
||||
it "scrolls one screen height up or down and moves the cursor one page length", ->
|
||||
editor.manageScrollPosition = true
|
||||
|
||||
editor.setLineHeight(10)
|
||||
editor.setLineHeightInPixels(10)
|
||||
editor.setHeight(50)
|
||||
expect(editor.getScrollHeight()).toBe 130
|
||||
expect(editor.getCursorBufferPosition().row).toBe 0
|
||||
|
||||
editor.pageDown()
|
||||
expect(editor.getScrollTop()).toBe 50
|
||||
expect(editor.getCursorBufferPosition().row).toBe 5
|
||||
|
||||
editor.pageDown()
|
||||
expect(editor.getScrollTop()).toBe 80
|
||||
expect(editor.getCursorBufferPosition().row).toBe 10
|
||||
|
||||
editor.pageUp()
|
||||
expect(editor.getScrollTop()).toBe 30
|
||||
expect(editor.getCursorBufferPosition().row).toBe 5
|
||||
|
||||
editor.pageUp()
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
expect(editor.getCursorBufferPosition().row).toBe 0
|
||||
|
||||
describe ".selectPageUp/Down()", ->
|
||||
it "selects one screen height of text up or down", ->
|
||||
editor.manageScrollPosition = true
|
||||
|
||||
editor.setLineHeightInPixels(10)
|
||||
editor.setHeight(50)
|
||||
expect(editor.getScrollHeight()).toBe 130
|
||||
expect(editor.getCursorBufferPosition().row).toBe 0
|
||||
|
||||
editor.selectPageDown()
|
||||
expect(editor.getScrollTop()).toBe 30
|
||||
expect(editor.getSelectedBufferRanges()).toEqual [[[0,0], [5,0]]]
|
||||
|
||||
editor.selectPageDown()
|
||||
expect(editor.getScrollTop()).toBe 80
|
||||
expect(editor.getSelectedBufferRanges()).toEqual [[[0,0], [10,0]]]
|
||||
|
||||
editor.selectPageDown()
|
||||
expect(editor.getScrollTop()).toBe 80
|
||||
expect(editor.getSelectedBufferRanges()).toEqual [[[0,0], [12,2]]]
|
||||
|
||||
editor.moveCursorToBottom()
|
||||
editor.selectPageUp()
|
||||
expect(editor.getScrollTop()).toBe 50
|
||||
expect(editor.getSelectedBufferRanges()).toEqual [[[7,0], [12,2]]]
|
||||
|
||||
editor.selectPageUp()
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
expect(editor.getSelectedBufferRanges()).toEqual [[[2,0], [12,2]]]
|
||||
|
||||
editor.selectPageUp()
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
expect(editor.getSelectedBufferRanges()).toEqual [[[0,0], [12,2]]]
|
||||
|
||||
@@ -10,6 +10,8 @@ describe "EditorView", ->
|
||||
[buffer, editorView, editor, cachedEditor, cachedLineHeight, cachedCharWidth, fart] = []
|
||||
|
||||
beforeEach ->
|
||||
atom.config.set 'core.useReactEditor', false
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.js').then (o) -> editor = o
|
||||
|
||||
@@ -33,10 +35,10 @@ describe "EditorView", ->
|
||||
$('#jasmine-content').append(this)
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-text', sync: true)
|
||||
atom.packages.activatePackage('language-text')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-javascript', sync: true)
|
||||
atom.packages.activatePackage('language-javascript')
|
||||
|
||||
getLineHeight = ->
|
||||
return cachedLineHeight if cachedLineHeight?
|
||||
@@ -1609,7 +1611,7 @@ describe "EditorView", ->
|
||||
editorView.attachToDom()
|
||||
|
||||
expect(atom.config.get("editor.showInvisibles")).toBeFalsy()
|
||||
expect(editorView.renderedLines.find('.line').text()).toBe " a line with tabs and spaces "
|
||||
expect(editorView.renderedLines.find('.line').text()).toBe " a line with tabs and spaces "
|
||||
|
||||
atom.config.set("editor.showInvisibles", true)
|
||||
space = editorView.invisibles?.space
|
||||
@@ -1618,10 +1620,10 @@ describe "EditorView", ->
|
||||
expect(tab).toBeTruthy()
|
||||
eol = editorView.invisibles?.eol
|
||||
expect(eol).toBeTruthy()
|
||||
expect(editorView.renderedLines.find('.line').text()).toBe "#{space}a line with tabs#{tab} and spaces#{space}#{eol}"
|
||||
expect(editorView.renderedLines.find('.line').text()).toBe "#{space}a line with tabs#{tab}and spaces#{space}#{eol}"
|
||||
|
||||
atom.config.set("editor.showInvisibles", false)
|
||||
expect(editorView.renderedLines.find('.line').text()).toBe " a line with tabs and spaces "
|
||||
expect(editorView.renderedLines.find('.line').text()).toBe " a line with tabs and spaces "
|
||||
|
||||
it "displays newlines as their own token outside of the other tokens scope", ->
|
||||
editorView.setShowInvisibles(true)
|
||||
@@ -1634,7 +1636,7 @@ describe "EditorView", ->
|
||||
editorView.attachToDom()
|
||||
atom.config.set("editor.showInvisibles", true)
|
||||
atom.config.set("editor.invisibles", eol: ";", space: "_", tab: "tab")
|
||||
expect(editorView.find(".line:first").text()).toBe "_tab _;"
|
||||
expect(editorView.find(".line:first").text()).toBe "_tab_;"
|
||||
|
||||
it "displays trailing carriage return using a visible non-empty value", ->
|
||||
editor.setText "a line that ends with a carriage return\r\n"
|
||||
@@ -2080,7 +2082,7 @@ describe "EditorView", ->
|
||||
tab = miniEditor.invisibles?.tab
|
||||
expect(tab).toBeTruthy()
|
||||
miniEditor.getEditor().setText(" a line with tabs\tand spaces ")
|
||||
expect(miniEditor.renderedLines.find('.line').text()).toBe "#{space}a line with tabs#{tab} and spaces#{space}"
|
||||
expect(miniEditor.renderedLines.find('.line').text()).toBe "#{space}a line with tabs#{tab}and spaces#{space}"
|
||||
|
||||
it "doesn't show the indent guide", ->
|
||||
atom.config.set "editor.showIndentGuide", true
|
||||
@@ -2413,20 +2415,21 @@ describe "EditorView", ->
|
||||
expect(editorView.getFirstVisibleScreenRow()).toBe(0)
|
||||
|
||||
describe ".checkoutHead()", ->
|
||||
[filePath, originalPathText] = []
|
||||
[filePath] = []
|
||||
|
||||
beforeEach ->
|
||||
filePath = atom.project.resolve('git/working-dir/file.txt')
|
||||
originalPathText = fs.readFileSync(filePath, 'utf8')
|
||||
workingDirPath = temp.mkdirSync('atom-working-dir')
|
||||
fs.copySync(path.join(__dirname, 'fixtures', 'git', 'working-dir'), workingDirPath)
|
||||
fs.renameSync(path.join(workingDirPath, 'git.git'), path.join(workingDirPath, '.git'))
|
||||
atom.project.setPath(workingDirPath)
|
||||
filePath = atom.project.resolve('file.txt')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(filePath).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
editorView.edit(editor)
|
||||
|
||||
afterEach ->
|
||||
fs.writeFileSync(filePath, originalPathText)
|
||||
|
||||
it "restores the contents of the editor view to the HEAD revision", ->
|
||||
editor.setText('')
|
||||
editor.save()
|
||||
@@ -2440,7 +2443,7 @@ describe "EditorView", ->
|
||||
fileChangeHandler.callCount > 0
|
||||
|
||||
runs ->
|
||||
expect(editor.getText()).toBe(originalPathText)
|
||||
expect(editor.getText()).toBe('undefined')
|
||||
|
||||
describe ".pixelPositionForBufferPosition(position)", ->
|
||||
describe "when the editor view is detached", ->
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
undefined
|
||||
Arquivo binário não exibido.
BIN
Arquivo binário não exibido.
BIN
Arquivo binário não exibido.
BIN
Arquivo binário não exibido.
BIN
Arquivo binário não exibido.
BIN
Arquivo binário não exibido.
+1
@@ -0,0 +1 @@
|
||||
x�ŽInB1³ö)úσ„¢°fÉ Úîvb�ù‘c†ãóQn�e=©žª,½· ÚÄ·9˜¡r&V!ªÆq¢êuH¢.Éâ)i6Ί|™àtuÞº�}-(+lUΉŒf_pUµQIcx�ßË€ßÚŽxoåÔ`wzáï}~ulçmYú(+•�QJ¤ëºvNþÿƒØµñž·ó1ÅiHL¢
|
||||
BIN
Arquivo binário não exibido.
BIN
Arquivo binário não exibido.
BIN
Arquivo binário não exibido.
@@ -1 +1 @@
|
||||
ef046e9eecaa5255ea5e9817132d4001724d6ae1
|
||||
8a9c86f1cb1f14b8f436eb91f4b052c8802ca99e
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
Full of text
|
||||
@@ -0,0 +1,4 @@
|
||||
# This is a comment
|
||||
if this.studyingEconomics
|
||||
buy() while supply > demand
|
||||
sell() until supply > demand
|
||||
+55
-96
@@ -4,6 +4,12 @@ fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
Task = require '../src/task'
|
||||
|
||||
copyRepository = ->
|
||||
workingDirPath = temp.mkdirSync('atom-working-dir')
|
||||
fs.copySync(path.join(__dirname, 'fixtures', 'git', 'working-dir'), workingDirPath)
|
||||
fs.renameSync(path.join(workingDirPath, 'git.git'), path.join(workingDirPath, '.git'))
|
||||
workingDirPath
|
||||
|
||||
describe "Git", ->
|
||||
repo = null
|
||||
|
||||
@@ -41,17 +47,13 @@ describe "Git", ->
|
||||
expect(repo.isPathIgnored('b.txt')).toBeFalsy()
|
||||
|
||||
describe ".isPathModified(path)", ->
|
||||
[repo, filePath, newPath, originalPathText] = []
|
||||
[repo, filePath, newPath] = []
|
||||
|
||||
beforeEach ->
|
||||
repo = new Git(path.join(__dirname, 'fixtures', 'git', 'working-dir'))
|
||||
filePath = require.resolve('./fixtures/git/working-dir/file.txt')
|
||||
newPath = path.join(__dirname, 'fixtures', 'git', 'working-dir', 'new-path.txt')
|
||||
originalPathText = fs.readFileSync(filePath, 'utf8')
|
||||
|
||||
afterEach ->
|
||||
fs.writeFileSync(filePath, originalPathText)
|
||||
fs.removeSync(newPath) if fs.existsSync(newPath)
|
||||
workingDirPath = copyRepository()
|
||||
repo = new Git(workingDirPath)
|
||||
filePath = path.join(workingDirPath, 'a.txt')
|
||||
newPath = path.join(workingDirPath, 'new-path.txt')
|
||||
|
||||
describe "when the path is unstaged", ->
|
||||
it "returns false if the path has not been modified", ->
|
||||
@@ -72,14 +74,12 @@ describe "Git", ->
|
||||
[filePath, newPath] = []
|
||||
|
||||
beforeEach ->
|
||||
repo = new Git(path.join(__dirname, 'fixtures', 'git', 'working-dir'))
|
||||
filePath = require.resolve('./fixtures/git/working-dir/file.txt')
|
||||
newPath = path.join(__dirname, 'fixtures', 'git', 'working-dir', 'new-path.txt')
|
||||
workingDirPath = copyRepository()
|
||||
repo = new Git(workingDirPath)
|
||||
filePath = path.join(workingDirPath, 'a.txt')
|
||||
newPath = path.join(workingDirPath, 'new-path.txt')
|
||||
fs.writeFileSync(newPath, "i'm new here")
|
||||
|
||||
afterEach ->
|
||||
fs.removeSync(newPath) if fs.existsSync(newPath)
|
||||
|
||||
describe "when the path is unstaged", ->
|
||||
it "returns true if the path is new", ->
|
||||
expect(repo.isPathNew(newPath)).toBeTruthy()
|
||||
@@ -88,48 +88,35 @@ describe "Git", ->
|
||||
expect(repo.isPathNew(filePath)).toBeFalsy()
|
||||
|
||||
describe ".checkoutHead(path)", ->
|
||||
[path1, path2, originalPath1Text, originalPath2Text] = []
|
||||
[filePath] = []
|
||||
|
||||
beforeEach ->
|
||||
repo = new Git(path.join(__dirname, 'fixtures', 'git', 'working-dir'))
|
||||
path1 = require.resolve('./fixtures/git/working-dir/file.txt')
|
||||
originalPath1Text = fs.readFileSync(path1, 'utf8')
|
||||
path2 = require.resolve('./fixtures/git/working-dir/other.txt')
|
||||
originalPath2Text = fs.readFileSync(path2, 'utf8')
|
||||
|
||||
afterEach ->
|
||||
fs.writeFileSync(path1, originalPath1Text)
|
||||
fs.writeFileSync(path2, originalPath2Text)
|
||||
workingDirPath = copyRepository()
|
||||
repo = new Git(workingDirPath)
|
||||
filePath = path.join(workingDirPath, 'a.txt')
|
||||
|
||||
it "no longer reports a path as modified after checkout", ->
|
||||
expect(repo.isPathModified(path1)).toBeFalsy()
|
||||
fs.writeFileSync(path1, '')
|
||||
expect(repo.isPathModified(path1)).toBeTruthy()
|
||||
expect(repo.checkoutHead(path1)).toBeTruthy()
|
||||
expect(repo.isPathModified(path1)).toBeFalsy()
|
||||
expect(repo.isPathModified(filePath)).toBeFalsy()
|
||||
fs.writeFileSync(filePath, 'ch ch changes')
|
||||
expect(repo.isPathModified(filePath)).toBeTruthy()
|
||||
expect(repo.checkoutHead(filePath)).toBeTruthy()
|
||||
expect(repo.isPathModified(filePath)).toBeFalsy()
|
||||
|
||||
it "restores the contents of the path to the original text", ->
|
||||
fs.writeFileSync(path1, '')
|
||||
expect(repo.checkoutHead(path1)).toBeTruthy()
|
||||
expect(fs.readFileSync(path1, 'utf8')).toBe(originalPath1Text)
|
||||
|
||||
it "only restores the path specified", ->
|
||||
fs.writeFileSync(path2, 'path 2 is edited')
|
||||
expect(repo.isPathModified(path2)).toBeTruthy()
|
||||
expect(repo.checkoutHead(path1)).toBeTruthy()
|
||||
expect(fs.readFileSync(path2, 'utf8')).toBe('path 2 is edited')
|
||||
expect(repo.isPathModified(path2)).toBeTruthy()
|
||||
fs.writeFileSync(filePath, 'ch ch changes')
|
||||
expect(repo.checkoutHead(filePath)).toBeTruthy()
|
||||
expect(fs.readFileSync(filePath, 'utf8')).toBe ''
|
||||
|
||||
it "fires a status-changed event if the checkout completes successfully", ->
|
||||
fs.writeFileSync(path1, '')
|
||||
repo.getPathStatus(path1)
|
||||
fs.writeFileSync(filePath, 'ch ch changes')
|
||||
repo.getPathStatus(filePath)
|
||||
statusHandler = jasmine.createSpy('statusHandler')
|
||||
repo.on 'status-changed', statusHandler
|
||||
repo.checkoutHead(path1)
|
||||
repo.checkoutHead(filePath)
|
||||
expect(statusHandler.callCount).toBe 1
|
||||
expect(statusHandler.argsForCall[0][0..1]).toEqual [path1, 0]
|
||||
expect(statusHandler.argsForCall[0][0..1]).toEqual [filePath, 0]
|
||||
|
||||
repo.checkoutHead(path1)
|
||||
repo.checkoutHead(filePath)
|
||||
expect(statusHandler.callCount).toBe 1
|
||||
|
||||
describe ".destroy()", ->
|
||||
@@ -138,32 +125,13 @@ describe "Git", ->
|
||||
repo.destroy()
|
||||
expect(-> repo.getShortHead()).toThrow()
|
||||
|
||||
describe ".getDiffStats(path)", ->
|
||||
[filePath, originalPathText] = []
|
||||
|
||||
beforeEach ->
|
||||
repo = new Git(path.join(__dirname, 'fixtures', 'git', 'working-dir'))
|
||||
filePath = require.resolve('./fixtures/git/working-dir/file.txt')
|
||||
originalPathText = fs.readFileSync(filePath, 'utf8')
|
||||
|
||||
afterEach ->
|
||||
fs.writeFileSync(filePath, originalPathText)
|
||||
|
||||
it "returns the number of lines added and deleted", ->
|
||||
expect(repo.getDiffStats(filePath)).toEqual {added: 0, deleted: 0}
|
||||
fs.writeFileSync(filePath, "#{originalPathText} edited line")
|
||||
expect(repo.getDiffStats(filePath)).toEqual {added: 1, deleted: 1}
|
||||
|
||||
describe ".getPathStatus(path)", ->
|
||||
[filePath, originalPathText] = []
|
||||
[filePath] = []
|
||||
|
||||
beforeEach ->
|
||||
repo = new Git(path.join(__dirname, 'fixtures', 'git', 'working-dir'))
|
||||
filePath = require.resolve('./fixtures/git/working-dir/file.txt')
|
||||
originalPathText = fs.readFileSync(filePath, 'utf8')
|
||||
|
||||
afterEach ->
|
||||
fs.writeFileSync(filePath, originalPathText)
|
||||
workingDirectory = copyRepository()
|
||||
repo = new Git(workingDirectory)
|
||||
filePath = path.join(workingDirectory, 'file.txt')
|
||||
|
||||
it "trigger a status-changed event when the new status differs from the last cached one", ->
|
||||
statusHandler = jasmine.createSpy("statusHandler")
|
||||
@@ -178,16 +146,13 @@ describe "Git", ->
|
||||
expect(statusHandler.callCount).toBe 1
|
||||
|
||||
describe ".getDirectoryStatus(path)", ->
|
||||
[directoryPath, filePath, originalPathText] = []
|
||||
[directoryPath, filePath] = []
|
||||
|
||||
beforeEach ->
|
||||
repo = new Git(path.join(__dirname, 'fixtures', 'git', 'working-dir'))
|
||||
directoryPath = path.join(__dirname, 'fixtures', 'git', 'working-dir', 'dir')
|
||||
filePath = require.resolve('./fixtures/git/working-dir/dir/b.txt')
|
||||
originalPathText = fs.readFileSync(filePath, 'utf8')
|
||||
|
||||
afterEach ->
|
||||
fs.writeFileSync(filePath, originalPathText)
|
||||
workingDirectory = copyRepository()
|
||||
repo = new Git(workingDirectory)
|
||||
directoryPath = path.join(workingDirectory, 'dir')
|
||||
filePath = path.join(directoryPath, 'b.txt')
|
||||
|
||||
it "gets the status based on the files inside the directory", ->
|
||||
expect(repo.isStatusModified(repo.getDirectoryStatus(directoryPath))).toBe false
|
||||
@@ -199,18 +164,15 @@ describe "Git", ->
|
||||
[newPath, modifiedPath, cleanPath, originalModifiedPathText] = []
|
||||
|
||||
beforeEach ->
|
||||
repo = new Git(path.join(__dirname, 'fixtures', 'git', 'working-dir'))
|
||||
modifiedPath = atom.project.resolve('git/working-dir/file.txt')
|
||||
originalModifiedPathText = fs.readFileSync(modifiedPath, 'utf8')
|
||||
newPath = atom.project.resolve('git/working-dir/untracked.txt')
|
||||
cleanPath = atom.project.resolve('git/working-dir/other.txt')
|
||||
workingDirectory = copyRepository()
|
||||
repo = new Git(workingDirectory)
|
||||
modifiedPath = path.join(workingDirectory, 'file.txt')
|
||||
newPath = path.join(workingDirectory, 'untracked.txt')
|
||||
cleanPath = path.join(workingDirectory, 'other.txt')
|
||||
fs.writeFileSync(cleanPath, 'Full of text')
|
||||
fs.writeFileSync(newPath, '')
|
||||
newPath = fs.absolute newPath # specs could be running under symbol path.
|
||||
|
||||
afterEach ->
|
||||
fs.writeFileSync(modifiedPath, originalModifiedPathText)
|
||||
fs.removeSync(newPath) if fs.existsSync(newPath)
|
||||
|
||||
it "returns status information for all new and modified files", ->
|
||||
fs.writeFileSync(modifiedPath, 'making this path modified')
|
||||
statusHandler = jasmine.createSpy('statusHandler')
|
||||
@@ -226,17 +188,13 @@ describe "Git", ->
|
||||
expect(repo.isStatusModified(repo.getCachedPathStatus(modifiedPath))).toBeTruthy()
|
||||
|
||||
describe "buffer events", ->
|
||||
[originalContent, editor] = []
|
||||
[editor] = []
|
||||
|
||||
beforeEach ->
|
||||
atom.project.setPath(copyRepository())
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.js').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
originalContent = editor.getText()
|
||||
|
||||
afterEach ->
|
||||
fs.writeFileSync(editor.getPath(), originalContent)
|
||||
atom.workspace.open('other.txt').then (o) -> editor = o
|
||||
|
||||
it "emits a status-changed event when a buffer is saved", ->
|
||||
editor.insertNewline()
|
||||
@@ -270,15 +228,16 @@ describe "Git", ->
|
||||
expect(statusHandler.callCount).toBe 1
|
||||
|
||||
describe "when a project is deserialized", ->
|
||||
[originalContent, buffer, project2] = []
|
||||
[buffer, project2] = []
|
||||
|
||||
afterEach ->
|
||||
fs.writeFileSync(buffer.getPath(), originalContent)
|
||||
project2?.destroy()
|
||||
|
||||
it "subscribes to all the serialized buffers in the project", ->
|
||||
atom.project.setPath(copyRepository())
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.js')
|
||||
atom.workspace.open('file.txt')
|
||||
|
||||
runs ->
|
||||
project2 = atom.project.testSerialization()
|
||||
|
||||
@@ -52,12 +52,17 @@ describe "LanguageMode", ->
|
||||
languageMode.toggleLineCommentsForBufferRows(0, 0)
|
||||
expect(buffer.lineForRow(0)).toBe " // "
|
||||
|
||||
buffer.setText (' a\n \n b')
|
||||
buffer.setText(' a\n \n b')
|
||||
languageMode.toggleLineCommentsForBufferRows(0, 2)
|
||||
expect(buffer.lineForRow(0)).toBe " // a"
|
||||
expect(buffer.lineForRow(1)).toBe " // "
|
||||
expect(buffer.lineForRow(2)).toBe " // b"
|
||||
|
||||
buffer.setText(' \n // var i;')
|
||||
languageMode.toggleLineCommentsForBufferRows(0, 1)
|
||||
expect(buffer.lineForRow(0)).toBe ' '
|
||||
expect(buffer.lineForRow(1)).toBe ' var i;'
|
||||
|
||||
describe ".rowRangeForCodeFoldAtBufferRow(bufferRow)", ->
|
||||
it "returns the start/end rows of the foldable region starting at the given row", ->
|
||||
expect(languageMode.rowRangeForCodeFoldAtBufferRow(0)).toEqual [0, 12]
|
||||
|
||||
@@ -16,6 +16,7 @@ describe "PaneContainer", ->
|
||||
containerA = new PaneContainer(root: pane1A)
|
||||
pane2A = pane1A.splitRight(items: [new Item])
|
||||
pane3A = pane2A.splitDown(items: [new Item])
|
||||
pane3A.focus()
|
||||
|
||||
it "preserves the focused pane across serialization", ->
|
||||
expect(pane3A.focused).toBe true
|
||||
|
||||
@@ -439,10 +439,11 @@ describe "Pane", ->
|
||||
expect(column.orientation).toBe 'vertical'
|
||||
expect(column.children).toEqual [pane1, pane3, pane2]
|
||||
|
||||
it "sets up the new pane to be focused", ->
|
||||
expect(pane1.focused).toBe false
|
||||
it "activates the new pane", ->
|
||||
expect(pane1.isActive()).toBe true
|
||||
pane2 = pane1.splitRight()
|
||||
expect(pane2.focused).toBe true
|
||||
expect(pane1.isActive()).toBe false
|
||||
expect(pane2.isActive()).toBe true
|
||||
|
||||
describe "::destroy()", ->
|
||||
[container, pane1, pane2] = []
|
||||
|
||||
@@ -166,7 +166,8 @@ describe "PaneView", ->
|
||||
it "removes the pane item", ->
|
||||
editor = null
|
||||
jasmine.unspy(window, 'setTimeout')
|
||||
filePath = temp.openSync('atom').path
|
||||
filePath = path.join(temp.mkdirSync(), 'file.txt')
|
||||
fs.writeFileSync(filePath, '')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(filePath).then (o) -> editor = o
|
||||
@@ -198,6 +199,7 @@ describe "PaneView", ->
|
||||
|
||||
it "focuses the next pane", ->
|
||||
container.attachToDom()
|
||||
pane2.activate()
|
||||
expect(pane.hasFocus()).toBe false
|
||||
expect(pane2.hasFocus()).toBe true
|
||||
pane2Model.destroy()
|
||||
|
||||
@@ -156,11 +156,20 @@ describe "Project", ->
|
||||
expect(atom.project.resolve('a')).toBe absolutePath
|
||||
expect(atom.project.resolve(absolutePath + '/../a')).toBe absolutePath
|
||||
expect(atom.project.resolve('a/../a')).toBe absolutePath
|
||||
expect(atom.project.resolve()).toBeUndefined()
|
||||
|
||||
describe "when passed a uri with a scheme", ->
|
||||
it "does not modify uris that begin with a scheme", ->
|
||||
expect(atom.project.resolve('http://zombo.com')).toBe 'http://zombo.com'
|
||||
|
||||
describe "when the project has no path", ->
|
||||
it "returns undefined for relative URIs", ->
|
||||
atom.project.setPath()
|
||||
expect(atom.project.resolve('test.txt')).toBeUndefined()
|
||||
expect(atom.project.resolve('http://github.com')).toBe 'http://github.com'
|
||||
absolutePath = fs.absolute(__dirname)
|
||||
expect(atom.project.resolve(absolutePath)).toBe absolutePath
|
||||
|
||||
describe ".setPath(path)", ->
|
||||
describe "when path is a file", ->
|
||||
it "sets its path to the files parent directory and updates the root directory", ->
|
||||
|
||||
@@ -24,19 +24,6 @@ describe "SpacePen extensions", ->
|
||||
expect(eventHandler).toHaveBeenCalled()
|
||||
|
||||
describe "tooltips", ->
|
||||
describe "humanizeKeystrokes", ->
|
||||
humanizeKeystrokes = $.fn.setTooltip.humanizeKeystrokes
|
||||
|
||||
it "replaces single keystroke", ->
|
||||
expect(humanizeKeystrokes('cmd-O')).toEqual '⌘⇧O'
|
||||
expect(humanizeKeystrokes('cmd-shift-up')).toEqual '⌘⇧↑'
|
||||
expect(humanizeKeystrokes('cmd-option-down')).toEqual '⌘⌥↓'
|
||||
expect(humanizeKeystrokes('cmd-option-left')).toEqual '⌘⌥←'
|
||||
expect(humanizeKeystrokes('cmd-option-right')).toEqual '⌘⌥→'
|
||||
|
||||
it "replaces multiple keystroke", ->
|
||||
expect(humanizeKeystrokes('cmd-o ctrl-2')).toEqual '⌘O ⌃2'
|
||||
|
||||
describe "when the window is resized", ->
|
||||
it "hides the tooltips", ->
|
||||
class TooltipView extends View
|
||||
|
||||
@@ -14,8 +14,8 @@ try
|
||||
|
||||
{runSpecSuite} = require './jasmine-helper'
|
||||
|
||||
# Add 'src/exports' to module search path.
|
||||
exportsPath = path.resolve(atom.getLoadSettings().resourcePath, 'exports')
|
||||
# Add 'exports' to module search path.
|
||||
exportsPath = path.join(atom.getLoadSettings().resourcePath, 'exports')
|
||||
require('module').globalPaths.push(exportsPath)
|
||||
# Still set NODE_PATH since tasks may need it.
|
||||
process.env.NODE_PATH = exportsPath
|
||||
|
||||
@@ -15,6 +15,7 @@ Project = require '../src/project'
|
||||
Editor = require '../src/editor'
|
||||
EditorView = require '../src/editor-view'
|
||||
TokenizedBuffer = require '../src/tokenized-buffer'
|
||||
EditorComponent = require '../src/editor-component'
|
||||
pathwatcher = require 'pathwatcher'
|
||||
clipboard = require 'clipboard'
|
||||
|
||||
@@ -33,7 +34,12 @@ $(window).on 'unload', ->
|
||||
$('html,body').css('overflow', 'auto')
|
||||
|
||||
jasmine.getEnv().addEqualityTester(_.isEqual) # Use underscore's definition of equality for toEqual assertions
|
||||
jasmine.getEnv().defaultTimeoutInterval = 5000
|
||||
|
||||
if process.platform is 'win32' and process.env.JANKY_SHA1
|
||||
# Use longer timeout on Windows CI
|
||||
jasmine.getEnv().defaultTimeoutInterval = 30000
|
||||
else
|
||||
jasmine.getEnv().defaultTimeoutInterval = 5000
|
||||
|
||||
specPackageName = null
|
||||
specPackagePath = null
|
||||
@@ -89,12 +95,14 @@ beforeEach ->
|
||||
config.set "editor.autoIndent", false
|
||||
config.set "core.disabledPackages", ["package-that-throws-an-exception",
|
||||
"package-with-broken-package-json", "package-with-broken-keymap"]
|
||||
config.set "core.useReactEditor", false
|
||||
config.set "core.useReactEditor", true
|
||||
config.save.reset()
|
||||
atom.config = config
|
||||
|
||||
# make editor display updates synchronous
|
||||
spyOn(EditorView.prototype, 'requestDisplayUpdate').andCallFake -> @updateDisplay()
|
||||
EditorComponent.performSyncUpdates = true
|
||||
|
||||
spyOn(WorkspaceView.prototype, 'setTitle').andCallFake (@title) ->
|
||||
spyOn(window, "setTimeout").andCallFake window.fakeSetTimeout
|
||||
spyOn(window, "clearTimeout").andCallFake window.fakeClearTimeout
|
||||
@@ -261,7 +269,9 @@ window.waitsForPromise = (args...) ->
|
||||
window.resetTimeouts = ->
|
||||
window.now = 0
|
||||
window.timeoutCount = 0
|
||||
window.intervalCount = 0
|
||||
window.timeouts = []
|
||||
window.intervalTimeouts = {}
|
||||
|
||||
window.fakeSetTimeout = (callback, ms) ->
|
||||
id = ++window.timeoutCount
|
||||
@@ -272,13 +282,15 @@ window.fakeClearTimeout = (idToClear) ->
|
||||
window.timeouts = window.timeouts.filter ([id]) -> id != idToClear
|
||||
|
||||
window.fakeSetInterval = (callback, ms) ->
|
||||
id = ++window.intervalCount
|
||||
action = ->
|
||||
callback()
|
||||
window.fakeSetTimeout(action, ms)
|
||||
window.fakeSetTimeout(action, ms)
|
||||
window.intervalTimeouts[id] = window.fakeSetTimeout(action, ms)
|
||||
window.intervalTimeouts[id] = window.fakeSetTimeout(action, ms)
|
||||
id
|
||||
|
||||
window.fakeClearInterval = (idToClear) ->
|
||||
window.fakeClearTimeout(idToClear)
|
||||
window.fakeClearTimeout(@intervalTimeouts[idToClear])
|
||||
|
||||
window.advanceClock = (delta=1) ->
|
||||
window.now += delta
|
||||
|
||||
@@ -27,10 +27,8 @@ setSpecDirectory = (specDirectory) ->
|
||||
runAllSpecs = ->
|
||||
{resourcePath} = atom.getLoadSettings()
|
||||
|
||||
# Only run core specs when resource path is the Atom repository
|
||||
if Git.exists(resourcePath)
|
||||
requireSpecs(path.join(resourcePath, 'spec'))
|
||||
setSpecType('core')
|
||||
requireSpecs(path.join(resourcePath, 'spec'))
|
||||
setSpecType('core')
|
||||
|
||||
fixturesPackagesPath = path.join(__dirname, 'fixtures', 'packages')
|
||||
packagePaths = atom.packages.getAvailablePackageNames().map (packageName) ->
|
||||
|
||||
@@ -20,7 +20,7 @@ describe "ThemeManager", ->
|
||||
|
||||
describe "theme getters and setters", ->
|
||||
beforeEach ->
|
||||
atom.packages.loadPackages(sync: true)
|
||||
atom.packages.loadPackages()
|
||||
|
||||
it 'getLoadedThemes get all the loaded themes', ->
|
||||
themes = themeManager.getLoadedThemes()
|
||||
@@ -280,15 +280,17 @@ describe "ThemeManager", ->
|
||||
|
||||
describe "when a non-existent theme is present in the config", ->
|
||||
it "logs a warning but does not throw an exception (regression)", ->
|
||||
reloaded = false
|
||||
|
||||
waitsForPromise ->
|
||||
themeManager.activateThemes()
|
||||
|
||||
runs ->
|
||||
themeManager.once 'reloaded', -> reloaded = true
|
||||
spyOn(console, 'warn')
|
||||
expect(-> atom.config.set('core.themes', ['atom-light-ui', 'theme-really-does-not-exist'])).not.toThrow()
|
||||
|
||||
waitsFor (done) ->
|
||||
themeManager.once 'reloaded', done
|
||||
waitsFor -> reloaded
|
||||
|
||||
runs ->
|
||||
expect(console.warn.callCount).toBe 1
|
||||
|
||||
@@ -344,6 +344,73 @@ describe "TokenizedBuffer", ->
|
||||
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).text).toBe "#{tabAsSpaces} buy()#{tabAsSpaces}while supply > demand"
|
||||
|
||||
it "aligns the hard tabs to the correct tab stop column", ->
|
||||
buffer.setText """
|
||||
1\t2 \t3\t4
|
||||
12\t3 \t4\t5
|
||||
123\t4 \t5\t6
|
||||
"""
|
||||
|
||||
tokenizedBuffer.setTabLength(4)
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).text).toBe "1 2 3 4"
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].bufferDelta).toBe 1
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].screenDelta).toBe 3
|
||||
|
||||
expect(tokenizedBuffer.lineForScreenRow(1).text).toBe "12 3 4 5"
|
||||
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].bufferDelta).toBe 1
|
||||
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].screenDelta).toBe 2
|
||||
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).text).toBe "123 4 5 6"
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].bufferDelta).toBe 1
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].screenDelta).toBe 1
|
||||
|
||||
tokenizedBuffer.setTabLength(3)
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).text).toBe "1 2 3 4"
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].bufferDelta).toBe 1
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].screenDelta).toBe 2
|
||||
|
||||
expect(tokenizedBuffer.lineForScreenRow(1).text).toBe "12 3 4 5"
|
||||
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].bufferDelta).toBe 1
|
||||
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].screenDelta).toBe 1
|
||||
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).text).toBe "123 4 5 6"
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].bufferDelta).toBe 1
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].screenDelta).toBe 3
|
||||
|
||||
tokenizedBuffer.setTabLength(2)
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).text).toBe "1 2 3 4"
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].bufferDelta).toBe 1
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].screenDelta).toBe 1
|
||||
|
||||
expect(tokenizedBuffer.lineForScreenRow(1).text).toBe "12 3 4 5"
|
||||
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].bufferDelta).toBe 1
|
||||
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].screenDelta).toBe 2
|
||||
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).text).toBe "123 4 5 6"
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].bufferDelta).toBe 1
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].screenDelta).toBe 1
|
||||
|
||||
tokenizedBuffer.setTabLength(1)
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).text).toBe "1 2 3 4"
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].bufferDelta).toBe 1
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].screenDelta).toBe 1
|
||||
|
||||
expect(tokenizedBuffer.lineForScreenRow(1).text).toBe "12 3 4 5"
|
||||
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].bufferDelta).toBe 1
|
||||
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].screenDelta).toBe 1
|
||||
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).text).toBe "123 4 5 6"
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].bufferDelta).toBe 1
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].screenDelta).toBe 1
|
||||
|
||||
describe "when the buffer contains surrogate pairs", ->
|
||||
beforeEach ->
|
||||
waitsForPromise ->
|
||||
@@ -385,7 +452,58 @@ describe "TokenizedBuffer", ->
|
||||
expect(tokens[1].value).toBeTruthy()
|
||||
expect(tokens[2].value).toBe 'xyz'
|
||||
|
||||
describe "when the grammar is tokenized", ->
|
||||
it "emits the `tokenized` event", ->
|
||||
editor = null
|
||||
tokenizedHandler = jasmine.createSpy("tokenized handler")
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample.js').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
tokenizedBuffer = editor.displayBuffer.tokenizedBuffer
|
||||
tokenizedBuffer.on 'tokenized', tokenizedHandler
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
expect(tokenizedHandler.callCount).toBe(1)
|
||||
|
||||
it "doesn't re-emit the `tokenized` event when it is re-tokenized", ->
|
||||
editor = null
|
||||
tokenizedHandler = jasmine.createSpy("tokenized handler")
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample.js').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
tokenizedBuffer = editor.displayBuffer.tokenizedBuffer
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
|
||||
tokenizedBuffer.on 'tokenized', tokenizedHandler
|
||||
editor.getBuffer().insert([0, 0], "'")
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
expect(tokenizedHandler).not.toHaveBeenCalled()
|
||||
|
||||
describe "when the grammar is updated because a grammar it includes is activated", ->
|
||||
it "re-emits the `tokenized` event", ->
|
||||
editor = null
|
||||
tokenizedBuffer = null
|
||||
tokenizedHandler = jasmine.createSpy("tokenized handler")
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('coffee.coffee').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
tokenizedBuffer = editor.displayBuffer.tokenizedBuffer
|
||||
tokenizedBuffer.on 'tokenized', tokenizedHandler
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
tokenizedHandler.reset()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-coffee-script')
|
||||
|
||||
runs ->
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
expect(tokenizedHandler.callCount).toBe(1)
|
||||
|
||||
it "retokenizes the buffer", ->
|
||||
|
||||
waitsForPromise ->
|
||||
|
||||
@@ -196,12 +196,14 @@ describe "WorkspaceView", ->
|
||||
atom.workspaceView.height(200)
|
||||
atom.workspaceView.attachToDom()
|
||||
rightEditorView = atom.workspaceView.getActiveView()
|
||||
rightEditorView.getEditor().setText(" \t ")
|
||||
rightEditorView.getEditor().setText("\t ")
|
||||
leftEditorView = rightEditorView.splitLeft()
|
||||
expect(rightEditorView.find(".line:first").text()).toBe " "
|
||||
expect(leftEditorView.find(".line:first").text()).toBe " "
|
||||
|
||||
withInvisiblesShowing = "#{rightEditorView.invisibles.space}#{rightEditorView.invisibles.tab} #{rightEditorView.invisibles.space}#{rightEditorView.invisibles.eol}"
|
||||
{invisibles} = rightEditorView.component.state
|
||||
{space, tab, eol} = invisibles
|
||||
withInvisiblesShowing = "#{tab} #{space}#{space}#{eol}"
|
||||
|
||||
atom.workspaceView.trigger "window:toggle-invisibles"
|
||||
expect(rightEditorView.find(".line:first").text()).toBe withInvisiblesShowing
|
||||
|
||||
+17
-10
@@ -24,7 +24,7 @@ WindowEventHandler = require './window-event-handler'
|
||||
# * `atom.config` - A {Config} instance
|
||||
# * `atom.contextMenu` - A {ContextMenuManager} instance
|
||||
# * `atom.deserializers` - A {DeserializerManager} instance
|
||||
# * `atom.keymaps` - A {Keymap} instance
|
||||
# * `atom.keymaps` - A {KeymapManager} instance
|
||||
# * `atom.menu` - A {MenuManager} instance
|
||||
# * `atom.packages` - A {PackageManager} instance
|
||||
# * `atom.project` - A {Project} instance
|
||||
@@ -38,8 +38,8 @@ class Atom extends Model
|
||||
|
||||
# Public: Load or create the Atom environment in the given mode.
|
||||
#
|
||||
# - mode: Pass 'editor' or 'spec' depending on the kind of environment you
|
||||
# want to build.
|
||||
# mode - Pass 'editor' or 'spec' depending on the kind of environment you
|
||||
# want to build.
|
||||
#
|
||||
# Returns an Atom instance, fully initialized
|
||||
@loadOrCreate: (mode) ->
|
||||
@@ -135,6 +135,13 @@ class Atom extends Model
|
||||
@executeJavaScriptInDevTools('InspectorFrontendAPI.showConsole()')
|
||||
@emit 'uncaught-error', arguments...
|
||||
|
||||
nativeConsoleError = console.error
|
||||
|
||||
console.error = =>
|
||||
@openDevTools()
|
||||
@executeJavaScriptInDevTools('InspectorFrontendAPI.showConsole()')
|
||||
nativeConsoleError.call console, arguments...
|
||||
|
||||
@unsubscribe()
|
||||
@setBodyPlatformClass()
|
||||
|
||||
@@ -151,8 +158,8 @@ class Atom extends Model
|
||||
{devMode, safeMode, resourcePath} = @getLoadSettings()
|
||||
configDirPath = @getConfigDirPath()
|
||||
|
||||
# Add 'src/exports' to module search path.
|
||||
exportsPath = path.resolve(resourcePath, 'exports')
|
||||
# Add 'exports' to module search path.
|
||||
exportsPath = path.join(resourcePath, 'exports')
|
||||
require('module').globalPaths.push(exportsPath)
|
||||
# Still set NODE_PATH since tasks may need it.
|
||||
process.env.NODE_PATH = exportsPath
|
||||
@@ -212,11 +219,11 @@ class Atom extends Model
|
||||
# in the dimensions parameter. If x or y are omitted the window will be
|
||||
# centered. If height or width are omitted only the position will be changed.
|
||||
#
|
||||
# * dimensions:
|
||||
# + x: The new x coordinate.
|
||||
# + y: The new y coordinate.
|
||||
# + width: The new width.
|
||||
# + height: The new height.
|
||||
# dimensions - An {Object} with the following keys:
|
||||
# :x - The new x coordinate.
|
||||
# :y - The new y coordinate.
|
||||
# :width - The new width.
|
||||
# :height - The new height.
|
||||
setWindowDimensions: ({x, y, width, height}) ->
|
||||
if width? and height?
|
||||
@setSize(width, height)
|
||||
|
||||
@@ -60,6 +60,10 @@ class AtomApplication
|
||||
|
||||
constructor: (options) ->
|
||||
{@resourcePath, @version, @devMode, @safeMode} = options
|
||||
|
||||
# Normalize to make sure drive letter case is consistent on Windows
|
||||
@resourcePath = path.normalize(@resourcePath) if @resourcePath
|
||||
|
||||
global.atomApplication = this
|
||||
|
||||
@pidsToOpenWindows = {}
|
||||
@@ -306,13 +310,7 @@ class AtomApplication
|
||||
# :safeMode - Boolean to control the opened window's safe mode.
|
||||
# :windowDimensions - Object with height and width keys.
|
||||
openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, windowDimensions}={}) ->
|
||||
if pathToOpen
|
||||
[basename, initialLine, initialColumn] = path.basename(pathToOpen).split(':')
|
||||
pathToOpen = path.join(path.dirname(pathToOpen), basename) if initialLine
|
||||
|
||||
# Convert line numbers to a base of 0
|
||||
initialLine -= 1 if initialLine
|
||||
initialColumn -= 1 if initialColumn
|
||||
{pathToOpen, initialLine, initialColumn} = @locationForPathToOpen(pathToOpen)
|
||||
|
||||
unless devMode
|
||||
existingWindow = @windowForPath(pathToOpen) unless pidToKillWhenClosed or newWindow
|
||||
@@ -415,6 +413,20 @@ class AtomApplication
|
||||
isSpec = true
|
||||
new AtomWindow({bootstrapScript, @resourcePath, isSpec})
|
||||
|
||||
locationForPathToOpen: (pathToOpen) ->
|
||||
return {pathToOpen} unless pathToOpen
|
||||
return {pathToOpen} if fs.existsSync(pathToOpen)
|
||||
|
||||
[fileToOpen, initialLine, initialColumn] = path.basename(pathToOpen).split(':')
|
||||
return {pathToOpen} unless initialLine
|
||||
return {pathToOpen} unless parseInt(initialLine) > 0
|
||||
|
||||
# Convert line numbers to a base of 0
|
||||
initialLine -= 1 if initialLine
|
||||
initialColumn -= 1 if initialColumn
|
||||
pathToOpen = path.join(path.dirname(pathToOpen), fileToOpen)
|
||||
{pathToOpen, initialLine, initialColumn}
|
||||
|
||||
# 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.
|
||||
|
||||
@@ -21,6 +21,10 @@ class AtomWindow
|
||||
|
||||
constructor: (settings={}) ->
|
||||
{@resourcePath, pathToOpen, initialLine, initialColumn, @isSpec, @exitWhenDone} = settings
|
||||
|
||||
# Normalize to make sure drive letter case is consistent on Windows
|
||||
@resourcePath = path.normalize(@resourcePath) if @resourcePath
|
||||
|
||||
global.atomApplication.addWindow(this)
|
||||
|
||||
@browserWindow = new BrowserWindow show: false, title: 'Atom', icon: @constructor.iconPath
|
||||
@@ -29,6 +33,7 @@ class AtomWindow
|
||||
loadSettings = _.extend({}, settings)
|
||||
loadSettings.windowState ?= '{}'
|
||||
loadSettings.appVersion = app.getVersion()
|
||||
loadSettings.resourcePath = @resourcePath
|
||||
|
||||
# Only send to the first non-spec window created
|
||||
if @constructor.includeShellLoadTime and not @isSpec
|
||||
@@ -109,9 +114,15 @@ class AtomWindow
|
||||
new ContextMenu(menuTemplate, this)
|
||||
|
||||
if @isSpec
|
||||
# Workaround for https://github.com/atom/atom-shell/issues/380
|
||||
# Don't focus the window when it is being blurred during close or
|
||||
# else the app will crash on Windows.
|
||||
if process.platform is 'win32'
|
||||
@browserWindow.on 'close', => @isWindowClosing = true
|
||||
|
||||
# Spec window's web view should always have focus
|
||||
@browserWindow.on 'blur', =>
|
||||
@browserWindow.focusOnWebView()
|
||||
@browserWindow.focusOnWebView() unless @isWindowClosing
|
||||
|
||||
openPath: (pathToOpen, initialLine, initialColumn) ->
|
||||
if @loaded
|
||||
|
||||
@@ -19,4 +19,6 @@ class ContextMenu
|
||||
do (item) =>
|
||||
item.click = =>
|
||||
global.atomApplication.sendCommandToWindow(item.command, @atomWindow, item.commandOptions)
|
||||
else if item.submenu
|
||||
@createClickHandlers(item.submenu)
|
||||
item
|
||||
|
||||
@@ -54,7 +54,9 @@ start = ->
|
||||
AtomApplication.open(args)
|
||||
console.log("App load time: #{Date.now() - global.shellStartTime}ms") unless args.test
|
||||
|
||||
global.devResourcePath = path.join(app.getHomeDir(), 'github', 'atom')
|
||||
global.devResourcePath = process.env.ATOM_DEV_RESOURCE_PATH ? path.join(app.getHomeDir(), 'github', 'atom')
|
||||
# Normalize to make sure drive letter case is consistent on Windows
|
||||
global.devResourcePath = path.normalize(global.devResourcePath) if global.devResourcePath
|
||||
|
||||
setupCrashReporter = ->
|
||||
crashReporter.start(productName: 'Atom', companyName: 'GitHub')
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
_ = require 'underscore-plus'
|
||||
ChildProcess = require 'child_process'
|
||||
|
||||
# Public: A wrapper which provides standard error/output line buffering for
|
||||
@@ -43,8 +44,13 @@ class BufferedProcess
|
||||
# process and will just orphan it. Does not escape ^ (cmd's escape symbol).
|
||||
# Related to joyent/node#2318
|
||||
if process.platform is "win32"
|
||||
@process = ChildProcess.spawn(process.env.comspec || "cmd.exe",
|
||||
[ "/c", command ].concat(args), options)
|
||||
# Quote all arguments and escapes inner quotes
|
||||
cmdArgs = args.map (arg) -> "\"#{arg.replace(/"/g, '\\"')}\""
|
||||
cmdArgs.unshift("\"#{command}\"")
|
||||
cmdArgs = ['/s', '/c', "\"#{cmdArgs.join(' ')}\""]
|
||||
cmdOptions = _.clone(options)
|
||||
cmdOptions.windowsVerbatimArguments = true
|
||||
@process = ChildProcess.spawn(process.env.comspec or 'cmd.exe', cmdArgs, cmdOptions)
|
||||
else
|
||||
@process = ChildProcess.spawn(command, args, options)
|
||||
@killed = false
|
||||
|
||||
@@ -33,8 +33,21 @@ class ContextMenuManager
|
||||
# Returns nothing.
|
||||
add: (name, object, {devMode}={}) ->
|
||||
for selector, items of object
|
||||
for label, command of items
|
||||
@addBySelector(selector, {label, command}, {devMode})
|
||||
for label, commandOrSubmenu of items
|
||||
if typeof commandOrSubmenu is 'object'
|
||||
submenu = []
|
||||
for submenuLabel, command of commandOrSubmenu
|
||||
submenu.push(@buildMenuItem(submenuLabel, command))
|
||||
@addBySelector(selector, {label: label, submenu: submenu}, {devMode})
|
||||
else
|
||||
menuItem = @buildMenuItem(label, commandOrSubmenu)
|
||||
@addBySelector(selector, menuItem, {devMode})
|
||||
|
||||
buildMenuItem: (label, command) ->
|
||||
if label is command is '-'
|
||||
{type: 'separator'}
|
||||
else
|
||||
{label, command}
|
||||
|
||||
# Registers a command to be displayed when the relevant item is right
|
||||
# clicked.
|
||||
@@ -98,5 +111,6 @@ class ContextMenuManager
|
||||
showForEvent: (event) ->
|
||||
@activeElement = event.target
|
||||
menuTemplate = @combinedMenuTemplateForElement(event.target)
|
||||
return unless menuTemplate?.length > 0
|
||||
@executeBuildHandlers(event, menuTemplate)
|
||||
remote.getCurrentWindow().emit('context-menu', menuTemplate)
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
React = require 'react'
|
||||
{div} = require 'reactionary'
|
||||
React = require 'react-atom-fork'
|
||||
{div} = require 'reactionary-atom-fork'
|
||||
|
||||
module.exports =
|
||||
CursorComponent = React.createClass
|
||||
displayName: 'CursorComponent'
|
||||
|
||||
render: ->
|
||||
{top, left, height, width} = @props.cursor.getPixelRect()
|
||||
className = 'cursor'
|
||||
className += ' blink-off' if @props.blinkOff
|
||||
{editor, screenRange, scrollTop, scrollLeft, defaultCharWidth} = @props
|
||||
{top, left, height, width} = editor.pixelRectForScreenRange(screenRange)
|
||||
top -= scrollTop
|
||||
left -= scrollLeft
|
||||
width = defaultCharWidth if width is 0
|
||||
WebkitTransform = "translate3d(#{left}px, #{top}px, 0px)"
|
||||
|
||||
div className: className, style: {top, left, height, width}
|
||||
div className: 'cursor', style: {height, width, WebkitTransform}
|
||||
|
||||
+39
-1
@@ -114,9 +114,10 @@ class Cursor extends Model
|
||||
|
||||
# Public: Get the RegExp used by the cursor to determine what a "word" is.
|
||||
#
|
||||
# options: An {Object} with the following keys:
|
||||
# options: An optional {Object} with the following keys:
|
||||
# :includeNonWordCharacters - A {Boolean} indicating whether to include
|
||||
# non-word characters in the regex.
|
||||
# (default: true)
|
||||
#
|
||||
# Returns a {RegExp}.
|
||||
wordRegExp: ({includeNonWordCharacters}={})->
|
||||
@@ -457,6 +458,43 @@ class Cursor extends Model
|
||||
getCurrentLineBufferRange: (options) ->
|
||||
@editor.bufferRangeForBufferRow(@getBufferRow(), options)
|
||||
|
||||
# Public: Moves the cursor to the beginning of the next paragraph
|
||||
moveToBeginningOfNextParagraph: ->
|
||||
if position = @getBeginningOfNextParagraphBufferPosition()
|
||||
@setBufferPosition(position)
|
||||
|
||||
# Public: Moves the cursor to the beginning of the previous paragraph
|
||||
moveToBeginningOfPreviousParagraph: ->
|
||||
if position = @getBeginningOfPreviousParagraphBufferPosition()
|
||||
@setBufferPosition(position)
|
||||
|
||||
getBeginningOfNextParagraphBufferPosition: (editor) ->
|
||||
start = @getBufferPosition()
|
||||
eof = @editor.getEofBufferPosition()
|
||||
scanRange = [start, eof]
|
||||
|
||||
{row, column} = eof
|
||||
position = new Point(row, column - 1)
|
||||
|
||||
@editor.scanInBufferRange /^\n*$/g, scanRange, ({range, stop}) =>
|
||||
if !range.start.isEqual(start)
|
||||
position = range.start
|
||||
stop()
|
||||
@editor.screenPositionForBufferPosition(position)
|
||||
|
||||
getBeginningOfPreviousParagraphBufferPosition: (editor) ->
|
||||
start = @editor.getCursorBufferPosition()
|
||||
|
||||
{row, column} = start
|
||||
scanRange = [[row-1, column], [0,0]]
|
||||
position = new Point(0, 0)
|
||||
zero = new Point(0,0)
|
||||
@editor.backwardsScanInBufferRange /^\n*$/g, scanRange, ({range, stop}) =>
|
||||
if !range.start.isEqual(zero)
|
||||
position = range.start
|
||||
stop()
|
||||
@editor.screenPositionForBufferPosition(position)
|
||||
|
||||
# Public: Retrieves the range for the current paragraph.
|
||||
#
|
||||
# A paragraph is defined as a block of text surrounded by empty lines.
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
React = require 'react'
|
||||
{div} = require 'reactionary'
|
||||
{debounce} = require 'underscore-plus'
|
||||
React = require 'react-atom-fork'
|
||||
{div} = require 'reactionary-atom-fork'
|
||||
{debounce, toArray, isEqualForProperties, isEqual} = require 'underscore-plus'
|
||||
SubscriberMixin = require './subscriber-mixin'
|
||||
CursorComponent = require './cursor-component'
|
||||
|
||||
|
||||
module.exports =
|
||||
CursorsComponent = React.createClass
|
||||
displayName: 'CursorsComponent'
|
||||
@@ -13,38 +12,49 @@ CursorsComponent = React.createClass
|
||||
cursorBlinkIntervalHandle: null
|
||||
|
||||
render: ->
|
||||
{editor} = @props
|
||||
blinkOff = @state.blinkCursorsOff
|
||||
{editor, cursorScreenRanges, scrollTop, scrollLeft, defaultCharWidth} = @props
|
||||
{blinkOff} = @state
|
||||
|
||||
div className: 'cursors',
|
||||
className = 'cursors'
|
||||
className += ' blink-off' if blinkOff
|
||||
|
||||
div {className},
|
||||
if @isMounted()
|
||||
for selection in editor.getSelections()
|
||||
if selection.isEmpty() and editor.selectionIntersectsVisibleRowRange(selection)
|
||||
{cursor} = selection
|
||||
CursorComponent({key: cursor.id, cursor, blinkOff})
|
||||
for key, screenRange of cursorScreenRanges
|
||||
CursorComponent({key, editor, screenRange, scrollTop, scrollLeft, defaultCharWidth})
|
||||
|
||||
getInitialState: ->
|
||||
blinkCursorsOff: false
|
||||
blinkOff: false
|
||||
|
||||
componentDidMount: ->
|
||||
{editor} = @props
|
||||
@startBlinkingCursors()
|
||||
|
||||
componentWillUnmount: ->
|
||||
clearInterval(@cursorBlinkIntervalHandle)
|
||||
@stopBlinkingCursors()
|
||||
|
||||
componentWillUpdate: ({cursorsMoved}) ->
|
||||
@pauseCursorBlinking() if cursorsMoved
|
||||
shouldComponentUpdate: (newProps, newState) ->
|
||||
not newState.blinkOff is @state.blinkOff or
|
||||
not isEqualForProperties(newProps, @props,
|
||||
'cursorScreenRanges', 'scrollTop', 'scrollLeft', 'lineHeightInPixels',
|
||||
'defaultCharWidth', 'scopedCharacterWidthsChangeCount'
|
||||
)
|
||||
|
||||
componentWillUpdate: (newProps) ->
|
||||
@pauseCursorBlinking() if @props.cursorScreenRanges and not isEqual(newProps.cursorScreenRanges, @props.cursorScreenRanges)
|
||||
|
||||
startBlinkingCursors: ->
|
||||
@cursorBlinkIntervalHandle = setInterval(@toggleCursorBlink, @props.cursorBlinkPeriod / 2)
|
||||
@toggleCursorBlinkHandle = setInterval(@toggleCursorBlink, @props.cursorBlinkPeriod / 2) if @isMounted()
|
||||
|
||||
startBlinkingCursorsAfterDelay: null # Created lazily
|
||||
|
||||
toggleCursorBlink: -> @setState(blinkCursorsOff: not @state.blinkCursorsOff)
|
||||
stopBlinkingCursors: ->
|
||||
clearInterval(@toggleCursorBlinkHandle)
|
||||
|
||||
toggleCursorBlink: ->
|
||||
@setState(blinkOff: not @state.blinkOff)
|
||||
|
||||
pauseCursorBlinking: ->
|
||||
@state.blinkCursorsOff = false
|
||||
clearInterval(@cursorBlinkIntervalHandle)
|
||||
@state.blinkOff = false
|
||||
@stopBlinkingCursors()
|
||||
@startBlinkingCursorsAfterDelay ?= debounce(@startBlinkingCursors, @props.cursorBlinkResumeDelay)
|
||||
@startBlinkingCursorsAfterDelay()
|
||||
|
||||
@@ -111,6 +111,34 @@ class DisplayBufferMarker
|
||||
setTailBufferPosition: (bufferPosition) ->
|
||||
@bufferMarker.setTailPosition(bufferPosition)
|
||||
|
||||
# Retrieves the screen position of the marker's start. This will always be
|
||||
# less than or equal to the result of {DisplayBufferMarker::getEndScreenPosition}.
|
||||
#
|
||||
# Returns a {Point}.
|
||||
getStartScreenPosition: ->
|
||||
@displayBuffer.screenPositionForBufferPosition(@getStartBufferPosition(), wrapAtSoftNewlines: true)
|
||||
|
||||
# Retrieves the buffer position of the marker's start. This will always be
|
||||
# less than or equal to the result of {DisplayBufferMarker::getEndBufferPosition}.
|
||||
#
|
||||
# Returns a {Point}.
|
||||
getStartBufferPosition: ->
|
||||
@bufferMarker.getStartPosition()
|
||||
|
||||
# Retrieves the screen position of the marker's end. This will always be
|
||||
# greater than or equal to the result of {DisplayBufferMarker::getStartScreenPosition}.
|
||||
#
|
||||
# Returns a {Point}.
|
||||
getEndScreenPosition: ->
|
||||
@displayBuffer.screenPositionForBufferPosition(@getEndBufferPosition(), wrapAtSoftNewlines: true)
|
||||
|
||||
# Retrieves the buffer position of the marker's end. This will always be
|
||||
# greater than or equal to the result of {DisplayBufferMarker::getStartBufferPosition}.
|
||||
#
|
||||
# Returns a {Point}.
|
||||
getEndBufferPosition: ->
|
||||
@bufferMarker.getEndPosition()
|
||||
|
||||
# Sets the marker's tail to the same position as the marker's head.
|
||||
#
|
||||
# This only works if there isn't already a tail position.
|
||||
|
||||
+120
-26
@@ -23,7 +23,7 @@ class DisplayBuffer extends Model
|
||||
manageScrollPosition: false
|
||||
softWrap: null
|
||||
editorWidthInChars: null
|
||||
lineHeight: null
|
||||
lineHeightInPixels: null
|
||||
defaultCharWidth: null
|
||||
height: null
|
||||
width: null
|
||||
@@ -34,6 +34,7 @@ class DisplayBuffer extends Model
|
||||
horizontalScrollMargin: 6
|
||||
horizontalScrollbarHeight: 15
|
||||
verticalScrollbarWidth: 15
|
||||
scopedCharacterWidthsChangeCount: 0
|
||||
|
||||
constructor: ({tabLength, @editorWidthInChars, @tokenizedBuffer, buffer}={}) ->
|
||||
super
|
||||
@@ -43,9 +44,12 @@ class DisplayBuffer extends Model
|
||||
@charWidthsByScope = {}
|
||||
@markers = {}
|
||||
@foldsByMarkerId = {}
|
||||
@decorationsByMarkerId = {}
|
||||
@decorationMarkerSubscriptions = {}
|
||||
@updateAllScreenLines()
|
||||
@createFoldForMarker(marker) for marker in @buffer.findMarkers(@getFoldMarkerAttributes())
|
||||
@subscribe @tokenizedBuffer, 'grammar-changed', (grammar) => @emit 'grammar-changed', grammar
|
||||
@subscribe @tokenizedBuffer, 'tokenized', => @emit 'tokenized'
|
||||
@subscribe @tokenizedBuffer, 'changed', @handleTokenizedBufferChange
|
||||
@subscribe @buffer, 'markers-updated', @handleBufferMarkersUpdated
|
||||
@subscribe @buffer, 'marker-created', @handleBufferMarkerCreated
|
||||
@@ -198,8 +202,8 @@ class DisplayBuffer extends Model
|
||||
@setScrollLeft(scrollRight - @width)
|
||||
@getScrollRight()
|
||||
|
||||
getLineHeight: -> @lineHeight
|
||||
setLineHeight: (@lineHeight) -> @lineHeight
|
||||
getLineHeightInPixels: -> @lineHeightInPixels
|
||||
setLineHeightInPixels: (@lineHeightInPixels) -> @lineHeightInPixels
|
||||
|
||||
getDefaultCharWidth: -> @defaultCharWidth
|
||||
setDefaultCharWidth: (@defaultCharWidth) -> @defaultCharWidth
|
||||
@@ -219,29 +223,30 @@ class DisplayBuffer extends Model
|
||||
|
||||
setScopedCharWidth: (scopeNames, char, width) ->
|
||||
@getScopedCharWidths(scopeNames)[char] = width
|
||||
@emit 'character-widths-changed', @scopedCharacterWidthsChangeCount++
|
||||
|
||||
setScopedCharWidths: (scopeNames, charWidths) ->
|
||||
_.extend(@getScopedCharWidths(scopeNames), charWidths)
|
||||
@emit 'character-widths-changed', @scopedCharacterWidthsChangeCount++
|
||||
|
||||
clearScopedCharWidths: ->
|
||||
@charWidthsByScope = {}
|
||||
|
||||
getScrollHeight: ->
|
||||
unless @getLineHeight() > 0
|
||||
throw new Error("You must assign lineHeight before calling ::getScrollHeight()")
|
||||
return 0 unless @getLineHeightInPixels() > 0
|
||||
|
||||
@getLineCount() * @getLineHeight()
|
||||
@getLineCount() * @getLineHeightInPixels()
|
||||
|
||||
getScrollWidth: ->
|
||||
(@getMaxLineLength() * @getDefaultCharWidth()) + @getCursorWidth()
|
||||
|
||||
getVisibleRowRange: ->
|
||||
unless @getLineHeight() > 0
|
||||
throw new Error("You must assign a non-zero lineHeight before calling ::getVisibleRowRange()")
|
||||
return [0, 0] unless @getLineHeightInPixels() > 0
|
||||
|
||||
heightInLines = Math.ceil(@getHeight() / @getLineHeightInPixels()) + 1
|
||||
startRow = Math.floor(@getScrollTop() / @getLineHeightInPixels())
|
||||
endRow = Math.min(@getLineCount(), startRow + heightInLines)
|
||||
|
||||
heightInLines = Math.ceil(@getHeight() / @getLineHeight()) + 1
|
||||
startRow = Math.floor(@getScrollTop() / @getLineHeight())
|
||||
endRow = Math.min(@getLineCount(), Math.ceil(startRow + heightInLines))
|
||||
[startRow, endRow]
|
||||
|
||||
intersectsVisibleRowRange: (startRow, endRow) ->
|
||||
@@ -252,15 +257,23 @@ class DisplayBuffer extends Model
|
||||
{start, end} = selection.getScreenRange()
|
||||
@intersectsVisibleRowRange(start.row, end.row + 1)
|
||||
|
||||
scrollToScreenRange: (screenRange) ->
|
||||
verticalScrollMarginInPixels = @getVerticalScrollMargin() * @getLineHeight()
|
||||
scrollToScreenRange: (screenRange, options) ->
|
||||
verticalScrollMarginInPixels = @getVerticalScrollMargin() * @getLineHeightInPixels()
|
||||
horizontalScrollMarginInPixels = @getHorizontalScrollMargin() * @getDefaultCharWidth()
|
||||
|
||||
{top, left, height, width} = @pixelRectForScreenRange(screenRange)
|
||||
bottom = top + height
|
||||
right = left + width
|
||||
desiredScrollTop = top - verticalScrollMarginInPixels
|
||||
desiredScrollBottom = bottom + verticalScrollMarginInPixels
|
||||
|
||||
if options?.center
|
||||
desiredScrollCenter = top + height / 2
|
||||
unless @getScrollTop() < desiredScrollCenter < @getScrollBottom()
|
||||
desiredScrollTop = desiredScrollCenter - @getHeight() / 2
|
||||
desiredScrollBottom = desiredScrollCenter + @getHeight() / 2
|
||||
else
|
||||
desiredScrollTop = top - verticalScrollMarginInPixels
|
||||
desiredScrollBottom = bottom + verticalScrollMarginInPixels
|
||||
|
||||
desiredScrollLeft = left - horizontalScrollMarginInPixels
|
||||
desiredScrollRight = right + horizontalScrollMarginInPixels
|
||||
|
||||
@@ -274,22 +287,22 @@ class DisplayBuffer extends Model
|
||||
else if desiredScrollRight > @getScrollRight()
|
||||
@setScrollRight(desiredScrollRight)
|
||||
|
||||
scrollToScreenPosition: (screenPosition) ->
|
||||
@scrollToScreenRange(new Range(screenPosition, screenPosition))
|
||||
scrollToScreenPosition: (screenPosition, options) ->
|
||||
@scrollToScreenRange(new Range(screenPosition, screenPosition), options)
|
||||
|
||||
scrollToBufferPosition: (bufferPosition) ->
|
||||
@scrollToScreenPosition(@screenPositionForBufferPosition(bufferPosition))
|
||||
scrollToBufferPosition: (bufferPosition, options) ->
|
||||
@scrollToScreenPosition(@screenPositionForBufferPosition(bufferPosition), options)
|
||||
|
||||
pixelRectForScreenRange: (screenRange) ->
|
||||
if screenRange.end.row > screenRange.start.row
|
||||
top = @pixelPositionForScreenPosition(screenRange.start).top
|
||||
left = 0
|
||||
height = (screenRange.end.row - screenRange.start.row + 1) * @getLineHeight()
|
||||
height = (screenRange.end.row - screenRange.start.row + 1) * @getLineHeightInPixels()
|
||||
width = @getScrollWidth()
|
||||
else
|
||||
{top, left} = @pixelPositionForScreenPosition(screenRange.start)
|
||||
height = @getLineHeight()
|
||||
width = @pixelPositionForScreenPosition(screenRange.end).left - left
|
||||
{top, left} = @pixelPositionForScreenPosition(screenRange.start, false)
|
||||
height = @getLineHeightInPixels()
|
||||
width = @pixelPositionForScreenPosition(screenRange.end, false).left - left
|
||||
|
||||
{top, left, width, height}
|
||||
|
||||
@@ -511,14 +524,14 @@ class DisplayBuffer extends Model
|
||||
targetColumn = screenPosition.column
|
||||
defaultCharWidth = @defaultCharWidth
|
||||
|
||||
top = targetRow * @lineHeight
|
||||
top = targetRow * @lineHeightInPixels
|
||||
left = 0
|
||||
column = 0
|
||||
for token in @lineForRow(targetRow).tokens
|
||||
charWidths = @getScopedCharWidths(token.scopes)
|
||||
for char in token.value
|
||||
return {top, left} if column is targetColumn
|
||||
left += charWidths[char] ? defaultCharWidth
|
||||
left += charWidths[char] ? defaultCharWidth unless char is '\0'
|
||||
column++
|
||||
{top, left}
|
||||
|
||||
@@ -526,7 +539,7 @@ class DisplayBuffer extends Model
|
||||
targetTop = pixelPosition.top
|
||||
targetLeft = pixelPosition.left
|
||||
defaultCharWidth = @defaultCharWidth
|
||||
row = Math.floor(targetTop / @getLineHeight())
|
||||
row = Math.floor(targetTop / @getLineHeightInPixels())
|
||||
row = Math.min(row, @getLastRow())
|
||||
row = Math.max(0, row)
|
||||
|
||||
@@ -716,6 +729,65 @@ class DisplayBuffer extends Model
|
||||
rangeForAllLines: ->
|
||||
new Range([0, 0], @clipScreenPosition([Infinity, Infinity]))
|
||||
|
||||
decorationsForScreenRowRange: (startScreenRow, endScreenRow) ->
|
||||
decorationsByMarkerId = {}
|
||||
|
||||
for marker in @findMarkers(intersectsScreenRowRange: [startScreenRow, endScreenRow])
|
||||
if decorations = @decorationsByMarkerId[marker.id]
|
||||
decorationsByMarkerId[marker.id] = decorations
|
||||
decorationsByMarkerId
|
||||
|
||||
decorationMatchesType: (decoration, type) ->
|
||||
if _.isArray(decoration.type)
|
||||
type in decoration.type
|
||||
else
|
||||
type is decoration.type
|
||||
|
||||
decorationMatchesPattern: (decoration, decorationPattern) ->
|
||||
return false unless decoration? and decorationPattern?
|
||||
for key, value of decorationPattern
|
||||
return false if decoration[key] != value
|
||||
true
|
||||
|
||||
addDecorationForMarker: (marker, decoration) ->
|
||||
unless marker?
|
||||
console.warn 'A null marker cannot be decorated'
|
||||
return
|
||||
|
||||
marker = @getMarker(marker.id)
|
||||
@decorationMarkerSubscriptions[marker.id] ?= @subscribe marker, 'destroyed', => @removeAllDecorationsForMarker(marker)
|
||||
|
||||
@decorationsByMarkerId[marker.id] ?= []
|
||||
@decorationsByMarkerId[marker.id].push(decoration)
|
||||
@emit 'decoration-added', marker, decoration
|
||||
|
||||
removeDecorationForMarker: (marker, decorationPattern) ->
|
||||
unless marker?
|
||||
console.warn 'A decoration cannot be removed from a null marker'
|
||||
return
|
||||
|
||||
return unless @decorationMarkerSubscriptions[marker.id]?
|
||||
|
||||
decorations = @decorationsByMarkerId[marker.id]
|
||||
for i in [decorations.length - 1..0]
|
||||
decoration = decorations[i]
|
||||
if @decorationMatchesPattern(decoration, decorationPattern)
|
||||
decorations.splice(i, 1)
|
||||
@emit 'decoration-removed', marker, decoration
|
||||
|
||||
@removedAllMarkerDecorations(marker) if decorations.length is 0
|
||||
|
||||
removeAllDecorationsForMarker: (marker) ->
|
||||
decorations = @decorationsByMarkerId[marker.id].slice()
|
||||
for decoration in decorations
|
||||
@emit 'decoration-removed', marker, decoration
|
||||
@removedAllMarkerDecorations(marker)
|
||||
|
||||
removedAllMarkerDecorations: (marker) ->
|
||||
@decorationMarkerSubscriptions[marker.id].off()
|
||||
delete @decorationsByMarkerId[marker.id]
|
||||
delete @decorationMarkerSubscriptions[marker.id]
|
||||
|
||||
# Retrieves a {DisplayBufferMarker} based on its id.
|
||||
#
|
||||
# id - A {Number} representing a marker id
|
||||
@@ -819,13 +891,34 @@ class DisplayBuffer extends Model
|
||||
key = 'startRow'
|
||||
when 'endBufferRow'
|
||||
key = 'endRow'
|
||||
when 'startScreenRow'
|
||||
key = 'startRow'
|
||||
value = @bufferRowForScreenRow(value)
|
||||
when 'endScreenRow'
|
||||
key = 'endRow'
|
||||
value = @bufferRowForScreenRow(value)
|
||||
when 'intersectsBufferRowRange'
|
||||
key = 'intersectsRowRange'
|
||||
when 'intersectsScreenRowRange'
|
||||
key = 'intersectsRowRange'
|
||||
[startRow, endRow] = value
|
||||
value = [@bufferRowForScreenRow(startRow), @bufferRowForScreenRow(endRow)]
|
||||
when 'containsBufferRange'
|
||||
key = 'containsRange'
|
||||
when 'containsBufferPosition'
|
||||
key = 'containsPosition'
|
||||
when 'containedInBufferRange'
|
||||
key = 'containedInRange'
|
||||
when 'containedInScreenRange'
|
||||
key = 'containedInRange'
|
||||
value = @bufferRangeForScreenRange(value)
|
||||
when 'intersectsBufferRange'
|
||||
key = 'intersectsRange'
|
||||
when 'intersectsScreenRange'
|
||||
key = 'intersectsRange'
|
||||
value = @bufferRangeForScreenRange(value)
|
||||
bufferMarkerParams[key] = value
|
||||
|
||||
bufferMarkerParams
|
||||
|
||||
findFoldMarker: (attributes) ->
|
||||
@@ -959,6 +1052,7 @@ class DisplayBuffer extends Model
|
||||
@emit 'marker-created', @getMarker(marker.id)
|
||||
|
||||
createFoldForMarker: (marker) ->
|
||||
@addDecorationForMarker(marker, type: 'gutter', class: 'folded')
|
||||
new Fold(this, marker)
|
||||
|
||||
foldForMarker: (marker) ->
|
||||
|
||||
+605
-119
@@ -1,64 +1,112 @@
|
||||
React = require 'react'
|
||||
{div, span} = require 'reactionary'
|
||||
{debounce} = require 'underscore-plus'
|
||||
React = require 'react-atom-fork'
|
||||
{div, span} = require 'reactionary-atom-fork'
|
||||
{debounce, defaults, isEqualForProperties} = require 'underscore-plus'
|
||||
scrollbarStyle = require 'scrollbar-style'
|
||||
{Range, Point} = require 'text-buffer'
|
||||
|
||||
GutterComponent = require './gutter-component'
|
||||
EditorScrollViewComponent = require './editor-scroll-view-component'
|
||||
InputComponent = require './input-component'
|
||||
CursorsComponent = require './cursors-component'
|
||||
LinesComponent = require './lines-component'
|
||||
ScrollbarComponent = require './scrollbar-component'
|
||||
ScrollbarCornerComponent = require './scrollbar-corner-component'
|
||||
SubscriberMixin = require './subscriber-mixin'
|
||||
|
||||
DummyHighlightDecoration = {id: 'dummy', screenRange: new Range(new Point(0, 0), new Point(0, 0)), decorations: [{class: 'dummy'}]}
|
||||
|
||||
module.exports =
|
||||
EditorComponent = React.createClass
|
||||
displayName: 'EditorComponent'
|
||||
mixins: [SubscriberMixin]
|
||||
|
||||
statics:
|
||||
performSyncUpdates: false
|
||||
|
||||
pendingScrollTop: null
|
||||
pendingScrollLeft: null
|
||||
selectOnMouseMove: false
|
||||
batchingUpdates: false
|
||||
updateRequested: false
|
||||
cursorsMoved: false
|
||||
preservedRowRange: null
|
||||
selectionChanged: false
|
||||
selectionAdded: false
|
||||
scrollingVertically: false
|
||||
gutterWidth: 0
|
||||
refreshingScrollbars: false
|
||||
measuringScrollbars: true
|
||||
pendingVerticalScrollDelta: 0
|
||||
pendingHorizontalScrollDelta: 0
|
||||
mouseWheelScreenRow: null
|
||||
mouseWheelScreenRowClearDelay: 150
|
||||
scrollSensitivity: 0.4
|
||||
scrollViewMeasurementRequested: false
|
||||
measureLineHeightAndDefaultCharWidthWhenShown: false
|
||||
remeasureCharacterWidthsWhenShown: false
|
||||
inputEnabled: true
|
||||
scrollViewMeasurementInterval: 100
|
||||
scopedCharacterWidthsChangeCount: null
|
||||
|
||||
render: ->
|
||||
{focused, fontSize, lineHeight, fontFamily, showIndentGuide} = @state
|
||||
{focused, fontSize, lineHeight, fontFamily, showIndentGuide, showInvisibles, visible} = @state
|
||||
{editor, cursorBlinkPeriod, cursorBlinkResumeDelay} = @props
|
||||
maxLineNumberDigits = editor.getScreenLineCount().toString().length
|
||||
maxLineNumberDigits = editor.getLineCount().toString().length
|
||||
invisibles = if showInvisibles then @state.invisibles else {}
|
||||
hasSelection = editor.getSelection()? and !editor.getSelection().isEmpty()
|
||||
|
||||
if @isMounted()
|
||||
renderedRowRange = @getRenderedRowRange()
|
||||
[renderedStartRow, renderedEndRow] = renderedRowRange
|
||||
cursorScreenRanges = @getCursorScreenRanges(renderedRowRange)
|
||||
|
||||
decorations = editor.decorationsForScreenRowRange(renderedStartRow, renderedEndRow)
|
||||
highlightDecorations = @getHighlightDecorations(decorations)
|
||||
lineDecorations = @getLineDecorations(decorations)
|
||||
|
||||
scrollHeight = editor.getScrollHeight()
|
||||
scrollWidth = editor.getScrollWidth()
|
||||
scrollTop = editor.getScrollTop()
|
||||
scrollLeft = editor.getScrollLeft()
|
||||
lineHeightInPixels = editor.getLineHeight()
|
||||
lineHeightInPixels = editor.getLineHeightInPixels()
|
||||
defaultCharWidth = editor.getDefaultCharWidth()
|
||||
scrollViewHeight = editor.getHeight()
|
||||
horizontalScrollbarHeight = editor.getHorizontalScrollbarHeight()
|
||||
verticalScrollbarWidth = editor.getVerticalScrollbarWidth()
|
||||
verticallyScrollable = editor.verticallyScrollable()
|
||||
horizontallyScrollable = editor.horizontallyScrollable()
|
||||
hiddenInputStyle = @getHiddenInputPosition()
|
||||
hiddenInputStyle.WebkitTransform = 'translateZ(0)'
|
||||
if @mouseWheelScreenRow? and not (renderedStartRow <= @mouseWheelScreenRow < renderedEndRow)
|
||||
mouseWheelScreenRow = @mouseWheelScreenRow
|
||||
|
||||
className = 'editor editor-colors react'
|
||||
className = 'editor-contents editor-colors'
|
||||
className += ' is-focused' if focused
|
||||
className += ' has-selection' if hasSelection
|
||||
|
||||
div className: className, style: {fontSize, lineHeight, fontFamily}, tabIndex: -1,
|
||||
GutterComponent {
|
||||
editor, renderedRowRange, maxLineNumberDigits, scrollTop, scrollHeight,
|
||||
lineHeight: lineHeightInPixels, fontSize, fontFamily, @pendingChanges,
|
||||
onWidthChanged: @onGutterWidthChanged
|
||||
ref: 'gutter', onMouseDown: @onGutterMouseDown, onWidthChanged: @onGutterWidthChanged,
|
||||
lineDecorations, defaultCharWidth, editor, renderedRowRange, maxLineNumberDigits, scrollViewHeight,
|
||||
scrollTop, scrollHeight, lineHeightInPixels, @pendingChanges, mouseWheelScreenRow
|
||||
}
|
||||
|
||||
EditorScrollViewComponent {
|
||||
ref: 'scrollView', editor, fontSize, fontFamily, showIndentGuide
|
||||
scrollHeight, scrollWidth, lineHeight: lineHeightInPixels,
|
||||
renderedRowRange, @pendingChanges, @scrollingVertically, @cursorsMoved,
|
||||
cursorBlinkPeriod, cursorBlinkResumeDelay, @onInputFocused, @onInputBlurred
|
||||
}
|
||||
div ref: 'scrollView', className: 'scroll-view', onMouseDown: @onMouseDown,
|
||||
InputComponent
|
||||
ref: 'input'
|
||||
className: 'hidden-input'
|
||||
style: hiddenInputStyle
|
||||
onFocus: @onInputFocused
|
||||
onBlur: @onInputBlurred
|
||||
|
||||
CursorsComponent {
|
||||
editor, scrollTop, scrollLeft, cursorScreenRanges, cursorBlinkPeriod, cursorBlinkResumeDelay,
|
||||
lineHeightInPixels, defaultCharWidth, @scopedCharacterWidthsChangeCount
|
||||
}
|
||||
LinesComponent {
|
||||
ref: 'lines',
|
||||
editor, lineHeightInPixels, defaultCharWidth, lineDecorations, highlightDecorations,
|
||||
showIndentGuide, renderedRowRange, @pendingChanges, scrollTop, scrollLeft,
|
||||
@scrollingVertically, scrollHeight, scrollWidth, mouseWheelScreenRow, invisibles,
|
||||
visible, scrollViewHeight, @scopedCharacterWidthsChangeCount
|
||||
}
|
||||
|
||||
ScrollbarComponent
|
||||
ref: 'verticalScrollbar'
|
||||
@@ -92,68 +140,197 @@ EditorComponent = React.createClass
|
||||
height: horizontalScrollbarHeight
|
||||
width: verticalScrollbarWidth
|
||||
|
||||
getRenderedRowRange: ->
|
||||
renderedRowRange = @props.editor.getVisibleRowRange()
|
||||
if @preservedRowRange?
|
||||
renderedRowRange[0] = Math.min(@preservedRowRange[0], renderedRowRange[0])
|
||||
renderedRowRange[1] = Math.max(@preservedRowRange[1], renderedRowRange[1])
|
||||
renderedRowRange
|
||||
getPageRows: ->
|
||||
{editor} = @props
|
||||
Math.max(1, Math.ceil(editor.getHeight() / editor.getLineHeightInPixels()))
|
||||
|
||||
getInitialState: -> {}
|
||||
getInitialState: ->
|
||||
visible: true
|
||||
|
||||
getDefaultProps: ->
|
||||
cursorBlinkPeriod: 800
|
||||
cursorBlinkResumeDelay: 200
|
||||
cursorBlinkResumeDelay: 100
|
||||
lineOverdrawMargin: 8
|
||||
|
||||
componentWillMount: ->
|
||||
@pendingChanges = []
|
||||
@props.editor.manageScrollPosition = true
|
||||
@observeConfig()
|
||||
@setScrollSensitivity(atom.config.get('editor.scrollSensitivity'))
|
||||
|
||||
componentDidMount: ->
|
||||
{editor} = @props
|
||||
|
||||
@scrollViewMeasurementIntervalId = setInterval(@requestScrollViewMeasurement, @scrollViewMeasurementInterval)
|
||||
|
||||
@observeEditor()
|
||||
@listenForDOMEvents()
|
||||
@listenForCommands()
|
||||
@measureScrollbars()
|
||||
|
||||
@subscribe atom.themes, 'stylesheet-added stylsheet-removed', @onStylesheetsChanged
|
||||
@subscribe scrollbarStyle.changes, @refreshScrollbars
|
||||
@props.editor.setVisible(true)
|
||||
@requestUpdate()
|
||||
|
||||
editor.setVisible(true)
|
||||
|
||||
@measureLineHeightAndDefaultCharWidth()
|
||||
@measureScrollView()
|
||||
@measureScrollbars()
|
||||
|
||||
componentWillUnmount: ->
|
||||
@unsubscribe()
|
||||
@getDOMNode().removeEventListener 'mousewheel', @onMouseWheel
|
||||
clearInterval(@scrollViewMeasurementIntervalId)
|
||||
@scrollViewMeasurementIntervalId = null
|
||||
|
||||
componentWillUpdate: ->
|
||||
@props.parentView.trigger 'cursor:moved' if @cursorsMoved
|
||||
|
||||
componentDidUpdate: ->
|
||||
componentDidUpdate: (prevProps, prevState) ->
|
||||
cursorsMoved = @cursorsMoved
|
||||
selectionChanged = @selectionChanged
|
||||
@pendingChanges.length = 0
|
||||
@cursorsMoved = false
|
||||
@selectionChanged = false
|
||||
@refreshingScrollbars = false
|
||||
|
||||
if @props.editor.isAlive()
|
||||
@updateParentViewFocusedClassIfNeeded(prevState)
|
||||
@props.parentView.trigger 'cursor:moved' if cursorsMoved
|
||||
@props.parentView.trigger 'selection:changed' if selectionChanged
|
||||
@props.parentView.trigger 'editor:display-updated'
|
||||
|
||||
@measureScrollbars() if @measuringScrollbars
|
||||
@props.parentView.trigger 'editor:display-updated'
|
||||
@measureLineHeightAndCharWidthsIfNeeded(prevState)
|
||||
@remeasureCharacterWidthsIfNeeded(prevState)
|
||||
|
||||
requestUpdate: ->
|
||||
if @performSyncUpdates ? EditorComponent.performSyncUpdates
|
||||
@forceUpdate()
|
||||
else unless @updateRequested
|
||||
@updateRequested = true
|
||||
process.nextTick =>
|
||||
@updateRequested = false
|
||||
@forceUpdate() if @isMounted()
|
||||
|
||||
getRenderedRowRange: ->
|
||||
{editor, lineOverdrawMargin} = @props
|
||||
[visibleStartRow, visibleEndRow] = editor.getVisibleRowRange()
|
||||
renderedStartRow = Math.max(0, visibleStartRow - lineOverdrawMargin)
|
||||
renderedEndRow = Math.min(editor.getScreenLineCount(), visibleEndRow + lineOverdrawMargin)
|
||||
[renderedStartRow, renderedEndRow]
|
||||
|
||||
getHiddenInputPosition: ->
|
||||
{editor} = @props
|
||||
{focused} = @state
|
||||
return {top: 0, left: 0} unless @isMounted() and focused and editor.getCursor()?
|
||||
|
||||
{top, left, height, width} = editor.getCursor().getPixelRect()
|
||||
width = 2 if width is 0 # Prevent autoscroll at the end of longest line
|
||||
top -= editor.getScrollTop()
|
||||
left -= editor.getScrollLeft()
|
||||
top = Math.max(0, Math.min(editor.getHeight() - height, top))
|
||||
left = Math.max(0, Math.min(editor.getWidth() - width, left))
|
||||
{top, left}
|
||||
|
||||
getCursorScreenRanges: (renderedRowRange) ->
|
||||
{editor} = @props
|
||||
[renderedStartRow, renderedEndRow] = renderedRowRange
|
||||
|
||||
cursorScreenRanges = {}
|
||||
for selection in editor.getSelections() when selection.isEmpty()
|
||||
{cursor} = selection
|
||||
screenRange = cursor.getScreenRange()
|
||||
if renderedStartRow <= screenRange.start.row < renderedEndRow
|
||||
cursorScreenRanges[cursor.id] = screenRange
|
||||
cursorScreenRanges
|
||||
|
||||
getLineDecorations: (decorationsByMarkerId) ->
|
||||
{editor} = @props
|
||||
decorationsByScreenRow = {}
|
||||
for markerId, decorations of decorationsByMarkerId
|
||||
marker = editor.getMarker(markerId)
|
||||
screenRange = null
|
||||
if marker.isValid()
|
||||
for decoration in decorations
|
||||
if editor.decorationMatchesType(decoration, 'gutter') or editor.decorationMatchesType(decoration, 'line')
|
||||
screenRange ?= marker.getScreenRange()
|
||||
startRow = screenRange.start.row
|
||||
endRow = screenRange.end.row
|
||||
endRow-- if not screenRange.isEmpty() and screenRange.end.column == 0
|
||||
for screenRow in [startRow..endRow]
|
||||
decorationsByScreenRow[screenRow] ?= []
|
||||
decorationsByScreenRow[screenRow].push decoration
|
||||
|
||||
decorationsByScreenRow
|
||||
|
||||
getHighlightDecorations: (decorationsByMarkerId) ->
|
||||
{editor} = @props
|
||||
filteredDecorations = {}
|
||||
for markerId, decorations of decorationsByMarkerId
|
||||
marker = editor.getMarker(markerId)
|
||||
if marker.isValid() and not marker.getScreenRange().isEmpty()
|
||||
for decoration in decorations
|
||||
if editor.decorationMatchesType(decoration, 'highlight')
|
||||
filteredDecorations[markerId] ?= {id: markerId, screenRange: marker.getScreenRange(), decorations: []}
|
||||
filteredDecorations[markerId].decorations.push decoration
|
||||
|
||||
# At least in Chromium 31, removing the last highlight causes a rendering
|
||||
# artifact where chunks of the lines disappear, so we always leave this
|
||||
# dummy highlight in place to prevent that.
|
||||
filteredDecorations['dummy'] = DummyHighlightDecoration
|
||||
|
||||
filteredDecorations
|
||||
|
||||
observeEditor: ->
|
||||
{editor} = @props
|
||||
@subscribe editor, 'batched-updates-started', @onBatchedUpdatesStarted
|
||||
@subscribe editor, 'batched-updates-ended', @onBatchedUpdatesEnded
|
||||
@subscribe editor, 'screen-lines-changed', @onScreenLinesChanged
|
||||
@subscribe editor, 'cursors-moved', @onCursorsMoved
|
||||
@subscribe editor, 'selection-screen-range-changed', @requestUpdate
|
||||
@subscribe editor, 'selection-removed selection-screen-range-changed', @onSelectionChanged
|
||||
@subscribe editor, 'selection-added', @onSelectionAdded
|
||||
@subscribe editor, 'selection-removed', @onSelectionAdded
|
||||
@subscribe editor, 'decoration-added', @onDecorationChanged
|
||||
@subscribe editor, 'decoration-removed', @onDecorationChanged
|
||||
@subscribe editor, 'character-widths-changed', @onCharacterWidthsChanged
|
||||
@subscribe editor.$scrollTop.changes, @onScrollTopChanged
|
||||
@subscribe editor.$scrollLeft.changes, @requestUpdate
|
||||
@subscribe editor.$height.changes, @requestUpdate
|
||||
@subscribe editor.$width.changes, @requestUpdate
|
||||
@subscribe editor.$defaultCharWidth.changes, @requestUpdate
|
||||
@subscribe editor.$lineHeight.changes, @requestUpdate
|
||||
@subscribe editor.$lineHeightInPixels.changes, @requestUpdate
|
||||
|
||||
listenForDOMEvents: ->
|
||||
node = @getDOMNode()
|
||||
node.addEventListener 'mousewheel', @onMouseWheel
|
||||
node.addEventListener 'focus', @onFocus # For some reason, React's built in focus events seem to bubble
|
||||
node.addEventListener 'textInput', @onTextInput
|
||||
|
||||
scrollViewNode = @refs.scrollView.getDOMNode()
|
||||
scrollViewNode.addEventListener 'scroll', @onScrollViewScroll
|
||||
window.addEventListener 'resize', @requestScrollViewMeasurement
|
||||
|
||||
@listenForIMEEvents()
|
||||
|
||||
listenForIMEEvents: ->
|
||||
node = @getDOMNode()
|
||||
{editor} = @props
|
||||
|
||||
# The IME composition events work like this:
|
||||
#
|
||||
# User types 's', chromium pops up the completion helper
|
||||
# 1. compositionstart fired
|
||||
# 2. compositionupdate fired; event.data == 's'
|
||||
# User hits arrow keys to move around in completion helper
|
||||
# 3. compositionupdate fired; event.data == 's' for each arry key press
|
||||
# User escape to cancel
|
||||
# 4. compositionend fired
|
||||
# OR User chooses a completion
|
||||
# 4. compositionend fired
|
||||
# 5. textInput fired; event.data == the completion string
|
||||
|
||||
selectedText = null
|
||||
node.addEventListener 'compositionstart', =>
|
||||
selectedText = editor.getSelectedText()
|
||||
node.addEventListener 'compositionupdate', (event) =>
|
||||
editor.insertText(event.data, select: true, undo: 'skip')
|
||||
node.addEventListener 'compositionend', =>
|
||||
editor.insertText(selectedText, select: true, undo: 'skip')
|
||||
|
||||
listenForCommands: ->
|
||||
{parentView, editor, mini} = @props
|
||||
@@ -176,9 +353,12 @@ EditorComponent = React.createClass
|
||||
'editor:consolidate-selections': @consolidateSelections
|
||||
'editor:delete-to-beginning-of-word': => editor.deleteToBeginningOfWord()
|
||||
'editor:delete-to-beginning-of-line': => editor.deleteToBeginningOfLine()
|
||||
'editor:delete-to-end-of-line': => editor.deleteToEndOfLine()
|
||||
'editor:delete-to-end-of-word': => editor.deleteToEndOfWord()
|
||||
'editor:delete-line': => editor.deleteLine()
|
||||
'editor:cut-to-end-of-line': => editor.cutToEndOfLine()
|
||||
'editor:move-to-beginning-of-next-paragraph': => editor.moveCursorToBeginningOfNextParagraph()
|
||||
'editor:move-to-beginning-of-previous-paragraph': => editor.moveCursorToBeginningOfPreviousParagraph()
|
||||
'editor:move-to-beginning-of-screen-line': => editor.moveCursorToBeginningOfScreenLine()
|
||||
'editor:move-to-beginning-of-line': => editor.moveCursorToBeginningOfLine()
|
||||
'editor:move-to-end-of-screen-line': => editor.moveCursorToEndOfScreenLine()
|
||||
@@ -189,6 +369,8 @@ EditorComponent = React.createClass
|
||||
'editor:move-to-beginning-of-next-word': => editor.moveCursorToBeginningOfNextWord()
|
||||
'editor:move-to-previous-word-boundary': => editor.moveCursorToPreviousWordBoundary()
|
||||
'editor:move-to-next-word-boundary': => editor.moveCursorToNextWordBoundary()
|
||||
'editor:select-to-beginning-of-next-paragraph': => editor.selectToBeginningOfNextParagraph()
|
||||
'editor:select-to-beginning-of-previous-paragraph': => editor.selectToBeginningOfPreviousParagraph()
|
||||
'editor:select-to-end-of-line': => editor.selectToEndOfLine()
|
||||
'editor:select-to-beginning-of-line': => editor.selectToBeginningOfLine()
|
||||
'editor:select-to-end-of-word': => editor.selectToEndOfWord()
|
||||
@@ -208,10 +390,14 @@ EditorComponent = React.createClass
|
||||
'core:move-down': => editor.moveCursorDown()
|
||||
'core:move-to-top': => editor.moveCursorToTop()
|
||||
'core:move-to-bottom': => editor.moveCursorToBottom()
|
||||
'core:page-up': => editor.pageUp()
|
||||
'core:page-down': => editor.pageDown()
|
||||
'core:select-up': => editor.selectUp()
|
||||
'core:select-down': => editor.selectDown()
|
||||
'core:select-to-top': => editor.selectToTop()
|
||||
'core:select-to-bottom': => editor.selectToBottom()
|
||||
'core:select-page-up': => editor.selectPageUp()
|
||||
'core:select-page-down': => editor.selectPageDown()
|
||||
'editor:indent': => editor.indent()
|
||||
'editor:auto-indent': => editor.autoIndentSelectedRows()
|
||||
'editor:indent-selected-rows': => editor.indentSelectedRows()
|
||||
@@ -249,8 +435,7 @@ EditorComponent = React.createClass
|
||||
'editor:toggle-indent-guide': => atom.config.toggle('editor.showIndentGuide')
|
||||
'editor:toggle-line-numbers': => atom.config.toggle('editor.showLineNumbers')
|
||||
'editor:scroll-to-cursor': => editor.scrollToCursorPosition()
|
||||
'core:page-up': => editor.pageUp()
|
||||
'core:page-down': => editor.pageDown()
|
||||
'benchmark:scroll': @runScrollBenchmark
|
||||
|
||||
addCommandListeners: (listenersByCommandName) ->
|
||||
{parentView} = @props
|
||||
@@ -261,32 +446,34 @@ EditorComponent = React.createClass
|
||||
observeConfig: ->
|
||||
@subscribe atom.config.observe 'editor.fontFamily', @setFontFamily
|
||||
@subscribe atom.config.observe 'editor.fontSize', @setFontSize
|
||||
@subscribe atom.config.observe 'editor.lineHeight', @setLineHeight
|
||||
@subscribe atom.config.observe 'editor.showIndentGuide', @setShowIndentGuide
|
||||
|
||||
measureScrollbars: ->
|
||||
@measuringScrollbars = false
|
||||
|
||||
{editor} = @props
|
||||
scrollbarCornerNode = @refs.scrollbarCorner.getDOMNode()
|
||||
width = (scrollbarCornerNode.offsetWidth - scrollbarCornerNode.clientWidth) or 15
|
||||
height = (scrollbarCornerNode.offsetHeight - scrollbarCornerNode.clientHeight) or 15
|
||||
editor.setVerticalScrollbarWidth(width)
|
||||
editor.setHorizontalScrollbarHeight(height)
|
||||
|
||||
setFontSize: (fontSize) ->
|
||||
@setState({fontSize})
|
||||
|
||||
setLineHeight: (lineHeight) ->
|
||||
@setState({lineHeight})
|
||||
|
||||
setFontFamily: (fontFamily) ->
|
||||
@setState({fontFamily})
|
||||
|
||||
setShowIndentGuide: (showIndentGuide) ->
|
||||
@setState({showIndentGuide})
|
||||
@subscribe atom.config.observe 'editor.invisibles', @setInvisibles
|
||||
@subscribe atom.config.observe 'editor.showInvisibles', @setShowInvisibles
|
||||
@subscribe atom.config.observe 'editor.scrollSensitivity', @setScrollSensitivity
|
||||
|
||||
onFocus: ->
|
||||
@refs.scrollView.focus()
|
||||
@refs.input.focus()
|
||||
|
||||
onTextInput: (event) ->
|
||||
return unless @isInputEnabled()
|
||||
|
||||
{editor} = @props
|
||||
inputNode = event.target
|
||||
|
||||
# Work around of the accented character suggestion feature in OS X.
|
||||
# Text input fires before a character is inserted, and if the browser is
|
||||
# replacing the previous un-accented character with an accented variant, it
|
||||
# will select backward over it.
|
||||
selectedLength = inputNode.selectionEnd - inputNode.selectionStart
|
||||
editor.selectLeft() if selectedLength is 1
|
||||
|
||||
editor.insertText(event.data)
|
||||
inputNode.value = event.data
|
||||
|
||||
# If we prevent the insertion of a space character, then the browser
|
||||
# interprets the spacebar keypress as a page-down command.
|
||||
event.preventDefault() unless event.data is ' '
|
||||
|
||||
onInputFocused: ->
|
||||
@setState(focused: true)
|
||||
@@ -319,18 +506,245 @@ EditorComponent = React.createClass
|
||||
@pendingScrollLeft = null
|
||||
|
||||
onMouseWheel: (event) ->
|
||||
event.preventDefault()
|
||||
animationFramePending = @pendingHorizontalScrollDelta isnt 0 or @pendingVerticalScrollDelta isnt 0
|
||||
|
||||
# Only scroll in one direction at a time
|
||||
{wheelDeltaX, wheelDeltaY} = event
|
||||
if Math.abs(wheelDeltaX) > Math.abs(wheelDeltaY)
|
||||
@refs.horizontalScrollbar.getDOMNode().scrollLeft -= wheelDeltaX
|
||||
# Scrolling horizontally
|
||||
@pendingHorizontalScrollDelta -= Math.round(wheelDeltaX * @scrollSensitivity)
|
||||
else
|
||||
@refs.verticalScrollbar.getDOMNode().scrollTop -= wheelDeltaY
|
||||
# Scrolling vertically
|
||||
@pendingVerticalScrollDelta -= Math.round(wheelDeltaY * @scrollSensitivity)
|
||||
@mouseWheelScreenRow = @screenRowForNode(event.target)
|
||||
@clearMouseWheelScreenRowAfterDelay ?= debounce(@clearMouseWheelScreenRow, @mouseWheelScreenRowClearDelay)
|
||||
@clearMouseWheelScreenRowAfterDelay()
|
||||
|
||||
event.preventDefault()
|
||||
unless animationFramePending
|
||||
requestAnimationFrame =>
|
||||
{editor} = @props
|
||||
editor.setScrollTop(editor.getScrollTop() + @pendingVerticalScrollDelta)
|
||||
editor.setScrollLeft(editor.getScrollLeft() + @pendingHorizontalScrollDelta)
|
||||
@pendingVerticalScrollDelta = 0
|
||||
@pendingHorizontalScrollDelta = 0
|
||||
|
||||
onScrollViewScroll: ->
|
||||
if @isMounted()
|
||||
console.warn "EditorScrollView scrolled when it shouldn't have."
|
||||
scrollViewNode = @refs.scrollView.getDOMNode()
|
||||
scrollViewNode.scrollTop = 0
|
||||
scrollViewNode.scrollLeft = 0
|
||||
|
||||
onMouseDown: (event) ->
|
||||
return unless event.button is 0 # only handle the left mouse button
|
||||
|
||||
{editor} = @props
|
||||
{detail, shiftKey, metaKey} = event
|
||||
screenPosition = @screenPositionForMouseEvent(event)
|
||||
|
||||
if event.target?.classList.contains('fold-marker')
|
||||
bufferRow = editor.bufferRowForScreenRow(screenPosition.row)
|
||||
editor.unfoldBufferRow(bufferRow)
|
||||
return
|
||||
|
||||
if shiftKey
|
||||
editor.selectToScreenPosition(screenPosition)
|
||||
else if metaKey
|
||||
editor.addCursorAtScreenPosition(screenPosition)
|
||||
else
|
||||
editor.setCursorScreenPosition(screenPosition)
|
||||
switch detail
|
||||
when 2 then editor.selectWord()
|
||||
when 3 then editor.selectLine()
|
||||
|
||||
@handleDragUntilMouseUp event, (screenPosition) ->
|
||||
editor.selectToScreenPosition(screenPosition)
|
||||
|
||||
onGutterMouseDown: (event) ->
|
||||
return unless event.button is 0 # only handle the left mouse button
|
||||
|
||||
if event.shiftKey
|
||||
@onGutterShiftClick(event)
|
||||
else
|
||||
@onGutterClick(event)
|
||||
|
||||
onGutterClick: (event) ->
|
||||
{editor} = @props
|
||||
clickedRow = @screenPositionForMouseEvent(event).row
|
||||
|
||||
editor.setCursorScreenPosition([clickedRow, 0])
|
||||
|
||||
@handleDragUntilMouseUp event, (screenPosition) ->
|
||||
dragRow = screenPosition.row
|
||||
if dragRow < clickedRow # dragging up
|
||||
editor.setSelectedScreenRange([[dragRow, 0], [clickedRow + 1, 0]])
|
||||
else
|
||||
editor.setSelectedScreenRange([[clickedRow, 0], [dragRow + 1, 0]])
|
||||
|
||||
onGutterShiftClick: (event) ->
|
||||
{editor} = @props
|
||||
clickedRow = @screenPositionForMouseEvent(event).row
|
||||
tailPosition = editor.getSelection().getTailScreenPosition()
|
||||
|
||||
if clickedRow < tailPosition.row
|
||||
editor.selectToScreenPosition([clickedRow, 0])
|
||||
else
|
||||
editor.selectToScreenPosition([clickedRow + 1, 0])
|
||||
|
||||
@handleDragUntilMouseUp event, (screenPosition) ->
|
||||
dragRow = screenPosition.row
|
||||
if dragRow < tailPosition.row # dragging up
|
||||
editor.setSelectedScreenRange([[dragRow, 0], tailPosition])
|
||||
else
|
||||
editor.setSelectedScreenRange([tailPosition, [dragRow + 1, 0]])
|
||||
|
||||
onStylesheetsChanged: (stylesheet) ->
|
||||
@refreshScrollbars() if @containsScrollbarSelector(stylesheet)
|
||||
|
||||
onScreenLinesChanged: (change) ->
|
||||
{editor} = @props
|
||||
@pendingChanges.push(change)
|
||||
@requestUpdate() if editor.intersectsVisibleRowRange(change.start, change.end + 1) # TODO: Use closed-open intervals for change events
|
||||
|
||||
onSelectionChanged: (selection) ->
|
||||
{editor} = @props
|
||||
if editor.selectionIntersectsVisibleRowRange(selection)
|
||||
@selectionChanged = true
|
||||
@requestUpdate()
|
||||
|
||||
onSelectionAdded: (selection) ->
|
||||
{editor} = @props
|
||||
if editor.selectionIntersectsVisibleRowRange(selection)
|
||||
@selectionChanged = true
|
||||
@selectionAdded = true
|
||||
@requestUpdate()
|
||||
|
||||
onScrollTopChanged: ->
|
||||
@scrollingVertically = true
|
||||
@requestUpdate()
|
||||
@onStoppedScrollingAfterDelay ?= debounce(@onStoppedScrolling, 100)
|
||||
@onStoppedScrollingAfterDelay()
|
||||
|
||||
onStoppedScrolling: ->
|
||||
return unless @isMounted()
|
||||
|
||||
@scrollingVertically = false
|
||||
@mouseWheelScreenRow = null
|
||||
@requestUpdate()
|
||||
|
||||
onStoppedScrollingAfterDelay: null # created lazily
|
||||
|
||||
onCursorsMoved: ->
|
||||
@cursorsMoved = true
|
||||
@requestUpdate()
|
||||
|
||||
onDecorationChanged: ->
|
||||
@requestUpdate()
|
||||
|
||||
onCharacterWidthsChanged: (@scopedCharacterWidthsChangeCount) ->
|
||||
@requestUpdate()
|
||||
|
||||
handleDragUntilMouseUp: (event, dragHandler) ->
|
||||
{editor} = @props
|
||||
dragging = false
|
||||
lastMousePosition = {}
|
||||
animationLoop = =>
|
||||
requestAnimationFrame =>
|
||||
if dragging
|
||||
screenPosition = @screenPositionForMouseEvent(lastMousePosition)
|
||||
dragHandler(screenPosition)
|
||||
animationLoop()
|
||||
|
||||
onMouseMove = (event) ->
|
||||
lastMousePosition.clientX = event.clientX
|
||||
lastMousePosition.clientY = event.clientY
|
||||
|
||||
# Start the animation loop when the mouse moves prior to a mouseup event
|
||||
unless dragging
|
||||
dragging = true
|
||||
animationLoop()
|
||||
|
||||
# Stop dragging when cursor enters dev tools because we can't detect mouseup
|
||||
onMouseUp() if event.which is 0
|
||||
|
||||
onMouseUp = ->
|
||||
dragging = false
|
||||
window.removeEventListener('mousemove', onMouseMove)
|
||||
window.removeEventListener('mouseup', onMouseUp)
|
||||
editor.finalizeSelections()
|
||||
|
||||
window.addEventListener('mousemove', onMouseMove)
|
||||
window.addEventListener('mouseup', onMouseUp)
|
||||
|
||||
requestScrollViewMeasurement: ->
|
||||
return if @measurementPending
|
||||
|
||||
@scrollViewMeasurementRequested = true
|
||||
requestAnimationFrame =>
|
||||
@scrollViewMeasurementRequested = false
|
||||
@measureScrollView()
|
||||
|
||||
# Measure explicitly-styled height and width and relay them to the model. If
|
||||
# these values aren't explicitly styled, we assume the editor is unconstrained
|
||||
# and use the scrollHeight / scrollWidth as its height and width in
|
||||
# calculations.
|
||||
measureScrollView: ->
|
||||
return unless @isMounted()
|
||||
|
||||
{editor} = @props
|
||||
editorNode = @getDOMNode()
|
||||
scrollViewNode = @refs.scrollView.getDOMNode()
|
||||
{position} = getComputedStyle(editorNode)
|
||||
{width, height} = editorNode.style
|
||||
|
||||
if position is 'absolute' or height
|
||||
clientHeight = scrollViewNode.clientHeight
|
||||
editor.setHeight(clientHeight) if clientHeight > 0
|
||||
|
||||
if position is 'absolute' or width
|
||||
clientWidth = scrollViewNode.clientWidth
|
||||
editor.setWidth(clientWidth) if clientWidth > 0
|
||||
|
||||
measureLineHeightAndCharWidthsIfNeeded: (prevState) ->
|
||||
if not isEqualForProperties(prevState, @state, 'lineHeight', 'fontSize', 'fontFamily')
|
||||
if @state.visible
|
||||
@measureLineHeightAndDefaultCharWidth()
|
||||
else
|
||||
@measureLineHeightAndDefaultCharWidthWhenShown = true
|
||||
else if @measureLineHeightAndDefaultCharWidthWhenShown and @state.visible and not prevState.visible
|
||||
@measureLineHeightAndDefaultCharWidth()
|
||||
|
||||
measureLineHeightAndDefaultCharWidth: ->
|
||||
@measureLineHeightAndDefaultCharWidthWhenShown = false
|
||||
@refs.lines.measureLineHeightAndDefaultCharWidth()
|
||||
|
||||
remeasureCharacterWidthsIfNeeded: (prevState) ->
|
||||
if not isEqualForProperties(prevState, @state, 'fontSize', 'fontFamily')
|
||||
if @state.visible
|
||||
@remeasureCharacterWidths()
|
||||
else
|
||||
@remeasureCharacterWidthsWhenShown = true
|
||||
else if @remeasureCharacterWidthsWhenShown and @state.visible and not prevState.visible
|
||||
@remeasureCharacterWidths()
|
||||
|
||||
remeasureCharacterWidths: ->
|
||||
@remeasureCharacterWidthsWhenShown = false
|
||||
@refs.lines.remeasureCharacterWidths()
|
||||
|
||||
onGutterWidthChanged: (@gutterWidth) ->
|
||||
@requestUpdate()
|
||||
|
||||
measureScrollbars: ->
|
||||
@measuringScrollbars = false
|
||||
|
||||
{editor} = @props
|
||||
scrollbarCornerNode = @refs.scrollbarCorner.getDOMNode()
|
||||
width = (scrollbarCornerNode.offsetWidth - scrollbarCornerNode.clientWidth) or 15
|
||||
height = (scrollbarCornerNode.offsetHeight - scrollbarCornerNode.clientHeight) or 15
|
||||
editor.setVerticalScrollbarWidth(width)
|
||||
editor.setHorizontalScrollbarHeight(height)
|
||||
|
||||
containsScrollbarSelector: (stylesheet) ->
|
||||
for rule in stylesheet.cssRules
|
||||
if rule.selectorText?.indexOf('scrollbar') > -1
|
||||
@@ -345,69 +759,141 @@ EditorComponent = React.createClass
|
||||
# visible, so first we need to hide scrollbars so we can redisplay them and
|
||||
# force Chromium to apply updates.
|
||||
@refreshingScrollbars = true
|
||||
@requestUpdate()
|
||||
@forceUpdate()
|
||||
|
||||
# Next, we display only the scrollbar corner so we can measure the new
|
||||
# scrollbar dimensions. The ::measuringScrollbars property will be set back
|
||||
# to false after the scrollbars are measured.
|
||||
@measuringScrollbars = true
|
||||
@requestUpdate()
|
||||
@forceUpdate()
|
||||
|
||||
# Finally, we restore the scrollbars based on the newly-measured dimensions
|
||||
# if the editor's content and dimensions require them to be visible.
|
||||
@requestUpdate()
|
||||
@forceUpdate()
|
||||
|
||||
clearPreservedRowRange: ->
|
||||
@preservedRowRange = null
|
||||
@scrollingVertically = false
|
||||
@requestUpdate()
|
||||
|
||||
clearPreservedRowRangeAfterDelay: null # Created lazily
|
||||
|
||||
onBatchedUpdatesStarted: ->
|
||||
@batchingUpdates = true
|
||||
|
||||
onBatchedUpdatesEnded: ->
|
||||
updateRequested = @updateRequested
|
||||
@updateRequested = false
|
||||
@batchingUpdates = false
|
||||
if updateRequested
|
||||
clearMouseWheelScreenRow: ->
|
||||
if @mouseWheelScreenRow?
|
||||
@mouseWheelScreenRow = null
|
||||
@requestUpdate()
|
||||
|
||||
onScreenLinesChanged: (change) ->
|
||||
{editor} = @props
|
||||
@pendingChanges.push(change)
|
||||
@requestUpdate() if editor.intersectsVisibleRowRange(change.start, change.end + 1) # TODO: Use closed-open intervals for change events
|
||||
|
||||
onSelectionAdded: (selection) ->
|
||||
{editor} = @props
|
||||
@requestUpdate() if editor.selectionIntersectsVisibleRowRange(selection)
|
||||
|
||||
onScrollTopChanged: ->
|
||||
@preservedRowRange = @getRenderedRowRange()
|
||||
@scrollingVertically = true
|
||||
@clearPreservedRowRangeAfterDelay ?= debounce(@clearPreservedRowRange, 200)
|
||||
@clearPreservedRowRangeAfterDelay()
|
||||
@requestUpdate()
|
||||
|
||||
onSelectionRemoved: (selection) ->
|
||||
{editor} = @props
|
||||
@requestUpdate() if editor.selectionIntersectsVisibleRowRange(selection)
|
||||
|
||||
onCursorsMoved: ->
|
||||
@cursorsMoved = true
|
||||
|
||||
onGutterWidthChanged: (@gutterWidth) ->
|
||||
@requestUpdate()
|
||||
|
||||
requestUpdate: ->
|
||||
if @batchingUpdates
|
||||
@updateRequested = true
|
||||
else
|
||||
@forceUpdate()
|
||||
|
||||
measureHeightAndWidth: ->
|
||||
@refs.scrollView.measureHeightAndWidth()
|
||||
clearMouseWheelScreenRowAfterDelay: null # created lazily
|
||||
|
||||
consolidateSelections: (e) ->
|
||||
e.abortKeyBinding() unless @props.editor.consolidateSelections()
|
||||
|
||||
lineNodeForScreenRow: (screenRow) -> @refs.lines.lineNodeForScreenRow(screenRow)
|
||||
|
||||
lineNumberNodeForScreenRow: (screenRow) -> @refs.gutter.lineNumberNodeForScreenRow(screenRow)
|
||||
|
||||
screenRowForNode: (node) ->
|
||||
while node isnt document
|
||||
if screenRow = node.dataset.screenRow
|
||||
return parseInt(screenRow)
|
||||
node = node.parentNode
|
||||
null
|
||||
|
||||
hide: ->
|
||||
@setState(visible: false)
|
||||
|
||||
show: ->
|
||||
@setState(visible: true)
|
||||
|
||||
getFontSize: ->
|
||||
@state.fontSize
|
||||
|
||||
setFontSize: (fontSize) ->
|
||||
@setState({fontSize})
|
||||
|
||||
getFontFamily: ->
|
||||
@state.fontFamily
|
||||
|
||||
setFontFamily: (fontFamily) ->
|
||||
@setState({fontFamily})
|
||||
|
||||
setLineHeight: (lineHeight) ->
|
||||
@setState({lineHeight})
|
||||
|
||||
setShowIndentGuide: (showIndentGuide) ->
|
||||
@setState({showIndentGuide})
|
||||
|
||||
# Public: Defines which characters are invisible.
|
||||
#
|
||||
# invisibles - An {Object} defining the invisible characters:
|
||||
# :eol - The end of line invisible {String} (default: `\u00ac`).
|
||||
# :space - The space invisible {String} (default: `\u00b7`).
|
||||
# :tab - The tab invisible {String} (default: `\u00bb`).
|
||||
# :cr - The carriage return invisible {String} (default: `\u00a4`).
|
||||
setInvisibles: (invisibles={}) ->
|
||||
defaults invisibles,
|
||||
eol: '\u00ac'
|
||||
space: '\u00b7'
|
||||
tab: '\u00bb'
|
||||
cr: '\u00a4'
|
||||
|
||||
@setState({invisibles})
|
||||
|
||||
setShowInvisibles: (showInvisibles) ->
|
||||
@setState({showInvisibles})
|
||||
|
||||
setScrollSensitivity: (scrollSensitivity) ->
|
||||
if scrollSensitivity = parseInt(scrollSensitivity)
|
||||
@scrollSensitivity = Math.abs(scrollSensitivity) / 100
|
||||
|
||||
screenPositionForMouseEvent: (event) ->
|
||||
pixelPosition = @pixelPositionForMouseEvent(event)
|
||||
@props.editor.screenPositionForPixelPosition(pixelPosition)
|
||||
|
||||
pixelPositionForMouseEvent: (event) ->
|
||||
{editor} = @props
|
||||
{clientX, clientY} = event
|
||||
|
||||
scrollViewClientRect = @refs.scrollView.getDOMNode().getBoundingClientRect()
|
||||
top = clientY - scrollViewClientRect.top + editor.getScrollTop()
|
||||
left = clientX - scrollViewClientRect.left + editor.getScrollLeft()
|
||||
{top, left}
|
||||
|
||||
getModel: ->
|
||||
@props.editor
|
||||
|
||||
isInputEnabled: -> @inputEnabled
|
||||
|
||||
setInputEnabled: (@inputEnabled) -> @inputEnabled
|
||||
|
||||
updateParentViewFocusedClassIfNeeded: (prevState) ->
|
||||
if prevState.focused isnt @state.focused
|
||||
@props.parentView.toggleClass('is-focused', @props.focused)
|
||||
|
||||
runScrollBenchmark: ->
|
||||
unless process.env.NODE_ENV is 'production'
|
||||
ReactPerf = require 'react-atom-fork/lib/ReactDefaultPerf'
|
||||
ReactPerf.start()
|
||||
|
||||
node = @getDOMNode()
|
||||
|
||||
scroll = (delta, done) ->
|
||||
dispatchMouseWheelEvent = ->
|
||||
node.dispatchEvent(new WheelEvent('mousewheel', wheelDeltaX: -0, wheelDeltaY: -delta))
|
||||
|
||||
stopScrolling = ->
|
||||
clearInterval(interval)
|
||||
done?()
|
||||
|
||||
interval = setInterval(dispatchMouseWheelEvent, 10)
|
||||
setTimeout(stopScrolling, 500)
|
||||
|
||||
console.timeline('scroll')
|
||||
scroll 50, ->
|
||||
scroll 100, ->
|
||||
scroll 200, ->
|
||||
scroll 400, ->
|
||||
scroll 800, ->
|
||||
scroll 1600, ->
|
||||
console.timelineEnd('scroll')
|
||||
unless process.env.NODE_ENV is 'production'
|
||||
ReactPerf.stop()
|
||||
console.log "Inclusive"
|
||||
ReactPerf.printInclusive()
|
||||
console.log "Exclusive"
|
||||
ReactPerf.printExclusive()
|
||||
console.log "Wasted"
|
||||
ReactPerf.printWasted()
|
||||
|
||||
@@ -1,200 +0,0 @@
|
||||
React = require 'react'
|
||||
{div} = require 'reactionary'
|
||||
{debounce} = require 'underscore-plus'
|
||||
|
||||
InputComponent = require './input-component'
|
||||
LinesComponent = require './lines-component'
|
||||
CursorsComponent = require './cursors-component'
|
||||
SelectionsComponent = require './selections-component'
|
||||
|
||||
module.exports =
|
||||
EditorScrollViewComponent = React.createClass
|
||||
displayName: 'EditorScrollViewComponent'
|
||||
|
||||
measurementPending: false
|
||||
overflowChangedEventsPaused: false
|
||||
overflowChangedWhilePaused: false
|
||||
|
||||
render: ->
|
||||
{editor, fontSize, fontFamily, lineHeight, showIndentGuide} = @props
|
||||
{scrollHeight, scrollWidth, renderedRowRange, pendingChanges, scrollingVertically} = @props
|
||||
{cursorBlinkPeriod, cursorBlinkResumeDelay, cursorsMoved, onInputFocused, onInputBlurred} = @props
|
||||
|
||||
if @isMounted()
|
||||
inputStyle = @getHiddenInputPosition()
|
||||
inputStyle.WebkitTransform = 'translateZ(0)'
|
||||
|
||||
contentStyle =
|
||||
height: scrollHeight
|
||||
minWidth: scrollWidth
|
||||
WebkitTransform: "translate3d(#{-editor.getScrollLeft()}px, #{-editor.getScrollTop()}px, 0)"
|
||||
|
||||
div className: 'scroll-view',
|
||||
InputComponent
|
||||
ref: 'input'
|
||||
className: 'hidden-input'
|
||||
style: inputStyle
|
||||
onInput: @onInput
|
||||
onFocus: onInputFocused
|
||||
onBlur: onInputBlurred
|
||||
|
||||
div className: 'scroll-view-content', style: contentStyle, onMouseDown: @onMouseDown,
|
||||
CursorsComponent({editor, cursorsMoved, cursorBlinkPeriod, cursorBlinkResumeDelay})
|
||||
LinesComponent {
|
||||
ref: 'lines', editor, fontSize, fontFamily, lineHeight, showIndentGuide,
|
||||
renderedRowRange, pendingChanges, scrollingVertically
|
||||
}
|
||||
div className: 'underlayer',
|
||||
SelectionsComponent({editor})
|
||||
|
||||
componentDidMount: ->
|
||||
@getDOMNode().addEventListener 'overflowchanged', @onOverflowChanged
|
||||
window.addEventListener('resize', @onWindowResize)
|
||||
|
||||
@measureHeightAndWidth()
|
||||
|
||||
componentDidUnmount: ->
|
||||
window.removeEventListener('resize', @onWindowResize)
|
||||
|
||||
componentDidUpdate: ->
|
||||
@pauseOverflowChangedEvents()
|
||||
|
||||
onOverflowChanged: ->
|
||||
if @overflowChangedEventsPaused
|
||||
@overflowChangedWhilePaused = true
|
||||
else
|
||||
@requestMeasurement()
|
||||
|
||||
onWindowResize: ->
|
||||
@requestMeasurement()
|
||||
|
||||
pauseOverflowChangedEvents: ->
|
||||
@overflowChangedEventsPaused = true
|
||||
@resumeOverflowChangedEventsAfterDelay ?= debounce(@resumeOverflowChangedEvents, 500)
|
||||
@resumeOverflowChangedEventsAfterDelay()
|
||||
|
||||
resumeOverflowChangedEvents: ->
|
||||
if @overflowChangedWhilePaused
|
||||
@overflowChangedWhilePaused = false
|
||||
@requestMeasurement()
|
||||
|
||||
resumeOverflowChangedEventsAfterDelay: null
|
||||
|
||||
requestMeasurement: ->
|
||||
return if @measurementPending
|
||||
|
||||
@measurementPending = true
|
||||
requestAnimationFrame =>
|
||||
@measurementPending = false
|
||||
@measureHeightAndWidth()
|
||||
|
||||
onInput: (char, replaceLastCharacter) ->
|
||||
{editor} = @props
|
||||
|
||||
if replaceLastCharacter
|
||||
editor.transact ->
|
||||
editor.selectLeft()
|
||||
editor.insertText(char)
|
||||
else
|
||||
editor.insertText(char)
|
||||
|
||||
onMouseDown: (event) ->
|
||||
{editor} = @props
|
||||
{detail, shiftKey, metaKey} = event
|
||||
screenPosition = @screenPositionForMouseEvent(event)
|
||||
|
||||
if shiftKey
|
||||
editor.selectToScreenPosition(screenPosition)
|
||||
else if metaKey
|
||||
editor.addCursorAtScreenPosition(screenPosition)
|
||||
else
|
||||
editor.setCursorScreenPosition(screenPosition)
|
||||
switch detail
|
||||
when 2 then editor.selectWord()
|
||||
when 3 then editor.selectLine()
|
||||
|
||||
@selectToMousePositionUntilMouseUp(event)
|
||||
|
||||
selectToMousePositionUntilMouseUp: (event) ->
|
||||
{editor} = @props
|
||||
dragging = false
|
||||
lastMousePosition = {}
|
||||
|
||||
animationLoop = =>
|
||||
requestAnimationFrame =>
|
||||
if dragging
|
||||
@selectToMousePosition(lastMousePosition)
|
||||
animationLoop()
|
||||
|
||||
onMouseMove = (event) ->
|
||||
lastMousePosition.clientX = event.clientX
|
||||
lastMousePosition.clientY = event.clientY
|
||||
|
||||
# Start the animation loop when the mouse moves prior to a mouseup event
|
||||
unless dragging
|
||||
dragging = true
|
||||
animationLoop()
|
||||
|
||||
# Stop dragging when cursor enters dev tools because we can't detect mouseup
|
||||
onMouseUp() if event.which is 0
|
||||
|
||||
onMouseUp = ->
|
||||
dragging = false
|
||||
window.removeEventListener('mousemove', onMouseMove)
|
||||
window.removeEventListener('mouseup', onMouseUp)
|
||||
editor.finalizeSelections()
|
||||
|
||||
window.addEventListener('mousemove', onMouseMove)
|
||||
window.addEventListener('mouseup', onMouseUp)
|
||||
|
||||
selectToMousePosition: (event) ->
|
||||
@props.editor.selectToScreenPosition(@screenPositionForMouseEvent(event))
|
||||
|
||||
screenPositionForMouseEvent: (event) ->
|
||||
pixelPosition = @pixelPositionForMouseEvent(event)
|
||||
@props.editor.screenPositionForPixelPosition(pixelPosition)
|
||||
|
||||
pixelPositionForMouseEvent: (event) ->
|
||||
{editor} = @props
|
||||
{clientX, clientY} = event
|
||||
|
||||
editorClientRect = @getDOMNode().getBoundingClientRect()
|
||||
top = clientY - editorClientRect.top + editor.getScrollTop()
|
||||
left = clientX - editorClientRect.left + editor.getScrollLeft()
|
||||
{top, left}
|
||||
|
||||
getHiddenInputPosition: ->
|
||||
{editor} = @props
|
||||
return {top: 0, left: 0} unless @isMounted() and editor.getCursor()?
|
||||
|
||||
{top, left, height, width} = editor.getCursor().getPixelRect()
|
||||
top = top - editor.getScrollTop()
|
||||
top = Math.max(0, Math.min(editor.getHeight() - height, top))
|
||||
left = left - editor.getScrollLeft()
|
||||
left = Math.max(0, Math.min(editor.getWidth() - width, left))
|
||||
|
||||
{top, left}
|
||||
|
||||
# Measure explicitly-styled height and width and relay them to the model. If
|
||||
# these values aren't explicitly styled, we assume the editor is unconstrained
|
||||
# and use the scrollHeight / scrollWidth as its height and width in
|
||||
# calculations.
|
||||
measureHeightAndWidth: ->
|
||||
return unless @isMounted()
|
||||
|
||||
{editor} = @props
|
||||
node = @getDOMNode()
|
||||
editorNode = node.parentNode
|
||||
{position} = getComputedStyle(editorNode)
|
||||
{width, height} = editorNode.style
|
||||
|
||||
if position is 'absolute' or height
|
||||
clientHeight = node.clientHeight
|
||||
editor.setHeight(clientHeight) if clientHeight > 0
|
||||
|
||||
if position is 'absolute' or width
|
||||
clientWidth = node.clientWidth
|
||||
editor.setWidth(clientWidth) if clientWidth > 0
|
||||
|
||||
focus: ->
|
||||
@refs.input.focus()
|
||||
@@ -28,7 +28,7 @@ LongLineLength = 1000
|
||||
# ## Iterating over the open editor views
|
||||
#
|
||||
# ```coffee
|
||||
# for editorView in atom.workspace.getEditorViews()
|
||||
# for editorView in atom.workspaceView.getEditorViews()
|
||||
# console.log(editorView.getEditor().getPath())
|
||||
# ```
|
||||
#
|
||||
@@ -56,6 +56,7 @@ class EditorView extends View
|
||||
softWrap: false
|
||||
softTabs: true
|
||||
softWrapAtPreferredLineLength: false
|
||||
scrollSensitivity: 40
|
||||
|
||||
@nextEditorId: 1
|
||||
|
||||
@@ -156,9 +157,12 @@ class EditorView extends View
|
||||
'editor:consolidate-selections': (event) => @consolidateSelections(event)
|
||||
'editor:delete-to-beginning-of-word': => @editor.deleteToBeginningOfWord()
|
||||
'editor:delete-to-beginning-of-line': => @editor.deleteToBeginningOfLine()
|
||||
'editor:delete-to-end-of-line': => @editor.deleteToEndOfLine()
|
||||
'editor:delete-to-end-of-word': => @editor.deleteToEndOfWord()
|
||||
'editor:delete-line': => @editor.deleteLine()
|
||||
'editor:cut-to-end-of-line': => @editor.cutToEndOfLine()
|
||||
'editor:move-to-beginning-of-next-paragraph': => @editor.moveCursorToBeginningOfNextParagraph()
|
||||
'editor:move-to-beginning-of-previous-paragraph': => @editor.moveCursorToBeginningOfPreviousParagraph()
|
||||
'editor:move-to-beginning-of-screen-line': => @editor.moveCursorToBeginningOfScreenLine()
|
||||
'editor:move-to-beginning-of-line': => @editor.moveCursorToBeginningOfLine()
|
||||
'editor:move-to-end-of-screen-line': => @editor.moveCursorToEndOfScreenLine()
|
||||
@@ -169,6 +173,8 @@ class EditorView extends View
|
||||
'editor:move-to-beginning-of-next-word': => @editor.moveCursorToBeginningOfNextWord()
|
||||
'editor:move-to-previous-word-boundary': => @editor.moveCursorToPreviousWordBoundary()
|
||||
'editor:move-to-next-word-boundary': => @editor.moveCursorToNextWordBoundary()
|
||||
'editor:select-to-beginning-of-next-paragraph': => @editor.selectToBeginningOfNextParagraph()
|
||||
'editor:select-to-beginning-of-previous-paragraph': => @editor.selectToBeginningOfPreviousParagraph()
|
||||
'editor:select-to-end-of-line': => @editor.selectToEndOfLine()
|
||||
'editor:select-to-beginning-of-line': => @editor.selectToBeginningOfLine()
|
||||
'editor:select-to-end-of-word': => @editor.selectToEndOfWord()
|
||||
@@ -188,12 +194,14 @@ class EditorView extends View
|
||||
'core:move-down': => @editor.moveCursorDown()
|
||||
'core:move-to-top': => @editor.moveCursorToTop()
|
||||
'core:move-to-bottom': => @editor.moveCursorToBottom()
|
||||
'core:page-down': => @pageDown()
|
||||
'core:page-up': => @pageUp()
|
||||
'core:page-down': => @pageDown()
|
||||
'core:select-up': => @editor.selectUp()
|
||||
'core:select-down': => @editor.selectDown()
|
||||
'core:select-to-top': => @editor.selectToTop()
|
||||
'core:select-to-bottom': => @editor.selectToBottom()
|
||||
'core:select-page-up': => @editor.selectUp(@getPageRows())
|
||||
'core:select-page-down': => @editor.selectDown(@getPageRows())
|
||||
'editor:indent': => @editor.indent()
|
||||
'editor:auto-indent': => @editor.autoIndentSelectedRows()
|
||||
'editor:indent-selected-rows': => @editor.indentSelectedRows()
|
||||
@@ -278,7 +286,7 @@ class EditorView extends View
|
||||
@editor.moveCursorUp(@getPageRows())
|
||||
@scrollTop(newScrollTop, adjustVerticalScrollbar: true)
|
||||
|
||||
# Public: Gets the number of actual page rows existing in an editor.
|
||||
# Gets the number of actual page rows existing in an editor.
|
||||
#
|
||||
# Returns a {Number}.
|
||||
getPageRows: ->
|
||||
@@ -363,6 +371,8 @@ class EditorView extends View
|
||||
false if @isFocused
|
||||
|
||||
@overlayer.on 'mousedown', (e) =>
|
||||
return unless e.which is 1 # only handle the left mouse button
|
||||
|
||||
@overlayer.hide()
|
||||
clickedElement = document.elementFromPoint(e.pageX, e.pageY)
|
||||
@overlayer.show()
|
||||
@@ -545,7 +555,6 @@ class EditorView extends View
|
||||
@showBufferConflictAlert(@editor)
|
||||
|
||||
@subscribe @editor, "path-changed", =>
|
||||
@editor.reloadGrammar()
|
||||
@trigger 'editor:path-changed'
|
||||
|
||||
@subscribe @editor, "grammar-changed", =>
|
||||
@@ -563,7 +572,7 @@ class EditorView extends View
|
||||
@scrollTop(scrollTop)
|
||||
|
||||
@subscribe @editor, 'scroll-left-changed', (scrollLeft) =>
|
||||
@scrollLeft(scrollLeft)
|
||||
@scrollView.scrollLeft(scrollLeft)
|
||||
|
||||
@subscribe @editor, 'soft-wrap-changed', (softWrap) =>
|
||||
@setSoftWrap(softWrap)
|
||||
|
||||
+139
-24
@@ -112,6 +112,7 @@ TextMateScopeSelector = require('first-mate').ScopeSelector
|
||||
# - {::deleteToBeginningOfWord}
|
||||
# - {::deleteToBeginningOfLine}
|
||||
# - {::delete}
|
||||
# - {::deleteToEndOfLine}
|
||||
# - {::deleteToEndOfWord}
|
||||
# - {::deleteLine}
|
||||
# - {::cutSelectedText}
|
||||
@@ -144,12 +145,13 @@ class Editor extends Model
|
||||
cursors: null
|
||||
selections: null
|
||||
suppressSelectionMerging: false
|
||||
updateBatchDepth: 0
|
||||
|
||||
@delegatesMethods 'suggestedIndentForBufferRow', 'autoIndentBufferRow', 'autoIndentBufferRows',
|
||||
'autoDecreaseIndentForBufferRow', 'toggleLineCommentForBufferRow', 'toggleLineCommentsForBufferRows',
|
||||
toProperty: 'languageMode'
|
||||
|
||||
@delegatesProperties '$lineHeight', '$defaultCharWidth', '$height', '$width',
|
||||
@delegatesProperties '$lineHeightInPixels', '$defaultCharWidth', '$height', '$width',
|
||||
'$scrollTop', '$scrollLeft', 'manageScrollPosition', toProperty: 'displayBuffer'
|
||||
|
||||
constructor: ({@softTabs, initialLine, initialColumn, tabLength, softWrap, @displayBuffer, buffer, registerEditor, suppressCursorCreation}) ->
|
||||
@@ -211,7 +213,11 @@ class Editor extends Model
|
||||
@subscribe @displayBuffer, "changed", (e) => @emit 'screen-lines-changed', e
|
||||
@subscribe @displayBuffer, "markers-updated", => @mergeIntersectingSelections()
|
||||
@subscribe @displayBuffer, 'grammar-changed', => @handleGrammarChange()
|
||||
@subscribe @displayBuffer, 'tokenized', => @handleTokenization()
|
||||
@subscribe @displayBuffer, 'soft-wrap-changed', (args...) => @emit 'soft-wrap-changed', args...
|
||||
@subscribe @displayBuffer, "decoration-added", (args...) => @emit 'decoration-added', args...
|
||||
@subscribe @displayBuffer, "decoration-removed", (args...) => @emit 'decoration-removed', args...
|
||||
@subscribe @displayBuffer, "character-widths-changed", (changeCount) => @emit 'character-widths-changed', changeCount
|
||||
|
||||
getViewClass: ->
|
||||
if atom.config.get('core.useReactEditor')
|
||||
@@ -259,7 +265,8 @@ class Editor extends Model
|
||||
getLongTitle: ->
|
||||
if sessionPath = @getPath()
|
||||
fileName = path.basename(sessionPath)
|
||||
directory = path.basename(path.dirname(sessionPath))
|
||||
directory = atom.project.relativize(path.dirname(sessionPath))
|
||||
directory = if directory.length > 0 then directory else path.basename(path.dirname(sessionPath))
|
||||
"#{fileName} - #{directory}"
|
||||
else
|
||||
'untitled'
|
||||
@@ -685,6 +692,13 @@ class Editor extends Model
|
||||
delete: ->
|
||||
@mutateSelectedText (selection) -> selection.delete()
|
||||
|
||||
# Public: For each selection, if the selection is not empty, deletes the
|
||||
# selection; otherwise, deletes all characters of the containing line
|
||||
# following the cursor. If the cursor is already at the end of the line,
|
||||
# deletes the following newline.
|
||||
deleteToEndOfLine: ->
|
||||
@mutateSelectedText (selection) -> selection.deleteToEndOfLine()
|
||||
|
||||
# Public: For each selection, if the selection is empty, delete all characters
|
||||
# of the containing word following the cursor. Otherwise delete the selected
|
||||
# text.
|
||||
@@ -839,6 +853,10 @@ class Editor extends Model
|
||||
isFoldableAtBufferRow: (bufferRow) ->
|
||||
@languageMode.isFoldableAtBufferRow(bufferRow)
|
||||
|
||||
isFoldableAtScreenRow: (screenRow) ->
|
||||
bufferRow = @displayBuffer.bufferRowForScreenRow(screenRow)
|
||||
@isFoldableAtBufferRow(bufferRow)
|
||||
|
||||
# TODO: Rename to foldRowRange?
|
||||
createFold: (startRow, endRow) ->
|
||||
@displayBuffer.createFold(startRow, endRow)
|
||||
@@ -1054,6 +1072,66 @@ class Editor extends Model
|
||||
selection.insertText(fn(text))
|
||||
selection.setBufferRange(range)
|
||||
|
||||
# Public: Get all the decorations within a screen row range.
|
||||
#
|
||||
# startScreenRow - the {Number} beginning screen row
|
||||
# endScreenRow - the {Number} end screen row (inclusive)
|
||||
#
|
||||
# Returns an {Object} of decorations in the form `{1: [{type: 'gutter', class: 'someclass'}], 2: ...}`
|
||||
# where the keys are markerIds, and the values are an array of decoration objects attached to the marker.
|
||||
# Returns an empty object when no decorations are found
|
||||
decorationsForScreenRowRange: (startScreenRow, endScreenRow) ->
|
||||
@displayBuffer.decorationsForScreenRowRange(startScreenRow, endScreenRow)
|
||||
|
||||
# Public: Adds a decoration that tracks a {Marker}. When the marker moves,
|
||||
# is invalidated, or is destroyed, the decoration will be updated to reflect the marker's state.
|
||||
#
|
||||
# There are a few supported decoration types:
|
||||
# * `gutter`: `{type: 'gutter', class: 'linter-error'}` Will add a class to the gutter rows associated with the marker.
|
||||
# * `line`: `{type: 'line', class: 'linter-error'}` Will add a class to the editor lines associated with the marker.
|
||||
# * `highlight`: `{type: 'highlight', class: 'linter-error'}` Will highlight the region of the buffer associated with the marker. Your specified class will be added to the highlight.
|
||||
#
|
||||
# marker - the {Marker} you want this decoration to follow
|
||||
# decoration - the {Object} decoration eg. `{type: 'gutter', class: 'linter-error'}`
|
||||
#
|
||||
# Returns nothing
|
||||
addDecorationForMarker: (marker, decoration) ->
|
||||
@displayBuffer.addDecorationForMarker(marker, decoration)
|
||||
|
||||
# Public: Removes all decorations associated with a {Marker} that match a
|
||||
# `decorationPattern` and stop tracking the {Marker}.
|
||||
#
|
||||
# ```coffee
|
||||
# marker = editor.markBufferRange([[4, 13], [5, 17]])
|
||||
# editor.removeDecorationForMarker(marker, {type: 'gutter', class: 'linter-error'})
|
||||
# ```
|
||||
#
|
||||
# All decorations matching a pattern will be removed. For example, you might
|
||||
# have decorations with a namespace like this attached to a row:
|
||||
#
|
||||
# ```coffee
|
||||
# [
|
||||
# {type: 'gutter', namespace: 'myns', class: 'something'},
|
||||
# {type: 'gutter', namespace: 'myns', class: 'something-else'}
|
||||
# ]
|
||||
# ```
|
||||
#
|
||||
# You can remove both with:
|
||||
#
|
||||
# ```coffee
|
||||
# editor.removeDecorationForMarker(marker, {namespace: 'myns'})
|
||||
# ```
|
||||
#
|
||||
# marker - the {Marker} to detach from
|
||||
# decorationPattern - the {Object} decoration type to filter by eg. `{type: 'gutter', class: 'linter-error'}`
|
||||
#
|
||||
# Returns nothing
|
||||
removeDecorationForMarker: (marker, decorationPattern) ->
|
||||
@displayBuffer.removeDecorationForMarker(marker, decorationPattern)
|
||||
|
||||
decorationMatchesType: (decoration, type) ->
|
||||
@displayBuffer.decorationMatchesType(decoration, type)
|
||||
|
||||
# Public: Get the {DisplayBufferMarker} for the given marker id.
|
||||
getMarker: (id) ->
|
||||
@displayBuffer.getMarker(id)
|
||||
@@ -1159,6 +1237,7 @@ class Editor extends Model
|
||||
addCursor: (marker) ->
|
||||
cursor = new Cursor(editor: this, marker: marker)
|
||||
@cursors.push(cursor)
|
||||
@addDecorationForMarker(marker, type: ['gutter', 'line'], class: 'cursor-line')
|
||||
@emit 'cursor-added', cursor
|
||||
cursor
|
||||
|
||||
@@ -1185,6 +1264,7 @@ class Editor extends Model
|
||||
if selection.intersectsBufferRange(selectionBufferRange)
|
||||
return selection
|
||||
else
|
||||
@addDecorationForMarker(marker, type: 'highlight', class: 'selection')
|
||||
@emit 'selection-added', selection
|
||||
selection
|
||||
|
||||
@@ -1198,7 +1278,9 @@ class Editor extends Model
|
||||
# Returns the added {Selection}.
|
||||
addSelectionForBufferRange: (bufferRange, options={}) ->
|
||||
@markBufferRange(bufferRange, _.defaults(@getSelectionMarkerAttributes(), options))
|
||||
@getLastSelection()
|
||||
selection = @getLastSelection()
|
||||
selection.autoscroll()
|
||||
selection
|
||||
|
||||
# Public: Set the selected range in buffer coordinates. If there are multiple
|
||||
# selections, they are reduced to a single selection with the given range.
|
||||
@@ -1269,6 +1351,9 @@ class Editor extends Model
|
||||
# Returns: An {Array} of {Selection}s.
|
||||
getSelections: -> new Array(@selections...)
|
||||
|
||||
selectionsForScreenRows: (startRow, endRow) ->
|
||||
@getSelections().filter (selection) -> selection.intersectsScreenRowRange(startRow, endRow)
|
||||
|
||||
# Public: Get the most recent {Selection} or the selection at the given
|
||||
# index.
|
||||
#
|
||||
@@ -1485,22 +1570,43 @@ class Editor extends Model
|
||||
moveCursorToNextWordBoundary: ->
|
||||
@moveCursors (cursor) -> cursor.moveToNextWordBoundary()
|
||||
|
||||
# Public: Move every cursor to the beginning of the next paragraph.
|
||||
moveCursorToBeginningOfNextParagraph: ->
|
||||
@moveCursors (cursor) -> cursor.moveToBeginningOfNextParagraph()
|
||||
|
||||
# Public: Move every cursor to the beginning of the previous paragraph.
|
||||
moveCursorToBeginningOfPreviousParagraph: ->
|
||||
@moveCursors (cursor) -> cursor.moveToBeginningOfPreviousParagraph()
|
||||
|
||||
scrollToCursorPosition: ->
|
||||
@getCursor().autoscroll()
|
||||
|
||||
pageUp: ->
|
||||
@setScrollTop(@getScrollTop() - @getHeight())
|
||||
newScrollTop = @getScrollTop() - @getHeight()
|
||||
@moveCursorUp(@getRowsPerPage())
|
||||
@setScrollTop(newScrollTop)
|
||||
|
||||
pageDown: ->
|
||||
@setScrollTop(@getScrollTop() + @getHeight())
|
||||
newScrollTop = @getScrollTop() + @getHeight()
|
||||
@moveCursorDown(@getRowsPerPage())
|
||||
@setScrollTop(newScrollTop)
|
||||
|
||||
selectPageUp: ->
|
||||
@selectUp(@getRowsPerPage())
|
||||
|
||||
selectPageDown: ->
|
||||
@selectDown(@getRowsPerPage())
|
||||
|
||||
# Returns the number of rows per page
|
||||
getRowsPerPage: ->
|
||||
Math.max(1, Math.ceil(@getHeight() / @getLineHeightInPixels()))
|
||||
|
||||
moveCursors: (fn) ->
|
||||
@movingCursors = true
|
||||
@batchUpdates =>
|
||||
fn(cursor) for cursor in @getCursors()
|
||||
@mergeCursors()
|
||||
@movingCursors = false
|
||||
@emit 'cursors-moved'
|
||||
fn(cursor) for cursor in @getCursors()
|
||||
@mergeCursors()
|
||||
@movingCursors = false
|
||||
@emit 'cursors-moved'
|
||||
|
||||
cursorMoved: (event) ->
|
||||
@emit 'cursor-moved', event
|
||||
@@ -1713,6 +1819,20 @@ class Editor extends Model
|
||||
selectWord: ->
|
||||
@expandSelectionsForward (selection) => selection.selectWord()
|
||||
|
||||
# Public: Expand selections to the beginning of the next paragraph.
|
||||
#
|
||||
# Operates on all selections. Moves the cursor to the beginning of the next
|
||||
# paragraph while preserving the selection's tail position.
|
||||
selectToBeginningOfNextParagraph: ->
|
||||
@expandSelectionsForward (selection) => selection.selectToBeginningOfNextParagraph()
|
||||
|
||||
# Public: Expand selections to the beginning of the next paragraph.
|
||||
#
|
||||
# Operates on all selections. Moves the cursor to the beginning of the next
|
||||
# paragraph while preserving the selection's tail position.
|
||||
selectToBeginningOfPreviousParagraph: ->
|
||||
@expandSelectionsBackward (selection) => selection.selectToBeginningOfPreviousParagraph()
|
||||
|
||||
# Public: Select the range of the given marker if it is valid.
|
||||
#
|
||||
# marker - A {DisplayBufferMarker}
|
||||
@@ -1806,9 +1926,7 @@ class Editor extends Model
|
||||
# execution and revert any changes performed up to the abortion.
|
||||
#
|
||||
# fn - A {Function} to call inside the transaction.
|
||||
transact: (fn) ->
|
||||
@batchUpdates =>
|
||||
@buffer.transact(fn)
|
||||
transact: (fn) -> @buffer.transact(fn)
|
||||
|
||||
# Public: Start an open-ended transaction.
|
||||
#
|
||||
@@ -1828,17 +1946,14 @@ class Editor extends Model
|
||||
# within the transaction.
|
||||
abortTransaction: -> @buffer.abortTransaction()
|
||||
|
||||
batchUpdates: (fn) ->
|
||||
@emit 'batched-updates-started'
|
||||
result = fn()
|
||||
@emit 'batched-updates-ended'
|
||||
result
|
||||
|
||||
inspect: ->
|
||||
"<Editor #{@id}>"
|
||||
|
||||
logScreenLines: (start, end) -> @displayBuffer.logLines(start, end)
|
||||
|
||||
handleTokenization: ->
|
||||
@softTabs = @usesSoftTabs() ? @softTabs
|
||||
|
||||
handleGrammarChange: ->
|
||||
@unfoldAll()
|
||||
@emit 'grammar-changed'
|
||||
@@ -1856,8 +1971,8 @@ class Editor extends Model
|
||||
getHorizontalScrollMargin: -> @displayBuffer.getHorizontalScrollMargin()
|
||||
setHorizontalScrollMargin: (horizontalScrollMargin) -> @displayBuffer.setHorizontalScrollMargin(horizontalScrollMargin)
|
||||
|
||||
getLineHeight: -> @displayBuffer.getLineHeight()
|
||||
setLineHeight: (lineHeight) -> @displayBuffer.setLineHeight(lineHeight)
|
||||
getLineHeightInPixels: -> @displayBuffer.getLineHeightInPixels()
|
||||
setLineHeightInPixels: (lineHeightInPixels) -> @displayBuffer.setLineHeightInPixels(lineHeightInPixels)
|
||||
|
||||
getScopedCharWidth: (scopeNames, char) -> @displayBuffer.getScopedCharWidth(scopeNames, char)
|
||||
setScopedCharWidth: (scopeNames, char, width) -> @displayBuffer.setScopedCharWidth(scopeNames, char, width)
|
||||
@@ -1906,11 +2021,11 @@ class Editor extends Model
|
||||
|
||||
pixelRectForScreenRange: (screenRange) -> @displayBuffer.pixelRectForScreenRange(screenRange)
|
||||
|
||||
scrollToScreenRange: (screenRange) -> @displayBuffer.scrollToScreenRange(screenRange)
|
||||
scrollToScreenRange: (screenRange, options) -> @displayBuffer.scrollToScreenRange(screenRange, options)
|
||||
|
||||
scrollToScreenPosition: (screenPosition) -> @displayBuffer.scrollToScreenPosition(screenPosition)
|
||||
scrollToScreenPosition: (screenPosition, options) -> @displayBuffer.scrollToScreenPosition(screenPosition, options)
|
||||
|
||||
scrollToBufferPosition: (bufferPosition) -> @displayBuffer.scrollToBufferPosition(bufferPosition)
|
||||
scrollToBufferPosition: (bufferPosition, options) -> @displayBuffer.scrollToBufferPosition(bufferPosition, options)
|
||||
|
||||
horizontallyScrollable: -> @displayBuffer.horizontallyScrollable()
|
||||
|
||||
|
||||
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