mirror of
https://github.com/neovim/neovim
synced 2025-07-24 07:11:49 +00:00
Compare commits
1148 Commits
Author | SHA1 | Date | |
---|---|---|---|
6190b6bc1d | |||
3e655d3e42 | |||
35af766de6 | |||
54b8c99e51 | |||
0dcdd65dcc | |||
61c4a6b3a9 | |||
95dfb063da | |||
4fe51dfdae | |||
1685c44dd4 | |||
e28aee0c72 | |||
d6704148bc | |||
c93091395b | |||
d591275db7 | |||
9377db2545 | |||
8b5d8dfc73 | |||
9fc985bc98 | |||
4fadc21e38 | |||
0bef1c88f3 | |||
9813c00dd3 | |||
1d2d6e31a7 | |||
05a83265f9 | |||
3a36df9b13 | |||
b0e8b0a35f | |||
7c38f428f4 | |||
9a5b3a39f3 | |||
371aa1c566 | |||
1d8e9b5d07 | |||
ea2d226df6 | |||
8ee82da3cf | |||
2795df7aac | |||
22d1fb8c01 | |||
bbc368dfce | |||
85bd0b6a03 | |||
f2d92ba6ca | |||
b79ed66e4a | |||
6a97eb332a | |||
4765d4e059 | |||
00c2e7d89c | |||
1e81b54075 | |||
fadbc0e717 | |||
441d222c0d | |||
c3991b8ef4 | |||
2495015455 | |||
b6b793634a | |||
c556c6677b | |||
6831c7de65 | |||
4962c60c6f | |||
5400df0f7f | |||
0f9b5dd0b4 | |||
b91613f42c | |||
14cafbcc85 | |||
8dfad04ce9 | |||
8f75c0b586 | |||
e5c2ce5905 | |||
c5167ffc18 | |||
db1542af3d | |||
f21ada30e1 | |||
b21c357b9c | |||
46648c3867 | |||
3a140ddbc6 | |||
10a0c59487 | |||
73943eb0d1 | |||
f2691199fa | |||
26bbeadda3 | |||
f5829957f2 | |||
586e6d427a | |||
a3cfdcebb9 | |||
538c945fdf | |||
d7050d6e39 | |||
9df9d3af3b | |||
fd5d04fbff | |||
1de2a03fc7 | |||
1255a8d88d | |||
995bc31eaf | |||
7631302ad6 | |||
4fe6fcc5b7 | |||
77c6cae25b | |||
ad0c21a445 | |||
2efc84d005 | |||
5671b61327 | |||
4f0ab9877b | |||
e0d179561d | |||
9d1333a385 | |||
1b6848c299 | |||
0d0655f725 | |||
4a4e6a792a | |||
be35864318 | |||
436ae1d23e | |||
a08d6a8ac1 | |||
e6ce067f02 | |||
8bf99ddbac | |||
e946951f6a | |||
1c6ddd9a5f | |||
fcec1610e7 | |||
8bccd07972 | |||
4195b82ec9 | |||
fa648731ec | |||
694f634556 | |||
83818b885a | |||
ace254c9ff | |||
5cfdd4d8b9 | |||
9789a3b854 | |||
112092271b | |||
d4c8e8df1c | |||
3eb597c999 | |||
73987a4301 | |||
a945686444 | |||
12276832ab | |||
7bf04bc01f | |||
9f16b598f9 | |||
f487ae90cf | |||
96ec4db3e9 | |||
7cd5356a6f | |||
444a8b3ec6 | |||
3e7f5d95aa | |||
73fbc693b5 | |||
89b946aa87 | |||
5c4f9b05fa | |||
7e8aa0585e | |||
a8d9f3331e | |||
7ac4cbcd2e | |||
4778a4c201 | |||
815916b450 | |||
f3a54e7ccf | |||
430be9d01d | |||
3812cb1cd1 | |||
2422fbdd5f | |||
eb5b4b9e57 | |||
d2098057a7 | |||
34fbfa3586 | |||
f1babb322b | |||
8c6ea76ebc | |||
d4074b812d | |||
7f5b5d34cf | |||
9e968635ef | |||
4f3aa7bafb | |||
7a69fefdb9 | |||
c3e2926f17 | |||
e78c877688 | |||
58df501913 | |||
00f8f94d5b | |||
54cde0674b | |||
9809ce8b47 | |||
68e316e3f9 | |||
7bd4dfd209 | |||
4745270bf1 | |||
213360c389 | |||
5803994a1c | |||
e644038f06 | |||
7f18811668 | |||
fccd016a0f | |||
e65c0a0810 | |||
fb0dc825e9 | |||
7526fb449d | |||
8aed423072 | |||
977e91b424 | |||
76f6868e0a | |||
840cdb9589 | |||
3a3484be29 | |||
3c9484b550 | |||
88774965e5 | |||
96aef50624 | |||
5fe310c5e6 | |||
ef0ec7edac | |||
db7c2acbc6 | |||
435f03ee10 | |||
bb6422f1ad | |||
28b7c2df52 | |||
f68a5c40f0 | |||
f576b59a09 | |||
bf9d3e4bf8 | |||
d88bebfbc7 | |||
27daeb0d68 | |||
ed8b022633 | |||
842ca1fd5c | |||
62822d750d | |||
5fd386a893 | |||
0c973bf442 | |||
d523750de0 | |||
c3c8d25293 | |||
2031287e93 | |||
0d9bf5b89f | |||
4310f3f580 | |||
d73788fad2 | |||
3177841bdf | |||
8d5452c46d | |||
55e3a75217 | |||
5973328eda | |||
6fd2a3040f | |||
2e2ac49c57 | |||
86a2ebd5fe | |||
18e0301e1f | |||
12689c73d8 | |||
957093da0d | |||
580b8cfac7 | |||
4f141dca8c | |||
09f9d72c24 | |||
cf5506f0fd | |||
5335d9991f | |||
8a4977e286 | |||
11e967d5af | |||
025c070312 | |||
9c04eb02ad | |||
6ebcb4a4d6 | |||
8fe4e120a2 | |||
55f003671d | |||
728b3e3d50 | |||
0ea7a65299 | |||
518f95e27e | |||
85e6feedb0 | |||
887255362f | |||
c3f35a38fe | |||
46727a7feb | |||
9a44bbd574 | |||
dd707246fd | |||
cc83854036 | |||
023f157a60 | |||
3564e62426 | |||
3bf27b2c74 | |||
d574f9479d | |||
11f8e8eb63 | |||
7138cdaef8 | |||
d9465e984b | |||
c30b93db93 | |||
0c02c9c70b | |||
52b9bab340 | |||
3342aead1d | |||
285ea2525f | |||
e34e2289c2 | |||
cbfc3d1cdc | |||
d21b8c949a | |||
cf0f90fe14 | |||
3694fcec28 | |||
16001b4d84 | |||
bb75610d99 | |||
c48dea20f5 | |||
5db833b475 | |||
f348c0ebba | |||
c925e7b8ba | |||
bfffe0d214 | |||
17ecb2b988 | |||
14d8d11671 | |||
eef62e815d | |||
f01419f3d5 | |||
715c28d67f | |||
ac75de0d2a | |||
a5e582dab6 | |||
0a6a73fd25 | |||
fc1be07d28 | |||
0a14ac3261 | |||
18cfbf8fb2 | |||
da42f99eb4 | |||
535e292436 | |||
168bf0024e | |||
94f44d58fd | |||
4eebc46930 | |||
e91224bfaa | |||
807bc00dd6 | |||
38aac21083 | |||
f731766474 | |||
99873296be | |||
66f02ee1fe | |||
af6b3d6fec | |||
773075b2bc | |||
649ff924d9 | |||
4034476dd3 | |||
d6d1bfd20d | |||
aeb8bca12d | |||
561021bacd | |||
ed7ff848a0 | |||
f7c939fa7a | |||
2f95abddfa | |||
1c52e90cd5 | |||
63a7b92e58 | |||
331de6afa6 | |||
10a03e83e3 | |||
bff7d3fd9f | |||
f1f106be3d | |||
c752016976 | |||
4ee2e365a5 | |||
f2988e05db | |||
bfe42c84de | |||
64753b5c37 | |||
0b91e9f83b | |||
e518666f1d | |||
2b4c1127ad | |||
6005bc68b2 | |||
f0c0c24ed7 | |||
5d06eade25 | |||
76de3e2d07 | |||
3eaa6c5a66 | |||
b40e658717 | |||
f0757ee590 | |||
e5dae58704 | |||
c730374d44 | |||
731e616a79 | |||
4369d7d9a7 | |||
0694ca8822 | |||
684be736c1 | |||
5ae41ddde3 | |||
efd0fa55c8 | |||
25000be845 | |||
5871d26779 | |||
6b6a4518c2 | |||
7f3249fa0d | |||
69c379dc44 | |||
92883b918c | |||
40c61bf205 | |||
6942dec9b2 | |||
fb5a51e775 | |||
835f11595f | |||
a5c55d200b | |||
462f7aaa8e | |||
534ec8d447 | |||
30f650420b | |||
233014f3ed | |||
69ef85a533 | |||
cfb4d3d2f2 | |||
ee2fc31b36 | |||
0980617c0d | |||
d0aedd36df | |||
cacb4ceeb4 | |||
927dc3c2c4 | |||
528381587b | |||
0dc900d744 | |||
150513a163 | |||
487112d674 | |||
2379fb053a | |||
255f313cf6 | |||
f038213617 | |||
fb8dba413f | |||
8ed6f00ab0 | |||
0456d75517 | |||
3594c213a7 | |||
8e17b72094 | |||
5cf135f9a0 | |||
32f30c4874 | |||
aa8c86e8f3 | |||
237bb9cb59 | |||
cb2367a1e2 | |||
c8e54bf49d | |||
3b85046ed5 | |||
8af2aea24f | |||
17c18efbe5 | |||
b3c78f4b3c | |||
2c9d21f722 | |||
286371b4d2 | |||
496691f985 | |||
e74753a221 | |||
006361fc6b | |||
1bf9a07b3e | |||
6976ff57dd | |||
cd06e0c9d6 | |||
ae0981070e | |||
3e984cf02b | |||
5647b45e69 | |||
24bb110588 | |||
35756022cb | |||
492ea28612 | |||
9f99bf48ea | |||
1d7823451e | |||
6ad2a13054 | |||
576e8f62c2 | |||
b2722181b0 | |||
5fe582448c | |||
8cfb993fdf | |||
b92e3889fe | |||
4b2c2eb120 | |||
00ad477419 | |||
29f2cb89f0 | |||
5ea6a022c0 | |||
5046ef4c8f | |||
0d658660c2 | |||
c7f38e3bc8 | |||
4367441213 | |||
1deba926c4 | |||
17571bc4c0 | |||
d21e2463fd | |||
76d213efbe | |||
8001276bd0 | |||
1d5b3b5b4c | |||
9ec6c19c67 | |||
76f76fb083 | |||
3e30323135 | |||
29c8dabd41 | |||
1ede826e04 | |||
beee60f3a0 | |||
90b682891d | |||
82d0883c2d | |||
7486c2f6aa | |||
f99e3a8a2a | |||
a9b8a8dc6c | |||
ac12dc49cc | |||
d86d4bacc1 | |||
221b6ddf1c | |||
b8ee354f12 | |||
dc05598d02 | |||
66e4784f5a | |||
5f00e6adaf | |||
3a2ac2300b | |||
47df8f5a4b | |||
6bee2f686f | |||
6a71239cd5 | |||
de87ceb3be | |||
966b1da183 | |||
7aafbca510 | |||
719c7e2312 | |||
8cd0ef06bb | |||
b1aed2b40a | |||
677a50bb26 | |||
bac133e4b6 | |||
fb7a234f01 | |||
37d6ac8a15 | |||
1abcd9fe28 | |||
79ce71430f | |||
8ea18de959 | |||
612f8e7c9e | |||
cbc9d9b9c7 | |||
5075043823 | |||
ac772706cc | |||
b5aef05b8f | |||
228ff6e547 | |||
c2aa5fd915 | |||
2dba5abcb2 | |||
b98eefd803 | |||
93925fe020 | |||
4387c26691 | |||
b7cb7fe51c | |||
5394320a67 | |||
2f167c53ac | |||
2c80b05cbd | |||
bcba067dc2 | |||
7a58cf4b96 | |||
78e2f62516 | |||
4fb36ea95f | |||
72f4bb9ae8 | |||
bcfc22853a | |||
cb4559bc32 | |||
d75ffa5934 | |||
a5f236291c | |||
e876a739ee | |||
2f0fbdaa48 | |||
2d980e37c8 | |||
336b46a879 | |||
8fadb80b3a | |||
76d0206342 | |||
ca9689858d | |||
cbaca9fee7 | |||
6f632a8615 | |||
811e12cebc | |||
680d3770b1 | |||
f2e60d000e | |||
58d85cd03d | |||
d2dad30898 | |||
2b79d9ba1a | |||
8b41df185c | |||
775e845d59 | |||
e21c54000e | |||
00bec1fd90 | |||
03bfc4e8d3 | |||
a1fc8bc17c | |||
a118597290 | |||
21a2411763 | |||
52c61d9690 | |||
faae1e72a2 | |||
96a0e5f265 | |||
c8c78b531b | |||
af82f36108 | |||
22389159f5 | |||
bf1d4e9793 | |||
3b6084ddf4 | |||
4c333fdbb7 | |||
744674900f | |||
99e6294819 | |||
cb036cae5f | |||
e5c5b563ec | |||
3165e94a64 | |||
9f505b4d0f | |||
60d0b7d0c3 | |||
552983515f | |||
4e71d3bfab | |||
a9f544b712 | |||
6171ab7f4e | |||
f89381e05c | |||
2b21c9c23f | |||
b6b35cb557 | |||
1c417b565e | |||
5e470c7af5 | |||
b16dc698cf | |||
a5bbdbb5d5 | |||
038fb30ece | |||
5e4700152b | |||
03832842d5 | |||
f577bb024e | |||
442dade5be | |||
7e393ff4f2 | |||
dd9ac565d8 | |||
97ca92f9dd | |||
3d1f907912 | |||
533cc0ab35 | |||
9641ad9369 | |||
3991f14621 | |||
eeacd7bd71 | |||
eb10852804 | |||
ee84518b94 | |||
049877d379 | |||
304a9baebd | |||
aa4fa24963 | |||
9c9c7ae30f | |||
525c02a89f | |||
9bfd0162dc | |||
bec1449cc5 | |||
2411f924a3 | |||
eeff6ca8ff | |||
13aec582b4 | |||
857ff5cae9 | |||
b6acf6112b | |||
c249389adb | |||
7651c43252 | |||
0af6d6ff5e | |||
33b0a004eb | |||
5e83d0f5ad | |||
963308439a | |||
86835b3db3 | |||
236243029d | |||
5fd03508aa | |||
06f07a104b | |||
52991d8728 | |||
981d4ba45e | |||
5cfbc35aa8 | |||
80753332d1 | |||
ff95d7ff9a | |||
b95189b7e3 | |||
84c7785546 | |||
b77666e6f9 | |||
7384cf015e | |||
4091f2c740 | |||
7a8b0cd0f8 | |||
f72c13341a | |||
0471cc7595 | |||
41179a6bc1 | |||
7082367b3a | |||
60b866049c | |||
2763d06100 | |||
11ae879ebd | |||
5ebaf83256 | |||
eb6ca14248 | |||
d29b800515 | |||
7ed8e96994 | |||
ade64c3ca3 | |||
9e81408b69 | |||
9d5eb3eda5 | |||
756751afa3 | |||
b28bbee539 | |||
f82219c490 | |||
532610388b | |||
cc264d51ab | |||
6c4ddf607f | |||
03933fe4c0 | |||
f2373a89d7 | |||
a4f318574a | |||
8af28ab9cb | |||
70697417c4 | |||
d22fcf2917 | |||
85d33514f9 | |||
3828856233 | |||
8defe1afb2 | |||
66dddd8b51 | |||
c4e52d604c | |||
8c5bd841ed | |||
092e49d020 | |||
a2daa3c0c0 | |||
fbf5fbacc2 | |||
e35a7d4782 | |||
5e64d92411 | |||
ba1cc9e10c | |||
aa9fd08034 | |||
c973c7ae6f | |||
a6e2c22347 | |||
bd01bd6564 | |||
4db58f78b4 | |||
52868977ae | |||
8b9500c886 | |||
06043af27d | |||
af947f0107 | |||
e25b99c5b6 | |||
c4501e98f2 | |||
a96665cf48 | |||
8a207b3e19 | |||
baabc35987 | |||
a59b052857 | |||
c9d8468020 | |||
9784bc1346 | |||
abb40ecedd | |||
7c2b4a0eaf | |||
6ce2877327 | |||
071dcab68f | |||
f791ae82e5 | |||
41c850e2c8 | |||
079e7d2b11 | |||
153a910897 | |||
f0fb6d448a | |||
927927e143 | |||
27bb814cb1 | |||
62ba6e8a76 | |||
fed9069b8d | |||
2d4b028d02 | |||
c81af9428c | |||
0412527a40 | |||
272e041780 | |||
322a6d305d | |||
172a90c245 | |||
7077c59295 | |||
2e0158650a | |||
19efabafc5 | |||
dd43eb445a | |||
cd9d8469b2 | |||
5ad01184f3 | |||
849e24f3cd | |||
14631e2264 | |||
dbe17da120 | |||
1524868711 | |||
8d397fa458 | |||
2045e9700c | |||
dfad613813 | |||
dc6fc11b87 | |||
dc6885dc24 | |||
3a35fdc347 | |||
a87aa68ed0 | |||
23c214ed4a | |||
5661f74ab2 | |||
ba237ce96c | |||
913e4c6010 | |||
4a6f017bc1 | |||
4eed85f9bd | |||
9a322f8103 | |||
81bb7613f9 | |||
8e8f4523c6 | |||
f40e140083 | |||
99384fcd9c | |||
ec5f054dc9 | |||
6af1b7e5e8 | |||
3659058e80 | |||
9d1996ac61 | |||
37cac18787 | |||
82027fd6bd | |||
6e3eb6663e | |||
1be2fdb910 | |||
469541c415 | |||
2fda267faf | |||
763e7428e2 | |||
142f914089 | |||
70eb416459 | |||
17e13ce3b6 | |||
f87b6230f1 | |||
6b9665a507 | |||
f2aec4bc05 | |||
d25eb246ef | |||
4d56dc43c0 | |||
b0bb3cccf9 | |||
2bfb12ef46 | |||
570e62d0f9 | |||
4fae013a21 | |||
40b64e9100 | |||
cc78f88201 | |||
a62e55d407 | |||
d539a952da | |||
e4c4d672b5 | |||
cc6ee59f5a | |||
2f24ae8de4 | |||
c681336e3c | |||
e5665754d1 | |||
e01f196e44 | |||
238e1d6ecc | |||
69d04ee99f | |||
d04cbb65b9 | |||
9c0afc8873 | |||
7369f80b19 | |||
ef5c5dc99b | |||
23bf4c0531 | |||
2c07428966 | |||
d95b0a5396 | |||
05dab80d8d | |||
4b3a9ac413 | |||
59c45b22d9 | |||
73e7e7631c | |||
1889c351fd | |||
a2c3591720 | |||
1826ad16af | |||
de45b8e275 | |||
bee45fc0e7 | |||
8605f5655b | |||
f38f92931a | |||
44a6e5ea99 | |||
1c96b72dfa | |||
1d9990daac | |||
9b11746d80 | |||
cb12c8fa47 | |||
1bfb8dd338 | |||
db702782e0 | |||
c2d218d0c6 | |||
e56292071a | |||
302e59f734 | |||
6adf48b66d | |||
7e787f6a4f | |||
3121e02ae0 | |||
15d31fe7a6 | |||
6b955af875 | |||
ab5c15610f | |||
50c200fcd4 | |||
ee1d389fa6 | |||
7c43f8e433 | |||
d976834864 | |||
1b8ae4336d | |||
2f2cba24f9 | |||
6dee1672cc | |||
27311b0b5c | |||
186851b1bd | |||
d8621a53ac | |||
45e9054813 | |||
ac67098998 | |||
2aa7948266 | |||
fb59188b6d | |||
f5b5f2095e | |||
a81d2b6703 | |||
8707ec2644 | |||
db2b774a16 | |||
c65817774d | |||
8d75910ef9 | |||
9efdd4fe98 | |||
1e7406fa38 | |||
912388f517 | |||
2d75ea6afe | |||
1ad9cdd403 | |||
40351bbbbe | |||
0862c1036a | |||
df345503eb | |||
0402f5a76b | |||
3268f51d20 | |||
d4ecfc4234 | |||
ba2a5a7787 | |||
72ec410134 | |||
fc2dee1736 | |||
af4f7f1618 | |||
8f5bd569c5 | |||
5c15df449a | |||
91e116f3a6 | |||
cb2ca54331 | |||
f1295fe76f | |||
921f8b0df7 | |||
627c648252 | |||
2c1f5a6aa5 | |||
9274532615 | |||
b877aa34cf | |||
047a10bfde | |||
8305af9bd2 | |||
6256adde2f | |||
b2a5105c66 | |||
d0867574bd | |||
902b689c4d | |||
403fcacfc1 | |||
03d378fda6 | |||
2e35161fa1 | |||
94bc7f47bf | |||
f048298e9a | |||
6b233cd1a1 | |||
5d1fd4aca5 | |||
adbd33027f | |||
862e676efc | |||
5a2edc483d | |||
34c769dd89 | |||
39a5b7f239 | |||
c916bdf329 | |||
8d6f016345 | |||
53b41ec7c2 | |||
da3eeb4b32 | |||
074a6abd55 | |||
0741d2520d | |||
3c7c824bdc | |||
4b5364b423 | |||
1fb0126a08 | |||
2c1c0b7af5 | |||
da401ca25b | |||
1f004970f0 | |||
ce8b755a86 | |||
dd71a21463 | |||
0b3c76502c | |||
65a4c8f3ca | |||
abc96ba0ce | |||
d1fed989f2 | |||
d567f899ef | |||
97a6259442 | |||
edc8e9f40a | |||
4bc7bac884 | |||
fae4abd2f4 | |||
b38525f65c | |||
ad48cccaa8 | |||
71f3a9c590 | |||
6577d72d81 | |||
f27fb737ce | |||
0015a105ca | |||
272dba7f07 | |||
f02484118c | |||
0ab0cdb2da | |||
99e754ae02 | |||
08c484f2ca | |||
9bbbeb60e3 | |||
c35dde03c8 | |||
ffb93d9883 | |||
e7e665b489 | |||
c489b5a3e3 | |||
7692a62b75 | |||
d107375f0c | |||
afcc4e95d5 | |||
c64cada12e | |||
d75410b091 | |||
43f3c4a48f | |||
bd413a2f55 | |||
317a897c46 | |||
ce097c5091 | |||
07a207a5f1 | |||
644c618825 | |||
36dbd2686f | |||
1f503ac7c0 | |||
52a4bc4548 | |||
a6591950f6 | |||
71455173b4 | |||
82b844fefe | |||
181df60533 | |||
63323a9c81 | |||
b98aefc584 | |||
ef16a02a76 | |||
e991133058 | |||
86b34ad073 | |||
a167800f1c | |||
923efaea28 | |||
c2fc867843 | |||
31e31273bc | |||
fcabbc2283 | |||
d6fffe6b32 | |||
66339e0641 | |||
c1d21492a6 | |||
2c3488c52e | |||
1999c4cdc1 | |||
dd18ab1691 | |||
e7410048fa | |||
d927a87ed6 | |||
f486f1742e | |||
8315697449 | |||
e45ec5a852 | |||
e324ab2b6b | |||
342974773c | |||
9e93bfdb5f | |||
8090dcf494 | |||
766cd01ff2 | |||
d01b2611a6 | |||
d9353bd442 | |||
06613989a6 | |||
1fed4412e4 | |||
9e450000d3 | |||
4ddd31de14 | |||
533ce0e807 | |||
7d569abb20 | |||
1670fbee0f | |||
276860b538 | |||
18e8839c80 | |||
8495d96238 | |||
9ff1239634 | |||
ca47cc39f8 | |||
ac8ae1596c | |||
63689deb45 | |||
921752d3e2 | |||
3d126ec89f | |||
07d60e8f19 | |||
a9f810b203 | |||
f3c4fec43f | |||
652c3e76c7 | |||
bc814cfb2c | |||
d4f2b9050d | |||
70d7979439 | |||
019b2050e1 | |||
8d68dbf906 | |||
2ea14c0cf4 | |||
1dbede5b93 | |||
803649da11 | |||
82f08f33c1 | |||
d3e495ce03 | |||
8c81ed8678 | |||
65170e8dad | |||
28e31f5d3d | |||
ab72799841 | |||
986b92eb07 | |||
7ba0f623d7 | |||
de7306a250 | |||
7ba043f0f3 | |||
98ec3fdf74 | |||
e3c3f4730d | |||
8051092414 | |||
9fafdcb99c | |||
7da1639a14 | |||
1437144740 | |||
d55330bcd1 | |||
351613bc1f | |||
4b02d1f6f6 | |||
d3cded796c | |||
c7d8812ca7 | |||
e4516a90b1 | |||
255bf6e5b1 | |||
1b0dedb81c | |||
df96276b19 | |||
ed5e70465a | |||
7380f8ec71 | |||
dca8b3fede | |||
c67398d31b | |||
9397fdafe1 | |||
44f1dbee0d | |||
0251a25541 | |||
ccdb37b075 | |||
34791f7988 | |||
9045656014 | |||
67d6f2baa4 | |||
5662bdafc2 | |||
3ee144aa95 | |||
234be4aebc | |||
1e2f86394a | |||
700840f4b7 | |||
e2fa151f9c | |||
8e5ef60540 | |||
118759aa6b | |||
fe7cd80cbc | |||
e2e6c159d3 | |||
0eb708aa8a | |||
bd0555ecd4 | |||
827cfe4a76 | |||
b4c759716a | |||
6926fc1615 | |||
2fcdeb0128 | |||
d7e0d46ffa | |||
34b4df774d | |||
5aa35691ab | |||
95a255a548 | |||
f9f6dc4262 | |||
e3e8dfe99c | |||
95e29dab70 | |||
afca5b564e | |||
54d6055098 | |||
6e5671b00d | |||
1c723b2e6f | |||
b64c2d763e | |||
284b0e4fa2 | |||
223ac7782e | |||
fd973c0a4e | |||
7432781e71 | |||
07d06dd396 | |||
1de276bbcd | |||
b0f97177d4 | |||
d2d1b5e944 | |||
5333d6371b | |||
07b33c3266 | |||
f29856d034 | |||
c58c650adf | |||
9272dc9597 | |||
3341ab0776 | |||
aa47c8efa9 | |||
287955cfb4 | |||
2d6120240d | |||
51caf0a3af | |||
fd76646a95 | |||
ec9931fae1 | |||
0f4623d346 | |||
52be3b14e3 | |||
2f8fb4f28a | |||
0977f70f4d | |||
ee3f9a1e03 | |||
0814086a23 | |||
60af1a1db2 | |||
b8763cb215 | |||
a8dd5c7e41 | |||
74ca73d545 | |||
d77d961b35 | |||
c8fbb0d2ee | |||
4a706a7092 | |||
064ff74cdb | |||
5111d66ac9 | |||
092962b07c | |||
6a728382f9 | |||
3aa833e0d9 | |||
7c15987444 | |||
dc00b37965 | |||
0ee5a4d481 | |||
627d0a2b32 | |||
51a967d58a | |||
f908fe4462 | |||
f068386c9f | |||
5a94edad70 | |||
ff2cbe8fac | |||
c73a827564 | |||
3647b821ea | |||
5b1561bb71 | |||
c0f46daca5 | |||
454abde1aa | |||
00eff4b196 | |||
36d143e707 | |||
8af9f8ab5e | |||
1ffc7d6bf8 | |||
2c960e8f04 | |||
ca16b54c86 | |||
cf59631f65 | |||
666a82374d | |||
12720e929d | |||
bd37348939 | |||
3ebde5ea14 | |||
1e9e523521 | |||
5e192dbce2 | |||
1867f2a830 | |||
2d11b981bf | |||
fece489794 | |||
28e8190185 | |||
f9dec1228d | |||
57d99a515f | |||
e8785c2e94 | |||
1e1384b6dd | |||
a8edf6e445 | |||
379c37fa0b | |||
98f5aa2564 | |||
b10cb0296a | |||
4983fa45fc | |||
b788c7fa6c | |||
74edfebbde | |||
b01921cb55 | |||
d9405c7935 | |||
4ef9dcb1eb | |||
71e133e5e6 | |||
eae2d3b145 | |||
974a3aa2c4 | |||
9722bd7b1b | |||
5cdfa3324f | |||
8cf413e450 | |||
18caa5fb23 | |||
8e2a9cbaa3 | |||
d9149a9a09 | |||
0b61bc8982 | |||
3af43cffa0 | |||
e5ddf7ae7d | |||
9b239a6a86 | |||
ec18ebcb41 | |||
0e7479bb76 | |||
ec6670080a | |||
4a36f234ac | |||
2322ae403b | |||
7e8b7bba21 | |||
32325a66ca | |||
8a40213eb3 | |||
e76a7e8afb | |||
f517fcd148 | |||
42657e70b8 | |||
2ee896201c | |||
04901f4ee7 | |||
089c28b1e8 | |||
216cc893bf | |||
57b4fb5c53 | |||
4dabeff308 | |||
2e5958186a | |||
28eaec5e15 | |||
ee143aaf65 | |||
8a7c9c971f | |||
b41e066aa1 | |||
cb247e06f0 | |||
90d15227c5 | |||
de96063bda | |||
49756ebc70 | |||
87b4469adc | |||
76cbe9c8f8 | |||
e87d2ae383 | |||
e4f37481ff | |||
431c037709 | |||
75fe540500 | |||
99529577cc | |||
5f9f5bc04d | |||
b4906577c9 | |||
f4fc769c81 | |||
6e12ef4a7b | |||
295ab46ea0 | |||
d6a5bc4e8b | |||
ab00aec67b | |||
0d73ec5834 | |||
52b19e0124 | |||
686e7aca40 | |||
675ee057e0 | |||
62da4e2949 | |||
89bc945554 | |||
78d2e0b43e | |||
874e214993 | |||
6ef5dd5266 | |||
2681e1fce3 | |||
cb31663663 | |||
f4ee0ab2f1 | |||
5554fcc286 | |||
95ab723995 | |||
ade58885c4 | |||
75cbd9a8ae | |||
18fa61049a | |||
edb9d0d21e | |||
e2e0f92f17 | |||
2331c52aff | |||
ae98d0a560 | |||
59e02ee93b | |||
d96a685fae | |||
558de3d9ad | |||
07f048a8d7 | |||
e1f1386d5e | |||
e4172bcbdf | |||
b20fc95c1a | |||
d01d476480 | |||
703f4037c4 | |||
ce0c0c31a0 | |||
424d30fe97 | |||
c5044bd021 | |||
750e1836af | |||
8f40ffdb92 | |||
797195e0ea | |||
f9280cde0a | |||
162edf7b30 | |||
ce590e2077 | |||
0af780e8df | |||
e39cdafed9 | |||
5975ddbdb8 | |||
28f6199474 | |||
cd95ea5d48 | |||
10fde593f1 | |||
17db70f3af | |||
90d59e6c8a | |||
3029357520 | |||
c17caca9b7 | |||
44f70b4be1 | |||
fbac254511 | |||
bf62672d59 | |||
767a52ba30 | |||
f4ddbaeb9e | |||
d9f4c1db23 | |||
9757b11aaf | |||
a9aedfbc58 | |||
d5a6040967 | |||
9acb52c8f3 | |||
c5f3b4ca02 | |||
c46b7ab9a3 | |||
2e68e9c051 | |||
0926098e9d |
@ -18,6 +18,7 @@ Checks: >
|
||||
-bugprone-not-null-terminated-result,
|
||||
-bugprone-suspicious-memory-comparison,
|
||||
-bugprone-switch-missing-default-case,
|
||||
-bugprone-tagged-union-member-count,
|
||||
-cert-env33-c,
|
||||
-cert-err33-c,
|
||||
-cert-err34-c,
|
||||
@ -63,6 +64,7 @@ Checks: >
|
||||
|
||||
Aliases. These are just duplicates of other warnings and should always be ignored,
|
||||
-bugprone-narrowing-conversions,
|
||||
-cert-arr39-c,
|
||||
-cert-dcl37-c,
|
||||
-cert-dcl51-cpp,
|
||||
-cert-exp42-c,
|
||||
|
14
.emmyrc.json
Normal file
14
.emmyrc.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"diagnostics" : {
|
||||
"disable" : [
|
||||
"unnecessary-if"
|
||||
]
|
||||
},
|
||||
"codeAction": {
|
||||
"insertSpace": true
|
||||
},
|
||||
"strict": {
|
||||
"typeCall": true,
|
||||
"arrayIndex": true
|
||||
}
|
||||
}
|
0
.gitattributes
vendored
Executable file → Normal file
0
.gitattributes
vendored
Executable file → Normal file
5
.github/pull_request_template.md
vendored
Normal file
5
.github/pull_request_template.md
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
<!--
|
||||
Thank you for contributing to Neovim!
|
||||
If this is your first time, check out https://github.com/neovim/neovim/blob/master/CONTRIBUTING.md#pull-requests-prs
|
||||
for our PR guidelines.
|
||||
-->
|
2
.github/scripts/reviewers_add.js
vendored
2
.github/scripts/reviewers_add.js
vendored
@ -57,6 +57,7 @@ module.exports = async ({ github, context }) => {
|
||||
|
||||
if (labels.includes("lsp")) {
|
||||
reviewers.add("MariaSolOs");
|
||||
reviewers.add("ribru17");
|
||||
}
|
||||
|
||||
if (labels.includes("netrw")) {
|
||||
@ -89,6 +90,7 @@ module.exports = async ({ github, context }) => {
|
||||
reviewers.add("clason");
|
||||
reviewers.add("lewis6991");
|
||||
reviewers.add("wookayin");
|
||||
reviewers.add("ribru17");
|
||||
}
|
||||
|
||||
if (labels.includes("tui")) {
|
||||
|
2
.github/workflows/backport.yml
vendored
2
.github/workflows/backport.yml
vendored
@ -13,7 +13,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/create-github-app-token@v1
|
||||
- uses: actions/create-github-app-token@v2
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ vars.BACKPORT_APP }}
|
||||
|
6
.github/workflows/notes.md
vendored
6
.github/workflows/notes.md
vendored
@ -36,7 +36,7 @@ Note: On Windows "Server" you may need to [install vcruntime140.dll](https://lea
|
||||
|
||||
### Linux (x86_64)
|
||||
|
||||
If your system does not have the [required glibc version](https://neovim.io/doc/user/support.html#supported-platforms), try the (unsupported) [builds for older glibc](https://github.com/neovim/neovim-releases).
|
||||
If your system does not have the required glibc version, try the (unsupported) [builds for older glibc](https://github.com/neovim/neovim-releases).
|
||||
|
||||
#### AppImage
|
||||
|
||||
@ -54,7 +54,7 @@ If your system does not have the [required glibc version](https://neovim.io/doc/
|
||||
2. Extract: `tar xzvf nvim-linux-x86_64.tar.gz`
|
||||
3. Run `./nvim-linux-x86_64/bin/nvim`
|
||||
|
||||
### Linux (arm64) - Untested
|
||||
### Linux (arm64)
|
||||
|
||||
#### AppImage
|
||||
|
||||
@ -75,5 +75,3 @@ If your system does not have the [required glibc version](https://neovim.io/doc/
|
||||
### Other
|
||||
|
||||
- Install by [package manager](https://github.com/neovim/neovim/blob/master/INSTALL.md#install-from-package)
|
||||
|
||||
## SHA256 Checksums
|
||||
|
18
.github/workflows/release.yml
vendored
18
.github/workflows/release.yml
vendored
@ -132,7 +132,7 @@ jobs:
|
||||
|
||||
windows:
|
||||
needs: setup
|
||||
runs-on: windows-2019
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@ -193,25 +193,13 @@ jobs:
|
||||
echo 'PRERELEASE=') >> $GITHUB_ENV
|
||||
gh release delete stable --yes || true
|
||||
git push origin :stable || true
|
||||
# `sha256sum` outputs <sha> <path>, so we cd into each dir to drop the
|
||||
# containing folder from the output.
|
||||
- run: |
|
||||
for i in nvim-*; do
|
||||
(
|
||||
cd $i || exit
|
||||
sha256sum * >> $GITHUB_WORKSPACE/shasum.txt
|
||||
)
|
||||
done
|
||||
- name: Publish release
|
||||
env:
|
||||
NVIM_VERSION: ${{ needs.linux.outputs.version }}
|
||||
DEBUG: api
|
||||
run: |
|
||||
envsubst < "$GITHUB_WORKSPACE/.github/workflows/notes.md" > "$RUNNER_TEMP/notes.md"
|
||||
echo '```' >> "$RUNNER_TEMP/notes.md"
|
||||
cat shasum.txt >> "$RUNNER_TEMP/notes.md"
|
||||
echo '```' >> "$RUNNER_TEMP/notes.md"
|
||||
if [ "$TAG_NAME" != "nightly" ]; then
|
||||
gh release create stable $PRERELEASE --notes-file "$RUNNER_TEMP/notes.md" --title "$SUBJECT" --target $GITHUB_SHA nvim-macos-x86_64/* nvim-macos-arm64/* nvim-linux-x86_64/* nvim-linux-arm64/* nvim-appimage-x86_64/* nvim-appimage-arm64/* nvim-win64/* shasum.txt
|
||||
gh release create stable $PRERELEASE --notes-file "$RUNNER_TEMP/notes.md" --title "$SUBJECT" --target $GITHUB_SHA nvim-macos-x86_64/* nvim-macos-arm64/* nvim-linux-x86_64/* nvim-linux-arm64/* nvim-appimage-x86_64/* nvim-appimage-arm64/* nvim-win64/*
|
||||
fi
|
||||
gh release create $TAG_NAME $PRERELEASE --notes-file "$RUNNER_TEMP/notes.md" --title "$SUBJECT" --target $GITHUB_SHA nvim-macos-x86_64/* nvim-macos-arm64/* nvim-linux-x86_64/* nvim-linux-arm64/* nvim-appimage-x86_64/* nvim-appimage-arm64/* nvim-win64/* shasum.txt
|
||||
gh release create $TAG_NAME $PRERELEASE --notes-file "$RUNNER_TEMP/notes.md" --title "$SUBJECT" --target $GITHUB_SHA nvim-macos-x86_64/* nvim-macos-arm64/* nvim-linux-x86_64/* nvim-linux-arm64/* nvim-appimage-x86_64/* nvim-appimage-arm64/* nvim-win64/*
|
||||
|
29
.github/workflows/test.yml
vendored
29
.github/workflows/test.yml
vendored
@ -28,7 +28,7 @@ env:
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-24.04-arm
|
||||
timeout-minutes: 10
|
||||
env:
|
||||
CC: clang
|
||||
@ -38,7 +38,7 @@ jobs:
|
||||
|
||||
- name: Install stylua
|
||||
run: |
|
||||
wget --directory-prefix="$BIN_DIR" https://github.com/JohnnyMorganz/StyLua/releases/latest/download/stylua-linux-x86_64.zip
|
||||
wget --directory-prefix="$BIN_DIR" https://github.com/JohnnyMorganz/StyLua/releases/latest/download/stylua-linux-aarch64.zip
|
||||
(cd "$BIN_DIR"; unzip stylua*.zip)
|
||||
|
||||
- name: Build third-party deps
|
||||
@ -82,7 +82,7 @@ jobs:
|
||||
run: cmake --build build --target lintc-uncrustify
|
||||
|
||||
clang-analyzer:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-24.04-arm
|
||||
timeout-minutes: 20
|
||||
env:
|
||||
CC: clang
|
||||
@ -111,7 +111,7 @@ jobs:
|
||||
{ runner: ubuntu-24.04, os: ubuntu, flavor: asan, cc: clang, flags: -D ENABLE_ASAN_UBSAN=ON },
|
||||
{ runner: ubuntu-24.04, os: ubuntu, flavor: tsan, cc: clang, flags: -D ENABLE_TSAN=ON },
|
||||
{ runner: ubuntu-24.04, os: ubuntu, flavor: release, cc: gcc, flags: -D CMAKE_BUILD_TYPE=Release -D ENABLE_TRANSLATIONS=ON },
|
||||
# { runner: ubuntu-24.04-arm, os: ubuntu, flavor: arm, cc: gcc, flags: -D CMAKE_BUILD_TYPE=RelWithDebInfo },
|
||||
{ runner: ubuntu-24.04-arm, os: ubuntu, flavor: arm, cc: clang, flags: -D CMAKE_BUILD_TYPE=RelWithDebInfo },
|
||||
{ runner: macos-13, os: macos, flavor: intel, cc: clang, flags: -D CMAKE_FIND_FRAMEWORK=NEVER, deps_flags: -D CMAKE_FIND_FRAMEWORK=NEVER },
|
||||
{ runner: macos-15, os: macos, flavor: arm, cc: clang, flags: -D CMAKE_FIND_FRAMEWORK=NEVER, deps_flags: -D CMAKE_FIND_FRAMEWORK=NEVER },
|
||||
{ runner: ubuntu-24.04, os: ubuntu, flavor: puc-lua, cc: gcc, deps_flags: -D USE_BUNDLED_LUAJIT=OFF -D USE_BUNDLED_LUA=ON, flags: -D PREFER_LUA=ON },
|
||||
@ -124,6 +124,10 @@ jobs:
|
||||
build: { flavor: puc-lua }
|
||||
- test: oldtest
|
||||
build: { flavor: tsan }
|
||||
- test: unittest
|
||||
build: { runner: ubuntu-24.04-arm }
|
||||
- test: oldtest
|
||||
build: { runner: ubuntu-24.04-arm }
|
||||
runs-on: ${{ matrix.build.runner }}
|
||||
timeout-minutes: 45
|
||||
env:
|
||||
@ -201,11 +205,26 @@ jobs:
|
||||
name: Show logs
|
||||
run: cat $(find "$LOG_DIR" -type f)
|
||||
|
||||
zig-build:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 45
|
||||
name: build using zig build
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: mlugg/setup-zig@v2
|
||||
with:
|
||||
version: 0.14.1
|
||||
- run: sudo apt-get install -y inotify-tools
|
||||
- run: zig build test_nlua0
|
||||
- run: zig build nvim_bin && ./zig-out/bin/nvim --version
|
||||
- run: zig build unittest
|
||||
- run: zig build functionaltest
|
||||
|
||||
windows:
|
||||
uses: ./.github/workflows/test_windows.yml
|
||||
|
||||
with-external-deps:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-24.04-arm
|
||||
timeout-minutes: 10
|
||||
env:
|
||||
CC: gcc
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -10,7 +10,8 @@ compile_commands.json
|
||||
/.idea/
|
||||
|
||||
# Build/deps dir
|
||||
/build/
|
||||
/.zig-cache/
|
||||
/zig-out/
|
||||
/.deps/
|
||||
/tmp/
|
||||
/.clangd/
|
||||
|
@ -49,6 +49,7 @@ exclude_files = {
|
||||
'runtime/lua/vim/_meta/vimfn.lua',
|
||||
'runtime/lua/vim/_meta/api.lua',
|
||||
'runtime/lua/vim/re.lua',
|
||||
'runtime/lua/uv/_meta.lua',
|
||||
'runtime/lua/coxpcall.lua',
|
||||
'src/nvim/eval.lua',
|
||||
}
|
||||
|
@ -5,13 +5,12 @@
|
||||
},
|
||||
"workspace": {
|
||||
"library": [
|
||||
"runtime/lua",
|
||||
"${3rd}/busted/library",
|
||||
"${3rd}/luv/library"
|
||||
"${3rd}/busted/library"
|
||||
],
|
||||
"ignoreDir": [
|
||||
"test",
|
||||
"_vim9script.lua"
|
||||
".deps",
|
||||
"build",
|
||||
"test"
|
||||
],
|
||||
"checkThirdParty": "Disable"
|
||||
},
|
||||
|
8
.stylua2.toml
Normal file
8
.stylua2.toml
Normal file
@ -0,0 +1,8 @@
|
||||
# Alternative settings for special snowflakes like: decorations_spec.lua, multigrid_spec.lua, etc.
|
||||
|
||||
column_width = 140
|
||||
line_endings = "Unix"
|
||||
indent_type = "Spaces"
|
||||
indent_width = 2
|
||||
quote_style = "AutoPreferSingle"
|
||||
call_parentheses = "Input"
|
@ -1,14 +1,15 @@
|
||||
/build/
|
||||
/.deps/
|
||||
/runtime/lua/coxpcall.lua
|
||||
/runtime/lua/vim/_meta
|
||||
/runtime/lua/vim/re.lua
|
||||
build/
|
||||
.deps/
|
||||
runtime/lua/coxpcall.lua
|
||||
runtime/lua/uv/_meta.lua
|
||||
runtime/lua/vim/_meta
|
||||
runtime/lua/vim/re.lua
|
||||
|
||||
# These are formatted explicitly by the "formatlua2" build task.
|
||||
test/functional/ui/decorations_spec.lua
|
||||
test/functional/ui/float_spec.lua
|
||||
test/functional/ui/multigrid_spec.lua
|
||||
/test/functional/fixtures/lua/syntax_error.lua
|
||||
/test/functional/legacy/030_fileformats_spec.lua
|
||||
/test/functional/legacy/044_099_regexp_multibyte_magic_spec.lua
|
||||
/test/functional/legacy/093_mksession_cursor_cols_latin1_spec.lua
|
||||
/test/functional/lua/luaeval_spec.lua
|
||||
test/functional/fixtures/lua/syntax_error.lua
|
||||
test/functional/legacy/030_fileformats_spec.lua
|
||||
test/functional/legacy/044_099_regexp_multibyte_magic_spec.lua
|
||||
test/functional/legacy/093_mksession_cursor_cols_latin1_spec.lua
|
||||
|
25
BUILD.md
25
BUILD.md
@ -223,7 +223,7 @@ rebuild:
|
||||
|
||||
## Third-party dependencies
|
||||
|
||||
Reference the [Debian package](https://packages.debian.org/sid/source/neovim) (or alternatively, the [Homebrew formula](https://github.com/Homebrew/homebrew-core/blob/master/Formula/neovim.rb)) for the precise list of dependencies/versions.
|
||||
Reference the [Debian package](https://packages.debian.org/sid/source/neovim) (or alternatively, the [Homebrew formula](https://github.com/Homebrew/homebrew-core/blob/master/Formula/n/neovim.rb)) for the precise list of dependencies/versions.
|
||||
|
||||
To build the bundled dependencies using CMake:
|
||||
|
||||
@ -259,6 +259,29 @@ cmake --build build
|
||||
- Using `ninja` is strongly recommended.
|
||||
4. If treesitter parsers are not bundled, they need to be available in a `parser/` runtime directory (e.g. `/usr/share/nvim/runtime/parser/`).
|
||||
|
||||
### How to build static binary (on Linux)
|
||||
|
||||
1. Use a linux distribution which uses musl C. We will use Alpine Linux but any distro with musl should work. (glibc does not support static linking)
|
||||
2. Run make passing the `STATIC_BUILD` variable: `make CMAKE_EXTRA_FLAGS="-DSTATIC_BUILD=1"`
|
||||
|
||||
In case you are not using Alpine Linux you can use a container to do the build the binary:
|
||||
|
||||
```bash
|
||||
podman run \
|
||||
--rm \
|
||||
-it \
|
||||
-v "$PWD:/workdir" \
|
||||
-w /workdir \
|
||||
alpine:latest \
|
||||
bash -c 'apk add build-base cmake coreutils curl gettext-tiny-dev && make CMAKE_EXTRA_FLAGS="-DSTATIC_BUILD=1"'
|
||||
```
|
||||
|
||||
The resulting binary in `build/bin/nvim` will have all the dependencies statically linked:
|
||||
|
||||
```
|
||||
build/bin/nvim: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked, BuildID[sha1]=b93fa8e678d508ac0a76a2e3da20b119105f1b2d, with debug_info, not stripped
|
||||
```
|
||||
|
||||
#### Debian 10 (Buster) example:
|
||||
|
||||
```sh
|
||||
|
@ -35,6 +35,11 @@ include(InstallHelpers)
|
||||
include(PreventInTreeBuilds)
|
||||
include(Util)
|
||||
|
||||
if(NOT PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR)
|
||||
# Auto-create a .gitignore in the specified "build" directory.
|
||||
file(GENERATE OUTPUT .gitignore CONTENT "*")
|
||||
endif()
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# User settings
|
||||
#-------------------------------------------------------------------------------
|
||||
@ -140,19 +145,19 @@ endif()
|
||||
# If not in a git repo (e.g., a tarball) these tokens define the complete
|
||||
# version string, else they are combined with the result of `git describe`.
|
||||
set(NVIM_VERSION_MAJOR 0)
|
||||
set(NVIM_VERSION_MINOR 11)
|
||||
set(NVIM_VERSION_MINOR 12)
|
||||
set(NVIM_VERSION_PATCH 0)
|
||||
set(NVIM_VERSION_PRERELEASE "") # for package maintainers
|
||||
set(NVIM_VERSION_PRERELEASE "-dev") # for package maintainers
|
||||
|
||||
# API level
|
||||
set(NVIM_API_LEVEL 13) # Bump this after any API/stdlib change.
|
||||
set(NVIM_API_LEVEL 14) # Bump this after any API/stdlib change.
|
||||
set(NVIM_API_LEVEL_COMPAT 0) # Adjust this after a _breaking_ API change.
|
||||
set(NVIM_API_PRERELEASE false)
|
||||
set(NVIM_API_PRERELEASE true)
|
||||
|
||||
# We _want_ assertions in RelWithDebInfo build-type.
|
||||
if(CMAKE_C_FLAGS_RELWITHDEBINFO MATCHES DNDEBUG)
|
||||
string(REPLACE "-DNDEBUG" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
|
||||
string(REPLACE "/DNDEBUG" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
|
||||
string(REPLACE "-DNDEBUG" "-DRELDEBUG" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
|
||||
string(REPLACE "/DNDEBUG" "/DRELDEBUG" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
|
||||
string(REPLACE " " " " CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") # Remove duplicate whitespace
|
||||
endif()
|
||||
|
||||
@ -236,7 +241,7 @@ set(STYLUA_DIRS runtime scripts src test contrib)
|
||||
add_glob_target(
|
||||
TARGET lintlua-luacheck
|
||||
COMMAND $<TARGET_FILE:nvim_bin>
|
||||
FLAGS -ll ${PROJECT_SOURCE_DIR}/test/lua_runner.lua ${CMAKE_BINARY_DIR}/usr luacheck -q
|
||||
FLAGS -ll ${PROJECT_SOURCE_DIR}/test/lua_runner.lua ${CMAKE_BINARY_DIR}/usr/share/lua/5.1 luacheck -q
|
||||
GLOB_DIRS runtime scripts src test
|
||||
GLOB_PAT *.lua
|
||||
TOUCH_STRATEGY PER_DIR)
|
||||
@ -249,6 +254,16 @@ add_glob_target(
|
||||
GLOB_DIRS ${STYLUA_DIRS}
|
||||
GLOB_PAT *.lua
|
||||
TOUCH_STRATEGY PER_DIR)
|
||||
# Special handling of some files (which are ignored in .styluaignore).
|
||||
# Workaround because stylua doesn't(?) support file-specific settings.
|
||||
add_custom_target(lintlua-stylua2
|
||||
COMMAND ${STYLUA_PRG} --config-path "${PROJECT_SOURCE_DIR}/.stylua2.toml"
|
||||
--color=always --check
|
||||
"${PROJECT_SOURCE_DIR}/test/functional/ui/decorations_spec.lua"
|
||||
"${PROJECT_SOURCE_DIR}/test/functional/ui/float_spec.lua"
|
||||
"${PROJECT_SOURCE_DIR}/test/functional/ui/multigrid_spec.lua"
|
||||
)
|
||||
add_dependencies(lintlua-stylua lintlua-stylua2)
|
||||
|
||||
add_custom_target(lintlua)
|
||||
add_dependencies(lintlua lintlua-luacheck lintlua-stylua)
|
||||
@ -262,7 +277,7 @@ add_glob_target(
|
||||
TOUCH_STRATEGY PER_DIR)
|
||||
|
||||
add_custom_target(lintcommit
|
||||
COMMAND $<TARGET_FILE:nvim_bin> -u NONE -l ${PROJECT_SOURCE_DIR}/scripts/lintcommit.lua main)
|
||||
COMMAND $<TARGET_FILE:nvim_bin> --clean -l ${PROJECT_SOURCE_DIR}/scripts/lintcommit.lua main)
|
||||
add_dependencies(lintcommit nvim_bin)
|
||||
|
||||
add_custom_target(lint)
|
||||
@ -276,7 +291,15 @@ add_glob_target(
|
||||
GLOB_DIRS ${STYLUA_DIRS}
|
||||
GLOB_PAT *.lua
|
||||
TOUCH_STRATEGY PER_DIR)
|
||||
|
||||
# Special handling of some files (which are ignored in .styluaignore).
|
||||
# Workaround because stylua doesn't(?) support file-specific settings.
|
||||
add_custom_target(formatlua2
|
||||
COMMAND ${STYLUA_PRG} --config-path "${PROJECT_SOURCE_DIR}/.stylua2.toml"
|
||||
"${PROJECT_SOURCE_DIR}/test/functional/ui/decorations_spec.lua"
|
||||
"${PROJECT_SOURCE_DIR}/test/functional/ui/float_spec.lua"
|
||||
"${PROJECT_SOURCE_DIR}/test/functional/ui/multigrid_spec.lua"
|
||||
)
|
||||
add_dependencies(formatlua formatlua2)
|
||||
add_custom_target(format)
|
||||
add_dependencies(format formatc formatlua)
|
||||
|
||||
@ -323,13 +346,13 @@ else()
|
||||
add_custom_target(lua_dev_deps)
|
||||
endif()
|
||||
|
||||
if (CMAKE_SYSTEM_PROCESSOR MATCHES arm64)
|
||||
if (CMAKE_SYSTEM_PROCESSOR MATCHES "arm|aarch")
|
||||
set(LUALS_ARCH arm64)
|
||||
else()
|
||||
set(LUALS_ARCH x64)
|
||||
endif()
|
||||
|
||||
set(LUALS_VERSION 3.13.9)
|
||||
set(LUALS_VERSION 3.15.0)
|
||||
set(LUALS "lua-language-server-${LUALS_VERSION}-${CMAKE_SYSTEM_NAME}-${LUALS_ARCH}")
|
||||
set(LUALS_TARBALL ${LUALS}.tar.gz)
|
||||
set(LUALS_URL https://github.com/LuaLS/lua-language-server/releases/download/${LUALS_VERSION}/${LUALS_TARBALL})
|
||||
|
@ -273,7 +273,7 @@ If you need to modify or debug the documentation flow, these are the main files:
|
||||
runtime/lua/vim/* => runtime/doc/lua.txt
|
||||
runtime/lua/vim/lsp/ => runtime/doc/lsp.txt
|
||||
src/nvim/api/* => runtime/doc/api.txt
|
||||
src/nvim/eval.lua => runtime/doc/builtin.txt
|
||||
src/nvim/eval.lua => runtime/doc/vimfn.txt
|
||||
src/nvim/options.lua => runtime/doc/options.txt
|
||||
```
|
||||
|
||||
@ -299,7 +299,7 @@ types, etc. See [:help dev-lua-doc][dev-lua-doc].
|
||||
- If possible, add type information (`table`, `string`, `number`, ...). Multiple valid types are separated by a bar (`string|table`). Indicate optional parameters via `type|nil`.
|
||||
- If a function in your Lua module should _not_ be documented, add `@nodoc`.
|
||||
- If the function is internal or otherwise non-public add `@private`.
|
||||
- Private functions usually should be underscore-prefixed (named "_foo", not "foo").
|
||||
- Private functions usually should be underscore-prefixed (named "_foo", not "foo"). Prefixing with an underscore implies `@nodoc`.
|
||||
- Mark deprecated functions with `@deprecated`.
|
||||
|
||||
Third-party dependencies
|
||||
|
@ -62,7 +62,7 @@ Several Neovim GUIs are available from scoop (extras): [scoop.sh/#/apps?q=neovim
|
||||
|
||||
- Add the `bin` folder (e.g. `C:\Program Files\nvim\bin`) to your PATH.
|
||||
- This makes it easy to run `nvim` from anywhere.
|
||||
- If `:set spell` does not work, create the `C:/Users/foo/AppData/Local/nvim/site/spell` folder.
|
||||
- If `:set spell` does not work, create the `%LOCALAPPDATA%/nvim-data/site/spell` folder.
|
||||
You can then copy your spell files over (for English, located
|
||||
[here](https://github.com/vim/vim/blob/master/runtime/spell/en.utf-8.spl) and
|
||||
[here](https://github.com/vim/vim/blob/master/runtime/spell/en.utf-8.sug));
|
||||
|
@ -289,3 +289,8 @@ IV) It is not allowed to remove this license from the distribution of the Vim
|
||||
license for previous Vim releases instead of the license that they came
|
||||
with, at your option.
|
||||
|
||||
====
|
||||
|
||||
In addition, different license conditions may apply to some runtime files
|
||||
included with Vim; these will be specified in the header of each respective
|
||||
file.
|
||||
|
@ -81,7 +81,7 @@ When a (non-experimental) feature is slated to be removed it should:
|
||||
as described for Lua features.
|
||||
- `vim.deprecate(…, 'x.y.z')` where major version `x` is greater than the
|
||||
current Nvim major version, is always treated as _soft_ deprecation.
|
||||
2. Be _hard_ deprecated in a following a release in which it was soft deprecated.
|
||||
2. Be _hard_ deprecated in a release following the release in which it was soft deprecated.
|
||||
- Use of the deprecated feature will still work but should issue a warning.
|
||||
- Features implemented in C will need bespoke implementations to communicate
|
||||
to users that the feature is deprecated.
|
||||
@ -127,7 +127,9 @@ Some can be auto-bumped by `scripts/bump_deps.lua`.
|
||||
* [LuaJIT](https://github.com/LuaJIT/LuaJIT)
|
||||
* [Lua](https://www.lua.org/download.html)
|
||||
* [Luv](https://github.com/luvit/luv)
|
||||
* When bumping, also sync [our bundled documentation](https://github.com/neovim/neovim/blob/master/runtime/doc/luvref.txt) with [the upstream documentation](https://github.com/luvit/luv/blob/master/docs.md).
|
||||
* When bumping, also sync
|
||||
- [our bundled meta file](https://github.com/neovim/neovim/blob/master/runtime/lua/uv/_meta.lua) with [the upstream meta file](https://github.com/luvit/luv/blob/master/docs/meta.lua);
|
||||
- [our bundled documentation](https://github.com/neovim/neovim/blob/master/runtime/doc/luvref.txt) with [the upstream documentation](https://github.com/luvit/luv/blob/master/docs/docs.md).
|
||||
* [gettext](https://ftp.gnu.org/pub/gnu/gettext/)
|
||||
* [libiconv](https://ftp.gnu.org/pub/gnu/libiconv)
|
||||
* [libuv](https://github.com/libuv/libuv)
|
||||
@ -152,7 +154,7 @@ These dependencies are "vendored" (inlined), we must update the sources manually
|
||||
* `src/nvim/tui/terminfo_defs.h`: terminfo definitions
|
||||
* Run `scripts/update_terminfo.sh` to update these definitions.
|
||||
* `runtime/lua/vim/lsp/_meta/protocol.lua`: LSP specification
|
||||
* Run `scripts/gen_lsp.lua` to update.
|
||||
* Run `src/gen/gen_lsp.lua` to update.
|
||||
* `runtime/lua/vim/_meta/lpeg.lua`: LPeg definitions.
|
||||
* Refer to [`LuaCATS/lpeg`](https://github.com/LuaCATS/lpeg) for updates.
|
||||
* Update the git SHA revision from which the documentation was taken.
|
||||
|
6
Makefile
6
Makefile
@ -182,3 +182,9 @@ appimage-%:
|
||||
bash scripts/genappimage.sh $*
|
||||
|
||||
.PHONY: test clean distclean nvim libnvim cmake deps install appimage checkprefix benchmark $(FORMAT) $(LINT) $(TEST)
|
||||
|
||||
.PHONY: emmylua-check
|
||||
emmylua-check:
|
||||
-emmylua_check runtime/lua \
|
||||
--config .luarc.json \
|
||||
--config .emmyrc.json
|
||||
|
446
build.zig
Normal file
446
build.zig
Normal file
@ -0,0 +1,446 @@
|
||||
const std = @import("std");
|
||||
const LazyPath = std.Build.LazyPath;
|
||||
const build_lua = @import("src/build_lua.zig");
|
||||
const gen = @import("src/gen/gen_steps.zig");
|
||||
const runtime = @import("runtime/gen_runtime.zig");
|
||||
const tests = @import("test/run_tests.zig");
|
||||
|
||||
const version = struct {
|
||||
const major = 0;
|
||||
const minor = 12;
|
||||
const patch = 0;
|
||||
const prerelease = "-dev";
|
||||
|
||||
const api_level = 14;
|
||||
const api_level_compat = 0;
|
||||
const api_prerelease = true;
|
||||
};
|
||||
|
||||
// TODO(bfredl): this is for an upstream issue
|
||||
pub fn lazyArtifact(d: *std.Build.Dependency, name: []const u8) ?*std.Build.Step.Compile {
|
||||
var found: ?*std.Build.Step.Compile = null;
|
||||
for (d.builder.install_tls.step.dependencies.items) |dep_step| {
|
||||
const inst = dep_step.cast(std.Build.Step.InstallArtifact) orelse continue;
|
||||
if (std.mem.eql(u8, inst.artifact.name, name)) {
|
||||
if (found != null) std.debug.panic("artifact name '{s}' is ambiguous", .{name});
|
||||
found = inst.artifact;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
pub fn build(b: *std.Build) !void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
const t = target.result;
|
||||
const os_tag = t.os.tag;
|
||||
const is_windows = (os_tag == .windows);
|
||||
const is_linux = (os_tag == .linux);
|
||||
const is_darwin = os_tag.isDarwin();
|
||||
const modern_unix = is_darwin or os_tag.isBSD() or is_linux;
|
||||
|
||||
const cross_compiling = b.option(bool, "cross", "cross compile") orelse false;
|
||||
// TODO(bfredl): option to set nlua0 target explicitly when cross compiling?
|
||||
const target_host = if (cross_compiling) b.graph.host else target;
|
||||
const optimize_host = .ReleaseSafe;
|
||||
|
||||
// puc lua 5.1 is not ReleaseSafe "safe"
|
||||
const optimize_lua = if (optimize == .Debug or optimize == .ReleaseSafe) .ReleaseSmall else optimize;
|
||||
|
||||
const arch = t.cpu.arch;
|
||||
const default_luajit = (is_linux and arch == .x86_64) or (is_darwin and arch == .aarch64);
|
||||
const use_luajit = b.option(bool, "luajit", "use luajit") orelse default_luajit;
|
||||
const host_use_luajit = if (cross_compiling) false else use_luajit;
|
||||
const E = enum { luajit, lua51 };
|
||||
|
||||
const ziglua = b.dependency("lua_wrapper", .{
|
||||
.target = target,
|
||||
.optimize = optimize_lua,
|
||||
.lang = if (use_luajit) E.luajit else E.lua51,
|
||||
.shared = false,
|
||||
});
|
||||
|
||||
const ziglua_host = if (cross_compiling) b.dependency("lua_wrapper", .{
|
||||
.target = target_host,
|
||||
.optimize = optimize_lua,
|
||||
.lang = if (host_use_luajit) E.luajit else E.lua51,
|
||||
.shared = false,
|
||||
}) else ziglua;
|
||||
|
||||
const lpeg = b.dependency("lpeg", .{});
|
||||
|
||||
const iconv_apple = if (cross_compiling and is_darwin) b.lazyDependency("iconv_apple", .{ .target = target, .optimize = optimize }) else null;
|
||||
|
||||
// this is currently not necessary, as ziglua currently doesn't use lazy dependencies
|
||||
// to circumvent ziglua.artifact() failing in a bad way.
|
||||
// const lua = lazyArtifact(ziglua, "lua") orelse return;
|
||||
const lua = ziglua.artifact("lua");
|
||||
|
||||
const libuv_dep = b.dependency("libuv", .{ .target = target, .optimize = optimize });
|
||||
const libuv = libuv_dep.artifact("uv");
|
||||
|
||||
const libluv = try build_lua.build_libluv(b, target, optimize, lua, libuv);
|
||||
|
||||
const utf8proc = b.dependency("utf8proc", .{ .target = target, .optimize = optimize });
|
||||
const unibilium = b.dependency("unibilium", .{ .target = target, .optimize = optimize });
|
||||
// TODO(bfredl): fix upstream bugs with UBSAN
|
||||
const treesitter = b.dependency("treesitter", .{ .target = target, .optimize = .ReleaseFast });
|
||||
|
||||
const nlua0 = build_lua.build_nlua0(b, target_host, optimize_host, host_use_luajit, ziglua_host, lpeg);
|
||||
|
||||
// usual caveat emptor: might need to force a rebuild if the only change is
|
||||
// addition of new .c files, as those are not seen by any hash
|
||||
const subdirs = [_][]const u8{
|
||||
"", // src/nvim itself
|
||||
"os/",
|
||||
"api/",
|
||||
"api/private/",
|
||||
"msgpack_rpc/",
|
||||
"tui/",
|
||||
"tui/termkey/",
|
||||
"event/",
|
||||
"eval/",
|
||||
"lib/",
|
||||
"lua/",
|
||||
"viml/",
|
||||
"viml/parser/",
|
||||
"vterm/",
|
||||
};
|
||||
|
||||
// source names _relative_ src/nvim/, not including other src/ subdircs
|
||||
var nvim_sources = try std.ArrayList(gen.SourceItem).initCapacity(b.allocator, 100);
|
||||
var nvim_headers = try std.ArrayList([]u8).initCapacity(b.allocator, 100);
|
||||
|
||||
// both source headers and the {module}.h.generated.h files
|
||||
var api_headers = try std.ArrayList(std.Build.LazyPath).initCapacity(b.allocator, 10);
|
||||
|
||||
// TODO(bfredl): these should just become subdirs..
|
||||
const windows_only = [_][]const u8{ "pty_proc_win.c", "pty_proc_win.h", "pty_conpty_win.c", "pty_conpty_win.h", "os_win_console.c", "win_defs.h" };
|
||||
const unix_only = [_][]const u8{ "unix_defs.h", "pty_proc_unix.c", "pty_proc_unix.h" };
|
||||
const exclude_list = if (is_windows) &unix_only else &windows_only;
|
||||
|
||||
const src_dir = b.build_root.handle;
|
||||
for (subdirs) |s| {
|
||||
var dir = try src_dir.openDir(b.fmt("src/nvim/{s}", .{s}), .{ .iterate = true });
|
||||
defer dir.close();
|
||||
var it = dir.iterateAssumeFirstIteration();
|
||||
const api_export = std.mem.eql(u8, s, "api/");
|
||||
const os_check = std.mem.eql(u8, s, "os/");
|
||||
entries: while (try it.next()) |entry| {
|
||||
if (entry.name.len < 3) continue;
|
||||
if (entry.name[0] < 'a' or entry.name[0] > 'z') continue;
|
||||
if (os_check) {
|
||||
for (exclude_list) |name| {
|
||||
if (std.mem.eql(u8, name, entry.name)) {
|
||||
continue :entries;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (std.mem.eql(u8, ".c", entry.name[entry.name.len - 2 ..])) {
|
||||
try nvim_sources.append(.{ .name = b.fmt("{s}{s}", .{ s, entry.name }), .api_export = api_export });
|
||||
}
|
||||
if (std.mem.eql(u8, ".h", entry.name[entry.name.len - 2 ..])) {
|
||||
try nvim_headers.append(b.fmt("{s}{s}", .{ s, entry.name }));
|
||||
if (api_export and !std.mem.eql(u8, "ui_events.in.h", entry.name)) {
|
||||
try api_headers.append(b.path(b.fmt("src/nvim/{s}{s}", .{ s, entry.name })));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const support_unittests = use_luajit;
|
||||
|
||||
const gen_config = b.addWriteFiles();
|
||||
|
||||
const version_lua = gen_config.add("nvim_version.lua", lua_version_info(b));
|
||||
|
||||
var config_str = b.fmt("zig build -Doptimize={s}", .{@tagName(optimize)});
|
||||
if (cross_compiling) {
|
||||
config_str = b.fmt("{s} -Dcross -Dtarget={s} (host: {s})", .{ config_str, try t.linuxTriple(b.allocator), try b.graph.host.result.linuxTriple(b.allocator) });
|
||||
}
|
||||
|
||||
const versiondef_step = b.addConfigHeader(.{ .style = .{ .cmake = b.path("cmake.config/versiondef.h.in") } }, .{
|
||||
.NVIM_VERSION_MAJOR = version.major,
|
||||
.NVIM_VERSION_MINOR = version.minor,
|
||||
.NVIM_VERSION_PATCH = version.patch,
|
||||
.NVIM_VERSION_PRERELEASE = version.prerelease,
|
||||
.NVIM_VERSION_MEDIUM = "",
|
||||
.VERSION_STRING = "TODO", // TODO(bfredl): not sure what to put here. summary already in "config_str"
|
||||
.CONFIG = config_str,
|
||||
});
|
||||
_ = gen_config.addCopyFile(versiondef_step.getOutput(), "auto/versiondef.h"); // run_preprocessor() workaronnd
|
||||
|
||||
const ptrwidth = t.ptrBitWidth() / 8;
|
||||
const sysconfig_step = b.addConfigHeader(.{ .style = .{ .cmake = b.path("cmake.config/config.h.in") } }, .{
|
||||
.SIZEOF_INT = t.cTypeByteSize(.int),
|
||||
.SIZEOF_INTMAX_T = t.cTypeByteSize(.longlong), // TODO
|
||||
.SIZEOF_LONG = t.cTypeByteSize(.long),
|
||||
.SIZEOF_SIZE_T = ptrwidth,
|
||||
.SIZEOF_VOID_PTR = ptrwidth,
|
||||
|
||||
.PROJECT_NAME = "nvim",
|
||||
|
||||
.HAVE__NSGETENVIRON = is_darwin,
|
||||
.HAVE_FD_CLOEXEC = modern_unix,
|
||||
.HAVE_FSEEKO = modern_unix,
|
||||
.HAVE_LANGINFO_H = modern_unix,
|
||||
.HAVE_NL_LANGINFO_CODESET = modern_unix,
|
||||
.HAVE_NL_MSG_CAT_CNTR = t.isGnuLibC(),
|
||||
.HAVE_PWD_FUNCS = modern_unix,
|
||||
.HAVE_READLINK = modern_unix,
|
||||
.HAVE_STRNLEN = modern_unix,
|
||||
.HAVE_STRCASECMP = modern_unix,
|
||||
.HAVE_STRINGS_H = modern_unix,
|
||||
.HAVE_STRNCASECMP = modern_unix,
|
||||
.HAVE_STRPTIME = modern_unix,
|
||||
.HAVE_XATTR = is_linux,
|
||||
.HAVE_SYS_SDT_H = false,
|
||||
.HAVE_SYS_UTSNAME_H = modern_unix,
|
||||
.HAVE_SYS_WAIT_H = false, // unused
|
||||
.HAVE_TERMIOS_H = modern_unix,
|
||||
.HAVE_WORKING_LIBINTL = t.isGnuLibC(),
|
||||
.UNIX = modern_unix,
|
||||
.CASE_INSENSITIVE_FILENAME = is_darwin or is_windows,
|
||||
.HAVE_SYS_UIO_H = modern_unix,
|
||||
.HAVE_READV = modern_unix,
|
||||
.HAVE_DIRFD_AND_FLOCK = modern_unix,
|
||||
.HAVE_FORKPTY = modern_unix and !is_darwin, // also on Darwin but we lack the headers :(
|
||||
.HAVE_BE64TOH = modern_unix and !is_darwin,
|
||||
.ORDER_BIG_ENDIAN = t.cpu.arch.endian() == .big,
|
||||
.ENDIAN_INCLUDE_FILE = "endian.h",
|
||||
.HAVE_EXECINFO_BACKTRACE = modern_unix and !t.isMuslLibC(),
|
||||
.HAVE_BUILTIN_ADD_OVERFLOW = true,
|
||||
.HAVE_WIMPLICIT_FALLTHROUGH_FLAG = true,
|
||||
.HAVE_BITSCANFORWARD64 = null,
|
||||
|
||||
.VTERM_TEST_FILE = "test/vterm_test_output", // TODO(bfredl): revisit when porting libvterm tests
|
||||
});
|
||||
|
||||
_ = gen_config.addCopyFile(sysconfig_step.getOutput(), "auto/config.h"); // run_preprocessor() workaronnd
|
||||
_ = gen_config.add("auto/pathdef.h", b.fmt(
|
||||
\\char *default_vim_dir = "/usr/local/share/nvim";
|
||||
\\char *default_vimruntime_dir = "";
|
||||
\\char *default_lib_dir = "/usr/local/lib/nvim";
|
||||
, .{}));
|
||||
|
||||
// TODO(bfredl): include git version when available
|
||||
const medium = b.fmt("v{}.{}.{}{s}+zig", .{ version.major, version.minor, version.patch, version.prerelease });
|
||||
const versiondef_git = gen_config.add("auto/versiondef_git.h", b.fmt(
|
||||
\\#define NVIM_VERSION_MEDIUM "{s}"
|
||||
\\#define NVIM_VERSION_BUILD "???"
|
||||
\\
|
||||
, .{medium}));
|
||||
|
||||
// TODO(zig): using getEmittedIncludeTree() is ugly af. we want run_preprocessor()
|
||||
// to use the std.build.Module include_path thing
|
||||
const include_path = [_]LazyPath{
|
||||
b.path("src/"),
|
||||
gen_config.getDirectory(),
|
||||
lua.getEmittedIncludeTree(),
|
||||
libuv.getEmittedIncludeTree(),
|
||||
libluv.getEmittedIncludeTree(),
|
||||
utf8proc.artifact("utf8proc").getEmittedIncludeTree(),
|
||||
unibilium.artifact("unibilium").getEmittedIncludeTree(),
|
||||
treesitter.artifact("tree-sitter").getEmittedIncludeTree(),
|
||||
};
|
||||
|
||||
const gen_headers, const funcs_data = try gen.nvim_gen_sources(b, nlua0, &nvim_sources, &nvim_headers, &api_headers, &include_path, target, versiondef_git, version_lua);
|
||||
|
||||
const test_config_step = b.addWriteFiles();
|
||||
_ = test_config_step.add("test/cmakeconfig/paths.lua", try test_config(b));
|
||||
|
||||
const test_gen_step = b.step("gen_headers", "debug: output generated headers");
|
||||
const config_install = b.addInstallDirectory(.{ .source_dir = gen_config.getDirectory(), .install_dir = .prefix, .install_subdir = "config/" });
|
||||
test_gen_step.dependOn(&config_install.step);
|
||||
test_gen_step.dependOn(&b.addInstallDirectory(.{ .source_dir = gen_headers.getDirectory(), .install_dir = .prefix, .install_subdir = "headers/" }).step);
|
||||
|
||||
const nvim_exe = b.addExecutable(.{
|
||||
.name = "nvim",
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
nvim_exe.rdynamic = true; // -E
|
||||
|
||||
nvim_exe.linkLibrary(lua);
|
||||
nvim_exe.linkLibrary(libuv);
|
||||
nvim_exe.linkLibrary(libluv);
|
||||
if (iconv_apple) |iconv| {
|
||||
nvim_exe.linkLibrary(iconv.artifact("iconv"));
|
||||
}
|
||||
nvim_exe.linkLibrary(utf8proc.artifact("utf8proc"));
|
||||
nvim_exe.linkLibrary(unibilium.artifact("unibilium"));
|
||||
nvim_exe.linkLibrary(treesitter.artifact("tree-sitter"));
|
||||
nvim_exe.addIncludePath(b.path("src"));
|
||||
nvim_exe.addIncludePath(gen_config.getDirectory());
|
||||
nvim_exe.addIncludePath(gen_headers.getDirectory());
|
||||
build_lua.add_lua_modules(nvim_exe.root_module, lpeg, use_luajit, false);
|
||||
|
||||
var unit_test_sources = try std.ArrayList([]u8).initCapacity(b.allocator, 10);
|
||||
if (support_unittests) {
|
||||
var unit_test_fixtures = try src_dir.openDir("test/unit/fixtures/", .{ .iterate = true });
|
||||
defer unit_test_fixtures.close();
|
||||
var it = unit_test_fixtures.iterateAssumeFirstIteration();
|
||||
while (try it.next()) |entry| {
|
||||
if (entry.name.len < 3) continue;
|
||||
if (std.mem.eql(u8, ".c", entry.name[entry.name.len - 2 ..])) {
|
||||
try unit_test_sources.append(b.fmt("test/unit/fixtures/{s}", .{entry.name}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const src_paths = try b.allocator.alloc([]u8, nvim_sources.items.len + unit_test_sources.items.len);
|
||||
for (nvim_sources.items, 0..) |s, i| {
|
||||
src_paths[i] = b.fmt("src/nvim/{s}", .{s.name});
|
||||
}
|
||||
@memcpy(src_paths[nvim_sources.items.len..], unit_test_sources.items);
|
||||
|
||||
const flags = [_][]const u8{
|
||||
"-std=gnu99",
|
||||
"-DINCLUDE_GENERATED_DECLARATIONS",
|
||||
"-DZIG_BUILD",
|
||||
"-D_GNU_SOURCE",
|
||||
if (support_unittests) "-DUNIT_TESTING" else "",
|
||||
if (use_luajit) "" else "-DNVIM_VENDOR_BIT",
|
||||
};
|
||||
nvim_exe.addCSourceFiles(.{ .files = src_paths, .flags = &flags });
|
||||
|
||||
nvim_exe.addCSourceFiles(.{ .files = &.{
|
||||
"src/xdiff/xdiffi.c",
|
||||
"src/xdiff/xemit.c",
|
||||
"src/xdiff/xhistogram.c",
|
||||
"src/xdiff/xpatience.c",
|
||||
"src/xdiff/xprepare.c",
|
||||
"src/xdiff/xutils.c",
|
||||
"src/cjson/lua_cjson.c",
|
||||
"src/cjson/fpconv.c",
|
||||
"src/cjson/strbuf.c",
|
||||
}, .flags = &flags });
|
||||
|
||||
const nvim_exe_step = b.step("nvim_bin", "only the binary (not a fully working install!)");
|
||||
const nvim_exe_install = b.addInstallArtifact(nvim_exe, .{});
|
||||
|
||||
nvim_exe_step.dependOn(&nvim_exe_install.step);
|
||||
|
||||
const gen_runtime = try runtime.nvim_gen_runtime(b, nlua0, nvim_exe, funcs_data);
|
||||
const runtime_install = b.addInstallDirectory(.{ .source_dir = gen_runtime.getDirectory(), .install_dir = .prefix, .install_subdir = "runtime/" });
|
||||
|
||||
const nvim = b.step("nvim", "build the editor");
|
||||
|
||||
nvim.dependOn(&nvim_exe_install.step);
|
||||
nvim.dependOn(&runtime_install.step);
|
||||
|
||||
const lua_dev_deps = b.dependency("lua_dev_deps", .{});
|
||||
|
||||
const test_deps = b.step("test_deps", "test prerequisites");
|
||||
test_deps.dependOn(&nvim_exe_install.step);
|
||||
test_deps.dependOn(&runtime_install.step);
|
||||
|
||||
test_deps.dependOn(test_fixture(b, "shell-test", null, target, optimize));
|
||||
test_deps.dependOn(test_fixture(b, "tty-test", libuv, target, optimize));
|
||||
test_deps.dependOn(test_fixture(b, "pwsh-test", null, target, optimize));
|
||||
test_deps.dependOn(test_fixture(b, "printargs-test", null, target, optimize));
|
||||
test_deps.dependOn(test_fixture(b, "printenv-test", null, target, optimize));
|
||||
test_deps.dependOn(test_fixture(b, "streams-test", libuv, target, optimize));
|
||||
|
||||
const parser_c = b.dependency("treesitter_c", .{ .target = target, .optimize = optimize });
|
||||
test_deps.dependOn(add_ts_parser(b, "c", parser_c.path("."), false, target, optimize));
|
||||
const parser_markdown = b.dependency("treesitter_markdown", .{ .target = target, .optimize = optimize });
|
||||
test_deps.dependOn(add_ts_parser(b, "markdown", parser_markdown.path("tree-sitter-markdown/"), true, target, optimize));
|
||||
test_deps.dependOn(add_ts_parser(b, "markdown_inline", parser_markdown.path("tree-sitter-markdown-inline/"), true, target, optimize));
|
||||
const parser_vim = b.dependency("treesitter_vim", .{ .target = target, .optimize = optimize });
|
||||
test_deps.dependOn(add_ts_parser(b, "vim", parser_vim.path("."), true, target, optimize));
|
||||
const parser_vimdoc = b.dependency("treesitter_vimdoc", .{ .target = target, .optimize = optimize });
|
||||
test_deps.dependOn(add_ts_parser(b, "vimdoc", parser_vimdoc.path("."), false, target, optimize));
|
||||
const parser_lua = b.dependency("treesitter_lua", .{ .target = target, .optimize = optimize });
|
||||
test_deps.dependOn(add_ts_parser(b, "lua", parser_lua.path("."), true, target, optimize));
|
||||
const parser_query = b.dependency("treesitter_query", .{ .target = target, .optimize = optimize });
|
||||
test_deps.dependOn(add_ts_parser(b, "query", parser_query.path("."), false, target, optimize));
|
||||
|
||||
const unit_headers: ?[]const LazyPath = if (support_unittests) &(include_path ++ .{gen_headers.getDirectory()}) else null;
|
||||
|
||||
try tests.test_steps(b, nvim_exe, test_deps, lua_dev_deps.path("."), test_config_step.getDirectory(), unit_headers);
|
||||
}
|
||||
|
||||
pub fn test_fixture(
|
||||
b: *std.Build,
|
||||
name: []const u8,
|
||||
libuv: ?*std.Build.Step.Compile,
|
||||
target: std.Build.ResolvedTarget,
|
||||
optimize: std.builtin.OptimizeMode,
|
||||
) *std.Build.Step {
|
||||
const fixture = b.addExecutable(.{
|
||||
.name = name,
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
const source = if (std.mem.eql(u8, name, "pwsh-test")) "shell-test" else name;
|
||||
fixture.addCSourceFile(.{ .file = b.path(b.fmt("./test/functional/fixtures/{s}.c", .{source})) });
|
||||
fixture.linkLibC();
|
||||
if (libuv) |uv| fixture.linkLibrary(uv);
|
||||
return &b.addInstallArtifact(fixture, .{}).step;
|
||||
}
|
||||
|
||||
pub fn add_ts_parser(
|
||||
b: *std.Build,
|
||||
name: []const u8,
|
||||
parser_dir: LazyPath,
|
||||
scanner: bool,
|
||||
target: std.Build.ResolvedTarget,
|
||||
optimize: std.builtin.OptimizeMode,
|
||||
) *std.Build.Step {
|
||||
const parser = b.addLibrary(.{
|
||||
.name = name,
|
||||
.root_module = b.createModule(.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
}),
|
||||
.linkage = .dynamic,
|
||||
});
|
||||
parser.addCSourceFile(.{ .file = parser_dir.path(b, "src/parser.c") });
|
||||
if (scanner) parser.addCSourceFile(.{ .file = parser_dir.path(b, "src/scanner.c") });
|
||||
parser.addIncludePath(parser_dir.path(b, "src"));
|
||||
parser.linkLibC();
|
||||
|
||||
const parser_install = b.addInstallArtifact(parser, .{ .dest_sub_path = b.fmt("parser/{s}.so", .{name}) });
|
||||
return &parser_install.step;
|
||||
}
|
||||
|
||||
pub fn lua_version_info(b: *std.Build) []u8 {
|
||||
const v = version;
|
||||
return b.fmt(
|
||||
\\return {{
|
||||
\\ {{"major", {}}},
|
||||
\\ {{"minor", {}}},
|
||||
\\ {{"patch", {}}},
|
||||
\\ {{"prerelease", {}}},
|
||||
\\ {{"api_level", {}}},
|
||||
\\ {{"api_compatible", {}}},
|
||||
\\ {{"api_prerelease", {}}},
|
||||
\\}}
|
||||
, .{ v.major, v.minor, v.patch, v.prerelease.len > 0, v.api_level, v.api_level_compat, v.api_prerelease });
|
||||
}
|
||||
|
||||
pub fn test_config(b: *std.Build) ![]u8 {
|
||||
var buf: [std.fs.max_path_bytes]u8 = undefined;
|
||||
const src_path = try b.build_root.handle.realpath(".", &buf);
|
||||
|
||||
// we don't use test/cmakeconfig/paths.lua.in because it contains cmake specific logic
|
||||
return b.fmt(
|
||||
\\local M = {{}}
|
||||
\\
|
||||
\\M.apple_sysroot = ""
|
||||
\\M.translations_enabled = "$ENABLE_TRANSLATIONS" == "ON"
|
||||
\\M.is_asan = "$ENABLE_ASAN_UBSAN" == "ON"
|
||||
\\M.is_zig_build = true
|
||||
\\M.vterm_test_file = "test/vterm_test_output"
|
||||
\\M.test_build_dir = "{[bin_dir]s}" -- bull
|
||||
\\M.test_source_path = "{[src_path]s}"
|
||||
\\M.test_lua_prg = ""
|
||||
\\M.test_luajit_prg = ""
|
||||
\\ -- include path passed on the cmdline, see test/lua_runner.lua
|
||||
\\M.include_paths = _G.c_include_path or {{}}
|
||||
\\
|
||||
\\return M
|
||||
, .{ .bin_dir = b.install_path, .src_path = src_path });
|
||||
}
|
65
build.zig.zon
Normal file
65
build.zig.zon
Normal file
@ -0,0 +1,65 @@
|
||||
.{
|
||||
.name = .neovim,
|
||||
.fingerprint = 0x66eb090879307a38,
|
||||
.version = "0.12.0",
|
||||
.minimum_zig_version = "0.14.0",
|
||||
|
||||
.dependencies = .{
|
||||
.lua_wrapper = .{
|
||||
.url = "git+https://github.com/natecraddock/ziglua#7bfb3c2b87220cdc89ef01cc99a200dad7a28e50",
|
||||
.hash = "lua_wrapper-0.1.0-OyMC27fOBAAU3E2ueB-EWGSgsuCFQZL83pT0nQJ1ufOI",
|
||||
},
|
||||
.lpeg = .{
|
||||
.url = "https://github.com/neovim/deps/raw/d495ee6f79e7962a53ad79670cb92488abe0b9b4/opt/lpeg-1.1.0.tar.gz",
|
||||
.hash = "N-V-__8AAMnaAwCEutreuREG3QayBVEZqUTDQFY1Nsrv2OIt",
|
||||
},
|
||||
.luv = .{
|
||||
.url = "git+https://github.com/luvit/luv?ref=1.51.0-1#4c9fbc6cf6f3338bb0e0426710cf885ee557b540",
|
||||
.hash = "N-V-__8AAMlNDwCY07jUoMiq3iORXdZy0uFWKiHsy8MaDBJA",
|
||||
},
|
||||
.lua_compat53 = .{
|
||||
.url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.13.tar.gz",
|
||||
.hash = "N-V-__8AADi-AwDnVoXwDCQvv2wcYOmN0bJLqZ44J3lwoQY2",
|
||||
},
|
||||
.treesitter = .{
|
||||
.url = "git+https://github.com/tree-sitter/tree-sitter?ref=v0.25.8#854f527f6ef9fdf563efb13d016e52df3ee6c45c",
|
||||
.hash = "tree_sitter-0.26.0-Tw2sR8u8CwBPBvzDbE0Ggokap5sll_qol0WSVuwjdOfC",
|
||||
},
|
||||
.libuv = .{ .path = "./deps/libuv" },
|
||||
.utf8proc = .{ .path = "./deps/utf8proc/" },
|
||||
.unibilium = .{ .path = "./deps/unibilium/" },
|
||||
.iconv_apple = .{ .path = "./deps/iconv_apple/", .lazy = true },
|
||||
.lua_dev_deps = .{
|
||||
.url = "https://github.com/neovim/deps/raw/06ef2b58b0876f8de1a3f5a710473dcd7afff251/opt/lua-dev-deps.tar.gz",
|
||||
.hash = "N-V-__8AAGevEQCHAkCozca5AIdN9DFc3Luf3g3r2AcbyOrm",
|
||||
},
|
||||
.treesitter_c = .{
|
||||
.url = "git+https://github.com/tree-sitter/tree-sitter-c?ref=v0.24.1#7fa1be1b694b6e763686793d97da01f36a0e5c12",
|
||||
.hash = "N-V-__8AANxPSABzw3WBTSH_YkwaGAfrK6PBqAMqQedkDDim",
|
||||
},
|
||||
.treesitter_markdown = .{
|
||||
.url = "git+https://github.com/tree-sitter-grammars/tree-sitter-markdown?ref=v0.5.0#afaa4138517363362f54c89330c9d79391e81168",
|
||||
.hash = "N-V-__8AAIIZUwD3CGdyI2DiHu7Suj2jIF_EAVlM6REFGwju",
|
||||
},
|
||||
.treesitter_lua = .{
|
||||
.url = "git+https://github.com/tree-sitter-grammars/tree-sitter-lua?ref=v0.4.0#4569d1c361129e71a205b94a05e158bd71b1709f",
|
||||
.hash = "N-V-__8AAEF5CABqSL9zqc03aQsT6Nni54ZCcL98pnuDL2D3",
|
||||
},
|
||||
.treesitter_vim = .{
|
||||
.url = "git+https://github.com/tree-sitter-grammars/tree-sitter-vim?ref=v0.7.0#3dd4747082d1b717b8978211c06ef7b6cd16125b",
|
||||
.hash = "N-V-__8AAMArVAB4uo2wg2XRs8HBviQ4Pq366cC_iRolX4Vc",
|
||||
},
|
||||
.treesitter_vimdoc = .{
|
||||
.url = "git+https://github.com/neovim/tree-sitter-vimdoc?ref=v4.0.0#9f6191a98702edc1084245abd5523279d4b681fb",
|
||||
.hash = "N-V-__8AAI4YCgD7OqxCEAmz2RqT_ohl6eA4F0fGMtLIe7nb",
|
||||
},
|
||||
.treesitter_query = .{
|
||||
.url = "git+https://github.com/tree-sitter-grammars/tree-sitter-query?ref=v0.6.2#8a43889f89fd0667289936341bff3a77bafade17",
|
||||
.hash = "N-V-__8AAARLBACBLGiXGFTijEzLv8AwiqT_kJpmVjir1BgX",
|
||||
},
|
||||
},
|
||||
.paths = .{
|
||||
// TODO(bfredl): explicitly list the subdirs which actually are used
|
||||
"",
|
||||
},
|
||||
}
|
@ -12,6 +12,10 @@
|
||||
#endif
|
||||
|
||||
#define NVIM_VERSION_CFLAGS "${VERSION_STRING}"
|
||||
#define NVIM_VERSION_BUILD_TYPE "$<CONFIG>"
|
||||
#ifdef ZIG_BUILD
|
||||
# define NVIM_VERSION_BUILD_TYPE "${CONFIG}"
|
||||
#else
|
||||
# define NVIM_VERSION_BUILD_TYPE "$<CONFIG>"
|
||||
#endif
|
||||
|
||||
#endif // AUTO_VERSIONDEF_H
|
||||
|
@ -42,7 +42,7 @@ if(APPLE)
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
BuildLuaJit(INSTALL_COMMAND ${BUILDCMD_UNIX}
|
||||
BuildLuajit(INSTALL_COMMAND ${BUILDCMD_UNIX}
|
||||
CC=${DEPS_C_COMPILER} PREFIX=${DEPS_INSTALL_DIR}
|
||||
${DEPLOYMENT_TARGET} install)
|
||||
|
||||
@ -53,7 +53,7 @@ elseif(MINGW)
|
||||
else()
|
||||
set(LUAJIT_MAKE_PRG ${CMAKE_MAKE_PROGRAM})
|
||||
endif()
|
||||
BuildLuaJit(BUILD_COMMAND ${LUAJIT_MAKE_PRG} CC=${DEPS_C_COMPILER}
|
||||
BuildLuajit(BUILD_COMMAND ${LUAJIT_MAKE_PRG} CC=${DEPS_C_COMPILER}
|
||||
PREFIX=${DEPS_INSTALL_DIR}
|
||||
CFLAGS+=-DLUA_USE_APICHECK
|
||||
CFLAGS+=-funwind-tables
|
||||
@ -75,7 +75,7 @@ elseif(MINGW)
|
||||
)
|
||||
elseif(MSVC)
|
||||
|
||||
BuildLuaJit(
|
||||
BuildLuajit(
|
||||
BUILD_COMMAND ${CMAKE_COMMAND} -E chdir ${DEPS_BUILD_DIR}/src/luajit/src ${DEPS_BUILD_DIR}/src/luajit/src/msvcbuild.bat
|
||||
INSTALL_COMMAND ${CMAKE_COMMAND} -E make_directory ${DEPS_BIN_DIR}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${DEPS_BUILD_DIR}/src/luajit/src/luajit.exe ${DEPS_BIN_DIR}
|
||||
|
@ -7,5 +7,6 @@ ExternalProject_Add(wasmtime
|
||||
-D WASMTIME_FASTEST_RUNTIME=ON # build with full LTO
|
||||
-D WASMTIME_DISABLE_ALL_FEATURES=ON # don't need all that crap...
|
||||
-D WASMTIME_FEATURE_CRANELIFT=ON # ...except this one (compiles wasm to platform code)
|
||||
-D WASMTIME_FEATURE_GC_DRC=ON # ...and this one (needed by ts to create engines)
|
||||
USES_TERMINAL_BUILD TRUE
|
||||
${EXTERNALPROJECT_OPTIONS})
|
||||
|
@ -1,8 +1,8 @@
|
||||
LIBUV_URL https://github.com/libuv/libuv/archive/v1.50.0.tar.gz
|
||||
LIBUV_SHA256 b1ec56444ee3f1e10c8bd3eed16ba47016ed0b94fe42137435aaf2e0bd574579
|
||||
LIBUV_URL https://github.com/libuv/libuv/archive/v1.51.0.tar.gz
|
||||
LIBUV_SHA256 27e55cf7083913bfb6826ca78cde9de7647cded648d35f24163f2d31bb9f51cd
|
||||
|
||||
LUAJIT_URL https://github.com/luajit/luajit/archive/538a82133ad6fddfd0ca64de167c4aca3bc1a2da.tar.gz
|
||||
LUAJIT_SHA256 7acbc36be8f21072422eb9a5e5fc468d0eaa55bec1b70260d651e845684621e2
|
||||
LUAJIT_URL https://github.com/luajit/luajit/archive/51d4c26ec7805d77bfc3470fdf99b73c4ef2faec.tar.gz
|
||||
LUAJIT_SHA256 7fd632850d28430b7e999bec9255d23ba7c6ecb3ecf1cafb481b8b8ecdb60612
|
||||
|
||||
LUA_URL https://www.lua.org/ftp/lua-5.1.5.tar.gz
|
||||
LUA_SHA256 2640fc56a795f29d28ef15e13c34a47e223960b0240e8cb0a82d9b0738695333
|
||||
@ -10,8 +10,8 @@ LUA_SHA256 2640fc56a795f29d28ef15e13c34a47e223960b0240e8cb0a82d9b0738695333
|
||||
UNIBILIUM_URL https://github.com/neovim/unibilium/archive/v2.1.2.tar.gz
|
||||
UNIBILIUM_SHA256 370ecb07fbbc20d91d1b350c55f1c806b06bf86797e164081ccc977fc9b3af7a
|
||||
|
||||
LUV_URL https://github.com/luvit/luv/archive/1.50.0-1.tar.gz
|
||||
LUV_SHA256 bb4f0570571e40c1d2a7644f6f9c1309a6ccdb19bf4d397e8d7bfd0c6b88e613
|
||||
LUV_URL https://github.com/luvit/luv/archive/1.51.0-1.tar.gz
|
||||
LUV_SHA256 d4a11178ae8e16ba5886799ea91905dd9b0b479c75aebd67866d37373e41526f
|
||||
|
||||
LPEG_URL https://github.com/neovim/deps/raw/d495ee6f79e7962a53ad79670cb92488abe0b9b4/opt/lpeg-1.1.0.tar.gz
|
||||
LPEG_SHA256 4b155d67d2246c1ffa7ad7bc466c1ea899bbc40fef0257cc9c03cecbaed4352a
|
||||
@ -34,25 +34,25 @@ LIBICONV_SHA256 8f74213b56238c85a50a5329f77e06198771e70dd9a739779f4c02f65d971313
|
||||
UTF8PROC_URL https://github.com/JuliaStrings/utf8proc/archive/v2.10.0.tar.gz
|
||||
UTF8PROC_SHA256 6f4f1b639daa6dca9f80bc5db1233e9cbaa31a67790887106160b33ef743f136
|
||||
|
||||
TREESITTER_C_URL https://github.com/tree-sitter/tree-sitter-c/archive/v0.23.4.tar.gz
|
||||
TREESITTER_C_SHA256 b66c5043e26d84e5f17a059af71b157bcf202221069ed220aa1696d7d1d28a7a
|
||||
TREESITTER_LUA_URL https://github.com/tree-sitter-grammars/tree-sitter-lua/archive/v0.3.0.tar.gz
|
||||
TREESITTER_LUA_SHA256 a34cc70abfd8d2d4b0fabf01403ea05f848e1a4bc37d8a4bfea7164657b35d31
|
||||
TREESITTER_VIM_URL https://github.com/tree-sitter-grammars/tree-sitter-vim/archive/v0.5.0.tar.gz
|
||||
TREESITTER_VIM_SHA256 90019d12d2da0751c027124f27f5335babf069a050457adaed53693b5e9cf10a
|
||||
TREESITTER_VIMDOC_URL https://github.com/neovim/tree-sitter-vimdoc/archive/v3.0.1.tar.gz
|
||||
TREESITTER_VIMDOC_SHA256 76b65e5bee9ff78eb21256619b1995aac4d80f252c19e1c710a4839481ded09e
|
||||
TREESITTER_QUERY_URL https://github.com/tree-sitter-grammars/tree-sitter-query/archive/v0.5.1.tar.gz
|
||||
TREESITTER_QUERY_SHA256 fe8c712880a529d454347cd4c58336ac2db22243bae5055bdb5844fb3ea56192
|
||||
TREESITTER_MARKDOWN_URL https://github.com/tree-sitter-grammars/tree-sitter-markdown/archive/v0.4.1.tar.gz
|
||||
TREESITTER_MARKDOWN_SHA256 e0fdb2dca1eb3063940122e1475c9c2b069062a638c95939e374c5427eddee9f
|
||||
TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/v0.25.3.tar.gz
|
||||
TREESITTER_SHA256 862fac52653bc7bc9d2cd0630483e6bdf3d02bcd23da956ca32663c4798a93e3
|
||||
TREESITTER_C_URL https://github.com/tree-sitter/tree-sitter-c/archive/v0.24.1.tar.gz
|
||||
TREESITTER_C_SHA256 25dd4bb3dec770769a407e0fc803f424ce02c494a56ce95fedc525316dcf9b48
|
||||
TREESITTER_LUA_URL https://github.com/tree-sitter-grammars/tree-sitter-lua/archive/v0.4.0.tar.gz
|
||||
TREESITTER_LUA_SHA256 b0977aced4a63bb75f26725787e047b8f5f4a092712c840ea7070765d4049559
|
||||
TREESITTER_VIM_URL https://github.com/tree-sitter-grammars/tree-sitter-vim/archive/v0.7.0.tar.gz
|
||||
TREESITTER_VIM_SHA256 44eabc31127c4feacda19f2a05a5788272128ff561ce01093a8b7a53aadcc7b2
|
||||
TREESITTER_VIMDOC_URL https://github.com/neovim/tree-sitter-vimdoc/archive/v4.0.0.tar.gz
|
||||
TREESITTER_VIMDOC_SHA256 8096794c0f090b2d74b7bff94548ac1be3285b929ec74f839bd9b3ff4f4c6a0b
|
||||
TREESITTER_QUERY_URL https://github.com/tree-sitter-grammars/tree-sitter-query/archive/v0.6.2.tar.gz
|
||||
TREESITTER_QUERY_SHA256 90682e128d048fbf2a2a17edca947db71e326fa0b3dba4136e041e096538b4eb
|
||||
TREESITTER_MARKDOWN_URL https://github.com/tree-sitter-grammars/tree-sitter-markdown/archive/v0.5.0.tar.gz
|
||||
TREESITTER_MARKDOWN_SHA256 14c2c948ccf0e9b606eec39b09286c59dddf28307849f71b7ce2b1d1ef06937e
|
||||
TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/v0.25.8.tar.gz
|
||||
TREESITTER_SHA256 178b575244d967f4920a4642408dc4edf6de96948d37d7f06e5b78acee9c0b4e
|
||||
|
||||
WASMTIME_URL https://github.com/bytecodealliance/wasmtime/archive/v29.0.1.tar.gz
|
||||
WASMTIME_SHA256 b94b6c6fd6aebaf05d4c69c1b12b5dc217b0d42c1a95f435b33af63dddfa5304
|
||||
|
||||
UNCRUSTIFY_URL https://github.com/uncrustify/uncrustify/archive/uncrustify-0.80.1.tar.gz
|
||||
UNCRUSTIFY_SHA256 0e2616ec2f78e12816388c513f7060072ff7942b42f1175eb28b24cb75aaec48
|
||||
UNCRUSTIFY_URL https://github.com/uncrustify/uncrustify/archive/uncrustify-0.81.0.tar.gz
|
||||
UNCRUSTIFY_SHA256 484623dc16b92206adc6ac0770077c6c67c6e441102148c2a121a19549330ff9
|
||||
LUA_DEV_DEPS_URL https://github.com/neovim/deps/raw/06ef2b58b0876f8de1a3f5a710473dcd7afff251/opt/lua-dev-deps.tar.gz
|
||||
LUA_DEV_DEPS_SHA256 49f8399e453103064a23c65534f266f3067cda716b6502f016bfafeed5799354
|
||||
|
@ -7,6 +7,7 @@ set(ENV{XDG_DATA_HOME} ${BUILD_DIR}/Xtest_xdg/share)
|
||||
set(ENV{XDG_STATE_HOME} ${BUILD_DIR}/Xtest_xdg/state)
|
||||
unset(ENV{XDG_DATA_DIRS})
|
||||
unset(ENV{NVIM}) # Clear $NVIM in case tests are running from Nvim. #11009
|
||||
unset(ENV{TMUX}) # Nvim TUI shouldn't think it's running in tmux. #34173
|
||||
|
||||
# TODO(dundargoc): The CIRRUS_CI environment variable isn't passed to here from
|
||||
# the main CMakeLists.txt, so we have to manually pass it to this script and
|
||||
@ -68,7 +69,7 @@ endif()
|
||||
execute_process(
|
||||
# Note: because of "-ll" (low-level interpreter mode), some modules like
|
||||
# _editor.lua are not loaded.
|
||||
COMMAND ${NVIM_PRG} -ll ${WORKING_DIR}/test/lua_runner.lua ${DEPS_INSTALL_DIR} busted -v -o test.busted.outputHandlers.nvim
|
||||
COMMAND ${NVIM_PRG} -ll ${WORKING_DIR}/test/lua_runner.lua ${DEPS_INSTALL_DIR}/share/lua/5.1/ busted -v -o test.busted.outputHandlers.nvim
|
||||
--lazy --helper=${TEST_DIR}/${TEST_TYPE}/preload.lua
|
||||
--lpath=${BUILD_DIR}/?.lua
|
||||
--lpath=${WORKING_DIR}/src/?.lua
|
||||
@ -78,7 +79,6 @@ execute_process(
|
||||
${TEST_PATH}
|
||||
TIMEOUT $ENV{TEST_TIMEOUT}
|
||||
WORKING_DIRECTORY ${WORKING_DIR}
|
||||
ERROR_VARIABLE err
|
||||
RESULT_VARIABLE res
|
||||
${EXTRA_ARGS})
|
||||
|
||||
@ -87,11 +87,6 @@ file(REMOVE_RECURSE ${RM_FILES})
|
||||
|
||||
if(res)
|
||||
message(STATUS "Tests exited non-zero: ${res}")
|
||||
if("${err}" STREQUAL "")
|
||||
message(STATUS "No output to stderr.")
|
||||
else()
|
||||
message(STATUS "Output to stderr:\n${err}")
|
||||
endif()
|
||||
|
||||
# Dump the logfile on CI (if not displayed and moved already).
|
||||
if(CI_BUILD)
|
||||
|
90
deps/iconv_apple/build.zig
vendored
Normal file
90
deps/iconv_apple/build.zig
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
const std = @import("std");
|
||||
|
||||
pub fn build(b: *std.Build) !void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
const upstream = b.dependency("libiconv", .{});
|
||||
const lib = b.addStaticLibrary(.{
|
||||
.name = "iconv",
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
lib.addIncludePath(b.path("include/"));
|
||||
lib.addIncludePath(upstream.path(""));
|
||||
lib.addIncludePath(upstream.path("citrus/"));
|
||||
lib.addIncludePath(upstream.path("libcharset/"));
|
||||
lib.addIncludePath(upstream.path("libiconv_modules/UTF8/"));
|
||||
// zig any-macos-any headers already includes iconv, it just cannot link without a SDK
|
||||
// lib.installHeader(upstream.path("iconv.h"), "iconv.h");
|
||||
|
||||
lib.linkLibC();
|
||||
|
||||
lib.addCSourceFiles(.{ .root = upstream.path(""), .files = &.{
|
||||
"citrus/bsd_iconv.c",
|
||||
"citrus/citrus_bcs.c",
|
||||
"citrus/citrus_bcs_strtol.c",
|
||||
"citrus/citrus_bcs_strtoul.c",
|
||||
"citrus/citrus_csmapper.c",
|
||||
"citrus/citrus_db.c",
|
||||
"citrus/citrus_db_factory.c",
|
||||
"citrus/citrus_db_hash.c",
|
||||
"citrus/citrus_esdb.c",
|
||||
"citrus/citrus_hash.c",
|
||||
"citrus/citrus_iconv.c",
|
||||
"citrus/citrus_lookup.c",
|
||||
"citrus/citrus_lookup_factory.c",
|
||||
"citrus/citrus_mapper.c",
|
||||
"citrus/citrus_memstream.c",
|
||||
"citrus/citrus_mmap.c",
|
||||
"citrus/citrus_module.c",
|
||||
"citrus/citrus_none.c",
|
||||
"citrus/citrus_pivot_factory.c",
|
||||
"citrus/citrus_prop.c",
|
||||
"citrus/citrus_stdenc.c",
|
||||
"citrus/__iconv.c",
|
||||
"citrus/iconv.c",
|
||||
"citrus/iconv_canonicalize.c",
|
||||
"citrus/iconv_close.c",
|
||||
"citrus/iconv_compat.c",
|
||||
"citrus/iconvctl.c",
|
||||
"citrus/__iconv_free_list.c",
|
||||
"citrus/__iconv_get_list.c",
|
||||
"citrus/iconvlist.c",
|
||||
"citrus/iconv_open.c",
|
||||
"citrus/iconv_open_into.c",
|
||||
"citrus/iconv_set_relocation_prefix.c",
|
||||
"libcharset/libcharset.c",
|
||||
"libiconv_modules/BIG5/citrus_big5.c",
|
||||
"libiconv_modules/DECHanyu/citrus_dechanyu.c",
|
||||
"libiconv_modules/DECKanji/citrus_deckanji.c",
|
||||
"libiconv_modules/EUC/citrus_euc.c",
|
||||
"libiconv_modules/EUCTW/citrus_euctw.c",
|
||||
"libiconv_modules/GBK2K/citrus_gbk2k.c",
|
||||
"libiconv_modules/HZ/citrus_hz.c",
|
||||
"libiconv_modules/iconv_none/citrus_iconv_none.c",
|
||||
"libiconv_modules/iconv_std/citrus_iconv_std.c",
|
||||
"libiconv_modules/ISO2022/citrus_iso2022.c",
|
||||
"libiconv_modules/JOHAB/citrus_johab.c",
|
||||
"libiconv_modules/mapper_646/citrus_mapper_646.c",
|
||||
"libiconv_modules/mapper_none/citrus_mapper_none.c",
|
||||
"libiconv_modules/mapper_serial/citrus_mapper_serial.c",
|
||||
"libiconv_modules/mapper_std/citrus_mapper_std.c",
|
||||
"libiconv_modules/mapper_zone/citrus_mapper_zone.c",
|
||||
"libiconv_modules/MSKanji/citrus_mskanji.c",
|
||||
"libiconv_modules/UES/citrus_ues.c",
|
||||
"libiconv_modules/UTF1632/citrus_utf1632.c",
|
||||
"libiconv_modules/UTF7/citrus_utf7.c",
|
||||
"libiconv_modules/UTF8/citrus_utf8.c",
|
||||
"libiconv_modules/UTF8MAC/citrus_utf8mac.c",
|
||||
"libiconv_modules/VIQR/citrus_viqr.c",
|
||||
"libiconv_modules/ZW/citrus_zw.c",
|
||||
}, .flags = &.{
|
||||
"-D_PATH_I18NMODULE=\"/usr/lib/i18n\"",
|
||||
"-D_PATH_ESDB=\"/usr/share/i18n/esdb\"",
|
||||
"-D_PATH_CSMAPPER=\"/usr/share/i18n/csmapper\"",
|
||||
} });
|
||||
|
||||
b.installArtifact(lib);
|
||||
}
|
12
deps/iconv_apple/build.zig.zon
vendored
Normal file
12
deps/iconv_apple/build.zig.zon
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
.{
|
||||
.name = "libiconv",
|
||||
.version = "107.0.0",
|
||||
.paths = .{""},
|
||||
|
||||
.dependencies = .{
|
||||
.libiconv = .{
|
||||
.url = "git+https://github.com/apple-oss-distributions/libiconv?ref=libiconv-107#a3f3b2c76dbf8ba11881debc6bcb4e309958d252",
|
||||
.hash = "N-V-__8AAKce8wQq3Mp26YIvUGtazS8KPihcFS4vSGgzQf1x",
|
||||
},
|
||||
},
|
||||
}
|
1
deps/iconv_apple/include/os/variant_private.h
vendored
Normal file
1
deps/iconv_apple/include/os/variant_private.h
vendored
Normal file
@ -0,0 +1 @@
|
||||
#define os_variant_has_internal_content(sys) false
|
125
deps/libuv/build.zig
vendored
Normal file
125
deps/libuv/build.zig
vendored
Normal file
@ -0,0 +1,125 @@
|
||||
const std = @import("std");
|
||||
|
||||
// Based on mitchellh/zig-libuv, with changes.
|
||||
pub fn build(b: *std.Build) !void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
const upstream = b.dependency("libuv", .{});
|
||||
const lib = b.addStaticLibrary(.{
|
||||
.name = "uv",
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
lib.addIncludePath(upstream.path("include"));
|
||||
lib.addIncludePath(upstream.path("src"));
|
||||
|
||||
lib.installHeadersDirectory(upstream.path("include"), ".", .{});
|
||||
|
||||
if (target.result.os.tag == .windows) {
|
||||
lib.linkSystemLibrary("psapi");
|
||||
lib.linkSystemLibrary("user32");
|
||||
lib.linkSystemLibrary("advapi32");
|
||||
lib.linkSystemLibrary("iphlpapi");
|
||||
lib.linkSystemLibrary("userenv");
|
||||
lib.linkSystemLibrary("ws2_32");
|
||||
}
|
||||
if (target.result.os.tag == .linux) {
|
||||
lib.linkSystemLibrary("pthread");
|
||||
}
|
||||
lib.linkLibC();
|
||||
|
||||
if (target.result.os.tag != .windows) {
|
||||
lib.root_module.addCMacro("FILE_OFFSET_BITS", "64");
|
||||
lib.root_module.addCMacro("_LARGEFILE_SOURCE", "");
|
||||
}
|
||||
|
||||
if (target.result.os.tag == .linux) {
|
||||
lib.root_module.addCMacro("_GNU_SOURCE", "");
|
||||
lib.root_module.addCMacro("_POSIX_C_SOURCE", "200112");
|
||||
}
|
||||
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
lib.root_module.addCMacro("_DARWIN_UNLIMITED_SELECT", "1");
|
||||
lib.root_module.addCMacro("_DARWIN_USE_64_BIT_INODE", "1");
|
||||
}
|
||||
|
||||
const root = upstream.path("");
|
||||
|
||||
// C files common to all platforms
|
||||
lib.addCSourceFiles(.{ .root = root, .files = &.{
|
||||
"src/fs-poll.c",
|
||||
"src/idna.c",
|
||||
"src/inet.c",
|
||||
"src/random.c",
|
||||
"src/strscpy.c",
|
||||
"src/strtok.c",
|
||||
"src/threadpool.c",
|
||||
"src/timer.c",
|
||||
"src/uv-common.c",
|
||||
"src/uv-data-getter-setters.c",
|
||||
"src/version.c",
|
||||
} });
|
||||
|
||||
if (target.result.os.tag != .windows) {
|
||||
lib.addCSourceFiles(.{ .root = root, .files = &.{
|
||||
"src/unix/async.c",
|
||||
"src/unix/core.c",
|
||||
"src/unix/dl.c",
|
||||
"src/unix/fs.c",
|
||||
"src/unix/getaddrinfo.c",
|
||||
"src/unix/getnameinfo.c",
|
||||
"src/unix/loop-watcher.c",
|
||||
"src/unix/loop.c",
|
||||
"src/unix/pipe.c",
|
||||
"src/unix/poll.c",
|
||||
"src/unix/process.c",
|
||||
"src/unix/random-devurandom.c",
|
||||
"src/unix/signal.c",
|
||||
"src/unix/stream.c",
|
||||
"src/unix/tcp.c",
|
||||
"src/unix/thread.c",
|
||||
"src/unix/tty.c",
|
||||
"src/unix/udp.c",
|
||||
} });
|
||||
}
|
||||
|
||||
if (target.result.os.tag == .linux or target.result.os.tag.isDarwin()) {
|
||||
lib.addCSourceFiles(.{ .root = root, .files = &.{
|
||||
"src/unix/proctitle.c",
|
||||
} });
|
||||
}
|
||||
|
||||
if (target.result.os.tag == .linux) {
|
||||
lib.addCSourceFiles(.{ .root = root, .files = &.{
|
||||
"src/unix/linux.c",
|
||||
"src/unix/procfs-exepath.c",
|
||||
"src/unix/random-getrandom.c",
|
||||
"src/unix/random-sysctl-linux.c",
|
||||
} });
|
||||
}
|
||||
|
||||
if (target.result.os.tag.isBSD()) {
|
||||
lib.addCSourceFiles(.{ .root = root, .files = &.{
|
||||
"src/unix/bsd-ifaddrs.c",
|
||||
"src/unix/kqueue.c",
|
||||
} });
|
||||
}
|
||||
|
||||
if (target.result.os.tag.isDarwin() or target.result.os.tag == .openbsd) {
|
||||
lib.addCSourceFiles(.{ .root = root, .files = &.{
|
||||
"src/unix/random-getentropy.c",
|
||||
} });
|
||||
}
|
||||
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
lib.addCSourceFiles(.{ .root = root, .files = &.{
|
||||
"src/unix/darwin-proctitle.c",
|
||||
"src/unix/darwin.c",
|
||||
"src/unix/fsevents.c",
|
||||
} });
|
||||
}
|
||||
|
||||
b.installArtifact(lib);
|
||||
}
|
12
deps/libuv/build.zig.zon
vendored
Normal file
12
deps/libuv/build.zig.zon
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
.{
|
||||
.name = "libuv",
|
||||
.version = "1.51.0",
|
||||
.paths = .{""},
|
||||
|
||||
.dependencies = .{
|
||||
.libuv = .{
|
||||
.url = "git+https://github.com/libuv/libuv?ref=v1.51.0#76fb3b73da3f8ddaeeb87d23fda04b9bda219f5e",
|
||||
.hash = "N-V-__8AAExNRADXPh6GLMmWlqC2EVkp6hzH9wPuzjh_eSkE",
|
||||
},
|
||||
},
|
||||
}
|
27
deps/unibilium/build.zig
vendored
Normal file
27
deps/unibilium/build.zig
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
const std = @import("std");
|
||||
|
||||
pub fn build(b: *std.Build) !void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
const upstream = b.dependency("unibilium", .{});
|
||||
const lib = b.addStaticLibrary(.{
|
||||
.name = "unibilium",
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
lib.addIncludePath(upstream.path(""));
|
||||
|
||||
lib.installHeader(upstream.path("unibilium.h"), "unibilium.h");
|
||||
|
||||
lib.linkLibC();
|
||||
|
||||
lib.addCSourceFiles(.{ .root = upstream.path(""), .files = &.{
|
||||
"unibilium.c",
|
||||
"uninames.c",
|
||||
"uniutil.c",
|
||||
}, .flags = &.{"-DTERMINFO_DIRS=\"/etc/terminfo:/usr/share/terminfo\""} });
|
||||
|
||||
b.installArtifact(lib);
|
||||
}
|
12
deps/unibilium/build.zig.zon
vendored
Normal file
12
deps/unibilium/build.zig.zon
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
.{
|
||||
.name = "unibilium",
|
||||
.version = "2.1.2",
|
||||
.paths = .{""},
|
||||
|
||||
.dependencies = .{
|
||||
.unibilium = .{
|
||||
.url = "git+https://github.com/neovim/unibilium?ref=v2.1.2#bfcb0350129dd76893bc90399cf37c45812268a2",
|
||||
.hash = "N-V-__8AADO1CgCggvx73yptnBlXbEm7TjOSO6VGIqc0CvYR",
|
||||
},
|
||||
},
|
||||
}
|
24
deps/utf8proc/build.zig
vendored
Normal file
24
deps/utf8proc/build.zig
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
const std = @import("std");
|
||||
|
||||
pub fn build(b: *std.Build) !void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
const upstream = b.dependency("utf8proc", .{});
|
||||
const lib = b.addStaticLibrary(.{
|
||||
.name = "utf8proc",
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
lib.addIncludePath(upstream.path(""));
|
||||
lib.installHeader(upstream.path("utf8proc.h"), "utf8proc.h");
|
||||
|
||||
lib.linkLibC();
|
||||
|
||||
lib.addCSourceFiles(.{ .root = upstream.path(""), .files = &.{
|
||||
"utf8proc.c",
|
||||
} });
|
||||
|
||||
b.installArtifact(lib);
|
||||
}
|
12
deps/utf8proc/build.zig.zon
vendored
Normal file
12
deps/utf8proc/build.zig.zon
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
.{
|
||||
.name = "utf8proc",
|
||||
.version = "2.10.0",
|
||||
.paths = .{""},
|
||||
|
||||
.dependencies = .{
|
||||
.utf8proc = .{
|
||||
.url = "git+https://github.com/JuliaStrings/utf8proc?ref=v2.10.0#a1b99daa2a3393884220264c927a48ba1251a9c6",
|
||||
.hash = "N-V-__8AAPJfKADYDOC95xuKyudrlob6eFqgzfFl8NbpOoU9",
|
||||
},
|
||||
},
|
||||
}
|
@ -12,12 +12,17 @@ get_directory_property(LUA_GEN_DEPS DIRECTORY ${PROJECT_SOURCE_DIR}/src/nvim DEF
|
||||
|
||||
add_custom_command(OUTPUT ${GENERATED_SYN_VIM}
|
||||
COMMAND ${LUA_GEN} ${SYN_VIM_GENERATOR} ${GENERATED_SYN_VIM} ${FUNCS_DATA}
|
||||
${PROJECT_SOURCE_DIR}/src/nvim/options.lua
|
||||
${PROJECT_SOURCE_DIR}/src/nvim/auevents.lua
|
||||
${PROJECT_SOURCE_DIR}/src/nvim/ex_cmds.lua
|
||||
${PROJECT_SOURCE_DIR}/src/nvim/vvars.lua
|
||||
DEPENDS
|
||||
${LUA_GEN_DEPS}
|
||||
${SYN_VIM_GENERATOR}
|
||||
${PROJECT_SOURCE_DIR}/src/nvim/ex_cmds.lua
|
||||
${PROJECT_SOURCE_DIR}/src/nvim/auevents.lua
|
||||
${PROJECT_SOURCE_DIR}/src/nvim/options.lua
|
||||
${PROJECT_SOURCE_DIR}/src/nvim/vvars.lua
|
||||
${PROJECT_SOURCE_DIR}/src/nvim/eval.c
|
||||
${FUNCS_DATA}
|
||||
)
|
||||
|
@ -1,859 +0,0 @@
|
||||
----------------------------------------
|
||||
-- This file is generated via github.com/tjdevries/vim9jit
|
||||
-- For any bugs, please first consider reporting there.
|
||||
----------------------------------------
|
||||
|
||||
-- Ignore "value assigned to a local variable is unused" because
|
||||
-- we can't guarantee that local variables will be used by plugins
|
||||
-- luacheck: ignore
|
||||
--- @diagnostic disable
|
||||
|
||||
local vim9 = require('_vim9script')
|
||||
local M = {}
|
||||
local prepended = nil
|
||||
local grepCache = nil
|
||||
local Complete = nil
|
||||
local GetAddition = nil
|
||||
local Tag2item = nil
|
||||
local Dict2info = nil
|
||||
local ParseTagline = nil
|
||||
local Tagline2item = nil
|
||||
local Tagcmd2extra = nil
|
||||
local Nextitem = nil
|
||||
local StructMembers = nil
|
||||
local SearchMembers = nil
|
||||
-- vim9script
|
||||
|
||||
-- # Vim completion script
|
||||
-- # Language: C
|
||||
-- # Maintainer: The Vim Project <https://github.com/vim/vim>
|
||||
-- # Last Change: 2023 Aug 10
|
||||
-- # Rewritten in Vim9 script by github user lacygoill
|
||||
-- # Former Maintainer: Bram Moolenaar <Bram@vim.org>
|
||||
|
||||
prepended = ''
|
||||
grepCache = vim.empty_dict()
|
||||
|
||||
-- # This function is used for the 'omnifunc' option.
|
||||
|
||||
Complete = function(findstart, abase)
|
||||
findstart = vim9.bool(findstart)
|
||||
if vim9.bool(findstart) then
|
||||
-- # Locate the start of the item, including ".", "->" and "[...]".
|
||||
local line = vim9.fn.getline('.')
|
||||
local start = vim9.fn.charcol('.') - 1
|
||||
local lastword = -1
|
||||
while start > 0 do
|
||||
if vim9.ops.RegexpMatches(vim9.index(line, vim9.ops.Minus(start, 1)), '\\w') then
|
||||
start = start - 1
|
||||
elseif
|
||||
vim9.bool(vim9.ops.RegexpMatches(vim9.index(line, vim9.ops.Minus(start, 1)), '\\.'))
|
||||
then
|
||||
if lastword == -1 then
|
||||
lastword = start
|
||||
end
|
||||
start = start - 1
|
||||
elseif
|
||||
vim9.bool(
|
||||
start > 1
|
||||
and vim9.index(line, vim9.ops.Minus(start, 2)) == '-'
|
||||
and vim9.index(line, vim9.ops.Minus(start, 1)) == '>'
|
||||
)
|
||||
then
|
||||
if lastword == -1 then
|
||||
lastword = start
|
||||
end
|
||||
start = vim9.ops.Minus(start, 2)
|
||||
elseif vim9.bool(vim9.index(line, vim9.ops.Minus(start, 1)) == ']') then
|
||||
-- # Skip over [...].
|
||||
local n = 0
|
||||
start = start - 1
|
||||
while start > 0 do
|
||||
start = start - 1
|
||||
if vim9.index(line, start) == '[' then
|
||||
if n == 0 then
|
||||
break
|
||||
end
|
||||
n = n - 1
|
||||
elseif vim9.bool(vim9.index(line, start) == ']') then
|
||||
n = n + 1
|
||||
end
|
||||
end
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- # Return the column of the last word, which is going to be changed.
|
||||
-- # Remember the text that comes before it in prepended.
|
||||
if lastword == -1 then
|
||||
prepended = ''
|
||||
return vim9.fn.byteidx(line, start)
|
||||
end
|
||||
prepended = vim9.slice(line, start, vim9.ops.Minus(lastword, 1))
|
||||
return vim9.fn.byteidx(line, lastword)
|
||||
end
|
||||
|
||||
-- # Return list of matches.
|
||||
|
||||
local base = prepended .. abase
|
||||
|
||||
-- # Don't do anything for an empty base, would result in all the tags in the
|
||||
-- # tags file.
|
||||
if base == '' then
|
||||
return {}
|
||||
end
|
||||
|
||||
-- # init cache for vimgrep to empty
|
||||
grepCache = {}
|
||||
|
||||
-- # Split item in words, keep empty word after "." or "->".
|
||||
-- # "aa" -> ['aa'], "aa." -> ['aa', ''], "aa.bb" -> ['aa', 'bb'], etc.
|
||||
-- # We can't use split, because we need to skip nested [...].
|
||||
-- # "aa[...]" -> ['aa', '[...]'], "aa.bb[...]" -> ['aa', 'bb', '[...]'], etc.
|
||||
local items = {}
|
||||
local s = 0
|
||||
local arrays = 0
|
||||
while 1 do
|
||||
local e = vim9.fn.charidx(base, vim9.fn.match(base, '\\.\\|->\\|\\[', s))
|
||||
if e < 0 then
|
||||
if s == 0 or vim9.index(base, vim9.ops.Minus(s, 1)) ~= ']' then
|
||||
vim9.fn.add(items, vim9.slice(base, s, nil))
|
||||
end
|
||||
break
|
||||
end
|
||||
if s == 0 or vim9.index(base, vim9.ops.Minus(s, 1)) ~= ']' then
|
||||
vim9.fn.add(items, vim9.slice(base, s, vim9.ops.Minus(e, 1)))
|
||||
end
|
||||
if vim9.index(base, e) == '.' then
|
||||
-- # skip over '.'
|
||||
s = vim9.ops.Plus(e, 1)
|
||||
elseif vim9.bool(vim9.index(base, e) == '-') then
|
||||
-- # skip over '->'
|
||||
s = vim9.ops.Plus(e, 2)
|
||||
else
|
||||
-- # Skip over [...].
|
||||
local n = 0
|
||||
s = e
|
||||
e = e + 1
|
||||
while e < vim9.fn.strcharlen(base) do
|
||||
if vim9.index(base, e) == ']' then
|
||||
if n == 0 then
|
||||
break
|
||||
end
|
||||
n = n - 1
|
||||
elseif vim9.bool(vim9.index(base, e) == '[') then
|
||||
n = n + 1
|
||||
end
|
||||
e = e + 1
|
||||
end
|
||||
e = e + 1
|
||||
vim9.fn.add(items, vim9.slice(base, s, vim9.ops.Minus(e, 1)))
|
||||
arrays = arrays + 1
|
||||
s = e
|
||||
end
|
||||
end
|
||||
|
||||
-- # Find the variable items[0].
|
||||
-- # 1. in current function (like with "gd")
|
||||
-- # 2. in tags file(s) (like with ":tag")
|
||||
-- # 3. in current file (like with "gD")
|
||||
local res = {}
|
||||
if vim9.fn.searchdecl(vim9.index(items, 0), false, true) == 0 then
|
||||
-- # Found, now figure out the type.
|
||||
-- # TODO: join previous line if it makes sense
|
||||
local line = vim9.fn.getline('.')
|
||||
local col = vim9.fn.charcol('.')
|
||||
if vim9.fn.stridx(vim9.slice(line, nil, vim9.ops.Minus(col, 1)), ';') >= 0 then
|
||||
-- # Handle multiple declarations on the same line.
|
||||
local col2 = vim9.ops.Minus(col, 1)
|
||||
while vim9.index(line, col2) ~= ';' do
|
||||
col2 = col2 - 1
|
||||
end
|
||||
line = vim9.slice(line, vim9.ops.Plus(col2, 1), nil)
|
||||
col = vim9.ops.Minus(col, col2)
|
||||
end
|
||||
if vim9.fn.stridx(vim9.slice(line, nil, vim9.ops.Minus(col, 1)), ',') >= 0 then
|
||||
-- # Handle multiple declarations on the same line in a function
|
||||
-- # declaration.
|
||||
local col2 = vim9.ops.Minus(col, 1)
|
||||
while vim9.index(line, col2) ~= ',' do
|
||||
col2 = col2 - 1
|
||||
end
|
||||
if
|
||||
vim9.ops.RegexpMatches(
|
||||
vim9.slice(line, vim9.ops.Plus(col2, 1), vim9.ops.Minus(col, 1)),
|
||||
' *[^ ][^ ]* *[^ ]'
|
||||
)
|
||||
then
|
||||
line = vim9.slice(line, vim9.ops.Plus(col2, 1), nil)
|
||||
col = vim9.ops.Minus(col, col2)
|
||||
end
|
||||
end
|
||||
if vim9.fn.len(items) == 1 then
|
||||
-- # Completing one word and it's a local variable: May add '[', '.' or
|
||||
-- # '->'.
|
||||
local match = vim9.index(items, 0)
|
||||
local kind = 'v'
|
||||
if vim9.fn.match(line, '\\<' .. match .. '\\s*\\[') > 0 then
|
||||
match = match .. '['
|
||||
else
|
||||
res = Nextitem(vim9.slice(line, nil, vim9.ops.Minus(col, 1)), { '' }, 0, true)
|
||||
if vim9.fn.len(res) > 0 then
|
||||
-- # There are members, thus add "." or "->".
|
||||
if vim9.fn.match(line, '\\*[ \\t(]*' .. match .. '\\>') > 0 then
|
||||
match = match .. '->'
|
||||
else
|
||||
match = match .. '.'
|
||||
end
|
||||
end
|
||||
end
|
||||
res = { { ['match'] = match, ['tagline'] = '', ['kind'] = kind, ['info'] = line } }
|
||||
elseif vim9.bool(vim9.fn.len(items) == vim9.ops.Plus(arrays, 1)) then
|
||||
-- # Completing one word and it's a local array variable: build tagline
|
||||
-- # from declaration line
|
||||
local match = vim9.index(items, 0)
|
||||
local kind = 'v'
|
||||
local tagline = '\t/^' .. line .. '$/'
|
||||
res = { { ['match'] = match, ['tagline'] = tagline, ['kind'] = kind, ['info'] = line } }
|
||||
else
|
||||
-- # Completing "var.", "var.something", etc.
|
||||
res =
|
||||
Nextitem(vim9.slice(line, nil, vim9.ops.Minus(col, 1)), vim9.slice(items, 1, nil), 0, true)
|
||||
end
|
||||
end
|
||||
|
||||
if vim9.fn.len(items) == 1 or vim9.fn.len(items) == vim9.ops.Plus(arrays, 1) then
|
||||
-- # Only one part, no "." or "->": complete from tags file.
|
||||
local tags = {}
|
||||
if vim9.fn.len(items) == 1 then
|
||||
tags = vim9.fn.taglist('^' .. base)
|
||||
else
|
||||
tags = vim9.fn.taglist('^' .. vim9.index(items, 0) .. '$')
|
||||
end
|
||||
|
||||
vim9.fn_mut('filter', {
|
||||
vim9.fn_mut('filter', {
|
||||
tags,
|
||||
function(_, v)
|
||||
return vim9.ternary(vim9.fn.has_key(v, 'kind'), function()
|
||||
return v.kind ~= 'm'
|
||||
end, true)
|
||||
end,
|
||||
}, { replace = 0 }),
|
||||
function(_, v)
|
||||
return vim9.ops.Or(
|
||||
vim9.ops.Or(
|
||||
vim9.prefix['Bang'](vim9.fn.has_key(v, 'static')),
|
||||
vim9.prefix['Bang'](vim9.index(v, 'static'))
|
||||
),
|
||||
vim9.fn.bufnr('%') == vim9.fn.bufnr(vim9.index(v, 'filename'))
|
||||
)
|
||||
end,
|
||||
}, { replace = 0 })
|
||||
|
||||
res = vim9.fn.extend(
|
||||
res,
|
||||
vim9.fn.map(tags, function(_, v)
|
||||
return Tag2item(v)
|
||||
end)
|
||||
)
|
||||
end
|
||||
|
||||
if vim9.fn.len(res) == 0 then
|
||||
-- # Find the variable in the tags file(s)
|
||||
local diclist = vim9.fn.filter(
|
||||
vim9.fn.taglist('^' .. vim9.index(items, 0) .. '$'),
|
||||
function(_, v)
|
||||
return vim9.ternary(vim9.fn.has_key(v, 'kind'), function()
|
||||
return v.kind ~= 'm'
|
||||
end, true)
|
||||
end
|
||||
)
|
||||
|
||||
res = {}
|
||||
|
||||
for _, i in vim9.iter(vim9.fn.range(vim9.fn.len(diclist))) do
|
||||
-- # New ctags has the "typeref" field. Patched version has "typename".
|
||||
if vim9.bool(vim9.fn.has_key(vim9.index(diclist, i), 'typename')) then
|
||||
res = vim9.fn.extend(
|
||||
res,
|
||||
StructMembers(
|
||||
vim9.index(vim9.index(diclist, i), 'typename'),
|
||||
vim9.slice(items, 1, nil),
|
||||
true
|
||||
)
|
||||
)
|
||||
elseif vim9.bool(vim9.fn.has_key(vim9.index(diclist, i), 'typeref')) then
|
||||
res = vim9.fn.extend(
|
||||
res,
|
||||
StructMembers(
|
||||
vim9.index(vim9.index(diclist, i), 'typeref'),
|
||||
vim9.slice(items, 1, nil),
|
||||
true
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
-- # For a variable use the command, which must be a search pattern that
|
||||
-- # shows the declaration of the variable.
|
||||
if vim9.index(vim9.index(diclist, i), 'kind') == 'v' then
|
||||
local line = vim9.index(vim9.index(diclist, i), 'cmd')
|
||||
if vim9.slice(line, nil, 1) == '/^' then
|
||||
local col =
|
||||
vim9.fn.charidx(line, vim9.fn.match(line, '\\<' .. vim9.index(items, 0) .. '\\>'))
|
||||
res = vim9.fn.extend(
|
||||
res,
|
||||
Nextitem(
|
||||
vim9.slice(line, 2, vim9.ops.Minus(col, 1)),
|
||||
vim9.slice(items, 1, nil),
|
||||
0,
|
||||
true
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if vim9.fn.len(res) == 0 and vim9.fn.searchdecl(vim9.index(items, 0), true) == 0 then
|
||||
-- # Found, now figure out the type.
|
||||
-- # TODO: join previous line if it makes sense
|
||||
local line = vim9.fn.getline('.')
|
||||
local col = vim9.fn.charcol('.')
|
||||
res =
|
||||
Nextitem(vim9.slice(line, nil, vim9.ops.Minus(col, 1)), vim9.slice(items, 1, nil), 0, true)
|
||||
end
|
||||
|
||||
-- # If the last item(s) are [...] they need to be added to the matches.
|
||||
local last = vim9.fn.len(items) - 1
|
||||
local brackets = ''
|
||||
while last >= 0 do
|
||||
if vim9.index(vim9.index(items, last), 0) ~= '[' then
|
||||
break
|
||||
end
|
||||
brackets = vim9.index(items, last) .. brackets
|
||||
last = last - 1
|
||||
end
|
||||
|
||||
return vim9.fn.map(res, function(_, v)
|
||||
return Tagline2item(v, brackets)
|
||||
end)
|
||||
end
|
||||
M['Complete'] = Complete
|
||||
|
||||
GetAddition = function(line, match, memarg, bracket)
|
||||
bracket = vim9.bool(bracket)
|
||||
-- # Guess if the item is an array.
|
||||
if vim9.bool(vim9.ops.And(bracket, vim9.fn.match(line, match .. '\\s*\\[') > 0)) then
|
||||
return '['
|
||||
end
|
||||
|
||||
-- # Check if the item has members.
|
||||
if vim9.fn.len(SearchMembers(memarg, { '' }, false)) > 0 then
|
||||
-- # If there is a '*' before the name use "->".
|
||||
if vim9.fn.match(line, '\\*[ \\t(]*' .. match .. '\\>') > 0 then
|
||||
return '->'
|
||||
else
|
||||
return '.'
|
||||
end
|
||||
end
|
||||
return ''
|
||||
end
|
||||
|
||||
Tag2item = function(val)
|
||||
-- # Turn the tag info "val" into an item for completion.
|
||||
-- # "val" is is an item in the list returned by taglist().
|
||||
-- # If it is a variable we may add "." or "->". Don't do it for other types,
|
||||
-- # such as a typedef, by not including the info that GetAddition() uses.
|
||||
local res = vim9.convert.decl_dict({ ['match'] = vim9.index(val, 'name') })
|
||||
|
||||
res[vim9.index_expr('extra')] =
|
||||
Tagcmd2extra(vim9.index(val, 'cmd'), vim9.index(val, 'name'), vim9.index(val, 'filename'))
|
||||
|
||||
local s = Dict2info(val)
|
||||
if s ~= '' then
|
||||
res[vim9.index_expr('info')] = s
|
||||
end
|
||||
|
||||
res[vim9.index_expr('tagline')] = ''
|
||||
if vim9.bool(vim9.fn.has_key(val, 'kind')) then
|
||||
local kind = vim9.index(val, 'kind')
|
||||
res[vim9.index_expr('kind')] = kind
|
||||
if kind == 'v' then
|
||||
res[vim9.index_expr('tagline')] = '\t' .. vim9.index(val, 'cmd')
|
||||
res[vim9.index_expr('dict')] = val
|
||||
elseif vim9.bool(kind == 'f') then
|
||||
res[vim9.index_expr('match')] = vim9.index(val, 'name') .. '('
|
||||
end
|
||||
end
|
||||
|
||||
return res
|
||||
end
|
||||
|
||||
Dict2info = function(dict)
|
||||
-- # Use all the items in dictionary for the "info" entry.
|
||||
local info = ''
|
||||
|
||||
for _, k in vim9.iter(vim9.fn_mut('sort', { vim9.fn.keys(dict) }, { replace = 0 })) do
|
||||
info = info .. k .. vim9.fn['repeat'](' ', 10 - vim9.fn.strlen(k))
|
||||
if k == 'cmd' then
|
||||
info = info
|
||||
.. vim9.fn.substitute(
|
||||
vim9.fn.matchstr(vim9.index(dict, 'cmd'), '/^\\s*\\zs.*\\ze$/'),
|
||||
'\\\\\\(.\\)',
|
||||
'\\1',
|
||||
'g'
|
||||
)
|
||||
else
|
||||
local dictk = vim9.index(dict, k)
|
||||
if vim9.fn.typename(dictk) ~= 'string' then
|
||||
info = info .. vim9.fn.string(dictk)
|
||||
else
|
||||
info = info .. dictk
|
||||
end
|
||||
end
|
||||
info = info .. '\n'
|
||||
end
|
||||
|
||||
return info
|
||||
end
|
||||
|
||||
ParseTagline = function(line)
|
||||
-- # Parse a tag line and return a dictionary with items like taglist()
|
||||
local l = vim9.fn.split(line, '\t')
|
||||
local d = vim.empty_dict()
|
||||
if vim9.fn.len(l) >= 3 then
|
||||
d[vim9.index_expr('name')] = vim9.index(l, 0)
|
||||
d[vim9.index_expr('filename')] = vim9.index(l, 1)
|
||||
d[vim9.index_expr('cmd')] = vim9.index(l, 2)
|
||||
local n = 2
|
||||
if vim9.ops.RegexpMatches(vim9.index(l, 2), '^/') then
|
||||
-- # Find end of cmd, it may contain Tabs.
|
||||
while n < vim9.fn.len(l) and vim9.ops.NotRegexpMatches(vim9.index(l, n), '/;"$') do
|
||||
n = n + 1
|
||||
d[vim9.index_expr('cmd')] = vim9.index(d, 'cmd') .. ' ' .. vim9.index(l, n)
|
||||
end
|
||||
end
|
||||
|
||||
for _, i in vim9.iter(vim9.fn.range(vim9.ops.Plus(n, 1), vim9.fn.len(l) - 1)) do
|
||||
if vim9.index(l, i) == 'file:' then
|
||||
d[vim9.index_expr('static')] = 1
|
||||
elseif vim9.bool(vim9.ops.NotRegexpMatches(vim9.index(l, i), ':')) then
|
||||
d[vim9.index_expr('kind')] = vim9.index(l, i)
|
||||
else
|
||||
d[vim9.index_expr(vim9.fn.matchstr(vim9.index(l, i), '[^:]*'))] =
|
||||
vim9.fn.matchstr(vim9.index(l, i), ':\\zs.*')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return d
|
||||
end
|
||||
|
||||
Tagline2item = function(val, brackets)
|
||||
-- # Turn a match item "val" into an item for completion.
|
||||
-- # "val['match']" is the matching item.
|
||||
-- # "val['tagline']" is the tagline in which the last part was found.
|
||||
local line = vim9.index(val, 'tagline')
|
||||
local add = GetAddition(line, vim9.index(val, 'match'), { val }, brackets == '')
|
||||
local res = vim9.convert.decl_dict({ ['word'] = vim9.index(val, 'match') .. brackets .. add })
|
||||
|
||||
if vim9.bool(vim9.fn.has_key(val, 'info')) then
|
||||
-- # Use info from Tag2item().
|
||||
res[vim9.index_expr('info')] = vim9.index(val, 'info')
|
||||
else
|
||||
-- # Parse the tag line and add each part to the "info" entry.
|
||||
local s = Dict2info(ParseTagline(line))
|
||||
if s ~= '' then
|
||||
res[vim9.index_expr('info')] = s
|
||||
end
|
||||
end
|
||||
|
||||
if vim9.bool(vim9.fn.has_key(val, 'kind')) then
|
||||
res[vim9.index_expr('kind')] = vim9.index(val, 'kind')
|
||||
elseif vim9.bool(add == '(') then
|
||||
res[vim9.index_expr('kind')] = 'f'
|
||||
else
|
||||
local s = vim9.fn.matchstr(line, '\\t\\(kind:\\)\\=\\zs\\S\\ze\\(\\t\\|$\\)')
|
||||
if s ~= '' then
|
||||
res[vim9.index_expr('kind')] = s
|
||||
end
|
||||
end
|
||||
|
||||
if vim9.bool(vim9.fn.has_key(val, 'extra')) then
|
||||
res[vim9.index_expr('menu')] = vim9.index(val, 'extra')
|
||||
return res
|
||||
end
|
||||
|
||||
-- # Isolate the command after the tag and filename.
|
||||
local s = vim9.fn.matchstr(
|
||||
line,
|
||||
'[^\\t]*\\t[^\\t]*\\t\\zs\\(/^.*$/\\|[^\\t]*\\)\\ze\\(;"\\t\\|\\t\\|$\\)'
|
||||
)
|
||||
if s ~= '' then
|
||||
res[vim9.index_expr('menu')] = Tagcmd2extra(
|
||||
s,
|
||||
vim9.index(val, 'match'),
|
||||
vim9.fn.matchstr(line, '[^\\t]*\\t\\zs[^\\t]*\\ze\\t')
|
||||
)
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
Tagcmd2extra = function(cmd, name, fname)
|
||||
-- # Turn a command from a tag line to something that is useful in the menu
|
||||
local x = ''
|
||||
if vim9.ops.RegexpMatches(cmd, '^/^') then
|
||||
-- # The command is a search command, useful to see what it is.
|
||||
x = vim9.fn.substitute(
|
||||
vim9.fn.substitute(
|
||||
vim9.fn.matchstr(cmd, '^/^\\s*\\zs.*\\ze$/'),
|
||||
'\\<' .. name .. '\\>',
|
||||
'@@',
|
||||
''
|
||||
),
|
||||
'\\\\\\(.\\)',
|
||||
'\\1',
|
||||
'g'
|
||||
) .. ' - ' .. fname
|
||||
elseif vim9.bool(vim9.ops.RegexpMatches(cmd, '^\\d*$')) then
|
||||
-- # The command is a line number, the file name is more useful.
|
||||
x = fname .. ' - ' .. cmd
|
||||
else
|
||||
-- # Not recognized, use command and file name.
|
||||
x = cmd .. ' - ' .. fname
|
||||
end
|
||||
return x
|
||||
end
|
||||
|
||||
Nextitem = function(lead, items, depth, all)
|
||||
all = vim9.bool(all)
|
||||
-- # Find composing type in "lead" and match items[0] with it.
|
||||
-- # Repeat this recursively for items[1], if it's there.
|
||||
-- # When resolving typedefs "depth" is used to avoid infinite recursion.
|
||||
-- # Return the list of matches.
|
||||
|
||||
-- # Use the text up to the variable name and split it in tokens.
|
||||
local tokens = vim9.fn.split(lead, '\\s\\+\\|\\<')
|
||||
|
||||
-- # Try to recognize the type of the variable. This is rough guessing...
|
||||
local res = {}
|
||||
|
||||
local body = function(_, tidx)
|
||||
-- # Skip tokens starting with a non-ID character.
|
||||
if vim9.ops.NotRegexpMatches(vim9.index(tokens, tidx), '^\\h') then
|
||||
return vim9.ITER_CONTINUE
|
||||
end
|
||||
|
||||
-- # Recognize "struct foobar" and "union foobar".
|
||||
-- # Also do "class foobar" when it's C++ after all (doesn't work very well
|
||||
-- # though).
|
||||
if
|
||||
(
|
||||
vim9.index(tokens, tidx) == 'struct'
|
||||
or vim9.index(tokens, tidx) == 'union'
|
||||
or vim9.index(tokens, tidx) == 'class'
|
||||
) and vim9.ops.Plus(tidx, 1) < vim9.fn.len(tokens)
|
||||
then
|
||||
res = StructMembers(
|
||||
vim9.index(tokens, tidx) .. ':' .. vim9.index(tokens, vim9.ops.Plus(tidx, 1)),
|
||||
items,
|
||||
all
|
||||
)
|
||||
return vim9.ITER_BREAK
|
||||
end
|
||||
|
||||
-- # TODO: add more reserved words
|
||||
if
|
||||
vim9.fn.index(
|
||||
{ 'int', 'short', 'char', 'float', 'double', 'static', 'unsigned', 'extern' },
|
||||
vim9.index(tokens, tidx)
|
||||
) >= 0
|
||||
then
|
||||
return vim9.ITER_CONTINUE
|
||||
end
|
||||
|
||||
-- # Use the tags file to find out if this is a typedef.
|
||||
local diclist = vim9.fn.taglist('^' .. vim9.index(tokens, tidx) .. '$')
|
||||
|
||||
local body = function(_, tagidx)
|
||||
local item = vim9.convert.decl_dict(vim9.index(diclist, tagidx))
|
||||
|
||||
-- # New ctags has the "typeref" field. Patched version has "typename".
|
||||
if vim9.bool(vim9.fn.has_key(item, 'typeref')) then
|
||||
res = vim9.fn.extend(res, StructMembers(vim9.index(item, 'typeref'), items, all))
|
||||
return vim9.ITER_CONTINUE
|
||||
end
|
||||
if vim9.bool(vim9.fn.has_key(item, 'typename')) then
|
||||
res = vim9.fn.extend(res, StructMembers(vim9.index(item, 'typename'), items, all))
|
||||
return vim9.ITER_CONTINUE
|
||||
end
|
||||
|
||||
-- # Only handle typedefs here.
|
||||
if vim9.index(item, 'kind') ~= 't' then
|
||||
return vim9.ITER_CONTINUE
|
||||
end
|
||||
|
||||
-- # Skip matches local to another file.
|
||||
if
|
||||
vim9.bool(
|
||||
vim9.ops.And(
|
||||
vim9.ops.And(vim9.fn.has_key(item, 'static'), vim9.index(item, 'static')),
|
||||
vim9.fn.bufnr('%') ~= vim9.fn.bufnr(vim9.index(item, 'filename'))
|
||||
)
|
||||
)
|
||||
then
|
||||
return vim9.ITER_CONTINUE
|
||||
end
|
||||
|
||||
-- # For old ctags we recognize "typedef struct aaa" and
|
||||
-- # "typedef union bbb" in the tags file command.
|
||||
local cmd = vim9.index(item, 'cmd')
|
||||
local ei = vim9.fn.charidx(cmd, vim9.fn.matchend(cmd, 'typedef\\s\\+'))
|
||||
if ei > 1 then
|
||||
local cmdtokens = vim9.fn.split(vim9.slice(cmd, ei, nil), '\\s\\+\\|\\<')
|
||||
if vim9.fn.len(cmdtokens) > 1 then
|
||||
if
|
||||
vim9.index(cmdtokens, 0) == 'struct'
|
||||
or vim9.index(cmdtokens, 0) == 'union'
|
||||
or vim9.index(cmdtokens, 0) == 'class'
|
||||
then
|
||||
local name = ''
|
||||
-- # Use the first identifier after the "struct" or "union"
|
||||
|
||||
for _, ti in vim9.iter(vim9.fn.range((vim9.fn.len(cmdtokens) - 1))) do
|
||||
if vim9.ops.RegexpMatches(vim9.index(cmdtokens, ti), '^\\w') then
|
||||
name = vim9.index(cmdtokens, ti)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if name ~= '' then
|
||||
res = vim9.fn.extend(
|
||||
res,
|
||||
StructMembers(vim9.index(cmdtokens, 0) .. ':' .. name, items, all)
|
||||
)
|
||||
end
|
||||
elseif vim9.bool(depth < 10) then
|
||||
-- # Could be "typedef other_T some_T".
|
||||
res = vim9.fn.extend(
|
||||
res,
|
||||
Nextitem(vim9.index(cmdtokens, 0), items, vim9.ops.Plus(depth, 1), all)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return vim9.ITER_DEFAULT
|
||||
end
|
||||
|
||||
for _, tagidx in vim9.iter(vim9.fn.range(vim9.fn.len(diclist))) do
|
||||
local nvim9_status, nvim9_ret = body(_, tagidx)
|
||||
if nvim9_status == vim9.ITER_BREAK then
|
||||
break
|
||||
elseif nvim9_status == vim9.ITER_RETURN then
|
||||
return nvim9_ret
|
||||
end
|
||||
end
|
||||
|
||||
if vim9.fn.len(res) > 0 then
|
||||
return vim9.ITER_BREAK
|
||||
end
|
||||
|
||||
return vim9.ITER_DEFAULT
|
||||
end
|
||||
|
||||
for _, tidx in vim9.iter(vim9.fn.range(vim9.fn.len(tokens))) do
|
||||
local nvim9_status, nvim9_ret = body(_, tidx)
|
||||
if nvim9_status == vim9.ITER_BREAK then
|
||||
break
|
||||
elseif nvim9_status == vim9.ITER_RETURN then
|
||||
return nvim9_ret
|
||||
end
|
||||
end
|
||||
|
||||
return res
|
||||
end
|
||||
|
||||
StructMembers = function(atypename, items, all)
|
||||
all = vim9.bool(all)
|
||||
|
||||
-- # Search for members of structure "typename" in tags files.
|
||||
-- # Return a list with resulting matches.
|
||||
-- # Each match is a dictionary with "match" and "tagline" entries.
|
||||
-- # When "all" is true find all, otherwise just return 1 if there is any member.
|
||||
|
||||
-- # Todo: What about local structures?
|
||||
local fnames = vim9.fn.join(vim9.fn.map(vim9.fn.tagfiles(), function(_, v)
|
||||
return vim9.fn.escape(v, ' \\#%')
|
||||
end))
|
||||
if fnames == '' then
|
||||
return {}
|
||||
end
|
||||
|
||||
local typename = atypename
|
||||
local qflist = {}
|
||||
local cached = 0
|
||||
local n = ''
|
||||
if vim9.bool(vim9.prefix['Bang'](all)) then
|
||||
n = '1'
|
||||
if vim9.bool(vim9.fn.has_key(grepCache, typename)) then
|
||||
qflist = vim9.index(grepCache, typename)
|
||||
cached = 1
|
||||
end
|
||||
else
|
||||
n = ''
|
||||
end
|
||||
if vim9.bool(vim9.prefix['Bang'](cached)) then
|
||||
while 1 do
|
||||
vim.api.nvim_command(
|
||||
'silent! keepjumps noautocmd '
|
||||
.. n
|
||||
.. 'vimgrep '
|
||||
.. '/\\t'
|
||||
.. typename
|
||||
.. '\\(\\t\\|$\\)/j '
|
||||
.. fnames
|
||||
)
|
||||
|
||||
qflist = vim9.fn.getqflist()
|
||||
if vim9.fn.len(qflist) > 0 or vim9.fn.match(typename, '::') < 0 then
|
||||
break
|
||||
end
|
||||
-- # No match for "struct:context::name", remove "context::" and try again.
|
||||
typename = vim9.fn.substitute(typename, ':[^:]*::', ':', '')
|
||||
end
|
||||
|
||||
if vim9.bool(vim9.prefix['Bang'](all)) then
|
||||
-- # Store the result to be able to use it again later.
|
||||
grepCache[vim9.index_expr(typename)] = qflist
|
||||
end
|
||||
end
|
||||
|
||||
-- # Skip over [...] items
|
||||
local idx = 0
|
||||
local target = ''
|
||||
while 1 do
|
||||
if idx >= vim9.fn.len(items) then
|
||||
target = ''
|
||||
break
|
||||
end
|
||||
if vim9.index(vim9.index(items, idx), 0) ~= '[' then
|
||||
target = vim9.index(items, idx)
|
||||
break
|
||||
end
|
||||
idx = idx + 1
|
||||
end
|
||||
-- # Put matching members in matches[].
|
||||
local matches = {}
|
||||
|
||||
for _, l in vim9.iter(qflist) do
|
||||
local memb = vim9.fn.matchstr(vim9.index(l, 'text'), '[^\\t]*')
|
||||
if vim9.ops.RegexpMatches(memb, '^' .. target) then
|
||||
-- # Skip matches local to another file.
|
||||
if
|
||||
vim9.fn.match(vim9.index(l, 'text'), '\tfile:') < 0
|
||||
or vim9.fn.bufnr('%')
|
||||
== vim9.fn.bufnr(vim9.fn.matchstr(vim9.index(l, 'text'), '\\t\\zs[^\\t]*'))
|
||||
then
|
||||
local item =
|
||||
vim9.convert.decl_dict({ ['match'] = memb, ['tagline'] = vim9.index(l, 'text') })
|
||||
|
||||
-- # Add the kind of item.
|
||||
local s =
|
||||
vim9.fn.matchstr(vim9.index(l, 'text'), '\\t\\(kind:\\)\\=\\zs\\S\\ze\\(\\t\\|$\\)')
|
||||
if s ~= '' then
|
||||
item[vim9.index_expr('kind')] = s
|
||||
if s == 'f' then
|
||||
item[vim9.index_expr('match')] = memb .. '('
|
||||
end
|
||||
end
|
||||
|
||||
vim9.fn.add(matches, item)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if vim9.fn.len(matches) > 0 then
|
||||
-- # Skip over next [...] items
|
||||
idx = idx + 1
|
||||
while 1 do
|
||||
if idx >= vim9.fn.len(items) then
|
||||
return matches
|
||||
end
|
||||
if vim9.index(vim9.index(items, idx), 0) ~= '[' then
|
||||
break
|
||||
end
|
||||
idx = idx + 1
|
||||
end
|
||||
|
||||
-- # More items following. For each of the possible members find the
|
||||
-- # matching following members.
|
||||
return SearchMembers(matches, vim9.slice(items, idx, nil), all)
|
||||
end
|
||||
|
||||
-- # Failed to find anything.
|
||||
return {}
|
||||
end
|
||||
|
||||
SearchMembers = function(matches, items, all)
|
||||
all = vim9.bool(all)
|
||||
|
||||
-- # For matching members, find matches for following items.
|
||||
-- # When "all" is true find all, otherwise just return 1 if there is any member.
|
||||
local res = {}
|
||||
|
||||
for _, i in vim9.iter(vim9.fn.range(vim9.fn.len(matches))) do
|
||||
local typename = ''
|
||||
local line = ''
|
||||
if vim9.bool(vim9.fn.has_key(vim9.index(matches, i), 'dict')) then
|
||||
if vim9.bool(vim9.fn.has_key(vim9.index(vim9.index(matches, i), 'dict'), 'typename')) then
|
||||
typename = vim9.index(vim9.index(vim9.index(matches, i), 'dict'), 'typename')
|
||||
elseif vim9.bool(vim9.fn.has_key(vim9.index(vim9.index(matches, i), 'dict'), 'typeref')) then
|
||||
typename = vim9.index(vim9.index(vim9.index(matches, i), 'dict'), 'typeref')
|
||||
end
|
||||
line = '\t' .. vim9.index(vim9.index(vim9.index(matches, i), 'dict'), 'cmd')
|
||||
else
|
||||
line = vim9.index(vim9.index(matches, i), 'tagline')
|
||||
local eb = vim9.fn.matchend(line, '\\ttypename:')
|
||||
local e = vim9.fn.charidx(line, eb)
|
||||
if e < 0 then
|
||||
eb = vim9.fn.matchend(line, '\\ttyperef:')
|
||||
e = vim9.fn.charidx(line, eb)
|
||||
end
|
||||
if e > 0 then
|
||||
-- # Use typename field
|
||||
typename = vim9.fn.matchstr(line, '[^\\t]*', eb)
|
||||
end
|
||||
end
|
||||
|
||||
if typename ~= '' then
|
||||
res = vim9.fn.extend(res, StructMembers(typename, items, all))
|
||||
else
|
||||
-- # Use the search command (the declaration itself).
|
||||
local sb = vim9.fn.match(line, '\\t\\zs/^')
|
||||
local s = vim9.fn.charidx(line, sb)
|
||||
if s > 0 then
|
||||
local e = vim9.fn.charidx(
|
||||
line,
|
||||
vim9.fn.match(line, '\\<' .. vim9.index(vim9.index(matches, i), 'match') .. '\\>', sb)
|
||||
)
|
||||
if e > 0 then
|
||||
res =
|
||||
vim9.fn.extend(res, Nextitem(vim9.slice(line, s, vim9.ops.Minus(e, 1)), items, 0, all))
|
||||
end
|
||||
end
|
||||
end
|
||||
if vim9.bool(vim9.ops.And(vim9.prefix['Bang'](all), vim9.fn.len(res) > 0)) then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return res
|
||||
end
|
||||
|
||||
-- #}}}1
|
||||
|
||||
-- # vim: noet sw=2 sts=2
|
||||
return M
|
@ -1,8 +1,639 @@
|
||||
" Generated vim file by vim9jit. Please do not edit
|
||||
let s:path = expand("<script>")
|
||||
let s:lua_path = fnamemodify(s:path, ":r") . ".lua"
|
||||
let s:nvim_module = luaeval('require("_vim9script").autoload(_A)', s:lua_path)
|
||||
" Vim completion script
|
||||
" Language: C
|
||||
" Maintainer: Bram Moolenaar <Bram@vim.org>
|
||||
" Last Change: 2020 Nov 14
|
||||
|
||||
function! ccomplete#Complete(findstart, abase) abort
|
||||
return s:nvim_module.Complete(a:findstart, a:abase)
|
||||
endfunction
|
||||
let s:cpo_save = &cpo
|
||||
set cpo&vim
|
||||
|
||||
" This function is used for the 'omnifunc' option.
|
||||
func ccomplete#Complete(findstart, base)
|
||||
if a:findstart
|
||||
" Locate the start of the item, including ".", "->" and "[...]".
|
||||
let line = getline('.')
|
||||
let start = col('.') - 1
|
||||
let lastword = -1
|
||||
while start > 0
|
||||
if line[start - 1] =~ '\w'
|
||||
let start -= 1
|
||||
elseif line[start - 1] =~ '\.'
|
||||
if lastword == -1
|
||||
let lastword = start
|
||||
endif
|
||||
let start -= 1
|
||||
elseif start > 1 && line[start - 2] == '-' && line[start - 1] == '>'
|
||||
if lastword == -1
|
||||
let lastword = start
|
||||
endif
|
||||
let start -= 2
|
||||
elseif line[start - 1] == ']'
|
||||
" Skip over [...].
|
||||
let n = 0
|
||||
let start -= 1
|
||||
while start > 0
|
||||
let start -= 1
|
||||
if line[start] == '['
|
||||
if n == 0
|
||||
break
|
||||
endif
|
||||
let n -= 1
|
||||
elseif line[start] == ']' " nested []
|
||||
let n += 1
|
||||
endif
|
||||
endwhile
|
||||
else
|
||||
break
|
||||
endif
|
||||
endwhile
|
||||
|
||||
" Return the column of the last word, which is going to be changed.
|
||||
" Remember the text that comes before it in s:prepended.
|
||||
if lastword == -1
|
||||
let s:prepended = ''
|
||||
return start
|
||||
endif
|
||||
let s:prepended = strpart(line, start, lastword - start)
|
||||
return lastword
|
||||
endif
|
||||
|
||||
" Return list of matches.
|
||||
|
||||
let base = s:prepended . a:base
|
||||
|
||||
" Don't do anything for an empty base, would result in all the tags in the
|
||||
" tags file.
|
||||
if base == ''
|
||||
return []
|
||||
endif
|
||||
|
||||
" init cache for vimgrep to empty
|
||||
let s:grepCache = {}
|
||||
|
||||
" Split item in words, keep empty word after "." or "->".
|
||||
" "aa" -> ['aa'], "aa." -> ['aa', ''], "aa.bb" -> ['aa', 'bb'], etc.
|
||||
" We can't use split, because we need to skip nested [...].
|
||||
" "aa[...]" -> ['aa', '[...]'], "aa.bb[...]" -> ['aa', 'bb', '[...]'], etc.
|
||||
let items = []
|
||||
let s = 0
|
||||
let arrays = 0
|
||||
while 1
|
||||
let e = match(base, '\.\|->\|\[', s)
|
||||
if e < 0
|
||||
if s == 0 || base[s - 1] != ']'
|
||||
call add(items, strpart(base, s))
|
||||
endif
|
||||
break
|
||||
endif
|
||||
if s == 0 || base[s - 1] != ']'
|
||||
call add(items, strpart(base, s, e - s))
|
||||
endif
|
||||
if base[e] == '.'
|
||||
let s = e + 1 " skip over '.'
|
||||
elseif base[e] == '-'
|
||||
let s = e + 2 " skip over '->'
|
||||
else
|
||||
" Skip over [...].
|
||||
let n = 0
|
||||
let s = e
|
||||
let e += 1
|
||||
while e < len(base)
|
||||
if base[e] == ']'
|
||||
if n == 0
|
||||
break
|
||||
endif
|
||||
let n -= 1
|
||||
elseif base[e] == '[' " nested [...]
|
||||
let n += 1
|
||||
endif
|
||||
let e += 1
|
||||
endwhile
|
||||
let e += 1
|
||||
call add(items, strpart(base, s, e - s))
|
||||
let arrays += 1
|
||||
let s = e
|
||||
endif
|
||||
endwhile
|
||||
|
||||
" Find the variable items[0].
|
||||
" 1. in current function (like with "gd")
|
||||
" 2. in tags file(s) (like with ":tag")
|
||||
" 3. in current file (like with "gD")
|
||||
let res = []
|
||||
if searchdecl(items[0], 0, 1) == 0
|
||||
" Found, now figure out the type.
|
||||
" TODO: join previous line if it makes sense
|
||||
let line = getline('.')
|
||||
let col = col('.')
|
||||
if stridx(strpart(line, 0, col), ';') != -1
|
||||
" Handle multiple declarations on the same line.
|
||||
let col2 = col - 1
|
||||
while line[col2] != ';'
|
||||
let col2 -= 1
|
||||
endwhile
|
||||
let line = strpart(line, col2 + 1)
|
||||
let col -= col2
|
||||
endif
|
||||
if stridx(strpart(line, 0, col), ',') != -1
|
||||
" Handle multiple declarations on the same line in a function
|
||||
" declaration.
|
||||
let col2 = col - 1
|
||||
while line[col2] != ','
|
||||
let col2 -= 1
|
||||
endwhile
|
||||
if strpart(line, col2 + 1, col - col2 - 1) =~ ' *[^ ][^ ]* *[^ ]'
|
||||
let line = strpart(line, col2 + 1)
|
||||
let col -= col2
|
||||
endif
|
||||
endif
|
||||
if len(items) == 1
|
||||
" Completing one word and it's a local variable: May add '[', '.' or
|
||||
" '->'.
|
||||
let match = items[0]
|
||||
let kind = 'v'
|
||||
if match(line, '\<' . match . '\s*\[') > 0
|
||||
let match .= '['
|
||||
else
|
||||
let res = s:Nextitem(strpart(line, 0, col), [''], 0, 1)
|
||||
if len(res) > 0
|
||||
" There are members, thus add "." or "->".
|
||||
if match(line, '\*[ \t(]*' . match . '\>') > 0
|
||||
let match .= '->'
|
||||
else
|
||||
let match .= '.'
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
let res = [{'match': match, 'tagline' : '', 'kind' : kind, 'info' : line}]
|
||||
elseif len(items) == arrays + 1
|
||||
" Completing one word and it's a local array variable: build tagline
|
||||
" from declaration line
|
||||
let match = items[0]
|
||||
let kind = 'v'
|
||||
let tagline = "\t/^" . line . '$/'
|
||||
let res = [{'match': match, 'tagline' : tagline, 'kind' : kind, 'info' : line}]
|
||||
else
|
||||
" Completing "var.", "var.something", etc.
|
||||
let res = s:Nextitem(strpart(line, 0, col), items[1:], 0, 1)
|
||||
endif
|
||||
endif
|
||||
|
||||
if len(items) == 1 || len(items) == arrays + 1
|
||||
" Only one part, no "." or "->": complete from tags file.
|
||||
if len(items) == 1
|
||||
let tags = taglist('^' . base)
|
||||
else
|
||||
let tags = taglist('^' . items[0] . '$')
|
||||
endif
|
||||
|
||||
" Remove members, these can't appear without something in front.
|
||||
call filter(tags, 'has_key(v:val, "kind") ? v:val["kind"] != "m" : 1')
|
||||
|
||||
" Remove static matches in other files.
|
||||
call filter(tags, '!has_key(v:val, "static") || !v:val["static"] || bufnr("%") == bufnr(v:val["filename"])')
|
||||
|
||||
call extend(res, map(tags, 's:Tag2item(v:val)'))
|
||||
endif
|
||||
|
||||
if len(res) == 0
|
||||
" Find the variable in the tags file(s)
|
||||
let diclist = taglist('^' . items[0] . '$')
|
||||
|
||||
" Remove members, these can't appear without something in front.
|
||||
call filter(diclist, 'has_key(v:val, "kind") ? v:val["kind"] != "m" : 1')
|
||||
|
||||
let res = []
|
||||
for i in range(len(diclist))
|
||||
" New ctags has the "typeref" field. Patched version has "typename".
|
||||
if has_key(diclist[i], 'typename')
|
||||
call extend(res, s:StructMembers(diclist[i]['typename'], items[1:], 1))
|
||||
elseif has_key(diclist[i], 'typeref')
|
||||
call extend(res, s:StructMembers(diclist[i]['typeref'], items[1:], 1))
|
||||
endif
|
||||
|
||||
" For a variable use the command, which must be a search pattern that
|
||||
" shows the declaration of the variable.
|
||||
if diclist[i]['kind'] == 'v'
|
||||
let line = diclist[i]['cmd']
|
||||
if line[0] == '/' && line[1] == '^'
|
||||
let col = match(line, '\<' . items[0] . '\>')
|
||||
call extend(res, s:Nextitem(strpart(line, 2, col - 2), items[1:], 0, 1))
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
|
||||
if len(res) == 0 && searchdecl(items[0], 1) == 0
|
||||
" Found, now figure out the type.
|
||||
" TODO: join previous line if it makes sense
|
||||
let line = getline('.')
|
||||
let col = col('.')
|
||||
let res = s:Nextitem(strpart(line, 0, col), items[1:], 0, 1)
|
||||
endif
|
||||
|
||||
" If the last item(s) are [...] they need to be added to the matches.
|
||||
let last = len(items) - 1
|
||||
let brackets = ''
|
||||
while last >= 0
|
||||
if items[last][0] != '['
|
||||
break
|
||||
endif
|
||||
let brackets = items[last] . brackets
|
||||
let last -= 1
|
||||
endwhile
|
||||
|
||||
return map(res, 's:Tagline2item(v:val, brackets)')
|
||||
endfunc
|
||||
|
||||
func s:GetAddition(line, match, memarg, bracket)
|
||||
" Guess if the item is an array.
|
||||
if a:bracket && match(a:line, a:match . '\s*\[') > 0
|
||||
return '['
|
||||
endif
|
||||
|
||||
" Check if the item has members.
|
||||
if len(s:SearchMembers(a:memarg, [''], 0)) > 0
|
||||
" If there is a '*' before the name use "->".
|
||||
if match(a:line, '\*[ \t(]*' . a:match . '\>') > 0
|
||||
return '->'
|
||||
else
|
||||
return '.'
|
||||
endif
|
||||
endif
|
||||
return ''
|
||||
endfunc
|
||||
|
||||
" Turn the tag info "val" into an item for completion.
|
||||
" "val" is is an item in the list returned by taglist().
|
||||
" If it is a variable we may add "." or "->". Don't do it for other types,
|
||||
" such as a typedef, by not including the info that s:GetAddition() uses.
|
||||
func s:Tag2item(val)
|
||||
let res = {'match': a:val['name']}
|
||||
|
||||
let res['extra'] = s:Tagcmd2extra(a:val['cmd'], a:val['name'], a:val['filename'])
|
||||
|
||||
let s = s:Dict2info(a:val)
|
||||
if s != ''
|
||||
let res['info'] = s
|
||||
endif
|
||||
|
||||
let res['tagline'] = ''
|
||||
if has_key(a:val, "kind")
|
||||
let kind = a:val['kind']
|
||||
let res['kind'] = kind
|
||||
if kind == 'v'
|
||||
let res['tagline'] = "\t" . a:val['cmd']
|
||||
let res['dict'] = a:val
|
||||
elseif kind == 'f'
|
||||
let res['match'] = a:val['name'] . '('
|
||||
endif
|
||||
endif
|
||||
|
||||
return res
|
||||
endfunc
|
||||
|
||||
" Use all the items in dictionary for the "info" entry.
|
||||
func s:Dict2info(dict)
|
||||
let info = ''
|
||||
for k in sort(keys(a:dict))
|
||||
let info .= k . repeat(' ', 10 - len(k))
|
||||
if k == 'cmd'
|
||||
let info .= substitute(matchstr(a:dict['cmd'], '/^\s*\zs.*\ze$/'), '\\\(.\)', '\1', 'g')
|
||||
else
|
||||
let info .= a:dict[k]
|
||||
endif
|
||||
let info .= "\n"
|
||||
endfor
|
||||
return info
|
||||
endfunc
|
||||
|
||||
" Parse a tag line and return a dictionary with items like taglist()
|
||||
func s:ParseTagline(line)
|
||||
let l = split(a:line, "\t")
|
||||
let d = {}
|
||||
if len(l) >= 3
|
||||
let d['name'] = l[0]
|
||||
let d['filename'] = l[1]
|
||||
let d['cmd'] = l[2]
|
||||
let n = 2
|
||||
if l[2] =~ '^/'
|
||||
" Find end of cmd, it may contain Tabs.
|
||||
while n < len(l) && l[n] !~ '/;"$'
|
||||
let n += 1
|
||||
let d['cmd'] .= " " . l[n]
|
||||
endwhile
|
||||
endif
|
||||
for i in range(n + 1, len(l) - 1)
|
||||
if l[i] == 'file:'
|
||||
let d['static'] = 1
|
||||
elseif l[i] !~ ':'
|
||||
let d['kind'] = l[i]
|
||||
else
|
||||
let d[matchstr(l[i], '[^:]*')] = matchstr(l[i], ':\zs.*')
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
|
||||
return d
|
||||
endfunc
|
||||
|
||||
" Turn a match item "val" into an item for completion.
|
||||
" "val['match']" is the matching item.
|
||||
" "val['tagline']" is the tagline in which the last part was found.
|
||||
func s:Tagline2item(val, brackets)
|
||||
let line = a:val['tagline']
|
||||
let add = s:GetAddition(line, a:val['match'], [a:val], a:brackets == '')
|
||||
let res = {'word': a:val['match'] . a:brackets . add }
|
||||
|
||||
if has_key(a:val, 'info')
|
||||
" Use info from Tag2item().
|
||||
let res['info'] = a:val['info']
|
||||
else
|
||||
" Parse the tag line and add each part to the "info" entry.
|
||||
let s = s:Dict2info(s:ParseTagline(line))
|
||||
if s != ''
|
||||
let res['info'] = s
|
||||
endif
|
||||
endif
|
||||
|
||||
if has_key(a:val, 'kind')
|
||||
let res['kind'] = a:val['kind']
|
||||
elseif add == '('
|
||||
let res['kind'] = 'f'
|
||||
else
|
||||
let s = matchstr(line, '\t\(kind:\)\=\zs\S\ze\(\t\|$\)')
|
||||
if s != ''
|
||||
let res['kind'] = s
|
||||
endif
|
||||
endif
|
||||
|
||||
if has_key(a:val, 'extra')
|
||||
let res['menu'] = a:val['extra']
|
||||
return res
|
||||
endif
|
||||
|
||||
" Isolate the command after the tag and filename.
|
||||
let s = matchstr(line, '[^\t]*\t[^\t]*\t\zs\(/^.*$/\|[^\t]*\)\ze\(;"\t\|\t\|$\)')
|
||||
if s != ''
|
||||
let res['menu'] = s:Tagcmd2extra(s, a:val['match'], matchstr(line, '[^\t]*\t\zs[^\t]*\ze\t'))
|
||||
endif
|
||||
return res
|
||||
endfunc
|
||||
|
||||
" Turn a command from a tag line to something that is useful in the menu
|
||||
func s:Tagcmd2extra(cmd, name, fname)
|
||||
if a:cmd =~ '^/^'
|
||||
" The command is a search command, useful to see what it is.
|
||||
let x = matchstr(a:cmd, '^/^\s*\zs.*\ze$/')
|
||||
let x = substitute(x, '\<' . a:name . '\>', '@@', '')
|
||||
let x = substitute(x, '\\\(.\)', '\1', 'g')
|
||||
let x = x . ' - ' . a:fname
|
||||
elseif a:cmd =~ '^\d*$'
|
||||
" The command is a line number, the file name is more useful.
|
||||
let x = a:fname . ' - ' . a:cmd
|
||||
else
|
||||
" Not recognized, use command and file name.
|
||||
let x = a:cmd . ' - ' . a:fname
|
||||
endif
|
||||
return x
|
||||
endfunc
|
||||
|
||||
" Find composing type in "lead" and match items[0] with it.
|
||||
" Repeat this recursively for items[1], if it's there.
|
||||
" When resolving typedefs "depth" is used to avoid infinite recursion.
|
||||
" Return the list of matches.
|
||||
func s:Nextitem(lead, items, depth, all)
|
||||
|
||||
" Use the text up to the variable name and split it in tokens.
|
||||
let tokens = split(a:lead, '\s\+\|\<')
|
||||
|
||||
" Try to recognize the type of the variable. This is rough guessing...
|
||||
let res = []
|
||||
for tidx in range(len(tokens))
|
||||
|
||||
" Skip tokens starting with a non-ID character.
|
||||
if tokens[tidx] !~ '^\h'
|
||||
continue
|
||||
endif
|
||||
|
||||
" Recognize "struct foobar" and "union foobar".
|
||||
" Also do "class foobar" when it's C++ after all (doesn't work very well
|
||||
" though).
|
||||
if (tokens[tidx] == 'struct' || tokens[tidx] == 'union' || tokens[tidx] == 'class') && tidx + 1 < len(tokens)
|
||||
let res = s:StructMembers(tokens[tidx] . ':' . tokens[tidx + 1], a:items, a:all)
|
||||
break
|
||||
endif
|
||||
|
||||
" TODO: add more reserved words
|
||||
if index(['int', 'short', 'char', 'float', 'double', 'static', 'unsigned', 'extern'], tokens[tidx]) >= 0
|
||||
continue
|
||||
endif
|
||||
|
||||
" Use the tags file to find out if this is a typedef.
|
||||
let diclist = taglist('^' . tokens[tidx] . '$')
|
||||
for tagidx in range(len(diclist))
|
||||
let item = diclist[tagidx]
|
||||
|
||||
" New ctags has the "typeref" field. Patched version has "typename".
|
||||
if has_key(item, 'typeref')
|
||||
call extend(res, s:StructMembers(item['typeref'], a:items, a:all))
|
||||
continue
|
||||
endif
|
||||
if has_key(item, 'typename')
|
||||
call extend(res, s:StructMembers(item['typename'], a:items, a:all))
|
||||
continue
|
||||
endif
|
||||
|
||||
" Only handle typedefs here.
|
||||
if item['kind'] != 't'
|
||||
continue
|
||||
endif
|
||||
|
||||
" Skip matches local to another file.
|
||||
if has_key(item, 'static') && item['static'] && bufnr('%') != bufnr(item['filename'])
|
||||
continue
|
||||
endif
|
||||
|
||||
" For old ctags we recognize "typedef struct aaa" and
|
||||
" "typedef union bbb" in the tags file command.
|
||||
let cmd = item['cmd']
|
||||
let ei = matchend(cmd, 'typedef\s\+')
|
||||
if ei > 1
|
||||
let cmdtokens = split(strpart(cmd, ei), '\s\+\|\<')
|
||||
if len(cmdtokens) > 1
|
||||
if cmdtokens[0] == 'struct' || cmdtokens[0] == 'union' || cmdtokens[0] == 'class'
|
||||
let name = ''
|
||||
" Use the first identifier after the "struct" or "union"
|
||||
for ti in range(len(cmdtokens) - 1)
|
||||
if cmdtokens[ti] =~ '^\w'
|
||||
let name = cmdtokens[ti]
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
if name != ''
|
||||
call extend(res, s:StructMembers(cmdtokens[0] . ':' . name, a:items, a:all))
|
||||
endif
|
||||
elseif a:depth < 10
|
||||
" Could be "typedef other_T some_T".
|
||||
call extend(res, s:Nextitem(cmdtokens[0], a:items, a:depth + 1, a:all))
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
if len(res) > 0
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
|
||||
return res
|
||||
endfunc
|
||||
|
||||
|
||||
" Search for members of structure "typename" in tags files.
|
||||
" Return a list with resulting matches.
|
||||
" Each match is a dictionary with "match" and "tagline" entries.
|
||||
" When "all" is non-zero find all, otherwise just return 1 if there is any
|
||||
" member.
|
||||
func s:StructMembers(typename, items, all)
|
||||
" Todo: What about local structures?
|
||||
let fnames = join(map(tagfiles(), 'escape(v:val, " \\#%")'))
|
||||
if fnames == ''
|
||||
return []
|
||||
endif
|
||||
|
||||
let typename = a:typename
|
||||
let qflist = []
|
||||
let cached = 0
|
||||
if a:all == 0
|
||||
let n = '1' " stop at first found match
|
||||
if has_key(s:grepCache, a:typename)
|
||||
let qflist = s:grepCache[a:typename]
|
||||
let cached = 1
|
||||
endif
|
||||
else
|
||||
let n = ''
|
||||
endif
|
||||
if !cached
|
||||
while 1
|
||||
exe 'silent! keepj noautocmd ' . n . 'vimgrep /\t' . typename . '\(\t\|$\)/j ' . fnames
|
||||
|
||||
let qflist = getqflist()
|
||||
if len(qflist) > 0 || match(typename, "::") < 0
|
||||
break
|
||||
endif
|
||||
" No match for "struct:context::name", remove "context::" and try again.
|
||||
let typename = substitute(typename, ':[^:]*::', ':', '')
|
||||
endwhile
|
||||
|
||||
if a:all == 0
|
||||
" Store the result to be able to use it again later.
|
||||
let s:grepCache[a:typename] = qflist
|
||||
endif
|
||||
endif
|
||||
|
||||
" Skip over [...] items
|
||||
let idx = 0
|
||||
while 1
|
||||
if idx >= len(a:items)
|
||||
let target = '' " No further items, matching all members
|
||||
break
|
||||
endif
|
||||
if a:items[idx][0] != '['
|
||||
let target = a:items[idx]
|
||||
break
|
||||
endif
|
||||
let idx += 1
|
||||
endwhile
|
||||
" Put matching members in matches[].
|
||||
let matches = []
|
||||
for l in qflist
|
||||
let memb = matchstr(l['text'], '[^\t]*')
|
||||
if memb =~ '^' . target
|
||||
" Skip matches local to another file.
|
||||
if match(l['text'], "\tfile:") < 0 || bufnr('%') == bufnr(matchstr(l['text'], '\t\zs[^\t]*'))
|
||||
let item = {'match': memb, 'tagline': l['text']}
|
||||
|
||||
" Add the kind of item.
|
||||
let s = matchstr(l['text'], '\t\(kind:\)\=\zs\S\ze\(\t\|$\)')
|
||||
if s != ''
|
||||
let item['kind'] = s
|
||||
if s == 'f'
|
||||
let item['match'] = memb . '('
|
||||
endif
|
||||
endif
|
||||
|
||||
call add(matches, item)
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
|
||||
if len(matches) > 0
|
||||
" Skip over next [...] items
|
||||
let idx += 1
|
||||
while 1
|
||||
if idx >= len(a:items)
|
||||
return matches " No further items, return the result.
|
||||
endif
|
||||
if a:items[idx][0] != '['
|
||||
break
|
||||
endif
|
||||
let idx += 1
|
||||
endwhile
|
||||
|
||||
" More items following. For each of the possible members find the
|
||||
" matching following members.
|
||||
return s:SearchMembers(matches, a:items[idx :], a:all)
|
||||
endif
|
||||
|
||||
" Failed to find anything.
|
||||
return []
|
||||
endfunc
|
||||
|
||||
" For matching members, find matches for following items.
|
||||
" When "all" is non-zero find all, otherwise just return 1 if there is any
|
||||
" member.
|
||||
func s:SearchMembers(matches, items, all)
|
||||
let res = []
|
||||
for i in range(len(a:matches))
|
||||
let typename = ''
|
||||
if has_key(a:matches[i], 'dict')
|
||||
if has_key(a:matches[i].dict, 'typename')
|
||||
let typename = a:matches[i].dict['typename']
|
||||
elseif has_key(a:matches[i].dict, 'typeref')
|
||||
let typename = a:matches[i].dict['typeref']
|
||||
endif
|
||||
let line = "\t" . a:matches[i].dict['cmd']
|
||||
else
|
||||
let line = a:matches[i]['tagline']
|
||||
let e = matchend(line, '\ttypename:')
|
||||
if e < 0
|
||||
let e = matchend(line, '\ttyperef:')
|
||||
endif
|
||||
if e > 0
|
||||
" Use typename field
|
||||
let typename = matchstr(line, '[^\t]*', e)
|
||||
endif
|
||||
endif
|
||||
|
||||
if typename != ''
|
||||
call extend(res, s:StructMembers(typename, a:items, a:all))
|
||||
else
|
||||
" Use the search command (the declaration itself).
|
||||
let s = match(line, '\t\zs/^')
|
||||
if s > 0
|
||||
let e = match(line, '\<' . a:matches[i]['match'] . '\>', s)
|
||||
if e > 0
|
||||
call extend(res, s:Nextitem(strpart(line, s, e - s), a:items, 0, a:all))
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
if a:all == 0 && len(res) > 0
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
return res
|
||||
endfunc
|
||||
|
||||
let &cpo = s:cpo_save
|
||||
unlet s:cpo_save
|
||||
|
||||
" vim: noet sw=2 sts=2
|
||||
|
@ -2,6 +2,21 @@
|
||||
" Maintainer: Gregory Anders
|
||||
" Last Change: 2024-09-03
|
||||
" Based on: https://github.com/hashivim/vim-terraform
|
||||
" License: ISC
|
||||
"
|
||||
" Copyright (c) 2014-2016 Mark Cornick <mark@markcornick.com>
|
||||
"
|
||||
" Permission to use, copy, modify, and/or distribute this software for any purpose
|
||||
" with or without fee is hereby granted, provided that the above copyright notice
|
||||
" and this permission notice appear in all copies.
|
||||
"
|
||||
" THE SOFTWARE IS PROVIDED 'AS IS' AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
" REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
" FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
" OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
" TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
" THIS SOFTWARE.
|
||||
|
||||
function! hcl#indentexpr(lnum)
|
||||
" Beginning of the file should have no indent
|
||||
|
192
runtime/autoload/htmlfold.vim
Normal file
192
runtime/autoload/htmlfold.vim
Normal file
@ -0,0 +1,192 @@
|
||||
" HTML folding script, :h ft-html-plugin
|
||||
" Latest Change: 2025 May 10
|
||||
" Original Author: Aliaksei Budavei <0x000c70@gmail.com>
|
||||
|
||||
function! htmlfold#MapBalancedTags() abort
|
||||
" Describe only _a capturable-name prefix_ for start and end patterns of
|
||||
" a tag so that start tags with attributes spanning across lines can also be
|
||||
" matched with a single call of "getline()".
|
||||
let tag = '\m\c</\=\([0-9A-Za-z-]\+\)'
|
||||
let names = []
|
||||
let pairs = []
|
||||
let ends = []
|
||||
let pos = getpos('.')
|
||||
|
||||
try
|
||||
call cursor(1, 1)
|
||||
let [lnum, cnum] = searchpos(tag, 'cnW')
|
||||
|
||||
" Pair up nearest non-inlined tags in scope.
|
||||
while lnum > 0
|
||||
let name_attr = synIDattr(synID(lnum, cnum, 0), 'name')
|
||||
|
||||
if name_attr ==# 'htmlTag' || name_attr ==# 'htmlScriptTag'
|
||||
let name = get(matchlist(getline(lnum), tag, (cnum - 1)), 1, '')
|
||||
|
||||
if !empty(name)
|
||||
call insert(names, tolower(name), 0)
|
||||
call insert(pairs, [lnum, -1], 0)
|
||||
endif
|
||||
elseif name_attr ==# 'htmlEndTag'
|
||||
let name = get(matchlist(getline(lnum), tag, (cnum - 1)), 1, '')
|
||||
|
||||
if !empty(name)
|
||||
let idx = index(names, tolower(name))
|
||||
|
||||
if idx >= 0
|
||||
" Dismiss inlined balanced tags and opened-only tags.
|
||||
if pairs[idx][0] != lnum
|
||||
let pairs[idx][1] = lnum
|
||||
call add(ends, lnum)
|
||||
endif
|
||||
|
||||
" Claim a pair.
|
||||
let names[: idx] = repeat([''], (idx + 1))
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
" Advance the cursor, at "<", past "</a", "<a>", etc.
|
||||
call cursor(lnum, (cnum + 3))
|
||||
let [lnum, cnum] = searchpos(tag, 'cnW')
|
||||
endwhile
|
||||
finally
|
||||
call setpos('.', pos)
|
||||
endtry
|
||||
|
||||
if empty(ends)
|
||||
return {}
|
||||
endif
|
||||
|
||||
let folds = {}
|
||||
let pending_end = ends[0]
|
||||
let level = 0
|
||||
|
||||
while !empty(pairs)
|
||||
let [start, end] = remove(pairs, -1)
|
||||
|
||||
if end < 0
|
||||
continue
|
||||
endif
|
||||
|
||||
if start >= pending_end
|
||||
" Mark a sibling tag.
|
||||
call remove(ends, 0)
|
||||
|
||||
while start >= ends[0]
|
||||
" Mark a parent tag.
|
||||
call remove(ends, 0)
|
||||
let level -= 1
|
||||
endwhile
|
||||
|
||||
let pending_end = ends[0]
|
||||
else
|
||||
" Mark a child tag.
|
||||
let level += 1
|
||||
endif
|
||||
|
||||
" Flatten the innermost inlined folds.
|
||||
let folds[start] = get(folds, start, ('>' . level))
|
||||
let folds[end] = get(folds, end, ('<' . level))
|
||||
endwhile
|
||||
|
||||
return folds
|
||||
endfunction
|
||||
|
||||
" See ":help vim9-mix".
|
||||
if !has("vim9script")
|
||||
finish
|
||||
endif
|
||||
|
||||
def! g:htmlfold#MapBalancedTags(): dict<string>
|
||||
# Describe only _a capturable-name prefix_ for start and end patterns of
|
||||
# a tag so that start tags with attributes spanning across lines can also be
|
||||
# matched with a single call of "getline()".
|
||||
const tag: string = '\m\c</\=\([0-9A-Za-z-]\+\)'
|
||||
var names: list<string> = []
|
||||
var pairs: list<list<number>> = []
|
||||
var ends: list<number> = []
|
||||
const pos: list<number> = getpos('.')
|
||||
|
||||
try
|
||||
cursor(1, 1)
|
||||
var [lnum: number, cnum: number] = searchpos(tag, 'cnW')
|
||||
|
||||
# Pair up nearest non-inlined tags in scope.
|
||||
while lnum > 0
|
||||
const name_attr: string = synIDattr(synID(lnum, cnum, 0), 'name')
|
||||
|
||||
if name_attr ==# 'htmlTag' || name_attr ==# 'htmlScriptTag'
|
||||
const name: string = get(matchlist(getline(lnum), tag, (cnum - 1)), 1, '')
|
||||
|
||||
if !empty(name)
|
||||
insert(names, tolower(name), 0)
|
||||
insert(pairs, [lnum, -1], 0)
|
||||
endif
|
||||
elseif name_attr ==# 'htmlEndTag'
|
||||
const name: string = get(matchlist(getline(lnum), tag, (cnum - 1)), 1, '')
|
||||
|
||||
if !empty(name)
|
||||
const idx: number = index(names, tolower(name))
|
||||
|
||||
if idx >= 0
|
||||
# Dismiss inlined balanced tags and opened-only tags.
|
||||
if pairs[idx][0] != lnum
|
||||
pairs[idx][1] = lnum
|
||||
add(ends, lnum)
|
||||
endif
|
||||
|
||||
# Claim a pair.
|
||||
names[: idx] = repeat([''], (idx + 1))
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
# Advance the cursor, at "<", past "</a", "<a>", etc.
|
||||
cursor(lnum, (cnum + 3))
|
||||
[lnum, cnum] = searchpos(tag, 'cnW')
|
||||
endwhile
|
||||
finally
|
||||
setpos('.', pos)
|
||||
endtry
|
||||
|
||||
if empty(ends)
|
||||
return {}
|
||||
endif
|
||||
|
||||
var folds: dict<string> = {}
|
||||
var pending_end: number = ends[0]
|
||||
var level: number = 0
|
||||
|
||||
while !empty(pairs)
|
||||
const [start: number, end: number] = remove(pairs, -1)
|
||||
|
||||
if end < 0
|
||||
continue
|
||||
endif
|
||||
|
||||
if start >= pending_end
|
||||
# Mark a sibling tag.
|
||||
remove(ends, 0)
|
||||
|
||||
while start >= ends[0]
|
||||
# Mark a parent tag.
|
||||
remove(ends, 0)
|
||||
level -= 1
|
||||
endwhile
|
||||
|
||||
pending_end = ends[0]
|
||||
else
|
||||
# Mark a child tag.
|
||||
level += 1
|
||||
endif
|
||||
|
||||
# Flatten the innermost inlined folds.
|
||||
folds[start] = get(folds, start, ('>' .. level))
|
||||
folds[end] = get(folds, end, ('<' .. level))
|
||||
endwhile
|
||||
|
||||
return folds
|
||||
enddef
|
||||
|
||||
" vim: fdm=syntax sw=2 ts=8 noet
|
@ -5,11 +5,11 @@
|
||||
if exists('g:loaded_clipboard_provider')
|
||||
finish
|
||||
endif
|
||||
" Default to 1. provider#clipboard#Executable() may set 2.
|
||||
" Default to 0. provider#clipboard#Executable() may set 2.
|
||||
" To force a reload:
|
||||
" :unlet g:loaded_clipboard_provider
|
||||
" :runtime autoload/provider/clipboard.vim
|
||||
let g:loaded_clipboard_provider = 1
|
||||
let g:loaded_clipboard_provider = 0
|
||||
|
||||
let s:copy = {}
|
||||
let s:paste = {}
|
||||
@ -67,6 +67,113 @@ function! s:set_osc52() abort
|
||||
return 'OSC 52'
|
||||
endfunction
|
||||
|
||||
function! s:set_pbcopy() abort
|
||||
let s:copy['+'] = ['pbcopy']
|
||||
let s:paste['+'] = ['pbpaste']
|
||||
let s:copy['*'] = s:copy['+']
|
||||
let s:paste['*'] = s:paste['+']
|
||||
let s:cache_enabled = 0
|
||||
return 'pbcopy'
|
||||
endfunction
|
||||
|
||||
function! s:set_wayland() abort
|
||||
let s:copy['+'] = ['wl-copy', '--type', 'text/plain']
|
||||
let s:paste['+'] = ['wl-paste', '--no-newline']
|
||||
let s:copy['*'] = ['wl-copy', '--primary', '--type', 'text/plain']
|
||||
let s:paste['*'] = ['wl-paste', '--no-newline', '--primary']
|
||||
return 'wl-copy'
|
||||
endfunction
|
||||
|
||||
function! s:set_wayclip() abort
|
||||
let s:copy['+'] = ['waycopy']
|
||||
let s:paste['+'] = ['waypaste']
|
||||
let s:copy['*'] = ['waycopy', '-p']
|
||||
let s:paste['*'] = ['waypaste', '-p']
|
||||
return 'wayclip'
|
||||
endfunction
|
||||
|
||||
function! s:set_xsel() abort
|
||||
let s:copy['+'] = ['xsel', '--nodetach', '-i', '-b']
|
||||
let s:paste['+'] = ['xsel', '-o', '-b']
|
||||
let s:copy['*'] = ['xsel', '--nodetach', '-i', '-p']
|
||||
let s:paste['*'] = ['xsel', '-o', '-p']
|
||||
return 'xsel'
|
||||
endfunction
|
||||
|
||||
function! s:set_xclip() abort
|
||||
let s:copy['+'] = ['xclip', '-quiet', '-i', '-selection', 'clipboard']
|
||||
let s:paste['+'] = ['xclip', '-o', '-selection', 'clipboard']
|
||||
let s:copy['*'] = ['xclip', '-quiet', '-i', '-selection', 'primary']
|
||||
let s:paste['*'] = ['xclip', '-o', '-selection', 'primary']
|
||||
return 'xclip'
|
||||
endfunction
|
||||
|
||||
function! s:set_lemonade() abort
|
||||
let s:copy['+'] = ['lemonade', 'copy']
|
||||
let s:paste['+'] = ['lemonade', 'paste']
|
||||
let s:copy['*'] = ['lemonade', 'copy']
|
||||
let s:paste['*'] = ['lemonade', 'paste']
|
||||
return 'lemonade'
|
||||
endfunction
|
||||
|
||||
function! s:set_doitclient() abort
|
||||
let s:copy['+'] = ['doitclient', 'wclip']
|
||||
let s:paste['+'] = ['doitclient', 'wclip', '-r']
|
||||
let s:copy['*'] = s:copy['+']
|
||||
let s:paste['*'] = s:paste['+']
|
||||
return 'doitclient'
|
||||
endfunction
|
||||
|
||||
function! s:set_win32yank() abort
|
||||
if has('wsl') && getftype(exepath('win32yank.exe')) == 'link'
|
||||
let win32yank = resolve(exepath('win32yank.exe'))
|
||||
else
|
||||
let win32yank = 'win32yank.exe'
|
||||
endif
|
||||
let s:copy['+'] = [win32yank, '-i', '--crlf']
|
||||
let s:paste['+'] = [win32yank, '-o', '--lf']
|
||||
let s:copy['*'] = s:copy['+']
|
||||
let s:paste['*'] = s:paste['+']
|
||||
return 'win32yank'
|
||||
endfunction
|
||||
|
||||
function! s:set_putclip() abort
|
||||
let s:copy['+'] = ['putclip']
|
||||
let s:paste['+'] = ['getclip']
|
||||
let s:copy['*'] = s:copy['+']
|
||||
let s:paste['*'] = s:paste['+']
|
||||
return 'putclip'
|
||||
endfunction
|
||||
|
||||
function! s:set_clip() abort
|
||||
let s:copy['+'] = ['clip']
|
||||
let s:paste['+'] = ['powershell', '-NoProfile', '-NoLogo', '-Command', 'Get-Clipboard']
|
||||
let s:copy['*'] = s:copy['+']
|
||||
let s:paste['*'] = s:paste['+']
|
||||
return 'clip'
|
||||
endfunction
|
||||
|
||||
function! s:set_termux() abort
|
||||
let s:copy['+'] = ['termux-clipboard-set']
|
||||
let s:paste['+'] = ['termux-clipboard-get']
|
||||
let s:copy['*'] = s:copy['+']
|
||||
let s:paste['*'] = s:paste['+']
|
||||
return 'termux-clipboard'
|
||||
endfunction
|
||||
|
||||
function! s:set_tmux() abort
|
||||
let tmux_v = v:lua.vim.version.parse(system(['tmux', '-V']))
|
||||
if !empty(tmux_v) && !v:lua.vim.version.lt(tmux_v, [3,2,0])
|
||||
let s:copy['+'] = ['tmux', 'load-buffer', '-w', '-']
|
||||
else
|
||||
let s:copy['+'] = ['tmux', 'load-buffer', '-']
|
||||
endif
|
||||
let s:paste['+'] = ['tmux', 'save-buffer', '-']
|
||||
let s:copy['*'] = s:copy['+']
|
||||
let s:paste['*'] = s:paste['+']
|
||||
return 'tmux'
|
||||
endfunction
|
||||
|
||||
let s:cache_enabled = 1
|
||||
let s:err = ''
|
||||
|
||||
@ -78,9 +185,34 @@ function! provider#clipboard#Executable() abort
|
||||
" Setting g:clipboard to v:false explicitly opts-in to using the "builtin" clipboard providers below
|
||||
if exists('g:clipboard') && g:clipboard isnot# v:false
|
||||
if v:t_string ==# type(g:clipboard)
|
||||
" Handle string form of g:clipboard for all builtin providers
|
||||
if 'osc52' == g:clipboard
|
||||
" User opted-in to OSC 52 by manually setting g:clipboard.
|
||||
return s:set_osc52()
|
||||
elseif 'pbcopy' == g:clipboard
|
||||
return s:set_pbcopy()
|
||||
elseif 'wl-copy' == g:clipboard
|
||||
return s:set_wayland()
|
||||
elseif 'wayclip' == g:clipboard
|
||||
return s:set_wayclip()
|
||||
elseif 'xsel' == g:clipboard
|
||||
return s:set_xsel()
|
||||
elseif 'xclip' == g:clipboard
|
||||
return s:set_xclip()
|
||||
elseif 'lemonade' == g:clipboard
|
||||
return s:set_lemonade()
|
||||
elseif 'doitclient' == g:clipboard
|
||||
return s:set_doitclient()
|
||||
elseif 'win32yank' == g:clipboard
|
||||
return s:set_win32yank()
|
||||
elseif 'putclip' == g:clipboard
|
||||
return s:set_putclip()
|
||||
elseif 'clip' == g:clipboard
|
||||
return s:set_clip()
|
||||
elseif 'termux' == g:clipboard
|
||||
return s:set_termux()
|
||||
elseif 'tmux' == g:clipboard
|
||||
return s:set_tmux()
|
||||
endif
|
||||
endif
|
||||
|
||||
@ -102,88 +234,29 @@ function! provider#clipboard#Executable() abort
|
||||
let s:cache_enabled = get(g:clipboard, 'cache_enabled', 0)
|
||||
return get(g:clipboard, 'name', 'g:clipboard')
|
||||
elseif has('mac')
|
||||
let s:copy['+'] = ['pbcopy']
|
||||
let s:paste['+'] = ['pbpaste']
|
||||
let s:copy['*'] = s:copy['+']
|
||||
let s:paste['*'] = s:paste['+']
|
||||
let s:cache_enabled = 0
|
||||
return 'pbcopy'
|
||||
return s:set_pbcopy()
|
||||
elseif !empty($WAYLAND_DISPLAY) && executable('wl-copy') && executable('wl-paste')
|
||||
let s:copy['+'] = ['wl-copy', '--type', 'text/plain']
|
||||
let s:paste['+'] = ['wl-paste', '--no-newline']
|
||||
let s:copy['*'] = ['wl-copy', '--primary', '--type', 'text/plain']
|
||||
let s:paste['*'] = ['wl-paste', '--no-newline', '--primary']
|
||||
return 'wl-copy'
|
||||
return s:set_wayland()
|
||||
elseif !empty($WAYLAND_DISPLAY) && executable('waycopy') && executable('waypaste')
|
||||
let s:copy['+'] = ['waycopy', '-t', 'text/plain']
|
||||
let s:paste['+'] = ['waypaste', '-t', 'text/plain']
|
||||
let s:copy['*'] = s:copy['+']
|
||||
let s:paste['*'] = s:paste['+']
|
||||
return 'wayclip'
|
||||
return s:set_wayclip()
|
||||
elseif !empty($DISPLAY) && executable('xsel') && s:cmd_ok('xsel -o -b')
|
||||
let s:copy['+'] = ['xsel', '--nodetach', '-i', '-b']
|
||||
let s:paste['+'] = ['xsel', '-o', '-b']
|
||||
let s:copy['*'] = ['xsel', '--nodetach', '-i', '-p']
|
||||
let s:paste['*'] = ['xsel', '-o', '-p']
|
||||
return 'xsel'
|
||||
return s:set_xsel()
|
||||
elseif !empty($DISPLAY) && executable('xclip')
|
||||
let s:copy['+'] = ['xclip', '-quiet', '-i', '-selection', 'clipboard']
|
||||
let s:paste['+'] = ['xclip', '-o', '-selection', 'clipboard']
|
||||
let s:copy['*'] = ['xclip', '-quiet', '-i', '-selection', 'primary']
|
||||
let s:paste['*'] = ['xclip', '-o', '-selection', 'primary']
|
||||
return 'xclip'
|
||||
return s:set_xclip()
|
||||
elseif executable('lemonade')
|
||||
let s:copy['+'] = ['lemonade', 'copy']
|
||||
let s:paste['+'] = ['lemonade', 'paste']
|
||||
let s:copy['*'] = ['lemonade', 'copy']
|
||||
let s:paste['*'] = ['lemonade', 'paste']
|
||||
return 'lemonade'
|
||||
return s:set_lemonade()
|
||||
elseif executable('doitclient')
|
||||
let s:copy['+'] = ['doitclient', 'wclip']
|
||||
let s:paste['+'] = ['doitclient', 'wclip', '-r']
|
||||
let s:copy['*'] = s:copy['+']
|
||||
let s:paste['*'] = s:paste['+']
|
||||
return 'doitclient'
|
||||
return s:set_doitclient()
|
||||
elseif executable('win32yank.exe')
|
||||
if has('wsl') && getftype(exepath('win32yank.exe')) == 'link'
|
||||
let win32yank = resolve(exepath('win32yank.exe'))
|
||||
else
|
||||
let win32yank = 'win32yank.exe'
|
||||
endif
|
||||
let s:copy['+'] = [win32yank, '-i', '--crlf']
|
||||
let s:paste['+'] = [win32yank, '-o', '--lf']
|
||||
let s:copy['*'] = s:copy['+']
|
||||
let s:paste['*'] = s:paste['+']
|
||||
return 'win32yank'
|
||||
return s:set_win32yank()
|
||||
elseif executable('putclip') && executable('getclip')
|
||||
let s:copy['+'] = ['putclip']
|
||||
let s:paste['+'] = ['getclip']
|
||||
let s:copy['*'] = s:copy['+']
|
||||
let s:paste['*'] = s:paste['+']
|
||||
return 'putclip'
|
||||
return s:set_putclip()
|
||||
elseif executable('clip') && executable('powershell')
|
||||
let s:copy['+'] = ['clip']
|
||||
let s:paste['+'] = ['powershell', '-NoProfile', '-NoLogo', '-Command', 'Get-Clipboard']
|
||||
let s:copy['*'] = s:copy['+']
|
||||
let s:paste['*'] = s:paste['+']
|
||||
return 'clip'
|
||||
return s:set_clip()
|
||||
elseif executable('termux-clipboard-set')
|
||||
let s:copy['+'] = ['termux-clipboard-set']
|
||||
let s:paste['+'] = ['termux-clipboard-get']
|
||||
let s:copy['*'] = s:copy['+']
|
||||
let s:paste['*'] = s:paste['+']
|
||||
return 'termux-clipboard'
|
||||
return s:set_termux()
|
||||
elseif executable('tmux') && (!empty($TMUX) || 0 == jobwait([jobstart(['tmux', 'list-buffers'])], 2000)[0])
|
||||
let tmux_v = v:lua.vim.version.parse(system(['tmux', '-V']))
|
||||
if !empty(tmux_v) && !v:lua.vim.version.lt(tmux_v, [3,2,0])
|
||||
let s:copy['+'] = ['tmux', 'load-buffer', '-w', '-']
|
||||
else
|
||||
let s:copy['+'] = ['tmux', 'load-buffer', '-']
|
||||
endif
|
||||
let s:paste['+'] = ['tmux', 'save-buffer', '-']
|
||||
let s:copy['*'] = s:copy['+']
|
||||
let s:paste['*'] = s:paste['+']
|
||||
return 'tmux'
|
||||
return s:set_tmux()
|
||||
elseif get(get(g:, 'termfeatures', {}), 'osc52') && &clipboard ==# ''
|
||||
" Don't use OSC 52 when 'clipboard' is set. It can be slow and cause a lot
|
||||
" of user prompts. Users can opt-in to it by setting g:clipboard manually.
|
||||
@ -195,13 +268,11 @@ function! provider#clipboard#Executable() abort
|
||||
endfunction
|
||||
|
||||
function! s:clipboard.get(reg) abort
|
||||
if type(s:paste[a:reg]) == v:t_func
|
||||
return s:paste[a:reg]()
|
||||
elseif s:selections[a:reg].owner > 0
|
||||
if s:selections[a:reg].owner > 0
|
||||
return s:selections[a:reg].data
|
||||
end
|
||||
|
||||
let clipboard_data = s:try_cmd(s:paste[a:reg])
|
||||
let clipboard_data = type(s:paste[a:reg]) == v:t_func ? s:paste[a:reg]() : s:try_cmd(s:paste[a:reg])
|
||||
if match(&clipboard, '\v(unnamed|unnamedplus)') >= 0
|
||||
\ && type(clipboard_data) == v:t_list
|
||||
\ && get(s:selections[a:reg].data, 0, []) ==# clipboard_data
|
||||
@ -221,13 +292,12 @@ function! s:clipboard.set(lines, regtype, reg) abort
|
||||
return 0
|
||||
end
|
||||
|
||||
if type(s:copy[a:reg]) == v:t_func
|
||||
call s:copy[a:reg](a:lines, a:regtype)
|
||||
return 0
|
||||
end
|
||||
|
||||
if s:cache_enabled == 0
|
||||
call s:try_cmd(s:copy[a:reg], a:lines)
|
||||
if s:cache_enabled == 0 || type(s:copy[a:reg]) == v:t_func
|
||||
if type(s:copy[a:reg]) == v:t_func
|
||||
call s:copy[a:reg](a:lines, a:regtype)
|
||||
else
|
||||
call s:try_cmd(s:copy[a:reg], a:lines)
|
||||
endif
|
||||
"Cache it anyway we can compare it later to get regtype of the yank
|
||||
let s:selections[a:reg] = copy(s:selection)
|
||||
let s:selections[a:reg].data = [a:lines, a:regtype]
|
||||
@ -284,4 +354,4 @@ function! provider#clipboard#Call(method, args) abort
|
||||
endfunction
|
||||
|
||||
" eval_has_provider() decides based on this variable.
|
||||
let g:loaded_clipboard_provider = empty(provider#clipboard#Executable()) ? 1 : 2
|
||||
let g:loaded_clipboard_provider = empty(provider#clipboard#Executable()) ? 0 : 2
|
||||
|
@ -1,7 +1,7 @@
|
||||
if exists('g:loaded_node_provider')
|
||||
finish
|
||||
endif
|
||||
let g:loaded_node_provider = 1
|
||||
let g:loaded_node_provider = 0
|
||||
|
||||
function! s:is_minimum_version(version, min_version) abort
|
||||
if empty(a:version)
|
||||
@ -152,7 +152,7 @@ endfunction
|
||||
|
||||
let s:err = ''
|
||||
let [s:prog, s:_] = provider#node#Detect()
|
||||
let g:loaded_node_provider = empty(s:prog) ? 1 : 2
|
||||
let g:loaded_node_provider = empty(s:prog) ? 0 : 2
|
||||
|
||||
if g:loaded_node_provider != 2
|
||||
let s:err = 'Cannot find the "neovim" node package. Try :checkhealth'
|
||||
|
@ -11,5 +11,5 @@ function! provider#perl#Require(host) abort
|
||||
endfunction
|
||||
|
||||
let s:prog = v:lua.vim.provider.perl.detect()
|
||||
let g:loaded_perl_provider = empty(s:prog) ? 1 : 2
|
||||
let g:loaded_perl_provider = empty(s:prog) ? 0 : 2
|
||||
call v:lua.require'vim.provider.perl'.start()
|
||||
|
@ -11,5 +11,5 @@ function! provider#python3#Require(host) abort
|
||||
endfunction
|
||||
|
||||
let s:prog = v:lua.vim.provider.python.detect_by_module('neovim')
|
||||
let g:loaded_python3_provider = empty(s:prog) ? 1 : 2
|
||||
let g:loaded_python3_provider = empty(s:prog) ? 0 : 2
|
||||
call v:lua.require'vim.provider.python'.start()
|
||||
|
@ -11,6 +11,6 @@ function! provider#ruby#Call(method, args) abort
|
||||
endfunction
|
||||
|
||||
let s:prog = v:lua.vim.provider.ruby.detect()
|
||||
let g:loaded_ruby_provider = empty(s:prog) ? 1 : 2
|
||||
let g:loaded_ruby_provider = empty(s:prog) ? 0 : 2
|
||||
let s:plugin_path = expand('<sfile>:p:h') . '/script_host.rb'
|
||||
call v:lua.require'vim.provider.ruby'.start(s:plugin_path)
|
||||
|
@ -1,5 +1,8 @@
|
||||
" Author: Stephen Sugden <stephen@stephensugden.com>
|
||||
" Last Modified: 2023-09-11
|
||||
" Last Change:
|
||||
" 2025 Mar 31 by Vim project (rename s:RustfmtConfigOptions())
|
||||
" 2025 Jul 14 by Vim project (don't parse rustfmt version automatically #17745)
|
||||
"
|
||||
" Adapted from https://github.com/fatih/vim-go
|
||||
" For bugs, patches and license go to https://github.com/rust-lang/rust.vim
|
||||
@ -21,6 +24,12 @@ if !exists("g:rustfmt_fail_silently")
|
||||
endif
|
||||
|
||||
function! rustfmt#DetectVersion()
|
||||
let s:rustfmt_version = "0"
|
||||
let s:rustfmt_help = ""
|
||||
let s:rustfmt_unstable_features = ""
|
||||
if !get(g:, 'rustfmt_detect_version', 0)
|
||||
return s:rustfmt_version
|
||||
endif
|
||||
" Save rustfmt '--help' for feature inspection
|
||||
silent let s:rustfmt_help = system(g:rustfmt_command . " --help")
|
||||
let s:rustfmt_unstable_features = s:rustfmt_help =~# "--unstable-features"
|
||||
@ -29,9 +38,7 @@ function! rustfmt#DetectVersion()
|
||||
silent let l:rustfmt_version_full = system(g:rustfmt_command . " --version")
|
||||
let l:rustfmt_version_list = matchlist(l:rustfmt_version_full,
|
||||
\ '\vrustfmt ([0-9]+[.][0-9]+[.][0-9]+)')
|
||||
if len(l:rustfmt_version_list) < 3
|
||||
let s:rustfmt_version = "0"
|
||||
else
|
||||
if len(l:rustfmt_version_list) >= 3
|
||||
let s:rustfmt_version = l:rustfmt_version_list[1]
|
||||
endif
|
||||
return s:rustfmt_version
|
||||
@ -61,7 +68,13 @@ function! s:RustfmtWriteMode()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:RustfmtConfigOptions()
|
||||
function! rustfmt#RustfmtConfigOptions()
|
||||
let default = '--edition 2018'
|
||||
|
||||
if !get(g:, 'rustfmt_find_toml', 0)
|
||||
return default
|
||||
endif
|
||||
|
||||
let l:rustfmt_toml = findfile('rustfmt.toml', expand('%:p:h') . ';')
|
||||
if l:rustfmt_toml !=# ''
|
||||
return '--config-path '.shellescape(fnamemodify(l:rustfmt_toml, ":p"))
|
||||
@ -73,7 +86,7 @@ function! s:RustfmtConfigOptions()
|
||||
endif
|
||||
|
||||
" Default to edition 2018 in case no rustfmt.toml was found.
|
||||
return '--edition 2018'
|
||||
return default
|
||||
endfunction
|
||||
|
||||
function! s:RustfmtCommandRange(filename, line1, line2)
|
||||
@ -84,7 +97,7 @@ function! s:RustfmtCommandRange(filename, line1, line2)
|
||||
|
||||
let l:arg = {"file": shellescape(a:filename), "range": [a:line1, a:line2]}
|
||||
let l:write_mode = s:RustfmtWriteMode()
|
||||
let l:rustfmt_config = s:RustfmtConfigOptions()
|
||||
let l:rustfmt_config = rustfmt#RustfmtConfigOptions()
|
||||
|
||||
" FIXME: When --file-lines gets to be stable, add version range checking
|
||||
" accordingly.
|
||||
@ -99,7 +112,7 @@ endfunction
|
||||
|
||||
function! s:RustfmtCommand()
|
||||
let write_mode = g:rustfmt_emit_files ? '--emit=stdout' : '--write-mode=display'
|
||||
let config = s:RustfmtConfigOptions()
|
||||
let config = rustfmt#RustfmtConfigOptions()
|
||||
return join([g:rustfmt_command, write_mode, config, g:rustfmt_options])
|
||||
endfunction
|
||||
|
||||
|
@ -12,6 +12,11 @@
|
||||
" 2025 Feb 28 by Vim Project: add support for bzip3 (#16755)
|
||||
" 2025 Mar 01 by Vim Project: fix syntax error in tar#Read()
|
||||
" 2025 Mar 02 by Vim Project: escape the filename before using :read
|
||||
" 2025 Mar 02 by Vim Project: determine the compression using readblob()
|
||||
" instead of shelling out to file(1)
|
||||
" 2025 Apr 16 by Vim Project: decouple from netrw by adding s:WinPath()
|
||||
" 2025 May 19 by Vim Project: restore working directory after read/write
|
||||
" 2025 Jul 13 by Vim Project: warn with path traversal attacks
|
||||
"
|
||||
" Contains many ideas from Michael Toren's <tar.vim>
|
||||
"
|
||||
@ -30,9 +35,9 @@ if &cp || exists("g:loaded_tar")
|
||||
finish
|
||||
endif
|
||||
let g:loaded_tar= "v32b"
|
||||
if v:version < 702
|
||||
if !has('nvim-0.12') && v:version < 900
|
||||
echohl WarningMsg
|
||||
echo "***warning*** this version of tar needs vim 7.2"
|
||||
echo "***warning*** this version of tar needs vim 9.0"
|
||||
echohl Normal
|
||||
finish
|
||||
endif
|
||||
@ -42,10 +47,10 @@ set cpo&vim
|
||||
" ---------------------------------------------------------------------
|
||||
" Default Settings: {{{1
|
||||
if !exists("g:tar_browseoptions")
|
||||
let g:tar_browseoptions= "Ptf"
|
||||
let g:tar_browseoptions= "tf"
|
||||
endif
|
||||
if !exists("g:tar_readoptions")
|
||||
let g:tar_readoptions= "pPxf"
|
||||
let g:tar_readoptions= "pxf"
|
||||
endif
|
||||
if !exists("g:tar_cmd")
|
||||
let g:tar_cmd= "tar"
|
||||
@ -54,6 +59,7 @@ if !exists("g:tar_writeoptions")
|
||||
let g:tar_writeoptions= "uf"
|
||||
endif
|
||||
if !exists("g:tar_delfile")
|
||||
" Note: not supported on BSD
|
||||
let g:tar_delfile="--delete -f"
|
||||
endif
|
||||
if !exists("g:netrw_cygwin")
|
||||
@ -102,10 +108,26 @@ if !exists("g:tar_shq")
|
||||
endif
|
||||
endif
|
||||
|
||||
let g:tar_secure=' -- '
|
||||
let g:tar_leading_pat='^\%([.]\{,2\}/\)\+'
|
||||
|
||||
" ----------------
|
||||
" Functions: {{{1
|
||||
" ----------------
|
||||
|
||||
" ---------------------------------------------------------------------
|
||||
" s:Msg: {{{2
|
||||
fun! s:Msg(func, severity, msg)
|
||||
redraw!
|
||||
if a:severity =~? 'error'
|
||||
echohl Error
|
||||
else
|
||||
echohl WarningMsg
|
||||
endif
|
||||
echo $"***{a:severity}*** ({a:func}) {a:msg}"
|
||||
echohl None
|
||||
endfunc
|
||||
|
||||
" ---------------------------------------------------------------------
|
||||
" tar#Browse: {{{2
|
||||
fun! tar#Browse(tarfile)
|
||||
@ -114,16 +136,14 @@ fun! tar#Browse(tarfile)
|
||||
|
||||
" sanity checks
|
||||
if !executable(g:tar_cmd)
|
||||
redraw!
|
||||
echohl Error | echo '***error*** (tar#Browse) "'.g:tar_cmd.'" not available on your system'
|
||||
call s:Msg('tar#Browse', 'error', $"{g:tar_cmd} not available on your system")
|
||||
let &report= repkeep
|
||||
return
|
||||
endif
|
||||
if !filereadable(a:tarfile)
|
||||
if a:tarfile !~# '^\a\+://'
|
||||
" if it's an url, don't complain, let url-handlers such as vim do its thing
|
||||
redraw!
|
||||
echohl Error | echo "***error*** (tar#Browse) File not readable<".a:tarfile.">" | echohl None
|
||||
call s:Msg('tar#Browse', 'error', $"File not readable<{a:tarfile}>")
|
||||
endif
|
||||
let &report= repkeep
|
||||
return
|
||||
@ -144,7 +164,7 @@ fun! tar#Browse(tarfile)
|
||||
let lastline= line("$")
|
||||
call setline(lastline+1,'" tar.vim version '.g:loaded_tar)
|
||||
call setline(lastline+2,'" Browsing tarfile '.a:tarfile)
|
||||
call setline(lastline+3,'" Select a file with cursor and press ENTER')
|
||||
call setline(lastline+3,'" Select a file with cursor and press ENTER, "x" to extract a file')
|
||||
keepj $put =''
|
||||
keepj sil! 0d
|
||||
keepj $
|
||||
@ -161,23 +181,19 @@ fun! tar#Browse(tarfile)
|
||||
|
||||
elseif tarfile =~# '\.\(tgz\)$' || tarfile =~# '\.\(tbz\)$' || tarfile =~# '\.\(txz\)$' ||
|
||||
\ tarfile =~# '\.\(tzst\)$' || tarfile =~# '\.\(tlz4\)$'
|
||||
if has("unix") && executable("file")
|
||||
let filekind= system("file ".shellescape(tarfile,1))
|
||||
else
|
||||
let filekind= ""
|
||||
endif
|
||||
let header= s:Header(tarfile)
|
||||
|
||||
if filekind =~ "bzip2"
|
||||
if header =~? 'bzip2'
|
||||
exe "sil! r! bzip2 -d -c -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - "
|
||||
elseif filekind =~ "bzip3"
|
||||
elseif header =~? 'bzip3'
|
||||
exe "sil! r! bzip3 -d -c -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - "
|
||||
elseif filekind =~ "XZ"
|
||||
elseif header =~? 'xz'
|
||||
exe "sil! r! xz -d -c -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - "
|
||||
elseif filekind =~ "Zstandard"
|
||||
elseif header =~? 'zstd'
|
||||
exe "sil! r! zstd --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - "
|
||||
elseif filekind =~ "LZ4"
|
||||
elseif header =~? 'lz4'
|
||||
exe "sil! r! lz4 --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - "
|
||||
else
|
||||
elseif header =~? 'gzip'
|
||||
exe "sil! r! gzip -d -c -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - "
|
||||
endif
|
||||
|
||||
@ -203,28 +219,18 @@ fun! tar#Browse(tarfile)
|
||||
exe "sil! r! ".g:tar_cmd." -".g:tar_browseoptions." ".shellescape(tarfile,1)
|
||||
endif
|
||||
if v:shell_error != 0
|
||||
redraw!
|
||||
echohl WarningMsg | echo "***warning*** (tar#Browse) please check your g:tar_browseoptions<".g:tar_browseoptions.">"
|
||||
call s:Msg('tar#Browse', 'warning', $"please check your g:tar_browseoptions '<{g:tar_browseoptions}>'")
|
||||
return
|
||||
endif
|
||||
"
|
||||
" The following should not be neccessary, since in case of errors the
|
||||
" previous if statement should have caught the problem (because tar exited
|
||||
" with a non-zero exit code).
|
||||
" if line("$") == curlast || ( line("$") == (curlast + 1) &&
|
||||
" \ getline("$") =~# '\c\<\%(warning\|error\|inappropriate\|unrecognized\)\>' &&
|
||||
" \ getline("$") =~ '\s' )
|
||||
" redraw!
|
||||
" echohl WarningMsg | echo "***warning*** (tar#Browse) ".a:tarfile." doesn't appear to be a tar file" | echohl None
|
||||
" keepj sil! %d
|
||||
" let eikeep= &ei
|
||||
" set ei=BufReadCmd,FileReadCmd
|
||||
" exe "r ".fnameescape(a:tarfile)
|
||||
" let &ei= eikeep
|
||||
" keepj sil! 1d
|
||||
" call Dret("tar#Browse : a:tarfile<".a:tarfile.">")
|
||||
" return
|
||||
" endif
|
||||
|
||||
" remove tar: Removing leading '/' from member names
|
||||
" Note: the message could be localized
|
||||
if search('^tar: ') > 0 || search(g:tar_leading_pat) > 0
|
||||
call append(3,'" Note: Path Traversal Attack detected!')
|
||||
let b:leading_slash = 1
|
||||
" remove the message output
|
||||
sil g/^tar: /d
|
||||
endif
|
||||
|
||||
" set up maps supported for tar
|
||||
setlocal noma nomod ro
|
||||
@ -243,12 +249,7 @@ fun! s:TarBrowseSelect()
|
||||
let repkeep= &report
|
||||
set report=10
|
||||
let fname= getline(".")
|
||||
|
||||
if !exists("g:tar_secure") && fname =~ '^\s*-\|\s\+-'
|
||||
redraw!
|
||||
echohl WarningMsg | echo '***warning*** (tar#BrowseSelect) rejecting tarfile member<'.fname.'> because of embedded "-"'
|
||||
return
|
||||
endif
|
||||
let ls= get(b:, 'leading_slash', 0)
|
||||
|
||||
" sanity check
|
||||
if fname =~ '^"'
|
||||
@ -270,7 +271,8 @@ fun! s:TarBrowseSelect()
|
||||
wincmd _
|
||||
endif
|
||||
let s:tblfile_{winnr()}= curfile
|
||||
call tar#Read("tarfile:".tarfile.'::'.fname,1)
|
||||
let b:leading_slash= ls
|
||||
call tar#Read("tarfile:".tarfile.'::'.fname)
|
||||
filetype detect
|
||||
set nomod
|
||||
exe 'com! -buffer -nargs=? -complete=file TarDiff :call tar#Diff(<q-args>,"'.fnameescape(fname).'")'
|
||||
@ -280,26 +282,18 @@ endfun
|
||||
|
||||
" ---------------------------------------------------------------------
|
||||
" tar#Read: {{{2
|
||||
fun! tar#Read(fname,mode)
|
||||
fun! tar#Read(fname)
|
||||
let repkeep= &report
|
||||
set report=10
|
||||
let tarfile = substitute(a:fname,'tarfile:\(.\{-}\)::.*$','\1','')
|
||||
let fname = substitute(a:fname,'tarfile:.\{-}::\(.*\)$','\1','')
|
||||
" be careful not to execute special crafted files
|
||||
let escape_file = fname->fnameescape()
|
||||
|
||||
" changing the directory to the temporary earlier to allow tar to extract the file with permissions intact
|
||||
if !exists("*mkdir")
|
||||
redraw!
|
||||
echohl Error | echo "***error*** (tar#Write) sorry, mkdir() doesn't work on your system" | echohl None
|
||||
let &report= repkeep
|
||||
return
|
||||
endif
|
||||
let escape_file = fname->substitute(g:tar_leading_pat, '', '')->fnameescape()
|
||||
|
||||
let curdir= getcwd()
|
||||
let b:curdir= curdir
|
||||
let tmpdir= tempname()
|
||||
let b:curdir= tmpdir
|
||||
let b:tmpdir= curdir
|
||||
let b:tmpdir= tmpdir
|
||||
if tmpdir =~ '\.'
|
||||
let tmpdir= substitute(tmpdir,'\.[^.]*$','','e')
|
||||
endif
|
||||
@ -307,10 +301,9 @@ fun! tar#Read(fname,mode)
|
||||
|
||||
" attempt to change to the indicated directory
|
||||
try
|
||||
exe "cd ".fnameescape(tmpdir)
|
||||
exe "lcd ".fnameescape(tmpdir)
|
||||
catch /^Vim\%((\a\+)\)\=:E344/
|
||||
redraw!
|
||||
echohl Error | echo "***error*** (tar#Write) cannot cd to temporary directory" | Echohl None
|
||||
call s:Msg('tar#Read', 'error', "cannot lcd to temporary directory")
|
||||
let &report= repkeep
|
||||
return
|
||||
endtry
|
||||
@ -320,7 +313,7 @@ fun! tar#Read(fname,mode)
|
||||
call s:Rmdir("_ZIPVIM_")
|
||||
endif
|
||||
call mkdir("_ZIPVIM_")
|
||||
cd _ZIPVIM_
|
||||
lcd _ZIPVIM_
|
||||
|
||||
if has("win32unix") && executable("cygpath")
|
||||
" assuming cygwin
|
||||
@ -333,7 +326,7 @@ fun! tar#Read(fname,mode)
|
||||
elseif fname =~ '\.bz3$' && executable("bz3cat")
|
||||
let decmp= "|bz3cat"
|
||||
let doro = 1
|
||||
elseif fname =~ '\.t\=gz$' && executable("zcat")
|
||||
elseif fname =~ '\.t\=gz$' && executable("zcat")
|
||||
let decmp= "|zcat"
|
||||
let doro = 1
|
||||
elseif fname =~ '\.lzma$' && executable("lzcat")
|
||||
@ -356,72 +349,66 @@ fun! tar#Read(fname,mode)
|
||||
endif
|
||||
endif
|
||||
|
||||
if exists("g:tar_secure")
|
||||
let tar_secure= " -- "
|
||||
else
|
||||
let tar_secure= " "
|
||||
endif
|
||||
|
||||
if tarfile =~# '\.bz2$'
|
||||
exe "sil! r! bzip2 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
|
||||
exe "sil! r! bzip2 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp
|
||||
exe "read ".escape_file
|
||||
elseif tarfile =~# '\.bz3$'
|
||||
exe "sil! r! bzip3 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
|
||||
exe "sil! r! bzip3 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp
|
||||
exe "read ".escape_file
|
||||
elseif tarfile =~# '\.\(gz\)$'
|
||||
exe "sil! r! gzip -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
|
||||
exe "sil! r! gzip -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp
|
||||
exe "read ".escape_file
|
||||
elseif tarfile =~# '\(\.tgz\|\.tbz\|\.txz\)'
|
||||
if has("unix") && executable("file")
|
||||
let filekind= system("file ".shellescape(tarfile,1))
|
||||
else
|
||||
let filekind= ""
|
||||
endif
|
||||
if filekind =~ "bzip2"
|
||||
exe "sil! r! bzip2 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
|
||||
let filekind= s:Header(tarfile)
|
||||
if filekind =~? "bzip2"
|
||||
exe "sil! r! bzip2 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp
|
||||
exe "read ".escape_file
|
||||
elseif filekind =~ "bzip3"
|
||||
exe "sil! r! bzip3 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
|
||||
exe "sil! r! bzip3 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp
|
||||
exe "read ".escape_file
|
||||
elseif filekind =~ "XZ"
|
||||
exe "sil! r! xz -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
|
||||
elseif filekind =~? "xz"
|
||||
exe "sil! r! xz -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp
|
||||
exe "read ".escape_file
|
||||
elseif filekind =~ "Zstandard"
|
||||
exe "sil! r! zstd --decompress --stdout -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
|
||||
elseif filekind =~? "zstd"
|
||||
exe "sil! r! zstd --decompress --stdout -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp
|
||||
exe "read ".escape_file
|
||||
else
|
||||
exe "sil! r! gzip -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
|
||||
elseif filekind =~? "gzip"
|
||||
exe "sil! r! gzip -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp
|
||||
exe "read ".escape_file
|
||||
endif
|
||||
|
||||
elseif tarfile =~# '\.lrp$'
|
||||
exe "sil! r! cat -- ".shellescape(tarfile,1)." | gzip -d -c - | ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
|
||||
exe "sil! r! cat -- ".shellescape(tarfile,1)." | gzip -d -c - | ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp
|
||||
exe "read ".escape_file
|
||||
elseif tarfile =~# '\.lzma$'
|
||||
exe "sil! r! lzma -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
|
||||
exe "sil! r! lzma -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp
|
||||
exe "read ".escape_file
|
||||
elseif tarfile =~# '\.\(xz\|txz\)$'
|
||||
exe "sil! r! xz --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
|
||||
exe "sil! r! xz --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp
|
||||
exe "read ".escape_file
|
||||
elseif tarfile =~# '\.\(lz4\|tlz4\)$'
|
||||
exe "sil! r! lz4 --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
|
||||
exe "sil! r! lz4 --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_readoptions." - ".g:tar_secure.shellescape(fname,1).decmp
|
||||
exe "read ".escape_file
|
||||
else
|
||||
if tarfile =~ '^\s*-'
|
||||
" A file name starting with a dash is taken as an option. Prepend ./ to avoid that.
|
||||
let tarfile = substitute(tarfile, '-', './-', '')
|
||||
endif
|
||||
exe "silent r! ".g:tar_cmd." -".g:tar_readoptions.shellescape(tarfile,1)." ".tar_secure.shellescape(fname,1).decmp
|
||||
exe "silent r! ".g:tar_cmd." -".g:tar_readoptions.shellescape(tarfile,1)." ".g:tar_secure.shellescape(fname,1).decmp
|
||||
exe "read ".escape_file
|
||||
endif
|
||||
if get(b:, 'leading_slash', 0)
|
||||
sil g/^tar: /d
|
||||
endif
|
||||
|
||||
redraw!
|
||||
|
||||
if v:shell_error != 0
|
||||
cd ..
|
||||
if v:shell_error != 0
|
||||
lcd ..
|
||||
call s:Rmdir("_ZIPVIM_")
|
||||
exe "cd ".fnameescape(curdir)
|
||||
echohl Error | echo "***error*** (tar#Read) sorry, unable to open or extract ".tarfile." with ".fname | echohl None
|
||||
exe "lcd ".fnameescape(curdir)
|
||||
call s:Msg('tar#Read', 'error', $"sorry, unable to open or extract {tarfile} with {fname}")
|
||||
endif
|
||||
|
||||
if doro
|
||||
@ -430,40 +417,54 @@ if v:shell_error != 0
|
||||
endif
|
||||
|
||||
let b:tarfile= a:fname
|
||||
exe "file tarfile::".fnameescape(fname)
|
||||
|
||||
" cleanup
|
||||
keepj sil! 0d
|
||||
set nomod
|
||||
|
||||
let &report= repkeep
|
||||
exe "lcd ".fnameescape(curdir)
|
||||
silent exe "file tarfile::". fname->fnameescape()
|
||||
endfun
|
||||
|
||||
" ---------------------------------------------------------------------
|
||||
" tar#Write: {{{2
|
||||
fun! tar#Write(fname)
|
||||
let pwdkeep= getcwd()
|
||||
let repkeep= &report
|
||||
set report=10
|
||||
" temporary buffer variable workaround because too fucking tired. but it works now
|
||||
let curdir= b:curdir
|
||||
let tmpdir= b:tmpdir
|
||||
|
||||
if !exists("g:tar_secure") && a:fname =~ '^\s*-\|\s\+-'
|
||||
redraw!
|
||||
echohl WarningMsg | echo '***warning*** (tar#Write) rejecting tarfile member<'.a:fname.'> because of embedded "-"'
|
||||
return
|
||||
endif
|
||||
|
||||
" sanity checks
|
||||
if !executable(g:tar_cmd)
|
||||
redraw!
|
||||
let &report= repkeep
|
||||
return
|
||||
endif
|
||||
|
||||
let tarfile = substitute(b:tarfile,'tarfile:\(.\{-}\)::.*$','\1','')
|
||||
let fname = substitute(b:tarfile,'tarfile:.\{-}::\(.*\)$','\1','')
|
||||
|
||||
if get(b:, 'leading_slash', 0)
|
||||
call s:Msg('tar#Write', 'error', $"sorry, not attempting to update {tarfile} with {fname}")
|
||||
let &report= repkeep
|
||||
return
|
||||
endif
|
||||
|
||||
if !isdirectory(fnameescape(tmpdir))
|
||||
call mkdir(fnameescape(tmpdir), 'p')
|
||||
endif
|
||||
exe $"lcd {fnameescape(tmpdir)}"
|
||||
if isdirectory("_ZIPVIM_")
|
||||
call s:Rmdir("_ZIPVIM_")
|
||||
endif
|
||||
call mkdir("_ZIPVIM_")
|
||||
lcd _ZIPVIM_
|
||||
let dir = fnamemodify(fname, ':p:h')
|
||||
if dir !~# '_ZIPVIM_$'
|
||||
call mkdir(dir)
|
||||
endif
|
||||
|
||||
" handle compressed archives
|
||||
if tarfile =~# '\.bz2'
|
||||
call system("bzip2 -d -- ".shellescape(tarfile,0))
|
||||
@ -499,10 +500,10 @@ fun! tar#Write(fname)
|
||||
let tarfile = substitute(tarfile,'\.lzma','','e')
|
||||
let compress= "lzma -- ".shellescape(tarfile,0)
|
||||
endif
|
||||
" Note: no support for name.tar.tbz/.txz/.tgz/.tlz4/.tzst
|
||||
|
||||
if v:shell_error != 0
|
||||
redraw!
|
||||
echohl Error | echo "***error*** (tar#Write) sorry, unable to update ".tarfile." with ".fname | echohl None
|
||||
call s:Msg('tar#Write', 'error', $"sorry, unable to update {tarfile} with {fname}")
|
||||
else
|
||||
|
||||
if fname =~ '/'
|
||||
@ -520,28 +521,22 @@ fun! tar#Write(fname)
|
||||
let tarfile = substitute(tarfile, '-', './-', '')
|
||||
endif
|
||||
|
||||
if exists("g:tar_secure")
|
||||
let tar_secure= " -- "
|
||||
else
|
||||
let tar_secure= " "
|
||||
endif
|
||||
exe "w! ".fnameescape(fname)
|
||||
" don't overwrite a file forcefully
|
||||
exe "w ".fnameescape(fname)
|
||||
if has("win32unix") && executable("cygpath")
|
||||
let tarfile = substitute(system("cygpath ".shellescape(tarfile,0)),'\n','','e')
|
||||
endif
|
||||
|
||||
" delete old file from tarfile
|
||||
call system(g:tar_cmd." ".g:tar_delfile." ".shellescape(tarfile,0).tar_secure.shellescape(fname,0))
|
||||
" Note: BSD tar does not support --delete flag
|
||||
call system(g:tar_cmd." ".g:tar_delfile." ".shellescape(tarfile,0).g:tar_secure.shellescape(fname,0))
|
||||
if v:shell_error != 0
|
||||
redraw!
|
||||
echohl Error | echo "***error*** (tar#Write) sorry, unable to update ".fnameescape(tarfile)." with ".fnameescape(fname) | echohl None
|
||||
call s:Msg('tar#Write', 'error', $"sorry, unable to update {fnameescape(tarfile)} with {fnameescape(fname)} --delete not supported?")
|
||||
else
|
||||
|
||||
" update tarfile with new file
|
||||
call system(g:tar_cmd." -".g:tar_writeoptions." ".shellescape(tarfile,0).tar_secure.shellescape(fname,0))
|
||||
call system(g:tar_cmd." -".g:tar_writeoptions." ".shellescape(tarfile,0).g:tar_secure.shellescape(fname,0))
|
||||
if v:shell_error != 0
|
||||
redraw!
|
||||
echohl Error | echo "***error*** (tar#Write) sorry, unable to update ".fnameescape(tarfile)." with ".fnameescape(fname) | echohl None
|
||||
call s:Msg('tar#Write', 'error', $"sorry, unable to update {fnameescape(tarfile)} with {fnameescape(fname)}")
|
||||
elseif exists("compress")
|
||||
call system(compress)
|
||||
if exists("tgz")
|
||||
@ -567,9 +562,9 @@ fun! tar#Write(fname)
|
||||
endif
|
||||
|
||||
" cleanup and restore current directory
|
||||
cd ..
|
||||
lcd ..
|
||||
call s:Rmdir("_ZIPVIM_")
|
||||
exe "cd ".fnameescape(curdir)
|
||||
exe "lcd ".fnameescape(pwdkeep)
|
||||
setlocal nomod
|
||||
|
||||
let &report= repkeep
|
||||
@ -582,6 +577,7 @@ fun! tar#Diff(userfname,fname)
|
||||
if a:userfname != ""
|
||||
let fname= a:userfname
|
||||
endif
|
||||
exe "lcd ".fnameescape(b:tmpdir). '/_ZIPVIM_'
|
||||
if filereadable(fname)
|
||||
" sets current file (from tarball) for diff'ing
|
||||
" splits window vertically
|
||||
@ -605,12 +601,6 @@ fun! tar#Extract()
|
||||
set report=10
|
||||
let fname= getline(".")
|
||||
|
||||
if !exists("g:tar_secure") && fname =~ '^\s*-\|\s\+-'
|
||||
redraw!
|
||||
echohl WarningMsg | echo '***warning*** (tar#BrowseSelect) rejecting tarfile member<'.fname.'> because of embedded "-"'
|
||||
return
|
||||
endif
|
||||
|
||||
" sanity check
|
||||
if fname =~ '^"'
|
||||
let &report= repkeep
|
||||
@ -620,20 +610,20 @@ fun! tar#Extract()
|
||||
let tarball = expand("%")
|
||||
let tarbase = substitute(tarball,'\..*$','','')
|
||||
|
||||
let extractcmd= netrw#WinPath(g:tar_extractcmd)
|
||||
let extractcmd= s:WinPath(g:tar_extractcmd)
|
||||
if filereadable(tarbase.".tar")
|
||||
call system(extractcmd." ".shellescape(tarbase).".tar ".shellescape(fname))
|
||||
if v:shell_error != 0
|
||||
echohl Error | echo "***error*** ".extractcmd." ".tarbase.".tar ".fname.": failed!" | echohl NONE
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tar {fname}: failed!")
|
||||
else
|
||||
echo "***note*** successfully extracted ".fname
|
||||
echo "***note*** successfully extracted ". fname
|
||||
endif
|
||||
|
||||
elseif filereadable(tarbase.".tgz")
|
||||
let extractcmd= substitute(extractcmd,"-","-z","")
|
||||
call system(extractcmd." ".shellescape(tarbase).".tgz ".shellescape(fname))
|
||||
if v:shell_error != 0
|
||||
echohl Error | echo "***error*** ".extractcmd." ".tarbase.".tgz ".fname.": failed!" | echohl NONE
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tgz {fname}: failed!")
|
||||
else
|
||||
echo "***note*** successfully extracted ".fname
|
||||
endif
|
||||
@ -642,7 +632,7 @@ fun! tar#Extract()
|
||||
let extractcmd= substitute(extractcmd,"-","-z","")
|
||||
call system(extractcmd." ".shellescape(tarbase).".tar.gz ".shellescape(fname))
|
||||
if v:shell_error != 0
|
||||
echohl Error | echo "***error*** ".extractcmd." ".tarbase.".tar.gz ".fname.": failed!" | echohl NONE
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tar.gz {fname}: failed!")
|
||||
else
|
||||
echo "***note*** successfully extracted ".fname
|
||||
endif
|
||||
@ -651,7 +641,7 @@ fun! tar#Extract()
|
||||
let extractcmd= substitute(extractcmd,"-","-j","")
|
||||
call system(extractcmd." ".shellescape(tarbase).".tbz ".shellescape(fname))
|
||||
if v:shell_error != 0
|
||||
echohl Error | echo "***error*** ".extractcmd."j ".tarbase.".tbz ".fname.": failed!" | echohl NONE
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tbz {fname}: failed!")
|
||||
else
|
||||
echo "***note*** successfully extracted ".fname
|
||||
endif
|
||||
@ -660,7 +650,7 @@ fun! tar#Extract()
|
||||
let extractcmd= substitute(extractcmd,"-","-j","")
|
||||
call system(extractcmd." ".shellescape(tarbase).".tar.bz2 ".shellescape(fname))
|
||||
if v:shell_error != 0
|
||||
echohl Error | echo "***error*** ".extractcmd."j ".tarbase.".tar.bz2 ".fname.": failed!" | echohl NONE
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tar.bz2 {fname}: failed!")
|
||||
else
|
||||
echo "***note*** successfully extracted ".fname
|
||||
endif
|
||||
@ -669,7 +659,7 @@ fun! tar#Extract()
|
||||
let extractcmd= substitute(extractcmd,"-","-j","")
|
||||
call system(extractcmd." ".shellescape(tarbase).".tar.bz3 ".shellescape(fname))
|
||||
if v:shell_error != 0
|
||||
echohl Error | echo "***error*** ".extractcmd."j ".tarbase.".tar.bz3 ".fname.": failed!" | echohl NONE
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tar.bz3 {fname}: failed!")
|
||||
else
|
||||
echo "***note*** successfully extracted ".fname
|
||||
endif
|
||||
@ -678,7 +668,7 @@ fun! tar#Extract()
|
||||
let extractcmd= substitute(extractcmd,"-","-J","")
|
||||
call system(extractcmd." ".shellescape(tarbase).".txz ".shellescape(fname))
|
||||
if v:shell_error != 0
|
||||
echohl Error | echo "***error*** ".extractcmd." ".tarbase.".txz ".fname.": failed!" | echohl NONE
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.txz {fname}: failed!")
|
||||
else
|
||||
echo "***note*** successfully extracted ".fname
|
||||
endif
|
||||
@ -687,7 +677,7 @@ fun! tar#Extract()
|
||||
let extractcmd= substitute(extractcmd,"-","-J","")
|
||||
call system(extractcmd." ".shellescape(tarbase).".tar.xz ".shellescape(fname))
|
||||
if v:shell_error != 0
|
||||
echohl Error | echo "***error*** ".extractcmd." ".tarbase.".tar.xz ".fname.": failed!" | echohl NONE
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tar.xz {fname}: failed!")
|
||||
else
|
||||
echo "***note*** successfully extracted ".fname
|
||||
endif
|
||||
@ -696,7 +686,7 @@ fun! tar#Extract()
|
||||
let extractcmd= substitute(extractcmd,"-","--zstd","")
|
||||
call system(extractcmd." ".shellescape(tarbase).".tzst ".shellescape(fname))
|
||||
if v:shell_error != 0
|
||||
echohl Error | echo "***error*** ".extractcmd." ".tarbase.".tzst ".fname.": failed!" | echohl NONE
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tzst {fname}: failed!")
|
||||
else
|
||||
echo "***note*** successfully extracted ".fname
|
||||
endif
|
||||
@ -705,7 +695,7 @@ fun! tar#Extract()
|
||||
let extractcmd= substitute(extractcmd,"-","--zstd","")
|
||||
call system(extractcmd." ".shellescape(tarbase).".tar.zst ".shellescape(fname))
|
||||
if v:shell_error != 0
|
||||
echohl Error | echo "***error*** ".extractcmd." ".tarbase.".tar.zst ".fname.": failed!" | echohl NONE
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tar.zst {fname}: failed!")
|
||||
else
|
||||
echo "***note*** successfully extracted ".fname
|
||||
endif
|
||||
@ -714,7 +704,7 @@ fun! tar#Extract()
|
||||
let extractcmd= substitute(extractcmd,"-","-I lz4","")
|
||||
call system(extractcmd." ".shellescape(tarbase).".tlz4 ".shellescape(fname))
|
||||
if v:shell_error != 0
|
||||
echohl Error | echo "***error*** ".extractcmd." ".tarbase.".tlz4 ".fname.": failed!" | echohl NONE
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tlz4 {fname}: failed!")
|
||||
else
|
||||
echo "***note*** successfully extracted ".fname
|
||||
endif
|
||||
@ -723,7 +713,7 @@ fun! tar#Extract()
|
||||
let extractcmd= substitute(extractcmd,"-","-I lz4","")
|
||||
call system(extractcmd." ".shellescape(tarbase).".tar.lz4".shellescape(fname))
|
||||
if v:shell_error != 0
|
||||
echohl Error | echo "***error*** ".extractcmd." ".tarbase.".tar.lz4 ".fname.": failed!" | echohl NONE
|
||||
call s:Msg('tar#Extract', 'error', $"{extractcmd} {tarbase}.tar.lz4 {fname}: failed!")
|
||||
else
|
||||
echo "***note*** successfully extracted ".fname
|
||||
endif
|
||||
@ -736,15 +726,50 @@ endfun
|
||||
" ---------------------------------------------------------------------
|
||||
" s:Rmdir: {{{2
|
||||
fun! s:Rmdir(fname)
|
||||
if has("unix")
|
||||
call system("/bin/rm -rf -- ".shellescape(a:fname,0))
|
||||
elseif has("win32") || has("win95") || has("win64") || has("win16")
|
||||
if &shell =~? "sh$"
|
||||
call system("/bin/rm -rf -- ".shellescape(a:fname,0))
|
||||
else
|
||||
call system("del /S ".shellescape(a:fname,0))
|
||||
endif
|
||||
call delete(a:fname, 'rf')
|
||||
endfun
|
||||
|
||||
" s:FileHeader: {{{2
|
||||
fun! s:Header(fname)
|
||||
let header= readblob(a:fname, 0, 6)
|
||||
" Nvim: see https://github.com/neovim/neovim/pull/34968
|
||||
if header[0:2] == 0z425A68 " bzip2 header
|
||||
return "bzip2"
|
||||
elseif header[0:2] == 0z425A33 " bzip3 header
|
||||
return "bzip3"
|
||||
elseif header == 0zFD377A58.5A00 " xz header
|
||||
return "xz"
|
||||
elseif header[0:3] == 0z28B52FFD " zstd header
|
||||
return "zstd"
|
||||
elseif header[0:3] == 0z04224D18 " lz4 header
|
||||
return "lz4"
|
||||
elseif (header[0:1] == 0z1F9D ||
|
||||
\ header[0:1] == 0z1F8B ||
|
||||
\ header[0:1] == 0z1F9E ||
|
||||
\ header[0:1] == 0z1FA0 ||
|
||||
\ header[0:1] == 0z1F1E)
|
||||
return "gzip"
|
||||
endif
|
||||
return "unknown"
|
||||
endfun
|
||||
|
||||
" ---------------------------------------------------------------------
|
||||
" s:WinPath: {{{2
|
||||
fun! s:WinPath(path)
|
||||
if (!g:netrw_cygwin || &shell !~ '\%(\<bash\>\|\<zsh\>\)\%(\.exe\)\=$') && has("win32")
|
||||
" remove cygdrive prefix, if present
|
||||
let path = substitute(a:path, '/cygdrive/\(.\)', '\1:', '')
|
||||
" remove trailing slash (Win95)
|
||||
let path = substitute(path, '\(\\\|/\)$', '', 'g')
|
||||
" remove escaped spaces
|
||||
let path = substitute(path, '\ ', ' ', 'g')
|
||||
" convert slashes to backslashes
|
||||
let path = substitute(path, '/', '\', 'g')
|
||||
else
|
||||
let path = a:path
|
||||
endif
|
||||
|
||||
return path
|
||||
endfun
|
||||
|
||||
" =====================================================================
|
||||
|
@ -77,49 +77,11 @@ function! tutor#TutorFolds()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Marks: {{{1
|
||||
|
||||
function! tutor#ApplyMarks()
|
||||
hi! link tutorExpect Special
|
||||
if exists('b:tutor_metadata') && has_key(b:tutor_metadata, 'expect')
|
||||
let b:tutor_sign_id = 1
|
||||
for expct in keys(b:tutor_metadata['expect'])
|
||||
let lnum = eval(expct)
|
||||
call matchaddpos('tutorExpect', [lnum])
|
||||
call tutor#CheckLine(lnum)
|
||||
endfor
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! tutor#ApplyMarksOnChanged()
|
||||
if exists('b:tutor_metadata') && has_key(b:tutor_metadata, 'expect')
|
||||
let lnum = line('.')
|
||||
if index(keys(b:tutor_metadata['expect']), string(lnum)) > -1
|
||||
call tutor#CheckLine(lnum)
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! tutor#CheckLine(line)
|
||||
if exists('b:tutor_metadata') && has_key(b:tutor_metadata, 'expect')
|
||||
let bufn = bufnr('%')
|
||||
let ctext = getline(a:line)
|
||||
let signs = sign_getplaced(bufn, {'lnum': a:line})[0].signs
|
||||
if !empty(signs)
|
||||
call sign_unplace('', {'id': signs[0].id})
|
||||
endif
|
||||
if b:tutor_metadata['expect'][string(a:line)] == -1 || ctext ==# b:tutor_metadata['expect'][string(a:line)]
|
||||
exe "sign place ".b:tutor_sign_id." line=".a:line." name=tutorok buffer=".bufn
|
||||
else
|
||||
exe "sign place ".b:tutor_sign_id." line=".a:line." name=tutorbad buffer=".bufn
|
||||
endif
|
||||
let b:tutor_sign_id+=1
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Tutor Cmd: {{{1
|
||||
|
||||
function! s:Locale()
|
||||
" Make sure l:lang exists before returning.
|
||||
let l:lang = 'en_US'
|
||||
if exists('v:lang') && v:lang =~ '\a\a'
|
||||
let l:lang = v:lang
|
||||
elseif $LC_ALL =~ '\a\a'
|
||||
@ -132,8 +94,6 @@ function! s:Locale()
|
||||
endif
|
||||
elseif $LANG =~ '\a\a'
|
||||
let l:lang = $LANG
|
||||
else
|
||||
let l:lang = 'en_US'
|
||||
endif
|
||||
return split(l:lang, '_')
|
||||
endfunction
|
||||
@ -167,15 +127,21 @@ function! s:Sort(a, b)
|
||||
return retval
|
||||
endfunction
|
||||
|
||||
function! s:GlobTutorials(name)
|
||||
" returns a list of all tutor files matching the given name
|
||||
function! tutor#GlobTutorials(name, locale)
|
||||
let locale = a:locale
|
||||
" pack/*/start/* are not reported in &rtp
|
||||
let rtp = nvim_list_runtime_paths()
|
||||
\ ->map({_, v -> escape(v:lua.vim.fs.normalize(v), ',')})
|
||||
\ ->join(',')
|
||||
" search for tutorials:
|
||||
" 1. non-localized
|
||||
let l:tutors = s:GlobPath(&rtp, 'tutor/'.a:name.'.tutor')
|
||||
let l:tutors = s:GlobPath(rtp, 'tutor/'.a:name.'.tutor')
|
||||
" 2. localized for current locale
|
||||
let l:locale_tutors = s:GlobPath(&rtp, 'tutor/'.s:Locale()[0].'/'.a:name.'.tutor')
|
||||
let l:locale_tutors = s:GlobPath(rtp, 'tutor/'.locale.'/'.a:name.'.tutor')
|
||||
" 3. fallback to 'en'
|
||||
if len(l:locale_tutors) == 0
|
||||
let l:locale_tutors = s:GlobPath(&rtp, 'tutor/en/'.a:name.'.tutor')
|
||||
let l:locale_tutors = s:GlobPath(rtp, 'tutor/en/'.a:name.'.tutor')
|
||||
endif
|
||||
call extend(l:tutors, l:locale_tutors)
|
||||
return uniq(sort(l:tutors, 's:Sort'), 's:Sort')
|
||||
@ -197,7 +163,7 @@ function! tutor#TutorCmd(tutor_name)
|
||||
let l:tutor_name = fnamemodify(l:tutor_name, ':r')
|
||||
endif
|
||||
|
||||
let l:tutors = s:GlobTutorials(l:tutor_name)
|
||||
let l:tutors = tutor#GlobTutorials(l:tutor_name, s:Locale()[0])
|
||||
|
||||
if len(l:tutors) == 0
|
||||
echom "No tutorial with that name found"
|
||||
@ -220,15 +186,37 @@ function! tutor#TutorCmd(tutor_name)
|
||||
|
||||
call tutor#SetupVim()
|
||||
exe "edit ".l:to_open
|
||||
call tutor#EnableInteractive(v:true)
|
||||
call tutor#ApplyTransform()
|
||||
endfunction
|
||||
|
||||
function! tutor#TutorCmdComplete(lead,line,pos)
|
||||
let l:tutors = s:GlobTutorials('*')
|
||||
let l:tutors = tutor#GlobTutorials('*', s:Locale()[0])
|
||||
let l:names = uniq(sort(map(l:tutors, 'fnamemodify(v:val, ":t:r")'), 's:Sort'))
|
||||
return join(l:names, "\n")
|
||||
endfunction
|
||||
|
||||
" Enables/disables interactive mode.
|
||||
function! tutor#EnableInteractive(enable)
|
||||
let enable = a:enable
|
||||
if enable
|
||||
setlocal buftype=nofile
|
||||
setlocal concealcursor+=inv
|
||||
setlocal conceallevel=2
|
||||
lua require('nvim.tutor').apply_marks()
|
||||
augroup tutor_interactive
|
||||
autocmd! TextChanged,TextChangedI <buffer> lua require('nvim.tutor').apply_marks_on_changed()
|
||||
augroup END
|
||||
else
|
||||
setlocal buftype<
|
||||
setlocal concealcursor<
|
||||
setlocal conceallevel<
|
||||
if exists('#tutor_interactive')
|
||||
autocmd! tutor_interactive * <buffer>
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! tutor#ApplyTransform()
|
||||
if has('win32')
|
||||
sil! %s/{unix:(\(.\{-}\)),win:(\(.\{-}\))}/\2/g
|
||||
|
@ -15,6 +15,7 @@
|
||||
" 2024 Aug 18 by Vim Project: correctly handle special globbing chars
|
||||
" 2024 Aug 21 by Vim Project: simplify condition to detect MS-Windows
|
||||
" 2025 Mar 11 by Vim Project: handle filenames with leading '-' correctly
|
||||
" 2025 Jul 12 by Vim Project: drop ../ on write to prevent path traversal attacks
|
||||
" License: Vim License (see vim's :help license)
|
||||
" Copyright: Copyright (C) 2005-2019 Charles E. Campbell {{{1
|
||||
" Permission is hereby granted to use and distribute this code,
|
||||
@ -71,8 +72,9 @@ fun! s:Mess(group, msg)
|
||||
echohl Normal
|
||||
endfun
|
||||
|
||||
if v:version < 702
|
||||
call s:Mess('WarningMsg', "***warning*** this version of zip needs vim 7.2 or later")
|
||||
if !has('nvim-0.10') && v:version < 901
|
||||
" required for defer
|
||||
call s:Mess('WarningMsg', "***warning*** this version of zip needs vim 9.1 or later")
|
||||
finish
|
||||
endif
|
||||
" sanity checks
|
||||
@ -235,59 +237,62 @@ endfun
|
||||
" zip#Write: {{{2
|
||||
fun! zip#Write(fname)
|
||||
let dict = s:SetSaneOpts()
|
||||
let need_rename = 0
|
||||
defer s:RestoreOpts(dict)
|
||||
|
||||
" sanity checks
|
||||
if !executable(substitute(g:zip_zipcmd,'\s\+.*$','',''))
|
||||
call s:Mess('Error', "***error*** (zip#Write) sorry, your system doesn't appear to have the ".g:zip_zipcmd." program")
|
||||
return
|
||||
endif
|
||||
if !exists("*mkdir")
|
||||
call s:Mess('Error', "***error*** (zip#Write) sorry, mkdir() doesn't work on your system")
|
||||
return
|
||||
call s:Mess('Error', "***error*** (zip#Write) sorry, your system doesn't appear to have the ".g:zip_zipcmd." program")
|
||||
return
|
||||
endif
|
||||
|
||||
let curdir= getcwd()
|
||||
let tmpdir= tempname()
|
||||
if tmpdir =~ '\.'
|
||||
let tmpdir= substitute(tmpdir,'\.[^.]*$','','e')
|
||||
let tmpdir= substitute(tmpdir,'\.[^.]*$','','e')
|
||||
endif
|
||||
call mkdir(tmpdir,"p")
|
||||
|
||||
" attempt to change to the indicated directory
|
||||
if s:ChgDir(tmpdir,s:ERROR,"(zip#Write) cannot cd to temporary directory")
|
||||
return
|
||||
return
|
||||
endif
|
||||
|
||||
" place temporary files under .../_ZIPVIM_/
|
||||
if isdirectory("_ZIPVIM_")
|
||||
call delete("_ZIPVIM_", "rf")
|
||||
call delete("_ZIPVIM_", "rf")
|
||||
endif
|
||||
call mkdir("_ZIPVIM_")
|
||||
cd _ZIPVIM_
|
||||
|
||||
if has("unix")
|
||||
let zipfile = substitute(a:fname,'zipfile://\(.\{-}\)::[^\\].*$','\1','')
|
||||
let fname = substitute(a:fname,'zipfile://.\{-}::\([^\\].*\)$','\1','')
|
||||
let zipfile = substitute(a:fname,'zipfile://\(.\{-}\)::[^\\].*$','\1','')
|
||||
let fname = substitute(a:fname,'zipfile://.\{-}::\([^\\].*\)$','\1','')
|
||||
else
|
||||
let zipfile = substitute(a:fname,'^.\{-}zipfile://\(.\{-}\)::[^\\].*$','\1','')
|
||||
let fname = substitute(a:fname,'^.\{-}zipfile://.\{-}::\([^\\].*\)$','\1','')
|
||||
let zipfile = substitute(a:fname,'^.\{-}zipfile://\(.\{-}\)::[^\\].*$','\1','')
|
||||
let fname = substitute(a:fname,'^.\{-}zipfile://.\{-}::\([^\\].*\)$','\1','')
|
||||
endif
|
||||
if fname =~ '^[.]\{1,2}/'
|
||||
call system(g:zip_zipcmd." -d ".s:Escape(fnamemodify(zipfile,":p"),0)." ".s:Escape(fname,0))
|
||||
let fname = fname->substitute('^\([.]\{1,2}/\)\+', '', 'g')
|
||||
let need_rename = 1
|
||||
endif
|
||||
|
||||
if fname =~ '/'
|
||||
let dirpath = substitute(fname,'/[^/]\+$','','e')
|
||||
if has("win32unix") && executable("cygpath")
|
||||
let dirpath = substitute(fname,'/[^/]\+$','','e')
|
||||
if has("win32unix") && executable("cygpath")
|
||||
let dirpath = substitute(system("cygpath ".s:Escape(dirpath,0)),'\n','','e')
|
||||
endif
|
||||
call mkdir(dirpath,"p")
|
||||
endif
|
||||
call mkdir(dirpath,"p")
|
||||
endif
|
||||
if zipfile !~ '/'
|
||||
let zipfile= curdir.'/'.zipfile
|
||||
let zipfile= curdir.'/'.zipfile
|
||||
endif
|
||||
|
||||
exe "w! ".fnameescape(fname)
|
||||
" don't overwrite files forcefully
|
||||
exe "w ".fnameescape(fname)
|
||||
if has("win32unix") && executable("cygpath")
|
||||
let zipfile = substitute(system("cygpath ".s:Escape(zipfile,0)),'\n','','e')
|
||||
let zipfile = substitute(system("cygpath ".s:Escape(zipfile,0)),'\n','','e')
|
||||
endif
|
||||
|
||||
if (has("win32") || has("win95") || has("win64") || has("win16")) && &shell !~? 'sh$'
|
||||
@ -296,21 +301,24 @@ fun! zip#Write(fname)
|
||||
|
||||
call system(g:zip_zipcmd." -u ".s:Escape(fnamemodify(zipfile,":p"),0)." ".s:Escape(fname,0))
|
||||
if v:shell_error != 0
|
||||
call s:Mess('Error', "***error*** (zip#Write) sorry, unable to update ".zipfile." with ".fname)
|
||||
call s:Mess('Error', "***error*** (zip#Write) sorry, unable to update ".zipfile." with ".fname)
|
||||
|
||||
elseif s:zipfile_{winnr()} =~ '^\a\+://'
|
||||
" support writing zipfiles across a network
|
||||
let netzipfile= s:zipfile_{winnr()}
|
||||
1split|enew
|
||||
let binkeep= &binary
|
||||
let eikeep = &ei
|
||||
set binary ei=all
|
||||
exe "noswapfile e! ".fnameescape(zipfile)
|
||||
call netrw#NetWrite(netzipfile)
|
||||
let &ei = eikeep
|
||||
let &binary = binkeep
|
||||
q!
|
||||
unlet s:zipfile_{winnr()}
|
||||
" support writing zipfiles across a network
|
||||
let netzipfile= s:zipfile_{winnr()}
|
||||
1split|enew
|
||||
let binkeep= &binary
|
||||
let eikeep = &ei
|
||||
set binary ei=all
|
||||
exe "noswapfile e! ".fnameescape(zipfile)
|
||||
call netrw#NetWrite(netzipfile)
|
||||
let &ei = eikeep
|
||||
let &binary = binkeep
|
||||
q!
|
||||
unlet s:zipfile_{winnr()}
|
||||
elseif need_rename
|
||||
exe $"sil keepalt file {fnameescape($"zipfile://{zipfile}::{fname}")}"
|
||||
call s:Mess('Warning', "***error*** (zip#Browse) Path Traversal Attack detected, dropping relative path")
|
||||
endif
|
||||
|
||||
" cleanup and restore current directory
|
||||
@ -319,7 +327,6 @@ fun! zip#Write(fname)
|
||||
call s:ChgDir(curdir,s:WARNING,"(zip#Write) unable to return to ".curdir."!")
|
||||
call delete(tmpdir, "rf")
|
||||
setlocal nomod
|
||||
|
||||
endfun
|
||||
|
||||
" ---------------------------------------------------------------------
|
||||
@ -332,15 +339,18 @@ fun! zip#Extract()
|
||||
|
||||
" sanity check
|
||||
if fname =~ '^"'
|
||||
return
|
||||
return
|
||||
endif
|
||||
if fname =~ '/$'
|
||||
call s:Mess('Error', "***error*** (zip#Extract) Please specify a file, not a directory")
|
||||
return
|
||||
call s:Mess('Error', "***error*** (zip#Extract) Please specify a file, not a directory")
|
||||
return
|
||||
elseif fname =~ '^[.]\?[.]/'
|
||||
call s:Mess('Error', "***error*** (zip#Browse) Path Traversal Attack detected, not extracting!")
|
||||
return
|
||||
endif
|
||||
if filereadable(fname)
|
||||
call s:Mess('Error', "***error*** (zip#Extract) <" .. fname .."> already exists in directory, not overwriting!")
|
||||
return
|
||||
call s:Mess('Error', "***error*** (zip#Extract) <" .. fname .."> already exists in directory, not overwriting!")
|
||||
return
|
||||
endif
|
||||
let target = fname->substitute('\[', '[[]', 'g')
|
||||
" unzip 6.0 does not support -- to denote end-of-arguments
|
||||
@ -362,13 +372,12 @@ fun! zip#Extract()
|
||||
" extract the file mentioned under the cursor
|
||||
call system($"{g:zip_extractcmd} -o {shellescape(b:zipfile)} {target}")
|
||||
if v:shell_error != 0
|
||||
call s:Mess('Error', "***error*** ".g:zip_extractcmd." ".b:zipfile." ".fname.": failed!")
|
||||
call s:Mess('Error', "***error*** ".g:zip_extractcmd." ".b:zipfile." ".fname.": failed!")
|
||||
elseif !filereadable(fname)
|
||||
call s:Mess('Error', "***error*** attempted to extract ".fname." but it doesn't appear to be present!")
|
||||
call s:Mess('Error', "***error*** attempted to extract ".fname." but it doesn't appear to be present!")
|
||||
else
|
||||
echomsg "***note*** successfully extracted ".fname
|
||||
echomsg "***note*** successfully extracted ".fname
|
||||
endif
|
||||
|
||||
endfun
|
||||
|
||||
" ---------------------------------------------------------------------
|
||||
|
@ -47,6 +47,7 @@ hi('WildMenu', { fg = 'Black', bg = 'Yellow', ctermfg = 'Black', cterm
|
||||
hi('VertSplit', { link = 'Normal' })
|
||||
hi('WinSeparator', { link = 'VertSplit' })
|
||||
hi('WinBarNC', { link = 'WinBar' })
|
||||
hi('DiffTextAdd', { link = 'DiffText' })
|
||||
hi('EndOfBuffer', { link = 'NonText' })
|
||||
hi('LineNrAbove', { link = 'LineNr' })
|
||||
hi('LineNrBelow', { link = 'LineNr' })
|
||||
|
25
runtime/compiler/gleam_build.vim
Normal file
25
runtime/compiler/gleam_build.vim
Normal file
@ -0,0 +1,25 @@
|
||||
" Vim compiler file
|
||||
" Language: Gleam
|
||||
" Maintainer: Kirill Morozov <kirill@robotix.pro>
|
||||
" Based On: https://github.com/gleam-lang/gleam.vim
|
||||
" Last Change: 2025 Apr 21
|
||||
|
||||
if exists('current_compiler')
|
||||
finish
|
||||
endif
|
||||
let current_compiler = "gleam_build"
|
||||
|
||||
CompilerSet makeprg=gleam\ build
|
||||
|
||||
" Example error message:
|
||||
"
|
||||
" error: Unknown variable
|
||||
" ┌─ /home/michael/root/projects/tutorials/gleam/try/code/src/main.gleam:19:18
|
||||
" │
|
||||
" 19 │ Ok(tuple(name, spot))
|
||||
" │ ^^^^ did you mean `sport`?
|
||||
"
|
||||
" The name `spot` is not in scope here.
|
||||
CompilerSet errorformat=%Eerror:\ %m,%Wwarning:\ %m,%C\ %#┌─%#\ %f:%l:%c\ %#-%#
|
||||
|
||||
" vim: sw=2 sts=2 et
|
@ -2,6 +2,7 @@
|
||||
" Compiler: Pandoc
|
||||
" Maintainer: Konfekt
|
||||
" Last Change: 2024 Nov 19
|
||||
" 2025 May 15 Update the title regex for CompilerSet #17321
|
||||
"
|
||||
" Expects output file extension, say `:make html` or `:make pdf`.
|
||||
" Passes additional arguments to pandoc, say `:make html --self-contained`.
|
||||
@ -51,7 +52,7 @@ endfunction
|
||||
|
||||
execute 'CompilerSet makeprg=pandoc'..escape(
|
||||
\ ' --standalone'..
|
||||
\ (s:PandocFiletype(&filetype) ==# 'markdown' && (getline(1) =~# '^%\s\+\S\+' || (search('^title:\s+\S+', 'cnw') > 0)) ?
|
||||
\ (s:PandocFiletype(&filetype) ==# 'markdown' && (getline(1) =~# '^%\s\+\S\+' || (search('^title:\s\+\S\+', 'cnw') > 0)) ?
|
||||
\ '' : ' --metadata title=%:t:r:S')..
|
||||
\ ' '..s:PandocLang()..
|
||||
\ ' --from='..s:PandocFiletype(&filetype)..
|
||||
|
12
runtime/compiler/phpstan.vim
Normal file
12
runtime/compiler/phpstan.vim
Normal file
@ -0,0 +1,12 @@
|
||||
" Vim compiler file
|
||||
" Compiler: PHPStan
|
||||
" Maintainer: Dietrich Moerman <dietrich.moerman@gmail.com>
|
||||
" Last Change: 2025 Jul 17
|
||||
|
||||
if exists("current_compiler")
|
||||
finish
|
||||
endif
|
||||
let current_compiler = "phpstan"
|
||||
|
||||
CompilerSet makeprg=composer\ exec\ --\ phpstan\ analyse\ -v\ --no-progress\ --error-format=raw
|
||||
CompilerSet errorformat=%f:%l:%m,%-G%.%#
|
@ -1,10 +1,13 @@
|
||||
*ui.txt* Nvim
|
||||
*api-ui-events.txt* Nvim
|
||||
|
||||
|
||||
NVIM REFERENCE MANUAL
|
||||
|
||||
|
||||
Nvim UI protocol *UI* *ui*
|
||||
Nvim UI protocol *UI* *ui* *api-ui-events*
|
||||
|
||||
This document describes the UI protocol. See |gui| and |tui| for user-facing
|
||||
UI components and features.
|
||||
|
||||
Type |gO| to see the table of contents.
|
||||
|
||||
@ -226,8 +229,7 @@ the editor.
|
||||
sent from Nvim, like for |ui-cmdline|.
|
||||
|
||||
["chdir", path] ~
|
||||
The |current-directory| of the embedded Nvim process changed to
|
||||
`path`.
|
||||
The |current-directory| changed to `path`.
|
||||
|
||||
["mode_change", mode, mode_idx] ~
|
||||
Editor mode changed. The `mode` parameter is a string representing
|
||||
@ -249,6 +251,14 @@ the editor.
|
||||
Indicates to the UI that it must stop rendering the cursor. This event
|
||||
is misnamed and does not actually have anything to do with busyness.
|
||||
|
||||
["restart", progpath, argv] ~
|
||||
|:restart| command has been used and the Nvim server is about to exit.
|
||||
The UI should wait for the server to exit, and then start a new server
|
||||
using `progpath` as the full path to the Nvim executable |v:progpath| and
|
||||
`argv` as its arguments |v:argv|, and reattach to the new server.
|
||||
Note: |--embed| and |--headless| are excluded from `argv`, and the client
|
||||
should decide itself whether to add either flag.
|
||||
|
||||
["suspend"] ~
|
||||
|:suspend| command or |CTRL-Z| mapping is used. A terminal client (or
|
||||
another client where it makes sense) could suspend itself. Other
|
||||
@ -609,12 +619,31 @@ tabs.
|
||||
size). If the window was previously hidden, it should now be shown
|
||||
again.
|
||||
|
||||
["win_float_pos", grid, win, anchor, anchor_grid, anchor_row, anchor_col, mouse_enabled, zindex] ~
|
||||
Display or reconfigure floating window `win`. The window should be
|
||||
displayed above another grid `anchor_grid` at the specified position
|
||||
`anchor_row` and `anchor_col`. For the meaning of `anchor` and more details
|
||||
of positioning, see |nvim_open_win()|. `mouse_enabled` is true if the
|
||||
window can receive mouse events.
|
||||
["win_float_pos", grid, win, anchor, anchor_grid, anchor_row, anchor_col, mouse_enabled, zindex, compindex, screen_row, screen_col] ~
|
||||
Display or reconfigure floating window `win`.
|
||||
|
||||
There are two alternative ways of positioning the window
|
||||
- Manually - The window should be displayed above another grid
|
||||
`anchor_grid` at the specified position `anchor_row` and
|
||||
`anchor_col`. For the meaning of `anchor` and more details of
|
||||
positioning, see |nvim_open_win()|. NOTE: you have to manually
|
||||
ensure that the window fits the screen, possibly by further
|
||||
reposition it. Ignore `screen_row` and `screen_col` in this case.
|
||||
- Let nvim take care of the positioning - You can ignore `anchor`
|
||||
and display the window at `screen_row` and `screen_col`.
|
||||
|
||||
`mouse_enabled` is true if the window can receive mouse events.
|
||||
|
||||
`zindex` is the configured zindex, while `compindex` is the exact
|
||||
rendering order of the windows determined by nvim. To render exactly
|
||||
like the TUI, first render all the non-floating windows, then render
|
||||
in the `compindex` order, overwriting any floating window cells.
|
||||
Finally, blend the floating window cells against the non-floating
|
||||
background. To add more blending, you can group the windows by zindex,
|
||||
and blend between the layers. But note that windows inside the same
|
||||
zindex should still overwrite previous cells inside the same layer
|
||||
without blending. This ensures that plugins that render multiple
|
||||
windows, to add borders for example, work as expected.
|
||||
|
||||
["win_external_pos", grid, win] ~
|
||||
Display or reconfigure external window `win`. The window should be
|
||||
@ -627,7 +656,7 @@ tabs.
|
||||
["win_close", grid] ~
|
||||
Close the window.
|
||||
|
||||
["msg_set_pos", grid, row, scrolled, sep_char] ~
|
||||
["msg_set_pos", grid, row, scrolled, sep_char, zindex, compindex] ~
|
||||
Display messages on `grid`. The grid will be displayed at `row` on
|
||||
the default grid (grid=1), covering the full column width. `scrolled`
|
||||
indicates whether the message area has been scrolled to cover other
|
||||
@ -638,6 +667,10 @@ tabs.
|
||||
When |ui-messages| is active, no message grid is used, and this event
|
||||
will not be sent.
|
||||
|
||||
`zindex` and `compindex` have the same meaning as for `win_float_pos`.
|
||||
The `zindex` always has a fixed value of 200 and included for
|
||||
completeness.
|
||||
|
||||
["win_viewport", grid, win, topline, botline, curline, curcol, line_count, scroll_delta] ~
|
||||
Indicates the range of buffer text displayed in the window, as well
|
||||
as the cursor position in the buffer. All positions are zero-based.
|
||||
@ -719,8 +752,8 @@ This UI extension delegates presentation of the |cmdline| (except 'wildmenu').
|
||||
For command-line 'wildmenu' UI events, activate |ui-popupmenu|.
|
||||
|
||||
["cmdline_show", content, pos, firstc, prompt, indent, level, hl_id] ~
|
||||
content: List of [attrs, string]
|
||||
[[{}, "t"], [attrs, "est"], ...]
|
||||
content: List of [attrs, string, hl_id]
|
||||
[[{}, "t", hl_id], [attrs, "est", hl_id], ...]
|
||||
|
||||
Triggered when the cmdline is displayed or changed.
|
||||
The `content` is the full content that should be displayed in the
|
||||
@ -752,9 +785,10 @@ For command-line 'wildmenu' UI events, activate |ui-popupmenu|.
|
||||
|
||||
Should be hidden at next cmdline_show.
|
||||
|
||||
["cmdline_hide", abort] ~
|
||||
Hide the cmdline. `abort` is true if the cmdline is hidden after an
|
||||
aborting condition (|c_Esc| or |c_CTRL-C|).
|
||||
["cmdline_hide", level, abort] ~
|
||||
Hide the cmdline. `level` is the nesting level of the cmdline being hidden.
|
||||
`abort` is true if the cmdline is hidden after an aborting condition
|
||||
(|c_Esc| or |c_CTRL-C|).
|
||||
|
||||
["cmdline_block_show", lines] ~
|
||||
Show a block of context to the current command line. For example if
|
||||
@ -787,12 +821,15 @@ will be set to zero, but can be changed and used for the replacing cmdline or
|
||||
message window. Cmdline state is emitted as |ui-cmdline| events, which the UI
|
||||
must handle.
|
||||
|
||||
["msg_show", kind, content, replace_last, history] ~
|
||||
["msg_show", kind, content, replace_last, history, append] ~
|
||||
Display a message to the user.
|
||||
|
||||
kind
|
||||
Name indicating the message kind:
|
||||
"" (empty) Unknown (consider a |feature-request|)
|
||||
"empty" Empty message (`:echo ""`), with empty `content`.
|
||||
Should clear messages sharing the 'cmdheight'
|
||||
area if it is the only message in a batch.
|
||||
"bufwrite" |:write| message
|
||||
"confirm" Message preceding a prompt (|:confirm|,
|
||||
|confirm()|, |inputlist()|, |z=|, …)
|
||||
@ -805,10 +842,10 @@ must handle.
|
||||
"lua_error" Error in |:lua| code
|
||||
"lua_print" |print()| from |:lua| code
|
||||
"rpc_error" Error response from |rpcrequest()|
|
||||
"return_prompt" |press-enter| prompt after a multiple messages
|
||||
"quickfix" Quickfix navigation message
|
||||
"search_cmd" Entered search command
|
||||
"search_count" Search count message ("S" flag of 'shortmess')
|
||||
"shell_cmd" |:!cmd| executed command
|
||||
"shell_err" |:!cmd| shell stderr output
|
||||
"shell_out" |:!cmd| shell stdout output
|
||||
"shell_ret" |:!cmd| shell return code
|
||||
@ -836,9 +873,14 @@ must handle.
|
||||
history
|
||||
True if the message was added to the |:messages| history.
|
||||
|
||||
append
|
||||
True if the message should be appeneded to the previous message,
|
||||
rather than started on a new line. Is set for |:echon|.
|
||||
|
||||
["msg_clear"] ~
|
||||
Clear all messages currently displayed by "msg_show". (Messages sent
|
||||
by other "msg_" events below will not be affected).
|
||||
Clear all messages currently displayed by "msg_show", emitted after
|
||||
clearing the screen (messages sent by other "msg_" events below should
|
||||
not be affected).
|
||||
|
||||
["msg_showmode", content] ~
|
||||
Shows 'showmode' and |recording| messages. `content` has the same
|
||||
@ -854,12 +896,11 @@ must handle.
|
||||
statusline. `content` has the same format as in "msg_show". This event is
|
||||
sent with empty `content` to hide the last message.
|
||||
|
||||
["msg_history_show", entries] ~
|
||||
Sent when |:messages| command is invoked. History is sent as a list of
|
||||
entries, where each entry is a `[kind, content]` tuple.
|
||||
["msg_history_show", entries, prev_cmd] ~
|
||||
Sent when |:messages| or |g<| command is invoked. History is sent as a
|
||||
list of entries, where each entry is a `[kind, content, append]` tuple.
|
||||
|
||||
["msg_history_clear"] ~
|
||||
Clear the |:messages| history.
|
||||
prev_cmd
|
||||
True when sent with |g<| command, false with |:messages|.
|
||||
|
||||
==============================================================================
|
||||
vim:tw=78:ts=8:noet:ft=help:norl:
|
1126
runtime/doc/api.txt
1126
runtime/doc/api.txt
File diff suppressed because it is too large
Load Diff
@ -73,11 +73,16 @@ Or use `:execute`: >
|
||||
Note that special characters (e.g., "%", "<cword>") in the ":autocmd"
|
||||
arguments are not expanded when the autocommand is defined. These will be
|
||||
expanded when the Event is recognized, and the {cmd} is executed. The only
|
||||
exception is that "<sfile>" is expanded when the autocmd is defined. Example:
|
||||
exception is that "<sfile>" (unlike "<script>") is expanded when the autocmd
|
||||
is defined. Example:
|
||||
>
|
||||
:au BufNewFile,BufRead *.html so <sfile>:h/html.vim
|
||||
|
||||
Here Vim expands <sfile> to the name of the file containing this line.
|
||||
However, <sfile> works differently in a function, in which case it's better to
|
||||
use `:execute` with <script> to achieve the same purpose:
|
||||
>
|
||||
:exe $'au BufNewFile,BufRead *.html so {expand("<script>:h")}/html.vim'
|
||||
|
||||
`:autocmd` adds to the list of autocommands regardless of whether they are
|
||||
already present. When your .vimrc file is sourced twice, the autocommands
|
||||
@ -257,7 +262,7 @@ BufLeave Before leaving to another buffer. Also when
|
||||
Not used for ":qa" or ":q" when exiting Vim.
|
||||
*BufModifiedSet*
|
||||
BufModifiedSet After the `'modified'` value of a buffer has
|
||||
been changed.
|
||||
been changed. Special-case of |OptionSet|.
|
||||
*BufNew*
|
||||
BufNew After creating a new buffer (except during
|
||||
startup, see |VimEnter|) or renaming an
|
||||
@ -344,7 +349,8 @@ BufWriteCmd Before writing the whole buffer to a file.
|
||||
The buffer contents should not be changed.
|
||||
When the command resets 'modified' the undo
|
||||
information is adjusted to mark older undo
|
||||
states as 'modified', like |:write| does.
|
||||
states as 'modified', like |:write| does. Use
|
||||
the |'[| and |']| marks for the range of lines.
|
||||
|Cmd-event|
|
||||
*BufWritePost*
|
||||
BufWritePost After writing the whole buffer to a file
|
||||
@ -400,6 +406,16 @@ CmdlineLeave Before leaving the command-line (including
|
||||
Note: `abort` can only be changed from false
|
||||
to true: cannot execute an already aborted
|
||||
cmdline by changing it to false.
|
||||
*CmdlineLeavePre*
|
||||
CmdlineLeavePre Just before leaving the command line, and
|
||||
before |CmdlineLeave|. Useful for capturing
|
||||
completion info with |cmdcomplete_info()|, as
|
||||
this information is cleared before
|
||||
|CmdlineLeave| is triggered. Triggered for
|
||||
non-interactive use of ":" in a mapping, but
|
||||
not when using |<Cmd>|. Also triggered when
|
||||
abandoning the command line by typing CTRL-C
|
||||
or <Esc>. <afile> is set to |cmdline-char|.
|
||||
*CmdwinEnter*
|
||||
CmdwinEnter After entering the command-line window.
|
||||
Useful for setting options specifically for
|
||||
@ -477,27 +493,16 @@ CompleteDone After Insert mode completion is done. Either
|
||||
- "accept": completion was
|
||||
accepted by |complete_CTRL-Y|.
|
||||
- "cancel": completion was
|
||||
stopped by |complete_CTRL-E.
|
||||
stopped by |complete_CTRL-E|.
|
||||
- "discard": completion was
|
||||
abandoned for other reason.
|
||||
|
||||
*CursorHold*
|
||||
CursorHold When the user doesn't press a key for the time
|
||||
specified with 'updatetime'. Not triggered
|
||||
until the user has pressed a key (i.e. doesn't
|
||||
fire every 'updatetime' ms if you leave Vim to
|
||||
make some coffee. :) See |CursorHold-example|
|
||||
for previewing tags.
|
||||
This event is only triggered in Normal mode.
|
||||
It is not triggered when waiting for a command
|
||||
argument to be typed, or a movement after an
|
||||
operator.
|
||||
While recording the CursorHold event is not
|
||||
triggered. |q|
|
||||
*<CursorHold>*
|
||||
Internally the autocommand is triggered by the
|
||||
<CursorHold> key. In an expression mapping
|
||||
|getchar()| may see this character.
|
||||
CursorHold When there is no user input for 'updatetime'
|
||||
duration, in Normal-mode. Not triggered while
|
||||
waiting for a command argument or movement
|
||||
after an operator, nor while |recording|
|
||||
a macro. See |CursorHold-example|.
|
||||
|
||||
Note: Interactive commands cannot be used for
|
||||
this event. There is no hit-enter prompt,
|
||||
@ -648,14 +653,14 @@ FileType When the 'filetype' option has been set. The
|
||||
FileWriteCmd Before writing to a file, when not writing the
|
||||
whole buffer. Should do the writing to the
|
||||
file. Should not change the buffer. Use the
|
||||
'[ and '] marks for the range of lines.
|
||||
|'[| and |']| marks for the range of lines.
|
||||
|Cmd-event|
|
||||
*FileWritePost*
|
||||
FileWritePost After writing to a file, when not writing the
|
||||
whole buffer.
|
||||
*FileWritePre*
|
||||
FileWritePre Before writing to a file, when not writing the
|
||||
whole buffer. Use the '[ and '] marks for the
|
||||
whole buffer. Use the |'[| and |']| marks for the
|
||||
range of lines.
|
||||
*FilterReadPost*
|
||||
FilterReadPost After reading a file from a filter command.
|
||||
@ -822,6 +827,10 @@ OptionSet After setting an option (except during
|
||||
always use |:noautocmd| to prevent triggering
|
||||
OptionSet.
|
||||
|
||||
Note: Not triggered by the 'modified' option;
|
||||
the |BufModifiedSet| event may be used to
|
||||
handle that.
|
||||
|
||||
Non-recursive: |:set| in the autocommand does
|
||||
not trigger OptionSet again.
|
||||
|
||||
@ -1034,7 +1043,7 @@ TermRequest When a |:terminal| child process emits an OSC,
|
||||
autocommand defined without |autocmd-nested|.
|
||||
|
||||
*TermResponse*
|
||||
TermResponse When Nvim receives an OSC or DCS response from
|
||||
TermResponse When Nvim receives a DA1, OSC, DCS, or APC response from
|
||||
the host terminal. Sets |v:termresponse|. The
|
||||
|event-data| is a table with the following fields:
|
||||
|
||||
@ -1186,6 +1195,13 @@ WinScrolled After any window in the current tab page
|
||||
or changed width or height. See
|
||||
|win-scrolled-resized|.
|
||||
|
||||
Note: This can not be skipped with
|
||||
`:noautocmd`, because it triggers after
|
||||
processing normal commands when Vim is back in
|
||||
the main loop. If you want to disable this,
|
||||
consider setting the 'eventignore' option
|
||||
instead.
|
||||
|
||||
The pattern is matched against the |window-ID|
|
||||
of the first window that scrolled or resized.
|
||||
Both <amatch> and <afile> are set to the
|
||||
|
@ -141,8 +141,8 @@ the 'joinspaces' option is on, these commands insert two spaces after a '.',
|
||||
The 'B' and 'M' flags in 'formatoptions' change the behavior for inserting
|
||||
spaces before and after a multibyte character |fo-table|.
|
||||
|
||||
The '[ mark is set at the end of the first line that was joined, '] at the end
|
||||
of the resulting line.
|
||||
The |'[| mark is set at the end of the first line that was joined, |']| at the
|
||||
end of the resulting line.
|
||||
|
||||
|
||||
==============================================================================
|
||||
@ -367,7 +367,7 @@ CTRL-A Add [count] to the number or alphabetic character at
|
||||
*v_g_CTRL-A*
|
||||
{Visual}g CTRL-A Add [count] to the number or alphabetic character in
|
||||
the highlighted text. If several lines are
|
||||
highlighted, each one will be incremented by an
|
||||
highlighted, each one will be incremented by an
|
||||
additional [count] (so effectively creating a
|
||||
[count] incrementing sequence).
|
||||
For Example, if you have this list of numbers:
|
||||
@ -644,8 +644,9 @@ original user.
|
||||
Repeat last :substitute with same search pattern and
|
||||
substitute string, but without the same flags. You
|
||||
may add [flags], see |:s_flags|.
|
||||
Note that after `:substitute` the '&' flag can't be
|
||||
used, it's recognized as a pattern separator.
|
||||
Note that after `:substitute` the '&' and '#' flags
|
||||
can't be used, they're recognized as a pattern
|
||||
separator.
|
||||
The space between `:substitute` and the 'c', 'g',
|
||||
'i', 'I' and 'r' flags isn't required, but in scripts
|
||||
it's a good idea to keep it to avoid confusion.
|
||||
@ -948,22 +949,26 @@ This replaces each 'E' character with a euro sign. Read more in |<Char->|.
|
||||
|
||||
4.3 Changing tabs *change-tabs*
|
||||
*:ret* *:retab* *:retab!*
|
||||
:[range]ret[ab][!] [new_tabstop]
|
||||
:[range]ret[ab][!] [-indentonly] [{new-tabstop}]
|
||||
Replace all sequences of white-space containing a
|
||||
<Tab> with new strings of white-space using the new
|
||||
tabstop value given. If you do not specify a new
|
||||
tabstop size or it is zero, Vim uses the current value
|
||||
of 'tabstop'.
|
||||
<Tab> with new strings of white-space using
|
||||
{new-tabstop}. If you do not specify {new-tabstop} or
|
||||
it is zero, Vim uses the current value of 'tabstop'.
|
||||
The current value of 'tabstop' is always used to
|
||||
compute the width of existing tabs.
|
||||
With !, Vim also replaces strings of only normal
|
||||
spaces with tabs where appropriate.
|
||||
With 'expandtab' on, Vim replaces all tabs with the
|
||||
appropriate number of spaces.
|
||||
This command sets 'tabstop' to the new value given,
|
||||
and if performed on the whole file, which is default,
|
||||
should not make any visible change.
|
||||
Careful: This command modifies any <Tab> characters
|
||||
This command sets 'tabstop' to {new-tabstop} and if
|
||||
performed on the whole file, which is default, should
|
||||
not make any visible change.
|
||||
|
||||
When [-indentonly] is specified, only the leading
|
||||
white-space will be targeted. Any other consecutive
|
||||
white-space will not be changed.
|
||||
|
||||
Warning: This command modifies any <Tab> characters
|
||||
inside of strings in a C program. Use "\t" to avoid
|
||||
this (that's a good habit anyway).
|
||||
`:retab!` may also change a sequence of spaces by
|
||||
@ -1105,6 +1110,11 @@ inside of strings can change! Also see 'softtabstop' option. >
|
||||
:[line]pu[t]! [x] Put the text [from register x] before [line] (default
|
||||
current line).
|
||||
|
||||
*:ip* *:iput*
|
||||
:[line]ip[ut] [x] like |:put|, but adjust indent to the current line
|
||||
|
||||
:[line]ip[ut]! [x] like |:put|!, but adjust indent to the current line
|
||||
|
||||
["x]]p or *]p* *]<MiddleMouse>*
|
||||
["x]]<MiddleMouse> Like "p", but adjust the indent to the current line.
|
||||
Using the mouse only works when 'mouse' contains 'n'
|
||||
@ -1139,8 +1149,8 @@ the ":put" command, Vim always inserts the text in the next line. You can
|
||||
exchange two characters with the command sequence "xp". You can exchange two
|
||||
lines with the command sequence "ddp". You can exchange two words with the
|
||||
command sequence "deep" (start with the cursor in the blank space before the
|
||||
first word). You can use the "']" or "`]" command after the put command to
|
||||
move the cursor to the end of the inserted text, or use "'[" or "`[" to move
|
||||
first word). You can use the |']| or |`]| command after the put command to
|
||||
move the cursor to the end of the inserted text, or use |'[| or |`[| to move
|
||||
the cursor to the start.
|
||||
|
||||
*put-Visual-mode* *v_p* *v_P*
|
||||
@ -1239,6 +1249,18 @@ mapped. E.g. |%| is mapped by the matchit plugin.
|
||||
With each successive deletion or change, Vim shifts the previous contents
|
||||
of register 1 into register 2, 2 into 3, and so forth, losing the previous
|
||||
contents of register 9.
|
||||
*yankring*
|
||||
To also store yanks (not only deletions) in registers 1-9, try this: >lua
|
||||
-- Yank-ring: store yanked text in registers 1-9.
|
||||
vim.api.nvim_create_autocmd('TextYankPost', {
|
||||
callback = function()
|
||||
if vim.v.event.operator == 'y' then
|
||||
for i = 9, 1, -1 do -- Shift all numbered registers.
|
||||
vim.fn.setreg(tostring(i), vim.fn.getreg(tostring(i - 1)))
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
3. Small delete register "- *quote_-* *quote-*
|
||||
This register contains text from commands that delete less than one line,
|
||||
@ -1714,7 +1736,7 @@ B When joining lines, don't insert a space between two multibyte
|
||||
j Where it makes sense, remove a comment leader when joining lines. For
|
||||
example, joining:
|
||||
int i; // the index ~
|
||||
// in the list ~
|
||||
// in the list ~
|
||||
Becomes:
|
||||
int i; // the index in the list ~
|
||||
*fo-p*
|
||||
@ -1817,6 +1839,7 @@ And a few warnings:
|
||||
|
||||
Vim has a sorting function and a sorting command. The sorting function can be
|
||||
found here: |sort()|, |uniq()|.
|
||||
Also see |:uniq|.
|
||||
|
||||
*:sor* *:sort*
|
||||
:[range]sor[t][!] [b][f][i][l][n][o][r][u][x] [/{pattern}/]
|
||||
@ -1826,7 +1849,7 @@ found here: |sort()|, |uniq()|.
|
||||
With [!] the order is reversed.
|
||||
|
||||
With [i] case is ignored.
|
||||
|
||||
*:sort-l*
|
||||
With [l] sort uses the current collation locale.
|
||||
Implementation details: strcoll() is used to compare
|
||||
strings. See |:language| to check or set the collation
|
||||
@ -1858,13 +1881,14 @@ found here: |sort()|, |uniq()|.
|
||||
|
||||
With [b] sorting is done on the first binary number in
|
||||
the line (after or inside a {pattern} match).
|
||||
|
||||
*:sort-u* *:sort-uniq*
|
||||
With [u] (u stands for unique) only keep the first of
|
||||
a sequence of identical lines (ignoring case when [i]
|
||||
is used). Without this flag, a sequence of identical
|
||||
lines will be kept in their original order.
|
||||
Note that leading and trailing white space may cause
|
||||
lines to be different.
|
||||
When you just want to make things unique, use |:uniq|.
|
||||
|
||||
When /{pattern}/ is specified and there is no [r] flag
|
||||
the text matched with {pattern} is skipped, so that
|
||||
@ -1911,4 +1935,55 @@ The sorting can be interrupted, but if you interrupt it too late in the
|
||||
process you may end up with duplicated lines. This also depends on the system
|
||||
library function used.
|
||||
|
||||
==============================================================================
|
||||
8. Deduplicating text *deduplicating* *unique*
|
||||
|
||||
Vim has a deduplicating function and a deduplicating command. The
|
||||
deduplicating function can be found here: |uniq()|.
|
||||
Also see |:sort-uniq|.
|
||||
|
||||
*:uni* *:uniq*
|
||||
:[range]uni[q][!] [i][l][r][u] [/{pattern}/]
|
||||
Remove duplicate lines that are adjacent to each other
|
||||
in [range]. When no range is given, all lines are
|
||||
processed.
|
||||
|
||||
With [i] case is ignored when comparing lines.
|
||||
|
||||
With [l] comparison uses the current collation locale.
|
||||
See |:sort-l| for more details.
|
||||
|
||||
With [r] comparison is done on the text that matches
|
||||
/{pattern}/ instead of the full line.
|
||||
|
||||
With [u] only keep lines that do not repeat (i.e., are
|
||||
not immediately followed by the same line).
|
||||
|
||||
With [!] only keep lines that are immediately followed
|
||||
by a duplicate.
|
||||
|
||||
If both [!] and [u] are given, [u] is ignored and [!]
|
||||
takes effect.
|
||||
|
||||
When /{pattern}/ is specified and [r] is not used, the
|
||||
text matched with {pattern} is skipped and comparison
|
||||
is done on what comes after the match.
|
||||
'ignorecase' applies to the pattern, but 'smartcase'
|
||||
is not used.
|
||||
Instead of the slash any non-letter can be used.
|
||||
|
||||
For example, to remove adjacent duplicate lines based
|
||||
on the second comma-separated field: >
|
||||
:uniq /[^,]*,/
|
||||
< Or to keep only unique lines ignoring the first 5
|
||||
characters: >
|
||||
:uniq u /.\{5}/
|
||||
< If {pattern} is empty (e.g. // is used), the last
|
||||
search pattern is used.
|
||||
|
||||
Note that leading and trailing white space may cause
|
||||
lines to be considered different.
|
||||
To remove all duplicates regardless of position, use
|
||||
|:sort-u| or external tools.
|
||||
|
||||
vim:tw=78:ts=8:noet:ft=help:norl:
|
||||
|
@ -177,84 +177,85 @@ Put this in `uppercase.vim` and run: >bash
|
||||
==============================================================================
|
||||
5. Using a prompt buffer *prompt-buffer*
|
||||
|
||||
If you want to type input for the job in a Vim window you have a few options:
|
||||
- Use a normal buffer and handle all possible commands yourself.
|
||||
This will be complicated, since there are so many possible commands.
|
||||
- Use a terminal window. This works well if what you type goes directly to
|
||||
the job and the job output is directly displayed in the window.
|
||||
See |terminal|.
|
||||
- Use a window with a prompt buffer. This works well when entering a line for
|
||||
the job in Vim while displaying (possibly filtered) output from the job.
|
||||
Prompt buffers provide a "prompt" interface: they are like regular buffers,
|
||||
except only the last section of the buffer is editable, and the user can
|
||||
"submit" the prompt by hitting Enter. Useful for implementing:
|
||||
|
||||
- chat UI
|
||||
- REPL or shell plugins
|
||||
- advanced "picker" plugins
|
||||
|
||||
A prompt buffer is created by setting 'buftype' to "prompt". You would
|
||||
normally only do that in a newly created buffer.
|
||||
normally only do that in a newly created buffer: >vim
|
||||
|
||||
The user can edit and enter one line of text at the very last line of the
|
||||
buffer. When pressing Enter in the prompt line the callback set with
|
||||
|prompt_setcallback()| is invoked. It would normally send the line to a job.
|
||||
Another callback would receive the output from the job and display it in the
|
||||
buffer, below the prompt (and above the next prompt).
|
||||
:set buftype=prompt
|
||||
|
||||
Only the text in the last line, after the prompt, is editable. The rest of the
|
||||
buffer is not modifiable with Normal mode commands. It can be modified by
|
||||
calling functions, such as |append()|. Using other commands may mess up the
|
||||
buffer.
|
||||
The user can edit and enter text at the end of the buffer. Pressing Enter in
|
||||
the prompt section invokes the |prompt_setcallback()| callback, which is
|
||||
typically expected to process the prompt and show results by appending to the
|
||||
buffer. To input multiline text, use Shift+Enter to add a new line without
|
||||
submitting the prompt, or just |put| or |paste| multiline text.
|
||||
|
||||
After setting 'buftype' to "prompt" Vim does not automatically start Insert
|
||||
mode, use `:startinsert` if you want to enter Insert mode, so that the user
|
||||
can start typing a line.
|
||||
Only the "prompt" part of the buffer user-editable, given by the |':| mark.
|
||||
The rest of the buffer is not modifiable with Normal mode commands, though it
|
||||
can be modified by functions such as |append()|. Using other commands may
|
||||
mess up the buffer.
|
||||
|
||||
The text of the prompt can be set with the |prompt_setprompt()| function. If
|
||||
no prompt is set with |prompt_setprompt()|, "% " is used. You can get the
|
||||
effective prompt text for a buffer, with |prompt_getprompt()|.
|
||||
After setting `buftype=prompt`:
|
||||
- Nvim unsets the 'comments' option.
|
||||
- Nvim does not automatically start Insert mode (use `:startinsert` if you
|
||||
want to enter Insert mode)
|
||||
|
||||
The prompt prefix defaults to "% ", but can be set with |prompt_setprompt()|.
|
||||
You can get the effective prompt prefix for with |prompt_getprompt()|.
|
||||
|
||||
The user can go to Normal mode and navigate through the buffer. This can be
|
||||
useful to see older output or copy text.
|
||||
|
||||
The CTRL-W key can be used to start a window command, such as CTRL-W w to
|
||||
switch to the next window. This also works in Insert mode (use Shift-CTRL-W
|
||||
to delete a word). When leaving the window Insert mode will be stopped. When
|
||||
coming back to the prompt window Insert mode will be restored.
|
||||
By default during prompt insert-mode, the CTRL-W key can be used to start
|
||||
a window command, such as CTRL-W w to switch to the next window. (Use
|
||||
Shift-CTRL-W to delete a word). When leaving the window Insert mode will be
|
||||
stopped. When coming back to the prompt window Insert mode will be restored.
|
||||
|
||||
Any command that starts Insert mode, such as "a", "i", "A" and "I", will move
|
||||
the cursor to the last line. "A" will move to the end of the line, "I" to the
|
||||
start of the line.
|
||||
|
||||
Here is an example for Unix. It starts a shell in the background and prompts
|
||||
for the next shell command. Output from the shell is displayed above the
|
||||
prompt. >vim
|
||||
Example: start a shell in the background and prompt for the next shell
|
||||
command, displaying shell output above the prompt: >vim
|
||||
|
||||
" Function handling a line of text that has been typed.
|
||||
func TextEntered(text)
|
||||
" Send the text to a shell with Enter appended.
|
||||
call chansend(g:shell_job, [a:text, ''])
|
||||
endfunc
|
||||
" Handles a line of user input.
|
||||
func OnSubmit(text)
|
||||
" Send the text to a shell with Enter appended.
|
||||
call chansend(g:shell_job, [a:text, ''])
|
||||
endfunc
|
||||
|
||||
" Function handling output from the shell: Add it above the prompt.
|
||||
func GotOutput(channel, msg, name)
|
||||
call append(line("$") - 1, a:msg)
|
||||
endfunc
|
||||
" Handles output from the shell.
|
||||
func OnOutput(channel, msg, name)
|
||||
" Add shell output above the prompt.
|
||||
call append(line('$') - 1, a:msg)
|
||||
endfunc
|
||||
|
||||
" Function handling the shell exits: close the window.
|
||||
func JobExit(job, status, event)
|
||||
quit!
|
||||
endfunc
|
||||
" Handles the shell exit.
|
||||
func JobExit(job, status, event)
|
||||
quit!
|
||||
endfunc
|
||||
|
||||
" Start a shell in the background.
|
||||
let shell_job = jobstart(["/bin/sh"], #{
|
||||
\ on_stdout: function('GotOutput'),
|
||||
\ on_stderr: function('GotOutput'),
|
||||
\ on_exit: function('JobExit'),
|
||||
\ })
|
||||
" Start a shell in the background.
|
||||
let shell_job = jobstart(['/bin/sh'], #{
|
||||
\ on_stdout: function('OnOutput'),
|
||||
\ on_stderr: function('OnOutput'),
|
||||
\ on_exit: function('JobExit'),
|
||||
\ })
|
||||
|
||||
new
|
||||
set buftype=prompt
|
||||
let buf = bufnr('')
|
||||
call prompt_setcallback(buf, function("TextEntered"))
|
||||
call prompt_setprompt(buf, "shell command: ")
|
||||
new
|
||||
set buftype=prompt
|
||||
let buf = bufnr('')
|
||||
call prompt_setcallback(buf, function('OnSubmit'))
|
||||
call prompt_setprompt(buf, 'shell command: ')
|
||||
|
||||
" start accepting shell commands
|
||||
startinsert
|
||||
" Start accepting shell commands.
|
||||
startinsert
|
||||
<
|
||||
|
||||
vim:tw=78:ts=8:noet:ft=help:norl:
|
||||
vim:tw=78:ts=8:et:sw=4:ft=help:norl:
|
||||
|
@ -388,7 +388,7 @@ CTRL-D List names that match the pattern in front of the cursor.
|
||||
to the end.
|
||||
The 'wildoptions' option can be set to "tagfile" to list the
|
||||
file of matching tags.
|
||||
*c_CTRL-I* *c_wildchar* *c_<Tab>*
|
||||
*c_CTRL-I* *c_wildchar* *c_<Tab>* */_<Tab>*
|
||||
'wildchar' option
|
||||
A match is done on the pattern in front of the cursor. The
|
||||
match (if there are several, the first match) is inserted
|
||||
@ -398,6 +398,10 @@ CTRL-D List names that match the pattern in front of the cursor.
|
||||
again and there were multiple matches, the next
|
||||
match is inserted. After the last match, the first is used
|
||||
again (wrap around).
|
||||
|
||||
In search context use <CTRL-V><Tab> or "\t" to search for a
|
||||
literal <Tab> instead of triggering completion.
|
||||
|
||||
The behavior can be changed with the 'wildmode' option.
|
||||
*c_<S-Tab>*
|
||||
<S-Tab> Like 'wildchar' or <Tab>, but begin with the last match and
|
||||
@ -430,7 +434,7 @@ CTRL-G When 'incsearch' is set, entering a search pattern for "/" or
|
||||
"?" and the current match is displayed then CTRL-G will move
|
||||
to the next match (does not take |search-offset| into account)
|
||||
Use CTRL-T to move to the previous match. Hint: on a regular
|
||||
keyboard T is above G.
|
||||
keyboard G is below T.
|
||||
*c_CTRL-T* */_CTRL-T*
|
||||
CTRL-T When 'incsearch' is set, entering a search pattern for "/" or
|
||||
"?" and the current match is displayed then CTRL-T will move
|
||||
@ -447,6 +451,8 @@ When repeating 'wildchar' or CTRL-N you cycle through the matches, eventually
|
||||
ending up back to what was typed. If the first match is not what you wanted,
|
||||
you can use <S-Tab> or CTRL-P to go straight back to what you typed.
|
||||
|
||||
See also |wildtrigger()|.
|
||||
|
||||
The 'wildmenu' option can be set to show the matches just above the command
|
||||
line.
|
||||
|
||||
@ -564,7 +570,6 @@ that see the '"' as part of their argument:
|
||||
:menu (and the like)
|
||||
:mkspell
|
||||
:normal
|
||||
:ownsyntax
|
||||
:popup
|
||||
:registers
|
||||
:return
|
||||
@ -937,14 +942,6 @@ Note: these are typed literally, they are not special keys!
|
||||
events).
|
||||
When the match is with a file name, it is expanded to the
|
||||
full path.
|
||||
*:<sfile>* *<sfile>*
|
||||
<sfile> When executing a `:source` command, is replaced with the
|
||||
file name of the sourced file. *E498*
|
||||
When executing a function, is replaced with the call stack,
|
||||
as with <stack> (this is for backwards compatibility, using
|
||||
<stack> or <script> is preferred).
|
||||
Note that filename-modifiers are useless when <sfile> is
|
||||
not used inside a script.
|
||||
*:<stack>* *<stack>*
|
||||
<stack> is replaced with the call stack, using
|
||||
"function {function-name}[{lnum}]" for a function line
|
||||
@ -952,7 +949,7 @@ Note: these are typed literally, they are not special keys!
|
||||
".." in between items. E.g.:
|
||||
"function {function-name1}[{lnum}]..{function-name2}[{lnum}]"
|
||||
If there is no call stack you get error *E489* .
|
||||
*:<script>* *<script>*
|
||||
*:<script>* *<script>* *E498*
|
||||
<script> When executing a `:source` command, is replaced with the file
|
||||
name of the sourced file. When executing a function, is
|
||||
replaced with the file name of the script where it is
|
||||
@ -971,7 +968,7 @@ Note: these are typed literally, they are not special keys!
|
||||
*filename-modifiers*
|
||||
*:_%:* *::8* *::p* *::.* *::~* *::h* *::t* *::r* *::e* *::s* *::gs* *::S*
|
||||
*%:8* *%:p* *%:.* *%:~* *%:h* *%:t* *%:r* *%:e* *%:s* *%:gs* *%:S*
|
||||
The file name modifiers can be used after "%", "#", "#n", "<cfile>", "<sfile>",
|
||||
The file name modifiers can be used after "%", "#", "#n", "<cfile>", "<script>",
|
||||
"<afile>" or "<abuf>". They are also used with the |fnamemodify()| function.
|
||||
These modifiers can be given, in this order:
|
||||
:p Make file name a full path. Must be the first modifier. Also
|
||||
|
@ -160,5 +160,4 @@ In WinDbg: choose Open Crash Dump on the File menu. Follow the instructions in
|
||||
Visual Studio 2017 Community Edition can be downloaded for free from:
|
||||
https://visualstudio.microsoft.com/downloads/
|
||||
|
||||
=========================================================================
|
||||
vim:tw=78:ts=8:noet:ft=help:norl:
|
||||
|
@ -12,6 +12,40 @@ They should not be used in new scripts, and old scripts should be updated.
|
||||
==============================================================================
|
||||
Deprecated features
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
DEPRECATED IN 0.12 *deprecated-0.12*
|
||||
|
||||
API
|
||||
|
||||
• todo
|
||||
|
||||
DIAGNOSTICS
|
||||
|
||||
• "float" in |vim.diagnostic.JumpOpts|. Use "on_jump" instead.
|
||||
• "float" in |vim.diagnostic.Opts.Jump|. Use "on_jump" instead.
|
||||
|
||||
HIGHLIGHTS
|
||||
|
||||
• *:ownsyntax* *w:current_syntax* Use 'winhighlight' instead.
|
||||
|
||||
LSP
|
||||
|
||||
• *vim.lsp.client_is_stopped()* Use |vim.lsp.get_client_by_id()| instead.
|
||||
• *vim.lsp.util.stylize_markdown()* Use |vim.treesitter.start()| with
|
||||
`vim.wo.conceallevel = 2`.
|
||||
• *vim.lsp.log.should_log()* Use |vim.lsp.log.set_format_func()| instead
|
||||
and return `nil` to omit entries from the logfile.
|
||||
• *vim.lsp.semantic_tokens.start()* Use `vim.lsp.semantic_tokens.enable(true)` instead
|
||||
• *vim.lsp.semantic_tokens.stop()* Use `vim.lsp.semantic_tokens.enable(false)` instead
|
||||
|
||||
LUA
|
||||
|
||||
• *vim.diff()* Renamed to |vim.text.diff()|
|
||||
|
||||
VIMSCRIPT
|
||||
|
||||
• todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
DEPRECATED IN 0.11 *deprecated-0.11*
|
||||
|
||||
@ -66,7 +100,7 @@ LUA
|
||||
• vim.validate(opts: table) Use form 1. See |vim.validate()|.
|
||||
|
||||
VIMSCRIPT
|
||||
• *termopen()* Use |jobstart() with `{term: v:true}`.
|
||||
• *termopen()* Use |jobstart()| with `{term: v:true}`.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
DEPRECATED IN 0.10 *deprecated-0.10*
|
||||
@ -298,13 +332,12 @@ UI EXTENSIONS
|
||||
• *term_background* Unused. The terminal background color is now detected
|
||||
by the Nvim core directly instead of the TUI.
|
||||
|
||||
VARIABLES
|
||||
VIMSCRIPT
|
||||
• *<sfile>* Use |<script>| or |<stack>| instead.
|
||||
• *b:terminal_job_pid* Use `jobpid(&channel)` instead.
|
||||
• *b:terminal_job_id* Use `&channel` instead. To access in non-current buffer:
|
||||
• Lua: `vim.bo[bufnr].channel`
|
||||
• Vimscript: `getbufvar(bufnr, '&channel')`
|
||||
|
||||
VIMSCRIPT
|
||||
• *buffer_exists()* Obsolete name for |bufexists()|.
|
||||
• *buffer_name()* Obsolete name for |bufname()|.
|
||||
• *buffer_number()* Obsolete name for |bufnr()|.
|
||||
|
@ -901,8 +901,8 @@ Return Values ~
|
||||
|
||||
Do not needlessly surround the `return` expression with parentheses.
|
||||
|
||||
Use parentheses in `return expr`; only where you would use them in `x =
|
||||
expr;`. >c
|
||||
Use parentheses in `return expr;` only where you would also use them in
|
||||
`x = expr;`. >c
|
||||
|
||||
return result;
|
||||
return (some_long_condition && another_condition);
|
||||
|
@ -171,8 +171,8 @@ USING GDBSERVER IN TMUX
|
||||
Consider using a custom makefile
|
||||
https://github.com/neovim/neovim/blob/master/BUILD.md#custom-makefile to
|
||||
quickly start debugging sessions using the `gdbserver` method mentioned above.
|
||||
This example `local.mk` will create the debugging session when you type `make
|
||||
debug`.
|
||||
This example `local.mk` will create the debugging session when you type
|
||||
`make debug`.
|
||||
>make
|
||||
.PHONY: dbg-start dbg-attach debug build
|
||||
|
||||
|
@ -311,7 +311,7 @@ Nvim's filetype detection behavior matches Vim, but is implemented as part of
|
||||
|vim.filetype| (see `$VIMRUNTIME/lua/vim/filetype.lua`). The logic is encoded in
|
||||
three tables, listed in order of precedence (the first match is returned):
|
||||
1. `filename` for literal full path or basename lookup;
|
||||
2. `pattern` for matching filenames or paths against |lua-patterns|, optimized
|
||||
2. `pattern` for matching filenames or paths against |lua-pattern|s, optimized
|
||||
for fast lookup;
|
||||
3. `extension` for literal extension lookup.
|
||||
|
||||
|
@ -201,7 +201,7 @@ Docstring format:
|
||||
- Markdown is supported.
|
||||
- Tags are written as `[tag]()`.
|
||||
- References are written as `[tag]`
|
||||
- Use ``` for code samples.
|
||||
- Use "```" for code samples.
|
||||
Code samples can be annotated as `vim` or `lua`
|
||||
|
||||
Example: the help for |nvim_open_win()| is generated from a docstring defined
|
||||
@ -245,7 +245,7 @@ Docstring format:
|
||||
- Markdown is supported.
|
||||
- Tags are written as `[tag]()`.
|
||||
- References are written as `[tag]`
|
||||
- Use ``` for code samples.
|
||||
- Use "```" for code samples.
|
||||
Code samples can be annotated as `vim` or `lua`
|
||||
- Use `@since <api-level>` to note the |api-level| when the function became
|
||||
"stable". If `<api-level>` is greater than the current stable release (or
|
||||
@ -426,6 +426,9 @@ Use existing common {verb} names (actions) if possible:
|
||||
- add: Appends or inserts into a collection
|
||||
- attach: Listens to something to get events from it (TODO: rename to "on"?)
|
||||
- call: Calls a function
|
||||
- callback Continuation callback: a single function parameter (not
|
||||
a field) that returns the result of an async function. Use
|
||||
"on_…" for all other callbacks and event handlers.
|
||||
- cancel: Cancels or dismisses an event or interaction, typically
|
||||
user-initiated and without error. (Compare "abort", which
|
||||
cancels and signals error/failure.)
|
||||
@ -441,8 +444,11 @@ Use existing common {verb} names (actions) if possible:
|
||||
- get: Gets things. Two variants (overloads):
|
||||
1. `get<T>(id: int): T` returns one item.
|
||||
2. `get<T>(filter: dict): T[]` returns a list.
|
||||
- has: Checks for the presence of an item, feature, etc.
|
||||
- inspect: Presents a high-level, often interactive, view
|
||||
- is_enabled: Checks if functionality is enabled.
|
||||
- on_…: Handles events or async results, or registers such
|
||||
a handler. |dev-name-events|
|
||||
- open: Opens something (a buffer, window, …)
|
||||
- parse: Parses something into a structured form
|
||||
- set: Sets a thing (or group of things)
|
||||
@ -452,6 +458,7 @@ Use existing common {verb} names (actions) if possible:
|
||||
- try_{verb}: Best-effort operation, failure returns null or error obj
|
||||
|
||||
Do NOT use these deprecated verbs:
|
||||
- contains: Prefer "has".
|
||||
- disable: Prefer `enable(enable: boolean)`.
|
||||
- exit: Prefer "cancel" (or "stop" if appropriate).
|
||||
- is_disabled: Prefer `is_enabled()`.
|
||||
@ -475,7 +482,6 @@ everywhere, not "buffer" in some places and "buf" in others.
|
||||
|
||||
Do NOT use these deprecated nouns:
|
||||
- buffer Use "buf" instead
|
||||
- callback Use on_foo instead
|
||||
- command Use "cmd" instead
|
||||
- window Use "win" instead
|
||||
|
||||
@ -666,6 +672,8 @@ External UIs are expected to implement these common features:
|
||||
the user).
|
||||
- Support the text decorations/attributes given by |ui-event-hl_attr_define|.
|
||||
The "url" attr should be presented as a clickable hyperlink.
|
||||
- Handle the "restart" UI event so that |:restart| works.
|
||||
- Detect capslock and show an indicator if capslock is active.
|
||||
|
||||
|
||||
vim:tw=78:ts=8:sw=4:et:ft=help:norl:
|
||||
|
@ -69,6 +69,16 @@ Functions that take a severity as an optional parameter (e.g.
|
||||
<
|
||||
This form allows users to filter for specific severities
|
||||
|
||||
==============================================================================
|
||||
DEFAULTS *diagnostic-defaults*
|
||||
|
||||
These diagnostic keymaps are created unconditionally when Nvim starts:
|
||||
- `]d` jumps to the next diagnostic in the buffer. |]d-default|
|
||||
- `[d` jumps to the previous diagnostic in the buffer. |[d-default|
|
||||
- `]D` jumps to the last diagnostic in the buffer. |]D-default|
|
||||
- `[D` jumps to the first diagnostic in the buffer. |[D-default|
|
||||
- `<C-w>d` shows diagnostic at cursor in a floating window. |CTRL-W_d-default|
|
||||
|
||||
==============================================================================
|
||||
HANDLERS *diagnostic-handlers*
|
||||
|
||||
@ -180,6 +190,28 @@ the `virtual_lines` handler with the following keymap: >lua
|
||||
end, { desc = 'Toggle diagnostic virtual_lines' })
|
||||
<
|
||||
|
||||
*diagnostic-on-jump-example*
|
||||
You can use the `on_jump` option from |vim.diagnostic.jump()| to show the
|
||||
diagnostic that was jumped to using a specific handler. For example, the
|
||||
following uses the `virtual_lines` handler when jumping to a diagnostic: >lua
|
||||
|
||||
local virt_lines_ns = vim.api.nvim_create_namespace 'on_diagnostic_jump'
|
||||
|
||||
--- @param diagnostic? vim.Diagnostic
|
||||
--- @param bufnr integer
|
||||
local function on_jump(diagnostic, bufnr)
|
||||
if not diagnostic then return end
|
||||
|
||||
vim.diagnostic.show(
|
||||
virt_lines_ns,
|
||||
bufnr,
|
||||
{ diagnostic },
|
||||
{ virtual_lines = { current_line = true }, virtual_text = false }
|
||||
)
|
||||
end
|
||||
|
||||
vim.diagnostic.config({ jump = { on_jump = on_jump } })
|
||||
<
|
||||
*diagnostic-loclist-example*
|
||||
Whenever the |location-list| is opened, the following `show` handler will show
|
||||
the most recent diagnostics: >lua
|
||||
@ -269,6 +301,26 @@ DiagnosticVirtualTextHint
|
||||
DiagnosticVirtualTextOk
|
||||
Used for "Ok" diagnostic virtual text.
|
||||
|
||||
*hl-DiagnosticVirtualLinesError*
|
||||
DiagnosticVirtualLinesError
|
||||
Used for "Error" diagnostic virtual lines.
|
||||
|
||||
*hl-DiagnosticVirtualLinesWarn*
|
||||
DiagnosticVirtualLinesWarn
|
||||
Used for "Warn" diagnostic virtual lines.
|
||||
|
||||
*hl-DiagnosticVirtualLinesInfo*
|
||||
DiagnosticVirtualLinesInfo
|
||||
Used for "Info" diagnostic virtual lines.
|
||||
|
||||
*hl-DiagnosticVirtualLinesHint*
|
||||
DiagnosticVirtualLinesHint
|
||||
Used for "Hint" diagnostic virtual lines.
|
||||
|
||||
*hl-DiagnosticVirtualLinesOk*
|
||||
DiagnosticVirtualLinesOk
|
||||
Used for "Ok" diagnostic virtual lines.
|
||||
|
||||
*hl-DiagnosticUnderlineError*
|
||||
DiagnosticUnderlineError
|
||||
Used to underline "Error" diagnostics.
|
||||
@ -388,27 +440,43 @@ Example: >lua
|
||||
Lua module: vim.diagnostic *diagnostic-api*
|
||||
|
||||
*vim.Diagnostic*
|
||||
Extends: |vim.Diagnostic.Set|
|
||||
|
||||
*diagnostic-structure*
|
||||
|
||||
Diagnostics use the same indexing as the rest of the Nvim API (i.e.
|
||||
0-based rows and columns). |api-indexing|
|
||||
|
||||
Fields: ~
|
||||
• {bufnr}? (`integer`) Buffer number
|
||||
• {lnum} (`integer`) The starting line of the diagnostic
|
||||
(0-indexed)
|
||||
• {end_lnum}? (`integer`) The final line of the diagnostic (0-indexed)
|
||||
• {bufnr} (`integer`) Buffer number
|
||||
• {end_lnum} (`integer`) The final line of the diagnostic (0-indexed)
|
||||
• {col} (`integer`) The starting column of the diagnostic
|
||||
(0-indexed)
|
||||
• {end_col}? (`integer`) The final column of the diagnostic
|
||||
• {end_col} (`integer`) The final column of the diagnostic
|
||||
(0-indexed)
|
||||
• {severity}? (`vim.diagnostic.Severity`) The severity of the
|
||||
• {severity} (`vim.diagnostic.Severity`) The severity of the
|
||||
diagnostic |vim.diagnostic.severity|
|
||||
• {namespace}? (`integer`)
|
||||
|
||||
*vim.Diagnostic.Set*
|
||||
Diagnostics use the same indexing as the rest of the Nvim API (i.e.
|
||||
0-based rows and columns). |api-indexing|
|
||||
|
||||
Fields: ~
|
||||
• {lnum} (`integer`) The starting line of the diagnostic
|
||||
(0-indexed)
|
||||
• {col}? (`integer`, default: `0`) The starting column of the
|
||||
diagnostic (0-indexed)
|
||||
• {end_lnum}? (`integer`, default: `lnum`) The final line of the
|
||||
diagnostic (0-indexed)
|
||||
• {end_col}? (`integer`, default: `col`) The final column of the
|
||||
diagnostic (0-indexed)
|
||||
• {severity}? (`vim.diagnostic.Severity`, default: `vim.diagnostic.severity.ERROR`)
|
||||
The severity of the diagnostic |vim.diagnostic.severity|
|
||||
• {message} (`string`) The diagnostic text
|
||||
• {source}? (`string`) The source of the diagnostic
|
||||
• {code}? (`string|integer`) The diagnostic code
|
||||
• {user_data}? (`any`) arbitrary data plugins can add
|
||||
• {namespace}? (`integer`)
|
||||
|
||||
*vim.diagnostic.GetOpts*
|
||||
A table with the following keys:
|
||||
@ -420,6 +488,9 @@ Lua module: vim.diagnostic *diagnostic-api*
|
||||
specified line number.
|
||||
• {severity}? (`vim.diagnostic.SeverityFilter`) See
|
||||
|diagnostic-severity|.
|
||||
• {enabled}? (`boolean`, default: `nil`) Limit diagnostics to only
|
||||
enabled or disabled. If nil, enablement is ignored. See
|
||||
|vim.diagnostic.enable()|
|
||||
|
||||
*vim.diagnostic.JumpOpts*
|
||||
Extends: |vim.diagnostic.GetOpts|
|
||||
@ -445,13 +516,9 @@ Lua module: vim.diagnostic *diagnostic-api*
|
||||
file or not. Similar to 'wrapscan'.
|
||||
• {severity}? (`vim.diagnostic.SeverityFilter`) See
|
||||
|diagnostic-severity|.
|
||||
• {float}? (`boolean|vim.diagnostic.Opts.Float`, default: `false`)
|
||||
If `true`, call |vim.diagnostic.open_float()| after
|
||||
moving. If a table, pass the table as the {opts}
|
||||
parameter to |vim.diagnostic.open_float()|. Unless
|
||||
overridden, the float will show diagnostics at the new
|
||||
cursor position (as if "cursor" were passed to the
|
||||
"scope" option).
|
||||
• {on_jump}? (`fun(diagnostic:vim.Diagnostic?, bufnr:integer)`)
|
||||
Optional callback invoked with the diagnostic that was
|
||||
jumped to.
|
||||
• {winid}? (`integer`, default: `0`) Window ID
|
||||
|
||||
*vim.diagnostic.NS*
|
||||
@ -505,7 +572,8 @@ Lua module: vim.diagnostic *diagnostic-api*
|
||||
Fields: ~
|
||||
• {bufnr}? (`integer`, default: current buffer) Buffer number
|
||||
to show diagnostics from.
|
||||
• {namespace}? (`integer`) Limit diagnostics to the given namespace
|
||||
• {namespace}? (`integer|integer[]`) Limit diagnostics to the given
|
||||
namespace(s).
|
||||
• {scope}? (`'line'|'buffer'|'cursor'|'c'|'l'|'b'`, default:
|
||||
`line`) Show diagnostics from the whole buffer
|
||||
(`buffer"`, the current cursor line (`line`), or the
|
||||
@ -563,8 +631,8 @@ Lua module: vim.diagnostic *diagnostic-api*
|
||||
*vim.diagnostic.Opts.Jump*
|
||||
|
||||
Fields: ~
|
||||
• {float}? (`boolean|vim.diagnostic.Opts.Float`, default: false)
|
||||
Default value of the {float} parameter of
|
||||
• {on_jump}? (`fun(diagnostic:vim.Diagnostic?, bufnr:integer)`)
|
||||
Default value of the {on_jump} parameter of
|
||||
|vim.diagnostic.jump()|.
|
||||
• {wrap}? (`boolean`, default: true) Default value of the {wrap}
|
||||
parameter of |vim.diagnostic.jump()|.
|
||||
@ -574,8 +642,8 @@ Lua module: vim.diagnostic *diagnostic-api*
|
||||
*vim.diagnostic.Opts.Signs*
|
||||
|
||||
Fields: ~
|
||||
• {severity}? (`vim.diagnostic.SeverityFilter`) Only show virtual text
|
||||
for diagnostics matching the given severity
|
||||
• {severity}? (`vim.diagnostic.SeverityFilter`) Only show signs for
|
||||
diagnostics matching the given severity
|
||||
|diagnostic-severity|
|
||||
• {priority}? (`integer`, default: `10`) Base priority to use for
|
||||
signs. When {severity_sort} is used, the priority of a
|
||||
@ -607,6 +675,9 @@ Lua module: vim.diagnostic *diagnostic-api*
|
||||
*vim.diagnostic.Opts.VirtualLines*
|
||||
|
||||
Fields: ~
|
||||
• {severity}? (`vim.diagnostic.SeverityFilter`) Only show virtual
|
||||
lines for diagnostics matching the given severity
|
||||
|diagnostic-severity|
|
||||
• {current_line}? (`boolean`, default: `false`) Only show diagnostics
|
||||
for the current line.
|
||||
• {format}? (`fun(diagnostic:vim.Diagnostic): string?`) A
|
||||
@ -621,8 +692,12 @@ Lua module: vim.diagnostic *diagnostic-api*
|
||||
• {severity}? (`vim.diagnostic.SeverityFilter`) Only show
|
||||
virtual text for diagnostics matching the given
|
||||
severity |diagnostic-severity|
|
||||
• {current_line}? (`boolean`) Only show diagnostics for the
|
||||
current line. (default `false`)
|
||||
• {current_line}? (`boolean`) Show or hide diagnostics based on
|
||||
the current cursor line. If `true`, only
|
||||
diagnostics on the current cursor line are
|
||||
shown. If `false`, all diagnostics are shown
|
||||
except on the current cursor line. If `nil`, all
|
||||
diagnostics are shown. (default `nil`)
|
||||
• {source}? (`boolean|"if_many"`) Include the diagnostic
|
||||
source in virtual text. Use `'if_many'` to only
|
||||
show sources if there is more than one
|
||||
@ -881,7 +956,7 @@ set({namespace}, {bufnr}, {diagnostics}, {opts}) *vim.diagnostic.set()*
|
||||
Parameters: ~
|
||||
• {namespace} (`integer`) The diagnostic namespace
|
||||
• {bufnr} (`integer`) Buffer number
|
||||
• {diagnostics} (`vim.Diagnostic[]`) See |vim.Diagnostic|.
|
||||
• {diagnostics} (`vim.Diagnostic.Set[]`) See |vim.Diagnostic.Set|.
|
||||
• {opts} (`vim.diagnostic.Opts?`) Display options to pass to
|
||||
|vim.diagnostic.show()|. See |vim.diagnostic.Opts|.
|
||||
|
||||
@ -890,8 +965,8 @@ setloclist({opts}) *vim.diagnostic.setloclist()*
|
||||
|
||||
Parameters: ~
|
||||
• {opts} (`table?`) Configuration table with the following keys:
|
||||
• {namespace}? (`integer`) Only add diagnostics from the given
|
||||
namespace.
|
||||
• {namespace}? (`integer[]|integer`) Only add diagnostics from
|
||||
the given namespace(s).
|
||||
• {winnr}? (`integer`, default: `0`) Window number to set
|
||||
location list for.
|
||||
• {open}? (`boolean`, default: `true`) Open the location list
|
||||
@ -900,14 +975,19 @@ setloclist({opts}) *vim.diagnostic.setloclist()*
|
||||
"Diagnostics".
|
||||
• {severity}? (`vim.diagnostic.SeverityFilter`) See
|
||||
|diagnostic-severity|.
|
||||
• {format}? (`fun(diagnostic:vim.Diagnostic): string?`) A
|
||||
function that takes a diagnostic as input and returns a
|
||||
string or nil. If the return value is nil, the diagnostic is
|
||||
not displayed in the location list. Else the output text is
|
||||
used to display the diagnostic.
|
||||
|
||||
setqflist({opts}) *vim.diagnostic.setqflist()*
|
||||
Add all diagnostics to the quickfix list.
|
||||
|
||||
Parameters: ~
|
||||
• {opts} (`table?`) Configuration table with the following keys:
|
||||
• {namespace}? (`integer`) Only add diagnostics from the given
|
||||
namespace.
|
||||
• {namespace}? (`integer[]|integer`) Only add diagnostics from
|
||||
the given namespace(s).
|
||||
• {open}? (`boolean`, default: `true`) Open quickfix list
|
||||
after setting.
|
||||
• {title}? (`string`) Title of quickfix list. Defaults to
|
||||
@ -915,6 +995,11 @@ setqflist({opts}) *vim.diagnostic.setqflist()*
|
||||
title, it's updated. If not, a new quickfix list is created.
|
||||
• {severity}? (`vim.diagnostic.SeverityFilter`) See
|
||||
|diagnostic-severity|.
|
||||
• {format}? (`fun(diagnostic:vim.Diagnostic): string?`) A
|
||||
function that takes a diagnostic as input and returns a
|
||||
string or nil. If the return value is nil, the diagnostic is
|
||||
not displayed in the quickfix list. Else the output text is
|
||||
used to display the diagnostic.
|
||||
|
||||
*vim.diagnostic.show()*
|
||||
show({namespace}, {bufnr}, {diagnostics}, {opts})
|
||||
|
@ -214,14 +214,28 @@ The diffs are highlighted with these groups:
|
||||
|hl-DiffAdd| DiffAdd Added (inserted) lines. These lines exist in
|
||||
this buffer but not in another.
|
||||
|hl-DiffChange| DiffChange Changed lines.
|
||||
|hl-DiffText| DiffText Changed text inside a Changed line. Vim
|
||||
finds the first character that is different,
|
||||
and the last character that is different
|
||||
(searching from the end of the line). The
|
||||
text in between is highlighted. This means
|
||||
that parts in the middle that are still the
|
||||
same are highlighted anyway. The 'diffopt'
|
||||
flags "iwhite" and "icase" are used here.
|
||||
|hl-DiffText| DiffText Changed text inside a Changed line. Exact
|
||||
behavior depends on the `inline:` setting in
|
||||
'diffopt'.
|
||||
With `inline:` set to "simple", Vim finds the
|
||||
first character that is different, and the
|
||||
last character that is different (searching
|
||||
from the end of the line). The text in
|
||||
between is highlighted. This means that parts
|
||||
in the middle that are still the same are
|
||||
highlighted anyway. The 'diffopt' flags
|
||||
"iwhite" and "icase" are used here.
|
||||
With `inline:` set to "char" or "word", Vim
|
||||
uses the internal diff library to perform a
|
||||
detailed diff between the changed blocks and
|
||||
highlight the exact difference between the
|
||||
two. Will respect any 'diffopt' flag that
|
||||
affects internal diff.
|
||||
Not used when `inline:` is set to "none".
|
||||
|hl-DiffTextAdd| DiffTextAdd Added text inside a Changed line. Similar to
|
||||
DiffText, but used when there is no
|
||||
corresponding text in other buffers. Not used
|
||||
when `inline:` is set to "simple" or "none".
|
||||
|hl-DiffDelete| DiffDelete Deleted lines. Also called filler lines,
|
||||
because they don't really exist in this
|
||||
buffer.
|
||||
@ -278,18 +292,20 @@ that the buffers will be equal within the specified range.
|
||||
|
||||
|
||||
When no [range] is given, the diff at the cursor position or just above it is
|
||||
affected. When [range] is used, Vim tries to only put or get the specified
|
||||
lines. When there are deleted lines, this may not always be possible.
|
||||
affected. There can be deleted lines below the last line of the buffer. When
|
||||
the cursor is on the last line in the buffer and there is no diff above this
|
||||
line, and no [range] is given, the diff below the cursor position will be used
|
||||
instead.
|
||||
|
||||
There can be deleted lines below the last line of the buffer. When the cursor
|
||||
is on the last line in the buffer and there is no diff above this line, the
|
||||
":diffget" and "do" commands will obtain lines from the other buffer.
|
||||
When [range] is used, Vim tries to only put or get the specified lines. When
|
||||
there are deleted lines, they will be used if they are between the lines
|
||||
specified by [range].
|
||||
|
||||
To be able to get those lines from another buffer in a [range] it's allowed to
|
||||
use the last line number plus one. This command gets all diffs from the other
|
||||
buffer: >
|
||||
To be able to put or get those lines to/from another buffer in a [range] it's
|
||||
allowed to use 0 and the last line number plus one. This command gets all
|
||||
diffs from the other buffer: >
|
||||
|
||||
:1,$+1diffget
|
||||
:0,$+1diffget
|
||||
|
||||
Note that deleted lines are displayed, but not counted as text lines. You
|
||||
can't move the cursor into them. To fill the deleted lines with the lines
|
||||
@ -308,7 +324,129 @@ name or a part of a buffer name. Examples:
|
||||
diff mode (e.g., "file.c.v2")
|
||||
|
||||
==============================================================================
|
||||
5. Diff options *diff-options*
|
||||
5. Diff anchors *diff-anchors*
|
||||
|
||||
Diff anchors allow you to control where the diff algorithm aligns and
|
||||
synchronize text across files. Each anchor matches each other in each file,
|
||||
allowing you to control the output of a diff.
|
||||
|
||||
This is useful when a change involves complicated edits. For example, if a
|
||||
function was moved to another location and further edited. By default, the
|
||||
algorithm aims to create the smallest diff, which results in that entire
|
||||
function being considered to be deleted and added on the other side, making it
|
||||
hard to see what the actual edit on it was. You can use diff anchors to pin
|
||||
that function so the diff algorithm will align based on it.
|
||||
|
||||
To use it, set anchors using 'diffanchors' which is a comma-separated list of
|
||||
{address} in each file, and then add "anchor" to 'diffopt'. Internaly, Vim
|
||||
splits each file up into sections split by the anchors. It performs the diff
|
||||
on each pair of sections separately before merging the results back.
|
||||
|
||||
Setting 'diffanchors' will update the diff immediately. If an anchor is tied
|
||||
to a mark, and you change what the mark is pointed to, you need to manually
|
||||
call |:diffupdate| afterwards to get the updated diff results.
|
||||
|
||||
Example:
|
||||
|
||||
Let's say we have the following files, side-by-side. We are interested in the
|
||||
change that happened to the function `foo()`, which was both edited and moved.
|
||||
|
||||
File A: >
|
||||
int foo() {
|
||||
int n = 1;
|
||||
return n;
|
||||
}
|
||||
|
||||
int g = 1;
|
||||
|
||||
int bar(int a) {
|
||||
a *= 2;
|
||||
a += 3;
|
||||
return a;
|
||||
}
|
||||
<File B: >
|
||||
int bar(int a) {
|
||||
a *= 2;
|
||||
a += 3;
|
||||
return a;
|
||||
}
|
||||
|
||||
int foo() {
|
||||
int n = 999;
|
||||
return n;
|
||||
}
|
||||
|
||||
int g = 1;
|
||||
<
|
||||
A normal diff will usually align the diff result as such: >
|
||||
|
||||
int foo() { |----------------
|
||||
int n = 1; |----------------
|
||||
return n; |----------------
|
||||
} |----------------
|
||||
|----------------
|
||||
int g = 1; |----------------
|
||||
|----------------
|
||||
int bar(int a) {|int bar(int a) {
|
||||
a *= 2; | a *= 2;
|
||||
a += 3; | a += 3;
|
||||
return a; | return a;
|
||||
} |}
|
||||
----------------|
|
||||
----------------|int foo() {
|
||||
----------------| int n = 999;
|
||||
----------------| return n;
|
||||
----------------|}
|
||||
----------------|
|
||||
----------------|int g = 1;
|
||||
<
|
||||
What we want is to instead ask the diff to align on `foo()`: >
|
||||
|
||||
----------------|int bar(int a) {
|
||||
----------------| a *= 2;
|
||||
----------------| a += 3;
|
||||
----------------| return a;
|
||||
----------------|}
|
||||
----------------|
|
||||
int foo() { |int foo() {
|
||||
int n = 1; | int n = 999;
|
||||
return n; | return n;
|
||||
} |}
|
||||
|
|
||||
int g = 1; |int g = 1;
|
||||
|----------------
|
||||
int bar(int a) {|----------------
|
||||
a *= 2; |----------------
|
||||
a += 3; |----------------
|
||||
return a; |----------------
|
||||
} |----------------
|
||||
<
|
||||
|
||||
Below are some ways of setting diff anchors to get the above result. In each
|
||||
example, 'diffopt' needs to have `anchor` set for this to take effect.
|
||||
|
||||
Marks: Set the |'a| mark on the `int foo()` lines in each file first before
|
||||
setting the anchors: >
|
||||
set diffanchors='a
|
||||
|
||||
Pattern: Specify the anchor using a |pattern| (see |:/|). Here, we make sure
|
||||
to always start search from line 1 for consistency: >
|
||||
set diffanchors=1/int\ foo(/
|
||||
<
|
||||
Selection: Use visual mode to select the entire `foo()` function body in each
|
||||
file. Here, we use two anchors. This does a better job of making sure only
|
||||
the function bodies are anchored against each other but not the lines after
|
||||
it. Note the `'>+1` below. The "+1" is necessary as we want the split to
|
||||
happen below the last line of the function, not above: >
|
||||
set diffanchors='<,'>+1
|
||||
<
|
||||
Manually set two anchors using line numbers via buffer-local options: >
|
||||
setlocal diffanchors=1,5
|
||||
wincmd w
|
||||
setlocal diffanchors=7,11
|
||||
<
|
||||
==============================================================================
|
||||
6. Diff options *diff-options*
|
||||
|
||||
Also see |'diffopt'| and the "diff" item of |'fillchars'|.
|
||||
|
||||
|
@ -630,7 +630,7 @@ list of the current window.
|
||||
buffer.
|
||||
Also see |++opt| and |+cmd|.
|
||||
|
||||
:[count]arge[dit][!] [++opt] [+cmd] {name} .. *:arge* *:argedit*
|
||||
:[count]arge[dit][!] [++opt] [+cmd] {name} ... *:arge* *:argedit*
|
||||
Add {name}s to the argument list and edit it.
|
||||
There is no check for duplicates, it is possible to
|
||||
add a file to the argument list twice |:argded|.
|
||||
@ -645,7 +645,7 @@ list of the current window.
|
||||
edited. No check for duplicates is done.
|
||||
Also see |++opt| and |+cmd|.
|
||||
|
||||
:[count]arga[dd] {name} .. *:arga* *:argadd* *E479*
|
||||
:[count]arga[dd] {name} ... *:arga* *:argadd* *E479*
|
||||
:[count]arga[dd] *E1156*
|
||||
Add the {name}s to the argument list. When {name} is
|
||||
omitted add the current buffer name to the argument
|
||||
@ -676,7 +676,7 @@ list of the current window.
|
||||
If your current file is a duplicate, your current file
|
||||
will change to the original file index.
|
||||
|
||||
:argd[elete] {pattern} .. *:argd* *:argdelete* *E480* *E610*
|
||||
:argd[elete] {pattern} ... *:argd* *:argdelete* *E480* *E610*
|
||||
Delete files from the argument list that match the
|
||||
{pattern}s. {pattern} is used like a file pattern,
|
||||
see |file-pattern|. "%" can be used to delete the
|
||||
@ -714,11 +714,14 @@ list of the current window.
|
||||
omitted the current entry is used.
|
||||
Also see |++opt| and |+cmd|.
|
||||
|
||||
:[count]n[ext] [++opt] [+cmd] *:n* *:ne* *:next* *]a* *E165* *E163*
|
||||
:[count]n[ext] [++opt] [+cmd] *:n* *:ne* *:next* *E165* *E163*
|
||||
Edit [count] next file. This fails when changes have
|
||||
been made and Vim does not want to |abandon| the
|
||||
current buffer. Also see |++opt| and |+cmd|.
|
||||
|
||||
*]a*
|
||||
]a Mapped to |:next|. |default-mappings|
|
||||
|
||||
:[count]n[ext]! [++opt] [+cmd]
|
||||
Edit [count] next file, discard any changes to the
|
||||
buffer. Also see |++opt| and |+cmd|.
|
||||
@ -740,16 +743,22 @@ list of the current window.
|
||||
any changes to the buffer. Also see |++opt| and
|
||||
|+cmd|.
|
||||
|
||||
:[count]prev[ious] [count] [++opt] [+cmd] *:prev* *:previous* *[a*
|
||||
:[count]prev[ious] [count] [++opt] [+cmd] *:prev* *:previous*
|
||||
Same as :Next. Also see |++opt| and |+cmd|.
|
||||
|
||||
*:rew* *:rewind* *[A*
|
||||
*[a*
|
||||
[a Mapped to |:previous|. |default-mappings|
|
||||
|
||||
*:rew* *:rewind*
|
||||
:rew[ind] [++opt] [+cmd]
|
||||
Start editing the first file in the argument list.
|
||||
This fails when changes have been made and Vim does
|
||||
not want to |abandon| the current buffer.
|
||||
Also see |++opt| and |+cmd|.
|
||||
|
||||
*[A*
|
||||
[A Mapped to |:rewind|. |default-mappings|
|
||||
|
||||
:rew[ind]! [++opt] [+cmd]
|
||||
Start editing the first file in the argument list.
|
||||
Discard any changes to the buffer. Also see |++opt|
|
||||
@ -759,13 +768,16 @@ list of the current window.
|
||||
:fir[st][!] [++opt] [+cmd]
|
||||
Other name for ":rewind".
|
||||
|
||||
*:la* *:last* *]A*
|
||||
*:la* *:last*
|
||||
:la[st] [++opt] [+cmd]
|
||||
Start editing the last file in the argument list.
|
||||
This fails when changes have been made and Vim does
|
||||
not want to |abandon| the current buffer.
|
||||
Also see |++opt| and |+cmd|.
|
||||
|
||||
*]A*
|
||||
]A Mapped to |:last|. |default-mappings|
|
||||
|
||||
:la[st]! [++opt] [+cmd]
|
||||
Start editing the last file in the argument list.
|
||||
Discard any changes to the buffer. Also see |++opt|
|
||||
@ -948,8 +960,9 @@ Note: When the 'write' option is off, you are not able to write any file.
|
||||
executed like with ":!{cmd}", any '!' is replaced with
|
||||
the previous command |:!|.
|
||||
|
||||
The default [range] for the ":w" command is the whole buffer (1,$). If you
|
||||
write the whole buffer, it is no longer considered changed. When you
|
||||
The default [range] for the ":w" command is the whole buffer (1,$). The |'[|
|
||||
and |']| marks will be set to the [range] being used for the write command.
|
||||
If you write the whole buffer, it is no longer considered changed. When you
|
||||
write it to a different file with ":w somefile" it depends on the "+" flag in
|
||||
'cpoptions'. When included, the write command will reset the 'modified' flag,
|
||||
even though the buffer itself may still be different from its file.
|
||||
@ -1303,9 +1316,15 @@ b:browsefilter variable. You would most likely set b:browsefilter in a
|
||||
filetype plugin, so that the browse dialog would contain entries related to
|
||||
the type of file you are currently editing. Disadvantage: This makes it
|
||||
difficult to start editing a file of a different type. To overcome this, you
|
||||
may want to add "All Files (*.*)\t*\n" as the final filter on Windows or "All
|
||||
Files (*)\t*\n" on other platforms, so that the user can still access any
|
||||
desired file.
|
||||
can add the following as the final filter on Windows: >
|
||||
|
||||
All Files\t(*.*)\t*\n
|
||||
<
|
||||
Or the following on other platforms, so that the user can still access any
|
||||
desired file: >
|
||||
|
||||
All Files\t(*)\t*\n
|
||||
<
|
||||
|
||||
To avoid setting browsefilter when Vim does not actually support it, you can
|
||||
use has("browsefilter"): >
|
||||
|
@ -205,17 +205,11 @@ Other hints:
|
||||
|
||||
:CHECKHEALTH REPORTS E5009: INVALID $VIMRUNTIME ~
|
||||
|
||||
This means `health#check()` couldn't load, which suggests that |$VIMRUNTIME|
|
||||
or 'runtimepath' is broken.
|
||||
This means |$VIMRUNTIME| or 'runtimepath' is broken.
|
||||
|
||||
- |$VIMRUNTIME| must point to Nvim's runtime files, not Vim's.
|
||||
- The |$VIMRUNTIME| directory contents should be readable by the current user.
|
||||
- Verify that `:echo &runtimepath` contains the $VIMRUNTIME path.
|
||||
- Check the output of: >vim
|
||||
|
||||
:call health#check()
|
||||
:verbose func health#check
|
||||
<
|
||||
|
||||
NEOVIM CAN'T FIND ITS RUNTIME ~
|
||||
|
||||
@ -456,10 +450,7 @@ grow and enhance it. Changing the rules of Lua gains nothing in this context.
|
||||
|
||||
WILL NEOVIM TRANSLATE VIMSCRIPT TO LUA, INSTEAD OF EXECUTING VIMSCRIPT DIRECTLY? ~
|
||||
|
||||
- We are experimenting with vim9jit https://github.com/tjdevries/vim9jit to
|
||||
transpile Vim9script (Vim9's Vimscript variant) to Lua and have used this to
|
||||
port Vim9 plugins https://github.com/neovim/neovim/pull/21662 to Nvim Lua.
|
||||
- We have no plans for transpiling legacy Vimscript.
|
||||
We have no plans for transpiling Vimscript. It was explored in https://github.com/tjdevries/vim9jit
|
||||
|
||||
|
||||
ARE PLUGIN AUTHORS ENCOURAGED TO PORT THEIR PLUGINS FROM VIMSCRIPT TO LUA? DO YOU PLAN ON SUPPORTING VIMSCRIPT INDEFINITELY? (#1152) ~
|
||||
@ -474,4 +465,8 @@ emphatically a fork of Vim in order to leverage the work already spent on
|
||||
thousands of Vim plugins, while enabling new types of plugins and
|
||||
integrations.
|
||||
|
||||
That being said, reimplementing legacy plugins in Lua in order to make use of
|
||||
Nvim API and to integrate with Nvim-specific features such as treesitter can
|
||||
be worthwhile.
|
||||
|
||||
vim:tw=78:ts=8:noet:ft=help:norl:
|
||||
|
@ -156,6 +156,8 @@ variables can be used to overrule the filetype used for certain extensions:
|
||||
`*.inc` g:filetype_inc
|
||||
`*.lsl` g:filetype_lsl
|
||||
`*.m` g:filetype_m |ft-mathematica-syntax|
|
||||
`*[mM]makefile,*.mk,*.mak,[mM]akefile*`
|
||||
g:make_flavor |ft-make-syntax|
|
||||
`*.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md`
|
||||
g:filetype_md |ft-pandoc-syntax|
|
||||
`*.mod` g:filetype_mod
|
||||
@ -262,7 +264,7 @@ D. If your filetype can only be detected by inspecting the contents of the
|
||||
item of the 'runtimepath' option. Example for Unix: >
|
||||
:!mkdir -p ~/.config/nvim
|
||||
<
|
||||
2. Create a vim script file for doing this. Example: >
|
||||
2. Create a Vim script file for doing this. Example: >
|
||||
if did_filetype() " filetype already set..
|
||||
finish " ..don't do these checks
|
||||
endif
|
||||
@ -623,6 +625,16 @@ possibilities: >
|
||||
The `:Cycle` command is also mapped to the CTRL-A and CTRL-X keys.
|
||||
For details, see `git-rebase --help`.
|
||||
|
||||
GLEAM *ft-gleam-plugin*
|
||||
|
||||
By default the following options are set for the recommended gleam style: >
|
||||
|
||||
setlocal expandtab shiftwidth=2 softtabstop=2
|
||||
|
||||
To disable this behavior, set the following variable in your vimrc: >
|
||||
|
||||
let g:gleam_recommended_style = 0
|
||||
|
||||
GO *ft-go-plugin*
|
||||
|
||||
By default the following options are set, based on Golang official docs: >
|
||||
@ -649,6 +661,32 @@ HARE *ft-hare*
|
||||
Since the text for this plugin is rather long it has been put in a separate
|
||||
file: |ft_hare.txt|.
|
||||
|
||||
HTML *ft-html-plugin*
|
||||
|
||||
Tag folding poses a few difficulties. Many elements, e.g. `blockquote`, are
|
||||
always delimited by start and end tags; end tags for some elements, e.g. `p`,
|
||||
can be omitted in certain contexts; void elements, e.g. `hr`, have no end tag.
|
||||
Although the rules for supporting omissible end tags are ad-hoc and involved
|
||||
[0], they apply to elements in scope. Assuming syntactical wellformedness, an
|
||||
end tag can be associated with its nearest matching start tag discoverable in
|
||||
scope [1] and towards the beginning of a file, whereas all unbalanced tags and
|
||||
inlined tags can be disregarded. Having syntax highlighting in effect, tag
|
||||
folding using the |fold-expr| method can be enabled with: >
|
||||
let g:html_expr_folding = 1
|
||||
<
|
||||
By default, tag folding will be redone from scratch after each occurrence of
|
||||
a |TextChanged| or an |InsertLeave| event. Such frequency may not be desired,
|
||||
especially for large files, and this recomputation can be disabled with: >
|
||||
let g:html_expr_folding_without_recomputation = 1
|
||||
doautocmd FileType
|
||||
<
|
||||
To force another recomputation, do: >
|
||||
unlet! b:foldsmap
|
||||
normal zx
|
||||
<
|
||||
[0] https://html.spec.whatwg.org/multipage/syntax.html#optional-tags
|
||||
[1] https://en.wikipedia.org/wiki/Dangling_else
|
||||
|
||||
IDRIS2 *ft-idris2-plugin*
|
||||
|
||||
By default the following options are set: >
|
||||
@ -785,8 +823,8 @@ Variables:
|
||||
For example in C one usually wants section 3 or 2: >
|
||||
:let b:man_default_sections = '3,2'
|
||||
*g:man_hardwrap* Hard-wrap to $MANWIDTH or window width if $MANWIDTH is
|
||||
empty. Enabled by default. Set |FALSE| to enable soft
|
||||
wrapping.
|
||||
empty or larger than the window width. Enabled by
|
||||
default. Set |FALSE| to enable soft wrapping.
|
||||
|
||||
To use Nvim as a manpager: >bash
|
||||
export MANPAGER='nvim +Man!'
|
||||
@ -1117,6 +1155,13 @@ functions with [[ and ]]. Move around comments with ]" and [".
|
||||
The mappings can be disabled with: >
|
||||
let g:no_vim_maps = 1
|
||||
|
||||
YAML *ft-yaml-plugin*
|
||||
By default, the YAML filetype plugin enables the following options: >
|
||||
setlocal shiftwidth=2 softtabstop=2
|
||||
|
||||
To disable this, set the following variable: >
|
||||
let g:yaml_recommended_style = 0
|
||||
|
||||
|
||||
ZIG *ft-zig-plugin*
|
||||
|
||||
|
@ -632,14 +632,17 @@ what you type!
|
||||
When using an operator, a closed fold is included as a whole. Thus "dl"
|
||||
deletes the whole closed fold under the cursor.
|
||||
|
||||
For Ex commands that work on buffer lines the range is adjusted to always
|
||||
For Ex commands that operate on buffer lines, the range is adjusted to always
|
||||
start at the first line of a closed fold and end at the last line of a closed
|
||||
fold. Thus this command: >
|
||||
fold. Thus, this command: >
|
||||
:s/foo/bar/g
|
||||
when used with the cursor on a closed fold, will replace "foo" with "bar" in
|
||||
all lines of the fold.
|
||||
This does not happen for |:folddoopen| and |:folddoclosed|.
|
||||
|
||||
Note that for some Ex commands like |:source| the range is only adjusted when
|
||||
using a two line specifiers [range].
|
||||
|
||||
When editing a buffer that has been edited before, the last used folding
|
||||
settings are used again. For manual folding the defined folds are restored.
|
||||
For all folding methods the manually opened and closed folds are restored.
|
||||
@ -647,5 +650,4 @@ If this buffer has been edited in this window, the values from back then are
|
||||
used. Otherwise the values from the window where the buffer was edited last
|
||||
are used.
|
||||
|
||||
==============================================================================
|
||||
vim:tw=78:ts=8:noet:ft=help:norl:
|
||||
|
@ -507,6 +507,4 @@ taglist.vim
|
||||
The GNU Ada Project distribution (http://gnuada.sourceforge.net) of Vim
|
||||
contains all of the above.
|
||||
|
||||
==============================================================================
|
||||
vim: textwidth=78 nowrap tabstop=8 shiftwidth=4 softtabstop=4 noexpandtab
|
||||
vim: filetype=help
|
||||
vim:tw=78:ts=8:noet:ft=help:norl:
|
||||
|
@ -73,5 +73,4 @@ The maximum search depth can be set to any integer, but using values higher
|
||||
than 2 is not recommended, and will likely provide no tangible benefit in most
|
||||
situations.
|
||||
|
||||
==============================================================================
|
||||
vim:tw=78:ts=8:noet:ft=help:norl:
|
||||
|
@ -60,5 +60,4 @@ Many other distributions are available for Windows like
|
||||
https://chocolatey.org/packages/less/. Make sure `less` is in a directory
|
||||
listed in the `PATH` environment variable, which chocolatey above does.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
vim:ft=help:
|
||||
|
@ -160,7 +160,18 @@ g:rustfmt_emit_files ~
|
||||
provided) instead of '--write-mode=overwrite'. >vim
|
||||
let g:rustfmt_emit_files = 0
|
||||
<
|
||||
|
||||
*g:rustfmt_detect_version*
|
||||
g:rustfmt_detect_version ~
|
||||
When set to 1, will try to parse the version output from "rustfmt".
|
||||
Disabled by default for performance reasons >vim
|
||||
let g:rustfmt_detect_version = 1
|
||||
<
|
||||
*g:rustfmt_find_toml*
|
||||
g:rustfmt_emit_files ~
|
||||
When set to 1, will try to find "rustfmt.toml" file by searching from
|
||||
current path upwards. Disabled by default for performance reasons >vim
|
||||
let g:rustfmt_find_toml = 1
|
||||
<
|
||||
*g:rust_playpen_url*
|
||||
g:rust_playpen_url ~
|
||||
Set this option to override the url for the playpen to use: >vim
|
||||
@ -475,4 +486,4 @@ MAPPINGS *rust-mappings*
|
||||
This plugin defines mappings for |[[| and |]]| to support hanging indents.
|
||||
|
||||
|
||||
vim:tw=78:sw=4:noet:ts=8:ft=help:norl:
|
||||
vim:tw=78:sw=4:noet:ts=8:ft=help:norl:
|
||||
|
@ -17,6 +17,8 @@ TUI and GUI (assuming the UI supports the given feature). See |TUI| for notes
|
||||
specific to the terminal UI. Help tags with the "gui-" prefix refer to UI
|
||||
features, whereas help tags with the "ui-" prefix refer to the |ui-protocol|.
|
||||
|
||||
Type |gO| to see the table of contents.
|
||||
|
||||
==============================================================================
|
||||
Third-party GUIs *third-party-guis* *vscode*
|
||||
|
||||
@ -34,8 +36,6 @@ a Nvim GUI.
|
||||
- VimR (macOS) https://github.com/qvacua/vimr
|
||||
- Others https://github.com/neovim/neovim/wiki/Related-projects#gui
|
||||
|
||||
Type |gO| to see the table of contents.
|
||||
|
||||
==============================================================================
|
||||
Starting the GUI *gui-config* *gui-start*
|
||||
|
||||
@ -64,7 +64,25 @@ Stop or detach the current UI
|
||||
the channel to be closed, it may be (incorrectly) reported as
|
||||
an error.
|
||||
|
||||
Note: Not supported on Windows, currently.
|
||||
Note: Not supported on Windows yet.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
Restart Nvim
|
||||
|
||||
*:restart*
|
||||
:restart [+cmd]
|
||||
Restarts the Nvim server with the same startup arguments
|
||||
|v:argv| and reattaches the current UI to the new server.
|
||||
All other UIs will detach.
|
||||
|
||||
Use with `:confirm` to prompt if changes have been made.
|
||||
|
||||
Example: `:restart +qall!` stops the server using `:qall!`.
|
||||
|
||||
Note: |+cmd| defaults to `qall!` if not specified.
|
||||
Note: If the current UI hasn't implemented the "restart" UI
|
||||
event, this command is equivalent to `:qall`.
|
||||
Note: Only works if the UI and server are on the same system.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
GUI commands
|
||||
|
@ -9,18 +9,18 @@
|
||||
==============================================================================
|
||||
Checkhealth *vim.health* *health*
|
||||
|
||||
|
||||
vim.health is a minimal framework to help users troubleshoot configuration and
|
||||
any other environment conditions that a plugin might care about. Nvim ships
|
||||
with healthchecks for configuration, performance, python support, ruby
|
||||
support, clipboard support, and more.
|
||||
|
||||
To run all healthchecks, use: >vim
|
||||
|
||||
:checkhealth
|
||||
:checkhealth
|
||||
<
|
||||
|
||||
Plugin authors are encouraged to write new healthchecks. |health-dev|
|
||||
|
||||
|
||||
COMMANDS *health-commands*
|
||||
|
||||
*:che* *:checkhealth*
|
||||
@ -56,7 +56,6 @@ Local mappings in the healthcheck buffer:
|
||||
q Closes the window.
|
||||
|
||||
Global configuration:
|
||||
|
||||
*g:health*
|
||||
g:health Dictionary with the following optional keys:
|
||||
- `style` (`'float'|nil`) Set to "float" to display :checkhealth in
|
||||
@ -65,16 +64,26 @@ g:health Dictionary with the following optional keys:
|
||||
Example: >lua
|
||||
vim.g.health = { style = 'float' }
|
||||
|
||||
|
||||
Local configuration:
|
||||
|
||||
Checkhealth sets its buffer filetype to "checkhealth". You can customize the
|
||||
buffer by handling the |FileType| event. For example if you don't want emojis
|
||||
in the health report: >vim
|
||||
autocmd FileType checkhealth :set modifiable | silent! %s/\v( ?[^\x00-\x7F])//g
|
||||
<
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
Create a healthcheck *health-dev*
|
||||
|
||||
Healthchecks are functions that check the user environment, configuration, or
|
||||
any other prerequisites that a plugin cares about. Nvim ships with
|
||||
healthchecks in:
|
||||
- $VIMRUNTIME/autoload/health/
|
||||
- $VIMRUNTIME/lua/vim/lsp/health.lua
|
||||
- $VIMRUNTIME/lua/vim/treesitter/health.lua
|
||||
- and more...
|
||||
• $VIMRUNTIME/autoload/health/
|
||||
• $VIMRUNTIME/lua/vim/lsp/health.lua
|
||||
• $VIMRUNTIME/lua/vim/treesitter/health.lua
|
||||
• and more...
|
||||
|
||||
To add a new healthcheck for your own plugin, simply create a "health.lua"
|
||||
module on 'runtimepath' that returns a table with a "check()" function. Then
|
||||
@ -82,35 +91,35 @@ module on 'runtimepath' that returns a table with a "check()" function. Then
|
||||
|
||||
For example if your plugin is named "foo", define your healthcheck module at
|
||||
one of these locations (on 'runtimepath'):
|
||||
- lua/foo/health/init.lua
|
||||
- lua/foo/health.lua
|
||||
• lua/foo/health/init.lua
|
||||
• lua/foo/health.lua
|
||||
|
||||
If your plugin also provides a submodule named "bar" for which you want
|
||||
a separate healthcheck, define the healthcheck at one of these locations:
|
||||
- lua/foo/bar/health/init.lua
|
||||
- lua/foo/bar/health.lua
|
||||
If your plugin also provides a submodule named "bar" for which you want a
|
||||
separate healthcheck, define the healthcheck at one of these locations:
|
||||
• lua/foo/bar/health/init.lua
|
||||
• lua/foo/bar/health.lua
|
||||
|
||||
All such health modules must return a Lua table containing a `check()`
|
||||
function.
|
||||
|
||||
Copy this sample code into `lua/foo/health.lua`, replacing "foo" in the path
|
||||
with your plugin name: >lua
|
||||
local M = {}
|
||||
|
||||
local M = {}
|
||||
M.check = function()
|
||||
vim.health.start("foo report")
|
||||
-- make sure setup function parameters are ok
|
||||
if check_setup() then
|
||||
vim.health.ok("Setup is correct")
|
||||
else
|
||||
vim.health.error("Setup is incorrect")
|
||||
end
|
||||
-- do some more checking
|
||||
-- ...
|
||||
end
|
||||
|
||||
M.check = function()
|
||||
vim.health.start("foo report")
|
||||
-- make sure setup function parameters are ok
|
||||
if check_setup() then
|
||||
vim.health.ok("Setup is correct")
|
||||
else
|
||||
vim.health.error("Setup is incorrect")
|
||||
end
|
||||
-- do some more checking
|
||||
-- ...
|
||||
end
|
||||
|
||||
return M
|
||||
return M
|
||||
<
|
||||
|
||||
|
||||
error({msg}, {...}) *vim.health.error()*
|
||||
|
@ -337,7 +337,7 @@ in such a modeline, that can have undesired consequences.
|
||||
|
||||
TAGS
|
||||
|
||||
To define a help tag, place the name between asterisks (*tag-name*). The
|
||||
To define a help tag, place the name between asterisks ("*tag-name*"). The
|
||||
tag-name should be different from all the Vim help tag names and ideally
|
||||
should begin with the name of the Vim plugin. The tag name is usually right
|
||||
aligned on a line.
|
||||
@ -373,11 +373,17 @@ To quote a block of ex-commands verbatim, place a greater than (>) character
|
||||
at the end of the line before the block and a less than (<) character as the
|
||||
first non-blank on a line following the block. Any line starting in column 1
|
||||
also implicitly stops the block of ex-commands before it. E.g. >
|
||||
function Example_Func()
|
||||
echo "Example"
|
||||
endfunction
|
||||
function Example_Func()
|
||||
echo "Example"
|
||||
endfunction
|
||||
<
|
||||
|
||||
To enable syntax highlighting for a block of code, place a language name
|
||||
annotation (e.g. "vim") after a greater than (>) character. E.g. >vim
|
||||
function Example_Func()
|
||||
echo "Example"
|
||||
endfunction
|
||||
<
|
||||
*help-notation*
|
||||
The following are highlighted differently in a Vim help file:
|
||||
- a special key name expressed either in <> notation as in <PageDown>, or
|
||||
as a Ctrl character as in CTRL-X
|
||||
@ -391,4 +397,10 @@ highlighting. So do these:
|
||||
You can find the details in $VIMRUNTIME/syntax/help.vim
|
||||
|
||||
|
||||
FILETYPE COMPLETION *ft-help-omni*
|
||||
|
||||
To get completion for help tags when writing a tag reference, you can use the
|
||||
|i_CTRL-X_CTRL-O| command.
|
||||
|
||||
|
||||
vim:tw=78:ts=8:noet:ft=help:norl:
|
||||
|
@ -268,5 +268,4 @@ These are also available via the "main" package:
|
||||
$main::curwin The current Window object.
|
||||
$main::curbuf The current Buffer object.
|
||||
|
||||
==============================================================================
|
||||
vim:tw=78:ts=8:noet:ft=help:norl:
|
||||
|
@ -645,6 +645,6 @@ To check if `pyx*` functions and commands are available: >vim
|
||||
if has('pythonx')
|
||||
echo 'pyx* commands are available. (Python ' .. &pyx .. ')'
|
||||
endif
|
||||
<
|
||||
|
||||
==============================================================================
|
||||
vim:tw=78:ts=8:noet:ft=help:norl:
|
||||
|
@ -189,5 +189,4 @@ evaluate Ruby expressions and pass their values to Vim script.
|
||||
The Ruby value "true", "false" and "nil" are converted to v:true, v:false and
|
||||
v:null, respectively.
|
||||
|
||||
==============================================================================
|
||||
vim:tw=78:ts=8:noet:ft=help:norl:
|
||||
|
@ -146,6 +146,7 @@ commands in CTRL-X submode *i_CTRL-X_index*
|
||||
|i_CTRL-X_CTRL-N| CTRL-X CTRL-N next completion
|
||||
|i_CTRL-X_CTRL-O| CTRL-X CTRL-O omni completion
|
||||
|i_CTRL-X_CTRL-P| CTRL-X CTRL-P previous completion
|
||||
|i_CTRL-X_CTRL-R| CTRL-X CTRL-R complete contents from registers
|
||||
|i_CTRL-X_CTRL-S| CTRL-X CTRL-S spelling suggestions
|
||||
|i_CTRL-X_CTRL-T| CTRL-X CTRL-T complete identifiers from thesaurus
|
||||
|i_CTRL-X_CTRL-Y| CTRL-X CTRL-Y scroll down
|
||||
@ -515,7 +516,7 @@ tag command action in op-pending and Visual mode ~
|
||||
tag command action in Normal mode ~
|
||||
------------------------------------------------------------------------------ ~
|
||||
|CTRL-W_CTRL-B| CTRL-W CTRL-B same as "CTRL-W b"
|
||||
|CTRL-W_CTRL-C| CTRL-W CTRL-C same as "CTRL-W c"
|
||||
|CTRL-W_CTRL-C| CTRL-W CTRL-C no-op
|
||||
|CTRL-W_CTRL-D| CTRL-W CTRL-D same as "CTRL-W d"
|
||||
|CTRL-W_CTRL-F| CTRL-W CTRL-F same as "CTRL-W f"
|
||||
CTRL-W CTRL-G same as "CTRL-W g .."
|
||||
@ -1265,6 +1266,7 @@ tag command action ~
|
||||
|:delcommand| :delc[ommand] delete user-defined command
|
||||
|:delfunction| :delf[unction] delete a user function
|
||||
|:delmarks| :delm[arks] delete marks
|
||||
|:detach| :detach detach the current UI
|
||||
|:diffupdate| :dif[fupdate] update 'diff' buffers
|
||||
|:diffget| :diffg[et] remove differences in current buffer
|
||||
|:diffoff| :diffo[ff] switch off diff mode
|
||||
@ -1348,6 +1350,8 @@ tag command action ~
|
||||
|:inoreabbrev| :inorea[bbrev] like ":noreabbrev" but for Insert mode
|
||||
|:inoremenu| :inoreme[nu] like ":noremenu" but for Insert mode
|
||||
|:intro| :int[ro] print the introductory message
|
||||
|:iput| :ip[ut] like |:put|, but adjust the indent to the
|
||||
current line
|
||||
|:isearch| :is[earch] list one line where identifier matches
|
||||
|:isplit| :isp[lit] split window and jump to definition of
|
||||
identifier
|
||||
@ -1469,7 +1473,6 @@ tag command action ~
|
||||
|:options| :opt[ions] open the options-window
|
||||
|:ounmap| :ou[nmap] like ":unmap" but for Operator-pending mode
|
||||
|:ounmenu| :ounme[nu] remove menu for Operator-pending mode
|
||||
|:ownsyntax| :ow[nsyntax] set new local syntax highlight for this window
|
||||
|:packadd| :pa[ckadd] add a plugin from 'packpath'
|
||||
|:packloadall| :packl[oadall] load all packages under 'packpath'
|
||||
|:pbuffer| :pb[uffer] edit buffer in the preview window
|
||||
@ -1522,6 +1525,7 @@ tag command action ~
|
||||
|:redrawtabline| :redrawt[abline] force a redraw of the tabline
|
||||
|:registers| :reg[isters] display the contents of registers
|
||||
|:resize| :res[ize] change current window height
|
||||
|:restart| :restart restart the Nvim server
|
||||
|:retab| :ret[ab] change tab size
|
||||
|:return| :retu[rn] return from a user function
|
||||
|:rewind| :rew[ind] go to the first file in the argument list
|
||||
@ -1663,6 +1667,7 @@ tag command action ~
|
||||
|:unabbreviate| :una[bbreviate] remove abbreviation
|
||||
|:unhide| :unh[ide] open a window for each loaded file in the
|
||||
buffer list
|
||||
|:uniq| :uni[q] uniq lines
|
||||
|:unlet| :unl[et] delete variable
|
||||
|:unlockvar| :unlo[ckvar] unlock variables
|
||||
|:unmap| :unm[ap] remove mapping
|
||||
|
@ -510,7 +510,7 @@ paragraph, no matter where the cursor currently is. Or you can use Visual
|
||||
mode: hit "v", move to the end of the block, and type "gq". See also |gq|.
|
||||
|
||||
==============================================================================
|
||||
4. 'expandtab', 'smarttab' and 'softtabstop' options *ins-expandtab*
|
||||
4. 'expandtab', 'softtabstop' and 'smarttab' options *ins-expandtab*
|
||||
|
||||
If the 'expandtab' option is on, spaces will be used to fill the amount of
|
||||
whitespace of the tab. If you want to enter a real <Tab>, type CTRL-V first
|
||||
@ -521,13 +521,6 @@ number of characters in the line increases. Backspacing will delete one
|
||||
space at a time. The original character will be put back for only one space
|
||||
that you backspace over (the last one).
|
||||
|
||||
*ins-smarttab*
|
||||
When the 'smarttab' option is on, a <Tab> inserts 'shiftwidth' positions at
|
||||
the beginning of a line and 'tabstop' positions in other places. This means
|
||||
that often spaces instead of a <Tab> character are inserted. When 'smarttab'
|
||||
is off, a <Tab> always inserts 'tabstop' positions, and 'shiftwidth' is only
|
||||
used for ">>" and the like.
|
||||
|
||||
*ins-softtabstop*
|
||||
When the 'softtabstop' option is non-zero, a <Tab> inserts 'softtabstop'
|
||||
positions, and a <BS> used to delete white space, will delete 'softtabstop'
|
||||
@ -542,6 +535,13 @@ the cursor. Otherwise you cannot always delete a single character before the
|
||||
cursor. You will have to delete 'softtabstop' characters first, and then type
|
||||
extra spaces to get where you want to be.
|
||||
|
||||
*ins-smarttab*
|
||||
When the 'smarttab' option is on, the <Tab> key indents by 'shiftwidth' if the
|
||||
cursor is in leading whitespace. The <BS> key has the opposite effect. This
|
||||
behaves as if 'softtabstop' were set to the value of 'shiftwidth'. This option
|
||||
allows the user to set 'softtabstop' to a value other than 'shiftwidth' and
|
||||
still use the <Tab> key for indentation.
|
||||
|
||||
==============================================================================
|
||||
5. Replace mode *Replace* *Replace-mode* *mode-replace*
|
||||
|
||||
@ -628,7 +628,8 @@ Completion can be done for:
|
||||
10. User defined completion |i_CTRL-X_CTRL-U|
|
||||
11. omni completion |i_CTRL-X_CTRL-O|
|
||||
12. Spelling suggestions |i_CTRL-X_s|
|
||||
13. keywords in 'complete' |i_CTRL-N| |i_CTRL-P|
|
||||
13. completions from 'complete' |i_CTRL-N| |i_CTRL-P|
|
||||
14. contents from registers |i_CTRL-X_CTRL-R|
|
||||
|
||||
Additionally, |i_CTRL-X_CTRL-Z| stops completion without changing the text.
|
||||
|
||||
@ -638,6 +639,9 @@ and one of the CTRL-X commands. You exit CTRL-X mode by typing a key that is
|
||||
not a valid CTRL-X mode command. Valid keys are the CTRL-X command itself,
|
||||
CTRL-N (next), and CTRL-P (previous).
|
||||
|
||||
By default, the possible completions are showed in a menu and the first
|
||||
completion is inserted into the text. This can be adjusted with 'completeopt'.
|
||||
|
||||
To get the current completion information, |complete_info()| can be used.
|
||||
Also see the 'infercase' option if you want to adjust the case of the match.
|
||||
|
||||
@ -651,10 +655,11 @@ When completion is active you can use CTRL-E to stop it and go back to the
|
||||
originally typed text. The CTRL-E will not be inserted.
|
||||
|
||||
*complete_CTRL-Y*
|
||||
When the popup menu is displayed you can use CTRL-Y to stop completion and
|
||||
accept the currently selected entry. The CTRL-Y is not inserted. Typing a
|
||||
space, Enter, or some other unprintable character will leave completion mode
|
||||
and insert that typed character.
|
||||
When the popup menu is displayed, CTRL-Y stops completion and accepts the
|
||||
currently selected entry. Typing a space, Enter, or some other unprintable
|
||||
character will leave completion mode and insert that typed character. If you
|
||||
want to use <Enter> to accept a completion item, use this mapping: >vim
|
||||
inoremap <expr> <cr> pumvisible() ? '<c-y>' : '<cr>'
|
||||
|
||||
When the popup menu is displayed there are a few more special keys, see
|
||||
|popupmenu-keys|.
|
||||
@ -998,6 +1003,25 @@ CTRL-X CTRL-V Guess what kind of item is in front of the cursor and
|
||||
completion, for example: >
|
||||
:imap <Tab> <C-X><C-V>
|
||||
|
||||
Completing contents from registers *compl-register-words*
|
||||
*i_CTRL-X_CTRL-R*
|
||||
CTRL-X CTRL-R Guess what kind of item is in front of the cursor from
|
||||
all registers and find the first match for it.
|
||||
Further use of CTRL-R (without CTRL-X) will insert the
|
||||
register content, see |i_CTRL-R|.
|
||||
'ignorecase' applies to the matching.
|
||||
|
||||
CTRL-N Search forwards for next match. This match replaces
|
||||
the previous one.
|
||||
|
||||
CTRL-P Search backwards for previous match. This match
|
||||
replaces the previous one.
|
||||
|
||||
CTRL-X CTRL-R Further use of CTRL-X CTRL-R will copy the line
|
||||
following the previous expansion in other contexts
|
||||
unless a double CTRL-X is used (e.g. this switches
|
||||
from completing register words to register contents).
|
||||
|
||||
User defined completion *compl-function*
|
||||
|
||||
Completion is done by a function that can be defined by the user with the
|
||||
@ -1058,25 +1082,23 @@ CTRL-X s Locate the word in front of the cursor and find the
|
||||
previous one.
|
||||
|
||||
|
||||
Completing keywords from different sources *compl-generic*
|
||||
Completing from different sources *compl-generic*
|
||||
|
||||
*i_CTRL-N*
|
||||
CTRL-N Find next match for words that start with the
|
||||
keyword in front of the cursor, looking in places
|
||||
specified with the 'complete' option. The found
|
||||
keyword is inserted in front of the cursor.
|
||||
CTRL-N Find the next match for a word ending at the cursor,
|
||||
using the sources specified in the 'complete' option.
|
||||
All sources complete from keywords, except functions,
|
||||
which may complete from non-keyword. The matched
|
||||
text is inserted before the cursor.
|
||||
|
||||
*i_CTRL-P*
|
||||
CTRL-P Find previous match for words that start with the
|
||||
keyword in front of the cursor, looking in places
|
||||
specified with the 'complete' option. The found
|
||||
keyword is inserted in front of the cursor.
|
||||
CTRL-P Same as CTRL-N, but find the previous match.
|
||||
|
||||
CTRL-N Search forward for next matching keyword. This
|
||||
keyword replaces the previous matching keyword.
|
||||
CTRL-N Search forward through the matches and insert the
|
||||
next one.
|
||||
|
||||
CTRL-P Search backwards for next matching keyword. This
|
||||
keyword replaces the previous matching keyword.
|
||||
CTRL-P Search backward through the matches and insert the
|
||||
previous one.
|
||||
|
||||
CTRL-X CTRL-N or
|
||||
CTRL-X CTRL-P Further use of CTRL-X CTRL-N or CTRL-X CTRL-P will
|
||||
@ -1162,6 +1184,9 @@ For example, the function can contain this: >
|
||||
let matches = ... list of words ...
|
||||
return {'words': matches, 'refresh': 'always'}
|
||||
<
|
||||
If looking for matches is time-consuming, |complete_check()| may be used to
|
||||
maintain responsiveness.
|
||||
|
||||
*complete-items*
|
||||
Each list item can either be a string or a Dictionary. When it is a string it
|
||||
is used as the completion. When it is a Dictionary it can contain these
|
||||
@ -1296,6 +1321,7 @@ use all space available.
|
||||
The 'pumwidth' option can be used to set a minimum width. The default is 15
|
||||
characters.
|
||||
|
||||
*compl-states*
|
||||
There are three states:
|
||||
1. A complete match has been inserted, e.g., after using CTRL-N or CTRL-P.
|
||||
2. A cursor key has been used to select another match. The match was not
|
||||
@ -1923,7 +1949,7 @@ These commands are used to start inserting text. You can end insert mode with
|
||||
<Esc>. See |mode-ins-repl| for the other special characters in Insert mode.
|
||||
The effect of [count] takes place after Insert mode is exited.
|
||||
|
||||
The following commands insert text, but stay in normal mode:
|
||||
The following |default-mappings| insert text, but stay in normal mode:
|
||||
|
||||
*]<Space>*
|
||||
]<Space> Insert an empty line below the cursor without leaving
|
||||
|
@ -89,7 +89,7 @@ To uninstall Nvim:
|
||||
- Scoop (Windows): `scoop uninstall neovim`
|
||||
|
||||
==============================================================================
|
||||
Sponsor Vim/Nvim development *sponsor* *register*
|
||||
Sponsor Vim/Nvim development *sponsor*
|
||||
|
||||
Fixing bugs and adding new features takes a lot of time and effort. To show
|
||||
your appreciation for the work and motivate developers to continue working on
|
||||
@ -711,5 +711,4 @@ Arbitrary code registered via |:UpdateRemotePlugins|, that runs in a separate
|
||||
process and communicates with Nvim via the |api|.
|
||||
|
||||
|
||||
==============================================================================
|
||||
vim:tw=78:ts=8:et:sw=4:ft=help:norl:
|
||||
|
@ -140,5 +140,4 @@ A job may be killed at any time with the |jobstop()| function:
|
||||
<
|
||||
Individual streams can be closed without killing the job, see |chanclose()|.
|
||||
|
||||
==============================================================================
|
||||
vim:tw=78:ts=8:noet:ft=help:norl:
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -379,5 +379,4 @@ COPYRIGHT
|
||||
Lua BitOp is Copyright (C) 2008-2012 Mike Pall.
|
||||
Lua BitOp is free software, released under the MIT license.
|
||||
|
||||
==============================================================================
|
||||
vim:tw=78:ts=4:sw=4:sts=4:et:ft=help:norl:
|
||||
|
@ -30,16 +30,17 @@ The purpose of this guide is to introduce the different ways of interacting
|
||||
with Nvim through Lua (the "API"). This API consists of three different
|
||||
layers:
|
||||
|
||||
1. The "Vim API" inherited from Vim: |Ex-commands| and |builtin-functions| as
|
||||
well as |user-function|s in Vimscript. These are accessed through |vim.cmd()|
|
||||
and |vim.fn| respectively, which are discussed under |lua-guide-vimscript|
|
||||
below.
|
||||
1. The "Vim API" inherited from Vim: |Ex-commands| and |vimscript-functions|
|
||||
as well as |user-function|s in Vimscript. These are accessed through
|
||||
|vim.cmd()| and |vim.fn| respectively, which are discussed under
|
||||
|lua-guide-vimscript| below.
|
||||
|
||||
2. The "Nvim API" written in C for use in remote plugins and GUIs; see |api|.
|
||||
These functions are accessed through |vim.api|.
|
||||
These functions are accessed through |vim.api|.
|
||||
|
||||
3. The "Lua API" written in and specifically for Lua. These are any other
|
||||
functions accessible through `vim.*` not mentioned already; see |lua-stdlib|.
|
||||
functions accessible through `vim.*` not mentioned already; see
|
||||
|lua-stdlib|.
|
||||
|
||||
This distinction is important, as API functions inherit behavior from their
|
||||
original layer: For example, Nvim API functions always need all arguments to
|
||||
@ -93,10 +94,9 @@ Finally, you can include Lua code in a Vimscript file by putting it inside a
|
||||
Using Lua files on startup *lua-guide-config*
|
||||
|
||||
Nvim supports using `init.vim` or `init.lua` as the configuration file, but
|
||||
not both at the same time. This should be placed in your |config| directory,
|
||||
which is typically `~/.config/nvim` for Linux, BSD, or macOS, and
|
||||
`~/AppData/Local/nvim/` for Windows. Note that you can use Lua in `init.vim`
|
||||
and Vimscript in `init.lua`, which will be covered below.
|
||||
not both at the same time. This should be placed in your |config| directory
|
||||
(run `:echo stdpath('config')` to see where it is). Note that you can also use
|
||||
Lua in `init.vim` and Vimscript in `init.lua`, which will be covered below.
|
||||
|
||||
If you'd like to run any other Lua script on |startup| automatically, then you
|
||||
can simply put it in `plugin/` in your |'runtimepath'|.
|
||||
@ -122,7 +122,6 @@ Let's assume you have the following directory structure:
|
||||
|-- syntax/
|
||||
|-- init.vim
|
||||
<
|
||||
|
||||
Then the following Lua code will load `myluamodule.lua`:
|
||||
>lua
|
||||
require("myluamodule")
|
||||
@ -135,7 +134,6 @@ Similarly, loading `other_modules/anothermodule.lua` is done via
|
||||
-- or
|
||||
require('other_modules.anothermodule')
|
||||
<
|
||||
|
||||
Note how "submodules" are just subdirectories; the `.` is equivalent to the
|
||||
path separator `/` (even on Windows).
|
||||
|
||||
@ -167,7 +165,7 @@ the cache manually first:
|
||||
<
|
||||
------------------------------------------------------------------------------
|
||||
See also:
|
||||
• |lua-module-load|
|
||||
• |lua-module-load|: how `require()` finds modules
|
||||
• |pcall()|
|
||||
|
||||
==============================================================================
|
||||
@ -226,7 +224,7 @@ Vimscript are automatically converted:
|
||||
|
||||
vim.fn.jobstart('ls', { on_stdout = print_stdout })
|
||||
<
|
||||
This works for both |builtin-functions| and |user-function|s.
|
||||
This works for both |vimscript-functions| and |user-function|s.
|
||||
|
||||
Note that hashes (`#`) are not valid characters for identifiers in Lua, so,
|
||||
e.g., |autoload| functions have to be called with this syntax:
|
||||
@ -235,10 +233,9 @@ e.g., |autoload| functions have to be called with this syntax:
|
||||
<
|
||||
------------------------------------------------------------------------------
|
||||
See also:
|
||||
• |builtin-functions|: alphabetic list of all Vimscript functions
|
||||
• |function-list|: list of all Vimscript functions grouped by topic
|
||||
• |:runtime|: run all Lua scripts matching a pattern in |'runtimepath'|
|
||||
• |package.path|: list of all paths searched by `require()`
|
||||
• |vimscript-functions|: descriptions of all Vimscript functions
|
||||
• |function-list|: Vimscript functions grouped by topic
|
||||
• |:runtime|: run all Lua scripts matching a pattern in |'runtimepath'|
|
||||
|
||||
==============================================================================
|
||||
Variables *lua-guide-variables*
|
||||
@ -531,7 +528,6 @@ Examples:
|
||||
callback = function() print("My Plugin Works!") end,
|
||||
})
|
||||
<
|
||||
|
||||
Nvim will always call a Lua function with a single table containing information
|
||||
about the triggered autocommand. The most useful keys are
|
||||
• `match`: a string that matched the `pattern` (see |<amatch>|)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1654,8 +1654,8 @@ lua_Alloc *lua_Alloc*
|
||||
`NULL` if and only if it cannot fill the request. When `nsize` is not
|
||||
zero and `osize` is zero, the allocator should behave like `malloc`.
|
||||
When `nsize` and `osize` are not zero, the allocator behaves like
|
||||
`realloc`. Lua assumes that the allocator never fails when `osize >=
|
||||
nsize`.
|
||||
`realloc`. Lua assumes that the allocator never fails when
|
||||
`osize >= nsize`.
|
||||
|
||||
Here is a simple implementation for the allocator function. It is used
|
||||
in the auxiliary library by `luaL_newstate` (see
|
||||
@ -3567,8 +3567,8 @@ collectgarbage({opt} [, {arg}]) *collectgarbage()*
|
||||
`true` if the step finished a collection cycle.
|
||||
`"setpause"` sets {arg} /100 as the new value for the `pause` of
|
||||
the collector (see |lua-gc|).
|
||||
`"setstepmul"` sets {arg} /100 as the new value for the `step
|
||||
multiplier` of the collector (see |lua-gc|).
|
||||
`"setstepmul"` sets {arg} /100 as the new value for the
|
||||
`step multiplier` of the collector (see |lua-gc|).
|
||||
|
||||
dofile({filename}) *dofile()*
|
||||
Opens the named file and executes its contents as a Lua chunk. When
|
||||
@ -4150,7 +4150,7 @@ string.upper({s}) *string.upper()*
|
||||
locale.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
5.4.1 Patterns *lua-patterns*
|
||||
5.4.1 Patterns *lua-pattern*
|
||||
|
||||
A character class is used to represent a set of characters. The following
|
||||
combinations are allowed in describing a character class:
|
||||
@ -4207,6 +4207,7 @@ A pattern item may be
|
||||
- a single character class followed by `+`, which matches 1 or more
|
||||
repetitions of characters in the class. These repetition items will
|
||||
always match the longest possible sequence;
|
||||
*lua-nongreedy*
|
||||
- a single character class followed by `-`, which also matches 0 or
|
||||
more repetitions of characters in the class. Unlike `*`, these
|
||||
repetition items will always match the shortest possible sequence;
|
||||
@ -4221,7 +4222,7 @@ A pattern item may be
|
||||
`y` where the count reaches 0. For instance, the item `%b()` matches
|
||||
expressions with balanced parentheses.
|
||||
|
||||
PATTERN *lua-pattern*
|
||||
PATTERN
|
||||
|
||||
A pattern is a sequence of pattern items. A `^` at the beginning of a pattern
|
||||
anchors the match at the beginning of the subject string. A `$` at the end of
|
||||
@ -4784,8 +4785,8 @@ debug.sethook([{thread},] {hook}, {mask} [, {count}]) *debug.sethook()*
|
||||
When called without arguments, the `debug.sethook` turns off the hook.
|
||||
|
||||
When the hook is called, its first parameter is a string describing
|
||||
the event that triggered its call: `"call"`, `"return"` (or `"tail
|
||||
return"`), `"line"`, and `"count"`. For line events, the hook also
|
||||
the event that triggered its call: `"call"`, `"return"` (or
|
||||
`"tail return"`), `"line"`, and `"count"`. For line events, the hook also
|
||||
gets the new line number as its second parameter. Inside a hook, you
|
||||
can call `getinfo` with level 2 to get more information about the
|
||||
running function (level 0 is the `getinfo` function, and level 1 is
|
||||
@ -4884,5 +4885,4 @@ Christian Habermann's CRefVim project
|
||||
Adapted for bundled Nvim documentation; the original plugin can be found at
|
||||
https://www.vim.org/scripts/script.php?script_id=1291
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
vi:tw=78:ts=4:ft=help:norl:et
|
||||
vim:tw=78:ts=4:ft=help:norl:et
|
||||
|
@ -220,6 +220,12 @@ TTY Modes ~
|
||||
- `TTY_MODE_NORMAL`: "normal"
|
||||
- `TTY_MODE_RAW`: "raw"
|
||||
- `TTY_MODE_IO`: "io"
|
||||
`TTY_MODE_RAW_VT`: "raw_vt"
|
||||
|
||||
FS Modification Times ~
|
||||
|
||||
- `FS_UTIME_NOW`: "now"
|
||||
- `FS_UTIME_OMIT`: "omit"
|
||||
|
||||
==============================================================================
|
||||
ERROR HANDLING *luv-error-handling*
|
||||
@ -2196,7 +2202,7 @@ uv.pipe_bind2({pipe}, {name}, {flags}) *uv.pipe_bind2()*
|
||||
|
||||
Returns: `0` or `fail`
|
||||
|
||||
*Note*:
|
||||
Note:
|
||||
1. Paths on Unix get truncated to sizeof(sockaddr_un.sun_path)
|
||||
bytes, typically between 92 and 108 bytes.
|
||||
2. New in version 1.46.0.
|
||||
@ -2229,7 +2235,7 @@ uv.pipe_connect2(pipe, name, [flags], [callback]) *uv.pipe_connect2()*
|
||||
|
||||
Returns: `uv_connect_t userdata` or `fail`
|
||||
|
||||
*Note*:
|
||||
Note:
|
||||
1. Paths on Unix get truncated to sizeof(sockaddr_un.sun_path)
|
||||
bytes, typically between 92 and 108 bytes.
|
||||
2. New in version 1.46.0.
|
||||
@ -3276,12 +3282,12 @@ uv.fs_fchmod({fd}, {mode} [, {callback}]) *uv.fs_fchmod()*
|
||||
|
||||
Returns (async version): `uv_fs_t userdata`
|
||||
|
||||
uv.fs_utime({path}, {atime}, {mtime} [, {callback}]) *uv.fs_utime()*
|
||||
uv.fs_utime({path} [, {atime}, {mtime}, {callback}]) *uv.fs_utime()*
|
||||
|
||||
Parameters:
|
||||
- `path`: `string`
|
||||
- `atime`: `number`
|
||||
- `mtime`: `number`
|
||||
- `atime`: `number` or `string` or `nil`
|
||||
- `mtime`: `number` or `string` or `nil`
|
||||
- `callback`: `callable` (async version) or `nil` (sync
|
||||
version)
|
||||
- `err`: `nil` or `string`
|
||||
@ -3289,39 +3295,66 @@ uv.fs_utime({path}, {atime}, {mtime} [, {callback}]) *uv.fs_utime()*
|
||||
|
||||
Equivalent to `utime(2)`.
|
||||
|
||||
See |luv-constants| for supported FS Modification Time
|
||||
constants.
|
||||
|
||||
Passing `"now"` or `uv.constants.FS_UTIME_NOW` as the atime or
|
||||
mtime sets the timestamp to the current time.
|
||||
|
||||
Passing `nil`, `"omit"`, or `uv.constants.FS_UTIME_OMIT` as
|
||||
the atime or mtime leaves the timestamp untouched.
|
||||
|
||||
Returns (sync version): `boolean` or `fail`
|
||||
|
||||
Returns (async version): `uv_fs_t userdata`
|
||||
|
||||
uv.fs_futime({fd}, {atime}, {mtime} [, {callback}]) *uv.fs_futime()*
|
||||
uv.fs_futime({fd} [, {atime}, {mtime}, {callback}]) *uv.fs_futime()*
|
||||
|
||||
Parameters:
|
||||
- `fd`: `integer`
|
||||
- `atime`: `number`
|
||||
- `mtime`: `number`
|
||||
- `atime`: `number` or `string` or `nil`
|
||||
- `mtime`: `number` or `string` or `nil`
|
||||
- `callback`: `callable` (async version) or `nil` (sync
|
||||
version)
|
||||
- `err`: `nil` or `string`
|
||||
- `success`: `boolean` or `nil`
|
||||
|
||||
Equivalent to `futime(2)`.
|
||||
Equivalent to `futimes(3)`.
|
||||
|
||||
See |luv-constants| for supported FS Modification Time
|
||||
constants.
|
||||
|
||||
Passing `"now"` or `uv.constants.FS_UTIME_NOW` as the atime or
|
||||
mtime sets the timestamp to the current time.
|
||||
|
||||
Passing `nil`, `"omit"`, or `uv.constants.FS_UTIME_OMIT` as
|
||||
the atime or mtime leaves the timestamp untouched.
|
||||
|
||||
Returns (sync version): `boolean` or `fail`
|
||||
|
||||
Returns (async version): `uv_fs_t userdata`
|
||||
|
||||
uv.fs_lutime({path}, {atime}, {mtime} [, {callback}]) *uv.fs_lutime()*
|
||||
uv.fs_lutime({path} [, {atime}, {mtime}, {callback}]) *uv.fs_lutime()*
|
||||
|
||||
Parameters:
|
||||
- `path`: `string`
|
||||
- `atime`: `number`
|
||||
- `mtime`: `number`
|
||||
- `atime`: `number` or `string` or `nil`
|
||||
- `mtime`: `number` or `string` or `nil`
|
||||
- `callback`: `callable` (async version) or `nil` (sync
|
||||
version)
|
||||
- `err`: `nil` or `string`
|
||||
- `success`: `boolean` or `nil`
|
||||
|
||||
Equivalent to `lutime(2)`.
|
||||
Equivalent to `lutimes(3)`.
|
||||
|
||||
See |luv-constants| for supported FS Modification Time
|
||||
constants.
|
||||
|
||||
Passing `"now"` or `uv.constants.FS_UTIME_NOW` as the atime or
|
||||
mtime sets the timestamp to the current time.
|
||||
|
||||
Passing `nil`, `"omit"`, or `uv.constants.FS_UTIME_OMIT` as
|
||||
the atime or mtime leaves the timestamp untouched.
|
||||
|
||||
Returns (sync version): `boolean` or `fail`
|
||||
|
||||
@ -3882,6 +3915,70 @@ uv.sleep({msec}) *uv.sleep()*
|
||||
|
||||
Returns: Nothing.
|
||||
|
||||
uv.new_sem([{value}]) *uv.new_sem()*
|
||||
|
||||
Parameters:
|
||||
- `value`: `integer` or `nil`
|
||||
|
||||
Creates a new semaphore with the specified initial value. A
|
||||
semaphore is safe to share across threads. It represents an
|
||||
unsigned integer value that can incremented and decremented
|
||||
atomically but any attempt to make it negative will "wait"
|
||||
until the value can be decremented by another thread
|
||||
incrementing it.
|
||||
|
||||
The initial value must be a non-negative integer.
|
||||
|
||||
Returns: `luv_sem_t userdata` or `fail`
|
||||
|
||||
Note: A semaphore must be shared between threads, any
|
||||
`uv.sem_wait()` on a single thread that blocks will deadlock.
|
||||
|
||||
uv.sem_post({sem}) *uv.sem_post()*
|
||||
|
||||
> method form `sem:post()`
|
||||
|
||||
Parameters:
|
||||
- `sem`: `luv_sem_t userdata`
|
||||
|
||||
Increments (unlocks) a semaphore, if the semaphore's value
|
||||
consequently becomes greater than zero then another thread
|
||||
blocked in a sem_wait call will be woken and proceed to
|
||||
decrement the semaphore.
|
||||
|
||||
Returns: Nothing.
|
||||
|
||||
uv.sem_wait({sem}) *uv.sem_wait()*
|
||||
|
||||
> method form `sem:wait()`
|
||||
|
||||
Parameters:
|
||||
- `sem`: `luv_sem_t userdata`
|
||||
|
||||
Decrements (locks) a semaphore, if the semaphore's value is
|
||||
greater than zero then the value is decremented and the call
|
||||
returns immediately. If the semaphore's value is zero then the
|
||||
call blocks until the semaphore's value rises above zero or
|
||||
the call is interrupted by a signal.
|
||||
|
||||
Returns: Nothing.
|
||||
|
||||
uv.sem_trywait({sem}) *uv.sem_trywait()*
|
||||
|
||||
> method form `sem:trywait()`
|
||||
|
||||
Parameters:
|
||||
- `sem`: `luv_sem_t userdata`
|
||||
|
||||
The same as `uv.sem_wait()` but returns immediately if the
|
||||
semaphore is not available.
|
||||
|
||||
If the semaphore's value was decremented then `true` is
|
||||
returned, otherwise the semaphore has a value of zero and
|
||||
`false` is returned.
|
||||
|
||||
Returns: `boolean`
|
||||
|
||||
==============================================================================
|
||||
MISCELLANEOUS UTILITIES *luv-miscellaneous-utilities*
|
||||
|
||||
|
@ -1410,6 +1410,7 @@ completion can be enabled:
|
||||
-complete=messages |:messages| suboptions
|
||||
-complete=option options
|
||||
-complete=packadd optional package |pack-add| names
|
||||
-complete=retab |:retab| suboptions
|
||||
-complete=runtime file and directory names in |'runtimepath'|
|
||||
-complete=scriptnames sourced script names
|
||||
-complete=shellcmd Shell command
|
||||
|
@ -19,12 +19,7 @@ For changing the language of messages and menus see |mlang.txt|.
|
||||
==============================================================================
|
||||
Getting started *mbyte-first*
|
||||
|
||||
This is a summary of the multibyte features in Vim. If you are lucky it works
|
||||
as described and you can start using Vim without much trouble. If something
|
||||
doesn't work you will have to read the rest. Don't be surprised if it takes
|
||||
quite a bit of work and experimenting to make Vim use all the multibyte
|
||||
features. Unfortunately, every system has its own way to deal with multibyte
|
||||
languages and it is quite complicated.
|
||||
This is a summary of the multibyte features in Nvim.
|
||||
|
||||
|
||||
LOCALE
|
||||
@ -54,14 +49,14 @@ See |mbyte-locale| for details.
|
||||
|
||||
ENCODING
|
||||
|
||||
Nvim always uses UTF-8 internally. Thus 'encoding' option is always set
|
||||
to "utf-8" and cannot be changed.
|
||||
Nvim always uses UTF-8 internally. Thus 'encoding' is always set to "utf-8"
|
||||
and cannot be changed.
|
||||
|
||||
All the text that is used inside Vim will be in UTF-8. Not only the text in
|
||||
the buffers, but also in registers, variables, etc.
|
||||
|
||||
You can edit files in different encodings than UTF-8. Nvim
|
||||
will convert the file when you read it and convert it back when you write it.
|
||||
You can edit files in different encodings than UTF-8. Nvim will convert the
|
||||
file when you read it and convert it back when you write it.
|
||||
See 'fileencoding', 'fileencodings' and |++enc|.
|
||||
|
||||
|
||||
@ -184,9 +179,9 @@ You could make a small shell script for this.
|
||||
==============================================================================
|
||||
Encoding *mbyte-encoding*
|
||||
|
||||
In Nvim UTF-8 is always used internally to encode characters.
|
||||
This applies to all the places where text is used, including buffers (files
|
||||
loaded into memory), registers and variables.
|
||||
UTF-8 is always used internally to encode characters. This applies to all the
|
||||
places where text is used, including buffers (files loaded into memory),
|
||||
registers and variables.
|
||||
|
||||
*charset* *codeset*
|
||||
Charset is another name for encoding. There are subtle differences, but these
|
||||
@ -481,7 +476,7 @@ and what the keymaps are to get those characters:
|
||||
|
||||
glyph encoding keymap ~
|
||||
Char UTF-8 cp1255 hebrew hebrewp name ~
|
||||
א 0x5d0 0xe0 t a ´alef
|
||||
א 0x5d0 0xe0 t a alef
|
||||
ב 0x5d1 0xe1 c b bet
|
||||
ג 0x5d2 0xe2 d g gimel
|
||||
ד 0x5d3 0xe3 s d dalet
|
||||
@ -499,7 +494,7 @@ Char UTF-8 cp1255 hebrew hebrewp name ~
|
||||
ן 0x5df 0xef i N nun sofit
|
||||
נ 0x5e0 0xf0 b n nun
|
||||
ס 0x5e1 0xf1 x s samech
|
||||
ע 0x5e2 0xf2 g u `ayin
|
||||
ע 0x5e2 0xf2 g u ayin
|
||||
ף 0x5e3 0xf3 ; P pe sofit
|
||||
פ 0x5e4 0xf4 p p pe
|
||||
ץ 0x5e5 0xf5 . X tsadi sofit
|
||||
@ -561,8 +556,8 @@ Char UTF-8 hebrew name
|
||||
ב֯ 0x5af CC masora circle
|
||||
|
||||
Combining forms:
|
||||
ﬠ 0xfb20 X` Alternative `ayin
|
||||
ﬡ 0xfb21 X' Alternative ´alef
|
||||
ﬠ 0xfb20 X` Alternative ayin
|
||||
ﬡ 0xfb21 X' Alternative alef
|
||||
ﬢ 0xfb22 X-d Alternative dalet
|
||||
ﬣ 0xfb23 X-h Alternative he
|
||||
ﬤ 0xfb24 X-k Alternative kaf
|
||||
@ -609,25 +604,25 @@ Combining forms:
|
||||
Using UTF-8 *mbyte-utf8* *UTF-8* *utf-8* *utf8*
|
||||
*Unicode* *unicode*
|
||||
The Unicode character set was designed to include all characters from other
|
||||
character sets. Therefore it is possible to write text in any language using
|
||||
Unicode (with a few rarely used languages excluded). And it's mostly possible
|
||||
to mix these languages in one file, which is impossible with other encodings.
|
||||
character sets. Therefore it is possible to write text in (almost) any
|
||||
language using Unicode. And it's mostly possible to mix these languages in
|
||||
one file, which is impossible with other encodings.
|
||||
|
||||
Unicode can be encoded in several ways. The most popular one is UTF-8, which
|
||||
uses one or more bytes for each character and is backwards compatible with
|
||||
ASCII. On MS-Windows UTF-16 is also used (previously UCS-2), which uses
|
||||
16-bit words. Vim can support all of these encodings, but always uses UTF-8
|
||||
ASCII. On MS-Windows UTF-16 is also used (previously UCS-2), which uses
|
||||
16-bit words. Nvim supports all of these encodings, but always uses UTF-8
|
||||
internally.
|
||||
|
||||
Vim has comprehensive UTF-8 support. It works well in:
|
||||
- xterm with UTF-8 support enabled
|
||||
- MS-Windows GUI
|
||||
- several other platforms
|
||||
|
||||
Double-width characters are supported. Works best with 'guifontwide'. When
|
||||
Nvim supports double-width characters; works best with 'guifontwide'. When
|
||||
using only 'guifont' the wide characters are drawn in the normal width and
|
||||
a space to fill the gap.
|
||||
|
||||
EMOJI *emoji*
|
||||
|
||||
You can list emoji characters using this script: >vim
|
||||
:source $VIMRUNTIME/scripts/emoji_list.lua
|
||||
<
|
||||
*bom-bytes*
|
||||
When reading a file a BOM (Byte Order Mark) can be used to recognize the
|
||||
Unicode encoding:
|
||||
@ -698,7 +693,7 @@ You need to specify a font to be used. For double-wide characters another
|
||||
font is required, which is exactly twice as wide. There are three ways to do
|
||||
this:
|
||||
|
||||
1. Set 'guifont' and let Vim find a matching 'guifontwide'
|
||||
1. Set 'guifont' and let Nvim find a matching 'guifontwide'
|
||||
2. Set 'guifont' and 'guifontwide'
|
||||
|
||||
See the documentation for each option for details. Example: >
|
||||
@ -730,7 +725,7 @@ COMMAND ARGUMENTS *utf-8-char-arg*
|
||||
|
||||
Commands like |f|, |F|, |t| and |r| take an argument of one character. For
|
||||
UTF-8 this argument may include one or two composing characters. These need
|
||||
to be produced together with the base character, Vim doesn't wait for the next
|
||||
to be produced together with the base character, Nvim doesn't wait for the next
|
||||
character to be typed to find out if it is a composing character or not.
|
||||
Using 'keymap' or |:lmap| is a nice way to type these characters.
|
||||
|
||||
@ -741,7 +736,6 @@ searching for a character with a composing character, this will only find
|
||||
matches with that composing character. It was implemented this way, because
|
||||
not everybody is able to type a composing character.
|
||||
|
||||
|
||||
==============================================================================
|
||||
Overview of options *mbyte-options*
|
||||
|
||||
|
@ -878,12 +878,12 @@ Numbered mark should be stored. See |shada-file-marks|.
|
||||
|
||||
|
||||
*'[* *`[*
|
||||
'[ `[ To the first character of the previously changed
|
||||
or yanked text.
|
||||
'[ `[ To the first character of the previously changed,
|
||||
or yanked text. Also set when writing the buffer.
|
||||
|
||||
*']* *`]*
|
||||
'] `] To the last character of the previously changed or
|
||||
yanked text.
|
||||
yanked text. Also set when writing the buffer.
|
||||
|
||||
After executing an operator the Cursor is put at the beginning of the text
|
||||
that was operated upon. After a put command ("p" or "P") the cursor is
|
||||
@ -942,6 +942,11 @@ was made yet in the current file.
|
||||
the position will be on the last character.
|
||||
To jump to older changes use |g;|.
|
||||
|
||||
*':* *`:*
|
||||
': In a prompt buffer, the start of the current prompt.
|
||||
Text from this line until end of buffer will be
|
||||
submitted when the user submits the prompt.
|
||||
|
||||
*'(* *`(*
|
||||
'( `( To the start of the current sentence, like the |(|
|
||||
command.
|
||||
|
@ -1,4 +1,4 @@
|
||||
*news-10.txt* Nvim
|
||||
*news-0.10.txt* Nvim
|
||||
|
||||
|
||||
NVIM REFERENCE MANUAL
|
||||
@ -213,7 +213,7 @@ The following new features were added.
|
||||
• By default, the swapfile "ATTENTION" |E325| dialog is skipped if the
|
||||
swapfile is owned by a running Nvim process, instead of prompting. If you
|
||||
always want the swapfile dialog, delete the default SwapExists handler:
|
||||
`autocmd! nvim_swapfile`. |default-autocmds|
|
||||
`autocmd! nvim.swapfile`. |default-autocmds|
|
||||
• Navigating the |jumplist| with CTRL+O, CTRL+I behaves more intuitively
|
||||
when deleting buffers, and avoids "invalid buffer" cases. #25461
|
||||
• |:fclose| command.
|
||||
|
499
runtime/doc/news-0.11.txt
Normal file
499
runtime/doc/news-0.11.txt
Normal file
@ -0,0 +1,499 @@
|
||||
*news-0.11.txt* Nvim
|
||||
|
||||
|
||||
NVIM REFERENCE MANUAL
|
||||
|
||||
|
||||
Notable changes since Nvim 0.10 *news-0.11*
|
||||
|
||||
For changes in the previous release, see |news-0.10|.
|
||||
|
||||
Type |gO| to see the table of contents.
|
||||
|
||||
==============================================================================
|
||||
BREAKING CHANGES
|
||||
|
||||
These changes may require adaptations in your config or plugins.
|
||||
|
||||
API
|
||||
|
||||
• `vim.rpcnotify(0)` and `rpcnotify(0)` broadcast to ALL channels. Previously
|
||||
they would "multicast" only to subscribed channels (controlled by
|
||||
`nvim_subscribe()`). Plugins and clients that want "multicast" behavior must
|
||||
now maintain their own list of channels.
|
||||
• In the future, |vim.rpcnotify()| may accept a list of channels, if there
|
||||
is demand for this use-case.
|
||||
• "Dictionary" was renamed to "Dict" internally and in the RPC |api-metadata|.
|
||||
This is not expected to break clients because there are no known clients
|
||||
that actually use the `return_type` field or the parameter type names
|
||||
reported by |--api-info| or |nvim_get_api_info()|.
|
||||
• Renamed `nvim__id_dictionary` (unsupported/experimental API) to
|
||||
`nvim__id_dict`.
|
||||
|
||||
BUILD
|
||||
|
||||
• On Windows, only building with the UCRT runtime is supported.
|
||||
• Translations are turned off by default. Enable by building Nvim with the
|
||||
CMake flag `ENABLE_TRANSLATIONS=ON`.
|
||||
|
||||
DIAGNOSTICS
|
||||
|
||||
• The "underline" diagnostics handler sorts diagnostics by severity when using
|
||||
the "severity_sort" option.
|
||||
• Diagnostics are filtered by severity before being passed to a diagnostic
|
||||
handler |diagnostic-handlers|.
|
||||
• The "virtual_text" handler is disabled by default. Enable with >lua
|
||||
vim.diagnostic.config({ virtual_text = true })
|
||||
<
|
||||
EDITOR
|
||||
|
||||
• The order in which signs are placed was changed. Higher priority signs will
|
||||
now appear left of lower priority signs.
|
||||
• |hl-CurSearch| now behaves the same as Vim and no longer updates on every
|
||||
cursor movement.
|
||||
• Moving in the buffer list using |:bnext| and similar commands behaves as
|
||||
documented and skips help buffers if run from a non-help buffer, otherwise
|
||||
it moves to another help buffer.
|
||||
• Bells from a |terminal| buffer are now silent by default, unless 'belloff'
|
||||
option doesn't contain "term" or "all".
|
||||
• Renamed autocmd group `nvim_swapfile` to `nvim.swapfile`. |default-autocmds|
|
||||
If you always want the swapfile dialog, delete the `nvim.swapfile` group:
|
||||
`autocmd! nvim.swapfile`.
|
||||
|
||||
EVENTS
|
||||
|
||||
• |vim.ui_attach()| callbacks for |ui-messages| `msg_show` events are executed in
|
||||
|api-fast| context.
|
||||
• New/enhanced arguments in these existing UI events:
|
||||
• `cmdline_hide`: Includes `level` and `abort` arguments, `abort` argument indicating if the cmdline was aborted.
|
||||
• `cmdline_show`:
|
||||
• Prompts that were previously emitted as `msg_show` events, are now routed
|
||||
through `cmdline_show`.
|
||||
• `hl_id` argument to highlight the prompt text.
|
||||
• `msg_show`:
|
||||
• `history` argument indicating if the message was added to the history.
|
||||
• new message kinds: "bufwrite", "completion", "list_cmd", "lua_print",
|
||||
"search_cmd", "shell_out/err/ret", "undo", "verbose", wildlist".
|
||||
• |TermRequest| and |TermResponse| |event-data| is now a table. The "sequence"
|
||||
field contains the received sequence. |TermRequest| also contains a "cursor"
|
||||
field indicating the cursor's position when the sequence was received.
|
||||
|
||||
HIGHLIGHTS
|
||||
|
||||
• |TermCursorNC| is removed and no longer supported. Unfocused terminals no
|
||||
longer have a cursor.
|
||||
|
||||
LSP
|
||||
|
||||
• |vim.lsp.buf.references()|, |vim.lsp.buf.declaration()|, |vim.lsp.buf.definition()|,
|
||||
|vim.lsp.buf.type_definition()|, |vim.lsp.buf.implementation()| and
|
||||
|vim.lsp.buf.hover()| now support merging the results of multiple clients
|
||||
but no longer trigger the global handlers from `vim.lsp.handlers`
|
||||
• |vim.lsp.buf.typehierarchy()| now passes the correct params for each
|
||||
client request.
|
||||
• |vim.lsp.handlers.signature_help()| is no longer used.
|
||||
• |vim.lsp.diagnostic.on_publish_diagnostics()| and
|
||||
|vim.lsp.diagnostic.on_diagnostic()| no longer accept a config parameter and
|
||||
can no longer be configured with |vim.lsp.with()|.
|
||||
Instead use: >lua
|
||||
vim.diagnostic.config(config, vim.lsp.diagnostic.get_namespace(client_id))
|
||||
<
|
||||
• |vim.lsp.util.make_position_params()|, |vim.lsp.util.make_range_params()|
|
||||
and |vim.lsp.util.make_given_range_params()| now require the `position_encoding`
|
||||
parameter.
|
||||
• |vim.lsp.util.symbols_to_items()| now requires the `position_encoding` parameter.
|
||||
|
||||
LUA
|
||||
|
||||
• API functions now consistently return an empty dictionary as
|
||||
|vim.empty_dict()|. Earlier, a |lua-special-tbl| was sometimes used.
|
||||
• |vim.json.encode()| no longer escapes forward slashes "/" by default
|
||||
|
||||
OPTIONS
|
||||
|
||||
• The 'statuscolumn' `%l` item can now be used as a number column segment that
|
||||
changes according to related options. It takes care of alignment, 'number',
|
||||
'relativenumber' and 'signcolumn' set to "number". The now redundant `%r` item
|
||||
is no longer treated specially for 'statuscolumn'.
|
||||
• `:set {option}<` removes the local value for all |global-local| options instead
|
||||
of just string |global-local| options.
|
||||
• `:setlocal {option}<` copies the global value to the local value for number
|
||||
and boolean |global-local| options instead of removing the local value.
|
||||
• Setting |hidden-options| now gives an error. In particular, setting
|
||||
'noshellslash' is now only allowed on Windows.
|
||||
|
||||
TREESITTER
|
||||
|
||||
• |Query:iter_matches()| correctly returns all matching nodes in a match
|
||||
instead of only the last node. This means that the returned table maps
|
||||
capture IDs to a list of nodes that need to be iterated over. For
|
||||
backwards compatibility, an option `all=false` (only return the last
|
||||
matching node) is provided that will be removed in a future release.
|
||||
• |vim.treesitter.language.get_filetypes()| always includes the {language}
|
||||
argument in addition to explicitly registered filetypes.
|
||||
• |vim.treesitter.language.get_lang()| falls back to the {filetype} argument
|
||||
if no languages are explicitly registered.
|
||||
• |vim.treesitter.language.add()| returns `true` if a parser was loaded
|
||||
successfully and `nil,errmsg` otherwise instead of throwing an error.
|
||||
• |vim.treesitter.get_parser()| and |vim.treesitter.start()| no longer parse the
|
||||
tree before returning. Scripts must call |LanguageTree:parse()| explicitly. >lua
|
||||
local p = vim.treesitter.get_parser(0, 'c')
|
||||
p:parse()
|
||||
• |vim.treesitter.get_parser()| expects its buffer to be loaded.
|
||||
|
||||
TUI
|
||||
|
||||
• OSC 52 is used as a fallback clipboard provider when no other
|
||||
|clipboard-tool| is found, even when not using SSH |clipboard-osc52|. To
|
||||
disable OSC 52 queries, set the "osc52" key of |g:termfeatures| to false.
|
||||
|
||||
VIMSCRIPT
|
||||
|
||||
• |v:msgpack_types| has the type "binary" removed. |msgpackparse()| no longer
|
||||
treats BIN, STR and FIXSTR as separate types. Any of these is returned as a
|
||||
string if possible, or a |blob| if the value contained embedded NUL:s.
|
||||
|
||||
==============================================================================
|
||||
NEW FEATURES
|
||||
|
||||
The following new features were added.
|
||||
|
||||
API
|
||||
|
||||
• Improved API "meta" docstrings and :help documentation.
|
||||
• |nvim__ns_set()| can set properties for a namespace
|
||||
• |nvim_echo()| `err` field to print error messages and `chunks` accepts
|
||||
highlight group IDs.
|
||||
• |nvim_open_win()| supports a `mouse` field that allows configuring mouse
|
||||
interaction with the window separately from `focusable` field.
|
||||
• |nvim_open_win()| `relative` field can be set to "laststatus" and "tabline".
|
||||
• Additions to |nvim_buf_set_extmark()|:
|
||||
• `conceal_lines` field to conceal an entire line.
|
||||
• `hl_group` field can be an array of layered groups.
|
||||
• `virt_text_pos` field accepts value `eol_right_align` to allow for right
|
||||
aligned text that truncates before covering up buffer text.
|
||||
• `virt_lines_overflow` field accepts value `scroll` to enable horizontal
|
||||
scrolling for virtual lines with 'nowrap'.
|
||||
|
||||
DEFAULTS
|
||||
|
||||
• Highlighting:
|
||||
• Improved styling of :checkhealth and :help buffers.
|
||||
|
||||
• Mappings:
|
||||
• |grn| in Normal mode maps to |vim.lsp.buf.rename()|
|
||||
• |grr| in Normal mode maps to |vim.lsp.buf.references()|
|
||||
• |gri| in Normal mode maps to |vim.lsp.buf.implementation()|
|
||||
• |gO| in Normal mode maps to |vim.lsp.buf.document_symbol()|
|
||||
• |gra| in Normal and Visual mode maps to |vim.lsp.buf.code_action()|
|
||||
• CTRL-S in Insert and Select mode maps to |vim.lsp.buf.signature_help()|
|
||||
• Mouse |popup-menu| includes an "Open in web browser" item when you right-click
|
||||
on a URL.
|
||||
• Mouse |popup-menu| includes a "Go to definition" item when LSP is active
|
||||
in the buffer.
|
||||
• Mouse |popup-menu| includes "Show Diagnostics", "Show All Diagnostics" and
|
||||
"Configure Diagnostics" items when there are diagnostics in the buffer.
|
||||
• |]d-default| and |[d-default| accept a count.
|
||||
• |[D-default| and |]D-default| jump to the first and last diagnostic in the
|
||||
current buffer, respectively.
|
||||
• Mappings inspired by Tim Pope's vim-unimpaired:
|
||||
• |[q|, |]q|, |[Q|, |]Q|, |[CTRL-Q|, |]CTRL-Q| navigate through the |quickfix| list
|
||||
• |[l|, |]l|, |[L|, |]L|, |[CTRL-L|, |]CTRL-L| navigate through the |location-list|
|
||||
• |[t|, |]t|, |[T|, |]T|, |[CTRL-T|, |]CTRL-T| navigate through the |tag-matchlist|
|
||||
• |[a|, |]a|, |[A|, |]A| navigate through the |argument-list|
|
||||
• |[b|, |]b|, |[B|, |]B| navigate through the |buffer-list|
|
||||
• |[<Space>|, |]<Space>| add an empty line above and below the cursor
|
||||
• |[[| and |]]| in Normal mode jump between shell prompts for shells which emit
|
||||
OSC 133 sequences ("shell integration" or "semantic prompts").
|
||||
|
||||
• Options:
|
||||
• 'diffopt' default includes "linematch:40".
|
||||
• 'number', 'relativenumber', 'signcolumn', and 'foldcolumn' are disabled in
|
||||
|terminal| buffers. |terminal-config| shows how to change these defaults.
|
||||
• Lua |ftplugin| sets 'omnifunc' to "v:lua.vim.lua_omnifunc".
|
||||
• Lua |ftplugin| sets 'foldexpr' to "v:lua.vim.treesitter.foldexpr()".
|
||||
|
||||
• Snippet:
|
||||
• `<Tab>` in Insert and Select mode maps to `vim.snippet.jump({ direction = 1 })`
|
||||
when a snippet is active and jumpable forwards.
|
||||
• `<S-Tab>` in Insert and Select mode maps to `vim.snippet.jump({ direction = -1 })`
|
||||
when a snippet is active and jumpable backwards.
|
||||
|
||||
DIAGNOSTICS
|
||||
|
||||
• |vim.diagnostic.config()| accepts a "jump" table to specify defaults for
|
||||
|vim.diagnostic.jump()|.
|
||||
• A "virtual_lines" diagnostic handler was added to render diagnostics using
|
||||
virtual lines below the respective code.
|
||||
• The "virtual_text" diagnostic handler accepts a `current_line` option to
|
||||
only show virtual text at the cursor's line.
|
||||
|
||||
EDITOR
|
||||
|
||||
• Improved |paste| handling for redo (dot-repeat) and macros (|recording|):
|
||||
• Redoing a large paste is significantly faster and ignores 'autoindent'.
|
||||
• Replaying a macro with |@| also replays pasted text.
|
||||
• On Windows, filename arguments on the command-line prefixed with "~\" or
|
||||
"~/" are now expanded to the user's profile directory, not a relative path
|
||||
to a literal "~" directory.
|
||||
• |hl-ComplMatchIns| shows matched text of the currently inserted completion.
|
||||
• |hl-PmenuMatch| and |hl-PmenuMatchSel| show matched text in completion popup.
|
||||
• |gO| now works in `help`, `checkhealth`, and `markdown` buffers.
|
||||
• Jump between sections in `help` and `checkhealth` buffers with `[[` and `]]`.
|
||||
|
||||
EVENTS
|
||||
|
||||
• |CompleteDone| now sets the `reason` key in `v:event` which specifies the reason
|
||||
for completion being done.
|
||||
• |vim.on_key()| callbacks can consume the key by returning an empty string.
|
||||
|
||||
LSP
|
||||
|
||||
• Improved rendering of LSP hover docs. |K-lsp-default|
|
||||
• |vim.lsp.completion.enable()| gained the `convert` callback which enables
|
||||
customizing the transformation of an LSP CompletionItem to |complete-items|.
|
||||
• |vim.lsp.diagnostic.from()| can be used to convert a list of
|
||||
|vim.Diagnostic| objects into their LSP diagnostic representation.
|
||||
• `:checkhealth vim.lsp` displays the server version (if available).
|
||||
• Completion side effects (including snippet expansion, execution of commands
|
||||
and application of additional text edits) is now built-in.
|
||||
• |vim.lsp.util.locations_to_items()| and |vim.lsp.util.symbols_to_items()| now
|
||||
sets `end_col` and `end_lnum` fields.
|
||||
• |vim.lsp.buf.format()| now supports passing a list of ranges
|
||||
via the `range` parameter (this requires support for the
|
||||
`textDocument/rangesFormatting` request).
|
||||
• |vim.lsp.buf.code_action()| actions show client name when there are multiple
|
||||
clients.
|
||||
• |vim.lsp.buf.signature_help()| can now cycle through different signatures
|
||||
using `<C-s>` and also support multiple clients.
|
||||
• The client now supports `'utf-8'` and `'utf-32'` position encodings.
|
||||
• |vim.lsp.buf.hover()| now highlights hover ranges using the
|
||||
|hl-LspReferenceTarget| highlight group.
|
||||
• Functions in |vim.lsp.Client| can now be called as methods.
|
||||
• Implemented LSP folding: |vim.lsp.foldexpr()|
|
||||
https://microsoft.github.io/language-server-protocol/specification/#textDocument_foldingRange
|
||||
• |vim.lsp.config()| has been added to define default configurations for
|
||||
servers. In addition, configurations can be specified in `lsp/<name>.lua`.
|
||||
• |vim.lsp.enable()| has been added to enable servers.
|
||||
• |vim.lsp.buf.code_action()| resolves the `command` property during the
|
||||
`codeAction/resolve` request.
|
||||
• The `textDocument/completion` request now includes the completion context in
|
||||
its parameters.
|
||||
|
||||
LUA
|
||||
|
||||
• Command-line completions for: `vim.g`, `vim.t`, `vim.w`, `vim.b`, `vim.v`,
|
||||
`vim.o`, `vim.wo`, `vim.bo`, `vim.opt`, `vim.opt_local`, `vim.opt_global`,
|
||||
`vim.env` and `vim.fn`.
|
||||
• Documentation for |lua-bit|.
|
||||
• |gf| in Lua buffers can go to module in same repo, |runtime-search-path| and
|
||||
|package.path|.
|
||||
• |vim.fs.rm()| can delete files and directories.
|
||||
• |vim.validate()| now has a new signature which uses less tables,
|
||||
is more performant and easier to read.
|
||||
• |vim.str_byteindex()| and |vim.str_utfindex()| gained overload signatures
|
||||
supporting two new parameters, `encoding` and `strict_indexing`.
|
||||
• |vim.json.encode()| has an option to enable forward slash escaping
|
||||
• |vim.fs.abspath()| converts paths to absolute paths.
|
||||
• |vim.fs.relpath()| gets relative path compared to base path.
|
||||
• |vim.fs.dir()| and |vim.fs.find()| can now follow symbolic links,
|
||||
the behavior can be turn on using the new `follow` option.
|
||||
• |vim.hl.range()| now has a optional `timeout` field which allows for a timed
|
||||
highlight.
|
||||
• |vim.text.indent()| indents/dedents text.
|
||||
|
||||
OPTIONS
|
||||
|
||||
• 'completeopt' flag "fuzzy" enables |fuzzy-matching| during |ins-completion|.
|
||||
• 'completeopt' flag "preinsert" highlights text to be inserted.
|
||||
• 'wildmode' flag "noselect" shows 'wildmenu' without selecting an entry.
|
||||
• 'messagesopt' configures |:messages| and |hit-enter| prompt.
|
||||
• 'tabclose' controls which tab page to focus when closing a tab page.
|
||||
• 'eventignorewin' to persistently ignore events in a window.
|
||||
• 'winborder' sets the default border for |floating-windows|.
|
||||
|
||||
PERFORMANCE
|
||||
|
||||
• Significantly reduced redraw time for long lines with treesitter
|
||||
highlighting.
|
||||
• LSP diagnostics and inlay hints are de-duplicated (new requests cancel
|
||||
inflight requests). This greatly improves performance with slow LSP servers.
|
||||
• 10x speedup for |vim.treesitter.foldexpr()| (when no parser exists for the
|
||||
buffer).
|
||||
• Strong |treesitter-query| caching makes repeat |vim.treesitter.query.get()|
|
||||
and |vim.treesitter.query.parse()| calls significantly faster for large
|
||||
queries.
|
||||
• Treesitter highlighting is now asynchronous. To force synchronous parsing,
|
||||
use `vim.g._ts_force_sync_parsing = true`.
|
||||
• Treesitter folding is now calculated asynchronously.
|
||||
• |LanguageTree:parse()| now only runs the injection query on the provided
|
||||
range (as long as the language does not have a combined injection),
|
||||
significantly improving |treesitter-highlight| performance.
|
||||
• Treesitter injection query iteration is now asynchronous, making edits in
|
||||
large buffers with combined injections much quicker.
|
||||
• 10x reduction in blocking time when attaching an LSP to a large buffer.
|
||||
|
||||
PLUGINS
|
||||
|
||||
• EditorConfig
|
||||
• spelling_language property is now supported.
|
||||
• 'inccommand' incremental preview can run on 'nomodifiable' buffers and
|
||||
restores their 'modifiable' state
|
||||
• Commenting
|
||||
• 'commentstring' values can now be specified in a Treesitter capture's
|
||||
`bo.commentstring` metadata field, providing finer grained support for
|
||||
languages like `JSX`.
|
||||
|
||||
STARTUP
|
||||
|
||||
• |-es| ("script mode") disables shada by default.
|
||||
• Nvim will fail if the |--listen| or |$NVIM_LISTEN_ADDRESS| address is
|
||||
invalid, instead of silently skipping an invalid address.
|
||||
|
||||
TERMINAL
|
||||
|
||||
• The |terminal| now understands the OSC 52 escape sequence to write to the
|
||||
system clipboard (copy). Querying with OSC 52 (paste) is not supported.
|
||||
• |hl-StatusLineTerm| and |hl-StatusLineTermNC| define highlights for the
|
||||
status line in |terminal| windows.
|
||||
• The terminal buffer now supports reflow (wrapped lines adapt when the buffer
|
||||
is resized horizontally). Note: Lines that are not visible and kept in
|
||||
'scrollback' are not reflown.
|
||||
• The |terminal| now supports OSC 8 escape sequences and will display
|
||||
hyperlinks in supporting host terminals.
|
||||
• The |terminal| now uses the actual cursor, rather than a "virtual" cursor.
|
||||
This means that escape codes sent by applications running in a terminal
|
||||
buffer can change the cursor shape and visibility. However, it also
|
||||
means that the |TermCursorNC| highlight group is no longer supported: an
|
||||
unfocused terminal window will have no cursor at all (so there is nothing to
|
||||
highlight).
|
||||
• |jobstart()| gained the "term" flag.
|
||||
• The |terminal| will send theme update notifications when 'background' is
|
||||
changed and DEC mode 2031 is enabled.
|
||||
• The |terminal| has experimental support for the Kitty keyboard protocol
|
||||
(sometimes called "CSI u" key encoding). Only the "Disambiguate escape
|
||||
codes" mode is currently supported.
|
||||
• The |terminal| emits a |TermRequest| autocommand event when the child process
|
||||
emits an APC control sequence.
|
||||
• |TermRequest| has a "cursor" field in its |event-data| indicating the
|
||||
cursor position when the sequence was received.
|
||||
|
||||
TREESITTER
|
||||
|
||||
• |LanguageTree:node_for_range()| gets anonymous and named nodes for a range
|
||||
• |vim.treesitter.get_node()| now takes an option `include_anonymous`, default
|
||||
false, which allows it to return anonymous nodes as well as named nodes.
|
||||
• |treesitter-directive-trim!| can trim all whitespace (not just empty lines)
|
||||
from both sides of a node.
|
||||
• |vim.treesitter.get_captures_at_pos()| now returns the `id` of each capture
|
||||
• New |TSNode:child_with_descendant()|, which efficiently gets the node's
|
||||
child that contains a given node as descendant.
|
||||
• |LanguageTree:parse()| optionally supports asynchronous invocation, which is
|
||||
activated by passing the `on_parse` callback parameter.
|
||||
• |vim.treesitter.query.set()| can now inherit and/or extend runtime file
|
||||
queries in addition to overriding.
|
||||
• |LanguageTree:is_valid()| now accepts a range parameter to narrow the scope
|
||||
of the validity check.
|
||||
• |:InspectTree| now shows which nodes are missing.
|
||||
• Bundled markdown highlight queries use `conceal_lines` metadata to conceal
|
||||
code block fence lines vertically.
|
||||
• |vim.treesitter.language.inspect()| shows additional information, including
|
||||
parser version for ABI 15 parsers.
|
||||
• |TSQuery:disable_pattern()| and |TSQuery:disable_capture()| to turn off
|
||||
a specific pattern or capture in a query.
|
||||
• |vim.treesitter.get_captures_at_pos()| returns the `pattern_id` of the
|
||||
pattern used to match each capture.
|
||||
• |Query:iter_captures()| now accepts an `opts` parameter, similar to
|
||||
|Query:iter_matches()|.
|
||||
|
||||
TUI
|
||||
|
||||
• The builtin UI declares info |nvim_set_client_info()| on its channel. See
|
||||
|startup-tui|. To see the current UI info, try this: >
|
||||
:lua =vim.api.nvim_get_chan_info(vim.api.nvim_list_uis()[1].chan)
|
||||
• |log| messages written by the builtin UI client (TUI, |--remote-ui|) are
|
||||
now prefixed with "ui" instead of "?".
|
||||
• The TUI will re-query the terminal's background color when a theme update
|
||||
notification is received and Nvim will update 'background' accordingly.
|
||||
|
||||
UI
|
||||
|
||||
• |:detach| the current UI, let the Nvim server continue running as a background
|
||||
process. Works with the builtin TUI, and all GUIs.
|
||||
• |vim.ui.open()| (by default bound to |gx|) accepts an `opt.cmd` parameter
|
||||
which controls the tool used to open the given path or URL. If you want to
|
||||
globally set this, you can override vim.ui.open using the same approach
|
||||
described at |vim.paste()|.
|
||||
• `vim.ui.open()` now supports
|
||||
[lemonade](https://github.com/lemonade-command/lemonade) as an option for
|
||||
opening urls/files. This is handy if you are in an ssh connection and use
|
||||
`lemonade`.
|
||||
• The |ins-completion-menu| now supports cascading highlight styles.
|
||||
|hl-PmenuSel| and |hl-PmenuMatch| both inherit from |hl-Pmenu|, and
|
||||
|hl-PmenuMatchSel| inherits highlights from both |hl-PmenuSel| and
|
||||
|hl-PmenuMatch|.
|
||||
• |vim.diagnostic.setqflist()| updates an existing quickfix list with the
|
||||
given title if found
|
||||
• |ui-messages| content chunks now also contain the highlight group ID.
|
||||
• |:checkhealth| can display in a floating window, controlled by the
|
||||
|g:health| variable.
|
||||
|
||||
VIMSCRIPT
|
||||
|
||||
• |getchar()| and |getcharstr()| have optional {opts} |Dict| argument to control:
|
||||
cursor behavior, return type, and whether to simplify the returned key.
|
||||
|
||||
==============================================================================
|
||||
CHANGED FEATURES
|
||||
|
||||
These existing features changed their behavior.
|
||||
|
||||
• 'scrollbind' now works properly with buffers that contain virtual lines.
|
||||
|
||||
Scrollbind works by aligning to a target top line of each window in a tab
|
||||
page. Previously this was done by calculating the difference between the old
|
||||
top line and the target top line, and scrolling by that amount. Now the
|
||||
top lines are calculated using screen line numbers which take virtual lines
|
||||
into account.
|
||||
|
||||
• The implementation of grapheme clusters (or combining chars |mbyte-combining|)
|
||||
was upgraded to closely follow extended grapheme clusters as defined by UAX#29
|
||||
in the unicode standard. Noteworthily, this enables proper display of many
|
||||
more emoji characters than before, including those encoded with multiple
|
||||
emoji codepoints combined with ZWJ (zero width joiner) codepoints.
|
||||
|
||||
This also applies to :terminal output, where width of cells will be calculated
|
||||
using the upgraded implementation.
|
||||
|
||||
• Custom highlights in 'rulerformat', 'statuscolumn', 'statusline', 'tabline',
|
||||
'winbar', and the sign/number column are stacked with their respective
|
||||
highlight groups, as opposed to |hl-Normal|.
|
||||
This is also reflected in the `highlights` from |nvim_eval_statusline()|,
|
||||
with a new `groups` field containing an array of stacked highlight groups.
|
||||
|
||||
• |vim.on_key()| callbacks won't be invoked recursively when a callback itself
|
||||
consumes input.
|
||||
|
||||
• "q" in man pages now uses |CTRL-W_q| instead of |CTRL-W_c| to close the
|
||||
current window, and it no longer throws |E444| when there is only one window
|
||||
on the screen. Global variable `vim.g.pager` is removed.
|
||||
|
||||
• Default 'titlestring' is now implemented with 'statusline' "%" format items.
|
||||
This means the default, empty value is essentially an alias to:
|
||||
`%t%(\ %M%)%(\ \(%{expand(\"%:~:h\")}\)%)%a\ -\ Nvim`. This is only an
|
||||
implementation simplification, not a behavior change.
|
||||
|
||||
==============================================================================
|
||||
REMOVED FEATURES
|
||||
|
||||
These deprecated features were removed.
|
||||
|
||||
• option `severity_limit` for `vim.lsp.diagnostic` (use `min=severity`
|
||||
instead |vim.diagnostic.severity|).
|
||||
|
||||
==============================================================================
|
||||
DEPRECATIONS
|
||||
|
||||
See |deprecated-0.11|.
|
||||
|
||||
vim:tw=78:ts=8:sw=2:et:ft=help:norl:
|
@ -140,7 +140,7 @@ The following new APIs or features were added.
|
||||
|
||||
• 'diffopt' now includes a `linematch` option to enable a second-stage diff on
|
||||
individual hunks to provide much more accurate diffs. This option is also
|
||||
available to |vim.diff()|
|
||||
available to |vim.text.diff()|
|
||||
|
||||
See https://github.com/neovim/neovim/pull/14537.
|
||||
|
||||
|
@ -4,12 +4,41 @@
|
||||
NVIM REFERENCE MANUAL
|
||||
|
||||
|
||||
Notable changes since Nvim 0.10 *news*
|
||||
Notable changes since Nvim 0.11 *news*
|
||||
|
||||
For changes in the previous release, see |news-0.10|.
|
||||
For changes in the previous release, see |news-0.11|.
|
||||
|
||||
Type |gO| to see the table of contents.
|
||||
|
||||
==============================================================================
|
||||
BREAKING CHANGES IN HEAD OR EXPERIMENTAL *news-breaking-dev*
|
||||
|
||||
====== Remove this section before release. ======
|
||||
|
||||
The following changes to UNRELEASED features were made during the development
|
||||
cycle (Nvim HEAD, the "master" branch).
|
||||
|
||||
EVENTS
|
||||
|
||||
• Renamed "nvim.find_exrc" |default-autocmds| group to "nvim.exrc".
|
||||
|
||||
EXPERIMENTS
|
||||
|
||||
• todo
|
||||
|
||||
LSP
|
||||
|
||||
• |vim.lsp.buf.selection_range()| now accepts an integer which specifies its
|
||||
direction, rather than a string `'outer'` or `'inner'`.
|
||||
|
||||
OPTIONS
|
||||
|
||||
• todo
|
||||
|
||||
TREESITTER
|
||||
|
||||
• todo
|
||||
|
||||
==============================================================================
|
||||
BREAKING CHANGES *news-breaking*
|
||||
|
||||
@ -17,143 +46,75 @@ These changes may require adaptations in your config or plugins.
|
||||
|
||||
API
|
||||
|
||||
• `vim.rpcnotify(0)` and `rpcnotify(0)` broadcast to ALL channels. Previously
|
||||
they would "multicast" only to subscribed channels (controlled by
|
||||
`nvim_subscribe()`). Plugins and clients that want "multicast" behavior must
|
||||
now maintain their own list of channels.
|
||||
• In the future, |vim.rpcnotify()| may accept a list of channels, if there
|
||||
is demand for this use-case.
|
||||
• "Dictionary" was renamed to "Dict" internally and in the RPC |api-metadata|.
|
||||
This is not expected to break clients because there are no known clients
|
||||
that actually use the `return_type` field or the parameter type names
|
||||
reported by |--api-info| or |nvim_get_api_info()|.
|
||||
• Renamed `nvim__id_dictionary` (unsupported/experimental API) to
|
||||
`nvim__id_dict`.
|
||||
• todo
|
||||
|
||||
BUILD
|
||||
|
||||
• On Windows, only building with the UCRT runtime is supported.
|
||||
• Translations are turned off by default. Enable by building Nvim with the
|
||||
CMake flag `ENABLE_TRANSLATIONS=ON`.
|
||||
• todo
|
||||
|
||||
DIAGNOSTICS
|
||||
|
||||
• The "underline" diagnostics handler sorts diagnostics by severity when using
|
||||
the "severity_sort" option.
|
||||
• Diagnostics are filtered by severity before being passed to a diagnostic
|
||||
handler |diagnostic-handlers|.
|
||||
• The "virtual_text" handler is disabled by default. Enable with >lua
|
||||
vim.diagnostic.config({ virtual_text = true })
|
||||
<
|
||||
• |diagnostic-signs| can no longer be configured with |:sign-define| or
|
||||
|sign_define()| (deprecated in Nvim 0.10 |deprecated-0.10|).
|
||||
• |vim.diagnostic.disable()| and |vim.diagnostic.is_disabled()| (deprecated in
|
||||
Nvim 0.10 |deprecated-0.10|) are removed.
|
||||
• The legacy signature of |vim.diagnostic.enable()| (deprecated in Nvim 0.10
|
||||
|deprecated-0.10|) is no longer supported.
|
||||
|
||||
EDITOR
|
||||
|
||||
• The order in which signs are placed was changed. Higher priority signs will
|
||||
now appear left of lower priority signs.
|
||||
• |hl-CurSearch| now behaves the same as Vim and no longer updates on every
|
||||
cursor movement.
|
||||
• Moving in the buffer list using |:bnext| and similar commands behaves as
|
||||
documented and skips help buffers if run from a non-help buffer, otherwise
|
||||
it moves to another help buffer.
|
||||
• Bells from a |terminal| buffer are now silent by default, unless 'belloff'
|
||||
option doesn't contain "term" or "all".
|
||||
• todo
|
||||
|
||||
EVENTS
|
||||
|
||||
• |vim.ui_attach()| callbacks for |ui-messages| `msg_show` events are executed in
|
||||
|api-fast| context.
|
||||
• New/enhanced arguments in these existing UI events:
|
||||
• `cmdline_hide`: `abort` argument indicating if the cmdline was aborted.
|
||||
• `cmdline_show`:
|
||||
• Prompts that were previously emitted as `msg_show` events, are now routed
|
||||
through `cmdline_show`.
|
||||
• `hl_id` argument to highlight the prompt text.
|
||||
• `msg_show`:
|
||||
• `history` argument indicating if the message was added to the history.
|
||||
• new message kinds: "bufwrite", "completion", "list_cmd", "lua_print",
|
||||
"search_cmd", "shell_out/err/ret", "undo", "verbose", wildlist".
|
||||
• |TermRequest| and |TermResponse| |event-data| is now a table. The "sequence"
|
||||
field contains the received sequence. |TermRequest| also contains a "cursor"
|
||||
field indicating the cursor's position when the sequence was received.
|
||||
• |ui-messages| no longer emits the `msg_show.return_prompt`, and
|
||||
`msg_history_clear` events. The `msg_clear` event was repurposed and is now
|
||||
emitted after the screen is cleared. These events arbitrarily assumed a
|
||||
message UI that mimicks the legacy message grid. Benefit: reduced UI event
|
||||
traffic and more flexibility for UIs.
|
||||
The `msg_history_show` event has an additional "prev_cmd" argument.
|
||||
• A new `empty` message kind is emitted for an empty (e.g. `:echo ""`) message.
|
||||
|
||||
HIGHLIGHTS
|
||||
|
||||
• |TermCursorNC| is removed and no longer supported. Unfocused terminals no
|
||||
longer have a cursor.
|
||||
• todo
|
||||
|
||||
LSP
|
||||
|
||||
• |vim.lsp.buf.references()|, |vim.lsp.buf.declaration()|, |vim.lsp.buf.definition()|,
|
||||
|vim.lsp.buf.type_definition()|, |vim.lsp.buf.implementation()| and
|
||||
|vim.lsp.buf.hover()| now support merging the results of multiple clients
|
||||
but no longer trigger the global handlers from `vim.lsp.handlers`
|
||||
• |vim.lsp.buf.typehierarchy()| now passes the correct params for each
|
||||
client request.
|
||||
• |vim.lsp.handlers.signature_help()| is no longer used.
|
||||
• |vim.lsp.diagnostic.on_publish_diagnostics()| and
|
||||
|vim.lsp.diagnostic.on_diagnostic()| no longer accept a config parameter and
|
||||
can no longer be configured with |vim.lsp.with()|.
|
||||
Instead use: >lua
|
||||
vim.diagnostic.config(config, vim.lsp.diagnostic.get_namespace(client_id))
|
||||
<
|
||||
• |vim.lsp.util.make_position_params()|, |vim.lsp.util.make_range_params()|
|
||||
and |vim.lsp.util.make_given_range_params()| now require the `position_encoding`
|
||||
parameter.
|
||||
• |vim.lsp.util.symbols_to_items()| now requires the `position_encoding` parameter.
|
||||
• `root_markers` in |vim.lsp.Config| can now be ordered by priority.
|
||||
• The function set with |vim.lsp.log.set_format_func()| is now given all
|
||||
arguments corresponding to a log entry instead of the individual arguments.
|
||||
• `vim.lsp.semantic_tokens.start/stop` now renamed to
|
||||
`vim.lsp.semantic_tokens.enable`
|
||||
|
||||
LUA
|
||||
|
||||
• API functions now consistently return an empty dictionary as
|
||||
|vim.empty_dict()|. Earlier, a |lua-special-tbl| was sometimes used.
|
||||
• |vim.json.encode()| no longer escapes forward slashes "/" by default
|
||||
• Renamed `vim.diff` to `vim.text.diff`.
|
||||
• |vim.net.request()| adds a minimal HTTP GET API using curl.
|
||||
|
||||
OPTIONS
|
||||
|
||||
• The 'statuscolumn' `%l` item can now be used as a number column segment that
|
||||
changes according to related options. It takes care of alignment, 'number',
|
||||
'relativenumber' and 'signcolumn' set to "number". The now redundant `%r` item
|
||||
is no longer treated specially for 'statuscolumn'.
|
||||
• `:set {option}<` removes the local value for all |global-local| options instead
|
||||
of just string |global-local| options.
|
||||
• `:setlocal {option}<` copies the global value to the local value for number
|
||||
and boolean |global-local| options instead of removing the local value.
|
||||
• Setting |hidden-options| now gives an error. In particular, setting
|
||||
'noshellslash' is now only allowed on Windows.
|
||||
• 'shelltemp' defaults to "false".
|
||||
|
||||
PLUGINS
|
||||
|
||||
• TODO
|
||||
• todo
|
||||
|
||||
TREESITTER
|
||||
|
||||
• |Query:iter_matches()| correctly returns all matching nodes in a match
|
||||
instead of only the last node. This means that the returned table maps
|
||||
capture IDs to a list of nodes that need to be iterated over. For
|
||||
backwards compatibility, an option `all=false` (only return the last
|
||||
matching node) is provided that will be removed in a future release.
|
||||
• |vim.treesitter.language.get_filetypes()| always includes the {language}
|
||||
argument in addition to explicitly registered filetypes.
|
||||
• |vim.treesitter.language.get_lang()| falls back to the {filetype} argument
|
||||
if no languages are explicitly registered.
|
||||
• |vim.treesitter.language.add()| returns `true` if a parser was loaded
|
||||
successfully and `nil,errmsg` otherwise instead of throwing an error.
|
||||
• |vim.treesitter.get_parser()| and |vim.treesitter.start()| no longer parse
|
||||
the tree before returning. Scripts must call |LanguageTree:parse()| explicitly. >lua
|
||||
local p = vim.treesitter.get_parser(0, 'c')
|
||||
p:parse()
|
||||
• |vim.treesitter.get_parser()| expects its buffer to be loaded.
|
||||
<
|
||||
• |treesitter-directive-offset!| can now be applied to quantified captures. It
|
||||
no longer sets `metadata[capture_id].range`; it instead sets
|
||||
`metadata[capture_id].offset`. The offset will be applied in
|
||||
|vim.treesitter.get_range()|, which should be preferred over reading
|
||||
metadata directly for retrieving node ranges.
|
||||
|
||||
TUI
|
||||
|
||||
• OSC 52 is used as a fallback clipboard provider when no other
|
||||
|clipboard-tool| is found, even when not using SSH |clipboard-osc52|. To
|
||||
disable OSC 52 queries, set the "osc52" key of |g:termfeatures| to false.
|
||||
• todo
|
||||
|
||||
VIMSCRIPT
|
||||
|
||||
• |v:msgpack_types| has the type "binary" removed. |msgpackparse()| no longer
|
||||
treats BIN, STR and FIXSTR as separate types. Any of these is returned as a
|
||||
string if possible, or a |blob| if the value contained embedded NUL:s.
|
||||
• todo
|
||||
|
||||
==============================================================================
|
||||
NEW FEATURES *news-features*
|
||||
@ -162,340 +123,205 @@ The following new features were added.
|
||||
|
||||
API
|
||||
|
||||
• Improved API "meta" docstrings and :help documentation.
|
||||
• |nvim__ns_set()| can set properties for a namespace
|
||||
• |nvim_echo()| `err` field to print error messages and `chunks` accepts
|
||||
highlight group IDs.
|
||||
• |nvim_open_win()| supports a `mouse` field that allows configuring mouse
|
||||
interaction with the window separately from `focusable` field.
|
||||
• |nvim_open_win()| `relative` field can be set to "laststatus" and "tabline".
|
||||
• Additions to |nvim_buf_set_extmark()|:
|
||||
• `conceal_lines` field to conceal an entire line.
|
||||
• `hl_group` field can be an array of layered groups.
|
||||
• `virt_text_pos` field accepts value `eol_right_align` to allow for right
|
||||
aligned text that truncates before covering up buffer text.
|
||||
• `virt_lines_overflow` field accepts value `scroll` to enable horizontal
|
||||
scrolling for virtual lines with 'nowrap'.
|
||||
• |vim.hl.range()| now has a optional `timeout` field which allows for a timed highlight
|
||||
• |api-contract| allows existing functions to change return-type from `void =>
|
||||
non-void`.
|
||||
• |nvim_win_text_height()| can limit the lines checked when a certain
|
||||
`max_height` is reached, and returns the `end_row` and `end_vcol` for which
|
||||
`max_height` or the calculated height is reached.
|
||||
• |vim.secure.read()| now returns `true` for trusted directories. Previously
|
||||
it would return `nil`, which made it impossible to tell if the directory was
|
||||
actually trusted.
|
||||
• Added |vim.lsp.is_enabled()| to check if a given LSP config has been enabled
|
||||
by |vim.lsp.enable()|.
|
||||
• |nvim_echo()| can set the |ui-messages| kind with which to emit the message.
|
||||
|
||||
BUILD
|
||||
|
||||
• A Zig-based build system has been added as an alternative to CMake. It is
|
||||
currently limited in functionality, and CMake remains the recommended option
|
||||
for the time being.
|
||||
|
||||
DEFAULTS
|
||||
|
||||
• Highlighting:
|
||||
• Improved styling of :checkhealth and :help buffers.
|
||||
|
||||
• 'statusline' default is exposed as a statusline expression (previously it
|
||||
was implemented as an internal C routine).
|
||||
• Project-local configuration ('exrc') is also loaded from parent directories.
|
||||
Unset 'exrc' to stop further search.
|
||||
• Mappings:
|
||||
• |grn| in Normal mode maps to |vim.lsp.buf.rename()|
|
||||
• |grr| in Normal mode maps to |vim.lsp.buf.references()|
|
||||
• |gri| in Normal mode maps to |vim.lsp.buf.implementation()|
|
||||
• |gO| in Normal mode maps to |vim.lsp.buf.document_symbol()|
|
||||
• |gra| in Normal and Visual mode maps to |vim.lsp.buf.code_action()|
|
||||
• CTRL-S in Insert and Select mode maps to |vim.lsp.buf.signature_help()|
|
||||
• Mouse |popup-menu| includes an "Open in web browser" item when you right-click
|
||||
on a URL.
|
||||
• Mouse |popup-menu| includes a "Go to definition" item when LSP is active
|
||||
in the buffer.
|
||||
• Mouse |popup-menu| includes "Show Diagnostics", "Show All Diagnostics" and
|
||||
"Configure Diagnostics" items when there are diagnostics in the buffer.
|
||||
• |]d-default| and |[d-default| accept a count.
|
||||
• |[D-default| and |]D-default| jump to the first and last diagnostic in the
|
||||
current buffer, respectively.
|
||||
• Mappings inspired by Tim Pope's vim-unimpaired:
|
||||
• |[q|, |]q|, |[Q|, |]Q|, |[CTRL-Q|, |]CTRL-Q| navigate through the |quickfix| list
|
||||
• |[l|, |]l|, |[L|, |]L|, |[CTRL-L|, |]CTRL-L| navigate through the |location-list|
|
||||
• |[t|, |]t|, |[T|, |]T|, |[CTRL-T|, |]CTRL-T| navigate through the |tag-matchlist|
|
||||
• |[a|, |]a|, |[A|, |]A| navigate through the |argument-list|
|
||||
• |[b|, |]b|, |[B|, |]B| navigate through the |buffer-list|
|
||||
• |[<Space>|, |]<Space>| add an empty line above and below the cursor
|
||||
• |[[| and |]]| in Normal mode jump between shell prompts for shells which emit
|
||||
OSC 133 sequences ("shell integration" or "semantic prompts").
|
||||
|
||||
• Options:
|
||||
• 'diffopt' default includes "linematch:40".
|
||||
• 'number', 'relativenumber', 'signcolumn', and 'foldcolumn' are disabled in
|
||||
|terminal| buffers. |terminal-config| shows how to change these defaults.
|
||||
• Lua |ftplugin| sets 'omnifunc' to "v:lua.vim.lua_omnifunc".
|
||||
• Lua |ftplugin| sets 'foldexpr' to "v:lua.vim.treesitter.foldexpr()".
|
||||
|
||||
• Snippet:
|
||||
• `<Tab>` in Insert and Select mode maps to `vim.snippet.jump({ direction = 1 })`
|
||||
when a snippet is active and jumpable forwards.
|
||||
• `<S-Tab>` in Insert and Select mode maps to `vim.snippet.jump({ direction = -1 })`
|
||||
when a snippet is active and jumpable backwards.
|
||||
• |grt| in Normal mode maps to |vim.lsp.buf.type_definition()|
|
||||
|
||||
DIAGNOSTICS
|
||||
|
||||
• |vim.diagnostic.config()| accepts a "jump" table to specify defaults for
|
||||
|vim.diagnostic.jump()|.
|
||||
• A "virtual_lines" diagnostic handler was added to render diagnostics using
|
||||
virtual lines below the respective code.
|
||||
• The "virtual_text" diagnostic handler accepts a `current_line` option to
|
||||
only show virtual text at the cursor's line.
|
||||
• |vim.diagnostic.setloclist()| and |vim.diagnostic.setqflist()| now support a
|
||||
`format` function to modify (or filter) diagnostics before being set in the
|
||||
location/quickfix list.
|
||||
• |vim.diagnostic.get()| now accepts an `enabled` filter to only return
|
||||
enabled or disabled diagnostics.
|
||||
|
||||
EDITOR
|
||||
|
||||
• Improved |paste| handling for redo (dot-repeat) and macros (|recording|):
|
||||
• Redoing a large paste is significantly faster and ignores 'autoindent'.
|
||||
• Replaying a macro with |@| also replays pasted text.
|
||||
• On Windows, filename arguments on the command-line prefixed with "~\" or
|
||||
"~/" are now expanded to the user's profile directory, not a relative path
|
||||
to a literal "~" directory.
|
||||
• |hl-ComplMatchIns| shows matched text of the currently inserted completion.
|
||||
• |hl-PmenuMatch| and |hl-PmenuMatchSel| show matched text in completion popup.
|
||||
• |gO| now works in `help`, `checkhealth`, and `markdown` buffers.
|
||||
• Jump between sections in `help` and `checkhealth` buffers with `[[` and
|
||||
`]]`.
|
||||
• |:iput| works like |:put| but adjusts indent.
|
||||
• |:retab| accepts new optional parameter -indentonly to only change leading
|
||||
whitespace in indented lines.
|
||||
• |:uniq| deduplicates text in the current buffer.
|
||||
• |omnicompletion| in `help` buffer. |ft-help-omni|
|
||||
• Setting "'0" in 'shada' prevents storing the jumplist in the shada file.
|
||||
• 'shada' now correctly respects "/0" and "f0".
|
||||
• |prompt-buffer| supports multiline input/paste, undo/redo, and o/O normal
|
||||
commands.
|
||||
• 'wildchar' now enables completion in search contexts using |/|, |?|, |:g|, |:v|
|
||||
and |:vimgrep| commands.
|
||||
|
||||
EVENTS
|
||||
|
||||
• |CompleteDone| now sets the `reason` key in `v:event` which specifies the reason
|
||||
for completion being done.
|
||||
• |vim.on_key()| callbacks can consume the key by returning an empty string.
|
||||
• |CmdlineLeavePre| triggered before preparing to leave the command line.
|
||||
• New `append` paremeter for |ui-messages| `msg_show` event.
|
||||
|
||||
HIGHLIGHTS
|
||||
|
||||
• |hl-DiffTextAdd| highlights added text within a changed line.
|
||||
• |hl-StderrMsg| |hl-StdoutMsg|
|
||||
|
||||
LSP
|
||||
|
||||
• Improved rendering of LSP hover docs. |K-lsp-default|
|
||||
• |vim.lsp.completion.enable()| gained the `convert` callback which enables
|
||||
customizing the transformation of an LSP CompletionItem to |complete-items|.
|
||||
• |vim.lsp.diagnostic.from()| can be used to convert a list of
|
||||
|vim.Diagnostic| objects into their LSP diagnostic representation.
|
||||
• `:checkhealth vim.lsp` displays the server version (if available).
|
||||
• Completion side effects (including snippet expansion, execution of commands
|
||||
and application of additional text edits) is now built-in.
|
||||
• |vim.lsp.util.locations_to_items()| and |vim.lsp.util.symbols_to_items()| now
|
||||
sets `end_col` and `end_lnum` fields.
|
||||
• |vim.lsp.buf.format()| now supports passing a list of ranges
|
||||
via the `range` parameter (this requires support for the
|
||||
`textDocument/rangesFormatting` request).
|
||||
• |vim.lsp.buf.code_action()| actions show client name when there are multiple
|
||||
clients.
|
||||
• |vim.lsp.buf.signature_help()| can now cycle through different signatures
|
||||
using `<C-s>` and also support multiple clients.
|
||||
• The client now supports `'utf-8'` and `'utf-32'` position encodings.
|
||||
• |vim.lsp.buf.hover()| now highlights hover ranges using the
|
||||
|hl-LspReferenceTarget| highlight group.
|
||||
• Functions in |vim.lsp.Client| can now be called as methods.
|
||||
• Implemented LSP folding: |vim.lsp.foldexpr()|
|
||||
https://microsoft.github.io/language-server-protocol/specification/#textDocument_foldingRange
|
||||
• |vim.lsp.config()| has been added to define default configurations for
|
||||
servers. In addition, configurations can be specified in `lsp/<name>.lua`.
|
||||
• |vim.lsp.enable()| has been added to enable servers.
|
||||
• |vim.lsp.buf.code_action()| resolves the `command` property during the
|
||||
`codeAction/resolve` request.
|
||||
• The `textDocument/completion` request now includes the completion context in
|
||||
its parameters.
|
||||
• |vim.lsp.ClientConfig| gained `workspace_required`.
|
||||
• You can control priority of |vim.lsp.Config| `root_markers`.
|
||||
• Support for `textDocument/documentColor`: |lsp-document_color|
|
||||
https://microsoft.github.io/language-server-protocol/specification/#textDocument_documentColor
|
||||
• Support for `textDocument/colorPresentation |lsp-document_color|
|
||||
https://microsoft.github.io/language-server-protocol/specification/#textDocument_colorPresentation
|
||||
• The `textDocument/diagnostic` request now includes the previous id in its
|
||||
parameters.
|
||||
• |vim.lsp.enable()| start/stops clients as necessary. And detaches
|
||||
non-applicable LSP clients.
|
||||
• |vim.lsp.is_enabled()| checks if a LSP config is enabled (without
|
||||
"resolving" it).
|
||||
• Support for `workspace/diagnostic`: |vim.lsp.buf.workspace_diagnostics()|
|
||||
https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_dagnostics
|
||||
• Incremental selection is now supported via `textDocument/selectionRange`.
|
||||
`an` selects outwards and `in` selects inwards.
|
||||
• Support for multiline semantic tokens.
|
||||
• Support for the `disabled` field on code actions.
|
||||
• The function form of `cmd` in a vim.lsp.Config or vim.lsp.ClientConfig
|
||||
receives the resolved config as the second arg: `cmd(dispatchers, config)`.
|
||||
• Support for annotated text edits.
|
||||
• `:checkhealth vim.lsp` is now available to check which buffers the active LSP features are attached to.
|
||||
• LSP `DiagnosticRelatedInformation` is now shown in
|
||||
|vim.diagnostic.open_float()|. It is read from the LSP diagnostic object
|
||||
stored in the `user_data` field.
|
||||
• When inside the float created by |vim.diagnostic.open_float()| and the
|
||||
cursor is on a line with `DiagnosticRelatedInformation`, |gf| can be used to
|
||||
jump to the problematic location.
|
||||
• Support for `textDocument/linkedEditingRange`: |lsp-linked_editing_range|
|
||||
https://microsoft.github.io/language-server-protocol/specification/#textDocument_linkedEditingRange
|
||||
• Support for related documents in pull diagnostics:
|
||||
https://microsoft.github.io/language-server-protocol/specifications/specification-current/#relatedFullDocumentDiagnosticReport
|
||||
|
||||
LUA
|
||||
|
||||
• Command-line completions for: `vim.g`, `vim.t`, `vim.w`, `vim.b`, `vim.v`,
|
||||
`vim.o`, `vim.wo`, `vim.bo`, `vim.opt`, `vim.opt_local`, `vim.opt_global`,
|
||||
and `vim.fn`.
|
||||
• Documentation for |lua-bit|.
|
||||
• |gf| in Lua buffers can go to module in same repo, |runtime-search-path| and
|
||||
|package.path|.
|
||||
• |vim.fs.rm()| can delete files and directories.
|
||||
• |vim.validate()| now has a new signature which uses less tables,
|
||||
is more performant and easier to read.
|
||||
• |vim.str_byteindex()| and |vim.str_utfindex()| gained overload signatures
|
||||
supporting two new parameters, `encoding` and `strict_indexing`.
|
||||
• |vim.json.encode()| has an option to enable forward slash escaping
|
||||
• |vim.fs.abspath()| converts paths to absolute paths.
|
||||
• |vim.fs.relpath()| gets relative path compared to base path.
|
||||
• |vim.fs.dir()| and |vim.fs.find()| can now follow symbolic links,
|
||||
the behavior can be turn on using the new `follow` option.
|
||||
• |vim.text.indent()| indents/dedents text.
|
||||
• Lua type annotations for `vim.uv`.
|
||||
• |vim.hl.range()| now allows multiple timed highlights.
|
||||
• |vim.tbl_extend()| and |vim.tbl_deep_extend()| now accept a function behavior argument.
|
||||
• |vim.fs.root()| can define "equal priority" via nested lists.
|
||||
• |vim.version.range()| output can be converted to human-readable string with |tostring()|.
|
||||
• |vim.version.intersect()| computes intersection of two version ranges.
|
||||
• |Iter:take()| and |Iter:skip()| now optionally accept predicates.
|
||||
• Built-in plugin manager |vim.pack|
|
||||
|
||||
OPTIONS
|
||||
|
||||
• 'completeopt' flag "fuzzy" enables |fuzzy-matching| during |ins-completion|.
|
||||
• 'completeopt' flag "preinsert" highlights text to be inserted.
|
||||
• 'wildmode' flag "noselect" shows 'wildmenu' without selecting an entry.
|
||||
• 'messagesopt' configures |:messages| and |hit-enter| prompt.
|
||||
• 'tabclose' controls which tab page to focus when closing a tab page.
|
||||
• 'eventignorewin' to persistently ignore events in a window.
|
||||
• 'winborder' sets the default border for |floating-windows|
|
||||
• 'autowriteall' writes all buffers upon receiving `SIGHUP`, `SIGQUIT` or `SIGTSTP`.
|
||||
• 'chistory' and 'lhistory' set size of the |quickfix-stack|.
|
||||
• 'completefuzzycollect' enables fuzzy collection of candidates for (some)
|
||||
|ins-completion| modes.
|
||||
• 'complete' new flags:
|
||||
• "F{func}" complete using given function
|
||||
• "F" complete using 'completefunc'
|
||||
• "o" complete using 'omnifunc'
|
||||
• 'complete' allows limiting matches for sources using "{flag}^<limit>".
|
||||
• 'completeopt' flag "nearset" sorts completion results by distance to cursor.
|
||||
• 'diffanchors' specifies addresses to anchor a diff.
|
||||
• 'diffopt' `inline:` configures diff highlighting for changes within a line.
|
||||
• 'grepformat' is now a |global-local| option.
|
||||
• 'maxsearchcount' sets maximum value for |searchcount()| and defaults to 999.
|
||||
• 'pummaxwidth' sets maximum width for the completion popup menu.
|
||||
• 'winborder' "bold" style, custom border style.
|
||||
• |g:clipboard| accepts a string name to force any builtin clipboard tool.
|
||||
• 'busy' sets a buffer "busy" status. Indicated in the default statusline.
|
||||
|
||||
PERFORMANCE
|
||||
|
||||
• Significantly reduced redraw time for long lines with treesitter
|
||||
highlighting.
|
||||
• LSP diagnostics and inlay hints are de-duplicated (new requests cancel
|
||||
inflight requests). This greatly improves performance with slow LSP servers.
|
||||
• 10x speedup for |vim.treesitter.foldexpr()| (when no parser exists for the
|
||||
buffer).
|
||||
• Strong |treesitter-query| caching makes repeat |vim.treesitter.query.get()|
|
||||
and |vim.treesitter.query.parse()| calls significantly faster for large
|
||||
queries.
|
||||
• Treesitter highlighting is now asynchronous. To force synchronous parsing,
|
||||
use `vim.g._ts_force_sync_parsing = true`.
|
||||
• Treesitter folding is now calculated asynchronously.
|
||||
• |LanguageTree:parse()| now only runs the injection query on the provided
|
||||
range (as long as the language does not have a combined injection),
|
||||
significantly improving |treesitter-highlight| performance.
|
||||
• Treesitter injection query iteration is now asynchronous, making edits in
|
||||
large buffers with combined injections much quicker.
|
||||
• 10x reduction in blocking time when attaching an LSP to a large buffer.
|
||||
• |vim.glob.to_lpeg()| uses a new LPeg-based implementation (Peglob) that
|
||||
provides ~50% speedup for complex patterns. The implementation restores
|
||||
support for nested braces and follows LSP 3.17 specification with
|
||||
additional constraints for improved correctness and resistance to
|
||||
backtracking edge cases.
|
||||
|
||||
PLUGINS
|
||||
|
||||
• EditorConfig
|
||||
• spelling_language property is now supported.
|
||||
• 'inccommand' incremental preview can run on 'nomodifiable' buffers and
|
||||
restores their 'modifiable' state
|
||||
• Commenting
|
||||
• 'commentstring' values can now be specified in a Treesitter capture's
|
||||
`bo.commentstring` metadata field, providing finer grained support for
|
||||
languages like `JSX`.
|
||||
• Customize :checkhealth by handling a `FileType checkhealth` event.
|
||||
|health-usage|
|
||||
|
||||
STARTUP
|
||||
|
||||
• |-es| ("script mode") disables shada by default.
|
||||
• Nvim will fail if the |--listen| or |$NVIM_LISTEN_ADDRESS| address is
|
||||
invalid, instead of silently skipping an invalid address.
|
||||
• todo
|
||||
|
||||
TERMINAL
|
||||
|
||||
• The |terminal| now understands the OSC 52 escape sequence to write to the
|
||||
system clipboard (copy). Querying with OSC 52 (paste) is not supported.
|
||||
• |hl-StatusLineTerm| and |hl-StatusLineTermNC| define highlights for the
|
||||
status line in |terminal| windows.
|
||||
• The terminal buffer now supports reflow (wrapped lines adapt when the buffer
|
||||
is resized horizontally). Note: Lines that are not visible and kept in
|
||||
'scrollback' are not reflown.
|
||||
• The |terminal| now supports OSC 8 escape sequences and will display
|
||||
hyperlinks in supporting host terminals.
|
||||
• The |terminal| now uses the actual cursor, rather than a "virtual" cursor.
|
||||
This means that escape codes sent by applications running in a terminal
|
||||
buffer can change the cursor shape and visibility. However, it also
|
||||
means that the |TermCursorNC| highlight group is no longer supported: an
|
||||
unfocused terminal window will have no cursor at all (so there is nothing to
|
||||
highlight).
|
||||
• |jobstart()| gained the "term" flag.
|
||||
• The |terminal| will send theme update notifications when 'background' is
|
||||
changed and DEC mode 2031 is enabled.
|
||||
• The |terminal| has experimental support for the Kitty keyboard protocol
|
||||
(sometimes called "CSI u" key encoding). Only the "Disambiguate escape
|
||||
codes" mode is currently supported.
|
||||
• The |terminal| emits a |TermRequest| autocommand event when the child process
|
||||
emits an APC control sequence.
|
||||
• |TermRequest| has a "cursor" field in its |event-data| indicating the
|
||||
cursor position when the sequence was received.
|
||||
• |nvim_open_term()| can be called with a non-empty buffer. The buffer
|
||||
contents are piped to the PTY and displayed as terminal output.
|
||||
|
||||
TREESITTER
|
||||
|
||||
• |LanguageTree:node_for_range()| gets anonymous and named nodes for a range
|
||||
• |vim.treesitter.get_node()| now takes an option `include_anonymous`, default
|
||||
false, which allows it to return anonymous nodes as well as named nodes.
|
||||
• |treesitter-directive-trim!| can trim all whitespace (not just empty lines)
|
||||
from both sides of a node.
|
||||
• |vim.treesitter.get_captures_at_pos()| now returns the `id` of each capture
|
||||
• New |TSNode:child_with_descendant()|, which efficiently gets the node's
|
||||
child that contains a given node as descendant.
|
||||
• |LanguageTree:parse()| optionally supports asynchronous invocation, which is
|
||||
activated by passing the `on_parse` callback parameter.
|
||||
• |vim.treesitter.query.set()| can now inherit and/or extend runtime file
|
||||
queries in addition to overriding.
|
||||
• |LanguageTree:is_valid()| now accepts a range parameter to narrow the scope
|
||||
of the validity check.
|
||||
• |:InspectTree| now shows which nodes are missing.
|
||||
• Bundled markdown highlight queries use `conceal_lines` metadata to conceal
|
||||
code block fence lines vertically.
|
||||
• |vim.treesitter.language.inspect()| shows additional information, including
|
||||
parser version for ABI 15 parsers.
|
||||
• |TSQuery:disable_pattern()| and |TSQuery:disable_capture()| to turn off
|
||||
a specific pattern or capture in a query.
|
||||
• |vim.treesitter.get_captures_at_pos()| returns the `pattern_id` of the
|
||||
pattern used to match each capture.
|
||||
• |Query:iter_captures()| now accepts an `opts` parameter, similar to
|
||||
|Query:iter_matches()|.
|
||||
• todo
|
||||
|
||||
TUI
|
||||
|
||||
• The builtin UI declares info |nvim_set_client_info()| on its channel. See
|
||||
|startup-tui|. To see the current UI info, try this: >
|
||||
:lua =vim.api.nvim_get_chan_info(vim.api.nvim_list_uis()[1].chan)
|
||||
• |log| messages written by the builtin UI client (TUI, |--remote-ui|) are
|
||||
now prefixed with "ui" instead of "?".
|
||||
• The TUI will re-query the terminal's background color when a theme update
|
||||
notification is received and Nvim will update 'background' accordingly.
|
||||
• |TermResponse| now supports DA1 and APC query responses.
|
||||
|
||||
UI
|
||||
|
||||
• |:detach| the current UI, let the Nvim server continue running as a background
|
||||
process. Works with the builtin TUI, and all GUIs.
|
||||
• |vim.ui.open()| (by default bound to |gx|) accepts an `opt.cmd` parameter
|
||||
which controls the tool used to open the given path or URL. If you want to
|
||||
globally set this, you can override vim.ui.open using the same approach
|
||||
described at |vim.paste()|.
|
||||
• `vim.ui.open()` now supports
|
||||
[lemonade](https://github.com/lemonade-command/lemonade) as an option for
|
||||
opening urls/files. This is handy if you are in an ssh connection and use
|
||||
`lemonade`.
|
||||
• The |ins-completion-menu| now supports cascading highlight styles.
|
||||
|hl-PmenuSel| and |hl-PmenuMatch| both inherit from |hl-Pmenu|, and
|
||||
|hl-PmenuMatchSel| inherits highlights from both |hl-PmenuSel| and
|
||||
|hl-PmenuMatch|.
|
||||
• |vim.diagnostic.setqflist()| updates an existing quickfix list with the
|
||||
given title if found
|
||||
• |ui-messages| content chunks now also contain the highlight group ID.
|
||||
• |:checkhealth| can display in a floating window, controlled by the
|
||||
|g:health| variable.
|
||||
• |:restart| restarts Nvim and reattaches the current UI.
|
||||
• |:checkhealth| shows a summary in the header for every healthcheck.
|
||||
• |ui-multigrid| provides composition information and absolute coordinates.
|
||||
• `vim._extui` provides an experimental commandline and message UI intended to
|
||||
replace the message grid in the TUI.
|
||||
• Error messages are more concise:
|
||||
• "Error detected while processing:" changed to "Error in:".
|
||||
• "Error executing Lua:" changed to "Lua:".
|
||||
• 'busy' status is shown in default statusline with symbol ◐
|
||||
|
||||
VIMSCRIPT
|
||||
|
||||
• |getchar()| and |getcharstr()| have optional {opts} |Dict| argument to control:
|
||||
cursor behavior, return type, and whether to simplify the returned key.
|
||||
• |cmdcomplete_info()| gets current cmdline completion info.
|
||||
• |getcompletiontype()| gets command-line completion type for any string.
|
||||
• |prompt_getinput()| gets current user-input in prompt-buffer.
|
||||
• |wildtrigger()| triggers command-line expansion.
|
||||
|
||||
==============================================================================
|
||||
CHANGED FEATURES *news-changed*
|
||||
|
||||
These existing features changed their behavior.
|
||||
|
||||
• 'scrollbind' now works properly with buffers that contain virtual lines.
|
||||
|
||||
Scrollbind works by aligning to a target top line of each window in a tab
|
||||
page. Previously this was done by calculating the difference between the old
|
||||
top line and the target top line, and scrolling by that amount. Now the
|
||||
top lines are calculated using screen line numbers which take virtual lines
|
||||
into account.
|
||||
|
||||
• The implementation of grapheme clusters (or combining chars |mbyte-combining|)
|
||||
was upgraded to closely follow extended grapheme clusters as defined by UAX#29
|
||||
in the unicode standard. Noteworthily, this enables proper display of many
|
||||
more emoji characters than before, including those encoded with multiple
|
||||
emoji codepoints combined with ZWJ (zero width joiner) codepoints.
|
||||
|
||||
This also applies to :terminal output, where width of cells will be calculated
|
||||
using the upgraded implementation.
|
||||
|
||||
• Custom highlights in 'rulerformat', 'statuscolumn', 'statusline', 'tabline',
|
||||
'winbar', and the sign/number column are stacked with their respective
|
||||
highlight groups, as opposed to |hl-Normal|.
|
||||
This is also reflected in the `highlights` from |nvim_eval_statusline()|,
|
||||
with a new `groups` field containing an array of stacked highlight groups.
|
||||
|
||||
• |vim.on_key()| callbacks won't be invoked recursively when a callback itself
|
||||
consumes input.
|
||||
|
||||
• "q" in man pages now uses |CTRL-W_q| instead of |CTRL-W_c| to close the
|
||||
current window, and it no longer throws |E444| when there is only one window
|
||||
on the screen. Global variable `vim.g.pager` is removed.
|
||||
|
||||
• Default 'titlestring' is now implemented with 'statusline' "%" format items.
|
||||
This means the default, empty value is essentially an alias to:
|
||||
`%t%(\ %M%)%(\ \(%{expand(\"%:~:h\")}\)%)%a\ -\ Nvim`. This is only an
|
||||
implementation simplification, not a behavior change.
|
||||
• |gv| works in operator pending mode and does not abort.
|
||||
• 'smartcase' applies to completion filtering.
|
||||
• 'spellfile' location defaults to `stdpath("data").."/site/spell/"` instead of
|
||||
the first writable directory in 'runtimepath'.
|
||||
• |vim.version.range()| doesn't exclude `to` if it is equal to `from`.
|
||||
• |$VIM| and |$VIMRUNTIME| no longer check for Vim version-specific runtime
|
||||
directory `vim{number}` (e.g. `vim82`).
|
||||
• 'scrollback' maximum value increased from 100000 to 1000000
|
||||
|
||||
==============================================================================
|
||||
REMOVED FEATURES *news-removed*
|
||||
|
||||
These deprecated features were removed.
|
||||
|
||||
• option `severity_limit` for `vim.lsp.diagnostic` (use `min=severity`
|
||||
instead |vim.diagnostic.severity|).
|
||||
• todo
|
||||
|
||||
==============================================================================
|
||||
DEPRECATIONS *news-deprecations*
|
||||
|
||||
See |deprecated-0.11|.
|
||||
See |deprecated-0.12|.
|
||||
|
||||
vim:tw=78:ts=8:sw=2:et:ft=help:norl:
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user