forked from Archives/navigator.lua
Compare commits
492 Commits
Author | SHA1 | Date |
---|---|---|
ray-x | cd98ca2c5b | 2 years ago |
ray-x | 451d761f76 | 2 years ago |
sp4ke | 8278f71878 | 2 years ago |
ray-x | 443fd4d585 | 2 years ago |
ray-x | 10fd76d6d0 | 2 years ago |
ray-x | 8d00282020 | 2 years ago |
ray-x | 9afcd37854 | 2 years ago |
ray-x | c70d032b08 | 2 years ago |
ray-x | fb6d19ddf4 | 2 years ago |
ray-x | af7fc7d649 | 2 years ago |
ray-x | d8f19f6fc1 | 2 years ago |
ray-x | df7f4d7229 | 2 years ago |
ray-x | fb87a0b1b7 | 2 years ago |
ray-x | 927c464b70 | 2 years ago |
ray-x | e9a40aca40 | 2 years ago |
ray-x | edee3e39c6 | 2 years ago |
sp4ke | a7886fc055 | 2 years ago |
yyk | de018d9ae3 | 2 years ago |
ray-x | ef0cee5bbd | 2 years ago |
ray-x | ab2e383b20 | 2 years ago |
ray-x | 1b262556c0 | 2 years ago |
rayx | b4ff1c43b9 | 2 years ago |
ray-x | ebd88f5d09 | 2 years ago |
ray-x | 28d245510f | 2 years ago |
ray-x | 213b30950e | 2 years ago |
ray-x | f05d2ec142 | 2 years ago |
ray-x | 9f151cf718 | 2 years ago |
ray-x | b131251ad8 | 2 years ago |
ray-x | 8978bdb1e3 | 2 years ago |
ray-x | ae251289b3 | 2 years ago |
ray-x | a9c223cc22 | 2 years ago |
ray-x | 0ab4b02ff7 | 2 years ago |
ray-x | 6c0e286170 | 2 years ago |
ray-x | f24a337f5d | 2 years ago |
ray-x | 3d87ed3b87 | 2 years ago |
ray-x | 5713f79265 | 2 years ago |
ray-x | 01ef2ce1a1 | 2 years ago |
ray-x | 547f2bc15d | 2 years ago |
ray-x | dc0b8504bb | 2 years ago |
ray-x | 486085070d | 2 years ago |
ray-x | bc356d555f | 2 years ago |
ray-x | 5b5a946d73 | 2 years ago |
ray-x | fca2fa5aaa | 2 years ago |
rayx | 49dbca889d | 2 years ago |
ray-x | 861ae038dd | 2 years ago |
ray-x | 814b712e91 | 2 years ago |
ray-x | dcc40278c5 | 2 years ago |
ray-x | 6736293182 | 2 years ago |
ray-x | 10ef469286 | 2 years ago |
ray-x | 4775d43218 | 2 years ago |
ray-x | 89dd02c927 | 2 years ago |
ray-x | bbdf86a66e | 2 years ago |
ray-x | ed47d386e6 | 2 years ago |
ray-x | 480824d3f3 | 2 years ago |
ray-x | c3ef990390 | 2 years ago |
ray-x | de5c88c766 | 2 years ago |
ray-x | 348ab9dced | 2 years ago |
ray-x | 967fd32bae | 2 years ago |
ray-x | 4aef8dc5f2 | 2 years ago |
ray-x | 0de6c290cf | 2 years ago |
ray-x | 9aad2978dc | 2 years ago |
ray-x | 49c3e5cd4d | 2 years ago |
ray-x | 47545e03c0 | 2 years ago |
ray-x | e5d16e4488 | 2 years ago |
ray-x | 3d9a9582dd | 2 years ago |
rayx | 05dfed9ed9 | 2 years ago |
ray-x | 05753da8db | 2 years ago |
ray-x | 4623677b2a | 2 years ago |
ray-x | 85e3f6e045 | 2 years ago |
ray-x | c30ccd07c9 | 2 years ago |
ray-x | 4c5d0e67d0 | 2 years ago |
ray-x | be6da35767 | 2 years ago |
ray-x | f567f1b99c | 2 years ago |
ray-x | a93f7cb20f | 2 years ago |
ray-x | 289f67013d | 2 years ago |
ray-x | 56b00b83d5 | 2 years ago |
ray-x | 3fe9a876c4 | 2 years ago |
rayx | acca6009e0 | 2 years ago |
ray-x | 792fd2831a | 2 years ago |
ray-x | a225d18eaf | 2 years ago |
ray-x | 7d84a9f0c0 | 2 years ago |
ray-x | 22e858f261 | 2 years ago |
ray-x | edba3efd1e | 2 years ago |
ray-x | 724d5f3439 | 2 years ago |
ray-x | 3dc8c02c39 | 2 years ago |
ray-x | 91d1366b65 | 2 years ago |
ray-x | d951a5fcd2 | 2 years ago |
ray-x | 68eb18c310 | 2 years ago |
ray-x | 8d77c3ab1e | 2 years ago |
ray-x | 309afcd681 | 2 years ago |
rayx | 9f7bd6ebff | 2 years ago |
ray-x | aba0d89745 | 2 years ago |
ray-x | c1b0694bef | 2 years ago |
ray-x | 9dee73010b | 2 years ago |
ray-x | 1b3a02df3e | 2 years ago |
ray-x | f856fa7033 | 2 years ago |
rayx | 1f6103ed95 | 2 years ago |
ray-x | 7bfd9157fe | 2 years ago |
ray-x | 48e35f4e56 | 2 years ago |
ray-x | 27442d2784 | 2 years ago |
ray-x | 3ad93531b5 | 2 years ago |
ray-x | c15bae89ab | 2 years ago |
ray-x | 61a82559d6 | 2 years ago |
ray-x | f8985d7aa2 | 2 years ago |
ray-x | 516d643ffe | 2 years ago |
ray-x | 6b4cfa3d59 | 2 years ago |
ray-x | cce0e90544 | 2 years ago |
rayx | 2f35446fbe | 2 years ago |
ray-x | 1908ea5175 | 2 years ago |
ray-x | 6c3ee44729 | 2 years ago |
ray-x | 6e937e9019 | 2 years ago |
ray-x | 01801ba8fa | 2 years ago |
ray-x | d0ab595b93 | 2 years ago |
ray-x | 3f49769abc | 2 years ago |
ray-x | 32ddd66dd2 | 2 years ago |
ray-x | feb780fb10 | 2 years ago |
ray-x | ea2c207ec9 | 2 years ago |
ray-x | b249d1680a | 2 years ago |
ray-x | 13c3dd4072 | 2 years ago |
ray-x | a0eff2c5a3 | 2 years ago |
ray-x | 51a05252a5 | 2 years ago |
Michael Adler | 2e96dcd327 | 2 years ago |
Michael Adler | ff4bcc6d83 | 2 years ago |
ray-x | 8a32139e1a | 2 years ago |
rayx | a73fb38ef9 | 2 years ago |
ray-x | 96ca715ea6 | 2 years ago |
ray-x | 45385ccc9a | 2 years ago |
ray-x | 4d93172915 | 2 years ago |
ray-x | 0ac13663cf | 2 years ago |
ray-x | 500553ae6b | 2 years ago |
rayx | c416d99f6f | 2 years ago |
ray-x | d1836f4299 | 2 years ago |
rayx | 5131b30ad7 | 2 years ago |
ray-x | eb75b09a33 | 2 years ago |
ray-x | 93e28f36d0 | 2 years ago |
ray-x | 77b572dd5a | 2 years ago |
rayx | 794e86057d | 2 years ago |
ray-x | 03d0aaa05d | 2 years ago |
ray-x | 9c67158d9c | 2 years ago |
ray-x | 0c31d692ee | 2 years ago |
ray-x | 9ceeb41b6f | 2 years ago |
ray-x | 0bdaf1f63c | 2 years ago |
ray-x | c2c1c57136 | 2 years ago |
0x7a7a | 595263e8b4 | 2 years ago |
ray-x | 2f3e2847a3 | 2 years ago |
ray-x | cd53b02f93 | 2 years ago |
ray-x | 15e6b315b7 | 2 years ago |
ray-x | 31f2f920e1 | 2 years ago |
ray-x | ab4daceede | 2 years ago |
ray-x | 23e25c298e | 2 years ago |
ray-x | 8b43ed23e2 | 2 years ago |
ray-x | 8dbac5efc9 | 2 years ago |
ray-x | d08d78f6a4 | 2 years ago |
ray-x | 3d217bffce | 2 years ago |
ray-x | 2ed33d7d60 | 2 years ago |
ray-x | e55ae08e9d | 2 years ago |
ray-x | d990da84a6 | 2 years ago |
ray-x | bb018d541b | 2 years ago |
ray-x | b69154f9ee | 2 years ago |
ray-x | 5c8b3b9ca1 | 2 years ago |
ray-x | 7f22411b1f | 2 years ago |
ray-x | 77dd031f8a | 2 years ago |
ray-x | d8e4787bfb | 2 years ago |
ray-x | ab96133b47 | 2 years ago |
ray-x | 34c3bc9c76 | 2 years ago |
ray-x | 46aeb778ce | 2 years ago |
studierer | 035917c57a | 2 years ago |
ray-x | a316e7f449 | 2 years ago |
ray-x | 209e5321a8 | 2 years ago |
ray-x | 4018cab16d | 2 years ago |
ray-x | 3e03e37d9f | 2 years ago |
ray-x | 5773f66d14 | 2 years ago |
ray-x | 74eccbd799 | 2 years ago |
ray-x | 0346fc3c0f | 2 years ago |
ray-x | b2d846647b | 2 years ago |
ray-x | cfe8738ad5 | 2 years ago |
ray-x | 982fe81922 | 2 years ago |
ray-x | d024335c91 | 2 years ago |
ray-x | 3d6187e534 | 2 years ago |
ray-x | 41593cb7e4 | 2 years ago |
ray-x | 429cd16292 | 2 years ago |
ray-x | 2c7334e1b6 | 2 years ago |
ray-x | 3adbbaf509 | 2 years ago |
ray-x | 37e8b68506 | 2 years ago |
ray-x | ff8ae83300 | 2 years ago |
Joseph DelCioppio | b10964e5a2 | 2 years ago |
ray-x | e4b2fc0afe | 2 years ago |
ray-x | 8e39f65f53 | 2 years ago |
ray-x | 2e43b8ee0a | 2 years ago |
ray-x | 2232317b0a | 2 years ago |
ray-x | ff57a1f916 | 2 years ago |
ray-x | 0f181f1d4e | 2 years ago |
ray-x | 9ed6e64877 | 2 years ago |
ray-x | f0c5610a1f | 2 years ago |
ray-x | 92f56ffe4b | 2 years ago |
ray-x | 76e0c8d3ff | 2 years ago |
ray-x | c7872c83a8 | 2 years ago |
ray-x | bf2e867354 | 2 years ago |
ray-x | 11d25933ad | 2 years ago |
ray-x | 21ddd7f2f6 | 2 years ago |
ray-x | 8e9bf39f13 | 2 years ago |
ray-x | ccb1bac250 | 2 years ago |
ray-x | 1feacfb4bd | 2 years ago |
ray-x | ded2a6510f | 2 years ago |
ray-x | 62477b294e | 2 years ago |
ray-x | c03cbca758 | 2 years ago |
ray-x | 2d5290d3d6 | 2 years ago |
David de Rosier | dcabc38a12 | 2 years ago |
ray-x | c9f34ac179 | 2 years ago |
ray-x | 2344a9d611 | 2 years ago |
ray-x | 1f3ae4a675 | 2 years ago |
ray-x | 45e0698d00 | 2 years ago |
ray-x | 5b2e003258 | 2 years ago |
ray-x | 72ed02f879 | 2 years ago |
ray-x | 92296c9fc8 | 2 years ago |
ray-x | 96885ae509 | 2 years ago |
ray-x | 4ca6b376a7 | 2 years ago |
ray-x | da9448a88c | 2 years ago |
ray-x | 3bc154bbb3 | 2 years ago |
ray-x | 7273aaa1d9 | 2 years ago |
ray-x | e83a017e61 | 2 years ago |
ray-x | e80f004f5b | 2 years ago |
ray-x | ed1cedefb6 | 2 years ago |
ray-x | e04914ab6c | 2 years ago |
ray-x | 73dfd12f0f | 2 years ago |
ray-x | db4eb5f155 | 2 years ago |
ray-x | bad19ebc84 | 2 years ago |
ray-x | 4144024068 | 2 years ago |
ray-x | f9af69e4bf | 2 years ago |
ray-x | 2ad5d1e1d0 | 2 years ago |
ray-x | a0679626e2 | 2 years ago |
ray-x | 1202df85cd | 2 years ago |
ray-x | b89811b1b6 | 2 years ago |
ray-x | c3f6b14233 | 2 years ago |
ray-x | 23090c567c | 2 years ago |
ray-x | 9957766620 | 2 years ago |
ray-x | aa9b80e848 | 2 years ago |
Ian C | 6e9f20f586 | 2 years ago |
Ian C | fcf7814c9a | 2 years ago |
Ian C | f3bf6ab4f6 | 2 years ago |
ray-x | ecc1f2d28a | 2 years ago |
ray-x | 4739722774 | 2 years ago |
ray-x | 19969e3902 | 2 years ago |
ray-x | 47bcf183b8 | 2 years ago |
ray-x | 97df091a8a | 2 years ago |
ray-x | abf5de64fd | 2 years ago |
Beau McCartney | b618358628 | 2 years ago |
ray-x | 873135bf9a | 2 years ago |
ray-x | 0f653784ea | 2 years ago |
ray-x | c528b58bb9 | 2 years ago |
ray-x | 85d907ffaf | 2 years ago |
ray-x | 5ab4dffba5 | 2 years ago |
ray-x | e869cedba3 | 2 years ago |
rayx | 941b3fc80f | 2 years ago |
ray-x | 4b1670423e | 2 years ago |
ray-x | 5c13477220 | 3 years ago |
ray-x | 1c67e790eb | 3 years ago |
ray-x | 3c9ee3785c | 3 years ago |
ray-x | 65701259c1 | 3 years ago |
ray-x | 03eef089c8 | 3 years ago |
ray-x | 73f0041dc1 | 3 years ago |
ray-x | ce3c5fe2cb | 3 years ago |
ray-x | ae13350ad1 | 3 years ago |
ray-x | 2f44f0115a | 3 years ago |
ray-x | 9aec552ac1 | 3 years ago |
Loreo13 | 3d6b24f919 | 3 years ago |
Loreo13 | c85fcb202f | 3 years ago |
ray-x | 315c284b08 | 3 years ago |
ray-x | f06b6b5a1a | 3 years ago |
Mateusz Kubaszek | 22da11569b | 3 years ago |
ray-x | cdee0ec57b | 3 years ago |
ray-x | 83b66dbea1 | 3 years ago |
ray-x | 49fb9032d8 | 3 years ago |
ray-x | 388711d97d | 3 years ago |
ray-x | 19df02d40d | 3 years ago |
ray-x | 0b2e66fa98 | 3 years ago |
ray-x | 5423a6ff36 | 3 years ago |
ray-x | 99b7b1c502 | 3 years ago |
ray-x | db09db7ef3 | 3 years ago |
ray-x | 93b38136f8 | 3 years ago |
ray-x | 342a429485 | 3 years ago |
ray-x | 04cfdbd4d2 | 3 years ago |
ray-x | 04d8e71008 | 3 years ago |
ray-x | a6f668e05f | 3 years ago |
ray-x | b196af9311 | 3 years ago |
ray-x | f43b0aba0e | 3 years ago |
ray-x | 63bbdf4cf2 | 3 years ago |
ray-x | 5a84868481 | 3 years ago |
ray-x | 4c7e7f683d | 3 years ago |
ray-x | 427007ee9b | 3 years ago |
ray-x | 262181246d | 3 years ago |
TANIGUCHI Masaya | d9fb882e98 | 3 years ago |
ray-x | 9b148290a4 | 3 years ago |
ray-x | 552dc8901f | 3 years ago |
ray-x | 622804e674 | 3 years ago |
ray-x | c9514dffe9 | 3 years ago |
ray-x | c890f3818d | 3 years ago |
ray-x | 74ea1ddd73 | 3 years ago |
ray-x | 062e7e4ffc | 3 years ago |
ray-x | fab08151e6 | 3 years ago |
ray-x | 0c0801c92d | 3 years ago |
ray-x | 5083b07972 | 3 years ago |
ray-x | b936cbb48d | 3 years ago |
ray-x | 87f4c2b664 | 3 years ago |
ray-x | 7514301d80 | 3 years ago |
ray-x | d6b81ba8ab | 3 years ago |
ray-x | 36c01adc2d | 3 years ago |
ray-x | 0a5db66968 | 3 years ago |
ray-x | c4bfcabd64 | 3 years ago |
ray-x | 36683e3646 | 3 years ago |
ray-x | 3be242ac6c | 3 years ago |
ray-x | 202628e695 | 3 years ago |
ray-x | 035013ada4 | 3 years ago |
ray-x | dc9e50d432 | 3 years ago |
ray-x | 7925fd8439 | 3 years ago |
ray-x | b98cfa2c40 | 3 years ago |
ray-x | f53d06b5fd | 3 years ago |
ray-x | 1d2e6b5296 | 3 years ago |
ray-x | ed834ecf0d | 3 years ago |
ray-x | 1b3ba27403 | 3 years ago |
ray-x | b521c2e7bb | 3 years ago |
ray-x | d932978441 | 3 years ago |
ray-x | 89b08bc968 | 3 years ago |
ray-x | a952d694e1 | 3 years ago |
ray-x | 1f3680d4b1 | 3 years ago |
ray-x | faab21a1a7 | 3 years ago |
ray-x | c08cbdda89 | 3 years ago |
rayx | 93c7eae2ca | 3 years ago |
ray-x | 74af2c1a72 | 3 years ago |
ray-x | 892804d51e | 3 years ago |
ray-x | 00a015e27a | 3 years ago |
ray-x | c55729e879 | 3 years ago |
ray-x | aa9133af7e | 3 years ago |
ray-x | 687f78db5b | 3 years ago |
ray-x | 1ba70b81d5 | 3 years ago |
ray-x | 4e69764a52 | 3 years ago |
ray-x | 9460b82d05 | 3 years ago |
ray-x | c035c225ea | 3 years ago |
ray-x | d793df9b42 | 3 years ago |
ray-x | 2afd51ae11 | 3 years ago |
ray-x | 0f2868c5e6 | 3 years ago |
spindensity | 633c7da38f | 3 years ago |
spindensity | 5391bf6aec | 3 years ago |
ray-x | 3c0646074a | 3 years ago |
ray-x | a2ddb1ff4b | 3 years ago |
ray-x | 5e500bef98 | 3 years ago |
ray-x | ecb25de260 | 3 years ago |
ray-x | 97b265a64d | 3 years ago |
ray-x | e56eeb4f88 | 3 years ago |
ray-x | 386661a6d9 | 3 years ago |
ray-x | 295b5e89ec | 3 years ago |
ray-x | 69578d6a3c | 3 years ago |
rayx | 79fee5dda8 | 3 years ago |
ray-x | 90039247b4 | 3 years ago |
rayx | 91e22f5e71 | 3 years ago |
ray-x | 507ad0b146 | 3 years ago |
ray-x | 26012cf9c1 | 3 years ago |
ray-x | 0dc5851d1c | 3 years ago |
ray-x | 2cb2b23c6d | 3 years ago |
ray-x | 890b3c5f7f | 3 years ago |
ray-x | 2a174d8eb4 | 3 years ago |
ray-x | 22028ff82e | 3 years ago |
ray-x | d60b3c4024 | 3 years ago |
rayx | 08dba1beb6 | 3 years ago |
ray-x | f33a3e8e7d | 3 years ago |
ray-x | b9f8ed3c55 | 3 years ago |
ray-x | 56479a0339 | 3 years ago |
ray-x | 2d1aa63b93 | 3 years ago |
ray-x | cde5c6be5c | 3 years ago |
Matt Bailey | d771df0fa7 | 3 years ago |
ray-x | e36809759b | 3 years ago |
ray-x | e37b52ffc1 | 3 years ago |
ray-x | be888b94a1 | 3 years ago |
ray-x | 5b65d8f389 | 3 years ago |
ray-x | 940349759b | 3 years ago |
ray-x | d39cf20903 | 3 years ago |
ray-x | dd4b04159d | 3 years ago |
ray-x | 01f97aa665 | 3 years ago |
Behzad | 5c7925a54a | 3 years ago |
rayx | 0038f13c62 | 3 years ago |
ray-x | 3f41ff3cd4 | 3 years ago |
ray-x | a3dd6ebcc4 | 3 years ago |
ray-x | ce449c440b | 3 years ago |
ray-x | 1373bc3856 | 3 years ago |
ray-x | 72e0b4e1e4 | 3 years ago |
ray-x | b292c2b981 | 3 years ago |
ray-x | f5a1fc747b | 3 years ago |
Beau | acc0a727fe | 3 years ago |
ray-x | aef51cc696 | 3 years ago |
ray-x | 78e574cbcd | 3 years ago |
ray-x | 369233a758 | 3 years ago |
ray-x | a200c1db2b | 3 years ago |
ray-x | 58ac955777 | 3 years ago |
ray-x | 48faeb69ab | 3 years ago |
ray-x | 51d32b26b9 | 3 years ago |
ray-x | d29ce05d16 | 3 years ago |
ray-x | 04cf51f6c8 | 3 years ago |
ray-x | 4f262e9909 | 3 years ago |
ray-x | 3c4838164b | 3 years ago |
ray-x | a1bd077939 | 3 years ago |
ray-x | d04159f633 | 3 years ago |
ray-x | a85c3e89ae | 3 years ago |
ray-x | 0584a5cd06 | 3 years ago |
ray-x | 7dd5d50691 | 3 years ago |
ray-x | 4ff9aa47a3 | 3 years ago |
ray-x | ef995eeb7e | 3 years ago |
ray-x | f16a04482d | 3 years ago |
ray-x | 54906cebaf | 3 years ago |
ray-x | 96e9772d5b | 3 years ago |
ray-x | 747db16f59 | 3 years ago |
ray-x | 2c11296b70 | 3 years ago |
ray-x | d034edbe0e | 3 years ago |
ray-x | 6c753645c3 | 3 years ago |
ray-x | 3d170771e9 | 3 years ago |
ray-x | 1fa56d20a5 | 3 years ago |
ray-x | 5b2dcb7cd0 | 3 years ago |
ray-x | 1ef00fe742 | 3 years ago |
ray-x | fec4640966 | 3 years ago |
ray-x | 5af79c7ff2 | 3 years ago |
ray-x | 86f3963e45 | 3 years ago |
ray-x | fe936ee69a | 3 years ago |
ray-x | 3f6de1f686 | 3 years ago |
zootedb0t | c4cf352798 | 3 years ago |
ray-x | 62178024fd | 3 years ago |
ray-x | 1df533bf5f | 3 years ago |
ray-x | dcc616765e | 3 years ago |
ray-x | 380c2c4c6e | 3 years ago |
ray-x | d58c377a73 | 3 years ago |
ray-x | f8060a72c8 | 3 years ago |
ray-x | d62b03c394 | 3 years ago |
ray-x | e64c56789f | 3 years ago |
ray-x | 47656e063e | 3 years ago |
ray-x | 18fc04a18c | 3 years ago |
ray-x | 70ebfffb55 | 3 years ago |
ray-x | a0fa3d278a | 3 years ago |
ray-x | f16893fc4f | 3 years ago |
ray-x | 0d29116b18 | 3 years ago |
ray-x | b08bfd6839 | 3 years ago |
ray-x | f30e5a290d | 3 years ago |
ray-x | f5f07d586d | 3 years ago |
ray-x | 05e51f2e74 | 3 years ago |
ray-x | 69e16a55d2 | 3 years ago |
RogerYK | 16da97e10d | 3 years ago |
ray-x | baad5112d8 | 3 years ago |
ray-x | 1acfe90f12 | 3 years ago |
ray-x | e4ca27ca86 | 3 years ago |
ray-x | c5fe79d6df | 3 years ago |
ray-x | 95b45a6cf6 | 3 years ago |
ray-x | b68340a467 | 3 years ago |
ray-x | 298c4659da | 3 years ago |
ray-x | 7514fa9f70 | 3 years ago |
ray-x | d8196c26a0 | 3 years ago |
ray-x | c818a97136 | 3 years ago |
ray-x | b60108978a | 3 years ago |
ray-x | 713dd7eeab | 3 years ago |
ray-x | 72ecc85842 | 3 years ago |
ray-x | b56ca88390 | 3 years ago |
ray-x | 01cd2e8020 | 3 years ago |
Daniel Nehrig | 8f99e669a2 | 3 years ago |
Mateus B. Melchiades | a955e07992 | 3 years ago |
ray-x | 77a525d2e4 | 3 years ago |
ray-x | b100c8aa06 | 3 years ago |
ray-x | a3a83e5ced | 3 years ago |
ray-x | 807f41975e | 3 years ago |
ray-x | 53f384ba46 | 3 years ago |
ray-x | 6c9ce98d03 | 3 years ago |
ray-x | f813aa97db | 3 years ago |
ray-x | 8b84a0e3aa | 3 years ago |
ray-x | 4ad8fa3e95 | 3 years ago |
ray-x | 09667c32a9 | 3 years ago |
ray-x | 2d7214d875 | 3 years ago |
ray-x | d8385f2993 | 3 years ago |
ray-x | 624053bd8f | 3 years ago |
ray-x | 2221cf5544 | 3 years ago |
ray-x | c872b43faf | 3 years ago |
ray-x | 8d75a1498a | 3 years ago |
ray-x | 9788bbaf54 | 3 years ago |
ray-x | 6a15e6838d | 3 years ago |
ray-x | 1546b6a604 | 3 years ago |
ray-x | fe65abed35 | 3 years ago |
ray-x | 41a43eaf64 | 3 years ago |
ray-x | b61e280400 | 3 years ago |
ray-x | 7e8c3376f4 | 3 years ago |
ray-x | 6bf9a5990b | 3 years ago |
ray-x | 8c055b7b03 | 3 years ago |
ray-x | 7c6c37d169 | 3 years ago |
ray-x | f430fdfbb9 | 3 years ago |
ray-x | 88ac6268cf | 3 years ago |
ray-x | 4e748eccab | 3 years ago |
ray-x | fc37a3f9a2 | 3 years ago |
ray-x | 777acc4b92 | 3 years ago |
ray-x | 7351a65917 | 3 years ago |
@ -0,0 +1,3 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: ray-x
|
@ -0,0 +1,58 @@
|
||||
name: Tests
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
unit_tests:
|
||||
name: unit tests
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-22.04
|
||||
url: https://github.com/neovim/neovim/releases/download/nightly/nvim-linux64.tar.gz
|
||||
manager: sudo snap
|
||||
packages: go
|
||||
- os: ubuntu-22.04
|
||||
url: https://github.com/neovim/neovim/releases/download/v0.7.0/nvim-linux64.tar.gz
|
||||
manager: sudo snap
|
||||
packages: go
|
||||
- os: ubuntu-22.04
|
||||
url: https://github.com/neovim/neovim/releases/download/v0.7.2/nvim-linux64.tar.gz
|
||||
manager: sudo snap
|
||||
packages: go
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: "^1.18.1" # The Go version to download (if necessary) and use.
|
||||
- run: date +%F > todays-date
|
||||
- name: Restore cache for today's nightly.
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: _neovim
|
||||
key: ${{ runner.os }}-${{ matrix.url }}-${{ hashFiles('todays-date') }}
|
||||
|
||||
- name: Prepare
|
||||
run: |
|
||||
${{ matrix.manager }} install --classic ${{ matrix.packages }}
|
||||
# sudo apt install go
|
||||
test -d _neovim || {
|
||||
mkdir -p _neovim
|
||||
curl -sL ${{ matrix.url }} | tar xzf - --strip-components=1 -C "${PWD}/_neovim"
|
||||
}
|
||||
GO111MODULE=on go install golang.org/x/tools/gopls@latest
|
||||
|
||||
mkdir -p ~/.local/share/nvim/site/pack/vendor/start
|
||||
git clone --depth 1 https://github.com/nvim-lua/plenary.nvim ~/.local/share/nvim/site/pack/vendor/start/plenary.nvim
|
||||
git clone --depth 1 https://github.com/ray-x/guihua.lua ~/.local/share/nvim/site/pack/vendor/start/guihua.lua
|
||||
git clone --depth 1 https://github.com/nvim-treesitter/nvim-treesitter ~/.local/share/nvim/site/pack/vendor/start/nvim-treesitter
|
||||
git clone --depth 1 https://github.com/kyazdani42/nvim-web-devicons ~/.local/share/nvim/site/pack/vendor/start/nvim-web-devicons
|
||||
git clone --depth 1 https://github.com/neovim/nvim-lspconfig ~/.local/share/nvim/site/pack/vendor/start/nvim-lspconfig
|
||||
ln -s $(pwd) ~/.local/share/nvim/site/pack/vendor/start
|
||||
- name: Run tests
|
||||
run: |
|
||||
export PATH="${PWD}/_neovim/bin:${PATH}"
|
||||
nvim --headless -u tests/minimal.vim -c "TSInstallSync go" -c "q"
|
||||
make test
|
@ -0,0 +1,3 @@
|
||||
selene.toml
|
||||
lua/navigator.lua.bak
|
||||
tests/fixtures/tests
|
@ -0,0 +1,2 @@
|
||||
test:
|
||||
nvim --headless --noplugin -u tests/minimal.vim -c "PlenaryBustedDirectory tests/ {minimal_init = 'tests/minimal.vim'}"
|
@ -0,0 +1,3 @@
|
||||
- Defination vs Reference (A seperate def call)
|
||||
- Called by (which function calls this or reference the variable)
|
||||
- inline edit in float window (Almost done)
|
@ -0,0 +1,4 @@
|
||||
function! folding#ngfoldexpr()
|
||||
" return luaeval(printf('require"navigator.foldinglsp".get_fold_indic(%d)', v:lnum))
|
||||
return luaeval(printf('require"navigator.foldts".get_fold_indic(%d)', v:lnum))
|
||||
endfunction
|
@ -0,0 +1,3 @@
|
||||
function! foldlsp#foldexpr()
|
||||
return luaeval(printf('require"navigator.foldlsp".get_fold_indic(%d)', v:lnum))
|
||||
endfunction
|
@ -0,0 +1,883 @@
|
||||
navigator.txt
|
||||
|
||||
================================================================================
|
||||
CONTENTS *navigator-contents*
|
||||
|
||||
1. Navigator.................................................|navigator-navigator|
|
||||
1.1. Example: Javascript closure.|navigator-example:_javascript_closure|
|
||||
1.2. Example: C++ definition.......|navigator-example:_c++_definition|
|
||||
1.3. Golang struct type.................|navigator-golang_struct_type|
|
||||
2. Features:.................................................|navigator-features:|
|
||||
3. Why a new plugin...................................|navigator-why_a_new_plugin|
|
||||
4. Similar projects / special mentions:.|navigator-similar_projects_/_special_mentions:|
|
||||
5. Install.....................................................|navigator-install|
|
||||
5.1. Setup...................................................|navigator-setup|
|
||||
5.2. Sample vimrc turning your neovim into a full-featured IDE.|navigator-sample_vimrc_turning_your_neovim_into_a_full-featured_ide|
|
||||
5.3. Work with nvim-cmp and nvim-autopairs.|navigator-work_with_nvim-cmp_and_nvim-autopairs|
|
||||
5.4. All configure options...................|navigator-all_configure_options|
|
||||
5.4.1. LSP clients.................................|navigator-lsp_clients|
|
||||
5.4.1.1. Add your own servers.........|navigator-add_your_own_servers|
|
||||
5.4.2. Disable a lsp client loading from navigator.|navigator-disable_a_lsp_client_loading_from_navigator|
|
||||
5.4.3. Try it your self.......................|navigator-try_it_your_self|
|
||||
5.4.4. Default keymaps.........................|navigator-default_keymaps|
|
||||
5.4.5. Colors/Highlight:.....................|navigator-colors/highlight:|
|
||||
5.5. Dependency.........................................|navigator-dependency|
|
||||
5.6. Integrat with lsp_installer (williamboman/nvim-lsp-installer).|navigator-integrat_with_lsp_installer_(williamboman/nvim-lsp-installer)|
|
||||
5.6.1. Integration with other lsp plugins (e.g. rust-tools, go.nvim, clangd extension).|navigator-integration_with_other_lsp_plugins_(e.g._rust-tools,_go.nvim,_clangd_extension)|
|
||||
5.7. Usage...................................................|navigator-usage|
|
||||
5.8. Configuration...................................|navigator-configuration|
|
||||
5.9. Highlight...........................................|navigator-highlight|
|
||||
5.10. commands............................................|navigator-commands|
|
||||
5.11. Screenshots......................................|navigator-screenshots|
|
||||
5.11.1. Reference....................................|navigator-reference|
|
||||
5.11.2. Definition preview..................|navigator-definition_preview|
|
||||
5.11.3. Sidebar, folding, outline....|navigator-sidebar,_folding,_outline|
|
||||
5.11.4. GUI and multigrid support....|navigator-gui_and_multigrid_support|
|
||||
5.11.5. Document Symbol and navigate through the list.|navigator-document_symbol_and_navigate_through_the_list|
|
||||
5.11.6. Workspace Symbol......................|navigator-workspace_symbol|
|
||||
5.11.7. highlight document symbol and jump between reference.|navigator-highlight_document_symbol_and_jump_between_reference|
|
||||
6. Current symbol highlight and jump backward/forward between symbols.|navigator-current_symbol_highlight_and_jump_backward/forward_between_symbols|
|
||||
6.1. Diagnostic.....................................|navigator-diagnostic|
|
||||
6.2. Edit in preview window.............|navigator-edit_in_preview_window|
|
||||
6.3. Implementation.............................|navigator-implementation|
|
||||
6.4. Fzy search in reference...........|navigator-fzy_search_in_reference|
|
||||
6.5. Code actions.................................|navigator-code_actions|
|
||||
6.6. Symbol rename...............................|navigator-symbol_rename|
|
||||
6.6.1. Fill struct with gopls.......|navigator-fill_struct_with_gopls|
|
||||
6.7. Code preview with highlight...|navigator-code_preview_with_highlight|
|
||||
6.8. Treesitter symbol.......................|navigator-treesitter_symbol|
|
||||
6.9. Signature help.............................|navigator-signature_help|
|
||||
6.10. Call hierarchy (incomming/outgoing calls).|navigator-call_hierarchy_(incomming/outgoing_calls)|
|
||||
6.11. Light bulb if codeAction available.|navigator-light_bulb_if_codeaction_available|
|
||||
6.12. Codelens........................................|navigator-codelens|
|
||||
6.13. Predefined LSP symbol nerdfont/emoji.|navigator-predefined_lsp_symbol_nerdfont/emoji|
|
||||
6.14. VS-code style folding with treesitter.|navigator-vs-code_style_folding_with_treesitter|
|
||||
6.14.1. folding function..................|navigator-folding_function|
|
||||
6.14.2. folding comments..................|navigator-folding_comments|
|
||||
7. Debug the plugin...................................|navigator-debug_the_plugin|
|
||||
8. Break changes and known issues.......|navigator-break_changes_and_known_issues|
|
||||
9. Todo...........................................................|navigator-todo|
|
||||
10. Errors and Bug Reporting..................|navigator-errors_and_bug_reporting|
|
||||
|
||||
================================================================================
|
||||
NAVIGATOR *navigator-navigator*
|
||||
|
||||
* Source code analysis and navigate tool
|
||||
* Easy code navigation, view diagnostic errors, see relationships of functions, variables
|
||||
* A plugin combines the power of LSP and 🌲🏡 Treesitter together. Not only provids a better highlight but also help you analyse symbol context effectively.
|
||||
* ctags fuzzy search & build ctags symbols
|
||||
|
||||
-
|
||||
|
||||
* [](https://youtu.be/P1kd7Y8AatE)
|
||||
|
||||
Here are some examples
|
||||
|
||||
EXAMPLE: JAVASCRIPT CLOSURE *navigator-example:_javascript_closure*
|
||||
|
||||
The following screenshot shows javascript call tree 🌲 of variable `browser` insides a closure. This feature is similar to incoming & outgoing calls from LSP. It is designed for the symbol analysis.
|
||||
|
||||
|
||||
|
||||
Explanation:
|
||||
|
||||
* The first line of floating windows shows there are 3 references for the symbol browser in closure.js
|
||||
* The first reference of browser is an assignment, an emoji 📝 indicates the value is changed in this line. In many
|
||||
cases, we search for references to find out when the value changed.
|
||||
* The second reference of `browser` is inside function `displayName` and `displayName` sit inside `makeFunc`, So you
|
||||
will see `displayName{} <- makeFunc{}`
|
||||
* The third similar to the second, as var browser is on the right side of '=', the value not changed in this line
|
||||
and emoji is not shown.
|
||||
|
||||
EXAMPLE: C++ DEFINITION *navigator-example:_c++_definition*
|
||||
|
||||
C++ example: search reference and definition
|
||||
|
||||
You may find a 🦕 dinosaur(d) on the line of `Rectangle rect,` which means there is a definition (d for def) of rect in this line.
|
||||
|
||||
`<- f main()` means the definition is inside function main().
|
||||
|
||||
GOLANG STRUCT TYPE *navigator-golang_struct_type*
|
||||
|
||||
Struct type references in multiple Go ﳑ files
|
||||
|
||||
|
||||
|
||||
This feature can provide you info in which function/class/method the variable was referenced. It is handy for a large
|
||||
project where class/function definition is too long to fit into the preview window. Also provides a bird's eye view of where the
|
||||
variable is:
|
||||
|
||||
* Referenced
|
||||
* Modified
|
||||
* Defined
|
||||
* Called
|
||||
|
||||
================================================================================
|
||||
FEATURES: *navigator-features:*
|
||||
|
||||
* LSP easy setup. Support the most commonly used lsp clients setup. Dynamic lsp activation based on buffer type. This
|
||||
also enables you to handle workspace with mixed types of codes (e.g. Go + javascript + yml). A better default setup is
|
||||
included for LSP clients.
|
||||
* Out of box experience. 10 lines of minimum vimrc can turn your neovim into a full-featured LSP & Treesitter powered IDE
|
||||
* UI with floating windows, navigator provides a visual way to manage and navigate through symbols, diagnostic errors, reference etc. It covers
|
||||
all features(handler) provided by LSP from commonly used search reference, to less commonly used search for interface
|
||||
implementation.
|
||||
* Code Action GUI
|
||||
* Luv async thread and tasks
|
||||
* Edit your code in preview window
|
||||
* Async request with lsp.buf_request for reference search
|
||||
* Treesitter symbol search. It is handy for large files (Some of LSP e.g. sumneko_lua, there is a 100kb file size limitation?)
|
||||
* FZY search with either native C (if gcc installed) or Lua-JIT
|
||||
* LSP multiple symbol highlight/marker and hop between document references
|
||||
* Preview definination/references
|
||||
* Better navigation for diagnostic errors, Navigate through all files/buffers that contain errors/warnings
|
||||
* Grouping references/implementation/incoming/outgoing based on file names.
|
||||
* Treesitter based variable/function context analysis. It is 10x times faster compared to purely rely on LSP. In most
|
||||
of the case, it takes treesitter less than 4 ms to read and render all nodes for a file of 1,000 LOC.
|
||||
* The first plugin, IMO, allows you to search in all treesitter symbols in the workspace.
|
||||
* Nerdfont, emoji for LSP and treesitter kind
|
||||
* Optimize display (remove trailing bracket/space), display the caller of reference, de-duplicate lsp results (e.g reference
|
||||
in the same line). Using treesitter for file preview highlighter etc
|
||||
* ccls call hierarchy (Non-standard `ccls/call` API) supports
|
||||
* Syntax folding based on treesitter or LSP_fold folding algorithm. (It behaves similar to vs-code); comment folding
|
||||
* Treesitter symbols sidebar, LSP document symbole sidebar. Both with preview and folding
|
||||
* Fully support LSP CodeAction, CodeLens, CodeLens action. Help you improve code quality.
|
||||
* LRU cache for treesitter nodes
|
||||
* Lazy loader friendly
|
||||
* Multigrid support (different font and detachable)
|
||||
|
||||
================================================================================
|
||||
WHY A NEW PLUGIN *navigator-why_a_new_plugin*
|
||||
|
||||
I'd like to go beyond what the system is offering.
|
||||
|
||||
================================================================================
|
||||
SIMILAR PROJECTS / SPECIAL MENTIONS: *navigator-similar_projects_/_special_mentions:*
|
||||
|
||||
* nvim-lsputils (https://github.com/RishabhRD/nvim-lsputils)
|
||||
* nvim-fzy (https://github.com/mfussenegger/nvim-fzy.git)
|
||||
* fuzzy (https://github.com/amirrezaask/fuzzy.nvim)
|
||||
* lspsaga (https://github.com/glepnir/lspsaga.nvim)
|
||||
* fzf-lsp lsp with fzf as gui backend (https://github.com/gfanto/fzf-lsp.nvim)
|
||||
* nvim-treesitter-textobjects (https://github.com/nvim-treesitter/nvim-treesitter-textobjects)
|
||||
|
||||
================================================================================
|
||||
INSTALL *navigator-install*
|
||||
|
||||
Require nvim-0.6.1 or above, nightly (0.8) prefered
|
||||
|
||||
You can remove your lspconfig setup and use this plugin.
|
||||
The plugin depends on lspconfig and guihua.lua (https://github.com/ray-x/guihua.lua), which provides GUI and fzy support(migrate from romgrk's project (romgrk/fzy-lua-native)).
|
||||
>
|
||||
Plug 'neovim/nvim-lspconfig'
|
||||
Plug 'ray-x/guihua.lua', {'do': 'cd lua/fzy && make' }
|
||||
Plug 'ray-x/navigator.lua'
|
||||
<
|
||||
|
||||
Note: Highly recommend: 'nvim-treesitter/nvim-treesitter'
|
||||
|
||||
Packer
|
||||
>
|
||||
use({
|
||||
'ray-x/navigator.lua',
|
||||
requires = {
|
||||
{ 'ray-x/guihua.lua', run = 'cd lua/fzy && make' },
|
||||
{ 'neovim/nvim-lspconfig' },
|
||||
},
|
||||
})
|
||||
<
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
SETUP *navigator-setup*
|
||||
|
||||
Easy setup BOTH lspconfig and navigator with one liner. Navigator covers around 20 most used LSP setup.
|
||||
>
|
||||
lua require'navigator'.setup()
|
||||
<
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
SAMPLE VIMRC TURNING YOUR NEOVIM INTO A FULL-FEATURED IDE *navigator-sample_vimrc_turning_your_neovim_into_a_full-featured_ide*
|
||||
>
|
||||
call plug#begin('~/.vim/plugged')
|
||||
Plug 'neovim/nvim-lspconfig'
|
||||
Plug 'ray-x/guihua.lua', {'do': 'cd lua/fzy && make' }
|
||||
Plug 'ray-x/navigator.lua'
|
||||
" Plug 'hrsh7th/nvim-cmp' and other plugins you commenly use...
|
||||
" optional, if you need treesitter symbol support
|
||||
Plug 'nvim-treesitter/nvim-treesitter', {'do': ':TSUpdate'}
|
||||
call plug#end()
|
||||
" No need for require('lspconfig'), navigator will configure it for you
|
||||
lua <<EOF
|
||||
require'navigator'.setup()
|
||||
EOF
|
||||
<
|
||||
|
||||
You can remove your lspconfig.lua and use the hooks of navigator.lua. As the
|
||||
navigator will bind keys and handler for you. The LSP will be loaded lazily based on filetype.
|
||||
|
||||
A treesitter only mode. In some cases LSP is buggy or not available, you can also use treesitter
|
||||
standalone
|
||||
>
|
||||
call plug#begin('~/.vim/plugged')
|
||||
Plug 'ray-x/guihua.lua', {'do': 'cd lua/fzy && make' }
|
||||
Plug 'ray-x/navigator.lua'
|
||||
" Plug 'hrsh7th/nvim-compe' and other plugins you commenly use...
|
||||
" optional, if you need treesitter symbol support
|
||||
Plug 'nvim-treesitter/nvim-treesitter', {'do': ':TSUpdate'}
|
||||
" optional:
|
||||
Plug 'nvim-treesitter/nvim-treesitter-refactor' " this provides "go to def" etc
|
||||
call plug#end()
|
||||
lua <<EOF
|
||||
require'navigator'.setup()
|
||||
EOF
|
||||
<
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
WORK WITH NVIM-CMP AND NVIM-AUTOPAIRS *navigator-work_with_nvim-cmp_and_nvim-autopairs*
|
||||
|
||||
The buffer type of navigator floating windows is `guihua`
|
||||
I would suggest disable `guihua` for autocomplete.
|
||||
e.g.
|
||||
>
|
||||
require('nvim-autopairs').setup{
|
||||
disable_filetype = { "TelescopePrompt" , "guihua", "guihua_rust", "clap_input" },
|
||||
if vim.o.ft == 'clap_input' and vim.o.ft == 'guihua' and vim.o.ft == 'guihua_rust' then
|
||||
require'cmp'.setup.buffer { completion = {enable = false} }
|
||||
end
|
||||
-- or with autocmd
|
||||
vim.cmd("autocmd FileType guihua lua require('cmp').setup.buffer { enabled = false }")
|
||||
vim.cmd("autocmd FileType guihua_rust lua require('cmp').setup.buffer { enabled = false }")
|
||||
...
|
||||
}
|
||||
<
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
ALL CONFIGURE OPTIONS *navigator-all_configure_options*
|
||||
|
||||
Nondefault configuration example:
|
||||
>
|
||||
require'navigator'.setup({
|
||||
debug = false, -- log output, set to true and log path: ~/.cache/nvim/gh.log
|
||||
width = 0.75, -- max width ratio (number of cols for the floating window) / (window width)
|
||||
height = 0.3, -- max list window height, 0.3 by default
|
||||
preview_height = 0.35, -- max height of preview windows
|
||||
border = {"╭", "─", "╮", "│", "╯", "─", "╰", "│"}, -- border style, can be one of 'none', 'single', 'double',
|
||||
-- 'shadow', or a list of chars which defines the border
|
||||
on_attach = function(client, bufnr)
|
||||
-- your hook
|
||||
end,
|
||||
-- put a on_attach of your own here, e.g
|
||||
-- function(client, bufnr)
|
||||
-- -- the on_attach will be called at end of navigator on_attach
|
||||
-- end,
|
||||
-- The attach code will apply to all LSP clients
|
||||
default_mapping = true, -- set to false if you will remap every key
|
||||
keymaps = {{key = "gK", func = "declaration()"}}, -- a list of key maps
|
||||
-- this kepmap gK will override "gD" mapping function declaration() in default kepmap
|
||||
-- please check mapping.lua for all keymaps
|
||||
treesitter_analysis = true, -- treesitter variable context
|
||||
transparency = 50, -- 0 ~ 100 blur the main window, 100: fully transparent, 0: opaque, set to nil or 100 to disable it
|
||||
lsp_signature_help = true, -- if you would like to hook ray-x/lsp_signature plugin in navigator
|
||||
-- setup here. if it is nil, navigator will not init signature help
|
||||
signature_help_cfg = nil, -- if you would like to init ray-x/lsp_signature plugin in navigator, and pass in your own config to signature help
|
||||
icons = {
|
||||
-- Code action
|
||||
code_action_icon = "🏏",
|
||||
-- Diagnostics
|
||||
diagnostic_head = '🐛',
|
||||
diagnostic_head_severity_1 = "🈲",
|
||||
-- refer to lua/navigator.lua for more icons setups
|
||||
},
|
||||
lsp_installer = false, -- set to true if you would like use the lsp installed by williamboman/nvim-lsp-installer
|
||||
lsp = {
|
||||
enable = true, -- skip lsp setup if disabled make sure add require('navigator.lspclient.mapping').setup() in you
|
||||
-- own on_attach
|
||||
code_action = {enable = true, sign = true, sign_priority = 40, virtual_text = true},
|
||||
code_lens_action = {enable = true, sign = true, sign_priority = 40, virtual_text = true},
|
||||
format_on_save = true, -- set to false to disable lsp code format on save (if you are using prettier/efm/formater etc)
|
||||
disable_format_cap = {"sqls", "sumneko_lua", "gopls"}, -- a list of lsp disable format capacity (e.g. if you using efm or vim-codeformat etc), empty {} by default
|
||||
disable_lsp = {'pylsd', 'sqlls'}, -- a list of lsp server disabled for your project, e.g. denols and tsserver you may
|
||||
-- only want to enable one lsp server
|
||||
-- to disable all default config and use your own lsp setup set
|
||||
-- disable_lsp = 'all'
|
||||
-- Default {}
|
||||
diagnostic = {
|
||||
underline = true,
|
||||
virtual_text = true, -- show virtual for diagnostic message
|
||||
update_in_insert = false, -- update diagnostic message in insert mode
|
||||
},
|
||||
diagnostic_scrollbar_sign = {'▃', '▆', '█'}, -- experimental: diagnostic status in scroll bar area; set to false to disable the diagnostic sign,
|
||||
-- for other style, set to {'╍', 'ﮆ'} or {'-', '='}
|
||||
diagnostic_virtual_text = true, -- show virtual for diagnostic message
|
||||
diagnostic_update_in_insert = false, -- update diagnostic message in insert mode
|
||||
disply_diagnostic_qf = true, -- always show quickfix if there are diagnostic errors, set to false if you want to
|
||||
ignore it
|
||||
tsserver = {
|
||||
filetypes = {'typescript'} -- disable javascript etc,
|
||||
-- set to {} to disable the lspclient for all filetypes
|
||||
},
|
||||
ctags ={
|
||||
cmd = 'ctags',
|
||||
tagfile = 'tags'
|
||||
options = '-R --exclude=.git --exclude=node_modules --exclude=test --exclude=vendor --excmd=number'
|
||||
}
|
||||
gopls = { -- gopls setting
|
||||
on_attach = function(client, bufnr) -- on_attach for gopls
|
||||
-- your special on attach here
|
||||
-- e.g. disable gopls format because a known issue https://github.com/golang/go/issues/45732
|
||||
print("i am a hook, I will disable document format")
|
||||
client.resolved_capabilities.document_formatting = false
|
||||
end,
|
||||
settings = {
|
||||
gopls = {gofumpt = false} -- disable gofumpt etc,
|
||||
}
|
||||
},
|
||||
sumneko_lua = {
|
||||
sumneko_root_path = vim.fn.expand("$HOME") .. "/github/sumneko/lua-language-server",
|
||||
sumneko_binary = vim.fn.expand("$HOME") .. "/github/sumneko/lua-language-server/bin/macOS/lua-language-server",
|
||||
},
|
||||
servers = {'cmake', 'ltex'}, -- by default empty, and it should load all LSP clients avalible based on filetype
|
||||
-- but if you whant navigator load e.g. `cmake` and `ltex` for you , you
|
||||
-- can put them in the `servers` list and navigator will auto load them.
|
||||
-- you could still specify the custom config like this
|
||||
-- cmake = {filetypes = {'cmake', 'makefile'}, single_file_support = false},
|
||||
}
|
||||
})
|
||||
<
|
||||
|
||||
LSP CLIENTS *navigator-lsp_clients*
|
||||
|
||||
Built clients:
|
||||
>
|
||||
local servers = {
|
||||
"angularls", "gopls", "tsserver", "flow", "bashls", "dockerls", "julials", "pylsp", "pyright",
|
||||
"jedi_language_server", "jdtls", "sumneko_lua", "vimls", "html", "jsonls", "solargraph", "cssls",
|
||||
"yamlls", "clangd", "ccls", "sqls", "denols", "graphql", "dartls", "dotls",
|
||||
"kotlin_language_server", "nimls", "intelephense", "vuels", "phpactor", "omnisharp",
|
||||
"r_language_server", "rust_analyzer", "terraformls", "svelte", "texlab", "clojure_lsp", "elixirls",
|
||||
"sourcekit", "fsautocomplete", "vls", "hls"
|
||||
}
|
||||
<
|
||||
|
||||
Navigator will try to load avalible lsp server/client based on filetype. The clients has none default on_attach.
|
||||
incremental sync and debounce is enabled by navigator. And the lsp
|
||||
snippet will be enabled. So you could use COQ and nvim-cmp snippet expand.
|
||||
|
||||
Other than above setup, additional none default setup are used for following lsp:
|
||||
|
||||
* gopls
|
||||
* clangd
|
||||
* rust_analyzer
|
||||
* sqls
|
||||
* sumneko_lua
|
||||
* pyright
|
||||
* ccls
|
||||
|
||||
Please check client setup (https://github.com/ray-x/navigator.lua/blob/26012cf9c172aa788a2e53018d94b32c5c75af75/lua/navigator/lspclient/clients.lua#L98-L234)
|
||||
|
||||
The plugin can work with multiple LSP, e.g sqls+gopls+efm. But there are cases you may need to disable some of the
|
||||
servers. (Prevent loading multiple LSP for same source code.) e.g. I saw strange behaviours when I use
|
||||
pylsp+pyright+jedi
|
||||
together. If you have multiple similar LSP installed and have trouble with the plugin, please enable only one at a time.
|
||||
|
||||
ADD YOUR OWN SERVERS *navigator-add_your_own_servers*
|
||||
|
||||
Above servers covered a small part neovim lspconfig support, You can still use lspconfig to add and config servers not
|
||||
in the list. If you would like to add a server not in the list, you can check this PR https://github.com/ray-x/navigator.lua/pull/107
|
||||
|
||||
Alternatively, update following option in setup(if you do not want a PR):
|
||||
>
|
||||
require'navigator'setup{lsp={servers={'cmake', 'lexls'}}}
|
||||
<
|
||||
|
||||
Above option add cmake and lexls to the default server list
|
||||
|
||||
DISABLE A LSP CLIENT LOADING FROM NAVIGATOR *navigator-disable_a_lsp_client_loading_from_navigator*
|
||||
|
||||
Note: If you have multiple lsp installed for same language, please only enable one at a time by disable others with e.g. `disable_lsp={'denols', 'clangd'}`
|
||||
To disable a specific LSP, set `filetypes` to {} e.g.
|
||||
>
|
||||
require'navigator'.setup({
|
||||
lsp={
|
||||
pylsd={filetype={}}
|
||||
}
|
||||
})
|
||||
<
|
||||
|
||||
Or:
|
||||
>
|
||||
require'navigator'.setup({
|
||||
lsp={
|
||||
disable_lsp = {'pylsd', 'sqlls'},
|
||||
}
|
||||
})
|
||||
<
|
||||
|
||||
TRY IT YOUR SELF *navigator-try_it_your_self*
|
||||
|
||||
In `playground` folder, there is a `init.lua` and source code for you to play with. Check playground/README.md (https://github.com/ray-x/navigator.lua/blob/master/playground/README.md) for more details
|
||||
|
||||
DEFAULT KEYMAPS *navigator-default_keymaps*
|
||||
|
||||
| mode | key | function |
|
||||
| ---- | --------------- | ---------------------------------------------------------- |
|
||||
| n | gr | async references, definitions and context |
|
||||
| n | <Leader>gr | show reference and context |
|
||||
| i | <m-k> | signature help |
|
||||
| n | <c-k> | signature help |
|
||||
| n | gW | workspace symbol |
|
||||
| n | gD | declaration |
|
||||
| n | gd | definition |
|
||||
| n | g0 | document symbol |
|
||||
| n | <C-]> | go to definition (if multiple show listview) |
|
||||
| n | gp | definition preview (Go to Preview) |
|
||||
| n | <C-LeftMouse> | definition |
|
||||
| n | g<LeftMouse> | implementation |
|
||||
| n | <Leader>gt | treesitter document symbol |
|
||||
| n | <Leader>gT | treesitter symbol for all open buffers |
|
||||
| n | <Leader> ct | ctags symbol search |
|
||||
| n | <Leader> cg | ctags symbol generate |
|
||||
| n | K | hover doc |
|
||||
| n | <Space>ca | code action (when you see 🏏 ) |
|
||||
| n | <Space>la | code lens action (when you see a codelens indicator) |
|
||||
| v | <Space>ca | range code action (when you see 🏏 ) |
|
||||
| n | <Space>rn | rename with floating window |
|
||||
| n | <Leader>re | rename (lsp default) |
|
||||
| n | <Leader>gi | hierarchy incoming calls |
|
||||
| n | <Leader>go | hierarchy outgoing calls |
|
||||
| n | gi | implementation |
|
||||
| n | <Space> D | type definition |
|
||||
| n | gL | show line diagnostic |
|
||||
| n | gG | show diagnostic for all buffers |
|
||||
| n | ]d | next diagnostic |
|
||||
| n | [d | previous diagnostic |
|
||||
| n | <Leader> dt | diagnostic toggle(enable/disable) |
|
||||
| n | ]r | next treesitter reference/usage |
|
||||
| n | [r | previous treesitter reference/usage |
|
||||
| n | <Space> wa | add workspace folder |
|
||||
| n | <Space> wr | remove workspace folder |
|
||||
| n | <Space> wl | print workspace folder |
|
||||
| n | <Leader>k | toggle reference highlight |
|
||||
| i/n | <C-p> | previous item in list |
|
||||
| i/n | <C-n> | next item in list |
|
||||
| i/n | number 1~9 | move to ith row/item in the list |
|
||||
| i/n | <Up> | previous item in list |
|
||||
| i/n | <Down> | next item in list |
|
||||
| n | <Ctrl-w>j | move cursor to preview (windows move to bottom view point) |
|
||||
| n | <Ctrl-w>k | move cursor to list (windows move to up view point) |
|
||||
| i/n | <C-o> | open preview file in nvim/Apply action |
|
||||
| n | <C-v> | open preview file in nvim with vsplit |
|
||||
| n | <C-s> | open preview file in nvim with split |
|
||||
| n | <Enter> | open preview file in nvim/Apply action |
|
||||
| n | <ESC> | close listview of floating window |
|
||||
| i/n | <C-e> | close listview of floating window |
|
||||
| i/n | <C-b> | previous page in listview |
|
||||
| i/n | <C-f> | next page in listview |
|
||||
| i/n | <C-s> | save the modification to preview window to file |
|
||||
|
||||
COLORS/HIGHLIGHT: *navigator-colors/highlight:*
|
||||
|
||||
You can override default highlight GuihuaListDark (listview) and GuihuaTextViewDark (code view) and GuihuaListHl (select item)
|
||||
|
||||
e.g.
|
||||
>
|
||||
hi default GuihuaTextViewDark guifg=#e0d8f4 guibg=#332e55
|
||||
hi default GuihuaListDark guifg=#e0d8f4 guibg=#103234
|
||||
hi default GuihuaListHl guifg=#e0d8f4 guibg=#404254
|
||||
<
|
||||
|
||||
There are other Lsp highlight been used in this plugin, e.g LspReferenceRead/Text/Write are used for document highlight,
|
||||
LspDiagnosticsXXX are used for diagnostic. Please check highlight.lua and dochighlight.lua for more info.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
DEPENDENCY *navigator-dependency*
|
||||
|
||||
* lspconfig
|
||||
* guihua.lua (provides floating window, FZY)
|
||||
* Optional:
|
||||
* treesitter (list treesitter symbols, object analysis)
|
||||
* lsp-signature (better signature help)
|
||||
|
||||
The plugin can be loaded lazily (packer `opt = true` ), And it will check if optional plugins existance and load those plugins only if they existed.
|
||||
|
||||
The terminal will need to be able to output nerdfont and emoji correctly. I am using Kitty with nerdfont (Victor Mono).
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
INTEGRAT WITH LSP_INSTALLER (WILLIAMBOMAN/NVIM-LSP-INSTALLER) *navigator-integrat_with_lsp_installer_(williamboman/nvim-lsp-installer)*
|
||||
|
||||
If you are using lsp_installer and would like to use the lsp servers installed by lsp_installer. Please set
|
||||
>
|
||||
lsp_installer = true
|
||||
<
|
||||
|
||||
In the config. Also please setup the lsp server from installer setup with `server:setup{opts}`
|
||||
|
||||
example:
|
||||
>
|
||||
use({
|
||||
'williamboman/nvim-lsp-installer',
|
||||
config = function()
|
||||
local lsp_installer = require('nvim-lsp-installer')
|
||||
lsp_installer.setup{}
|
||||
end,
|
||||
})
|
||||
use({
|
||||
'ray-x/navigator.lua',
|
||||
config = function()
|
||||
require('navigator').setup({
|
||||
debug = true,
|
||||
lsp_installer = true,
|
||||
keymaps = { { key = 'gR', func = "require('navigator.reference').async_ref()" } },
|
||||
})
|
||||
end,
|
||||
})
|
||||
<
|
||||
|
||||
Please refer to lsp_installer_config (https://github.com/ray-x/navigator.lua/blob/master/playground/init_lsp_installer.lua)
|
||||
for more info
|
||||
|
||||
Alternatively, Navigator can be used to startup the server installed by lsp-installer.
|
||||
as it will override the navigator setup
|
||||
|
||||
To start LSP installed by lsp_installer, please use following setups
|
||||
>
|
||||
require'navigator'.setup({
|
||||
-- lsp_installer = false -- default value is false
|
||||
lsp = {
|
||||
tsserver = { cmd = {'your tsserver installed by lsp_installer'} }
|
||||
}
|
||||
})
|
||||
<
|
||||
|
||||
example cmd setup (mac) for pyright :
|
||||
>
|
||||
require'navigator'.setup({
|
||||
-- lsp_installer = false -- default value is false
|
||||
lsp = {
|
||||
tsserver = {
|
||||
cmd = { "/Users/username/.local/share/nvim/lsp_servers/python/node_modules/.bin/pyright-langserver", "--stdio" }
|
||||
}
|
||||
}
|
||||
}
|
||||
<
|
||||
|
||||
The lsp servers installed by nvim-lsp-installer is in following dir
|
||||
>
|
||||
local path = require 'nvim-lsp-installer.path'
|
||||
local install_root_dir = path.concat {vim.fn.stdpath 'data', 'lsp_servers'}
|
||||
<
|
||||
|
||||
And you can setup binary full path to this: (e.g. with gopls)
|
||||
`install_root_dir .. '/go/gopls'` So the config is
|
||||
>
|
||||
local path = require 'nvim-lsp-installer.path'
|
||||
local install_root_dir = path.concat {vim.fn.stdpath 'data', 'lsp_servers'}
|
||||
require'navigator'.setup({
|
||||
-- lsp_installer = false -- default value is false
|
||||
lsp = {
|
||||
gopls = {
|
||||
cmd = { install_root_dir .. '/go/gopls' }
|
||||
}
|
||||
}
|
||||
}
|
||||
<
|
||||
|
||||
Use lsp_installer configs
|
||||
You can delegate the lsp server setup to lsp_installer with `server:setup{opts}`
|
||||
Here is an example init_lsp_installer.lua (https://github.com/ray-x/navigator.lua/blob/master/playground/init_lsp_installer.lua)
|
||||
|
||||
INTEGRATION WITH OTHER LSP PLUGINS (E.G. RUST-TOOLS, GO.NVIM, CLANGD EXTENSION) *navigator-integration_with_other_lsp_plugins_(e.g._rust-tools,_go.nvim,_clangd_extension)*
|
||||
|
||||
There are lots of plugins provides lsp support
|
||||
go.nvim allow you either hook gopls from go.nvim or from navigator and it can export the lsp setup from go.nvim.
|
||||
|
||||
rust-tools and clangd allow you to setup on_attach from config server
|
||||
Here is an example to setup rust with rust-tools
|
||||
>
|
||||
require'navigator'.setup({
|
||||
lsp = {
|
||||
disable_lsp = { "rust_analyzer", "clangd" }, -- will not run rust_analyzer setup from navigator
|
||||
}
|
||||
})
|
||||
require('rust-tools').setup({
|
||||
server = {
|
||||
on_attach = function(_, _)
|
||||
require('navigator.lspclient.mapping').setup() -- setup navigator keymaps here,
|
||||
-- otherwise, you can define your own commands to call navigator functions
|
||||
end,
|
||||
}
|
||||
})
|
||||
require("clangd_extensions").setup {
|
||||
server = {
|
||||
on_attach = function(_, _)
|
||||
require('navigator.lspclient.mapping').setup() -- setup navigator keymaps here,
|
||||
-- otherwise, you can define your own commands to call navigator functions
|
||||
end,
|
||||
}
|
||||
}
|
||||
<
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
USAGE *navigator-usage*
|
||||
|
||||
Please refer to lua/navigator/lspclient/mapping.lua on key mappings. Should be able to work out-of-box.
|
||||
|
||||
* Use <c-e> or `:q!` to kill the floating window
|
||||
* (or <c-n>, <c-p>) to move
|
||||
* <c-o> or <CR> to open location or apply code actions. Note: <CR> might be bound in insert mode by other plugins
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
CONFIGURATION *navigator-configuration*
|
||||
|
||||
In `navigator.lua` there is a default configuration. You can override the values by passing your own values
|
||||
|
||||
e.g
|
||||
>
|
||||
-- The attach will be call at end of navigator on_attach()
|
||||
require'navigator'.setup({on_attach = function(client, bufnr) require 'illuminate'.on_attach(client)})
|
||||
<
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
HIGHLIGHT *navigator-highlight*
|
||||
|
||||
Highlight I am using:
|
||||
|
||||
* LspReferenceRead, LspReferenceText and LspReferenceWrite are used for `autocmd CursorHold <buffer> lua vim.lsp.buf.document_highlight()`
|
||||
That is where you saw the current symbol been highlighted.
|
||||
* GuihuaListDark and GuihuaTextViewDark is used for floating listvew and TextView. They are be based on current background
|
||||
(Normal) and PmenuSel
|
||||
* In future, I will use NormalFloat for floating view. But ATM, most of colorscheme does not define NormalFloat
|
||||
|
||||
You can override the above highlight to fit your current colorscheme
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
COMMANDS *navigator-commands*
|
||||
|
||||
| command | function |
|
||||
| ------------ | ------------------------- |
|
||||
| LspToggleFmt | toggle lsp auto format |
|
||||
| LspKeymaps | show LSP releated keymaps |
|
||||
| Nctags {args} | show ctags symbols, args: -g regen ctags |
|
||||
| LspRestart | reload lsp |
|
||||
| LspSymbols | document symbol in side panel |
|
||||
| NRefPanel |symbol reference in side panel |
|
||||
| TSymobls | treesitter symbol in side panel |
|
||||
| Calltree {args} | lsp call hierarchy call tree, args: -i (incomming default), -o (outgoing) |
|
||||
|
||||
:LspToggleFmt *:LspToggleFmt*
|
||||
Toggle lsp auto format.
|
||||
|
||||
:LspKeymaps *:LspKeymaps*
|
||||
Show Lsp keymaps.
|
||||
|
||||
:Nctags [flags] *:Nctags*
|
||||
Show ctags symbols.
|
||||
[flags]:
|
||||
-g regen ctags
|
||||
|
||||
:LspRestart *:LspRestart*
|
||||
Restart Lsp.
|
||||
|
||||
:LspSymbols *:LspSymbols*
|
||||
Lsp document symbol in side panel.
|
||||
|
||||
:TSSymbols *:TSSymbols*
|
||||
Treesitter symbol in side panel.
|
||||
|
||||
:NRefPanel *:NRefPanel*
|
||||
Symbol reference in side panel.
|
||||
|
||||
:Calltree [flags] *:Calltree*
|
||||
Lsp call hierarchy call tree.
|
||||
[flags]:
|
||||
-i: incomming default
|
||||
-o: outgoing
|
||||
--------------------------------------------------------------------------------
|
||||
SCREENSHOTS *navigator-screenshots*
|
||||
|
||||
colorscheme: aurora (https://github.com/ray-x/aurora)
|
||||
|
||||
REFERENCE *navigator-reference*
|
||||
|
||||
Pls check the first part of README
|
||||
|
||||
DEFINITION PREVIEW *navigator-definition_preview*
|
||||
|
||||
Using treesitter and LSP to view the symbol definition
|
||||
|
||||
|
||||
|
||||
SIDEBAR, FOLDING, OUTLINE *navigator-sidebar,_folding,_outline*
|
||||
|
||||
Treesitter outline and Diagnostics
|
||||
|
||||
|
||||
|
||||
GUI AND MULTIGRID SUPPORT *navigator-gui_and_multigrid_support*
|
||||
|
||||
You can load a different font size for floating win
|
||||
|
||||
|
||||
|
||||
DOCUMENT SYMBOL AND NAVIGATE THROUGH THE LIST *navigator-document_symbol_and_navigate_through_the_list*
|
||||
|
||||
|
||||
The key binding to navigate in the list.
|
||||
|
||||
* up and down key
|
||||
* `<Ctrl-f/b>` for page up and down
|
||||
* number key 1~9 go to the ith item.
|
||||
* If there are loads of results, would be good to use fzy search prompt to filter out the result you are interested.
|
||||
|
||||
WORKSPACE SYMBOL *navigator-workspace_symbol*
|
||||
|
||||
|
||||
|
||||
HIGHLIGHT DOCUMENT SYMBOL AND JUMP BETWEEN REFERENCE *navigator-highlight_document_symbol_and_jump_between_reference*
|
||||
|
||||
|
||||
|
||||
================================================================================
|
||||
CURRENT SYMBOL HIGHLIGHT AND JUMP BACKWARD/FORWARD BETWEEN SYMBOLS *navigator-current_symbol_highlight_and_jump_backward/forward_between_symbols*
|
||||
|
||||
Document highlight provided by LSP.
|
||||
Jump between symbols with treesitter (with `]r` and `[r`)
|
||||
|
||||
|
||||
DIAGNOSTIC *navigator-diagnostic*
|
||||
|
||||
Visual studio code style show errors minimap in scroll bar area
|
||||
(Check setup for `diagnostic_scrollbar_sign`)
|
||||
|
||||
|
||||
|
||||
Diagnostic in single bufer
|
||||
|
||||
|
||||
|
||||
Show diagnostic in all buffers
|
||||
|
||||
|
||||
|
||||
EDIT IN PREVIEW WINDOW *navigator-edit_in_preview_window*
|
||||
|
||||
You can in place edit your code in floating window
|
||||
|
||||
https://user-images.githubusercontent.com/1681295/121832919-89cbc080-cd0e-11eb-9778-11d0f356b38d.mov
|
||||
|
||||
(Note: This feature only avalible in `find reference` and `find diagnostic`, You can not add/remove lines in floating window)
|
||||
|
||||
IMPLEMENTATION *navigator-implementation*
|
||||
|
||||
|
||||
|
||||
FZY SEARCH IN REFERENCE *navigator-fzy_search_in_reference*
|
||||
|
||||
|
||||
|
||||
CODE ACTIONS *navigator-code_actions*
|
||||
|
||||
|
||||
|
||||
SYMBOL RENAME *navigator-symbol_rename*
|
||||
|
||||
|
||||
|
||||
FILL STRUCT WITH GOPLS *navigator-fill_struct_with_gopls*
|
||||
|
||||
|
||||
|
||||
CODE PREVIEW WITH HIGHLIGHT *navigator-code_preview_with_highlight*
|
||||
|
||||
|
||||
|
||||
TREESITTER SYMBOL *navigator-treesitter_symbol*
|
||||
|
||||
Treetsitter symbols in all buffers
|
||||
|
||||
|
||||
SIGNATURE HELP *navigator-signature_help*
|
||||
|
||||
Improved signature help with current parameter highlighted
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
CALL HIERARCHY (INCOMMING/OUTGOING CALLS) *navigator-call_hierarchy_(incomming/outgoing_calls)*
|
||||
|
||||
|
||||
|
||||
LIGHT BULB IF CODEACTION AVAILABLE *navigator-light_bulb_if_codeaction_available*
|
||||
|
||||
|
||||
|
||||
CODELENS *navigator-codelens*
|
||||
|
||||
Codelens for gopls/golang. Garbage collection analyse:
|
||||
|
||||
|
||||
|
||||
Codelens for C++/ccls. Symbol reference
|
||||
|
||||
|
||||
|
||||
PREDEFINED LSP SYMBOL NERDFONT/EMOJI *navigator-predefined_lsp_symbol_nerdfont/emoji*
|
||||
|
||||
|
||||
|
||||
VS-CODE STYLE FOLDING WITH TREESITTER *navigator-vs-code_style_folding_with_treesitter*
|
||||
|
||||
FOLDING FUNCTION *navigator-folding_function*
|
||||
|
||||
|
||||
|
||||
FOLDING COMMENTS *navigator-folding_comments*
|
||||
|
||||
|
||||
|
||||
================================================================================
|
||||
DEBUG THE PLUGIN *navigator-debug_the_plugin*
|
||||
|
||||
One simple way to gether debug info and understand what is wrong is output the debug logs
|
||||
>
|
||||
require'navigator'.setup({
|
||||
debug = false, -- log output, set to true and log path: ~/.local/share/nvim/gh.log
|
||||
})
|
||||
<
|
||||
>
|
||||
-- a example of adding logs in the plugin
|
||||
local log = require"navigator.util".log
|
||||
local definition_hdlr = util.mk_handler(function(err, locations, ctx, _)
|
||||
-- output your log
|
||||
log('[definition] log for locations', locations, "and ctx", ctx)
|
||||
if err ~= nil then
|
||||
return
|
||||
end
|
||||
end
|
||||
<
|
||||
|
||||
================================================================================
|
||||
BREAK CHANGES AND KNOWN ISSUES *navigator-break_changes_and_known_issues*
|
||||
|
||||
known issues I am working on (https://github.com/ray-x/navigator.lua/issues/1)
|
||||
|
||||
================================================================================
|
||||
TODO *navigator-todo*
|
||||
|
||||
* The project is in the early phase, bugs expected, PRs and suggestions are welcome
|
||||
* Async (some of the requests is slow on large codebases and might be good to use co-rountine)
|
||||
* More clients. I use go, python, js/ts, java, c/cpp, lua most of the time. Did not test other languages (e.g dart, swift etc)
|
||||
* Configuration options
|
||||
|
||||
================================================================================
|
||||
ERRORS AND BUG REPORTING *navigator-errors_and_bug_reporting*
|
||||
|
||||
* Please double check your setup and check if minium setup works or not
|
||||
* It should works for 0.6.1, neovim 0.7.x prefered.
|
||||
* Check console output
|
||||
* Check `LspInfo` and treesitter status with `checkhealth`
|
||||
* Turn on log and attach the log to your issue if possible you can remove any personal/company info in the log
|
||||
* Submit Issue with minium vimrc. Please check playground/init.lua as a vimrc template. !!!Please DONOT use a packer vimrc
|
||||
|
||||
that installs everything to default folder!!! Also check this repo navigator bug report (https://github.com/fky2015/navigator.nvim-bug-report)
|
@ -0,0 +1,4 @@
|
||||
autocmd BufRead,BufNewFile *.tf,*.tfvars set filetype=terraform
|
||||
autocmd BufRead,BufNewFile *.tfstate,*.tfstate.backup set filetype=json
|
||||
autocmd BufRead,BufNewFile *.hcl set filetype=hcl
|
||||
autocmd BufRead,BufNewFile .terraformrc,terraform.rc set filetype=hcl
|
@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title></title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link href="css/style.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -1 +0,0 @@
|
||||
TODO.txt
|
@ -0,0 +1,105 @@
|
||||
local gui = require('navigator.gui')
|
||||
local util = require('navigator.util')
|
||||
local log = util.log
|
||||
local partial = util.partial
|
||||
local lsphelper = require('navigator.lspwrapper')
|
||||
local cwd = vim.loop.cwd()
|
||||
|
||||
local path_sep = require('navigator.util').path_sep()
|
||||
local path_cur = require('navigator.util').path_cur()
|
||||
local M = {}
|
||||
|
||||
local function call_hierarchy_handler(direction, err, result, ctx, cfg, error_message)
|
||||
log('call_hierarchy')
|
||||
log('call_hierarchy', direction, err, result, ctx, cfg)
|
||||
|
||||
assert(next(vim.lsp.buf_get_clients()), 'Must have a client running to use lsp_tags')
|
||||
if err ~= nil then
|
||||
log('hierarchy error', ctx, 'dir', direction, 'result', result, 'err', err)
|
||||
vim.notify('ERROR: ' .. error_message, vim.lsp.log_levels.WARN)
|
||||
return
|
||||
end
|
||||
-- log(funcs)
|
||||
local items = {}
|
||||
for _, call_hierarchy in pairs(result) do
|
||||
local kind = ' '
|
||||
local range = call_hierarchy.range
|
||||
local filename = assert(vim.uri_to_fname(call_hierarchy.uri))
|
||||
|
||||
local display_filename = filename:gsub(cwd .. path_sep, path_cur, 1)
|
||||
|
||||
local bufnr = vim.uri_to_bufnr(call_hierarchy.uri)
|
||||
local row = range.start.line
|
||||
local line = (vim.api.nvim_buf_get_lines(bufnr, row, row + 1, false) or { '' })[1]
|
||||
local fn = ''
|
||||
if line ~= nil then
|
||||
fn = line:sub(range.start.character, range['end'].character + 1)
|
||||
end
|
||||
table.insert(items, {
|
||||
uri = call_hierarchy.uri,
|
||||
filename = filename,
|
||||
display_filename = display_filename,
|
||||
text = kind .. fn,
|
||||
range = range,
|
||||
lnum = range.start.line + 1,
|
||||
col = range.start.character,
|
||||
})
|
||||
end
|
||||
return items
|
||||
end
|
||||
|
||||
local call_hierarchy_handler_from = partial(call_hierarchy_handler, 'from')
|
||||
local call_hierarchy_handler_to = partial(call_hierarchy_handler, 'to')
|
||||
|
||||
local function incoming_calls_handler(_, err, result, ctx, cfg)
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
assert(next(vim.lsp.buf_get_clients(bufnr)), 'Must have a client running to use lsp_tags')
|
||||
|
||||
local results = call_hierarchy_handler_from(err, result, ctx, cfg, 'Incoming calls not found')
|
||||
|
||||
local ft = vim.api.nvim_buf_get_option(ctx.bufnr or 0, 'ft')
|
||||
gui.new_list_view({ items = results, ft = ft or 'cpp', api = ' ' })
|
||||
end
|
||||
-- err, method, result, client_id, bufnr
|
||||
local function outgoing_calls_handler(_, err, result, ctx, cfg)
|
||||
local results = call_hierarchy_handler_to(err, result, ctx, cfg, 'Outgoing calls not found')
|
||||
|
||||
local ft = vim.api.nvim_buf_get_option(ctx.bufnr or 0, 'ft')
|
||||
gui.new_list_view({ items = results, ft = ft or 'cpp', api = ' ' })
|
||||
-- fzf_locations(bang, "", "Outgoing Calls", results, false)
|
||||
end
|
||||
|
||||
function M.incoming_calls(bang, opts)
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
assert(next(vim.lsp.buf_get_clients(bufnr)), 'Must have a client running to use lsp_tags')
|
||||
-- if not lsphelper.check_capabilities("call_hierarchy") then
|
||||
-- return
|
||||
-- end
|
||||
|
||||
local params = vim.lsp.util.make_position_params()
|
||||
-- params['hierarchy'] = true
|
||||
params['levels'] = 2
|
||||
params['callee'] = false
|
||||
-- params['callee'] = true
|
||||
log(params)
|
||||
log(opts)
|
||||
lsphelper.call_sync('$ccls/call', params, opts, partial(incoming_calls_handler, bang))
|
||||
end
|
||||
|
||||
function M.outgoing_calls(bang, opts)
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
assert(next(vim.lsp.buf_get_clients(bufnr)), 'Must have a client running to use lsp_tags')
|
||||
local params = vim.lsp.util.make_position_params()
|
||||
params['levels'] = 2
|
||||
params['callee'] = true
|
||||
log(params)
|
||||
lsphelper.call_sync('$ccls/call', params, opts, partial(outgoing_calls_handler, bang))
|
||||
end
|
||||
|
||||
M.incoming_calls_call = partial(M.incoming_calls, 0)
|
||||
M.outgoing_calls_call = partial(M.outgoing_calls, 0)
|
||||
|
||||
M.incoming_calls_handler = partial(incoming_calls_handler, 0)
|
||||
M.outgoing_calls_handler = partial(outgoing_calls_handler, 0)
|
||||
|
||||
return M
|
@ -0,0 +1,144 @@
|
||||
-- codelenses
|
||||
-- https://github.com/josa42/nvim-lsp-codelenses/blob/master/lua/jg/lsp/codelenses.lua
|
||||
-- https://github.com/neovim/neovim/blob/master/runtime/lua/vim/lsp/codelens.lua
|
||||
local codelens = require('vim.lsp.codelens')
|
||||
|
||||
local log = require('navigator.util').log
|
||||
local trace = require('navigator.util').trace
|
||||
-- trace = log
|
||||
local lsphelper = require('navigator.lspwrapper')
|
||||
local api = vim.api
|
||||
local M = {}
|
||||
|
||||
local config = require('navigator').config_values()
|
||||
local sign_name = 'NavigatorCodeLensLightBulb'
|
||||
if vim.tbl_isempty(vim.fn.sign_getdefined(sign_name)) then
|
||||
vim.fn.sign_define(sign_name, { text = config.icons.code_lens_action_icon, texthl = 'LspDiagnosticsSignHint' })
|
||||
end
|
||||
|
||||
local sign_group = 'nvcodelensaction'
|
||||
|
||||
local get_current_winid = require('navigator.util').get_current_winid
|
||||
|
||||
local is_enabled = true
|
||||
local code_lens_action = {}
|
||||
|
||||
local function _update_sign(line)
|
||||
trace('update sign at line ', line)
|
||||
local winid = get_current_winid()
|
||||
if code_lens_action[winid] == nil then
|
||||
code_lens_action[winid] = {}
|
||||
end
|
||||
if code_lens_action[winid].lightbulb_line ~= 0 then
|
||||
vim.fn.sign_unplace(sign_group, { id = code_lens_action[winid].lightbulb_line, buffer = '%' })
|
||||
end
|
||||
|
||||
if line then
|
||||
-- log("updatasign", line, sign_group, sign_name)
|
||||
vim.fn.sign_place(
|
||||
line,
|
||||
sign_group,
|
||||
sign_name,
|
||||
'%',
|
||||
{ lnum = line + 1, priority = config.lsp.code_lens_action.sign_priority }
|
||||
)
|
||||
code_lens_action[winid].lightbulb_line = line
|
||||
end
|
||||
end
|
||||
|
||||
local codelens_hdlr = function(err, result, ctx, cfg)
|
||||
trace(ctx, result)
|
||||
M.codelens_ctx = ctx
|
||||
if err or result == nil then
|
||||
if err then
|
||||
log('lsp code lens', vim.inspect(err), ctx, cfg)
|
||||
end
|
||||
return
|
||||
end
|
||||
trace('codelenes result', result)
|
||||
for _, v in pairs(result) do
|
||||
_update_sign(v.range.start.line)
|
||||
end
|
||||
end
|
||||
|
||||
function M.setup(bufnr)
|
||||
log('setup for ****** ', bufnr)
|
||||
vim.api.nvim_set_hl(0, 'LspCodeLens', { link = 'DiagnosticsHint', default = true })
|
||||
vim.api.nvim_set_hl(0, 'LspCodeLensText', { link = 'DiagnosticsInformation', default = true })
|
||||
vim.api.nvim_set_hl(0, 'LspCodeLensSign', { link = 'DiagnosticsInformation', default = true })
|
||||
vim.api.nvim_set_hl(0, 'LspCodeLensSeparator', { link = 'Boolean', default = true })
|
||||
vim.api.nvim_create_autocmd({ 'CursorHold', 'CursorHoldI', 'InsertLeave' }, {
|
||||
group = vim.api.nvim_create_augroup('nv__codelenses', {}),
|
||||
buffer = bufnr or vim.api.nvim_win_get_buf(),
|
||||
callback = function()
|
||||
require('navigator.codelens').refresh()
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
M.lsp_clients = {}
|
||||
|
||||
function M.refresh()
|
||||
if next(vim.lsp.buf_get_clients(0)) == nil then
|
||||
log('Must have a client running to use lsp code action')
|
||||
return
|
||||
end
|
||||
if not lsphelper.check_capabilities('codeLensProvider') then
|
||||
return
|
||||
end
|
||||
M.inline()
|
||||
end
|
||||
|
||||
local virtual_types_ns = api.nvim_create_namespace('ng_virtual_types')
|
||||
|
||||
function M.disable()
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
vim.api.nvim_buf_clear_namespace(bufnr, virtual_types_ns, 0, -1)
|
||||
is_enabled = false
|
||||
end
|
||||
|
||||
function M.run_action()
|
||||
local original_select = vim.ui.select
|
||||
vim.ui.select = require('guihua.gui').select
|
||||
|
||||
log('codelens action')
|
||||
|
||||
codelens.run()
|
||||
vim.defer_fn(function()
|
||||
vim.ui.select = original_select
|
||||
end, 1000)
|
||||
|
||||
end
|
||||
|
||||
M.inline = function()
|
||||
local lsp = vim.lsp
|
||||
if is_enabled == false then
|
||||
return
|
||||
end
|
||||
if vim.fn.getcmdwintype() == ':' then
|
||||
return
|
||||
end
|
||||
|
||||
if next(vim.lsp.buf_get_clients(0)) == nil then
|
||||
return
|
||||
end
|
||||
|
||||
local bufnr = api.nvim_get_current_buf()
|
||||
local parameter = lsp.util.make_position_params()
|
||||
|
||||
local on_codelens = vim.lsp.handlers['textDocument/codeLens']
|
||||
lsp.buf_request(bufnr, 'textDocument/codeLens', parameter, function(err, response, ctx, _)
|
||||
-- Clear previous highlighting
|
||||
api.nvim_buf_clear_namespace(bufnr, virtual_types_ns, 0, -1)
|
||||
|
||||
if response then
|
||||
trace(response)
|
||||
|
||||
on_codelens(err, response, ctx, _)
|
||||
|
||||
codelens_hdlr (err, response, ctx, _)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
return M
|
@ -0,0 +1,177 @@
|
||||
local type_to_lspkind = { c = 5, m = 7, f = 6, s = 5 }
|
||||
local util = require('navigator.util')
|
||||
local log = util.log
|
||||
local sep = util.path_sep()
|
||||
local vfn = vim.fn
|
||||
local cur_dir = vfn.getcwd()
|
||||
|
||||
-- convert ctags line to lsp entry
|
||||
local function entry_to_item(entry)
|
||||
local item = {}
|
||||
item.name, item.filename, item.line, item.remain = string.match(entry, '(.*)\t(.*)\t(%d+);(.*)')
|
||||
local type = 'combine'
|
||||
item.remain = item.remain or ''
|
||||
if item.remain:sub(1, 1) == [["]] then
|
||||
type = 'number'
|
||||
end
|
||||
if item.name == nil or item.filename == nil then
|
||||
return
|
||||
end
|
||||
|
||||
if type == 'combine' then
|
||||
-- '/^type ServerResponse struct {$/;"\ts\tpackage:client'
|
||||
item.inline, item.type, item.containerName, item.ref = string.match(item.remain, '/^(.*)$/;"\t(%a)\t(.+)')
|
||||
else
|
||||
-- '"\tm\tstruct:store.Customer\ttyperef:typename:string'
|
||||
item.type, item.containerName, item.ref = string.match(item.remain, '"\t(%a)\t(.+)')
|
||||
end
|
||||
item.kind = type_to_lspkind[item.type] or 13
|
||||
item.lnum = tonumber(item.line) - 1
|
||||
item.location = {
|
||||
uri = 'file://' .. cur_dir .. sep .. item.filename,
|
||||
range = {
|
||||
start = { line = item.lnum, character = 0 },
|
||||
['end'] = { line = item.lnum, character = 0 },
|
||||
},
|
||||
}
|
||||
|
||||
item.uri = 'file://' .. cur_dir .. sep .. item.filename
|
||||
item.range = {
|
||||
start = { line = item.lnum, character = 0 },
|
||||
['end'] = { line = item.lnum, character = 0 },
|
||||
}
|
||||
|
||||
-- item.detail = (item.containerName or '') .. (item.ref or '')
|
||||
-- item.text = '[' .. kind .. ']' .. item.name .. ' ' .. item.detail
|
||||
|
||||
if item.lnum == nil then
|
||||
vim.notify('incorrect ctags format, need run ctag with "-excmd=number|combine" option')
|
||||
end
|
||||
item.remain = nil
|
||||
return item
|
||||
end
|
||||
|
||||
local function ctags_gen()
|
||||
local cmd = 'ctags' -- -x -n -u -f - ' .. vfn.expand('%:p')
|
||||
local output = _NgConfigValues.ctags.tagfile
|
||||
-- rm file first
|
||||
util.rm_file(output)
|
||||
local options = '-R --exclude=.git --exclude=node_modules --exclude=test --exclude=vendor --excmd=number '
|
||||
if _NgConfigValues.ctags then
|
||||
cmd = _NgConfigValues.ctags.cmd
|
||||
options = _NgConfigValues.ctags.options or options
|
||||
end
|
||||
|
||||
local lang = vim.o.ft
|
||||
options = options .. '--language=' .. lang
|
||||
cmd = cmd .. ' ' .. options
|
||||
cmd = string.format('%s -f %s %s --language=%s', cmd, output, options, lang)
|
||||
cmd = vim.split(cmd, ' ')
|
||||
log(cmd)
|
||||
vfn.jobstart(cmd, {
|
||||
on_stdout = function(_, _, _)
|
||||
vim.notify('ctags completed')
|
||||
end,
|
||||
|
||||
on_exit = function(_, data, _) -- id, data, event
|
||||
-- log(vim.inspect(data) .. "exit")
|
||||
if data and data ~= 0 then
|
||||
return vim.notify(cmd .. ' failed ' .. tostring(data), vim.lsp.log_levels.ERROR)
|
||||
else
|
||||
vim.notify('ctags generated')
|
||||
end
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
local symbols_to_items = require('navigator.lspwrapper').symbols_to_items
|
||||
local function ctags_symbols()
|
||||
local height = _NgConfigValues.height or 0.4
|
||||
local width = _NgConfigValues.width or 0.7
|
||||
height = math.floor(height * vfn.winheight('%'))
|
||||
width = math.floor(vim.api.nvim_get_option('columns') * width)
|
||||
local items = {}
|
||||
local ctags_file = _NgConfigValues.ctags.tagfile
|
||||
if not util.file_exists(ctags_file) then
|
||||
ctags_gen()
|
||||
vim.cmd('sleep 200m')
|
||||
end
|
||||
local cnts = util.io_read(ctags_file)
|
||||
if cnts == nil then
|
||||
return vim.notify('ctags file ' .. ctags_file .. ' not found')
|
||||
end
|
||||
cnts = vfn.split(cnts, '\n')
|
||||
for _, value in pairs(cnts) do
|
||||
local it = entry_to_item(value)
|
||||
if it then
|
||||
table.insert(items, it)
|
||||
end
|
||||
end
|
||||
cnts = nil
|
||||
|
||||
local ft = vim.o.ft
|
||||
local result = symbols_to_items(items)
|
||||
if next(result) == nil then
|
||||
return vim.notify('no symbols found')
|
||||
end
|
||||
log(result[1])
|
||||
local opt = {
|
||||
api = ' ',
|
||||
ft = ft,
|
||||
bg = 'GuihuaListDark',
|
||||
data = result,
|
||||
items = result,
|
||||
enter = true,
|
||||
loc = 'top_center',
|
||||
transparency = 50,
|
||||
prompt = true,
|
||||
rawdata = true,
|
||||
rect = { height = height, pos_x = 0, pos_y = 0, width = width },
|
||||
}
|
||||
|
||||
require('navigator.gui').new_list_view(opt)
|
||||
end
|
||||
|
||||
-- gen_ctags()
|
||||
|
||||
local function ctags(...)
|
||||
local gen = select(1, ...)
|
||||
log(gen)
|
||||
if gen == '-g' then
|
||||
ctags_gen()
|
||||
vim.cmd('sleep 200m')
|
||||
ctags_symbols()
|
||||
else
|
||||
ctags_symbols()
|
||||
end
|
||||
end
|
||||
|
||||
local function testitem()
|
||||
local e = [[ServerResponse internal/clients/server.go /^type ServerResponse struct {$/;" s package:client]]
|
||||
local ecombine = [[ServerResponse internal/clients/server.go 5;/^type ServerResponse struct {$/;" s package:client]]
|
||||
local enumber = [[CustomerID internal/store/models.go 17;" m struct:store.Customer typeref:typename:string]]
|
||||
local enumber2 = [[CustomerDescription internal/controllers/customer.go 27;" c package:controllers]]
|
||||
local enumber3 = [[add_servers lua/navigator/lspclient/clients.lua 680;" f]]
|
||||
local i = entry_to_item(ecombine)
|
||||
print(vim.inspect(i))
|
||||
|
||||
i = entry_to_item(enumber)
|
||||
print(vim.inspect(i))
|
||||
|
||||
i = entry_to_item(enumber2)
|
||||
print(vim.inspect(i))
|
||||
|
||||
i = entry_to_item(enumber3)
|
||||
print(vim.inspect(i))
|
||||
i = entry_to_item(e)
|
||||
print(vim.inspect(i))
|
||||
end
|
||||
-- testitem()
|
||||
-- gen_ctags()
|
||||
-- ctags_symbols()
|
||||
|
||||
return {
|
||||
ctags_gen = ctags_gen,
|
||||
ctags = ctags,
|
||||
ctags_symbols = ctags_symbols,
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
local M = {}
|
||||
|
||||
function M.debounce_trailing(ms, fn)
|
||||
local timer = vim.loop.new_timer()
|
||||
return function(...)
|
||||
local argv = {...}
|
||||
timer:start(ms, 0, function()
|
||||
timer:stop()
|
||||
fn(unpack(argv))
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
function M.throttle_leading(ms, fn)
|
||||
local timer = vim.loop.new_timer()
|
||||
local running = false
|
||||
return function(...)
|
||||
if not running then
|
||||
timer:start(ms, 0, function()
|
||||
running = false
|
||||
timer:stop()
|
||||
end)
|
||||
running = true
|
||||
fn(...)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
@ -1,88 +1,557 @@
|
||||
local gui = require "navigator.gui"
|
||||
local gui = require('navigator.gui')
|
||||
local diagnostic_list = {}
|
||||
|
||||
local util = require "navigator.util"
|
||||
local diagnostic = vim.diagnostic or vim.lsp.diagnostic
|
||||
-- local hide = diagnostic.hide or diagnostic.clear
|
||||
local util = require('navigator.util')
|
||||
local log = util.log
|
||||
local trace = require('guihua.log').trace
|
||||
-- trace = log
|
||||
local error = util.error
|
||||
local path_sep = require('navigator.util').path_sep()
|
||||
local path_cur = require('navigator.util').path_cur()
|
||||
local empty = util.empty
|
||||
local api = vim.api
|
||||
_NG_VT_DIAG_NS = api.nvim_create_namespace('navigator_lua_diag')
|
||||
|
||||
if not util.nvim_0_6_1() then
|
||||
util.warn('Navigator 0.4+ only support nvim-0.6+, please use Navigator 0.3.x or a newer version of neovim')
|
||||
end
|
||||
diagnostic_list[vim.bo.filetype] = {}
|
||||
|
||||
local diag_hdlr = function(err, method, result, client_id, br, config)
|
||||
-- log(result)
|
||||
vim.lsp.diagnostic.on_publish_diagnostics(err, method, result, client_id, br, config)
|
||||
if err ~= nil then log(err, config) end
|
||||
local cwd = vim.fn.getcwd(0)
|
||||
local diag_map = {}
|
||||
if vim.diagnostic then
|
||||
diag_map = {
|
||||
Error = vim.diagnostic.severity.ERROR,
|
||||
Warning = vim.diagnostic.severity.WARN,
|
||||
Info = vim.diagnostic.severity.Info,
|
||||
Hint = vim.diagnostic.severity.Hint,
|
||||
}
|
||||
end
|
||||
|
||||
local diagnostic_cfg
|
||||
|
||||
local function get_count(bufnr, level)
|
||||
if vim.diagnostic ~= nil then
|
||||
return #diagnostic.get(bufnr, { severity = diag_map[level] })
|
||||
else
|
||||
return diagnostic.get_count(bufnr, level)
|
||||
end
|
||||
end
|
||||
|
||||
local function error_marker(result, ctx, config)
|
||||
if
|
||||
_NgConfigValues.lsp.diagnostic_scrollbar_sign == nil
|
||||
or empty(_NgConfigValues.lsp.diagnostic_scrollbar_sign)
|
||||
or _NgConfigValues.lsp.diagnostic_scrollbar_sign == false
|
||||
then -- not enabled or already shown
|
||||
return
|
||||
end
|
||||
|
||||
vim.defer_fn(function()
|
||||
if vim.tbl_isempty(result.diagnostics) then
|
||||
return
|
||||
end
|
||||
local first_line = vim.fn.line('w0')
|
||||
-- local rootfolder = vim.fn.expand('%:h:t') -- get the current file root folder
|
||||
|
||||
local bufnr = ctx.bufnr
|
||||
if bufnr == nil then
|
||||
bufnr = vim.uri_to_bufnr(result.uri)
|
||||
end
|
||||
local success, fname = pcall(api.nvim_buf_get_name, bufnr)
|
||||
if not success then
|
||||
return
|
||||
end
|
||||
local uri = vim.uri_from_fname(fname)
|
||||
if uri ~= result.uri then
|
||||
log('not same buf', ctx, result.uri, bufnr, vim.fn.bufnr())
|
||||
return
|
||||
end
|
||||
|
||||
if not api.nvim_buf_is_loaded(bufnr) then
|
||||
trace('buf not loaded', bufnr)
|
||||
return
|
||||
end
|
||||
|
||||
trace('schedule callback', result, ctx, config)
|
||||
trace('total diag ', #result.diagnostics, bufnr)
|
||||
|
||||
if result == nil or result.diagnostics == nil or #result.diagnostics == 0 then
|
||||
local diag_cnt = get_count(bufnr, [[Error]]) + get_count(bufnr, [[Warning]])
|
||||
if diag_cnt == 0 and _NG_VT_DIAG_NS ~= nil then
|
||||
log('great no errors')
|
||||
api.nvim_buf_clear_namespace(bufnr, _NG_VT_DIAG_NS, 0, -1)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
-- total line num of current buffer
|
||||
|
||||
-- local winid = vim.fn.win_getid(vim.fn.winnr())
|
||||
-- local winid = api.nvim_get_current_win()
|
||||
local total_num = api.nvim_buf_line_count(bufnr)
|
||||
-- local total_num = vim.fn.getbufinfo(vim.fn.winbufnr(winid))[1].linecount
|
||||
-- window size of current buffer
|
||||
|
||||
local stats = api.nvim_list_uis()[1]
|
||||
-- local wwidth = stats.width;
|
||||
local wheight = stats.height
|
||||
|
||||
if total_num <= wheight then
|
||||
return
|
||||
end
|
||||
if _NG_VT_DIAG_NS == nil then
|
||||
_NG_VT_DIAG_NS = api.nvim_create_namespace('navigator_lua_diag')
|
||||
end
|
||||
|
||||
local pos = {}
|
||||
local diags = result.diagnostics
|
||||
|
||||
for i, _ in ipairs(diags) do
|
||||
if not diags[i].range then
|
||||
diags[i].range = { start = { line = diags[i].lnum } }
|
||||
end
|
||||
end
|
||||
|
||||
table.sort(diags, function(a, b)
|
||||
return a.range.start.line < b.range.start.line
|
||||
end)
|
||||
-- pos of virtual text
|
||||
for _, diag in pairs(result.diagnostics) do
|
||||
local p
|
||||
if not diag.range then
|
||||
diag.range = { start = { line = diag.lnum } }
|
||||
end
|
||||
if diag.range and diag.range.start and diag.range.start.line then
|
||||
p = diag.range.start.line
|
||||
p = util.round(p * wheight / math.max(wheight, total_num))
|
||||
if pos[#pos] and pos[#pos].line == p then
|
||||
local bar = _NgConfigValues.lsp.diagnostic_scrollbar_sign[2]
|
||||
if pos[#pos] == bar then
|
||||
bar = _NgConfigValues.lsp.diagnostic_scrollbar_sign[3]
|
||||
end
|
||||
pos[#pos] = { line = p, sign = bar, severity = math.min(diag.severity, pos[#pos].severity) }
|
||||
else
|
||||
table.insert(pos, {
|
||||
line = p,
|
||||
sign = _NgConfigValues.lsp.diagnostic_scrollbar_sign[1],
|
||||
severity = diag.severity,
|
||||
})
|
||||
end
|
||||
end
|
||||
trace('pos, line:', p, diag.severity, diag.range)
|
||||
end
|
||||
|
||||
if not vim.tbl_isempty(pos) then
|
||||
api.nvim_buf_clear_namespace(bufnr, _NG_VT_DIAG_NS, 0, -1)
|
||||
end
|
||||
for _, s in pairs(pos) do
|
||||
local hl = 'ErrorMsg'
|
||||
if type(s.severity) == 'number' then
|
||||
if s.severity == 2 then
|
||||
hl = 'WarningMsg'
|
||||
elseif s.severity >= 3 then
|
||||
hl = 'DiagnosticInfo'
|
||||
end
|
||||
elseif type(s.severity) == 'string' then
|
||||
if s.severity:lower() == 'warn' then
|
||||
hl = 'WarningMsg'
|
||||
end
|
||||
end
|
||||
local l = s.line + first_line
|
||||
if l > total_num then
|
||||
l = total_num
|
||||
end
|
||||
trace('add pos', s, bufnr)
|
||||
|
||||
api.nvim_buf_set_extmark(
|
||||
bufnr,
|
||||
_NG_VT_DIAG_NS,
|
||||
l,
|
||||
-1,
|
||||
{ virt_text = { { s.sign, hl } }, virt_text_pos = 'right_align' }
|
||||
)
|
||||
end
|
||||
end, 10) -- defer in 10ms
|
||||
end
|
||||
|
||||
local update_err_marker_async = function()
|
||||
local debounce = require('navigator.debounce').debounce_trailing
|
||||
return debounce(400, error_marker)
|
||||
end
|
||||
|
||||
local diag_hdlr = function(err, result, ctx, config)
|
||||
require('navigator.lspclient.highlight').diagnositc_config_sign()
|
||||
config = config or diagnostic_cfg
|
||||
if err ~= nil then
|
||||
log(err, config, result)
|
||||
return
|
||||
end
|
||||
|
||||
local mode = api.nvim_get_mode().mode
|
||||
if mode ~= 'n' and config.update_in_insert == false then
|
||||
trace('skip sign update in insert mode')
|
||||
end
|
||||
local cwd = vim.loop.cwd()
|
||||
local ft = vim.bo.filetype
|
||||
if diagnostic_list[ft] == nil then diagnostic_list[vim.bo.filetype] = {} end
|
||||
-- vim.lsp.diagnostic.clear(vim.fn.bufnr(), client.id, nil, nil)
|
||||
if diagnostic_list[ft] == nil then
|
||||
diagnostic_list[vim.bo.filetype] = {}
|
||||
end
|
||||
|
||||
local client_id = ctx.client_id
|
||||
local bufnr = ctx.bufnr or 0
|
||||
if result.diagnostics ~= nil and result.diagnostics ~= {} then
|
||||
trace('diagnostic', result.diagnostics, ctx, config)
|
||||
end
|
||||
|
||||
trace(err, result, ctx, config)
|
||||
vim.lsp.diagnostic.on_publish_diagnostics(err, result, ctx, config)
|
||||
local uri = result.uri
|
||||
|
||||
local diag_cnt = get_count(bufnr, [[Error]]) + get_count(bufnr, [[Warning]])
|
||||
|
||||
if empty(result.diagnostics) and diag_cnt > 0 then
|
||||
trace('no result? ', diag_cnt)
|
||||
return
|
||||
end
|
||||
-- trace("diag: ", mode, result, ctx, config)
|
||||
if result and result.diagnostics then
|
||||
local item_list = {}
|
||||
|
||||
for _, v in ipairs(result.diagnostics) do
|
||||
local item = v
|
||||
item.filename = assert(vim.uri_to_fname(uri))
|
||||
item.display_filename = item.filename:gsub(cwd .. "/", "./", 1)
|
||||
item.display_filename = item.filename:gsub(cwd .. path_sep, path_cur, 1)
|
||||
item.lnum = v.range.start.line + 1
|
||||
item.col = v.range.start.character + 1
|
||||
item.uri = uri
|
||||
local head = "🐛"
|
||||
if v.severity == 1 then head = "🈲" end
|
||||
if v.severity == 2 then head = "☣️" end
|
||||
if v.severity > 2 then head = "👎" end
|
||||
local bufnr = vim.uri_to_bufnr(uri)
|
||||
vim.fn.bufload(bufnr)
|
||||
local pos = v.range.start
|
||||
local row = pos.line
|
||||
local line = (vim.api.nvim_buf_get_lines(bufnr, row, row + 1, false) or {""})[1]
|
||||
item.text = head .. line .. " 📛 " .. v.message
|
||||
-- trace(item)
|
||||
local head = _NgConfigValues.icons.diagnostic_head
|
||||
if v.severity then
|
||||
if v.severity == 1 then
|
||||
head = _NgConfigValues.icons.diagnostic_head_severity_1
|
||||
end
|
||||
if v.severity == 2 then
|
||||
head = _NgConfigValues.icons.diagnostic_head_severity_2
|
||||
end
|
||||
if v.severity > 2 then
|
||||
head = _NgConfigValues.icons.diagnostic_head_severity_3
|
||||
end
|
||||
else
|
||||
v.severity = 2
|
||||
end
|
||||
if v.relatedInformation and v.relatedInformation[1] then
|
||||
local info = v.relatedInformation[1]
|
||||
-- trace(info)
|
||||
if info.message then
|
||||
v.releated_msg = info.message
|
||||
end
|
||||
if info.location and info.location.range then
|
||||
v.releated_lnum = info.location.range.start.line
|
||||
end
|
||||
end
|
||||
local bufnr1 = vim.uri_to_bufnr(uri)
|
||||
local loaded = api.nvim_buf_is_loaded(bufnr1)
|
||||
if _NgConfigValues.diagnostic_load_files then
|
||||
-- print('load buffers')
|
||||
if not loaded then
|
||||
vim.fn.bufload(bufnr1) -- this may slow down the neovim
|
||||
end
|
||||
local pos = v.range.start
|
||||
local row = pos.line
|
||||
local line = (api.nvim_buf_get_lines(bufnr1, row, row + 1, false) or { '' })[1]
|
||||
if line ~= nil then
|
||||
item.text = head .. line .. _NgConfigValues.icons.diagnostic_head_description .. v.message
|
||||
else
|
||||
error('diagnostic result empty line', v, row, bufnr1)
|
||||
end
|
||||
else
|
||||
item.text = head .. _NgConfigValues.icons.diagnostic_head_description .. v.message
|
||||
end
|
||||
|
||||
if v.releated_msg then
|
||||
item.text = item.text .. '; ' .. item.releated_msg
|
||||
end
|
||||
|
||||
if v.releated_lnum then
|
||||
item.text = item.text .. ':' .. tostring(item.releated_lnum)
|
||||
end
|
||||
|
||||
table.insert(item_list, item)
|
||||
end
|
||||
-- local old_items = vim.fn.getqflist()
|
||||
diagnostic_list[ft][uri] = item_list
|
||||
if diagnostic_list[ft][uri] == nil then
|
||||
diagnostic_list[ft][uri] = {}
|
||||
end
|
||||
diagnostic_list[ft][uri][tostring(client_id)] = item_list
|
||||
trace(uri, ft, diagnostic_list)
|
||||
if not result.uri then
|
||||
result.uri = uri
|
||||
end
|
||||
|
||||
local marker = update_err_marker_async()
|
||||
marker(result, ctx, config)
|
||||
else
|
||||
trace('great, no diag errors')
|
||||
api.nvim_buf_clear_namespace(0, _NG_VT_DIAG_NS, 0, -1)
|
||||
_NG_VT_DIAG_NS = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- local diag_hdlr_async = function()
|
||||
-- local debounce = require('navigator.debounce').debounce_trailing
|
||||
-- return debounce(100, diag_hdlr)
|
||||
-- end
|
||||
|
||||
local M = {}
|
||||
-- vim.lsp.handlers["textDocument/publishDiagnostics"] =
|
||||
M.diagnostic_handler = vim.lsp.with(diag_hdlr, {
|
||||
-- Enable underline, use default values
|
||||
underline = true,
|
||||
-- Enable virtual text, override spacing to 0
|
||||
virtual_text = {
|
||||
spacing = 0,
|
||||
prefix = "🦊" -- ' ,
|
||||
},
|
||||
-- Use a function to dynamically turn signs off
|
||||
-- and on, using buffer local variables
|
||||
signs = true,
|
||||
-- Disable a feature
|
||||
update_in_insert = false
|
||||
})
|
||||
|
||||
M.show_diagnostic = function()
|
||||
vim.lsp.diagnostic.get_all()
|
||||
|
||||
local bufs = vim.api.nvim_list_bufs()
|
||||
for _, buf in ipairs(bufs) do
|
||||
local bname = vim.fn.bufname(buf)
|
||||
if #bname > 0 and not util.exclude(bname) then
|
||||
if vim.api.nvim_buf_is_loaded(buf) then vim.lsp.diagnostic.get(buf, nil) end
|
||||
end
|
||||
function M.setup()
|
||||
if diagnostic_cfg ~= nil and diagnostic_cfg.float ~= nil then
|
||||
return
|
||||
end
|
||||
diagnostic_cfg = {
|
||||
-- Enable underline, use default values
|
||||
underline = _NgConfigValues.lsp.diagnostic.underline,
|
||||
-- Enable virtual
|
||||
-- Use a function to dynamically turn signs off
|
||||
-- and on, using buffer local variables
|
||||
signs = true,
|
||||
update_in_insert = _NgConfigValues.lsp.diagnostic.update_in_insert or false,
|
||||
severity_sort = _NgConfigValues.lsp.diagnostic.severity_sort,
|
||||
float = {
|
||||
focusable = false,
|
||||
style = 'minimal',
|
||||
border = 'rounded',
|
||||
source = 'always',
|
||||
header = '',
|
||||
prefix = '',
|
||||
},
|
||||
}
|
||||
diagnostic_cfg.virtual_text = _NgConfigValues.lsp.diagnostic.virtual_text
|
||||
if type(_NgConfigValues.lsp.diagnostic.virtual_text) == 'table' then
|
||||
diagnostic_cfg.virtual_text.prefix = _NgConfigValues.icons.diagnostic_virtual_text
|
||||
end
|
||||
-- vim.lsp.handlers["textDocument/publishDiagnostics"]
|
||||
M.diagnostic_handler = vim.lsp.with(diag_hdlr, diagnostic_cfg)
|
||||
|
||||
vim.diagnostic.config(diagnostic_cfg)
|
||||
|
||||
if _NgConfigValues.lsp.diagnostic_scrollbar_sign then
|
||||
api.nvim_create_autocmd({ 'WinScrolled' }, {
|
||||
group = api.nvim_create_augroup('NGWinScrolledGroup', {}),
|
||||
pattern = '*',
|
||||
callback = function()
|
||||
require('navigator.diagnostics').update_err_marker()
|
||||
end,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
local function clear_diag_VT(bufnr) -- important for clearing out when no more errors
|
||||
bufnr = bufnr or api.nvim_get_current_buf()
|
||||
log(bufnr, _NG_VT_DIAG_NS)
|
||||
if _NG_VT_DIAG_NS == nil then
|
||||
return
|
||||
end
|
||||
|
||||
api.nvim_buf_clear_namespace(bufnr, _NG_VT_DIAG_NS, 0, -1)
|
||||
_NG_VT_DIAG_NS = nil
|
||||
end
|
||||
|
||||
M.hide_diagnostic = function()
|
||||
if _NG_VT_DIAG_NS then
|
||||
clear_diag_VT()
|
||||
end
|
||||
end
|
||||
|
||||
M.toggle_diagnostics = function()
|
||||
if M.diagnostic_enabled then
|
||||
M.diagnostic_enabled = false
|
||||
return vim.diagnostic.disable()
|
||||
end
|
||||
vim.diagnostic.enable()
|
||||
M.diagnostic_enabled = true
|
||||
end
|
||||
|
||||
M.show_buf_diagnostics = function()
|
||||
if diagnostic_list[vim.bo.filetype] ~= nil then
|
||||
-- log(diagnostic_list[vim.bo.filetype])
|
||||
-- vim.fn.setqflist({}, " ", {title = "LSP", items = diagnostic_list[vim.bo.filetype]})
|
||||
local results = diagnostic_list[vim.bo.filetype]
|
||||
local display_items = {}
|
||||
for _, items in pairs(results) do
|
||||
for _, it in pairs(items) do table.insert(display_items, it) end
|
||||
for _, client_items in pairs(results) do
|
||||
for _, items in pairs(client_items) do
|
||||
for _, it in pairs(items) do
|
||||
table.insert(display_items, it)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- log(display_items)
|
||||
if #display_items > 0 then
|
||||
gui.new_list_view({items = display_items, api = "🚑🐛 Diagnostic "})
|
||||
local listview = gui.new_list_view({
|
||||
items = display_items,
|
||||
api = _NgConfigValues.icons.diagnostic_file .. _NgConfigValues.icons.diagnostic_head .. ' Diagnostic ',
|
||||
enable_preview_edit = true,
|
||||
})
|
||||
if listview == nil then
|
||||
return log('nil listview')
|
||||
end
|
||||
trace('new buffer', listview.bufnr)
|
||||
if listview.bufnr then
|
||||
api.nvim_buf_add_highlight(listview.bufnr, -1, 'Title', 0, 0, -1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- set loc list win
|
||||
M.set_diag_loclist = function(bufnr)
|
||||
bufnr = bufnr or api.nvim_get_current_buf()
|
||||
local diag_cnt = get_count(bufnr, [[Error]]) + get_count(bufnr, [[Warning]])
|
||||
if diag_cnt == 0 then
|
||||
log('great, no errors!')
|
||||
return
|
||||
end
|
||||
|
||||
local clients = vim.lsp.buf_get_clients(bufnr)
|
||||
local cfg = { open = diag_cnt > 0 }
|
||||
for _, client in pairs(clients) do
|
||||
cfg.client_id = client['id']
|
||||
break
|
||||
end
|
||||
|
||||
if not vim.tbl_isempty(vim.lsp.buf_get_clients(bufnr)) then
|
||||
local err_cnt = get_count(0, [[Error]])
|
||||
if err_cnt > 0 and _NgConfigValues.lsp.disply_diagnostic_qf then
|
||||
if diagnostic.set_loclist then
|
||||
diagnostic.set_loclist(cfg)
|
||||
else
|
||||
cfg.namespaces = diagnostic.get_namespaces()
|
||||
diagnostic.setloclist(cfg)
|
||||
end
|
||||
else
|
||||
vim.cmd('lclose')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- TODO: callback when scroll
|
||||
function M.update_err_marker()
|
||||
trace('update err marker', _NG_VT_DIAG_NS)
|
||||
if _NG_VT_DIAG_NS == nil then
|
||||
-- nothing to update
|
||||
return
|
||||
end
|
||||
local bufnr = api.nvim_get_current_buf()
|
||||
|
||||
local diag_cnt = get_count(bufnr, [[Error]])
|
||||
+ get_count(bufnr, [[Warning]])
|
||||
+ get_count(bufnr, [[Info]])
|
||||
+ get_count(bufnr, [[Hint]])
|
||||
|
||||
-- redraw
|
||||
if diag_cnt == 0 and _NG_VT_DIAG_NS ~= nil then
|
||||
api.nvim_buf_clear_namespace(bufnr, _NG_VT_DIAG_NS, 0, -1)
|
||||
trace('no errors')
|
||||
return
|
||||
end
|
||||
|
||||
api.nvim_buf_clear_namespace(bufnr, _NG_VT_DIAG_NS, 0, -1)
|
||||
local errors = diagnostic.get(bufnr)
|
||||
if #errors == 0 then
|
||||
trace('no errors', errors)
|
||||
return
|
||||
end
|
||||
local uri = vim.uri_from_bufnr(bufnr)
|
||||
local result = { diagnostics = errors, uri = errors[1].uri or uri }
|
||||
|
||||
trace(result)
|
||||
local marker = update_err_marker_async()
|
||||
marker(result, { bufnr = bufnr, method = 'textDocument/publishDiagnostics' })
|
||||
end
|
||||
|
||||
function M.get_line_diagnostic()
|
||||
local lnum = api.nvim_win_get_cursor(0)[1] - 1
|
||||
local diags = diagnostic.get(api.nvim_get_current_buf(), { lnum = lnum })
|
||||
|
||||
table.sort(diags, function(diag1, diag2)
|
||||
return diag1.severity < diag2.severity
|
||||
end)
|
||||
return diags
|
||||
end
|
||||
|
||||
function M.show_diagnostics(pos)
|
||||
local bufnr = api.nvim_get_current_buf()
|
||||
|
||||
local lnum, col = unpack(api.nvim_win_get_cursor(0))
|
||||
lnum = lnum - 1
|
||||
local opt = { border = 'single', severity_sort = true }
|
||||
|
||||
if pos ~= nil and type(pos) == 'number' then
|
||||
opt.scope = 'buffer'
|
||||
else
|
||||
if pos == true then
|
||||
opt.scope = 'cursor'
|
||||
else
|
||||
opt.scope = 'line'
|
||||
end
|
||||
end
|
||||
|
||||
local diags = M.get_line_diagnostic()
|
||||
if diags == nil or next(diags) == nil then
|
||||
return
|
||||
end
|
||||
local diag1 = diags[1]
|
||||
opt.offset_x = -1 * (col - diag1.col)
|
||||
diagnostic.open_float(bufnr, opt)
|
||||
end
|
||||
|
||||
function M.treesitter_and_diag_panel()
|
||||
local Panel = require('guihua.panel')
|
||||
|
||||
local ft = vim.bo.filetype
|
||||
local results = diagnostic_list[ft]
|
||||
log(diagnostic_list, ft)
|
||||
|
||||
local bufnr = api.nvim_get_current_buf()
|
||||
local p = Panel:new({
|
||||
header = 'treesitter',
|
||||
render = function(b)
|
||||
log('render for ', bufnr, b)
|
||||
return require('navigator.treesitter').all_ts_nodes(b)
|
||||
end,
|
||||
})
|
||||
p:add_section({
|
||||
header = 'diagnostic',
|
||||
render = function(buf)
|
||||
log(buf, diagnostic)
|
||||
if diagnostic_list[ft] ~= nil then
|
||||
local display_items = {}
|
||||
for _, client_items in pairs(results) do
|
||||
for _, items in pairs(client_items) do
|
||||
for _, it in pairs(items) do
|
||||
log(it)
|
||||
table.insert(display_items, it)
|
||||
end
|
||||
end
|
||||
end
|
||||
return display_items
|
||||
else
|
||||
return {}
|
||||
end
|
||||
end,
|
||||
})
|
||||
p:open(true)
|
||||
end
|
||||
|
||||
function M.config(cfg)
|
||||
M.setup()
|
||||
cfg = cfg or {}
|
||||
log('diag config', cfg)
|
||||
local default_cfg = {
|
||||
underline = true,
|
||||
virtual_text = true,
|
||||
signs = { _NgConfigValues.icons.diagnostic_err },
|
||||
update_in_insert = false,
|
||||
}
|
||||
cfg = vim.tbl_extend('keep', cfg, default_cfg)
|
||||
vim.diagnostic.config(cfg)
|
||||
end
|
||||
|
||||
return M
|
||||
|
@ -0,0 +1,163 @@
|
||||
local log = require('navigator.util').log
|
||||
|
||||
local lsp = vim.lsp
|
||||
local api = vim.api
|
||||
|
||||
local M = {}
|
||||
|
||||
-- TODO: per-buffer fold table?
|
||||
M.current_buf_folds = {}
|
||||
|
||||
-- Informative table keeping track of language servers that implement textDocument/foldingRange.
|
||||
-- Not used at runtime (capability is resolved dynamically)
|
||||
M.servers_supporting_folding = {
|
||||
pylsp = true,
|
||||
pyright = false,
|
||||
sumneko_lua = true,
|
||||
texlab = true,
|
||||
clangd = false,
|
||||
gopls = true,
|
||||
julials = false,
|
||||
}
|
||||
|
||||
M.active_folding_clients = {}
|
||||
|
||||
function M.on_attach()
|
||||
M.setup_plugin()
|
||||
M.update_folds()
|
||||
end
|
||||
|
||||
function M.setup_plugin()
|
||||
local cmd_group = api.nvim_create_augroup('NGFoldGroup', {})
|
||||
api.nvim_create_autocmd({ 'BufEnter', 'BufWritePost' }, {
|
||||
group = cmd_group,
|
||||
pattern = '*',
|
||||
callback = function()
|
||||
require('navigator.foldlsp').update_folds()
|
||||
end,
|
||||
})
|
||||
|
||||
local clients = vim.lsp.buf_get_clients(0)
|
||||
|
||||
for _, client in pairs(clients) do
|
||||
local client_id = client['id']
|
||||
if M.active_folding_clients[client_id] == nil then
|
||||
local server_supports_folding = client['server_capabilities']['foldingRangeProvider'] or false
|
||||
-- if not server_supports_folding then
|
||||
-- api.nvim_command(string.format('echom "lsp-folding: %s does not provide folding requests"',
|
||||
-- client['name']))
|
||||
-- end
|
||||
|
||||
M.active_folding_clients[client_id] = server_supports_folding
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function M.update_folds()
|
||||
local current_window = api.nvim_get_current_win()
|
||||
local in_diff_mode = api.nvim_win_get_option(current_window, 'diff')
|
||||
if in_diff_mode then
|
||||
-- In diff mode, use diff folding.
|
||||
api.nvim_win_set_option(current_window, 'foldmethod', 'diff')
|
||||
else
|
||||
local clients = lsp.buf_get_clients(0)
|
||||
for client_id, client in pairs(clients) do
|
||||
if M.active_folding_clients[client_id] then
|
||||
-- XXX: better to pass callback in this method or add it directly in the config?
|
||||
-- client.config.callbacks['textDocument/foldingRange'] = M.fold_handler
|
||||
local current_bufnr = api.nvim_get_current_buf()
|
||||
local params = { uri = vim.uri_from_bufnr(current_bufnr) }
|
||||
client.request('textDocument/foldingRange', { textDocument = params }, M.fold_handler, current_bufnr)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function M.debug_folds()
|
||||
for _, table in ipairs(M.current_buf_folds) do
|
||||
local start_line = table['startLine']
|
||||
local end_line = table['endLine']
|
||||
log('startline', start_line, 'endline', end_line)
|
||||
end
|
||||
end
|
||||
|
||||
M.fold_handler = function(err, result, ctx, _)
|
||||
-- params: err, method, result, client_id, bufnr
|
||||
-- XXX: handle err?
|
||||
if err or result == nil or #result == 0 then
|
||||
vim.notify(string.format('%s %s ', tostring(err), vim.inspect(ctx)), vim.lsp.log_levels.WARN)
|
||||
return
|
||||
end
|
||||
M.debug_folds()
|
||||
local current_bufnr = api.nvim_get_current_buf()
|
||||
-- Discard the folding result if buffer focus has changed since the request was
|
||||
-- done.
|
||||
if current_bufnr == ctx.bufnr then
|
||||
for _, fold in ipairs(result) do
|
||||
fold['startLine'] = M.adjust_foldstart(fold['startLine'])
|
||||
fold['endLine'] = M.adjust_foldend(fold['endLine'])
|
||||
end
|
||||
table.sort(result, function(a, b)
|
||||
return a['startLine'] < b['startLine']
|
||||
end)
|
||||
M.current_buf_folds = result
|
||||
local current_window = api.nvim_get_current_win()
|
||||
api.nvim_win_set_option(current_window, 'foldmethod', 'expr')
|
||||
api.nvim_win_set_option(current_window, 'foldexpr', 'foldlsp#foldexpr()')
|
||||
end
|
||||
end
|
||||
|
||||
function M.adjust_foldstart(line_no)
|
||||
return line_no + 1
|
||||
end
|
||||
|
||||
function M.adjust_foldend(line_no)
|
||||
local bufnr = api.nvim_get_current_buf()
|
||||
local filetype = api.nvim_buf_get_option(bufnr, 'filetype')
|
||||
if filetype == 'lua' then
|
||||
return line_no + 2
|
||||
else
|
||||
return line_no + 1
|
||||
end
|
||||
end
|
||||
|
||||
function M.get_fold_indic(lnum)
|
||||
local fold_level = 0
|
||||
local is_foldstart = false
|
||||
local is_foldend = false
|
||||
|
||||
for _, table in ipairs(M.current_buf_folds) do
|
||||
local start_line = table['startLine']
|
||||
local end_line = table['endLine']
|
||||
|
||||
-- can exit early b/c folds get pre-orderered manually
|
||||
if lnum < start_line then
|
||||
break
|
||||
end
|
||||
|
||||
if lnum >= start_line and lnum <= end_line then
|
||||
fold_level = fold_level + 1
|
||||
if lnum == start_line then
|
||||
is_foldstart = true
|
||||
end
|
||||
if lnum == end_line then
|
||||
is_foldend = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if is_foldend and is_foldstart then
|
||||
-- If line marks both start and end of folds (like ``else`` statement),
|
||||
-- merge the two folds into one by returning the current foldlevel
|
||||
-- without any marker.
|
||||
return fold_level
|
||||
elseif is_foldstart then
|
||||
return string.format('>%d', fold_level)
|
||||
elseif is_foldend then
|
||||
return string.format('<%d', fold_level)
|
||||
else
|
||||
return fold_level
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
@ -0,0 +1,243 @@
|
||||
-- NOTE: this file is a modified version of fold.lua from nvim-treesitter
|
||||
|
||||
local log = require('navigator.util').log
|
||||
local trace = require('navigator.util').trace
|
||||
local api = vim.api
|
||||
local tsutils = require('nvim-treesitter.ts_utils')
|
||||
local query = require('nvim-treesitter.query')
|
||||
local parsers = require('nvim-treesitter.parsers')
|
||||
local get_node_at_line = require('navigator.treesitter').get_node_at_line
|
||||
local M = {}
|
||||
|
||||
-- TODO: per-buffer fold table?
|
||||
M.current_buf_folds = {}
|
||||
|
||||
function M.on_attach()
|
||||
M.setup_fold()
|
||||
-- M.update_folds()
|
||||
end
|
||||
|
||||
function NG_custom_fold_text()
|
||||
local line = vim.fn.getline(vim.v.foldstart)
|
||||
local line_count = vim.v.foldend - vim.v.foldstart + 1
|
||||
-- log("" .. line .. " // " .. line_count .. " lines")
|
||||
local ss, se = line:find('^%s*')
|
||||
local spaces = line:sub(ss, se)
|
||||
local tabspace = string.rep(' ', vim.o.tabstop)
|
||||
spaces = spaces:gsub('\t', tabspace)
|
||||
line = line:gsub('^%s*(.-)%s*$', '%1')
|
||||
return spaces .. '⚡' .. line .. ': ' .. line_count .. ' lines'
|
||||
end
|
||||
|
||||
vim.opt.foldtext = NG_custom_fold_text()
|
||||
vim.opt.fillchars = { eob = '-', fold = ' ' }
|
||||
|
||||
vim.opt.viewoptions:remove('options')
|
||||
|
||||
function M.setup_fold()
|
||||
api.nvim_command('augroup FoldingCommand')
|
||||
api.nvim_command('autocmd! * <buffer>')
|
||||
api.nvim_command('augroup end')
|
||||
vim.opt.foldtext = 'v:lua.NG_custom_fold_text()'
|
||||
vim.opt.fillchars = { eob = '-', fold = ' ' }
|
||||
vim.opt.viewoptions:remove('options')
|
||||
|
||||
local current_window = api.nvim_get_current_win()
|
||||
if not parsers.has_parser() then
|
||||
api.nvim_win_set_option(current_window, 'foldmethod', 'indent')
|
||||
log('fallback to indent folding')
|
||||
return
|
||||
end
|
||||
log('setup treesitter folding')
|
||||
api.nvim_win_set_option(current_window, 'foldmethod', 'expr')
|
||||
api.nvim_win_set_option(current_window, 'foldexpr', 'folding#ngfoldexpr()')
|
||||
end
|
||||
|
||||
local function get_fold_level(levels, lnum)
|
||||
local prev_l = levels[lnum]
|
||||
local prev_ln
|
||||
if prev_l:find('>') then
|
||||
prev_ln = tonumber(prev_l:sub(2))
|
||||
else
|
||||
prev_ln = tonumber(prev_l)
|
||||
end
|
||||
return prev_ln
|
||||
end
|
||||
|
||||
-- This is cached on buf tick to avoid computing that multiple times
|
||||
-- Especially not for every line in the file when `zx` is hit
|
||||
local folds_levels = tsutils.memoize_by_buf_tick(function(bufnr)
|
||||
local max_fold_level = api.nvim_win_get_option(0, 'foldnestmax')
|
||||
local trim_level = function(level)
|
||||
if level > max_fold_level then
|
||||
return max_fold_level
|
||||
end
|
||||
return level
|
||||
end
|
||||
|
||||
local parser = parsers.get_parser(bufnr)
|
||||
|
||||
if not parser then
|
||||
log('treesitter parser not loaded')
|
||||
return {}
|
||||
end
|
||||
|
||||
local matches = query.get_capture_matches_recursively(bufnr, function(lang)
|
||||
if query.has_folds(lang) then
|
||||
return '@fold', 'folds'
|
||||
elseif query.has_locals(lang) then
|
||||
return '@scope', 'locals'
|
||||
end
|
||||
end)
|
||||
|
||||
-- start..stop is an inclusive range
|
||||
local start_counts = {}
|
||||
local stop_counts = {}
|
||||
|
||||
local prev_start = -1
|
||||
local prev_stop = -1
|
||||
|
||||
local min_fold_lines = api.nvim_win_get_option(0, 'foldminlines')
|
||||
|
||||
for _, node in ipairs(matches) do
|
||||
local start, _, stop, stop_col = node.node:range()
|
||||
|
||||
if stop_col == 0 then
|
||||
stop = stop - 1
|
||||
end
|
||||
|
||||
local fold_length = stop - start + 1
|
||||
local should_fold = fold_length > min_fold_lines
|
||||
|
||||
-- Fold only multiline nodes that are not exactly the same as previously met folds
|
||||
-- Checking against just the previously found fold is sufficient if nodes
|
||||
-- are returned in preorder or postorder when traversing tree
|
||||
if should_fold and not (start == prev_start and stop == prev_stop) then
|
||||
start_counts[start] = (start_counts[start] or 0) + 1
|
||||
stop_counts[stop] = (stop_counts[stop] or 0) + 1
|
||||
prev_start = start
|
||||
prev_stop = stop
|
||||
end
|
||||
end
|
||||
trace(start_counts)
|
||||
trace(stop_counts)
|
||||
|
||||
local levels = {}
|
||||
local current_level = 0
|
||||
|
||||
-- We now have the list of fold opening and closing, fill the gaps and mark where fold start
|
||||
local pre_node
|
||||
for lnum = 0, api.nvim_buf_line_count(bufnr) do
|
||||
local node, _ = get_node_at_line(lnum + 1)
|
||||
local comment = node:type() == 'comment'
|
||||
|
||||
local next_node, _ = get_node_at_line(lnum + 1)
|
||||
local next_comment = node and node:type() == 'comment'
|
||||
local last_trimmed_level = trim_level(current_level)
|
||||
current_level = current_level + (start_counts[lnum] or 0)
|
||||
local trimmed_level = trim_level(current_level)
|
||||
local current_level2 = current_level - (stop_counts[lnum] or 0)
|
||||
local next_trimmed_level = trim_level(current_level2)
|
||||
|
||||
trace(lnum, node:type(), node, last_trimmed_level, trimmed_level, next_trimmed_level)
|
||||
if comment then
|
||||
trace('comment node', trimmed_level)
|
||||
-- if trimmed_level == 0 then
|
||||
-- trimmed_level = 1
|
||||
-- end
|
||||
|
||||
levels[lnum + 1] = tostring(trimmed_level + 2)
|
||||
if pre_node and pre_node:type() ~= 'comment' then
|
||||
levels[lnum + 1] = '>' .. tostring(trimmed_level + 2)
|
||||
end
|
||||
if next_node and next_node:type() ~= 'comment' then
|
||||
levels[lnum + 1] = tostring(trimmed_level + 1)
|
||||
end
|
||||
else
|
||||
-- Determine if it's the start/end of a fold
|
||||
-- NB: vim's fold-expr interface does not have a mechanism to indicate that
|
||||
-- two (or more) folds start at this line, so it cannot distinguish between
|
||||
-- ( \n ( \n )) \n (( \n ) \n )
|
||||
-- versus
|
||||
-- ( \n ( \n ) \n ( \n ) \n )
|
||||
-- If it did have such a mechansim, (trimmed_level - last_trimmed_level)
|
||||
-- would be the correct number of starts to pass on.
|
||||
if trimmed_level - last_trimmed_level > 0 then
|
||||
if levels[lnum + 1] ~= '>' .. tostring(trimmed_level) then
|
||||
levels[lnum + 1] = tostring(trimmed_level) -- hack do not fold current line as it is first in fold range
|
||||
end
|
||||
levels[lnum + 2] = '>' .. tostring(trimmed_level + 1) -- dirty hack fold start from next line
|
||||
trace('fold start')
|
||||
elseif trimmed_level - next_trimmed_level > 0 then -- last line in fold range
|
||||
-- Ending marks tend to confuse vim more than it helps, particularly when
|
||||
-- the fold level changes by at least 2; we can uncomment this if
|
||||
-- vim's behavior gets fixed.
|
||||
|
||||
trace('fold end')
|
||||
if levels[lnum + 1] then
|
||||
trace('already set reset as fold is ending', levels[lnum + 1])
|
||||
levels[lnum + 1] = tostring(trimmed_level + 1)
|
||||
else
|
||||
local prev_ln = get_fold_level(levels, lnum) - 1
|
||||
if prev_ln == 0 then
|
||||
prev_ln = 1
|
||||
end
|
||||
levels[lnum + 1] = tostring(prev_ln)
|
||||
end
|
||||
-- levels[lnum + 1] = tostring(trimmed_level + 1)
|
||||
-- else
|
||||
current_level = current_level - 1
|
||||
else
|
||||
trace('same')
|
||||
if pre_node and pre_node:type() == 'comment' then
|
||||
local prev_ln = get_fold_level(levels, lnum) - 1
|
||||
levels[lnum + 1] = tostring(prev_ln)
|
||||
else
|
||||
local n = math.max(trimmed_level, 1)
|
||||
if lnum > 1 then
|
||||
if levels[lnum + 1] then
|
||||
trace('already set', levels[lnum + 1])
|
||||
else
|
||||
local prev_l = levels[lnum]
|
||||
if prev_l:find('>') then
|
||||
levels[lnum + 1] = prev_l:sub(2)
|
||||
else
|
||||
levels[lnum + 1] = prev_l
|
||||
end
|
||||
end
|
||||
else
|
||||
levels[lnum + 1] = tostring(n)
|
||||
end
|
||||
end
|
||||
end
|
||||
trace(levels)
|
||||
end
|
||||
pre_node = node
|
||||
end
|
||||
trace(levels)
|
||||
return levels
|
||||
end)
|
||||
|
||||
function M.get_fold_indic(lnum)
|
||||
if not parsers.has_parser() or not lnum then
|
||||
return '0'
|
||||
end
|
||||
local buf = api.nvim_get_current_buf()
|
||||
local shown = false
|
||||
for i = 1, vim.fn.tabpagenr('$') do
|
||||
for _, value in pairs(vim.fn.tabpagebuflist(i)) do
|
||||
if value == buf then
|
||||
shown = true
|
||||
end
|
||||
end
|
||||
end
|
||||
if not shown then
|
||||
return '0'
|
||||
end
|
||||
local levels = folds_levels(buf) or {}
|
||||
|
||||
-- trace(lnum, levels[lnum]) -- TODO: comment it out in master
|
||||
return levels[lnum] or '0'
|
||||
end
|
||||
|
||||
return M
|
@ -0,0 +1,49 @@
|
||||
-- https://github.com/wention/dotfiles/blob/master/.config/nvim/lua/config/lsp.lua
|
||||
-- https://github.com/lukas-reineke/dotfiles/blob/master/vim/lua/lsp/handlers.lua
|
||||
|
||||
return {
|
||||
format_hdl = function(err, result, ctx, _) -- FIXME: bufnr is nil
|
||||
if err ~= nil or result == nil then
|
||||
return
|
||||
end
|
||||
|
||||
local util = require('navigator.util')
|
||||
local log = util.log
|
||||
|
||||
local offset_encoding = util.encoding(vim.lsp.get_client_by_id(ctx.client_id))
|
||||
|
||||
-- If the buffer hasn't been modified before the formatting has finished,
|
||||
-- update the buffer
|
||||
-- if not vim.api.nvim_buf_get_option(ctx.bufnr, 'modified') then
|
||||
vim.defer_fn(function()
|
||||
log('fmt callback')
|
||||
|
||||
if ctx.bufnr == vim.api.nvim_get_current_buf() or not vim.api.nvim_buf_get_option(ctx.bufnr, 'modified') then
|
||||
local view = vim.fn.winsaveview()
|
||||
vim.lsp.util.apply_text_edits(result, ctx.bufnr, offset_encoding)
|
||||
vim.fn.winrestview(view)
|
||||
-- FIXME: commented out as a workaround
|
||||
-- if bufnr == vim.api.nvim_get_current_buf() then
|
||||
vim.api.nvim_command('noautocmd :update')
|
||||
|
||||
-- Trigger post-formatting autocommand which can be used to refresh gitgutter
|
||||
vim.api.nvim_command('silent doautocmd <nomodeline> User FormatterPost')
|
||||
-- end
|
||||
end
|
||||
end, 100)
|
||||
end,
|
||||
range_format = function()
|
||||
local old_func = vim.go.operatorfunc
|
||||
_G.op_func_formatting = function()
|
||||
print('formatting range')
|
||||
local start = vim.api.nvim_buf_get_mark(0, '[')
|
||||
local finish = vim.api.nvim_buf_get_mark(0, ']')
|
||||
print(vim.inspect(start), vim.inspect(finish))
|
||||
vim.lsp.buf.range_formatting({}, start, finish)
|
||||
vim.go.operatorfunc = old_func
|
||||
_G.op_func_formatting = nil
|
||||
end
|
||||
vim.go.operatorfunc = 'v:lua.op_func_formatting'
|
||||
vim.api.nvim_feedkeys('g@', 'n', false)
|
||||
end,
|
||||
}
|
@ -1,160 +1,133 @@
|
||||
local M = {}
|
||||
local ListView = require "guihua.listview"
|
||||
local TextView = require "guihua.textview"
|
||||
local util = require "navigator.util"
|
||||
local log = require "navigator.util".log
|
||||
local verbose = require "navigator.util".verbose
|
||||
-- local ListView = require('guihua.listview')
|
||||
-- local TextView = require('guihua.textview')
|
||||
local util = require('navigator.util')
|
||||
local log = util.log
|
||||
local trace = require('navigator.util').trace
|
||||
local api = vim.api
|
||||
local active_list_view -- only one listview at a time
|
||||
|
||||
function M.new_preview(opts)
|
||||
return TextView:new(
|
||||
{
|
||||
loc = "top_center",
|
||||
rect = {
|
||||
height = opts.preview_heigh or 12,
|
||||
width = opts.width or 100,
|
||||
pos_x = opts.pos_x or 0,
|
||||
pos_y = opts.pos_y or 4
|
||||
},
|
||||
-- data = display_data,
|
||||
relative = opts.relative,
|
||||
data = opts.items,
|
||||
syntax = opts.syntax,
|
||||
enter = opts.enter or false,
|
||||
hl_line = opts.hl_line
|
||||
}
|
||||
)
|
||||
end
|
||||
function M.new_list_view(opts)
|
||||
-- log(opts)
|
||||
local config = require('navigator').config_values()
|
||||
|
||||
function M._preview_location(opts) --location, width, pos_x, pos_y
|
||||
local uri = opts.location.targetUri or opts.location.uri
|
||||
if opts.uri == nil then
|
||||
log("invalid/nil uri ")
|
||||
return
|
||||
end
|
||||
local bufnr = vim.uri_to_bufnr(uri)
|
||||
if not api.nvim_buf_is_loaded(bufnr) then
|
||||
vim.fn.bufload(bufnr)
|
||||
end
|
||||
--
|
||||
if active_list_view ~= nil then
|
||||
trace(active_list_view)
|
||||
local winnr = active_list_view.win
|
||||
local bufnr = active_list_view.buf
|
||||
|
||||
local range = opts.location.targetRange or opts.location.range
|
||||
if range.start == nil then
|
||||
print("error invalid range")
|
||||
return
|
||||
if bufnr and api.nvim_buf_is_valid(bufnr) and winnr and api.nvim_win_is_valid(winnr) then
|
||||
log('list view already present')
|
||||
return active_list_view
|
||||
end
|
||||
end
|
||||
if range.start.line == nil then
|
||||
range.start.line = range["end"].line - 1
|
||||
opts.lnum = range["end"].line + 1
|
||||
log(opts)
|
||||
local items = opts.items
|
||||
|
||||
opts.height_ratio = opts.height or config.height
|
||||
opts.width_ratio = opts.height or config.width
|
||||
opts.preview_height_ratio = opts.preview_height or config.preview_height
|
||||
opts.preview_lines = config.preview_lines
|
||||
if opts.rawdata then
|
||||
opts.data = items
|
||||
else
|
||||
opts.data = require('navigator.render').prepare_for_render(items, opts)
|
||||
end
|
||||
if range["end"].line == nil then
|
||||
range["end"].line = range.start.line + 1
|
||||
opts.lnum = range.start.line + 1
|
||||
log(opts)
|
||||
opts.border = config.border or 'shadow'
|
||||
if vim.fn.hlID('TelescopePromptBorder') > 0 then
|
||||
opts.border_hl = 'TelescopePromptBorder'
|
||||
opts.list_hl = 'TelescopeNormal'
|
||||
opts.bg_hl = 'TelescopePreviewNormal'
|
||||
opts.sel_hl = 'TelescopeSelection'
|
||||
else
|
||||
opts.border_hl = 'FloatBorder'
|
||||
opts.bg_hl = 'NormalFloat'
|
||||
opts.list_hl = 'NormalFloat'
|
||||
opts.sel_hl = 'PmenuSel'
|
||||
end
|
||||
local contents = api.nvim_buf_get_lines(bufnr, range.start.line, (range["end"].line or 1) + 10, false)
|
||||
--
|
||||
local syntax = api.nvim_buf_get_option(bufnr, "syntax")
|
||||
if syntax == nil or #syntax < 1 then
|
||||
syntax = api.nvim_buf_get_option(bufnr, "ft")
|
||||
if not items or vim.tbl_isempty(items) then
|
||||
log('empty data return')
|
||||
return
|
||||
end
|
||||
|
||||
verbose(syntax, contents)
|
||||
local win_opts = {syntax = syntax, width = opts.width, pos_x = opts.offset_x or 0, pos_y = opts.offset_y or 10}
|
||||
win_opts.items = contents
|
||||
win_opts.hl_line = opts.lnum - range.start.line
|
||||
if win_opts.hl_line < 0 then
|
||||
win_opts.hl_line = 1
|
||||
opts.transparency = config.transparency
|
||||
if #items >= config.lines_show_prompt then
|
||||
opts.prompt = true
|
||||
end
|
||||
verbose(opts.lnum, range.start.line, win_opts.hl_line)
|
||||
local w = M.new_preview(win_opts)
|
||||
|
||||
return w
|
||||
end
|
||||
|
||||
function M.preview_uri(opts) -- uri, width, line, col, offset_x, offset_y
|
||||
local line_beg = opts.lnum - 1
|
||||
if line_beg >= 2 then
|
||||
line_beg = line_beg - 2
|
||||
opts.external = config.external
|
||||
opts.preview_lines_before = 4
|
||||
if _NgConfigValues.debug then
|
||||
local logopts = { items = {}, data = {} }
|
||||
logopts = vim.tbl_deep_extend('keep', logopts, opts)
|
||||
log(logopts)
|
||||
end
|
||||
local loc = {uri = opts.uri, targetRange = {start = {line = line_beg}}}
|
||||
-- TODO: options for 8
|
||||
loc.targetRange["end"] = {line = opts.lnum + 8}
|
||||
opts.location = loc
|
||||
|
||||
-- log("uri", opts.uri, opts.lnum, opts.location)
|
||||
return M._preview_location(opts)
|
||||
active_list_view = require('guihua.gui').new_list_view(opts)
|
||||
return active_list_view
|
||||
end
|
||||
|
||||
function M.new_list_view(opts)
|
||||
local config = require("navigator").config_values()
|
||||
return M
|
||||
|
||||
local items = opts.items
|
||||
local data = {}
|
||||
if opts.rawdata then
|
||||
data = items
|
||||
else
|
||||
data = require "guihua.util".aggregate_filename(items, opts)
|
||||
end
|
||||
local wwidth = api.nvim_get_option("columns")
|
||||
local width = math.min(opts.width or config.width or 120, math.floor(wwidth * 0.8))
|
||||
local wheight = config.height or math.floor(api.nvim_get_option("lines") * 0.8)
|
||||
local prompt = opts.prompt or false
|
||||
if data and not vim.tbl_isempty(data) then
|
||||
-- replace
|
||||
-- TODO: 10 vimrc opt
|
||||
if #data > 10 and opts.prompt == nil then
|
||||
prompt = true
|
||||
end
|
||||
-- Doc
|
||||
|
||||
local height = math.min(#data, math.floor(wheight / 2))
|
||||
local offset_y = height
|
||||
if prompt then
|
||||
offset_y = offset_y + 1
|
||||
end
|
||||
return ListView:new(
|
||||
{
|
||||
loc = "top_center",
|
||||
prompt = prompt,
|
||||
relative = opts.relative,
|
||||
style = opts.style,
|
||||
api = opts.api,
|
||||
rect = {
|
||||
height = height,
|
||||
width = width,
|
||||
pos_x = 0,
|
||||
pos_y = 0
|
||||
--[[
|
||||
-- each item should look like this
|
||||
-- update if API changes
|
||||
{
|
||||
call_by = { <table 1> },
|
||||
col = 40,
|
||||
display_filename = "./curry.js",
|
||||
filename = "/Users/username/lsp_test/js/curry.js",
|
||||
lnum = 4,
|
||||
range = {
|
||||
end = {
|
||||
character = 46,
|
||||
line = 3 -- note: C index
|
||||
},
|
||||
-- data = display_data,
|
||||
data = data,
|
||||
on_confirm = opts.on_confirm or function(pos)
|
||||
if pos == 0 then
|
||||
pos = 1
|
||||
end
|
||||
local l = data[pos]
|
||||
if l.filename ~= nil then
|
||||
verbose("openfile ", l.filename, l.lnum, l.col)
|
||||
util.open_file_at(l.filename, l.lnum, l.col)
|
||||
end
|
||||
end,
|
||||
on_move = opts.on_move or function(pos)
|
||||
if pos == 0 then
|
||||
pos = 1
|
||||
end
|
||||
local l = data[pos]
|
||||
verbose("on move", pos, l.text or l, l.uri, l.filename)
|
||||
-- todo fix
|
||||
if l.uri == nil then
|
||||
l.uri = "file:///" .. l.filename
|
||||
end
|
||||
return M.preview_uri(
|
||||
{uri = l.uri, width = width, lnum = l.lnum, col = l.col, offset_x = 0, offset_y = offset_y}
|
||||
)
|
||||
end
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
start = {
|
||||
character = 39,
|
||||
line = 3
|
||||
}
|
||||
},
|
||||
rpath = "js/curry.js",
|
||||
text = " (sum, element, index) => (sum += element * vector2[index]),",
|
||||
uri = "file:///Users/username/lsp_test/js/curry.js"
|
||||
}
|
||||
--]]
|
||||
|
||||
return M
|
||||
-- on move item:
|
||||
--[[
|
||||
|
||||
call_by = { {
|
||||
kind = " ",
|
||||
node_scope = {
|
||||
end = {
|
||||
character = 1,
|
||||
line = 7
|
||||
},
|
||||
start = {
|
||||
character = 0,
|
||||
line = 0
|
||||
}
|
||||
},
|
||||
node_text = "curriedDot",
|
||||
type = "var"
|
||||
} },
|
||||
col = 22,
|
||||
display_filename = "./curry.js",
|
||||
filename = "/Users/username/lsp_test/js/curry.js",
|
||||
lnum = 4,
|
||||
range = {
|
||||
end = {
|
||||
character = 26,
|
||||
line = 3
|
||||
},
|
||||
start = {
|
||||
character = 21,
|
||||
line = 3
|
||||
}
|
||||
},
|
||||
rpath = "js/curry.js",
|
||||
text = " 4: (sum, element, index) => (sum += element * vector curriedDot()",
|
||||
uri = "file:///Users/username/lsp_test/js/curry.js"
|
||||
--
|
||||
]]
|
||||
|
@ -1,90 +1,312 @@
|
||||
local gui = require "navigator.gui"
|
||||
local util = require "navigator.util"
|
||||
local gui = require('navigator.gui')
|
||||
local util = require('navigator.util')
|
||||
local log = util.log
|
||||
local partial = util.partial
|
||||
local lsphelper = require "navigator.lspwrapper"
|
||||
local cwd = vim.fn.getcwd(0)
|
||||
local trace = util.trace
|
||||
local partial = util.partial
|
||||
local lsphelper = require('navigator.lspwrapper')
|
||||
|
||||
local path_sep = require('navigator.util').path_sep()
|
||||
local path_cur = require('navigator.util').path_cur()
|
||||
local cwd = vim.loop.cwd()
|
||||
local in_method = 'callHierarchy/incomingCalls'
|
||||
local out_method = 'callHierarchy/outgoingCalls'
|
||||
|
||||
local lsp_method = { to = out_method, from = in_method }
|
||||
local panel_method = { to = out_method, from = in_method }
|
||||
|
||||
local M = {}
|
||||
local outgoing_calls_handler
|
||||
local incoming_calls_handler
|
||||
local hierarchy_handler
|
||||
|
||||
local call_hierarchy
|
||||
|
||||
local function pick_call_hierarchy_item(call_hierarchy_items)
|
||||
if not call_hierarchy_items then
|
||||
return
|
||||
end
|
||||
if #call_hierarchy_items == 1 then
|
||||
return call_hierarchy_items[1]
|
||||
end
|
||||
local items = {}
|
||||
for i, item in pairs(call_hierarchy_items) do
|
||||
local entry = item.detail or item.name
|
||||
table.insert(items, string.format('%d. %s', i, entry))
|
||||
end
|
||||
local choice = vim.fn.inputlist(items)
|
||||
if choice < 1 or choice > #items then
|
||||
return
|
||||
end
|
||||
return choice
|
||||
end
|
||||
|
||||
local function call_hierarchy_handler(direction, err, _, result, _, _, error_message)
|
||||
-- log('call_hierarchy')
|
||||
-- convert lsp result to navigator items
|
||||
local function call_hierarchy_result_procesor(direction, err, result, ctx, config)
|
||||
math.randomseed(os.clock() * 100000000000)
|
||||
trace(direction, err, ctx, config)
|
||||
trace(result)
|
||||
if not result then
|
||||
vim.notify('No call hierarchy items found', vim.lsp.log_levels.WARN)
|
||||
return
|
||||
end
|
||||
-- trace('call_hierarchy', result)
|
||||
|
||||
assert(#vim.lsp.buf_get_clients() > 0, "Must have a client running to use lsp_tags")
|
||||
local bufnr = ctx.bufnr or vim.api.nvim_get_current_buf()
|
||||
assert(next(vim.lsp.buf_get_clients(bufnr)), 'Must have a client running to use call hierarchy')
|
||||
if err ~= nil then
|
||||
print("ERROR: " .. error_message)
|
||||
log('dir', direction, 'result', result, 'err', err, ctx)
|
||||
vim.notify('ERROR: ' .. err, vim.lsp.log_levels.WARN)
|
||||
return
|
||||
end
|
||||
|
||||
-- log("dir", direction, "result", result)
|
||||
local items = {}
|
||||
for _, call_hierarchy_call in pairs(result) do
|
||||
local call_hierarchy_item = call_hierarchy_call[direction]
|
||||
local kind = ' '
|
||||
local items = ctx.items or {}
|
||||
|
||||
local kind = ' '
|
||||
for _, call_hierarchy_result in pairs(result) do
|
||||
local call_hierarchy_item = call_hierarchy_result[direction]
|
||||
if call_hierarchy_item.kind then
|
||||
kind = require'navigator.lspclient.lspkind'.symbol_kind(call_hierarchy_item.kind) .. ' '
|
||||
end
|
||||
for _, range in pairs(call_hierarchy_call.fromRanges) do
|
||||
local filename = assert(vim.uri_to_fname(call_hierarchy_item.uri))
|
||||
local display_filename = filename:gsub(cwd .. "/", "./", 1)
|
||||
table.insert(
|
||||
items,
|
||||
{
|
||||
uri = call_hierarchy_item.uri,
|
||||
filename = filename,
|
||||
-- display_filename = filename:gsub(cwd .. "/", "./", 1),
|
||||
display_filename = call_hierarchy_item.detail or display_filename,
|
||||
text = kind .. call_hierarchy_item.name,
|
||||
range = range,
|
||||
lnum = range.start.line,
|
||||
col = range.start.character
|
||||
}
|
||||
)
|
||||
kind = require('navigator.lspclient.lspkind').symbol_kind(call_hierarchy_item.kind) .. ' '
|
||||
end
|
||||
local filename = assert(vim.uri_to_fname(call_hierarchy_item.uri))
|
||||
local display_filename = filename:gsub(cwd .. path_sep, path_cur, 1)
|
||||
call_hierarchy_item.detail = call_hierarchy_item.detail or ''
|
||||
call_hierarchy_item.detail = string.gsub(call_hierarchy_item.detail, '\n', ' ↳ ')
|
||||
trace(call_hierarchy_item)
|
||||
|
||||
local disp_item = vim.tbl_deep_extend('force', {}, call_hierarchy_item)
|
||||
disp_item = vim.tbl_deep_extend('force', disp_item, {
|
||||
filename = filename,
|
||||
display_filename = display_filename,
|
||||
indent_level = ctx.depth or 1,
|
||||
method = lsp_method[direction],
|
||||
node_text = call_hierarchy_item.name,
|
||||
type = kind,
|
||||
id = math.random(1, 100000),
|
||||
text = kind .. call_hierarchy_item.name .. ' ﰲ ' .. call_hierarchy_item.detail,
|
||||
lnum = call_hierarchy_item.selectionRange.start.line + 1,
|
||||
col = call_hierarchy_item.selectionRange.start.character,
|
||||
})
|
||||
table.insert(items, disp_item)
|
||||
end
|
||||
trace(items)
|
||||
return items
|
||||
end
|
||||
|
||||
local call_hierarchy_handler_from = partial(call_hierarchy_handler, "from")
|
||||
local call_hierarchy_handler_to = partial(call_hierarchy_handler, "to")
|
||||
local call_hierarchy_handler_from = partial(call_hierarchy_result_procesor, 'from')
|
||||
local call_hierarchy_handler_to = partial(call_hierarchy_result_procesor, 'to')
|
||||
|
||||
-- the handler that deal all lsp request
|
||||
hierarchy_handler = function(dir, handler, show, api, err, result, ctx, cfg)
|
||||
trace(dir, handler, api, show, err, result, ctx, cfg)
|
||||
ctx = ctx or {} -- can be nil if it is async call
|
||||
cfg = cfg or {}
|
||||
local opts = ctx.opts or {}
|
||||
vim.validate({ handler = { handler, 'function' }, show = { show, 'function' }, api = { api, 'string' } })
|
||||
local bufnr = ctx.bufnr or vim.api.nvim_get_current_buf()
|
||||
assert(next(vim.lsp.buf_get_clients(bufnr)), 'Must have a client running to use lsp hierarchy')
|
||||
|
||||
local results = handler(err, result, ctx, cfg, 'Incoming calls not found')
|
||||
|
||||
local ft = vim.api.nvim_buf_get_option(ctx.bufnr or vim.api.nvim_get_current_buf(), 'ft')
|
||||
if ctx.no_show then
|
||||
return results
|
||||
end
|
||||
-- local panel = args.panel
|
||||
-- local items = args.items
|
||||
-- local parent_node = args.node
|
||||
-- local section_id = args.section_id or 1
|
||||
local show_args = {
|
||||
items = results,
|
||||
ft = ft,
|
||||
api = api,
|
||||
bufnr = bufnr,
|
||||
panel = opts.panel,
|
||||
parent_node = opts.parent_node,
|
||||
}
|
||||
local win = show(show_args)
|
||||
return results, win
|
||||
end
|
||||
|
||||
local make_params = function(uri, pos)
|
||||
return {
|
||||
textDocument = {
|
||||
uri = uri,
|
||||
},
|
||||
position = pos,
|
||||
}
|
||||
end
|
||||
|
||||
local function display_panel(args)
|
||||
-- args = {items=results, ft=ft, api=api}
|
||||
log(args)
|
||||
|
||||
local function incoming_calls_handler(bang, err, method, result, client_id, bufnr)
|
||||
assert(#vim.lsp.buf_get_clients() > 0, "Must have a client running to use lsp_tags")
|
||||
local results = call_hierarchy_handler_from(err, method, result, client_id, bufnr, "Incoming calls not found")
|
||||
gui.new_list_view({items = results, api = ' '})
|
||||
local Panel = require('guihua.panel')
|
||||
local bufnr = args.bufnr or vim.api.nvim_get_current_buf()
|
||||
-- local ft = args.ft or vim.api.nvim_buf_get_option(bufnr, 'buftype')
|
||||
local items = args.items
|
||||
local p = Panel:new({
|
||||
header = args.header or 'Call Hierarchy',
|
||||
render = function(buf)
|
||||
log(buf)
|
||||
return items
|
||||
end,
|
||||
fold = function(panel, node)
|
||||
if node.expanded ~= nil then
|
||||
node.expanded = not node.expanded
|
||||
vim.cmd('normal! za')
|
||||
else
|
||||
expand(panel, node)
|
||||
node.expanded = true
|
||||
end
|
||||
log('fold')
|
||||
return node
|
||||
end,
|
||||
})
|
||||
p:open(true)
|
||||
end
|
||||
|
||||
local function outgoing_calls_handler(bang, err, method, result, client_id, bufnr)
|
||||
local results = call_hierarchy_handler_to(err, method, result, client_id, bufnr, "Outgoing calls not found")
|
||||
local function expand_item(args)
|
||||
-- args = {items=results, ft=ft, api=api}
|
||||
print('dispaly panel')
|
||||
trace(args, args.parent_node)
|
||||
local panel = args.panel
|
||||
local items = args.items
|
||||
local parent_node = args.parent_node
|
||||
local section_id = args.section_id or 1
|
||||
|
||||
gui.new_list_view({items =results, api = ' '})
|
||||
--fzf_locations(bang, "", "Outgoing Calls", results, false)
|
||||
local sect
|
||||
local sectid = 1
|
||||
for i, s in pairs(panel.sections) do
|
||||
if s.id == section_id then
|
||||
sectid = i
|
||||
break
|
||||
end
|
||||
end
|
||||
sect = panel.sections[sectid]
|
||||
for i, node in pairs(sect.nodes) do
|
||||
if node.id == parent_node.id then
|
||||
for j in ipairs(items) do
|
||||
items[j].indent_level = parent_node.indent_level + 1
|
||||
table.insert(sect.nodes, i + j, args.items[j])
|
||||
end
|
||||
sect.nodes[i].expanded = true
|
||||
sect.nodes[i].expandable = false
|
||||
break
|
||||
end
|
||||
end
|
||||
trace(panel.sections[sectid])
|
||||
-- render the panel again
|
||||
panel:redraw(false)
|
||||
end
|
||||
|
||||
incoming_calls_handler = util.partial4(
|
||||
hierarchy_handler,
|
||||
'from',
|
||||
call_hierarchy_handler_from,
|
||||
gui.new_list_view,
|
||||
' '
|
||||
)
|
||||
outgoing_calls_handler = util.partial4(hierarchy_handler, 'to', call_hierarchy_handler_to, gui.new_list_view, ' ')
|
||||
|
||||
function M.incoming_calls(bang, opts)
|
||||
assert(#vim.lsp.buf_get_clients() > 0, "Must have a client running to use lsp_tags")
|
||||
if not lsphelper.check_capabilities("call_hierarchy") then
|
||||
return
|
||||
local incoming_calls_panel = util.partial4(
|
||||
hierarchy_handler,
|
||||
'from',
|
||||
call_hierarchy_handler_from,
|
||||
display_panel,
|
||||
' '
|
||||
)
|
||||
local outgoing_calls_panel = util.partial4(hierarchy_handler, 'to', call_hierarchy_handler_to, display_panel, ' ')
|
||||
|
||||
local incoming_calls_expand = util.partial4(hierarchy_handler, 'from', call_hierarchy_handler_from, expand_item, ' ')
|
||||
local outgoing_calls_expand = util.partial4(hierarchy_handler, 'to', call_hierarchy_handler_to, expand_item, ' ')
|
||||
|
||||
function expand(panel, node)
|
||||
trace(panel, node)
|
||||
local params = make_params(node.uri, {
|
||||
line = node.range.start.line,
|
||||
character = node.range.start.character,
|
||||
})
|
||||
local handler = incoming_calls_expand
|
||||
if node.api == out_method then
|
||||
handler = outgoing_calls_expand
|
||||
end
|
||||
|
||||
local params = vim.lsp.util.make_position_params()
|
||||
util.call_sync("callHierarchy/incomingCalls", params, opts, partial(incoming_calls_handler, bang))
|
||||
local bufnr = vim.uri_to_bufnr(node.uri)
|
||||
call_hierarchy(node.method, {
|
||||
params = params,
|
||||
panel = panel,
|
||||
parent_node = node,
|
||||
handler = handler,
|
||||
bufnr = bufnr,
|
||||
})
|
||||
end
|
||||
|
||||
function M.outgoing_calls(bang, opts)
|
||||
assert(#vim.lsp.buf_get_clients() > 0, "Must have a client running to use lsp_tags")
|
||||
if not lsphelper.check_capabilities("call_hierarchy") then
|
||||
return
|
||||
local request = vim.lsp.buf_request
|
||||
|
||||
-- call_hierarchy with floating window
|
||||
call_hierarchy = function(method, opts)
|
||||
trace(method, opts)
|
||||
opts = opts or {}
|
||||
local params = opts.params or vim.lsp.util.make_position_params()
|
||||
local bufnr = opts.bufnr
|
||||
local handler = function(err, result, ctx, cfg)
|
||||
ctx.opts = opts
|
||||
return opts.handler(err, result, ctx, cfg)
|
||||
end
|
||||
-- log(opts, params)
|
||||
return request(
|
||||
bufnr,
|
||||
'textDocument/prepareCallHierarchy',
|
||||
params,
|
||||
vim.lsp.with(function(err, result, ctx)
|
||||
if err then
|
||||
vim.notify(err.message, vim.log.levels.WARN)
|
||||
return
|
||||
end
|
||||
local call_hierarchy_item = pick_call_hierarchy_item(result)
|
||||
local client = vim.lsp.get_client_by_id(ctx.client_id)
|
||||
if client then
|
||||
trace('result', result, 'items', call_hierarchy_item, method, ctx, client.name)
|
||||
client.request(method, {
|
||||
item = call_hierarchy_item,
|
||||
args = {
|
||||
method = method,
|
||||
},
|
||||
}, handler, ctx.bufnr)
|
||||
else
|
||||
vim.notify(string.format('Client with id=%d stopped', ctx.client_id), vim.log.levels.WARN)
|
||||
end
|
||||
end, { direction = method, depth = opts.depth })
|
||||
)
|
||||
end
|
||||
|
||||
local params = vim.lsp.util.make_position_params()
|
||||
util.call_sync("callHierarchy/outgoingCalls", params, opts, partial(outgoing_calls_handler, bang))
|
||||
function M.incoming_calls(opts)
|
||||
call_hierarchy(in_method, opts)
|
||||
end
|
||||
|
||||
M.incoming_calls_call = partial(M.incoming_calls, 0)
|
||||
M.outgoing_calls_call = partial(M.outgoing_calls, 0)
|
||||
function M.outgoing_calls(opts)
|
||||
call_hierarchy(out_method, opts)
|
||||
end
|
||||
|
||||
M.incoming_calls_handler = partial(incoming_calls_handler, 0)
|
||||
M.outgoing_calls_handler = partial(outgoing_calls_handler, 0)
|
||||
function M.incoming_calls_panel(opts)
|
||||
opts = vim.tbl_extend('force', { handler = incoming_calls_panel }, opts or {})
|
||||
call_hierarchy(in_method, opts)
|
||||
end
|
||||
|
||||
function M.outgoing_calls_panel(opts)
|
||||
opts = vim.tbl_extend('force', { handler = outgoing_calls_panel }, opts or {})
|
||||
call_hierarchy(out_method, opts)
|
||||
end
|
||||
|
||||
M.incoming_calls_handler = incoming_calls_handler
|
||||
M.outgoing_calls_handler = outgoing_calls_handler
|
||||
-- for testing
|
||||
M._call_hierarchy = call_hierarchy
|
||||
|
||||
function M.calltree(args)
|
||||
if args == '-o' then
|
||||
return M.outgoing_calls_panel()
|
||||
end
|
||||
M.incoming_calls_panel()
|
||||
end
|
||||
return M
|
||||
|
@ -1,23 +0,0 @@
|
||||
-- TODO: change background and use TextView?
|
||||
local lsp = require("vim.lsp")
|
||||
return { hover_handler = function(_, method, result)
|
||||
vim.lsp.util.focusable_float(
|
||||
method,
|
||||
function()
|
||||
if not (result and result.contents) then
|
||||
return
|
||||
end
|
||||
local markdown_lines = lsp.util.convert_input_to_markdown_lines(result.contents)
|
||||
markdown_lines = lsp.util.trim_empty_lines(markdown_lines)
|
||||
if vim.tbl_isempty(markdown_lines) then
|
||||
return
|
||||
end
|
||||
|
||||
local bnr, contents_winid, _, border_winid = vim.lsp.util.fancy_floating_markdown(markdown_lines)
|
||||
lsp.util.close_preview_autocmd({"CursorMoved", "BufHidden", "InsertCharPre"}, contents_winid)
|
||||
lsp.util.close_preview_autocmd({"CursorMoved", "BufHidden", "InsertCharPre"}, border_winid)
|
||||
return bnr, contents_winid
|
||||
end
|
||||
)
|
||||
end
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
return {
|
||||
init = function()
|
||||
local loader = nil
|
||||
local log = require('navigator.util').log
|
||||
-- packer only
|
||||
if packer_plugins ~= nil then -- packer install
|
||||
local lazy_plugins = {
|
||||
['nvim-lspconfig'] = 'neovim/nvim-lspconfig',
|
||||
['guihua.lua'] = 'ray-x/guihua.lua',
|
||||
}
|
||||
|
||||
if _NgConfigValues.lsp_installer == true then
|
||||
lazy_plugins['nvim-lsp-installer'] = 'williamboman/nvim-lsp-installer'
|
||||
end
|
||||
|
||||
-- packer installed
|
||||
loader = require('packer').loader
|
||||
for plugin, url in pairs(lazy_plugins) do
|
||||
if not packer_plugins[url] or not packer_plugins[url].loaded then
|
||||
-- log("loading ", plugin)
|
||||
loader(plugin)
|
||||
end
|
||||
end
|
||||
else
|
||||
loader = function(plugin)
|
||||
local cmd = 'packadd ' .. plugin
|
||||
vim.cmd(cmd)
|
||||
end
|
||||
end
|
||||
|
||||
if _NgConfigValues.lsp_installer == true then
|
||||
vim.cmd('packadd nvim-lsp-installer')
|
||||
local has_lspinst, lspinst = pcall(require, 'nvim-lsp-installer')
|
||||
log('lsp_installer installed', has_lspinst)
|
||||
if has_lspinst then
|
||||
lspinst.setup()
|
||||
local configs = require('lspconfig/configs')
|
||||
local servers = require('nvim-lsp-installer').get_installed_servers()
|
||||
for _, server in pairs(servers) do
|
||||
local cfg = require('navigator.lspclient.clients').get_cfg(server)
|
||||
local lsp_inst_cfg = configs[server]
|
||||
if lsp_inst_cfg and lsp_inst_cfg.document_config.default_config then
|
||||
lsp_inst_cfg = lsp_inst_cfg.document_config.default_config
|
||||
lsp_inst_cfg = vim.tbl_deep_extend('keep', lsp_inst_cfg, cfg)
|
||||
require('lspconfig')[server].setup(lsp_inst_cfg)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
load = function(plugin_name, path)
|
||||
local loader = nil
|
||||
packer_plugins = packer_plugins or nil -- suppress warnings
|
||||
-- packer only
|
||||
if packer_plugins ~= nil then -- packer install
|
||||
local lazy_plugins = {}
|
||||
lazy_plugins[plugin_name] = path
|
||||
loader = require('packer').loader
|
||||
for plugin, _ in pairs(lazy_plugins) do
|
||||
if packer_plugins[plugin] and packer_plugins[plugin].loaded == false then
|
||||
-- log("loading ", plugin)
|
||||
pcall(loader, plugin)
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
}
|
@ -0,0 +1,176 @@
|
||||
-- lua-lru, LRU cache in Lua
|
||||
-- Copyright (c) 2015 Boris Nagaev
|
||||
-- See the LICENSE file for terms of use.
|
||||
--[[
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Boris Nagaev
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
]]--
|
||||
|
||||
local lru = {}
|
||||
|
||||
function lru.new(max_size, max_bytes)
|
||||
|
||||
assert(max_size >= 1, "max_size must be >= 1")
|
||||
assert(not max_bytes or max_bytes >= 1, "max_bytes must be >= 1")
|
||||
|
||||
-- current size
|
||||
local size = 0
|
||||
local bytes_used = 0
|
||||
|
||||
-- map is a hash map from keys to tuples
|
||||
-- tuple: value, prev, next, key
|
||||
-- prev and next are pointers to tuples
|
||||
local map = {}
|
||||
|
||||
-- indices of tuple
|
||||
local VALUE = 1
|
||||
local PREV = 2
|
||||
local NEXT = 3
|
||||
local KEY = 4
|
||||
local BYTES = 5
|
||||
|
||||
-- newest and oldest are ends of double-linked list
|
||||
local newest = nil -- first
|
||||
local oldest = nil -- last
|
||||
|
||||
local removed_tuple -- created in del(), removed in set()
|
||||
|
||||
-- remove a tuple from linked list
|
||||
local function cut(tuple)
|
||||
local tuple_prev = tuple[PREV]
|
||||
local tuple_next = tuple[NEXT]
|
||||
tuple[PREV] = nil
|
||||
tuple[NEXT] = nil
|
||||
if tuple_prev and tuple_next then
|
||||
tuple_prev[NEXT] = tuple_next
|
||||
tuple_next[PREV] = tuple_prev
|
||||
elseif tuple_prev then
|
||||
-- tuple is the oldest element
|
||||
tuple_prev[NEXT] = nil
|
||||
oldest = tuple_prev
|
||||
elseif tuple_next then
|
||||
-- tuple is the newest element
|
||||
tuple_next[PREV] = nil
|
||||
newest = tuple_next
|
||||
else
|
||||
-- tuple is the only element
|
||||
newest = nil
|
||||
oldest = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- insert a tuple to the newest end
|
||||
local function setNewest(tuple)
|
||||
if not newest then
|
||||
newest = tuple
|
||||
oldest = tuple
|
||||
else
|
||||
tuple[NEXT] = newest
|
||||
newest[PREV] = tuple
|
||||
newest = tuple
|
||||
end
|
||||
end
|
||||
|
||||
local function del(key, tuple)
|
||||
map[key] = nil
|
||||
cut(tuple)
|
||||
size = size - 1
|
||||
bytes_used = bytes_used - (tuple[BYTES] or 0)
|
||||
removed_tuple = tuple
|
||||
end
|
||||
|
||||
-- removes elemenets to provide enough memory
|
||||
-- returns last removed element or nil
|
||||
local function makeFreeSpace(bytes)
|
||||
while size + 1 > max_size or (max_bytes and bytes_used + bytes > max_bytes) do
|
||||
assert(oldest, "not enough storage for cache")
|
||||
del(oldest[KEY], oldest)
|
||||
end
|
||||
end
|
||||
|
||||
local function get(_, key)
|
||||
local tuple = map[key]
|
||||
if not tuple then
|
||||
return nil
|
||||
end
|
||||
cut(tuple)
|
||||
setNewest(tuple)
|
||||
return tuple[VALUE]
|
||||
end
|
||||
|
||||
local function set(_, key, value, bytes)
|
||||
local tuple = map[key]
|
||||
if tuple then
|
||||
del(key, tuple)
|
||||
end
|
||||
if value ~= nil then
|
||||
-- the value is not removed
|
||||
bytes = max_bytes and (bytes or #value) or 0
|
||||
makeFreeSpace(bytes)
|
||||
local tuple1 = removed_tuple or {}
|
||||
map[key] = tuple1
|
||||
tuple1[VALUE] = value
|
||||
tuple1[KEY] = key
|
||||
tuple1[BYTES] = max_bytes and bytes
|
||||
size = size + 1
|
||||
bytes_used = bytes_used + bytes
|
||||
setNewest(tuple1)
|
||||
else
|
||||
assert(key ~= nil, "Key may not be nil")
|
||||
end
|
||||
removed_tuple = nil
|
||||
end
|
||||
|
||||
local function delete(_, key)
|
||||
return set(_, key, nil)
|
||||
end
|
||||
|
||||
local function mynext(_, prev_key)
|
||||
local tuple
|
||||
if prev_key then
|
||||
tuple = map[prev_key][NEXT]
|
||||
else
|
||||
tuple = newest
|
||||
end
|
||||
if tuple then
|
||||
return tuple[KEY], tuple[VALUE]
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
-- returns iterator for keys and values
|
||||
local function lru_pairs()
|
||||
return mynext, nil, nil
|
||||
end
|
||||
|
||||
local mt = {
|
||||
__index = {get = get, set = set, delete = delete, pairs = lru_pairs},
|
||||
__pairs = lru_pairs
|
||||
}
|
||||
|
||||
return setmetatable({}, mt)
|
||||
end
|
||||
|
||||
return lru
|
@ -1,47 +1,88 @@
|
||||
local vim, api = vim, vim.api
|
||||
local lsp = require("vim.lsp")
|
||||
local lsp = require('vim.lsp')
|
||||
|
||||
local util = require "navigator.util"
|
||||
local util = require('navigator.util')
|
||||
local log = util.log
|
||||
|
||||
local diagnostic_map = function(bufnr)
|
||||
local opts = {noremap = true, silent = true}
|
||||
api.nvim_buf_set_keymap(bufnr, "n", "]O", ":lua vim.lsp.diagnostic.set_loclist()<CR>", opts)
|
||||
end
|
||||
local trace = util.trace
|
||||
_NG_Attached = {}
|
||||
local M = {}
|
||||
|
||||
M.on_attach = function(client, bufnr)
|
||||
log("attaching")
|
||||
bufnr = bufnr or 0
|
||||
|
||||
local hassig, sig = pcall(require, "lsp_signature")
|
||||
if hassig then
|
||||
sig.on_attach()
|
||||
if bufnr == 0 then
|
||||
vim.notify('no bufnr provided from LSP ' .. client.name, vim.log.levels.DEBUG)
|
||||
end
|
||||
diagnostic_map(bufnr)
|
||||
-- lspsaga
|
||||
require "navigator.lspclient.highlight".add_highlight()
|
||||
local uri = vim.uri_from_bufnr(bufnr)
|
||||
|
||||
if uri == 'file://' or uri == 'file:///' or #uri < 11 then
|
||||
log('skip for float buffer', uri)
|
||||
return { error = 'invalid file', result = nil }
|
||||
end
|
||||
|
||||
log('attaching: ', bufnr, client.name, uri)
|
||||
|
||||
api.nvim_buf_set_option(bufnr, "omnifunc", "v:lua.vim.lsp.omnifunc")
|
||||
trace(client)
|
||||
_NG_Attached[client.name] = true
|
||||
|
||||
require("navigator.lspclient.mapping").setup({client = client, bufnr = bufnr, cap = client.resolved_capabilities})
|
||||
-- add highlight for Lspxxx
|
||||
require('navigator.lspclient.highlight').add_highlight()
|
||||
require('navigator.lspclient.highlight').diagnositc_config_sign()
|
||||
api.nvim_buf_set_option(bufnr, 'omnifunc', 'v:lua.vim.lsp.omnifunc')
|
||||
|
||||
if client.resolved_capabilities.document_highlight then
|
||||
require("navigator.dochighlight").documentHighlight()
|
||||
require('navigator.lspclient.mapping').setup({
|
||||
client = client,
|
||||
bufnr = bufnr,
|
||||
})
|
||||
|
||||
if client.server_capabilities.documentHighlightProvider == true then
|
||||
trace('attaching doc highlight: ', bufnr, client.name)
|
||||
vim.defer_fn(function()
|
||||
require('navigator.dochighlight').documentHighlight(bufnr)
|
||||
end, 50) -- allow a bit time for it to settle down
|
||||
else
|
||||
log('skip doc highlight: ', bufnr, client.name)
|
||||
end
|
||||
|
||||
require "navigator.lspclient.lspkind".init()
|
||||
|
||||
|
||||
require('navigator.lspclient.lspkind').init()
|
||||
|
||||
local capabilities = vim.lsp.protocol.make_client_capabilities()
|
||||
capabilities.textDocument.completion.completionItem.snippetSupport = true
|
||||
local config = require "navigator".config_value
|
||||
if config ~= nil and config.on_attach ~= nil then
|
||||
local config = require('navigator').config_values()
|
||||
trace(client.name, 'navigator on attach')
|
||||
if config.on_attach ~= nil then
|
||||
log(client.name, 'customized attach for all clients')
|
||||
config.on_attach(client, bufnr)
|
||||
end
|
||||
end
|
||||
if config.lsp and config.lsp[client.name] then
|
||||
if type(config.lsp[client.name]) == 'function' then
|
||||
local attach = config.lsp[client.name]().on_attach
|
||||
if attach then
|
||||
attach(client, bufnr)
|
||||
end
|
||||
elseif config.lsp[client.name].on_attach ~= nil then
|
||||
log(client.name, 'customized attach for this client')
|
||||
log('lsp client specific attach for', client.name)
|
||||
config.lsp[client.name].on_attach(client, bufnr)
|
||||
end
|
||||
end
|
||||
|
||||
M.setup = function(cfg)
|
||||
return M
|
||||
if _NgConfigValues.lsp.code_action.enable then
|
||||
if client.server_capabilities.codeActionProvider and client.name ~= 'null-ls' then
|
||||
log('code action enabled for client', client.server_capabilities.codeActionProvider)
|
||||
api.nvim_create_autocmd({ 'CursorHold', 'CursorHoldI' }, {
|
||||
group = api.nvim_create_augroup('NGCodeActGroup_'..tostring(bufnr), {}),
|
||||
buffer = bufnr,
|
||||
callback = function()
|
||||
require('navigator.codeAction').code_action_prompt(bufnr)
|
||||
end,
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- M.setup = function(cfg)
|
||||
-- return M
|
||||
-- end
|
||||
|
||||
return M
|
||||
|
@ -0,0 +1,191 @@
|
||||
local M = {}
|
||||
local vfn = vim.fn
|
||||
M.defaults = function()
|
||||
local has_lsp, lspconfig = pcall(require, 'lspconfig')
|
||||
local highlight = require('navigator.lspclient.highlight')
|
||||
if not has_lsp then
|
||||
return {
|
||||
setup = function()
|
||||
vim.notify('loading lsp config failed LSP may not working correctly', vim.lsp.log_levels.WARN)
|
||||
end,
|
||||
}
|
||||
end
|
||||
local util = lspconfig.util
|
||||
local on_attach = require('navigator.lspclient.attach').on_attach
|
||||
|
||||
|
||||
local setups = {
|
||||
clojure_lsp = {
|
||||
root_dir = function(fname)
|
||||
return util.root_pattern('deps.edn', 'build.boot', 'project.clj', 'shadow-cljs.edn', 'bb.edn', '.git')(fname)
|
||||
or util.path.dirname(fname)
|
||||
end,
|
||||
on_attach = on_attach,
|
||||
filetypes = { 'clojure', 'edn' },
|
||||
message_level = vim.lsp.protocol.MessageType.error,
|
||||
cmd = { 'clojure-lsp' },
|
||||
},
|
||||
|
||||
elixirls = {
|
||||
on_attach = on_attach,
|
||||
filetypes = { 'elixir', 'eelixir' },
|
||||
cmd = { 'elixir-ls' },
|
||||
message_level = vim.lsp.protocol.MessageType.error,
|
||||
settings = {
|
||||
elixirLS = {
|
||||
dialyzerEnabled = true,
|
||||
fetchDeps = false,
|
||||
},
|
||||
},
|
||||
root_dir = function(fname)
|
||||
return util.root_pattern('mix.exs', '.git')(fname) or util.path.dirname(fname)
|
||||
end,
|
||||
},
|
||||
|
||||
gopls = {
|
||||
on_attach = on_attach,
|
||||
-- capabilities = cap,
|
||||
filetypes = { 'go', 'gomod', 'gohtmltmpl', 'gotexttmpl' },
|
||||
message_level = vim.lsp.protocol.MessageType.Error,
|
||||
cmd = {
|
||||
'gopls', -- share the gopls instance if there is one already
|
||||
'-remote=auto', --[[ debug options ]] --
|
||||
-- "-logfile=auto",
|
||||
-- "-debug=:0",
|
||||
'-remote.debug=:0',
|
||||
-- "-rpc.trace",
|
||||
},
|
||||
|
||||
flags = { allow_incremental_sync = true, debounce_text_changes = 1000 },
|
||||
settings = {
|
||||
gopls = {
|
||||
-- more settings: https://github.com/golang/tools/blob/master/gopls/doc/settings.md
|
||||
-- flags = {allow_incremental_sync = true, debounce_text_changes = 500},
|
||||
-- not supported
|
||||
analyses = { unusedparams = true, unreachable = false },
|
||||
codelenses = {
|
||||
generate = true, -- show the `go generate` lens.
|
||||
gc_details = true, -- // Show a code lens toggling the display of gc's choices.
|
||||
test = true,
|
||||
tidy = true,
|
||||
},
|
||||
usePlaceholders = true,
|
||||
completeUnimported = true,
|
||||
staticcheck = true,
|
||||
matcher = 'fuzzy',
|
||||
diagnosticsDelay = '500ms',
|
||||
experimentalWatchedFileDelay = '1000ms',
|
||||
symbolMatcher = 'fuzzy',
|
||||
gofumpt = false, -- true, -- turn on for new repos, gofmpt is good but also create code turmoils
|
||||
buildFlags = { '-tags', 'integration' },
|
||||
-- buildFlags = {"-tags", "functional"}
|
||||
},
|
||||
},
|
||||
root_dir = function(fname)
|
||||
return util.root_pattern('go.mod', '.git')(fname) or dirname(fname) -- util.path.dirname(fname)
|
||||
end,
|
||||
},
|
||||
clangd = {
|
||||
flags = { allow_incremental_sync = true, debounce_text_changes = 500 },
|
||||
cmd = {
|
||||
'clangd',
|
||||
'--background-index',
|
||||
'--suggest-missing-includes',
|
||||
'--clang-tidy',
|
||||
'--header-insertion=iwyu',
|
||||
'--clang-tidy-checks=-*,llvm-*,clang-analyzer-*',
|
||||
'--cross-file-rename',
|
||||
},
|
||||
filetypes = { 'c', 'cpp', 'objc', 'objcpp' },
|
||||
on_attach = function(client, bufnr)
|
||||
client.server_capabilities.documentFormattingProvider = client.server_capabilities.documentFormattingProvider
|
||||
or true
|
||||
on_attach(client, bufnr)
|
||||
end,
|
||||
},
|
||||
rust_analyzer = {
|
||||
root_dir = function(fname)
|
||||
return util.root_pattern('Cargo.toml', 'rust-project.json', '.git')(fname) or util.path.dirname(fname)
|
||||
end,
|
||||
filetypes = { 'rust' },
|
||||
message_level = vim.lsp.protocol.MessageType.error,
|
||||
on_attach = on_attach,
|
||||
settings = {
|
||||
['rust-analyzer'] = {
|
||||
assist = { importMergeBehavior = 'last', importPrefix = 'by_self' },
|
||||
cargo = { loadOutDirsFromCheck = true },
|
||||
procMacro = { enable = true },
|
||||
},
|
||||
},
|
||||
flags = { allow_incremental_sync = true, debounce_text_changes = 500 },
|
||||
},
|
||||
sqls = {
|
||||
filetypes = { 'sql' },
|
||||
on_attach = function(client, _)
|
||||
client.server_capabilities.executeCommandProvider = client.server_capabilities.documentFormattingProvider
|
||||
or true
|
||||
highlight.diagnositc_config_sign()
|
||||
require('sqls').setup({ picker = 'telescope' }) -- or default
|
||||
end,
|
||||
flags = { allow_incremental_sync = true, debounce_text_changes = 500 },
|
||||
settings = {
|
||||
cmd = { 'sqls', '-config', '$HOME/.config/sqls/config.yml' },
|
||||
-- alterantively:
|
||||
-- connections = {
|
||||
-- {
|
||||
-- driver = 'postgresql',
|
||||
-- datasourcename = 'host=127.0.0.1 port=5432 user=postgres password=password dbname=user_db sslmode=disable',
|
||||
-- },
|
||||
-- },
|
||||
},
|
||||
},
|
||||
|
||||
pyright = {
|
||||
on_attach = on_attach,
|
||||
cmd = { 'pyright-langserver', '--stdio' },
|
||||
filetypes = { 'python' },
|
||||
flags = { allow_incremental_sync = true, debounce_text_changes = 500 },
|
||||
settings = {
|
||||
python = {
|
||||
formatting = { provider = 'black' },
|
||||
analysis = {
|
||||
autoSearchPaths = true,
|
||||
useLibraryCodeForTypes = true,
|
||||
diagnosticMode = 'workspace',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ccls = {
|
||||
on_attach = on_attach,
|
||||
init_options = {
|
||||
compilationDatabaseDirectory = 'build',
|
||||
root_dir = [[ util.root_pattern("compile_commands.json", "compile_flags.txt", "CMakeLists.txt", "Makefile", ".git") or util.path.dirname ]],
|
||||
index = { threads = 2 },
|
||||
clang = { excludeArgs = { '-frounding-math' } },
|
||||
},
|
||||
flags = { allow_incremental_sync = true },
|
||||
},
|
||||
jdtls = {
|
||||
settings = {
|
||||
java = { signatureHelp = { enabled = true }, contentProvider = { preferred = 'fernflower' } },
|
||||
},
|
||||
},
|
||||
omnisharp = {
|
||||
cmd = { 'omnisharp', '--languageserver', '--hostPID', tostring(vfn.getpid()) },
|
||||
},
|
||||
terraformls = {
|
||||
filetypes = { 'terraform', 'tf' },
|
||||
},
|
||||
|
||||
sourcekit = {
|
||||
cmd = { 'sourcekit-lsp' },
|
||||
filetypes = { 'swift' }, -- This is recommended if you have separate settings for clangd.
|
||||
},
|
||||
}
|
||||
|
||||
setups.sumneko_lua = require('navigator.lspclient.sumneko_lua').sumneko_lua()
|
||||
return setups
|
||||
end
|
||||
|
||||
return M
|
@ -1,23 +1,72 @@
|
||||
local M = {}
|
||||
|
||||
-- local log = require('navigator.util').log
|
||||
local api = vim.api
|
||||
|
||||
local cmd_group = api.nvim_create_augroup('NGHiGroup', {})
|
||||
-- lsp sign ﮻ ﯭ ﳀ
|
||||
function M.diagnositc_config_sign()
|
||||
vim.fn.sign_define('LspDiagnosticsSignError', {text='', texthl='LspDiagnosticsSignError',linehl='', numhl=''})
|
||||
vim.fn.sign_define('LspDiagnosticsSignWarning', {text='', texthl='LspDiagnosticsSignWarning', linehl='', numhl=''})
|
||||
vim.fn.sign_define('LspDiagnosticsSignInformation', {text='', texthl='LspDiagnosticsSignInformation', linehl='', numhl=''})
|
||||
vim.fn.sign_define('LspDiagnosticsSignHint', {text='💡', texthl='LspDiagnosticsSignHint', linehl='', numhl=''})
|
||||
if M.configed then
|
||||
return
|
||||
end
|
||||
local icons = _NgConfigValues.icons
|
||||
|
||||
local sign_name = 'NavigatorLightBulb'
|
||||
if vim.fn.sign_getdefined(sign_name).text == nil then
|
||||
vim.fn.sign_define(sign_name, { text = icons.code_action_icon, texthl = 'LspDiagnosticsSignHint' })
|
||||
|
||||
sign_name = 'NavigatorCodeLensLightBulb'
|
||||
vim.fn.sign_define(sign_name, { text = icons.code_lens_action_icon, texthl = 'LspDiagnosticsSignHint' })
|
||||
end
|
||||
|
||||
local e, w, i, h = icons.diagnostic_err, icons.diagnostic_warn, icons.diagnostic_info, icons.diagnostic_hint
|
||||
local t = vim.fn.sign_getdefined('DiagnosticSignWarn')
|
||||
if vim.tbl_isempty(t) or t[1].text == 'W ' and icons.icons == true then
|
||||
vim.fn.sign_define('DiagnosticSignError', { text = e, texthl = 'DiagnosticError', linehl = '', numhl = '' })
|
||||
vim.fn.sign_define('DiagnosticSignWarn', { text = w, texthl = 'DiagnosticWarn', linehl = '', numhl = '' })
|
||||
vim.fn.sign_define('DiagnosticSignInfo', { text = i, texthl = 'DiagnosticInfo', linehl = '', numhl = '' })
|
||||
vim.fn.sign_define('DiagnosticSignHint', { text = h, texthl = 'DiagnosticHint', linehl = '', numhl = '' })
|
||||
|
||||
t = vim.fn.sign_getdefined('DiagnosticSignWarn')
|
||||
end
|
||||
M.configed = true
|
||||
end
|
||||
|
||||
function M.add_highlight()
|
||||
local colors = {
|
||||
{ '#aefe00', '#aede00', '#aebe00', '#4e7efe' },
|
||||
{ '#ff00e0', '#df00e0', '#af00e0', '#fedefe' },
|
||||
{ '#1000ef', '#2000df', '#2000cf', '#f0f040' },
|
||||
{ '#d8a8a3', '#c8a8a3', '#b8a8a3', '#4e2c33' },
|
||||
{ '#ffa724', '#efa024', '#dfa724', '#0040ff' },
|
||||
{ '#afdc2b', '#09dc4b', '#08d04b', '#ef4f8f' },
|
||||
}
|
||||
|
||||
function M.add_highlight()
|
||||
-- lsp system default
|
||||
api.nvim_command("hi! link LspDiagnosticsUnderlineError SpellBad")
|
||||
api.nvim_command("hi! link LspDiagnosticsUnderlineWarning SpellRare")
|
||||
api.nvim_command("hi! link LspDiagnosticsUnderlineInformation SpellRare")
|
||||
api.nvim_command("hi! link LspDiagnosticsUnderlineHint SpellRare")
|
||||
api.nvim_command("hi def link DefinitionPreviewTitle Title")
|
||||
|
||||
api.nvim_set_hl(0, 'DiagnosticUnderlineError', { link = 'SpellBad', default = true })
|
||||
api.nvim_set_hl(0, 'DiagnosticUnderlineWarning', { link = 'SpellRare', default = true })
|
||||
api.nvim_set_hl(0, 'DiagnosticUnderlineInformation', { link = 'SpellRare', default = true })
|
||||
api.nvim_set_hl(0, 'DiagnosticUnderlineHint', { link = 'SpellRare', default = true })
|
||||
api.nvim_set_hl(0, 'NGPreviewTitle', { link = 'Title', default = true })
|
||||
api.nvim_set_hl(0, 'LspReferenceRead', { default = true, link = 'IncSearch'})
|
||||
api.nvim_set_hl(0, 'LspReferenceText', { default = true, link = 'Visual'})
|
||||
api.nvim_set_hl( 0, 'LspReferenceWrite', { default = true, link = 'Search'})
|
||||
|
||||
for i = 1, #colors do
|
||||
for j = 1, 3 do
|
||||
local hlg = string.format('NGHiReference_%i_%i', i, j) -- , colors[i][j], colors[i][4]
|
||||
api.nvim_set_hl(0, hlg, { fg = colors[i][j], bg = colors[i][4], default = true })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
api.nvim_create_autocmd('ColorScheme', {
|
||||
group = cmd_group,
|
||||
pattern = '*',
|
||||
callback = function()
|
||||
M.add_highlight()
|
||||
end,
|
||||
})
|
||||
|
||||
return M
|
||||
|
@ -1,9 +0,0 @@
|
||||
-- local log = require "navigator.util".log
|
||||
local M = {}
|
||||
M.setup = function(cfg)
|
||||
cfg = cfg or {}
|
||||
require('navigator.lspclient.clients').setup(cfg)
|
||||
require("navigator.lspclient.mapping").setup(cfg)
|
||||
end
|
||||
|
||||
return M
|
@ -1,138 +1,398 @@
|
||||
local log = require"navigator.util".log
|
||||
local function set_keymap(...) vim.api.nvim_set_keymap(...) end
|
||||
local util = require('navigator.util')
|
||||
local log = util.log
|
||||
local trace = util.trace
|
||||
local api = vim.api
|
||||
|
||||
local event_hdlrs = {
|
||||
{ev = "BufWritePre", func = "diagnostic.set_loclist({open_loclist = false})"},
|
||||
{ev = "CursorHold", func = "document_highlight()"}, {ev = "CursorHoldI", func = "document_highlight()"},
|
||||
{ev = "CursorMoved", func = "clear_references()"}
|
||||
}
|
||||
if vim.lsp.buf.format == nil then
|
||||
vim.lsp.buf.format = vim.lsp.buf.formatting
|
||||
end
|
||||
|
||||
if vim.diagnostic == nil then
|
||||
util.error('Please update nvim to 0.6.1+')
|
||||
end
|
||||
local double = { '╔', '═', '╗', '║', '╝', '═', '╚', '║' }
|
||||
local single = { '╭', '─', '╮', '│', '╯', '─', '╰', '│' }
|
||||
-- TODO https://github.com/neovim/neovim/pull/16591 use vimkeymap.set/del
|
||||
-- LuaFormatter off
|
||||
local key_maps = {
|
||||
{key = "gr", func = "references()"}, {mode = "i", key = "<M-k>", func = "signature_help()"},
|
||||
{key = "gs", func = "signature_help()"}, {key = "g0", func = "document_symbol()"},
|
||||
{key = "gW", func = "workspace_symbol()"}, {key = "<c-]>", func = "definition()"},
|
||||
{key = "gD", func = "declaration()"}, {key = "gp", func = "require('navigator.definition').definition_preview()"},
|
||||
{key = "gT", func = "require('navigator.treesitter').buf_ts()"},
|
||||
{key = "GT", func = "require('navigator.treesitter').bufs_ts()"}, {key = "K", func = "hover()"},
|
||||
{key = "ga", mode = "n", func = "code_action()"}, {key = "ga", mode = "v", func = "range_code_action()"},
|
||||
{key = "<Leader>re", func = "rename()"}, {key = "<Leader>gi", func = "incoming_calls()"},
|
||||
{key = "<Leader>go", func = "outgoing_calls()"}, {key = "gi", func = "implementation()"},
|
||||
{key = "gt", func = "type_definition()"}, {key = "gL", func = "diagnostic.show_line_diagnostics()"},
|
||||
{key = "gG", func = "require('navigator.diagnostics').show_diagnostic()"},
|
||||
{key = "]d", func = "diagnostic.goto_next()"}, {key = "[d", func = "diagnostic.goto_prev()"},
|
||||
{key = "]r", func = "require('navigator.treesitter').goto_next_usage()"},
|
||||
{key = "[r", func = "require('navigator.treesitter').goto_previous_usage()"},
|
||||
{key = "<C-LeftMouse>", func = "definition()"}, {key = "g<LeftMouse>", func = "implementation()"}
|
||||
{ key = 'gr', func = require('navigator.reference').async_ref, desc = 'async_ref' },
|
||||
{ key = '<Leader>gr', func = require('navigator.reference').reference, desc = 'reference' }, -- reference deprecated
|
||||
{ mode = 'i', key = '<M-k>', func = vim.lsp.signature_help, desc = 'signature_help' },
|
||||
{ key = '<c-k>', func = vim.lsp.buf.signature_help, desc = 'signature_help' },
|
||||
{ key = 'g0', func = require('navigator.symbols').document_symbols, desc = 'document_symbols' },
|
||||
{ key = 'gW', func = require('navigator.workspace').workspace_symbol_live, desc = 'workspace_symbol_live' },
|
||||
{ key = '<c-]>', func = require('navigator.definition').definition, desc = 'definition' },
|
||||
{ key = 'gd', func = require('navigator.definition').definition, desc = 'definition' },
|
||||
{ key = 'gD', func = vim.lsp.buf.declaration, desc = 'declaration' },
|
||||
{ key = 'gp', func = require('navigator.definition').definition_preview, desc = 'definition_preview' },
|
||||
{ key = '<Leader>gt', func = require('navigator.treesitter').buf_ts, desc = 'buf_ts' },
|
||||
{ key = '<Leader>gT', func = require('navigator.treesitter').bufs_ts, desc = 'bufs_ts' },
|
||||
{ key = '<Leader>ct', func = require('navigator.ctags').ctags, desc = 'ctags' },
|
||||
{ key = 'K', func = vim.lsp.buf.hover, desc = 'hover' },
|
||||
{ key = '<Space>ca', mode = 'n', func = require('navigator.codeAction').code_action, desc = 'code_action' },
|
||||
{
|
||||
key = '<Space>ca',
|
||||
mode = 'v',
|
||||
func = require('navigator.codeAction').range_code_action,
|
||||
desc = 'range_code_action',
|
||||
},
|
||||
-- { key = '<Leader>re', func = 'rename()' },
|
||||
{ key = '<Space>rn', func = require('navigator.rename').rename, desc = 'rename' },
|
||||
{ key = '<Leader>gi', func = vim.lsp.buf.incoming_calls, desc = 'incoming_calls' },
|
||||
{ key = '<Leader>go', func = vim.lsp.buf.outgoing_calls, desc = 'outgoing_calls' },
|
||||
{ key = 'gi', func = vim.lsp.buf.implementation, desc = 'implementation' },
|
||||
{ key = '<Space>D', func = vim.lsp.buf.type_definition, desc = 'type_definition' },
|
||||
{ key = 'gL', func = require('navigator.diagnostics').show_diagnostics, desc = 'show_diagnostics' },
|
||||
{ key = 'gG', func = require('navigator.diagnostics').show_buf_diagnostics, desc = 'show_buf_diagnostics' },
|
||||
{ key = '<Leader>dt', func = require('navigator.diagnostics').toggle_diagnostics, desc = 'toggle_diagnostics' },
|
||||
{ key = ']d', func = vim.diagnostic.goto_next, desc = 'next diagnostics' },
|
||||
{ key = '[d', func = vim.diagnostic.goto_prev, desc = 'prev diagnostics' },
|
||||
{ key = ']O', func = vim.diagnostic.set_loclist, desc = 'diagnostics set loclist' },
|
||||
{ key = ']r', func = require('navigator.treesitter').goto_next_usage, desc = 'goto_next_usage' },
|
||||
{ key = '[r', func = require('navigator.treesitter').goto_previous_usage, desc = 'goto_previous_usage' },
|
||||
{ key = '<C-LeftMouse>', func = vim.lsp.buf.definition, desc = 'definition' },
|
||||
{ key = 'g<LeftMouse>', func = vim.lsp.buf.implementation, desc = 'implementation' },
|
||||
{ key = '<Leader>k', func = require('navigator.dochighlight').hi_symbol, desc = 'hi_symbol' },
|
||||
{ key = '<Space>wa', func = require('navigator.workspace').add_workspace_folder, desc = 'add_workspace_folder' },
|
||||
{
|
||||
key = '<Space>wr',
|
||||
func = require('navigator.workspace').remove_workspace_folder,
|
||||
desc = 'remove_workspace_folder',
|
||||
},
|
||||
{ key = '<Space>ff', func = vim.lsp.buf.format, mode = 'n', desc = 'format' },
|
||||
{ key = '<Space>ff', func = vim.lsp.buf.range_formatting, mode = 'v', desc = 'range format' },
|
||||
{
|
||||
key = '<Space>gm',
|
||||
func = require('navigator.formatting').range_format,
|
||||
mode = 'n',
|
||||
desc = 'range format operator e.g gmip',
|
||||
},
|
||||
{ key = '<Space>wl', func = require('navigator.workspace').list_workspace_folders, desc = 'list_workspace_folders' },
|
||||
{ key = '<Space>la', mode = 'n', func = require('navigator.codelens').run_action, desc = 'run code lens action' },
|
||||
}
|
||||
|
||||
local function set_mapping(user_opts)
|
||||
local opts = {noremap = true, silent = true}
|
||||
user_opts = user_opts or {}
|
||||
local key_maps_help = {}
|
||||
-- LuaFormatter on
|
||||
local M = {}
|
||||
|
||||
local user_key = user_opts.keymaps or {}
|
||||
local bufnr = user_opts.bufnr or 0
|
||||
local ccls_mappings = {
|
||||
{ key = '<Leader>gi', func = require('navigator.cclshierarchy').incoming_calls, desc = 'incoming_calls' },
|
||||
{ key = '<Leader>go', func = require('navigator.cclshierarchy').outgoing_calls, desc = 'outgoing_calls' },
|
||||
}
|
||||
|
||||
local function buf_set_keymap(...) vim.api.nvim_buf_set_keymap(bufnr, ...) end
|
||||
local check_cap = function(opts)
|
||||
-- log(vim.lsp.buf_get_clients(0))
|
||||
local fmt, rfmt, ccls
|
||||
local cap = opts.cap
|
||||
if cap == nil then
|
||||
if opts.client and opts.client.server_capabilities then
|
||||
cap = opts.client.server_capabilities
|
||||
end
|
||||
end
|
||||
if cap and cap.documentFormattingProvider then
|
||||
fmt = true
|
||||
end
|
||||
if cap and cap.documentRangeFormattingProvider then
|
||||
rfmt = true
|
||||
end
|
||||
for _, value in pairs(vim.lsp.buf_get_clients(0)) do
|
||||
trace(value)
|
||||
if value ~= nil and value.server_capabilities == nil then
|
||||
if value.server_capabilities.documentFormattingProvider then
|
||||
fmt = true
|
||||
end
|
||||
if value.server_capabilities.documentRangeFormattingProvider then
|
||||
rfmt = true
|
||||
end
|
||||
|
||||
log('override ccls', value.config)
|
||||
if value.config.name == 'ccls' then
|
||||
ccls = true
|
||||
end
|
||||
end
|
||||
end
|
||||
return fmt, rfmt, ccls
|
||||
end
|
||||
|
||||
local function set_cmds(_)
|
||||
local commands = {
|
||||
[[command! -nargs=* Nctags lua require("navigator.ctags").ctags(<f-args>)]],
|
||||
"command! -nargs=0 LspLog lua require'navigator.lspclient.config'.open_lsp_log()",
|
||||
"command! -nargs=0 LspRestart lua require'navigator.lspclient.config'.reload_lsp()",
|
||||
"command! -nargs=0 LspToggleFmt lua require'navigator.lspclient.mapping'.toggle_lspformat()<CR>",
|
||||
"command! -nargs=0 LspKeymaps lua require'navigator.lspclient.mapping'.get_keymaps_help()<CR>",
|
||||
"command! -nargs=0 LspSymbols lua require'navigator.symbols'.side_panel()<CR>",
|
||||
"command! -nargs=0 TSymbols lua require'navigator.treesitter'.side_panel()<CR>",
|
||||
"command! -nargs=0 NRefPanel lua require'navigator.reference'.side_panel()<CR>",
|
||||
"command! -nargs=* Calltree lua require'navigator.hierarchy'.calltree(<f-args>)<CR>",
|
||||
}
|
||||
|
||||
for _, value in pairs(commands) do
|
||||
vim.cmd(value)
|
||||
end
|
||||
end
|
||||
|
||||
-- should works for both 1)attach from known lsp client or from a disabled lsp client
|
||||
-- executed in on_attach context
|
||||
local function set_mapping(lsp_attach_info)
|
||||
local opts = { noremap = true, silent = true }
|
||||
vim.validate({
|
||||
lsp_attach_info = { lsp_attach_info, 'table' },
|
||||
})
|
||||
if _NgConfigValues.debug then
|
||||
log('setup mapping for client', lsp_attach_info.client.name, lsp_attach_info.client.cmd)
|
||||
end
|
||||
local user_key = _NgConfigValues.keymaps or {}
|
||||
local bufnr = lsp_attach_info.bufnr or 0
|
||||
|
||||
local function del_keymap(mode, key, ...)
|
||||
local ks = vim.api.nvim_buf_get_keymap(bufnr, mode)
|
||||
if vim.tbl_contains(ks, key) then
|
||||
vim.api.nvim_buf_del_keymap(bufnr, mode, key, ...)
|
||||
end
|
||||
end
|
||||
|
||||
local function set_keymap(...)
|
||||
vim.api.nvim_buf_set_keymap(bufnr, ...)
|
||||
end
|
||||
|
||||
-- local function buf_set_option(...)
|
||||
-- vim.api.nvim_buf_set_option(bufnr, ...)
|
||||
-- end
|
||||
for _, v in pairs(user_key) do
|
||||
local exists = false
|
||||
for _, default in pairs(key_maps) do
|
||||
if v.func == default.func then
|
||||
default.key, exists = v.key, true
|
||||
break
|
||||
local doc_fmt, range_fmt, ccls = check_cap(lsp_attach_info)
|
||||
|
||||
if ccls then
|
||||
vim.list_extend(key_maps, ccls_mappings)
|
||||
end
|
||||
|
||||
if _NgConfigValues.default_mapping ~= false then
|
||||
for _, v in pairs(user_key) do
|
||||
trace('binding', v)
|
||||
local exists = false
|
||||
for _, default in pairs(key_maps) do
|
||||
if v.func == default.func and (v.mode or 'n') == (default.mode or 'n') and not default.override then
|
||||
default.key, default.override, exists = v.key, true, true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not exists then
|
||||
table.insert(key_maps, v)
|
||||
end
|
||||
end
|
||||
if not exists then table.insert(key_maps, v) end
|
||||
else
|
||||
key_maps = _NgConfigValues.keymaps or {}
|
||||
log('setting maps to ', key_maps)
|
||||
end
|
||||
|
||||
-- local key_opts = {vim.tbl_deep_extend("force", key_maps, unpack(result))}
|
||||
local fmtkey, rfmtkey, nrfmtkey
|
||||
require('navigator.formatting')
|
||||
for _, value in pairs(key_maps) do
|
||||
local f = "<Cmd>lua vim.lsp.buf." .. value.func .. "<CR>"
|
||||
if string.find(value.func, "require") then
|
||||
f = "<Cmd>lua " .. value.func .. "<CR>"
|
||||
elseif string.find(value.func, "diagnostic") then
|
||||
f = "<Cmd>lua vim.lsp." .. value.func .. "<CR>"
|
||||
if value.doc then
|
||||
vim.notify('doc field no longer supported in navigator mapping, use desc instead')
|
||||
end
|
||||
local k = value.key
|
||||
local m = value.mode or "n"
|
||||
buf_set_keymap(m, k, f, opts)
|
||||
end
|
||||
if type(value.func) == 'string' then -- deprecated will remove when 0.8 is out
|
||||
vim.notify('keymap config updated: ' .. value.key .. ' func ' .. value.func .. ' should be a function')
|
||||
local f = '<Cmd>lua vim.lsp.buf.' .. value.func .. '<CR>'
|
||||
if string.find(value.func, 'require') or string.find(value.func, 'vim.') then
|
||||
f = '<Cmd>lua ' .. value.func .. '<CR>'
|
||||
elseif string.find(value.func, 'diagnostic') then
|
||||
local diagnostic = '<Cmd>lua vim.'
|
||||
diagnostic = '<Cmd>lua vim.'
|
||||
f = diagnostic .. value.func .. '<CR>'
|
||||
end
|
||||
|
||||
local k = value.key
|
||||
local m = value.mode or 'n'
|
||||
if string.find(value.func, 'range_formatting') then
|
||||
rfmtkey = value.key
|
||||
elseif string.find(value.func, 'format') then
|
||||
fmtkey = value.key
|
||||
end
|
||||
trace('binding', k, f)
|
||||
set_keymap(m, k, f, opts)
|
||||
end
|
||||
if type(value.func) == 'function' then -- new from 0.7.x
|
||||
-- neovim 0.7.0
|
||||
|
||||
-- format setup
|
||||
opts.buffer = key_maps.buffer or value.buffer
|
||||
if value.desc then
|
||||
opts.desc = value.desc
|
||||
end
|
||||
opts.buffer = bufnr
|
||||
vim.keymap.set(value.mode or 'n', value.key, value.func, opts)
|
||||
if string.find(value.desc, 'range format') and value.mode == 'v' then
|
||||
rfmtkey = value.key
|
||||
if string.find(value.desc, 'range format') and value.mode == 'n' then
|
||||
nrfmtkey = value.key
|
||||
elseif string.find(value.desc, 'format') then
|
||||
fmtkey = value.key
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
for _, val in pairs(key_maps) do
|
||||
local helper_msg = ''
|
||||
if val.desc then
|
||||
helper_msg = val.desc
|
||||
elseif type(val.func) == 'string' then
|
||||
helper_msg = val.func
|
||||
end
|
||||
|
||||
local range_fmt = false
|
||||
local doc_fmt = false
|
||||
for _, value in pairs(vim.lsp.buf_get_clients(0)) do
|
||||
if value == nil or value.resolved_capabilities == nil then return end
|
||||
if value.resolved_capabilities.document_formatting then doc_fmt = true end
|
||||
if value.resolved_capabilities.document_range_formatting then range_fmt = true end
|
||||
local item = (val.mode or 'n') .. '|' .. val.key .. '|' .. helper_msg
|
||||
if not vim.tbl_contains(key_maps_help, item) then
|
||||
table.insert(key_maps_help, (val.mode or 'n') .. '|' .. val.key .. '|' .. helper_msg)
|
||||
end
|
||||
end
|
||||
|
||||
-- if user_opts.cap.document_formatting then
|
||||
if doc_fmt then
|
||||
buf_set_keymap("n", "<space>ff", "<cmd>lua vim.lsp.buf.formatting()<CR>", opts)
|
||||
vim.cmd([[autocmd BufWritePre <buffer> lua vim.lsp.buf.formatting()]])
|
||||
|
||||
if doc_fmt and _NgConfigValues.lsp.format_on_save then
|
||||
local gn = api.nvim_create_augroup('NavAuGroupFormat', {})
|
||||
|
||||
local fopts = _NgConfigValues.lsp.format_options
|
||||
|
||||
if not fopts.async and vim.api.nvim_buf_line_count(0) > 4000 then
|
||||
fopts.async = true
|
||||
end
|
||||
|
||||
api.nvim_create_autocmd({ 'BufWritePre' }, {
|
||||
group = gn,
|
||||
buffer = bufnr,
|
||||
callback = function()
|
||||
trace('format' .. vim.inspect(fopts))
|
||||
vim.lsp.buf.format(fopts)
|
||||
end,
|
||||
})
|
||||
elseif fmtkey then
|
||||
del_keymap('n', fmtkey)
|
||||
end
|
||||
|
||||
if lsp_attach_info.cap and lsp_attach_info.cap.document_range_formatting then
|
||||
log('formatting enabled', lsp_attach_info.cap)
|
||||
end
|
||||
|
||||
if not range_fmt and rfmtkey then
|
||||
del_keymap('v', rfmtkey)
|
||||
end
|
||||
|
||||
if not range_fmt and nrfmtkey then
|
||||
del_keymap('n', nrfmtkey)
|
||||
end
|
||||
-- if user_opts.cap.document_range_formatting then
|
||||
if range_fmt then buf_set_keymap("v", "<space>ff", "<cmd>lua vim.lsp.buf.range_formatting()<CR>", opts) end
|
||||
log('enable format ', doc_fmt, range_fmt, _NgConfigValues.lsp.format_on_save)
|
||||
end
|
||||
|
||||
local function set_event_handler(user_opts)
|
||||
user_opts = user_opts or {}
|
||||
local file_types = "c,cpp,h,go,python,vim,sh,javascript,html,css,lua,typescript,rust"
|
||||
-- local format_files = "c,cpp,h,go,python,vim,javascript,typescript" --html,css,
|
||||
vim.api.nvim_command [[augroup nvim_lsp_autos]]
|
||||
vim.api.nvim_command [[autocmd!]]
|
||||
|
||||
for _, value in pairs(event_hdlrs) do
|
||||
local f = ""
|
||||
if string.find(value.func, "diagnostic") then
|
||||
f = "lua vim.lsp." .. value.func
|
||||
else
|
||||
f = "lua vim.lsp.buf." .. value.func
|
||||
local function autocmd()
|
||||
local gn = api.nvim_create_augroup('NavAuGroupDocHlAu', {})
|
||||
|
||||
api.nvim_create_autocmd({ 'BufWritePre' }, {
|
||||
group = gn,
|
||||
callback = require('navigator.dochighlight').cmd_nohl,
|
||||
})
|
||||
end
|
||||
|
||||
M.toggle_lspformat = function(on)
|
||||
if on == nil then
|
||||
_NgConfigValues.lsp.format_on_save = not _NgConfigValues.lsp.format_on_save
|
||||
else
|
||||
_NgConfigValues.lsp.format_on_save = on
|
||||
end
|
||||
if _NgConfigValues.lsp.format_on_save then
|
||||
if on == nil then
|
||||
vim.notify('format on save true', vim.lsp.log_levels.INFO)
|
||||
end
|
||||
vim.cmd([[set eventignore-=BufWritePre]])
|
||||
else
|
||||
if on == nil then
|
||||
vim.notify('format on save false', vim.lsp.log_levels.INFO)
|
||||
end
|
||||
local cmd = "autocmd FileType " .. file_types .. " autocmd nvim_lsp_autos " .. value.ev .. " <buffer> silent! " .. f
|
||||
vim.api.nvim_command(cmd)
|
||||
vim.cmd([[set eventignore+=BufWritePre]])
|
||||
end
|
||||
vim.api.nvim_command([[augroup END]])
|
||||
end
|
||||
|
||||
local M = {}
|
||||
function M.setup(attach_opts)
|
||||
if not attach_opts or not attach_opts.client then
|
||||
vim.notify(
|
||||
'please call require"navigator.mapping".setup({bufnr=bufnr, client=client}) inside on_attach(client,bufnr)',
|
||||
vim.lsp.log_levels.WARN
|
||||
)
|
||||
end
|
||||
attach_opts = attach_opts or { bufnr = 0, client = {}, cap = {} }
|
||||
set_mapping(attach_opts)
|
||||
set_cmds(attach_opts)
|
||||
|
||||
autocmd()
|
||||
|
||||
local client = attach_opts.client or {}
|
||||
local cap = client.server_capabilities or vim.lsp.protocol.make_client_capabilities()
|
||||
|
||||
function M.setup(user_opts)
|
||||
user_opts = user_opts or {}
|
||||
user_opts.cap = vim.lsp.protocol.make_client_capabilities()
|
||||
log('lsp cap:', cap.codeActionProvider)
|
||||
|
||||
set_mapping(user_opts)
|
||||
set_event_handler(user_opts)
|
||||
local cap = user_opts.cap or {}
|
||||
if cap.call_hierarchy or cap.callHierarchy then
|
||||
vim.lsp.handlers["callHierarchy/incomingCalls"] = require"navigator.hierarchy".incoming_calls_handler
|
||||
vim.lsp.handlers["callHierarchy/outgoingCalls"] = require"navigator.hierarchy".outgoing_calls_handler
|
||||
if cap.call_hierarchy or cap.callHierarchyProvider then
|
||||
vim.lsp.handlers['callHierarchy/incomingCalls'] = require('navigator.hierarchy').incoming_calls_handler
|
||||
vim.lsp.handlers['callHierarchy/outgoingCalls'] = require('navigator.hierarchy').outgoing_calls_handler
|
||||
end
|
||||
|
||||
vim.lsp.handlers["textDocument/references"] = require"navigator.reference".reference_handler
|
||||
vim.lsp.handlers["textDocument/codeAction"] = require"navigator.codeAction".code_action_handler
|
||||
vim.lsp.handlers["textDocument/definition"] = require"navigator.definition".definition_handler
|
||||
vim.lsp.handlers['textDocument/references'] = require('navigator.reference').reference_handler
|
||||
-- vim.lsp.handlers["textDocument/codeAction"] = require"navigator.codeAction".code_action_handler
|
||||
vim.lsp.handlers['textDocument/definition'] = require('navigator.definition').definition_handler
|
||||
|
||||
if cap.declaration then
|
||||
vim.lsp.handlers["textDocument/declaration"] = require"navigator.definition".declaration_handler
|
||||
if cap.declarationProvider then
|
||||
vim.lsp.handlers['textDocument/declaration'] = require('navigator.definition').declaration_handler
|
||||
end
|
||||
|
||||
vim.lsp.handlers["textDocument/typeDefinition"] = require"navigator.definition".typeDefinition_handler
|
||||
vim.lsp.handlers["textDocument/implementation"] = require"navigator.implementation".implementation_handler
|
||||
vim.lsp.handlers['textDocument/typeDefinition'] = require('navigator.definition').typeDefinition_handler
|
||||
vim.lsp.handlers['textDocument/implementation'] = require('navigator.implementation').implementation_handler
|
||||
|
||||
vim.lsp.handlers["textDocument/documentSymbol"] = require"navigator.symbols".document_symbol_handler
|
||||
vim.lsp.handlers["workspace/symbol"] = require"navigator.symbols".workspace_symbol_handler
|
||||
vim.lsp.handlers["textDocument/publishDiagnostics"] = require"navigator.diagnostics".diagnostic_handler
|
||||
-- vim.lsp.handlers['textDocument/documentSymbol'] = require('navigator.symbols').document_symbol_handler
|
||||
vim.lsp.handlers['workspace/symbol'] = require('navigator.symbols').workspace_symbol_handler
|
||||
vim.lsp.handlers['textDocument/publishDiagnostics'] = require('navigator.diagnostics').diagnostic_handler
|
||||
|
||||
-- TODO: when active signature merge to neovim, remove this setup:
|
||||
|
||||
if
|
||||
_NgConfigValues.signature_help_cfg and #_NgConfigValues.signature_help_cfg > 0 or _NgConfigValues.lsp_signature_help
|
||||
then
|
||||
log('setup signature from navigator')
|
||||
local hassig, sig = pcall(require, 'lsp_signature')
|
||||
if hassig then
|
||||
sig.setup(_NgConfigValues.signature_help_cfg or {})
|
||||
end
|
||||
else
|
||||
vim.lsp.handlers['textDocument/signatureHelp'] = vim.lsp.with(require('navigator.signature').signature_handler, {
|
||||
border = { '╭', '─', '╮', '│', '╯', '─', '╰', '│' },
|
||||
})
|
||||
end
|
||||
|
||||
api.nvim_create_autocmd({ 'BufWritePre' }, {
|
||||
group = api.nvim_create_augroup('nvim_nv_event_autos', {}),
|
||||
buffer = attach_opts.bufnr,
|
||||
callback = function()
|
||||
require('navigator.diagnostics').set_diag_loclist(attach_opts.bufnr)
|
||||
end,
|
||||
})
|
||||
|
||||
local border_style = single
|
||||
if _NgConfigValues.border == 'double' then
|
||||
border_style = double
|
||||
end
|
||||
vim.lsp.handlers['textDocument/hover'] = vim.lsp.with(vim.lsp.handlers.hover, { border = border_style })
|
||||
if cap.documentFormattingProvider then
|
||||
log('formatting enabled setup hdl')
|
||||
vim.lsp.handlers['textDocument/formatting'] = require('navigator.formatting').format_hdl
|
||||
end
|
||||
end
|
||||
|
||||
local hassig, sig = pcall(require, "lsp_signature")
|
||||
if not hassig then vim.lsp.handlers["textDocument/signatureHelp"] = require"navigator.signature".signature_handler end
|
||||
M.get_keymaps_help = function()
|
||||
local ListView = require('guihua.listview')
|
||||
local win = ListView:new({
|
||||
loc = 'top_center',
|
||||
border = 'none',
|
||||
prompt = true,
|
||||
enter = true,
|
||||
rect = { height = 24, width = 50 },
|
||||
data = key_maps_help,
|
||||
})
|
||||
|
||||
-- vim.lsp.handlers["textDocument/hover"] = require 'navigator.hover'.hover_handler
|
||||
return win
|
||||
end
|
||||
|
||||
return M
|
||||
|
@ -0,0 +1,47 @@
|
||||
return {
|
||||
'angularls',
|
||||
'gopls',
|
||||
'tsserver',
|
||||
'flow',
|
||||
'bashls',
|
||||
'dockerls',
|
||||
'julials',
|
||||
'pylsp',
|
||||
'pyright',
|
||||
'jedi_language_server',
|
||||
'jdtls',
|
||||
'sumneko_lua',
|
||||
'vimls',
|
||||
'html',
|
||||
'jsonls',
|
||||
'solargraph',
|
||||
'cssls',
|
||||
'yamlls',
|
||||
'clangd',
|
||||
'ccls',
|
||||
'sqls',
|
||||
'denols',
|
||||
'graphql',
|
||||
'dartls',
|
||||
'dotls',
|
||||
'kotlin_language_server',
|
||||
'nimls',
|
||||
'intelephense',
|
||||
'vuels',
|
||||
'volar',
|
||||
'phpactor',
|
||||
'omnisharp',
|
||||
'r_language_server',
|
||||
'rust_analyzer',
|
||||
'terraformls',
|
||||
'svelte',
|
||||
'texlab',
|
||||
'clojure_lsp',
|
||||
'elixirls',
|
||||
'sourcekit',
|
||||
'fsautocomplete',
|
||||
'vls',
|
||||
'hls',
|
||||
'tflint',
|
||||
'terraform_lsp',
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
local vfn = vim.fn
|
||||
|
||||
local library = {}
|
||||
local sumneko_cfg = {
|
||||
cmd = { 'lua-language-server' },
|
||||
filetypes = { 'lua' },
|
||||
on_attach = on_attach,
|
||||
flags = { allow_incremental_sync = true, debounce_text_changes = 500 },
|
||||
settings = {
|
||||
Lua = {
|
||||
runtime = {
|
||||
-- Tell the language server which version of Lua you're using (most likely LuaJIT in the case of Neovim)
|
||||
version = 'LuaJIT',
|
||||
},
|
||||
diagnostics = {
|
||||
enable = true,
|
||||
-- Get the language server to recognize the `vim` global
|
||||
globals = { 'vim', 'describe', 'it', 'before_each', 'after_each', 'teardown', 'pending' },
|
||||
},
|
||||
completion = { callSnippet = 'Both' },
|
||||
workspace = {
|
||||
-- Make the server aware of Neovim runtime files
|
||||
library = library,
|
||||
maxPreload = 2000,
|
||||
preloadFileSize = 40000,
|
||||
},
|
||||
telemetry = { enable = false },
|
||||
},
|
||||
},
|
||||
on_new_config = function(cfg, root)
|
||||
local libs = vim.tbl_deep_extend('force', {}, library)
|
||||
libs[root] = nil
|
||||
cfg.settings.Lua.workspace.library = libs
|
||||
return cfg
|
||||
end,
|
||||
}
|
||||
|
||||
local function add(lib)
|
||||
for _, p in pairs(vfn.expand(lib, false, true)) do
|
||||
p = vim.loop.fs_realpath(p)
|
||||
if p then
|
||||
library[p] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
local function sumneko_lua()
|
||||
-- add runtime
|
||||
-- add plugins it may be very slow to add all in path
|
||||
add('$VIMRUNTIME')
|
||||
-- add your config
|
||||
-- local home = vfn.expand("$HOME")
|
||||
add(vfn.stdpath('config'))
|
||||
|
||||
library[vfn.expand('$VIMRUNTIME/lua')] = true
|
||||
library[vfn.expand('$VIMRUNTIME/lua/vim')] = true
|
||||
library[vfn.expand('$VIMRUNTIME/lua/vim/lsp')] = true
|
||||
|
||||
local on_attach = require('navigator.lspclient.attach').on_attach
|
||||
local luadevcfg = {
|
||||
library = {
|
||||
vimruntime = true, -- runtime path
|
||||
types = true, -- full signature, docs and completion of vim.api, vim.treesitter, vim.lsp and others
|
||||
plugins = { 'nvim-treesitter', 'plenary.nvim' },
|
||||
},
|
||||
lspconfig = {
|
||||
-- cmd = {sumneko_binary},
|
||||
on_attach = on_attach,
|
||||
},
|
||||
}
|
||||
|
||||
local luadev = {}
|
||||
local user_luadev = _NgConfigValues.lsp['lua-dev']
|
||||
if user_luadev then
|
||||
luadevcfg = vim.tbl_deep_extend('force', luadevcfg, user_luadev)
|
||||
end
|
||||
require('navigator.lazyloader').load('lua-dev.nvim', 'folke/lua-dev.nvim')
|
||||
|
||||
local ok, l = pcall(require, 'lua-dev')
|
||||
if ok and l then
|
||||
luadev = l.setup(luadevcfg)
|
||||
end
|
||||
|
||||
sumneko_cfg = vim.tbl_deep_extend('force', sumneko_cfg, luadev)
|
||||
return sumneko_cfg
|
||||
end
|
||||
|
||||
return {
|
||||
sumneko_lua = sumneko_lua,
|
||||
}
|
@ -1,41 +1,260 @@
|
||||
local util = require "navigator.util"
|
||||
local util = require('navigator.util')
|
||||
local log = util.log
|
||||
local lsphelper = require "navigator.lspwrapper"
|
||||
local gui = require "navigator.gui"
|
||||
local lsp = require "navigator.lspwrapper"
|
||||
local verbose = require "navigator.util".verbose
|
||||
-- local log = util.log
|
||||
local lsphelper = require('navigator.lspwrapper')
|
||||
local gui = require('navigator.gui')
|
||||
local lsp = require('navigator.lspwrapper')
|
||||
local trace = require('navigator.util').trace
|
||||
-- local partial = util.partial
|
||||
-- local cwd = vim.fn.getcwd(0)
|
||||
-- local cwd = vim.loop.cwd()
|
||||
-- local lsphelper = require "navigator.lspwrapper"
|
||||
local locations_to_items = lsphelper.locations_to_items
|
||||
|
||||
--vim.api.nvim_set_option("navtator_options", {width = 90, height = 60, location = require "navigator.location".center})
|
||||
-- local options = vim.g.navtator_options or {width = 60, height = 40, location = location.center}
|
||||
local function ref_hdlr(arg1, api, locations, num, bufnr)
|
||||
local M = {}
|
||||
local ref_view = function(err, locations, ctx, cfg)
|
||||
cfg = cfg or {}
|
||||
local truncate = cfg and cfg.truncate or 20
|
||||
local opts = {}
|
||||
-- log("arg1", arg1)
|
||||
-- log(api)
|
||||
-- log(locations)
|
||||
trace('arg1', err, ctx, locations)
|
||||
-- log(#locations, locations[1])
|
||||
if ctx.combine then
|
||||
-- wait for both reference and definition LSP request
|
||||
if ctx.results == nil then
|
||||
return
|
||||
end
|
||||
if (ctx.results.definitions == nil) or (ctx.results.references == nil) then
|
||||
log('not all requests returned')
|
||||
return
|
||||
end
|
||||
local definitions = ctx.results.definitions
|
||||
local references = ctx.results.references
|
||||
if _NgConfigValues.debug then
|
||||
local logctx = { results = {} }
|
||||
logctx = vim.tbl_extend('keep', logctx, ctx)
|
||||
log(logctx, 'result size', 'def', #ctx.results.definitions, 'ref', #ctx.results.references)
|
||||
end
|
||||
if definitions.error and references.error then
|
||||
vim.notify('lsp ref callback error' .. vim.inspect(ctx.result), vim.lsp.log_levels.WARN)
|
||||
end
|
||||
locations = {}
|
||||
if definitions and definitions.result then
|
||||
for i, _ in ipairs(definitions.result) do
|
||||
definitions.result[i].definition = true
|
||||
end
|
||||
vim.list_extend(locations, definitions.result)
|
||||
end
|
||||
|
||||
if references and references.result and #references.result > 0 then
|
||||
local refs = references.result
|
||||
vim.list_extend(locations, refs)
|
||||
end
|
||||
err = nil
|
||||
trace(locations)
|
||||
-- lets de-dup first 10 elements. some lsp does not recognize definition and reference difference
|
||||
locations = util.dedup(locations)
|
||||
trace(locations)
|
||||
end
|
||||
-- log("num", num)
|
||||
-- log("bfnr", bufnr)
|
||||
if err ~= nil then
|
||||
vim.notify(
|
||||
'lsp ref callback error' .. vim.inspect(err) .. vim.inspect(ctx) .. vim.inspect(locations),
|
||||
vim.lsp.log_levels.WARN
|
||||
)
|
||||
log('ref callback error, lsp may not ready', err, ctx, vim.inspect(locations))
|
||||
return
|
||||
end
|
||||
if type(locations) ~= 'table' then
|
||||
log(locations)
|
||||
log('ctx', ctx)
|
||||
vim.notify('incorrect setup' .. vim.inspect(locations), vim.lsp.log_levels.WARN)
|
||||
return
|
||||
end
|
||||
if locations == nil or vim.tbl_isempty(locations) then
|
||||
print "References not found"
|
||||
vim.notify('References not found', vim.lsp.log_levels.INFO)
|
||||
return
|
||||
end
|
||||
verbose(locations)
|
||||
local items = locations_to_items(locations)
|
||||
gui.new_list_view({items = items, api = "Reference"})
|
||||
|
||||
ctx.max_items = truncate
|
||||
local items, width, second_part = locations_to_items(locations, ctx)
|
||||
local thread_items = vim.deepcopy(items)
|
||||
log('splits: ', #items, #second_part)
|
||||
|
||||
local ft = vim.api.nvim_buf_get_option(ctx.bufnr or 0, 'ft')
|
||||
|
||||
local wwidth = vim.api.nvim_get_option('columns')
|
||||
local mwidth = _NgConfigValues.width
|
||||
width = math.min(width + 30, math.floor(wwidth * mwidth))
|
||||
-- log(items)
|
||||
-- log(width)
|
||||
opts = {
|
||||
total = #locations,
|
||||
items = items,
|
||||
rawdata = false,
|
||||
ft = ft,
|
||||
width = width,
|
||||
api = 'Reference',
|
||||
enable_preview_edit = true,
|
||||
}
|
||||
local listview
|
||||
if not ctx.no_show then
|
||||
listview = gui.new_list_view(opts)
|
||||
|
||||
if listview == nil then
|
||||
vim.notify('failed to create preview windows', vim.lsp.log_levels.INFO)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if ctx.no_show then
|
||||
opts.side_panel = true
|
||||
local data = require('navigator.render').prepare_for_render(items, opts)
|
||||
return data
|
||||
end
|
||||
|
||||
-- trace("update items", listview.ctrl.class)
|
||||
local nv_ref_async
|
||||
nv_ref_async = vim.loop.new_async(vim.schedule_wrap(function()
|
||||
log('$$$$$$$$ seperate thread... $$$$$$$$')
|
||||
if vim.tbl_isempty(second_part) then
|
||||
return
|
||||
end
|
||||
ctx.max_items = #second_part
|
||||
local items2 = locations_to_items(second_part, ctx)
|
||||
|
||||
vim.list_extend(thread_items, items2)
|
||||
|
||||
local data = require('navigator.render').prepare_for_render(thread_items, opts)
|
||||
log('thread data size', #data)
|
||||
listview.ctrl:on_data_update(data)
|
||||
if nv_ref_async then
|
||||
vim.loop.close(nv_ref_async)
|
||||
else
|
||||
log('invalid asy', nv_ref_async)
|
||||
end
|
||||
end))
|
||||
|
||||
vim.defer_fn(function()
|
||||
vim.loop.new_thread(function(asy)
|
||||
asy:send()
|
||||
end, nv_ref_async)
|
||||
end, 100)
|
||||
|
||||
return listview, items, width
|
||||
end
|
||||
|
||||
local ref_hdlr = function(err, locations, ctx, cfg)
|
||||
_NgConfigValues.closer = nil
|
||||
trace(err, locations, ctx, cfg)
|
||||
if ctx.no_show then
|
||||
return ref_view(err, locations, ctx, cfg)
|
||||
end
|
||||
M.async_hdlr = vim.loop.new_async(vim.schedule_wrap(function()
|
||||
ref_view(err, locations, ctx, cfg)
|
||||
if M.async_hdlr:is_active() then
|
||||
M.async_hdlr:close()
|
||||
end
|
||||
end))
|
||||
M.async_hdlr:send()
|
||||
end
|
||||
|
||||
local async_reference_request = function()
|
||||
local method = {"textDocument/references"}
|
||||
local async_ref = function()
|
||||
local ref_params = vim.lsp.util.make_position_params()
|
||||
local results = {}
|
||||
lsp.call_async('textDocument/definition', ref_params, function(err, result, ctx, config)
|
||||
trace(err, result, ctx, config)
|
||||
if err ~= nil or result == nil then
|
||||
log('failed to get def', err, result, ctx, config)
|
||||
result = {}
|
||||
end
|
||||
for i = 1, #result do
|
||||
if result[i].range == nil and result[i].targetRange then
|
||||
result[i].range = result[i].targetRange
|
||||
end
|
||||
end
|
||||
results.definitions = { error = err, result = result, ctx = ctx, config = config }
|
||||
log(result)
|
||||
ctx = ctx or {}
|
||||
ctx.results = results
|
||||
ctx.combine = true
|
||||
ref_view(err, result, ctx, config)
|
||||
end) -- return asyncresult, canceller
|
||||
|
||||
ref_params.context = { includeDeclaration = false }
|
||||
lsp.call_async('textDocument/references', ref_params, function(err, result, ctx, config)
|
||||
if err ~= nil or result == nil then
|
||||
log('failed to get ref', err, result, ctx, config)
|
||||
result = {}
|
||||
end
|
||||
trace(err, result, ctx, config)
|
||||
results.references = { error = err, result = result, ctx = ctx, config = config }
|
||||
ctx = ctx or {}
|
||||
ctx.results = results
|
||||
ctx.combine = true
|
||||
ref_view(err, result, ctx, config)
|
||||
end) -- return asyncresult, canceller
|
||||
end
|
||||
|
||||
local ref_req = function()
|
||||
if _NgConfigValues.closer ~= nil then
|
||||
-- do not call it twice
|
||||
_NgConfigValues.closer()
|
||||
end
|
||||
local ref_params = vim.lsp.util.make_position_params()
|
||||
ref_params.context = {includeDeclaration = true}
|
||||
return lsp.call_async(method[1], ref_params, ref_hdlr) -- return asyncresult, canceller
|
||||
ref_params.context = { includeDeclaration = true }
|
||||
-- lsp.call_async("textDocument/references", ref_params, ref_hdlr) -- return asyncresult, canceller
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
log('bufnr', bufnr)
|
||||
local ids, closer = vim.lsp.buf_request(bufnr, 'textDocument/references', ref_params, ref_hdlr)
|
||||
log(ids)
|
||||
|
||||
_NgConfigValues.closer = closer
|
||||
return ids, closer
|
||||
end
|
||||
|
||||
local ref = function()
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
|
||||
local ref_params = vim.lsp.util.make_position_params()
|
||||
vim.lsp.for_each_buffer_client(bufnr, function(client, _, _)
|
||||
if client.server_capabilities.referencesProvider then
|
||||
client.request('textDocument/references', ref_params, ref_hdlr, bufnr)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local function side_panel()
|
||||
local Panel = require('guihua.panel')
|
||||
|
||||
local currentWord = vim.fn.expand('<cword>')
|
||||
local p = Panel:new({
|
||||
scope = 'range',
|
||||
header = ' ' .. currentWord .. ' ref ',
|
||||
render = function(bufnr)
|
||||
local ft = vim.api.nvim_buf_get_option(bufnr, 'buftype')
|
||||
if ft == 'nofile' or ft == 'guihua' or ft == 'prompt' then
|
||||
return
|
||||
end
|
||||
local ref_params = vim.lsp.util.make_position_params()
|
||||
local sync_req = require('navigator.lspwrapper').call_sync
|
||||
return sync_req(
|
||||
'textDocument/references',
|
||||
ref_params,
|
||||
{ timeout = 1000, bufnr = bufnr, no_show = true },
|
||||
vim.lsp.with(function(err, locations, ctx, cfg)
|
||||
cfg.side_panel = true
|
||||
return ref_hdlr(err, locations, ctx, cfg)
|
||||
end, { no_show = true })
|
||||
)
|
||||
end,
|
||||
})
|
||||
p:open(true)
|
||||
end
|
||||
|
||||
return {
|
||||
side_panel = side_panel,
|
||||
reference_handler = ref_hdlr,
|
||||
show_reference = async_reference_request
|
||||
reference = ref_req,
|
||||
ref_view = ref_view,
|
||||
async_ref = async_ref,
|
||||
all_ref = ref,
|
||||
}
|
||||
|
@ -0,0 +1,16 @@
|
||||
-- https://github.com/lukas-reineke/dotfiles/blob/master/vim/lua/lsp/rename.lua
|
||||
local M = {}
|
||||
local util = require('navigator.util')
|
||||
-- local rename_prompt = 'Rename -> '
|
||||
|
||||
M.rename = function()
|
||||
local input = vim.ui.input
|
||||
|
||||
vim.ui.input = require('guihua.floating').input
|
||||
vim.lsp.buf.rename()
|
||||
vim.defer_fn(function()
|
||||
vim.ui.input = input
|
||||
end, 1000)
|
||||
end
|
||||
|
||||
return M
|
@ -0,0 +1,199 @@
|
||||
local util = require('navigator.util')
|
||||
local log = util.log
|
||||
local trace = util.trace
|
||||
local clone = require('guihua.util').clone
|
||||
|
||||
local M = {}
|
||||
local function filename(url)
|
||||
if url == nil then
|
||||
return ''
|
||||
end
|
||||
return url:match('^.+/(.+)$') or url
|
||||
end
|
||||
|
||||
local function extension(url)
|
||||
local ext = url:match('^.+(%..+)$') or 'txt'
|
||||
return string.sub(ext, 2)
|
||||
end
|
||||
|
||||
local function get_pads(win_width, text, postfix)
|
||||
local trim = false
|
||||
local margin = win_width - #text - #postfix
|
||||
if margin < 0 then
|
||||
trace('line too long', win_width, #text, #postfix)
|
||||
if #postfix > 1 then
|
||||
trim = true
|
||||
end
|
||||
end
|
||||
local sz = #text
|
||||
if sz < 30 then
|
||||
sz = 30
|
||||
end
|
||||
local space
|
||||
local i = math.floor((sz + 10) / 10)
|
||||
i = i * 10 - #text
|
||||
trace(i, #text, #postfix, postfix, text, win_width)
|
||||
if i + #text + #postfix < win_width then
|
||||
local rem = win_width - i - #text - #postfix
|
||||
rem = math.floor(rem / 10)
|
||||
if rem > 0 then
|
||||
i = i + rem * 10
|
||||
-- log(i)
|
||||
end
|
||||
end
|
||||
|
||||
if i > 3 then
|
||||
i = i - 3
|
||||
end
|
||||
space = string.rep(' ', i)
|
||||
trace(text, i, postfix, win_width)
|
||||
return space, trim
|
||||
end
|
||||
|
||||
function M.prepare_for_render(items, opts)
|
||||
opts = opts or {}
|
||||
if items == nil or #items < 1 then
|
||||
vim.notify('no item found or empty fields', vim.lsp.log_levels.INFO)
|
||||
return
|
||||
end
|
||||
local item = clone(items[1])
|
||||
local display_items = { item }
|
||||
local last_summary_idx = 1
|
||||
local total_ref_in_file = 1
|
||||
local total = opts.total
|
||||
local icon = ' '
|
||||
local lspapi = opts.api or '∑'
|
||||
|
||||
local ok, devicons = pcall(require, 'nvim-web-devicons')
|
||||
if ok then
|
||||
local fn = filename(items[1].filename)
|
||||
local ext = extension(fn)
|
||||
icon = devicons.get_icon(fn, ext) or icon
|
||||
end
|
||||
-- local call_by_presented = false
|
||||
opts.width = opts.width or math.floor(vim.api.nvim_get_option('columns') * 0.8)
|
||||
local win_width = opts.width -- buf
|
||||
|
||||
for i = 1, #items do
|
||||
local space
|
||||
local trim
|
||||
local lspapi_display = lspapi
|
||||
items[i].symbol_name = items[i].symbol_name or '' -- some LSP API does not have range for this
|
||||
|
||||
local fn = display_items[last_summary_idx].filename
|
||||
local dfn = items[i].display_filename
|
||||
if last_summary_idx == 1 then
|
||||
lspapi_display = items[i].symbol_name .. ' ' .. lspapi_display
|
||||
|
||||
trace(items[1], lspapi_display, display_items[last_summary_idx])
|
||||
end
|
||||
|
||||
display_items[last_summary_idx].filename_only = true
|
||||
-- trace(items[i], items[i].filename, last_summary_idx, display_items[last_summary_idx].filename)
|
||||
-- TODO refact display_filename generate part
|
||||
if items[i].filename == fn or opts.hide_filename then
|
||||
space, trim = get_pads(opts.width, icon .. ' ' .. dfn, lspapi_display .. ' 14 of 33 ')
|
||||
if trim and opts.width > 50 and #dfn > opts.width - 20 then
|
||||
local fn1 = string.sub(dfn, 1, opts.width - 50)
|
||||
local fn2 = string.sub(dfn, #dfn - 10, #dfn)
|
||||
display_items[last_summary_idx].display_filename = fn1 .. '' .. fn2
|
||||
space = ' '
|
||||
-- log("trim", fn1, fn2)
|
||||
end
|
||||
local api_disp = string.format(
|
||||
'%s %s%s%s %i',
|
||||
icon,
|
||||
display_items[last_summary_idx].display_filename,
|
||||
space,
|
||||
lspapi_display,
|
||||
total_ref_in_file
|
||||
)
|
||||
|
||||
if total then
|
||||
api_disp = api_disp .. ' of: ' .. tostring(total)
|
||||
end
|
||||
|
||||
display_items[last_summary_idx].text = api_disp
|
||||
total_ref_in_file = total_ref_in_file + 1
|
||||
else
|
||||
lspapi_display = lspapi
|
||||
item = clone(items[i])
|
||||
|
||||
space, trim = get_pads(opts.width, icon .. ' ' .. item.display_filename, lspapi_display .. ' 12 of 33')
|
||||
if trim and opts.width > 52 and #item.display_filename > opts.width - 20 then
|
||||
item.display_filename = string.sub(item.display_filename, 1, opts.width - 52)
|
||||
.. ''
|
||||
.. string.sub(item.display_filename, #item.display_filename - 10, #item.display_filename)
|
||||
space = ' '
|
||||
end
|
||||
item.text = string.format('%s %s%s%s 1', icon, item.display_filename, space, lspapi_display)
|
||||
|
||||
trace(item.text)
|
||||
table.insert(display_items, item)
|
||||
total_ref_in_file = 1
|
||||
last_summary_idx = #display_items
|
||||
end
|
||||
-- content of code lines
|
||||
item = clone(items[i])
|
||||
item.text = require('navigator.util').trim_and_pad(item.text)
|
||||
item.text = string.format('%4i: %s', item.lnum, item.text)
|
||||
local ts_report = ''
|
||||
if item.lhs then
|
||||
ts_report = _NgConfigValues.icons.value_changed
|
||||
end
|
||||
|
||||
-- log(item.text, item.symbol_name, item.uri)
|
||||
-- log(item.text)
|
||||
if item.definition then
|
||||
log('definition', item)
|
||||
ts_report = ts_report .. _NgConfigValues.icons.value_definition .. ' '
|
||||
end
|
||||
local header_len = #ts_report + 4 -- magic number 2
|
||||
trace(ts_report, header_len)
|
||||
|
||||
item.text = item.text:gsub('%s*[%[%(%{]*%s*$', '')
|
||||
if item.call_by ~= nil and item.call_by ~= '' then
|
||||
ts_report = ts_report .. ' ' .. item.call_by
|
||||
end
|
||||
if #ts_report > 1 then
|
||||
space, trim = get_pads(win_width, item.text, ts_report)
|
||||
|
||||
local l = math.max(20, opts.width - math.min(20, #ts_report))
|
||||
if trim and #item.text < l then
|
||||
trim = false
|
||||
end
|
||||
if trim then
|
||||
item.text = string.sub(item.text, 1, l)
|
||||
item.text = util.sub_match(item.text)
|
||||
-- let check if there are unmatched "/'
|
||||
end
|
||||
if #space + #item.text + #ts_report >= win_width then
|
||||
if #item.text + #ts_report >= win_width then
|
||||
space = ' '
|
||||
local len = math.max(win_width - #item.text - 4, 16)
|
||||
|
||||
trace('exceeding', #item.text, #ts_report, win_width, len)
|
||||
ts_report = ts_report:sub(1, len)
|
||||
else
|
||||
local remain = win_width - #item.text - #ts_report
|
||||
trace('remain', remain)
|
||||
space = string.rep(' ', remain)
|
||||
end
|
||||
end
|
||||
item.text = item.text .. space .. ts_report
|
||||
end
|
||||
local tail = display_items[#display_items].text
|
||||
if tail ~= item.text then -- deduplicate
|
||||
trace(item.text)
|
||||
trace(item.call_by)
|
||||
table.insert(display_items, item)
|
||||
end
|
||||
end
|
||||
|
||||
display_items[last_summary_idx].filename_only = true
|
||||
-- display_items[last_summary_idx].text=string.format("%s [%i]", display_items[last_summary_idx].filename,
|
||||
-- total_ref_in_file)
|
||||
return display_items
|
||||
end
|
||||
|
||||
return M
|
@ -0,0 +1,104 @@
|
||||
-- https://github.com/lukas-reineke/dotfiles/blob/master/vim/lua/lsp/rename.lua
|
||||
local M = {}
|
||||
local util = require('navigator.util')
|
||||
local gutil = require('guihua.util')
|
||||
local lsphelper = require('navigator.lspwrapper')
|
||||
local symbols_to_items = lsphelper.symbols_to_items
|
||||
local vfn = vim.fn
|
||||
|
||||
M.add_workspace_folder = function()
|
||||
util.log(vim.ui.input)
|
||||
local input = require('guihua.floating').input
|
||||
input({ prompt = 'Workspace To Add: ', default = vfn.expand('%:p:h') }, function(inputs)
|
||||
vim.lsp.buf.add_workspace_folder(inputs)
|
||||
end)
|
||||
end
|
||||
|
||||
M.remove_workspace_folder = function()
|
||||
local select = require('guihua.gui').select
|
||||
local folders = vim.lsp.buf.list_workspace_folders()
|
||||
|
||||
if #folders > 1 then
|
||||
return select(folders, { prompt = 'select workspace to delete' }, function(workspace)
|
||||
vim.lsp.buf.remove_workspace_folder(workspace)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
M.workspace_symbol = function()
|
||||
local input = require('guihua.floating').input
|
||||
input({ prompt = 'Search symbol: ', default = '' }, function(inputs)
|
||||
util.log(inputs)
|
||||
vim.lsp.buf.workspace_symbol(inputs)
|
||||
end)
|
||||
end
|
||||
|
||||
function M.workspace_symbol_live()
|
||||
local height = _NgConfigValues.height or 0.4
|
||||
height = math.floor(height * vfn.winheight('%'))
|
||||
local width = _NgConfigValues.width or 0.7
|
||||
width = math.floor(vim.api.nvim_get_option('columns') * width)
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
local ft = vim.o.ft
|
||||
local data = { { text = 'input the symbol name to start fuzzy search' } }
|
||||
for _ = 1, height do
|
||||
table.insert(data, { text = '' })
|
||||
end
|
||||
local ListView = require('guihua.listview')
|
||||
local opt = {
|
||||
api = ' ',
|
||||
bg = 'GuihuaListDark',
|
||||
data = data,
|
||||
items = data,
|
||||
enter = true,
|
||||
ft = ft,
|
||||
loc = 'top_center',
|
||||
transparency = 50,
|
||||
prompt = true,
|
||||
on_confirm = function(item)
|
||||
vim.defer_fn(function()
|
||||
if item and item.name then
|
||||
require('navigator.symbols').workspace_symbols(item.name)
|
||||
end
|
||||
end, 10)
|
||||
end,
|
||||
on_input_filter = function(text)
|
||||
local params = { query = text or '#' }
|
||||
local results = vim.lsp.buf_request_sync(bufnr, 'workspace/symbol', params)
|
||||
local result
|
||||
for _, r in pairs(results) do
|
||||
-- util.log(r)
|
||||
if r.result then
|
||||
result = r.result
|
||||
break
|
||||
end
|
||||
end
|
||||
if not result then
|
||||
result = {}
|
||||
end
|
||||
|
||||
local items = symbols_to_items(result)
|
||||
items = gutil.dedup(items, 'name', 'kind')
|
||||
return items
|
||||
end,
|
||||
rect = { height = height, pos_x = 0, pos_y = 0, width = width },
|
||||
}
|
||||
|
||||
local win = ListView:new(opt)
|
||||
win:on_draw({})
|
||||
-- require('guihua.gui').new_list_view(opt)
|
||||
end
|
||||
|
||||
M.list_workspace_folders = function()
|
||||
local folders = vim.lsp.buf.list_workspace_folders()
|
||||
if #folders > 0 then
|
||||
return require('navigator.gui').new_list_view({
|
||||
items = folders,
|
||||
border = 'single',
|
||||
rawdata = true,
|
||||
on_move = function() end,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
@ -0,0 +1,38 @@
|
||||
# Sandbox/Tutorial
|
||||
|
||||
## introduction
|
||||
|
||||
The folder contains `init.lua`, whitch is a minium vimrc to setup following plugins. Those plugin are some of the
|
||||
most used plugins for programmer.
|
||||
|
||||
- lspconfig
|
||||
- treesitter
|
||||
- navigator
|
||||
- nvim-cmp
|
||||
- luasnip
|
||||
- aurora (colorscheme used in the screenshot)
|
||||
|
||||
There are three folders `js`, `go`, `py`. Those folders have some basic source code you can play with.
|
||||
The init will install the plugins in ``/tmp/nvim`` folder. It will not affect your current setup.
|
||||
|
||||
## Install LSP
|
||||
|
||||
The playground has js, py, go folder, so you can install either one your self in your PATH.
|
||||
If you want to try lua, Please check sumneko setup in init.lua make sure it pointed to correct path. By default it
|
||||
potint to ~/github/sumneko if not existed in your PATH.
|
||||
|
||||
## run init.lua
|
||||
|
||||
```bash
|
||||
cd py
|
||||
neovim -u init.lua
|
||||
```
|
||||
|
||||
Move your cursor around and try to
|
||||
|
||||
- Edit the code
|
||||
- Check symbol reference with `<esc>gr`
|
||||
- Check document symbol with `<esc>g0`
|
||||
- treesitter symbole `<esc>gT`
|
||||
- peek definition `<esc>gp`
|
||||
- ...
|
@ -0,0 +1,8 @@
|
||||
package main
|
||||
|
||||
func Fib(n int) int {
|
||||
if n < 2 {
|
||||
return n
|
||||
}
|
||||
return Fib(n-1) + Fib(n-2)
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestFib(t *testing.T) {
|
||||
require.NoError(t, nil)
|
||||
d := Fib(1)
|
||||
fmt.Println(d)
|
||||
if d != 1 {
|
||||
t.Errorf("NewDog failled %v", d)
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
// "net/http"
|
||||
"net/http/httptest"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Dog struct {
|
||||
name string
|
||||
age int
|
||||
owner string
|
||||
}
|
||||
|
||||
func NewDog(name string, age int) *Dog {
|
||||
return &Dog{name: name, age: age}
|
||||
}
|
||||
|
||||
// SetOwner
|
||||
func (d *Dog) SetOwner(owner string) {
|
||||
d.owner = owner
|
||||
}
|
||||
|
||||
// SetDogName
|
||||
func (d *Dog) SetDogName(name string) {
|
||||
if d == nil {
|
||||
d = NewDog(name, 0)
|
||||
d.name = name
|
||||
} else {
|
||||
d.name = name
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Dog) SetOwnerUtf8(name []byte) {
|
||||
}
|
||||
|
||||
func fun1() {
|
||||
}
|
||||
|
||||
func fun1_test() {
|
||||
d := NewDog("", 1)
|
||||
NewDog("abc", 12)
|
||||
// fmt.Printf("abc", 1)
|
||||
time.Date(12, 12, 12, 33, 12, 55, 22, nil)
|
||||
|
||||
d.SetOwnerUtf8([]byte{1})
|
||||
w := httptest.NewRecorder()
|
||||
w.Write([]byte{})
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestDog(t *testing.T) {
|
||||
require.NoError(t, nil)
|
||||
d := NewDog("Fibi", 4)
|
||||
fmt.Println(d.name)
|
||||
if d.name != "Fibi" {
|
||||
t.Errorf("NewDog failled %v", d)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCat(t *testing.T) {
|
||||
d := NewDog("Fibi cat", 4)
|
||||
fmt.Println(d.name)
|
||||
if d.name != "Fibi cat" {
|
||||
t.Errorf("NewDog failled %v", d)
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestCow(t *testing.T) {
|
||||
require.NoError(t, nil)
|
||||
d := NewDog("Fibi", 4)
|
||||
fmt.Println(d.name)
|
||||
if d.name != "Fibi" {
|
||||
t.Errorf("NewDog failled %v", d)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHorse(t *testing.T) {
|
||||
d := NewDog("Fibi cat", 4)
|
||||
fmt.Println(d.name)
|
||||
if d.name != "Fibi cat" {
|
||||
t.Errorf("NewDog failled %v", d)
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
//"math"
|
||||
)
|
||||
|
||||
type geometry interface {
|
||||
area() float64
|
||||
perim() float64
|
||||
}
|
||||
|
||||
type rect struct {
|
||||
width float64 `-line:"width"`
|
||||
height float64 `-line:"height"`
|
||||
}
|
||||
|
||||
type rect2 struct {
|
||||
width int `yml:"width"`
|
||||
height int `yml:"height"`
|
||||
}
|
||||
|
||||
func (r rect) area() float64 {
|
||||
return r.width * r.height
|
||||
}
|
||||
|
||||
func (r rect) perim() float64 {
|
||||
return 2*r.width + 2*r.height
|
||||
}
|
||||
|
||||
type circle struct {
|
||||
radius float64
|
||||
}
|
||||
|
||||
func (c circle) area() float64 {
|
||||
return math.Pi * c.radius * c.radius
|
||||
}
|
||||
|
||||
func (c circle) perim() float64 {
|
||||
return 2 * math.Pi * c.radius
|
||||
}
|
||||
|
||||
func measure(g geometry) int {
|
||||
fmt.Println(g)
|
||||
fmt.Println(g.area())
|
||||
fmt.Println(g.perim())
|
||||
return 1
|
||||
}
|
||||
|
||||
func m2() {
|
||||
measure(rect{width: 3})
|
||||
}
|
||||
|
||||
func M2() {
|
||||
measure(rect{width: 3})
|
||||
}
|
||||
|
||||
func interfaceTest() {
|
||||
r := rect{width: 3, height: 4}
|
||||
c := circle{radius: 5}
|
||||
measure(r)
|
||||
measure(c)
|
||||
d := circle{radius: 10}
|
||||
fmt.Println()
|
||||
fun2(d)
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// main
|
||||
// note: this is main func
|
||||
func main() {
|
||||
i := 32
|
||||
i = i + 1
|
||||
fmt.Println("hello, world", i)
|
||||
var uns1 unsafe.Pointer
|
||||
|
||||
var x struct {
|
||||
a int64
|
||||
b bool
|
||||
c string
|
||||
}
|
||||
const M, N = unsafe.Sizeof(x.c), unsafe.Sizeof(x)
|
||||
fmt.Println(M, N, uns1) // 16 32
|
||||
|
||||
var perr *fs.PathError
|
||||
if errors.As(nil, &perr) {
|
||||
fmt.Println(perr.Path)
|
||||
}
|
||||
myfunc3("a", "b")
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
// import "fmt"
|
||||
|
||||
type person struct {
|
||||
name string
|
||||
age int
|
||||
}
|
||||
|
||||
type say interface {
|
||||
hello() string
|
||||
}
|
||||
|
||||
type strudent struct {
|
||||
person struct {
|
||||
name string
|
||||
age int
|
||||
}
|
||||
}
|
||||
|
||||
func newPerson(name string) *person {
|
||||
p := person{name: name}
|
||||
fmt.Println("")
|
||||
p.age = 42
|
||||
return &p
|
||||
}
|
||||
|
||||
func newPerson2(name, say string) {
|
||||
fmt.Println(name, say)
|
||||
}
|
||||
|
||||
func b() {
|
||||
newPerson2("a", "say")
|
||||
|
||||
ret := measure(rect{width: 3})
|
||||
fmt.Println(ret)
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package test
|
||||
|
||||
type Dog struct {
|
||||
name string
|
||||
age int
|
||||
owner string
|
||||
}
|
||||
|
||||
func NewDog(name string, age int) *Dog {
|
||||
return &Dog{name: name, age: age}
|
||||
}
|
||||
|
||||
// SetOwner
|
||||
func (d *Dog) SetOwner(owner string) {
|
||||
d.owner = owner
|
||||
}
|
||||
|
||||
// SetName
|
||||
func (d *Dog) SetName(name string) {
|
||||
if d == nil {
|
||||
d = NewDog(name, 0)
|
||||
d.name = name
|
||||
} else {
|
||||
d.name = name
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package tekkkt
|
||||
|
||||
type Dog kkktruct {
|
||||
name kkktring
|
||||
age int
|
||||
owner kkktring
|
||||
}
|
||||
|
||||
func NewDog(name kkktring, age int) *Dog {
|
||||
return &Dog{name: name, age: age}
|
||||
}
|
||||
|
||||
// kkketOwner
|
||||
func (d *Dog) kkketOwner(owner kkktring) {
|
||||
d.owner = owner
|
||||
}
|
||||
|
||||
// kkketName
|
||||
func (d *Dog) kkketName(name kkktring) {
|
||||
if d == nil {
|
||||
d = NewDog(name, 0)
|
||||
d.name = name
|
||||
} elkkke {
|
||||
d.name = name
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDog(t *testing.T) {
|
||||
d := NewDog("Fibi", 4)
|
||||
fmt.Println(d.name)
|
||||
if d.name != "Fibi" {
|
||||
t.Errorf("NewDog failled %v", d)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCat(t *testing.T) {
|
||||
d := NewDog("Fibi cat", 4)
|
||||
fmt.Println(d.name)
|
||||
if d.name != "Fibi cat" {
|
||||
t.Errorf("NewDog failled %v", d)
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
// "strings"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// type Name2 struct {
|
||||
// f1 string
|
||||
// f2 int
|
||||
// }
|
||||
//
|
||||
// type name4 struct {
|
||||
// f1 string
|
||||
// f2 int
|
||||
// }
|
||||
//
|
||||
// type name5 struct {
|
||||
// f1 string
|
||||
// f2 int
|
||||
// }
|
||||
//
|
||||
// func test2() {
|
||||
// type some struct {
|
||||
// Success bool `-line:"success"`
|
||||
// Failure bool
|
||||
// }
|
||||
//
|
||||
// // myfunc("aaa", "bbb")
|
||||
// }
|
||||
|
||||
func myfunc3(v, v2 string) error {
|
||||
time.After(time.Hour)
|
||||
fmt.Println(v, v2)
|
||||
// fmt.Println(kk)
|
||||
//
|
||||
|
||||
time.Date(2020, 12, 11, 21, 11, 44, 12, nil)
|
||||
time.Date(2020, 1, 11, 11, 11, 2, 1, nil)
|
||||
time.Date(1111, 22, 11, 1, 1, 1, 1, nil)
|
||||
time.Date(12345, 2333, 444, 555, 66, 1, 22, nil)
|
||||
fmt.Println(`kkkkkk`)
|
||||
log.Info(`abc`)
|
||||
log.Infof(`log %s`, `def`)
|
||||
log.Infof(`log %d`, 33)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// func myfunc4() {
|
||||
// // myfunc("aaa", "bbb") // time.Date(12,11, )
|
||||
// // myfunc("abc", "def")
|
||||
// // myfunc("1", "2")
|
||||
// }
|
||||
//
|
||||
// func mytest2() {
|
||||
// i := 1
|
||||
// log.Infof("%d", i)
|
||||
// myfunc4()
|
||||
// }
|
||||
//
|
||||
// func myfunc5() {
|
||||
// hellostring := "hello"
|
||||
// if strings.Contains(hellostring, "hello") {
|
||||
// fmt.Println("it is there")
|
||||
// }
|
||||
// }
|
@ -0,0 +1,132 @@
|
||||
vim.cmd([[set runtimepath=$VIMRUNTIME]])
|
||||
vim.cmd([[set packpath=/tmp/nvim/site]])
|
||||
|
||||
local package_root = '/tmp/nvim/site/pack'
|
||||
local install_path = package_root .. '/packer/start/packer.nvim'
|
||||
|
||||
-- IMPORTANT: update the sumneko setup if you need lua language server
|
||||
-- I installed it in '/github/sumneko/lua-language-server'
|
||||
local sumneko_root_path = vim.fn.expand('$HOME') .. '/github/sumneko/lua-language-server'
|
||||
local sumneko_binary = vim.fn.expand('$HOME') .. '/github/sumneko/lua-language-server/bin/macOS/lua-language-server'
|
||||
|
||||
local lua_cfg = {
|
||||
-- cmd = { sumneko_binary, '-E', sumneko_root_path .. '/main.lua' },
|
||||
settings = {
|
||||
Lua = {
|
||||
runtime = { version = 'LuaJIT', path = vim.split(package.path, ';') },
|
||||
diagnostics = { enable = true },
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if vim.fn.executable('lua-language-server') == 0 then
|
||||
lua_cfg.cmd = { sumneko_binary, '-E', sumneko_root_path .. '/main.lua' }
|
||||
end
|
||||
|
||||
local function load_plugins()
|
||||
require('packer').startup({
|
||||
function(use)
|
||||
use({ 'wbthomason/packer.nvim' })
|
||||
use({
|
||||
'nvim-treesitter/nvim-treesitter',
|
||||
config = function()
|
||||
require('nvim-treesitter.configs').setup({
|
||||
ensure_installed = { 'python', 'go', 'javascript' },
|
||||
highlight = { enable = true },
|
||||
})
|
||||
end,
|
||||
run = ':TSUpdate',
|
||||
})
|
||||
use({ 'neovim/nvim-lspconfig' })
|
||||
use({ 'ray-x/lsp_signature.nvim' })
|
||||
use({ 'ray-x/aurora' })
|
||||
use({
|
||||
-- 'ray-x/navigator.lua',
|
||||
'~/github/ray-x/navigator.lua',
|
||||
requires = { 'ray-x/guihua.lua', run = 'cd lua/fzy && make' },
|
||||
config = function()
|
||||
require('navigator').setup({
|
||||
debug = true,
|
||||
keymaps = {
|
||||
{ key = 'gK', func = vim.lsp.buf.definition, doc = 'definition' },
|
||||
{
|
||||
key = '<leader>ld',
|
||||
func = require('navigator.diagnostics').show_buf_diagnostics,
|
||||
desc = 'show_buf_diagnostics',
|
||||
},
|
||||
},
|
||||
icons = {
|
||||
diagnostic_virtual_text = '',
|
||||
},
|
||||
})
|
||||
end,
|
||||
})
|
||||
use({ 'L3MON4D3/LuaSnip' })
|
||||
use({
|
||||
'hrsh7th/nvim-cmp',
|
||||
requires = {
|
||||
'hrsh7th/cmp-nvim-lsp',
|
||||
'saadparwaiz1/cmp_luasnip',
|
||||
},
|
||||
config = function()
|
||||
local cmp = require('cmp')
|
||||
local luasnip = require('luasnip')
|
||||
cmp.setup({
|
||||
snippet = {
|
||||
expand = function(args)
|
||||
require('luasnip').lsp_expand(args.body)
|
||||
end,
|
||||
},
|
||||
|
||||
mapping = {
|
||||
['<CR>'] = cmp.mapping.confirm({ select = true }),
|
||||
['<Tab>'] = cmp.mapping(function(fallback)
|
||||
if cmp.visible() then
|
||||
cmp.confirm({ select = true })
|
||||
elseif luasnip.expand_or_locally_jumpable() then
|
||||
luasnip.expand_or_jump()
|
||||
else
|
||||
fallback()
|
||||
end
|
||||
end, { 'i', 's' }),
|
||||
},
|
||||
|
||||
sources = {
|
||||
{ name = 'nvim_lsp' },
|
||||
{ name = 'buffer' },
|
||||
},
|
||||
})
|
||||
require('cmp').setup.cmdline(':', {
|
||||
sources = {
|
||||
{ name = 'cmdline' },
|
||||
},
|
||||
})
|
||||
require('cmp').setup.cmdline('/', {
|
||||
sources = {
|
||||
{ name = 'buffer' },
|
||||
},
|
||||
})
|
||||
end,
|
||||
})
|
||||
end,
|
||||
config = {
|
||||
package_root = package_root,
|
||||
compile_path = install_path .. '/plugin/packer_compiled.lua',
|
||||
},
|
||||
})
|
||||
end
|
||||
|
||||
if vim.fn.isdirectory(install_path) == 0 then
|
||||
vim.fn.system({
|
||||
'git',
|
||||
'clone',
|
||||
'https://github.com/wbthomason/packer.nvim',
|
||||
install_path,
|
||||
})
|
||||
load_plugins()
|
||||
require('packer').sync()
|
||||
vim.cmd('colorscheme aurora')
|
||||
else
|
||||
load_plugins()
|
||||
vim.cmd('colorscheme aurora')
|
||||
end
|
@ -0,0 +1,61 @@
|
||||
vim.cmd([[set runtimepath=$VIMRUNTIME]])
|
||||
vim.cmd([[set packpath=/tmp/nvim/site]])
|
||||
|
||||
local package_root = '/tmp/nvim/site/pack'
|
||||
local install_path = package_root .. '/packer/start/packer.nvim'
|
||||
vim.g.coq_settings = {
|
||||
['auto_start'] = 'shut-up',
|
||||
}
|
||||
|
||||
local function load_plugins()
|
||||
require('packer').startup({
|
||||
function(use)
|
||||
use('wbthomason/packer.nvim')
|
||||
use('neovim/nvim-lspconfig')
|
||||
use({
|
||||
'williamboman/nvim-lsp-installer',
|
||||
config = function()
|
||||
local lsp_installer = require('nvim-lsp-installer')
|
||||
lsp_installer.setup{}
|
||||
end,
|
||||
})
|
||||
use({
|
||||
'ray-x/navigator.lua',
|
||||
config = function()
|
||||
require('navigator').setup({
|
||||
debug = true,
|
||||
lsp_installer = true,
|
||||
keymaps = { { key = 'gR', func = "require('navigator.reference').async_ref()" } },
|
||||
})
|
||||
end,
|
||||
})
|
||||
use('ray-x/guihua.lua')
|
||||
-- -- COQ (Autocompletion)
|
||||
use('ms-jpq/coq_nvim')
|
||||
use('ms-jpq/coq.artifacts')
|
||||
use('ms-jpq/coq.thirdparty')
|
||||
use('ray-x/aurora')
|
||||
end,
|
||||
config = {
|
||||
package_root = package_root,
|
||||
compile_path = install_path .. '/plugin/packer_compiled.lua',
|
||||
},
|
||||
})
|
||||
-- navigator/LSP setup
|
||||
end
|
||||
|
||||
if vim.fn.isdirectory(install_path) == 0 then
|
||||
print('install packer')
|
||||
vim.fn.system({
|
||||
'git',
|
||||
'clone',
|
||||
'https://github.com/wbthomason/packer.nvim',
|
||||
install_path,
|
||||
})
|
||||
load_plugins()
|
||||
require('packer').sync()
|
||||
vim.cmd('colorscheme aurora')
|
||||
else
|
||||
load_plugins()
|
||||
vim.cmd('colorscheme aurora')
|
||||
end
|
@ -0,0 +1,79 @@
|
||||
vim.cmd([[set runtimepath=$VIMRUNTIME]])
|
||||
vim.cmd([[set packpath=/tmp/nvim/site]])
|
||||
|
||||
local package_root = '/tmp/nvim/site/pack'
|
||||
local install_path = package_root .. '/packer/start/packer.nvim'
|
||||
|
||||
local function load_plugins()
|
||||
require('packer').startup({
|
||||
function(use)
|
||||
use('wbthomason/packer.nvim')
|
||||
use('neovim/nvim-lspconfig')
|
||||
use({
|
||||
'williamboman/nvim-lsp-installer',
|
||||
config = function()
|
||||
require('nvim-lsp-installer').setup({})
|
||||
end,
|
||||
})
|
||||
use({
|
||||
'ray-x/navigator.lua',
|
||||
-- '~/github/ray-x/navigator.lua',
|
||||
config = function()
|
||||
require('navigator').setup({
|
||||
debug = true,
|
||||
lsp_installer = true,
|
||||
keymaps = { { key = 'gR', func = "require('navigator.reference').async_ref()" } },
|
||||
})
|
||||
end,
|
||||
})
|
||||
use('ray-x/guihua.lua')
|
||||
|
||||
use({
|
||||
'hrsh7th/nvim-cmp',
|
||||
requires = {
|
||||
'hrsh7th/cmp-nvim-lsp',
|
||||
},
|
||||
config = function()
|
||||
local cmp = require('cmp')
|
||||
cmp.setup({
|
||||
mapping = {
|
||||
['<CR>'] = cmp.mapping.confirm({ select = true }),
|
||||
['<Tab>'] = cmp.mapping(function(fallback)
|
||||
if cmp.visible() then
|
||||
cmp.confirm({ select = true })
|
||||
else
|
||||
fallback()
|
||||
end
|
||||
end, { 'i', 's' }),
|
||||
},
|
||||
sources = {
|
||||
{ name = 'nvim_lsp' },
|
||||
},
|
||||
})
|
||||
end,
|
||||
})
|
||||
use('ray-x/aurora')
|
||||
end,
|
||||
config = {
|
||||
package_root = package_root,
|
||||
compile_path = install_path .. '/plugin/packer_compiled.lua',
|
||||
},
|
||||
})
|
||||
-- navigator/LSP setup
|
||||
end
|
||||
|
||||
if vim.fn.isdirectory(install_path) == 0 then
|
||||
print('install packer')
|
||||
vim.fn.system({
|
||||
'git',
|
||||
'clone',
|
||||
'https://github.com/wbthomason/packer.nvim',
|
||||
install_path,
|
||||
})
|
||||
load_plugins()
|
||||
require('packer').sync()
|
||||
vim.cmd('colorscheme aurora')
|
||||
else
|
||||
load_plugins()
|
||||
vim.cmd('colorscheme aurora')
|
||||
end
|
@ -0,0 +1,7 @@
|
||||
const sayHiToSomeone = (callback) => {
|
||||
return callbcak();
|
||||
};
|
||||
|
||||
sayHiToSomeone(()=> {
|
||||
console.log("aaa")
|
||||
})
|
@ -0,0 +1,12 @@
|
||||
function makeFunc() {
|
||||
var browser = 'Mozilla';
|
||||
function displayName() {
|
||||
alert(browser);
|
||||
var message = 'hello ' + browser;
|
||||
alert(message);
|
||||
}
|
||||
return displayName;
|
||||
}
|
||||
|
||||
var myFunc = makeFunc();
|
||||
myFunc();
|
@ -0,0 +1,11 @@
|
||||
function curriedDot(vector1) {
|
||||
return function(vector2) {
|
||||
return vector1.reduce(
|
||||
(sum, element, index) => (sum += element * vector2[index]),
|
||||
0
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const sumElements = curriedDot([1, 1, 1]);
|
||||
console.log()
|
@ -0,0 +1 @@
|
||||
const time = new Date(12, 33, )
|
@ -0,0 +1,3 @@
|
||||
console.log("abc");
|
||||
var kingsglove = "abcdefg";
|
||||
console.log()
|
@ -0,0 +1,14 @@
|
||||
from random import shuffle
|
||||
a = list(range(5))
|
||||
|
||||
def go(beg, c, b):
|
||||
if beg >= len(a):
|
||||
print(a )
|
||||
for i in range(beg, len(a)):
|
||||
a[beg], a[i] = a[i], a[beg]
|
||||
go(beg + 1)
|
||||
a[beg], a[i] = a[i], a[beg]
|
||||
print(a, b)
|
||||
|
||||
go(0, 1, 4)
|
||||
shuffle([1, 2,3 ])
|
@ -0,0 +1,79 @@
|
||||
import math
|
||||
import numpy as np
|
||||
import os
|
||||
|
||||
class Dog:
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.tricks = [] # creates a new empty list for each dog
|
||||
|
||||
def add_trick(self, trick):
|
||||
self.tricks.append(trick)
|
||||
|
||||
|
||||
d = Dog('Fido')
|
||||
d.add_trick('roll over')
|
||||
print(d.tricks)
|
||||
|
||||
def test_func():
|
||||
k = [1, 2, 3]
|
||||
sum = 0
|
||||
for i in range(k, 1, 2):
|
||||
sum += 1
|
||||
print(sum)
|
||||
|
||||
def greet(greeting, name):
|
||||
"""
|
||||
This function greets to
|
||||
the person passed in as
|
||||
a parameter
|
||||
"""
|
||||
print(greeting + name + ". Good morning!")
|
||||
|
||||
|
||||
# def greet(greeting, name, msg1, msg2):
|
||||
# """
|
||||
# This function greets to
|
||||
# the person passed in as
|
||||
# a parameter
|
||||
# """
|
||||
# print(greeting + name + ". Good morning!")
|
||||
|
||||
|
||||
greet("a", "b")
|
||||
|
||||
|
||||
def greet2():
|
||||
print("whatever")
|
||||
|
||||
|
||||
def greet3(name):
|
||||
greet2()
|
||||
greet("hey", "dude", "", "")
|
||||
print("whatever" + name)
|
||||
|
||||
def greet3():
|
||||
pass
|
||||
|
||||
|
||||
greet2()
|
||||
|
||||
greet("name", "name")
|
||||
|
||||
greet3("name")
|
||||
greet3("")
|
||||
|
||||
greet("1", "2")
|
||||
|
||||
|
||||
def greeting(greet: int, *, g):
|
||||
"""
|
||||
This function greets to
|
||||
the person passed in as
|
||||
a parameter
|
||||
"""
|
||||
print(greet + g + ". Good morning!")
|
||||
|
||||
|
||||
np.empty(1, order="F")
|
||||
np.empty(1, order="F")
|
@ -0,0 +1,19 @@
|
||||
import pandas as pd
|
||||
import io
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
pow()
|
||||
|
||||
|
||||
arg = 111
|
||||
bufio = io
|
||||
filename = 'my_excel.xls'
|
||||
|
||||
|
||||
|
||||
|
||||
df = pd.read_excel(abc, defgh)
|
@ -1,24 +0,0 @@
|
||||
" built upon popfix api(https://github.com/RishabhRD/popfix)
|
||||
" for parameter references see popfix readme.
|
||||
|
||||
if exists('g:loaded_navigator_lsp') | finish | endif
|
||||
|
||||
let s:save_cpo = &cpo
|
||||
set cpo&vim
|
||||
|
||||
if ! exists('g:navigator_lsp_location_opts')
|
||||
let g:navigator_lsp_location_opts = v:null
|
||||
endif
|
||||
|
||||
if ! exists('g:navigator_lsp_symbols_opts')
|
||||
let g:navigator_lsp_symbols_opts = v:null
|
||||
endif
|
||||
|
||||
if ! exists('g:navigator_lsp_codeaction_opts')
|
||||
let g:navigator_lsp_codeaction_opts = v:null
|
||||
endif
|
||||
|
||||
let &cpo = s:save_cpo
|
||||
unlet s:save_cpo
|
||||
|
||||
let g:loaded_navigator_lsp = 1
|
@ -0,0 +1,6 @@
|
||||
std="lua52+vim"
|
||||
|
||||
[rules]
|
||||
global_usage = "allow"
|
||||
multiple_statements = "allow"
|
||||
unused_variable = "allow"
|
@ -0,0 +1,4 @@
|
||||
indent_type = "Spaces"
|
||||
indent_width = 2
|
||||
column_width = 120
|
||||
quote_style = "AutoPreferSingle"
|
@ -0,0 +1,69 @@
|
||||
local busted = require('plenary/busted')
|
||||
|
||||
local eq = assert.are.same
|
||||
local cur_dir = vim.fn.expand('%:p:h')
|
||||
-- local status = require("plenary.reload").reload_module("go.nvim")
|
||||
-- status = require("plenary.reload").reload_module("nvim-treesitter")
|
||||
|
||||
-- local ulog = require('go.utils').log
|
||||
describe('should run lsp call hierarchy', function()
|
||||
vim.cmd([[packadd navigator.lua]])
|
||||
vim.cmd([[packadd guihua.lua]])
|
||||
local status = require('plenary.reload').reload_module('navigator')
|
||||
status = require('plenary.reload').reload_module('guihua')
|
||||
status = require('plenary.reload').reload_module('lspconfig')
|
||||
|
||||
local path = cur_dir .. '/tests/fixtures/interface.go' -- %:p:h ? %:p
|
||||
local cmd = " silent exe 'e " .. path .. "'"
|
||||
vim.cmd(cmd)
|
||||
vim.cmd([[cd %:p:h]])
|
||||
local bufn = vim.fn.bufnr('')
|
||||
require('navigator').setup({
|
||||
debug = true, -- log output, set to true and log path: ~/.local/share/nvim/gh.log
|
||||
width = 0.75, -- max width ratio (number of cols for the floating window) / (window width)
|
||||
height = 0.3, -- max list window height, 0.3 by default
|
||||
preview_height = 0.35, -- max height of preview windows
|
||||
border = 'none',
|
||||
})
|
||||
|
||||
-- allow gopls start
|
||||
for _ = 1, 20 do
|
||||
vim.wait(400, function() end)
|
||||
local found = false
|
||||
for _, client in ipairs(vim.lsp.get_active_clients()) do
|
||||
if client.name == 'gopls' then
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if found then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
it('should show panel', function()
|
||||
vim.fn.setpos('.', { bufn, 24, 15, 0 })
|
||||
require('navigator.hierarchy').incoming_calls_panel()
|
||||
|
||||
vim.wait(300, function() end)
|
||||
|
||||
local panel = require('guihua.panel').debug()
|
||||
eq(panel.name, 'Panel')
|
||||
|
||||
vim.wait(500, function() end)
|
||||
panel = require('guihua.panel').debug()
|
||||
print(vim.inspect(panel))
|
||||
-- eq(
|
||||
-- panel.activePanel.sections[1].header[1],
|
||||
-- '──────────Call Hierarchy──────────'
|
||||
-- )
|
||||
-- eq(panel.activePanel.sections[1].nodes[1].name, 'measure')
|
||||
end)
|
||||
|
||||
it('should not crash and show hierarchy', function()
|
||||
vim.fn.setpos('.', { bufn, 24, 15, 0 })
|
||||
local ret = require('navigator.hierarchy')._call_hierarchy()
|
||||
vim.wait(400, function() end)
|
||||
eq(ret, ret) -- make sure doesn't crash the result
|
||||
end)
|
||||
end)
|
@ -0,0 +1,3 @@
|
||||
module github.com/navigator/tests
|
||||
|
||||
go 1.17
|
@ -0,0 +1,72 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
//"math"
|
||||
)
|
||||
|
||||
type geometry interface {
|
||||
area() float64
|
||||
perim() float64
|
||||
}
|
||||
|
||||
type rect struct {
|
||||
width float64 `-line:"width"`
|
||||
height float64 `-line:"height"`
|
||||
}
|
||||
|
||||
type rect2 struct {
|
||||
width int `yml:"width"`
|
||||
height int `yml:"height"`
|
||||
}
|
||||
|
||||
func (r rect) area() float64 {
|
||||
return r.width * r.height
|
||||
}
|
||||
|
||||
func (r rect) perim() float64 {
|
||||
return 2*r.width + 2*r.height
|
||||
}
|
||||
|
||||
type circle struct {
|
||||
radius float64
|
||||
}
|
||||
|
||||
func (c circle) area() float64 {
|
||||
return math.Pi * c.radius * c.radius
|
||||
}
|
||||
|
||||
func (c circle) perim() float64 {
|
||||
return 2 * math.Pi * c.radius
|
||||
}
|
||||
|
||||
func measure(g geometry) int {
|
||||
fmt.Println(g)
|
||||
fmt.Println(g.area())
|
||||
fmt.Println(g.perim())
|
||||
return 1
|
||||
}
|
||||
|
||||
func m2() {
|
||||
measure(rect{width: 3})
|
||||
}
|
||||
|
||||
func M2() {
|
||||
measure(rect{width: 3})
|
||||
}
|
||||
|
||||
func runinterface() {
|
||||
r := rect{width: 3, height: 4}
|
||||
c := circle{radius: 5}
|
||||
measure(r)
|
||||
measure(c)
|
||||
d := circle{radius: 10}
|
||||
fmt.Println(d)
|
||||
}
|
||||
|
||||
func main() {
|
||||
M2()
|
||||
m2()
|
||||
runinterface()
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func interfaceTest() {
|
||||
r := rect{width: 3, height: 4}
|
||||
c := circle{radius: 5}
|
||||
measure(r)
|
||||
measure(c)
|
||||
d := circle{radius: 10}
|
||||
fmt.Println(d)
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
set rtp +=.
|
||||
set rtp +=../plenary.nvim/
|
||||
set rtp +=../nvim-treesitter/
|
||||
set rtp +=../nvim-lspconfig/
|
||||
set rtp +=../guihua.lua/
|
||||
set rtp +=../navigator.lua/
|
||||
|
||||
runtime! plugin/plenary.vim
|
||||
runtime! plugin/nvim-treesitter.vim
|
||||
runtime! plugin/guihua.vim
|
||||
runtime! plugin/navigator.vim
|
||||
runtime! plugin/nvim-lspconfig.vim
|
||||
|
||||
set noswapfile
|
||||
set nobackup
|
||||
|
||||
filetype indent off
|
||||
set nowritebackup
|
||||
set noautoindent
|
||||
set nocindent
|
||||
set nosmartindent
|
||||
set indentexpr=
|
||||
|
||||
|
||||
lua << EOF
|
||||
_G.test_rename = true
|
||||
_G.test_close = true
|
||||
require("plenary/busted")
|
||||
require'nvim-treesitter.configs'.setup {
|
||||
ensure_installed = {"go"}, -- one of "all", "maintained" (parsers with maintainers), or a list of languages
|
||||
highlight = {
|
||||
enable = true, -- false will disable the whole extension
|
||||
},
|
||||
}
|
||||
|
||||
-- for testing load gopls ahead
|
||||
|
||||
require'lspconfig'.gopls.setup{}
|
||||
|
||||
require'navigator'.setup({
|
||||
debug = false, -- log output, set to true and log path: ~/.local/share/nvim/gh.log
|
||||
|
||||
icons={code_action_icon = " "},
|
||||
|
||||
width = 0.75, -- max width ratio (number of cols for the floating window) / (window width)
|
||||
height = 0.3, -- max list window height, 0.3 by default
|
||||
preview_height = 0.35, -- max height of preview windows
|
||||
border = 'none',
|
||||
})
|
||||
EOF
|
@ -0,0 +1,146 @@
|
||||
local helpers = {}
|
||||
local busted = require('plenary/busted')
|
||||
|
||||
local eq = assert.are.same
|
||||
local cur_dir = vim.fn.expand('%:p:h')
|
||||
-- local status = require("plenary.reload").reload_module("go.nvim")
|
||||
-- status = require("plenary.reload").reload_module("nvim-treesitter")
|
||||
|
||||
-- local ulog = require('go.utils').log
|
||||
describe('should run lsp reference', function()
|
||||
-- vim.fn.readfile('minimal.vim')
|
||||
local nvim_6 = true
|
||||
if debug.getinfo(vim.lsp.handlers.signature_help).nparams > 4 then
|
||||
nvim_6 = false
|
||||
end
|
||||
local result = {
|
||||
{
|
||||
range = { ['end'] = { character = 6, line = 14 }, start = { character = 1, line = 14 } },
|
||||
uri = 'file://' .. cur_dir .. '/tests/fixtures/interface.go',
|
||||
},
|
||||
{
|
||||
range = { ['end'] = { character = 15, line = 24 }, start = { character = 10, line = 24 } },
|
||||
uri = 'file://' .. cur_dir .. '/tests/fixtures/interface.go',
|
||||
},
|
||||
{
|
||||
range = { ['end'] = { character = 17, line = 28 }, start = { character = 12, line = 28 } },
|
||||
uri = 'file://' .. cur_dir .. '/tests/fixtures/interface.go',
|
||||
},
|
||||
{
|
||||
range = { ['end'] = { character = 19, line = 51 }, start = { character = 14, line = 51 } },
|
||||
uri = 'file://' .. cur_dir .. '/tests/fixtures/interface.go',
|
||||
},
|
||||
{
|
||||
range = { ['end'] = { character = 19, line = 55 }, start = { character = 14, line = 55 } },
|
||||
uri = 'file://' .. cur_dir .. '/tests/fixtures/interface.go',
|
||||
},
|
||||
{
|
||||
range = { ['end'] = { character = 16, line = 59 }, start = { character = 11, line = 59 } },
|
||||
|
||||
uri = 'file://' .. cur_dir .. '/tests/fixtures/interface.go',
|
||||
},
|
||||
{
|
||||
range = { ['end'] = { character = 16, line = 5 }, start = { character = 11, line = 5 } },
|
||||
uri = 'file://' .. cur_dir .. '/tests/fixtures/interface_test.go',
|
||||
},
|
||||
}
|
||||
local status = require('plenary.reload').reload_module('navigator')
|
||||
status = require('plenary.reload').reload_module('guihua')
|
||||
status = require('plenary.reload').reload_module('lspconfig')
|
||||
|
||||
vim.cmd([[packadd navigator.lua]])
|
||||
vim.cmd([[packadd guihua.lua]])
|
||||
local path = cur_dir .. '/tests/fixtures/interface.go' -- %:p:h ? %:p
|
||||
local cmd = " silent exe 'e " .. path .. "'"
|
||||
vim.cmd(cmd)
|
||||
vim.cmd([[cd %:p:h]])
|
||||
local bufn = vim.fn.bufnr('')
|
||||
-- require'lspconfig'.gopls.setup {}
|
||||
require('navigator').setup({
|
||||
debug = true, -- log output, set to true and log path: ~/.local/share/nvim/gh.log
|
||||
icons = { code_action_icon = 'A ' },
|
||||
width = 0.75, -- max width ratio (number of cols for the floating window) / (window width)
|
||||
height = 0.3, -- max list window height, 0.3 by default
|
||||
preview_height = 0.35, -- max height of preview windows
|
||||
border = 'none',
|
||||
})
|
||||
|
||||
if vim.fn.has('nvim-0.7') then
|
||||
_NgConfigValues.treesitter_analysis = true
|
||||
else
|
||||
_NgConfigValues.treesitter_analysis = false
|
||||
end
|
||||
-- allow gopls start
|
||||
|
||||
for _ = 1, 20 do
|
||||
vim.wait(400, function() end)
|
||||
local found = false
|
||||
for _, client in ipairs(vim.lsp.get_active_clients()) do
|
||||
if client.name == 'gopls' then
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if found then
|
||||
break
|
||||
end
|
||||
end
|
||||
it('should show references', function()
|
||||
vim.fn.setpos('.', { bufn, 15, 4, 0 }) -- width
|
||||
|
||||
vim.bo.filetype = 'go'
|
||||
vim.lsp.buf.references()
|
||||
eq(1, 1)
|
||||
end)
|
||||
it('reference handler should return items', function()
|
||||
vim.fn.setpos('.', { bufn, 15, 4, 0 }) -- width
|
||||
|
||||
|
||||
vim.bo.filetype = 'go'
|
||||
-- allow gopls start
|
||||
vim.wait(200, function() end)
|
||||
|
||||
local win, items, width
|
||||
|
||||
if nvim_6 then
|
||||
win, items, width = require('navigator.reference').ref_view(nil, result, {
|
||||
method = 'textDocument/references',
|
||||
bufnr = 1,
|
||||
client_id = 1,
|
||||
}, {})
|
||||
else
|
||||
win, items, width = require('navigator.reference').reference_handler(nil, 'textDocument/references', result, 1, 1)
|
||||
end
|
||||
|
||||
-- print('win', vim.inspect(win))
|
||||
print('items', vim.inspect(items))
|
||||
eq(win.ctrl.data[1].display_filename, './tests/fixtures/interface.go')
|
||||
eq(win.ctrl.data[2].range.start.line, 14)
|
||||
eq(items[1].display_filename, './tests/fixtures/interface.go')
|
||||
|
||||
-- eq(width, 60)
|
||||
end)
|
||||
it('reference handler should return items with thread', function()
|
||||
vim.wait(200, function() end)
|
||||
|
||||
local win, items, width
|
||||
|
||||
if nvim_6 then
|
||||
win, items, width = require('navigator.reference').ref_view(nil, result, {
|
||||
method = 'textDocument/references',
|
||||
bufnr = 1,
|
||||
client_id = 1,
|
||||
}, { truncate = 2 })
|
||||
else
|
||||
win, items, width = require('navigator.reference').reference_handler(nil, 'textDocument/references', result, 1, 1)
|
||||
end
|
||||
-- print('win', vim.inspect(win))
|
||||
print('items', vim.inspect(items))
|
||||
-- eq(win.ctrl.data, "./interface.go")
|
||||
eq(win.ctrl.data[1].display_filename, './tests/fixtures/interface.go')
|
||||
eq(win.ctrl.data[2].range.start.line, 14)
|
||||
-- eq(items[1].display_filename, "./interface.go")
|
||||
|
||||
-- eq(width, 60)
|
||||
end)
|
||||
end)
|
@ -0,0 +1,217 @@
|
||||
local golden_result = {
|
||||
{
|
||||
col = 9,
|
||||
display_filename = '/tmp/github/ray-x/navigator.lua/tests/fixtures/interface_test.go',
|
||||
filename = '/tmp/github/ray-x/navigator.lua/tests/fixtures/interface_test.go',
|
||||
full_text = 'package main',
|
||||
kind = '🚀',
|
||||
lnum = 1,
|
||||
node_scope = {
|
||||
['end'] = {
|
||||
character = 0,
|
||||
line = 12,
|
||||
},
|
||||
start = {
|
||||
character = 0,
|
||||
line = 0,
|
||||
},
|
||||
},
|
||||
node_text = 'main',
|
||||
indent = '',
|
||||
range = {
|
||||
['end'] = {
|
||||
character = 12,
|
||||
line = 0,
|
||||
},
|
||||
start = {
|
||||
character = 8,
|
||||
line = 0,
|
||||
},
|
||||
},
|
||||
text = ' 🚀 main \t package main',
|
||||
type = 'namespace',
|
||||
uri = 'file:///tmp/github/ray-x/navigator.lua/tests/fixtures/interface_test.go',
|
||||
},
|
||||
{
|
||||
col = 6,
|
||||
display_filename = '/tmp/github/ray-x/navigator.lua/tests/fixtures/interface_test.go',
|
||||
filename = '/tmp/github/ray-x/navigator.lua/tests/fixtures/interface_test.go',
|
||||
full_text = 'func interfaceTest()',
|
||||
kind = ' ',
|
||||
lnum = 5,
|
||||
indent = '',
|
||||
node_scope = {
|
||||
['end'] = {
|
||||
character = 1,
|
||||
line = 11,
|
||||
},
|
||||
start = {
|
||||
character = 0,
|
||||
line = 4,
|
||||
},
|
||||
},
|
||||
node_text = 'interfaceTest',
|
||||
range = {
|
||||
['end'] = {
|
||||
character = 18,
|
||||
line = 4,
|
||||
},
|
||||
start = {
|
||||
character = 5,
|
||||
line = 4,
|
||||
},
|
||||
},
|
||||
text = ' interfaceTest\t func interfaceTest()',
|
||||
type = 'function',
|
||||
uri = 'file:///tmp/github/ray-x/navigator.lua/tests/fixtures/interface_test.go',
|
||||
},
|
||||
{
|
||||
col = 2,
|
||||
display_filename = '/tmp/github/ray-x/navigator.lua/tests/fixtures/interface_test.go',
|
||||
filename = '/tmp/github/ray-x/navigator.lua/tests/fixtures/interface_test.go',
|
||||
full_text = 'r := rect{width: 3, height: 4}',
|
||||
kind = ' ',
|
||||
lnum = 6,
|
||||
node_scope = {
|
||||
['end'] = {
|
||||
character = 1,
|
||||
line = 11,
|
||||
},
|
||||
start = {
|
||||
character = 21,
|
||||
line = 4,
|
||||
},
|
||||
},
|
||||
|
||||
indent = ' ',
|
||||
node_text = 'r',
|
||||
range = {
|
||||
['end'] = {
|
||||
character = 2,
|
||||
line = 5,
|
||||
},
|
||||
start = {
|
||||
character = 1,
|
||||
line = 5,
|
||||
},
|
||||
},
|
||||
text = ' r \t r := rect{width: 3, height: 4}',
|
||||
type = 'var',
|
||||
uri = 'file:///tmp/github/ray-x/navigator.lua/tests/fixtures/interface_test.go',
|
||||
},
|
||||
{
|
||||
col = 2,
|
||||
display_filename = '/tmp/github/ray-x/navigator.lua/tests/fixtures/interface_test.go',
|
||||
filename = '/tmp/github/ray-x/navigator.lua/tests/fixtures/interface_test.go',
|
||||
full_text = 'c := circle{radius: 5}',
|
||||
kind = ' ',
|
||||
lnum = 7,
|
||||
node_scope = {
|
||||
['end'] = {
|
||||
character = 1,
|
||||
line = 11,
|
||||
},
|
||||
start = {
|
||||
character = 21,
|
||||
line = 4,
|
||||
},
|
||||
},
|
||||
node_text = 'c',
|
||||
indent = ' ',
|
||||
range = {
|
||||
['end'] = {
|
||||
character = 2,
|
||||
line = 6,
|
||||
},
|
||||
start = {
|
||||
character = 1,
|
||||
line = 6,
|
||||
},
|
||||
},
|
||||
text = ' c \t c := circle{radius: 5}',
|
||||
type = 'var',
|
||||
uri = 'file:///tmp/github/ray-x/navigator.lua/tests/fixtures/interface_test.go',
|
||||
},
|
||||
{
|
||||
col = 2,
|
||||
display_filename = '/tmp/github/ray-x/navigator.lua/tests/fixtures/interface_test.go',
|
||||
filename = '/tmp/github/ray-x/navigator.lua/tests/fixtures/interface_test.go',
|
||||
full_text = 'd := circle{radius: 10}',
|
||||
kind = ' ',
|
||||
lnum = 10,
|
||||
indent = ' ',
|
||||
node_scope = {
|
||||
['end'] = {
|
||||
character = 1,
|
||||
line = 11,
|
||||
},
|
||||
start = {
|
||||
character = 21,
|
||||
line = 4,
|
||||
},
|
||||
},
|
||||
node_text = 'd',
|
||||
range = {
|
||||
['end'] = {
|
||||
character = 2,
|
||||
line = 9,
|
||||
},
|
||||
start = {
|
||||
character = 1,
|
||||
line = 9,
|
||||
},
|
||||
},
|
||||
text = ' d \t d := circle{radius: 10}',
|
||||
type = 'var',
|
||||
uri = 'file:///tmp/github/ray-x/navigator.lua/tests/fixtures/interface_test.go',
|
||||
},
|
||||
}
|
||||
|
||||
print(golden_result[1].node_text)
|
||||
|
||||
local busted = require('plenary/busted')
|
||||
|
||||
local eq = assert.are.same
|
||||
local cur_dir = vim.fn.expand('%:p:h')
|
||||
-- local status = require("plenary.reload").reload_module("go.nvim")
|
||||
-- status = require("plenary.reload").reload_module("nvim-treesitter")
|
||||
|
||||
-- local ulog = require('go.utils').log
|
||||
describe('should run lsp reference', function()
|
||||
-- vim.fn.readfile('minimal.vim')
|
||||
it('should show ts nodes', function()
|
||||
local status = require('plenary.reload').reload_module('navigator')
|
||||
local status = require('plenary.reload').reload_module('guihua')
|
||||
local status = require('plenary.reload').reload_module('lspconfig')
|
||||
|
||||
vim.cmd([[packadd nvim-lspconfig]])
|
||||
vim.cmd([[packadd navigator.lua]])
|
||||
vim.cmd([[packadd guihua.lua]])
|
||||
local path = cur_dir .. '/tests/fixtures/interface_test.go' -- %:p:h ? %:p
|
||||
local cmd = " silent exe 'e " .. path .. "'"
|
||||
vim.cmd(cmd)
|
||||
vim.cmd([[cd %:p:h]])
|
||||
local bufn = vim.fn.bufnr('')
|
||||
-- require'lspconfig'.gopls.setup {}
|
||||
require('navigator').setup({
|
||||
debug = true, -- log output, set to true and log path: ~/.local/share/nvim/gh.log
|
||||
})
|
||||
|
||||
-- allow gopls start
|
||||
for i = 1, 10 do
|
||||
vim.wait(400, function() end)
|
||||
local clients = vim.lsp.get_active_clients()
|
||||
print('lsp clients: ', #clients)
|
||||
if #clients > 0 then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
vim.fn.setpos('.', { bufn, 15, 4, 0 }) -- width
|
||||
|
||||
vim.bo.filetype = 'go'
|
||||
local view, items, w = require('navigator.treesitter').buf_ts()
|
||||
eq(items[1].node_text, golden_result[1].node_text)
|
||||
eq(items[2].node_text, golden_result[2].node_text)
|
||||
end)
|
||||
end)
|
@ -0,0 +1,20 @@
|
||||
local func = function(p, uv)
|
||||
local before = os.time()
|
||||
local async
|
||||
async = uv.new_async(function(a, b, c)
|
||||
p('in async notify callback')
|
||||
p(a, b, c)
|
||||
uv.close(async)
|
||||
end)
|
||||
local args = {500, 'string', nil, false, 5, "helloworld", async}
|
||||
local unpack = unpack or table.unpack
|
||||
uv.new_thread(function(num, s, null, bool, five, hw, asy)
|
||||
local uv2 = require 'luv'
|
||||
uv2.async_send(asy, 'a', true, 250)
|
||||
uv2.sleep(1000)
|
||||
end, unpack(args)):join()
|
||||
local elapsed = (os.time() - before) * 1000
|
||||
assert(elapsed >= 1000, "elapsed should be at least delay ")
|
||||
end
|
||||
|
||||
func(print, vim.loop)
|
@ -0,0 +1,58 @@
|
||||
[selene]
|
||||
base = "lua52"
|
||||
name = "vim"
|
||||
|
||||
[vim]
|
||||
any = true
|
||||
|
||||
[_G]
|
||||
property = true
|
||||
writable = "new-fields"
|
||||
|
||||
[_NgConfigValues]
|
||||
any = true
|
||||
# property = true
|
||||
# writable = "full-write"
|
||||
|
||||
[debug]
|
||||
property = true
|
||||
|
||||
[[describe.args]]
|
||||
type = "string"
|
||||
[[describe.args]]
|
||||
type = "function"
|
||||
|
||||
[[it.args]]
|
||||
type = "string"
|
||||
[[it.args]]
|
||||
type = "function"
|
||||
|
||||
[[before_each.args]]
|
||||
type = "function"
|
||||
[[after_each.args]]
|
||||
type = "function"
|
||||
|
||||
[assert.is_not]
|
||||
any = true
|
||||
|
||||
[[assert.equals.args]]
|
||||
type = "any"
|
||||
[[assert.equals.args]]
|
||||
type = "any"
|
||||
[[assert.equals.args]]
|
||||
type = "any"
|
||||
required = false
|
||||
|
||||
[[assert.same.args]]
|
||||
type = "any"
|
||||
[[assert.same.args]]
|
||||
type = "any"
|
||||
|
||||
[[assert.truthy.args]]
|
||||
type = "any"
|
||||
|
||||
[[assert.spy.args]]
|
||||
type = "any"
|
||||
|
||||
[[assert.stub.args]]
|
||||
type = "any"
|
@ -0,0 +1,47 @@
|
||||
---
|
||||
base: lua52
|
||||
name: vim
|
||||
globals:
|
||||
_G:
|
||||
property: new-fields
|
||||
_NgConfigValues:
|
||||
any: true
|
||||
after_each:
|
||||
args:
|
||||
- type: function
|
||||
assert.equals:
|
||||
args:
|
||||
- type: any
|
||||
- type: any
|
||||
- required: false
|
||||
type: any
|
||||
assert.is_not:
|
||||
any: true
|
||||
assert.same:
|
||||
args:
|
||||
- type: any
|
||||
- type: any
|
||||
assert.spy:
|
||||
args:
|
||||
- type: any
|
||||
assert.stub:
|
||||
args:
|
||||
- type: any
|
||||
assert.truthy:
|
||||
args:
|
||||
- type: any
|
||||
before_each:
|
||||
args:
|
||||
- type: function
|
||||
debug:
|
||||
property: read-only
|
||||
describe:
|
||||
args:
|
||||
- type: string
|
||||
- type: function
|
||||
it:
|
||||
args:
|
||||
- type: string
|
||||
- type: function
|
||||
vim:
|
||||
any: true
|
Loading…
Reference in New Issue