Comparar commits
783 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 1d01ff0797 | |||
| a1d78a1062 | |||
| 3ac41a544a | |||
| 143738033b | |||
| f1ed5dedd7 | |||
| c9e297a511 | |||
| 18082f7cdc | |||
| bb59e46267 | |||
| 86c4b99eab | |||
| a1e1a00f9f | |||
| 53996e7bb0 | |||
| f88c71e1a1 | |||
| 2cccbff509 | |||
| b173fcdd59 | |||
| 7b6c62ab5e | |||
| 809e57cb84 | |||
| de16ed6250 | |||
| 606160d312 | |||
| 78e990d1f9 | |||
| d47cc6fa0b | |||
| 8f3951fbd8 | |||
| e09486d425 | |||
| 662f252912 | |||
| 784d22368e | |||
| a40660d125 | |||
| af632df48b | |||
| 4a35c9a1af | |||
| f90f48e3f0 | |||
| 9c6a3c3d03 | |||
| 4bccb81656 | |||
| 870e80446f | |||
| 4165a69fed | |||
| 93d9a00819 | |||
| a3789411de | |||
| 2b6b40bda7 | |||
| 61ae185494 | |||
| 0eae68973b | |||
| 6f2695388c | |||
| 0c12f712c9 | |||
| 727d1cf4aa | |||
| 5aff4a042b | |||
| e36bc5bc9f | |||
| 1a88937f5a | |||
| 5737593957 | |||
| d61d8bea86 | |||
| 062974882b | |||
| 8415ddcb49 | |||
| 64f392a380 | |||
| fce09f9bfe | |||
| f04ce025f4 | |||
| 57844c2ca4 | |||
| 91433cfe90 | |||
| 86423698b1 | |||
| 7dda8e1b80 | |||
| 70cd6a6bc3 | |||
| 6e9217be5f | |||
| 3d8c916a72 | |||
| cae9c96622 | |||
| aaf283ceaa | |||
| 4bac60ad94 | |||
| cc2e87b784 | |||
| 363fb0d66e | |||
| 2d2295dcc6 | |||
| bf3daeccc5 | |||
| 63d5caebbc | |||
| 3ac3a89fa5 | |||
| af6d7204f9 | |||
| 642671161d | |||
| b2fdc25c83 | |||
| 893a3f63dd | |||
| 271b104120 | |||
| 247eec44d5 | |||
| d064c27faf | |||
| 1021979d98 | |||
| fcc4376cdd | |||
| e858f74a17 | |||
| 58dc45d496 | |||
| 3029dc8d2a | |||
| 11d7562c12 | |||
| b8b95d537b | |||
| 9ec342a545 | |||
| cf60b1fde3 | |||
| 556cdfd300 | |||
| c566e7f1f3 | |||
| 366312dee8 | |||
| 1acc6bfadf | |||
| 9fd21ce2e1 | |||
| 5525e046e9 | |||
| 68e1e36347 | |||
| 199a0f7089 | |||
| 65564e2012 | |||
| d612a71af5 | |||
| 477624387f | |||
| bf686101dc | |||
| b348ef633c | |||
| 68022837b4 | |||
| 537981ff62 | |||
| 5bc339afae | |||
| 4e9871a26a | |||
| e334d2b640 | |||
| c7efaef1be | |||
| ad751a1a2a | |||
| fad21c6d3e | |||
| 373a7a6d04 | |||
| 0742909953 | |||
| 25fcd25c32 | |||
| 0fe4258a44 | |||
| 0727c8efab | |||
| 7198740b26 | |||
| 634a12470b | |||
| 940145be7a | |||
| fca03552e2 | |||
| f42e880804 | |||
| 341c474dfa | |||
| c3a1831959 | |||
| dde1a0b2eb | |||
| ecfddc1523 | |||
| 13b59213eb | |||
| c0bb3b07c6 | |||
| c804c5ada3 | |||
| 0816e923f9 | |||
| 5d30e30a63 | |||
| 89fdffdfdc | |||
| 8f089a5ce1 | |||
| f3bc2310f0 | |||
| bd9cabea75 | |||
| 2520b3f85a | |||
| 22b967adf5 | |||
| cb514d10d5 | |||
| 9e3b67b4b9 | |||
| 49556e2aa8 | |||
| 94e70d3f25 | |||
| 05c47bd3c0 | |||
| 5b6fe70b7e | |||
| 424bf706e9 | |||
| b1feb9cf2f | |||
| 6948183270 | |||
| 4aa612e70c | |||
| d146faae1d | |||
| aa02bc1aaf | |||
| f9eb8e3466 | |||
| 18e13cfc3b | |||
| c46238f795 | |||
| 50e045212b | |||
| d5c831c64b | |||
| 75b355d632 | |||
| dcf4394741 | |||
| 36a6ecdd9a | |||
| d8dfea00d0 | |||
| 9784d49667 | |||
| cb76c698e7 | |||
| 9d2957a7c9 | |||
| 92a722495b | |||
| 30a2e5d902 | |||
| 409d5c7783 | |||
| 9f567051fb | |||
| 624c7baf44 | |||
| 2671d8bd46 | |||
| 8b928d9320 | |||
| 27ddcfcbcb | |||
| 48798dead9 | |||
| 0adae86b4d | |||
| 92283cabfa | |||
| a4774ada84 | |||
| e6bcf7ec6e | |||
| 27ef1f8749 | |||
| 8ee1c2b591 | |||
| f6f659aec6 | |||
| 61372241f7 | |||
| d398d89de9 | |||
| af4a2340c4 | |||
| 2d9791d61a | |||
| f874ec7cb6 | |||
| 9e4baad701 | |||
| 59b711447c | |||
| 2bb4866e1a | |||
| 72ceaf772d | |||
| 2da9ee0cee | |||
| 9c070cd71d | |||
| 6f068f14fd | |||
| 67d8db8b9a | |||
| 03b9a25897 | |||
| 645fc1511a | |||
| ae1d3b1e80 | |||
| 627a839779 | |||
| 5151faea3d | |||
| eb1bed118f | |||
| fd6476e4d1 | |||
| d62b3d5236 | |||
| bb6aa5eedb | |||
| e9f4820dd4 | |||
| 6bd73f2647 | |||
| d816eca300 | |||
| 03d4fdb890 | |||
| 4aa6e78a4e | |||
| 7ecb0dcd4b | |||
| 1cdec9386c | |||
| ba8f6bccec | |||
| 22c8746ed6 | |||
| 96503f74e4 | |||
| 7fb3396f65 | |||
| 66fa40b29e | |||
| b5aefc6f5e | |||
| cf590685b9 | |||
| a604bfcdf1 | |||
| c389bccfa0 | |||
| ce02dcf5a5 | |||
| d3d38c0312 | |||
| 95d097dd7b | |||
| 47f3b562b5 | |||
| 5eb12e671b | |||
| 023cb2ea55 | |||
| 98ea42d808 | |||
| 4e3a46ee71 | |||
| 9ebc5fa30e | |||
| 810ca750cd | |||
| 424652e27c | |||
| 831beceaac | |||
| 2daf026967 | |||
| dbd6a98bbe | |||
| a4ffdeb842 | |||
| 9b6194c5a4 | |||
| 8e4573677d | |||
| 61e9befbe7 | |||
| 0f50c40a93 | |||
| 907f8c34ac | |||
| c178d4c874 | |||
| 233fd44b01 | |||
| ab88edaa02 | |||
| 50c25d9e44 | |||
| 9be593d390 | |||
| 318c43931c | |||
| 244fc33f49 | |||
| f83f5263a9 | |||
| 3266dde2e3 | |||
| 3428ee335a | |||
| db6b4d7b81 | |||
| 1c195987c1 | |||
| 4913714a61 | |||
| 8e2856465c | |||
| 868c7a3908 | |||
| afaf91ebde | |||
| c92fe1452b | |||
| 2bde128fed | |||
| 89461505b5 | |||
| 85df5e61e5 | |||
| 5e477ff984 | |||
| 2baf9eda61 | |||
| 7d6d8175b9 | |||
| 0fdda032cc | |||
| c82d0f8c1c | |||
| 65ff108615 | |||
| 075611eb65 | |||
| b82537b020 | |||
| 06fee4636a | |||
| 5fe1af3239 | |||
| bf6cc3d384 | |||
| b4a4ba91b0 | |||
| 271776944a | |||
| b1d5a3d75f | |||
| bd68790a10 | |||
| f0a7663447 | |||
| db627d65c7 | |||
| a9f581797a | |||
| 763291230d | |||
| 55a77a34bd | |||
| f4f975c6b7 | |||
| 2d26382510 | |||
| c5cd56a99e | |||
| 24943dd526 | |||
| 8b32e30ee7 | |||
| 72c99be0f2 | |||
| 10ac1f6ae8 | |||
| 524170534c | |||
| d542f35336 | |||
| 697ba53c6b | |||
| 148a8bad2e | |||
| 7a344b91aa | |||
| 5783350484 | |||
| 9fce23d5ac | |||
| 7c17c99b9e | |||
| ff560bc3a3 | |||
| 61f01f4713 | |||
| 2e8c0234bb | |||
| 8e62d772b3 | |||
| 532cfb5775 | |||
| f912eb805d | |||
| 6838ff8ea2 | |||
| 8aa2c40bbf | |||
| c2d603769e | |||
| 3710d85e63 | |||
| 12a72302d9 | |||
| 2c70f0dc27 | |||
| 6165c65a51 | |||
| 3ea3f64214 | |||
| 08601d32a3 | |||
| 0ae1f6858c | |||
| f2e5b480e1 | |||
| 19ab197bc1 | |||
| 8bf1464b64 | |||
| 0ee3421cbc | |||
| a18536e8a4 | |||
| cc2e1eecd3 | |||
| 87b95128f9 | |||
| 344a56b47a | |||
| da8d055817 | |||
| c07272633f | |||
| b26e0d42d5 | |||
| 8ee4e927a1 | |||
| 7eaa3cb2b6 | |||
| 696928540c | |||
| b33f36d30a | |||
| 179b392a49 | |||
| 857f19c382 | |||
| 8a333208a2 | |||
| ff23f62c3e | |||
| dcdc9d6b90 | |||
| 3d28f957c7 | |||
| 2eb2aa5bef | |||
| 371820fd59 | |||
| 596c584ef1 | |||
| 27a1577021 | |||
| 8f2745c248 | |||
| 1c964d05f8 | |||
| 2dcbf7f751 | |||
| 067f73da38 | |||
| ae324c13a6 | |||
| 9a488adbb9 | |||
| 4c0f1efec6 | |||
| 8974cb5f34 | |||
| cb303a3149 | |||
| c44628a5b1 | |||
| fb1effc654 | |||
| 5ab213b854 | |||
| bbf738635c | |||
| 705d3e9fbc | |||
| 6bd3728548 | |||
| 7d997f6d9a | |||
| e919eb3eba | |||
| c2b2096c8c | |||
| 46638d2ea1 | |||
| fdb08517d3 | |||
| f272962562 | |||
| 9e661d8a99 | |||
| 43c0b79273 | |||
| 96e96c3c7f | |||
| 15c51b4417 | |||
| 6c93ca0e42 | |||
| a3cb98a3d3 | |||
| 31ecd39f08 | |||
| 4d986b8417 | |||
| 2d14c06089 | |||
| 7746ad0b13 | |||
| 1cbaf8d1f5 | |||
| cb41e2c41a | |||
| 2fd71f2fa8 | |||
| 37d67e8a83 | |||
| 2f8e67d679 | |||
| 22dc165a25 | |||
| ebfe50aafc | |||
| de58936ed1 | |||
| eba2abd5d9 | |||
| 864ab0c095 | |||
| de3d424f51 | |||
| 68c2c18d83 | |||
| 54907455fe | |||
| ba8ab21a0d | |||
| f272d9abde | |||
| 972f194388 | |||
| adb2f31e7f | |||
| ccfd239ad1 | |||
| 6fc56b9372 | |||
| 9072a6da7a | |||
| d39547097c | |||
| 3b2f58fa22 | |||
| cbddc4eb6f | |||
| 96a0c1039a | |||
| 1390bef626 | |||
| e70a2ab3de | |||
| e0d1bdc072 | |||
| 79c60d3884 | |||
| 1e85bc66b4 | |||
| 0d633a1e27 | |||
| 0759f6a1fd | |||
| 99b5675c4e | |||
| 4f7957183c | |||
| 2de18d3c4d | |||
| fecf13e2df | |||
| 31e44d50e4 | |||
| c28aeeac4a | |||
| 5649de6cd1 | |||
| 26a649abda | |||
| 3b02ae1ce9 | |||
| 13278c3d40 | |||
| 17760a458a | |||
| 282814fe59 | |||
| 35fb02fce9 | |||
| 7286c339c8 | |||
| b956fa4d1f | |||
| 8cb66895f0 | |||
| 3a9584b840 | |||
| 5d20a518ae | |||
| bd3dc453ef | |||
| 151d22c325 | |||
| d6433a67c8 | |||
| be561f0e5e | |||
| 1f6d90319b | |||
| eca63364a6 | |||
| 38f25160d6 | |||
| 28ce023164 | |||
| 10b3d56682 | |||
| 945011f9e3 | |||
| d7c6cd68b9 | |||
| ed4c3fde2d | |||
| c5db1c33a0 | |||
| d719ea74dd | |||
| 996defaadb | |||
| 86cd7f7a01 | |||
| a79090c65a | |||
| 86c720af81 | |||
| a9becd5cc8 | |||
| 1e327699b8 | |||
| 0ba9425bb6 | |||
| 7d19b839d9 | |||
| e1a9f0a533 | |||
| f6d0051446 | |||
| 126df1fa03 | |||
| 0a72d9539f | |||
| 60ecbe054e | |||
| 5a3fa18863 | |||
| bea4f2abde | |||
| 3fc2ca3d77 | |||
| 29fcc4727a | |||
| ddb973b03a | |||
| c2b05f9956 | |||
| 7fd452102f | |||
| c80d3eea47 | |||
| 8421edbb72 | |||
| 03587f54be | |||
| dac7760018 | |||
| bd28d5d7b1 | |||
| 34df19b204 | |||
| 6e824dadf2 | |||
| c50cfc1714 | |||
| d0fcd573bd | |||
| 79089ced97 | |||
| aa6811a088 | |||
| dd27a35039 | |||
| f3b696c5ec | |||
| 8405041f64 | |||
| a372993c44 | |||
| 909e0d7312 | |||
| e8503f7ddc | |||
| 42a6caf7dc | |||
| eaffb12ffb | |||
| 105e0d3c82 | |||
| 534a36c7e1 | |||
| b5b8f757b2 | |||
| 10e3dfbfdb | |||
| bfdcbbe9f1 | |||
| 5d49839236 | |||
| e6508237e7 | |||
| 2d4797c84e | |||
| 392516e60f | |||
| d09a2d0772 | |||
| 2bd5c10f09 | |||
| 5c910113a3 | |||
| c591a2e098 | |||
| b5acc9b093 | |||
| 5b6f8ff0f6 | |||
| d530d0a4d5 | |||
| 211ce4b2d3 | |||
| 1800438a77 | |||
| 1eda9a839a | |||
| e3cc400ac2 | |||
| b9b3d021cc | |||
| 6e202e18d8 | |||
| 750b57859a | |||
| 7ba520fea1 | |||
| da85a07dae | |||
| 01851523a0 | |||
| eda744f07f | |||
| 4acfe11af1 | |||
| 85824c5df6 | |||
| 20a0c27111 | |||
| 76200884d5 | |||
| ce4ce55b29 | |||
| 66f6e38788 | |||
| d97a0a3324 | |||
| 63f5a0a324 | |||
| f0837bb98b | |||
| 0f98a72876 | |||
| 1dd59204e9 | |||
| decae725a6 | |||
| 6c92d45ff3 | |||
| 272dd4a076 | |||
| 626ebe380e | |||
| f86ce48d65 | |||
| ef92cca9db | |||
| aa71810bfb | |||
| 22c47ac648 | |||
| e592528937 | |||
| 1fdb49f314 | |||
| aff37d1ae4 | |||
| a0234d0cc6 | |||
| 8a77acb51e | |||
| 690bbbd14c | |||
| 9c9bb2f192 | |||
| 23a40fe051 | |||
| 5d9cd662fc | |||
| 6c01589d3b | |||
| 820dde8ad2 | |||
| 3de4d63f44 | |||
| e1df82e0c3 | |||
| c1985b4a10 | |||
| 1ca9ce4db3 | |||
| 636705bd70 | |||
| 153dcd8ad3 | |||
| f2c2fe11b4 | |||
| 7a2c4fa5cc | |||
| 923816ca8e | |||
| 23d0b7b89e | |||
| a6b35f3a22 | |||
| 87fb39c8a5 | |||
| 4d188a79fb | |||
| a02b807dad | |||
| e0fa9d0213 | |||
| 35ad8abf4c | |||
| 372ca374cc | |||
| 75b6e94be1 | |||
| f912d0ef88 | |||
| 1bf8a01d0b | |||
| 5e8213d45f | |||
| 8b093122ac | |||
| bc14ad5b15 | |||
| fc543fc5a6 | |||
| 2e3aec81e7 | |||
| 9b04578d3e | |||
| 6654d32229 | |||
| 7c2c9448a3 | |||
| 6531128647 | |||
| fd1b895ff9 | |||
| f4e88bbcc0 | |||
| 7993f98166 | |||
| e11b775a31 | |||
| b999494154 | |||
| 6a7ed1a948 | |||
| d0889cca31 | |||
| 8b673c7adf | |||
| f1b0390b9b | |||
| b43d767a26 | |||
| bd4f642045 | |||
| 3bdfc7d785 | |||
| 4aa73968f0 | |||
| 06bc09951d | |||
| 9d59043788 | |||
| 33f0ca3042 | |||
| e1bc62dae3 | |||
| 77dbe9ccac | |||
| 150d8c2119 | |||
| b16f6adf76 | |||
| 834dd963ef | |||
| 01e0f9c2b7 | |||
| b4c0bb1f18 | |||
| f70fc683d1 | |||
| 956d4bd5bf | |||
| 8b45f89a75 | |||
| def6b67c8f | |||
| e8136853db | |||
| 084b41e33b | |||
| 6242bd7eb7 | |||
| 5fbe298f9c | |||
| b1c2c645df | |||
| d2a6aa5462 | |||
| 71abe66b8f | |||
| 01eb6e31ba | |||
| 071e6f885f | |||
| 5fcde96f88 | |||
| a1ad10b3ee | |||
| 6d26732208 | |||
| 20a396f190 | |||
| 4b7e5ca9fc | |||
| 8522707bd2 | |||
| a1505736d7 | |||
| 5cd17028d6 | |||
| 3089dd8688 | |||
| 044c45225b | |||
| 0c1ade82b2 | |||
| 7fdf5ed7dc | |||
| 6fb956688a | |||
| 28b362f8ff | |||
| 7035ccdcd2 | |||
| ba5ac8d872 | |||
| ea16ecc81f | |||
| 0eac9d3e6f | |||
| 68a8b6d437 | |||
| e136ba9f3e | |||
| 9ee6bea772 | |||
| 79bdde4f08 | |||
| 2a5f0e3c9f | |||
| 3c42f3de47 | |||
| 7cd15d408e | |||
| 5228b778dc | |||
| 49eaf7afeb | |||
| b2f02232f2 | |||
| 2f2d7da20b | |||
| 168043d422 | |||
| 101e1f6b50 | |||
| 323b6cec9d | |||
| 019a04c488 | |||
| e566bbc5e7 | |||
| d2140672fd | |||
| 667df80d35 | |||
| 0d8ad2d8b0 | |||
| 1796ff6871 | |||
| 49c54ee69a | |||
| d8e314b0a0 | |||
| 65acfe61ce | |||
| 2f067de10a | |||
| acecb50f7e | |||
| 9b27932d2c | |||
| 4aa8c0a76a | |||
| 246e43217a | |||
| 6925a5f3a4 | |||
| 81a92a9f13 | |||
| 8440d66d33 | |||
| 63ce978afe | |||
| b4e6386496 | |||
| f524a96add | |||
| 1d0f3bb831 | |||
| 2e0ef27570 | |||
| ebbb8fcef1 | |||
| 1d89d3dbe9 | |||
| 18512f5b99 | |||
| 5d4906b4d1 | |||
| 5e83a0eea6 | |||
| 3f43856145 | |||
| bb16ca6394 | |||
| 3f83aaf32d | |||
| e8ec565273 | |||
| 8ab6460571 | |||
| 19f7abf0f8 | |||
| ce2ad727c6 | |||
| fe213d1e13 | |||
| 35b78af446 | |||
| a72d4ccded | |||
| 1babf4ba55 | |||
| 18ab2477a8 | |||
| 9d56392cbc | |||
| 7cc68f59a7 | |||
| d6a9a0b15f | |||
| 766471f4b9 | |||
| 143a6a9cca | |||
| 7ad41a3ff2 | |||
| 12fadffb00 | |||
| ef97128fe6 | |||
| 1b0bc366e4 | |||
| 89c87f99e8 | |||
| 0e0b6a4978 | |||
| 7fe3caf841 | |||
| 2799892f1d | |||
| 7ecd839310 | |||
| 11a2628ed2 | |||
| a24b9cf9b9 | |||
| 705f77f5ba | |||
| c71cbf2e09 | |||
| 33aba7b721 | |||
| 58f4e5bf76 | |||
| 2095c7546a | |||
| 6005444fda | |||
| 658ccaf78f | |||
| 3112b2b071 | |||
| 32f746b918 | |||
| 5145a0260d | |||
| acc782b754 | |||
| e6508e6978 | |||
| 4e45fbbc04 | |||
| 81c2d70fbb | |||
| d2ec20bd10 | |||
| 6e3a7f8fa0 | |||
| 8e83acbafd | |||
| 40a8522460 | |||
| dfa9ca733e | |||
| 4681098e8c | |||
| 4f81d53d11 | |||
| dc5dc608ba | |||
| 83dc1c76ef | |||
| d660e9a066 | |||
| abcaaa3264 | |||
| 7f2b871885 | |||
| e51dd05989 | |||
| 51da7732f4 | |||
| 1b7dc2f147 | |||
| 63aedb65d9 | |||
| 9c503fe8d6 | |||
| 83e59bf5b0 | |||
| 4ef5c374ef | |||
| 764b31fdcd | |||
| 7fe2b41209 | |||
| 25a14bf44f | |||
| bde3606757 | |||
| 84f7af7e58 | |||
| bf0a448bff | |||
| be148574e3 | |||
| 235e00c19a | |||
| 87035eb4a9 | |||
| e67a9c9664 | |||
| 719dfd91ab | |||
| 5f97c46e5f | |||
| 739d171462 | |||
| f105602da5 | |||
| 01f4ebde54 | |||
| 97f3d1662e | |||
| aa04589dd2 | |||
| 9473039a0b | |||
| 574cc098c6 | |||
| f17c490768 | |||
| 6d246f5244 | |||
| bec30ae833 | |||
| feb501c76f | |||
| b32f4ad80a | |||
| 4b12228b15 | |||
| afd576697e | |||
| 6a24360ffd | |||
| 5faa69b66c | |||
| 833498011c | |||
| 4f6cc659c4 | |||
| 5cef77e52c | |||
| 712ab734dd | |||
| 0f0a57af1c | |||
| ce5eef2605 | |||
| 6d6960badb | |||
| 54269aa92a | |||
| ec65a71d6d | |||
| 761fcde654 | |||
| 3346ddac38 | |||
| f20c55f849 | |||
| 37c5c35a12 | |||
| e541ccb197 | |||
| 1f7027d825 | |||
| 0d9e7a5e08 | |||
| c4ac96e669 | |||
| 74f65b978e | |||
| eab874b3ef | |||
| 54d9361dad | |||
| e8cd130ad6 | |||
| 2f70f4ba25 | |||
| 1548167b94 | |||
| 91a320127a | |||
| 7a0a4dc3b3 | |||
| ba9c006cb4 | |||
| 2f92160e9c | |||
| 8f0063465c | |||
| 0c8bb089b9 | |||
| 746b99508b | |||
| 05ce497f29 | |||
| 5bfb382209 | |||
| 32efa7b112 | |||
| e4fcd589db | |||
| 8da5a99196 | |||
| d5cb79027a | |||
| fea1a001ee | |||
| 3ae6f0a93d | |||
| 28d7db2371 | |||
| 02b582a60d | |||
| 83a40e1b33 | |||
| ca0a875e6b | |||
| 9932d4789e | |||
| 2c68dfd8cf | |||
| 64f66fad4d | |||
| 5a8e3100b9 | |||
| 87dedc3dd2 | |||
| 69b442c2a9 | |||
| 77bf358d7a | |||
| 9ed7254277 | |||
| 1a08d99079 | |||
| f852dcfd20 | |||
| 04a4f4d5bb | |||
| 2e42dd3308 | |||
| e9cf8d4647 | |||
| 216351803b | |||
| d3eb969095 | |||
| 77c405626f |
@@ -1,4 +1,5 @@
|
||||
*.swp
|
||||
*~
|
||||
.DS_Store
|
||||
.project
|
||||
.svn
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
ca =
|
||||
cache = ~/.atom/.npm
|
||||
+2
-1
@@ -10,7 +10,7 @@ to propose changes to this document in a pull request.
|
||||
that behavior such as Emacs, vi, Xcode, etc.
|
||||
* Check the Console app for stack traces to include if reporting a crash.
|
||||
* Check the Dev tools (`alt-cmd-i`) for errors and stack traces to include.
|
||||
|
||||
|
||||
### Package Repositories
|
||||
|
||||
This is the repository for the core Atom editor only. Atom comes bundled with
|
||||
@@ -56,6 +56,7 @@ in the proper package's repository.
|
||||
* :racehorse: when improving performance
|
||||
* :non-potable_water: when plugging memory leaks
|
||||
* :memo: when writing docs
|
||||
* :penguin: when fixing something on Linux
|
||||
|
||||
## CoffeeScript Styleguide
|
||||
|
||||
|
||||
+59
-15
@@ -1,11 +1,13 @@
|
||||
#!/bin/sh
|
||||
ATOM_PATH=${ATOM_PATH-/Applications/Atom.app}
|
||||
ATOM_BINARY=$ATOM_PATH/Contents/MacOS/Atom
|
||||
#!/bin/bash
|
||||
|
||||
if [ ! -d $ATOM_PATH ]; then sleep 5; fi # Wait for Atom to reappear, Sparkle may be replacing it.
|
||||
|
||||
if [ ! -d $ATOM_PATH ]; then
|
||||
echo "Atom application not found at '$ATOM_PATH'" >&2
|
||||
if [ "`uname`" == 'Darwin' ]; then
|
||||
OS='Mac'
|
||||
elif [ "`expr substr $(uname -s) 1 5`" == 'Linux' ]; then
|
||||
OS='Linux'
|
||||
elif [ "`expr substr $(uname -s) 1 10`" == 'MINGW32_NT' ]; then
|
||||
OS='Cygwin'
|
||||
else
|
||||
echo "Your platform (`uname -a`) is not supported."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -16,7 +18,11 @@ while getopts ":wtfvhs-:" opt; do
|
||||
wait)
|
||||
WAIT=1
|
||||
;;
|
||||
help|version|foreground|test)
|
||||
help|version)
|
||||
REDIRECT_STDERR=1
|
||||
EXPECT_OUTPUT=1
|
||||
;;
|
||||
foreground|test)
|
||||
EXPECT_OUTPUT=1
|
||||
;;
|
||||
esac
|
||||
@@ -24,25 +30,63 @@ while getopts ":wtfvhs-:" opt; do
|
||||
w)
|
||||
WAIT=1
|
||||
;;
|
||||
h|v|f|t)
|
||||
h|v)
|
||||
REDIRECT_STDERR=1
|
||||
EXPECT_OUTPUT=1
|
||||
;;
|
||||
f|t)
|
||||
EXPECT_OUTPUT=1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ $EXPECT_OUTPUT ]; then
|
||||
$ATOM_BINARY --executed-from="$(pwd)" --pid=$$ $@
|
||||
exit $?
|
||||
else
|
||||
open -a $ATOM_PATH -n --args --executed-from="$(pwd)" --pid=$$ $@
|
||||
if [ $REDIRECT_STDERR ]; then
|
||||
exec 2> /dev/null
|
||||
fi
|
||||
|
||||
# Used to exit process when atom is used as $EDITOR
|
||||
if [ $OS == 'Mac' ]; then
|
||||
ATOM_PATH=${ATOM_PATH:-/Applications} # Set ATOM_PATH unless it is already set
|
||||
ATOM_APP_NAME=Atom.app
|
||||
|
||||
# If ATOM_PATH isn't a executable file, use spotlight to search for Atom
|
||||
if [ ! -x "$ATOM_PATH/$ATOM_APP_NAME" ]; then
|
||||
ATOM_PATH=$(mdfind "kMDItemCFBundleIdentifier == 'com.github.atom'" | head -1 | xargs dirname)
|
||||
fi
|
||||
|
||||
# Exit if Atom can't be found
|
||||
if [ -z "$ATOM_PATH" ]; then
|
||||
echo "Cannot locate Atom.app, it is usually located in /Applications. Set the ATOM_PATH environment variable to the directory containing Atom.app."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $EXPECT_OUTPUT ]; then
|
||||
"$ATOM_PATH/$ATOM_APP_NAME/Contents/MacOS/Atom" --executed-from="$(pwd)" --pid=$$ "$@"
|
||||
exit $?
|
||||
else
|
||||
open -a "$ATOM_PATH/$ATOM_APP_NAME" -n --args --executed-from="$(pwd)" --pid=$$ "$@"
|
||||
fi
|
||||
elif [ $OS == 'Linux' ]; then
|
||||
SCRIPT=`readlink -f "$0"`
|
||||
USR_DIRECTORY=`readlink -f $(dirname $SCRIPT)/..`
|
||||
ATOM_PATH="$USR_DIRECTORY/share/atom/atom"
|
||||
|
||||
[ -x "$ATOM_PATH" ] || ATOM_PATH='/tmp/atom-build/Atom/atom'
|
||||
|
||||
if [ $EXPECT_OUTPUT ]; then
|
||||
"$ATOM_PATH" --executed-from="$(pwd)" --pid=$$ "$@"
|
||||
exit $?
|
||||
else
|
||||
nohup "$ATOM_PATH" --executed-from="$(pwd)" --pid=$$ "$@" > /dev/null 2>&1 &
|
||||
fi
|
||||
fi
|
||||
|
||||
# Exits this process when Atom is used as $EDITOR
|
||||
on_die() {
|
||||
exit 0
|
||||
}
|
||||
trap 'on_die' SIGQUIT SIGTERM
|
||||
|
||||
# If the wait flag is set, don't exit this process until Atom tells it to.
|
||||
if [ $WAIT ]; then
|
||||
while true; do
|
||||
sleep 1
|
||||
|
||||
@@ -39,23 +39,33 @@ module.exports = (grunt) ->
|
||||
if process.platform is 'win32'
|
||||
appName = 'Atom'
|
||||
tmpDir = os.tmpdir()
|
||||
installRoot = process.env.ProgramFiles
|
||||
buildDir = grunt.option('build-dir') ? path.join(tmpDir, 'atom-build')
|
||||
symbolsDir = path.join(buildDir, 'Atom.breakpad.syms')
|
||||
shellAppDir = path.join(buildDir, appName)
|
||||
contentsDir = shellAppDir
|
||||
appDir = path.join(shellAppDir, 'resources', 'app')
|
||||
atomShellDownloadDir = path.join(os.tmpdir(), 'atom-cached-atom-shells')
|
||||
else
|
||||
installDir = path.join(process.env.ProgramFiles, appName)
|
||||
else if process.platform is 'darwin'
|
||||
appName = 'Atom.app'
|
||||
tmpDir = '/tmp'
|
||||
installRoot = '/Applications'
|
||||
buildDir = grunt.option('build-dir') ? path.join(tmpDir, 'atom-build')
|
||||
symbolsDir = path.join(buildDir, 'Atom.breakpad.syms')
|
||||
shellAppDir = path.join(buildDir, appName)
|
||||
contentsDir = path.join(shellAppDir, 'Contents')
|
||||
appDir = path.join(contentsDir, 'Resources', 'app')
|
||||
atomShellDownloadDir = '/tmp/atom-cached-atom-shells'
|
||||
|
||||
installDir = path.join(installRoot, appName)
|
||||
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 =
|
||||
options:
|
||||
@@ -123,7 +133,7 @@ module.exports = (grunt) ->
|
||||
grunt.initConfig
|
||||
pkg: grunt.file.readJSON('package.json')
|
||||
|
||||
atom: {appDir, appName, buildDir, contentsDir, installDir, shellAppDir}
|
||||
atom: {appDir, appName, symbolsDir, buildDir, contentsDir, installDir, shellAppDir}
|
||||
|
||||
coffee: coffeeConfig
|
||||
|
||||
@@ -223,6 +233,9 @@ module.exports = (grunt) ->
|
||||
grunt.registerTask('compile', ['coffee', 'prebuild-less', 'cson', 'peg'])
|
||||
grunt.registerTask('lint', ['coffeelint', 'csslint', 'lesslint'])
|
||||
grunt.registerTask('test', ['shell:kill-atom', 'run-specs'])
|
||||
grunt.registerTask('ci', ['output-disk-space', 'download-atom-shell', 'build', 'set-version', 'check-licenses', 'lint', 'test', 'codesign', 'publish-build'])
|
||||
grunt.registerTask('ci', ['output-disk-space', 'download-atom-shell', 'build', 'dump-symbols', 'set-version', 'check-licenses', 'lint', 'test', 'codesign', 'publish-build'])
|
||||
grunt.registerTask('docs', ['markdown:guides', 'build-docs'])
|
||||
grunt.registerTask('default', ['download-atom-shell', 'build', 'set-version', 'install'])
|
||||
|
||||
defaultTasks = ['download-atom-shell', 'build', 'set-version']
|
||||
defaultTasks.push 'install' unless process.platform is 'linux'
|
||||
grunt.registerTask('default', defaultTasks)
|
||||
|
||||
@@ -17,21 +17,23 @@
|
||||
"grunt-contrib-csslint": "~0.1.2",
|
||||
"grunt-contrib-coffee": "~0.9.0",
|
||||
"grunt-contrib-less": "~0.8.0",
|
||||
"grunt-cson": "0.6.0",
|
||||
"grunt-download-atom-shell": "git+https://atom-bot:467bac80a0017b96fb5be5cfc686f5e0cc607b10@github.com/atom/grunt-download-atom-shell#v0.6.0",
|
||||
"grunt-cson": "0.8.0",
|
||||
"grunt-download-atom-shell": "git+https://atom-bot:467bac80a0017b96fb5be5cfc686f5e0cc607b10@github.com/atom/grunt-download-atom-shell#v0.6.1",
|
||||
"grunt-lesslint": "0.13.0",
|
||||
"grunt-markdown": "~0.4.0",
|
||||
"grunt-peg": "~1.1.0",
|
||||
"grunt-shell": "~0.3.1",
|
||||
"harmony-collections": "~0.3.8",
|
||||
"json-front-matter": "~0.1.3",
|
||||
"legal-eagle": "~0.3.0",
|
||||
"legal-eagle": "~0.4.0",
|
||||
"minidump": "0.5.x",
|
||||
"rcedit": "~0.1.2",
|
||||
"request": "~2.27.0",
|
||||
"rimraf": "~2.2.2",
|
||||
"runas": "0.5.x",
|
||||
"underscore-plus": "1.x",
|
||||
"unzip": "~0.1.9",
|
||||
"vm-compatibility-layer": "~0.1.0"
|
||||
"vm-compatibility-layer": "~0.1.0",
|
||||
"npm": "~1.4.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ module.exports = (grunt) ->
|
||||
|
||||
if process.platform is 'darwin'
|
||||
cp 'atom-shell/Atom.app', shellAppDir
|
||||
else if process.platform is 'win32'
|
||||
else
|
||||
cp 'atom-shell', shellAppDir
|
||||
|
||||
mkdir appDir
|
||||
@@ -47,7 +47,9 @@ module.exports = (grunt) ->
|
||||
path.join('less', 'test')
|
||||
path.join('bootstrap', 'docs')
|
||||
path.join('bootstrap', 'examples')
|
||||
path.join('spellchecker', 'vendor')
|
||||
path.join('pegjs', 'examples')
|
||||
# Add .* to avoid matching hunspell_dictionaries.
|
||||
path.join('spellchecker', 'vendor', 'hunspell', '.*')
|
||||
path.join('xmldom', 'test')
|
||||
path.join('jasmine-reporters', 'ext')
|
||||
path.join('build', 'Release', 'obj.target')
|
||||
@@ -56,6 +58,9 @@ module.exports = (grunt) ->
|
||||
path.join('resources', 'mac')
|
||||
path.join('resources', 'win')
|
||||
]
|
||||
# Hunspell dictionaries are only not needed on OS X.
|
||||
if process.platform is 'darwin'
|
||||
ignoredPaths.push path.join('spellchecker', 'vendor', 'hunspell_dictionaries')
|
||||
ignoredPaths = ignoredPaths.map (ignoredPath) -> "(#{ignoredPath})"
|
||||
nodeModulesFilter = new RegExp(ignoredPaths.join('|'))
|
||||
packageFilter = new RegExp("(#{ignoredPaths.join('|')})|(.+\\.(cson|coffee)$)")
|
||||
|
||||
@@ -15,6 +15,9 @@ module.exports = (grunt) ->
|
||||
console.error(err)
|
||||
exit 1
|
||||
|
||||
for key of summary
|
||||
delete summary[key] if key.match /^atom@/
|
||||
|
||||
if size(summary)
|
||||
console.error "Found dependencies without permissive licenses:"
|
||||
for name in keys(summary).sort()
|
||||
|
||||
@@ -143,6 +143,8 @@ downloadFileFromRepo = ({repo, file}, callback) ->
|
||||
|
||||
downloadIncludes = (callback) ->
|
||||
includes = [
|
||||
{repo: 'atom-keymap', file: 'src/keymap.coffee'}
|
||||
{repo: 'atom-keymap', file: 'src/key-binding.coffee'}
|
||||
{repo: 'first-mate', file: 'src/grammar.coffee'}
|
||||
{repo: 'first-mate', file: 'src/grammar-registry.coffee'}
|
||||
{repo: 'node-pathwatcher', file: 'src/directory.coffee'}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
async = require 'async'
|
||||
fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
minidump = require 'minidump'
|
||||
|
||||
module.exports = (grunt) ->
|
||||
{mkdir, rm} = require('./task-helpers')(grunt)
|
||||
|
||||
dumpSymbolTo = (binaryPath, targetDirectory, callback) ->
|
||||
minidump.dumpSymbol binaryPath, (error, content) ->
|
||||
return callback(error) if error?
|
||||
|
||||
moduleLine = /MODULE [^ ]+ [^ ]+ ([0-9A-F]+) (.*)\n/.exec(content)
|
||||
if moduleLine.length isnt 3
|
||||
return callback("Invalid output when dumping symbol for #{binaryPath}")
|
||||
|
||||
filename = moduleLine[2]
|
||||
targetPathDirname = path.join(targetDirectory, filename, moduleLine[1])
|
||||
mkdir targetPathDirname
|
||||
|
||||
targetPath = path.join(targetPathDirname, "#{filename}.sym")
|
||||
fs.writeFile(targetPath, content, callback)
|
||||
|
||||
grunt.registerTask 'dump-symbols', 'Dump symbols for native modules', ->
|
||||
done = @async()
|
||||
|
||||
symbolsDir = grunt.config.get('atom.symbolsDir')
|
||||
rm symbolsDir
|
||||
mkdir symbolsDir
|
||||
|
||||
tasks = []
|
||||
onFile = (binaryPath) ->
|
||||
if /.*\.node$/.test(binaryPath)
|
||||
tasks.push(dumpSymbolTo.bind(this, binaryPath, symbolsDir))
|
||||
onDirectory = ->
|
||||
true
|
||||
fs.traverseTreeSync 'node_modules', onFile, onDirectory
|
||||
|
||||
async.parallel tasks, done
|
||||
@@ -1,4 +1,6 @@
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
fs = require 'fs-plus'
|
||||
runas = null
|
||||
|
||||
module.exports = (grunt) ->
|
||||
@@ -15,7 +17,23 @@ module.exports = (grunt) ->
|
||||
|
||||
createShortcut = path.resolve 'script', 'create-shortcut.cmd'
|
||||
runas('cmd', ['/c', createShortcut, path.join(installDir, 'atom.exe'), 'Atom'])
|
||||
else
|
||||
else if process.platform is 'darwin'
|
||||
rm installDir
|
||||
mkdir path.dirname(installDir)
|
||||
cp shellAppDir, installDir
|
||||
else
|
||||
binDir = path.join(installDir, 'bin')
|
||||
shareDir = path.join(installDir, 'share', 'atom')
|
||||
|
||||
mkdir binDir
|
||||
cp 'atom.sh', path.join(binDir, 'atom')
|
||||
rm shareDir
|
||||
mkdir path.dirname(shareDir)
|
||||
cp shellAppDir, shareDir
|
||||
|
||||
# Create relative symbol link for apm.
|
||||
process.chdir(binDir)
|
||||
rm('apm')
|
||||
fs.symlinkSync(path.join('..', 'share', 'atom', 'resources', 'app', 'apm', 'node_modules', '.bin', 'apm'), 'apm')
|
||||
|
||||
fs.chmodSync(path.join(shareDir, 'atom'), "755")
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
_ = require 'underscore-plus'
|
||||
|
||||
fillTemplate = (filePath, data) ->
|
||||
template = _.template(String(fs.readFileSync(filePath + '.in')))
|
||||
filled = template(data)
|
||||
fs.writeFileSync(filePath, filled)
|
||||
|
||||
module.exports = (grunt) ->
|
||||
{spawn} = require('./task-helpers')(grunt)
|
||||
|
||||
grunt.registerTask 'mkdeb', 'Create debian package', ->
|
||||
done = @async()
|
||||
|
||||
{name, version, description} = grunt.file.readJSON('package.json')
|
||||
section = 'devel'
|
||||
arch = 'amd64'
|
||||
maintainer = 'GitHub <atom@github.com>'
|
||||
data = {name, version, description, section, arch, maintainer}
|
||||
|
||||
control = path.join('resources', 'linux', 'debian', 'control')
|
||||
fillTemplate(control, data)
|
||||
desktop = path.join('resources', 'linux', 'Atom.desktop')
|
||||
fillTemplate(desktop, data)
|
||||
icon = path.join('resources', 'atom.png')
|
||||
buildDir = grunt.config.get('atom.buildDir')
|
||||
|
||||
cmd = path.join('script', 'mkdeb')
|
||||
args = [version, control, desktop, icon, buildDir]
|
||||
spawn({cmd, args}, done)
|
||||
@@ -2,14 +2,17 @@ child_process = require 'child_process'
|
||||
path = require 'path'
|
||||
|
||||
_ = require 'underscore-plus'
|
||||
async = require 'async'
|
||||
fs = require 'fs-plus'
|
||||
GitHub = require 'github-releases'
|
||||
request = require 'request'
|
||||
|
||||
grunt = null
|
||||
maxReleases = 10
|
||||
assetName = 'atom-mac.zip'
|
||||
assetPath = "/tmp/atom-build/#{assetName}"
|
||||
assets = [
|
||||
{assetName: 'atom-mac.zip', sourceName: 'Atom.app'}
|
||||
{assetName: 'atom-mac-symbols.zip', sourceName: 'Atom.breakpad.syms'}
|
||||
]
|
||||
commitSha = process.env.JANKY_SHA1
|
||||
token = process.env.ATOM_ACCESS_TOKEN
|
||||
defaultHeaders =
|
||||
@@ -18,39 +21,48 @@ defaultHeaders =
|
||||
|
||||
module.exports = (gruntObject) ->
|
||||
grunt = gruntObject
|
||||
|
||||
grunt.registerTask 'publish-build', 'Publish the built app', ->
|
||||
return unless process.platform is 'darwin'
|
||||
return if process.env.JANKY_SHA1 and process.env.JANKY_BRANCH isnt 'master'
|
||||
|
||||
done = @async()
|
||||
buildDir = grunt.config.get('atom.buildDir')
|
||||
|
||||
createBuildRelease (error, release) ->
|
||||
return done(error) if error?
|
||||
zipApp (error) ->
|
||||
|
||||
zipApps buildDir, assets, (error) ->
|
||||
return done(error) if error?
|
||||
uploadAsset release, (error) ->
|
||||
uploadAssets release, buildDir, assets, (error) ->
|
||||
return done(error) if error?
|
||||
publishRelease release, (error) ->
|
||||
return done(error) if error?
|
||||
getAtomDraftRelease (error, release) ->
|
||||
return done(error) if error?
|
||||
deleteExistingAsset release, (error) ->
|
||||
assetNames = (asset.assetName for asset in assets)
|
||||
deleteExistingAssets release, assetNames, (error) ->
|
||||
return done(error) if error?
|
||||
uploadAsset(release, done)
|
||||
uploadAssets(release, buildDir, assets, done)
|
||||
|
||||
logError = (message, error, details) ->
|
||||
grunt.log.error(message)
|
||||
grunt.log.error(error.message ? error) if error?
|
||||
grunt.log.error(details) if details
|
||||
|
||||
zipApp = (callback) ->
|
||||
fs.removeSync(assetPath)
|
||||
zipApps = (buildDir, assets, callback) ->
|
||||
zip = (directory, sourceName, assetName, callback) ->
|
||||
options = {cwd: directory, maxBuffer: Infinity}
|
||||
child_process.exec "zip -r --symlinks #{assetName} #{sourceName}", options, (error, stdout, stderr) ->
|
||||
if error?
|
||||
logError("Zipping #{sourceName} failed", error, stderr)
|
||||
callback(error)
|
||||
|
||||
options = {cwd: path.dirname(assetPath), maxBuffer: Infinity}
|
||||
child_process.exec "zip -r --symlinks #{assetName} Atom.app", options, (error, stdout, stderr) ->
|
||||
if error?
|
||||
logError('Zipping Atom.app failed', error, stderr)
|
||||
callback(error)
|
||||
tasks = []
|
||||
for {assetName, sourceName} in assets
|
||||
fs.removeSync(path.join(buildDir, assetName))
|
||||
tasks.push(zip.bind(this, buildDir, sourceName, assetName))
|
||||
async.parallel(tasks, callback)
|
||||
|
||||
getRelease = (callback) ->
|
||||
options =
|
||||
@@ -93,10 +105,12 @@ deleteRelease = (release) ->
|
||||
if error? or response.statusCode isnt 204
|
||||
logError('Deleting release failed', error, body)
|
||||
|
||||
deleteExistingAsset = (release, callback) ->
|
||||
for asset in release.assets when asset.name is assetName
|
||||
deleteExistingAssets = (release, assetNames, callback) ->
|
||||
[callback, assetNames] = [assetNames, callback] if not callback?
|
||||
|
||||
deleteAsset = (url, callback) ->
|
||||
options =
|
||||
uri: asset.url
|
||||
uri: url
|
||||
method: 'DELETE'
|
||||
headers: defaultHeaders
|
||||
request options, (error, response, body='') ->
|
||||
@@ -106,9 +120,10 @@ deleteExistingAsset = (release, callback) ->
|
||||
else
|
||||
callback()
|
||||
|
||||
return
|
||||
|
||||
callback()
|
||||
tasks = []
|
||||
for asset in release.assets when not assetNames? or asset.name in assetNames
|
||||
tasks.push(deleteAsset.bind(this, asset.url))
|
||||
async.parallel(tasks, callback)
|
||||
|
||||
createBuildRelease = (callback) ->
|
||||
getRelease (error, release) ->
|
||||
@@ -117,7 +132,7 @@ createBuildRelease = (callback) ->
|
||||
return
|
||||
|
||||
if release?
|
||||
deleteExistingAsset release, (error) ->
|
||||
deleteExistingAssets release, (error) ->
|
||||
callback(error, release)
|
||||
return
|
||||
|
||||
@@ -139,23 +154,30 @@ createBuildRelease = (callback) ->
|
||||
else
|
||||
callback(null, release)
|
||||
|
||||
uploadAsset = (release, callback) ->
|
||||
options =
|
||||
uri: release.upload_url.replace(/\{.*$/, "?name=#{assetName}")
|
||||
method: 'POST'
|
||||
headers: _.extend({
|
||||
'Content-Type': 'application/zip'
|
||||
'Content-Length': fs.getSizeSync(assetPath)
|
||||
}, defaultHeaders)
|
||||
uploadAssets = (release, buildDir, assets, callback) ->
|
||||
upload = (release, assetName, assetPath, callback) ->
|
||||
options =
|
||||
uri: release.upload_url.replace(/\{.*$/, "?name=#{assetName}")
|
||||
method: 'POST'
|
||||
headers: _.extend({
|
||||
'Content-Type': 'application/zip'
|
||||
'Content-Length': fs.getSizeSync(assetPath)
|
||||
}, defaultHeaders)
|
||||
|
||||
assetRequest = request options, (error, response, body='') ->
|
||||
if error? or response.statusCode >= 400
|
||||
logError('Upload release asset failed', error, body)
|
||||
callback(error ? new Error(response.statusCode))
|
||||
else
|
||||
callback(null, release)
|
||||
assetRequest = request options, (error, response, body='') ->
|
||||
if error? or response.statusCode >= 400
|
||||
logError("Upload release asset #{assetName} failed", error, body)
|
||||
callback(error ? new Error(response.statusCode))
|
||||
else
|
||||
callback(null, release)
|
||||
|
||||
fs.createReadStream(assetPath).pipe(assetRequest)
|
||||
fs.createReadStream(assetPath).pipe(assetRequest)
|
||||
|
||||
tasks = []
|
||||
for {assetName, sourceName} in assets
|
||||
assetPath = path.join(buildDir, assetName)
|
||||
tasks.push(upload.bind(this, release, assetName, assetPath))
|
||||
async.parallel(tasks, callback)
|
||||
|
||||
publishRelease = (release, callback) ->
|
||||
options =
|
||||
|
||||
@@ -48,3 +48,5 @@ module.exports = (grunt) ->
|
||||
|
||||
rcedit = require('rcedit')
|
||||
rcedit(shellExePath, {'version-string': strings}, done)
|
||||
else
|
||||
done()
|
||||
|
||||
@@ -31,6 +31,7 @@ The classes available from `require 'atom'` are:
|
||||
* [SelectListView][SelectListView]
|
||||
* [View][View]
|
||||
* [WorkspaceView][WorkspaceView]
|
||||
* [Workspace][Workspace]
|
||||
|
||||
### How do I create a package?
|
||||
|
||||
@@ -54,5 +55,6 @@ Atom ships with node 0.11.10 and the comprehensive node API docs are available
|
||||
[SelectListView]: ../classes/SelectListView.html
|
||||
[View]: ../classes/View.html
|
||||
[WorkspaceView]: ../classes/WorkspaceView.html
|
||||
[Workspace]: ../classes/Workspace.html
|
||||
[creating-a-package]: https://atom.io/docs/latest/creating-a-package
|
||||
[node-docs]: http://nodejs.org/docs/v0.11.10/api
|
||||
|
||||
@@ -83,6 +83,22 @@ file. For now, we've opted to handle cases where selector ordering is critical
|
||||
by breaking the keymap into two separate files, such as `snippets-1.cson` and
|
||||
`snippets-2.cson`.
|
||||
|
||||
## Removing Bindings
|
||||
|
||||
When the keymap system encounters a binding with the `unset!` directive as its
|
||||
command, it will treat the current element as if it had no key bindings matching
|
||||
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.
|
||||
|
||||
## Forcing Chromium's Native Keystroke Handling
|
||||
|
||||
If you want to force the native browser behavior for a given keystroke, use the
|
||||
`native!` directive as the command of a binding. This can be useful to enable
|
||||
the correct behavior in native input elements, for example. If you apply the
|
||||
`.native-key-bindings` class to an element, all the keystrokes typically handled
|
||||
by the browser will be assigned the `native!` directive.
|
||||
|
||||
## Overloading Key Bindings
|
||||
|
||||
Occasionally, it makes sense to layer multiple actions on top of the same key
|
||||
|
||||
@@ -19,7 +19,7 @@ module.exports =
|
||||
activate: (state) ->
|
||||
@myObject =
|
||||
if state
|
||||
deserialize(state)
|
||||
atom.deserializers.deserialize(state)
|
||||
else
|
||||
new MyObject("Hello")
|
||||
|
||||
@@ -31,7 +31,8 @@ module.exports =
|
||||
|
||||
```coffee-script
|
||||
class MyObject
|
||||
registerDeserializer(this)
|
||||
atom.deserializers.add(this)
|
||||
|
||||
@deserialize: ({data}) -> new MyObject(data)
|
||||
constructor: (@data) ->
|
||||
serialize: -> { deserializer: 'MyObject', data: @data }
|
||||
@@ -50,8 +51,8 @@ class-level method on the same class that implements `serialize`. This method's
|
||||
job is to convert a state object returned from a previous call `serialize` back
|
||||
into a genuine object.
|
||||
|
||||
#### registerDeserializer(klass)
|
||||
You need to call the global `registerDeserializer` method with your class in
|
||||
#### atom.deserializers.add(klass)
|
||||
You need to call the `atom.deserializers.add` method with your class in
|
||||
order to make it available to the deserialization system. Now you can call the
|
||||
global `deserialize` method with state returned from `serialize`, and your
|
||||
class's `deserialize` method will be selected automatically.
|
||||
@@ -60,14 +61,15 @@ class's `deserialize` method will be selected automatically.
|
||||
|
||||
```coffee-script
|
||||
class MyObject
|
||||
atom.deserializers.add(this)
|
||||
|
||||
@version: 2
|
||||
@deserialize: (state) -> ...
|
||||
serialize: -> { version: MyObject.version, ... }
|
||||
serialize: -> { version: @constructor.version, ... }
|
||||
```
|
||||
|
||||
Your serializable class can optionally have a class-level `@version` property
|
||||
and include a `version` key in its serialized state. When deserializing, Atom
|
||||
will only attempt to call deserialize if the two versions match, and otherwise
|
||||
return undefined. We plan on implementing a migration system in the future, but
|
||||
this at least protects you from improperly deserializing old state. If you find
|
||||
yourself in dire need of the migration system, let us know.
|
||||
this at least protects you from improperly deserializing old state.
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
## Building Atom
|
||||
|
||||
These guide is meant only for users who wish to help develop atom core,
|
||||
if you're just interested in using atom you should just [download
|
||||
atom][download].
|
||||
|
||||
## OSX
|
||||
|
||||
* Use OS X 10.8 or later
|
||||
* Install the latest node 0.10.x release (32bit preferable)
|
||||
* Clone [atom][atom-git] to `~/github/atom`
|
||||
* Run `~/github/atom/script/build`
|
||||
|
||||
## Windows
|
||||
|
||||
* Install [Visual C++ 2010 Express][win-vs2010]
|
||||
* Install the [latest 32bit Node 0.10.x][win-node]
|
||||
* Install the [latest Python 2.7.x][win-python]
|
||||
* Install [GitHub for Windows][win-github]
|
||||
* Clone [atom/atom][atom-git] to `C:\Users\<user>\github\atom\`
|
||||
* Add `C:\Python27;C:\Program Files\nodejs;C:\Users\<user>\github\atom\node_modules\`
|
||||
to your PATH
|
||||
* Set ATOM_ACCESS_TOKEN to your oauth2 credentials (run `security -q
|
||||
find-generic-password -ws 'GitHub API Token'` on OSX to get your
|
||||
credentials).
|
||||
* Use the Windows GitHub shell and cd into `C:\Users\<user>\github\atom`
|
||||
* Run `script\bootstrap`
|
||||
|
||||
[download]: https://github.com/atom/atom/releases/latest
|
||||
[win-node]: http://nodejs.org/download/
|
||||
[win-python]: http://www.python.org/download/
|
||||
[win-github]: http://windows.github.com/
|
||||
[win-vs2010]: http://www.microsoft.com/visualstudio/eng/products/visual-studio-2010-express
|
||||
[atom-git]: https://github.com/atom/atom/
|
||||
@@ -40,7 +40,7 @@ the editor to see it in action!
|
||||
|
||||
### Further Reading
|
||||
|
||||
* Check out [Publishing a Package](publish-a-package.html) for more information
|
||||
* Check out [Publishing a Package](publishing-a-package.html) for more information
|
||||
on publishing the package you just created to [atom.io][atomio].
|
||||
|
||||
[atomio]: https://atom.io
|
||||
|
||||
@@ -57,7 +57,7 @@ __Syntax Theme__ dropdown menu to enable your new theme.
|
||||
|
||||
### Further Reading
|
||||
|
||||
* Check out [Publishing a Package](publish-a-package.html) for more information
|
||||
* Check out [Publishing a Package](publishing-a-package.html) for more information
|
||||
on publishing the theme you just created to [atom.io][atomio].
|
||||
|
||||
[atomio]: https://atom.io
|
||||
|
||||
@@ -24,6 +24,9 @@ Not every package will have (or need) all of these directories.
|
||||
|
||||
We have [a tutorial on creating your first package][first-package].
|
||||
|
||||
There are also guides for converting [TextMate bundles][convert-bundle] and
|
||||
[TextMate themes][convert-theme] so they work in Atom.
|
||||
|
||||
## package.json
|
||||
|
||||
Similar to [npm packages][npm], Atom packages contain a _package.json_ file
|
||||
@@ -127,7 +130,7 @@ Ideally, you won't need much in the way of styling. We've provided a standard
|
||||
set of components which define both the colors and UI elements for any package
|
||||
that fits into Atom seamlessly. You can view all of Atom's UI components by opening
|
||||
the styleguide: open the command palette (`cmd-shift-P`) and search for _styleguide_,
|
||||
or just type `cmd-ctrl-G`.
|
||||
or just type `cmd-ctrl-shift-G`.
|
||||
|
||||
If you _do_ need special styling, try to keep only structural styles in the package
|
||||
stylesheets. If you _must_ specify colors and sizing, these should be taken from
|
||||
@@ -322,27 +325,20 @@ Your package **should** have tests, and if they're placed in the _spec_
|
||||
directory, they can be run by Atom.
|
||||
|
||||
Under the hood, [Jasmine] executes your tests, so you can assume that any DSL
|
||||
available there is available to your package as well.
|
||||
|
||||
**FIXME: Explain the following**
|
||||
|
||||
* jasmine
|
||||
* jasmine-focused
|
||||
* `spec/fixtures` and global.project
|
||||
* setTimeout
|
||||
* whatever else is different in spec-helper
|
||||
available there is also available to your package.
|
||||
|
||||
## Running Tests
|
||||
|
||||
TODO: Probably use the menu option now.
|
||||
Once you've got your test suite written, you can run it by pressing
|
||||
`cmd-alt-ctrl-p` or via the _Developer > Run Package Specs_ menu.
|
||||
|
||||
Once you've got your test suite written, the recommended way to run it is `apm
|
||||
test`. `apm test` prints its output to the console and returns the proper status
|
||||
code depending on whether tests passed or failed.
|
||||
You can also use the `apm test` command to run them from the command line. It
|
||||
prints the test output and results to the console and returns the proper status
|
||||
code depending on whether the tests passed or failed.
|
||||
|
||||
## Publishing
|
||||
|
||||
Atom bundles a command line utility called [apm] which can be used to publish
|
||||
Atom bundles a command line utility called apm which can be used to publish
|
||||
Atom packages to the public registry.
|
||||
|
||||
Once your package is written and ready for distribution you can run the
|
||||
@@ -360,25 +356,11 @@ registry.
|
||||
Run `apm help publish` to see all the available options and `apm help` to see
|
||||
all the other available commands.
|
||||
|
||||
## Included Libraries
|
||||
|
||||
FIXME: Describe `require 'atom'
|
||||
|
||||
In addition to core node.js modules, all packages can `require` the following
|
||||
popular libraries into their packages:
|
||||
|
||||
* [SpacePen] (as `require 'space-pen'`)
|
||||
* [jQuery] (as `require 'jquery'`)
|
||||
* [Underscore] (as `require 'underscore'`)
|
||||
|
||||
Additional libraries can be found by browsing Atom's *node_modules* folder.
|
||||
|
||||
[file-tree]: https://github.com/atom/tree-view
|
||||
[status-bar]: https://github.com/atom/status-bar
|
||||
[cs-syntax]: https://github.com/atom/language-coffee-script
|
||||
[npm]: http://en.wikipedia.org/wiki/Npm_(software)
|
||||
[npm-keys]: https://npmjs.org/doc/json.html
|
||||
[apm]: https://github.com/atom/apm
|
||||
[git-tag]: http://git-scm.com/book/en/Git-Basics-Tagging
|
||||
[wrap-guide]: https://github.com/atom/wrap-guide/
|
||||
[keymaps]: advanced/keymaps.md
|
||||
@@ -388,8 +370,10 @@ Additional libraries can be found by browsing Atom's *node_modules* folder.
|
||||
[path]: http://nodejs.org/docs/latest/api/path.html
|
||||
[jquery]: http://jquery.com/
|
||||
[underscore]: http://underscorejs.org/
|
||||
[jasmine]: https://github.com/pivotal/jasmine
|
||||
[jasmine]: http://jasmine.github.io
|
||||
[cson]: https://github.com/atom/season
|
||||
[less]: http://lesscss.org
|
||||
[ui-variables]: https://github.com/atom/atom-dark-ui/blob/master/stylesheets/ui-variables.less
|
||||
[first-package]: your-first-package.html
|
||||
[convert-bundle]: converting-a-text-mate-bundle.html
|
||||
[convert-theme]: converting-a-text-mate-theme.html
|
||||
|
||||
+20
-13
@@ -32,14 +32,15 @@ Let's create your first theme.
|
||||
|
||||
To get started, hit `cmd-shift-P`, and start typing "Generate Syntax Theme" to
|
||||
generate a new theme package. Select "Generate Syntax Theme," and you'll be
|
||||
asked for the path where your theme will be created. Let's call ours _motif_.
|
||||
asked for the path where your theme will be created. Let's call ours
|
||||
_motif-syntax_. __Tip:__ syntax themes should end with _-syntax_.
|
||||
|
||||
Atom will pop open a new window, showing the _motif_ theme, with a default set
|
||||
of folders and files created for us. If you open the settings view (`cmd-,`)
|
||||
and navigate to the _Themes_ section on the left, you'll see the _Motif_ theme
|
||||
listed in the _Syntax Theme_ drop-down. Select it from the menu to activate it,
|
||||
now when you open an editor you should see that your new _motif_ theme in
|
||||
action.
|
||||
Atom will pop open a new window, showing the _motif-syntax_ theme, with a
|
||||
default set of folders and files created for us. If you open the settings view
|
||||
(`cmd-,`) and navigate to the _Themes_ section on the left, you'll see the
|
||||
_Motif_ theme listed in the _Syntax Theme_ drop-down. Select it from the menu to
|
||||
activate it, now when you open an editor you should see that your new
|
||||
_motif-syntax_ theme in action.
|
||||
|
||||
Open up _stylesheets/colors.less_ to change the various colors variables which
|
||||
have been already been defined. For example, turn `@red` into `#f4c2c1`.
|
||||
@@ -50,9 +51,14 @@ editor such as comments, strings and the line numbers in the gutter.
|
||||
|
||||
As an example, let's make the `.gutter` `background-color` into `@red`.
|
||||
|
||||
Reload Atom by pressing `cmd-alt-option-L` to see the changes you made reflected
|
||||
Reload Atom by pressing `cmd-alt-ctrl-l` to see the changes you made reflected
|
||||
in your Atom window. Pretty neat!
|
||||
|
||||
__Tip:__ You can avoid reloading to see changes you make by opening an atom
|
||||
window in dev mode. To open a Dev Mode Atom window run `atom --dev .` in the
|
||||
terminal, use `cmd-shift-o` or use the _View > Developer > Open in Dev Mode_
|
||||
menu. When you edit your theme, changes will instantly be reflected!
|
||||
|
||||
## Creating an Interface Theme
|
||||
|
||||
Interface themes **must** provide a `ui-variables.less` file which contains all
|
||||
@@ -66,13 +72,14 @@ To create an interface UI theme, do the following:
|
||||
2. Clone the forked repository to the local filesystem
|
||||
3. Open a terminal in the forked theme's directory
|
||||
4. Open your new theme in a Dev Mode Atom window run `atom --dev .` in the
|
||||
terminal or use the _View > Developer > Open in Dev Mode_ menu)
|
||||
terminal or use the _View > Developer > Open in Dev Mode_ menu
|
||||
5. Change the name of the theme in the theme's `package.json` file
|
||||
6. Run `apm link` to symlink your repository to `~/.atom/packages`
|
||||
7. Reload Atom using `cmd-alt-ctrl-L`
|
||||
8. Enable the theme via _UI Theme_ drop-down in the _Themes_ section of the
|
||||
6. Name your theme end with a `-ui`. i.e. `super-white-ui`
|
||||
7. Run `apm link` to symlink your repository to `~/.atom/packages`
|
||||
8. Reload Atom using `cmd-alt-ctrl-L`
|
||||
9. Enable the theme via _UI Theme_ drop-down in the _Themes_ section of the
|
||||
settings view
|
||||
9. Make changes! Since you opened the theme in a Dev Mode window, changes will
|
||||
10. Make changes! Since you opened the theme in a Dev Mode window, changes will
|
||||
be instantly reflected in the editor without having to reload.
|
||||
|
||||
## Development workflow
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Customizing Atom
|
||||
|
||||
To change a setting, configure a theme, or install a package just open the
|
||||
Settings view in the current window by pressing `cmd+,`.
|
||||
Settings view in the current window by pressing `cmd-,`.
|
||||
|
||||
## Changing The Theme
|
||||
|
||||
@@ -63,9 +63,8 @@ built-in keymaps:
|
||||
'.editor':
|
||||
'enter': 'editor:newline'
|
||||
|
||||
'body':
|
||||
'ctrl-b': 'core:move-left'
|
||||
'ctrl-f': 'core:move-right'
|
||||
'.mini.editor input':
|
||||
'enter': 'core:confirm'
|
||||
```
|
||||
|
||||
This keymap defines the meaning of `enter` in two different contexts. In a
|
||||
@@ -87,7 +86,7 @@ currently in use.
|
||||
## Advanced Configuration
|
||||
|
||||
Atom loads configuration settings from the `config.cson` file in your _~/.atom_
|
||||
directory, which contains CoffeeScript-style JSON:
|
||||
directory, which contains [CoffeeScript-style JSON][CSON] (CSON):
|
||||
|
||||
```coffee
|
||||
'core':
|
||||
@@ -111,7 +110,6 @@ You can open this file in an editor from the _Atom > Open Your Config_ menu.
|
||||
- `themes`: An array of theme names to load, in cascading order
|
||||
- `editor`
|
||||
- `autoIndent`: Enable/disable basic auto-indent (defaults to `true`)
|
||||
- `autoIndentOnPaste`: Enable/disable auto-indented pasted text (defaults to `false`)
|
||||
- `nonWordCharacters`: A string of non-word characters to define word boundaries
|
||||
- `fontSize`: The editor font size
|
||||
- `fontFamily`: The editor font family
|
||||
@@ -142,13 +140,21 @@ You can open this file in an editor from the _Atom > Open Your Config_ menu.
|
||||
### init.coffee
|
||||
|
||||
When Atom finishes loading, it will evaluate _init.coffee_ in your _~/.atom_
|
||||
directory, giving you a chance to run arbitrary personal CoffeeScript code to
|
||||
directory, giving you a chance to run arbitrary personal [CoffeeScript][] code to
|
||||
make customizations. You have full access to Atom's API from code in this file.
|
||||
If customizations become extensive, consider [creating a package][create-a-package].
|
||||
If customizations become extensive, consider [creating a package][creating-a-package].
|
||||
|
||||
You can open this file in an editor from the _Atom > Open Your Init Script_
|
||||
menu.
|
||||
|
||||
For example, if you have the Audio Beep configuration setting enabled, you
|
||||
could add the following code to your _~/.atom/init.coffee_ file to have Atom
|
||||
greet you with an audio beep every time it loads:
|
||||
|
||||
```coffee
|
||||
atom.beep()
|
||||
```
|
||||
|
||||
This file can also be named _init.js_ and contain JavaScript code.
|
||||
|
||||
### styles.less
|
||||
@@ -172,6 +178,8 @@ Unfamiliar with LESS? Read more about it [here][LESS].
|
||||
|
||||
This file can also be named _styles.css_ and contain CSS.
|
||||
|
||||
[create-a-package]: creating-packages.md
|
||||
[creating-a-package]: creating-a-package.md
|
||||
[create-theme]: creating-a-theme.md
|
||||
[LESS]: http://www.lesscss.org
|
||||
[CSON]: https://github.com/atom/season
|
||||
[CoffeeScript]: http://coffeescript.org/
|
||||
|
||||
@@ -73,7 +73,7 @@ from.
|
||||
You can split any editor pane horizontally or vertically by using `cmd-k right`
|
||||
or `cmd-k down`. Once you have a split pane, you can move focus between them
|
||||
with `cmd-k cmd-right` or `cmd-k cmd-down`. To close a pane, close all its
|
||||
editors with `meta-w`, then press `meta-w` one more time to close the pane. You
|
||||
editors with `cmd-w`, then press `cmd-w` one more time to close the pane. You
|
||||
can configure panes to auto-close when empty in the Settings view.
|
||||
|
||||
### Folding
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
* [Creating a Package](creating-a-package.md)
|
||||
* [Creating a Theme](creating-a-theme.md)
|
||||
* [Publishing a Package](publishing-a-package.md)
|
||||
* [Converting a TextMate Bundle](converting-a-text-mate-bundle.md)
|
||||
* [Converting a TextMate Theme](converting-a-text-mate-theme.md)
|
||||
* [Contributing](contributing.md)
|
||||
|
||||
### Advanced Topics
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
# Setting up Travis CI
|
||||
|
||||
Packages under the [atom org][atom-org] should use [Travis CI][travis-ci] for
|
||||
builds.
|
||||
|
||||
Currently we have a [Travis Pro][travis-pro] account since the repositories
|
||||
are private. This process will be simpler and have fewer steps once the
|
||||
package repos are made public.
|
||||
|
||||
Each package builds using the [build-package][build-package] script, any
|
||||
changes to the build should be made in that script and will affect all
|
||||
package builds immediately.
|
||||
|
||||
Each package builds against the latest successful build of atom@master. The
|
||||
master builds are stored in the [atom-master-builds][atom-master-builds] repo
|
||||
as releases named by the SHA-1 built.
|
||||
|
||||
## Configuring a package
|
||||
|
||||
* Run `cd ~/github/my-package` to navigate to the package repo locally
|
||||
* Run `apm test` to verify that the package currently builds via [apm][apm]
|
||||
* Add the package repo to the [Travis CI team][travis-ci-team]
|
||||
* Run `gem install travis` to install the [travis gem][travis-gem]
|
||||
* Run `travis login --pro` and log in using the [atom-build][atom-build] user
|
||||
and the password from the *Shared-Developers* folder in LastPass
|
||||
* Run `apm ci` to add a `.travis.yml` file to the repo and to configure Travis
|
||||
* Log into [Travis][travis-ci] as the `atom-build` user and you should now see
|
||||
the package listed and building
|
||||
|
||||
|
||||
[apm]: https://github.com/atom/apm
|
||||
[build-package]: https://github.com/atom/apm/blob/master/script/build-package
|
||||
[atom-build]: https://github.com/atom-build
|
||||
[atom-master-builds]: https://github.com/atom/atom-master-builds/releases
|
||||
[atom-org]: https://github.com/atom
|
||||
[travis-ci]: https://magnum.travis-ci.com
|
||||
[travis-ci-team]: https://github.com/organizations/atom/teams/596636
|
||||
[travis-gem]: https://rubygems.org/gems/travis
|
||||
[travis-pro]: http://about.travis-ci.org/docs/user/travis-pro
|
||||
@@ -20,7 +20,8 @@ The final package can be viewed at
|
||||
To begin, press `cmd-shift-P` to bring up the [Command
|
||||
Palette](https://github.com/atom/command-palette). Type "generate package" and
|
||||
select the "Package Generator: Generate Package" command. Now we need to name
|
||||
the package. Let's call it _ascii-art_.
|
||||
the package. Try to avoid naming your package with the *atom-* prefix, for
|
||||
example we are going to call this package _ascii-art_.
|
||||
|
||||
Atom will open a new window with the contents of our new _ascii-art_ package
|
||||
displayed in the Tree View. Because this window is opened **after** the package
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
# '.editor':
|
||||
# 'enter': 'editor:newline'
|
||||
#
|
||||
# 'body':
|
||||
# '.workspace':
|
||||
# 'ctrl-P': 'core:move-up'
|
||||
# 'ctrl-p': 'core:move-down'
|
||||
#
|
||||
|
||||
@@ -21,3 +21,4 @@ unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
|
||||
module.exports.Task = require '../src/task'
|
||||
module.exports.View = View
|
||||
module.exports.WorkspaceView = require '../src/workspace-view'
|
||||
module.exports.Workspace = require '../src/workspace'
|
||||
|
||||
@@ -9,9 +9,6 @@
|
||||
'shift-home': 'editor:select-to-first-character-of-line'
|
||||
'shift-end': 'editor:select-to-end-of-line'
|
||||
|
||||
# Sublime Parity
|
||||
'ctrl-t': 'editor:transpose'
|
||||
|
||||
'.editor:not(.mini)':
|
||||
# Atom Specific
|
||||
'ctrl-C': 'editor:copy-path'
|
||||
|
||||
@@ -96,6 +96,7 @@
|
||||
'.editor':
|
||||
# Apple Specific
|
||||
'cmd-backspace': 'editor:backspace-to-beginning-of-line'
|
||||
'cmd-shift-backspace': 'editor:backspace-to-beginning-of-line'
|
||||
'cmd-delete': 'editor:backspace-to-beginning-of-line'
|
||||
'ctrl-A': 'editor:select-to-first-character-of-line'
|
||||
'ctrl-E': 'editor:select-to-end-of-line'
|
||||
@@ -118,6 +119,7 @@
|
||||
'cmd-k cmd-u': 'editor:upper-case'
|
||||
'cmd-k cmd-l': 'editor:lower-case'
|
||||
'cmd-l': 'editor:select-line'
|
||||
'ctrl-t': 'editor:transpose'
|
||||
|
||||
'.workspace .editor:not(.mini)':
|
||||
# Atom specific
|
||||
@@ -133,8 +135,8 @@
|
||||
'ctrl-cmd-up': 'editor:move-line-up'
|
||||
'ctrl-cmd-down': 'editor:move-line-down'
|
||||
'cmd-/': 'editor:toggle-line-comments'
|
||||
'cmd-j': 'editor:join-line'
|
||||
'cmd-D': 'editor:duplicate-line'
|
||||
'cmd-j': 'editor:join-lines'
|
||||
'cmd-D': 'editor:duplicate-lines'
|
||||
'cmd-L': 'editor:split-selections-into-lines'
|
||||
|
||||
'cmd-alt-[': 'editor:fold-current-row'
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
'body':
|
||||
# Atom Specific
|
||||
'enter': 'core:confirm'
|
||||
'escape': 'core:cancel'
|
||||
'up': 'core:move-up'
|
||||
'down': 'core:move-down'
|
||||
'left': 'core:move-left'
|
||||
'right': 'core:move-right'
|
||||
'ctrl-alt-r': 'window:reload'
|
||||
'ctrl-alt-i': 'window:toggle-dev-tools'
|
||||
'ctrl-alt-p': 'window:run-package-specs'
|
||||
'ctrl-alt-s': 'application:run-all-specs'
|
||||
'ctrl-shift-o': 'application:open-dev'
|
||||
|
||||
# Sublime Parity
|
||||
'ctrl-N': 'application:new-window'
|
||||
'ctrl-W': 'window:close'
|
||||
'ctrl-o': 'application:open'
|
||||
'ctrl-q': 'application:quit'
|
||||
'ctrl-T': 'pane:reopen-closed-item'
|
||||
'ctrl-n': 'application:new-file'
|
||||
'ctrl-s': 'core:save'
|
||||
'ctrl-S': 'core:save-as'
|
||||
'ctrl-w': 'core:close'
|
||||
'ctrl-z': 'core:undo'
|
||||
'ctrl-y': 'core:redo'
|
||||
'ctrl-x': 'core:cut'
|
||||
'ctrl-c': 'core:copy'
|
||||
'ctrl-v': 'core:paste'
|
||||
'shift-up': 'core:select-up'
|
||||
'shift-down': 'core:select-down'
|
||||
'shift-left': 'core:select-left'
|
||||
'shift-right': 'core:select-right'
|
||||
'delete': 'core:delete'
|
||||
'pageup': 'core:page-up'
|
||||
'pagedown': 'core:page-down'
|
||||
'backspace': 'core:backspace'
|
||||
'ctrl-tab': 'pane:show-next-item'
|
||||
'ctrl-shift-tab': 'pane:show-previous-item'
|
||||
'ctrl-shift-up': 'core:move-up'
|
||||
'ctrl-shift-down': 'core:move-down'
|
||||
'ctrl-=': 'window:increase-font-size'
|
||||
'ctrl-+': 'window:increase-font-size'
|
||||
'ctrl--': 'window:decrease-font-size'
|
||||
'ctrl-_': 'window:decrease-font-size'
|
||||
'ctrl-0': 'window:reset-font-size'
|
||||
|
||||
'ctrl-k up': 'pane:split-up' # Atom Specific
|
||||
'ctrl-k down': 'pane:split-down' # Atom Specific
|
||||
'ctrl-k left': 'pane:split-left' # Atom Specific
|
||||
'ctrl-k right': 'pane:split-right' # Atom Specific
|
||||
'ctrl-k ctrl-w': 'pane:close' # Atom Specific
|
||||
'ctrl-k alt-ctrl-w': 'pane:close-other-items' # Atom Specific
|
||||
'ctrl-k ctrl-p': 'window:focus-previous-pane'
|
||||
'ctrl-k ctrl-n': 'window:focus-next-pane'
|
||||
'ctrl-k ctrl-up': 'window:focus-pane-above'
|
||||
'ctrl-k ctrl-down': 'window:focus-pane-below'
|
||||
'ctrl-k ctrl-left': 'window:focus-pane-on-left'
|
||||
'ctrl-k ctrl-right': 'window:focus-pane-on-right'
|
||||
|
||||
'.workspace .editor':
|
||||
# Windows specific
|
||||
'ctrl-delete': 'editor:backspace-to-beginning-of-word'
|
||||
|
||||
# Sublime Parity
|
||||
'ctrl-a': 'core:select-all'
|
||||
'ctrl-alt-p': 'editor:log-cursor-scope'
|
||||
'ctrl-k ctrl-u': 'editor:upper-case'
|
||||
'ctrl-k ctrl-l': 'editor:lower-case'
|
||||
|
||||
'.workspace .editor:not(.mini)':
|
||||
# Atom specific
|
||||
'alt-ctrl-z': 'editor:checkout-head-revision'
|
||||
'ctrl-<': 'editor:scroll-to-cursor'
|
||||
'alt-ctrl-f': 'editor:fold-selection'
|
||||
|
||||
# Sublime Parity
|
||||
'ctrl-enter': 'editor:newline-below'
|
||||
'ctrl-shift-enter': 'editor:newline-above'
|
||||
'ctrl-]': 'editor:indent-selected-rows'
|
||||
'ctrl-[': 'editor:outdent-selected-rows'
|
||||
'ctrl-up': 'editor:move-line-up'
|
||||
'ctrl-down': 'editor:move-line-down'
|
||||
'ctrl-/': 'editor:toggle-line-comments'
|
||||
'ctrl-j': 'editor:join-lines'
|
||||
'ctrl-D': 'editor:duplicate-lines'
|
||||
|
||||
'ctrl-alt-[': 'editor:fold-current-row'
|
||||
'ctrl-alt-]': 'editor:unfold-current-row'
|
||||
'ctrl-alt-{': 'editor:fold-all' # Atom Specific
|
||||
'ctrl-alt-}': 'editor:unfold-all' # Atom Specific
|
||||
'ctrl-k ctrl-0': 'editor:unfold-all'
|
||||
'ctrl-k ctrl-1': 'editor:fold-at-indent-level-1'
|
||||
'ctrl-k ctrl-2': 'editor:fold-at-indent-level-2'
|
||||
'ctrl-k ctrl-3': 'editor:fold-at-indent-level-3'
|
||||
'ctrl-k ctrl-4': 'editor:fold-at-indent-level-4'
|
||||
'ctrl-k ctrl-5': 'editor:fold-at-indent-level-5'
|
||||
'ctrl-k ctrl-6': 'editor:fold-at-indent-level-6'
|
||||
'ctrl-k ctrl-7': 'editor:fold-at-indent-level-7'
|
||||
'ctrl-k ctrl-8': 'editor:fold-at-indent-level-8'
|
||||
'ctrl-k ctrl-9': 'editor:fold-at-indent-level-9'
|
||||
|
||||
# allow standard input fields to work correctly
|
||||
'body .native-key-bindings':
|
||||
'ctrl-z': 'native!'
|
||||
'ctrl-Z': 'native!'
|
||||
'ctrl-x': 'native!'
|
||||
'ctrl-c': 'native!'
|
||||
'ctrl-v': 'native!'
|
||||
@@ -80,8 +80,8 @@
|
||||
'ctrl-up': 'editor:move-line-up'
|
||||
'ctrl-down': 'editor:move-line-down'
|
||||
'ctrl-/': 'editor:toggle-line-comments'
|
||||
'ctrl-j': 'editor:join-line'
|
||||
'ctrl-D': 'editor:duplicate-line'
|
||||
'ctrl-j': 'editor:join-lines'
|
||||
'ctrl-D': 'editor:duplicate-lines'
|
||||
|
||||
'ctrl-alt-[': 'editor:fold-current-row'
|
||||
'ctrl-alt-]': 'editor:unfold-current-row'
|
||||
|
||||
+4
-3
@@ -7,6 +7,7 @@
|
||||
{ label: "VERSION", enabled: false }
|
||||
{ label: "Restart and Install Update", command: 'application:install-update', visible: false}
|
||||
{ label: "Check for Update", command: 'application:check-for-update', visible: false}
|
||||
{ label: "Downloading Update", command: 'application:check-for-update', enabled: false, visible: false}
|
||||
{ type: 'separator' }
|
||||
{ label: 'Preferences...', command: 'application:show-settings' }
|
||||
{ label: 'Open Your Config', command: 'application:open-your-config' }
|
||||
@@ -37,7 +38,7 @@
|
||||
{ label: 'Save All', command: 'window:save-all' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Close Buffer', command: 'core:close' }
|
||||
{ label: 'Close All Buffers', command: 'pane:close' }
|
||||
{ label: 'Close Pane', command: 'pane:close' }
|
||||
{ label: 'Close Window', command: 'window:close' }
|
||||
]
|
||||
}
|
||||
@@ -64,9 +65,9 @@
|
||||
{ type: 'separator' }
|
||||
{ label: 'Move Line Up', command: 'editor:move-line-up' }
|
||||
{ label: 'Move Line Down', command: 'editor:move-line-down' }
|
||||
{ label: 'Duplicate Line', command: 'editor:duplicate-line' }
|
||||
{ label: 'Duplicate Lines', command: 'editor:duplicate-lines' }
|
||||
{ label: 'Delete Line', command: 'editor:delete-line' }
|
||||
{ label: 'Join Lines', command: 'editor:join-line' }
|
||||
{ label: 'Join Lines', command: 'editor:join-lines' }
|
||||
]
|
||||
}
|
||||
{
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
'menu': [
|
||||
{
|
||||
label: '&File'
|
||||
submenu: [
|
||||
{ label: 'New &Window', command: 'application:new-window' }
|
||||
{ label: '&New File', command: 'application:new-file' }
|
||||
{ label: '&Open...', command: 'application:open' }
|
||||
{ label: 'Reopen Last &Item', command: 'pane:reopen-closed-item' }
|
||||
{ type: 'separator' }
|
||||
{ label: '&Preferences...', command: 'application:show-settings' }
|
||||
{ type: 'separator' }
|
||||
{ label: '&Save', command: 'core:save' }
|
||||
{ label: 'Save &As...', command: 'core:save-as' }
|
||||
{ label: 'Save A&ll', command: 'window:save-all' }
|
||||
{ type: 'separator' }
|
||||
{ label: '&Close Buffer', command: 'core:close' }
|
||||
{ label: 'Close All &Buffers', command: 'pane:close' }
|
||||
{ label: 'Clos&e Window', command: 'window:close' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Quit', command: 'application:quit' }
|
||||
]
|
||||
}
|
||||
|
||||
{
|
||||
label: '&Edit'
|
||||
submenu: [
|
||||
{ label: '&Undo', command: 'core:undo' }
|
||||
{ label: '&Redo', command: 'core:redo' }
|
||||
{ type: 'separator' }
|
||||
{ label: '&Cut', command: 'core:cut' }
|
||||
{ label: 'C&opy', command: 'core:copy' }
|
||||
{ label: 'Copy Pat&h', command: 'editor:copy-path' }
|
||||
{ label: '&Paste', command: 'core:paste' }
|
||||
{ label: 'Select &All', command: 'core:select-all' }
|
||||
{ type: 'separator' }
|
||||
{ label: '&Toggle Comments', command: 'editor:toggle-line-comments' }
|
||||
{
|
||||
label: 'Lines',
|
||||
submenu: [
|
||||
{ label: '&Indent', command: 'editor:indent-selected-rows' }
|
||||
{ label: '&Outdent', command: 'editor:outdent-selected-rows' }
|
||||
{ label: '&Auto Indent', command: 'editor:auto-indent' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Move Line &Up', command: 'editor:move-line-up' }
|
||||
{ label: 'Move Line &Down', command: 'editor:move-line-down' }
|
||||
{ label: 'Du&plicate Lines', command: 'editor:duplicate-lines' }
|
||||
{ label: 'D&elete Line', command: 'editor:delete-line' }
|
||||
{ label: '&Join Lines', command: 'editor:join-lines' }
|
||||
]
|
||||
}
|
||||
{
|
||||
label: 'Text',
|
||||
submenu: [
|
||||
{ label: '&Upper Case', command: 'editor:upper-case' }
|
||||
{ label: '&Lower Case', command: 'editor:lower-case' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Delete to End of &Word', command: 'editor:delete-to-end-of-word' }
|
||||
{ label: '&Delete Line', command: 'editor:delete-line' }
|
||||
{ type: 'separator' }
|
||||
{ label: '&Transpose', command: 'editor:transpose' }
|
||||
]
|
||||
}
|
||||
{
|
||||
label: 'Folding',
|
||||
submenu: [
|
||||
{ label: '&Fold', command: 'editor:fold-current-row' }
|
||||
{ label: '&Unfold', command: 'editor:unfold-current-row' }
|
||||
{ label: 'Unfold &All', command: 'editor:unfold-all' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Fol&d All', command: 'editor:fold-all' }
|
||||
{ label: 'Fold Level 1', command: 'editor:fold-at-indent-level-1' }
|
||||
{ label: 'Fold Level 2', command: 'editor:fold-at-indent-level-2' }
|
||||
{ label: 'Fold Level 3', command: 'editor:fold-at-indent-level-3' }
|
||||
{ label: 'Fold Level 4', command: 'editor:fold-at-indent-level-4' }
|
||||
{ label: 'Fold Level 5', command: 'editor:fold-at-indent-level-5' }
|
||||
{ label: 'Fold Level 6', command: 'editor:fold-at-indent-level-6' }
|
||||
{ label: 'Fold Level 7', command: 'editor:fold-at-indent-level-7' }
|
||||
{ label: 'Fold Level 8', command: 'editor:fold-at-indent-level-8' }
|
||||
{ label: 'Fold Level 9', command: 'editor:fold-at-indent-level-9' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
{
|
||||
label: '&View'
|
||||
submenu: [
|
||||
{ label: '&Reload', command: 'window:reload' }
|
||||
{ label: 'Toggle &Full Screen', command: 'window:toggle-full-screen' }
|
||||
{
|
||||
label: 'Developer'
|
||||
submenu: [
|
||||
{ label: 'Open In &Dev Mode...', command: 'application:open-dev' }
|
||||
{ label: 'Run &Atom Specs', command: 'application:run-all-specs' }
|
||||
{ label: 'Run Package &Specs', command: 'window:run-package-specs' }
|
||||
{ label: 'Toggle Developer &Tools', command: 'window:toggle-dev-tools' }
|
||||
]
|
||||
}
|
||||
{ type: 'separator' }
|
||||
{ label: 'Toggle Soft &Wrap', command: 'editor:toggle-soft-wrap' }
|
||||
]
|
||||
}
|
||||
|
||||
{
|
||||
label: '&Selection'
|
||||
submenu: [
|
||||
{ label: 'Add Selection &Above', command: 'editor:add-selection-above' }
|
||||
{ label: 'Add Selection &Below', command: 'editor:add-selection-below' }
|
||||
{ label: 'S&plit into Lines', command: 'editor:split-selections-into-lines'}
|
||||
{ type: 'separator' }
|
||||
{ label: 'Select to &Top', command: 'core:select-to-top' }
|
||||
{ label: 'Select to Botto&m', command: 'core:select-to-bottom' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Select &Line', command: 'editor:select-line' }
|
||||
{ label: 'Select &Word', command: 'editor:select-word' }
|
||||
{ label: 'Select to Beginning of W&ord', command: 'editor:select-to-beginning-of-word' }
|
||||
{ label: 'Select to Beginning of L&ine', command: 'editor:select-to-beginning-of-line' }
|
||||
{ label: 'Select to First &Character of Line', command: 'editor:select-to-first-character-of-line' }
|
||||
{ label: 'Select to End of Wor&d', command: 'editor:select-to-end-of-word' }
|
||||
{ label: 'Select to End of Lin&e', command: 'editor:select-to-end-of-line' }
|
||||
]
|
||||
}
|
||||
|
||||
{
|
||||
label: 'F&ind'
|
||||
submenu: []
|
||||
}
|
||||
|
||||
{
|
||||
label: '&Packages'
|
||||
submenu: []
|
||||
}
|
||||
|
||||
{
|
||||
label: '&Window'
|
||||
submenu: [
|
||||
{ label: 'Mi&nimize', command: 'application:minimize' }
|
||||
{ label: 'Ma&ximize', command: 'application:zoom' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Bring &All to Front', command: 'application:bring-all-windows-to-front' }
|
||||
]
|
||||
}
|
||||
|
||||
{
|
||||
label: '&Help'
|
||||
submenu: [
|
||||
{ label: 'View &License', command: 'application:open-license' }
|
||||
{ label: "VERSION", enabled: false }
|
||||
{ type: 'separator' }
|
||||
{ label: '&Documentation', command: 'application:open-documentation' }
|
||||
{ type: 'separator' }
|
||||
]
|
||||
}
|
||||
]
|
||||
+2
-2
@@ -43,9 +43,9 @@
|
||||
{ type: 'separator' }
|
||||
{ label: 'Move Line &Up', command: 'editor:move-line-up' }
|
||||
{ label: 'Move Line &Down', command: 'editor:move-line-down' }
|
||||
{ label: 'Du&plicate Line', command: 'editor:duplicate-line' }
|
||||
{ label: 'Du&plicate Lines', command: 'editor:duplicate-lines' }
|
||||
{ label: 'D&elete Line', command: 'editor:delete-line' }
|
||||
{ label: '&Join Lines', command: 'editor:join-line' }
|
||||
{ label: '&Join Lines', command: 'editor:join-lines' }
|
||||
]
|
||||
}
|
||||
{
|
||||
|
||||
+85
-87
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"name": "atom",
|
||||
"productName": "Atom",
|
||||
"version": "0.56.0",
|
||||
"version": "0.83.0",
|
||||
"description": "A hackable text editor for the 21st Century.",
|
||||
"main": "./src/browser/main.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -10,125 +11,122 @@
|
||||
"bugs": {
|
||||
"url": "https://github.com/atom/atom/issues"
|
||||
},
|
||||
"licenses": [
|
||||
{
|
||||
"type": "Apache",
|
||||
"url": "http://github.com/atom/atom/raw/master/LICENSE.md"
|
||||
}
|
||||
],
|
||||
"atomShellVersion": "0.10.1",
|
||||
"license": "All Rights Reserved",
|
||||
"atomShellVersion": "0.11.5",
|
||||
"dependencies": {
|
||||
"async": "0.2.6",
|
||||
"atom-keymap": "^0.16.0",
|
||||
"bootstrap": "git://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372",
|
||||
"clear-cut": "0.4.0",
|
||||
"coffee-script": "1.7.0",
|
||||
"coffeestack": "0.7.0",
|
||||
"delegato": "1.x",
|
||||
"emissary": "1.x",
|
||||
"first-mate": ">=1.1.5 <2.0",
|
||||
"fs-plus": "2.x",
|
||||
"emissary": "^1.2.1",
|
||||
"first-mate": "^1.5.1",
|
||||
"fs-plus": "^2.2",
|
||||
"fstream": "0.1.24",
|
||||
"fuzzaldrin": "1.x",
|
||||
"git-utils": "1.x",
|
||||
"fuzzaldrin": "~1.1",
|
||||
"git-utils": "^1.2.2",
|
||||
"guid": "0.0.10",
|
||||
"jasmine-tagged": ">=1.1.1 <2.0",
|
||||
"mkdirp": "0.3.5",
|
||||
"keytar": "0.15.1",
|
||||
"jasmine-tagged": "^1.1.1",
|
||||
"keytar": "1.x",
|
||||
"less-cache": "0.12.0",
|
||||
"mixto": "1.x",
|
||||
"mkdirp": "0.3.5",
|
||||
"nslog": "0.5.0",
|
||||
"oniguruma": "1.x",
|
||||
"oniguruma": "^1.0.6",
|
||||
"optimist": "0.4.0",
|
||||
"pathwatcher": "0.16.0",
|
||||
"pegjs": "0.8.0",
|
||||
"pathwatcher": "^1.1.1",
|
||||
"property-accessors": "1.x",
|
||||
"q": "1.0.x",
|
||||
"q": "^1.0.1",
|
||||
"random-words": "0.0.1",
|
||||
"runas": "0.5.x",
|
||||
"scandal": "0.15.0",
|
||||
"season": ">=1.0.2 <2.0",
|
||||
"scandal": "0.15.2",
|
||||
"scoped-property-store": "^0.8.0",
|
||||
"scrollbar-style": "^0.1.0",
|
||||
"season": "^1.0.2",
|
||||
"semver": "1.1.4",
|
||||
"serializable": "1.x",
|
||||
"space-pen": "3.1.1",
|
||||
"temp": "0.5.0",
|
||||
"text-buffer": ">=1.1.2 <2.0",
|
||||
"text-buffer": "^1.4.6",
|
||||
"theorist": "1.x",
|
||||
"underscore-plus": "1.x",
|
||||
"underscore-plus": "^1.1.2",
|
||||
"vm-compatibility-layer": "0.1.0"
|
||||
},
|
||||
"packageDependencies": {
|
||||
"atom-dark-syntax": "0.14.0",
|
||||
"atom-dark-ui": "0.23.0",
|
||||
"atom-light-syntax": "0.14.0",
|
||||
"atom-light-ui": "0.22.0",
|
||||
"base16-tomorrow-dark-theme": "0.12.0",
|
||||
"solarized-dark-syntax": "0.10.0",
|
||||
"solarized-light-syntax": "0.6.0",
|
||||
"archive-view": "0.24.0",
|
||||
"autocomplete": "0.24.0",
|
||||
"atom-dark-syntax": "0.15.0",
|
||||
"atom-dark-ui": "0.26.0",
|
||||
"atom-light-syntax": "0.16.0",
|
||||
"atom-light-ui": "0.23.0",
|
||||
"base16-tomorrow-dark-theme": "0.13.0",
|
||||
"solarized-dark-syntax": "0.14.0",
|
||||
"solarized-light-syntax": "0.7.0",
|
||||
"archive-view": "0.30.0",
|
||||
"autocomplete": "0.27.0",
|
||||
"autoflow": "0.15.0",
|
||||
"autosave": "0.12.0",
|
||||
"background-tips": "0.8.0",
|
||||
"bookmarks": "0.21.0",
|
||||
"bracket-matcher": "0.22.0",
|
||||
"command-palette": "0.18.0",
|
||||
"dev-live-reload": "0.28.0",
|
||||
"exception-reporting": "0.15.0",
|
||||
"feedback": "0.27.0",
|
||||
"find-and-replace": "0.85.0",
|
||||
"fuzzy-finder": "0.37.0",
|
||||
"git-diff": "0.25.0",
|
||||
"go-to-line": "0.17.0",
|
||||
"grammar-selector": "0.21.0",
|
||||
"image-view": "0.25.0",
|
||||
"keybinding-resolver": "0.11.0",
|
||||
"link": "0.18.0",
|
||||
"markdown-preview": "0.37.0",
|
||||
"metrics": "0.28.0",
|
||||
"open-on-github": "0.21.0",
|
||||
"package-generator": "0.28.0",
|
||||
"release-notes": "0.24.0",
|
||||
"settings-view": "0.82.0",
|
||||
"snippets": "0.32.0",
|
||||
"spell-check": "0.26.0",
|
||||
"status-bar": "0.33.0",
|
||||
"styleguide": "0.25.0",
|
||||
"symbols-view": "0.38.0",
|
||||
"tabs": "0.24.0",
|
||||
"timecop": "0.15.0",
|
||||
"tree-view": "0.71.0",
|
||||
"update-package-dependencies": "0.4.0",
|
||||
"welcome": "0.8.0",
|
||||
"whitespace": "0.15.0",
|
||||
"wrap-guide": "0.15.0",
|
||||
"language-c": "0.12.0",
|
||||
"language-coffee-script": "0.13.0",
|
||||
"language-css": "0.10.0",
|
||||
"language-gfm": "0.18.0",
|
||||
"autosave": "0.13.0",
|
||||
"background-tips": "0.10.0",
|
||||
"bookmarks": "0.22.0",
|
||||
"bracket-matcher": "0.29.0",
|
||||
"command-palette": "0.20.0",
|
||||
"dev-live-reload": "0.30.0",
|
||||
"exception-reporting": "0.17.0",
|
||||
"feedback": "0.28.0",
|
||||
"find-and-replace": "0.94.0",
|
||||
"fuzzy-finder": "0.45.0",
|
||||
"git-diff": "0.27.0",
|
||||
"go-to-line": "0.18.0",
|
||||
"grammar-selector": "0.23.0",
|
||||
"image-view": "0.32.0",
|
||||
"keybinding-resolver": "0.15.0",
|
||||
"link": "0.20.0",
|
||||
"markdown-preview": "0.58.0",
|
||||
"metrics": "0.32.0",
|
||||
"open-on-github": "0.25.0",
|
||||
"package-generator": "0.30.0",
|
||||
"release-notes": "0.26.0",
|
||||
"settings-view": "0.107.0",
|
||||
"snippets": "0.40.0",
|
||||
"spell-check": "0.32.0",
|
||||
"status-bar": "0.38.0",
|
||||
"styleguide": "0.28.0",
|
||||
"symbols-view": "0.49.0",
|
||||
"tabs": "0.34.0",
|
||||
"timecop": "0.17.0",
|
||||
"tree-view": "0.86.0",
|
||||
"update-package-dependencies": "0.6.0",
|
||||
"welcome": "0.12.0",
|
||||
"whitespace": "0.22.0",
|
||||
"wrap-guide": "0.18.0",
|
||||
"language-c": "0.14.0",
|
||||
"language-coffee-script": "0.18.0",
|
||||
"language-css": "0.13.0",
|
||||
"language-gfm": "0.28.0",
|
||||
"language-git": "0.9.0",
|
||||
"language-go": "0.6.0",
|
||||
"language-html": "0.8.0",
|
||||
"language-hyperlink": "0.8.0",
|
||||
"language-java": "0.8.0",
|
||||
"language-javascript": "0.11.0",
|
||||
"language-go": "0.8.0",
|
||||
"language-html": "0.17.0",
|
||||
"language-hyperlink": "0.9.0",
|
||||
"language-java": "0.9.0",
|
||||
"language-javascript": "0.21.0",
|
||||
"language-json": "0.8.0",
|
||||
"language-less": "0.5.0",
|
||||
"language-make": "0.8.0",
|
||||
"language-objective-c": "0.9.0",
|
||||
"language-less": "0.6.0",
|
||||
"language-make": "0.9.0",
|
||||
"language-objective-c": "0.11.0",
|
||||
"language-perl": "0.8.0",
|
||||
"language-php": "0.8.0",
|
||||
"language-php": "0.14.0",
|
||||
"language-property-list": "0.7.0",
|
||||
"language-python": "0.8.0",
|
||||
"language-ruby": "0.13.0",
|
||||
"language-ruby-on-rails": "0.7.0",
|
||||
"language-python": "0.14.0",
|
||||
"language-ruby": "0.21.0",
|
||||
"language-ruby-on-rails": "0.12.0",
|
||||
"language-sass": "0.8.0",
|
||||
"language-shellscript": "0.7.0",
|
||||
"language-shellscript": "0.8.0",
|
||||
"language-source": "0.7.0",
|
||||
"language-sql": "0.7.0",
|
||||
"language-text": "0.6.0",
|
||||
"language-todo": "0.6.0",
|
||||
"language-toml": "0.11.0",
|
||||
"language-xml": "0.7.0",
|
||||
"language-todo": "0.9.0",
|
||||
"language-toml": "0.12.0",
|
||||
"language-xml": "0.9.0",
|
||||
"language-yaml": "0.6.0"
|
||||
},
|
||||
"private": true,
|
||||
|
||||
Arquivo binário não exibido.
|
Antes Largura: | Altura: | Tamanho: 48 KiB Depois Largura: | Altura: | Tamanho: 191 KiB |
@@ -0,0 +1,8 @@
|
||||
[Desktop Entry]
|
||||
Name=Atom
|
||||
Comment=<%= description %>
|
||||
Exec=/usr/share/atom/atom %U
|
||||
Icon=atom
|
||||
Type=Application
|
||||
StartupNotify=true
|
||||
Categories=GNOME;GTK;Utility;TextEditor;
|
||||
@@ -0,0 +1,8 @@
|
||||
Package: <%= name %>
|
||||
Version: <%= version %>
|
||||
Section: <%= section %>
|
||||
Priority: optional
|
||||
Architecture: <%= arch %>
|
||||
Installed-Size: `du -ks usr|cut -f 1`
|
||||
Maintainer: <%= maintainer %>
|
||||
Description: <%= description %>
|
||||
@@ -25,13 +25,15 @@
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.developer-tools</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.7</string>
|
||||
<string>10.8</string>
|
||||
<key>NSAppleScriptEnabled</key>
|
||||
<string>YES</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>AtomApplication</string>
|
||||
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
||||
<true/>
|
||||
<key>SUPublicDSAKeyFile</key>
|
||||
<string>speakeasy.pem</string>
|
||||
<key>SUScheduledCheckInterval</key>
|
||||
|
||||
+20
-9
@@ -1,4 +1,11 @@
|
||||
#!/usr/bin/env node --harmony_collections
|
||||
#!/usr/bin/env node
|
||||
|
||||
var nodeMinorVersion = process.versions.node.split('.')[1]
|
||||
if (nodeMinorVersion !== '10') {
|
||||
console.warn("You must run script/bootstrap and script/build with node v0.10.x");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var safeExec = require('./utils/child-process-wrapper.js').safeExec;
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
@@ -25,21 +32,25 @@ if (!fs.existsSync(apmInstallPath))
|
||||
if (!fs.existsSync(path.join(apmInstallPath, 'node_modules')))
|
||||
fs.mkdirSync(path.join(apmInstallPath, 'node_modules'));
|
||||
|
||||
var apmPath = 'apm/node_modules/atom-package-manager/bin/apm'
|
||||
var apmFlags = process.env.JANKY_SHA1 || process.argv.indexOf('--no-color') !== -1 ? '--no-color' : '';
|
||||
|
||||
var npmPath = path.resolve(__dirname, '..', 'build', 'node_modules', '.bin', 'npm');
|
||||
var npmFlags = ' --userconfig=' + path.resolve('.npmrc') + ' ';
|
||||
|
||||
var packagesToDedupe = ['fs-plus', 'humanize-plus', 'oniguruma', 'roaster', 'season'];
|
||||
var echoNewLine = process.platform == 'win32' ? 'echo.' : 'echo';
|
||||
|
||||
var commands = [
|
||||
'git submodule --quiet sync',
|
||||
'git submodule --quiet update --recursive --init',
|
||||
{command: 'npm install --quiet', options: {cwd: path.resolve(__dirname, '..', 'build'), ignoreStdout: true}},
|
||||
{command: 'npm install --quiet', options: {cwd: apmVendorPath, ignoreStdout: true}},
|
||||
{command: 'npm install --quiet ' + apmVendorPath, options: {cwd: apmInstallPath, ignoreStdout: true}},
|
||||
{command: 'npm install --quiet ' + apmVendorPath, options: {ignoreStdout: true}},
|
||||
{command: 'node ../../apm/node_modules/atom-package-manager/bin/apm rebuild', options: {cwd: path.resolve('node_modules', 'atom-package-manager'), ignoreStdout: true}},
|
||||
{command: 'npm' + npmFlags + 'install --quiet', options: {cwd: path.resolve(__dirname, '..', 'build'), ignoreStdout: true}},
|
||||
{command: npmPath + npmFlags + 'install --quiet', options: {cwd: apmVendorPath, ignoreStdout: true}},
|
||||
{command: npmPath + npmFlags + 'install --quiet ' + apmVendorPath, options: {cwd: apmInstallPath, ignoreStdout: true}},
|
||||
echoNewLine,
|
||||
'node apm/node_modules/atom-package-manager/bin/apm clean ' + apmFlags,
|
||||
'node apm/node_modules/atom-package-manager/bin/apm install --quiet ' + apmFlags,
|
||||
'node apm/node_modules/atom-package-manager/bin/apm dedupe --quiet ' + apmFlags + ' ' + packagesToDedupe.join(' '),
|
||||
apmPath + ' clean ' + apmFlags,
|
||||
apmPath + ' install --quiet ' + apmFlags,
|
||||
apmPath + ' dedupe --quiet ' + apmFlags + ' ' + packagesToDedupe.join(' '),
|
||||
];
|
||||
|
||||
process.chdir(path.dirname(__dirname));
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env node --harmony_collections
|
||||
#!/usr/bin/env node
|
||||
var cp = require('./utils/child-process-wrapper.js');
|
||||
var path = require('path');
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env node --harmony_collections
|
||||
#!/usr/bin/env node
|
||||
var cp = require('./utils/child-process-wrapper.js');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
+2
-1
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env node --harmony_collections
|
||||
#!/usr/bin/env node
|
||||
var cp = require('./utils/child-process-wrapper.js');
|
||||
var path = require('path');
|
||||
var os = require('os');
|
||||
@@ -22,6 +22,7 @@ var commands = [
|
||||
[__dirname, '..', 'atom-shell'],
|
||||
[home, '.atom', '.node-gyp'],
|
||||
[home, '.atom', 'storage'],
|
||||
[home, '.atom', '.npm'],
|
||||
[tmpdir, 'atom-build'],
|
||||
[tmpdir, 'atom-cached-atom-shells'],
|
||||
[tmpdir, 'atom-compile-cache'],
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env node --harmony_collections
|
||||
#!/usr/bin/env node
|
||||
var cp = require('./utils/child-process-wrapper.js');
|
||||
var path = require('path');
|
||||
|
||||
|
||||
Arquivo executável
+31
@@ -0,0 +1,31 @@
|
||||
#!/bin/bash
|
||||
# mkdeb version control-file-path deb-file-path
|
||||
|
||||
SCRIPT=`readlink -f "$0"`
|
||||
ROOT=`readlink -f $(dirname $SCRIPT)/..`
|
||||
cd $ROOT
|
||||
|
||||
VERSION="$1"
|
||||
CONTROL_FILE="$2"
|
||||
DESKTOP_FILE="$3"
|
||||
ICON_FILE="$4"
|
||||
DEB_PATH="$5"
|
||||
|
||||
TARGET_ROOT="`mktemp -d`"
|
||||
TARGET="$TARGET_ROOT/atom-$VERSION-amd64"
|
||||
|
||||
mkdir -p "$TARGET/usr"
|
||||
env INSTALL_PREFIX="$TARGET/usr" script/grunt install
|
||||
|
||||
mkdir -p "$TARGET/DEBIAN"
|
||||
mv "$CONTROL_FILE" "$TARGET/DEBIAN/control"
|
||||
|
||||
mkdir -p "$TARGET/usr/share/applications"
|
||||
mv "$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"
|
||||
rm -rf $TARGET_ROOT
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env node --harmony_collections
|
||||
#!/usr/bin/env node
|
||||
var safeExec = require('./utils/child-process-wrapper.js').safeExec;
|
||||
var path = require('path');
|
||||
|
||||
|
||||
+22
-12
@@ -126,6 +126,16 @@ describe "the `atom` global", ->
|
||||
expect(eventHandler.callCount).toBe 2
|
||||
expect(mainModule.activate.callCount).toBe 1
|
||||
|
||||
it "activates the package immediately when the events are empty", ->
|
||||
mainModule = require './fixtures/packages/package-with-empty-activation-events/index'
|
||||
spyOn(mainModule, 'activate').andCallThrough()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-empty-activation-events')
|
||||
|
||||
runs ->
|
||||
expect(mainModule.activate.callCount).toBe 1
|
||||
|
||||
describe "when the package has no main module", ->
|
||||
it "does not throw an exception", ->
|
||||
spyOn(console, "error")
|
||||
@@ -160,28 +170,28 @@ describe "the `atom` global", ->
|
||||
element2 = $$ -> @div class: 'test-2'
|
||||
element3 = $$ -> @div class: 'test-3'
|
||||
|
||||
expect(atom.keymap.keyBindingsForKeystrokeMatchingElement('ctrl-z', element1)).toHaveLength 0
|
||||
expect(atom.keymap.keyBindingsForKeystrokeMatchingElement('ctrl-z', element2)).toHaveLength 0
|
||||
expect(atom.keymap.keyBindingsForKeystrokeMatchingElement('ctrl-z', element3)).toHaveLength 0
|
||||
expect(atom.keymaps.keyBindingsForKeystrokeMatchingElement('ctrl-z', element1)).toHaveLength 0
|
||||
expect(atom.keymaps.keyBindingsForKeystrokeMatchingElement('ctrl-z', element2)).toHaveLength 0
|
||||
expect(atom.keymaps.keyBindingsForKeystrokeMatchingElement('ctrl-z', element3)).toHaveLength 0
|
||||
|
||||
atom.packages.activatePackage("package-with-keymaps")
|
||||
|
||||
expect(atom.keymap.keyBindingsForKeystrokeMatchingElement('ctrl-z', element1)[0].command).toBe "test-1"
|
||||
expect(atom.keymap.keyBindingsForKeystrokeMatchingElement('ctrl-z', element2)[0].command).toBe "test-2"
|
||||
expect(atom.keymap.keyBindingsForKeystrokeMatchingElement('ctrl-z', element3)).toHaveLength 0
|
||||
expect(atom.keymaps.keyBindingsForKeystrokeMatchingElement('ctrl-z', element1)[0].command).toBe "test-1"
|
||||
expect(atom.keymaps.keyBindingsForKeystrokeMatchingElement('ctrl-z', element2)[0].command).toBe "test-2"
|
||||
expect(atom.keymaps.keyBindingsForKeystrokeMatchingElement('ctrl-z', element3)).toHaveLength 0
|
||||
|
||||
describe "when the metadata contains a 'keymaps' manifest", ->
|
||||
it "loads only the keymaps specified by the manifest, in the specified order", ->
|
||||
element1 = $$ -> @div class: 'test-1'
|
||||
element3 = $$ -> @div class: 'test-3'
|
||||
|
||||
expect(atom.keymap.keyBindingsForKeystrokeMatchingElement('ctrl-z', element1)).toHaveLength 0
|
||||
expect(atom.keymaps.keyBindingsForKeystrokeMatchingElement('ctrl-z', element1)).toHaveLength 0
|
||||
|
||||
atom.packages.activatePackage("package-with-keymaps-manifest")
|
||||
|
||||
expect(atom.keymap.keyBindingsForKeystrokeMatchingElement('ctrl-z', element1)[0].command).toBe 'keymap-1'
|
||||
expect(atom.keymap.keyBindingsForKeystrokeMatchingElement('ctrl-n', element1)[0].command).toBe 'keymap-2'
|
||||
expect(atom.keymap.keyBindingsForKeystrokeMatchingElement('ctrl-y', element3)).toHaveLength 0
|
||||
expect(atom.keymaps.keyBindingsForKeystrokeMatchingElement('ctrl-z', element1)[0].command).toBe 'keymap-1'
|
||||
expect(atom.keymaps.keyBindingsForKeystrokeMatchingElement('ctrl-n', element1)[0].command).toBe 'keymap-2'
|
||||
expect(atom.keymaps.keyBindingsForKeystrokeMatchingElement('ctrl-y', element3)).toHaveLength 0
|
||||
|
||||
describe "menu loading", ->
|
||||
beforeEach ->
|
||||
@@ -367,8 +377,8 @@ describe "the `atom` global", ->
|
||||
|
||||
runs ->
|
||||
atom.packages.deactivatePackage('package-with-keymaps')
|
||||
expect(atom.keymap.keyBindingsForKeystrokeMatchingElement('ctrl-z', $$ -> @div class: 'test-1')).toHaveLength 0
|
||||
expect(atom.keymap.keyBindingsForKeystrokeMatchingElement('ctrl-z', $$ -> @div class: 'test-2')).toHaveLength 0
|
||||
expect(atom.keymaps.keyBindingsForKeystrokeMatchingElement('ctrl-z', $$ -> @div class: 'test-1')).toHaveLength 0
|
||||
expect(atom.keymaps.keyBindingsForKeystrokeMatchingElement('ctrl-z', $$ -> @div class: 'test-2')).toHaveLength 0
|
||||
|
||||
it "removes the package's stylesheets", ->
|
||||
waitsForPromise ->
|
||||
|
||||
@@ -18,7 +18,7 @@ describe "DisplayBuffer", ->
|
||||
displayBuffer.destroy()
|
||||
buffer.release()
|
||||
|
||||
describe ".copy()", ->
|
||||
describe "::copy()", ->
|
||||
it "creates a new DisplayBuffer with the same initial state", ->
|
||||
marker1 = displayBuffer.markBufferRange([[1, 2], [3, 4]], id: 1)
|
||||
marker2 = displayBuffer.markBufferRange([[2, 3], [4, 5]], isReversed: true, id: 2)
|
||||
@@ -37,7 +37,7 @@ describe "DisplayBuffer", ->
|
||||
expect(displayBuffer2.isFoldedAtBufferRow(3)).toBeTruthy()
|
||||
|
||||
# can diverge from origin
|
||||
displayBuffer2.destroyFoldsContainingBufferRow(3)
|
||||
displayBuffer2.unfoldBufferRow(3)
|
||||
expect(displayBuffer2.isFoldedAtBufferRow(3)).not.toBe displayBuffer.isFoldedAtBufferRow(3)
|
||||
|
||||
describe "when the buffer changes", ->
|
||||
@@ -200,6 +200,12 @@ describe "DisplayBuffer", ->
|
||||
expect(tokensText displayBuffer.lineForRow(12).tokens).toBe 'sort(left).concat(pivot).concat(sort(rig'
|
||||
expect(changeHandler).toHaveBeenCalledWith(start: 0, end: 15, screenDelta: 3, bufferDelta: 0)
|
||||
|
||||
it "only allows positive widths to be assigned", ->
|
||||
displayBuffer.setEditorWidthInChars(0)
|
||||
expect(displayBuffer.editorWidthInChars).not.toBe 0
|
||||
displayBuffer.setEditorWidthInChars(-1)
|
||||
expect(displayBuffer.editorWidthInChars).not.toBe -1
|
||||
|
||||
describe "primitive folding", ->
|
||||
beforeEach ->
|
||||
displayBuffer.destroy()
|
||||
@@ -460,6 +466,12 @@ describe "DisplayBuffer", ->
|
||||
|
||||
expect(changeHandler).toHaveBeenCalledWith(start: 3, end: 3, screenDelta: 1, bufferDelta: 1)
|
||||
|
||||
describe "when the change starts at the beginning of a fold but does not extend to the end (regression)", ->
|
||||
it "preserves a proper mapping between buffer and screen coordinates", ->
|
||||
expect(displayBuffer.screenPositionForBufferPosition([8, 0])).toEqual [4, 0]
|
||||
buffer.setTextInRange([[2, 0], [3, 0]], "\n")
|
||||
expect(displayBuffer.screenPositionForBufferPosition([8, 0])).toEqual [4, 0]
|
||||
|
||||
describe "position translation", ->
|
||||
it "translates positions to account for folded lines and characters and the placeholder", ->
|
||||
fold = displayBuffer.createFold(4, 7)
|
||||
@@ -495,7 +507,7 @@ describe "DisplayBuffer", ->
|
||||
expect(displayBuffer.bufferPositionForScreenPosition([5, 0])).toEqual [5, 0]
|
||||
expect(displayBuffer.bufferPositionForScreenPosition([9, 2])).toEqual [9, 2]
|
||||
|
||||
describe ".destroyFoldsContainingBufferRow(row)", ->
|
||||
describe ".unfoldBufferRow(row)", ->
|
||||
it "destroys all folds containing the given row", ->
|
||||
displayBuffer.createFold(2, 4)
|
||||
displayBuffer.createFold(2, 6)
|
||||
@@ -506,14 +518,25 @@ describe "DisplayBuffer", ->
|
||||
expect(displayBuffer.lineForRow(1).text).toBe '1'
|
||||
expect(displayBuffer.lineForRow(2).text).toBe '10'
|
||||
|
||||
displayBuffer.destroyFoldsContainingBufferRow(2)
|
||||
displayBuffer.unfoldBufferRow(2)
|
||||
expect(displayBuffer.lineForRow(1).text).toBe '1'
|
||||
expect(displayBuffer.lineForRow(2).text).toBe '2'
|
||||
expect(displayBuffer.lineForRow(7).fold).toBeDefined()
|
||||
expect(displayBuffer.lineForRow(8).text).toMatch /^9-+/
|
||||
expect(displayBuffer.lineForRow(10).fold).toBeDefined()
|
||||
|
||||
describe ".clipScreenPosition(screenPosition, wrapBeyondNewlines: false, wrapAtSoftNewlines: false, skipAtomicTokens: false)", ->
|
||||
describe ".outermostFoldsInBufferRowRange(startRow, endRow)", ->
|
||||
it "returns the outermost folds entirely contained in the given row range, exclusive of end row", ->
|
||||
fold1 = displayBuffer.createFold(4, 7)
|
||||
fold2 = displayBuffer.createFold(5, 6)
|
||||
fold3 = displayBuffer.createFold(11, 15)
|
||||
fold4 = displayBuffer.createFold(12, 13)
|
||||
fold5 = displayBuffer.createFold(16, 17)
|
||||
|
||||
expect(displayBuffer.outermostFoldsInBufferRowRange(3, 18)).toEqual [fold1, fold3, fold5]
|
||||
expect(displayBuffer.outermostFoldsInBufferRowRange(5, 16)).toEqual [fold3]
|
||||
|
||||
describe "::clipScreenPosition(screenPosition, wrapBeyondNewlines: false, wrapAtSoftNewlines: false, skipAtomicTokens: false)", ->
|
||||
beforeEach ->
|
||||
displayBuffer.setSoftWrap(true)
|
||||
displayBuffer.setEditorWidthInChars(50)
|
||||
@@ -575,7 +598,7 @@ describe "DisplayBuffer", ->
|
||||
expect(displayBuffer.clipScreenPosition([0, 1], skipAtomicTokens: true)).toEqual [0, tabLength]
|
||||
expect(displayBuffer.clipScreenPosition([0, tabLength], skipAtomicTokens: true)).toEqual [0, tabLength]
|
||||
|
||||
describe ".screenPositionForBufferPosition(bufferPosition, options)", ->
|
||||
describe "::screenPositionForBufferPosition(bufferPosition, options)", ->
|
||||
it "clips the specified buffer position", ->
|
||||
expect(displayBuffer.screenPositionForBufferPosition([0, 2])).toEqual [0, 2]
|
||||
expect(displayBuffer.screenPositionForBufferPosition([0, 100000])).toEqual [0, 29]
|
||||
@@ -588,13 +611,20 @@ describe "DisplayBuffer", ->
|
||||
expect(displayBuffer.screenPositionForBufferPosition([0, 1])).toEqual [0, 2]
|
||||
expect(displayBuffer.bufferPositionForScreenPosition([0, 2])).toEqual [0, 1]
|
||||
|
||||
describe ".getMaxLineLength()", ->
|
||||
it "correctly translates positions on soft wrapped lines containing tabs", ->
|
||||
buffer.setText('\t\taa bb cc dd ee ff gg')
|
||||
displayBuffer.setSoftWrap(true)
|
||||
displayBuffer.setEditorWidthInChars(10)
|
||||
expect(displayBuffer.screenPositionForBufferPosition([0, 10], wrapAtSoftNewlines: true)).toEqual [1, 0]
|
||||
expect(displayBuffer.bufferPositionForScreenPosition([1, 0])).toEqual [0, 10]
|
||||
|
||||
describe "::getMaxLineLength()", ->
|
||||
it "returns the length of the longest screen line", ->
|
||||
expect(displayBuffer.getMaxLineLength()).toBe 65
|
||||
buffer.delete([[6, 0], [6, 65]])
|
||||
expect(displayBuffer.getMaxLineLength()).toBe 62
|
||||
|
||||
describe ".destroy()", ->
|
||||
describe "::destroy()", ->
|
||||
it "unsubscribes all display buffer markers from their underlying buffer marker (regression)", ->
|
||||
marker = displayBuffer.markBufferPosition([12, 2])
|
||||
displayBuffer.destroy()
|
||||
@@ -684,7 +714,7 @@ describe "DisplayBuffer", ->
|
||||
}
|
||||
markerChangedHandler.reset()
|
||||
|
||||
displayBuffer.destroyFoldsContainingBufferRow(4)
|
||||
displayBuffer.unfoldBufferRow(4)
|
||||
expect(markerChangedHandler).toHaveBeenCalled()
|
||||
expect(markerChangedHandler.argsForCall[0][0]).toEqual {
|
||||
oldHeadScreenPosition: [8, 23]
|
||||
@@ -747,17 +777,17 @@ describe "DisplayBuffer", ->
|
||||
isValid: true
|
||||
}
|
||||
|
||||
xit "triggers the 'changed' event whenever the marker is invalidated or revalidated", ->
|
||||
it "triggers the 'changed' event whenever the marker is invalidated or revalidated", ->
|
||||
buffer.deleteRow(8)
|
||||
expect(markerChangedHandler).toHaveBeenCalled()
|
||||
expect(markerChangedHandler.argsForCall[0][0]).toEqual {
|
||||
oldHeadScreenPosition: [5, 10]
|
||||
oldHeadBufferPosition: [8, 10]
|
||||
newHeadScreenPosition: [5, 10]
|
||||
newHeadScreenPosition: [5, 0]
|
||||
newHeadBufferPosition: [8, 0]
|
||||
oldTailScreenPosition: [5, 4]
|
||||
oldTailBufferPosition: [8, 4]
|
||||
newTailScreenPosition: [5, 4]
|
||||
newTailScreenPosition: [5, 0]
|
||||
newTailBufferPosition: [8, 0]
|
||||
textChanged: true
|
||||
isValid: false
|
||||
@@ -768,12 +798,12 @@ describe "DisplayBuffer", ->
|
||||
|
||||
expect(markerChangedHandler).toHaveBeenCalled()
|
||||
expect(markerChangedHandler.argsForCall[0][0]).toEqual {
|
||||
oldHeadScreenPosition: [5, 10]
|
||||
oldHeadBufferPosition: [8, 10]
|
||||
oldHeadScreenPosition: [5, 0]
|
||||
oldHeadBufferPosition: [8, 0]
|
||||
newHeadScreenPosition: [5, 10]
|
||||
newHeadBufferPosition: [8, 10]
|
||||
oldTailScreenPosition: [5, 4]
|
||||
oldTailBufferPosition: [8, 4]
|
||||
oldTailScreenPosition: [5, 0]
|
||||
oldTailBufferPosition: [8, 0]
|
||||
newTailScreenPosition: [5, 4]
|
||||
newTailBufferPosition: [8, 4]
|
||||
textChanged: true
|
||||
@@ -784,7 +814,7 @@ describe "DisplayBuffer", ->
|
||||
displayBuffer.createFold(10, 11)
|
||||
expect(markerChangedHandler).not.toHaveBeenCalled()
|
||||
|
||||
xit "updates markers before emitting buffer change events, but does not notify their observers until the change event", ->
|
||||
it "updates markers before emitting buffer change events, but does not notify their observers until the change event", ->
|
||||
marker2 = displayBuffer.markBufferRange([[8, 1], [8, 1]])
|
||||
marker2.on 'changed', marker2ChangedHandler = jasmine.createSpy("marker2ChangedHandler")
|
||||
displayBuffer.on 'changed', changeHandler = jasmine.createSpy("changeHandler").andCallFake -> onDisplayBufferChange()
|
||||
@@ -867,12 +897,12 @@ describe "DisplayBuffer", ->
|
||||
expect(marker.getHeadScreenPosition()).toEqual [8, 10]
|
||||
expect(marker.getTailScreenPosition()).toEqual [8, 4]
|
||||
|
||||
displayBuffer.destroyFoldsContainingBufferRow(4)
|
||||
displayBuffer.unfoldBufferRow(4)
|
||||
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
expect(markerChangedHandler).toHaveBeenCalled()
|
||||
|
||||
describe ".findMarkers(attributes)", ->
|
||||
describe "::findMarkers(attributes)", ->
|
||||
it "allows the startBufferRow and endBufferRow to be specified", ->
|
||||
marker1 = displayBuffer.markBufferRange([[0, 0], [3, 0]], class: 'a')
|
||||
marker2 = displayBuffer.markBufferRange([[0, 0], [5, 0]], class: 'a')
|
||||
@@ -902,7 +932,7 @@ describe "DisplayBuffer", ->
|
||||
buffer.getMarker(marker2.id).destroy()
|
||||
expect(destroyedHandler).toHaveBeenCalled()
|
||||
|
||||
describe "DisplayBufferMarker.copy(attributes)", ->
|
||||
describe "DisplayBufferMarker::copy(attributes)", ->
|
||||
it "creates a copy of the marker with the given attributes merged in", ->
|
||||
initialMarkerCount = displayBuffer.getMarkerCount()
|
||||
marker1 = displayBuffer.markScreenRange([[5, 4], [5, 10]], a: 1, b: 2)
|
||||
|
||||
+2523
-2420
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+82
-109
@@ -587,7 +587,7 @@ describe "EditorView", ->
|
||||
editorView.renderedLines.trigger mousedownEvent(editorView: editorView, point: [4, 10])
|
||||
|
||||
# moving changes selection
|
||||
$(document).trigger mousemoveEvent(editorView: editorView, point: [5, 27])
|
||||
$(document).trigger mousemoveEvent(editorView: editorView, point: [5, 27], which: 1)
|
||||
|
||||
range = editor.getSelection().getScreenRange()
|
||||
expect(range.start).toEqual({row: 4, column: 10})
|
||||
@@ -617,12 +617,12 @@ describe "EditorView", ->
|
||||
originalScrollTop = editorView.scrollTop()
|
||||
|
||||
# moving changes selection
|
||||
$(document).trigger mousemoveEvent(editorView: editorView, pageX: 0, pageY: -1)
|
||||
$(document).trigger mousemoveEvent(editorView: editorView, pageX: 0, pageY: -1, which: 1)
|
||||
expect(editorView.scrollTop()).toBe originalScrollTop - editorView.lineHeight
|
||||
|
||||
# every mouse move selects more text
|
||||
for x in [0..10]
|
||||
$(document).trigger mousemoveEvent(editorView: editorView, pageX: 0, pageY: -1)
|
||||
$(document).trigger mousemoveEvent(editorView: editorView, pageX: 0, pageY: -1, which: 1)
|
||||
|
||||
expect(editorView.scrollTop()).toBe 0
|
||||
|
||||
@@ -633,7 +633,7 @@ describe "EditorView", ->
|
||||
event = mousedownEvent(editorView: editorView, point: [4, 10])
|
||||
event.originalEvent.which = 2
|
||||
editorView.renderedLines.trigger(event)
|
||||
$(document).trigger mousemoveEvent(editorView: editorView, point: [5, 27])
|
||||
$(document).trigger mousemoveEvent(editorView: editorView, point: [5, 27], which: 1)
|
||||
$(document).trigger 'mouseup'
|
||||
|
||||
range = editor.getSelection().getScreenRange()
|
||||
@@ -654,6 +654,25 @@ describe "EditorView", ->
|
||||
expect(range.start).toEqual({row: 4, column: 10})
|
||||
expect(range.end).toEqual({row: 4, column: 10})
|
||||
|
||||
describe "when the editor is hidden", ->
|
||||
it "stops scrolling the editor", ->
|
||||
editorView.vScrollMargin = 0
|
||||
editorView.attachToDom(heightInLines: 5)
|
||||
editorView.scrollToBottom()
|
||||
|
||||
spyOn(window, 'setInterval').andCallFake ->
|
||||
|
||||
editorView.renderedLines.trigger mousedownEvent(editorView: editorView, point: [12, 0])
|
||||
originalScrollTop = editorView.scrollTop()
|
||||
|
||||
$(document).trigger mousemoveEvent(editorView: editorView, pageX: 0, pageY: -1, which: 1)
|
||||
expect(editorView.scrollTop()).toBe originalScrollTop - editorView.lineHeight
|
||||
|
||||
editorView.hide()
|
||||
|
||||
$(document).trigger mousemoveEvent(editorView: editorView, pageX: 100000, pageY: -1, which: 1)
|
||||
expect(editorView.scrollTop()).toBe originalScrollTop - editorView.lineHeight
|
||||
|
||||
describe "double-click and drag", ->
|
||||
it "selects the word under the cursor, then continues to select by word in either direction as the mouse is dragged", ->
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: 0, column: 0)
|
||||
@@ -662,11 +681,11 @@ describe "EditorView", ->
|
||||
editorView.renderedLines.trigger mousedownEvent(editorView: editorView, point: [0, 8], originalEvent: {detail: 2})
|
||||
expect(editor.getSelectedText()).toBe "quicksort"
|
||||
|
||||
editorView.renderedLines.trigger mousemoveEvent(editorView: editorView, point: [1, 8])
|
||||
editorView.renderedLines.trigger mousemoveEvent(editorView: editorView, point: [1, 8], which: 1)
|
||||
expect(editor.getSelectedBufferRange()).toEqual [[0, 4], [1, 10]]
|
||||
expect(editor.getCursorBufferPosition()).toEqual [1, 10]
|
||||
|
||||
editorView.renderedLines.trigger mousemoveEvent(editorView: editorView, point: [0, 1])
|
||||
editorView.renderedLines.trigger mousemoveEvent(editorView: editorView, point: [0, 1], which: 1)
|
||||
expect(editor.getSelectedBufferRange()).toEqual [[0, 0], [0, 13]]
|
||||
expect(editor.getCursorBufferPosition()).toEqual [0, 0]
|
||||
|
||||
@@ -691,12 +710,12 @@ describe "EditorView", ->
|
||||
expect(editor.getSelectedBufferRange()).toEqual [[4, 0], [5, 0]]
|
||||
|
||||
# moving changes selection linewise
|
||||
editorView.renderedLines.trigger mousemoveEvent(editorView: editorView, point: [5, 27])
|
||||
editorView.renderedLines.trigger mousemoveEvent(editorView: editorView, point: [5, 27], which: 1)
|
||||
expect(editor.getSelectedBufferRange()).toEqual [[4, 0], [6, 0]]
|
||||
expect(editor.getCursorBufferPosition()).toEqual [6, 0]
|
||||
|
||||
# moving changes selection linewise
|
||||
editorView.renderedLines.trigger mousemoveEvent(editorView: editorView, point: [2, 27])
|
||||
editorView.renderedLines.trigger mousemoveEvent(editorView: editorView, point: [2, 27], which: 1)
|
||||
expect(editor.getSelectedBufferRange()).toEqual [[2, 0], [5, 0]]
|
||||
expect(editor.getCursorBufferPosition()).toEqual [2, 0]
|
||||
|
||||
@@ -706,11 +725,11 @@ describe "EditorView", ->
|
||||
describe "meta-click and drag", ->
|
||||
it "adds an additional selection", ->
|
||||
editorView.renderedLines.trigger mousedownEvent(editorView: editorView, point: [4, 10])
|
||||
editorView.renderedLines.trigger mousemoveEvent(editorView: editorView, point: [5, 27])
|
||||
editorView.renderedLines.trigger mousemoveEvent(editorView: editorView, point: [5, 27], which: 1)
|
||||
editorView.renderedLines.trigger 'mouseup'
|
||||
|
||||
editorView.renderedLines.trigger mousedownEvent(editorView: editorView, point: [6, 10], metaKey: true)
|
||||
editorView.renderedLines.trigger mousemoveEvent(editorView: editorView, point: [8, 27], metaKey: true)
|
||||
editorView.renderedLines.trigger mousemoveEvent(editorView: editorView, point: [8, 27], metaKey: true, which: 1)
|
||||
editorView.renderedLines.trigger 'mouseup'
|
||||
|
||||
selections = editor.getSelections()
|
||||
@@ -1806,6 +1825,17 @@ describe "EditorView", ->
|
||||
runs ->
|
||||
expect(editor.getSoftWrapColumn()).toBeLessThan previousSoftWrapColumn
|
||||
|
||||
it "accounts for the width of the scrollbar if there is one", ->
|
||||
# force the scrollbar to always be visible, regardless of OS visibility setting
|
||||
$('#jasmine-content').prepend """
|
||||
<style>
|
||||
::-webkit-scrollbar { width: 15px; }
|
||||
</style>
|
||||
"""
|
||||
setEditorHeightInLines(editorView, 5)
|
||||
setEditorWidthInChars(editorView, 40)
|
||||
expect(editor.lineForScreenRow(2).text.length).toBe 34
|
||||
|
||||
describe "gutter rendering", ->
|
||||
beforeEach ->
|
||||
editorView.attachToDom(heightInLines: 5.5)
|
||||
@@ -2419,51 +2449,11 @@ describe "EditorView", ->
|
||||
editorView.underlayer.trigger event
|
||||
expect(editor.getSelection().getScreenRange()).toEqual [[0,0], [12,2]]
|
||||
|
||||
# TODO: Move to editor-spec
|
||||
describe ".reloadGrammar()", ->
|
||||
[filePath] = []
|
||||
|
||||
beforeEach ->
|
||||
tmpdir = fs.absolute(temp.dir)
|
||||
filePath = path.join(tmpdir, "grammar-change.txt")
|
||||
fs.writeFileSync(filePath, "var i;")
|
||||
|
||||
afterEach ->
|
||||
fs.removeSync(filePath) if fs.existsSync(filePath)
|
||||
|
||||
it "updates all the rendered lines when the grammar changes", ->
|
||||
editor = atom.project.openSync(filePath)
|
||||
editorView.edit(editor)
|
||||
expect(editor.getGrammar().name).toBe 'Plain Text'
|
||||
atom.syntax.setGrammarOverrideForPath(filePath, 'source.js')
|
||||
editor.reloadGrammar()
|
||||
expect(editor.getGrammar().name).toBe 'JavaScript'
|
||||
|
||||
tokenizedBuffer = editorView.editor.displayBuffer.tokenizedBuffer
|
||||
line0 = tokenizedBuffer.lineForScreenRow(0)
|
||||
expect(line0.tokens.length).toBe 3
|
||||
expect(line0.tokens[0]).toEqual(value: 'var', scopes: ['source.js', 'storage.modifier.js'])
|
||||
|
||||
it "doesn't update the rendered lines when the grammar doesn't change", ->
|
||||
expect(editor.getGrammar().name).toBe 'JavaScript'
|
||||
spyOn(editorView, 'updateDisplay').andCallThrough()
|
||||
editor.reloadGrammar()
|
||||
expect(editor.reloadGrammar()).toBeFalsy()
|
||||
expect(editorView.updateDisplay).not.toHaveBeenCalled()
|
||||
expect(editor.getGrammar().name).toBe 'JavaScript'
|
||||
|
||||
it "emits an editor:grammar-changed event when updated", ->
|
||||
editor = atom.project.openSync(filePath)
|
||||
editorView.edit(editor)
|
||||
|
||||
describe "when the editor's grammar is changed", ->
|
||||
it "emits an editor:grammar-changed event", ->
|
||||
eventHandler = jasmine.createSpy('eventHandler')
|
||||
editorView.on('editor:grammar-changed', eventHandler)
|
||||
editor.reloadGrammar()
|
||||
|
||||
expect(eventHandler).not.toHaveBeenCalled()
|
||||
|
||||
atom.syntax.setGrammarOverrideForPath(filePath, 'source.js')
|
||||
editor.reloadGrammar()
|
||||
editor.setGrammar(atom.syntax.selectGrammar('.coffee'))
|
||||
expect(eventHandler).toHaveBeenCalled()
|
||||
|
||||
describe ".replaceSelectedText()", ->
|
||||
@@ -2810,64 +2800,9 @@ describe "EditorView", ->
|
||||
expect(buffer.lineForRow(1)).toBe ' if (items.length <= 1) return items;'
|
||||
expect(buffer.lineForRow(2)).toBe ' var sort = function(items) {'
|
||||
|
||||
describe "when editor:duplicate-line is triggered", ->
|
||||
describe "where there is no selection", ->
|
||||
describe "when the cursor isn't on a folded line", ->
|
||||
it "duplicates the current line below and moves the cursor down one row", ->
|
||||
editor.setCursorBufferPosition([0, 5])
|
||||
editorView.trigger 'editor:duplicate-line'
|
||||
expect(buffer.lineForRow(0)).toBe 'var quicksort = function () {'
|
||||
expect(buffer.lineForRow(1)).toBe 'var quicksort = function () {'
|
||||
expect(editor.getCursorBufferPosition()).toEqual [1, 5]
|
||||
|
||||
describe "when the cursor is on a folded line", ->
|
||||
it "duplicates the entire fold before and moves the cursor to the new fold", ->
|
||||
editor.setCursorBufferPosition([4])
|
||||
editor.foldCurrentRow()
|
||||
editorView.trigger 'editor:duplicate-line'
|
||||
expect(editor.getCursorScreenPosition()).toEqual [5]
|
||||
expect(editor.isFoldedAtScreenRow(4)).toBeTruthy()
|
||||
expect(editor.isFoldedAtScreenRow(5)).toBeTruthy()
|
||||
expect(buffer.lineForRow(8)).toBe ' while(items.length > 0) {'
|
||||
expect(buffer.lineForRow(9)).toBe ' current = items.shift();'
|
||||
expect(buffer.lineForRow(10)).toBe ' current < pivot ? left.push(current) : right.push(current);'
|
||||
expect(buffer.lineForRow(11)).toBe ' }'
|
||||
|
||||
describe "when the cursor is on the last line and it doesn't have a trailing newline", ->
|
||||
it "inserts a newline and the duplicated line", ->
|
||||
editor.moveCursorToBottom()
|
||||
editorView.trigger 'editor:duplicate-line'
|
||||
expect(buffer.lineForRow(12)).toBe '};'
|
||||
expect(buffer.lineForRow(13)).toBe '};'
|
||||
expect(buffer.lineForRow(14)).toBeUndefined()
|
||||
expect(editor.getCursorBufferPosition()).toEqual [13, 2]
|
||||
|
||||
describe "when the cursor in on the last line and it is only a newline", ->
|
||||
it "duplicates the current line below and moves the cursor down one row", ->
|
||||
editor.moveCursorToBottom()
|
||||
editor.insertNewline()
|
||||
editor.moveCursorToBottom()
|
||||
editorView.trigger 'editor:duplicate-line'
|
||||
expect(buffer.lineForRow(13)).toBe ''
|
||||
expect(buffer.lineForRow(14)).toBe ''
|
||||
expect(buffer.lineForRow(15)).toBeUndefined()
|
||||
expect(editor.getCursorBufferPosition()).toEqual [14, 0]
|
||||
|
||||
describe "when the cursor is on the second to last line and the last line only a newline", ->
|
||||
it "duplicates the current line below and moves the cursor down one row", ->
|
||||
editor.moveCursorToBottom()
|
||||
editor.insertNewline()
|
||||
editor.setCursorBufferPosition([12])
|
||||
editorView.trigger 'editor:duplicate-line'
|
||||
expect(buffer.lineForRow(12)).toBe '};'
|
||||
expect(buffer.lineForRow(13)).toBe '};'
|
||||
expect(buffer.lineForRow(14)).toBe ''
|
||||
expect(buffer.lineForRow(15)).toBeUndefined()
|
||||
expect(editor.getCursorBufferPosition()).toEqual [13, 0]
|
||||
|
||||
describe "when the escape key is pressed on the editor view", ->
|
||||
it "clears multiple selections if there are any, and otherwise allows other bindings to be handled", ->
|
||||
atom.keymap.bindKeys 'name', '.editor', {'escape': 'test-event'}
|
||||
atom.keymaps.bindKeys 'name', '.editor', {'escape': 'test-event'}
|
||||
testEventHandler = jasmine.createSpy("testEventHandler")
|
||||
|
||||
editorView.on 'test-event', testEventHandler
|
||||
@@ -2959,6 +2894,20 @@ describe "EditorView", ->
|
||||
for rowNumber in [1..5]
|
||||
expect(editorView.lineElementForScreenRow(rowNumber).text()).toBe buffer.lineForRow(rowNumber)
|
||||
|
||||
it "correctly calculates the position left for non-monospaced invisibles", ->
|
||||
editorView.setShowInvisibles(true)
|
||||
editorView.setInvisibles tab: '♘'
|
||||
editor.setText('\tx')
|
||||
|
||||
editorView.setFontFamily('serif')
|
||||
editorView.setFontSize(10)
|
||||
editorView.attachToDom()
|
||||
editorView.setWidthInChars(5)
|
||||
|
||||
expect(editorView.pixelPositionForScreenPosition([0, 0]).left).toEqual 0
|
||||
expect(editorView.pixelPositionForScreenPosition([0, 1]).left).toEqual 10
|
||||
expect(editorView.pixelPositionForScreenPosition([0, 2]).left).toEqual 13
|
||||
|
||||
describe "when the window is resized", ->
|
||||
it "updates the active edit session with the current soft wrap column", ->
|
||||
editorView.attachToDom()
|
||||
@@ -2987,6 +2936,30 @@ describe "EditorView", ->
|
||||
editorView.pixelPositionForScreenPosition([1, 5])
|
||||
expect(editorView.measureToColumn.callCount).toBe 0
|
||||
|
||||
describe "when stylesheets are changed", ->
|
||||
afterEach ->
|
||||
atom.themes.removeStylesheet 'line-height'
|
||||
atom.themes.removeStylesheet 'char-width'
|
||||
|
||||
it "updates the editor if the line height or character width changes due to a stylesheet change", ->
|
||||
editorView.attachToDom()
|
||||
editor.setCursorScreenPosition([1, 3])
|
||||
expect(editorView.pixelPositionForScreenPosition([1, 3])).toEqual {top: 20, left: 30}
|
||||
expect(editorView.getCursorView().position()).toEqual {top: 20, left: 30}
|
||||
|
||||
atom.themes.applyStylesheet 'line-height', """
|
||||
.editor { line-height: 2; }
|
||||
"""
|
||||
|
||||
expect(editorView.pixelPositionForScreenPosition([1, 3])).toEqual {top: 20, left: 30}
|
||||
expect(editorView.getCursorView().position()).toEqual {top: 20, left: 30}
|
||||
|
||||
atom.themes.applyStylesheet 'char-width', """
|
||||
.editor { letter-spacing: 2px; }
|
||||
"""
|
||||
expect(editorView.pixelPositionForScreenPosition([1, 3])).toEqual {top: 20, left: 36}
|
||||
expect(editorView.getCursorView().position()).toEqual {top: 20, left: 36}
|
||||
|
||||
describe "when the editor contains hard tabs", ->
|
||||
it "correctly calculates the the position left for a column", ->
|
||||
editor.setText('\ttest')
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
module.exports = activate: ->
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "no events",
|
||||
"version": "0.1.0",
|
||||
"activationEvents": []
|
||||
}
|
||||
+21
-4
@@ -177,6 +177,24 @@ describe "Git", ->
|
||||
status = repo.getPathStatus(filePath)
|
||||
expect(statusHandler.callCount).toBe 1
|
||||
|
||||
describe ".getDirectoryStatus(path)", ->
|
||||
[directoryPath, filePath, originalPathText] = []
|
||||
|
||||
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)
|
||||
|
||||
it "gets the status based on the files inside the directory", ->
|
||||
expect(repo.isStatusModified(repo.getDirectoryStatus(directoryPath))).toBe false
|
||||
fs.writeFileSync(filePath, 'abc')
|
||||
repo.getPathStatus(filePath)
|
||||
expect(repo.isStatusModified(repo.getDirectoryStatus(directoryPath))).toBe true
|
||||
|
||||
describe ".refreshStatus()", ->
|
||||
[newPath, modifiedPath, cleanPath, originalModifiedPathText] = []
|
||||
|
||||
@@ -203,10 +221,9 @@ describe "Git", ->
|
||||
statusHandler.callCount > 0
|
||||
|
||||
runs ->
|
||||
statuses = repo.statuses
|
||||
expect(statuses[cleanPath]).toBeUndefined()
|
||||
expect(repo.isStatusNew(statuses[newPath])).toBeTruthy()
|
||||
expect(repo.isStatusModified(statuses[modifiedPath])).toBeTruthy()
|
||||
expect(repo.getCachedPathStatus(cleanPath)).toBeUndefined()
|
||||
expect(repo.isStatusNew(repo.getCachedPathStatus(newPath))).toBeTruthy()
|
||||
expect(repo.isStatusModified(repo.getCachedPathStatus(modifiedPath))).toBeTruthy()
|
||||
|
||||
describe "buffer events", ->
|
||||
[originalContent, editor] = []
|
||||
|
||||
@@ -1,430 +0,0 @@
|
||||
fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
temp = require 'temp'
|
||||
Keymap = require '../src/keymap'
|
||||
{$, $$, WorkspaceView} = require 'atom'
|
||||
|
||||
describe "Keymap", ->
|
||||
fragment = null
|
||||
keymap = null
|
||||
resourcePath = atom.getLoadSettings().resourcePath
|
||||
configDirPath = null
|
||||
|
||||
beforeEach ->
|
||||
configDirPath = temp.mkdirSync('atom')
|
||||
keymap = new Keymap({configDirPath, resourcePath})
|
||||
fragment = $ """
|
||||
<div class="command-mode">
|
||||
<div class="child-node">
|
||||
<div class="grandchild-node"/>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
|
||||
afterEach ->
|
||||
keymap.destroy()
|
||||
|
||||
describe ".handleKeyEvent(event)", ->
|
||||
deleteCharHandler = null
|
||||
insertCharHandler = null
|
||||
commandZHandler = null
|
||||
|
||||
beforeEach ->
|
||||
keymap.bindKeys 'name', '.command-mode', 'x': 'deleteChar'
|
||||
keymap.bindKeys 'name', '.insert-mode', 'x': 'insertChar'
|
||||
keymap.bindKeys 'name', '.command-mode', 'cmd-z': 'commandZPressed'
|
||||
|
||||
deleteCharHandler = jasmine.createSpy('deleteCharHandler')
|
||||
insertCharHandler = jasmine.createSpy('insertCharHandler')
|
||||
commandZHandler = jasmine.createSpy('commandZHandler')
|
||||
fragment.on 'deleteChar', deleteCharHandler
|
||||
fragment.on 'insertChar', insertCharHandler
|
||||
fragment.on 'commandZPressed', commandZHandler
|
||||
|
||||
describe "when no binding matches the event's keystroke", ->
|
||||
it "does not return false so the event continues to propagate", ->
|
||||
expect(keymap.handleKeyEvent(keydownEvent('0', target: fragment[0]))).not.toBe false
|
||||
|
||||
describe "when a non-English keyboard language is used", ->
|
||||
it "uses the physical character pressed instead of the character it maps to in the current language", ->
|
||||
event = keydownEvent('U+03B6', metaKey: true, which: 122, target: fragment[0]) # This is the 'z' key using the Greek keyboard layout
|
||||
result = keymap.handleKeyEvent(event)
|
||||
|
||||
expect(result).toBe(false)
|
||||
expect(commandZHandler).toHaveBeenCalled()
|
||||
|
||||
describe "when at least one binding fully matches the event's keystroke", ->
|
||||
describe "when the event's target node matches a selector with a matching binding", ->
|
||||
it "triggers the command event associated with that binding on the target node and returns false", ->
|
||||
result = keymap.handleKeyEvent(keydownEvent('x', target: fragment[0]))
|
||||
expect(result).toBe(false)
|
||||
expect(deleteCharHandler).toHaveBeenCalled()
|
||||
expect(insertCharHandler).not.toHaveBeenCalled()
|
||||
|
||||
deleteCharHandler.reset()
|
||||
fragment.removeClass('command-mode').addClass('insert-mode')
|
||||
|
||||
event = keydownEvent('x', target: fragment[0])
|
||||
keymap.handleKeyEvent(event)
|
||||
expect(deleteCharHandler).not.toHaveBeenCalled()
|
||||
expect(insertCharHandler).toHaveBeenCalled()
|
||||
|
||||
describe "when the event's target node *descends* from a selector with a matching binding", ->
|
||||
it "triggers the command event associated with that binding on the target node and returns false", ->
|
||||
target = fragment.find('.child-node')[0]
|
||||
result = keymap.handleKeyEvent(keydownEvent('x', target: target))
|
||||
expect(result).toBe(false)
|
||||
expect(deleteCharHandler).toHaveBeenCalled()
|
||||
expect(insertCharHandler).not.toHaveBeenCalled()
|
||||
|
||||
deleteCharHandler.reset()
|
||||
fragment.removeClass('command-mode').addClass('insert-mode')
|
||||
|
||||
keymap.handleKeyEvent(keydownEvent('x', target: target))
|
||||
expect(deleteCharHandler).not.toHaveBeenCalled()
|
||||
expect(insertCharHandler).toHaveBeenCalled()
|
||||
|
||||
describe "when the event's target node descends from multiple nodes that match selectors with a binding", ->
|
||||
beforeEach ->
|
||||
keymap.bindKeys 'name', '.child-node', 'x': 'foo'
|
||||
|
||||
it "only triggers bindings on selectors associated with the closest ancestor node", ->
|
||||
fooHandler = jasmine.createSpy 'fooHandler'
|
||||
fragment.on 'foo', fooHandler
|
||||
|
||||
target = fragment.find('.grandchild-node')[0]
|
||||
keymap.handleKeyEvent(keydownEvent('x', target: target))
|
||||
expect(fooHandler).toHaveBeenCalled()
|
||||
expect(deleteCharHandler).not.toHaveBeenCalled()
|
||||
expect(insertCharHandler).not.toHaveBeenCalled()
|
||||
|
||||
describe "when 'abortKeyBinding' is called on the triggered event", ->
|
||||
[fooHandler1, fooHandler2] = []
|
||||
|
||||
beforeEach ->
|
||||
fooHandler1 = jasmine.createSpy('fooHandler1').andCallFake (e) ->
|
||||
expect(deleteCharHandler).not.toHaveBeenCalled()
|
||||
e.abortKeyBinding()
|
||||
fooHandler2 = jasmine.createSpy('fooHandler2')
|
||||
|
||||
fragment.find('.child-node').on 'foo', fooHandler1
|
||||
fragment.on 'foo', fooHandler2
|
||||
|
||||
it "aborts the current event and tries again with the next-most-specific key binding", ->
|
||||
target = fragment.find('.grandchild-node')[0]
|
||||
keymap.handleKeyEvent(keydownEvent('x', target: target))
|
||||
expect(fooHandler1).toHaveBeenCalled()
|
||||
expect(fooHandler2).not.toHaveBeenCalled()
|
||||
expect(deleteCharHandler).toHaveBeenCalled()
|
||||
|
||||
it "does not throw an exception if the event was not triggered by the keymap", ->
|
||||
fragment.find('.grandchild-node').trigger 'foo'
|
||||
|
||||
describe "when the event bubbles to a node that matches multiple selectors", ->
|
||||
describe "when the matching selectors differ in specificity", ->
|
||||
it "triggers the binding for the most specific selector", ->
|
||||
keymap.bindKeys 'name', 'div .child-node', 'x': 'foo'
|
||||
keymap.bindKeys 'name', '.command-mode .child-node !important', 'x': 'baz'
|
||||
keymap.bindKeys 'name', '.command-mode .child-node', 'x': 'quux'
|
||||
keymap.bindKeys 'name', '.child-node', 'x': 'bar'
|
||||
|
||||
fooHandler = jasmine.createSpy 'fooHandler'
|
||||
barHandler = jasmine.createSpy 'barHandler'
|
||||
bazHandler = jasmine.createSpy 'bazHandler'
|
||||
fragment.on 'foo', fooHandler
|
||||
fragment.on 'bar', barHandler
|
||||
fragment.on 'baz', bazHandler
|
||||
|
||||
target = fragment.find('.grandchild-node')[0]
|
||||
keymap.handleKeyEvent(keydownEvent('x', target: target))
|
||||
|
||||
expect(fooHandler).not.toHaveBeenCalled()
|
||||
expect(barHandler).not.toHaveBeenCalled()
|
||||
expect(bazHandler).toHaveBeenCalled()
|
||||
|
||||
describe "when the matching selectors have the same specificity", ->
|
||||
it "triggers the bindings for the most recently declared selector", ->
|
||||
keymap.bindKeys 'name', '.child-node', 'x': 'foo', 'y': 'baz'
|
||||
keymap.bindKeys 'name', '.child-node', 'x': 'bar'
|
||||
|
||||
fooHandler = jasmine.createSpy 'fooHandler'
|
||||
barHandler = jasmine.createSpy 'barHandler'
|
||||
bazHandler = jasmine.createSpy 'bazHandler'
|
||||
fragment.on 'foo', fooHandler
|
||||
fragment.on 'bar', barHandler
|
||||
fragment.on 'baz', bazHandler
|
||||
|
||||
target = fragment.find('.grandchild-node')[0]
|
||||
keymap.handleKeyEvent(keydownEvent('x', target: target))
|
||||
|
||||
expect(barHandler).toHaveBeenCalled()
|
||||
expect(fooHandler).not.toHaveBeenCalled()
|
||||
|
||||
keymap.handleKeyEvent(keydownEvent('y', target: target))
|
||||
expect(bazHandler).toHaveBeenCalled()
|
||||
|
||||
describe "when the event's target is the document body", ->
|
||||
it "triggers the mapped event on the workspaceView", ->
|
||||
atom.workspaceView = new WorkspaceView
|
||||
atom.workspaceView.attachToDom()
|
||||
keymap.bindKeys 'name', 'body', 'x': 'foo'
|
||||
fooHandler = jasmine.createSpy("fooHandler")
|
||||
atom.workspaceView.on 'foo', fooHandler
|
||||
|
||||
result = keymap.handleKeyEvent(keydownEvent('x', target: document.body))
|
||||
expect(result).toBe(false)
|
||||
expect(fooHandler).toHaveBeenCalled()
|
||||
expect(deleteCharHandler).not.toHaveBeenCalled()
|
||||
expect(insertCharHandler).not.toHaveBeenCalled()
|
||||
|
||||
describe "when the event matches a 'native!' binding", ->
|
||||
it "returns true, allowing the browser's native key handling to process the event", ->
|
||||
keymap.bindKeys 'name', '.grandchild-node', 'x': 'native!'
|
||||
nativeHandler = jasmine.createSpy("nativeHandler")
|
||||
fragment.on 'native!', nativeHandler
|
||||
expect(keymap.handleKeyEvent(keydownEvent('x', target: fragment.find('.grandchild-node')[0]))).toBe true
|
||||
expect(nativeHandler).not.toHaveBeenCalled()
|
||||
|
||||
describe "when at least one binding partially matches the event's keystroke", ->
|
||||
[quitHandler, closeOtherWindowsHandler] = []
|
||||
|
||||
beforeEach ->
|
||||
keymap.bindKeys 'name', "*",
|
||||
'ctrl-x ctrl-c': 'quit'
|
||||
'ctrl-x 1': 'close-other-windows'
|
||||
|
||||
quitHandler = jasmine.createSpy('quitHandler')
|
||||
closeOtherWindowsHandler = jasmine.createSpy('closeOtherWindowsHandler')
|
||||
fragment.on 'quit', quitHandler
|
||||
fragment.on 'close-other-windows', closeOtherWindowsHandler
|
||||
|
||||
it "only matches entire keystroke patterns", ->
|
||||
expect(keymap.handleKeyEvent(keydownEvent('c', target: fragment[0]))).not.toBe false
|
||||
|
||||
describe "when the event's target node matches a selector with a partially matching multi-stroke binding", ->
|
||||
describe "when a second keystroke added to the first to match a multi-stroke binding completely", ->
|
||||
it "triggers the event associated with the matched multi-stroke binding", ->
|
||||
expect(keymap.handleKeyEvent(keydownEvent('x', target: fragment[0], ctrlKey: true))).toBeFalsy()
|
||||
expect(keymap.handleKeyEvent(keydownEvent('ctrl', target: fragment[0]))).toBeFalsy() # This simulates actual key event behavior
|
||||
expect(keymap.handleKeyEvent(keydownEvent('c', target: fragment[0], ctrlKey: true))).toBeFalsy()
|
||||
|
||||
expect(quitHandler).toHaveBeenCalled()
|
||||
expect(closeOtherWindowsHandler).not.toHaveBeenCalled()
|
||||
quitHandler.reset()
|
||||
|
||||
expect(keymap.handleKeyEvent(keydownEvent('x', target: fragment[0], ctrlKey: true))).toBeFalsy()
|
||||
expect(keymap.handleKeyEvent(keydownEvent('1', target: fragment[0]))).toBeFalsy()
|
||||
|
||||
expect(quitHandler).not.toHaveBeenCalled()
|
||||
expect(closeOtherWindowsHandler).toHaveBeenCalled()
|
||||
|
||||
describe "when a second keystroke added to the first doesn't match any bindings", ->
|
||||
it "clears the queued keystroke without triggering any events", ->
|
||||
expect(keymap.handleKeyEvent(keydownEvent('x', target: fragment[0], ctrlKey: true))).toBe false
|
||||
expect(keymap.handleKeyEvent(keydownEvent('c', target: fragment[0]))).toBe false
|
||||
expect(quitHandler).not.toHaveBeenCalled()
|
||||
expect(closeOtherWindowsHandler).not.toHaveBeenCalled()
|
||||
|
||||
expect(keymap.handleKeyEvent(keydownEvent('c', target: fragment[0]))).not.toBe false
|
||||
|
||||
describe "when the event's target node descends from multiple nodes that match selectors with a partial binding match", ->
|
||||
it "allows any of the bindings to be triggered upon a second keystroke, favoring the most specific selector", ->
|
||||
keymap.bindKeys 'name', ".grandchild-node", 'ctrl-x ctrl-c': 'more-specific-quit'
|
||||
grandchildNode = fragment.find('.grandchild-node')[0]
|
||||
moreSpecificQuitHandler = jasmine.createSpy('moreSpecificQuitHandler')
|
||||
fragment.on 'more-specific-quit', moreSpecificQuitHandler
|
||||
|
||||
expect(keymap.handleKeyEvent(keydownEvent('x', target: grandchildNode, ctrlKey: true))).toBeFalsy()
|
||||
expect(keymap.handleKeyEvent(keydownEvent('1', target: grandchildNode))).toBeFalsy()
|
||||
expect(quitHandler).not.toHaveBeenCalled()
|
||||
expect(moreSpecificQuitHandler).not.toHaveBeenCalled()
|
||||
expect(closeOtherWindowsHandler).toHaveBeenCalled()
|
||||
closeOtherWindowsHandler.reset()
|
||||
|
||||
expect(keymap.handleKeyEvent(keydownEvent('x', target: grandchildNode, ctrlKey: true))).toBeFalsy()
|
||||
expect(keymap.handleKeyEvent(keydownEvent('c', target: grandchildNode, ctrlKey: true))).toBeFalsy()
|
||||
expect(quitHandler).not.toHaveBeenCalled()
|
||||
expect(closeOtherWindowsHandler).not.toHaveBeenCalled()
|
||||
expect(moreSpecificQuitHandler).toHaveBeenCalled()
|
||||
|
||||
describe "when there is a complete binding with a less specific selector", ->
|
||||
it "favors the more specific partial match", ->
|
||||
|
||||
describe "when there is a complete binding with a more specific selector", ->
|
||||
it "favors the more specific complete match", ->
|
||||
|
||||
describe ".bindKeys(name, selector, bindings)", ->
|
||||
it "normalizes the key patterns in the hash to put the modifiers in alphabetical order", ->
|
||||
fooHandler = jasmine.createSpy('fooHandler')
|
||||
fragment.on 'foo', fooHandler
|
||||
keymap.bindKeys 'name', '*', 'ctrl-alt-delete': 'foo'
|
||||
result = keymap.handleKeyEvent(keydownEvent('delete', ctrlKey: true, altKey: true, target: fragment[0]))
|
||||
expect(result).toBe(false)
|
||||
expect(fooHandler).toHaveBeenCalled()
|
||||
|
||||
fooHandler.reset()
|
||||
keymap.bindKeys 'name', '*', 'ctrl-alt--': 'foo'
|
||||
result = keymap.handleKeyEvent(keydownEvent('-', ctrlKey: true, altKey: true, target: fragment[0]))
|
||||
expect(result).toBe(false)
|
||||
expect(fooHandler).toHaveBeenCalled()
|
||||
|
||||
describe ".remove(name)", ->
|
||||
it "removes the binding set with the given selector and bindings", ->
|
||||
keymap.add 'nature',
|
||||
'.green':
|
||||
'ctrl-c': 'cultivate'
|
||||
'.brown':
|
||||
'ctrl-h': 'harvest'
|
||||
|
||||
keymap.add 'medical',
|
||||
'.green':
|
||||
'ctrl-v': 'vomit'
|
||||
|
||||
expect(keymap.keyBindingsMatchingElement($$ -> @div class: 'green')).toHaveLength 2
|
||||
expect(keymap.keyBindingsMatchingElement($$ -> @div class: 'brown')).toHaveLength 1
|
||||
|
||||
keymap.remove('nature')
|
||||
|
||||
expect(keymap.keyBindingsMatchingElement($$ -> @div class: 'green')).toHaveLength 1
|
||||
expect(keymap.keyBindingsMatchingElement($$ -> @div class: 'brown')).toEqual []
|
||||
|
||||
describe ".keystrokeStringForEvent(event)", ->
|
||||
describe "when no modifiers are pressed", ->
|
||||
it "returns a string that identifies the key pressed", ->
|
||||
expect(keymap.keystrokeStringForEvent(keydownEvent('a'))).toBe 'a'
|
||||
expect(keymap.keystrokeStringForEvent(keydownEvent('['))).toBe '['
|
||||
expect(keymap.keystrokeStringForEvent(keydownEvent('*'))).toBe '*'
|
||||
expect(keymap.keystrokeStringForEvent(keydownEvent('left'))).toBe 'left'
|
||||
expect(keymap.keystrokeStringForEvent(keydownEvent('\b'))).toBe 'backspace'
|
||||
|
||||
describe "when ctrl, alt or command is pressed with a non-modifier key", ->
|
||||
it "returns a string that identifies the key pressed", ->
|
||||
expect(keymap.keystrokeStringForEvent(keydownEvent('a', altKey: true))).toBe 'alt-a'
|
||||
expect(keymap.keystrokeStringForEvent(keydownEvent('[', metaKey: true))).toBe 'cmd-['
|
||||
expect(keymap.keystrokeStringForEvent(keydownEvent('*', ctrlKey: true))).toBe 'ctrl-*'
|
||||
expect(keymap.keystrokeStringForEvent(keydownEvent('left', ctrlKey: true, metaKey: true, altKey: true))).toBe 'alt-cmd-ctrl-left'
|
||||
|
||||
describe "when shift is pressed when a non-modifer key", ->
|
||||
it "returns a string that identifies the key pressed", ->
|
||||
expect(keymap.keystrokeStringForEvent(keydownEvent('A', shiftKey: true))).toBe 'A'
|
||||
expect(keymap.keystrokeStringForEvent(keydownEvent('{', shiftKey: true))).toBe '{'
|
||||
expect(keymap.keystrokeStringForEvent(keydownEvent('left', shiftKey: true))).toBe 'shift-left'
|
||||
expect(keymap.keystrokeStringForEvent(keydownEvent('Left', shiftKey: true))).toBe 'shift-left'
|
||||
|
||||
describe ".keyBindingsMatchingElement(element)", ->
|
||||
it "returns the matching bindings for the element", ->
|
||||
keymap.bindKeys 'name', '.command-mode', 'c': 'c'
|
||||
keymap.bindKeys 'name', '.grandchild-node', 'g': 'g'
|
||||
|
||||
bindings = keymap.keyBindingsMatchingElement(fragment.find('.grandchild-node'))
|
||||
expect(bindings).toHaveLength 2
|
||||
expect(bindings[0].command).toEqual "g"
|
||||
expect(bindings[1].command).toEqual "c"
|
||||
|
||||
describe "when multiple bindings match a keystroke", ->
|
||||
it "only returns bindings that match the most specific selector", ->
|
||||
keymap.bindKeys 'name', '.command-mode', 'g': 'cmd-mode'
|
||||
keymap.bindKeys 'name', '.command-mode .grandchild-node', 'g': 'cmd-and-grandchild-node'
|
||||
keymap.bindKeys 'name', '.grandchild-node', 'g': 'grandchild-node'
|
||||
|
||||
bindings = keymap.keyBindingsMatchingElement(fragment.find('.grandchild-node'))
|
||||
expect(bindings).toHaveLength 3
|
||||
expect(bindings[0].command).toEqual "cmd-and-grandchild-node"
|
||||
|
||||
describe ".keyBindingsForCommandMatchingElement(element)", ->
|
||||
beforeEach ->
|
||||
keymap.add 'nature',
|
||||
'.green':
|
||||
'ctrl-c': 'cultivate'
|
||||
'.green-2':
|
||||
'ctrl-o': 'cultivate'
|
||||
'.brown':
|
||||
'ctrl-h': 'harvest'
|
||||
'.blue':
|
||||
'ctrl-c': 'fly'
|
||||
|
||||
it "finds a keymap for an element", ->
|
||||
el = $$ -> @div class: 'green'
|
||||
bindings = keymap.keyBindingsForCommandMatchingElement('cultivate', el)
|
||||
expect(bindings).toHaveLength 1
|
||||
expect(bindings[0].keystroke).toEqual "ctrl-c"
|
||||
|
||||
it "no keymap an element without that map", ->
|
||||
el = $$ -> @div class: 'brown'
|
||||
bindings = keymap.keyBindingsForCommandMatchingElement('cultivate', el)
|
||||
expect(bindings).toHaveLength 0
|
||||
|
||||
describe "loading platform specific keybindings", ->
|
||||
customKeymap = null
|
||||
|
||||
beforeEach ->
|
||||
resourcePath = temp.mkdirSync('atom')
|
||||
customKeymap = new Keymap({configDirPath, resourcePath})
|
||||
|
||||
afterEach ->
|
||||
customKeymap.destroy()
|
||||
|
||||
it "doesn't load keybindings from other platforms", ->
|
||||
win32FilePath = path.join(resourcePath, "keymaps", "win32.cson")
|
||||
darwinFilePath = path.join(resourcePath, "keymaps", "darwin.cson")
|
||||
fs.writeFileSync(win32FilePath, '"body": "ctrl-l": "core:win32-move-left"')
|
||||
fs.writeFileSync(darwinFilePath, '"body": "ctrl-l": "core:darwin-move-left"')
|
||||
|
||||
customKeymap.loadBundledKeymaps()
|
||||
keyBindings = customKeymap.keyBindingsForKeystroke('ctrl-l')
|
||||
expect(keyBindings).toHaveLength 1
|
||||
expect(keyBindings[0].command).toBe "core:#{process.platform}-move-left"
|
||||
|
||||
describe "when the user keymap file is changed", ->
|
||||
it "is reloaded", ->
|
||||
keymapFilePath = path.join(configDirPath, "keymap.cson")
|
||||
fs.writeFileSync(keymapFilePath, '"body": "ctrl-l": "core:move-left"')
|
||||
keymap.loadUserKeymap()
|
||||
|
||||
spyOn(keymap, 'loadUserKeymap').andCallThrough()
|
||||
fs.writeFileSync(keymapFilePath, "'body': 'ctrl-l': 'core:move-right'")
|
||||
|
||||
waitsFor ->
|
||||
keymap.loadUserKeymap.callCount > 0
|
||||
|
||||
runs ->
|
||||
keyBinding = keymap.keyBindingsForKeystroke('ctrl-l')[0]
|
||||
expect(keyBinding.command).toBe 'core:move-right'
|
||||
keymap.loadUserKeymap.reset()
|
||||
fs.removeSync(keymapFilePath)
|
||||
|
||||
waitsFor ->
|
||||
keymap.loadUserKeymap.callCount > 0
|
||||
|
||||
runs ->
|
||||
keyBinding = keymap.keyBindingsForKeystroke('ctrl-l')[0]
|
||||
expect(keyBinding).toBeUndefined()
|
||||
|
||||
it "logs a warning when it can't be parsed", ->
|
||||
keymapFilePath = path.join(configDirPath, "keymap.json")
|
||||
fs.writeFileSync(keymapFilePath, '')
|
||||
keymap.loadUserKeymap()
|
||||
|
||||
spyOn(keymap, 'loadUserKeymap').andCallThrough()
|
||||
fs.writeFileSync(keymapFilePath, '}{')
|
||||
spyOn(console, 'warn')
|
||||
|
||||
waitsFor ->
|
||||
keymap.loadUserKeymap.callCount > 0
|
||||
|
||||
runs ->
|
||||
expect(console.warn.callCount).toBe 1
|
||||
expect(console.warn.argsForCall[0][0].length).toBeGreaterThan 0
|
||||
|
||||
describe "when adding a binding with an invalid selector", ->
|
||||
it "logs a warning and does not add it", ->
|
||||
spyOn(console, 'warn')
|
||||
keybinding =
|
||||
'##selector':
|
||||
'cmd-a': 'invalid-command'
|
||||
keymap.add('test', keybinding)
|
||||
|
||||
expect(console.warn.callCount).toBe 1
|
||||
expect(console.warn.argsForCall[0][0].length).toBeGreaterThan 0
|
||||
expect(-> keymap.keyBindingsMatchingElement(document.body)).not.toThrow()
|
||||
expect(keymap.keyBindingsForCommand('invalid:command')).toEqual []
|
||||
@@ -208,6 +208,20 @@ describe "LanguageMode", ->
|
||||
languageMode.toggleLineCommentsForBufferRows(0, 0)
|
||||
expect(buffer.lineForRow(0)).toBe "// @color: #4D926F;"
|
||||
|
||||
describe "xml", ->
|
||||
beforeEach ->
|
||||
editor = atom.project.openSync('sample.xml', autoIndent: false)
|
||||
editor.setText("<!-- test -->")
|
||||
{buffer, languageMode} = editor
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-xml')
|
||||
|
||||
describe "when uncommenting lines", ->
|
||||
it "removes the leading whitespace from the comment end pattern match", ->
|
||||
languageMode.toggleLineCommentsForBufferRows(0, 0)
|
||||
expect(buffer.lineForRow(0)).toBe "test"
|
||||
|
||||
describe "folding", ->
|
||||
beforeEach ->
|
||||
editor = atom.project.openSync('sample.js', autoIndent: false)
|
||||
@@ -285,21 +299,6 @@ describe "LanguageMode", ->
|
||||
expect(fold.getStartRow()).toBe 0
|
||||
expect(fold.getEndRow()).toBe 13
|
||||
|
||||
describe ".unfoldBufferRow(bufferRow)", ->
|
||||
describe "when bufferRow can be unfolded", ->
|
||||
it "destroys a fold based on the syntactic region starting at the given row", ->
|
||||
languageMode.foldBufferRow(1)
|
||||
expect(editor.lineForScreenRow(1).fold).toBeDefined()
|
||||
|
||||
languageMode.unfoldBufferRow(1)
|
||||
expect(editor.lineForScreenRow(1).fold).toBeUndefined()
|
||||
|
||||
describe "when bufferRow can't be unfolded", ->
|
||||
it "does not throw an error", ->
|
||||
expect(editor.lineForScreenRow(1).fold).toBeUndefined()
|
||||
languageMode.unfoldBufferRow(1)
|
||||
expect(editor.lineForScreenRow(1).fold).toBeUndefined()
|
||||
|
||||
describe ".isFoldableAtBufferRow(bufferRow)", ->
|
||||
it "returns true if the line starts a foldable row range", ->
|
||||
expect(languageMode.isFoldableAtBufferRow(0)).toBe true
|
||||
|
||||
@@ -292,7 +292,7 @@ describe "Pane", ->
|
||||
pane.activeItem.path = __filename
|
||||
pane.activeItem.saveAs = jasmine.createSpy("saveAs")
|
||||
pane.saveActiveItemAs()
|
||||
expect(atom.showSaveDialogSync).toHaveBeenCalledWith(__dirname)
|
||||
expect(atom.showSaveDialogSync).toHaveBeenCalledWith(__filename)
|
||||
expect(pane.activeItem.saveAs).toHaveBeenCalledWith('/selected/path')
|
||||
|
||||
describe "when the current item does not have a saveAs method", ->
|
||||
|
||||
@@ -159,14 +159,14 @@ describe "PaneView", ->
|
||||
|
||||
describe "when an unmodifed buffer's path is deleted", ->
|
||||
it "removes the pane item", ->
|
||||
jasmine.unspy(window, 'setTimeout')
|
||||
filePath = temp.openSync('atom').path
|
||||
editor = atom.project.openSync(filePath)
|
||||
pane.activateItem(editor)
|
||||
expect(pane.items).toHaveLength(5)
|
||||
|
||||
fs.removeSync(filePath)
|
||||
waitsFor 30000, ->
|
||||
pane.items.length == 4
|
||||
waitsFor -> pane.items.length == 4
|
||||
|
||||
describe "when a pane is destroyed", ->
|
||||
[pane2, pane2Model] = []
|
||||
|
||||
@@ -491,6 +491,16 @@ describe "Project", ->
|
||||
expect(resultForA.matches).toHaveLength 1
|
||||
expect(resultForA.matches[0].matchText).toBe 'Elephant'
|
||||
|
||||
it "ignores buffers outside the project", ->
|
||||
editor = atom.project.openSync(temp.openSync().path)
|
||||
editor.setText("Elephant")
|
||||
results = []
|
||||
waitsForPromise ->
|
||||
atom.project.scan /Elephant/, (result) -> results.push result
|
||||
|
||||
runs ->
|
||||
expect(results).toHaveLength 0
|
||||
|
||||
describe ".eachBuffer(callback)", ->
|
||||
beforeEach ->
|
||||
atom.project.bufferForPathSync('a')
|
||||
|
||||
@@ -43,6 +43,15 @@ describe "SelectListView", ->
|
||||
expect(list.find('li:eq(0)')).toHaveClass 'A'
|
||||
expect(selectList.getSelectedItem()).toBe items[0]
|
||||
|
||||
it "allows raw HTML to be returned", ->
|
||||
selectList.viewForItem = (item) ->
|
||||
"<li>#{item}</li>"
|
||||
|
||||
selectList.setItems(['Bermuda', 'Bahama'])
|
||||
|
||||
expect(list.find('li:eq(0)')).toHaveText 'Bermuda'
|
||||
expect(selectList.getSelectedItem()).toBe 'Bermuda'
|
||||
|
||||
describe "when the text of the mini editor changes", ->
|
||||
beforeEach ->
|
||||
selectList.attachToDom()
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# Start the crash reporter before anything else.
|
||||
require('crash-reporter').start(productName: 'Atom', companyName: 'GitHub')
|
||||
|
||||
path = require 'path'
|
||||
|
||||
try
|
||||
require '../src/window'
|
||||
Atom = require '../src/atom'
|
||||
@@ -12,6 +14,12 @@ try
|
||||
|
||||
{runSpecSuite} = require './jasmine-helper'
|
||||
|
||||
# Add 'src/exports' to module search path.
|
||||
exportsPath = path.resolve(atom.getLoadSettings().resourcePath, 'exports')
|
||||
require('module').globalPaths.push(exportsPath)
|
||||
# Still set NODE_PATH since tasks may need it.
|
||||
process.env.NODE_PATH = exportsPath
|
||||
|
||||
document.title = "Spec Suite"
|
||||
runSpecSuite './spec-suite', atom.getLoadSettings().logFile
|
||||
catch error
|
||||
|
||||
@@ -6,8 +6,8 @@ require '../vendor/jasmine-jquery'
|
||||
path = require 'path'
|
||||
_ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
{$, WorkspaceView} = require 'atom'
|
||||
Keymap = require '../src/keymap'
|
||||
KeymapManager = require '../src/keymap-extensions'
|
||||
{$, WorkspaceView, Workspace} = require 'atom'
|
||||
Config = require '../src/config'
|
||||
{Point} = require 'text-buffer'
|
||||
Project = require '../src/project'
|
||||
@@ -22,8 +22,8 @@ atom.themes.requireStylesheet '../static/jasmine'
|
||||
|
||||
fixturePackagesPath = path.resolve(__dirname, './fixtures/packages')
|
||||
atom.packages.packageDirPaths.unshift(fixturePackagesPath)
|
||||
atom.keymap.loadBundledKeymaps()
|
||||
keyBindingsToRestore = atom.keymap.getKeyBindings()
|
||||
atom.keymaps.loadBundledKeymaps()
|
||||
keyBindingsToRestore = atom.keymaps.getKeyBindings()
|
||||
|
||||
$(window).on 'core:close', -> window.close()
|
||||
$(window).on 'unload', ->
|
||||
@@ -50,7 +50,8 @@ beforeEach ->
|
||||
$.fx.off = true
|
||||
projectPath = specProjectPath ? path.join(@specDirectory, 'fixtures')
|
||||
atom.project = new Project(path: projectPath)
|
||||
atom.keymap.keyBindings = _.clone(keyBindingsToRestore)
|
||||
atom.workspace = new Workspace()
|
||||
atom.keymaps.keyBindings = _.clone(keyBindingsToRestore)
|
||||
|
||||
window.resetTimeouts()
|
||||
atom.packages.packageStates = {}
|
||||
@@ -112,7 +113,7 @@ afterEach ->
|
||||
atom.workspaceView = null
|
||||
delete atom.state.workspace
|
||||
|
||||
atom.project?.destroy?()
|
||||
atom.project?.destroy()
|
||||
atom.project = null
|
||||
|
||||
delete atom.state.packageStates
|
||||
@@ -180,7 +181,15 @@ window.keyIdentifierForKey = (key) ->
|
||||
"U+00" + charCode.toString(16)
|
||||
|
||||
window.keydownEvent = (key, properties={}) ->
|
||||
properties = $.extend({originalEvent: { keyIdentifier: keyIdentifierForKey(key) }}, properties)
|
||||
originalEventProperties = {}
|
||||
originalEventProperties.ctrl = properties.ctrlKey
|
||||
originalEventProperties.alt = properties.altKey
|
||||
originalEventProperties.shift = properties.shiftKey
|
||||
originalEventProperties.cmd = properties.metaKey
|
||||
originalEventProperties.target = properties.target?[0] ? properties.target
|
||||
originalEventProperties.which = properties.which
|
||||
originalEvent = KeymapManager.keydownEvent(key, originalEventProperties)
|
||||
properties = $.extend({originalEvent}, properties)
|
||||
$.Event("keydown", properties)
|
||||
|
||||
window.mouseEvent = (type, properties) ->
|
||||
@@ -270,7 +279,7 @@ $.fn.resultOfTrigger = (type) ->
|
||||
event.result
|
||||
|
||||
$.fn.enableKeymap = ->
|
||||
@on 'keydown', (e) => atom.keymap.handleKeyEvent(e)
|
||||
@on 'keydown', (e) => atom.keymaps.handleKeyEvent(e)
|
||||
|
||||
$.fn.attachToDom = ->
|
||||
@appendTo($('#jasmine-content'))
|
||||
|
||||
@@ -5,7 +5,7 @@ path = require 'path'
|
||||
require './spec-helper'
|
||||
|
||||
requireSpecs = (specDirectory, specType) ->
|
||||
for specFilePath in fs.listTreeSync(specDirectory) when /-spec\.coffee$/.test specFilePath
|
||||
for specFilePath in fs.listTreeSync(specDirectory) when /-spec\.(coffee|js)$/.test specFilePath
|
||||
require specFilePath
|
||||
|
||||
# Set spec directory on spec for setting up the project in spec-helper
|
||||
@@ -26,6 +26,7 @@ setSpecDirectory = (specDirectory) ->
|
||||
|
||||
runAllSpecs = ->
|
||||
{resourcePath} = atom.getLoadSettings()
|
||||
|
||||
# Only run core specs when resource path is the Atom repository
|
||||
if Git.exists(resourcePath)
|
||||
requireSpecs(path.join(resourcePath, 'spec'))
|
||||
|
||||
@@ -170,8 +170,11 @@ describe "ThemeManager", ->
|
||||
expect($(document.body).css('font-weight')).not.toBe("bold")
|
||||
themeManager.requireStylesheet(cssPath)
|
||||
expect($(document.body).css('font-weight')).toBe("bold")
|
||||
|
||||
themeManager.on 'stylesheets-changed', stylesheetsChangedHandler = jasmine.createSpy("stylesheetsChangedHandler")
|
||||
themeManager.removeStylesheet(cssPath)
|
||||
expect($(document.body).css('font-weight')).not.toBe("bold")
|
||||
expect(stylesheetsChangedHandler).toHaveBeenCalled()
|
||||
|
||||
describe "base stylesheet loading", ->
|
||||
beforeEach ->
|
||||
@@ -204,12 +207,15 @@ describe "ThemeManager", ->
|
||||
fs.writeFileSync(userStylesheetPath, 'body {border-style: dotted !important;}')
|
||||
|
||||
spyOn(themeManager, 'getUserStylesheetPath').andReturn userStylesheetPath
|
||||
themeManager.on 'stylesheets-changed', stylesheetsChangedHandler = jasmine.createSpy("stylesheetsChangedHandler")
|
||||
|
||||
waitsForPromise ->
|
||||
themeManager.activateThemes()
|
||||
|
||||
runs ->
|
||||
expect($(document.body).css('border-style')).toBe 'dotted'
|
||||
expect(stylesheetsChangedHandler).toHaveBeenCalled()
|
||||
stylesheetsChangedHandler.reset()
|
||||
spyOn(themeManager, 'loadUserStylesheet').andCallThrough()
|
||||
fs.writeFileSync(userStylesheetPath, 'body {border-style: dashed}')
|
||||
|
||||
@@ -218,6 +224,8 @@ describe "ThemeManager", ->
|
||||
|
||||
runs ->
|
||||
expect($(document.body).css('border-style')).toBe 'dashed'
|
||||
expect(stylesheetsChangedHandler).toHaveBeenCalled()
|
||||
stylesheetsChangedHandler.reset()
|
||||
fs.removeSync(userStylesheetPath)
|
||||
|
||||
waitsFor ->
|
||||
@@ -225,6 +233,7 @@ describe "ThemeManager", ->
|
||||
|
||||
runs ->
|
||||
expect($(document.body).css('border-style')).toBe 'none'
|
||||
expect(stylesheetsChangedHandler).toHaveBeenCalled()
|
||||
|
||||
describe "when a non-existent theme is present in the config", ->
|
||||
it "logs a warning but does not throw an exception (regression)", ->
|
||||
|
||||
@@ -452,3 +452,14 @@ describe "TokenizedBuffer", ->
|
||||
expect(tokenizedBuffer.tokenForPosition([0,0]).value).toBe ' '
|
||||
atom.config.set('editor.tabLength', 6)
|
||||
expect(tokenizedBuffer.tokenForPosition([0,0]).value).toBe ' '
|
||||
|
||||
it "does not allow the tab length to be less than 1", ->
|
||||
buffer = atom.project.bufferForPathSync('sample.js')
|
||||
buffer.setText('\ttest')
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
expect(tokenizedBuffer.tokenForPosition([0,0]).value).toBe ' '
|
||||
atom.config.set('editor.tabLength', 1)
|
||||
expect(tokenizedBuffer.tokenForPosition([0,0]).value).toBe ' '
|
||||
atom.config.set('editor.tabLength', 0)
|
||||
expect(tokenizedBuffer.tokenForPosition([0,0]).value).toBe ' '
|
||||
|
||||
@@ -90,11 +90,13 @@ describe "Window", ->
|
||||
it "saves the serialized state of the window so it can be deserialized after reload", ->
|
||||
workspaceState = atom.workspace.serialize()
|
||||
syntaxState = atom.syntax.serialize()
|
||||
projectState = atom.project.serialize()
|
||||
|
||||
atom.unloadEditorWindow()
|
||||
|
||||
expect(atom.state.workspace).toEqual workspaceState
|
||||
expect(atom.state.syntax).toEqual syntaxState
|
||||
expect(atom.state.project).toEqual projectState
|
||||
expect(atom.saveSync).toHaveBeenCalled()
|
||||
|
||||
it "unsubscribes from all buffers", ->
|
||||
|
||||
@@ -14,14 +14,24 @@ describe "Workspace", ->
|
||||
describe "when the 'searchAllPanes' option is false (default)", ->
|
||||
describe "when called without a uri", ->
|
||||
it "adds and activates an empty editor on the active pane", ->
|
||||
editor = null
|
||||
[editor1, editor2] = []
|
||||
|
||||
waitsForPromise ->
|
||||
workspace.open().then (o) -> editor = o
|
||||
workspace.open().then (editor) -> editor1 = editor
|
||||
|
||||
runs ->
|
||||
expect(editor.getPath()).toBeUndefined()
|
||||
expect(workspace.activePane.items).toEqual [editor]
|
||||
expect(workspace.activePaneItem).toBe editor
|
||||
expect(editor1.getPath()).toBeUndefined()
|
||||
expect(workspace.activePane.items).toEqual [editor1]
|
||||
expect(workspace.activePaneItem).toBe editor1
|
||||
expect(workspace.activePane.activate).toHaveBeenCalled()
|
||||
|
||||
waitsForPromise ->
|
||||
workspace.open().then (editor) -> editor2 = editor
|
||||
|
||||
runs ->
|
||||
expect(editor2.getPath()).toBeUndefined()
|
||||
expect(workspace.activePane.items).toEqual [editor1, editor2]
|
||||
expect(workspace.activePaneItem).toBe editor2
|
||||
expect(workspace.activePane.activate).toHaveBeenCalled()
|
||||
|
||||
describe "when called with a uri", ->
|
||||
|
||||
@@ -111,7 +111,7 @@ describe "WorkspaceView", ->
|
||||
commandHandler = jasmine.createSpy('commandHandler')
|
||||
atom.workspaceView.on('foo-command', commandHandler)
|
||||
|
||||
atom.keymap.bindKeys('name', '*', 'x': 'foo-command')
|
||||
atom.keymaps.bindKeys('name', '*', 'x': 'foo-command')
|
||||
|
||||
describe "when a keydown event is triggered in the WorkspaceView", ->
|
||||
it "triggers matching keybindings for that event", ->
|
||||
@@ -241,3 +241,11 @@ describe "WorkspaceView", ->
|
||||
expect(atom.workspaceView.getActivePane().getItems()).toHaveLength 1
|
||||
atom.workspaceView.trigger('core:close')
|
||||
expect(atom.workspaceView.getActivePane().getItems()).toHaveLength 0
|
||||
|
||||
describe "the scrollbar visibility class", ->
|
||||
it "has a class based on the style of the scrollbar", ->
|
||||
scrollbarStyle = require 'scrollbar-style'
|
||||
scrollbarStyle.emitValue 'legacy'
|
||||
expect(atom.workspaceView).toHaveClass 'scrollbars-visible-always'
|
||||
scrollbarStyle.emitValue 'overlay'
|
||||
expect(atom.workspaceView).toHaveClass 'scrollbars-visible-when-scrolling'
|
||||
|
||||
+21
-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.keymap` - A {Keymap} instance
|
||||
# * `atom.keymaps` - A {Keymap} instance
|
||||
# * `atom.menu` - A {MenuManager} instance
|
||||
# * `atom.packages` - A {PackageManager} instance
|
||||
# * `atom.project` - A {Project} instance
|
||||
@@ -34,6 +34,8 @@ WindowEventHandler = require './window-event-handler'
|
||||
# * `atom.workspaceView` - A {WorkspaceView} instance
|
||||
module.exports =
|
||||
class Atom extends Model
|
||||
@version: 1 # Increment this when the serialization format changes
|
||||
|
||||
# Public: Load or create the Atom environment in the given mode.
|
||||
#
|
||||
# - mode: Pass 'editor' or 'spec' depending on the kind of environment you
|
||||
@@ -41,11 +43,11 @@ class Atom extends Model
|
||||
#
|
||||
# Returns an Atom instance, fully initialized
|
||||
@loadOrCreate: (mode) ->
|
||||
@deserialize(@loadState(mode)) ? new this({mode, version: @getVersion()})
|
||||
@deserialize(@loadState(mode)) ? new this({mode, @version})
|
||||
|
||||
# Deserializes the Atom environment from a state object
|
||||
@deserialize: (state) ->
|
||||
new this(state) if state?.version is @getVersion()
|
||||
new this(state) if state?.version is @version
|
||||
|
||||
# Loads and returns the serialized state corresponding to this window
|
||||
# if it exists; otherwise returns undefined.
|
||||
@@ -110,7 +112,7 @@ class Atom extends Model
|
||||
|
||||
# Get the version of the Atom application.
|
||||
@getVersion: ->
|
||||
@version ?= @getLoadSettings().appVersion
|
||||
@appVersion ?= @getLoadSettings().appVersion
|
||||
|
||||
# Determine whether the current version is an official release.
|
||||
@isReleasedVersion: ->
|
||||
@@ -138,7 +140,7 @@ class Atom extends Model
|
||||
@loadTime = null
|
||||
|
||||
Config = require './config'
|
||||
Keymap = require './keymap'
|
||||
KeymapManager = require './keymap-extensions'
|
||||
PackageManager = require './package-manager'
|
||||
Clipboard = require './clipboard'
|
||||
Syntax = require './syntax'
|
||||
@@ -148,8 +150,15 @@ class Atom extends Model
|
||||
{devMode, resourcePath} = @getLoadSettings()
|
||||
configDirPath = @getConfigDirPath()
|
||||
|
||||
# Add 'src/exports' to module search path.
|
||||
exportsPath = path.resolve(resourcePath, 'exports')
|
||||
require('module').globalPaths.push(exportsPath)
|
||||
# Still set NODE_PATH since tasks may need it.
|
||||
process.env.NODE_PATH = exportsPath
|
||||
|
||||
@config = new Config({configDirPath, resourcePath})
|
||||
@keymap = new Keymap({configDirPath, resourcePath})
|
||||
@keymaps = new KeymapManager({configDirPath, resourcePath})
|
||||
@keymap = @keymaps # Deprecated
|
||||
@packages = new PackageManager({devMode, configDirPath, resourcePath})
|
||||
@themes = new ThemeManager({packageManager: @packages, configDirPath, resourcePath})
|
||||
@contextMenu = new ContextMenuManager(devMode)
|
||||
@@ -229,13 +238,14 @@ class Atom extends Model
|
||||
|
||||
deserializeProject: ->
|
||||
Project = require './project'
|
||||
@project ?= @deserializers.deserialize(@project) ? new Project(path: @getLoadSettings().initialPath)
|
||||
@project ?= @deserializers.deserialize(@state.project) ? new Project(path: @getLoadSettings().initialPath)
|
||||
|
||||
deserializeWorkspaceView: ->
|
||||
Workspace = require './workspace'
|
||||
WorkspaceView = require './workspace-view'
|
||||
@workspace = Workspace.deserialize(@state.workspace) ? new Workspace
|
||||
@workspaceView = new WorkspaceView(@workspace)
|
||||
@keymaps.defaultTarget = @workspaceView[0]
|
||||
$(@workspaceViewParentSelector).append(@workspaceView)
|
||||
|
||||
deserializePackageStates: ->
|
||||
@@ -260,12 +270,12 @@ class Atom extends Model
|
||||
@config.load()
|
||||
@config.setDefaults('core', require('./workspace-view').configDefaults)
|
||||
@config.setDefaults('editor', require('./editor-view').configDefaults)
|
||||
@keymap.loadBundledKeymaps()
|
||||
@keymaps.loadBundledKeymaps()
|
||||
@themes.loadBaseStylesheets()
|
||||
@packages.loadPackages()
|
||||
@deserializeEditorWindow()
|
||||
@packages.activate()
|
||||
@keymap.loadUserKeymap()
|
||||
@keymaps.loadUserKeymap()
|
||||
@requireUserInitScript()
|
||||
@menu.update()
|
||||
|
||||
@@ -280,6 +290,7 @@ class Atom extends Model
|
||||
return if not @project and not @workspaceView
|
||||
|
||||
@state.syntax = @syntax.serialize()
|
||||
@state.project = @project.serialize()
|
||||
@state.workspace = @workspace.serialize()
|
||||
@packages.deactivatePackages()
|
||||
@state.packageStates = @packages.packageStates
|
||||
@@ -288,7 +299,7 @@ class Atom extends Model
|
||||
@workspaceView = null
|
||||
@project.destroy()
|
||||
@windowEventHandler?.unsubscribe()
|
||||
@keymap.destroy()
|
||||
@keymaps.destroy()
|
||||
@windowState = null
|
||||
|
||||
loadThemes: ->
|
||||
|
||||
@@ -9,9 +9,6 @@ _ = require 'underscore-plus'
|
||||
# and maintain the state of all menu items.
|
||||
module.exports =
|
||||
class ApplicationMenu
|
||||
version: null
|
||||
menu: null
|
||||
|
||||
constructor: (@version) ->
|
||||
@menu = Menu.buildFromTemplate @getDefaultTemplate()
|
||||
Menu.setApplicationMenu @menu
|
||||
@@ -71,11 +68,28 @@ class ApplicationMenu
|
||||
|
||||
# Toggles Install Update Item
|
||||
showInstallUpdateItem: (visible=true) ->
|
||||
if visible
|
||||
@showDownloadingUpdateItem(false)
|
||||
@showCheckForUpdateItem(false)
|
||||
|
||||
if (item = _.find(@flattenMenuItems(@menu), (i) -> i.label == 'Restart and Install Update'))
|
||||
item.visible = visible
|
||||
|
||||
# Toggles Downloading Update Item
|
||||
showDownloadingUpdateItem: (visible=true) ->
|
||||
if visible
|
||||
@showInstallUpdateItem(false)
|
||||
@showCheckForUpdateItem(false)
|
||||
|
||||
if (item = _.find(@flattenMenuItems(@menu), (i) -> i.label == 'Downloading Update'))
|
||||
item.visible = visible
|
||||
|
||||
# Toggles Check For Update Item
|
||||
showCheckForUpdateItem: (visible=true) ->
|
||||
if visible
|
||||
@showDownloadingUpdateItem(false)
|
||||
@showInstallUpdateItem(false)
|
||||
|
||||
if (item = _.find(@flattenMenuItems(@menu), (i) -> i.label == 'Check for Update'))
|
||||
item.visible = visible
|
||||
|
||||
@@ -86,13 +100,16 @@ class ApplicationMenu
|
||||
[
|
||||
label: "Atom"
|
||||
submenu: [
|
||||
{ label: 'Reload', accelerator: 'Command+R', click: -> @focusedWindow()?.reload() }
|
||||
{ label: 'Close Window', accelerator: 'Command+Shift+W', click: -> @focusedWindow()?.close() }
|
||||
{ label: 'Toggle Dev Tools', accelerator: 'Command+Alt+I', click: -> @focusedWindow()?.toggleDevTools() }
|
||||
{ label: 'Reload', accelerator: 'Command+R', click: => @focusedWindow()?.reload() }
|
||||
{ label: 'Close Window', accelerator: 'Command+Shift+W', click: => @focusedWindow()?.close() }
|
||||
{ label: 'Toggle Dev Tools', accelerator: 'Command+Alt+I', click: => @focusedWindow()?.toggleDevTools() }
|
||||
{ label: 'Quit', accelerator: 'Command+Q', click: -> app.quit() }
|
||||
]
|
||||
]
|
||||
|
||||
focusedWindow: ->
|
||||
_.find global.atomApplication.windows, (atomWindow) -> atomWindow.isFocused()
|
||||
|
||||
# Combines a menu template with the appropriate keystroke.
|
||||
#
|
||||
# * template:
|
||||
@@ -130,7 +147,6 @@ class ApplicationMenu
|
||||
modifiers = firstKeystroke.split('-')
|
||||
key = modifiers.pop()
|
||||
|
||||
modifiers.push("Shift") if key != key.toLowerCase()
|
||||
modifiers = modifiers.map (modifier) ->
|
||||
modifier.replace(/shift/ig, "Shift")
|
||||
.replace(/cmd/ig, "Command")
|
||||
|
||||
@@ -30,7 +30,6 @@ socketPath =
|
||||
module.exports =
|
||||
class AtomApplication
|
||||
_.extend @prototype, EventEmitter.prototype
|
||||
updateVersion: null
|
||||
|
||||
# Public: The entry point into the Atom application.
|
||||
@open: (options) ->
|
||||
@@ -126,78 +125,74 @@ class AtomApplication
|
||||
|
||||
# Configures required javascript environment flags.
|
||||
setupJavaScriptArguments: ->
|
||||
app.commandLine.appendSwitch 'js-flags', '--harmony_collections --harmony-proxies'
|
||||
app.commandLine.appendSwitch 'js-flags', '--harmony'
|
||||
|
||||
# Enable updates unless running from a local build of Atom.
|
||||
setupAutoUpdater: ->
|
||||
return if /\w{7}/.test(@version) # Only released versions should check for updates.
|
||||
|
||||
autoUpdater.setFeedUrl "https://atom.io/api/updates?version=#{@version}"
|
||||
|
||||
autoUpdater.on 'checking-for-update', =>
|
||||
@applicationMenu.showDownloadingUpdateItem(false)
|
||||
@applicationMenu.showInstallUpdateItem(false)
|
||||
@applicationMenu.showCheckForUpdateItem(false)
|
||||
|
||||
autoUpdater.on 'update-not-available', =>
|
||||
@applicationMenu.showInstallUpdateItem(false)
|
||||
@applicationMenu.showCheckForUpdateItem(true)
|
||||
|
||||
autoUpdater.on 'update-downloaded', (event, releaseNotes, releaseName, releaseDate, releaseURL) =>
|
||||
atomWindow.sendCommand('window:update-available', [releaseName, releaseNotes]) for atomWindow in @windows
|
||||
autoUpdater.on 'update-available', =>
|
||||
@applicationMenu.showDownloadingUpdateItem(true)
|
||||
|
||||
autoUpdater.on 'update-downloaded', (event, releaseNotes, releaseVersion, releaseDate, releaseURL) =>
|
||||
atomWindow.sendCommand('window:update-available', [releaseVersion, releaseNotes]) for atomWindow in @windows
|
||||
@applicationMenu.showInstallUpdateItem(true)
|
||||
@applicationMenu.showCheckForUpdateItem(false)
|
||||
@updateVersion = releaseName
|
||||
|
||||
autoUpdater.on 'error', (event, message) =>
|
||||
@applicationMenu.showInstallUpdateItem(false)
|
||||
@applicationMenu.showCheckForUpdateItem(true)
|
||||
|
||||
# Check for update after Atom has fully started and the menus are created
|
||||
setTimeout((-> autoUpdater.checkForUpdates()), 5000)
|
||||
|
||||
checkForUpdate: ->
|
||||
autoUpdater.once 'update-available', ->
|
||||
dialog.showMessageBox
|
||||
type: 'info'
|
||||
buttons: ['OK']
|
||||
message: 'Update available.'
|
||||
detail: 'A new update is being downloaded.'
|
||||
@onUpdateNotAvailable ?= =>
|
||||
autoUpdater.removeListener 'error', @onUpdateError
|
||||
dialog.showMessageBox type: 'info', buttons: ['OK'], message: 'No update available.', detail: "Version #{@version} is the latest version."
|
||||
|
||||
autoUpdater.once 'update-not-available', =>
|
||||
dialog.showMessageBox
|
||||
type: 'info'
|
||||
buttons: ['OK']
|
||||
message: 'No update available.'
|
||||
detail: "Version #{@version} is the latest version."
|
||||
|
||||
autoUpdater.once 'error', (event, message)->
|
||||
dialog.showMessageBox
|
||||
type: 'warning'
|
||||
buttons: ['OK']
|
||||
message: 'There was an error checking for updates.'
|
||||
detail: message
|
||||
@onUpdateError ?= (event, message) =>
|
||||
autoUpdater.removeListener 'update-not-available', @onUpdateNotAvailable
|
||||
dialog.showMessageBox type: 'warning', buttons: ['OK'], message: 'There was an error checking for updates.', detail: message
|
||||
|
||||
autoUpdater.once 'update-not-available', @onUpdateNotAvailable
|
||||
autoUpdater.once 'error', @onUpdateError
|
||||
autoUpdater.checkForUpdates()
|
||||
|
||||
# Registers basic application commands, non-idempotent.
|
||||
handleEvents: ->
|
||||
@on 'application:about', -> Menu.sendActionToFirstResponder('orderFrontStandardAboutPanel:')
|
||||
@on 'application:run-all-specs', -> @runSpecs(exitWhenDone: false, resourcePath: global.devResourcePath)
|
||||
@on 'application:run-benchmarks', -> @runBenchmarks()
|
||||
@on 'application:quit', -> app.quit()
|
||||
@on 'application:hide', -> Menu.sendActionToFirstResponder('hide:')
|
||||
@on 'application:hide-other-applications', -> Menu.sendActionToFirstResponder('hideOtherApplications:')
|
||||
@on 'application:unhide-all-applications', -> Menu.sendActionToFirstResponder('unhideAllApplications:')
|
||||
@on 'application:new-window', -> @openPath(initialSize: @getFocusedWindowSize())
|
||||
@on 'application:new-file', -> (@focusedWindow() ? this).openPath()
|
||||
@on 'application:open', -> @promptForPath()
|
||||
@on 'application:open-dev', -> @promptForPath(devMode: true)
|
||||
@on 'application:minimize', -> Menu.sendActionToFirstResponder('performMiniaturize:')
|
||||
@on 'application:zoom', -> Menu.sendActionToFirstResponder('zoom:')
|
||||
@on 'application:bring-all-windows-to-front', -> Menu.sendActionToFirstResponder('arrangeInFront:')
|
||||
@on 'application:inspect', ({x,y}) -> @focusedWindow().browserWindow.inspectElement(x, y)
|
||||
@on 'application:open-documentation', -> shell.openExternal('https://atom.io/docs/latest/?app')
|
||||
@on 'application:install-update', -> autoUpdater.quitAndInstall()
|
||||
@on 'application:check-for-update', => @checkForUpdate()
|
||||
|
||||
if process.platform is 'darwin'
|
||||
@on 'application:about', -> Menu.sendActionToFirstResponder('orderFrontStandardAboutPanel:')
|
||||
@on 'application:bring-all-windows-to-front', -> Menu.sendActionToFirstResponder('arrangeInFront:')
|
||||
@on 'application:hide', -> Menu.sendActionToFirstResponder('hide:')
|
||||
@on 'application:hide-other-applications', -> Menu.sendActionToFirstResponder('hideOtherApplications:')
|
||||
@on 'application:minimize', -> Menu.sendActionToFirstResponder('performMiniaturize:')
|
||||
@on 'application:unhide-all-applications', -> Menu.sendActionToFirstResponder('unhideAllApplications:')
|
||||
@on 'application:zoom', -> Menu.sendActionToFirstResponder('zoom:')
|
||||
else
|
||||
@on 'application:minimize', -> @focusedWindow()?.minimize()
|
||||
@on 'application:zoom', -> @focusedWindow()?.maximize()
|
||||
|
||||
@openPathOnEvent('application:show-settings', 'atom://config')
|
||||
@openPathOnEvent('application:open-your-config', 'atom://.atom/config')
|
||||
@openPathOnEvent('application:open-your-init-script', 'atom://.atom/init-script')
|
||||
@@ -206,10 +201,15 @@ class AtomApplication
|
||||
@openPathOnEvent('application:open-your-stylesheet', 'atom://.atom/stylesheet')
|
||||
|
||||
app.on 'window-all-closed', ->
|
||||
app.quit() if process.platform is 'win32'
|
||||
app.quit() if process.platform in ['win32', 'linux']
|
||||
|
||||
app.on 'will-quit', => @deleteSocketFile()
|
||||
app.on 'will-exit', => @deleteSocketFile()
|
||||
app.on 'will-quit', =>
|
||||
@killAllProcesses()
|
||||
@deleteSocketFile()
|
||||
|
||||
app.on 'will-exit', =>
|
||||
@killAllProcesses()
|
||||
@deleteSocketFile()
|
||||
|
||||
app.on 'open-file', (event, pathToOpen) =>
|
||||
event.preventDefault()
|
||||
@@ -256,7 +256,26 @@ class AtomApplication
|
||||
# The optional arguments to pass along.
|
||||
sendCommand: (command, args...) ->
|
||||
unless @emit(command, args...)
|
||||
@focusedWindow()?.sendCommand(command, args...)
|
||||
focusedWindow = @focusedWindow()
|
||||
if focusedWindow?
|
||||
focusedWindow.sendCommand(command, args...)
|
||||
else
|
||||
@sendCommandToFirstResponder(command)
|
||||
|
||||
# Translates the command into OS X action and sends it to application's first
|
||||
# responder.
|
||||
sendCommandToFirstResponder: (command) ->
|
||||
return false unless process.platform is 'darwin'
|
||||
|
||||
switch command
|
||||
when 'core:undo' then Menu.sendActionToFirstResponder('undo:')
|
||||
when 'core:redo' then Menu.sendActionToFirstResponder('redo:')
|
||||
when 'core:copy' then Menu.sendActionToFirstResponder('copy:')
|
||||
when 'core:cut' then Menu.sendActionToFirstResponder('cut:')
|
||||
when 'core:paste' then Menu.sendActionToFirstResponder('paste:')
|
||||
when 'core:select-all' then Menu.sendActionToFirstResponder('selectAll:')
|
||||
else return false
|
||||
true
|
||||
|
||||
# Public: Open the given path in the focused window when the event is
|
||||
# triggered.
|
||||
@@ -345,13 +364,25 @@ class AtomApplication
|
||||
@pidsToOpenWindows[pidToKillWhenClosed] = openedWindow
|
||||
|
||||
openedWindow.browserWindow.on 'destroyed', =>
|
||||
for pid, trackedWindow of @pidsToOpenWindows when trackedWindow is openedWindow
|
||||
try
|
||||
process.kill(pid)
|
||||
catch error
|
||||
if error.code isnt 'ESRCH'
|
||||
console.log("Killing process #{pid} failed: #{error.code}")
|
||||
delete @pidsToOpenWindows[pid]
|
||||
@killProcessForWindow(openedWindow)
|
||||
|
||||
# Kill all processes associated with opened windows.
|
||||
killAllProcesses: ->
|
||||
@killProcess(pid) for pid of @pidsToOpenWindows
|
||||
|
||||
# Kill process associated with the given opened window.
|
||||
killProcessForWindow: (openedWindow) ->
|
||||
for pid, trackedWindow of @pidsToOpenWindows
|
||||
@killProcess(pid) if trackedWindow is openedWindow
|
||||
|
||||
# Kill the process with the given pid.
|
||||
killProcess: (pid) ->
|
||||
try
|
||||
process.kill(pid)
|
||||
catch error
|
||||
if error.code isnt 'ESRCH'
|
||||
console.log("Killing process #{pid} failed: #{error.code}")
|
||||
delete @pidsToOpenWindows[pid]
|
||||
|
||||
# Open an atom:// url.
|
||||
#
|
||||
@@ -427,8 +458,3 @@ class AtomApplication
|
||||
promptForPath: ({devMode}={}) ->
|
||||
dialog.showOpenDialog title: 'Open', properties: ['openFile', 'openDirectory', 'multiSelections', 'createDirectory'], (pathsToOpen) =>
|
||||
@openPaths({pathsToOpen, devMode})
|
||||
|
||||
# Public: If an update is available, it returns the new version string
|
||||
# otherwise it returns null.
|
||||
getUpdateVersion: ->
|
||||
@updateVersion
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
BrowserWindow = require 'browser-window'
|
||||
Menu = require 'menu'
|
||||
ContextMenu = require './context-menu'
|
||||
app = require 'app'
|
||||
dialog = require 'dialog'
|
||||
@@ -22,12 +21,7 @@ class AtomWindow
|
||||
{@resourcePath, pathToOpen, initialLine, @isSpec, @exitWhenDone} = settings
|
||||
global.atomApplication.addWindow(this)
|
||||
|
||||
@setupNodePath(@resourcePath)
|
||||
@browserWindow = new BrowserWindow show: false, title: 'Atom', icon: @constructor.iconPath
|
||||
@browserWindow.restart = _.wrap _.bind(@browserWindow.restart, @browserWindow), (restart) =>
|
||||
@setupNodePath(@resourcePath)
|
||||
restart()
|
||||
|
||||
@handleEvents()
|
||||
|
||||
loadSettings = _.extend({}, settings)
|
||||
@@ -50,9 +44,6 @@ class AtomWindow
|
||||
|
||||
@openPath(pathToOpen, initialLine)
|
||||
|
||||
setupNodePath: (resourcePath) ->
|
||||
process.env['NODE_PATH'] = path.resolve(resourcePath, 'exports')
|
||||
|
||||
getUrl: (loadSettingsObj) ->
|
||||
# Ignore the windowState when passing loadSettings via URL, since it could
|
||||
# be quite large.
|
||||
@@ -104,7 +95,7 @@ class AtomWindow
|
||||
type: 'warning'
|
||||
buttons: ['Close Window', 'Reload', 'Keep It Open']
|
||||
message: 'The editor has crashed'
|
||||
detail: 'Please report this issue to https://github.com/atom/atom/issues'
|
||||
detail: 'Please report this issue to atom@github.com'
|
||||
switch chosen
|
||||
when 0 then @browserWindow.destroy()
|
||||
when 1 then @browserWindow.restart()
|
||||
@@ -121,13 +112,12 @@ class AtomWindow
|
||||
if @loaded
|
||||
@focus()
|
||||
@sendCommand('window:open-path', {pathToOpen, initialLine})
|
||||
@sendCommand('window:update-available', global.atomApplication.getUpdateVersion()) if global.atomApplication.getUpdateVersion()
|
||||
else
|
||||
@browserWindow.once 'window:loaded', => @openPath(pathToOpen, initialLine)
|
||||
|
||||
sendCommand: (command, args...) ->
|
||||
if @isSpecWindow()
|
||||
unless @sendCommandToFirstResponder(command)
|
||||
unless global.atomApplication.sendCommandToFirstResponder(command)
|
||||
switch command
|
||||
when 'window:reload' then @reload()
|
||||
when 'window:toggle-dev-tools' then @toggleDevTools()
|
||||
@@ -135,30 +125,23 @@ class AtomWindow
|
||||
else if @isWebViewFocused()
|
||||
@sendCommandToBrowserWindow(command, args...)
|
||||
else
|
||||
unless @sendCommandToFirstResponder(command)
|
||||
unless global.atomApplication.sendCommandToFirstResponder(command)
|
||||
@sendCommandToBrowserWindow(command, args...)
|
||||
|
||||
sendCommandToBrowserWindow: (command, args...) ->
|
||||
action = if args[0]?.contextCommand then 'context-command' else 'command'
|
||||
ipc.sendChannel @browserWindow.getProcessId(), @browserWindow.getRoutingId(), action, command, args...
|
||||
|
||||
sendCommandToFirstResponder: (command) ->
|
||||
switch command
|
||||
when 'core:undo' then Menu.sendActionToFirstResponder('undo:')
|
||||
when 'core:redo' then Menu.sendActionToFirstResponder('redo:')
|
||||
when 'core:copy' then Menu.sendActionToFirstResponder('copy:')
|
||||
when 'core:cut' then Menu.sendActionToFirstResponder('cut:')
|
||||
when 'core:paste' then Menu.sendActionToFirstResponder('paste:')
|
||||
when 'core:select-all' then Menu.sendActionToFirstResponder('selectAll:')
|
||||
else return false
|
||||
true
|
||||
|
||||
close: -> @browserWindow.close()
|
||||
|
||||
focus: -> @browserWindow.focus()
|
||||
|
||||
getSize: -> @browserWindow.getSize()
|
||||
|
||||
minimize: -> @browserWindow.minimize()
|
||||
|
||||
maximize: -> @browserWindow.maximize()
|
||||
|
||||
handlesAtomCommands: ->
|
||||
not @isSpecWindow() and @isWebViewFocused()
|
||||
|
||||
|
||||
@@ -9,12 +9,7 @@ optimist = require 'optimist'
|
||||
nslog = require 'nslog'
|
||||
dialog = require 'dialog'
|
||||
|
||||
console.log = (args...) ->
|
||||
# TODO: Make NSLog work as expected
|
||||
output = args.map((arg) -> JSON.stringify(arg)).join(" ")
|
||||
nslog(output)
|
||||
if process.platform isnt 'darwin'
|
||||
fs.writeFileSync('debug.log', output, flag: 'a')
|
||||
console.log = nslog
|
||||
|
||||
process.on 'uncaughtException', (error={}) ->
|
||||
nslog(error.message) if error.message?
|
||||
@@ -77,7 +72,7 @@ parseCommandLine = ->
|
||||
options.alias('h', 'help').boolean('h').describe('h', 'Print this usage message.')
|
||||
options.alias('l', 'log-file').string('l').describe('l', 'Log all output to file.')
|
||||
options.alias('n', 'new-window').boolean('n').describe('n', 'Open a new window.')
|
||||
options.alias('s', 'spec-directory').string('s').describe('s', 'Set the directory from which specs are loaded (default: Atom\'s spec directory).')
|
||||
options.alias('s', 'spec-directory').string('s').describe('s', 'Set the spec directory (default: Atom\'s spec directory).')
|
||||
options.alias('t', 'test').boolean('t').describe('t', 'Run the specified specs and exit with error code on failures.')
|
||||
options.alias('v', 'version').boolean('v').describe('v', 'Print the version.')
|
||||
options.alias('w', 'wait').boolean('w').describe('w', 'Wait for window to be closed before returning.')
|
||||
|
||||
@@ -146,7 +146,7 @@ class DisplayBufferMarker
|
||||
@bufferMarker.setAttributes(attributes)
|
||||
|
||||
matchesAttributes: (attributes) ->
|
||||
attributes = @displayBuffer.translateToBufferMarkerAttributes(attributes)
|
||||
attributes = @displayBuffer.translateToBufferMarkerParams(attributes)
|
||||
@bufferMarker.matchesAttributes(attributes)
|
||||
|
||||
# Destroys the marker
|
||||
|
||||
+55
-27
@@ -10,6 +10,11 @@ Fold = require './fold'
|
||||
Token = require './token'
|
||||
DisplayBufferMarker = require './display-buffer-marker'
|
||||
|
||||
class BufferToScreenConversionError extends Error
|
||||
constructor: (@message, @metadata) ->
|
||||
super
|
||||
Error.captureStackTrace(this, BufferToScreenConversionError)
|
||||
|
||||
module.exports =
|
||||
class DisplayBuffer extends Model
|
||||
Serializable.includeInto(this)
|
||||
@@ -94,10 +99,11 @@ class DisplayBuffer extends Model
|
||||
#
|
||||
# editorWidthInChars - A {Number} of characters.
|
||||
setEditorWidthInChars: (editorWidthInChars) ->
|
||||
previousWidthInChars = @editorWidthInChars
|
||||
@editorWidthInChars = editorWidthInChars
|
||||
if editorWidthInChars isnt previousWidthInChars and @softWrap
|
||||
@updateWrappedScreenLines()
|
||||
if editorWidthInChars > 0
|
||||
previousWidthInChars = @editorWidthInChars
|
||||
@editorWidthInChars = editorWidthInChars
|
||||
if editorWidthInChars isnt previousWidthInChars and @softWrap
|
||||
@updateWrappedScreenLines()
|
||||
|
||||
getSoftWrapColumn: ->
|
||||
if atom.config.get('editor.softWrapAtPreferredLineLength')
|
||||
@@ -164,7 +170,7 @@ class DisplayBuffer extends Model
|
||||
# Removes any folds found that contain the given buffer row.
|
||||
#
|
||||
# bufferRow - The buffer row {Number} to check against
|
||||
destroyFoldsContainingBufferRow: (bufferRow) ->
|
||||
unfoldBufferRow: (bufferRow) ->
|
||||
fold.destroy() for fold in @foldsContainingBufferRow(bufferRow)
|
||||
|
||||
# Given a buffer row, this returns the largest fold that starts there.
|
||||
@@ -209,6 +215,13 @@ class DisplayBuffer extends Model
|
||||
largestFoldContainingBufferRow: (bufferRow) ->
|
||||
@foldsContainingBufferRow(bufferRow)[0]
|
||||
|
||||
# Returns the folds in the given row range (exclusive of end row) that are
|
||||
# not contained by any other folds.
|
||||
outermostFoldsInBufferRowRange: (startRow, endRow) ->
|
||||
@findFoldMarkers(containedInRange: [[startRow, 0], [endRow, 0]])
|
||||
.map (marker) => @foldForMarker(marker)
|
||||
.filter (fold) -> not fold.isInsideLargerFold()
|
||||
|
||||
# Public: Given a buffer row, this returns folds that include it.
|
||||
#
|
||||
#
|
||||
@@ -291,13 +304,15 @@ class DisplayBuffer extends Model
|
||||
{ row, column } = @buffer.clipPosition(bufferPosition)
|
||||
[startScreenRow, endScreenRow] = @rowMap.screenRowRangeForBufferRow(row)
|
||||
for screenRow in [startScreenRow...endScreenRow]
|
||||
unless screenLine = @screenLines[screenRow]
|
||||
throw new Error """
|
||||
No screen line exists for screen row #{screenRow}, converted from buffer position (#{row}, #{column})
|
||||
Soft wrap enabled: #{@getSoftWrap()}
|
||||
Fold count: #{@findFoldMarkers().length}
|
||||
Last buffer row: #{@getLastRow()}
|
||||
"""
|
||||
screenLine = @screenLines[screenRow]
|
||||
|
||||
unless screenLine?
|
||||
throw new BufferToScreenConversionError "No screen line exists when converting buffer row to screen row",
|
||||
softWrapEnabled: @getSoftWrap()
|
||||
foldCount: @findFoldMarkers().length
|
||||
lastBufferRow: @buffer.getLastRow()
|
||||
lastScreenRow: @getLastRow()
|
||||
|
||||
maxBufferColumn = screenLine.getMaxBufferColumn()
|
||||
if screenLine.isSoftWrapped() and column > maxBufferColumn
|
||||
continue
|
||||
@@ -511,24 +526,34 @@ class DisplayBuffer extends Model
|
||||
# Refer to {DisplayBuffer::findMarkers} for details.
|
||||
#
|
||||
# Returns a {DisplayBufferMarker} or null
|
||||
findMarker: (attributes) ->
|
||||
@findMarkers(attributes)[0]
|
||||
findMarker: (params) ->
|
||||
@findMarkers(params)[0]
|
||||
|
||||
# Finds all valid markers satisfying the given attributes
|
||||
# Public: Find all markers satisfying a set of parameters.
|
||||
#
|
||||
# attributes - The attributes against which to compare the markers' attributes
|
||||
# There are some reserved keys that match against derived marker properties:
|
||||
# startBufferRow - The buffer row at which the marker starts
|
||||
# endBufferRow - The buffer row at which the marker ends
|
||||
# params - An {Object} containing parameters that all returned markers must
|
||||
# satisfy. Unreserved keys will be compared against the markers' custom
|
||||
# properties. There are also the following reserved keys with special
|
||||
# meaning for the query:
|
||||
# :startBufferRow - A {Number}. Only returns markers starting at this row in
|
||||
# buffer coordinates.
|
||||
# :endBufferRow - A {Number}. Only returns markers ending at this row in
|
||||
# buffer coordinates.
|
||||
# :containsBufferRange - A {Range} or range-compatible {Array}. Only returns
|
||||
# markers containing this range in buffer coordinates.
|
||||
# :containsBufferPosition - A {Point} or point-compatible {Array}. Only
|
||||
# returns markers containing this position in buffer coordinates.
|
||||
# :containedInBufferRange - A {Range} or range-compatible {Array}. Only
|
||||
# returns markers contained within this range.
|
||||
#
|
||||
# Returns an {Array} of {DisplayBufferMarker}s
|
||||
findMarkers: (attributes) ->
|
||||
attributes = @translateToBufferMarkerAttributes(attributes)
|
||||
@buffer.findMarkers(attributes).map (stringMarker) => @getMarker(stringMarker.id)
|
||||
findMarkers: (params) ->
|
||||
params = @translateToBufferMarkerParams(params)
|
||||
@buffer.findMarkers(params).map (stringMarker) => @getMarker(stringMarker.id)
|
||||
|
||||
translateToBufferMarkerAttributes: (attributes) ->
|
||||
stringMarkerAttributes = {}
|
||||
for key, value of attributes
|
||||
translateToBufferMarkerParams: (params) ->
|
||||
bufferMarkerParams = {}
|
||||
for key, value of params
|
||||
switch key
|
||||
when 'startBufferRow'
|
||||
key = 'startRow'
|
||||
@@ -538,8 +563,10 @@ class DisplayBuffer extends Model
|
||||
key = 'containsRange'
|
||||
when 'containsBufferPosition'
|
||||
key = 'containsPosition'
|
||||
stringMarkerAttributes[key] = value
|
||||
stringMarkerAttributes
|
||||
when 'containedInBufferRange'
|
||||
key = 'containedInRange'
|
||||
bufferMarkerParams[key] = value
|
||||
bufferMarkerParams
|
||||
|
||||
findFoldMarker: (attributes) ->
|
||||
@findFoldMarkers(attributes)[0]
|
||||
@@ -577,6 +604,7 @@ class DisplayBuffer extends Model
|
||||
|
||||
updateScreenLines: (startBufferRow, endBufferRow, bufferDelta=0, options={}) ->
|
||||
startBufferRow = @rowMap.bufferRowRangeForBufferRow(startBufferRow)[0]
|
||||
endBufferRow = @rowMap.bufferRowRangeForBufferRow(endBufferRow - 1)[1]
|
||||
startScreenRow = @rowMap.screenRowRangeForBufferRow(startBufferRow)[0]
|
||||
endScreenRow = @rowMap.screenRowRangeForBufferRow(endBufferRow - 1)[1]
|
||||
|
||||
|
||||
+89
-29
@@ -20,14 +20,31 @@ LongLineLength = 1000
|
||||
# ## Requiring in packages
|
||||
#
|
||||
# ```coffee
|
||||
# {EditorView} = require 'atom'
|
||||
# {EditorView} = require 'atom'
|
||||
#
|
||||
# miniEditorView = new EditorView(mini: true)
|
||||
# ```
|
||||
#
|
||||
# ## Iterating over the open editor views
|
||||
#
|
||||
# ```coffee
|
||||
# for editorView in atom.workspace.getEditorViews()
|
||||
# console.log(editorView.getEditor().getPath())
|
||||
# ```
|
||||
#
|
||||
# ## Subscribing to every current and future editor
|
||||
#
|
||||
# ```coffee
|
||||
# atom.workspace.eachEditorView (editorView) ->
|
||||
# console.log(editorView.getEditor().getPath())
|
||||
# ```
|
||||
module.exports =
|
||||
class EditorView extends View
|
||||
@characterWidthCache: {}
|
||||
@configDefaults:
|
||||
fontFamily: ''
|
||||
fontSize: 20
|
||||
fontSize: 16
|
||||
lineHeight: 1.3
|
||||
showInvisibles: false
|
||||
showIndentGuide: false
|
||||
showLineNumbers: true
|
||||
@@ -193,7 +210,7 @@ class EditorView extends View
|
||||
'editor:unfold-all': => @editor.unfoldAll()
|
||||
'editor:fold-current-row': => @editor.foldCurrentRow()
|
||||
'editor:unfold-current-row': => @editor.unfoldCurrentRow()
|
||||
'editor:fold-selection': => @editor.foldSelection()
|
||||
'editor:fold-selection': => @editor.foldSelectedLines()
|
||||
'editor:fold-at-indent-level-1': => @editor.foldAllAtIndentLevel(0)
|
||||
'editor:fold-at-indent-level-2': => @editor.foldAllAtIndentLevel(1)
|
||||
'editor:fold-at-indent-level-3': => @editor.foldAllAtIndentLevel(2)
|
||||
@@ -209,8 +226,8 @@ class EditorView extends View
|
||||
'editor:copy-path': => @copyPathToClipboard()
|
||||
'editor:move-line-up': => @editor.moveLineUp()
|
||||
'editor:move-line-down': => @editor.moveLineDown()
|
||||
'editor:duplicate-line': => @editor.duplicateLine()
|
||||
'editor:join-line': => @editor.joinLine()
|
||||
'editor:duplicate-lines': => @editor.duplicateLines()
|
||||
'editor:join-lines': => @editor.joinLines()
|
||||
'editor:toggle-indent-guide': => atom.config.toggle('editor.showIndentGuide')
|
||||
'editor:toggle-line-numbers': => atom.config.toggle('editor.showLineNumbers')
|
||||
'editor:scroll-to-cursor': => @scrollToCursorPosition()
|
||||
@@ -324,6 +341,8 @@ class EditorView extends View
|
||||
@subscribe atom.config.observe 'editor.invisibles', (invisibles) => @setInvisibles(invisibles)
|
||||
@subscribe atom.config.observe 'editor.fontSize', (fontSize) => @setFontSize(fontSize)
|
||||
@subscribe atom.config.observe 'editor.fontFamily', (fontFamily) => @setFontFamily(fontFamily)
|
||||
@subscribe atom.config.observe 'editor.lineHeight', (lineHeight) => @setLineHeight(lineHeight)
|
||||
|
||||
|
||||
handleEvents: ->
|
||||
@on 'focus', =>
|
||||
@@ -403,6 +422,8 @@ class EditorView extends View
|
||||
@scrollView.on 'overflowchanged', =>
|
||||
updateWidthInChars() if @[0].classList.contains('soft-wrap')
|
||||
|
||||
@subscribe atom.themes, 'stylesheets-changed', => @recalculateDimensions()
|
||||
|
||||
handleInputEvents: ->
|
||||
@on 'cursor:moved', =>
|
||||
return unless @isFocused
|
||||
@@ -445,20 +466,29 @@ class EditorView extends View
|
||||
|
||||
selectOnMousemoveUntilMouseup: ->
|
||||
lastMoveEvent = null
|
||||
|
||||
finalizeSelections = =>
|
||||
clearInterval(interval)
|
||||
$(document).off 'mousemove', moveHandler
|
||||
$(document).off 'mouseup', finalizeSelections
|
||||
|
||||
unless @editor.isDestroyed()
|
||||
@editor.mergeIntersectingSelections(isReversed: @editor.getLastSelection().isReversed())
|
||||
@editor.finalizeSelections()
|
||||
@syncCursorAnimations()
|
||||
|
||||
moveHandler = (event = lastMoveEvent) =>
|
||||
if event
|
||||
return unless event?
|
||||
|
||||
if event.which is 1 and @[0].style.display isnt 'none'
|
||||
@editor.selectToScreenPosition(@screenPositionFromMouseEvent(event))
|
||||
lastMoveEvent = event
|
||||
else
|
||||
finalizeSelections()
|
||||
|
||||
$(document).on "mousemove.editor-#{@id}", moveHandler
|
||||
interval = setInterval(moveHandler, 20)
|
||||
|
||||
$(document).one "mouseup.editor-#{@id}", =>
|
||||
clearInterval(interval)
|
||||
$(document).off 'mousemove', moveHandler
|
||||
@editor.mergeIntersectingSelections(isReversed: @editor.getLastSelection().isReversed())
|
||||
@editor.finalizeSelections()
|
||||
@syncCursorAnimations()
|
||||
$(document).one "mouseup.editor-#{@id}", finalizeSelections
|
||||
|
||||
afterAttach: (onDom) ->
|
||||
return unless onDom
|
||||
@@ -667,11 +697,15 @@ class EditorView extends View
|
||||
@editor.setSoftWrap(not @editor.getSoftWrap())
|
||||
|
||||
calculateWidthInChars: ->
|
||||
Math.floor(@scrollView.width() / @charWidth)
|
||||
Math.floor((@scrollView.width() - @getScrollbarWidth()) / @charWidth)
|
||||
|
||||
calculateHeightInLines: ->
|
||||
Math.ceil($(window).height() / @lineHeight)
|
||||
|
||||
getScrollbarWidth: ->
|
||||
scrollbarElement = @verticalScrollbar[0]
|
||||
scrollbarElement.offsetWidth - scrollbarElement.clientWidth
|
||||
|
||||
# Public: Enables/disables soft wrap on the editor.
|
||||
#
|
||||
# softWrap - A {Boolean} which, if `true`, enables soft wrap
|
||||
@@ -716,6 +750,17 @@ class EditorView extends View
|
||||
# Returns a {String} identifying the CSS `font-family`.
|
||||
getFontFamily: -> @css("font-family")
|
||||
|
||||
# Public: Sets the line height of the editor.
|
||||
#
|
||||
# Calling this method has no effect when called on a mini editor.
|
||||
#
|
||||
# lineHeight - A {Number} without a unit suffix identifying the CSS
|
||||
# `line-height`.
|
||||
setLineHeight: (lineHeight) ->
|
||||
return if @mini
|
||||
@css('line-height', lineHeight)
|
||||
@redraw()
|
||||
|
||||
# Public: Redraw the editor
|
||||
redraw: ->
|
||||
return unless @hasParent()
|
||||
@@ -853,7 +898,19 @@ class EditorView extends View
|
||||
fragment.remove()
|
||||
@setHeightInLines()
|
||||
|
||||
updateLayerDimensions: ->
|
||||
recalculateDimensions: ->
|
||||
return unless @attached and @isVisible()
|
||||
|
||||
oldCharWidth = @charWidth
|
||||
oldLineHeight = @lineHeight
|
||||
|
||||
@calculateDimensions()
|
||||
|
||||
unless @charWidth is oldCharWidth and @lineHeight is oldLineHeight
|
||||
@clearCharacterWidthCache()
|
||||
@requestDisplayUpdate()
|
||||
|
||||
updateLayerDimensions: (scrollViewWidth) ->
|
||||
height = @lineHeight * @editor.getScreenLineCount()
|
||||
unless @layerHeight == height
|
||||
@layerHeight = height
|
||||
@@ -863,7 +920,7 @@ class EditorView extends View
|
||||
@verticalScrollbarContent.height(@layerHeight)
|
||||
@scrollBottom(height) if @scrollBottom() > height
|
||||
|
||||
minWidth = Math.max(@charWidth * @editor.getMaxScreenLineLength() + 20, @scrollView.width())
|
||||
minWidth = Math.max(@charWidth * @editor.getMaxScreenLineLength() + 20, scrollViewWidth)
|
||||
unless @layerMinWidth == minWidth
|
||||
@renderedLines.css('min-width', minWidth)
|
||||
@underlayer.css('min-width', minWidth)
|
||||
@@ -897,7 +954,7 @@ class EditorView extends View
|
||||
@setSoftWrap(@editor.getSoftWrap())
|
||||
@newCursors = @editor.getCursors()
|
||||
@newSelections = @editor.getSelections()
|
||||
@updateDisplay(suppressAutoScroll: true)
|
||||
@updateDisplay(suppressAutoscroll: true)
|
||||
|
||||
requestDisplayUpdate: ->
|
||||
return if @pendingDisplayUpdate
|
||||
@@ -907,19 +964,20 @@ class EditorView extends View
|
||||
@updateDisplay()
|
||||
@pendingDisplayUpdate = false
|
||||
|
||||
updateDisplay: (options={}) ->
|
||||
updateDisplay: (options) ->
|
||||
return unless @attached and @editor
|
||||
return if @editor.isDestroyed()
|
||||
unless @isOnDom() and @isVisible()
|
||||
@redrawOnReattach = true
|
||||
return
|
||||
|
||||
@updateRenderedLines()
|
||||
scrollViewWidth = @scrollView.width()
|
||||
@updateRenderedLines(scrollViewWidth)
|
||||
@updatePlaceholderText()
|
||||
@highlightCursorLine()
|
||||
@updateCursorViews()
|
||||
@updateSelectionViews()
|
||||
@autoscroll(options)
|
||||
@autoscroll(options?.suppressAutoscroll ? false)
|
||||
@trigger 'editor:display-updated'
|
||||
|
||||
updateCursorViews: ->
|
||||
@@ -960,17 +1018,16 @@ class EditorView extends View
|
||||
(startRow <= @firstRenderedScreenRow and endRow >= @lastRenderedScreenRow) # selection surrounds the rendered items
|
||||
|
||||
syncCursorAnimations: ->
|
||||
for cursorView in @getCursorViews()
|
||||
do (cursorView) -> cursorView.resetBlinking()
|
||||
cursorView.resetBlinking() for cursorView in @getCursorViews()
|
||||
|
||||
autoscroll: (options={}) ->
|
||||
autoscroll: (suppressAutoscroll) ->
|
||||
for cursorView in @getCursorViews()
|
||||
if !options.suppressAutoScroll and cursorView.needsAutoscroll()
|
||||
if !suppressAutoscroll and cursorView.needsAutoscroll()
|
||||
@scrollToPixelPosition(cursorView.getPixelPosition())
|
||||
cursorView.clearAutoscroll()
|
||||
|
||||
for selectionView in @getSelectionViews()
|
||||
if !options.suppressAutoScroll and selectionView.needsAutoscroll()
|
||||
if !suppressAutoscroll and selectionView.needsAutoscroll()
|
||||
@scrollToPixelPosition(selectionView.getCenterPixelPosition(), center: true)
|
||||
selectionView.highlight()
|
||||
selectionView.clearAutoscroll()
|
||||
@@ -986,7 +1043,7 @@ class EditorView extends View
|
||||
else
|
||||
@underlayer.append($('<span/>', class: 'placeholder-text', text: @placeholderText))
|
||||
|
||||
updateRenderedLines: ->
|
||||
updateRenderedLines: (scrollViewWidth) ->
|
||||
firstVisibleScreenRow = @getFirstVisibleScreenRow()
|
||||
lastScreenRowToRender = firstVisibleScreenRow + @heightInLines - 1
|
||||
lastScreenRow = @editor.getLastScreenRow()
|
||||
@@ -1010,7 +1067,7 @@ class EditorView extends View
|
||||
@fillDirtyRanges(intactRanges, renderFrom, renderTo)
|
||||
@firstRenderedScreenRow = renderFrom
|
||||
@lastRenderedScreenRow = renderTo
|
||||
@updateLayerDimensions()
|
||||
@updateLayerDimensions(scrollViewWidth)
|
||||
@updatePaddingOfRenderedLines()
|
||||
|
||||
computeSurroundingEmptyLineChanges: (change) ->
|
||||
@@ -1281,14 +1338,17 @@ class EditorView extends View
|
||||
return 0 if screenColumn == 0
|
||||
|
||||
tokenizedLine = @editor.displayBuffer.lineForRow(screenRow)
|
||||
textContent = lineElement.textContent
|
||||
|
||||
left = 0
|
||||
index = 0
|
||||
for token in tokenizedLine.tokens
|
||||
for char in token.value
|
||||
for bufferChar in token.value
|
||||
return left if index >= screenColumn
|
||||
|
||||
val = @getCharacterWidthCache(token.scopes, char)
|
||||
# Invisibles might cause renderedChar to be different than bufferChar
|
||||
renderedChar = textContent[index]
|
||||
val = @getCharacterWidthCache(token.scopes, renderedChar)
|
||||
if val?
|
||||
left += val
|
||||
else
|
||||
|
||||
+732
-331
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -41,6 +41,10 @@ class Fold
|
||||
range.end.column = 0
|
||||
range
|
||||
|
||||
getBufferRowRange: ->
|
||||
{start, end} = @getBufferRange()
|
||||
[start.row, end.row]
|
||||
|
||||
# Returns the fold's start row as a {Number}.
|
||||
getStartRow: ->
|
||||
@getBufferRange().start.row
|
||||
|
||||
+108
-24
@@ -1,15 +1,30 @@
|
||||
{join, sep} = require 'path'
|
||||
|
||||
_ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
Task = require './task'
|
||||
{Emitter, Subscriber} = require 'emissary'
|
||||
fs = require 'fs-plus'
|
||||
GitUtils = require 'git-utils'
|
||||
|
||||
Task = require './task'
|
||||
|
||||
# Public: Represents the underlying git operations performed by Atom.
|
||||
#
|
||||
# This class shouldn't be instantiated directly but instead by accessing the
|
||||
# `atom.project` global and calling `getRepo()`. Note that this will only be
|
||||
# available when the project is backed by a Git repository.
|
||||
#
|
||||
# This class handles submodules automically by taking a `path` argument to many
|
||||
# of the methods. This `path` argument will determine which underlying
|
||||
# repository is used.
|
||||
#
|
||||
# For a repository with submodules this would have the following outcome:
|
||||
#
|
||||
# ```coffee
|
||||
# repo = atom.project.getRepo()
|
||||
# repo.getShortHead() # 'master'
|
||||
# repo.getShortHead('vendor/path/to/a/submodule') # 'dead1234'
|
||||
# ```
|
||||
#
|
||||
# ## Example
|
||||
#
|
||||
# ```coffeescript
|
||||
@@ -89,10 +104,11 @@ class Git
|
||||
@unsubscribe()
|
||||
|
||||
# Returns the corresponding {Repository}
|
||||
getRepo: ->
|
||||
unless @repo?
|
||||
getRepo: (path) ->
|
||||
if @repo?
|
||||
@repo.submoduleForPath(path) ? @repo
|
||||
else
|
||||
throw new Error("Repository has been destroyed")
|
||||
@repo
|
||||
|
||||
# Reread the index to update any values that have changed since the
|
||||
# last time the index was read.
|
||||
@@ -112,12 +128,14 @@ class Git
|
||||
# Returns a {Number} representing the status. This value can be passed to
|
||||
# {::isStatusModified} or {::isStatusNew} to get more information.
|
||||
getPathStatus: (path) ->
|
||||
currentPathStatus = @statuses[path] ? 0
|
||||
pathStatus = @getRepo().getStatus(@relativize(path)) ? 0
|
||||
repo = @getRepo(path)
|
||||
relativePath = @relativize(path)
|
||||
currentPathStatus = @statuses[relativePath] ? 0
|
||||
pathStatus = repo.getStatus(repo.relativize(path)) ? 0
|
||||
if pathStatus > 0
|
||||
@statuses[path] = pathStatus
|
||||
@statuses[relativePath] = pathStatus
|
||||
else
|
||||
delete @statuses[path]
|
||||
delete @statuses[relativePath]
|
||||
if currentPathStatus isnt pathStatus
|
||||
@emit 'status-changed', path, pathStatus
|
||||
pathStatus
|
||||
@@ -153,8 +171,11 @@ class Git
|
||||
# `refs/remotes`. It also shortens the SHA-1 of a detached `HEAD` to 7
|
||||
# characters.
|
||||
#
|
||||
# path - An optional {String} path in the repository to get this information
|
||||
# for, only needed if the repository contains submodules.
|
||||
#
|
||||
# Returns a {String}.
|
||||
getShortHead: -> @getRepo().getShortHead()
|
||||
getShortHead: (path) -> @getRepo(path).getShortHead()
|
||||
|
||||
# Public: Restore the contents of a path in the working directory and index
|
||||
# to the version at `HEAD`.
|
||||
@@ -170,7 +191,8 @@ class Git
|
||||
#
|
||||
# Returns a {Boolean} that's true if the method was successful.
|
||||
checkoutHead: (path) ->
|
||||
headCheckedOut = @getRepo().checkoutHead(@relativize(path))
|
||||
repo = @getRepo(path)
|
||||
headCheckedOut = repo.checkoutHead(repo.relativize(path))
|
||||
@getPathStatus(path) if headCheckedOut
|
||||
headCheckedOut
|
||||
|
||||
@@ -194,14 +216,24 @@ class Git
|
||||
# Returns an {Object} with the following keys:
|
||||
# :added - The {Number} of added lines.
|
||||
# :deleted - The {Number} of deleted lines.
|
||||
getDiffStats: (path) -> @getRepo().getDiffStats(@relativize(path))
|
||||
getDiffStats: (path) ->
|
||||
repo = @getRepo(path)
|
||||
repo.getDiffStats(repo.relativize(path))
|
||||
|
||||
# Public: Is the given path a submodule in the repository?
|
||||
#
|
||||
# path - The {String} path to check.
|
||||
#
|
||||
# Returns a {Boolean}.
|
||||
isSubmodule: (path) -> @getRepo().isSubmodule(@relativize(path))
|
||||
isSubmodule: (path) ->
|
||||
return false unless path
|
||||
|
||||
repo = @getRepo(path)
|
||||
if repo.isSubmodule(repo.relativize(path))
|
||||
true
|
||||
else
|
||||
# Check if the path is a working directory in a repo that isn't the root.
|
||||
repo isnt @getRepo() and repo.relativize(join(path, 'dir')) is 'dir'
|
||||
|
||||
# Public: Get the status of a directory in the repository's working directory.
|
||||
#
|
||||
@@ -210,8 +242,7 @@ class Git
|
||||
# Returns a {Number} representing the status. This value can be passed to
|
||||
# {::isStatusModified} or {::isStatusNew} to get more information.
|
||||
getDirectoryStatus: (directoryPath) ->
|
||||
{sep} = require 'path'
|
||||
directoryPath = "#{directoryPath}#{sep}"
|
||||
directoryPath = "#{@relativize(directoryPath)}#{sep}"
|
||||
directoryStatus = 0
|
||||
for path, status of @statuses
|
||||
directoryStatus |= status if path.indexOf(directoryPath) is 0
|
||||
@@ -232,34 +263,77 @@ class Git
|
||||
# Ignore eol of line differences on windows so that files checked in as
|
||||
# LF don't report every line modified when the text contains CRLF endings.
|
||||
options = ignoreEolWhitespace: process.platform is 'win32'
|
||||
@getRepo().getLineDiffs(@relativize(path), text, options)
|
||||
repo = @getRepo(path)
|
||||
repo.getLineDiffs(repo.relativize(path), text, options)
|
||||
|
||||
# Public: Returns the git configuration value specified by the key.
|
||||
getConfigValue: (key) -> @getRepo().getConfigValue(key)
|
||||
#
|
||||
# path - An optional {String} path in the repository to get this information
|
||||
# for, only needed if the repository has submodules.
|
||||
getConfigValue: (key, path) -> @getRepo(path).getConfigValue(key)
|
||||
|
||||
# Public: Returns the origin url of the repository.
|
||||
getOriginUrl: -> @getConfigValue('remote.origin.url')
|
||||
#
|
||||
# path - An optional {String} path in the repository to get this information
|
||||
# for, only needed if the repository has submodules.
|
||||
getOriginUrl: (path) -> @getConfigValue('remote.origin.url', path)
|
||||
|
||||
# Public: Returns the upstream branch for the current HEAD, or null if there
|
||||
# is no upstream branch for the current HEAD.
|
||||
#
|
||||
# path - An optional {String} path in the repo to get this information for,
|
||||
# only needed if the repository contains submodules.
|
||||
#
|
||||
# Returns a {String} branch name such as `refs/remotes/origin/master`.
|
||||
getUpstreamBranch: -> @getRepo().getUpstreamBranch()
|
||||
getUpstreamBranch: (path) -> @getRepo(path).getUpstreamBranch()
|
||||
|
||||
# Public: Returns the current SHA for the given reference.
|
||||
getReferenceTarget: (reference) -> @getRepo().getReferenceTarget(reference)
|
||||
#
|
||||
# reference - The {String} reference to get the target of.
|
||||
# path - An optional {String} path in the repo to get the reference target
|
||||
# for. Only needed if the repository contains submodules.
|
||||
getReferenceTarget: (reference, path) ->
|
||||
@getRepo(path).getReferenceTarget(reference)
|
||||
|
||||
# Public: Gets all the local and remote references.
|
||||
#
|
||||
# path - An optional {String} path in the repository to get this information
|
||||
# for, only needed if the repository has submodules.
|
||||
#
|
||||
# Returns an {Object} with the following keys:
|
||||
# :heads - An {Array} of head reference names.
|
||||
# :remotes - An {Array} of remote reference names.
|
||||
# :tags - An {Array} of tag reference names.
|
||||
getReferences: -> @getRepo().getReferences()
|
||||
getReferences: (path) -> @getRepo(path).getReferences()
|
||||
|
||||
# Public: Returns the number of commits behind the current branch is from the
|
||||
# its upstream remote branch.
|
||||
getAheadBehindCount: (reference) -> @getRepo().getAheadBehindCount(reference)
|
||||
#
|
||||
# reference - The {String} branch reference name.
|
||||
# path - The {String} path in the repository to get this information for,
|
||||
# only needed if the repository contains submodules.
|
||||
getAheadBehindCount: (reference, path) ->
|
||||
@getRepo(path).getAheadBehindCount(reference)
|
||||
|
||||
# Public: Get the cached ahead/behind commit counts for the current branch's
|
||||
# upstream branch.
|
||||
#
|
||||
# path - An optional {String} path in the repository to get this information
|
||||
# for, only needed if the repository has submodules.
|
||||
#
|
||||
# Returns an {Object} with the following keys:
|
||||
# :ahead - The {Number} of commits ahead.
|
||||
# :behind - The {Number} of commits behind.
|
||||
getCachedUpstreamAheadBehindCount: (path) ->
|
||||
@getRepo(path).upstream ? @upstream
|
||||
|
||||
# Public: Get the cached status for the given path.
|
||||
#
|
||||
# path - A {String} path in the repository, relative or absolute.
|
||||
#
|
||||
# Returns a status {Number} or null if the path is not in the cache.
|
||||
getCachedPathStatus: (path) ->
|
||||
@statuses[@relativize(path)]
|
||||
|
||||
# Public: Returns true if the given branch exists.
|
||||
hasBranch: (branch) -> @getReferenceTarget("refs/heads/#{branch}")?
|
||||
@@ -267,9 +341,19 @@ class Git
|
||||
# Refreshes the current git status in an outside process and asynchronously
|
||||
# updates the relevant properties.
|
||||
refreshStatus: ->
|
||||
@statusTask = Task.once require.resolve('./repository-status-handler'), @getPath(), ({statuses, upstream, branch}) =>
|
||||
statusesUnchanged = _.isEqual(statuses, @statuses) and _.isEqual(upstream, @upstream) and _.isEqual(branch, @branch)
|
||||
handlerPath = require.resolve('./repository-status-handler')
|
||||
@statusTask = Task.once handlerPath, @getPath(), ({statuses, upstream, branch, submodules}) =>
|
||||
statusesUnchanged = _.isEqual(statuses, @statuses) and
|
||||
_.isEqual(upstream, @upstream) and
|
||||
_.isEqual(branch, @branch) and
|
||||
_.isEqual(submodules, @submodules)
|
||||
|
||||
@statuses = statuses
|
||||
@upstream = upstream
|
||||
@branch = branch
|
||||
@submodules = submodules
|
||||
|
||||
for submodulePath, submoduleRepo of @getRepo().submodules
|
||||
submoduleRepo.upstream = submodules[submodulePath].upstream
|
||||
|
||||
@emit 'statuses-changed' unless statusesUnchanged
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
_ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
{specificity} = require 'clear-cut'
|
||||
|
||||
module.exports =
|
||||
class KeyBinding
|
||||
@parser: null
|
||||
@currentIndex: 1
|
||||
@specificities: null
|
||||
|
||||
@calculateSpecificity: (selector) ->
|
||||
@specificities ?= {}
|
||||
value = @specificities[selector]
|
||||
unless value?
|
||||
value = specificity(selector)
|
||||
@specificities[selector] = value
|
||||
value
|
||||
|
||||
@normalizeKeystroke: (keystroke) ->
|
||||
normalizedKeystroke = keystroke.split(/\s+/).map (keystroke) =>
|
||||
keys = @parseKeystroke(keystroke)
|
||||
modifiers = keys[0...-1]
|
||||
modifiers.sort()
|
||||
[modifiers..., _.last(keys)].join('-')
|
||||
normalizedKeystroke.join(' ')
|
||||
|
||||
@parseKeystroke: (keystroke) ->
|
||||
unless @parser?
|
||||
try
|
||||
@parser = require './keystroke-pattern'
|
||||
catch
|
||||
keystrokePattern = fs.readFileSync(require.resolve('./keystroke-pattern.pegjs'), 'utf8')
|
||||
PEG = require 'pegjs'
|
||||
@parser = PEG.buildParser(keystrokePattern)
|
||||
|
||||
@parser.parse(keystroke)
|
||||
|
||||
constructor: (source, command, keystroke, selector) ->
|
||||
@source = source
|
||||
@command = command
|
||||
@keystroke = KeyBinding.normalizeKeystroke(keystroke)
|
||||
@selector = selector.replace(/!important/g, '')
|
||||
@specificity = KeyBinding.calculateSpecificity(selector)
|
||||
@index = KeyBinding.currentIndex++
|
||||
|
||||
matches: (keystroke) ->
|
||||
multiKeystroke = /\s/.test keystroke
|
||||
if multiKeystroke
|
||||
keystroke == @keystroke
|
||||
else
|
||||
keystroke.split(' ')[0] == @keystroke.split(' ')[0]
|
||||
|
||||
compare: (keyBinding) ->
|
||||
if keyBinding.specificity == @specificity
|
||||
keyBinding.index - @index
|
||||
else
|
||||
keyBinding.specificity - @specificity
|
||||
@@ -0,0 +1,27 @@
|
||||
fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
KeymapManager = require 'atom-keymap'
|
||||
CSON = require 'season'
|
||||
{jQuery} = require 'space-pen'
|
||||
|
||||
KeymapManager::loadBundledKeymaps = ->
|
||||
@loadKeymap(path.join(@resourcePath, 'keymaps'))
|
||||
@emit('bundled-keymaps-loaded')
|
||||
|
||||
KeymapManager::getUserKeymapPath = ->
|
||||
if userKeymapPath = CSON.resolve(path.join(@configDirPath, 'keymap'))
|
||||
userKeymapPath
|
||||
else
|
||||
path.join(@configDirPath, 'keymap.cson')
|
||||
|
||||
KeymapManager::loadUserKeymap = ->
|
||||
userKeymapPath = @getUserKeymapPath()
|
||||
if fs.isFileSync(userKeymapPath)
|
||||
@loadKeymap(userKeymapPath, watch: true, suppressErrors: true)
|
||||
|
||||
# This enables command handlers registered via jQuery to call
|
||||
# `.abortKeyBinding()` on the `jQuery.Event` object passed to the handler.
|
||||
jQuery.Event::abortKeyBinding = ->
|
||||
@originalEvent?.abortKeyBinding?()
|
||||
|
||||
module.exports = KeymapManager
|
||||
@@ -1,221 +0,0 @@
|
||||
{$} = require './space-pen-extensions'
|
||||
_ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
CSON = require 'season'
|
||||
KeyBinding = require './key-binding'
|
||||
{File} = require 'pathwatcher'
|
||||
{Emitter} = require 'emissary'
|
||||
|
||||
Modifiers = ['alt', 'control', 'ctrl', 'shift', 'cmd']
|
||||
|
||||
# Public: Associates keybindings with commands.
|
||||
#
|
||||
# An instance of this class is always available as the `atom.keymap` global.
|
||||
#
|
||||
# Keymaps are defined in a CSON/JSON format. A typical keymap looks something
|
||||
# like this:
|
||||
#
|
||||
# ```cson
|
||||
# 'body':
|
||||
# 'ctrl-l': 'package:do-something'
|
||||
# '.someClass':
|
||||
# 'enter': 'package:confirm'
|
||||
# ```
|
||||
#
|
||||
# As a key, you define the DOM element you want to work on, using CSS notation.
|
||||
# For that key, you define one or more key:value pairs, associating keystrokes
|
||||
# with a command to execute.
|
||||
module.exports =
|
||||
class Keymap
|
||||
Emitter.includeInto(this)
|
||||
|
||||
constructor: ({@resourcePath, @configDirPath})->
|
||||
@keyBindings = []
|
||||
|
||||
destroy: ->
|
||||
@unwatchUserKeymap()
|
||||
|
||||
# Public: Returns an array of all {KeyBinding}s.
|
||||
getKeyBindings: ->
|
||||
_.clone(@keyBindings)
|
||||
|
||||
# Public: Returns a array of {KeyBinding}s (sorted by selector specificity)
|
||||
# that match a keystroke and element.
|
||||
#
|
||||
# keystroke - The {String} representing the keys pressed (e.g. ctrl-P).
|
||||
# element - The DOM node that will match a {KeyBinding}'s selector.
|
||||
keyBindingsForKeystrokeMatchingElement: (keystroke, element) ->
|
||||
keyBindings = @keyBindingsForKeystroke(keystroke)
|
||||
@keyBindingsMatchingElement(element, keyBindings)
|
||||
|
||||
# Public: Returns a array of {KeyBinding}s (sorted by selector specificity)
|
||||
# that match a command.
|
||||
#
|
||||
# command - The {String} representing the command (tree-view:toggle).
|
||||
# element - The DOM node that will match a {KeyBinding}'s selector.
|
||||
keyBindingsForCommandMatchingElement: (command, element) ->
|
||||
keyBindings = @keyBindingsForCommand(command)
|
||||
@keyBindingsMatchingElement(element, keyBindings)
|
||||
|
||||
# Public: Returns an array of {KeyBinding}s that match a keystroke
|
||||
#
|
||||
# keystroke: The {String} representing the keys pressed (e.g. ctrl-P)
|
||||
keyBindingsForKeystroke: (keystroke) ->
|
||||
keystroke = KeyBinding.normalizeKeystroke(keystroke)
|
||||
@keyBindings.filter (keyBinding) -> keyBinding.matches(keystroke)
|
||||
|
||||
# Public: Returns an array of {KeyBinding}s that match a command
|
||||
#
|
||||
# keystroke - The {String} representing the keys pressed (e.g. ctrl-P)
|
||||
keyBindingsForCommand: (command) ->
|
||||
@keyBindings.filter (keyBinding) -> keyBinding.command == command
|
||||
|
||||
# Public: Returns a array of {KeyBinding}s (sorted by selector specificity)
|
||||
# whos selector matches the element.
|
||||
#
|
||||
# element - The DOM node that will match a {KeyBinding}'s selector.
|
||||
keyBindingsMatchingElement: (element, keyBindings=@keyBindings) ->
|
||||
keyBindings = keyBindings.filter ({selector}) -> $(element).closest(selector).length > 0
|
||||
keyBindings.sort (a, b) -> a.compare(b)
|
||||
|
||||
# Public: Returns a keystroke string derived from an event.
|
||||
#
|
||||
# event - A DOM or jQuery event.
|
||||
# previousKeystroke - An optional string used for multiKeystrokes.
|
||||
keystrokeStringForEvent: (event, previousKeystroke) ->
|
||||
if event.originalEvent.keyIdentifier.indexOf('U+') == 0
|
||||
hexCharCode = event.originalEvent.keyIdentifier[2..]
|
||||
charCode = parseInt(hexCharCode, 16)
|
||||
charCode = event.which if !@isAscii(charCode) and @isAscii(event.which)
|
||||
key = @keyFromCharCode(charCode)
|
||||
else
|
||||
key = event.originalEvent.keyIdentifier.toLowerCase()
|
||||
|
||||
modifiers = []
|
||||
if event.altKey and key not in Modifiers
|
||||
modifiers.push 'alt'
|
||||
if event.metaKey and key not in Modifiers
|
||||
modifiers.push 'cmd'
|
||||
if event.ctrlKey and key not in Modifiers
|
||||
modifiers.push 'ctrl'
|
||||
|
||||
if event.shiftKey and key not in Modifiers
|
||||
isNamedKey = key.length > 1
|
||||
modifiers.push 'shift' if isNamedKey
|
||||
else
|
||||
key = key.toLowerCase()
|
||||
|
||||
keystroke = [modifiers..., key].join('-')
|
||||
|
||||
if previousKeystroke
|
||||
if keystroke in Modifiers
|
||||
previousKeystroke
|
||||
else
|
||||
"#{previousKeystroke} #{keystroke}"
|
||||
else
|
||||
keystroke
|
||||
|
||||
loadBundledKeymaps: ->
|
||||
@loadDirectory(path.join(@resourcePath, 'keymaps'))
|
||||
@emit('bundled-keymaps-loaded')
|
||||
|
||||
getUserKeymapPath: ->
|
||||
if userKeymapPath = CSON.resolve(path.join(@configDirPath, 'keymap'))
|
||||
userKeymapPath
|
||||
else
|
||||
path.join(@configDirPath, 'keymap.cson')
|
||||
|
||||
unwatchUserKeymap: ->
|
||||
@userKeymapFile?.off()
|
||||
@remove(@userKeymapPath) if @userKeymapPath?
|
||||
|
||||
loadUserKeymap: ->
|
||||
@unwatchUserKeymap()
|
||||
userKeymapPath = @getUserKeymapPath()
|
||||
if fs.isFileSync(userKeymapPath)
|
||||
@userKeymapPath = userKeymapPath
|
||||
@userKeymapFile = new File(userKeymapPath)
|
||||
@userKeymapFile.on 'contents-changed moved removed', => @loadUserKeymap()
|
||||
@add(@userKeymapPath, @readUserKeymap())
|
||||
|
||||
readUserKeymap: ->
|
||||
try
|
||||
CSON.readFileSync(@userKeymapPath) ? {}
|
||||
catch error
|
||||
console.warn("Failed to load your keymap file: #{@userKeymapPath}", error.stack ? error)
|
||||
{}
|
||||
|
||||
loadDirectory: (directoryPath) ->
|
||||
platforms = ['darwin', 'freebsd', 'linux', 'sunos', 'win32']
|
||||
otherPlatforms = platforms.filter (name) -> name != process.platform
|
||||
|
||||
for filePath in fs.listSync(directoryPath, ['.cson', '.json'])
|
||||
continue if path.basename(filePath, path.extname(filePath)) in otherPlatforms
|
||||
@load(filePath)
|
||||
|
||||
load: (path) ->
|
||||
@add(path, CSON.readFileSync(path))
|
||||
|
||||
add: (source, keyMappingsBySelector) ->
|
||||
for selector, keyMappings of keyMappingsBySelector
|
||||
@bindKeys(source, selector, keyMappings)
|
||||
|
||||
remove: (source) ->
|
||||
@keyBindings = @keyBindings.filter (keyBinding) -> keyBinding.source isnt source
|
||||
|
||||
bindKeys: (source, selector, keyMappings) ->
|
||||
for keystroke, command of keyMappings
|
||||
keyBinding = new KeyBinding(source, command, keystroke, selector)
|
||||
try
|
||||
$(keyBinding.selector) # Verify selector is valid before registering
|
||||
@keyBindings.push(keyBinding)
|
||||
catch
|
||||
console.warn("Keybinding '#{keystroke}': '#{command}' in #{source} has an invalid selector: '#{selector}'")
|
||||
|
||||
handleKeyEvent: (event) ->
|
||||
element = event.target
|
||||
element = atom.workspaceView if element == document.body
|
||||
keystroke = @keystrokeStringForEvent(event, @queuedKeystroke)
|
||||
keyBindings = @keyBindingsForKeystrokeMatchingElement(keystroke, element)
|
||||
|
||||
if keyBindings.length == 0 and @queuedKeystroke
|
||||
@queuedKeystroke = null
|
||||
return false
|
||||
else
|
||||
@queuedKeystroke = null
|
||||
|
||||
for keyBinding in keyBindings
|
||||
partialMatch = keyBinding.keystroke isnt keystroke
|
||||
if partialMatch
|
||||
@queuedKeystroke = keystroke
|
||||
shouldBubble = false
|
||||
else
|
||||
if keyBinding.command is 'native!'
|
||||
shouldBubble = true
|
||||
else if @triggerCommandEvent(element, keyBinding.command, event)
|
||||
shouldBubble = false
|
||||
|
||||
break if shouldBubble?
|
||||
|
||||
shouldBubble ? true
|
||||
|
||||
triggerCommandEvent: (element, commandName, event) ->
|
||||
commandEvent = $.Event(commandName)
|
||||
commandEvent.originalEvent = event
|
||||
commandEvent.abortKeyBinding = -> commandEvent.stopImmediatePropagation()
|
||||
$(element).trigger(commandEvent)
|
||||
not commandEvent.isImmediatePropagationStopped()
|
||||
|
||||
isAscii: (charCode) ->
|
||||
0 <= charCode <= 127
|
||||
|
||||
keyFromCharCode: (charCode) ->
|
||||
switch charCode
|
||||
when 8 then 'backspace'
|
||||
when 9 then 'tab'
|
||||
when 13 then 'enter'
|
||||
when 27 then 'escape'
|
||||
when 32 then 'space'
|
||||
when 127 then 'delete'
|
||||
else String.fromCharCode(charCode)
|
||||
@@ -1,3 +0,0 @@
|
||||
keystrokePattern = key:key additionalKeys:additionalKey* { return [key].concat(additionalKeys); }
|
||||
additionalKey = '-' key:key { return key; }
|
||||
key = '-' / chars:[^-]+ { return chars.join('') }
|
||||
@@ -39,13 +39,13 @@ class LanguageMode
|
||||
return unless commentStartString
|
||||
|
||||
buffer = @editor.buffer
|
||||
commentStartRegexString = _.escapeRegExp(commentStartString).replace(/(\s+)$/, '($1)?')
|
||||
commentStartRegexString = _.escapeRegExp(commentStartString).replace(/(\s+)$/, '(?:$1)?')
|
||||
commentStartRegex = new OnigRegExp("^(\\s*)(#{commentStartRegexString})")
|
||||
shouldUncomment = commentStartRegex.test(buffer.lineForRow(start))
|
||||
|
||||
if commentEndString
|
||||
if shouldUncomment
|
||||
commentEndRegexString = _.escapeRegExp(commentEndString).replace(/^(\s+)/, '($1)?')
|
||||
commentEndRegexString = _.escapeRegExp(commentEndString).replace(/^(\s+)/, '(?:$1)?')
|
||||
commentEndRegex = new OnigRegExp("(#{commentEndRegexString})(\\s*)$")
|
||||
startMatch = commentStartRegex.search(buffer.lineForRow(start))
|
||||
endMatch = commentEndRegex.search(buffer.lineForRow(end))
|
||||
@@ -121,12 +121,6 @@ class LanguageMode
|
||||
fold = @editor.displayBuffer.largestFoldStartingAtBufferRow(startRow)
|
||||
return @editor.createFold(startRow, endRow) unless fold
|
||||
|
||||
# Given a buffer row, this unfolds it.
|
||||
#
|
||||
# bufferRow - A {Number} indicating the buffer row
|
||||
unfoldBufferRow: (bufferRow) ->
|
||||
@editor.displayBuffer.largestFoldContainingBufferRow(bufferRow)?.destroy()
|
||||
|
||||
# Find the row range for a fold at a given bufferRow. Will handle comments
|
||||
# and code.
|
||||
#
|
||||
@@ -271,10 +265,11 @@ class LanguageMode
|
||||
|
||||
# Given a buffer row, this indents it.
|
||||
#
|
||||
# bufferRow - The row {Number}
|
||||
autoIndentBufferRow: (bufferRow) ->
|
||||
# bufferRow - The row {Number}.
|
||||
# options - An options {Object} to pass through to {Editor::setIndentationForBufferRow}.
|
||||
autoIndentBufferRow: (bufferRow, options) ->
|
||||
indentLevel = @suggestedIndentForBufferRow(bufferRow)
|
||||
@editor.setIndentationForBufferRow(bufferRow, indentLevel)
|
||||
@editor.setIndentationForBufferRow(bufferRow, indentLevel, options)
|
||||
|
||||
# Given a buffer row, this decreases the indentation.
|
||||
#
|
||||
|
||||
@@ -14,7 +14,7 @@ class MenuManager
|
||||
constructor: ({@resourcePath}) ->
|
||||
@pendingUpdateOperation = null
|
||||
@template = []
|
||||
atom.keymap.on 'bundled-keymaps-loaded', => @loadPlatformItems()
|
||||
atom.keymaps.on 'bundled-keymaps-loaded', => @loadPlatformItems()
|
||||
|
||||
# Public: Adds the given item definition to the existing template.
|
||||
#
|
||||
@@ -59,7 +59,8 @@ class MenuManager
|
||||
testBody.classList.add(@classesForElement(document.body)...)
|
||||
|
||||
testWorkspace = document.createElement('body')
|
||||
workspaceClasses = @classesForElement(document.body.querySelector('.workspace')) ? ['.workspace']
|
||||
workspaceClasses = @classesForElement(document.body.querySelector('.workspace'))
|
||||
workspaceClasses = ['workspace'] if workspaceClasses.length is 0
|
||||
testWorkspace.classList.add(workspaceClasses...)
|
||||
|
||||
testBody.appendChild(testWorkspace)
|
||||
@@ -75,9 +76,9 @@ class MenuManager
|
||||
clearImmediate(@pendingUpdateOperation) if @pendingUpdateOperation?
|
||||
@pendingUpdateOperation = setImmediate =>
|
||||
keystrokesByCommand = {}
|
||||
for binding in atom.keymap.getKeyBindings() when @includeSelector(binding.selector)
|
||||
for binding in atom.keymaps.getKeyBindings() when @includeSelector(binding.selector)
|
||||
keystrokesByCommand[binding.command] ?= []
|
||||
keystrokesByCommand[binding.command].push binding.keystroke
|
||||
keystrokesByCommand[binding.command].unshift binding.keystroke
|
||||
@sendToBrowserProcess(@template, keystrokesByCommand)
|
||||
|
||||
loadPlatformItems: ->
|
||||
@@ -116,10 +117,10 @@ class MenuManager
|
||||
normalizeLabel: (label) ->
|
||||
return undefined unless label?
|
||||
|
||||
if process.platform is 'win32'
|
||||
label.replace(/\&/g, '')
|
||||
else
|
||||
if process.platform is 'darwin'
|
||||
label
|
||||
else
|
||||
label.replace(/\&/g, '')
|
||||
|
||||
# Get an {Array} of {String} classes for the given element.
|
||||
classesForElement: (element) ->
|
||||
|
||||
@@ -41,7 +41,7 @@ class PackageManager
|
||||
|
||||
# Public: Get the path to the apm command
|
||||
getApmPath: ->
|
||||
@apmPath ?= require.resolve('atom-package-manager/bin/apm')
|
||||
@apmPath ?= path.resolve(__dirname, '..', 'apm', 'node_modules', 'atom-package-manager', 'bin', 'apm')
|
||||
|
||||
# Public: Get the paths being used to look for packages.
|
||||
#
|
||||
|
||||
+16
-4
@@ -69,7 +69,7 @@ class Package
|
||||
@loadStylesheets()
|
||||
@grammarsPromise = @loadGrammars()
|
||||
@scopedPropertiesPromise = @loadScopedProperties()
|
||||
@requireMainModule() unless @metadata.activationEvents?
|
||||
@requireMainModule() unless @hasActivationEvents()
|
||||
|
||||
catch error
|
||||
console.warn "Failed to load package named '#{@name}'", error.stack ? error
|
||||
@@ -87,7 +87,7 @@ class Package
|
||||
@activationDeferred = Q.defer()
|
||||
@measure 'activateTime', =>
|
||||
@activateResources()
|
||||
if @metadata.activationEvents?
|
||||
if @hasActivationEvents()
|
||||
@subscribeToActivationEvents()
|
||||
else
|
||||
@activateNow()
|
||||
@@ -124,7 +124,7 @@ class Package
|
||||
@stylesheetsActivated = true
|
||||
|
||||
activateResources: ->
|
||||
atom.keymap.add(keymapPath, map) for [keymapPath, map] in @keymaps
|
||||
atom.keymaps.add(keymapPath, map) for [keymapPath, map] in @keymaps
|
||||
atom.contextMenu.add(menuPath, map['context-menu']) for [menuPath, map] in @menus
|
||||
atom.menu.add(map.menu) for [menuPath, map] in @menus when map.menu
|
||||
|
||||
@@ -232,7 +232,7 @@ class Package
|
||||
deactivateResources: ->
|
||||
grammar.deactivate() for grammar in @grammars
|
||||
scopedProperties.deactivate() for scopedProperties in @scopedProperties
|
||||
atom.keymap.remove(keymapPath) for [keymapPath] in @keymaps
|
||||
atom.keymaps.remove(keymapPath) for [keymapPath] in @keymaps
|
||||
atom.themes.removeStylesheet(stylesheetPath) for [stylesheetPath] in @stylesheets
|
||||
@stylesheetsActivated = false
|
||||
@grammarsActivated = false
|
||||
@@ -262,6 +262,18 @@ class Package
|
||||
path.join(@path, 'index')
|
||||
@mainModulePath = fs.resolveExtension(mainModulePath, ["", _.keys(require.extensions)...])
|
||||
|
||||
hasActivationEvents: ->
|
||||
if _.isArray(@metadata.activationEvents)
|
||||
return @metadata.activationEvents.some (activationEvent) ->
|
||||
activationEvent?.length > 0
|
||||
else if _.isString(@metadata.activationEvents)
|
||||
return @metadata.activationEvents.length > 0
|
||||
else if _.isObject(@metadata.activationEvents)
|
||||
for event, selector of @metadata.activationEvents
|
||||
return true if event.length > 0 and selector.length > 0
|
||||
|
||||
false
|
||||
|
||||
subscribeToActivationEvents: ->
|
||||
return unless @metadata.activationEvents?
|
||||
if _.isArray(@metadata.activationEvents)
|
||||
|
||||
@@ -75,7 +75,9 @@ class PaneView extends View
|
||||
@command 'pane:split-right', => @splitRight(@copyActiveItem())
|
||||
@command 'pane:split-up', => @splitUp(@copyActiveItem())
|
||||
@command 'pane:split-down', => @splitDown(@copyActiveItem())
|
||||
@command 'pane:close', => @model.destroy()
|
||||
@command 'pane:close', =>
|
||||
@model.destroyItems()
|
||||
@model.destroy()
|
||||
@command 'pane:close-other-items', => @destroyInactiveItems()
|
||||
|
||||
# Deprecated: Use ::destroyItem
|
||||
|
||||
+3
-5
@@ -1,5 +1,4 @@
|
||||
{find, compact, extend, last} = require 'underscore-plus'
|
||||
{dirname} = require 'path'
|
||||
{Model, Sequence} = require 'theorist'
|
||||
Serializable = require 'serializable'
|
||||
PaneAxis = require './pane-axis'
|
||||
@@ -265,10 +264,9 @@ class Pane extends Model
|
||||
return unless item?.saveAs?
|
||||
|
||||
itemPath = item.getPath?()
|
||||
itemPath = dirname(itemPath) if itemPath
|
||||
path = atom.showSaveDialogSync(itemPath)
|
||||
if path
|
||||
item.saveAs(path)
|
||||
newItemPath = atom.showSaveDialogSync(itemPath)
|
||||
if newItemPath
|
||||
item.saveAs(newItemPath)
|
||||
nextAction?()
|
||||
|
||||
# Public: Saves all items.
|
||||
|
||||
@@ -189,8 +189,8 @@ class Project extends Model
|
||||
#
|
||||
# Returns a promise that resolves to the {TextBuffer}.
|
||||
buildBuffer: (absoluteFilePath) ->
|
||||
if fs.getSizeSync(absoluteFilePath) >= 1048576 # 1MB
|
||||
throw new Error("Atom can only handle files < 1MB, for now.")
|
||||
if fs.getSizeSync(absoluteFilePath) >= 2 * 1048576 # 2MB
|
||||
throw new Error("Atom can only handle files < 2MB, for now.")
|
||||
|
||||
buffer = new TextBuffer({filePath: absoluteFilePath})
|
||||
@addBuffer(buffer)
|
||||
@@ -251,6 +251,7 @@ class Project extends Model
|
||||
|
||||
for buffer in @getBuffers() when buffer.isModified()
|
||||
filePath = buffer.getPath()
|
||||
continue unless @contains(filePath)
|
||||
matches = []
|
||||
buffer.scan regex, (match) -> matches.push match
|
||||
iterator {filePath, matches} if matches.length > 0
|
||||
|
||||
@@ -3,17 +3,33 @@ path = require 'path'
|
||||
|
||||
module.exports = (repoPath) ->
|
||||
repo = Git.open(repoPath)
|
||||
|
||||
upstream = {}
|
||||
statuses = {}
|
||||
submodules = {}
|
||||
branch = null
|
||||
|
||||
if repo?
|
||||
# Statuses in main repo
|
||||
workingDirectoryPath = repo.getWorkingDirectory()
|
||||
statuses = {}
|
||||
for filePath, status of repo.getStatus()
|
||||
statuses[path.join(workingDirectoryPath, filePath)] = status
|
||||
statuses[filePath] = status
|
||||
|
||||
# Statuses in submodules
|
||||
for submodulePath, submoduleRepo of repo.submodules
|
||||
submodules[submodulePath] =
|
||||
branch: submoduleRepo.getHead()
|
||||
upstream: submoduleRepo.getAheadBehindCount()
|
||||
|
||||
workingDirectoryPath = submoduleRepo.getWorkingDirectory()
|
||||
for filePath, status of submoduleRepo.getStatus()
|
||||
absolutePath = path.join(workingDirectoryPath, filePath)
|
||||
# Make path relative to parent repository
|
||||
relativePath = repo.relativize(absolutePath)
|
||||
statuses[relativePath] = status
|
||||
|
||||
upstream = repo.getAheadBehindCount()
|
||||
branch = repo.getHead()
|
||||
repo.release()
|
||||
else
|
||||
upstream = {}
|
||||
statuses = {}
|
||||
branch = null
|
||||
|
||||
{statuses, upstream, branch}
|
||||
{statuses, upstream, branch, submodules}
|
||||
|
||||
@@ -56,6 +56,11 @@ class SelectListView extends View
|
||||
@filterEditorView.hiddenInput.on 'focusout', =>
|
||||
@cancel() unless @cancelling
|
||||
|
||||
# This prevents the focusout event from firing on the filter editor view
|
||||
# when the list is scrolled by clicking the scrollbar and dragging.
|
||||
@list.on 'mousedown', ({target}) =>
|
||||
false if target is @list[0]
|
||||
|
||||
@on 'core:move-up', =>
|
||||
@selectPreviousItemView()
|
||||
@on 'core:move-down', =>
|
||||
@@ -148,8 +153,8 @@ class SelectListView extends View
|
||||
|
||||
for i in [0...Math.min(filteredItems.length, @maxItems)]
|
||||
item = filteredItems[i]
|
||||
itemView = @viewForItem(item)
|
||||
$(itemView).data('select-list-item', item)
|
||||
itemView = $(@viewForItem(item))
|
||||
itemView.data('select-list-item', item)
|
||||
@list.append(itemView)
|
||||
|
||||
@selectItemView(@list.find('li:first'))
|
||||
|
||||
+13
-7
@@ -1,4 +1,4 @@
|
||||
{Range} = require 'text-buffer'
|
||||
{Point, Range} = require 'text-buffer'
|
||||
{Emitter} = require 'emissary'
|
||||
{pick} = require 'underscore-plus'
|
||||
|
||||
@@ -141,6 +141,8 @@ class Selection
|
||||
#
|
||||
# position - An instance of {Point}, with a given `row` and `column`.
|
||||
selectToScreenPosition: (position) ->
|
||||
position = Point.fromObject(position)
|
||||
|
||||
@modifySelection =>
|
||||
if @initialScreenRange
|
||||
if position.isLessThan(@initialScreenRange.start)
|
||||
@@ -282,7 +284,7 @@ class Selection
|
||||
# :undo - if `skip`, skips the undo stack for this operation.
|
||||
insertText: (text, options={}) ->
|
||||
oldBufferRange = @getBufferRange()
|
||||
@editor.destroyFoldsContainingBufferRow(oldBufferRange.end.row)
|
||||
@editor.unfoldBufferRow(oldBufferRange.end.row)
|
||||
wasReversed = @isReversed()
|
||||
@clear()
|
||||
@cursor.needsAutoscroll = @cursor.isLastCursor()
|
||||
@@ -299,7 +301,7 @@ class Selection
|
||||
if options.autoIndent
|
||||
@editor.autoIndentBufferRow(row) for row in newBufferRange.getRows()
|
||||
else if options.autoIndentNewline and text == '\n'
|
||||
@editor.autoIndentBufferRow(newBufferRange.end.row)
|
||||
@editor.autoIndentBufferRow(newBufferRange.end.row, preserveLeadingWhitespace: true)
|
||||
else if options.autoDecreaseIndent and /\S/.test text
|
||||
@editor.autoDecreaseIndentForBufferRow(newBufferRange.start.row)
|
||||
|
||||
@@ -334,11 +336,15 @@ class Selection
|
||||
|
||||
normalizedLines.join('\n')
|
||||
|
||||
# Public: Indents the selection.
|
||||
# Indent the current line(s).
|
||||
#
|
||||
# If the selection is empty, indents the current line if the cursor precedes
|
||||
# non-whitespace characters, and otherwise inserts a tab. If the selection is
|
||||
# non empty, calls {::indentSelectedRows}.
|
||||
#
|
||||
# options - A {Object} with the keys:
|
||||
# :autoIndent - If `true`, the indentation is performed appropriately.
|
||||
# Otherwise, {Editor::getTabText} is used.
|
||||
# :autoIndent - If `true`, the line is indented to an automatically-inferred
|
||||
# level. Otherwise, {Editor::getTabText} is inserted.
|
||||
indent: ({ autoIndent }={})->
|
||||
{ row, column } = @cursor.getBufferPosition()
|
||||
|
||||
@@ -433,7 +439,7 @@ class Selection
|
||||
# Public: Joins the current line with the one below it.
|
||||
#
|
||||
# If there selection spans more than one line, all the lines are joined together.
|
||||
joinLine: ->
|
||||
joinLines: ->
|
||||
selectedRange = @getBufferRange()
|
||||
if selectedRange.isEmpty()
|
||||
return if selectedRange.start.row is @editor.buffer.getLastRow()
|
||||
|
||||
@@ -39,10 +39,10 @@ jQuery.fn.setTooltip = (tooltipOptions, {command, commandElement}={}) ->
|
||||
|
||||
tooltipOptions = {title: tooltipOptions} if _.isString(tooltipOptions)
|
||||
|
||||
bindings = if commandElement
|
||||
atom.keymap.keyBindingsForCommandMatchingElement(command, commandElement)
|
||||
else
|
||||
atom.keymap.keyBindingsForCommand(command)
|
||||
if commandElement
|
||||
bindings = atom.keymaps.keyBindingsForCommandMatchingElement(command, commandElement)
|
||||
else if command
|
||||
bindings = atom.keymaps.keyBindingsForCommand(command)
|
||||
|
||||
tooltipOptions.title = "#{tooltipOptions.title} #{getKeystroke(bindings)}"
|
||||
|
||||
|
||||
+24
-54
@@ -2,6 +2,8 @@ _ = require 'underscore-plus'
|
||||
{specificity} = require 'clear-cut'
|
||||
{Subscriber} = require 'emissary'
|
||||
{GrammarRegistry, ScopeSelector} = require 'first-mate'
|
||||
ScopedPropertyStore = require 'scoped-property-store'
|
||||
PropertyAccessors = require 'property-accessors'
|
||||
|
||||
{$, $$} = require './space-pen-extensions'
|
||||
Token = require './token'
|
||||
@@ -14,6 +16,7 @@ Token = require './token'
|
||||
# language-specific comment regexes.
|
||||
module.exports =
|
||||
class Syntax extends GrammarRegistry
|
||||
PropertyAccessors.includeInto(this)
|
||||
Subscriber.includeInto(this)
|
||||
atom.deserializers.add(this)
|
||||
|
||||
@@ -24,34 +27,28 @@ class Syntax extends GrammarRegistry
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
@scopedPropertiesIndex = 0
|
||||
@scopedProperties = []
|
||||
@propertyStore = new ScopedPropertyStore
|
||||
|
||||
serialize: ->
|
||||
{deserializer: @constructor.name, @grammarOverridesByPath}
|
||||
|
||||
createToken: (value, scopes) -> new Token({value, scopes})
|
||||
|
||||
# Deprecated: Used by settings-view to display snippets for packages
|
||||
@::accessor 'scopedProperties', -> @propertyStore.propertySets
|
||||
|
||||
addProperties: (args...) ->
|
||||
name = args.shift() if args.length > 2
|
||||
[selector, properties] = args
|
||||
|
||||
@scopedProperties.unshift(
|
||||
name: name
|
||||
selector: selector,
|
||||
properties: properties,
|
||||
specificity: specificity(selector),
|
||||
index: @scopedPropertiesIndex++
|
||||
)
|
||||
propertiesBySelector = {}
|
||||
propertiesBySelector[selector] = properties
|
||||
@propertyStore.addProperties(name, propertiesBySelector)
|
||||
|
||||
removeProperties: (name) ->
|
||||
for properties in @scopedProperties.filter((properties) -> properties.name is name)
|
||||
_.remove(@scopedProperties, properties)
|
||||
@propertyStore.removeProperties(name)
|
||||
|
||||
clearProperties: ->
|
||||
@scopedProperties = []
|
||||
@scopedPropertiesIndex = 0
|
||||
@propertyStore = new ScopedPropertyStore
|
||||
|
||||
# Public: Get a property for the given scope and key path.
|
||||
#
|
||||
@@ -66,48 +63,21 @@ class Syntax extends GrammarRegistry
|
||||
#
|
||||
# Returns a {String} property value or undefined.
|
||||
getProperty: (scope, keyPath) ->
|
||||
for object in @propertiesForScope(scope, keyPath)
|
||||
value = _.valueForKeyPath(object, keyPath)
|
||||
return value if value?
|
||||
undefined
|
||||
scopeChain = scope
|
||||
.map (scope) ->
|
||||
scope = ".#{scope}" unless scope.indexOf('.') is 0
|
||||
scope
|
||||
.join(' ')
|
||||
@propertyStore.getPropertyValue(scopeChain, keyPath)
|
||||
|
||||
propertiesForScope: (scope, keyPath) ->
|
||||
matchingProperties = []
|
||||
candidates = @scopedProperties.filter ({properties}) -> _.valueForKeyPath(properties, keyPath)?
|
||||
if candidates.length
|
||||
element = @buildScopeElement(scope)
|
||||
while element
|
||||
matchingProperties.push(@matchingPropertiesForElement(element, candidates)...)
|
||||
element = element.parentNode
|
||||
matchingProperties
|
||||
scopeChain = scope
|
||||
.map (scope) ->
|
||||
scope = ".#{scope}" unless scope.indexOf('.') is 0
|
||||
scope
|
||||
.join(' ')
|
||||
|
||||
matchingPropertiesForElement: (element, candidates) ->
|
||||
matchingScopedProperties = candidates.filter ({selector}) ->
|
||||
$.find.matchesSelector(element, selector)
|
||||
matchingScopedProperties.sort (a, b) ->
|
||||
if a.specificity == b.specificity
|
||||
b.index - a.index
|
||||
else
|
||||
b.specificity - a.specificity
|
||||
_.pluck matchingScopedProperties, 'properties'
|
||||
|
||||
buildScopeElement: (scope) ->
|
||||
scope = scope.slice()
|
||||
element = $$ ->
|
||||
elementsForRemainingScopes = =>
|
||||
classString = scope.shift()
|
||||
classes = classString.replace(/^\./, '').replace(/\./g, ' ')
|
||||
if scope.length
|
||||
@div class: classes, elementsForRemainingScopes
|
||||
else
|
||||
@div class: classes
|
||||
elementsForRemainingScopes()
|
||||
|
||||
deepestChild = element.find(":not(:has(*))")
|
||||
if deepestChild.length
|
||||
deepestChild[0]
|
||||
else
|
||||
element[0]
|
||||
@propertyStore.getProperties(scopeChain, keyPath)
|
||||
|
||||
cssSelectorFromScopeSelector: (scopeSelector) ->
|
||||
new ScopeSelector(scopeSelector).toCssSelector()
|
||||
|
||||
+1
-1
@@ -87,7 +87,7 @@ class Task
|
||||
if _.isFunction(callback)
|
||||
@callback = callback
|
||||
else
|
||||
args = arguments
|
||||
args.push(callback)
|
||||
@send({event: 'start', args})
|
||||
|
||||
# Public: Send message to the task.
|
||||
|
||||
@@ -191,6 +191,7 @@ class ThemeManager
|
||||
removeStylesheet: (stylesheetPath) ->
|
||||
fullPath = @resolveStylesheet(stylesheetPath) ? stylesheetPath
|
||||
@stylesheetElementForId(@stringToId(fullPath)).remove()
|
||||
@emit 'stylesheets-changed'
|
||||
|
||||
applyStylesheet: (path, text, ttype = 'bundled', htmlElement=$('html')) ->
|
||||
styleElement = @stylesheetElementForId(@stringToId(path), htmlElement)
|
||||
@@ -201,3 +202,4 @@ class ThemeManager
|
||||
htmlElement.find("head style.#{ttype}:last").after "<style class='#{ttype}' id='#{@stringToId(path)}'>#{text}</style>"
|
||||
else
|
||||
htmlElement.find("head").append "<style class='#{ttype}' id='#{@stringToId(path)}'>#{text}</style>"
|
||||
@emit 'stylesheets-changed'
|
||||
|
||||
@@ -20,7 +20,7 @@ class TokenizedBuffer extends Model
|
||||
visible: false
|
||||
|
||||
constructor: ({@buffer, @tabLength}) ->
|
||||
@tabLength ?= atom.config.get('editor.tabLength') ? 2
|
||||
@tabLength ?= atom.config.getPositiveInt('editor.tabLength', 2)
|
||||
|
||||
@subscribe atom.syntax, 'grammar-added grammar-updated', (grammar) =>
|
||||
if grammar.injectionSelector?
|
||||
@@ -40,7 +40,7 @@ class TokenizedBuffer extends Model
|
||||
@emit "changed", { start: 0, end: lastRow, delta: 0 }
|
||||
|
||||
@subscribe atom.config.observe 'editor.tabLength', callNow: false, =>
|
||||
@setTabLength(atom.config.getPositiveInt('editor.tabLength'))
|
||||
@setTabLength(atom.config.getPositiveInt('editor.tabLength', 2))
|
||||
|
||||
@reloadGrammar()
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ class TokenizedLine
|
||||
@tokens = @breakOutAtomicTokens(tokens, tabLength)
|
||||
@startBufferColumn ?= 0
|
||||
@text = _.pluck(@tokens, 'value').join('')
|
||||
@bufferDelta = _.sum(_.pluck(@tokens, 'bufferDelta'))
|
||||
|
||||
copy: ->
|
||||
new TokenizedLine({@tokens, @lineEnding, @ruleStack, @startBufferColumn, @fold})
|
||||
@@ -55,7 +56,7 @@ class TokenizedLine
|
||||
@text.length
|
||||
|
||||
getMaxBufferColumn: ->
|
||||
@startBufferColumn + @getMaxScreenColumn()
|
||||
@startBufferColumn + @bufferDelta
|
||||
|
||||
softWrapAt: (column) ->
|
||||
return [new TokenizedLine([], '', [0, 0], [0, 0]), this] if column == 0
|
||||
@@ -78,7 +79,7 @@ class TokenizedLine
|
||||
)
|
||||
rightFragment = new TokenizedLine(
|
||||
tokens: rightTokens
|
||||
startBufferColumn: @startBufferColumn + column
|
||||
startBufferColumn: @bufferColumnForScreenColumn(column)
|
||||
ruleStack: @ruleStack
|
||||
lineEnding: @lineEnding
|
||||
)
|
||||
|
||||
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