Comparar commits
541 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| ec5cd6a68e | |||
| 0fc94faf29 | |||
| de2d9739c8 | |||
| a4fe594441 | |||
| 9d0e46126b | |||
| cb1bb4a691 | |||
| d3a24c3749 | |||
| 092849835e | |||
| b24ade4de5 | |||
| 0f77a2eef9 | |||
| 662c2fc9d3 | |||
| 510b1a7068 | |||
| c4f9914df6 | |||
| 2140ce3beb | |||
| a597bca75e | |||
| 2895aae121 | |||
| 4e20d93f03 | |||
| 1cc4e2e045 | |||
| 9fb427c468 | |||
| a9bd061144 | |||
| 0736b28abf | |||
| 9ac5b67b6e | |||
| 25601d691d | |||
| 0d1c11764b | |||
| 729ff461f1 | |||
| 0360a1918c | |||
| 23f21bcda2 | |||
| 800d65e3de | |||
| 5ce9b3ac55 | |||
| f86191dff8 | |||
| 412793697f | |||
| 3274ef9fb9 | |||
| f8e2231dfc | |||
| 837eaccd16 | |||
| 4f3570b56b | |||
| 8918a42b3b | |||
| bd77a02207 | |||
| eebbb99fc8 | |||
| 2b27c0b440 | |||
| 8e69b0c4a0 | |||
| 532744b4eb | |||
| ddd89ed6d1 | |||
| 5a53e5b96a | |||
| 69f84f7e6d | |||
| e2c65345ab | |||
| f47bcddf10 | |||
| 5e19230809 | |||
| f8961fbd53 | |||
| bef750cb1f | |||
| 4e2f06aec7 | |||
| 02c47ba1ea | |||
| f6cb59be47 | |||
| 397871a012 | |||
| 10239e0466 | |||
| 69ef99481b | |||
| fc20de82ce | |||
| 0232da27f5 | |||
| ba452e2400 | |||
| 9b5b8e7528 | |||
| 6e65947d54 | |||
| 93c5e241f3 | |||
| e0c61136a6 | |||
| c5cc13ddb3 | |||
| fd47c89f9d | |||
| 34ad902cb3 | |||
| 9678418e56 | |||
| 691d6c3b5f | |||
| 431555195a | |||
| b0aa5e6c88 | |||
| b3c2417578 | |||
| 7f882b00f5 | |||
| 3a9aa80914 | |||
| 3af3a0d27e | |||
| 7e415ffdb7 | |||
| e70c696fef | |||
| b2258d9b8a | |||
| 40eab806c4 | |||
| 319455f2da | |||
| 63867ba803 | |||
| 65ffd21574 | |||
| 393552a4b6 | |||
| 444c18be34 | |||
| dca096b8e3 | |||
| 57a03e7884 | |||
| fe1819f587 | |||
| aa157af93e | |||
| 0e58e03de7 | |||
| e011c80b07 | |||
| 9ae007a6d7 | |||
| 9dc59b9807 | |||
| 15689ebfb5 | |||
| 6250419fcb | |||
| 70621afe62 | |||
| 6f29710d88 | |||
| 7b07d7116b | |||
| f175086865 | |||
| c6071a9802 | |||
| ac138c1dc8 | |||
| 85b7261d31 | |||
| d47348e8f9 | |||
| 56df7bdbe3 | |||
| 1ea909d4db | |||
| c748fc49bb | |||
| 3bd1ec08e1 | |||
| caa6f9b06e | |||
| 32045a3f22 | |||
| 736952d0a2 | |||
| 684f15ab89 | |||
| 4238e031da | |||
| a457d8a849 | |||
| 0b3c0fc622 | |||
| a3d82e9414 | |||
| 37165f3293 | |||
| f2507fc9d4 | |||
| 7515fd94ba | |||
| 8cc1029bbf | |||
| 85363f8eaa | |||
| c5b3f18783 | |||
| 7738eeeacc | |||
| c6116468e4 | |||
| 2a2d0b60f7 | |||
| 9a5fddbcbb | |||
| 25c737de56 | |||
| 8ad8be2583 | |||
| f29f8e37d1 | |||
| b922f01257 | |||
| c1ec87c41b | |||
| c8aea97f16 | |||
| c9587a8638 | |||
| 15fc7a8bc5 | |||
| 76eb3b4c72 | |||
| c03d34f535 | |||
| 7cfdcf0c1b | |||
| d3a46b6bc9 | |||
| cc27f2dbb6 | |||
| 54ce852be4 | |||
| 83ad1fe8af | |||
| dcbf730129 | |||
| 39868a2330 | |||
| 5d00ca8bb6 | |||
| 772726ca96 | |||
| 00275d95ec | |||
| 242df788e6 | |||
| 3295b9b0dd | |||
| 2a9c78ef92 | |||
| a896d71948 | |||
| e3e0df7728 | |||
| 0acd3ebd4b | |||
| 82f0a68419 | |||
| 9a95c3acef | |||
| 22eb16352c | |||
| 5355310cc7 | |||
| 9f9ca0a2cf | |||
| 29970acaa9 | |||
| 8c0b9017c2 | |||
| e9890810d3 | |||
| 0e201d539a | |||
| 6a0e7cfb24 | |||
| e13defc0f7 | |||
| 3326cf357f | |||
| 9c78b9832b | |||
| 662b8b30a1 | |||
| caa15e42ac | |||
| 75410e07da | |||
| 72727c2a81 | |||
| adaee84933 | |||
| d761684212 | |||
| 307d4984a2 | |||
| 09711d5a88 | |||
| 2e1239345e | |||
| 8d6325b081 | |||
| 8a8144defa | |||
| ed867666ed | |||
| 84ff28ee69 | |||
| 97f032c66f | |||
| 18ea3bcb99 | |||
| 8da4ed147b | |||
| edd1f46ad2 | |||
| cfb1501720 | |||
| 17ceb34140 | |||
| c551b58490 | |||
| 6c736ace1a | |||
| 4ff2429f71 | |||
| 01499fe674 | |||
| c4d26f6405 | |||
| bd93f243dc | |||
| 1663315323 | |||
| ffb041a160 | |||
| f5f9de1bf8 | |||
| 2f47e8a462 | |||
| 119b446c3b | |||
| c2042ad74a | |||
| 361f8ec770 | |||
| 48a5123202 | |||
| 0f1d155685 | |||
| d3a6e79428 | |||
| 5f7f5b5367 | |||
| 2fe647c950 | |||
| 683f8e06f8 | |||
| bc4173f856 | |||
| 8443f0e2b9 | |||
| b9e2c47321 | |||
| 8099c46c8e | |||
| a3f046b948 | |||
| 911ca0d846 | |||
| 88d1ba2271 | |||
| bbfd9b8178 | |||
| 3818dee175 | |||
| 6d34de68ac | |||
| 10fb929a1b | |||
| d1a610dcb6 | |||
| 17364cd528 | |||
| c67f8493e0 | |||
| 1a90588752 | |||
| 4f4b840f67 | |||
| 77158738e6 | |||
| 27d0743edc | |||
| 9aca6a4489 | |||
| 866fd69008 | |||
| d9a942d6c6 | |||
| 6f0920c04b | |||
| 2e4893c786 | |||
| 5871bee791 | |||
| adea792b78 | |||
| 36f1ebfb6f | |||
| a45e38cd8a | |||
| 46b95318a1 | |||
| 50086df804 | |||
| 52e049bedc | |||
| a6640f6da7 | |||
| 2f82fb2ceb | |||
| c50c25b2d4 | |||
| 89733300a5 | |||
| b9658e23f4 | |||
| 1757ff18f2 | |||
| a26cb6023e | |||
| ccd631a934 | |||
| ab980d78d2 | |||
| f5951425c3 | |||
| 74992b1397 | |||
| 4b07b803b3 | |||
| 94f871e37e | |||
| 4a8a741ef0 | |||
| 162d5a0e0d | |||
| a22cf44b49 | |||
| 10bad42e7a | |||
| 8a6753905c | |||
| 73354f56f4 | |||
| 43c9e21f1d | |||
| ba21f0b0d8 | |||
| 0ee953fe26 | |||
| a68b9a793f | |||
| fb4361e976 | |||
| f9d866fa32 | |||
| 0c4da92d6b | |||
| 6377c7ebf4 | |||
| 08ecba72e6 | |||
| 38b286f989 | |||
| df7f816c88 | |||
| ca1220a682 | |||
| 9bb6c3cc3d | |||
| 4a8ac85ffb | |||
| c4177aba3e | |||
| 3206fdce9e | |||
| 0346e5809a | |||
| 99704517bb | |||
| 783ef730e2 | |||
| e81db5d706 | |||
| a0f75f1639 | |||
| d0893ccdaf | |||
| a9c7842a50 | |||
| 544c759fd1 | |||
| 759dbc061d | |||
| 56c9f75e8c | |||
| 635f288050 | |||
| cc8b7b13b3 | |||
| 4020ed1535 | |||
| e999ef00e7 | |||
| f16ea63a95 | |||
| 754f995c91 | |||
| ac8a67822e | |||
| 1c7926dea6 | |||
| 2bd8015a9d | |||
| 09e8aa0571 | |||
| 364e06483c | |||
| 2d07d6662c | |||
| 3d53749771 | |||
| eeadd823e6 | |||
| 8a5bd357cd | |||
| 79ee887c9a | |||
| 37d0a7f7e5 | |||
| ed4324dedc | |||
| d2da914151 | |||
| ca39e7f7de | |||
| 7bf2b7237e | |||
| c264855f87 | |||
| a5f2a44a45 | |||
| 4960a63bd8 | |||
| 42621805a7 | |||
| fed55b8896 | |||
| 73daa4bb74 | |||
| 92546c60b3 | |||
| 2fa91e5dfb | |||
| aac0913b8b | |||
| acc75ca859 | |||
| 8eb4e13df8 | |||
| 087d9c1da6 | |||
| 18336076a8 | |||
| 7fee5f5f25 | |||
| c2f04a00d2 | |||
| cc927123f9 | |||
| 97b426429b | |||
| 3686530943 | |||
| 621ef450da | |||
| 1e08bcd634 | |||
| ede468d4c9 | |||
| 1278f88dd9 | |||
| 6faf3bd827 | |||
| 92a2b52f53 | |||
| 8135458670 | |||
| 160a1cd690 | |||
| 2d3a133790 | |||
| af5384cd51 | |||
| 27423fcc15 | |||
| cdb5fe15d2 | |||
| 608c2b5354 | |||
| 121350f8e5 | |||
| 7bcc91e7d2 | |||
| b192622ad8 | |||
| 778e6f4492 | |||
| 8614777af4 | |||
| cce49da18c | |||
| 66bfefc09d | |||
| 29e883cf36 | |||
| 381d5b91b2 | |||
| b744997201 | |||
| 0357872558 | |||
| 844186f5fc | |||
| 0a818cfdd7 | |||
| cd1a17fb0a | |||
| 9abab27ba7 | |||
| 0faff626d1 | |||
| c355ade477 | |||
| 18818c9ba5 | |||
| b4ca3e46e6 | |||
| 262ba6be20 | |||
| 50c5d12ced | |||
| d6d51155ac | |||
| b100310764 | |||
| 7ac3e6d9a5 | |||
| 2742995541 | |||
| b8c0c125a2 | |||
| d78eb3d142 | |||
| 36769c35fc | |||
| e6c0c38894 | |||
| 1f77450f7e | |||
| c4204eb9e9 | |||
| 9a393a6ec9 | |||
| bbe02fc6b0 | |||
| 9fbc6d4f02 | |||
| e620121953 | |||
| 41c8878769 | |||
| d2834fa651 | |||
| 4155c53bd6 | |||
| d3538502c5 | |||
| 90a17de8bd | |||
| a82ea86a05 | |||
| 22c4992788 | |||
| 2a5d034248 | |||
| ed3c37c101 | |||
| 558e5e52c5 | |||
| 92d16a9d0a | |||
| f224a6d5f0 | |||
| 16f95a1420 | |||
| 0231d02877 | |||
| 6d2b70b3d9 | |||
| 49b825aeb3 | |||
| 357299a700 | |||
| 88df674dd6 | |||
| 31afa0abd5 | |||
| b11accec6d | |||
| defa869d5c | |||
| 8d4be6ab57 | |||
| 9976166902 | |||
| 8ea277ef77 | |||
| d85b8bfaf3 | |||
| d9e15d937e | |||
| 908ff5d3cd | |||
| 35b4ba3066 | |||
| f90e47daef | |||
| 5440dd68a7 | |||
| 11205d9eaa | |||
| 34e37fce7c | |||
| 3402c8dcd1 | |||
| 3921a63f67 | |||
| 5ecaf5dfc4 | |||
| 475f92351f | |||
| 0a5b378425 | |||
| 157774f552 | |||
| 320c12134a | |||
| 280b451835 | |||
| 4ee03fe590 | |||
| db1652f1ed | |||
| 8013ff7775 | |||
| c24475c2c8 | |||
| 580c639265 | |||
| 4c33549371 | |||
| 7be5553ba1 | |||
| 43936a1faf | |||
| e3c44bf551 | |||
| 6b0636d331 | |||
| cb0ee735be | |||
| 036dc06bac | |||
| 7155ec4b73 | |||
| 86ea4d94bb | |||
| 6a2021ac98 | |||
| 6fe05064eb | |||
| dd5c9ff6d4 | |||
| 29179d0bbc | |||
| f6400a4097 | |||
| e170b9f56b | |||
| 2ea8418c66 | |||
| c20a4a3084 | |||
| 0be64f9902 | |||
| 5300fefef4 | |||
| 2602e6ec0a | |||
| 1a22fc3c68 | |||
| 6d02861f11 | |||
| 57ed190ea3 | |||
| 436d7de817 | |||
| a9feed2e4a | |||
| 8b04e94d09 | |||
| 5c5576c39d | |||
| 2b957beeda | |||
| 832aeffd4f | |||
| 5d08ecdcb2 | |||
| 997529774c | |||
| 48d20ff1ec | |||
| 0793f291d1 | |||
| 8d479328ec | |||
| 569326e76a | |||
| 8372b84e9f | |||
| eda55156e5 | |||
| c40a526302 | |||
| 540b038ced | |||
| ce1ebec253 | |||
| 44e121c997 | |||
| 3579404bed | |||
| 1e19860409 | |||
| eab4b578a3 | |||
| 2878196e0a | |||
| 1c037411e9 | |||
| 68144681b2 | |||
| 484a516bd6 | |||
| fa6e84415b | |||
| 7117634ba8 | |||
| a108c283cf | |||
| 3dc61f4a7a | |||
| 9685e3f1db | |||
| b2c70f9e69 | |||
| d7a3ffa9de | |||
| 18ed91a402 | |||
| e991b3d10c | |||
| f1b7f9ca30 | |||
| e1e510e473 | |||
| d042d15a50 | |||
| fe9fec733d | |||
| 06095e57d7 | |||
| b83f908e28 | |||
| fad2a63a14 | |||
| 2de42303d4 | |||
| a7aed07d70 | |||
| 673b62f547 | |||
| 19835f2f66 | |||
| 7474de8f7e | |||
| 84c30ef6c5 | |||
| 0aa5fa9eeb | |||
| b5f8b159fc | |||
| 79357be899 | |||
| 12d6a90ddc | |||
| 4eb3be6f17 | |||
| af622c6b74 | |||
| df8e0a8464 | |||
| a1c1879ba6 | |||
| d1e52d4105 | |||
| 0f01840e3e | |||
| e1945fce14 | |||
| e6ecf10616 | |||
| b85ebbad2a | |||
| 38ba96a54f | |||
| 334e2ef7ab | |||
| 58efeb8a20 | |||
| 3ae6540c70 | |||
| 497ac5e5ce | |||
| 8735780473 | |||
| 888b5ab098 | |||
| c897f42d51 | |||
| 3c5312e834 | |||
| c59cbb3b25 | |||
| b3da11edfb | |||
| f56b487935 | |||
| 840abd6780 | |||
| 2e554ac819 | |||
| 35c7bc0eef | |||
| d99a9b0f3f | |||
| 7ac8b80172 | |||
| 68f2bd56f0 | |||
| e709b986cd | |||
| 74bdd5f0e8 | |||
| 48b6c24882 | |||
| e5f800ef35 | |||
| 492022fdd8 | |||
| cf7b87842e | |||
| 1838ff2502 | |||
| 505bfc28db | |||
| abbe8d2eec | |||
| bf33d96899 | |||
| a56b5eef2f | |||
| 80eb31679f | |||
| 54039e9d3b | |||
| 92c28fc44f | |||
| bc67efb72b | |||
| 0ee4d864be | |||
| 1d724339d6 | |||
| ce90b72807 | |||
| 4f356121d7 | |||
| 7b19152a58 | |||
| 15da69287e | |||
| 8d8db5142f | |||
| 6d7881bcfe | |||
| c2b7955ec6 | |||
| cc073ae462 | |||
| 3348c0e75a | |||
| 376a850507 | |||
| 168c6cdbca | |||
| 9ece33dbfe | |||
| 942041f214 | |||
| 260be2e096 | |||
| 6c8b4de986 | |||
| 9b267728d0 | |||
| 126d0d1b3c |
@@ -13,5 +13,3 @@ debug.log
|
||||
docs/output
|
||||
docs/includes
|
||||
spec/fixtures/evil-files/
|
||||
resources/linux/Atom.desktop
|
||||
resources/linux/debian/control
|
||||
|
||||
+16
@@ -6,10 +6,25 @@ Visit [atom.io](https://atom.io) to learn more.
|
||||
|
||||
## Installing
|
||||
|
||||
### Mac OS X
|
||||
|
||||
Download the latest [Atom release](https://github.com/atom/atom/releases/latest).
|
||||
|
||||
Atom will automatically update when a new release is available.
|
||||
|
||||
### Windows
|
||||
|
||||
Install the [Atom chocolatey package](https://chocolatey.org/packages/Atom).
|
||||
|
||||
1. Install [chocolatey](https://chocolatey.org).
|
||||
2. Close and reopen your command prompt or PowerShell window.
|
||||
3. Run `cinst Atom`
|
||||
4. In the future run `cup Atom` to upgrade to the latest release.
|
||||
|
||||
You can also download a `.zip` file from the [releases page](https://github.com/atom/atom/releases/latest).
|
||||
The Windows version does not currently automatically update so you will need to
|
||||
manually upgrade to future releases by re-downloading the `.zip` file.
|
||||
|
||||
## Building
|
||||
|
||||
* [Linux](docs/build-instructions/linux.md)
|
||||
@@ -18,4 +33,5 @@ Atom will automatically update when a new release is available.
|
||||
* [Windows](docs/build-instructions/windows.md)
|
||||
|
||||
## Developing
|
||||
|
||||
Check out the [guides](https://atom.io/docs/latest) and the [API reference](https://atom.io/docs/api).
|
||||
|
||||
+1
-1
@@ -6,6 +6,6 @@
|
||||
"url": "https://github.com/atom/atom.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"atom-package-manager": "0.70.0"
|
||||
"atom-package-manager": "0.87.0"
|
||||
}
|
||||
}
|
||||
|
||||
+7
-2
@@ -69,6 +69,11 @@ elif [ $OS == 'Linux' ]; then
|
||||
SCRIPT=$(readlink -f "$0")
|
||||
USR_DIRECTORY=$(readlink -f $(dirname $SCRIPT)/..)
|
||||
ATOM_PATH="$USR_DIRECTORY/share/atom/atom"
|
||||
DOT_ATOM_DIR="$HOME/.atom"
|
||||
|
||||
if [ ! -d "$DOT_ATOM_DIR" ]; then
|
||||
mkdir -p "$DOT_ATOM_DIR"
|
||||
fi
|
||||
|
||||
: ${TMPDIR:=/tmp}
|
||||
|
||||
@@ -79,9 +84,9 @@ elif [ $OS == 'Linux' ]; then
|
||||
exit $?
|
||||
else
|
||||
(
|
||||
nohup "$ATOM_PATH" --executed-from="$(pwd)" --pid=$$ "$@" > "$TMPDIR/atom-nohup.out" 2>&1
|
||||
nohup "$ATOM_PATH" --executed-from="$(pwd)" --pid=$$ "$@" > "$DOT_ATOM_DIR/nohup.out" 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
cat "$TMPDIR/atom-nohup.out"
|
||||
cat "$DOT_ATOM_DIR/nohup.out"
|
||||
exit $?
|
||||
fi
|
||||
) &
|
||||
|
||||
@@ -40,21 +40,27 @@ module.exports = (grunt) ->
|
||||
appName = if process.platform is 'darwin' then 'Atom.app' else 'Atom'
|
||||
buildDir = grunt.option('build-dir') ? path.join(tmpDir, 'atom-build')
|
||||
installDir = grunt.option('install-dir')
|
||||
atomShellDownloadDir = path.join(os.tmpdir(), 'atom-cached-atom-shells')
|
||||
|
||||
home = if process.platform is 'win32' then process.env.USERPROFILE else process.env.HOME
|
||||
atomShellDownloadDir = path.join(home, '.atom', 'atom-shell')
|
||||
|
||||
symbolsDir = path.join(buildDir, 'Atom.breakpad.syms')
|
||||
shellAppDir = path.join(buildDir, appName)
|
||||
if process.platform is 'win32'
|
||||
contentsDir = shellAppDir
|
||||
appDir = path.join(shellAppDir, 'resources', 'app')
|
||||
installDir ?= path.join(process.env.ProgramFiles, appName)
|
||||
killCommand = 'taskkill /F /IM atom.exe'
|
||||
else if process.platform is 'darwin'
|
||||
contentsDir = path.join(shellAppDir, 'Contents')
|
||||
appDir = path.join(contentsDir, 'Resources', 'app')
|
||||
installDir ?= path.join('/Applications', appName)
|
||||
killCommand = 'pkill -9 Atom'
|
||||
else
|
||||
contentsDir = shellAppDir
|
||||
appDir = path.join(shellAppDir, 'resources', 'app')
|
||||
installDir ?= process.env.INSTALL_PREFIX ? '/usr/local'
|
||||
killCommand ='pkill -9 Atom'
|
||||
|
||||
coffeeConfig =
|
||||
glob_to_multiple:
|
||||
@@ -90,6 +96,8 @@ module.exports = (grunt) ->
|
||||
csonConfig =
|
||||
options:
|
||||
rootObject: true
|
||||
cachePath: path.join(home, '.atom', 'compile-cache', 'grunt-cson')
|
||||
|
||||
glob_to_multiple:
|
||||
expand: true
|
||||
src: [
|
||||
@@ -213,7 +221,7 @@ module.exports = (grunt) ->
|
||||
|
||||
shell:
|
||||
'kill-atom':
|
||||
command: 'pkill -9 Atom'
|
||||
command: killCommand
|
||||
options:
|
||||
stdout: false
|
||||
stderr: false
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
"grunt": "~0.4.1",
|
||||
"grunt-cli": "~0.1.9",
|
||||
"grunt-coffeelint": "git+https://github.com/atom/grunt-coffeelint.git",
|
||||
"grunt-contrib-csslint": "~0.1.2",
|
||||
"grunt-contrib-coffee": "~0.9.0",
|
||||
"grunt-contrib-csslint": "~0.1.2",
|
||||
"grunt-contrib-less": "~0.8.0",
|
||||
"grunt-cson": "0.8.0",
|
||||
"grunt-cson": "0.10.0",
|
||||
"grunt-download-atom-shell": "~0.8.0",
|
||||
"grunt-lesslint": "0.13.0",
|
||||
"grunt-markdown": "~0.4.0",
|
||||
@@ -27,15 +27,15 @@
|
||||
"json-front-matter": "~0.1.3",
|
||||
"legal-eagle": "~0.4.0",
|
||||
"minidump": "~0.7",
|
||||
"read-package-json": "1.1.8",
|
||||
"normalize-package-data": "0.2.12",
|
||||
"npm": "~1.4.5",
|
||||
"rcedit": "~0.1.2",
|
||||
"read-package-json": "1.1.8",
|
||||
"request": "~2.27.0",
|
||||
"rimraf": "~2.2.2",
|
||||
"runas": "0.5.x",
|
||||
"runas": "~1.0.1",
|
||||
"underscore-plus": "1.x",
|
||||
"unzip": "~0.1.9",
|
||||
"vm-compatibility-layer": "~0.1.0",
|
||||
"npm": "~1.4.5"
|
||||
"vm-compatibility-layer": "~0.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,9 +14,9 @@ module.exports = (grunt) ->
|
||||
mkdir path.dirname(buildDir)
|
||||
|
||||
if process.platform is 'darwin'
|
||||
cp 'atom-shell/Atom.app', shellAppDir
|
||||
cp 'atom-shell/Atom.app', shellAppDir, filter: /default_app/
|
||||
else
|
||||
cp 'atom-shell', shellAppDir
|
||||
cp 'atom-shell', shellAppDir, filter: /default_app/
|
||||
|
||||
mkdir appDir
|
||||
|
||||
@@ -45,19 +45,45 @@ module.exports = (grunt) ->
|
||||
path.join('git-utils', 'deps')
|
||||
path.join('oniguruma', 'deps')
|
||||
path.join('less', 'dist')
|
||||
path.join('less', 'test')
|
||||
path.join('bootstrap', 'docs')
|
||||
path.join('bootstrap', 'examples')
|
||||
path.join('bootstrap', '_config.yml')
|
||||
path.join('bootstrap', '_includes')
|
||||
path.join('bootstrap', '_layouts')
|
||||
path.join('npm', 'doc')
|
||||
path.join('npm', 'html')
|
||||
path.join('npm', 'man')
|
||||
path.join('npm', 'node_modules', '.bin', 'beep')
|
||||
path.join('npm', 'node_modules', '.bin', 'clear')
|
||||
path.join('npm', 'node_modules', '.bin', 'starwars')
|
||||
path.join('pegjs', 'examples')
|
||||
path.join('plist', 'tests')
|
||||
path.join('xmldom', 'test')
|
||||
path.join('jasmine-reporters', 'ext')
|
||||
path.join('jasmine-node', 'node_modules', 'gaze')
|
||||
path.join('jasmine-node', 'spec')
|
||||
path.join('node_modules', 'nan')
|
||||
path.join('build', 'binding.Makefile')
|
||||
path.join('build', 'config.gypi')
|
||||
path.join('build', 'gyp-mac-tool')
|
||||
path.join('build', 'Makefile')
|
||||
path.join('build', 'Release', 'obj.target')
|
||||
path.join('build', 'Release', 'obj')
|
||||
path.join('build', 'Release', '.deps')
|
||||
path.join('vendor', 'apm')
|
||||
path.join('resources', 'mac')
|
||||
path.join('resources', 'win')
|
||||
|
||||
# These are only require in dev mode when the grammar isn't precompiled
|
||||
path.join('atom-keymap', 'node_modules', 'loophole')
|
||||
path.join('atom-keymap', 'node_modules', 'pegjs')
|
||||
path.join('atom-keymap', 'node_modules', '.bin', 'pegjs')
|
||||
path.join('snippets', 'node_modules', 'loophole')
|
||||
path.join('snippets', 'node_modules', 'pegjs')
|
||||
path.join('snippets', 'node_modules', '.bin', 'pegjs')
|
||||
|
||||
'.DS_Store'
|
||||
'.jshintrc'
|
||||
'.npmignore'
|
||||
'.pairs'
|
||||
'.travis.yml'
|
||||
]
|
||||
ignoredPaths = ignoredPaths.map (ignoredPath) -> _.escapeRegExp(ignoredPath)
|
||||
|
||||
@@ -65,21 +91,56 @@ module.exports = (grunt) ->
|
||||
ignoredPaths.push "#{_.escapeRegExp(path.join('spellchecker', 'vendor', 'hunspell') + path.sep)}.*"
|
||||
ignoredPaths.push "#{_.escapeRegExp(path.join('build', 'Release') + path.sep)}.*\\.pdb"
|
||||
|
||||
# Ignore *.cc and *.h files from native modules
|
||||
ignoredPaths.push "#{_.escapeRegExp(path.join('ctags', 'src') + path.sep)}.*\\.(cc|h)*"
|
||||
ignoredPaths.push "#{_.escapeRegExp(path.join('git-utils', 'src') + path.sep)}.*\\.(cc|h)*"
|
||||
ignoredPaths.push "#{_.escapeRegExp(path.join('keytar', 'src') + path.sep)}.*\\.(cc|h)*"
|
||||
ignoredPaths.push "#{_.escapeRegExp(path.join('nslog', 'src') + path.sep)}.*\\.(cc|h)*"
|
||||
ignoredPaths.push "#{_.escapeRegExp(path.join('oniguruma', 'src') + path.sep)}.*\\.(cc|h)*"
|
||||
ignoredPaths.push "#{_.escapeRegExp(path.join('pathwatcher', 'src') + path.sep)}.*\\.(cc|h)*"
|
||||
ignoredPaths.push "#{_.escapeRegExp(path.join('runas', 'src') + path.sep)}.*\\.(cc|h)*"
|
||||
ignoredPaths.push "#{_.escapeRegExp(path.join('scrollbar-style', 'src') + path.sep)}.*\\.(cc|h)*"
|
||||
ignoredPaths.push "#{_.escapeRegExp(path.join('spellchecker', 'src') + path.sep)}.*\\.(cc|h)*"
|
||||
|
||||
# Ignore build files
|
||||
ignoredPaths.push "#{_.escapeRegExp(path.sep)}binding\\.gyp$"
|
||||
ignoredPaths.push "#{_.escapeRegExp(path.sep)}.+\\.target.mk$"
|
||||
ignoredPaths.push "#{_.escapeRegExp(path.sep)}linker\\.lock$"
|
||||
ignoredPaths.push "#{_.escapeRegExp(path.join('build', 'Release') + path.sep)}.+\\.node\\.dSYM"
|
||||
|
||||
# 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})"
|
||||
|
||||
testFolderPattern = new RegExp("#{_.escapeRegExp(path.sep)}te?sts?#{_.escapeRegExp(path.sep)}")
|
||||
exampleFolderPattern = new RegExp("#{_.escapeRegExp(path.sep)}examples?#{_.escapeRegExp(path.sep)}")
|
||||
benchmarkFolderPattern = new RegExp("#{_.escapeRegExp(path.sep)}benchmarks?#{_.escapeRegExp(path.sep)}")
|
||||
|
||||
nodeModulesFilter = new RegExp(ignoredPaths.join('|'))
|
||||
filterNodeModule = (pathToCopy) ->
|
||||
return true if benchmarkFolderPattern.test(pathToCopy)
|
||||
|
||||
pathToCopy = path.resolve(pathToCopy)
|
||||
nodeModulesFilter.test(pathToCopy) or testFolderPattern.test(pathToCopy) or exampleFolderPattern.test(pathToCopy)
|
||||
|
||||
packageFilter = new RegExp("(#{ignoredPaths.join('|')})|(.+\\.(cson|coffee)$)")
|
||||
filterPackage = (pathToCopy) ->
|
||||
return true if benchmarkFolderPattern.test(pathToCopy)
|
||||
|
||||
pathToCopy = path.resolve(pathToCopy)
|
||||
packageFilter.test(pathToCopy) or testFolderPattern.test(pathToCopy) or exampleFolderPattern.test(pathToCopy)
|
||||
|
||||
for directory in nonPackageDirectories
|
||||
cp directory, path.join(appDir, directory), filter: nodeModulesFilter
|
||||
cp directory, path.join(appDir, directory), filter: filterNodeModule
|
||||
|
||||
for directory in packageDirectories
|
||||
cp directory, path.join(appDir, directory), filter: packageFilter
|
||||
cp directory, path.join(appDir, directory), filter: filterPackage
|
||||
|
||||
cp 'spec', path.join(appDir, 'spec')
|
||||
cp 'src', path.join(appDir, 'src'), filter: /.+\.(cson|coffee)$/
|
||||
cp 'static', path.join(appDir, 'static')
|
||||
cp 'apm', path.join(appDir, 'apm'), filter: nodeModulesFilter
|
||||
cp 'apm', path.join(appDir, 'apm'), filter: filterNodeModule
|
||||
|
||||
if process.platform is 'darwin'
|
||||
grunt.file.recurse path.join('resources', 'mac'), (sourcePath, rootDirectory, subDirectory='', filename) ->
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
path = require 'path'
|
||||
|
||||
module.exports = (grunt) ->
|
||||
{spawn} = require('./task-helpers')(grunt)
|
||||
|
||||
grunt.registerTask 'codesign', 'Codesign the app', ->
|
||||
return unless process.platform is 'darwin'
|
||||
|
||||
done = @async()
|
||||
|
||||
if process.env.XCODE_KEYCHAIN
|
||||
if process.platform is 'darwin' and process.env.XCODE_KEYCHAIN
|
||||
unlockKeychain (error) ->
|
||||
if error?
|
||||
done(error)
|
||||
@@ -22,6 +22,15 @@ module.exports = (grunt) ->
|
||||
spawn {cmd, args}, (error) -> callback(error)
|
||||
|
||||
signApp = (callback) ->
|
||||
cmd = 'codesign'
|
||||
args = ['-f', '-v', '-s', 'Developer ID Application: GitHub', grunt.config.get('atom.shellAppDir')]
|
||||
spawn {cmd, args}, (error) -> callback(error)
|
||||
switch process.platform
|
||||
when 'darwin'
|
||||
cmd = 'codesign'
|
||||
args = ['-f', '-v', '-s', 'Developer ID Application: GitHub', grunt.config.get('atom.shellAppDir')]
|
||||
spawn {cmd, args}, (error) -> callback(error)
|
||||
when 'win32'
|
||||
spawn {cmd: 'taskkill', args: ['/F', '/IM', 'atom.exe']}, ->
|
||||
cmd = process.env.JANKY_SIGNTOOL ? 'signtool'
|
||||
args = [path.join(grunt.config.get('atom.shellAppDir'), 'atom.exe')]
|
||||
spawn {cmd, args}, (error) -> callback(error)
|
||||
else
|
||||
callback()
|
||||
|
||||
@@ -4,17 +4,13 @@ _ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
runas = null
|
||||
|
||||
fillTemplate = (filePath, data) ->
|
||||
template = _.template(String(fs.readFileSync(filePath + '.in')))
|
||||
filled = template(data)
|
||||
fs.writeFileSync(filePath, filled)
|
||||
|
||||
module.exports = (grunt) ->
|
||||
{cp, mkdir, rm} = require('./task-helpers')(grunt)
|
||||
|
||||
grunt.registerTask 'install', 'Install the built application', ->
|
||||
installDir = grunt.config.get('atom.installDir')
|
||||
shellAppDir = grunt.config.get('atom.shellAppDir')
|
||||
|
||||
if process.platform is 'win32'
|
||||
runas ?= require 'runas'
|
||||
copyFolder = path.resolve 'script', 'copy-folder.cmd'
|
||||
@@ -32,7 +28,6 @@ module.exports = (grunt) ->
|
||||
shareDir = path.join(installDir, 'share', 'atom')
|
||||
|
||||
iconName = path.join(shareDir,'resources','app','resources','atom.png')
|
||||
desktopFile = path.join('resources', 'linux', 'Atom.desktop')
|
||||
|
||||
mkdir binDir
|
||||
cp 'atom.sh', path.join(binDir, 'atom')
|
||||
@@ -42,13 +37,17 @@ module.exports = (grunt) ->
|
||||
|
||||
# Create Atom.desktop if installation not in temporary folder
|
||||
tmpDir = if process.env.TMPDIR? then process.env.TMPDIR else '/tmp'
|
||||
desktopInstallFile = path.join(installDir,'share','applications','Atom.desktop')
|
||||
if installDir.indexOf(tmpDir) isnt 0
|
||||
mkdir path.dirname(desktopInstallFile)
|
||||
desktopFile = path.join('resources', 'linux', 'Atom.desktop.in')
|
||||
desktopInstallFile = path.join(installDir, 'share', 'applications', 'Atom.desktop')
|
||||
|
||||
{description} = grunt.file.readJSON('package.json')
|
||||
installDir = path.join(installDir,'.') # To prevent "Exec=/usr/local//share/atom/atom"
|
||||
fillTemplate(desktopFile, {description, installDir, iconName})
|
||||
cp desktopFile, desktopInstallFile
|
||||
iconName = path.join(shareDir, 'resources', 'app', 'resources', 'atom.png')
|
||||
installDir = path.join(installDir, '.') # To prevent "Exec=/usr/local//share/atom/atom"
|
||||
template = _.template(String(fs.readFileSync(desktopFile)))
|
||||
filled = template({description, installDir, iconName})
|
||||
|
||||
grunt.file.write(desktopInstallFile, filled)
|
||||
|
||||
# Create relative symbol link for apm.
|
||||
process.chdir(binDir)
|
||||
|
||||
@@ -2,14 +2,17 @@ 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)
|
||||
|
||||
fillTemplate = (filePath, data) ->
|
||||
template = _.template(String(fs.readFileSync("#{filePath}.in")))
|
||||
filled = template(data)
|
||||
|
||||
outputPath = path.join(grunt.config.get('atom.buildDir'), path.basename(filePath))
|
||||
grunt.file.write(outputPath, filled)
|
||||
outputPath
|
||||
|
||||
grunt.registerTask 'mkdeb', 'Create debian package', ->
|
||||
done = @async()
|
||||
|
||||
@@ -27,13 +30,11 @@ module.exports = (grunt) ->
|
||||
iconName = 'atom'
|
||||
data = {name, version, description, section, arch, maintainer, installDir, iconName}
|
||||
|
||||
control = path.join('resources', 'linux', 'debian', 'control')
|
||||
fillTemplate(control, data)
|
||||
desktop = path.join('resources', 'linux', 'Atom.desktop')
|
||||
fillTemplate(desktop, data)
|
||||
controlFilePath = fillTemplate(path.join('resources', 'linux', 'debian', 'control'), data)
|
||||
desktopFilePath = fillTemplate(path.join('resources', 'linux', 'Atom.desktop'), data)
|
||||
icon = path.join('resources', 'atom.png')
|
||||
buildDir = grunt.config.get('atom.buildDir')
|
||||
|
||||
cmd = path.join('script', 'mkdeb')
|
||||
args = [version, arch, control, desktop, icon, buildDir]
|
||||
args = [version, arch, controlFilePath, desktopFilePath, icon, buildDir]
|
||||
spawn({cmd, args}, done)
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
path = require 'path'
|
||||
|
||||
module.exports = (grunt) ->
|
||||
grunt.registerTask 'output-build-filetypes', 'Log counts for each filetype in the built application', ->
|
||||
shellAppDir = grunt.config.get('atom.shellAppDir')
|
||||
|
||||
types = {}
|
||||
grunt.file.recurse shellAppDir, (absolutePath, rootPath, relativePath, fileName) ->
|
||||
extension = path.extname(fileName) or fileName
|
||||
types[extension] ?= 0
|
||||
types[extension]++
|
||||
|
||||
extensions = Object.keys(types).sort (extension1, extension2) ->
|
||||
diff = types[extension2] - types[extension1]
|
||||
if diff is 0
|
||||
extension1.toLowerCase().localeCompare(extension2.toLowerCase())
|
||||
else
|
||||
diff
|
||||
|
||||
extensions.forEach (extension) ->
|
||||
grunt.log.error "#{extension}: #{types[extension]}"
|
||||
@@ -0,0 +1,18 @@
|
||||
path = require 'path'
|
||||
|
||||
module.exports = (grunt) ->
|
||||
grunt.registerTask 'output-long-paths', 'Log long paths in the built application', ->
|
||||
shellAppDir = grunt.config.get('atom.shellAppDir')
|
||||
|
||||
longPaths = []
|
||||
grunt.file.recurse shellAppDir, (absolutePath, rootPath, relativePath, fileName) ->
|
||||
if relativePath
|
||||
fullPath = path.join(relativePath, fileName)
|
||||
else
|
||||
fullPath = fileName
|
||||
longPaths.push(fullPath) if fullPath.length >= 200
|
||||
|
||||
longPaths.sort (longPath1, longPath2) -> longPath2.length - longPath1.length
|
||||
|
||||
longPaths.forEach (longPath) ->
|
||||
grunt.log.error "#{longPath.length} character path: #{longPath}"
|
||||
@@ -9,10 +9,12 @@ module.exports = (grunt) ->
|
||||
['atom-dark-ui', 'atom-light-syntax']
|
||||
['atom-dark-ui', 'solarized-dark-syntax']
|
||||
['atom-dark-ui', 'base16-tomorrow-dark-theme']
|
||||
['atom-dark-ui', 'base16-tomorrow-light-theme']
|
||||
['atom-light-ui', 'atom-light-syntax']
|
||||
['atom-light-ui', 'atom-dark-syntax']
|
||||
['atom-light-ui', 'solarized-dark-syntax']
|
||||
['atom-light-ui', 'base16-tomorrow-dark-theme']
|
||||
['atom-light-ui', 'base16-tomorrow-light-theme']
|
||||
]
|
||||
|
||||
directory = path.join(grunt.config.get('atom.appDir'), 'less-compile-cache')
|
||||
|
||||
@@ -53,9 +53,7 @@ module.exports = (grunt) ->
|
||||
continue unless isAtomPackage(packagePath)
|
||||
packageSpecQueue.push(packagePath)
|
||||
|
||||
# TODO: Restore concurrency on Windows
|
||||
packageSpecQueue.concurrency = 1 unless process.platform is 'win32'
|
||||
|
||||
packageSpecQueue.concurrency = 1
|
||||
packageSpecQueue.drain = -> callback(null, failedPackages)
|
||||
|
||||
runCoreSpecs = (callback) ->
|
||||
@@ -105,4 +103,9 @@ module.exports = (grunt) ->
|
||||
failures.push "atom core" if coreSpecFailed
|
||||
|
||||
grunt.log.error("[Error]".red + " #{failures.join(', ')} spec(s) failed") if failures.length > 0
|
||||
done(!coreSpecFailed and failedPackages.length == 0)
|
||||
|
||||
if process.platform is 'win32' and process.env.JANKY_SHA1
|
||||
# Package specs are still flaky on Windows CI
|
||||
done(!coreSpecFailed)
|
||||
else
|
||||
done(!coreSpecFailed and failedPackages.length == 0)
|
||||
|
||||
@@ -7,7 +7,7 @@ module.exports = (grunt) ->
|
||||
grunt.fatal("Cannot copy non-existent #{source.cyan} to #{destination.cyan}")
|
||||
|
||||
copyFile = (sourcePath, destinationPath) ->
|
||||
return if filter?.test(sourcePath)
|
||||
return if filter?(sourcePath) or filter?.test?(sourcePath)
|
||||
|
||||
stats = fs.lstatSync(sourcePath)
|
||||
if stats.isSymbolicLink()
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
# API Guidelines
|
||||
|
||||
__Note__: These are not all in practice yet. We are still sorting this out, and plan to move the entire API this way.
|
||||
|
||||
## General Guidelines
|
||||
|
||||
We should strive to have only one way to do something, and make it clear what that way is.
|
||||
|
||||
__Bad__
|
||||
* Several ways to get the `Editor` model from the view.
|
||||
* `EditorView.editor`
|
||||
* `EditorView.getModel()`
|
||||
* `EditorView.getEditor()`
|
||||
* Delegated methods on the views when there is a model counterpart
|
||||
* `Editor.toggleSoftTabs()`
|
||||
* `EditorView.toggleSoftTabs()`
|
||||
|
||||
__Good__
|
||||
* One way to get the `Editor` model from the view
|
||||
* `EditorView.getModel()`
|
||||
* Use the method on the model
|
||||
* `Editor.toggleSoftTabs()`
|
||||
* One clear way to subscribe to events
|
||||
* `subscription = @subscribe thing, 'event', -> ...`
|
||||
* One clear way to unsubscribe to events
|
||||
* `subscription.off()` only; not `thing.off 'event', -> ...`
|
||||
|
||||
## Essential vs Extended
|
||||
|
||||
There are two groups of classes / methods. We break them up to facilitate a gentle introduction into the API and help authors build a knowledge foundation more quickly.
|
||||
|
||||
### Essential
|
||||
|
||||
These are classes, methods, and concepts nearly every package author will need to know about. Need to create commands? Subscribe to atom events? Get a reference to all the editors? Highlight a line in the editor? Patterns and methods for these things will be explained in the essential API.
|
||||
|
||||
We want to keep the essential API minimal and focused.
|
||||
|
||||
### Extended
|
||||
|
||||
The extended API contains The Power. Need to move one cursor independent of the others? Want to do some processing on the markers? You can do it with the extended API.
|
||||
|
||||
## View / Model
|
||||
|
||||
Operations on Views should be limited to DOM manipulation only. A package author should only need access to, say, the `EditorView` when it needs to directly modify the `EditorView`'s DOM.
|
||||
|
||||
## Properties
|
||||
|
||||
No public properties. Use methods instead.
|
||||
|
||||
## Methods
|
||||
|
||||
### Naming
|
||||
|
||||
We strive to fit the [Objective C][naming] naming conventions for the sake of readability.
|
||||
|
||||
* Be descriptive, always write out the whole word. `selection` not `sel`, `cursor` not `cur`.
|
||||
* Describe the arguments names in the method name eg. `decorationsForMarker(marker)`, `objectAtIndex(index)`
|
||||
* Use `get` prefix only when there are no arguments `getCursors()`, `getLastCursor()`, `cursorForMarker(marker)`
|
||||
* Prefix bool methods with `is` eg. `isDefault()`
|
||||
|
||||
Array accessor methods would be written as follows
|
||||
|
||||
```coffee
|
||||
getObjects()
|
||||
addObject(object)
|
||||
removeObject(object)
|
||||
removeObjectAtIndex(index)
|
||||
objectAtIndex(index)
|
||||
objectsForThing(thing)
|
||||
objectForThing(thing)
|
||||
```
|
||||
|
||||
## Events
|
||||
|
||||
There will be no `off()` method on objects. `on()` will return a subscription object which contains the `off()` method.
|
||||
|
||||
* Events should be emitted with one event object as an argument, rather than a bunch of arguments.
|
||||
* If an event is cancelable, it will provide a `cancel` function in the event object.
|
||||
|
||||
### Naming
|
||||
|
||||
Past tense. ???
|
||||
|
||||
## Documentation
|
||||
|
||||
Comment doc strings on methods, events, etc
|
||||
|
||||
* how to doc sections?
|
||||
* events?
|
||||
* props?
|
||||
* callback args?
|
||||
* option hashes?
|
||||
|
||||
### Method organization
|
||||
|
||||
* All methods in classes should be grouped into sections by usage pattern.
|
||||
* Methods within a section should be ordered with the most commonly used methods at the top. `Essential` methods always go above `Extended` methods.
|
||||
* Sections should be ordered in the class with the most commonly used sections at the top.
|
||||
|
||||
A section:
|
||||
|
||||
```coffee
|
||||
###
|
||||
Section: Reading Text
|
||||
###
|
||||
|
||||
# Essential: Returns a {String} representing the entire contents of the editor.
|
||||
getText: -> @buffer.getText()
|
||||
```
|
||||
|
||||
|
||||
[naming]:https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingMethods.html
|
||||
+50
-8
@@ -1,4 +1,4 @@
|
||||
## Atom.io package and update API
|
||||
# Atom.io package and update API
|
||||
|
||||
This guide describes the web API used by [apm](https://github.com/atom/apm) and
|
||||
Atom. The vast majority of use cases are met by the `apm` command-line tool,
|
||||
@@ -8,6 +8,8 @@ and making sure you have pushed your git tag. In fact, Atom itself shells out to
|
||||
uses `apm`, see the [PackageManager class](https://github.com/atom/settings-view/blob/master/lib/package-manager.coffee)
|
||||
in the `settings-view` package.
|
||||
|
||||
*This API should be considered pre-release and is subject to change (though significant breaking changes are unlikely).*
|
||||
|
||||
### Authorization
|
||||
|
||||
For calls to the API that require authentication, provide a valid token from your
|
||||
@@ -17,12 +19,18 @@ For calls to the API that require authentication, provide a valid token from you
|
||||
|
||||
All requests that take parameters require `application/json`.
|
||||
|
||||
## Resources
|
||||
# API Resources
|
||||
|
||||
### Packages
|
||||
## Packages
|
||||
|
||||
### Listing packages
|
||||
|
||||
#### GET /api/packages
|
||||
|
||||
Parameters:
|
||||
|
||||
- **page** (optional)
|
||||
|
||||
Returns a list of all packages in the following format:
|
||||
```json
|
||||
[
|
||||
@@ -40,6 +48,17 @@ Returns a list of all packages in the following format:
|
||||
]
|
||||
```
|
||||
|
||||
Results are paginated 30 at a time, and links to the next and last pages are
|
||||
provided in the `Link` header:
|
||||
|
||||
```
|
||||
Link: <https://www.atom.io/api/packages?page=1>; rel="self",
|
||||
<https://www.atom.io/api/packages?page=41>; rel="last",
|
||||
<https://www.atom.io/api/packages?page=2>; rel="next"
|
||||
```
|
||||
|
||||
### Showing package details
|
||||
|
||||
#### GET /api/packages/:package_name
|
||||
|
||||
Returns package details and versions for a single package
|
||||
@@ -68,6 +87,8 @@ Returns:
|
||||
}
|
||||
```
|
||||
|
||||
### Creating a package
|
||||
|
||||
#### POST /api/packages
|
||||
|
||||
Create a new package; requires authentication.
|
||||
@@ -92,6 +113,7 @@ Returns:
|
||||
- The package.json at owner/repo isn't valid
|
||||
- **409** - A package by that name already exists
|
||||
|
||||
### Deleting a package
|
||||
|
||||
#### DELETE /api/packages/:package_name
|
||||
|
||||
@@ -103,6 +125,13 @@ Returns:
|
||||
- **400** - Repository is inaccessible
|
||||
- **401** - Unauthorized
|
||||
|
||||
### Renaming a package
|
||||
|
||||
Packages are renamed by publishing a new version with the name changed in `package.json`
|
||||
See [Creating a new package version](#creating-a-new-package-version) for details.
|
||||
|
||||
Requests made to the previous name will forward to the new name.
|
||||
|
||||
### Package Versions
|
||||
|
||||
#### GET /api/packages/:package_name/versions/:version_name
|
||||
@@ -144,7 +173,9 @@ Returns `package.json` with `dist` key added for e.g. tarball download:
|
||||
|
||||
#### POST /api/packages/:package_name/versions
|
||||
|
||||
Creates a new package version from a git tag; requires authentication.
|
||||
Creates a new package version from a git tag; requires authentication. If `rename`
|
||||
is not `true`, the `name` field in `package.json` *must* match the current package
|
||||
name.
|
||||
|
||||
#### Parameters
|
||||
|
||||
@@ -152,14 +183,15 @@ Creates a new package version from a git tag; requires authentication.
|
||||
that the version name will not be taken from the tag, but from the `version`
|
||||
key in the `package.json` file at that ref. The authenticating user *must* have
|
||||
access to the package repository.
|
||||
- **rename** - Boolean indicating whether this version contains a new name for the package.
|
||||
|
||||
#### Returns
|
||||
|
||||
- **201** - Successfully created. Returns created version.
|
||||
- **400** - Git tag not found / Repository inaccessible
|
||||
- **400** - Git tag not found / Repository inaccessible / package.json invalid
|
||||
- **409** - Version exists
|
||||
|
||||
### Delete a version
|
||||
### Deleting a version
|
||||
|
||||
#### DELETE /api/packages/:package_name/versions/:version_name
|
||||
|
||||
@@ -172,7 +204,9 @@ you'll need to increment the version when republishing.
|
||||
Returns 204 No Content
|
||||
|
||||
|
||||
### Stars
|
||||
## Stars
|
||||
|
||||
### Listing user stars
|
||||
|
||||
#### GET /api/users/:login/stars
|
||||
|
||||
@@ -186,18 +220,24 @@ List the authenticated user's starred packages; requires authentication.
|
||||
|
||||
Return value is similar to **GET /api/packages**
|
||||
|
||||
### Starring a package
|
||||
|
||||
#### POST /api/packages/:name/star
|
||||
|
||||
Star a package; requires authentication.
|
||||
|
||||
Returns a package.
|
||||
|
||||
### Unstarring a package
|
||||
|
||||
#### DELETE /api/packages/:name/star
|
||||
|
||||
Unstar a package; requires authentication.
|
||||
|
||||
Returns 204 No Content.
|
||||
|
||||
### Listing a package's stargazers
|
||||
|
||||
#### GET /api/packages/:name/stargazers
|
||||
|
||||
List the users that have starred a package.
|
||||
@@ -211,7 +251,9 @@ Returns a list of user objects:
|
||||
]
|
||||
```
|
||||
|
||||
### Atom updates
|
||||
## Atom updates
|
||||
|
||||
### Listing Atom updates
|
||||
|
||||
#### GET /api/updates
|
||||
|
||||
|
||||
@@ -6,38 +6,52 @@ Ubuntu LTS 12.04 64-bit is the recommended platform.
|
||||
|
||||
* OS with 64-bit or 32-bit architecture
|
||||
* C++ toolchain
|
||||
* on Ubuntu/Debian: `sudo apt-get install build-essential`
|
||||
* on Fedora: `sudo yum --assumeyes install make gcc gcc-c++ glibc-devel`
|
||||
* git
|
||||
* [node.js](http://nodejs.org/download/) v0.10.x
|
||||
* [Ubuntu/Debian/Mint instructions](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager#ubuntu-mint-elementary-os)
|
||||
* [Fedora instructions](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager#fedora)
|
||||
* [npm](http://www.npmjs.org/) v1.4.x
|
||||
* `npm` comes with node.js so no explicit installation is needed here.
|
||||
* You can check `npm` 1.4 or above is installed by running `npm -v`.
|
||||
* [npm](http://www.npmjs.org/) v1.4.x (bundled with node.js)
|
||||
* `npm -v` to check the version.
|
||||
* `npm config set python /usr/bin/python2 -g` to ensure that gyp uses python2.
|
||||
* You might need to run this command as `sudo`, depending on how you have set up [npm](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager#ubuntu-mint-elementary-os).
|
||||
* libgnome-keyring-dev
|
||||
* on Ubuntu/Debian: `sudo apt-get install libgnome-keyring-dev`
|
||||
* on Fedora: `sudo yum --assumeyes install libgnome-keyring-devel`
|
||||
* on other distributions refer to the manual on how to install packages
|
||||
* `npm config set python /usr/bin/python2 -g` to ensure that gyp uses Python 2
|
||||
* This command may require `sudo` depending on how you have
|
||||
[configured npm](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager#ubuntu-mint-elementary-os).
|
||||
* Git
|
||||
* on Ubuntu/Debian: `sudo apt-get install git`
|
||||
* on Fedora: `sudo yum install git-core`
|
||||
|
||||
### Ubuntu / Debian
|
||||
* `sudo apt-get install build-essential git libgnome-keyring-dev`
|
||||
* Instructions for [node.js](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager#ubuntu-mint-elementary-os).
|
||||
|
||||
### Fedora
|
||||
* `sudo yum --assumeyes install make gcc gcc-c++ glibc-devel git-core libgnome-keyring-devel`
|
||||
* Instructions for [node.js](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager#fedora).
|
||||
|
||||
### Arch
|
||||
* `sudo pacman -S base-devel git nodejs libgnome-keyring`
|
||||
* `export PYTHON=/usr/bin/python2` before building Atom.
|
||||
|
||||
## Instructions
|
||||
|
||||
```sh
|
||||
git clone https://github.com/atom/atom
|
||||
cd atom
|
||||
script/build # Creates application at $TMPDIR/atom-build/Atom
|
||||
sudo script/grunt install # Installs command to /usr/local/bin/atom
|
||||
script/grunt mkdeb # Generates a .deb package at $TMPDIR/atom-build
|
||||
```
|
||||
If you have problems with permissions don't forget to prefix with `sudo`
|
||||
|
||||
Create the atom application at `$TMPDIR/atom-build/Atom`:
|
||||
|
||||
```sh
|
||||
script/build
|
||||
```
|
||||
|
||||
Install the `atom` and `apm` commands to `/usr/local/bin`:
|
||||
|
||||
```sh
|
||||
sudo script/grunt install
|
||||
```
|
||||
|
||||
Generate a `.deb` package at `$TMPDIR/atom-build`: (*optional*)
|
||||
|
||||
```sh
|
||||
script/grunt mkdeb
|
||||
```
|
||||
|
||||
Use the newly installed atom by restarting any running atom instances.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
|
||||
### Exception: "TypeError: Unable to watch path"
|
||||
|
||||
If you get following error with a big traceback right after Atom starts:
|
||||
|
||||
@@ -35,10 +35,14 @@
|
||||
|
||||
## Why do I have to use GitHub for Windows?
|
||||
|
||||
You don't, You can use your existing Git! GitHub for Windows's Git Shell is just
|
||||
easier to set up. You need to have Posix tools in your `%PATH%` (i.e. `grep`,
|
||||
`sed`, et al.), which isn't the default configuration when you install Git. To
|
||||
fix this, you probably need to fiddle with your system PATH.
|
||||
You don't. You can use your existing Git! GitHub for Windows's Git Shell is just
|
||||
easier to set up.
|
||||
|
||||
If you _prefer_ using your existing Git installation, make sure git's cmd directory is in your PATH env variable (e.g. `C:\Program Files (x86)\Git\cmd`) before you open your powershell or command window.
|
||||
Note that you may have to open your command window as administrator. For powershell that doesn't seem to always be the case, though.
|
||||
|
||||
If none of this works, do install Github for Windows and use its Git shell. Makes life easier.
|
||||
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
@@ -62,5 +66,11 @@ fix this, you probably need to fiddle with your system PATH.
|
||||
* https://github.com/TooTallNate/node-gyp/issues/297
|
||||
* https://code.google.com/p/gyp/issues/detail?id=393
|
||||
|
||||
* Other `node-gyp` errors on first build attempt, even though the right node and python versions are installed.
|
||||
* Do try the build command one more time, as experience shows it often works on second try in many of these cases.
|
||||
|
||||
|
||||
### Windows build error reports in atom/atom
|
||||
* Use [this search](https://github.com/atom/atom/search?q=label%3Abuild-error+label%3Awindows&type=Issues) to get a list of reports about build errors on Windows.
|
||||
* If all fails, use [this search](https://github.com/atom/atom/search?q=label%3Abuild-error+label%3Awindows&type=Issues) to get a list of reports about build errors on Windows, and see if yours has already been reported.
|
||||
|
||||
* If it hasn't, please open a new issue with your Windows version 32/64bit and a print/screenshot of your build output, incl. the node and python versions.
|
||||
|
||||
@@ -227,15 +227,16 @@ or one of its parents has the `tree-view` class applied to it.
|
||||
|
||||
You can also add separators and submenus to your context menus. To add a
|
||||
submenu, pass in another object instead of a command. To add a separator, use
|
||||
`-` for the name and command of the item.
|
||||
`-` for the command of the item.
|
||||
|
||||
```coffeescript
|
||||
'context-menu':
|
||||
'.workspace':
|
||||
'Inspect Element': 'core:inspect'
|
||||
'-': '-'
|
||||
'Separator': '-'
|
||||
'Text':
|
||||
'Select All': 'core:select-all'
|
||||
'Another Separator': '-'
|
||||
'Deleted Selected Text': 'core:delete'
|
||||
```
|
||||
|
||||
|
||||
@@ -169,7 +169,7 @@ For example, to change the color of the cursor, you could add the following
|
||||
rule to your _~/.atom/styles.less_ file:
|
||||
|
||||
```less
|
||||
.editor .cursor {
|
||||
.editor.is-focused .cursor {
|
||||
border-color: pink;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -15,10 +15,15 @@ unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
|
||||
module.exports.$ = $
|
||||
module.exports.$$ = $$
|
||||
module.exports.$$$ = $$$
|
||||
module.exports.EditorView = require '../src/editor-view'
|
||||
if atom.config.get('core.useReactMiniEditors')
|
||||
module.exports.EditorView = require '../src/react-editor-view'
|
||||
else
|
||||
module.exports.EditorView = require '../src/editor-view'
|
||||
module.exports.ScrollView = require '../src/scroll-view'
|
||||
module.exports.SelectListView = require '../src/select-list-view'
|
||||
module.exports.Task = require '../src/task'
|
||||
module.exports.View = View
|
||||
module.exports.WorkspaceView = require '../src/workspace-view'
|
||||
module.exports.Workspace = require '../src/workspace'
|
||||
module.exports.React = require 'react-atom-fork'
|
||||
module.exports.Reactionary = require 'reactionary-atom-fork'
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
'ctrl-w': 'core:close'
|
||||
'ctrl-z': 'core:undo'
|
||||
'ctrl-y': 'core:redo'
|
||||
'ctrl-shift-z': 'core:redo'
|
||||
'ctrl-x': 'core:cut'
|
||||
'ctrl-c': 'core:copy'
|
||||
'ctrl-v': 'core:paste'
|
||||
@@ -38,7 +39,7 @@
|
||||
'shift-pageup': 'core:select-page-up'
|
||||
'shift-pagedown': 'core:select-page-down'
|
||||
'delete': 'core:delete'
|
||||
'shift-delete': 'core:delete'
|
||||
'shift-delete': 'core:cut'
|
||||
'pageup': 'core:page-up'
|
||||
'pagedown': 'core:page-down'
|
||||
'backspace': 'core:backspace'
|
||||
@@ -95,6 +96,7 @@
|
||||
'ctrl-alt-shift-p': 'editor:log-cursor-scope'
|
||||
'ctrl-k ctrl-u': 'editor:upper-case'
|
||||
'ctrl-k ctrl-l': 'editor:lower-case'
|
||||
'ctrl-l': 'editor:select-line'
|
||||
|
||||
'.workspace .editor:not(.mini)':
|
||||
# Atom specific
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
'F11': 'window:toggle-full-screen'
|
||||
|
||||
# Sublime Parity
|
||||
'ctrl-,': 'application:show-settings'
|
||||
'ctrl-N': 'application:new-window'
|
||||
'ctrl-W': 'window:close'
|
||||
'ctrl-o': 'application:open-file'
|
||||
@@ -26,7 +27,9 @@
|
||||
'ctrl-s': 'core:save'
|
||||
'ctrl-S': 'core:save-as'
|
||||
'ctrl-w': 'core:close'
|
||||
'ctrl-f4': 'core:close'
|
||||
'ctrl-z': 'core:undo'
|
||||
'ctrl-shift-z': 'core:redo'
|
||||
'ctrl-y': 'core:redo'
|
||||
'ctrl-x': 'core:cut'
|
||||
'ctrl-c': 'core:copy'
|
||||
@@ -40,7 +43,7 @@
|
||||
'shift-pageup': 'core:select-page-up'
|
||||
'shift-pagedown': 'core:select-page-down'
|
||||
'delete': 'core:delete'
|
||||
'shift-delete': 'core:delete'
|
||||
'shift-delete': 'core:cut'
|
||||
'pageup': 'core:page-up'
|
||||
'pagedown': 'core:page-down'
|
||||
'backspace': 'core:backspace'
|
||||
@@ -82,12 +85,15 @@
|
||||
'ctrl-delete': 'editor:delete-to-end-of-word'
|
||||
'ctrl-home': 'core:move-to-top'
|
||||
'ctrl-end': 'core:move-to-bottom'
|
||||
'ctrl-shift-home': 'core:select-to-top'
|
||||
'ctrl-shift-end': 'core:select-to-bottom'
|
||||
|
||||
# Sublime Parity
|
||||
'ctrl-a': 'core:select-all'
|
||||
'ctrl-alt-shift-p': 'editor:log-cursor-scope'
|
||||
'ctrl-k ctrl-u': 'editor:upper-case'
|
||||
'ctrl-k ctrl-l': 'editor:lower-case'
|
||||
'ctrl-l': 'editor:select-line'
|
||||
|
||||
'.workspace .editor:not(.mini)':
|
||||
# Atom specific
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@
|
||||
{ label: 'Save As...', command: 'core:save-as' }
|
||||
{ label: 'Save All', command: 'window:save-all' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Close Buffer', command: 'core:close' }
|
||||
{ label: 'Close Tab', command: 'core:close' }
|
||||
{ label: 'Close Pane', command: 'pane:close' }
|
||||
{ label: 'Close Window', command: 'window:close' }
|
||||
]
|
||||
|
||||
+2
-2
@@ -14,8 +14,8 @@
|
||||
{ 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: '&Close Tab', command: 'core:close' }
|
||||
{ label: 'Close &Pane', command: 'pane:close' }
|
||||
{ label: 'Clos&e Window', command: 'window:close' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Quit', command: 'application:quit' }
|
||||
|
||||
+7
-2
@@ -9,13 +9,18 @@
|
||||
{ label: 'Reopen Last &Item', command: 'pane:reopen-closed-item' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Se&ttings', command: 'application:show-settings' }
|
||||
{ label: 'Open Your Config', command: 'application:open-your-config' }
|
||||
{ label: 'Open Your Init Script', command: 'application:open-your-init-script' }
|
||||
{ label: 'Open Your Keymap', command: 'application:open-your-keymap' }
|
||||
{ label: 'Open Your Snippets', command: 'application:open-your-snippets' }
|
||||
{ label: 'Open Your Stylesheet', command: 'application:open-your-stylesheet' }
|
||||
{ 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: '&Close Tab', command: 'core:close' }
|
||||
{ label: 'Close &Pane', command: 'pane:close' }
|
||||
{ label: 'Clos&e Window', command: 'window:close' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'E&xit', command: 'application:quit' }
|
||||
|
||||
+60
-58
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "atom",
|
||||
"productName": "Atom",
|
||||
"version": "0.109.0",
|
||||
"version": "0.121.0",
|
||||
"description": "A hackable text editor for the 21st Century.",
|
||||
"main": "./src/browser/main.js",
|
||||
"repository": {
|
||||
@@ -17,126 +17,128 @@
|
||||
"url": "http://github.com/atom/atom/raw/master/LICENSE.md"
|
||||
}
|
||||
],
|
||||
"atomShellVersion": "0.13.3",
|
||||
"atomShellVersion": "0.15.0",
|
||||
"dependencies": {
|
||||
"async": "0.2.6",
|
||||
"atom-keymap": "^0.27.0",
|
||||
"atom-keymap": "^1.0.0",
|
||||
"bootstrap": "git+https://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372",
|
||||
"clear-cut": "0.4.0",
|
||||
"coffee-script": "1.7.0",
|
||||
"coffeestack": "0.7.0",
|
||||
"delegato": "^1",
|
||||
"emissary": "^1.2.1",
|
||||
"first-mate": "^1.7.1",
|
||||
"fs-plus": "^2.2.3",
|
||||
"first-mate": "^2.0.1",
|
||||
"fs-plus": "^2.2.6",
|
||||
"fstream": "0.1.24",
|
||||
"fuzzaldrin": "^1.1",
|
||||
"git-utils": "^1.3",
|
||||
"git-utils": "^2.1.3",
|
||||
"grim": "0.11.0",
|
||||
"guid": "0.0.10",
|
||||
"jasmine-tagged": "^1.1.2",
|
||||
"less-cache": "0.12.0",
|
||||
"less-cache": "0.13.0",
|
||||
"mixto": "^1",
|
||||
"mkdirp": "0.3.5",
|
||||
"nslog": "0.5.0",
|
||||
"oniguruma": "^1.0.6",
|
||||
"nslog": "^1.0.1",
|
||||
"oniguruma": "^3.0.3",
|
||||
"optimist": "0.4.0",
|
||||
"pathwatcher": "^1.3.2",
|
||||
"pathwatcher": "^2.0.6",
|
||||
"property-accessors": "^1",
|
||||
"q": "^1.0.1",
|
||||
"random-words": "0.0.1",
|
||||
"react-atom-fork": "^0.10.0",
|
||||
"reactionary-atom-fork": "^0.9.0",
|
||||
"runas": "0.5.4",
|
||||
"scandal": "0.16.0",
|
||||
"react-atom-fork": "^0.11.1",
|
||||
"reactionary-atom-fork": "^1.0.0",
|
||||
"runas": "1.0.1",
|
||||
"scandal": "1.0.0",
|
||||
"scoped-property-store": "^0.9.0",
|
||||
"scrollbar-style": "^0.4.0",
|
||||
"scrollbar-style": "^1.0.1",
|
||||
"season": "^1.0.2",
|
||||
"semver": "1.1.4",
|
||||
"serializable": "^1",
|
||||
"space-pen": "3.2.0",
|
||||
"temp": "0.7.0",
|
||||
"text-buffer": "^2.4.2",
|
||||
"text-buffer": "^3.0.0",
|
||||
"theorist": "^1",
|
||||
"underscore-plus": "^1.5.0",
|
||||
"underscore-plus": "^1.5.1",
|
||||
"vm-compatibility-layer": "0.1.0"
|
||||
},
|
||||
"packageDependencies": {
|
||||
"atom-dark-syntax": "0.17.0",
|
||||
"atom-dark-ui": "0.30.0",
|
||||
"atom-light-syntax": "0.18.0",
|
||||
"atom-light-ui": "0.26.0",
|
||||
"base16-tomorrow-dark-theme": "0.17.0",
|
||||
"solarized-dark-syntax": "0.18.0",
|
||||
"solarized-light-syntax": "0.9.0",
|
||||
"archive-view": "0.33.0",
|
||||
"autocomplete": "0.28.0",
|
||||
"atom-dark-syntax": "0.19.0",
|
||||
"atom-dark-ui": "0.33.0",
|
||||
"atom-light-syntax": "0.20.0",
|
||||
"atom-light-ui": "0.29.0",
|
||||
"base16-tomorrow-dark-theme": "0.20.0",
|
||||
"base16-tomorrow-light-theme": "0.4.0",
|
||||
"solarized-dark-syntax": "0.22.0",
|
||||
"solarized-light-syntax": "0.12.0",
|
||||
"archive-view": "0.35.0",
|
||||
"autocomplete": "0.29.0",
|
||||
"autoflow": "0.17.0",
|
||||
"autosave": "0.14.0",
|
||||
"background-tips": "0.15.0",
|
||||
"bookmarks": "0.26.0",
|
||||
"bracket-matcher": "0.48.0",
|
||||
"bookmarks": "0.27.0",
|
||||
"bracket-matcher": "0.51.0",
|
||||
"command-palette": "0.24.0",
|
||||
"deprecation-cop": "0.7.0",
|
||||
"dev-live-reload": "0.31.0",
|
||||
"exception-reporting": "0.18.0",
|
||||
"dev-live-reload": "0.33.0",
|
||||
"exception-reporting": "0.19.0",
|
||||
"feedback": "0.33.0",
|
||||
"find-and-replace": "0.122.0",
|
||||
"fuzzy-finder": "0.56.0",
|
||||
"git-diff": "0.34.0",
|
||||
"find-and-replace": "0.127.0",
|
||||
"fuzzy-finder": "0.57.0",
|
||||
"git-diff": "0.37.0",
|
||||
"go-to-line": "0.23.0",
|
||||
"grammar-selector": "0.27.0",
|
||||
"image-view": "0.36.0",
|
||||
"incompatible-packages": "0.3.0",
|
||||
"keybinding-resolver": "0.18.0",
|
||||
"link": "0.24.0",
|
||||
"markdown-preview": "0.86.0",
|
||||
"metrics": "0.32.0",
|
||||
"link": "0.25.0",
|
||||
"markdown-preview": "0.94.0",
|
||||
"metrics": "0.33.0",
|
||||
"open-on-github": "0.29.0",
|
||||
"package-generator": "0.31.0",
|
||||
"release-notes": "0.32.0",
|
||||
"settings-view": "0.129.0",
|
||||
"snippets": "0.47.0",
|
||||
"spell-check": "0.38.0",
|
||||
"release-notes": "0.36.0",
|
||||
"settings-view": "0.137.0",
|
||||
"snippets": "0.50.0",
|
||||
"spell-check": "0.40.0",
|
||||
"status-bar": "0.41.0",
|
||||
"styleguide": "0.29.0",
|
||||
"symbols-view": "0.59.0",
|
||||
"tabs": "0.42.0",
|
||||
"timecop": "0.21.0",
|
||||
"tree-view": "0.108.0",
|
||||
"symbols-view": "0.63.0",
|
||||
"tabs": "0.48.0",
|
||||
"timecop": "0.22.0",
|
||||
"tree-view": "0.112.0",
|
||||
"update-package-dependencies": "0.6.0",
|
||||
"welcome": "0.17.0",
|
||||
"whitespace": "0.23.0",
|
||||
"wrap-guide": "0.19.0",
|
||||
"whitespace": "0.25.0",
|
||||
"wrap-guide": "0.21.0",
|
||||
|
||||
"language-c": "0.21.0",
|
||||
"language-coffee-script": "0.23.0",
|
||||
"language-c": "0.26.0",
|
||||
"language-coffee-script": "0.28.0",
|
||||
"language-css": "0.17.0",
|
||||
"language-gfm": "0.42.0",
|
||||
"language-gfm": "0.44.0",
|
||||
"language-git": "0.9.0",
|
||||
"language-go": "0.13.0",
|
||||
"language-go": "0.16.0",
|
||||
"language-html": "0.22.0",
|
||||
"language-hyperlink": "0.10.0",
|
||||
"language-java": "0.11.0",
|
||||
"language-javascript": "0.32.0",
|
||||
"language-javascript": "0.39.0",
|
||||
"language-json": "0.8.0",
|
||||
"language-less": "0.11.0",
|
||||
"language-less": "0.13.0",
|
||||
"language-make": "0.10.0",
|
||||
"language-objective-c": "0.11.0",
|
||||
"language-perl": "0.9.0",
|
||||
"language-php": "0.15.0",
|
||||
"language-property-list": "0.7.0",
|
||||
"language-python": "0.18.0",
|
||||
"language-ruby": "0.30.0",
|
||||
"language-ruby": "0.33.0",
|
||||
"language-ruby-on-rails": "0.15.0",
|
||||
"language-sass": "0.13.0",
|
||||
"language-sass": "0.14.0",
|
||||
"language-shellscript": "0.8.0",
|
||||
"language-source": "0.7.0",
|
||||
"language-sql": "0.8.0",
|
||||
"language-source": "0.8.0",
|
||||
"language-sql": "0.9.0",
|
||||
"language-text": "0.6.0",
|
||||
"language-todo": "0.10.0",
|
||||
"language-toml": "0.12.0",
|
||||
"language-xml": "0.15.0",
|
||||
"language-yaml": "0.11.0"
|
||||
"language-xml": "0.17.0",
|
||||
"language-yaml": "0.13.0"
|
||||
},
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
+26
-5
@@ -44,23 +44,44 @@ function bootstrap() {
|
||||
var apmInstallCommand = npmPath + npmFlags + 'install';
|
||||
var apmInstallOptions = {cwd: apmInstallPath};
|
||||
var moduleInstallCommand = apmPath + ' install' + apmFlags;
|
||||
var dedupeCommand = apmPath + ' dedupe' + apmFlags;
|
||||
var dedupeApmCommand = apmPath + ' dedupe' + apmFlags;
|
||||
var dedupeNpmCommand = npmPath + npmFlags + 'dedupe';
|
||||
|
||||
if (process.argv.indexOf('--no-quiet') === -1) {
|
||||
buildInstallCommand += ' --quiet';
|
||||
apmInstallCommand += ' --quiet';
|
||||
moduleInstallCommand += ' --quiet';
|
||||
dedupeCommand += ' --quiet';
|
||||
dedupeApmCommand += ' --quiet';
|
||||
dedupeNpmCommand += ' --quiet';
|
||||
buildInstallOptions.ignoreStdout = true;
|
||||
apmInstallOptions.ignoreStdout = true;
|
||||
}
|
||||
|
||||
// apm ships with 32-bit node so make sure its native modules are compiled
|
||||
// for a 32-bit target architecture
|
||||
if (process.env.JANKY_SHA1 && process.platform === 'win32')
|
||||
apmInstallCommand += ' --arch=ia32';
|
||||
|
||||
var commands = [
|
||||
{command: buildInstallCommand, message: 'Installing build modules...', options: buildInstallOptions},
|
||||
{command: apmInstallCommand, message: 'Installing apm...', options: apmInstallOptions},
|
||||
{
|
||||
command: buildInstallCommand,
|
||||
message: 'Installing build modules...',
|
||||
options: buildInstallOptions
|
||||
},
|
||||
{
|
||||
command: apmInstallCommand,
|
||||
message: 'Installing apm...',
|
||||
options: apmInstallOptions
|
||||
},
|
||||
apmPath + ' clean' + apmFlags,
|
||||
moduleInstallCommand,
|
||||
dedupeCommand + ' ' + packagesToDedupe.join(' '),
|
||||
dedupeApmCommand + ' ' + packagesToDedupe.join(' '),
|
||||
{
|
||||
command: dedupeNpmCommand + ' request semver',
|
||||
options: {
|
||||
cwd: path.resolve(__dirname, '..', 'apm', 'node_modules', 'atom-package-manager')
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
process.chdir(path.dirname(__dirname));
|
||||
|
||||
@@ -24,6 +24,7 @@ var commands = [
|
||||
[home, '.atom', 'storage'],
|
||||
[home, '.atom', '.npm'],
|
||||
[home, '.atom', 'compile-cache'],
|
||||
[home, '.atom', 'atom-shell'],
|
||||
[tmpdir, 'atom-build'],
|
||||
[tmpdir, 'atom-cached-atom-shells'],
|
||||
];
|
||||
|
||||
+16
-1
@@ -531,7 +531,22 @@ describe "the `atom` global", ->
|
||||
describe ".isReleasedVersion()", ->
|
||||
it "returns false if the version is a SHA and true otherwise", ->
|
||||
version = '0.1.0'
|
||||
spyOn(atom.constructor, 'getVersion').andCallFake -> version
|
||||
spyOn(atom, 'getVersion').andCallFake -> version
|
||||
expect(atom.isReleasedVersion()).toBe true
|
||||
version = '36b5518'
|
||||
expect(atom.isReleasedVersion()).toBe false
|
||||
|
||||
describe "window:update-available", ->
|
||||
it "is triggered when the auto-updater sends the update-downloaded event", ->
|
||||
updateAvailableHandler = jasmine.createSpy("update-available-handler")
|
||||
atom.workspaceView.on 'window:update-available', updateAvailableHandler
|
||||
autoUpdater = require('remote').require('auto-updater')
|
||||
autoUpdater.emit 'update-downloaded', null, "notes", "version"
|
||||
|
||||
waitsFor ->
|
||||
updateAvailableHandler.callCount > 0
|
||||
|
||||
runs ->
|
||||
[event, version, notes] = updateAvailableHandler.mostRecentCall.args
|
||||
expect(notes).toBe 'notes'
|
||||
expect(version).toBe 'version'
|
||||
|
||||
@@ -30,6 +30,16 @@ describe "ContextMenuManager", ->
|
||||
expect(contextMenu.definitions['.selector'][0].command).toEqual 'command'
|
||||
expect(contextMenu.definitions['.selector'].length).toBe 1
|
||||
|
||||
it 'allows multiple separators', ->
|
||||
contextMenu.add 'file-path',
|
||||
'.selector':
|
||||
'separator1': '-'
|
||||
'separator2': '-'
|
||||
|
||||
expect(contextMenu.definitions['.selector'].length).toBe 2
|
||||
expect(contextMenu.definitions['.selector'][0].type).toEqual 'separator'
|
||||
expect(contextMenu.definitions['.selector'][1].type).toEqual 'separator'
|
||||
|
||||
it 'allows duplicate commands with different labels', ->
|
||||
contextMenu.add 'file-path',
|
||||
'.selector':
|
||||
|
||||
@@ -215,6 +215,19 @@ describe "DisplayBuffer", ->
|
||||
displayBuffer.setEditorWidthInChars(-1)
|
||||
expect(displayBuffer.editorWidthInChars).not.toBe -1
|
||||
|
||||
it "sets ::scrollLeft to 0 and keeps it there when soft wrapping is enabled", ->
|
||||
displayBuffer.setDefaultCharWidth(10)
|
||||
displayBuffer.setWidth(50)
|
||||
displayBuffer.manageScrollPosition = true
|
||||
|
||||
displayBuffer.setSoftWrap(false)
|
||||
displayBuffer.setScrollLeft(Infinity)
|
||||
expect(displayBuffer.getScrollLeft()).toBeGreaterThan 0
|
||||
displayBuffer.setSoftWrap(true)
|
||||
expect(displayBuffer.getScrollLeft()).toBe 0
|
||||
displayBuffer.setScrollLeft(10)
|
||||
expect(displayBuffer.getScrollLeft()).toBe 0
|
||||
|
||||
describe "primitive folding", ->
|
||||
beforeEach ->
|
||||
displayBuffer.destroy()
|
||||
@@ -329,8 +342,6 @@ describe "DisplayBuffer", ->
|
||||
fold2 = displayBuffer.createFold(4, 9)
|
||||
fold1 = displayBuffer.createFold(0, 4)
|
||||
|
||||
displayBuffer.logLines(0, 20)
|
||||
|
||||
expect(displayBuffer.lineForRow(0).text).toMatch /^0/
|
||||
expect(displayBuffer.lineForRow(1).text).toMatch /^10/
|
||||
|
||||
@@ -643,6 +654,19 @@ describe "DisplayBuffer", ->
|
||||
buffer.delete([[6, 0], [6, 65]])
|
||||
expect(displayBuffer.getMaxLineLength()).toBe 62
|
||||
|
||||
it "correctly updates the location of the longest screen line when changes occur", ->
|
||||
expect(displayBuffer.getLongestScreenRow()).toBe 6
|
||||
buffer.delete([[0, 0], [2, 0]])
|
||||
expect(displayBuffer.getLongestScreenRow()).toBe 4
|
||||
buffer.delete([[4, 0], [5, 0]])
|
||||
|
||||
expect(displayBuffer.getLongestScreenRow()).toBe 1
|
||||
expect(displayBuffer.getMaxLineLength()).toBe 62
|
||||
|
||||
buffer.delete([[2, 0], [4, 0]])
|
||||
expect(displayBuffer.getLongestScreenRow()).toBe 1
|
||||
expect(displayBuffer.getMaxLineLength()).toBe 62
|
||||
|
||||
describe "::destroy()", ->
|
||||
it "unsubscribes all display buffer markers from their underlying buffer marker (regression)", ->
|
||||
marker = displayBuffer.markBufferPosition([12, 2])
|
||||
@@ -1014,15 +1038,35 @@ describe "DisplayBuffer", ->
|
||||
expect(start.left).toBe (4 * 10) + (6 * 11)
|
||||
|
||||
describe "decorations", ->
|
||||
it "can add decorations associated with markers and remove them", ->
|
||||
decoration = {type: 'gutter', class: 'one'}
|
||||
[marker, decoration, decorationParams] = []
|
||||
beforeEach ->
|
||||
marker = displayBuffer.markBufferRange([[2, 13], [3, 15]])
|
||||
decorationParams = {type: 'gutter', class: 'one'}
|
||||
decoration = displayBuffer.decorateMarker(marker, decorationParams)
|
||||
|
||||
displayBuffer.addDecorationForMarker(marker, decoration)
|
||||
it "can add decorations associated with markers and remove them", ->
|
||||
expect(decoration).toBeDefined()
|
||||
expect(decoration.getParams()).toBe decorationParams
|
||||
expect(displayBuffer.decorationForId(decoration.id)).toBe decoration
|
||||
expect(displayBuffer.decorationsForScreenRowRange(2, 3)[marker.id][0]).toBe decoration
|
||||
|
||||
displayBuffer.removeDecorationForMarker(marker, decoration)
|
||||
decoration.destroy()
|
||||
expect(displayBuffer.decorationsForScreenRowRange(2, 3)[marker.id]).not.toBeDefined()
|
||||
expect(displayBuffer.decorationForId(decoration.id)).not.toBeDefined()
|
||||
|
||||
it "will not fail if the decoration is removed twice", ->
|
||||
decoration.destroy()
|
||||
decoration.destroy()
|
||||
expect(displayBuffer.decorationForId(decoration.id)).not.toBeDefined()
|
||||
|
||||
describe "when a decoration is updated via Decoration::update()", ->
|
||||
it "emits an 'updated' event containing the new and old params", ->
|
||||
decoration.on 'updated', updatedSpy = jasmine.createSpy()
|
||||
decoration.update type: 'gutter', class: 'two'
|
||||
|
||||
{oldParams, newParams} = updatedSpy.mostRecentCall.args[0]
|
||||
expect(oldParams).toEqual decorationParams
|
||||
expect(newParams).toEqual type: 'gutter', class: 'two', id: decoration.id
|
||||
|
||||
describe "::setScrollTop", ->
|
||||
beforeEach ->
|
||||
|
||||
+780
-453
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -785,6 +785,19 @@ describe "Editor", ->
|
||||
editor.moveCursorLeft()
|
||||
expect(editor.getScrollLeft()).toBe 58 * 10
|
||||
|
||||
it "scrolls down when inserting lines makes the document longer than the editor's height", ->
|
||||
editor.setCursorScreenPosition([13, Infinity])
|
||||
editor.insertNewline()
|
||||
expect(editor.getScrollBottom()).toBe 14 * 10
|
||||
editor.insertNewline()
|
||||
expect(editor.getScrollBottom()).toBe 15 * 10
|
||||
|
||||
it "autoscrolls to the cursor when it moves due to undo", ->
|
||||
editor.insertText('abc')
|
||||
editor.setScrollTop(Infinity)
|
||||
editor.undo()
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
|
||||
describe "selection", ->
|
||||
selection = null
|
||||
|
||||
@@ -1227,6 +1240,8 @@ describe "Editor", ->
|
||||
expect(editor.getSelectedBufferRanges()).toEqual [[[0, 0], [0, 0]], [[3, 4], [5, 6]]]
|
||||
|
||||
it "autoscrolls to the added selection if needed", ->
|
||||
editor.manageScrollPosition = true
|
||||
|
||||
editor.setLineHeightInPixels(10)
|
||||
editor.setDefaultCharWidth(10)
|
||||
editor.setHeight(50)
|
||||
@@ -2066,6 +2081,20 @@ describe "Editor", ->
|
||||
editor.indent()
|
||||
expect(buffer.lineForRow(0)).toMatch(tabRegex)
|
||||
|
||||
it "respects the tab stops when cursor is in the middle of a tab", ->
|
||||
editor.setTabLength(4)
|
||||
buffer.insert([12, 2], "\n ")
|
||||
editor.setCursorBufferPosition [13, 1]
|
||||
editor.indent()
|
||||
expect(buffer.lineForRow(13)).toMatch /^\s+$/
|
||||
expect(buffer.lineForRow(13).length).toBe 4
|
||||
expect(editor.getCursorBufferPosition()).toEqual [13, 4]
|
||||
|
||||
buffer.insert([13, 0], " ")
|
||||
editor.setCursorBufferPosition [13, 6]
|
||||
editor.indent()
|
||||
expect(buffer.lineForRow(13).length).toBe 8
|
||||
|
||||
describe "if 'softTabs' is false", ->
|
||||
it "insert a \t into the buffer", ->
|
||||
editor.setSoftTabs(false)
|
||||
@@ -2084,6 +2113,20 @@ describe "Editor", ->
|
||||
expect(buffer.lineForRow(5).length).toBe 6
|
||||
expect(editor.getCursorBufferPosition()).toEqual [5, 6]
|
||||
|
||||
it "respects the tab stops when cursor is in the middle of a tab", ->
|
||||
editor.setTabLength(4)
|
||||
buffer.insert([12, 2], "\n ")
|
||||
editor.setCursorBufferPosition [13, 1]
|
||||
editor.indent(autoIndent: true)
|
||||
expect(buffer.lineForRow(13)).toMatch /^\s+$/
|
||||
expect(buffer.lineForRow(13).length).toBe 4
|
||||
expect(editor.getCursorBufferPosition()).toEqual [13, 4]
|
||||
|
||||
buffer.insert([13, 0], " ")
|
||||
editor.setCursorBufferPosition [13, 6]
|
||||
editor.indent(autoIndent: true)
|
||||
expect(buffer.lineForRow(13).length).toBe 8
|
||||
|
||||
describe "when 'softTabs' is false", ->
|
||||
it "moves the cursor to the end of the leading whitespace and inserts enough tabs to bring the line to the suggested level of indentaion", ->
|
||||
convertToHardTabs(buffer)
|
||||
@@ -2814,7 +2857,7 @@ describe "Editor", ->
|
||||
|
||||
atom.config.set("editor.autoIndent", false)
|
||||
editor.indent()
|
||||
expect(editor.lineForBufferRow(2)).toBe " "
|
||||
expect(editor.lineForBufferRow(2)).toBe " "
|
||||
|
||||
describe "when editor.autoIndent is true", ->
|
||||
beforeEach ->
|
||||
|
||||
@@ -2652,7 +2652,6 @@ describe "EditorView", ->
|
||||
expect(editor.getCursorBufferPosition()).toEqual [0, 0]
|
||||
expect(buffer.lineForRow(0)).toBe 'var quicksort = function () {'
|
||||
expect(buffer.lineForRow(13)).toBe 'var a = function() {'
|
||||
editor.logScreenLines()
|
||||
expect(editor.isFoldedAtBufferRow(0)).toBe true
|
||||
expect(editor.isFoldedAtBufferRow(13)).toBe true
|
||||
|
||||
|
||||
externo
BIN
Arquivo binário não exibido.
|
Antes Largura: | Altura: | Tamanho: 392 B |
externo
-1
@@ -1 +0,0 @@
|
||||
this tests files with no extensions
|
||||
gerado
externo
gerado
externo
+1
@@ -0,0 +1 @@
|
||||
throw new Error("this simulates a native module's failure to load")
|
||||
gerado
externo
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "native-module",
|
||||
"main": "./main.js"
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "package-with-incompatible-native-module",
|
||||
"version": "1.0",
|
||||
"main": "./main.js"
|
||||
}
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
'fileTypes': ['package-with-infinite-loop-grammar']
|
||||
'name': 'package-with-infinite-loop-grammar'
|
||||
'scopeName': 'source.package-with-infinite-loop-grammar'
|
||||
|
||||
# This grammar should loop forever if the line contains an `a`
|
||||
'patterns': [
|
||||
{
|
||||
'name': 'start'
|
||||
'begin': '^'
|
||||
'end': '$'
|
||||
'patterns': [
|
||||
{
|
||||
name: 'negative-look-ahead'
|
||||
match: "(?!a)"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -1 +0,0 @@
|
||||
This is a hidden file. Don't even try to load it as a snippet
|
||||
@@ -1 +0,0 @@
|
||||
This file isn't CSON, but shouldn't be a big deal
|
||||
@@ -1,4 +0,0 @@
|
||||
".test":
|
||||
"Test Snippet":
|
||||
prefix: "test"
|
||||
body: "testing 123"
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"theme": "ui",
|
||||
"stylesheets": ["editor.less"]
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
@import "ui-variables";
|
||||
|
||||
.editor {
|
||||
padding-top: @component-padding;
|
||||
padding-right: @component-padding;
|
||||
padding-bottom: @component-padding;
|
||||
|
||||
color: @input-background-color;
|
||||
background-color: @background-color-info; // From the fallback variables, not overridden
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
// This does not contain all of the ui-variables available.
|
||||
@app-background-color: #00f; // Changed
|
||||
@input-background-color: #f00; // Changed
|
||||
@@ -1,3 +0,0 @@
|
||||
@import "stylesheets/first";
|
||||
@import "stylesheets/second";
|
||||
@import "stylesheets/last";
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"theme": "ui"
|
||||
}
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
.editor {
|
||||
padding-top: 101px;
|
||||
padding-right: 101px;
|
||||
padding-bottom: 101px;
|
||||
|
||||
color: red;
|
||||
}
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
.editor {
|
||||
/* padding-top: 103px;
|
||||
padding-right: 103px;*/
|
||||
padding-bottom: 103px;
|
||||
}
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
@import "ui-variables";
|
||||
|
||||
@number: 102px;
|
||||
|
||||
.editor {
|
||||
/* padding-top: 102px;*/
|
||||
padding-right: @number;
|
||||
padding-bottom: @number;
|
||||
}
|
||||
-75
@@ -1,75 +0,0 @@
|
||||
// Variables different from the original are marked 'Changed'
|
||||
|
||||
@text-color: #333;
|
||||
@text-color-subtle: #777;
|
||||
@text-color-highlight: #111;
|
||||
@text-color-selected: @text-color-highlight;
|
||||
|
||||
@text-color-info: #5293d8;
|
||||
@text-color-success: #1fe977;
|
||||
@text-color-warning: #f78a46;
|
||||
@text-color-error: #c00;
|
||||
|
||||
@background-color-info: #0098ff;
|
||||
@background-color-success: #17ca65;
|
||||
@background-color-warning: #ff4800;
|
||||
@background-color-error: #c00;
|
||||
@background-color-highlight: rgba(255, 255, 255, 0.10);
|
||||
@background-color-selected: @background-color-highlight;
|
||||
|
||||
@app-background-color: #00f; // Changed
|
||||
|
||||
@base-background-color: #fff;
|
||||
@base-border-color: #eee;
|
||||
|
||||
@pane-item-background-color: @base-background-color;
|
||||
@pane-item-border-color: @base-border-color;
|
||||
|
||||
@input-background-color: #f00; // Changed
|
||||
@input-border-color: @base-border-color;
|
||||
|
||||
@tool-panel-background-color: #f4f4f4;
|
||||
@tool-panel-border-color: @base-border-color;
|
||||
|
||||
@inset-panel-background-color: #eee;
|
||||
@inset-panel-border-color: @base-border-color;
|
||||
|
||||
@panel-heading-background-color: #ddd;
|
||||
@panel-heading-border-color: transparent;
|
||||
|
||||
@overlay-background-color: #f4f4f4;
|
||||
@overlay-border-color: @base-border-color;
|
||||
|
||||
@button-background-color: #ccc;
|
||||
@button-background-color-hover: lighten(@button-background-color, 5%);
|
||||
@button-background-color-selected: @button-background-color-hover;
|
||||
@button-border-color: #aaa;
|
||||
|
||||
@tab-bar-background-color: #fff;
|
||||
@tab-bar-border-color: darken(@tab-background-color-active, 10%);
|
||||
@tab-background-color: #f4f4f4;
|
||||
@tab-background-color-active: #fff;
|
||||
@tab-border-color: @base-border-color;
|
||||
|
||||
@tree-view-background-color: @tool-panel-background-color;
|
||||
@tree-view-border-color: @tool-panel-border-color;
|
||||
|
||||
@ui-site-color-1: @background-color-success; // green
|
||||
@ui-site-color-2: @background-color-info; // blue
|
||||
@ui-site-color-3: @background-color-warning; // orange
|
||||
@ui-site-color-4: #db2ff4; // purple
|
||||
@ui-site-color-5: #f5e11d; // yellow
|
||||
|
||||
@font-size: 12px;
|
||||
|
||||
@disclosure-arrow-size: 12px;
|
||||
|
||||
@component-padding: 150px;
|
||||
@component-icon-padding: 5px;
|
||||
@component-icon-size: 16px;
|
||||
@component-line-height: 25px;
|
||||
@component-border-radius: 2px;
|
||||
|
||||
@tab-height: 30px;
|
||||
|
||||
@font-family: Arial;
|
||||
@@ -1 +0,0 @@
|
||||
Hello World!
|
||||
@@ -1 +0,0 @@
|
||||
Goodbye World!
|
||||
@@ -1 +0,0 @@
|
||||
Hello World!
|
||||
@@ -1 +0,0 @@
|
||||
Goodbye World!
|
||||
-1
@@ -1 +0,0 @@
|
||||
#header {
|
||||
externo
-71
@@ -1,71 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>fileTypes</key>
|
||||
<array>
|
||||
<string>txt</string>
|
||||
</array>
|
||||
<key>keyEquivalent</key>
|
||||
<string>^~P</string>
|
||||
<key>name</key>
|
||||
<string>Plain Text</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>captures</key>
|
||||
<dict>
|
||||
<key>1</key>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>punctuation.definition.item.text</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>match</key>
|
||||
<string>^\s*(•).*$\n?</string>
|
||||
<key>name</key>
|
||||
<string>meta.bullet-point.strong.text</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>captures</key>
|
||||
<dict>
|
||||
<key>1</key>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>punctuation.definition.item.text</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>match</key>
|
||||
<string>^\s*(·).*$\n?</string>
|
||||
<key>name</key>
|
||||
<string>meta.bullet-point.light.text</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>captures</key>
|
||||
<dict>
|
||||
<key>1</key>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>punctuation.definition.item.text</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>match</key>
|
||||
<string>^\s*(\*).*$\n?</string>
|
||||
<key>name</key>
|
||||
<string>meta.bullet-point.star.text</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>begin</key>
|
||||
<string>^([ \t]*)(?=\S)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.paragraph.text</string>
|
||||
<key>end</key>
|
||||
<string>^(?!\1(?=\S))</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>scopeName</key>
|
||||
<string>text.plain</string>
|
||||
<key>uuid</key>
|
||||
<string>3130E4FA-B10E-11D9-9F75-000D93589AF6</string>
|
||||
</dict>
|
||||
</plist>
|
||||
externo
-1
@@ -1 +0,0 @@
|
||||
dir
|
||||
externo
-1
@@ -1 +0,0 @@
|
||||
sample.js
|
||||
externo
-1
@@ -1 +0,0 @@
|
||||
a
|
||||
@@ -1,7 +1,8 @@
|
||||
fs = require 'fs'
|
||||
|
||||
module.exports.runSpecSuite = (specSuite, logFile, logErrors=true) ->
|
||||
{$, $$} = require 'atom'
|
||||
{$, $$} = require '../src/space-pen-extensions'
|
||||
|
||||
window[key] = value for key, value of require '../vendor/jasmine'
|
||||
|
||||
{TerminalReporter} = require 'jasmine-tagged'
|
||||
|
||||
@@ -1,8 +1,36 @@
|
||||
{$} = require 'atom'
|
||||
path = require 'path'
|
||||
Package = require '../src/package'
|
||||
ThemePackage = require '../src/theme-package'
|
||||
|
||||
describe "Package", ->
|
||||
describe "when the package contains incompatible native modules", ->
|
||||
it "does not activate it", ->
|
||||
packagePath = atom.project.resolve('packages/package-with-incompatible-native-module')
|
||||
pack = new Package(packagePath)
|
||||
expect(pack.isCompatible()).toBe false
|
||||
expect(pack.incompatibleModules[0].name).toBe 'native-module'
|
||||
expect(pack.incompatibleModules[0].path).toBe path.join(packagePath, 'node_modules', 'native-module')
|
||||
|
||||
it "caches the incompatible native modules in local storage", ->
|
||||
packagePath = atom.project.resolve('packages/package-with-incompatible-native-module')
|
||||
cacheKey = null
|
||||
cacheItem = null
|
||||
|
||||
spyOn(global.localStorage, 'setItem').andCallFake (key, item) ->
|
||||
cacheKey = key
|
||||
cacheItem = item
|
||||
spyOn(global.localStorage, 'getItem').andCallFake (key) ->
|
||||
return cacheItem if cacheKey is key
|
||||
|
||||
expect(new Package(packagePath).isCompatible()).toBe false
|
||||
expect(global.localStorage.getItem.callCount).toBe 1
|
||||
expect(global.localStorage.setItem.callCount).toBe 1
|
||||
|
||||
expect(new Package(packagePath).isCompatible()).toBe false
|
||||
expect(global.localStorage.getItem.callCount).toBe 2
|
||||
expect(global.localStorage.setItem.callCount).toBe 1
|
||||
|
||||
describe "theme", ->
|
||||
theme = null
|
||||
|
||||
|
||||
@@ -208,13 +208,16 @@ describe "Project", ->
|
||||
describe "when a file doesn't exist", ->
|
||||
it "calls back with an error", ->
|
||||
errors = []
|
||||
missingPath = path.resolve('/not-a-file.js')
|
||||
expect(fs.existsSync(missingPath)).toBeFalsy()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.replace /items/gi, 'items', ['/not-a-file.js'], (result, error) ->
|
||||
atom.project.replace /items/gi, 'items', [missingPath], (result, error) ->
|
||||
errors.push(error)
|
||||
|
||||
runs ->
|
||||
expect(errors).toHaveLength 1
|
||||
expect(errors[0].path).toBe '/not-a-file.js'
|
||||
expect(errors[0].path).toBe missingPath
|
||||
|
||||
describe "when called with unopened files", ->
|
||||
it "replaces properly", ->
|
||||
|
||||
@@ -37,7 +37,7 @@ jasmine.getEnv().addEqualityTester(_.isEqual) # Use underscore's definition of e
|
||||
|
||||
if process.platform is 'win32' and process.env.JANKY_SHA1
|
||||
# Use longer timeout on Windows CI
|
||||
jasmine.getEnv().defaultTimeoutInterval = 30000
|
||||
jasmine.getEnv().defaultTimeoutInterval = 60000
|
||||
else
|
||||
jasmine.getEnv().defaultTimeoutInterval = 5000
|
||||
|
||||
@@ -130,6 +130,8 @@ afterEach ->
|
||||
atom.project?.destroy()
|
||||
atom.project = null
|
||||
|
||||
atom.themes.removeStylesheet('global-editor-styles')
|
||||
|
||||
delete atom.state.packageStates
|
||||
|
||||
$('#jasmine-content').empty() unless window.debugContent
|
||||
@@ -318,9 +320,13 @@ window.setEditorWidthInChars = (editorView, widthInChars, charWidth=editorView.c
|
||||
editorView.width(charWidth * widthInChars + editorView.gutter.outerWidth())
|
||||
$(window).trigger 'resize' # update width of editor view's on-screen lines
|
||||
|
||||
window.setEditorHeightInLines = (editorView, heightInChars, charHeight=editorView.lineHeight) ->
|
||||
editorView.height(charHeight * heightInChars + editorView.renderedLines.position().top)
|
||||
$(window).trigger 'resize' # update editor view's on-screen lines
|
||||
window.setEditorHeightInLines = (editorView, heightInLines, lineHeight=editorView.lineHeight) ->
|
||||
if editorView.hasClass('react')
|
||||
editorView.height(editorView.getEditor().getLineHeightInPixels() * heightInLines)
|
||||
editorView.component?.measureHeightAndWidth()
|
||||
else
|
||||
editorView.height(lineHeight * heightInLines + editorView.renderedLines.position().top)
|
||||
$(window).trigger 'resize' # update editor view's on-screen lines
|
||||
|
||||
$.fn.resultOfTrigger = (type) ->
|
||||
event = $.Event(type)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
_ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
{Git} = require 'atom'
|
||||
path = require 'path'
|
||||
require './spec-helper'
|
||||
|
||||
|
||||
@@ -232,6 +232,21 @@ describe "ThemeManager", ->
|
||||
expect($(".editor").css("padding-right")).toBe "150px"
|
||||
expect($(".editor").css("padding-bottom")).toBe "150px"
|
||||
|
||||
describe "when there is a theme with incomplete variables", ->
|
||||
it "loads the correct values from the fallback ui-variables", ->
|
||||
themeManager.on 'reloaded', reloadHandler = jasmine.createSpy()
|
||||
atom.config.set('core.themes', ['theme-with-incomplete-ui-variables'])
|
||||
|
||||
waitsFor ->
|
||||
reloadHandler.callCount > 0
|
||||
|
||||
runs ->
|
||||
# an override loaded in the base css
|
||||
expect(atom.workspaceView.css("background-color")).toBe "rgb(0, 0, 255)"
|
||||
|
||||
# from within the theme itself
|
||||
expect($(".editor").css("background-color")).toBe "rgb(0, 152, 255)"
|
||||
|
||||
describe "when the user stylesheet changes", ->
|
||||
it "reloads it", ->
|
||||
[stylesheetRemovedHandler, stylesheetAddedHandler, stylesheetsChangedHandler] = []
|
||||
|
||||
@@ -684,8 +684,8 @@ describe "TokenizedBuffer", ->
|
||||
|
||||
expect(tokenizedBuffer.lineForScreenRow(5).indentLevel).toBe 3
|
||||
expect(tokenizedBuffer.lineForScreenRow(6).indentLevel).toBe 3
|
||||
expect(tokenizedBuffer.lineForScreenRow(9).indentLevel).toBe 2
|
||||
expect(tokenizedBuffer.lineForScreenRow(10).indentLevel).toBe 2
|
||||
expect(tokenizedBuffer.lineForScreenRow(9).indentLevel).toBe 3
|
||||
expect(tokenizedBuffer.lineForScreenRow(10).indentLevel).toBe 3
|
||||
expect(tokenizedBuffer.lineForScreenRow(11).indentLevel).toBe 2
|
||||
|
||||
tokenizedBuffer.on "changed", changeHandler = jasmine.createSpy('changeHandler')
|
||||
@@ -693,12 +693,12 @@ describe "TokenizedBuffer", ->
|
||||
buffer.setTextInRange([[7, 0], [8, 65]], ' one\n two\n three\n four')
|
||||
|
||||
delete changeHandler.argsForCall[0][0].bufferChange
|
||||
expect(changeHandler).toHaveBeenCalledWith(start: 5, end: 8, delta: 2)
|
||||
expect(changeHandler).toHaveBeenCalledWith(start: 5, end: 10, delta: 2)
|
||||
|
||||
expect(tokenizedBuffer.lineForScreenRow(5).indentLevel).toBe 4
|
||||
expect(tokenizedBuffer.lineForScreenRow(6).indentLevel).toBe 4
|
||||
expect(tokenizedBuffer.lineForScreenRow(11).indentLevel).toBe 2
|
||||
expect(tokenizedBuffer.lineForScreenRow(12).indentLevel).toBe 2
|
||||
expect(tokenizedBuffer.lineForScreenRow(11).indentLevel).toBe 4
|
||||
expect(tokenizedBuffer.lineForScreenRow(12).indentLevel).toBe 4
|
||||
expect(tokenizedBuffer.lineForScreenRow(13).indentLevel).toBe 2
|
||||
|
||||
it "updates the indentLevel of empty lines surrounding a change that removes lines", ->
|
||||
@@ -711,7 +711,7 @@ describe "TokenizedBuffer", ->
|
||||
buffer.setTextInRange([[7, 0], [8, 65]], ' ok')
|
||||
|
||||
delete changeHandler.argsForCall[0][0].bufferChange
|
||||
expect(changeHandler).toHaveBeenCalledWith(start: 5, end: 8, delta: -1)
|
||||
expect(changeHandler).toHaveBeenCalledWith(start: 5, end: 10, delta: -1)
|
||||
|
||||
expect(tokenizedBuffer.lineForScreenRow(5).indentLevel).toBe 2
|
||||
expect(tokenizedBuffer.lineForScreenRow(6).indentLevel).toBe 2
|
||||
|
||||
@@ -20,7 +20,6 @@ describe "WorkspaceView", ->
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(pathToOpen)
|
||||
|
||||
|
||||
describe "@deserialize()", ->
|
||||
viewState = null
|
||||
|
||||
@@ -294,3 +293,31 @@ describe "WorkspaceView", ->
|
||||
expect(atom.workspaceView).toHaveClass 'scrollbars-visible-always'
|
||||
scrollbarStyle.emitValue 'overlay'
|
||||
expect(atom.workspaceView).toHaveClass 'scrollbars-visible-when-scrolling'
|
||||
|
||||
describe "editor font styling", ->
|
||||
[editorNode, editor] = []
|
||||
|
||||
beforeEach ->
|
||||
atom.workspaceView.attachToDom()
|
||||
editorNode = atom.workspaceView.find('.editor')[0]
|
||||
editor = atom.workspaceView.find('.editor').view().getEditor()
|
||||
|
||||
it "updates the font-size based on the 'editor.fontSize' config value", ->
|
||||
initialCharWidth = editor.getDefaultCharWidth()
|
||||
expect(getComputedStyle(editorNode).fontSize).toBe atom.config.get('editor.fontSize') + 'px'
|
||||
atom.config.set('editor.fontSize', atom.config.get('editor.fontSize') + 5)
|
||||
expect(getComputedStyle(editorNode).fontSize).toBe atom.config.get('editor.fontSize') + 'px'
|
||||
expect(editor.getDefaultCharWidth()).toBeGreaterThan initialCharWidth
|
||||
|
||||
it "updates the font-family based on the 'editor.fontFamily' config value", ->
|
||||
initialCharWidth = editor.getDefaultCharWidth()
|
||||
expect(getComputedStyle(editorNode).fontFamily).toBe atom.config.get('editor.fontFamily')
|
||||
atom.config.set('editor.fontFamily', 'sans-serif')
|
||||
expect(getComputedStyle(editorNode).fontFamily).toBe atom.config.get('editor.fontFamily')
|
||||
expect(editor.getDefaultCharWidth()).not.toBe initialCharWidth
|
||||
|
||||
it "updates the line-height based on the 'editor.lineHeight' config value", ->
|
||||
initialLineHeight = editor.getLineHeightInPixels()
|
||||
atom.config.set('editor.lineHeight', '30px')
|
||||
expect(getComputedStyle(editorNode).lineHeight).toBe atom.config.get('editor.lineHeight')
|
||||
expect(editor.getLineHeightInPixels()).not.toBe initialLineHeight
|
||||
|
||||
+23
-19
@@ -110,14 +110,6 @@ class Atom extends Model
|
||||
@getCurrentWindow: ->
|
||||
remote.getCurrentWindow()
|
||||
|
||||
# Get the version of the Atom application.
|
||||
@getVersion: ->
|
||||
@appVersion ?= @getLoadSettings().appVersion
|
||||
|
||||
# Determine whether the current version is an official release.
|
||||
@isReleasedVersion: ->
|
||||
not /\w{7}/.test(@getVersion()) # Check if the release is a 7-character SHA prefix
|
||||
|
||||
workspaceViewParentSelector: 'body'
|
||||
|
||||
# Call .loadOrCreate instead
|
||||
@@ -158,7 +150,7 @@ class Atom extends Model
|
||||
process.env.NODE_PATH = exportsPath
|
||||
|
||||
# Make react.js faster
|
||||
process.env.NODE_ENV ?= 'production'
|
||||
process.env.NODE_ENV ?= 'production' unless devMode
|
||||
|
||||
@config = new Config({configDirPath, resourcePath})
|
||||
@keymaps = new KeymapManager({configDirPath, resourcePath})
|
||||
@@ -225,9 +217,15 @@ class Atom extends Model
|
||||
else
|
||||
@center()
|
||||
|
||||
# Returns true if the dimensions are useable, false if they should be ignored.
|
||||
# Work around for https://github.com/atom/atom-shell/issues/473
|
||||
isValidDimensions: ({x, y, width, height}={}) ->
|
||||
width > 0 and height > 0 and x + width > 0 and y + height > 0
|
||||
|
||||
storeDefaultWindowDimensions: ->
|
||||
dimensions = JSON.stringify(atom.getWindowDimensions())
|
||||
localStorage.setItem("defaultWindowDimensions", dimensions)
|
||||
dimensions = @getWindowDimensions()
|
||||
if @isValidDimensions(dimensions)
|
||||
localStorage.setItem("defaultWindowDimensions", JSON.stringify(dimensions))
|
||||
|
||||
getDefaultWindowDimensions: ->
|
||||
{windowDimensions} = @getLoadSettings()
|
||||
@@ -240,15 +238,21 @@ class Atom extends Model
|
||||
console.warn "Error parsing default window dimensions", error
|
||||
localStorage.removeItem("defaultWindowDimensions")
|
||||
|
||||
{width, height} = screen.getPrimaryDisplay().workAreaSize
|
||||
dimensions ? {x: 0, y: 0, width: Math.min(1024, width), height: height}
|
||||
if @isValidDimensions(dimensions)
|
||||
dimensions
|
||||
else
|
||||
{width, height} = screen.getPrimaryDisplay().workAreaSize
|
||||
{x: 0, y: 0, width: Math.min(1024, width), height}
|
||||
|
||||
restoreWindowDimensions: ->
|
||||
windowDimensions = @state.windowDimensions ? @getDefaultWindowDimensions()
|
||||
@setWindowDimensions(windowDimensions)
|
||||
dimensions = @state.windowDimensions
|
||||
unless @isValidDimensions(dimensions)
|
||||
dimensions = @getDefaultWindowDimensions()
|
||||
@setWindowDimensions(dimensions)
|
||||
|
||||
storeWindowDimensions: ->
|
||||
@state.windowDimensions = @getWindowDimensions()
|
||||
dimensions = @getWindowDimensions()
|
||||
@state.windowDimensions = dimensions if @isValidDimensions(dimensions)
|
||||
|
||||
# Public: Get the load settings for the current window.
|
||||
#
|
||||
@@ -434,7 +438,7 @@ class Atom extends Model
|
||||
# width - The {Number} of pixels.
|
||||
# height - The {Number} of pixels.
|
||||
setSize: (width, height) ->
|
||||
ipc.send('call-window-method', 'setSize', width, height)
|
||||
@getCurrentWindow().setSize(width, height)
|
||||
|
||||
# Public: Set the position of current window.
|
||||
#
|
||||
@@ -491,11 +495,11 @@ class Atom extends Model
|
||||
#
|
||||
# Returns the version text {String}.
|
||||
getVersion: ->
|
||||
@constructor.getVersion()
|
||||
@appVersion ?= @getLoadSettings().appVersion
|
||||
|
||||
# Public: Determine whether the current version is an official release.
|
||||
isReleasedVersion: ->
|
||||
@constructor.isReleasedVersion()
|
||||
not /\w{7}/.test(@getVersion()) # Check if the release is a 7-character SHA prefix
|
||||
|
||||
# Public: Get the directory path to Atom's configuration area.
|
||||
#
|
||||
|
||||
@@ -105,7 +105,7 @@ class AtomWindow
|
||||
type: 'warning'
|
||||
buttons: ['Close Window', 'Reload', 'Keep It Open']
|
||||
message: 'The editor has crashed'
|
||||
detail: 'Please report this issue to atom@github.com'
|
||||
detail: 'Please report this issue to https://github.com/atom/atom'
|
||||
switch chosen
|
||||
when 0 then @browserWindow.destroy()
|
||||
when 1 then @browserWindow.restart()
|
||||
@@ -138,6 +138,7 @@ class AtomWindow
|
||||
when 'window:reload' then @reload()
|
||||
when 'window:toggle-dev-tools' then @toggleDevTools()
|
||||
when 'window:close' then @close()
|
||||
when 'window:update-available' then @sendCommandToBrowserWindow(command, args...) # For spec testing
|
||||
else if @isWebViewFocused()
|
||||
@sendCommandToBrowserWindow(command, args...)
|
||||
else
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
https = require 'https'
|
||||
autoUpdater = require 'auto-updater'
|
||||
dialog = require 'dialog'
|
||||
_ = require 'underscore-plus'
|
||||
@@ -16,11 +17,12 @@ class AutoUpdateManager
|
||||
|
||||
constructor: (@version) ->
|
||||
@state = IDLE_STATE
|
||||
@feedUrl = "https://atom.io/api/updates?version=#{@version}"
|
||||
|
||||
# Only released versions should check for updates.
|
||||
return if /\w{7}/.test(@version)
|
||||
if process.platform is 'win32'
|
||||
autoUpdater.checkForUpdates = => @checkForUpdatesShim()
|
||||
|
||||
autoUpdater.setFeedUrl "https://atom.io/api/updates?version=#{@version}"
|
||||
autoUpdater.setFeedUrl @feedUrl
|
||||
|
||||
autoUpdater.on 'checking-for-update', =>
|
||||
@setState(CHECKING_STATE)
|
||||
@@ -39,7 +41,25 @@ class AutoUpdateManager
|
||||
@setState(UPDATE_AVAILABLE_STATE)
|
||||
@emitUpdateAvailableEvent(@getWindows()...)
|
||||
|
||||
@check(hidePopups: true)
|
||||
# Only released versions should check for updates.
|
||||
unless /\w{7}/.test(@version)
|
||||
@check(hidePopups: true)
|
||||
|
||||
# Windows doesn't have an auto-updater, so use this method to shim the events.
|
||||
checkForUpdatesShim: ->
|
||||
autoUpdater.emit 'checking-for-update'
|
||||
request = https.get @feedUrl, (response) ->
|
||||
if response.statusCode == 200
|
||||
body = ""
|
||||
response.on 'data', (chunk) -> body += chunk
|
||||
response.on 'end', ->
|
||||
{notes, name} = JSON.parse(body)
|
||||
autoUpdater.emit 'update-downloaded', null, notes, name
|
||||
else
|
||||
autoUpdater.emit 'update-not-available'
|
||||
|
||||
request.on 'error', (error) ->
|
||||
autoUpdater.emit 'error', null, error.message
|
||||
|
||||
emitUpdateAvailableEvent: (windows...) ->
|
||||
return unless @releaseVersion? and @releaseNotes
|
||||
|
||||
@@ -27,10 +27,6 @@ start = ->
|
||||
event.preventDefault()
|
||||
args.urlsToOpen.push(urlToOpen)
|
||||
|
||||
app.on 'open-url', (event, urlToOpen) ->
|
||||
event.preventDefault()
|
||||
args.urlsToOpen.push(urlToOpen)
|
||||
|
||||
app.on 'open-file', addPathToOpen
|
||||
app.on 'open-url', addUrlToOpen
|
||||
|
||||
|
||||
@@ -45,7 +45,16 @@ class BufferedProcess
|
||||
# Related to joyent/node#2318
|
||||
if process.platform is "win32"
|
||||
# Quote all arguments and escapes inner quotes
|
||||
cmdArgs = args.map (arg) -> "\"#{arg.replace(/"/g, '\\"')}\""
|
||||
if args?
|
||||
cmdArgs = args.map (arg) ->
|
||||
if command in ['explorer.exe', 'explorer'] and /^\/[a-zA-Z]+,.*$/.test(arg)
|
||||
# Don't wrap /root,C:\folder style arguments to explorer calls in
|
||||
# quotes since they will not be interpreted correctly if they are
|
||||
arg
|
||||
else
|
||||
"\"#{arg.replace(/"/g, '\\"')}\""
|
||||
else
|
||||
cmdArgs = []
|
||||
cmdArgs.unshift("\"#{command}\"")
|
||||
cmdArgs = ['/s', '/c', "\"#{cmdArgs.join(' ')}\""]
|
||||
cmdOptions = _.clone(options)
|
||||
|
||||
@@ -18,11 +18,16 @@ getCachedJavaScript = (cachePath) ->
|
||||
try
|
||||
fs.readFileSync(cachePath, 'utf8')
|
||||
|
||||
convertFilePath = (filePath) ->
|
||||
if process.platform is 'win32'
|
||||
filePath = "/#{path.resolve(filePath).replace(/\\/g, '/')}"
|
||||
encodeURI(filePath)
|
||||
|
||||
compileCoffeeScript = (coffee, filePath, cachePath) ->
|
||||
{js, v3SourceMap} = CoffeeScript.compile(coffee, filename: filePath, sourceMap: true)
|
||||
# Include source map in the web page environment.
|
||||
if btoa? and JSON? and unescape? and encodeURIComponent?
|
||||
js = "#{js}\n//# sourceMappingURL=data:application/json;base64,#{btoa unescape encodeURIComponent v3SourceMap}\n//# sourceURL=#{filePath}"
|
||||
js = "#{js}\n//# sourceMappingURL=data:application/json;base64,#{btoa unescape encodeURIComponent v3SourceMap}\n//# sourceURL=#{convertFilePath(filePath)}"
|
||||
try
|
||||
fs.writeFileSync(cachePath, js)
|
||||
js
|
||||
|
||||
@@ -44,7 +44,7 @@ class ContextMenuManager
|
||||
@addBySelector(selector, menuItem, {devMode})
|
||||
|
||||
buildMenuItem: (label, command) ->
|
||||
if label is command is '-'
|
||||
if command is '-'
|
||||
{type: 'separator'}
|
||||
else
|
||||
{label, command}
|
||||
@@ -60,7 +60,7 @@ class ContextMenuManager
|
||||
# editor is in dev mode.
|
||||
addBySelector: (selector, definition, {devMode}={}) ->
|
||||
definitions = if devMode then @devModeDefinitions else @definitions
|
||||
unless _.findWhere(definitions[selector], definition)
|
||||
if not _.findWhere(definitions[selector], definition) or _.isEqual(definition, {type: 'separator'})
|
||||
(definitions[selector] ?= []).push(definition)
|
||||
|
||||
# Returns definitions which match the element and devMode.
|
||||
|
||||
@@ -8,22 +8,11 @@ CursorComponent = React.createClass
|
||||
|
||||
render: ->
|
||||
{pixelRect, defaultCharWidth} = @props
|
||||
{height, width} = pixelRect
|
||||
{top, left, height, width} = pixelRect
|
||||
width = defaultCharWidth if width is 0
|
||||
WebkitTransform = @getTransform()
|
||||
WebkitTransform = "translate(#{left}px, #{top}px)"
|
||||
|
||||
div className: 'cursor', style: {height, width, WebkitTransform}
|
||||
|
||||
getTransform: ->
|
||||
{pixelRect, scrollTop, scrollLeft, useHardwareAcceleration} = @props
|
||||
{top, left} = pixelRect
|
||||
top -= scrollTop
|
||||
left -= scrollLeft
|
||||
|
||||
if useHardwareAcceleration
|
||||
"translate3d(#{left}px, #{top}px, 0px)"
|
||||
else
|
||||
"translate(#{left}px, #{top}px)"
|
||||
|
||||
shouldComponentUpdate: (newProps) ->
|
||||
not isEqualForProperties(newProps, @props, 'pixelRect', 'scrollTop', 'scrollLeft', 'defaultCharWidth')
|
||||
not isEqualForProperties(newProps, @props, 'pixelRect', 'defaultCharWidth')
|
||||
|
||||
@@ -28,6 +28,7 @@ class Cursor extends Model
|
||||
|
||||
# Supports old editor view
|
||||
@needsAutoscroll ?= @isLastCursor() and !textChanged
|
||||
@autoscroll() if @editor.manageScrollPosition and @isLastCursor() and textChanged
|
||||
|
||||
@goalColumn = null
|
||||
|
||||
|
||||
@@ -12,16 +12,16 @@ CursorsComponent = React.createClass
|
||||
cursorBlinkIntervalHandle: null
|
||||
|
||||
render: ->
|
||||
{cursorPixelRects, scrollTop, scrollLeft, defaultCharWidth, useHardwareAcceleration} = @props
|
||||
{performedInitialMeasurement, cursorPixelRects, defaultCharWidth} = @props
|
||||
{blinkOff} = @state
|
||||
|
||||
className = 'cursors'
|
||||
className += ' blink-off' if blinkOff
|
||||
|
||||
div {className},
|
||||
if @isMounted()
|
||||
if performedInitialMeasurement
|
||||
for key, pixelRect of cursorPixelRects
|
||||
CursorComponent({key, pixelRect, scrollTop, scrollLeft, defaultCharWidth, useHardwareAcceleration})
|
||||
CursorComponent({key, pixelRect, defaultCharWidth})
|
||||
|
||||
getInitialState: ->
|
||||
blinkOff: false
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
_ = require 'underscore-plus'
|
||||
{Subscriber, Emitter} = require 'emissary'
|
||||
|
||||
idCounter = 0
|
||||
nextId = -> idCounter++
|
||||
|
||||
# Public: Represents a decoration that follows a {Marker}. A decoration is
|
||||
# basically a visual representation of a marker. It allows you to add CSS
|
||||
# classes to line numbers in the gutter, lines, and add selection-line regions
|
||||
# around marked ranges of text.
|
||||
#
|
||||
# {Decoration} objects are not meant to be created directly, but created with
|
||||
# {Editor::decorateMarker}. eg.
|
||||
#
|
||||
# ```coffee
|
||||
# range = editor.getSelectedBufferRange() # any range you like
|
||||
# marker = editor.markBufferRange(range)
|
||||
# decoration = editor.decorateMarker(marker, {type: 'line', class: 'my-line-class'})
|
||||
# ```
|
||||
#
|
||||
# Best practice for destorying the decoration is by destroying the {Marker}.
|
||||
#
|
||||
# ```
|
||||
# marker.destroy()
|
||||
# ```
|
||||
#
|
||||
# You should only use {Decoration::destroy} when you still need or do not own
|
||||
# the marker.
|
||||
#
|
||||
# ### IDs
|
||||
# Each {Decoration} has a unique ID available via `decoration.id`.
|
||||
#
|
||||
# ### Events
|
||||
# A couple of events are emitted:
|
||||
#
|
||||
# * `destroyed`: When the {Decoration} is destroyed
|
||||
# * `updated`: When the {Decoration} is updated via {Decoration::update}.
|
||||
# Event object has properties `oldParams` and `newParams`
|
||||
#
|
||||
module.exports =
|
||||
class Decoration
|
||||
Emitter.includeInto(this)
|
||||
|
||||
@isType: (decorationParams, type) ->
|
||||
if _.isArray(decorationParams.type)
|
||||
type in decorationParams.type
|
||||
else
|
||||
type is decorationParams.type
|
||||
|
||||
constructor: (@marker, @displayBuffer, @params) ->
|
||||
@id = nextId()
|
||||
@params.id = @id
|
||||
@flashQueue = null
|
||||
@isDestroyed = false
|
||||
|
||||
# Public: Destroy this marker.
|
||||
#
|
||||
# If you own the marker, you should use {Marker::destroy} which will destroy
|
||||
# this decoration.
|
||||
destroy: ->
|
||||
return if @isDestroyed
|
||||
@isDestroyed = true
|
||||
@displayBuffer.removeDecoration(this)
|
||||
@emit 'destroyed'
|
||||
|
||||
# Public: Update the marker with new params. Allows you to change the decoration's class.
|
||||
#
|
||||
# ```
|
||||
# decoration.update({type: 'gutter', class: 'my-new-class'})
|
||||
# ```
|
||||
update: (newParams) ->
|
||||
return if @isDestroyed
|
||||
oldParams = @params
|
||||
@params = newParams
|
||||
@params.id = @id
|
||||
@displayBuffer.decorationUpdated(this)
|
||||
@emit 'updated', {oldParams, newParams}
|
||||
|
||||
# Public: Returns the marker associated with this {Decoration}
|
||||
getMarker: -> @marker
|
||||
|
||||
# Public: Returns the {Decoration}'s params.
|
||||
getParams: -> @params
|
||||
|
||||
# Public: Check if this decoration is of type `type`
|
||||
#
|
||||
# type - A {String} type like `'gutter'`
|
||||
#
|
||||
# Returns a {Boolean}
|
||||
isType: (type) ->
|
||||
Decoration.isType(@params, type)
|
||||
|
||||
matchesPattern: (decorationPattern) ->
|
||||
return false unless decorationPattern?
|
||||
for key, value of decorationPattern
|
||||
return false if @params[key] != value
|
||||
true
|
||||
|
||||
flash: (klass, duration=500) ->
|
||||
flashObject = {class: klass, duration}
|
||||
@flashQueue ?= []
|
||||
@flashQueue.push(flashObject)
|
||||
@emit 'flash'
|
||||
|
||||
consumeNextFlash: ->
|
||||
return @flashQueue.shift() if @flashQueue?.length > 0
|
||||
null
|
||||
+46
-54
@@ -8,6 +8,7 @@ TokenizedBuffer = require './tokenized-buffer'
|
||||
RowMap = require './row-map'
|
||||
Fold = require './fold'
|
||||
Token = require './token'
|
||||
Decoration = require './decoration'
|
||||
DisplayBufferMarker = require './display-buffer-marker'
|
||||
|
||||
class BufferToScreenConversionError extends Error
|
||||
@@ -45,6 +46,7 @@ class DisplayBuffer extends Model
|
||||
@charWidthsByScope = {}
|
||||
@markers = {}
|
||||
@foldsByMarkerId = {}
|
||||
@decorationsById = {}
|
||||
@decorationsByMarkerId = {}
|
||||
@decorationMarkerChangedSubscriptions = {}
|
||||
@decorationMarkerDestroyedSubscriptions = {}
|
||||
@@ -202,6 +204,9 @@ class DisplayBuffer extends Model
|
||||
else
|
||||
@scrollLeft = Math.round(scrollLeft)
|
||||
|
||||
getMaxScrollLeft: ->
|
||||
@getScrollWidth() - @getClientWidth()
|
||||
|
||||
getScrollRight: -> @scrollLeft + @width
|
||||
setScrollRight: (scrollRight) ->
|
||||
@setScrollLeft(scrollRight - @width)
|
||||
@@ -351,8 +356,10 @@ class DisplayBuffer extends Model
|
||||
if editorWidthInChars isnt previousWidthInChars and @softWrap
|
||||
@updateWrappedScreenLines()
|
||||
|
||||
# Returns the editor width in characters for soft wrap.
|
||||
getEditorWidthInChars: ->
|
||||
width = @getWidth()
|
||||
width = @width ? @getScrollWidth()
|
||||
width -= @getVerticalScrollbarWidth()
|
||||
if width? and @defaultCharWidth > 0
|
||||
Math.floor(width / @defaultCharWidth)
|
||||
else
|
||||
@@ -593,6 +600,12 @@ class DisplayBuffer extends Model
|
||||
getMaxLineLength: ->
|
||||
@maxLineLength
|
||||
|
||||
# Gets the row number of the longest screen line.
|
||||
#
|
||||
# Return a {}
|
||||
getLongestScreenRow: ->
|
||||
@longestScreenRow
|
||||
|
||||
# Given a buffer position, this converts it into a screen position.
|
||||
#
|
||||
# bufferPosition - An object that represents a buffer position. It can be either
|
||||
@@ -746,31 +759,17 @@ class DisplayBuffer extends Model
|
||||
rangeForAllLines: ->
|
||||
new Range([0, 0], @clipScreenPosition([Infinity, Infinity]))
|
||||
|
||||
decorationForId: (id) ->
|
||||
@decorationsById[id]
|
||||
|
||||
decorationsForScreenRowRange: (startScreenRow, endScreenRow) ->
|
||||
decorationsByMarkerId = {}
|
||||
|
||||
for marker in @findMarkers(intersectsScreenRowRange: [startScreenRow, endScreenRow])
|
||||
if decorations = @decorationsByMarkerId[marker.id]
|
||||
decorationsByMarkerId[marker.id] = decorations
|
||||
decorationsByMarkerId
|
||||
|
||||
decorationMatchesType: (decoration, type) ->
|
||||
if _.isArray(decoration.type)
|
||||
type in decoration.type
|
||||
else
|
||||
type is decoration.type
|
||||
|
||||
decorationMatchesPattern: (decoration, decorationPattern) ->
|
||||
return false unless decoration? and decorationPattern?
|
||||
for key, value of decorationPattern
|
||||
return false if decoration[key] != value
|
||||
true
|
||||
|
||||
addDecorationForMarker: (marker, decoration) ->
|
||||
unless marker?
|
||||
console.warn 'A null marker cannot be decorated'
|
||||
return
|
||||
|
||||
decorateMarker: (marker, decorationParams) ->
|
||||
marker = @getMarker(marker.id)
|
||||
|
||||
@decorationMarkerDestroyedSubscriptions[marker.id] ?= @subscribe marker, 'destroyed', =>
|
||||
@@ -785,24 +784,23 @@ class DisplayBuffer extends Model
|
||||
for decoration in decorations
|
||||
@emit 'decoration-changed', marker, decoration, event
|
||||
|
||||
decoration = new Decoration(marker, this, decorationParams)
|
||||
@decorationsByMarkerId[marker.id] ?= []
|
||||
@decorationsByMarkerId[marker.id].push(decoration)
|
||||
@decorationsById[decoration.id] = decoration
|
||||
@emit 'decoration-added', marker, decoration
|
||||
decoration
|
||||
|
||||
removeDecorationForMarker: (marker, decorationPattern) ->
|
||||
unless marker?
|
||||
console.warn 'A decoration cannot be removed from a null marker'
|
||||
return
|
||||
|
||||
removeDecoration: (decoration) ->
|
||||
{marker} = decoration
|
||||
return unless decorations = @decorationsByMarkerId[marker.id]
|
||||
index = decorations.indexOf(decoration)
|
||||
|
||||
for i in [decorations.length - 1..0]
|
||||
decoration = decorations[i]
|
||||
if @decorationMatchesPattern(decoration, decorationPattern)
|
||||
decorations.splice(i, 1)
|
||||
@emit 'decoration-removed', marker, decoration
|
||||
|
||||
@removedAllMarkerDecorations(marker) if decorations.length is 0
|
||||
if index > -1
|
||||
decorations.splice(index, 1)
|
||||
delete @decorationsById[decoration.id]
|
||||
@emit 'decoration-removed', marker, decoration
|
||||
@removedAllMarkerDecorations(marker) if decorations.length is 0
|
||||
|
||||
removeAllDecorationsForMarker: (marker) ->
|
||||
decorations = @decorationsByMarkerId[marker.id].slice()
|
||||
@@ -818,6 +816,9 @@ class DisplayBuffer extends Model
|
||||
delete @decorationMarkerChangedSubscriptions[marker.id]
|
||||
delete @decorationMarkerDestroyedSubscriptions[marker.id]
|
||||
|
||||
decorationUpdated: (decoration) ->
|
||||
@emit 'decoration-updated', decoration
|
||||
|
||||
# Retrieves a {DisplayBufferMarker} based on its id.
|
||||
#
|
||||
# id - A {Number} representing a marker id
|
||||
@@ -971,7 +972,7 @@ class DisplayBuffer extends Model
|
||||
for marker in @getMarkers()
|
||||
marker.notifyObservers(textChanged: false)
|
||||
|
||||
destroy: ->
|
||||
destroyed: ->
|
||||
marker.unsubscribe() for marker in @getMarkers()
|
||||
@tokenizedBuffer.destroy()
|
||||
@unsubscribe()
|
||||
@@ -991,18 +992,19 @@ class DisplayBuffer extends Model
|
||||
endBufferRow = @rowMap.bufferRowRangeForBufferRow(endBufferRow - 1)[1]
|
||||
startScreenRow = @rowMap.screenRowRangeForBufferRow(startBufferRow)[0]
|
||||
endScreenRow = @rowMap.screenRowRangeForBufferRow(endBufferRow - 1)[1]
|
||||
|
||||
{screenLines, regions} = @buildScreenLines(startBufferRow, endBufferRow + bufferDelta)
|
||||
screenDelta = screenLines.length - (endScreenRow - startScreenRow)
|
||||
|
||||
@screenLines[startScreenRow...endScreenRow] = screenLines
|
||||
@rowMap.spliceRegions(startBufferRow, endBufferRow - startBufferRow, regions)
|
||||
@findMaxLineLength(startScreenRow, endScreenRow, screenLines)
|
||||
@findMaxLineLength(startScreenRow, endScreenRow, screenLines, screenDelta)
|
||||
|
||||
return if options.suppressChangeEvent
|
||||
|
||||
changeEvent =
|
||||
start: startScreenRow
|
||||
end: endScreenRow - 1
|
||||
screenDelta: screenLines.length - (endScreenRow - startScreenRow)
|
||||
screenDelta: screenDelta
|
||||
bufferDelta: bufferDelta
|
||||
|
||||
if options.delayChangeEvent
|
||||
@@ -1057,7 +1059,7 @@ class DisplayBuffer extends Model
|
||||
|
||||
{screenLines, regions}
|
||||
|
||||
findMaxLineLength: (startScreenRow, endScreenRow, newScreenLines) ->
|
||||
findMaxLineLength: (startScreenRow, endScreenRow, newScreenLines, screenDelta) ->
|
||||
oldMaxLineLength = @maxLineLength
|
||||
|
||||
if startScreenRow <= @longestScreenRow < endScreenRow
|
||||
@@ -1066,33 +1068,23 @@ class DisplayBuffer extends Model
|
||||
maxLengthCandidatesStartRow = 0
|
||||
maxLengthCandidates = @screenLines
|
||||
else
|
||||
@longestScreenRow += screenDelta if endScreenRow < @longestScreenRow
|
||||
maxLengthCandidatesStartRow = startScreenRow
|
||||
maxLengthCandidates = newScreenLines
|
||||
|
||||
for screenLine, screenRow in maxLengthCandidates
|
||||
for screenLine, i in maxLengthCandidates
|
||||
screenRow = maxLengthCandidatesStartRow + i
|
||||
length = screenLine.text.length
|
||||
if length > @maxLineLength
|
||||
@longestScreenRow = maxLengthCandidatesStartRow + screenRow
|
||||
@longestScreenRow = screenRow
|
||||
@maxLineLength = length
|
||||
|
||||
if atom.config.get('editor.debugFindMaxLineLength')
|
||||
unless @maxLineLength is @findReferenceMaxLineLength()
|
||||
debugger
|
||||
throw new Error("Found wrong max line length")
|
||||
|
||||
@computeScrollWidth() if oldMaxLineLength isnt @maxLineLength
|
||||
|
||||
findReferenceMaxLineLength: ->
|
||||
maxLineLength = 0
|
||||
|
||||
for line in @screenLines
|
||||
length = line.text.length
|
||||
maxLineLength = length if length > maxLineLength
|
||||
|
||||
maxLineLength
|
||||
|
||||
computeScrollWidth: ->
|
||||
@scrollWidth = @pixelPositionForScreenPosition([@longestScreenRow, @maxLineLength]).left + 1
|
||||
@scrollWidth = @pixelPositionForScreenPosition([@longestScreenRow, @maxLineLength]).left
|
||||
@scrollWidth += 1 unless @getSoftWrap()
|
||||
@setScrollLeft(Math.min(@getScrollLeft(), @getMaxScrollLeft()))
|
||||
|
||||
handleBufferMarkersUpdated: =>
|
||||
if event = @pendingChangeEvent
|
||||
@@ -1104,7 +1096,7 @@ class DisplayBuffer extends Model
|
||||
@emit 'marker-created', @getMarker(marker.id)
|
||||
|
||||
createFoldForMarker: (marker) ->
|
||||
@addDecorationForMarker(marker, type: 'gutter', class: 'folded')
|
||||
@decorateMarker(marker, type: 'gutter', class: 'folded')
|
||||
new Fold(this, marker)
|
||||
|
||||
foldForMarker: (marker) ->
|
||||
|
||||
+212
-148
@@ -6,14 +6,11 @@ scrollbarStyle = require 'scrollbar-style'
|
||||
|
||||
GutterComponent = require './gutter-component'
|
||||
InputComponent = require './input-component'
|
||||
CursorsComponent = require './cursors-component'
|
||||
LinesComponent = require './lines-component'
|
||||
ScrollbarComponent = require './scrollbar-component'
|
||||
ScrollbarCornerComponent = require './scrollbar-corner-component'
|
||||
SubscriberMixin = require './subscriber-mixin'
|
||||
|
||||
DummyHighlightDecoration = {id: 'dummy', startPixelPosition: {top: 0, left: 0}, endPixelPosition: {top: 0, left: 0}, decorations: [{class: 'dummy'}]}
|
||||
|
||||
module.exports =
|
||||
EditorComponent = React.createClass
|
||||
displayName: 'EditorComponent'
|
||||
@@ -22,6 +19,10 @@ EditorComponent = React.createClass
|
||||
statics:
|
||||
performSyncUpdates: false
|
||||
|
||||
visible: false
|
||||
autoHeight: false
|
||||
backgroundColor: null
|
||||
gutterBackgroundColor: null
|
||||
pendingScrollTop: null
|
||||
pendingScrollLeft: null
|
||||
selectOnMouseMove: false
|
||||
@@ -32,30 +33,29 @@ EditorComponent = React.createClass
|
||||
selectionChanged: false
|
||||
selectionAdded: false
|
||||
scrollingVertically: false
|
||||
gutterWidth: 0
|
||||
refreshingScrollbars: false
|
||||
measuringScrollbars: true
|
||||
pendingVerticalScrollDelta: 0
|
||||
pendingHorizontalScrollDelta: 0
|
||||
mouseWheelScreenRow: null
|
||||
mouseWheelScreenRowClearDelay: 150
|
||||
scrollSensitivity: 0.4
|
||||
scrollViewMeasurementRequested: false
|
||||
heightAndWidthMeasurementRequested: false
|
||||
measureLineHeightAndDefaultCharWidthWhenShown: false
|
||||
remeasureCharacterWidthsWhenShown: false
|
||||
inputEnabled: true
|
||||
scrollViewMeasurementInterval: 100
|
||||
scopedCharacterWidthsChangeCount: null
|
||||
scrollViewMeasurementPaused: false
|
||||
domPollingInterval: 100
|
||||
domPollingIntervalId: null
|
||||
domPollingPaused: false
|
||||
|
||||
render: ->
|
||||
{focused, fontSize, lineHeight, fontFamily, showIndentGuide, showInvisibles, showLineNumbers, visible} = @state
|
||||
{editor, cursorBlinkPeriod, cursorBlinkResumeDelay} = @props
|
||||
{focused, showIndentGuide, showInvisibles, showLineNumbers, visible} = @state
|
||||
{editor, mini, cursorBlinkPeriod, cursorBlinkResumeDelay} = @props
|
||||
maxLineNumberDigits = editor.getLineCount().toString().length
|
||||
invisibles = if showInvisibles then @state.invisibles else {}
|
||||
invisibles = if showInvisibles and not mini then @state.invisibles else {}
|
||||
hasSelection = editor.getSelection()? and !editor.getSelection().isEmpty()
|
||||
style = {}
|
||||
|
||||
if @isMounted()
|
||||
if @performedInitialMeasurement
|
||||
renderedRowRange = @getRenderedRowRange()
|
||||
[renderedStartRow, renderedEndRow] = renderedRowRange
|
||||
cursorPixelRects = @getCursorPixelRects(renderedRowRange)
|
||||
@@ -63,6 +63,7 @@ EditorComponent = React.createClass
|
||||
decorations = editor.decorationsForScreenRowRange(renderedStartRow, renderedEndRow)
|
||||
highlightDecorations = @getHighlightDecorations(decorations)
|
||||
lineDecorations = @getLineDecorations(decorations)
|
||||
placeholderText = @props.placeholderText if @props.placeholderText? and editor.isEmpty()
|
||||
|
||||
scrollHeight = editor.getScrollHeight()
|
||||
scrollWidth = editor.getScrollWidth()
|
||||
@@ -81,16 +82,19 @@ EditorComponent = React.createClass
|
||||
if @mouseWheelScreenRow? and not (renderedStartRow <= @mouseWheelScreenRow < renderedEndRow)
|
||||
mouseWheelScreenRow = @mouseWheelScreenRow
|
||||
|
||||
className = 'editor-contents editor-colors'
|
||||
style.height = scrollViewHeight if @autoHeight
|
||||
|
||||
className = 'editor-contents'
|
||||
className += ' is-focused' if focused
|
||||
className += ' has-selection' if hasSelection
|
||||
|
||||
div className: className, style: {fontSize, lineHeight, fontFamily}, tabIndex: -1,
|
||||
if showLineNumbers
|
||||
div {className, style, tabIndex: -1},
|
||||
if @shouldRenderGutter()
|
||||
GutterComponent {
|
||||
ref: 'gutter', onMouseDown: @onGutterMouseDown, onWidthChanged: @onGutterWidthChanged,
|
||||
lineDecorations, defaultCharWidth, editor, renderedRowRange, maxLineNumberDigits, scrollViewHeight,
|
||||
scrollTop, scrollHeight, lineHeightInPixels, @pendingChanges, mouseWheelScreenRow, @useHardwareAcceleration
|
||||
ref: 'gutter', onMouseDown: @onGutterMouseDown, lineDecorations,
|
||||
defaultCharWidth, editor, renderedRowRange, maxLineNumberDigits, scrollViewHeight,
|
||||
scrollTop, scrollHeight, lineHeightInPixels, @pendingChanges, mouseWheelScreenRow,
|
||||
@useHardwareAcceleration, @performedInitialMeasurement, @backgroundColor, @gutterBackgroundColor
|
||||
}
|
||||
|
||||
div ref: 'scrollView', className: 'scroll-view', onMouseDown: @onMouseDown,
|
||||
@@ -101,18 +105,28 @@ EditorComponent = React.createClass
|
||||
onFocus: @onInputFocused
|
||||
onBlur: @onInputBlurred
|
||||
|
||||
CursorsComponent {
|
||||
scrollTop, scrollLeft, cursorPixelRects, cursorBlinkPeriod, cursorBlinkResumeDelay,
|
||||
lineHeightInPixels, defaultCharWidth, @scopedCharacterWidthsChangeCount, @useHardwareAcceleration
|
||||
}
|
||||
LinesComponent {
|
||||
ref: 'lines',
|
||||
editor, lineHeightInPixels, defaultCharWidth, lineDecorations, highlightDecorations,
|
||||
showIndentGuide, renderedRowRange, @pendingChanges, scrollTop, scrollLeft,
|
||||
@scrollingVertically, scrollHeight, scrollWidth, mouseWheelScreenRow, invisibles,
|
||||
visible, scrollViewHeight, @scopedCharacterWidthsChangeCount, lineWidth, @useHardwareAcceleration
|
||||
@visible, scrollViewHeight, @scopedCharacterWidthsChangeCount, lineWidth, @useHardwareAcceleration,
|
||||
placeholderText, @performedInitialMeasurement, @backgroundColor, cursorPixelRects,
|
||||
cursorBlinkPeriod, cursorBlinkResumeDelay
|
||||
}
|
||||
|
||||
ScrollbarComponent
|
||||
ref: 'horizontalScrollbar'
|
||||
className: 'horizontal-scrollbar'
|
||||
orientation: 'horizontal'
|
||||
onScroll: @onHorizontalScroll
|
||||
scrollLeft: scrollLeft
|
||||
scrollWidth: scrollWidth
|
||||
visible: horizontallyScrollable and not @refreshingScrollbars and not @measuringScrollbars
|
||||
scrollableInOppositeDirection: verticallyScrollable
|
||||
verticalScrollbarWidth: verticalScrollbarWidth
|
||||
horizontalScrollbarHeight: horizontalScrollbarHeight
|
||||
|
||||
ScrollbarComponent
|
||||
ref: 'verticalScrollbar'
|
||||
className: 'vertical-scrollbar'
|
||||
@@ -125,18 +139,6 @@ EditorComponent = React.createClass
|
||||
verticalScrollbarWidth: verticalScrollbarWidth
|
||||
horizontalScrollbarHeight: horizontalScrollbarHeight
|
||||
|
||||
ScrollbarComponent
|
||||
ref: 'horizontalScrollbar'
|
||||
className: 'horizontal-scrollbar'
|
||||
orientation: 'horizontal'
|
||||
onScroll: @onHorizontalScroll
|
||||
scrollLeft: scrollLeft
|
||||
scrollWidth: scrollWidth + @gutterWidth
|
||||
visible: horizontallyScrollable and not @refreshingScrollbars and not @measuringScrollbars
|
||||
scrollableInOppositeDirection: verticallyScrollable
|
||||
verticalScrollbarWidth: verticalScrollbarWidth
|
||||
horizontalScrollbarHeight: horizontalScrollbarHeight
|
||||
|
||||
# Also used to measure the height/width of scrollbars after the initial render
|
||||
ScrollbarCornerComponent
|
||||
ref: 'scrollbarCorner'
|
||||
@@ -149,13 +151,15 @@ EditorComponent = React.createClass
|
||||
{editor} = @props
|
||||
Math.max(1, Math.ceil(editor.getHeight() / editor.getLineHeightInPixels()))
|
||||
|
||||
getInitialState: ->
|
||||
visible: true
|
||||
shouldRenderGutter: ->
|
||||
not @props.mini and @state.showLineNumbers
|
||||
|
||||
getInitialState: -> {}
|
||||
|
||||
getDefaultProps: ->
|
||||
cursorBlinkPeriod: 800
|
||||
cursorBlinkResumeDelay: 100
|
||||
lineOverdrawMargin: 8
|
||||
lineOverdrawMargin: 15
|
||||
|
||||
componentWillMount: ->
|
||||
@pendingChanges = []
|
||||
@@ -166,25 +170,29 @@ EditorComponent = React.createClass
|
||||
componentDidMount: ->
|
||||
{editor} = @props
|
||||
|
||||
@scrollViewMeasurementIntervalId = setInterval(@measureScrollView, @scrollViewMeasurementInterval)
|
||||
@domPollingIntervalId = setInterval(@pollDOM, @domPollingInterval)
|
||||
|
||||
@observeEditor()
|
||||
@listenForDOMEvents()
|
||||
@listenForCommands()
|
||||
|
||||
@subscribe atom.themes, 'stylesheet-added stylsheet-removed', @onStylesheetsChanged
|
||||
@subscribe atom.themes, 'stylesheet-added stylesheet-removed stylesheet-updated', @onStylesheetsChanged
|
||||
@subscribe scrollbarStyle.changes, @refreshScrollbars
|
||||
|
||||
editor.setVisible(true)
|
||||
|
||||
@measureLineHeightAndDefaultCharWidth()
|
||||
@measureScrollView()
|
||||
@measureScrollbars()
|
||||
if @visible = @isVisible()
|
||||
@performInitialMeasurement()
|
||||
@forceUpdate()
|
||||
|
||||
componentWillUnmount: ->
|
||||
@props.parentView.trigger 'editor:will-be-removed', [@props.parentView]
|
||||
@unsubscribe()
|
||||
clearInterval(@scrollViewMeasurementIntervalId)
|
||||
@scrollViewMeasurementIntervalId = null
|
||||
clearInterval(@domPollingIntervalId)
|
||||
@domPollingIntervalId = null
|
||||
|
||||
componentWillUpdate: ->
|
||||
wasVisible = @visible
|
||||
@visible = @isVisible()
|
||||
@performInitialMeasurement() if @visible and not wasVisible
|
||||
|
||||
componentDidUpdate: (prevProps, prevState) ->
|
||||
cursorsMoved = @cursorsMoved
|
||||
@@ -196,15 +204,29 @@ EditorComponent = React.createClass
|
||||
|
||||
if @props.editor.isAlive()
|
||||
@updateParentViewFocusedClassIfNeeded(prevState)
|
||||
@updateParentViewMiniClassIfNeeded(prevState)
|
||||
@props.parentView.trigger 'cursor:moved' if cursorsMoved
|
||||
@props.parentView.trigger 'selection:changed' if selectionChanged
|
||||
@props.parentView.trigger 'editor:display-updated'
|
||||
|
||||
@measureScrollbars() if @measuringScrollbars
|
||||
@measureLineHeightAndCharWidthsIfNeeded(prevState)
|
||||
@remeasureCharacterWidthsIfNeeded(prevState)
|
||||
if @performedInitialMeasurement
|
||||
@measureScrollbars() if @measuringScrollbars
|
||||
|
||||
performInitialMeasurement: ->
|
||||
@updatesPaused = true
|
||||
@measureHeightAndWidth()
|
||||
@sampleFontStyling()
|
||||
@sampleBackgroundColors()
|
||||
@measureScrollbars()
|
||||
@measureLineHeightAndDefaultCharWidth() if @measureLineHeightAndDefaultCharWidthWhenShown
|
||||
@remeasureCharacterWidths() if @remeasureCharacterWidthsWhenShown
|
||||
@props.editor.setVisible(true)
|
||||
@updatesPaused = false
|
||||
@performedInitialMeasurement = true
|
||||
|
||||
requestUpdate: ->
|
||||
return unless @isMounted()
|
||||
|
||||
if @updatesPaused
|
||||
@updateRequestedWhilePaused = true
|
||||
return
|
||||
@@ -213,13 +235,13 @@ EditorComponent = React.createClass
|
||||
@forceUpdate()
|
||||
else unless @updateRequested
|
||||
@updateRequested = true
|
||||
setImmediate =>
|
||||
requestAnimationFrame =>
|
||||
@updateRequested = false
|
||||
@forceUpdate() if @isMounted()
|
||||
|
||||
requestAnimationFrame: (fn) ->
|
||||
@updatesPaused = true
|
||||
@pauseScrollViewMeasurement()
|
||||
@pauseDOMPolling()
|
||||
requestAnimationFrame =>
|
||||
fn()
|
||||
@updatesPaused = false
|
||||
@@ -227,6 +249,9 @@ EditorComponent = React.createClass
|
||||
@updateRequestedWhilePaused = false
|
||||
@forceUpdate()
|
||||
|
||||
getTopmostDOMNode: ->
|
||||
@props.parentView.element
|
||||
|
||||
getRenderedRowRange: ->
|
||||
{editor, lineOverdrawMargin} = @props
|
||||
[visibleStartRow, visibleEndRow] = editor.getVisibleRowRange()
|
||||
@@ -272,7 +297,9 @@ EditorComponent = React.createClass
|
||||
cursorPixelRects
|
||||
|
||||
getLineDecorations: (decorationsByMarkerId) ->
|
||||
{editor} = @props
|
||||
{editor, mini} = @props
|
||||
return {} if mini
|
||||
|
||||
decorationsByScreenRow = {}
|
||||
for markerId, decorations of decorationsByMarkerId
|
||||
marker = editor.getMarker(markerId)
|
||||
@@ -280,21 +307,22 @@ EditorComponent = React.createClass
|
||||
headScreenRow = null
|
||||
if marker.isValid()
|
||||
for decoration in decorations
|
||||
if editor.decorationMatchesType(decoration, 'gutter') or editor.decorationMatchesType(decoration, 'line')
|
||||
if decoration.isType('gutter') or decoration.isType('line')
|
||||
decorationParams = decoration.getParams()
|
||||
screenRange ?= marker.getScreenRange()
|
||||
headScreenRow ?= marker.getHeadScreenPosition().row
|
||||
startRow = screenRange.start.row
|
||||
endRow = screenRange.end.row
|
||||
endRow-- if not screenRange.isEmpty() and screenRange.end.column == 0
|
||||
for screenRow in [startRow..endRow]
|
||||
continue if decoration.onlyHead and screenRow isnt headScreenRow
|
||||
continue if decorationParams.onlyHead and screenRow isnt headScreenRow
|
||||
if screenRange.isEmpty()
|
||||
continue if decoration.onlyNonEmpty
|
||||
continue if decorationParams.onlyNonEmpty
|
||||
else
|
||||
continue if decoration.onlyEmpty
|
||||
continue if decorationParams.onlyEmpty
|
||||
|
||||
decorationsByScreenRow[screenRow] ?= []
|
||||
decorationsByScreenRow[screenRow].push decoration
|
||||
decorationsByScreenRow[screenRow] ?= {}
|
||||
decorationsByScreenRow[screenRow][decoration.id] = decorationParams
|
||||
|
||||
decorationsByScreenRow
|
||||
|
||||
@@ -306,18 +334,14 @@ EditorComponent = React.createClass
|
||||
screenRange = marker.getScreenRange()
|
||||
if marker.isValid() and not screenRange.isEmpty()
|
||||
for decoration in decorations
|
||||
if editor.decorationMatchesType(decoration, 'highlight')
|
||||
if decoration.isType('highlight')
|
||||
decorationParams = decoration.getParams()
|
||||
filteredDecorations[markerId] ?=
|
||||
id: markerId
|
||||
startPixelPosition: editor.pixelPositionForScreenPosition(screenRange.start)
|
||||
endPixelPosition: editor.pixelPositionForScreenPosition(screenRange.end)
|
||||
decorations: []
|
||||
filteredDecorations[markerId].decorations.push decoration
|
||||
|
||||
# At least in Chromium 31, removing the last highlight causes a rendering
|
||||
# artifact where chunks of the lines disappear, so we always leave this
|
||||
# dummy highlight in place to prevent that.
|
||||
filteredDecorations['dummy'] = DummyHighlightDecoration
|
||||
filteredDecorations[markerId].decorations.push decorationParams
|
||||
|
||||
filteredDecorations
|
||||
|
||||
@@ -330,6 +354,7 @@ EditorComponent = React.createClass
|
||||
@subscribe editor, 'decoration-added', @onDecorationChanged
|
||||
@subscribe editor, 'decoration-removed', @onDecorationChanged
|
||||
@subscribe editor, 'decoration-changed', @onDecorationChanged
|
||||
@subscribe editor, 'decoration-updated', @onDecorationChanged
|
||||
@subscribe editor, 'character-widths-changed', @onCharacterWidthsChanged
|
||||
@subscribe editor.$scrollTop.changes, @onScrollTopChanged
|
||||
@subscribe editor.$scrollLeft.changes, @requestUpdate
|
||||
@@ -346,7 +371,7 @@ EditorComponent = React.createClass
|
||||
|
||||
scrollViewNode = @refs.scrollView.getDOMNode()
|
||||
scrollViewNode.addEventListener 'scroll', @onScrollViewScroll
|
||||
window.addEventListener 'resize', @requestScrollViewMeasurement
|
||||
window.addEventListener 'resize', @requestHeightAndWidthMeasurement
|
||||
|
||||
@listenForIMEEvents()
|
||||
|
||||
@@ -458,7 +483,7 @@ EditorComponent = React.createClass
|
||||
'editor:unfold-all': => editor.unfoldAll()
|
||||
'editor:fold-current-row': => editor.foldCurrentRow()
|
||||
'editor:unfold-current-row': => editor.unfoldCurrentRow()
|
||||
'editor:fold-selection': => neditor.foldSelectedLines()
|
||||
'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)
|
||||
@@ -488,9 +513,6 @@ EditorComponent = React.createClass
|
||||
parentView.command command, listener
|
||||
|
||||
observeConfig: ->
|
||||
@subscribe atom.config.observe 'editor.fontFamily', @setFontFamily
|
||||
@subscribe atom.config.observe 'editor.fontSize', @setFontSize
|
||||
@subscribe atom.config.observe 'editor.lineHeight', @setLineHeight
|
||||
@subscribe atom.config.observe 'editor.showIndentGuide', @setShowIndentGuide
|
||||
@subscribe atom.config.observe 'editor.invisibles', @setInvisibles
|
||||
@subscribe atom.config.observe 'editor.showInvisibles', @setShowInvisibles
|
||||
@@ -553,28 +575,23 @@ EditorComponent = React.createClass
|
||||
@pendingScrollLeft = null
|
||||
|
||||
onMouseWheel: (event) ->
|
||||
event.preventDefault()
|
||||
animationFramePending = @pendingHorizontalScrollDelta isnt 0 or @pendingVerticalScrollDelta isnt 0
|
||||
{editor} = @props
|
||||
|
||||
# Only scroll in one direction at a time
|
||||
{wheelDeltaX, wheelDeltaY} = event
|
||||
if Math.abs(wheelDeltaX) > Math.abs(wheelDeltaY)
|
||||
# Scrolling horizontally
|
||||
@pendingHorizontalScrollDelta -= Math.round(wheelDeltaX * @scrollSensitivity)
|
||||
previousScrollLeft = editor.getScrollLeft()
|
||||
editor.setScrollLeft(previousScrollLeft - Math.round(wheelDeltaX * @scrollSensitivity))
|
||||
event.preventDefault() unless previousScrollLeft is editor.getScrollLeft()
|
||||
else
|
||||
# Scrolling vertically
|
||||
@pendingVerticalScrollDelta -= Math.round(wheelDeltaY * @scrollSensitivity)
|
||||
@mouseWheelScreenRow = @screenRowForNode(event.target)
|
||||
@clearMouseWheelScreenRowAfterDelay ?= debounce(@clearMouseWheelScreenRow, @mouseWheelScreenRowClearDelay)
|
||||
@clearMouseWheelScreenRowAfterDelay()
|
||||
|
||||
unless animationFramePending
|
||||
@requestAnimationFrame =>
|
||||
{editor} = @props
|
||||
editor.setScrollTop(editor.getScrollTop() + @pendingVerticalScrollDelta)
|
||||
editor.setScrollLeft(editor.getScrollLeft() + @pendingHorizontalScrollDelta)
|
||||
@pendingVerticalScrollDelta = 0
|
||||
@pendingHorizontalScrollDelta = 0
|
||||
previousScrollTop = editor.getScrollTop()
|
||||
editor.setScrollTop(previousScrollTop - Math.round(wheelDeltaY * @scrollSensitivity))
|
||||
event.preventDefault() unless previousScrollTop is editor.getScrollTop()
|
||||
|
||||
onScrollViewScroll: ->
|
||||
if @isMounted()
|
||||
@@ -595,15 +612,18 @@ EditorComponent = React.createClass
|
||||
editor.unfoldBufferRow(bufferRow)
|
||||
return
|
||||
|
||||
if shiftKey
|
||||
editor.selectToScreenPosition(screenPosition)
|
||||
else if metaKey or (ctrlKey and process.platform isnt 'darwin')
|
||||
editor.addCursorAtScreenPosition(screenPosition)
|
||||
else
|
||||
editor.setCursorScreenPosition(screenPosition)
|
||||
switch detail
|
||||
when 2 then editor.selectWord()
|
||||
when 3 then editor.selectLine()
|
||||
switch detail
|
||||
when 1
|
||||
if shiftKey
|
||||
editor.selectToScreenPosition(screenPosition)
|
||||
else if metaKey or (ctrlKey and process.platform isnt 'darwin')
|
||||
editor.addCursorAtScreenPosition(screenPosition)
|
||||
else
|
||||
editor.setCursorScreenPosition(screenPosition)
|
||||
when 2
|
||||
editor.getLastSelection().selectWord()
|
||||
when 3
|
||||
editor.getLastSelection().selectLine()
|
||||
|
||||
@handleDragUntilMouseUp event, (screenPosition) ->
|
||||
editor.selectToScreenPosition(screenPosition)
|
||||
@@ -647,7 +667,12 @@ EditorComponent = React.createClass
|
||||
editor.setSelectedScreenRange([tailPosition, [dragRow + 1, 0]])
|
||||
|
||||
onStylesheetsChanged: (stylesheet) ->
|
||||
return unless @performedInitialMeasurement
|
||||
|
||||
@refreshScrollbars() if @containsScrollbarSelector(stylesheet)
|
||||
@sampleFontStyling()
|
||||
@sampleBackgroundColors()
|
||||
@remeasureCharacterWidths()
|
||||
|
||||
onScreenLinesChanged: (change) ->
|
||||
{editor} = @props
|
||||
@@ -724,76 +749,114 @@ EditorComponent = React.createClass
|
||||
window.addEventListener('mousemove', onMouseMove)
|
||||
window.addEventListener('mouseup', onMouseUp)
|
||||
|
||||
pauseScrollViewMeasurement: ->
|
||||
@scrollViewMeasurementPaused = true
|
||||
@resumeScrollViewMeasurementAfterDelay ?= debounce(@resumeScrollViewMeasurement, 100)
|
||||
@resumeScrollViewMeasurementAfterDelay()
|
||||
isVisible: ->
|
||||
node = @getDOMNode()
|
||||
node.offsetHeight > 0 or node.offsetWidth > 0
|
||||
|
||||
resumeScrollViewMeasurement: ->
|
||||
@scrollViewMeasurementPaused = false
|
||||
pauseDOMPolling: ->
|
||||
@domPollingPaused = true
|
||||
@resumeDOMPollingAfterDelay ?= debounce(@resumeDOMPolling, 100)
|
||||
@resumeDOMPollingAfterDelay()
|
||||
|
||||
resumeScrollViewMeasurementAfterDelay: null # created lazily
|
||||
resumeDOMPolling: ->
|
||||
@domPollingPaused = false
|
||||
|
||||
requestScrollViewMeasurement: ->
|
||||
return if @scrollViewMeasurementRequested
|
||||
resumeDOMPollingAfterDelay: null # created lazily
|
||||
|
||||
@scrollViewMeasurementRequested = true
|
||||
pollDOM: ->
|
||||
return if @domPollingPaused or @updateRequested or not @isMounted()
|
||||
|
||||
wasVisible = @visible
|
||||
if @visible = @isVisible()
|
||||
if wasVisible
|
||||
@measureHeightAndWidth()
|
||||
@sampleFontStyling()
|
||||
@sampleBackgroundColors()
|
||||
else
|
||||
@performInitialMeasurement()
|
||||
@forceUpdate()
|
||||
|
||||
requestHeightAndWidthMeasurement: ->
|
||||
return if @heightAndWidthMeasurementRequested
|
||||
|
||||
@heightAndWidthMeasurementRequested = true
|
||||
requestAnimationFrame =>
|
||||
@scrollViewMeasurementRequested = false
|
||||
@measureScrollView()
|
||||
@heightAndWidthMeasurementRequested = false
|
||||
@measureHeightAndWidth()
|
||||
|
||||
# Measure explicitly-styled height and width and relay them to the model. If
|
||||
# these values aren't explicitly styled, we assume the editor is unconstrained
|
||||
# and use the scrollHeight / scrollWidth as its height and width in
|
||||
# calculations.
|
||||
measureScrollView: ->
|
||||
return if @scrollViewMeasurementPaused
|
||||
measureHeightAndWidth: ->
|
||||
return unless @isMounted()
|
||||
|
||||
{editor} = @props
|
||||
editorNode = @getDOMNode()
|
||||
{editor, parentView} = @props
|
||||
parentNode = parentView.element
|
||||
scrollViewNode = @refs.scrollView.getDOMNode()
|
||||
{position} = getComputedStyle(editorNode)
|
||||
{width, height} = editorNode.style
|
||||
{position} = getComputedStyle(parentNode)
|
||||
{height} = parentNode.style
|
||||
|
||||
if position is 'absolute' or height
|
||||
if @autoHeight
|
||||
@autoHeight = false
|
||||
@forceUpdate()
|
||||
|
||||
clientHeight = scrollViewNode.clientHeight
|
||||
editor.setHeight(clientHeight) if clientHeight > 0
|
||||
else
|
||||
editor.setHeight(null)
|
||||
@autoHeight = true
|
||||
|
||||
if position is 'absolute' or width
|
||||
clientWidth = scrollViewNode.clientWidth
|
||||
editor.setWidth(clientWidth) if clientWidth > 0
|
||||
clientWidth = scrollViewNode.clientWidth
|
||||
paddingLeft = parseInt(getComputedStyle(scrollViewNode).paddingLeft)
|
||||
clientWidth -= paddingLeft
|
||||
editor.setWidth(clientWidth) if clientWidth > 0
|
||||
|
||||
measureLineHeightAndCharWidthsIfNeeded: (prevState) ->
|
||||
if not isEqualForProperties(prevState, @state, 'lineHeight', 'fontSize', 'fontFamily')
|
||||
if @state.visible
|
||||
@measureLineHeightAndDefaultCharWidth()
|
||||
else
|
||||
@measureLineHeightAndDefaultCharWidthWhenShown = true
|
||||
else if @measureLineHeightAndDefaultCharWidthWhenShown and @state.visible and not prevState.visible
|
||||
sampleFontStyling: ->
|
||||
oldFontSize = @fontSize
|
||||
oldFontFamily = @fontFamily
|
||||
oldLineHeight = @lineHeight
|
||||
|
||||
{@fontSize, @fontFamily, @lineHeight} = getComputedStyle(@getTopmostDOMNode())
|
||||
|
||||
if @fontSize isnt oldFontSize or @fontFamily isnt oldFontFamily or @lineHeight isnt oldLineHeight
|
||||
@measureLineHeightAndDefaultCharWidth()
|
||||
|
||||
measureLineHeightAndDefaultCharWidth: ->
|
||||
@measureLineHeightAndDefaultCharWidthWhenShown = false
|
||||
@refs.lines.measureLineHeightAndDefaultCharWidth()
|
||||
|
||||
remeasureCharacterWidthsIfNeeded: (prevState) ->
|
||||
if not isEqualForProperties(prevState, @state, 'fontSize', 'fontFamily')
|
||||
if @state.visible
|
||||
@remeasureCharacterWidths()
|
||||
else
|
||||
@remeasureCharacterWidthsWhenShown = true
|
||||
else if @remeasureCharacterWidthsWhenShown and @state.visible and not prevState.visible
|
||||
if (@fontSize isnt oldFontSize or @fontFamily isnt oldFontFamily) and @performedInitialMeasurement
|
||||
@remeasureCharacterWidths()
|
||||
|
||||
remeasureCharacterWidths: ->
|
||||
@remeasureCharacterWidthsWhenShown = false
|
||||
@refs.lines.remeasureCharacterWidths()
|
||||
sampleBackgroundColors: (suppressUpdate) ->
|
||||
{parentView} = @props
|
||||
{showLineNumbers} = @state
|
||||
{backgroundColor} = getComputedStyle(parentView.element)
|
||||
|
||||
onGutterWidthChanged: (@gutterWidth) ->
|
||||
@requestUpdate()
|
||||
if backgroundColor isnt @backgroundColor
|
||||
@backgroundColor = backgroundColor
|
||||
@requestUpdate() unless suppressUpdate
|
||||
|
||||
if @shouldRenderGutter()
|
||||
gutterBackgroundColor = getComputedStyle(@refs.gutter.getDOMNode()).backgroundColor
|
||||
if gutterBackgroundColor isnt @gutterBackgroundColor
|
||||
@gutterBackgroundColor = gutterBackgroundColor
|
||||
@requestUpdate() unless suppressUpdate
|
||||
|
||||
measureLineHeightAndDefaultCharWidth: ->
|
||||
if @visible
|
||||
@measureLineHeightAndDefaultCharWidthWhenShown = false
|
||||
@refs.lines.measureLineHeightAndDefaultCharWidth()
|
||||
else
|
||||
@measureLineHeightAndDefaultCharWidthWhenShown = true
|
||||
|
||||
remeasureCharacterWidths: ->
|
||||
if @visible
|
||||
@remeasureCharacterWidthsWhenShown = false
|
||||
@refs.lines.remeasureCharacterWidths()
|
||||
else
|
||||
@remeasureCharacterWidthsWhenShown = true
|
||||
|
||||
measureScrollbars: ->
|
||||
return unless @visible
|
||||
@measuringScrollbars = false
|
||||
|
||||
{editor} = @props
|
||||
@@ -850,26 +913,23 @@ EditorComponent = React.createClass
|
||||
node = node.parentNode
|
||||
null
|
||||
|
||||
hide: ->
|
||||
@setState(visible: false)
|
||||
|
||||
show: ->
|
||||
@setState(visible: true)
|
||||
|
||||
getFontSize: ->
|
||||
@state.fontSize
|
||||
parseInt(getComputedStyle(@getTopmostDOMNode()).fontSize)
|
||||
|
||||
setFontSize: (fontSize) ->
|
||||
@setState({fontSize})
|
||||
@getTopmostDOMNode().style.fontSize = fontSize + 'px'
|
||||
@sampleFontStyling()
|
||||
|
||||
getFontFamily: ->
|
||||
@state.fontFamily
|
||||
getComputedStyle(@getTopmostDOMNode()).fontFamily
|
||||
|
||||
setFontFamily: (fontFamily) ->
|
||||
@setState({fontFamily})
|
||||
@getTopmostDOMNode().style.fontFamily = fontFamily
|
||||
@sampleFontStyling()
|
||||
|
||||
setLineHeight: (lineHeight) ->
|
||||
@setState({lineHeight})
|
||||
@getTopmostDOMNode().style.lineHeight = lineHeight
|
||||
@sampleFontStyling()
|
||||
|
||||
setShowIndentGuide: (showIndentGuide) ->
|
||||
@setState({showIndentGuide})
|
||||
@@ -929,6 +989,10 @@ EditorComponent = React.createClass
|
||||
if prevState.focused isnt @state.focused
|
||||
@props.parentView.toggleClass('is-focused', @props.focused)
|
||||
|
||||
updateParentViewMiniClassIfNeeded: (prevProps) ->
|
||||
if prevProps.mini isnt @props.mini
|
||||
@props.parentView.toggleClass('mini', @props.mini)
|
||||
|
||||
runScrollBenchmark: ->
|
||||
unless process.env.NODE_ENV is 'production'
|
||||
ReactPerf = require 'react-atom-fork/lib/ReactDefaultPerf'
|
||||
|
||||
+62
-67
@@ -131,6 +131,10 @@ TextMateScopeSelector = require('first-mate').ScopeSelector
|
||||
# - {::markScreenRange}
|
||||
# - {::getMarker}
|
||||
# - {::findMarkers}
|
||||
#
|
||||
# ### Decorations
|
||||
# - {::decorateMarker}
|
||||
# - {::decorationsForScreenRowRange}
|
||||
module.exports =
|
||||
class Editor extends Model
|
||||
Serializable.includeInto(this)
|
||||
@@ -146,6 +150,7 @@ class Editor extends Model
|
||||
selections: null
|
||||
suppressSelectionMerging: false
|
||||
updateBatchDepth: 0
|
||||
selectionFlashDuration: 500
|
||||
|
||||
@delegatesMethods 'suggestedIndentForBufferRow', 'autoIndentBufferRow', 'autoIndentBufferRows',
|
||||
'autoDecreaseIndentForBufferRow', 'toggleLineCommentForBufferRow', 'toggleLineCommentsForBufferRows',
|
||||
@@ -218,6 +223,7 @@ class Editor extends Model
|
||||
@subscribe @displayBuffer, "decoration-added", (args...) => @emit 'decoration-added', args...
|
||||
@subscribe @displayBuffer, "decoration-removed", (args...) => @emit 'decoration-removed', args...
|
||||
@subscribe @displayBuffer, "decoration-changed", (args...) => @emit 'decoration-changed', args...
|
||||
@subscribe @displayBuffer, "decoration-updated", (args...) => @emit 'decoration-updated', args...
|
||||
@subscribe @displayBuffer, "character-widths-changed", (changeCount) => @emit 'character-widths-changed', changeCount
|
||||
|
||||
getViewClass: ->
|
||||
@@ -410,9 +416,10 @@ class Editor extends Model
|
||||
@displayBuffer.indentLevelForLine(line)
|
||||
|
||||
# Constructs the string used for tabs.
|
||||
buildIndentString: (number) ->
|
||||
buildIndentString: (number, column=0) ->
|
||||
if @getSoftTabs()
|
||||
_.multiplyString(" ", Math.floor(number * @getTabLength()))
|
||||
tabStopViolation = column % @getTabLength()
|
||||
_.multiplyString(" ", Math.floor(number * @getTabLength()) - tabStopViolation)
|
||||
else
|
||||
_.multiplyString("\t", Math.floor(number))
|
||||
|
||||
@@ -511,6 +518,8 @@ class Editor extends Model
|
||||
# {Delegates to: TextBuffer.isModified}
|
||||
isModified: -> @buffer.isModified()
|
||||
|
||||
isEmpty: -> @buffer.isEmpty()
|
||||
|
||||
# Public: Determine whether the user should be prompted to save before closing
|
||||
# this editor.
|
||||
shouldPromptToSave: -> @isModified() and not @buffer.hasMultipleEditors()
|
||||
@@ -1058,9 +1067,11 @@ class Editor extends Model
|
||||
# All the changes made inside the given {Function} can be reverted with a
|
||||
# single call to {::undo}.
|
||||
#
|
||||
# fn - A {Function} that will be called with each {Selection}.
|
||||
# fn - A {Function} that will be called once for each {Selection}. The first
|
||||
# argument will be a {Selection} and the second argument will be the
|
||||
# {Number} index of that selection.
|
||||
mutateSelectedText: (fn) ->
|
||||
@transact => fn(selection,index) for selection,index in @getSelections()
|
||||
@transact => fn(selection, index) for selection, index in @getSelections()
|
||||
|
||||
replaceSelectedText: (options={}, fn) ->
|
||||
{selectWordIfEmpty} = options
|
||||
@@ -1078,8 +1089,10 @@ class Editor extends Model
|
||||
# startScreenRow - the {Number} beginning screen row
|
||||
# endScreenRow - the {Number} end screen row (inclusive)
|
||||
#
|
||||
# Returns an {Object} of decorations in the form `{1: [{type: 'gutter', class: 'someclass'}], 2: ...}`
|
||||
# where the keys are markerIds, and the values are an array of decoration objects attached to the marker.
|
||||
# Returns an {Object} of decorations in the form
|
||||
# `{1: [{id: 10, type: 'gutter', class: 'someclass'}], 2: ...}`
|
||||
# where the keys are {Marker} IDs, and the values are an array of decoration
|
||||
# params objects attached to the marker.
|
||||
# Returns an empty object when no decorations are found
|
||||
decorationsForScreenRowRange: (startScreenRow, endScreenRow) ->
|
||||
@displayBuffer.decorationsForScreenRowRange(startScreenRow, endScreenRow)
|
||||
@@ -1088,62 +1101,45 @@ class Editor extends Model
|
||||
# is invalidated, or is destroyed, the decoration will be updated to reflect
|
||||
# the marker's state.
|
||||
#
|
||||
# There are three types of supported decorations:
|
||||
# * `line`: Adds your CSS `class` to the line nodes within the range
|
||||
# marked by the marker
|
||||
# * `gutter`: Adds your CSS `class` to the line number nodes within the
|
||||
# range marked by the marker
|
||||
# * `highlight`: Adds a new highlight div to the editor surrounding the
|
||||
# range marked by the marker. When the user selects text, the selection is
|
||||
# visualized with a highlight decoration internally. The structure of this
|
||||
# highlight will be:
|
||||
# ```html
|
||||
# <div class="highlight <your-class>">
|
||||
# <!-- Will be one region for each row in the range. Spans 2 lines? There will be 2 regions. -->
|
||||
# <div class="region"></div>
|
||||
# </div>
|
||||
# ```
|
||||
#
|
||||
# marker - A {Marker} you want this decoration to follow.
|
||||
# decoration - An {Object} representing the decoration eg. `{type: 'gutter', class: 'linter-error'}`
|
||||
# The decoration can contain the following keys:
|
||||
# * type: There are a few supported decoration types:
|
||||
# * `gutter`: Applies the decoration to the line numbers spanned by the
|
||||
# marker.
|
||||
# * `line`: Applies the decoration to the lines spanned by the marker.
|
||||
# * `highlight`: Applies the decoration to a "highlight" behind the
|
||||
# marked range. When the user selects text, the selection is
|
||||
# visualized with a highlight decoration internally.
|
||||
# * class: This CSS class will be applied to the decorated line number,
|
||||
# line, or highlight.
|
||||
# * onlyHead: If `true`, the decoration will only be applied to the head
|
||||
# of the marker. Only applicable to the `line` and `gutter` types.
|
||||
# * onlyEmpty: If `true`, the decoration will only be applied if the
|
||||
# associated marker is empty. Only applicable to the `line` and
|
||||
# `gutter` types.
|
||||
# * onlyNonEmpty: If `true`, the decoration will only be applied if the
|
||||
# associated marker is non-empty. Only applicable to the `line` and
|
||||
# gutter types.
|
||||
addDecorationForMarker: (marker, decoration) ->
|
||||
@displayBuffer.addDecorationForMarker(marker, decoration)
|
||||
# decorationParams - An {Object} representing the decoration eg. `{type: 'gutter', class: 'linter-error'}`
|
||||
# :type - There are a few supported decoration types:
|
||||
# * `gutter`: Applies the decoration to the line numbers spanned by the marker.
|
||||
# * `line`: Applies the decoration to the lines spanned by the marker.
|
||||
# * `highlight`: Applies the decoration to a "highlight" behind the marked range.
|
||||
# :class - This CSS class will be applied to the decorated line number,
|
||||
# line, or highlight.
|
||||
# :onlyHead - If `true`, the decoration will only be applied to the head
|
||||
# of the marker. Only applicable to the `line` and `gutter` types.
|
||||
# :onlyEmpty - If `true`, the decoration will only be applied if the
|
||||
# associated marker is empty. Only applicable to the `line` and
|
||||
# `gutter` types.
|
||||
# :onlyNonEmpty - If `true`, the decoration will only be applied if the
|
||||
# associated marker is non-empty. Only applicable to the `line` and
|
||||
# gutter types.
|
||||
#
|
||||
# Returns a {Decoration} object
|
||||
decorateMarker: (marker, decorationParams) ->
|
||||
@displayBuffer.decorateMarker(marker, decorationParams)
|
||||
|
||||
# Public: Removes all decorations associated with a {Marker} that match a
|
||||
# `decorationPattern` and stop tracking the {Marker}.
|
||||
#
|
||||
# ```coffee
|
||||
# marker = editor.markBufferRange([[4, 13], [5, 17]])
|
||||
# editor.removeDecorationForMarker(marker, {type: 'gutter', class: 'linter-error'})
|
||||
# ```
|
||||
#
|
||||
# All decorations matching a pattern will be removed. For example, you might
|
||||
# have decorations with a namespace like this attached to a row:
|
||||
#
|
||||
# ```coffee
|
||||
# [
|
||||
# {type: 'gutter', namespace: 'myns', class: 'something'},
|
||||
# {type: 'gutter', namespace: 'myns', class: 'something-else'}
|
||||
# ]
|
||||
# ```
|
||||
#
|
||||
# You can remove both with:
|
||||
#
|
||||
# ```coffee
|
||||
# editor.removeDecorationForMarker(marker, {namespace: 'myns'})
|
||||
# ```
|
||||
#
|
||||
# marker - the {Marker} to detach from
|
||||
# decorationPattern - the {Object} decoration type to filter by eg. `{type: 'gutter', class: 'linter-error'}`
|
||||
#
|
||||
# Returns nothing
|
||||
removeDecorationForMarker: (marker, decorationPattern) ->
|
||||
@displayBuffer.removeDecorationForMarker(marker, decorationPattern)
|
||||
|
||||
decorationMatchesType: (decoration, type) ->
|
||||
@displayBuffer.decorationMatchesType(decoration, type)
|
||||
decorationForId: (id) ->
|
||||
@displayBuffer.decorationForId(id)
|
||||
|
||||
# Public: Get the {DisplayBufferMarker} for the given marker id.
|
||||
getMarker: (id) ->
|
||||
@@ -1250,9 +1246,9 @@ class Editor extends Model
|
||||
addCursor: (marker) ->
|
||||
cursor = new Cursor(editor: this, marker: marker)
|
||||
@cursors.push(cursor)
|
||||
@addDecorationForMarker(marker, type: 'gutter', class: 'cursor-line')
|
||||
@addDecorationForMarker(marker, type: 'gutter', class: 'cursor-line-no-selection', onlyHead: true, onlyEmpty: true)
|
||||
@addDecorationForMarker(marker, type: 'line', class: 'cursor-line', onlyEmpty: true)
|
||||
@decorateMarker(marker, type: 'gutter', class: 'cursor-line')
|
||||
@decorateMarker(marker, type: 'gutter', class: 'cursor-line-no-selection', onlyHead: true, onlyEmpty: true)
|
||||
@decorateMarker(marker, type: 'line', class: 'cursor-line', onlyEmpty: true)
|
||||
@emit 'cursor-added', cursor
|
||||
cursor
|
||||
|
||||
@@ -1279,7 +1275,6 @@ class Editor extends Model
|
||||
if selection.intersectsBufferRange(selectionBufferRange)
|
||||
return selection
|
||||
else
|
||||
@addDecorationForMarker(marker, type: 'highlight', class: 'selection')
|
||||
@emit 'selection-added', selection
|
||||
selection
|
||||
|
||||
@@ -1294,7 +1289,7 @@ class Editor extends Model
|
||||
addSelectionForBufferRange: (bufferRange, options={}) ->
|
||||
@markBufferRange(bufferRange, _.defaults(@getSelectionMarkerAttributes(), options))
|
||||
selection = @getLastSelection()
|
||||
selection.autoscroll()
|
||||
selection.autoscroll() if @manageScrollPosition
|
||||
selection
|
||||
|
||||
# Public: Set the selected range in buffer coordinates. If there are multiple
|
||||
@@ -1502,7 +1497,7 @@ class Editor extends Model
|
||||
# text - A {String}
|
||||
#
|
||||
# Returns the {Range} of the newly-inserted text.
|
||||
setTextInBufferRange: (range, text) -> @getBuffer().setTextInRange(range, text)
|
||||
setTextInBufferRange: (range, text, normalizeLineEndings) -> @getBuffer().setTextInRange(range, text, normalizeLineEndings)
|
||||
|
||||
# Public: Get the {Range} of the paragraph surrounding the most recently added
|
||||
# cursor.
|
||||
@@ -1767,7 +1762,7 @@ class Editor extends Model
|
||||
{row} = start
|
||||
while ++row < end.row
|
||||
@addSelectionForBufferRange([[row, 0], [row, Infinity]])
|
||||
@addSelectionForBufferRange([[end.row, 0], [end.row, end.column]])
|
||||
@addSelectionForBufferRange([[end.row, 0], [end.row, end.column]]) unless end.column is 0
|
||||
|
||||
# Public: For each selection, transpose the selected text.
|
||||
#
|
||||
|
||||
@@ -2,6 +2,7 @@ _ = require 'underscore-plus'
|
||||
React = require 'react-atom-fork'
|
||||
{div} = require 'reactionary-atom-fork'
|
||||
{isEqual, isEqualForProperties, multiplyString, toArray} = require 'underscore-plus'
|
||||
Decoration = require './decoration'
|
||||
SubscriberMixin = require './subscriber-mixin'
|
||||
|
||||
WrapperDiv = document.createElement('div')
|
||||
@@ -15,14 +16,16 @@ GutterComponent = React.createClass
|
||||
measuredWidth: null
|
||||
|
||||
render: ->
|
||||
{scrollHeight, scrollViewHeight, onMouseDown} = @props
|
||||
{scrollHeight, scrollViewHeight, onMouseDown, backgroundColor, gutterBackgroundColor} = @props
|
||||
|
||||
if gutterBackgroundColor isnt 'rbga(0, 0, 0, 0)'
|
||||
backgroundColor = gutterBackgroundColor
|
||||
|
||||
div className: 'gutter', onClick: @onClick, onMouseDown: onMouseDown,
|
||||
# The line-numbers div must have the 'editor-colors' class so it has an
|
||||
# opaque background to avoid sub-pixel anti-aliasing problems on the GPU
|
||||
div className: 'gutter line-numbers editor-colors', ref: 'lineNumbers', style:
|
||||
div className: 'line-numbers', ref: 'lineNumbers', style:
|
||||
height: Math.max(scrollHeight, scrollViewHeight)
|
||||
WebkitTransform: @getTransform()
|
||||
backgroundColor: backgroundColor
|
||||
|
||||
getTransform: ->
|
||||
{scrollTop, useHardwareAcceleration} = @props
|
||||
@@ -40,6 +43,7 @@ GutterComponent = React.createClass
|
||||
|
||||
componentDidMount: ->
|
||||
@appendDummyLineNumber()
|
||||
@updateLineNumbers() if @props.performedInitialMeasurement
|
||||
|
||||
# Only update the gutter if the visible row range has changed or if a
|
||||
# non-zero-delta change to the screen lines has occurred within the current
|
||||
@@ -47,23 +51,24 @@ GutterComponent = React.createClass
|
||||
shouldComponentUpdate: (newProps) ->
|
||||
return true unless isEqualForProperties(newProps, @props,
|
||||
'renderedRowRange', 'scrollTop', 'lineHeightInPixels', 'mouseWheelScreenRow', 'lineDecorations',
|
||||
'scrollViewHeight', 'useHardwareAcceleration'
|
||||
'scrollViewHeight', 'useHardwareAcceleration', 'backgroundColor', 'gutterBackgroundColor'
|
||||
)
|
||||
|
||||
{renderedRowRange, pendingChanges, lineDecorations} = newProps
|
||||
return false unless renderedRowRange?
|
||||
|
||||
for change in pendingChanges when Math.abs(change.screenDelta) > 0 or Math.abs(change.bufferDelta) > 0
|
||||
return true unless change.end <= renderedRowRange.start or renderedRowRange.end <= change.start
|
||||
|
||||
false
|
||||
|
||||
componentDidUpdate: (oldProps) ->
|
||||
return unless @props.performedInitialMeasurement
|
||||
|
||||
unless isEqualForProperties(oldProps, @props, 'maxLineNumberDigits')
|
||||
@updateDummyLineNumber()
|
||||
@removeLineNumberNodes()
|
||||
|
||||
unless isEqualForProperties(oldProps, @props, 'maxLineNumberDigits', 'defaultCharWidth')
|
||||
@measureWidth()
|
||||
|
||||
@clearScreenRowCaches() unless oldProps.lineHeightInPixels is @props.lineHeightInPixels
|
||||
@updateLineNumbers()
|
||||
|
||||
@@ -153,8 +158,8 @@ GutterComponent = React.createClass
|
||||
|
||||
classes = ''
|
||||
if lineDecorations? and decorations = lineDecorations[screenRow]
|
||||
for decoration in decorations
|
||||
if editor.decorationMatchesType(decoration, 'gutter')
|
||||
for id, decoration of decorations
|
||||
if Decoration.isType(decoration, 'gutter')
|
||||
classes += decoration.class + ' '
|
||||
|
||||
classes += "foldable " if bufferRow >= 0 and editor.isFoldableAtBufferRow(bufferRow)
|
||||
@@ -185,12 +190,13 @@ GutterComponent = React.createClass
|
||||
previousDecorations = @renderedDecorationsByLineNumberId[lineNumberId]
|
||||
|
||||
if previousDecorations?
|
||||
for decoration in previousDecorations
|
||||
node.classList.remove(decoration.class) if editor.decorationMatchesType(decoration, 'gutter') and not _.deepContains(decorations, decoration)
|
||||
for id, decoration of previousDecorations
|
||||
if Decoration.isType(decoration, 'gutter') and not @hasDecoration(decorations, decoration)
|
||||
node.classList.remove(decoration.class)
|
||||
|
||||
if decorations?
|
||||
for decoration in decorations
|
||||
if editor.decorationMatchesType(decoration, 'gutter') and not _.deepContains(previousDecorations, decoration)
|
||||
for id, decoration of decorations
|
||||
if Decoration.isType(decoration, 'gutter') and not @hasDecoration(previousDecorations, decoration)
|
||||
node.classList.add(decoration.class)
|
||||
|
||||
unless @screenRowsByLineNumberId[lineNumberId] is screenRow
|
||||
@@ -200,6 +206,9 @@ GutterComponent = React.createClass
|
||||
@screenRowsByLineNumberId[lineNumberId] = screenRow
|
||||
@lineNumberIdsByScreenRow[screenRow] = lineNumberId
|
||||
|
||||
hasDecoration: (decorations, decoration) ->
|
||||
decorations? and decorations[decoration.id] is decoration
|
||||
|
||||
hasLineNumberNode: (lineNumberId) ->
|
||||
@lineNumberNodesById.hasOwnProperty(lineNumberId)
|
||||
|
||||
@@ -217,9 +226,3 @@ GutterComponent = React.createClass
|
||||
editor.unfoldBufferRow(bufferRow)
|
||||
else
|
||||
editor.foldBufferRow(bufferRow)
|
||||
|
||||
measureWidth: ->
|
||||
width = @getDOMNode().offsetWidth
|
||||
unless width is @measuredWidth
|
||||
@measuredWidth = width
|
||||
@props.onWidthChanged?(width)
|
||||
|
||||
@@ -11,12 +11,35 @@ HighlightComponent = React.createClass
|
||||
|
||||
className = 'highlight'
|
||||
className += " #{decoration.class}" if decoration.class?
|
||||
|
||||
div {className},
|
||||
if endPixelPosition.top is startPixelPosition.top
|
||||
@renderSingleLineRegions()
|
||||
else
|
||||
@renderMultiLineRegions()
|
||||
|
||||
componentDidMount: ->
|
||||
{editor, decoration} = @props
|
||||
if decoration.id?
|
||||
@decoration = editor.decorationForId(decoration.id)
|
||||
@decoration.on 'flash', @startFlashAnimation
|
||||
@startFlashAnimation()
|
||||
|
||||
componentWillUnmount: ->
|
||||
@decoration?.off 'flash', @startFlashAnimation
|
||||
|
||||
startFlashAnimation: ->
|
||||
return unless flash = @decoration.consumeNextFlash()
|
||||
|
||||
node = @getDOMNode()
|
||||
node.classList.remove(flash.class)
|
||||
|
||||
requestAnimationFrame =>
|
||||
node.classList.add(flash.class)
|
||||
clearTimeout(@flashTimeoutId)
|
||||
removeFlashClass = -> node.classList.remove(flash.class)
|
||||
@flashTimeoutId = setTimeout(removeFlashClass, flash.duration)
|
||||
|
||||
renderSingleLineRegions: ->
|
||||
{startPixelPosition, endPixelPosition, lineHeightInPixels} = @props
|
||||
|
||||
|
||||
@@ -9,15 +9,15 @@ HighlightsComponent = React.createClass
|
||||
|
||||
render: ->
|
||||
div className: 'highlights',
|
||||
@renderHighlights() if @isMounted()
|
||||
@renderHighlights() if @props.performedInitialMeasurement
|
||||
|
||||
renderHighlights: ->
|
||||
{highlightDecorations, lineHeightInPixels} = @props
|
||||
{editor, highlightDecorations, lineHeightInPixels} = @props
|
||||
|
||||
highlightComponents = []
|
||||
for markerId, {startPixelPosition, endPixelPosition, decorations} of highlightDecorations
|
||||
for decoration in decorations
|
||||
highlightComponents.push(HighlightComponent({key: "#{markerId}-#{decoration.class}", startPixelPosition, endPixelPosition, decoration, lineHeightInPixels}))
|
||||
highlightComponents.push(HighlightComponent({editor, key: "#{markerId}-#{decoration.class}", startPixelPosition, endPixelPosition, decoration, lineHeightInPixels}))
|
||||
|
||||
highlightComponents
|
||||
|
||||
|
||||
+10
-10
@@ -43,12 +43,12 @@ class LanguageMode
|
||||
commentStartRegex = new OnigRegExp("^(\\s*)(#{commentStartRegexString})")
|
||||
|
||||
if commentEndString
|
||||
shouldUncomment = commentStartRegex.test(buffer.lineForRow(start))
|
||||
shouldUncomment = commentStartRegex.testSync(buffer.lineForRow(start))
|
||||
if shouldUncomment
|
||||
commentEndRegexString = _.escapeRegExp(commentEndString).replace(/^(\s+)/, '(?:$1)?')
|
||||
commentEndRegex = new OnigRegExp("(#{commentEndRegexString})(\\s*)$")
|
||||
startMatch = commentStartRegex.search(buffer.lineForRow(start))
|
||||
endMatch = commentEndRegex.search(buffer.lineForRow(end))
|
||||
startMatch = commentStartRegex.searchSync(buffer.lineForRow(start))
|
||||
endMatch = commentEndRegex.searchSync(buffer.lineForRow(end))
|
||||
if startMatch and endMatch
|
||||
buffer.transact ->
|
||||
columnStart = startMatch[1].length
|
||||
@@ -72,13 +72,13 @@ class LanguageMode
|
||||
blank = line?.match(/^\s*$/)
|
||||
|
||||
allBlank = false unless blank
|
||||
allBlankOrCommented = false unless blank or commentStartRegex.test(line)
|
||||
allBlankOrCommented = false unless blank or commentStartRegex.testSync(line)
|
||||
|
||||
shouldUncomment = allBlankOrCommented and not allBlank
|
||||
|
||||
if shouldUncomment
|
||||
for row in [start..end]
|
||||
if match = commentStartRegex.search(buffer.lineForRow(row))
|
||||
if match = commentStartRegex.searchSync(buffer.lineForRow(row))
|
||||
columnStart = match[1].length
|
||||
columnEnd = columnStart + match[2].length
|
||||
buffer.setTextInRange([[row, columnStart], [row, columnEnd]], "")
|
||||
@@ -168,7 +168,7 @@ class LanguageMode
|
||||
continue if @editor.isBufferRowBlank(row)
|
||||
indentation = @editor.indentationForBufferRow(row)
|
||||
if indentation <= startIndentLevel
|
||||
includeRowInFold = indentation == startIndentLevel and @foldEndRegexForScopes(scopes)?.search(@editor.lineForBufferRow(row))
|
||||
includeRowInFold = indentation == startIndentLevel and @foldEndRegexForScopes(scopes)?.searchSync(@editor.lineForBufferRow(row))
|
||||
foldEndRow = row if includeRowInFold
|
||||
break
|
||||
|
||||
@@ -250,10 +250,10 @@ class LanguageMode
|
||||
|
||||
precedingLine = @buffer.lineForRow(precedingRow)
|
||||
desiredIndentLevel = @editor.indentationForBufferRow(precedingRow)
|
||||
desiredIndentLevel += 1 if increaseIndentRegex.test(precedingLine) and not @editor.isBufferRowCommented(precedingRow)
|
||||
desiredIndentLevel += 1 if increaseIndentRegex.testSync(precedingLine) and not @editor.isBufferRowCommented(precedingRow)
|
||||
|
||||
return desiredIndentLevel unless decreaseIndentRegex = @decreaseIndentRegexForScopes(scopes)
|
||||
desiredIndentLevel -= 1 if decreaseIndentRegex.test(currentLine)
|
||||
desiredIndentLevel -= 1 if decreaseIndentRegex.testSync(currentLine)
|
||||
|
||||
Math.max(desiredIndentLevel, 0)
|
||||
|
||||
@@ -293,7 +293,7 @@ class LanguageMode
|
||||
return unless increaseIndentRegex and decreaseIndentRegex
|
||||
|
||||
line = @buffer.lineForRow(bufferRow)
|
||||
return unless decreaseIndentRegex.test(line)
|
||||
return unless decreaseIndentRegex.testSync(line)
|
||||
|
||||
currentIndentLevel = @editor.indentationForBufferRow(bufferRow)
|
||||
return if currentIndentLevel is 0
|
||||
@@ -302,7 +302,7 @@ class LanguageMode
|
||||
precedingLine = @buffer.lineForRow(precedingRow)
|
||||
|
||||
desiredIndentLevel = @editor.indentationForBufferRow(precedingRow)
|
||||
desiredIndentLevel -= 1 unless increaseIndentRegex.test(precedingLine)
|
||||
desiredIndentLevel -= 1 unless increaseIndentRegex.testSync(precedingLine)
|
||||
if desiredIndentLevel >= 0 and desiredIndentLevel < currentIndentLevel
|
||||
@editor.setIndentationForBufferRow(bufferRow, desiredIndentLevel)
|
||||
|
||||
|
||||
@@ -30,6 +30,10 @@ class LessCompileCache
|
||||
setImportPaths: (importPaths=[]) ->
|
||||
@cache.setImportPaths(importPaths.concat(@lessSearchPaths))
|
||||
|
||||
read: (stylesheetPath) -> @cache.readFileSync(stylesheetPath)
|
||||
read: (stylesheetPath) ->
|
||||
@cache.readFileSync(stylesheetPath)
|
||||
|
||||
cssForFile: (stylesheetPath, lessContent) ->
|
||||
@cache.cssForFile(stylesheetPath, lessContent)
|
||||
|
||||
destroy: -> @unsubscribe()
|
||||
|
||||
@@ -4,6 +4,8 @@ React = require 'react-atom-fork'
|
||||
{debounce, isEqual, isEqualForProperties, multiplyString, toArray} = require 'underscore-plus'
|
||||
{$$} = require 'space-pen'
|
||||
|
||||
Decoration = require './decoration'
|
||||
CursorsComponent = require './cursors-component'
|
||||
HighlightsComponent = require './highlights-component'
|
||||
|
||||
DummyLineNode = $$(-> @div className: 'line', style: 'position: absolute; visibility: hidden;', => @span 'x')[0]
|
||||
@@ -15,18 +17,30 @@ LinesComponent = React.createClass
|
||||
displayName: 'LinesComponent'
|
||||
|
||||
render: ->
|
||||
if @isMounted()
|
||||
{editor, highlightDecorations, scrollHeight, scrollWidth} = @props
|
||||
{performedInitialMeasurement, cursorBlinkPeriod, cursorBlinkResumeDelay} = @props
|
||||
|
||||
if performedInitialMeasurement
|
||||
{editor, highlightDecorations, scrollHeight, scrollWidth, placeholderText, backgroundColor} = @props
|
||||
{lineHeightInPixels, defaultCharWidth, scrollViewHeight, scopedCharacterWidthsChangeCount} = @props
|
||||
{scrollTop, scrollLeft, cursorPixelRects} = @props
|
||||
style =
|
||||
height: Math.max(scrollHeight, scrollViewHeight)
|
||||
width: scrollWidth
|
||||
WebkitTransform: @getTransform()
|
||||
backgroundColor: backgroundColor
|
||||
|
||||
# The lines div must have the 'editor-colors' class so it has an opaque
|
||||
# background to avoid sub-pixel anti-aliasing problems on the GPU
|
||||
div {className: 'lines editor-colors', style},
|
||||
HighlightsComponent({editor, highlightDecorations, lineHeightInPixels, defaultCharWidth, scopedCharacterWidthsChangeCount})
|
||||
div {className: 'lines', style},
|
||||
div className: 'placeholder-text', placeholderText if placeholderText?
|
||||
|
||||
CursorsComponent {
|
||||
cursorPixelRects, cursorBlinkPeriod, cursorBlinkResumeDelay, lineHeightInPixels,
|
||||
defaultCharWidth, scopedCharacterWidthsChangeCount, performedInitialMeasurement
|
||||
}
|
||||
|
||||
HighlightsComponent {
|
||||
editor, highlightDecorations, lineHeightInPixels, defaultCharWidth,
|
||||
scopedCharacterWidthsChangeCount, performedInitialMeasurement
|
||||
}
|
||||
|
||||
getTransform: ->
|
||||
{scrollTop, scrollLeft, useHardwareAcceleration} = @props
|
||||
@@ -47,10 +61,13 @@ LinesComponent = React.createClass
|
||||
return true unless isEqualForProperties(newProps, @props,
|
||||
'renderedRowRange', 'lineDecorations', 'highlightDecorations', 'lineHeightInPixels', 'defaultCharWidth',
|
||||
'scrollTop', 'scrollLeft', 'showIndentGuide', 'scrollingVertically', 'invisibles', 'visible',
|
||||
'scrollViewHeight', 'mouseWheelScreenRow', 'scopedCharacterWidthsChangeCount', 'lineWidth', 'useHardwareAcceleration'
|
||||
'scrollViewHeight', 'mouseWheelScreenRow', 'scopedCharacterWidthsChangeCount', 'lineWidth', 'useHardwareAcceleration',
|
||||
'placeholderText', 'performedInitialMeasurement', 'backgroundColor', 'cursorPixelRects'
|
||||
)
|
||||
|
||||
{renderedRowRange, pendingChanges} = newProps
|
||||
return false unless renderedRowRange?
|
||||
|
||||
[renderedStartRow, renderedEndRow] = renderedRowRange
|
||||
for change in pendingChanges
|
||||
if change.screenDelta is 0
|
||||
@@ -61,7 +78,8 @@ LinesComponent = React.createClass
|
||||
false
|
||||
|
||||
componentDidUpdate: (prevProps) ->
|
||||
{visible, scrollingVertically} = @props
|
||||
{visible, scrollingVertically, performedInitialMeasurement} = @props
|
||||
return unless performedInitialMeasurement
|
||||
|
||||
@clearScreenRowCaches() unless prevProps.lineHeightInPixels is @props.lineHeightInPixels
|
||||
@removeLineNodes() unless isEqualForProperties(prevProps, @props, 'showIndentGuide', 'invisibles')
|
||||
@@ -134,8 +152,8 @@ LinesComponent = React.createClass
|
||||
|
||||
classes = ''
|
||||
if decorations = lineDecorations[screenRow]
|
||||
for decoration in decorations
|
||||
if editor.decorationMatchesType(decoration, 'line')
|
||||
for id, decoration of decorations
|
||||
if Decoration.isType(decoration, 'line')
|
||||
classes += decoration.class + ' '
|
||||
classes += 'line'
|
||||
|
||||
@@ -152,14 +170,31 @@ LinesComponent = React.createClass
|
||||
lineHTML
|
||||
|
||||
buildEmptyLineInnerHTML: (line) ->
|
||||
{showIndentGuide} = @props
|
||||
{showIndentGuide, invisibles} = @props
|
||||
{cr, eol} = invisibles
|
||||
{indentLevel, tabLength} = line
|
||||
|
||||
if showIndentGuide and indentLevel > 0
|
||||
indentSpan = "<span class='indent-guide'>#{multiplyString(' ', tabLength)}</span>"
|
||||
multiplyString(indentSpan, indentLevel + 1)
|
||||
invisiblesToRender = []
|
||||
invisiblesToRender.push(cr) if cr? and line.lineEnding is '\r\n'
|
||||
invisiblesToRender.push(eol) if eol?
|
||||
|
||||
lineHTML = ''
|
||||
for i in [0...indentLevel]
|
||||
lineHTML += "<span class='indent-guide'>"
|
||||
for j in [0...tabLength]
|
||||
if invisible = invisiblesToRender.shift()
|
||||
lineHTML += "<span class='invisible-character'>#{invisible}</span>"
|
||||
else
|
||||
lineHTML += ' '
|
||||
lineHTML += "</span>"
|
||||
|
||||
while invisiblesToRender.length
|
||||
lineHTML += "<span class='invisible-character'>#{invisiblesToRender.shift()}</span>"
|
||||
|
||||
lineHTML
|
||||
else
|
||||
" "
|
||||
@buildEndOfLineHTML(line, @props.invisibles) or ' '
|
||||
|
||||
buildLineInnerHTML: (line) ->
|
||||
{invisibles, mini, showIndentGuide, invisibles} = @props
|
||||
@@ -171,7 +206,7 @@ LinesComponent = React.createClass
|
||||
lineIsWhitespaceOnly = firstTrailingWhitespacePosition is 0
|
||||
for token in tokens
|
||||
innerHTML += @updateScopeStack(scopeStack, token.scopes)
|
||||
hasIndentGuide = not mini and showIndentGuide and token.hasLeadingWhitespace or (token.hasTrailingWhitespace and lineIsWhitespaceOnly)
|
||||
hasIndentGuide = not mini and showIndentGuide and (token.hasLeadingWhitespace or (token.hasTrailingWhitespace and lineIsWhitespaceOnly))
|
||||
innerHTML += token.getValueAsHtml({invisibles, hasIndentGuide})
|
||||
|
||||
innerHTML += @popScope(scopeStack) while scopeStack.length > 0
|
||||
@@ -182,9 +217,11 @@ LinesComponent = React.createClass
|
||||
return '' if @props.mini or line.isSoftWrapped()
|
||||
|
||||
html = ''
|
||||
if invisibles.cr? and line.lineEnding is '\r\n'
|
||||
# Note the lack of '?' in the character checks. A user can set the chars
|
||||
# to an empty string which we will interpret as not-set
|
||||
if invisibles.cr and line.lineEnding is '\r\n'
|
||||
html += "<span class='invisible-character'>#{invisibles.cr}</span>"
|
||||
if invisibles.eol?
|
||||
if invisibles.eol
|
||||
html += "<span class='invisible-character'>#{invisibles.eol}</span>"
|
||||
|
||||
html
|
||||
@@ -194,7 +231,7 @@ LinesComponent = React.createClass
|
||||
|
||||
# Find a common prefix
|
||||
for scope, i in desiredScopes
|
||||
break unless scopeStack[i]?.scope is desiredScopes[i]
|
||||
break unless scopeStack[i] is desiredScopes[i]
|
||||
|
||||
# Pop scopes until we're at the common prefx
|
||||
until scopeStack.length is i
|
||||
@@ -222,12 +259,13 @@ LinesComponent = React.createClass
|
||||
previousDecorations = @renderedDecorationsByLineId[line.id]
|
||||
|
||||
if previousDecorations?
|
||||
for decoration in previousDecorations
|
||||
lineNode.classList.remove(decoration.class) if editor.decorationMatchesType(decoration, 'line') and not _.deepContains(decorations, decoration)
|
||||
for id, decoration of previousDecorations
|
||||
if Decoration.isType(decoration, 'line') and not @hasDecoration(decorations, decoration)
|
||||
lineNode.classList.remove(decoration.class)
|
||||
|
||||
if decorations?
|
||||
for decoration in decorations
|
||||
if editor.decorationMatchesType(decoration, 'line') and not _.deepContains(previousDecorations, decoration)
|
||||
for id, decoration of decorations
|
||||
if Decoration.isType(decoration, 'line') and not @hasDecoration(previousDecorations, decoration)
|
||||
lineNode.classList.add(decoration.class)
|
||||
|
||||
lineNode.style.width = lineWidth + 'px' if updateWidth
|
||||
@@ -238,6 +276,9 @@ LinesComponent = React.createClass
|
||||
@screenRowsByLineId[line.id] = screenRow
|
||||
@lineIdsByScreenRow[screenRow] = line.id
|
||||
|
||||
hasDecoration: (decorations, decoration) ->
|
||||
decorations? and decorations[decoration.id] is decoration
|
||||
|
||||
lineNodeForScreenRow: (screenRow) ->
|
||||
@lineNodesByLineId[@lineIdsByScreenRow[screenRow]]
|
||||
|
||||
|
||||
+70
-1
@@ -158,7 +158,7 @@ class Package
|
||||
|
||||
loadStylesheets: ->
|
||||
@stylesheets = @getStylesheetPaths().map (stylesheetPath) ->
|
||||
[stylesheetPath, atom.themes.loadStylesheet(stylesheetPath)]
|
||||
[stylesheetPath, atom.themes.loadStylesheet(stylesheetPath, true)]
|
||||
|
||||
getStylesheetsPath: ->
|
||||
path.join(@path, @constructor.stylesheetsDir)
|
||||
@@ -269,6 +269,7 @@ class Package
|
||||
|
||||
requireMainModule: ->
|
||||
return @mainModule if @mainModule?
|
||||
return unless @isCompatible()
|
||||
mainModulePath = @getMainModulePath()
|
||||
@mainModule = require(mainModulePath) if fs.isFileSync(mainModulePath)
|
||||
|
||||
@@ -340,3 +341,71 @@ class Package
|
||||
for eventHandler in eventHandlers
|
||||
eventHandler.handler = eventHandler.disabledHandler
|
||||
delete eventHandler.disabledHandler
|
||||
|
||||
# Does the given module path contain native code?
|
||||
isNativeModule: (modulePath) ->
|
||||
try
|
||||
fs.listSync(path.join(modulePath, 'build', 'Release'), ['.node']).length > 0
|
||||
catch error
|
||||
false
|
||||
|
||||
# Get an array of all the native modules that this package depends on.
|
||||
# This will recurse through all dependencies.
|
||||
getNativeModuleDependencyPaths: ->
|
||||
nativeModulePaths = []
|
||||
|
||||
traversePath = (nodeModulesPath) =>
|
||||
try
|
||||
for modulePath in fs.listSync(nodeModulesPath)
|
||||
nativeModulePaths.push(modulePath) if @isNativeModule(modulePath)
|
||||
traversePath(path.join(modulePath, 'node_modules'))
|
||||
|
||||
traversePath(path.join(@path, 'node_modules'))
|
||||
nativeModulePaths
|
||||
|
||||
# Get the incompatible native modules that this package depends on.
|
||||
# This recurses through all dependencies and requires all modules that
|
||||
# contain a `.node` file.
|
||||
#
|
||||
# This information is cached in local storage on a per package/version basis
|
||||
# to minimize the impact on startup time.
|
||||
getIncompatibleNativeModules: ->
|
||||
localStorageKey = "installed-packages:#{@name}:#{@metadata.version}"
|
||||
try
|
||||
{incompatibleNativeModules} = JSON.parse(global.localStorage.getItem(localStorageKey)) ? {}
|
||||
return incompatibleNativeModules if incompatibleNativeModules?
|
||||
|
||||
incompatibleNativeModules = []
|
||||
for nativeModulePath in @getNativeModuleDependencyPaths()
|
||||
try
|
||||
require(nativeModulePath)
|
||||
catch error
|
||||
try
|
||||
version = require("#{nativeModulePath}/package.json").version
|
||||
incompatibleNativeModules.push
|
||||
path: nativeModulePath
|
||||
name: path.basename(nativeModulePath)
|
||||
version: version
|
||||
error: error.message
|
||||
|
||||
global.localStorage.setItem(localStorageKey, JSON.stringify({incompatibleNativeModules}))
|
||||
incompatibleNativeModules
|
||||
|
||||
# Public: Is this package compatible with this version of Atom?
|
||||
#
|
||||
# Incompatible packages cannot be activated. This will include packages
|
||||
# installed to ~/.atom/packages that were built against node 0.11.10 but
|
||||
# now need to be upgrade to node 0.11.13.
|
||||
#
|
||||
# Returns a {Boolean}, true if compatible, false if incompatible.
|
||||
isCompatible: ->
|
||||
return @compatible if @compatible?
|
||||
|
||||
if @path.indexOf(path.join(atom.packages.resourcePath, 'node_modules') + path.sep) is 0
|
||||
# Bundled packages are always considered compatible
|
||||
@compatible = true
|
||||
else if packageMain = @getMainModulePath()
|
||||
@incompatibleModules = @getIncompatibleNativeModules()
|
||||
@compatible = @incompatibleModules.length is 0
|
||||
else
|
||||
@compatible = true
|
||||
|
||||
@@ -8,6 +8,8 @@ class PaneContainer extends Model
|
||||
atom.deserializers.add(this)
|
||||
Serializable.includeInto(this)
|
||||
|
||||
@version: 1
|
||||
|
||||
@properties
|
||||
root: -> new Pane
|
||||
activePane: null
|
||||
@@ -27,10 +29,12 @@ class PaneContainer extends Model
|
||||
deserializeParams: (params) ->
|
||||
params.root = atom.deserializers.deserialize(params.root, container: this)
|
||||
params.destroyEmptyPanes = atom.config.get('core.destroyEmptyPanes')
|
||||
params.activePane = params.root.getPanes().find (pane) -> pane.id is params.activePaneId
|
||||
params
|
||||
|
||||
serializeParams: (params) ->
|
||||
root: @root?.serialize()
|
||||
activePaneId: @activePane.id
|
||||
|
||||
replaceChild: (oldChild, newChild) ->
|
||||
throw new Error("Replacing non-existent child") if oldChild isnt @root
|
||||
|
||||
+1
-3
@@ -40,14 +40,12 @@ class Pane extends Model
|
||||
@subscribe @items.onRemoval (item, index) =>
|
||||
@unsubscribe item if typeof item.on is 'function'
|
||||
|
||||
@activate() if params?.active
|
||||
|
||||
# Called by the Serializable mixin during serialization.
|
||||
serializeParams: ->
|
||||
id: @id
|
||||
items: compact(@items.map((item) -> item.serialize?()))
|
||||
activeItemUri: @activeItem?.getUri?()
|
||||
focused: @focused
|
||||
active: @active
|
||||
|
||||
# Called by the Serializable mixin during deserialization.
|
||||
deserializeParams: (params) ->
|
||||
|
||||
@@ -1,34 +1,36 @@
|
||||
{View, $} = require 'space-pen'
|
||||
React = require 'react-atom-fork'
|
||||
EditorComponent = require './editor-component'
|
||||
{defaults} = require 'underscore-plus'
|
||||
TextBuffer = require 'text-buffer'
|
||||
Editor = require './editor'
|
||||
EditorComponent = require './editor-component'
|
||||
|
||||
module.exports =
|
||||
class ReactEditorView extends View
|
||||
@content: -> @div class: 'editor react'
|
||||
@content: (params) ->
|
||||
attributes = params.attributes ? {}
|
||||
attributes.class = 'editor react editor-colors'
|
||||
@div attributes
|
||||
|
||||
focusOnAttach: false
|
||||
|
||||
constructor: (@editor, @props) ->
|
||||
constructor: (editorOrParams, props) ->
|
||||
super
|
||||
|
||||
getEditor: -> @editor
|
||||
if editorOrParams instanceof Editor
|
||||
@editor = editorOrParams
|
||||
else
|
||||
{@editor, mini, placeholderText} = editorOrParams
|
||||
props ?= {}
|
||||
props.mini = mini
|
||||
props.placeholderText = placeholderText
|
||||
@editor ?= new Editor
|
||||
buffer: new TextBuffer
|
||||
softWrap: false
|
||||
tabLength: 2
|
||||
softTabs: true
|
||||
|
||||
getModel: -> @editor
|
||||
|
||||
Object.defineProperty @::, 'lineHeight', get: -> @editor.getLineHeightInPixels()
|
||||
Object.defineProperty @::, 'charWidth', get: -> @editor.getDefaultCharWidth()
|
||||
Object.defineProperty @::, 'firstRenderedScreenRow', get: -> @component.getRenderedRowRange()[0]
|
||||
Object.defineProperty @::, 'lastRenderedScreenRow', get: -> @component.getRenderedRowRange()[1]
|
||||
Object.defineProperty @::, 'active', get: -> @is(@getPane().activeView)
|
||||
Object.defineProperty @::, 'isFocused', get: -> @component?.state.focused
|
||||
|
||||
afterAttach: (onDom) ->
|
||||
return unless onDom
|
||||
return if @attached
|
||||
|
||||
@attached = true
|
||||
props = defaults({@editor, parentView: this}, @props)
|
||||
props = defaults({@editor, parentView: this}, props)
|
||||
@component = React.renderComponent(EditorComponent(props), @element)
|
||||
|
||||
node = @component.getDOMNode()
|
||||
@@ -38,20 +40,39 @@ class ReactEditorView extends View
|
||||
@overlayer = $(node).find('.lines').addClass('overlayer')
|
||||
@hiddenInput = $(node).find('.hidden-input')
|
||||
|
||||
@gutter = $(node).find('.gutter')
|
||||
@gutter.removeClassFromAllLines = (klass) =>
|
||||
@gutter.find('.line-number').removeClass(klass)
|
||||
# FIXME: there should be a better way to deal with the gutter element
|
||||
@subscribe atom.config.observe 'editor.showLineNumbers', =>
|
||||
@gutter = $(node).find('.gutter')
|
||||
|
||||
@gutter.getLineNumberElement = (bufferRow) =>
|
||||
@gutter.find("[data-buffer-row='#{bufferRow}']")
|
||||
@gutter.removeClassFromAllLines = (klass) =>
|
||||
@gutter.find('.line-number').removeClass(klass)
|
||||
|
||||
@gutter.addClassToLine = (bufferRow, klass) =>
|
||||
lines = @gutter.find("[data-buffer-row='#{bufferRow}']")
|
||||
lines.addClass(klass)
|
||||
lines.length > 0
|
||||
@gutter.getLineNumberElement = (bufferRow) =>
|
||||
@gutter.find("[data-buffer-row='#{bufferRow}']")
|
||||
|
||||
@gutter.addClassToLine = (bufferRow, klass) =>
|
||||
lines = @gutter.find("[data-buffer-row='#{bufferRow}']")
|
||||
lines.addClass(klass)
|
||||
lines.length > 0
|
||||
|
||||
|
||||
getEditor: -> @editor
|
||||
|
||||
getModel: -> @editor
|
||||
|
||||
Object.defineProperty @::, 'lineHeight', get: -> @editor.getLineHeightInPixels()
|
||||
Object.defineProperty @::, 'charWidth', get: -> @editor.getDefaultCharWidth()
|
||||
Object.defineProperty @::, 'firstRenderedScreenRow', get: -> @component.getRenderedRowRange()[0]
|
||||
Object.defineProperty @::, 'lastRenderedScreenRow', get: -> @component.getRenderedRowRange()[1]
|
||||
Object.defineProperty @::, 'active', get: -> @is(@getPane()?.activeView)
|
||||
Object.defineProperty @::, 'isFocused', get: -> @component?.state.focused
|
||||
|
||||
afterAttach: (onDom) ->
|
||||
return unless onDom
|
||||
return if @attached
|
||||
@attached = true
|
||||
@component.pollDOM()
|
||||
@focus() if @focusOnAttach
|
||||
|
||||
@trigger 'editor:attached', [this]
|
||||
|
||||
scrollTop: (scrollTop) ->
|
||||
@@ -94,7 +115,7 @@ class ReactEditorView extends View
|
||||
@find('.lines').prepend(view)
|
||||
|
||||
beforeRemove: ->
|
||||
React.unmountComponentAtNode(@element)
|
||||
React.unmountComponentAtNode(@element) if @component.isMounted()
|
||||
@attached = false
|
||||
@trigger 'editor:detached', this
|
||||
|
||||
@@ -119,7 +140,7 @@ class ReactEditorView extends View
|
||||
pane?.splitDown(pane?.copyActiveItem()).activeView
|
||||
|
||||
getPane: ->
|
||||
@closest('.pane').view()
|
||||
@parent('.item-views').parents('.pane').view()
|
||||
|
||||
focus: ->
|
||||
if @component?
|
||||
@@ -129,11 +150,18 @@ class ReactEditorView extends View
|
||||
|
||||
hide: ->
|
||||
super
|
||||
@component?.hide()
|
||||
@pollComponentDOM()
|
||||
|
||||
show: ->
|
||||
super
|
||||
@component?.show()
|
||||
@pollComponentDOM()
|
||||
|
||||
pollComponentDOM: ->
|
||||
return unless @component?
|
||||
valueToRestore = @component.performSyncUpdates
|
||||
@component.performSyncUpdates = true
|
||||
@component.pollDOM()
|
||||
@component.performSyncUpdates = valueToRestore
|
||||
|
||||
pageDown: ->
|
||||
@editor.pageDown()
|
||||
@@ -205,3 +233,12 @@ class ReactEditorView extends View
|
||||
resetDisplay: -> # No-op shim for package specs
|
||||
|
||||
redraw: -> # No-op shim
|
||||
|
||||
setPlaceholderText: (placeholderText) ->
|
||||
if @component?
|
||||
@component.setProps({placeholderText})
|
||||
else
|
||||
@props.placeholderText = placeholderText
|
||||
|
||||
lineElementForScreenRow: (screenRow) ->
|
||||
$(@component.lineNodeForScreenRow(screenRow))
|
||||
|
||||
@@ -17,8 +17,9 @@ ScrollbarComponent = React.createClass
|
||||
style.width = verticalScrollbarWidth
|
||||
style.bottom = horizontalScrollbarHeight if scrollableInOppositeDirection
|
||||
when 'horizontal'
|
||||
style.height = horizontalScrollbarHeight
|
||||
style.left = 0
|
||||
style.right = verticalScrollbarWidth if scrollableInOppositeDirection
|
||||
style.height = horizontalScrollbarHeight
|
||||
|
||||
div {className, style, @onScroll},
|
||||
switch orientation
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
{$, View} = require './space-pen-extensions'
|
||||
EditorView = require './editor-view'
|
||||
if atom.config.get('core.useReactMiniEditors')
|
||||
EditorView = require './react-editor-view'
|
||||
else
|
||||
EditorView = require './editor-view'
|
||||
fuzzyFilter = require('fuzzaldrin').filter
|
||||
|
||||
# Public: Provides a view that renders a list of items with an editor that
|
||||
|
||||
@@ -15,6 +15,8 @@ class Selection extends Model
|
||||
constructor: ({@cursor, @marker, @editor, id}) ->
|
||||
@assignId(id)
|
||||
@cursor.selection = this
|
||||
@decoration = @editor.decorateMarker(@marker, type: 'highlight', class: 'selection')
|
||||
|
||||
@marker.on 'changed', => @screenRangeChanged()
|
||||
@marker.on 'destroyed', =>
|
||||
@destroyed = true
|
||||
@@ -76,9 +78,12 @@ class Selection extends Model
|
||||
options.reversed ?= @isReversed()
|
||||
@editor.destroyFoldsIntersectingBufferRange(bufferRange) unless options.preserveFolds
|
||||
@modifySelection =>
|
||||
needsFlash = options.flash
|
||||
delete options.flash if options.flash?
|
||||
@cursor.needsAutoscroll = false if @needsAutoscroll?
|
||||
@marker.setBufferRange(bufferRange, options)
|
||||
@autoscroll() if @needsAutoscroll and @editor.manageScrollPosition
|
||||
@decoration.flash('flash', @editor.selectionFlashDuration) if needsFlash
|
||||
|
||||
# Public: Returns the starting and ending buffer rows the selection is
|
||||
# highlighting.
|
||||
@@ -315,12 +320,12 @@ class Selection extends Model
|
||||
wasReversed = @isReversed()
|
||||
@clear()
|
||||
@cursor.needsAutoscroll = @cursor.isLastCursor()
|
||||
@cursor.autoscroll() if @editor.manageScrollPosition and @cursor.isLastCursor()
|
||||
|
||||
if options.indentBasis? and not options.autoIndent
|
||||
text = @normalizeIndents(text, options.indentBasis)
|
||||
|
||||
newBufferRange = @editor.buffer.setTextInRange(oldBufferRange, text, pick(options, 'undo'))
|
||||
|
||||
if options.select
|
||||
@setBufferRange(newBufferRange, reversed: wasReversed)
|
||||
else
|
||||
@@ -387,7 +392,7 @@ class Selection extends Model
|
||||
if autoIndent and delta > 0
|
||||
@insertText(@editor.buildIndentString(delta))
|
||||
else
|
||||
@insertText(@editor.getTabText())
|
||||
@insertText(@editor.buildIndentString(1, @cursor.getBufferColumn()))
|
||||
else
|
||||
@indentSelectedRows()
|
||||
|
||||
|
||||
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