mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-05-23 21:31:14 -03:00
Compare commits
804 Commits
Integratio
...
4.3.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c5bc7bd5f9 | ||
|
|
2b3bd29588 | ||
|
|
0be3f9e57e | ||
|
|
2524ece2cc | ||
|
|
b975472828 | ||
|
|
20427ff1f6 | ||
|
|
5b3b825ab2 | ||
|
|
ccd3348eed | ||
|
|
845b9be1f5 | ||
|
|
400f2b130a | ||
|
|
362f7cedf6 | ||
|
|
2c959469f0 | ||
|
|
6c34bcf8f6 | ||
|
|
f510b62b7f | ||
|
|
b31387416d | ||
|
|
941a6cb434 | ||
|
|
931072f5d1 | ||
|
|
f4f9db73da | ||
|
|
9ef3f30c56 | ||
|
|
d19c927760 | ||
|
|
22e5b21f10 | ||
|
|
f0d2444769 | ||
|
|
7975060e4a | ||
|
|
354dc3d272 | ||
|
|
7640e95bd7 | ||
|
|
767115a93d | ||
|
|
f0c8788a52 | ||
|
|
a3cbb01b27 | ||
|
|
d630b4ae8a | ||
|
|
a2c5b2a567 | ||
|
|
18295f4402 | ||
|
|
443fd604cc | ||
|
|
9e022ff7cf | ||
|
|
aba927054f | ||
|
|
bdfc491d56 | ||
|
|
b72127a0b7 | ||
|
|
0ab2a46424 | ||
|
|
5844650881 | ||
|
|
3c77a67668 | ||
|
|
3105f88622 | ||
|
|
5702b26b22 | ||
|
|
60ef7ca210 | ||
|
|
c486c54120 | ||
|
|
6273b9420b | ||
|
|
4bb0d956eb | ||
|
|
92db03ac9f | ||
|
|
0d6aaa36d3 | ||
|
|
88a7888478 | ||
|
|
74cb96d55b | ||
|
|
30942e16dc | ||
|
|
a8ded9cb0d | ||
|
|
4d67678217 | ||
|
|
9460559345 | ||
|
|
74af4f10de | ||
|
|
b2f4befc7e | ||
|
|
771b33b3a3 | ||
|
|
1cf4e191b3 | ||
|
|
b88a5eaad5 | ||
|
|
1c1baddf4f | ||
|
|
107cbaddf0 | ||
|
|
daa554123f | ||
|
|
979320063e | ||
|
|
fed0269762 | ||
|
|
6d68dfe12b | ||
|
|
97c59fa991 | ||
|
|
128fafce1e | ||
|
|
f1c8e6995d | ||
|
|
02061be279 | ||
|
|
c9b30b748d | ||
|
|
167cfd0892 | ||
|
|
5c3941f0dd | ||
|
|
d4745b633b | ||
|
|
dd97842964 | ||
|
|
5715d143a5 | ||
|
|
41571dec0f | ||
|
|
3c7517bf28 | ||
|
|
81fce66269 | ||
|
|
7b8f97c1ff | ||
|
|
9b75b6ee88 | ||
|
|
1ebf750bc0 | ||
|
|
dcd07d754d | ||
|
|
26873d4ad2 | ||
|
|
17c35217b9 | ||
|
|
b62a312cba | ||
|
|
3b976a3364 | ||
|
|
3df88597ca | ||
|
|
3ec603fc55 | ||
|
|
5545c648d9 | ||
|
|
765305d0e4 | ||
|
|
a261ca2aff | ||
|
|
556be5c4a8 | ||
|
|
92c5da1b25 | ||
|
|
fb161e9f4d | ||
|
|
67d78fb258 | ||
|
|
caef2c309d | ||
|
|
2f37eda9d9 | ||
|
|
5a35acf2e7 | ||
|
|
e1a6b7ea5a | ||
|
|
c9fcd31480 | ||
|
|
d6108e5bc0 | ||
|
|
2611646232 | ||
|
|
08600d012f | ||
|
|
16f14f0e89 | ||
|
|
50bcc3cf4f | ||
|
|
ee2d99ecf3 | ||
|
|
81e1f6937f | ||
|
|
03a3a3b52f | ||
|
|
074ab45049 | ||
|
|
aa8f5fc77e | ||
|
|
c0b95a0ee1 | ||
|
|
dd93a7e003 | ||
|
|
8064a13af9 | ||
|
|
ab7b522b64 | ||
|
|
0c9b73e317 | ||
|
|
b29a85f45f | ||
|
|
f0b4921ccf | ||
|
|
1d3aca2b44 | ||
|
|
574a8728af | ||
|
|
e7c1a6a67d | ||
|
|
54127e1028 | ||
|
|
a5330c7ba2 | ||
|
|
377abde112 | ||
|
|
62628f6fb1 | ||
|
|
64da7ca124 | ||
|
|
1db4dc4c3e | ||
|
|
ebc140a3ea | ||
|
|
5e401fc6ea | ||
|
|
608269320e | ||
|
|
c3a9edceac | ||
|
|
32cee9caec | ||
|
|
f417cbc981 | ||
|
|
92c814841a | ||
|
|
bf38e1beca | ||
|
|
17ba602acf | ||
|
|
5d37698ef8 | ||
|
|
7a7c0d6490 | ||
|
|
d88c0674a3 | ||
|
|
0306ec673f | ||
|
|
b14b6c9f42 | ||
|
|
8061c41c9b | ||
|
|
190d367bc4 | ||
|
|
f1f14cc8fa | ||
|
|
707bfe3ce6 | ||
|
|
d8f1a2a24f | ||
|
|
dbdecaba6d | ||
|
|
66f6493fbf | ||
|
|
76e0f9a3e8 | ||
|
|
697afdefeb | ||
|
|
aba89f9088 | ||
|
|
344187e01a | ||
|
|
9f11de24d4 | ||
|
|
7996637db5 | ||
|
|
d67cdf5f6f | ||
|
|
7dd2004da7 | ||
|
|
4000503c03 | ||
|
|
7c994cd784 | ||
|
|
e68ea35f02 | ||
|
|
5cc953b18d | ||
|
|
f264ee0b10 | ||
|
|
3c6978c038 | ||
|
|
d5732b132e | ||
|
|
ae22cc93db | ||
|
|
51e551fe5f | ||
|
|
33cb8679ba | ||
|
|
655b1aa7a1 | ||
|
|
daba5fdbcd | ||
|
|
01bd380d00 | ||
|
|
801c4f8158 | ||
|
|
e331e30e38 | ||
|
|
7bd30ac3c4 | ||
|
|
5631a7ec86 | ||
|
|
a9c43e7396 | ||
|
|
2a6c0e4437 | ||
|
|
7f224d0dfd | ||
|
|
f818002f38 | ||
|
|
6b8e82946a | ||
|
|
faaff2754b | ||
|
|
5c0e72bb89 | ||
|
|
b3b7d2cb00 | ||
|
|
f503dcb92d | ||
|
|
7f1b53a9f1 | ||
|
|
938e780007 | ||
|
|
3e7c5ae399 | ||
|
|
548f37eabb | ||
|
|
135fc73191 | ||
|
|
1fe5497b5d | ||
|
|
6b85450dea | ||
|
|
2309c27a2d | ||
|
|
8b5d66def8 | ||
|
|
27852a6734 | ||
|
|
cc29216ea9 | ||
|
|
831411ddd5 | ||
|
|
ec77c34ebe | ||
|
|
d1c7a4b6e7 | ||
|
|
7fc27e9e54 | ||
|
|
a4b949b0ca | ||
|
|
64196a2a9e | ||
|
|
353ecfadaf | ||
|
|
0e9ceb154e | ||
|
|
baaf06b2c6 | ||
|
|
106f7b86dc | ||
|
|
64e3b419b6 | ||
|
|
3237efc582 | ||
|
|
717d301b7f | ||
|
|
6a36d92173 | ||
|
|
75c005a4d4 | ||
|
|
07389055f1 | ||
|
|
692e6d57cf | ||
|
|
7952545460 | ||
|
|
4aa967cd5d | ||
|
|
3e2336043a | ||
|
|
c1db2744cf | ||
|
|
c6252967ab | ||
|
|
0fb5ab4098 | ||
|
|
de3d390391 | ||
|
|
76b0961e91 | ||
|
|
c0f91a50fa | ||
|
|
77fbd0a005 | ||
|
|
c9ab2c26aa | ||
|
|
b1769658f5 | ||
|
|
3518d4f6ad | ||
|
|
aa4ebd96f9 | ||
|
|
656b39a0b3 | ||
|
|
fceb600be5 | ||
|
|
47c773300a | ||
|
|
2d29749eae | ||
|
|
22a252d064 | ||
|
|
4642b28ea7 | ||
|
|
b8662f9c7f | ||
|
|
9af85f4c3b | ||
|
|
aa742f0b57 | ||
|
|
e648da98da | ||
|
|
94367b08ba | ||
|
|
97b45dc705 | ||
|
|
198768a1c7 | ||
|
|
7c27c1e7d0 | ||
|
|
9f8d8ebc2c | ||
|
|
87a312ccba | ||
|
|
838f48a861 | ||
|
|
52286f087d | ||
|
|
902d4be664 | ||
|
|
16a91f8e3c | ||
|
|
3cac5ff75e | ||
|
|
5210c16bfa | ||
|
|
8a75bccf00 | ||
|
|
5130fc6f17 | ||
|
|
b0a04f8648 | ||
|
|
60f41a738d | ||
|
|
9814bae727 | ||
|
|
63cc800cd1 | ||
|
|
47c139b916 | ||
|
|
107352c000 | ||
|
|
26cb522140 | ||
|
|
7db3009968 | ||
|
|
13e296db76 | ||
|
|
6fa992c8d3 | ||
|
|
7ca78e7178 | ||
|
|
2ee4f239d1 | ||
|
|
4ffa06fb7e | ||
|
|
a1baf97f54 | ||
|
|
2a7c57035e | ||
|
|
19e1ad7cfe | ||
|
|
2ea3da4819 | ||
|
|
3b100fce2d | ||
|
|
0c67d0565a | ||
|
|
95aeb16ca2 | ||
|
|
4770ef2df8 | ||
|
|
0ee0f5df97 | ||
|
|
4f5cad977c | ||
|
|
bed2da9b83 | ||
|
|
462fa9077a | ||
|
|
0f9749c140 | ||
|
|
acae88e618 | ||
|
|
75bf46de70 | ||
|
|
f598186574 | ||
|
|
d99aa696db | ||
|
|
790beedbb0 | ||
|
|
b1e681030b | ||
|
|
5225b477ff | ||
|
|
c53b787339 | ||
|
|
64cb4398c6 | ||
|
|
9165251a0b | ||
|
|
7e86e07fb0 | ||
|
|
02a6afd2b0 | ||
|
|
0b414b9662 | ||
|
|
012007ce7b | ||
|
|
031d501381 | ||
|
|
b0773890ea | ||
|
|
55b3b6af79 | ||
|
|
1bcfc64e13 | ||
|
|
7b4802091a | ||
|
|
7774c74826 | ||
|
|
97e58f381b | ||
|
|
015f247998 | ||
|
|
ef3923c992 | ||
|
|
7fdb1b4d1f | ||
|
|
fb83a86c17 | ||
|
|
289057f981 | ||
|
|
b48106a741 | ||
|
|
fbad0ab50a | ||
|
|
a8bf4db32d | ||
|
|
b33bad1258 | ||
|
|
29024806e5 | ||
|
|
4ef1f993a1 | ||
|
|
7297178091 | ||
|
|
3786c20dcf | ||
|
|
125fc142ba | ||
|
|
d716b32bed | ||
|
|
a56b1099aa | ||
|
|
f3f231cf70 | ||
|
|
c49ff931b1 | ||
|
|
d3c3dfda7d | ||
|
|
302c33e377 | ||
|
|
e77b1c9744 | ||
|
|
5c2073135e | ||
|
|
58cc0ad760 | ||
|
|
41387a6a3a | ||
|
|
ee94272eaf | ||
|
|
dd6000f1fd | ||
|
|
3bc896bd89 | ||
|
|
80b46fbc28 | ||
|
|
b9af3eca9f | ||
|
|
840efb76d0 | ||
|
|
8a845861f3 | ||
|
|
39d6443b6b | ||
|
|
1c9d4e77df | ||
|
|
15f9d6d279 | ||
|
|
cf2f7eb785 | ||
|
|
e7d740785d | ||
|
|
8cc25fe772 | ||
|
|
896f0606cd | ||
|
|
2649f8d591 | ||
|
|
e77102d73e | ||
|
|
ac94bc774b | ||
|
|
83eca32111 | ||
|
|
f5662d578e | ||
|
|
80363314aa | ||
|
|
6ce3bb858d | ||
|
|
1c34fb064a | ||
|
|
366b85beb2 | ||
|
|
82038e236d | ||
|
|
f72fc7f09b | ||
|
|
c323a2d5fe | ||
|
|
662b55ee6b | ||
|
|
2e92255032 | ||
|
|
5182901bcc | ||
|
|
248eb2eb4a | ||
|
|
458fe1be2f | ||
|
|
8589231742 | ||
|
|
59658b44a9 | ||
|
|
3f2e4b71bc | ||
|
|
9b42051ba7 | ||
|
|
674e93d127 | ||
|
|
b1472827e7 | ||
|
|
856e649487 | ||
|
|
bc71a1662d | ||
|
|
33bf808084 | ||
|
|
78f71971cb | ||
|
|
b4fc5160ba | ||
|
|
9d3acbdd82 | ||
|
|
873ede7a77 | ||
|
|
d7581dbaa4 | ||
|
|
71e4d7ba87 | ||
|
|
46f7f47bda | ||
|
|
4046df7412 | ||
|
|
a772470b76 | ||
|
|
e1ce53fe15 | ||
|
|
77bdd4fbde | ||
|
|
3fdaa543ed | ||
|
|
336be1e36d | ||
|
|
382027663f | ||
|
|
1d58b84637 | ||
|
|
88ead18709 | ||
|
|
70058bdee2 | ||
|
|
d1c85966d9 | ||
|
|
0679d98950 | ||
|
|
a8b7d89ba5 | ||
|
|
828773b391 | ||
|
|
35f4eb8e9a | ||
|
|
8c69e62a78 | ||
|
|
8e4fa9aafb | ||
|
|
d6ed5f843e | ||
|
|
ba7bc2be13 | ||
|
|
199475b6ca | ||
|
|
60b50afefd | ||
|
|
7aa64dc423 | ||
|
|
7a59540517 | ||
|
|
2cd60077e6 | ||
|
|
2c68a6704f | ||
|
|
cc95cef165 | ||
|
|
cd76c2cb26 | ||
|
|
c586210306 | ||
|
|
ec3cd4f4cb | ||
|
|
eef5a7ff2b | ||
|
|
988985727f | ||
|
|
dad58ac20a | ||
|
|
3f9d8db5b7 | ||
|
|
0b6afbd17b | ||
|
|
e9936bc5ed | ||
|
|
068a1ab95c | ||
|
|
74d9a3537c | ||
|
|
143a4aca0f | ||
|
|
20e66ad990 | ||
|
|
ceec382161 | ||
|
|
782916930a | ||
|
|
a767739c06 | ||
|
|
cf3c9d75d7 | ||
|
|
1846d7fd7e | ||
|
|
b8c7ee3a85 | ||
|
|
0709e4be8b | ||
|
|
328f9a9d16 | ||
|
|
1d9233abc7 | ||
|
|
c9cc2a4069 | ||
|
|
e0a2fa35cc | ||
|
|
da5a57890a | ||
|
|
c7772db4fb | ||
|
|
f00b775172 | ||
|
|
a5cbbd7f10 | ||
|
|
c409e816df | ||
|
|
8d02987c64 | ||
|
|
e091bc3ba2 | ||
|
|
4f9c9b5be4 | ||
|
|
10e0515d50 | ||
|
|
bae735740c | ||
|
|
3b0fa95870 | ||
|
|
d4390c2fad | ||
|
|
9845074a53 | ||
|
|
e7dc1c4635 | ||
|
|
07e26518fc | ||
|
|
034b3b758d | ||
|
|
ea5d77ad6f | ||
|
|
cb320e17ed | ||
|
|
ca8b18cad5 | ||
|
|
aec459c795 | ||
|
|
13d62d5851 | ||
|
|
d8516139c8 | ||
|
|
7f8263b625 | ||
|
|
daadd81ab6 | ||
|
|
c0b7167082 | ||
|
|
ff50e761dd | ||
|
|
7c61fc5151 | ||
|
|
ab39fab68c | ||
|
|
9953edb9ab | ||
|
|
8d2dabbded | ||
|
|
708703b9ec | ||
|
|
def9230ad6 | ||
|
|
4ef0e37011 | ||
|
|
ce82577d2f | ||
|
|
f6584225c2 | ||
|
|
a0a8a0b817 | ||
|
|
f88b1fd393 | ||
|
|
bd720ec9f6 | ||
|
|
56555f6319 | ||
|
|
71a962653d | ||
|
|
732942ec62 | ||
|
|
5eebeff5a9 | ||
|
|
f6d7198317 | ||
|
|
dc553ac628 | ||
|
|
6643b8c3e1 | ||
|
|
2954ff3991 | ||
|
|
ab69ef4b83 | ||
|
|
e8c0b3df24 | ||
|
|
5a12247572 | ||
|
|
58eec96a5b | ||
|
|
2be3f34f2c | ||
|
|
7bd6e577d9 | ||
|
|
e09583e99e | ||
|
|
d1983b29c1 | ||
|
|
c0a988da21 | ||
|
|
f5544fe2ae | ||
|
|
75be4e3f6a | ||
|
|
6c267e88a1 | ||
|
|
27f49b9523 | ||
|
|
b8f12ed857 | ||
|
|
5cad71c081 | ||
|
|
f331f6a8a9 | ||
|
|
461670c36a | ||
|
|
0f32866980 | ||
|
|
c123126991 | ||
|
|
1302ac16f0 | ||
|
|
cc51d91e77 | ||
|
|
2d1c34c36a | ||
|
|
6422139fe0 | ||
|
|
f511ef69c3 | ||
|
|
525c9bbdcb | ||
|
|
7bc560190f | ||
|
|
54b39be7e7 | ||
|
|
578f46c008 | ||
|
|
b1cbbf7ce5 | ||
|
|
af9b03625b | ||
|
|
71f0e75651 | ||
|
|
3c4243fdd2 | ||
|
|
1a1da0649a | ||
|
|
69ccc9be18 | ||
|
|
61d6a83661 | ||
|
|
2f5260aabd | ||
|
|
eca19006ad | ||
|
|
d22b5910c2 | ||
|
|
a868be6ba4 | ||
|
|
8822ba3035 | ||
|
|
e20b06df1a | ||
|
|
e299b71560 | ||
|
|
d6f0e1fdf2 | ||
|
|
4a5bce3fb8 | ||
|
|
7f1dc80b9c | ||
|
|
43731c88bd | ||
|
|
332712866c | ||
|
|
b0d643c4ce | ||
|
|
2b9967bf01 | ||
|
|
9d53d61141 | ||
|
|
c66fa682e9 | ||
|
|
819759840e | ||
|
|
ccde87c4e3 | ||
|
|
3a9c5c7dc0 | ||
|
|
d27537c4fc | ||
|
|
973f0f6134 | ||
|
|
1973f3110e | ||
|
|
95e7977e70 | ||
|
|
15d06f964d | ||
|
|
5f96a4e665 | ||
|
|
075e4040be | ||
|
|
7d41158b1d | ||
|
|
00784248db | ||
|
|
b47b61ea08 | ||
|
|
787c6a443d | ||
|
|
f075c58eb5 | ||
|
|
07f0b1816e | ||
|
|
73696da21c | ||
|
|
e22d90cbad | ||
|
|
c7fdb8dc6b | ||
|
|
f7359751c9 | ||
|
|
0b7ab5a1b5 | ||
|
|
e7ad7e5cf6 | ||
|
|
9ccd6fb2d2 | ||
|
|
e7e97833a3 | ||
|
|
2dd6a7ba22 | ||
|
|
034cd7ea35 | ||
|
|
037a399746 | ||
|
|
6a86974b96 | ||
|
|
3c468054bd | ||
|
|
6fd1304e52 | ||
|
|
a51b2f4023 | ||
|
|
abf3f50bb9 | ||
|
|
20a6ac947b | ||
|
|
b158ba1523 | ||
|
|
372a65aa15 | ||
|
|
804bda5ba6 | ||
|
|
2f07df717d | ||
|
|
1d0de5ce71 | ||
|
|
c8001b5023 | ||
|
|
755d5ae222 | ||
|
|
5cfcfc64d8 | ||
|
|
606802daaf | ||
|
|
71b619bab0 | ||
|
|
a033a5d0e7 | ||
|
|
3f2c58a269 | ||
|
|
f946e5ec73 | ||
|
|
9d06302778 | ||
|
|
bb7180a2d8 | ||
|
|
6f5644a77c | ||
|
|
d79273089f | ||
|
|
68d02916e2 | ||
|
|
d414967b79 | ||
|
|
448471bd50 | ||
|
|
15fd99072b | ||
|
|
61ee695e56 | ||
|
|
1fe6b28877 | ||
|
|
4f48797a09 | ||
|
|
3736636d99 | ||
|
|
16f2135976 | ||
|
|
73fe50f6b1 | ||
|
|
0b5f82a5f0 | ||
|
|
02725b66b3 | ||
|
|
52ea511768 | ||
|
|
c65748c098 | ||
|
|
8aeafa13c9 | ||
|
|
07514c5df0 | ||
|
|
43f8d7478e | ||
|
|
1c3a6a463d | ||
|
|
41636c8e35 | ||
|
|
78e8f87e54 | ||
|
|
8cb5ad9693 | ||
|
|
83ece2161d | ||
|
|
63cda65815 | ||
|
|
165e0d0ed5 | ||
|
|
cab6b97539 | ||
|
|
1c853a4d24 | ||
|
|
73fbd5d994 | ||
|
|
9a43acd77b | ||
|
|
28e8f45828 | ||
|
|
ac8ef4da9e | ||
|
|
52241712b4 | ||
|
|
584a21b34b | ||
|
|
b82920dc26 | ||
|
|
ea69133e48 | ||
|
|
f72ebca1e4 | ||
|
|
40d772fde3 | ||
|
|
d4837f9ef1 | ||
|
|
b44209e14e | ||
|
|
531269bb84 | ||
|
|
80faf5e805 | ||
|
|
0d5fd181be | ||
|
|
8c279b854d | ||
|
|
f1f95c6867 | ||
|
|
ecedd8caed | ||
|
|
ce5b5ec053 | ||
|
|
37e0a5ae8d | ||
|
|
5792df9738 | ||
|
|
73f0e14d90 | ||
|
|
a216cfdd2f | ||
|
|
fad0e39cfa | ||
|
|
4532fc0c1b | ||
|
|
03d21edd63 | ||
|
|
f72b833e38 | ||
|
|
45a3f4f1d6 | ||
|
|
3aab119e5b | ||
|
|
0a1ca206fa | ||
|
|
028e05fff1 | ||
|
|
dabd956216 | ||
|
|
441f90fb55 | ||
|
|
3b52d3db42 | ||
|
|
39943a8406 | ||
|
|
48bdf24964 | ||
|
|
fed2714e30 | ||
|
|
c8262929e1 | ||
|
|
0ded3ed6f9 | ||
|
|
2b428fae38 | ||
|
|
b07adb532a | ||
|
|
af72d4aebc | ||
|
|
bfab595379 | ||
|
|
d72adc0124 | ||
|
|
5f0d83d2f2 | ||
|
|
03f54171c6 | ||
|
|
f391b4a179 | ||
|
|
8db674b6b5 | ||
|
|
f03113d048 | ||
|
|
6c48e214ca | ||
|
|
189a2e90dd | ||
|
|
9b44138917 | ||
|
|
ec7d20b347 | ||
|
|
84b52a3ed1 | ||
|
|
30b1c9570f | ||
|
|
b88622bc35 | ||
|
|
a4edb4020d | ||
|
|
e1e5dfdd62 | ||
|
|
5102c8b137 | ||
|
|
9ae9db7f70 | ||
|
|
d0aaa8d809 | ||
|
|
6024539c12 | ||
|
|
fb06ad4a44 | ||
|
|
598e98794c | ||
|
|
b3a295959d | ||
|
|
50dfd962ec | ||
|
|
65332eaacc | ||
|
|
a00e6f8696 | ||
|
|
6415dfbd35 | ||
|
|
8c387c58de | ||
|
|
da411f6fa7 | ||
|
|
8fe402e9f7 | ||
|
|
c41fc52077 | ||
|
|
f7d730390c | ||
|
|
8fc30d5243 | ||
|
|
93c4d63295 | ||
|
|
7a07c08860 | ||
|
|
1cf110d083 | ||
|
|
fef358fc74 | ||
|
|
b5feb79a7c | ||
|
|
4d52245617 | ||
|
|
ff308b36af | ||
|
|
fa8cf8a1a5 | ||
|
|
5ade4a037e | ||
|
|
861002917a | ||
|
|
eddb26d490 | ||
|
|
b7fe3190bb | ||
|
|
b6ddb56cc7 | ||
|
|
8dd59081d7 | ||
|
|
3ae17ea100 | ||
|
|
10c34c5353 | ||
|
|
e3ebda3647 | ||
|
|
092e7fa274 | ||
|
|
dd47c2baa2 | ||
|
|
15065255e9 | ||
|
|
594f1df39c | ||
|
|
724416125e | ||
|
|
3afafe6398 | ||
|
|
af7446a055 | ||
|
|
7be101e8c9 | ||
|
|
5f18b173dd | ||
|
|
3fec9c8145 | ||
|
|
bdca70bfb0 | ||
|
|
5e28f068ec | ||
|
|
a0b22077a5 | ||
|
|
1d36b04ea6 | ||
|
|
6829c9d678 | ||
|
|
e1f6ab8916 | ||
|
|
778baaecb5 | ||
|
|
a189f79590 | ||
|
|
6395644e8c | ||
|
|
a958f23f63 | ||
|
|
ec8756d7a3 | ||
|
|
b7fabb11ac | ||
|
|
74ba4e9a98 | ||
|
|
b1e8fdfaa2 | ||
|
|
9eb439c01d | ||
|
|
fbfd29d6d2 | ||
|
|
f158a3ae3e | ||
|
|
7d59b4f4e2 | ||
|
|
e99eca47c3 | ||
|
|
d683769e1f | ||
|
|
9ea328e43a | ||
|
|
f6d93f2fdb | ||
|
|
b644fdbb04 | ||
|
|
7647d68b68 | ||
|
|
d167ab9376 | ||
|
|
e68bd2f980 | ||
|
|
b5c17d4743 | ||
|
|
66ca7ac6d0 | ||
|
|
e97a616ffa | ||
|
|
061517cd14 | ||
|
|
6accc475c9 | ||
|
|
c2e2fd6432 | ||
|
|
83af5c91bd | ||
|
|
e9f5982147 | ||
|
|
50819666b1 | ||
|
|
6ad13e35c0 | ||
|
|
39e2f1138b | ||
|
|
cd37c71e29 | ||
|
|
c1f3d93b3b | ||
|
|
0aa05032c4 | ||
|
|
174130fe2f | ||
|
|
d06f7f01d2 | ||
|
|
a04ddd9b17 | ||
|
|
12929fed74 | ||
|
|
87bf580f68 | ||
|
|
66bab5e767 | ||
|
|
4b12fb2887 | ||
|
|
623c14aed0 | ||
|
|
7d83dc4758 | ||
|
|
493d0bca95 | ||
|
|
983501ff8c | ||
|
|
20da9a2b51 | ||
|
|
7aec6c55f9 | ||
|
|
532f30e031 | ||
|
|
1d7ab57e3a | ||
|
|
8adc598e90 | ||
|
|
c884c08257 | ||
|
|
66dc734c11 | ||
|
|
77fee9acb9 | ||
|
|
6b66c2bc1d | ||
|
|
81b9f50dc2 | ||
|
|
fcd246064b | ||
|
|
86a0a348ee | ||
|
|
ed36e852d2 | ||
|
|
da5d93c1e2 | ||
|
|
7b59ae0d82 | ||
|
|
97acc12d62 | ||
|
|
db6a7d26cd | ||
|
|
6be03d7cc4 | ||
|
|
617a6edb13 | ||
|
|
31c85723e8 | ||
|
|
d22c905d9f | ||
|
|
216dc2d473 | ||
|
|
918e7abe6b | ||
|
|
c145ee6df3 | ||
|
|
62543b36a4 | ||
|
|
751aad5302 | ||
|
|
efabab492a | ||
|
|
c7cdbe60cd | ||
|
|
412149a5de | ||
|
|
abd23d2a1b | ||
|
|
b774c54a6f | ||
|
|
e4b797405b | ||
|
|
81a89a5dec | ||
|
|
0da12a6b55 | ||
|
|
86ec8994e6 | ||
|
|
caf426ddb2 | ||
|
|
508ae410a6 | ||
|
|
993b977c9b | ||
|
|
a7f0138fc7 | ||
|
|
ab3c932903 | ||
|
|
ae0fdadcff | ||
|
|
e3974989d8 | ||
|
|
080b1e0e4f | ||
|
|
a5db91dd85 | ||
|
|
b62f54631b | ||
|
|
d835c5252a | ||
|
|
a53db72564 | ||
|
|
61b0368dac | ||
|
|
568b4a22f9 | ||
|
|
8abba8a089 | ||
|
|
b3b789cd68 | ||
|
|
425a166111 | ||
|
|
1dcc290e29 | ||
|
|
863204dbfa | ||
|
|
4b21e7c9c7 | ||
|
|
df5230ff4a | ||
|
|
7cd0943056 | ||
|
|
6f0532460a | ||
|
|
29a35a7951 | ||
|
|
dd0d45f88f | ||
|
|
0ff0de7efe | ||
|
|
092ef99551 | ||
|
|
97ae05b69d | ||
|
|
3d8eca178e |
@@ -1,7 +1,6 @@
|
|||||||
image: alpine/edge
|
image: alpine/edge
|
||||||
packages:
|
packages:
|
||||||
- cargo
|
- cargo
|
||||||
- clang17-libclang
|
|
||||||
- cmake
|
- cmake
|
||||||
- ninja
|
- ninja
|
||||||
- pcre2-dev
|
- pcre2-dev
|
||||||
@@ -24,4 +23,4 @@ tasks:
|
|||||||
ninja
|
ninja
|
||||||
- test: |
|
- test: |
|
||||||
cd fish-shell/build
|
cd fish-shell/build
|
||||||
ninja test
|
ninja fish_run_tests
|
||||||
|
|||||||
@@ -20,4 +20,4 @@ tasks:
|
|||||||
ninja
|
ninja
|
||||||
- test: |
|
- test: |
|
||||||
cd fish/build
|
cd fish/build
|
||||||
ninja test
|
ninja fish_run_tests
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ packages:
|
|||||||
- gettext
|
- gettext
|
||||||
- gmake
|
- gmake
|
||||||
- llvm
|
- llvm
|
||||||
- terminfo-db
|
|
||||||
- ninja
|
- ninja
|
||||||
- pcre2
|
- pcre2
|
||||||
- py311-pexpect
|
- py311-pexpect
|
||||||
|
- py311-sphinx
|
||||||
- python
|
- python
|
||||||
- rust
|
- rust
|
||||||
- tmux
|
- tmux
|
||||||
@@ -27,4 +27,4 @@ tasks:
|
|||||||
ninja
|
ninja
|
||||||
- test: |
|
- test: |
|
||||||
cd fish-shell/build
|
cd fish-shell/build
|
||||||
ninja test
|
ninja fish_run_tests
|
||||||
|
|||||||
30
.builds/openbsd.yml
Normal file
30
.builds/openbsd.yml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
image: openbsd/latest
|
||||||
|
packages:
|
||||||
|
- cmake
|
||||||
|
- gcc
|
||||||
|
- gettext
|
||||||
|
- gmake
|
||||||
|
- llvm
|
||||||
|
- ninja
|
||||||
|
- pcre2
|
||||||
|
- py3-pexpect
|
||||||
|
- py3-sphinx
|
||||||
|
- python
|
||||||
|
- rust
|
||||||
|
- tmux
|
||||||
|
sources:
|
||||||
|
- https://github.com/fish-shell/fish-shell
|
||||||
|
tasks:
|
||||||
|
- build: |
|
||||||
|
cd fish-shell
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake -GNinja .. \
|
||||||
|
-DCMAKE_INSTALL_PREFIX=/usr \
|
||||||
|
-DCMAKE_INSTALL_DATADIR=share \
|
||||||
|
-DCMAKE_INSTALL_DOCDIR=share/doc/fish \
|
||||||
|
-DCMAKE_INSTALL_SYSCONFDIR=/etc
|
||||||
|
ninja
|
||||||
|
- test: |
|
||||||
|
cd fish-shell/build
|
||||||
|
ninja fish_run_tests
|
||||||
37
.cirrus.yml
37
.cirrus.yml
@@ -8,18 +8,10 @@ linux_task:
|
|||||||
container: &step
|
container: &step
|
||||||
image: ghcr.io/krobelus/fish-ci/alpine:latest
|
image: ghcr.io/krobelus/fish-ci/alpine:latest
|
||||||
memory: 4GB
|
memory: 4GB
|
||||||
- name: jammy
|
- name: ubuntu-oldest-supported
|
||||||
container:
|
container:
|
||||||
<<: *step
|
<<: *step
|
||||||
image: ghcr.io/krobelus/fish-ci/jammy:latest
|
image: ghcr.io/krobelus/fish-ci/ubuntu-oldest-supported:latest
|
||||||
# - name: jammy-asan
|
|
||||||
# container:
|
|
||||||
# <<: *step
|
|
||||||
# image: ghcr.io/krobelus/fish-ci/jammy-asan:latest
|
|
||||||
# - name: focal-32bit
|
|
||||||
# container:
|
|
||||||
# <<: *step
|
|
||||||
# image: ghcr.io/krobelus/fish-ci/focal-32bit:latest
|
|
||||||
tests_script:
|
tests_script:
|
||||||
# cirrus at times gives us 32 procs and 2 GB of RAM
|
# cirrus at times gives us 32 procs and 2 GB of RAM
|
||||||
# Unrestriced parallelism results in OOM
|
# Unrestriced parallelism results in OOM
|
||||||
@@ -31,32 +23,11 @@ linux_task:
|
|||||||
- ninja fish_run_tests
|
- ninja fish_run_tests
|
||||||
only_if: $CIRRUS_REPO_OWNER == 'fish-shell'
|
only_if: $CIRRUS_REPO_OWNER == 'fish-shell'
|
||||||
|
|
||||||
linux_arm_task:
|
|
||||||
matrix:
|
|
||||||
- name: focal-arm64
|
|
||||||
arm_container:
|
|
||||||
image: ghcr.io/fish-shell/fish-ci/focal-arm64
|
|
||||||
- name: jammy-armv7-32bit
|
|
||||||
arm_container:
|
|
||||||
image: ghcr.io/fish-shell/fish-ci/jammy-armv7-32bit
|
|
||||||
tests_script:
|
|
||||||
# cirrus at times gives us 32 procs and 2 GB of RAM
|
|
||||||
# Unrestriced parallelism results in OOM
|
|
||||||
- lscpu || true
|
|
||||||
- (cat /proc/meminfo | grep MemTotal) || true
|
|
||||||
- mkdir build && cd build
|
|
||||||
- FISH_TEST_MAX_CONCURRENCY=6 cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug ..
|
|
||||||
- ninja -j 6 fish
|
|
||||||
- file ./fish
|
|
||||||
- ninja fish_run_tests
|
|
||||||
# CI task disabled during RIIR transition
|
|
||||||
only_if: false && $CIRRUS_REPO_OWNER == 'fish-shell'
|
|
||||||
|
|
||||||
freebsd_task:
|
freebsd_task:
|
||||||
matrix:
|
matrix:
|
||||||
- name: FreeBSD 14
|
- name: FreeBSD Stable
|
||||||
freebsd_instance:
|
freebsd_instance:
|
||||||
image: freebsd-14-3-release-amd64-ufs
|
image: freebsd-15-0-release-amd64-ufs # updatecli.d/cirrus-freebsd.yml
|
||||||
tests_script:
|
tests_script:
|
||||||
- pkg install -y cmake-core devel/pcre2 devel/ninja gettext git-lite lang/rust misc/py-pexpect
|
- pkg install -y cmake-core devel/pcre2 devel/ninja gettext git-lite lang/rust misc/py-pexpect
|
||||||
# libclang.so is a required build dependency for rust-c++ ffi bridge
|
# libclang.so is a required build dependency for rust-c++ ffi bridge
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ indent_style = tab
|
|||||||
|
|
||||||
[*.{md,rst}]
|
[*.{md,rst}]
|
||||||
max_line_length = unset
|
max_line_length = unset
|
||||||
trim_trailing_whitespace = false
|
|
||||||
|
|
||||||
[*.sh]
|
[*.sh]
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
|
|||||||
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -14,8 +14,6 @@
|
|||||||
.gitattributes export-ignore
|
.gitattributes export-ignore
|
||||||
.gitignore export-ignore
|
.gitignore export-ignore
|
||||||
/build_tools/make_tarball.sh export-ignore
|
/build_tools/make_tarball.sh export-ignore
|
||||||
/debian export-ignore
|
|
||||||
/debian/* export-ignore
|
|
||||||
/.github export-ignore
|
/.github export-ignore
|
||||||
/.github/* export-ignore
|
/.github/* export-ignore
|
||||||
/.builds export-ignore
|
/.builds export-ignore
|
||||||
|
|||||||
2
.github/FUNDING.yml
vendored
Normal file
2
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
github:
|
||||||
|
- krobelus
|
||||||
41
.github/actions/install-dependencies/action.yml
vendored
Normal file
41
.github/actions/install-dependencies/action.yml
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
name: Install dependencies for system tests
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
include_sphinx:
|
||||||
|
description: Whether to install Sphinx
|
||||||
|
required: true
|
||||||
|
default: false
|
||||||
|
include_pcre:
|
||||||
|
description: Whether to install the PCRE library
|
||||||
|
required: false
|
||||||
|
default: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- shell: bash
|
||||||
|
env:
|
||||||
|
include_pcre: ${{ inputs.include_pcre }}
|
||||||
|
run: |
|
||||||
|
set -x
|
||||||
|
: "optional dependencies"
|
||||||
|
sudo apt install \
|
||||||
|
gettext \
|
||||||
|
$(if $include_pcre; then echo libpcre2-dev; fi) \
|
||||||
|
;
|
||||||
|
: "system test dependencies"
|
||||||
|
sudo apt install \
|
||||||
|
diffutils $(: "for diff") \
|
||||||
|
git \
|
||||||
|
gettext \
|
||||||
|
less \
|
||||||
|
$(if ${{ inputs.include_pcre }}; then echo libpcre2-dev; fi) \
|
||||||
|
python3-pexpect \
|
||||||
|
tmux \
|
||||||
|
wget \
|
||||||
|
;
|
||||||
|
- uses: ./.github/actions/install-sphinx
|
||||||
|
if: ${{ inputs.include_sphinx == 'true' }}
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
name: Install sphinx-markdown-builder
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: "composite"
|
|
||||||
steps:
|
|
||||||
- shell: bash
|
|
||||||
run: |
|
|
||||||
set -x
|
|
||||||
commit=b259de1dc97573a71470a1d71c3d83535934136b
|
|
||||||
pip install git+https://github.com/krobelus/sphinx-markdown-builder@"$commit"
|
|
||||||
python -c 'import sphinx_markdown_builder'
|
|
||||||
23
.github/actions/install-sphinx/action.yml
vendored
Normal file
23
.github/actions/install-sphinx/action.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
name: Install sphinx
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- shell: bash
|
||||||
|
run: |
|
||||||
|
set -x
|
||||||
|
sudo pip install uv --break-system-packages
|
||||||
|
command -v uv
|
||||||
|
command -v uvx
|
||||||
|
# Check that pyproject.toml and the lock file are in sync.
|
||||||
|
# TODO Use "uv" to install Python as well.
|
||||||
|
: 'Note that --no-managed-python below would be implied but be explicit'
|
||||||
|
uv='env UV_PYTHON=python uv --no-managed-python'
|
||||||
|
$uv lock --check --exclude-newer="$(awk -F'"' <uv.lock '/^exclude-newer[[:space:]]*=/ {print $2}')"
|
||||||
|
# Install globally.
|
||||||
|
sudo $uv pip install --group=dev --system --break-system-packages
|
||||||
|
# Smoke test.
|
||||||
|
python -c 'import sphinx; import sphinx_markdown_builder'
|
||||||
41
.github/actions/rust-toolchain/action.yml
vendored
Normal file
41
.github/actions/rust-toolchain/action.yml
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
name: Rust Toolchain
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
toolchain_channel:
|
||||||
|
description: Either "stable" or "msrv"
|
||||||
|
required: true
|
||||||
|
targets:
|
||||||
|
description: Comma-separated list of target triples to install for this toolchain
|
||||||
|
required: false
|
||||||
|
components:
|
||||||
|
description: Comma-separated list of components to be additionally installed
|
||||||
|
required: false
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- name: Set toolchain
|
||||||
|
env:
|
||||||
|
toolchain_channel: ${{ inputs.toolchain_channel }}
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -x
|
||||||
|
toolchain=$(
|
||||||
|
case "$toolchain_channel" in
|
||||||
|
(stable) echo 1.92 ;; # updatecli.d/rust.yml
|
||||||
|
(msrv) echo 1.85 ;; # updatecli.d/rust.yml
|
||||||
|
(*)
|
||||||
|
printf >&2 "error: unsupported toolchain channel %s" "$toolchain_channel"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
)
|
||||||
|
printf 'TOOLCHAIN=%s\n' "$toolchain" >>"$GITHUB_ENV"
|
||||||
|
- uses: dtolnay/rust-toolchain@master
|
||||||
|
with:
|
||||||
|
toolchain: ${{ env.TOOLCHAIN }}
|
||||||
|
targets: ${{ inputs.targets }}
|
||||||
|
components: ${{ inputs.components }}
|
||||||
@@ -14,7 +14,8 @@ permissions:
|
|||||||
runs:
|
runs:
|
||||||
using: "composite"
|
using: "composite"
|
||||||
steps:
|
steps:
|
||||||
- uses: dtolnay/rust-toolchain@1.70
|
- uses: ./.github/actions/rust-toolchain
|
||||||
with:
|
with:
|
||||||
|
toolchain_channel: "msrv"
|
||||||
targets: ${{ inputs.targets }}
|
targets: ${{ inputs.targets }}
|
||||||
components: ${{ inputs.components}}
|
components: ${{ inputs.components }}
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ permissions:
|
|||||||
runs:
|
runs:
|
||||||
using: "composite"
|
using: "composite"
|
||||||
steps:
|
steps:
|
||||||
- uses: dtolnay/rust-toolchain@1.90
|
- uses: ./.github/actions/rust-toolchain
|
||||||
with:
|
with:
|
||||||
|
toolchain_channel: "stable"
|
||||||
targets: ${{ inputs.targets }}
|
targets: ${{ inputs.targets }}
|
||||||
components: ${{ inputs.components }}
|
components: ${{ inputs.components }}
|
||||||
|
|||||||
64
.github/workflows/build_docker_images.yml
vendored
Normal file
64
.github/workflows/build_docker_images.yml
vendored
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
name: Build Docker test images
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths:
|
||||||
|
- 'docker/**'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: docker-builds
|
||||||
|
|
||||||
|
env:
|
||||||
|
REGISTRY: ghcr.io
|
||||||
|
NAMESPACE: fish-ci
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docker-build:
|
||||||
|
if: github.repository_owner == 'fish-shell'
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
attestations: write
|
||||||
|
id-token: write
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- os: ubuntu-latest
|
||||||
|
target: alpine
|
||||||
|
- os: ubuntu-latest
|
||||||
|
target: ubuntu-oldest-supported
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Checkout
|
||||||
|
uses: actions/checkout@v5
|
||||||
|
-
|
||||||
|
name: Login to Container registry
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ${{ env.REGISTRY }}
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
-
|
||||||
|
name: Extract metadata (tags, labels) for Docker
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
|
||||||
|
with:
|
||||||
|
images: ${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.NAMESPACE }}/${{ matrix.target }}
|
||||||
|
flavor: |
|
||||||
|
latest=true
|
||||||
|
-
|
||||||
|
name: Build and push
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: docker/context
|
||||||
|
push: true
|
||||||
|
file: docker/${{ matrix.target }}.Dockerfile
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
24
.github/workflows/lint-dependencies.yml
vendored
Normal file
24
.github/workflows/lint-dependencies.yml
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
name: Lint Dependencies
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/lint-dependencies.yml'
|
||||||
|
- 'Cargo.lock'
|
||||||
|
- '**/Cargo.toml'
|
||||||
|
- 'deny.toml'
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/lint-dependencies.yml'
|
||||||
|
- 'Cargo.lock'
|
||||||
|
- '**/Cargo.toml'
|
||||||
|
- 'deny.toml'
|
||||||
|
jobs:
|
||||||
|
cargo-deny:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: EmbarkStudios/cargo-deny-action@v2
|
||||||
|
with:
|
||||||
|
command: check licenses
|
||||||
|
arguments: --all-features --locked --exclude-dev
|
||||||
|
rust-version: 1.92 # updatecli.d/rust.yml
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
name: Rust checks
|
name: Lint
|
||||||
|
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
@@ -6,25 +6,39 @@ permissions:
|
|||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
rustfmt:
|
format:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: ./.github/actions/rust-toolchain@stable
|
- uses: ./.github/actions/rust-toolchain@stable
|
||||||
with:
|
with:
|
||||||
components: rustfmt
|
components: rustfmt
|
||||||
- name: cargo fmt
|
- name: install dependencies
|
||||||
run: cargo fmt --check
|
run: pip install ruff
|
||||||
|
- name: build fish
|
||||||
|
run: cargo build
|
||||||
|
- name: check format
|
||||||
|
run: PATH="target/debug:$PATH" build_tools/style.fish --all --check
|
||||||
|
- name: check rustfmt
|
||||||
|
run: find build.rs crates src -type f -name '*.rs' | xargs rustfmt --check
|
||||||
|
|
||||||
clippy-stable:
|
|
||||||
|
clippy:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
features: ["", "--no-default-features"]
|
include:
|
||||||
|
- rust_version: "stable"
|
||||||
|
features: ""
|
||||||
|
- rust_version: "stable"
|
||||||
|
features: "--no-default-features"
|
||||||
|
- rust_version: "msrv"
|
||||||
|
features: ""
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: ./.github/actions/rust-toolchain@stable
|
- uses: ./.github/actions/rust-toolchain
|
||||||
with:
|
with:
|
||||||
|
toolchain_channel: ${{ matrix.rust_version }}
|
||||||
components: clippy
|
components: clippy
|
||||||
- name: Install deps
|
- name: Install deps
|
||||||
run: |
|
run: |
|
||||||
@@ -32,19 +46,6 @@ jobs:
|
|||||||
- name: cargo clippy
|
- name: cargo clippy
|
||||||
run: cargo clippy --workspace --all-targets ${{ matrix.features }} -- --deny=warnings
|
run: cargo clippy --workspace --all-targets ${{ matrix.features }} -- --deny=warnings
|
||||||
|
|
||||||
clippy-msrv:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: ./.github/actions/rust-toolchain@oldest-supported
|
|
||||||
with:
|
|
||||||
components: clippy
|
|
||||||
- name: Install deps
|
|
||||||
run: |
|
|
||||||
sudo apt install gettext
|
|
||||||
- name: cargo clippy
|
|
||||||
run: cargo clippy --workspace --all-targets -- --deny=warnings
|
|
||||||
|
|
||||||
rustdoc:
|
rustdoc:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
1
.github/workflows/lockthreads.yml
vendored
1
.github/workflows/lockthreads.yml
vendored
@@ -12,6 +12,7 @@ permissions:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lock:
|
lock:
|
||||||
|
if: github.repository_owner == 'fish-shell'
|
||||||
permissions:
|
permissions:
|
||||||
issues: write # for dessant/lock-threads to lock issues
|
issues: write # for dessant/lock-threads to lock issues
|
||||||
pull-requests: write # for dessant/lock-threads to lock PRs
|
pull-requests: write # for dessant/lock-threads to lock PRs
|
||||||
|
|||||||
25
.github/workflows/release.yml
vendored
25
.github/workflows/release.yml
vendored
@@ -41,8 +41,8 @@ jobs:
|
|||||||
# Workaround for https://github.com/actions/checkout/issues/882
|
# Workaround for https://github.com/actions/checkout/issues/882
|
||||||
ref: ${{ inputs.version }}
|
ref: ${{ inputs.version }}
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: sudo apt install cmake gettext ninja-build python3-pip python3-sphinx
|
run: sudo apt install cmake gettext ninja-build python3-pip
|
||||||
- uses: ./.github/actions/install-sphinx-markdown-builder
|
- uses: ./.github/actions/install-sphinx
|
||||||
- name: Create tarball
|
- name: Create tarball
|
||||||
run: |
|
run: |
|
||||||
set -x
|
set -x
|
||||||
@@ -52,7 +52,10 @@ jobs:
|
|||||||
# Need history since the last release (i.e. tag) for stats.
|
# Need history since the last release (i.e. tag) for stats.
|
||||||
git fetch --tags
|
git fetch --tags
|
||||||
git fetch --unshallow
|
git fetch --unshallow
|
||||||
sh -x ./build_tools/release-notes.sh >"$relnotes"
|
gpg_public_key_url=https://github.com/${{ github.actor }}.gpg
|
||||||
|
curl -sS "$gpg_public_key_url" | grep 'PGP PUBLIC KEY BLOCK' -A5
|
||||||
|
FISH_GPG_PUBLIC_KEY_URL=$gpg_public_key_url \
|
||||||
|
sh -x ./build_tools/release-notes.sh >"$relnotes"
|
||||||
# Delete title
|
# Delete title
|
||||||
sed -n 1p "$relnotes" | grep -q "^## fish .*"
|
sed -n 1p "$relnotes" | grep -q "^## fish .*"
|
||||||
sed -n 2p "$relnotes" | grep -q '^$'
|
sed -n 2p "$relnotes" | grep -q '^$'
|
||||||
@@ -68,7 +71,7 @@ jobs:
|
|||||||
|
|
||||||
packages-for-linux:
|
packages-for-linux:
|
||||||
needs: [is-release-tag]
|
needs: [is-release-tag]
|
||||||
name: Build single-file fish for Linux (experimental)
|
name: Build single-file fish for Linux
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -80,7 +83,8 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
targets: x86_64-unknown-linux-musl,aarch64-unknown-linux-musl
|
targets: x86_64-unknown-linux-musl,aarch64-unknown-linux-musl
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: sudo apt install crossbuild-essential-arm64 musl-tools python3-sphinx
|
run: sudo apt install crossbuild-essential-arm64 gettext musl-tools
|
||||||
|
- uses: ./.github/actions/install-sphinx
|
||||||
- name: Build statically-linked executables
|
- name: Build statically-linked executables
|
||||||
run: |
|
run: |
|
||||||
set -x
|
set -x
|
||||||
@@ -143,13 +147,12 @@ jobs:
|
|||||||
# Workaround for https://github.com/actions/checkout/issues/882
|
# Workaround for https://github.com/actions/checkout/issues/882
|
||||||
ref: ${{ inputs.version }}
|
ref: ${{ inputs.version }}
|
||||||
- name: Install Rust
|
- name: Install Rust
|
||||||
uses: ./.github/actions/rust-toolchain@oldest-supported
|
|
||||||
with:
|
|
||||||
targets: x86_64-apple-darwin
|
|
||||||
- name: Install Rust Stable
|
|
||||||
uses: ./.github/actions/rust-toolchain@stable
|
uses: ./.github/actions/rust-toolchain@stable
|
||||||
with:
|
with:
|
||||||
targets: aarch64-apple-darwin
|
targets: aarch64-apple-darwin,x86_64-apple-darwin
|
||||||
|
- name: Install dependencies
|
||||||
|
run: brew install gettext
|
||||||
|
- uses: ./.github/actions/install-sphinx
|
||||||
- name: Build and codesign
|
- name: Build and codesign
|
||||||
run: |
|
run: |
|
||||||
die() { echo >&2 "$*"; exit 1; }
|
die() { echo >&2 "$*"; exit 1; }
|
||||||
@@ -169,7 +172,7 @@ jobs:
|
|||||||
echo "$MACOS_NOTARIZE_JSON" >/tmp/notarize.json
|
echo "$MACOS_NOTARIZE_JSON" >/tmp/notarize.json
|
||||||
./build_tools/make_macos_pkg.sh -s -f /tmp/app.p12 \
|
./build_tools/make_macos_pkg.sh -s -f /tmp/app.p12 \
|
||||||
-i /tmp/installer.p12 -p "$MAC_CODESIGN_PASSWORD" \
|
-i /tmp/installer.p12 -p "$MAC_CODESIGN_PASSWORD" \
|
||||||
-n -j /tmp/notarize.json
|
-n -j /tmp/notarize.json -- -c "-DWITH_DOCS=ON"
|
||||||
version=$(git describe)
|
version=$(git describe)
|
||||||
[ -f "${FISH_ARTEFACT_PATH}/fish-$version.app.zip" ]
|
[ -f "${FISH_ARTEFACT_PATH}/fish-$version.app.zip" ]
|
||||||
[ -f "${FISH_ARTEFACT_PATH}/fish-$version.pkg" ]
|
[ -f "${FISH_ARTEFACT_PATH}/fish-$version.pkg" ]
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
name: make fish_run_tests
|
name: Test
|
||||||
|
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
@@ -11,18 +11,17 @@ permissions:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
ubuntu:
|
ubuntu:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: ./.github/actions/rust-toolchain@oldest-supported
|
- uses: ./.github/actions/rust-toolchain@oldest-supported
|
||||||
- name: Install deps
|
- name: Install deps
|
||||||
|
uses: ./.github/actions/install-dependencies
|
||||||
|
with:
|
||||||
|
include_sphinx: true
|
||||||
|
- name: Generate a locale that uses a comma as decimal separator.
|
||||||
run: |
|
run: |
|
||||||
sudo apt install gettext libpcre2-dev python3-pexpect python3-sphinx tmux
|
|
||||||
# Generate a locale that uses a comma as decimal separator.
|
|
||||||
sudo locale-gen fr_FR.UTF-8
|
sudo locale-gen fr_FR.UTF-8
|
||||||
- uses: ./.github/actions/install-sphinx-markdown-builder
|
|
||||||
- name: cmake
|
- name: cmake
|
||||||
run: |
|
run: |
|
||||||
mkdir build && cd build
|
mkdir build && cd build
|
||||||
@@ -43,18 +42,20 @@ jobs:
|
|||||||
git --no-pager diff --exit-code || { echo 'There are uncommitted changes after regenerating the gettext PO files. Make sure to update them via `build_tools/update_translations.fish` after changing source files.'; exit 1; }
|
git --no-pager diff --exit-code || { echo 'There are uncommitted changes after regenerating the gettext PO files. Make sure to update them via `build_tools/update_translations.fish` after changing source files.'; exit 1; }
|
||||||
|
|
||||||
ubuntu-32bit-static-pcre2:
|
ubuntu-32bit-static-pcre2:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: ./.github/actions/rust-toolchain@oldest-supported
|
- uses: ./.github/actions/rust-toolchain@oldest-supported
|
||||||
with:
|
with:
|
||||||
targets: "i586-unknown-linux-gnu" # rust-toolchain wants this comma-separated
|
targets: "i586-unknown-linux-gnu"
|
||||||
- name: Install deps
|
- name: Install deps
|
||||||
|
uses: ./.github/actions/install-dependencies
|
||||||
|
with:
|
||||||
|
include_pcre: false
|
||||||
|
include_sphinx: false
|
||||||
|
- name: Install g++-multilib
|
||||||
run: |
|
run: |
|
||||||
sudo apt update
|
sudo apt install g++-multilib
|
||||||
sudo apt install gettext python3-pexpect g++-multilib tmux
|
|
||||||
- name: cmake
|
- name: cmake
|
||||||
env:
|
env:
|
||||||
CFLAGS: "-m32"
|
CFLAGS: "-m32"
|
||||||
@@ -69,7 +70,6 @@ jobs:
|
|||||||
make -C build VERBOSE=1 fish_run_tests
|
make -C build VERBOSE=1 fish_run_tests
|
||||||
|
|
||||||
ubuntu-asan:
|
ubuntu-asan:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
env:
|
env:
|
||||||
# Rust has two different memory sanitizers of interest; they can't be used at the same time:
|
# Rust has two different memory sanitizers of interest; they can't be used at the same time:
|
||||||
@@ -79,7 +79,6 @@ jobs:
|
|||||||
#
|
#
|
||||||
RUSTFLAGS: "-Zsanitizer=address"
|
RUSTFLAGS: "-Zsanitizer=address"
|
||||||
# RUSTFLAGS: "-Zsanitizer=memory -Zsanitizer-memory-track-origins"
|
# RUSTFLAGS: "-Zsanitizer=memory -Zsanitizer-memory-track-origins"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
# All -Z options require running nightly
|
# All -Z options require running nightly
|
||||||
@@ -89,8 +88,11 @@ jobs:
|
|||||||
# this is comma-separated
|
# this is comma-separated
|
||||||
components: rust-src
|
components: rust-src
|
||||||
- name: Install deps
|
- name: Install deps
|
||||||
|
uses: ./.github/actions/install-dependencies
|
||||||
|
with:
|
||||||
|
include_sphinx: false
|
||||||
|
- name: Install llvm
|
||||||
run: |
|
run: |
|
||||||
sudo apt install gettext libpcre2-dev python3-pexpect tmux
|
|
||||||
sudo apt install llvm # for llvm-symbolizer
|
sudo apt install llvm # for llvm-symbolizer
|
||||||
- name: cmake
|
- name: cmake
|
||||||
env:
|
env:
|
||||||
@@ -119,38 +121,8 @@ jobs:
|
|||||||
export LSAN_OPTIONS="$LSAN_OPTIONS:suppressions=$PWD/build_tools/lsan_suppressions.txt"
|
export LSAN_OPTIONS="$LSAN_OPTIONS:suppressions=$PWD/build_tools/lsan_suppressions.txt"
|
||||||
make -C build VERBOSE=1 fish_run_tests
|
make -C build VERBOSE=1 fish_run_tests
|
||||||
|
|
||||||
# Our clang++ tsan builds are not recognizing safe rust patterns (such as the fact that Drop
|
|
||||||
# cannot be called while a thread is using the object in question). Rust has its own way of
|
|
||||||
# running TSAN, but for the duration of the port from C++ to Rust, we'll keep this disabled.
|
|
||||||
|
|
||||||
# ubuntu-threadsan:
|
|
||||||
#
|
|
||||||
# runs-on: ubuntu-latest
|
|
||||||
#
|
|
||||||
# steps:
|
|
||||||
# - uses: actions/checkout@v4
|
|
||||||
# - uses: ./.github/actions/rust-toolchain@oldest-supported
|
|
||||||
# - name: Install deps
|
|
||||||
# run: |
|
|
||||||
# sudo apt install gettext libpcre2-dev python3-pexpect tmux
|
|
||||||
# - name: cmake
|
|
||||||
# env:
|
|
||||||
# FISH_CI_SAN: 1
|
|
||||||
# CC: clang
|
|
||||||
# run: |
|
|
||||||
# mkdir build && cd build
|
|
||||||
# cmake ..
|
|
||||||
# - name: make
|
|
||||||
# run: |
|
|
||||||
# make
|
|
||||||
# - name: make fish_run_tests
|
|
||||||
# run: |
|
|
||||||
# make -C build fish_run_tests
|
|
||||||
|
|
||||||
macos:
|
macos:
|
||||||
|
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
|
|
||||||
env:
|
env:
|
||||||
# macOS runners keep having issues loading Cargo.toml dependencies from git (GitHub) instead
|
# macOS runners keep having issues loading Cargo.toml dependencies from git (GitHub) instead
|
||||||
# of crates.io, so give this a try. It's also sometimes significantly faster on all platforms.
|
# of crates.io, so give this a try. It's also sometimes significantly faster on all platforms.
|
||||||
@@ -163,14 +135,42 @@ jobs:
|
|||||||
# --break-system-packages because homebrew has now declared itself "externally managed".
|
# --break-system-packages because homebrew has now declared itself "externally managed".
|
||||||
# this is CI so we don't actually care.
|
# this is CI so we don't actually care.
|
||||||
sudo pip3 install --break-system-packages pexpect
|
sudo pip3 install --break-system-packages pexpect
|
||||||
brew install tmux
|
brew install gettext tmux
|
||||||
|
- uses: ./.github/actions/install-sphinx
|
||||||
- name: cmake
|
- name: cmake
|
||||||
run: |
|
run: |
|
||||||
mkdir build && cd build
|
mkdir build && cd build
|
||||||
cmake -DCMAKE_BUILD_TYPE=Debug ..
|
FISH_TEST_MAX_CONCURRENCY=1 \
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Debug ..
|
||||||
- name: make
|
- name: make
|
||||||
run: |
|
run: |
|
||||||
make -C build VERBOSE=1
|
make -C build VERBOSE=1
|
||||||
- name: make fish_run_tests
|
- name: make fish_run_tests
|
||||||
run: |
|
run: |
|
||||||
make -C build VERBOSE=1 fish_run_tests
|
make -C build VERBOSE=1 fish_run_tests
|
||||||
|
|
||||||
|
windows:
|
||||||
|
runs-on: windows-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: msys2 {0}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: msys2/setup-msys2@v2
|
||||||
|
with:
|
||||||
|
update: true
|
||||||
|
msystem: MSYS
|
||||||
|
- name: Install deps
|
||||||
|
# Not using setup-msys2 `install` option to make it easier to copy/paste
|
||||||
|
run: |
|
||||||
|
pacman --noconfirm -S --needed git rust
|
||||||
|
- name: cargo build
|
||||||
|
run: |
|
||||||
|
cargo build
|
||||||
|
- name: smoketest
|
||||||
|
# We can't run `build_tools/check.sh` yet, there are just too many failures
|
||||||
|
# so this is just a quick check to make sure that fish can swim
|
||||||
|
run: |
|
||||||
|
set -x
|
||||||
|
[ "$(target/debug/fish.exe -c 'echo (math 1 + 1)')" = 2 ]
|
||||||
|
cargo test
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -7,7 +7,6 @@
|
|||||||
*.DS_Store
|
*.DS_Store
|
||||||
*.a
|
*.a
|
||||||
*.app
|
*.app
|
||||||
*.d
|
|
||||||
*.dll
|
*.dll
|
||||||
*.dylib
|
*.dylib
|
||||||
*.exe
|
*.exe
|
||||||
@@ -105,3 +104,6 @@ target/
|
|||||||
|
|
||||||
# JetBrains editors.
|
# JetBrains editors.
|
||||||
.idea/
|
.idea/
|
||||||
|
|
||||||
|
# AI slop
|
||||||
|
.claude/
|
||||||
|
|||||||
1
.rustfmt.toml
Normal file
1
.rustfmt.toml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
edition = "2024"
|
||||||
202
CHANGELOG.rst
202
CHANGELOG.rst
@@ -1,3 +1,196 @@
|
|||||||
|
fish 4.3.2 (released December 30, 2025)
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
This release fixes the following problems identified in 4.3.0:
|
||||||
|
|
||||||
|
- Pre-built macOS packages failed to start due to a ``Malformed Mach-O file`` error (:issue:`12224`).
|
||||||
|
- ``extra_functionsdir`` (usually ``vendor_functions.d``) and friends were not used (:issue:`12226`).
|
||||||
|
- Sample config file ``~/.config/fish/config.fish/`` and config directories ``~/.config/fish/conf.d/``, ``~/.config/fish/completions/`` and ``~/.config/fish/functions/`` were recreated on every startup instead of only the first time fish runs on a system (:issue:`12230`).
|
||||||
|
- Spurious echo of ``^[[I`` in some scenarios (:issue:`12232`).
|
||||||
|
- Infinite prompt redraw loop on some prompts (:issue:`12233`).
|
||||||
|
- The removal of pre-built HTML docs from tarballs revealed that cross compilation is broken because we use ``${CMAKE_BINARY_DIR}/fish_indent`` for building HTML docs.
|
||||||
|
As a workaround, the new CMake build option ``FISH_INDENT_FOR_BUILDING_DOCS`` can be set to the path of a runnable ``fish_indent`` binary.
|
||||||
|
|
||||||
|
fish 4.3.1 (released December 28, 2025)
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
This release fixes the following problem identified in 4.3.0:
|
||||||
|
|
||||||
|
- Possible crash after expanding an abbreviation (:issue:`12223`).
|
||||||
|
|
||||||
|
fish 4.3.0 (released December 28, 2025)
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
Deprecations and removed features
|
||||||
|
---------------------------------
|
||||||
|
- fish no longer sets user-facing :ref:`universal variables <variables-universal>` by default, making the configuration easier to understand.
|
||||||
|
Specifically, the ``fish_color_*``, ``fish_pager_color_*`` and ``fish_key_bindings`` variables are now set in the global scope by default.
|
||||||
|
After upgrading to 4.3.0, fish will (once and never again) migrate these universals to globals set at startup in the
|
||||||
|
``~/.config/fish/conf.d/fish_frozen_theme.fish`` and
|
||||||
|
``~/.config/fish/conf.d/fish_frozen_key_bindings.fish`` files.
|
||||||
|
We suggest that you delete those files and :ref:`set your theme <syntax-highlighting>` in ``~/.config/fish/config.fish``.
|
||||||
|
|
||||||
|
- You can still configure fish to propagate theme changes instantly; see :ref:`here <syntax-highlighting-instant-update>` for an example.
|
||||||
|
- You can still opt into storing color variables in the universal scope
|
||||||
|
via ``fish_config theme save`` though unlike ``fish_config theme choose``,
|
||||||
|
it does not support dynamic theme switching based on the terminal's color theme (see below).
|
||||||
|
- In addition to setting the variables which are explicitly defined in the given theme,
|
||||||
|
``fish_config theme choose`` now clears only color variables that were set by earlier invocations of a ``fish_config theme choose`` command
|
||||||
|
(which is how fish's default theme is set).
|
||||||
|
|
||||||
|
Scripting improvements
|
||||||
|
----------------------
|
||||||
|
- New :ref:`status language <status-language>` command allows showing and modifying language settings for fish messages without having to modify environment variables.
|
||||||
|
- When using a noninteractive fish instance to compute completions, ``commandline --cursor`` works as expected instead of throwing an error (:issue:`11993`).
|
||||||
|
- :envvar:`fish_trace` can now be set to ``all`` to also trace execution of key bindings, event handlers as well as prompt and title functions.
|
||||||
|
|
||||||
|
Interactive improvements
|
||||||
|
------------------------
|
||||||
|
- When typing immediately after starting fish, the first prompt is now rendered correctly.
|
||||||
|
- Completion accuracy was improved for file paths containing ``=`` or ``:`` (:issue:`5363`).
|
||||||
|
- Prefix-matching completions are now shown even if they don't match the case typed by the user (:issue:`7944`).
|
||||||
|
- On Cygwin/MSYS, command name completion will favor the non-exe name (``foo``) unless the user started typing the extension.
|
||||||
|
- When using the exe name (``foo.exe``), fish will use the description and completions for ``foo`` if there are none for ``foo.exe``.
|
||||||
|
- Autosuggestions now also show soft-wrapped portions (:issue:`12045`).
|
||||||
|
|
||||||
|
New or improved bindings
|
||||||
|
------------------------
|
||||||
|
- :kbd:`ctrl-w` (``backward-kill-path-component``) also deletes escaped spaces (:issue:`2016`).
|
||||||
|
- New special input functions ``backward-path-component``, ``forward-path-component`` and ``kill-path-component`` (:issue:`12127`).
|
||||||
|
|
||||||
|
Improved terminal support
|
||||||
|
-------------------------
|
||||||
|
- Themes can now be made color-theme-aware by including both ``[light]`` and ``[dark]`` sections in the :ref:`theme file <fish-config-theme-files>`.
|
||||||
|
Some default themes have been made color-theme-aware, meaning they dynamically adjust as your terminal's background color switches between light and dark colors (:issue:`11580`).
|
||||||
|
- The working directory is now reported on every fresh prompt (via OSC 7), fixing scenarios where a child process (like ``ssh``) left behind a stale working directory (:issue:`12191`).
|
||||||
|
- OSC 133 prompt markers now also mark the prompt end, which improves shell integration with terminals like iTerm2 (:issue:`11837`).
|
||||||
|
- Operating-system-specific key bindings are now decided based on the :ref:`terminal's host OS <status-terminal-os>`.
|
||||||
|
- New :ref:`feature flag <featureflags>` ``omit-term-workarounds`` can be turned on to prevent fish from trying to work around some incompatible terminals.
|
||||||
|
|
||||||
|
For distributors and developers
|
||||||
|
-------------------------------
|
||||||
|
- Tarballs no longer contain prebuilt documentation,
|
||||||
|
so building and installing documentation requires Sphinx.
|
||||||
|
To avoid users accidentally losing docs, the ``BUILD_DOCS`` and ``INSTALL_DOCS`` configuration options have been replaced with a new ``WITH_DOCS`` option.
|
||||||
|
- ``fish_key_reader`` and ``fish_indent`` are now installed as hardlinks to ``fish``, to save some space.
|
||||||
|
|
||||||
|
Regression fixes:
|
||||||
|
-----------------
|
||||||
|
- (from 4.1.0) Crash on incorrectly-set color variables (:issue:`12078`).
|
||||||
|
- (from 4.1.0) Crash when autosuggesting Unicode characters with nontrivial lowercase mapping.
|
||||||
|
- (from 4.2.0) Incorrect emoji width computation on macOS.
|
||||||
|
- (from 4.2.0) Mouse clicks and :kbd:`ctrl-l` edge cases in multiline command lines (:issue:`12121`).
|
||||||
|
- (from 4.2.0) Completions for Git remote names on some non-glibc systems.
|
||||||
|
- (from 4.2.0) Expansion of ``~$USER``.
|
||||||
|
|
||||||
|
fish 4.2.1 (released November 13, 2025)
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
This release fixes the following problems identified in 4.2.0:
|
||||||
|
|
||||||
|
- When building from a tarball without Sphinx (that is, with ``-DBUILD_DOCS=OFF`` or when ``sphinx-build`` is not found),
|
||||||
|
builtin man pages and help files were missing, which has been fixed (:issue:`12052`).
|
||||||
|
- ``fish_config``'s theme selector (the "colors" tab) was broken, which has been fixed (:issue:`12053`).
|
||||||
|
|
||||||
|
fish 4.2.0 (released November 10, 2025)
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
Notable improvements and fixes
|
||||||
|
------------------------------
|
||||||
|
- History-based autosuggestions now include multi-line commands.
|
||||||
|
- A :ref:`transient prompt <transient-prompt>` containing more lines than the final prompt will now be cleared properly (:issue:`11875`).
|
||||||
|
- Taiwanese Chinese translations have been added.
|
||||||
|
- French translations have been supplemented (:issue:`11842`).
|
||||||
|
|
||||||
|
Deprecations and removed features
|
||||||
|
---------------------------------
|
||||||
|
- fish now assumes UTF-8 for character encoding even if the system does not have a UTF-8 locale.
|
||||||
|
Input bytes which are not valid UTF-8 are still round-tripped correctly.
|
||||||
|
For example, file paths using legacy encodings can still be used,
|
||||||
|
but may be rendered differently on the command line.
|
||||||
|
- On systems where no multi-byte locale is available,
|
||||||
|
fish will no longer fall back to using ASCII replacements for :ref:`Unicode characters <term-compat-unicode-codepoints>` such as "…".
|
||||||
|
|
||||||
|
Interactive improvements
|
||||||
|
------------------------
|
||||||
|
- The title of the terminal tab can now be set separately from the window title by defining the :doc:`fish_tab_title <cmds/fish_tab_title>` function (:issue:`2692`).
|
||||||
|
- fish now hides the portion of a multiline prompt that is scrolled out of view due to a huge command line. This prevents duplicate lines after repainting with partially visible prompt (:issue:`11911`).
|
||||||
|
- :doc:`fish_config prompt <cmds/fish_config>`'s ``choose`` and ``save`` subcommands have been taught to reset :doc:`fish_mode_prompt <cmds/fish_mode_prompt>` in addition to the other prompt functions (:issue:`11937`).
|
||||||
|
- fish no longer force-disables mouse capture (DECSET/DECRST 1000),
|
||||||
|
so you can use those commands
|
||||||
|
to let mouse clicks move the cursor or select completions items (:issue:`4918`).
|
||||||
|
- The :kbd:`alt-p` binding no longer adds a redundant space to the command line.
|
||||||
|
- When run as a login shell on macOS, fish now sets :envvar:`MANPATH` correctly when that variable was already present in the environment (:issue:`10684`).
|
||||||
|
- A Windows-specific case of the :doc:`web-based config <cmds/fish_config>` failing to launch has been fixed (:issue:`11805`).
|
||||||
|
- A MSYS2-specific workaround for Konsole and WezTerm has been added,
|
||||||
|
to prevent them from using the wrong working directory when opening new tabs (:issue:`11981`).
|
||||||
|
|
||||||
|
For distributors and developers
|
||||||
|
-------------------------------
|
||||||
|
- Release tags and source code tarballs are GPG-signed again (:issue:`11996`).
|
||||||
|
- Documentation in release tarballs is now built with the latest version of Sphinx,
|
||||||
|
which means that pre-built man pages include :ref:`OSC 8 hyperlinks <term-compat-osc-8>`.
|
||||||
|
- The Sphinx dependency is now specified in ``pyproject.toml``,
|
||||||
|
which allows you to use `uv <https://github.com/astral-sh/uv>`__ to provide Sphinx for building documentation (e.g. ``uv run cargo install --path .``).
|
||||||
|
- The minimum supported Rust version (MSRV) has been updated to 1.85.
|
||||||
|
- The standalone build mode has been made the default.
|
||||||
|
This means that the files in ``$CMAKE_INSTALL_PREFIX/share/fish`` will not be used anymore, except for HTML docs.
|
||||||
|
As a result, future upgrades will no longer break running shells
|
||||||
|
if one of fish's internal helper functions has been changed in the updated version.
|
||||||
|
For now, the data files are still installed redundantly,
|
||||||
|
to prevent upgrades from breaking already-running shells (:issue:`11921`).
|
||||||
|
To reverse this change (which should not be necessary),
|
||||||
|
patch out the ``embed-data`` feature from ``cmake/Rust.cmake``.
|
||||||
|
This option will be removed in future.
|
||||||
|
- OpenBSD 7.8 revealed an issue with fish's approach for displaying builtin man pages, which has been fixed.
|
||||||
|
|
||||||
|
Regression fixes:
|
||||||
|
-----------------
|
||||||
|
- (from 4.1.0) Fix the :doc:`web-based config <cmds/fish_config>` for Python 3.9 and older (:issue:`12039`).
|
||||||
|
- (from 4.1.0) Correct wrong terminal modes set by ``fish -c 'read; cat`` (:issue:`12024`).
|
||||||
|
- (from 4.1.0) On VTE-based terminals, stop redrawing the prompt on resize again, to avoid glitches.
|
||||||
|
- (from 4.1.0) On MSYS2, fix saving/loading of universal variables (:issue:`11948`).
|
||||||
|
- (from 4.1.0) Fix error using ``man`` for the commands ``!`` ``.`` ``:`` ``[`` ``{`` (:issue:`11955`).
|
||||||
|
- (from 4.1.0) Fix build issues on illumos systems (:issue:`11982`).
|
||||||
|
- (from 4.1.0) Fix crash on invalid :doc:`function <cmds/function>` command (:issue:`11912`).
|
||||||
|
- (from 4.0.0) Fix build on SPARC and MIPS Linux by disabling ``SIGSTKFLT``.
|
||||||
|
- (from 4.0.0) Fix crash when passing negative PIDs to builtin :doc:`wait <cmds/wait>` (:issue:`11929`).
|
||||||
|
- (from 4.0.0) On Linux, fix :doc:`status fish-path <cmds/status>` output when fish has been reinstalled since it was started.
|
||||||
|
|
||||||
|
fish 4.1.2 (released October 7, 2025)
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
This release fixes the following regressions identified in 4.1.0:
|
||||||
|
|
||||||
|
- Fixed spurious error output when completing remote file paths for ``scp`` (:issue:`11860`).
|
||||||
|
- Fixed the :kbd:`alt-l` binding not formatting ``ls`` output correctly (one entry per line, no colors) (:issue:`11888`).
|
||||||
|
- Fixed an issue where focus events (currently only enabled in ``tmux``) would cause multiline prompts to be redrawn in the wrong line (:issue:`11870`).
|
||||||
|
- Stopped printing output that would cause a glitch on old versions of Midnight Commander (:issue:`11869`).
|
||||||
|
- Added a fix for some configurations of Zellij where :kbd:`escape` key processing was delayed (:issue:`11868`).
|
||||||
|
- Fixed a case where the :doc:`web-based configuration tool <cmds/fish_config>` would generate invalid configuration (:issue:`11861`).
|
||||||
|
- Fixed a case where pasting into ``fish -c read`` would fail with a noisy error (:issue:`11836`).
|
||||||
|
- Fixed a case where upgrading fish would break old versions of fish that were still running.
|
||||||
|
|
||||||
|
In general, fish still needs to be restarted after it is upgraded,
|
||||||
|
except for `standalone builds <https://github.com/fish-shell/fish-shell/?tab=readme-ov-file#building-fish-with-embedded-data-experimental>`__.
|
||||||
|
|
||||||
|
fish 4.1.1 (released September 30, 2025)
|
||||||
|
========================================
|
||||||
|
|
||||||
|
This release fixes the following regressions identified in 4.1.0:
|
||||||
|
|
||||||
|
- Many of our new Chinese translations were more confusing than helpful; they have been fixed or removed (:issue:`11833`).
|
||||||
|
|
||||||
|
Note that you can work around this type of issue by configuring fish's :doc:`message localization <cmds/_>`:
|
||||||
|
if your environment contains something like ``LANG=zh_CN.UTF-8``,
|
||||||
|
you can use ``set -g LC_MESSAGES en`` to use English messages inside fish.
|
||||||
|
This will not affect fish's child processes unless ``LC_MESSAGES`` was already exported.
|
||||||
|
|
||||||
|
- Some :doc:`fish_config <cmds/fish_config>` subcommands for showing prompts and themes had been broken in standalone Linux builds (those using the ``embed-data`` cargo feature), which has been fixed (:issue:`11832`).
|
||||||
|
- On Windows Terminal, we observed an issue where fish would fail to read the terminal's response to our new startup queries, causing noticeable lags and a misleading error message. A workaround has been added (:issue:`11841`).
|
||||||
|
- A WezTerm `issue breaking shifted key input <https://github.com/wezterm/wezterm/issues/6087>`__ has resurfaced on some versions of WezTerm; our workaround has been extended to cover all versions for now (:issue:`11204`).
|
||||||
|
- Fixed a crash in :doc:`the web-based configuration tool <cmds/fish_config>` when using the new underline styles (:issue:`11840`).
|
||||||
|
|
||||||
fish 4.1.0 (released September 27, 2025)
|
fish 4.1.0 (released September 27, 2025)
|
||||||
========================================
|
========================================
|
||||||
|
|
||||||
@@ -30,7 +223,7 @@ Deprecations and removed features
|
|||||||
- The ``--install`` option when fish is built as self-installing is removed, see :ref:`below <changelog-4.1-embedded>`.
|
- The ``--install`` option when fish is built as self-installing is removed, see :ref:`below <changelog-4.1-embedded>`.
|
||||||
- ``set_color ff0000`` now outputs 24-bit RGB true-color even if :envvar:`COLORTERM` is unset.
|
- ``set_color ff0000`` now outputs 24-bit RGB true-color even if :envvar:`COLORTERM` is unset.
|
||||||
One can override this by setting :envvar:`fish_term24bit` to 0 (:issue:`11372`).
|
One can override this by setting :envvar:`fish_term24bit` to 0 (:issue:`11372`).
|
||||||
- fish now requires the terminal to respond to queries for the :ref:`primary device attribute <term-compat-primary-da>`.
|
- fish now requires the terminal to respond to queries for the :ref:`Primary Device Attribute <term-compat-primary-da>`.
|
||||||
For now, this can be reversed via a :ref:`feature flag <featureflags>`,
|
For now, this can be reversed via a :ref:`feature flag <featureflags>`,
|
||||||
by running (once) ``set -Ua fish_features no-query-term`` and restarting fish.
|
by running (once) ``set -Ua fish_features no-query-term`` and restarting fish.
|
||||||
- Users of GNU screen may experience :ref:`minor glitches <term-compat-dcs-gnu-screen>` when starting fish.
|
- Users of GNU screen may experience :ref:`minor glitches <term-compat-dcs-gnu-screen>` when starting fish.
|
||||||
@@ -83,9 +276,6 @@ Improved terminal support
|
|||||||
- Support for double, curly, dotted and dashed underlines, for use in ``fish_color_*`` variables and the :doc:`set_color builtin <cmds/set_color>` (:issue:`10957`).
|
- Support for double, curly, dotted and dashed underlines, for use in ``fish_color_*`` variables and the :doc:`set_color builtin <cmds/set_color>` (:issue:`10957`).
|
||||||
- Underlines can now be colored independent of text (:issue:`7619`).
|
- Underlines can now be colored independent of text (:issue:`7619`).
|
||||||
- New documentation page :doc:`Terminal Compatibility <terminal-compatibility>` (also accessible via ``man fish-terminal-compatibility``) lists the terminal control sequences used by fish.
|
- New documentation page :doc:`Terminal Compatibility <terminal-compatibility>` (also accessible via ``man fish-terminal-compatibility``) lists the terminal control sequences used by fish.
|
||||||
- fish now requires the terminal to respond to queries for the :ref:`primary device attribute <term-compat-primary-da>`.
|
|
||||||
For now, this can be reversed via a :ref:`feature flag <featureflags>`,
|
|
||||||
by running (once) ``set -Ua fish_features no-query-term``.
|
|
||||||
|
|
||||||
Other improvements
|
Other improvements
|
||||||
------------------
|
------------------
|
||||||
@@ -827,7 +1017,7 @@ Notable improvements and fixes
|
|||||||
|
|
||||||
which expands ``!!`` to the last history item, anywhere on the command line, mimicking other shells' history expansion.
|
which expands ``!!`` to the last history item, anywhere on the command line, mimicking other shells' history expansion.
|
||||||
|
|
||||||
See :ref:`the documentation <cmd-abbr>` for more.
|
See :doc:`the documentation <cmds/abbr>` for more.
|
||||||
- ``path`` gained a new ``mtime`` subcommand to print the modification time stamp for files. For example, this can be used to handle cache file ages (:issue:`9057`)::
|
- ``path`` gained a new ``mtime`` subcommand to print the modification time stamp for files. For example, this can be used to handle cache file ages (:issue:`9057`)::
|
||||||
|
|
||||||
> touch foo
|
> touch foo
|
||||||
@@ -1252,7 +1442,7 @@ Scripting improvements
|
|||||||
two
|
two
|
||||||
'blue '
|
'blue '
|
||||||
|
|
||||||
- ``$fish_user_paths`` is now automatically deduplicated to fix a common user error of appending to it in config.fish when it is universal (:issue:`8117`). :ref:`fish_add_path <cmd-fish_add_path>` remains the recommended way to add to $PATH.
|
- ``$fish_user_paths`` is now automatically deduplicated to fix a common user error of appending to it in config.fish when it is universal (:issue:`8117`). :doc:`fish_add_path <cmds/fish_add_path>` remains the recommended way to add to $PATH.
|
||||||
- ``return`` can now be used outside functions. In scripts, it does the same thing as ``exit``. In interactive mode,it sets ``$status`` without exiting (:issue:`8148`).
|
- ``return`` can now be used outside functions. In scripts, it does the same thing as ``exit``. In interactive mode,it sets ``$status`` without exiting (:issue:`8148`).
|
||||||
- An oversight prevented all syntax checks from running on commands given to ``fish -c`` (:issue:`8171`). This includes checks such as ``exec`` not being allowed in a pipeline, and ``$$`` not being a valid variable. Generally, another error was generated anyway.
|
- An oversight prevented all syntax checks from running on commands given to ``fish -c`` (:issue:`8171`). This includes checks such as ``exec`` not being allowed in a pipeline, and ``$$`` not being a valid variable. Generally, another error was generated anyway.
|
||||||
- ``fish_indent`` now correctly reformats tokens that end with a backslash followed by a newline (:issue:`8197`).
|
- ``fish_indent`` now correctly reformats tokens that end with a backslash followed by a newline (:issue:`8197`).
|
||||||
|
|||||||
@@ -28,6 +28,23 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
|
|||||||
# This defines the FBVF variable.
|
# This defines the FBVF variable.
|
||||||
include(Version)
|
include(Version)
|
||||||
|
|
||||||
|
# Set up the docs.
|
||||||
|
include(cmake/Docs.cmake)
|
||||||
|
|
||||||
|
# Tell Cargo where our build directory is so it can find Cargo.toml.
|
||||||
|
set(VARS_FOR_CARGO
|
||||||
|
"FISH_CMAKE_BINARY_DIR=${CMAKE_BINARY_DIR}"
|
||||||
|
"PREFIX=${CMAKE_INSTALL_PREFIX}"
|
||||||
|
"DOCDIR=${CMAKE_INSTALL_FULL_DOCDIR}"
|
||||||
|
"DATADIR=${CMAKE_INSTALL_FULL_DATADIR}"
|
||||||
|
"SYSCONFDIR=${CMAKE_INSTALL_FULL_SYSCONFDIR}"
|
||||||
|
"BINDIR=${CMAKE_INSTALL_FULL_BINDIR}"
|
||||||
|
"CARGO_TARGET_DIR=${FISH_RUST_BUILD_DIR}"
|
||||||
|
"CARGO_BUILD_RUSTC=${Rust_COMPILER}"
|
||||||
|
"${FISH_PCRE2_BUILDFLAG}"
|
||||||
|
"FISH_SPHINX=${SPHINX_EXECUTABLE}"
|
||||||
|
)
|
||||||
|
|
||||||
# Let fish pick up when we're running out of the build directory without installing
|
# Let fish pick up when we're running out of the build directory without installing
|
||||||
get_filename_component(REAL_CMAKE_BINARY_DIR "${CMAKE_BINARY_DIR}" REALPATH)
|
get_filename_component(REAL_CMAKE_BINARY_DIR "${CMAKE_BINARY_DIR}" REALPATH)
|
||||||
get_filename_component(REAL_CMAKE_SOURCE_DIR "${CMAKE_SOURCE_DIR}" REALPATH)
|
get_filename_component(REAL_CMAKE_SOURCE_DIR "${CMAKE_SOURCE_DIR}" REALPATH)
|
||||||
@@ -39,40 +56,40 @@ if(NOT "${CMAKE_BUILD_TYPE}" IN_LIST build_types)
|
|||||||
message(WARNING "Unsupported build type ${CMAKE_BUILD_TYPE}. If this doesn't build, try one of Release, RelWithDebInfo or Debug")
|
message(WARNING "Unsupported build type ${CMAKE_BUILD_TYPE}. If this doesn't build, try one of Release, RelWithDebInfo or Debug")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Define a function to build and link dependencies.
|
add_custom_target(
|
||||||
function(CREATE_TARGET target)
|
fish ALL
|
||||||
|
COMMAND
|
||||||
|
"${CMAKE_COMMAND}" -E
|
||||||
|
env ${VARS_FOR_CARGO}
|
||||||
|
${Rust_CARGO}
|
||||||
|
build --bin fish
|
||||||
|
$<$<CONFIG:Release>:--release>
|
||||||
|
$<$<CONFIG:RelWithDebInfo>:--profile=release-with-debug>
|
||||||
|
--target ${Rust_CARGO_TARGET}
|
||||||
|
--no-default-features
|
||||||
|
--features=${FISH_CARGO_FEATURES}
|
||||||
|
${CARGO_FLAGS}
|
||||||
|
&&
|
||||||
|
"${CMAKE_COMMAND}" -E
|
||||||
|
copy "${rust_target_dir}/${rust_profile}/fish" "${CMAKE_CURRENT_BINARY_DIR}"
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
USES_TERMINAL
|
||||||
|
)
|
||||||
|
|
||||||
|
function(CREATE_LINK target)
|
||||||
add_custom_target(
|
add_custom_target(
|
||||||
${target} ALL
|
${target} ALL
|
||||||
COMMAND
|
DEPENDS fish
|
||||||
"${CMAKE_COMMAND}" -E
|
COMMAND ln -f fish ${target}
|
||||||
env ${VARS_FOR_CARGO}
|
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||||
${Rust_CARGO}
|
|
||||||
build --bin ${target}
|
|
||||||
$<$<CONFIG:Release>:--release>
|
|
||||||
$<$<CONFIG:RelWithDebInfo>:--profile=release-with-debug>
|
|
||||||
--target ${Rust_CARGO_TARGET}
|
|
||||||
--no-default-features
|
|
||||||
--features=${FISH_CARGO_FEATURES}
|
|
||||||
${CARGO_FLAGS}
|
|
||||||
&&
|
|
||||||
"${CMAKE_COMMAND}" -E
|
|
||||||
copy "${rust_target_dir}/${rust_profile}/${target}" "${CMAKE_CURRENT_BINARY_DIR}"
|
|
||||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
|
||||||
USES_TERMINAL
|
|
||||||
)
|
)
|
||||||
endfunction(CREATE_TARGET)
|
endfunction(CREATE_LINK)
|
||||||
|
|
||||||
# Define fish.
|
|
||||||
create_target(fish)
|
|
||||||
|
|
||||||
# Define fish_indent.
|
# Define fish_indent.
|
||||||
create_target(fish_indent)
|
create_link(fish_indent)
|
||||||
|
|
||||||
# Define fish_key_reader.
|
# Define fish_key_reader.
|
||||||
create_target(fish_key_reader)
|
create_link(fish_key_reader)
|
||||||
|
|
||||||
# Set up the docs.
|
|
||||||
include(cmake/Docs.cmake)
|
|
||||||
|
|
||||||
# Set up tests.
|
# Set up tests.
|
||||||
include(cmake/Tests.cmake)
|
include(cmake/Tests.cmake)
|
||||||
|
|||||||
177
CONTRIBUTING.rst
177
CONTRIBUTING.rst
@@ -21,10 +21,10 @@ Archives are available at https://lists.sr.ht/~krobelus/fish-shell/.
|
|||||||
GitHub
|
GitHub
|
||||||
======
|
======
|
||||||
|
|
||||||
Fish is available on Github, at https://github.com/fish-shell/fish-shell.
|
Fish is available on GitHub, at https://github.com/fish-shell/fish-shell.
|
||||||
|
|
||||||
First, you'll need an account there, and you'll need a git clone of fish.
|
First, you'll need an account there, and you'll need a git clone of fish.
|
||||||
Fork it on Github and then run::
|
Fork it on GitHub and then run::
|
||||||
|
|
||||||
git clone https://github.com/<USERNAME>/fish-shell.git
|
git clone https://github.com/<USERNAME>/fish-shell.git
|
||||||
|
|
||||||
@@ -52,6 +52,23 @@ In short:
|
|||||||
- Be conservative in what you need (keep to the agreed minimum supported Rust version, limit new dependencies)
|
- Be conservative in what you need (keep to the agreed minimum supported Rust version, limit new dependencies)
|
||||||
- Use automated tools to help you (``build_tools/check.sh``)
|
- Use automated tools to help you (``build_tools/check.sh``)
|
||||||
|
|
||||||
|
Commit History
|
||||||
|
==============
|
||||||
|
|
||||||
|
We use a linear, `recipe-style <https://www.bitsnbites.eu/git-history-work-log-vs-recipe/>`__ history.
|
||||||
|
Every commit should pass our checks.
|
||||||
|
We do not want "fixup" commits in our history.
|
||||||
|
If you notice an issue with a commit in a pull request, or get feedback suggesting changes,
|
||||||
|
you should rewrite the commit history and fix the relevant commits directly,
|
||||||
|
instead of adding new "fixup" commits.
|
||||||
|
When a pull request is ready, we rebase it on top of the current master branch,
|
||||||
|
so don't be shy about rewriting the history of commits which are not on master yet.
|
||||||
|
Rebasing (not merging) your pull request on the latest version of master is also welcome, especially if it resolves conflicts.
|
||||||
|
|
||||||
|
If you're using Git, consider using `jj <https://www.jj-vcs.dev/>`__ to make this easier.
|
||||||
|
|
||||||
|
If a commit should close an issue, add a ``Fixes #<issue-number>`` line at the end of the commit description.
|
||||||
|
|
||||||
Contributing completions
|
Contributing completions
|
||||||
========================
|
========================
|
||||||
|
|
||||||
@@ -71,7 +88,7 @@ Completion scripts should
|
|||||||
|
|
||||||
1. Use as few dependencies as possible - try to use fish's builtins like ``string`` instead of ``grep`` and ``awk``,
|
1. Use as few dependencies as possible - try to use fish's builtins like ``string`` instead of ``grep`` and ``awk``,
|
||||||
use ``python`` to read json instead of ``jq`` (because it's already a soft dependency for fish's tools)
|
use ``python`` to read json instead of ``jq`` (because it's already a soft dependency for fish's tools)
|
||||||
2. If it uses a common unix tool, use posix-compatible invocations - ideally it would work on GNU/Linux, macOS, the BSDs and other systems
|
2. If it uses a common unix tool, use POSIX-compatible invocations - ideally it would work on GNU/Linux, macOS, the BSDs and other systems
|
||||||
3. Option and argument descriptions should be kept short.
|
3. Option and argument descriptions should be kept short.
|
||||||
The shorter the description, the more likely it is that fish can use more columns.
|
The shorter the description, the more likely it is that fish can use more columns.
|
||||||
4. Function names should start with ``__fish``, and functions should be kept in the completion file unless they're used elsewhere.
|
4. Function names should start with ``__fish``, and functions should be kept in the completion file unless they're used elsewhere.
|
||||||
@@ -89,44 +106,36 @@ Contributing documentation
|
|||||||
|
|
||||||
The documentation is stored in ``doc_src/``, and written in ReStructured Text and built with Sphinx.
|
The documentation is stored in ``doc_src/``, and written in ReStructured Text and built with Sphinx.
|
||||||
|
|
||||||
To build it locally, run from the main fish-shell directory::
|
To build it locally, run either::
|
||||||
|
|
||||||
sphinx-build -j 8 -b html -n doc_src/ /tmp/fish-doc/
|
sphinx-build -j auto -b html doc_src/ /tmp/fish-doc/
|
||||||
|
|
||||||
which will build the docs as html in /tmp/fish-doc. You can open it in a browser and see that it looks okay.
|
which will output HTML docs to /tmp/fish-doc.
|
||||||
|
You can open it in a browser and see that it looks okay.
|
||||||
|
|
||||||
|
Alternatively, you can use::
|
||||||
|
|
||||||
|
cmake --build build -t sphinx-docs
|
||||||
|
|
||||||
|
which outputs to build/user_doc/html/.
|
||||||
|
|
||||||
The builtins and various functions shipped with fish are documented in doc_src/cmds/.
|
The builtins and various functions shipped with fish are documented in doc_src/cmds/.
|
||||||
|
|
||||||
Code Style
|
Code Style
|
||||||
==========
|
==========
|
||||||
|
|
||||||
To ensure your changes conform to the style rules run
|
For formatting, we use:
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
build_tools/style.fish
|
|
||||||
|
|
||||||
before committing your change. That will run our autoformatters:
|
|
||||||
|
|
||||||
- ``rustfmt`` for Rust
|
- ``rustfmt`` for Rust
|
||||||
- ``fish_indent`` (shipped with fish) for fish script
|
- ``fish_indent`` (shipped with fish) for fish script
|
||||||
- ``black`` for python
|
- ``ruff format`` for Python
|
||||||
|
|
||||||
If you’ve already committed your changes that’s okay since it will then
|
To reformat files, there is a script
|
||||||
check the files in the most recent commit. This can be useful after
|
|
||||||
you’ve merged another person’s change and want to check that it’s style
|
|
||||||
is acceptable. However, in that case it will run ``clang-format`` to
|
|
||||||
ensure the entire file, not just the lines modified by the commit,
|
|
||||||
conform to the style.
|
|
||||||
|
|
||||||
If you want to check the style of the entire code base run
|
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
build_tools/style.fish --all
|
build_tools/style.fish --all
|
||||||
|
build_tools/style.fish somefile.rs some.fish
|
||||||
That command will refuse to restyle any files if you have uncommitted
|
|
||||||
changes.
|
|
||||||
|
|
||||||
Fish Script Style Guide
|
Fish Script Style Guide
|
||||||
-----------------------
|
-----------------------
|
||||||
@@ -178,10 +187,10 @@ made to run fish_indent via e.g.
|
|||||||
(add-hook 'fish-mode-hook (lambda ()
|
(add-hook 'fish-mode-hook (lambda ()
|
||||||
(add-hook 'before-save-hook 'fish_indent-before-save)))
|
(add-hook 'before-save-hook 'fish_indent-before-save)))
|
||||||
|
|
||||||
Rust Style Guide
|
Minimum Supported Rust Version (MSRV) Policy
|
||||||
----------------
|
--------------------------------------------
|
||||||
|
|
||||||
Use ``cargo fmt`` and ``cargo clippy``. Clippy warnings can be turned off if there's a good reason to.
|
We support at least the version of ``rustc`` available in Debian Stable.
|
||||||
|
|
||||||
Testing
|
Testing
|
||||||
=======
|
=======
|
||||||
@@ -190,84 +199,53 @@ The source code for fish includes a large collection of tests. If you
|
|||||||
are making any changes to fish, running these tests is a good way to make
|
are making any changes to fish, running these tests is a good way to make
|
||||||
sure the behaviour remains consistent and regressions are not
|
sure the behaviour remains consistent and regressions are not
|
||||||
introduced. Even if you don’t run the tests on your machine, they will
|
introduced. Even if you don’t run the tests on your machine, they will
|
||||||
still be run via Github Actions.
|
still be run via GitHub Actions.
|
||||||
|
|
||||||
You are strongly encouraged to add tests when changing the functionality
|
You are strongly encouraged to add tests when changing the functionality
|
||||||
of fish, especially if you are fixing a bug to help ensure there are no
|
of fish, especially if you are fixing a bug to help ensure there are no
|
||||||
regressions in the future (i.e., we don’t reintroduce the bug).
|
regressions in the future (i.e., we don’t reintroduce the bug).
|
||||||
|
|
||||||
The tests can be found in three places:
|
Unit tests live next to the implementation in Rust source files, in inline submodules (``mod tests {}``).
|
||||||
|
|
||||||
- src/tests for unit tests.
|
System tests live in ``tests/``:
|
||||||
- tests/checks for script tests, run by `littlecheck <https://github.com/ridiculousfish/littlecheck>`__
|
|
||||||
- tests/pexpects for interactive tests using `pexpect <https://pexpect.readthedocs.io/en/stable/>`__
|
|
||||||
|
|
||||||
When in doubt, the bulk of the tests should be added as a littlecheck test in tests/checks, as they are the easiest to modify and run, and much faster and more dependable than pexpect tests. The syntax is fairly self-explanatory. It's a fish script with the expected output in ``# CHECK:`` or ``# CHECKERR:`` (for stderr) comments.
|
- ``tests/checks`` are run by `littlecheck <https://github.com/ridiculousfish/littlecheck>`__
|
||||||
If your littlecheck test has a specific dependency, use ``# REQUIRE: ...`` with a posix sh script.
|
and test noninteractive (script) behavior,
|
||||||
|
except for ``tests/checks/tmux-*`` which test interactive scenarios.
|
||||||
|
- ``tests/pexpects`` tests interactive scenarios using `pexpect <https://pexpect.readthedocs.io/en/stable/>`__
|
||||||
|
|
||||||
The pexpects are written in python and can simulate input and output to/from a terminal, so they are needed for anything that needs actual interactivity. The runner is in tests/pexpect_helper.py, in case you need to modify something there.
|
When in doubt, the bulk of the tests should be added as a littlecheck test in tests/checks, as they are the easiest to modify and run, and much faster and more dependable than pexpect tests.
|
||||||
|
The syntax is fairly self-explanatory.
|
||||||
|
It's a fish script with the expected output in ``# CHECK:`` or ``# CHECKERR:`` (for stderr) comments.
|
||||||
|
If your littlecheck test has a specific dependency, use ``# REQUIRE: ...`` with a POSIX sh script.
|
||||||
|
|
||||||
These tests can be run via the tests/test_driver.py python script, which will set up the environment.
|
The pexpect tests are written in Python and can simulate input and output to/from a terminal, so they are needed for anything that needs actual interactivity.
|
||||||
|
The runner is in tests/pexpect_helper.py, in case you need to modify something there.
|
||||||
|
|
||||||
|
These tests can be run via the tests/test_driver.py Python script, which will set up the environment.
|
||||||
It sets up a temporary $HOME and also uses it as the current directory, so you do not need to create a temporary directory in them.
|
It sets up a temporary $HOME and also uses it as the current directory, so you do not need to create a temporary directory in them.
|
||||||
|
|
||||||
If you need a command to do something weird to test something, maybe add it to the ``fish_test_helper`` binary (in tests/fish_test_helper.c), or see if it can already do it.
|
If you need a command to do something weird to test something, maybe add it to the ``fish_test_helper`` binary (in ``tests/fish_test_helper.c``).
|
||||||
|
|
||||||
Local testing
|
Local testing
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
The tests can be run on your local computer on all operating systems.
|
The tests can be run on your local system::
|
||||||
|
|
||||||
::
|
cargo build
|
||||||
|
# Run unit tests
|
||||||
cmake path/to/fish-shell
|
cargo test
|
||||||
make fish_run_tests
|
# Run system tests
|
||||||
|
tests/test_driver.py target/debug
|
||||||
Or you can run them on a fish, without involving cmake::
|
# Run a specific system test.
|
||||||
|
tests/test_driver.py target/debug tests/checks/abbr.fish
|
||||||
cargo build
|
|
||||||
cargo test # for the unit tests
|
|
||||||
tests/test_driver.py target/debug # for the script and interactive tests
|
|
||||||
|
|
||||||
Here, the first argument to test_driver.py refers to a directory with ``fish``, ``fish_indent`` and ``fish_key_reader`` in it.
|
Here, the first argument to test_driver.py refers to a directory with ``fish``, ``fish_indent`` and ``fish_key_reader`` in it.
|
||||||
In this example we're in the root of the git repo and have run ``cargo build`` without ``--release``, so it's a debug build.
|
In this example we're in the root of the workspace and have run ``cargo build`` without ``--release``, so it's a debug build.
|
||||||
|
|
||||||
Git hooks
|
To run all tests and linters, use::
|
||||||
---------
|
|
||||||
|
|
||||||
Since developers sometimes forget to run the tests, it can be helpful to
|
build_tools/check.sh
|
||||||
use git hooks (see githooks(5)) to automate it.
|
|
||||||
|
|
||||||
One possibility is a pre-push hook script like this one:
|
|
||||||
|
|
||||||
.. code:: sh
|
|
||||||
|
|
||||||
#!/bin/sh
|
|
||||||
#### A pre-push hook for the fish-shell project
|
|
||||||
# This will run the tests when a push to master is detected, and will stop that if the tests fail
|
|
||||||
# Save this as .git/hooks/pre-push and make it executable
|
|
||||||
|
|
||||||
protected_branch='master'
|
|
||||||
|
|
||||||
# Git gives us lines like "refs/heads/frombranch SOMESHA1 refs/heads/tobranch SOMESHA1"
|
|
||||||
# We're only interested in the branches
|
|
||||||
isprotected=false
|
|
||||||
while read from _ to _; do
|
|
||||||
if [ "$to" = "refs/heads/$protected_branch" ]; then
|
|
||||||
isprotected=true
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if "$isprotected"; then
|
|
||||||
echo "Running checks before push to master"
|
|
||||||
build_tools/check.sh
|
|
||||||
fi
|
|
||||||
|
|
||||||
This will check if the push is to the master branch and, if it is, only
|
|
||||||
allow the push if running ``build_tools/check.sh`` succeeds. In some circumstances
|
|
||||||
it may be advisable to circumvent this check with
|
|
||||||
``git push --no-verify``, but usually that isn’t necessary.
|
|
||||||
|
|
||||||
To install the hook, place the code in a new file
|
|
||||||
``.git/hooks/pre-push`` and make it executable.
|
|
||||||
|
|
||||||
Contributing Translations
|
Contributing Translations
|
||||||
=========================
|
=========================
|
||||||
@@ -279,9 +257,8 @@ It also means that some features are not supported, such as message context and
|
|||||||
We also expect all files to be UTF-8-encoded.
|
We also expect all files to be UTF-8-encoded.
|
||||||
In practice, this should not matter much for contributing translations.
|
In practice, this should not matter much for contributing translations.
|
||||||
|
|
||||||
Translation sources are
|
Translation sources are stored in the ``localization/po`` directory and named ``ll_CC.po``,
|
||||||
stored in the ``po`` directory, named ``ll_CC.po``, where ``ll`` is the
|
where ``ll`` is the two (or possibly three) letter ISO 639-1 language code of the target language
|
||||||
two (or possibly three) letter ISO 639-1 language code of the target language
|
|
||||||
(e.g. ``pt`` for Portuguese). ``CC`` is an ISO 3166 country/territory code,
|
(e.g. ``pt`` for Portuguese). ``CC`` is an ISO 3166 country/territory code,
|
||||||
(e.g. ``BR`` for Brazil).
|
(e.g. ``BR`` for Brazil).
|
||||||
An example for a valid name is ``pt_BR.po``, indicating Brazilian Portuguese.
|
An example for a valid name is ``pt_BR.po``, indicating Brazilian Portuguese.
|
||||||
@@ -295,7 +272,7 @@ More specifically, you will need ``msguniq`` and ``msgmerge`` for creating trans
|
|||||||
language.
|
language.
|
||||||
To create a new translation, run::
|
To create a new translation, run::
|
||||||
|
|
||||||
build_tools/update_translations.fish po/ll_CC.po
|
build_tools/update_translations.fish localization/po/ll_CC.po
|
||||||
|
|
||||||
This will create a new PO file containing all messages available for translation.
|
This will create a new PO file containing all messages available for translation.
|
||||||
If the file already exists, it will be updated.
|
If the file already exists, it will be updated.
|
||||||
@@ -341,9 +318,9 @@ Editing PO files
|
|||||||
Many tools are available for editing translation files, including
|
Many tools are available for editing translation files, including
|
||||||
command-line and graphical user interface programs. For simple use, you can use your text editor.
|
command-line and graphical user interface programs. For simple use, you can use your text editor.
|
||||||
|
|
||||||
Open up the PO file, for example ``po/sv.po``, and you'll see something like::
|
Open up the PO file, for example ``localization/po/sv.po``, and you'll see something like::
|
||||||
|
|
||||||
msgid "%ls: No suitable job\n"
|
msgid "%s: No suitable job\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
The ``msgid`` here is the "name" of the string to translate, typically the English string to translate.
|
The ``msgid`` here is the "name" of the string to translate, typically the English string to translate.
|
||||||
@@ -351,10 +328,10 @@ The second line (``msgstr``) is where your translation goes.
|
|||||||
|
|
||||||
For example::
|
For example::
|
||||||
|
|
||||||
msgid "%ls: No suitable job\n"
|
msgid "%s: No suitable job\n"
|
||||||
msgstr "%ls: Inget passande jobb\n"
|
msgstr "%s: Inget passande jobb\n"
|
||||||
|
|
||||||
Any ``%s`` / ``%ls`` or ``%d`` are placeholders that fish will use for formatting at runtime. It is important that they match - the translated string should have the same placeholders in the same order.
|
Any ``%s`` or ``%d`` are placeholders that fish will use for formatting at runtime. It is important that they match - the translated string should have the same placeholders in the same order.
|
||||||
|
|
||||||
Also any escaped characters, like that ``\n`` newline at the end, should be kept so the translation has the same behavior.
|
Also any escaped characters, like that ``\n`` newline at the end, should be kept so the translation has the same behavior.
|
||||||
|
|
||||||
@@ -369,7 +346,7 @@ Modifications to strings in source files
|
|||||||
If a string changes in the sources, the old translations will no longer work.
|
If a string changes in the sources, the old translations will no longer work.
|
||||||
They will be preserved in the PO files, but commented-out (starting with ``#~``).
|
They will be preserved in the PO files, but commented-out (starting with ``#~``).
|
||||||
If you add/remove/change a translatable strings in a source file,
|
If you add/remove/change a translatable strings in a source file,
|
||||||
run ``build_tools/update_translations.fish`` to propagate this to all translation files (``po/*.po``).
|
run ``build_tools/update_translations.fish`` to propagate this to all translation files (``localization/po/*.po``).
|
||||||
This is only relevant for developers modifying the source files of fish or fish scripts.
|
This is only relevant for developers modifying the source files of fish or fish scripts.
|
||||||
|
|
||||||
Setting Code Up For Translations
|
Setting Code Up For Translations
|
||||||
@@ -381,7 +358,7 @@ macros:
|
|||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
streams.out.append(wgettext_fmt!("%ls: There are no jobs\n", argv[0]));
|
streams.out.append(wgettext_fmt!("%s: There are no jobs\n", argv[0]));
|
||||||
|
|
||||||
All messages in fish script must be enclosed in single or double quote
|
All messages in fish script must be enclosed in single or double quote
|
||||||
characters for our message extraction script to find them.
|
characters for our message extraction script to find them.
|
||||||
@@ -404,6 +381,12 @@ You can use either single or double quotes to enclose the
|
|||||||
message to be translated. You can also optionally include spaces after
|
message to be translated. You can also optionally include spaces after
|
||||||
the opening parentheses or before the closing parentheses.
|
the opening parentheses or before the closing parentheses.
|
||||||
|
|
||||||
|
Updating Dependencies
|
||||||
|
=====================
|
||||||
|
|
||||||
|
To update dependencies, run ``build_tools/update-dependencies.sh``.
|
||||||
|
This currently requires `updatecli <https://github.com/updatecli/updatecli>`__ and a few other tools.
|
||||||
|
|
||||||
Versioning
|
Versioning
|
||||||
==========
|
==========
|
||||||
|
|
||||||
|
|||||||
597
Cargo.lock
generated
597
Cargo.lock
generated
@@ -1,6 +1,15 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "1.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "allocator-api2"
|
name = "allocator-api2"
|
||||||
@@ -10,15 +19,15 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.4.0"
|
version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.6.0"
|
version = "2.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "block-buffer"
|
name = "block-buffer"
|
||||||
@@ -30,11 +39,22 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "bstr"
|
||||||
version = "1.2.7"
|
version = "1.12.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a012a0df96dd6d06ba9a1b29d6402d1a5d77c6befd2566afdc26e10603dc93d7"
|
checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.2.41"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7"
|
||||||
|
dependencies = [
|
||||||
|
"find-msvc-tools",
|
||||||
"jobserver",
|
"jobserver",
|
||||||
"libc",
|
"libc",
|
||||||
"shlex",
|
"shlex",
|
||||||
@@ -42,9 +62,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.0"
|
version = "1.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg_aliases"
|
name = "cfg_aliases"
|
||||||
@@ -54,9 +74,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cpufeatures"
|
name = "cpufeatures"
|
||||||
version = "0.2.16"
|
version = "0.2.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3"
|
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
@@ -82,16 +102,37 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "equivalent"
|
name = "dirs"
|
||||||
version = "1.0.1"
|
version = "6.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
|
||||||
|
dependencies = [
|
||||||
|
"dirs-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dirs-sys"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"option-ext",
|
||||||
|
"redox_users",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "equivalent"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
version = "0.3.11"
|
version = "0.3.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
|
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys",
|
"windows-sys",
|
||||||
@@ -103,35 +144,48 @@ version = "2.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "find-msvc-tools"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fish"
|
name = "fish"
|
||||||
version = "4.1.0"
|
version = "4.3.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"cc",
|
"cc",
|
||||||
|
"cfg-if",
|
||||||
"errno",
|
"errno",
|
||||||
"fish-build-helper",
|
"fish-build-helper",
|
||||||
"fish-build-man-pages",
|
"fish-build-man-pages",
|
||||||
|
"fish-common",
|
||||||
|
"fish-fallback",
|
||||||
|
"fish-gettext",
|
||||||
"fish-gettext-extraction",
|
"fish-gettext-extraction",
|
||||||
"fish-gettext-maps",
|
|
||||||
"fish-gettext-mo-file-parser",
|
"fish-gettext-mo-file-parser",
|
||||||
"fish-printf",
|
"fish-printf",
|
||||||
|
"fish-tempfile",
|
||||||
|
"fish-wchar",
|
||||||
|
"fish-widecharwidth",
|
||||||
"libc",
|
"libc",
|
||||||
"lru",
|
"lru",
|
||||||
|
"macro_rules_attribute",
|
||||||
"nix",
|
"nix",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"pcre2",
|
"pcre2",
|
||||||
"phf 0.12.1",
|
|
||||||
"phf_codegen 0.12.1",
|
"phf_codegen 0.12.1",
|
||||||
"portable-atomic",
|
"portable-atomic",
|
||||||
"rand",
|
"rand 0.9.2",
|
||||||
"rsconf",
|
"rsconf",
|
||||||
"rust-embed",
|
"rust-embed",
|
||||||
"serial_test",
|
"serial_test",
|
||||||
"terminfo",
|
"terminfo",
|
||||||
"unix_path",
|
"unix_path",
|
||||||
"widestring",
|
"widestring",
|
||||||
|
"xterm-color",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -149,11 +203,45 @@ dependencies = [
|
|||||||
"rsconf",
|
"rsconf",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fish-common"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"nix",
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fish-fallback"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"fish-build-helper",
|
||||||
|
"fish-common",
|
||||||
|
"fish-wchar",
|
||||||
|
"fish-widecharwidth",
|
||||||
|
"libc",
|
||||||
|
"once_cell",
|
||||||
|
"rsconf",
|
||||||
|
"widestring",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fish-gettext"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"fish-gettext-maps",
|
||||||
|
"once_cell",
|
||||||
|
"phf 0.12.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fish-gettext-extraction"
|
name = "fish-gettext-extraction"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"fish-tempfile",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
"rsconf",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -181,6 +269,26 @@ dependencies = [
|
|||||||
"widestring",
|
"widestring",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fish-tempfile"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"nix",
|
||||||
|
"rand 0.9.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fish-wchar"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"fish-common",
|
||||||
|
"widestring",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fish-widecharwidth"
|
||||||
|
version = "0.0.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
@@ -189,25 +297,61 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "foldhash"
|
name = "foldhash"
|
||||||
version = "0.1.4"
|
version = "0.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f"
|
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "generic-array"
|
name = "generic-array"
|
||||||
version = "0.14.7"
|
version = "0.14.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"typenum",
|
"typenum",
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "getrandom"
|
||||||
version = "0.15.2"
|
version = "0.2.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"r-efi",
|
||||||
|
"wasip2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "globset"
|
||||||
|
version = "0.4.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "54a1028dfc5f5df5da8a56a73e6c153c9a9708ec57232470703592a3f18e49f5"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"bstr",
|
||||||
|
"log",
|
||||||
|
"regex-automata",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.15.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"allocator-api2",
|
"allocator-api2",
|
||||||
"equivalent",
|
"equivalent",
|
||||||
@@ -216,34 +360,44 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jobserver"
|
name = "jobserver"
|
||||||
version = "0.1.32"
|
version = "0.1.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
|
checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"getrandom 0.3.4",
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.172"
|
version = "0.2.177"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libredox"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
version = "0.4.12"
|
version = "0.4.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
|
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
|
||||||
"scopeguard",
|
"scopeguard",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.22"
|
version = "0.4.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lru"
|
name = "lru"
|
||||||
@@ -255,10 +409,26 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "macro_rules_attribute"
|
||||||
version = "2.7.4"
|
version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
checksum = "65049d7923698040cd0b1ddcced9b0eb14dd22c5f86ae59c3740eab64a676520"
|
||||||
|
dependencies = [
|
||||||
|
"macro_rules_attribute-proc_macro",
|
||||||
|
"paste",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "macro_rules_attribute-proc_macro"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "670fdfda89751bc4a84ac13eaa63e205cf0fd22b4c9a5fbfa085b63c1f1d3a30"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.7.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "minimal-lexical"
|
name = "minimal-lexical"
|
||||||
@@ -299,15 +469,21 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.20.2"
|
version = "1.21.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "option-ext"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.12.3"
|
version = "0.12.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
|
checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lock_api",
|
"lock_api",
|
||||||
"parking_lot_core",
|
"parking_lot_core",
|
||||||
@@ -315,17 +491,23 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot_core"
|
name = "parking_lot_core"
|
||||||
version = "0.9.10"
|
version = "0.9.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
|
checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"windows-targets",
|
"windows-link",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "paste"
|
||||||
|
version = "1.0.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pcre2"
|
name = "pcre2"
|
||||||
version = "0.2.9"
|
version = "0.2.9"
|
||||||
@@ -391,7 +573,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
|
checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"phf_shared 0.11.3",
|
"phf_shared 0.11.3",
|
||||||
"rand",
|
"rand 0.8.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -424,41 +606,76 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pkg-config"
|
name = "pkg-config"
|
||||||
version = "0.3.31"
|
version = "0.3.32"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
|
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "portable-atomic"
|
name = "portable-atomic"
|
||||||
version = "1.10.0"
|
version = "1.11.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6"
|
checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
|
||||||
|
dependencies = [
|
||||||
|
"zerocopy",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.95"
|
version = "1.0.101"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
|
checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.40"
|
version = "1.0.41"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "r-efi"
|
||||||
|
version = "5.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.8.5"
|
version = "0.8.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand_core",
|
"rand_core 0.6.4",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.9.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
|
||||||
|
dependencies = [
|
||||||
|
"rand_chacha",
|
||||||
|
"rand_core 0.9.3",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core 0.9.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -468,14 +685,51 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "rand_core"
|
||||||
version = "0.5.8"
|
version = "0.9.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
|
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.3.4",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_syscall"
|
||||||
|
version = "0.5.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_users"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.2.16",
|
||||||
|
"libredox",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.4.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.8.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rsconf"
|
name = "rsconf"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
@@ -487,9 +741,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rust-embed"
|
name = "rust-embed"
|
||||||
version = "8.7.2"
|
version = "8.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "025908b8682a26ba8d12f6f2d66b987584a4a87bc024abc5bbc12553a8cd178a"
|
checksum = "947d7f3fad52b283d261c4c99a084937e2fe492248cb9a68a8435a861b8798ca"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rust-embed-impl",
|
"rust-embed-impl",
|
||||||
"rust-embed-utils",
|
"rust-embed-utils",
|
||||||
@@ -498,23 +752,25 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rust-embed-impl"
|
name = "rust-embed-impl"
|
||||||
version = "8.7.2"
|
version = "8.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6065f1a4392b71819ec1ea1df1120673418bf386f50de1d6f54204d836d4349c"
|
checksum = "5fa2c8c9e8711e10f9c4fd2d64317ef13feaab820a4c51541f1a8c8e2e851ab2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"rust-embed-utils",
|
"rust-embed-utils",
|
||||||
|
"shellexpand",
|
||||||
"syn",
|
"syn",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rust-embed-utils"
|
name = "rust-embed-utils"
|
||||||
version = "8.7.2"
|
version = "8.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f6cc0c81648b20b70c491ff8cce00c1c3b223bb8ed2b5d41f0e54c6c4c0a3594"
|
checksum = "60b161f275cb337fe0a44d924a5f4df0ed69c2c39519858f931ce61c779d3475"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"globset",
|
||||||
"sha2",
|
"sha2",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
]
|
]
|
||||||
@@ -530,9 +786,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scc"
|
name = "scc"
|
||||||
version = "2.3.0"
|
version = "2.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "28e1c91382686d21b5ac7959341fcb9780fa7c03773646995a87c950fa7be640"
|
checksum = "46e6f046b7fef48e2660c57ed794263155d713de679057f2d0c169bfc6e756cc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"sdd",
|
"sdd",
|
||||||
]
|
]
|
||||||
@@ -545,9 +801,38 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sdd"
|
name = "sdd"
|
||||||
version = "3.0.5"
|
version = "3.0.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "478f121bb72bbf63c52c93011ea1791dca40140dfe13f8336c4c5ac952c33aa9"
|
checksum = "490dcfcbfef26be6800d11870ff2df8774fa6e86d047e3e8c8a76b25655e41ca"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.228"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||||
|
dependencies = [
|
||||||
|
"serde_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_core"
|
||||||
|
version = "1.0.228"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.228"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serial_test"
|
name = "serial_test"
|
||||||
@@ -574,15 +859,24 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha2"
|
name = "sha2"
|
||||||
version = "0.10.8"
|
version = "0.10.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"cpufeatures",
|
"cpufeatures",
|
||||||
"digest",
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shellexpand"
|
||||||
|
version = "3.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8b1fdf65dd6331831494dd616b30351c38e96e45921a27745cf98490458b90bb"
|
||||||
|
dependencies = [
|
||||||
|
"dirs",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shlex"
|
name = "shlex"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
@@ -597,15 +891,15 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "smallvec"
|
||||||
version = "1.13.2"
|
version = "1.15.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.95"
|
version = "2.0.107"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "46f71c0377baf4ef1cc3e3402ded576dccc315800fbc62dfc7fe04b009773b4a"
|
checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -625,16 +919,36 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typenum"
|
name = "thiserror"
|
||||||
version = "1.17.0"
|
version = "2.0.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror-impl"
|
||||||
|
version = "2.0.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.14"
|
version = "1.0.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
|
checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-segmentation"
|
name = "unicode-segmentation"
|
||||||
@@ -644,9 +958,9 @@ checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-width"
|
name = "unicode-width"
|
||||||
version = "0.2.0"
|
version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
|
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unix_path"
|
name = "unix_path"
|
||||||
@@ -680,89 +994,78 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "widestring"
|
name = "wasi"
|
||||||
version = "1.2.0"
|
version = "0.11.1+wasi-snapshot-preview1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d"
|
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasip2"
|
||||||
|
version = "1.0.1+wasi-0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
|
||||||
|
dependencies = [
|
||||||
|
"wit-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "widestring"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi-util"
|
name = "winapi-util"
|
||||||
version = "0.1.9"
|
version = "0.1.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-link"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.59.0"
|
version = "0.61.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-targets",
|
"windows-link",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-targets"
|
name = "wit-bindgen"
|
||||||
version = "0.52.6"
|
version = "0.46.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xterm-color"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4de5f056fb9dc8b7908754867544e26145767187aaac5a98495e88ad7cb8a80f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy"
|
||||||
|
version = "0.8.27"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows_aarch64_gnullvm",
|
"zerocopy-derive",
|
||||||
"windows_aarch64_msvc",
|
|
||||||
"windows_i686_gnu",
|
|
||||||
"windows_i686_gnullvm",
|
|
||||||
"windows_i686_msvc",
|
|
||||||
"windows_x86_64_gnu",
|
|
||||||
"windows_x86_64_gnullvm",
|
|
||||||
"windows_x86_64_msvc",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_gnullvm"
|
name = "zerocopy-derive"
|
||||||
version = "0.52.6"
|
version = "0.8.27"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831"
|
||||||
|
dependencies = [
|
||||||
[[package]]
|
"proc-macro2",
|
||||||
name = "windows_aarch64_msvc"
|
"quote",
|
||||||
version = "0.52.6"
|
"syn",
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
]
|
||||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_gnu"
|
|
||||||
version = "0.52.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_gnullvm"
|
|
||||||
version = "0.52.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_msvc"
|
|
||||||
version = "0.52.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnu"
|
|
||||||
version = "0.52.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnullvm"
|
|
||||||
version = "0.52.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_msvc"
|
|
||||||
version = "0.52.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
|
||||||
|
|||||||
76
Cargo.toml
76
Cargo.toml
@@ -1,24 +1,33 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
resolver = "2"
|
|
||||||
members = ["crates/*"]
|
members = ["crates/*"]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
# To build revisions that use Corrosion (those before 2024-01), use CMake 3.19, Rustc 1.78 and Rustup 1.27.
|
# To build revisions that use Corrosion (those before 2024-01), use CMake 3.19, Rustc 1.78 and Rustup 1.27.
|
||||||
rust-version = "1.70"
|
rust-version = "1.85"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
repository = "https://github.com/fish-shell/fish-shell"
|
repository = "https://github.com/fish-shell/fish-shell"
|
||||||
|
# see doc_src/license.rst for details
|
||||||
|
# don't forget to update COPYING and debian/copyright too
|
||||||
|
license = "GPL-2.0-only AND LGPL-2.0-or-later AND MIT AND PSF-2.0"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
bitflags = "2.5.0"
|
bitflags = "2.5.0"
|
||||||
cc = "1.0.94"
|
cc = "1.0.94"
|
||||||
|
cfg-if = "1.0.3"
|
||||||
errno = "0.3.0"
|
errno = "0.3.0"
|
||||||
fish-build-helper = { path = "crates/build-helper" }
|
fish-build-helper = { path = "crates/build-helper" }
|
||||||
fish-build-man-pages = { path = "crates/build-man-pages" }
|
fish-build-man-pages = { path = "crates/build-man-pages" }
|
||||||
|
fish-common = { path = "crates/common" }
|
||||||
|
fish-fallback = { path = "crates/fallback" }
|
||||||
|
fish-gettext = { path = "crates/gettext" }
|
||||||
fish-gettext-extraction = { path = "crates/gettext-extraction" }
|
fish-gettext-extraction = { path = "crates/gettext-extraction" }
|
||||||
fish-gettext-maps = { path = "crates/gettext-maps" }
|
fish-gettext-maps = { path = "crates/gettext-maps" }
|
||||||
fish-gettext-mo-file-parser = { path = "crates/gettext-mo-file-parser" }
|
fish-gettext-mo-file-parser = { path = "crates/gettext-mo-file-parser" }
|
||||||
fish-printf = { path = "crates/printf", features = ["widestring"] }
|
fish-printf = { path = "crates/printf", features = ["widestring"] }
|
||||||
libc = "0.2.155"
|
fish-tempfile = { path = "crates/tempfile" }
|
||||||
|
fish-wchar = { path = "crates/wchar" }
|
||||||
|
fish-widecharwidth = { path = "crates/widecharwidth" }
|
||||||
|
libc = "0.2.177"
|
||||||
# lru pulls in hashbrown by default, which uses a faster (though less DoS resistant) hashing algo.
|
# lru pulls in hashbrown by default, which uses a faster (though less DoS resistant) hashing algo.
|
||||||
# disabling default features uses the stdlib instead, but it doubles the time to rewrite the history
|
# disabling default features uses the stdlib instead, but it doubles the time to rewrite the history
|
||||||
# files as of 22 April 2024.
|
# files as of 22 April 2024.
|
||||||
@@ -28,6 +37,7 @@ nix = { version = "0.30.1", default-features = false, features = [
|
|||||||
"inotify",
|
"inotify",
|
||||||
"resource",
|
"resource",
|
||||||
"fs",
|
"fs",
|
||||||
|
"term",
|
||||||
] }
|
] }
|
||||||
num-traits = "0.2.19"
|
num-traits = "0.2.19"
|
||||||
once_cell = "1.19.0"
|
once_cell = "1.19.0"
|
||||||
@@ -40,12 +50,16 @@ portable-atomic = { version = "1", default-features = false, features = [
|
|||||||
"fallback",
|
"fallback",
|
||||||
] }
|
] }
|
||||||
proc-macro2 = "1.0"
|
proc-macro2 = "1.0"
|
||||||
# Don't use the "getrandom" feature as it requires "getentropy" which was not
|
rand = { version = "0.9.2", default-features = false, features = [
|
||||||
# available on macOS < 10.12. We can enable "getrandom" when we raise the
|
"small_rng",
|
||||||
# minimum supported version to 10.12.
|
"thread_rng",
|
||||||
rand = { version = "0.8.5", default-features = false, features = ["small_rng"] }
|
] }
|
||||||
rsconf = "0.2.2"
|
rsconf = "0.2.2"
|
||||||
rust-embed = { version = "8.7.2", features = ["deterministic-timestamps"] }
|
rust-embed = { version = "8.9.0", features = [
|
||||||
|
"deterministic-timestamps",
|
||||||
|
"include-exclude",
|
||||||
|
"interpolate-folder-path",
|
||||||
|
] }
|
||||||
serial_test = { version = "3", default-features = false }
|
serial_test = { version = "3", default-features = false }
|
||||||
# We need 0.9.0 specifically for some crash fixes.
|
# We need 0.9.0 specifically for some crash fixes.
|
||||||
terminfo = "0.9.0"
|
terminfo = "0.9.0"
|
||||||
@@ -53,6 +67,7 @@ widestring = "1.2.0"
|
|||||||
unicode-segmentation = "1.12.0"
|
unicode-segmentation = "1.12.0"
|
||||||
unicode-width = "0.2.0"
|
unicode-width = "0.2.0"
|
||||||
unix_path = "1.0.1"
|
unix_path = "1.0.1"
|
||||||
|
xterm-color = "1.0.1"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
overflow-checks = true
|
overflow-checks = true
|
||||||
@@ -64,42 +79,56 @@ debug = true
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "fish"
|
name = "fish"
|
||||||
version = "4.1.0"
|
version = "4.3.2"
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
rust-version.workspace = true
|
rust-version.workspace = true
|
||||||
default-run = "fish"
|
default-run = "fish"
|
||||||
# see doc_src/license.rst for details
|
license.workspace = true
|
||||||
# don't forget to update COPYING and debian/copyright too
|
|
||||||
license = "GPL-2.0-only AND LGPL-2.0-or-later AND MIT AND PSF-2.0"
|
|
||||||
homepage = "https://fishshell.com"
|
homepage = "https://fishshell.com"
|
||||||
readme = "README.rst"
|
readme = "README.rst"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bitflags.workspace = true
|
bitflags.workspace = true
|
||||||
|
cfg-if.workspace = true
|
||||||
errno.workspace = true
|
errno.workspace = true
|
||||||
fish-build-helper.workspace = true
|
fish-build-helper.workspace = true
|
||||||
fish-build-man-pages = { workspace = true, optional = true }
|
fish-build-man-pages = { workspace = true, optional = true }
|
||||||
|
fish-common.workspace = true
|
||||||
|
fish-fallback.workspace = true
|
||||||
|
fish-gettext = { workspace = true, optional = true }
|
||||||
fish-gettext-extraction = { workspace = true, optional = true }
|
fish-gettext-extraction = { workspace = true, optional = true }
|
||||||
fish-gettext-maps = { workspace = true, optional = true }
|
|
||||||
fish-printf.workspace = true
|
fish-printf.workspace = true
|
||||||
|
fish-tempfile.workspace = true
|
||||||
|
fish-wchar.workspace = true
|
||||||
|
fish-widecharwidth.workspace = true
|
||||||
libc.workspace = true
|
libc.workspace = true
|
||||||
lru.workspace = true
|
lru.workspace = true
|
||||||
|
macro_rules_attribute = "0.2.2"
|
||||||
nix.workspace = true
|
nix.workspace = true
|
||||||
num-traits.workspace = true
|
num-traits.workspace = true
|
||||||
once_cell.workspace = true
|
once_cell.workspace = true
|
||||||
pcre2.workspace = true
|
pcre2.workspace = true
|
||||||
phf = { workspace = true, optional = true }
|
|
||||||
rand.workspace = true
|
rand.workspace = true
|
||||||
terminfo.workspace = true
|
terminfo.workspace = true
|
||||||
|
xterm-color.workspace = true
|
||||||
widestring.workspace = true
|
widestring.workspace = true
|
||||||
|
|
||||||
[target.'cfg(not(target_has_atomic = "64"))'.dependencies]
|
[target.'cfg(not(target_has_atomic = "64"))'.dependencies]
|
||||||
portable-atomic.workspace = true
|
portable-atomic.workspace = true
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
rust-embed = { workspace = true, optional = true, features = ["deterministic-timestamps", "debug-embed"] }
|
rust-embed = { workspace = true, features = [
|
||||||
|
"deterministic-timestamps",
|
||||||
|
"debug-embed",
|
||||||
|
"include-exclude",
|
||||||
|
"interpolate-folder-path",
|
||||||
|
] }
|
||||||
[target.'cfg(not(windows))'.dependencies]
|
[target.'cfg(not(windows))'.dependencies]
|
||||||
rust-embed = { workspace = true, optional = true, features = ["deterministic-timestamps"] }
|
rust-embed = { workspace = true, features = [
|
||||||
|
"deterministic-timestamps",
|
||||||
|
"include-exclude",
|
||||||
|
"interpolate-folder-path",
|
||||||
|
] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serial_test.workspace = true
|
serial_test.workspace = true
|
||||||
@@ -131,12 +160,12 @@ name = "fish_key_reader"
|
|||||||
path = "src/bin/fish_key_reader.rs"
|
path = "src/bin/fish_key_reader.rs"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["embed-data", "localize-messages"]
|
default = ["embed-manpages", "localize-messages"]
|
||||||
benchmark = []
|
benchmark = []
|
||||||
embed-data = ["dep:rust-embed", "dep:fish-build-man-pages"]
|
embed-manpages = ["dep:fish-build-man-pages"]
|
||||||
# Enable gettext localization at runtime. Requires the `msgfmt` tool to generate catalog data at
|
# Enable gettext localization at runtime. Requires the `msgfmt` tool to generate catalog data at
|
||||||
# build time.
|
# build time.
|
||||||
localize-messages = ["dep:phf", "dep:fish-gettext-maps"]
|
localize-messages = ["dep:fish-gettext"]
|
||||||
# This feature is used to enable extracting messages from the source code for localization.
|
# This feature is used to enable extracting messages from the source code for localization.
|
||||||
# It only needs to be enabled if updating these messages (and the corresponding PO files) is
|
# It only needs to be enabled if updating these messages (and the corresponding PO files) is
|
||||||
# desired. This happens when running tests via `build_tools/check.sh` and when calling
|
# desired. This happens when running tests via `build_tools/check.sh` and when calling
|
||||||
@@ -152,9 +181,14 @@ rust.non_camel_case_types = "allow"
|
|||||||
rust.non_upper_case_globals = "allow"
|
rust.non_upper_case_globals = "allow"
|
||||||
rust.unknown_lints = "allow"
|
rust.unknown_lints = "allow"
|
||||||
rust.unstable_name_collisions = "allow"
|
rust.unstable_name_collisions = "allow"
|
||||||
|
rustdoc.private_intra_doc_links = "allow"
|
||||||
|
clippy.len_without_is_empty = "allow" # we're not a library crate
|
||||||
|
clippy.let_and_return = "allow"
|
||||||
clippy.manual_range_contains = "allow"
|
clippy.manual_range_contains = "allow"
|
||||||
clippy.needless_return = "allow"
|
clippy.map_unwrap_or = "warn"
|
||||||
clippy.needless_lifetimes = "allow"
|
clippy.needless_lifetimes = "allow"
|
||||||
|
clippy.new_without_default = "allow"
|
||||||
|
clippy.option_map_unit_fn = "allow"
|
||||||
|
|
||||||
# We do not want to use the e?print(ln)?! macros.
|
# We do not want to use the e?print(ln)?! macros.
|
||||||
# These lints flag their use.
|
# These lints flag their use.
|
||||||
|
|||||||
66
README.rst
66
README.rst
@@ -37,7 +37,7 @@ fish can be installed:
|
|||||||
- using the `installer from fishshell.com <https://fishshell.com/>`__
|
- using the `installer from fishshell.com <https://fishshell.com/>`__
|
||||||
- as a `standalone app from fishshell.com <https://fishshell.com/>`__
|
- as a `standalone app from fishshell.com <https://fishshell.com/>`__
|
||||||
|
|
||||||
Note: The minimum supported macOS version is 10.10 "Yosemite".
|
Note: The minimum supported macOS version is 10.12.
|
||||||
|
|
||||||
Packages for Linux
|
Packages for Linux
|
||||||
~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~
|
||||||
@@ -90,7 +90,7 @@ Running fish requires:
|
|||||||
|
|
||||||
- some common \*nix system utilities (currently ``mktemp``), in
|
- some common \*nix system utilities (currently ``mktemp``), in
|
||||||
addition to the basic POSIX utilities (``cat``, ``cut``, ``dirname``,
|
addition to the basic POSIX utilities (``cat``, ``cut``, ``dirname``,
|
||||||
``file``, ``ls``, ``mkdir``, ``mkfifo``, ``rm``, ``sh``, ``sort``, ``tee``, ``tr``,
|
``ls``, ``mkdir``, ``mkfifo``, ``rm``, ``sh``, ``sort``, ``tee``, ``tr``,
|
||||||
``uname`` and ``sed`` at least, but the full coreutils plus ``find`` and
|
``uname`` and ``sed`` at least, but the full coreutils plus ``find`` and
|
||||||
``awk`` is preferred)
|
``awk`` is preferred)
|
||||||
|
|
||||||
@@ -100,6 +100,7 @@ The following optional features also have specific requirements:
|
|||||||
messages require ``man`` for display
|
messages require ``man`` for display
|
||||||
- automated completion generation from manual pages requires Python 3.5+
|
- automated completion generation from manual pages requires Python 3.5+
|
||||||
- the ``fish_config`` web configuration tool requires Python 3.5+ and a web browser
|
- the ``fish_config`` web configuration tool requires Python 3.5+ and a web browser
|
||||||
|
- the :ref:`alt-o <shared-binds-alt-o>` binding requires the ``file`` program.
|
||||||
- system clipboard integration (with the default Ctrl-V and Ctrl-X
|
- system clipboard integration (with the default Ctrl-V and Ctrl-X
|
||||||
bindings) require either the ``xsel``, ``xclip``,
|
bindings) require either the ``xsel``, ``xclip``,
|
||||||
``wl-copy``/``wl-paste`` or ``pbcopy``/``pbpaste`` utilities
|
``wl-copy``/``wl-paste`` or ``pbcopy``/``pbpaste`` utilities
|
||||||
@@ -111,14 +112,12 @@ The following optional features also have specific requirements:
|
|||||||
Building
|
Building
|
||||||
--------
|
--------
|
||||||
|
|
||||||
.. _dependencies-1:
|
|
||||||
|
|
||||||
Dependencies
|
Dependencies
|
||||||
~~~~~~~~~~~~
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
Compiling fish requires:
|
Compiling fish requires:
|
||||||
|
|
||||||
- Rust (version 1.70 or later)
|
- Rust (version 1.85 or later)
|
||||||
- CMake (version 3.15 or later)
|
- CMake (version 3.15 or later)
|
||||||
- a C compiler (for system feature detection and the test helper binary)
|
- a C compiler (for system feature detection and the test helper binary)
|
||||||
- PCRE2 (headers and libraries) - optional, this will be downloaded if missing
|
- PCRE2 (headers and libraries) - optional, this will be downloaded if missing
|
||||||
@@ -128,7 +127,7 @@ Compiling fish requires:
|
|||||||
Sphinx is also optionally required to build the documentation from a
|
Sphinx is also optionally required to build the documentation from a
|
||||||
cloned git repository.
|
cloned git repository.
|
||||||
|
|
||||||
Additionally, running the full test suite requires Python 3.5+, tmux, and the pexpect package.
|
Additionally, running the full test suite requires diff, git, Python 3.5+, pexpect, less, tmux and wget.
|
||||||
|
|
||||||
Building from source with CMake
|
Building from source with CMake
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
@@ -140,7 +139,7 @@ links above, and up-to-date `development builds of fish are available for many p
|
|||||||
|
|
||||||
To install into ``/usr/local``, run:
|
To install into ``/usr/local``, run:
|
||||||
|
|
||||||
.. code:: bash
|
.. code:: shell
|
||||||
|
|
||||||
mkdir build; cd build
|
mkdir build; cd build
|
||||||
cmake ..
|
cmake ..
|
||||||
@@ -158,41 +157,52 @@ In addition to the normal CMake build options (like ``CMAKE_INSTALL_PREFIX``), f
|
|||||||
- Rust_COMPILER=path - the path to rustc. If not set, cmake will check $PATH and ~/.cargo/bin
|
- Rust_COMPILER=path - the path to rustc. If not set, cmake will check $PATH and ~/.cargo/bin
|
||||||
- Rust_CARGO=path - the path to cargo. If not set, cmake will check $PATH and ~/.cargo/bin
|
- Rust_CARGO=path - the path to cargo. If not set, cmake will check $PATH and ~/.cargo/bin
|
||||||
- Rust_CARGO_TARGET=target - the target to pass to cargo. Set this for cross-compilation.
|
- Rust_CARGO_TARGET=target - the target to pass to cargo. Set this for cross-compilation.
|
||||||
- BUILD_DOCS=ON|OFF - whether to build the documentation. This is automatically set to OFF when Sphinx isn't installed.
|
- WITH_DOCS=ON|OFF - whether to build the documentation. By default, this is ON when Sphinx is installed.
|
||||||
- INSTALL_DOCS=ON|OFF - whether to install the docs. This is automatically set to on when BUILD_DOCS is or prebuilt documentation is available (like when building in-tree from a tarball).
|
- FISH_INDENT_FOR_BUILDING_DOCS - useful for cross-compilation.
|
||||||
|
Set this to the path to the ``fish_indent`` executable to use for building HTML docs.
|
||||||
|
By default, ``${CMAKE_BINARY_DIR}/fish_indent`` will be used.
|
||||||
|
If that's not runnable on the compile host,
|
||||||
|
you can build a native one with ``cargo build --bin fish_indent`` and set this to ``$PWD/target/debug/fish_indent``.
|
||||||
- FISH_USE_SYSTEM_PCRE2=ON|OFF - whether to use an installed pcre2. This is normally autodetected.
|
- FISH_USE_SYSTEM_PCRE2=ON|OFF - whether to use an installed pcre2. This is normally autodetected.
|
||||||
- MAC_CODESIGN_ID=String|OFF - the codesign ID to use on Mac, or "OFF" to disable codesigning.
|
|
||||||
- WITH_GETTEXT=ON|OFF - whether to include translations.
|
- WITH_GETTEXT=ON|OFF - whether to include translations.
|
||||||
- extra_functionsdir, extra_completionsdir and extra_confdir - to compile in an additional directory to be searched for functions, completions and configuration snippets
|
- extra_functionsdir, extra_completionsdir and extra_confdir - to compile in an additional directory to be searched for functions, completions and configuration snippets
|
||||||
|
|
||||||
Building fish with embedded data (experimental)
|
Building fish with Cargo
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
You can also build fish with the data files embedded.
|
You can also build fish with Cargo.
|
||||||
|
This example uses `uv <https://github.com/astral-sh/uv>`__ to install Sphinx (which is used for man-pages and ``--help`` options).
|
||||||
|
You can also install Sphinx another way and drop the ``uv run --no-managed-python`` prefix.
|
||||||
|
|
||||||
This will include all the datafiles like the included functions or web configuration tool in the main ``fish`` binary.
|
.. code:: shell
|
||||||
|
|
||||||
Fish will then read these right from its own binary, and print them out when needed. Some files, like the webconfig tool and the manpage completion generator, will be extracted to a temporary directory on-demand. You can list the files with ``status list-files`` and print one with ``status get-file path/to/file`` (e.g. ``status get-file functions/fish_prompt.fish`` to get the default prompt).
|
git clone https://github.com/fish-shell/fish-shell
|
||||||
|
cd fish-shell
|
||||||
|
|
||||||
To install fish with embedded files, just use ``cargo``, like::
|
# Optional: check out a specific version rather than building the latest
|
||||||
|
# development version.
|
||||||
|
git checkout "$(git for-each-ref refs/tags/ | awk '$2 == "tag" { print $3 }' | tail -1)"
|
||||||
|
|
||||||
cargo install --path /path/to/fish # if you have a git clone
|
uv run --no-managed-python \
|
||||||
cargo install --git https://github.com/fish-shell/fish-shell --tag "$(curl -s https://api.github.com/repos/fish-shell/fish-shell/releases/latest | jq -r .tag_name)" # to build the latest release
|
cargo install --path .
|
||||||
cargo install --git https://github.com/fish-shell/fish-shell # to build the latest development snapshot
|
|
||||||
|
|
||||||
This will place the binaries in ``~/.cargo/bin/``, but you can place them wherever you want.
|
This will place standalone binaries in ``~/.cargo/bin/``, but you can move them wherever you want.
|
||||||
|
|
||||||
This build won't have the HTML docs (``help`` will open the online version).
|
To disable translations, disable the ``localize-messages`` feature by passing ``--no-default-features --features=embed-manpages`` to cargo.
|
||||||
It will try to build the man pages with sphinx-build. If that is not available and you would like to include man pages, you need to install it and retrigger the build script, e.g. by setting FISH_BUILD_DOCS=1::
|
|
||||||
|
|
||||||
FISH_BUILD_DOCS=1 cargo install --path .
|
|
||||||
|
|
||||||
Setting it to "0" disables the inclusion of man pages.
|
|
||||||
|
|
||||||
To disable translations, disable the ``localize-messages`` feature by passing ``--no-default-features --features=embed-data`` to cargo.
|
|
||||||
|
|
||||||
You can also link this build statically (but not against glibc) and move it to other computers.
|
You can also link this build statically (but not against glibc) and move it to other computers.
|
||||||
|
|
||||||
|
Here are the remaining advantages of a full installation, as currently done by CMake:
|
||||||
|
|
||||||
|
- Man pages like ``fish(1)`` installed in standard locations, easily accessible from outside fish.
|
||||||
|
- Separate files for builtins (e.g. ``$PREFIX/share/fish/man/man1/abbr.1``).
|
||||||
|
- A local copy of the HTML documentation, typically accessed via the ``help`` fish function.
|
||||||
|
In Cargo builds, ``help`` will redirect to `<https://fishshell.com/docs/current/>`__
|
||||||
|
- Ability to use our CMake options extra_functionsdir, extra_completionsdir and extra_confdir,
|
||||||
|
(also recorded in ``$PREFIX/share/pkgconfig/fish.pc``)
|
||||||
|
which are used by some package managers to house third-party completions.
|
||||||
|
Regardless of build system, fish uses ``$XDG_DATA_DIRS/{vendor_completion.d,vendor_conf.d,vendor_functions.d}``.
|
||||||
|
|
||||||
Contributing Changes to the Code
|
Contributing Changes to the Code
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
|
|||||||
239
build.rs
239
build.rs
@@ -1,9 +1,9 @@
|
|||||||
#![allow(clippy::uninlined_format_args)]
|
use fish_build_helper::{
|
||||||
|
env_var, fish_build_dir, target_os, target_os_is_apple, target_os_is_bsd, target_os_is_cygwin,
|
||||||
use fish_build_helper::{fish_build_dir, workspace_root};
|
workspace_root,
|
||||||
|
};
|
||||||
use rsconf::Target;
|
use rsconf::Target;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::error::Error;
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
fn canonicalize<P: AsRef<Path>>(path: P) -> PathBuf {
|
fn canonicalize<P: AsRef<Path>>(path: P) -> PathBuf {
|
||||||
@@ -17,7 +17,7 @@ fn main() {
|
|||||||
// language server.
|
// language server.
|
||||||
|
|
||||||
rsconf::set_env_value(
|
rsconf::set_env_value(
|
||||||
"FISH_BUILD_DIR",
|
"FISH_RESOLVED_BUILD_DIR",
|
||||||
// If set by CMake, this might include symlinks. Since we want to compare this to the
|
// If set by CMake, this might include symlinks. Since we want to compare this to the
|
||||||
// dir fish is executed in we need to canonicalize it.
|
// dir fish is executed in we need to canonicalize it.
|
||||||
canonicalize(fish_build_dir()).to_str().unwrap(),
|
canonicalize(fish_build_dir()).to_str().unwrap(),
|
||||||
@@ -31,28 +31,16 @@ fn main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Some build info
|
// Some build info
|
||||||
rsconf::set_env_value("BUILD_TARGET_TRIPLE", &env::var("TARGET").unwrap());
|
rsconf::set_env_value("BUILD_TARGET_TRIPLE", &env_var("TARGET").unwrap());
|
||||||
rsconf::set_env_value("BUILD_HOST_TRIPLE", &env::var("HOST").unwrap());
|
rsconf::set_env_value("BUILD_HOST_TRIPLE", &env_var("HOST").unwrap());
|
||||||
rsconf::set_env_value("BUILD_PROFILE", &env::var("PROFILE").unwrap());
|
rsconf::set_env_value("BUILD_PROFILE", &env_var("PROFILE").unwrap());
|
||||||
|
|
||||||
let version = &get_version(&env::current_dir().unwrap());
|
let version = &get_version(&env::current_dir().unwrap());
|
||||||
// Per https://doc.rust-lang.org/cargo/reference/build-scripts.html#inputs-to-the-build-script,
|
// Per https://doc.rust-lang.org/cargo/reference/build-scripts.html#inputs-to-the-build-script,
|
||||||
// the source directory is the current working directory of the build script
|
// the source directory is the current working directory of the build script
|
||||||
rsconf::set_env_value("FISH_BUILD_VERSION", version);
|
rsconf::set_env_value("FISH_BUILD_VERSION", version);
|
||||||
|
|
||||||
std::env::set_var("FISH_BUILD_VERSION", version);
|
fish_build_helper::rebuild_if_embedded_path_changed("share");
|
||||||
|
|
||||||
// These are necessary if built with embedded functions,
|
|
||||||
// but only in release builds (because rust-embed in debug builds reads from the filesystem).
|
|
||||||
#[cfg(feature = "embed-data")]
|
|
||||||
#[cfg(any(windows, not(debug_assertions)))]
|
|
||||||
rsconf::rebuild_if_path_changed("share");
|
|
||||||
|
|
||||||
#[cfg(feature = "gettext-extract")]
|
|
||||||
rsconf::rebuild_if_env_changed("FISH_GETTEXT_EXTRACTION_FILE");
|
|
||||||
|
|
||||||
rsconf::rebuild_if_path_changed("src/libc.c");
|
|
||||||
cc::Build::new().file("src/libc.c").compile("flibc.a");
|
|
||||||
|
|
||||||
let build = cc::Build::new();
|
let build = cc::Build::new();
|
||||||
let mut target = Target::new_from(build).unwrap();
|
let mut target = Target::new_from(build).unwrap();
|
||||||
@@ -61,7 +49,9 @@ fn main() {
|
|||||||
detect_cfgs(&mut target);
|
detect_cfgs(&mut target);
|
||||||
|
|
||||||
#[cfg(all(target_env = "gnu", target_feature = "crt-static"))]
|
#[cfg(all(target_env = "gnu", target_feature = "crt-static"))]
|
||||||
compile_error!("Statically linking against glibc has unavoidable crashes and is unsupported. Use dynamic linking or link statically against musl.");
|
compile_error!(
|
||||||
|
"Statically linking against glibc has unavoidable crashes and is unsupported. Use dynamic linking or link statically against musl."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check target system support for certain functionality dynamically when the build is invoked,
|
/// Check target system support for certain functionality dynamically when the build is invoked,
|
||||||
@@ -76,115 +66,76 @@ fn main() {
|
|||||||
/// `Cargo.toml`) behind a feature we just enabled.
|
/// `Cargo.toml`) behind a feature we just enabled.
|
||||||
///
|
///
|
||||||
/// [0]: https://github.com/rust-lang/cargo/issues/5499
|
/// [0]: https://github.com/rust-lang/cargo/issues/5499
|
||||||
#[rustfmt::skip]
|
|
||||||
fn detect_cfgs(target: &mut Target) {
|
fn detect_cfgs(target: &mut Target) {
|
||||||
for (name, handler) in [
|
for (name, handler) in [
|
||||||
// Ignore the first entry, it just sets up the type inference. Model new entries after the
|
// Ignore the first entry, it just sets up the type inference.
|
||||||
// second line.
|
("", &(|_: &Target| false) as &dyn Fn(&Target) -> bool),
|
||||||
(
|
("apple", &(|_| target_os_is_apple())),
|
||||||
"",
|
("bsd", &(|_| target_os_is_bsd())),
|
||||||
&(|_: &Target| Ok(false)) as &dyn Fn(&Target) -> Result<bool, Box<dyn Error>>,
|
("cygwin", &(|_| target_os_is_cygwin())),
|
||||||
),
|
("have_eventfd", &|target| {
|
||||||
("apple", &detect_apple),
|
|
||||||
("bsd", &detect_bsd),
|
|
||||||
("cygwin", &detect_cygwin),
|
|
||||||
("small_main_stack", &has_small_stack),
|
|
||||||
// See if libc supports the thread-safe localeconv_l(3) alternative to localeconv(3).
|
|
||||||
("localeconv_l", &|target| {
|
|
||||||
Ok(target.has_symbol("localeconv_l"))
|
|
||||||
}),
|
|
||||||
("FISH_USE_POSIX_SPAWN", &|target| {
|
|
||||||
Ok(target.has_header("spawn.h"))
|
|
||||||
}),
|
|
||||||
("HAVE_PIPE2", &|target| {
|
|
||||||
Ok(target.has_symbol("pipe2"))
|
|
||||||
}),
|
|
||||||
("HAVE_EVENTFD", &|target| {
|
|
||||||
// FIXME: NetBSD 10 has eventfd, but the libc crate does not expose it.
|
// FIXME: NetBSD 10 has eventfd, but the libc crate does not expose it.
|
||||||
if cfg!(target_os = "netbsd") {
|
if target_os() == "netbsd" {
|
||||||
Ok(false)
|
false
|
||||||
} else {
|
} else {
|
||||||
Ok(target.has_header("sys/eventfd.h"))
|
target.has_header("sys/eventfd.h")
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
("HAVE_WAITSTATUS_SIGNAL_RET", &|target| {
|
("have_localeconv_l", &|target| {
|
||||||
Ok(target.r#if("WEXITSTATUS(0x007f) == 0x7f", &["sys/wait.h"]))
|
target.has_symbol("localeconv_l")
|
||||||
|
}),
|
||||||
|
("have_pipe2", &|target| target.has_symbol("pipe2")),
|
||||||
|
("have_posix_spawn", &|target| {
|
||||||
|
if matches!(target_os().as_str(), "openbsd" | "android") {
|
||||||
|
// OpenBSD's posix_spawn returns status 127 instead of erroring with ENOEXEC when faced with a
|
||||||
|
// shebang-less script. Disable posix_spawn on OpenBSD.
|
||||||
|
//
|
||||||
|
// Android is broken for unclear reasons
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
target.has_header("spawn.h")
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
("small_main_stack", &has_small_stack),
|
||||||
|
("using_cmake", &|_| {
|
||||||
|
option_env!("FISH_CMAKE_BINARY_DIR").is_some()
|
||||||
|
}),
|
||||||
|
("waitstatus_signal_ret", &|target| {
|
||||||
|
target.r#if("WEXITSTATUS(0x007f) == 0x7f", &["sys/wait.h"])
|
||||||
}),
|
}),
|
||||||
] {
|
] {
|
||||||
match handler(target) {
|
rsconf::declare_cfg(name, handler(target))
|
||||||
Err(e) => {
|
|
||||||
rsconf::warn!("{}: {}", name, e);
|
|
||||||
rsconf::declare_cfg(name, false);
|
|
||||||
},
|
|
||||||
Ok(enabled) => rsconf::declare_cfg(name, enabled),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn detect_apple(_: &Target) -> Result<bool, Box<dyn Error>> {
|
|
||||||
Ok(cfg!(any(target_os = "ios", target_os = "macos")))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn detect_cygwin(_: &Target) -> Result<bool, Box<dyn Error>> {
|
|
||||||
// Cygwin target is usually cross-compiled.
|
|
||||||
Ok(std::env::var("CARGO_CFG_TARGET_OS").unwrap() == "cygwin")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Detect if we're being compiled for a BSD-derived OS, allowing targeting code conditionally with
|
|
||||||
/// `#[cfg(bsd)]`.
|
|
||||||
///
|
|
||||||
/// Rust offers fine-grained conditional compilation per-os for the popular operating systems, but
|
|
||||||
/// doesn't necessarily include less-popular forks nor does it group them into families more
|
|
||||||
/// specific than "windows" vs "unix" so we can conditionally compile code for BSD systems.
|
|
||||||
fn detect_bsd(_: &Target) -> Result<bool, Box<dyn Error>> {
|
|
||||||
// Instead of using `uname`, we can inspect the TARGET env variable set by Cargo. This lets us
|
|
||||||
// support cross-compilation scenarios.
|
|
||||||
let mut target = std::env::var("TARGET").unwrap();
|
|
||||||
if !target.chars().all(|c| c.is_ascii_lowercase()) {
|
|
||||||
target = target.to_ascii_lowercase();
|
|
||||||
}
|
|
||||||
let is_bsd = target.ends_with("bsd") || target.ends_with("dragonfly");
|
|
||||||
#[cfg(any(
|
|
||||||
target_os = "dragonfly",
|
|
||||||
target_os = "freebsd",
|
|
||||||
target_os = "netbsd",
|
|
||||||
target_os = "openbsd",
|
|
||||||
))]
|
|
||||||
assert!(is_bsd, "Target incorrectly detected as not BSD!");
|
|
||||||
Ok(is_bsd)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Rust sets the stack size of newly created threads to a sane value, but is at at the mercy of the
|
/// Rust sets the stack size of newly created threads to a sane value, but is at at the mercy of the
|
||||||
/// OS when it comes to the size of the main stack. Some platforms we support default to a tiny
|
/// OS when it comes to the size of the main stack. Some platforms we support default to a tiny
|
||||||
/// 0.5 MiB main stack, which is insufficient for fish's MAX_EVAL_DEPTH/MAX_STACK_DEPTH values.
|
/// 0.5 MiB main stack, which is insufficient for fish's MAX_EVAL_DEPTH/MAX_STACK_DEPTH values.
|
||||||
///
|
///
|
||||||
/// 0.5 MiB is small enough that we'd have to drastically reduce MAX_STACK_DEPTH to less than 10, so
|
/// 0.5 MiB is small enough that we'd have to drastically reduce MAX_STACK_DEPTH to less than 10, so
|
||||||
/// we instead use a workaround to increase the main thread size.
|
/// we instead use a workaround to increase the main thread size.
|
||||||
fn has_small_stack(_: &Target) -> Result<bool, Box<dyn Error>> {
|
fn has_small_stack(_: &Target) -> bool {
|
||||||
#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "netbsd")))]
|
#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "netbsd")))]
|
||||||
return Ok(false);
|
return false;
|
||||||
|
|
||||||
// NetBSD 10 also needs this but can't find pthread_get_stacksize_np.
|
// NetBSD 10 also needs this but can't find pthread_get_stacksize_np.
|
||||||
#[cfg(target_os = "netbsd")]
|
#[cfg(target_os = "netbsd")]
|
||||||
return Ok(true);
|
return true;
|
||||||
|
|
||||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||||
{
|
{
|
||||||
use core::ffi;
|
use core::ffi;
|
||||||
|
|
||||||
extern "C" {
|
unsafe extern "C" {
|
||||||
fn pthread_get_stacksize_np(thread: *const ffi::c_void) -> usize;
|
unsafe fn pthread_get_stacksize_np(thread: *const ffi::c_void) -> usize;
|
||||||
fn pthread_self() -> *const ffi::c_void;
|
unsafe fn pthread_self() -> *const ffi::c_void;
|
||||||
}
|
}
|
||||||
|
|
||||||
// build.rs is executed on the main thread, so we are getting the main thread's stack size.
|
// build.rs is executed on the main thread, so we are getting the main thread's stack size.
|
||||||
// Modern macOS versions default to an 8 MiB main stack but legacy OS X have a 0.5 MiB one.
|
// Modern macOS versions default to an 8 MiB main stack but legacy OS X have a 0.5 MiB one.
|
||||||
let stack_size = unsafe { pthread_get_stacksize_np(pthread_self()) };
|
let stack_size = unsafe { pthread_get_stacksize_np(pthread_self()) };
|
||||||
const TWO_MIB: usize = 2 * 1024 * 1024 - 1;
|
const TWO_MIB: usize = 2 * 1024 * 1024 - 1;
|
||||||
match stack_size {
|
stack_size <= TWO_MIB
|
||||||
0..=TWO_MIB => Ok(true),
|
|
||||||
_ => Ok(false),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,59 +143,63 @@ fn setup_paths() {
|
|||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use unix_path::{Path, PathBuf};
|
use unix_path::{Path, PathBuf};
|
||||||
|
|
||||||
fn get_path(name: &str, default: &str, onvar: &Path) -> PathBuf {
|
fn overridable_path(
|
||||||
let mut var = PathBuf::from(env::var(name).unwrap_or(default.to_string()));
|
env_var_name: &str,
|
||||||
if var.is_relative() {
|
f: impl FnOnce(Option<String>) -> Option<PathBuf>,
|
||||||
var = onvar.join(var);
|
) -> Option<PathBuf> {
|
||||||
|
rsconf::rebuild_if_env_changed(env_var_name);
|
||||||
|
let maybe_path = f(env_var(env_var_name));
|
||||||
|
if let Some(path) = maybe_path.as_ref() {
|
||||||
|
rsconf::set_env_value(env_var_name, path.to_str().unwrap());
|
||||||
}
|
}
|
||||||
var
|
maybe_path
|
||||||
}
|
}
|
||||||
|
|
||||||
let prefix = PathBuf::from(env::var("PREFIX").unwrap_or("/usr/local".to_string()));
|
fn join_if_relative(parent_if_relative: &Path, path: String) -> PathBuf {
|
||||||
rsconf::rebuild_if_env_changed("PREFIX");
|
let path = PathBuf::from(path);
|
||||||
rsconf::set_env_value("PREFIX", prefix.to_str().unwrap());
|
if path.is_relative() {
|
||||||
|
parent_if_relative.join(path)
|
||||||
let datadir = get_path("DATADIR", "share/", &prefix);
|
|
||||||
|
|
||||||
let sysconfdir = get_path(
|
|
||||||
"SYSCONFDIR",
|
|
||||||
// Embedded builds use "/etc," not "./share/etc".
|
|
||||||
if cfg!(feature = "embed-data") {
|
|
||||||
"/etc/"
|
|
||||||
} else {
|
} else {
|
||||||
"etc/"
|
path
|
||||||
},
|
}
|
||||||
&datadir,
|
|
||||||
);
|
|
||||||
rsconf::set_env_value("SYSCONFDIR", sysconfdir.to_str().unwrap());
|
|
||||||
rsconf::rebuild_if_env_changed("SYSCONFDIR");
|
|
||||||
|
|
||||||
#[cfg(not(feature = "embed-data"))]
|
|
||||||
{
|
|
||||||
rsconf::set_env_value("DATADIR", datadir.to_str().unwrap());
|
|
||||||
rsconf::rebuild_if_env_changed("DATADIR");
|
|
||||||
|
|
||||||
let bindir = get_path("BINDIR", "bin/", &prefix);
|
|
||||||
rsconf::set_env_value("BINDIR", bindir.to_str().unwrap());
|
|
||||||
rsconf::rebuild_if_env_changed("BINDIR");
|
|
||||||
|
|
||||||
let localedir = get_path("LOCALEDIR", "locale/", &datadir);
|
|
||||||
let localedir = localedir.to_str().unwrap();
|
|
||||||
assert!(!localedir.is_empty(), "empty LOCALEDIR is not supported");
|
|
||||||
rsconf::set_env_value("LOCALEDIR", localedir);
|
|
||||||
rsconf::rebuild_if_env_changed("LOCALEDIR");
|
|
||||||
|
|
||||||
let docdir = get_path("DOCDIR", "doc/fish", &datadir);
|
|
||||||
rsconf::set_env_value("DOCDIR", docdir.to_str().unwrap());
|
|
||||||
rsconf::rebuild_if_env_changed("DOCDIR");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let prefix = overridable_path("PREFIX", |env_prefix| {
|
||||||
|
Some(PathBuf::from(
|
||||||
|
env_prefix.unwrap_or("/usr/local".to_string()),
|
||||||
|
))
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
overridable_path("SYSCONFDIR", |env_sysconfdir| {
|
||||||
|
Some(join_if_relative(
|
||||||
|
&prefix,
|
||||||
|
env_sysconfdir.unwrap_or("/etc/".to_string()),
|
||||||
|
))
|
||||||
|
});
|
||||||
|
|
||||||
|
let datadir = overridable_path("DATADIR", |env_datadir| {
|
||||||
|
env_datadir.map(|p| join_if_relative(&prefix, p))
|
||||||
|
});
|
||||||
|
overridable_path("BINDIR", |env_bindir| {
|
||||||
|
env_bindir.map(|p| join_if_relative(&prefix, p))
|
||||||
|
});
|
||||||
|
overridable_path("DOCDIR", |env_docdir| {
|
||||||
|
env_docdir.map(|p| {
|
||||||
|
join_if_relative(
|
||||||
|
&datadir
|
||||||
|
.expect("Setting DOCDIR without setting DATADIR is not currently supported"),
|
||||||
|
p,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_version(src_dir: &Path) -> String {
|
fn get_version(src_dir: &Path) -> String {
|
||||||
use std::fs::read_to_string;
|
use std::fs::read_to_string;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
if let Ok(var) = std::env::var("FISH_BUILD_VERSION") {
|
if let Some(var) = env_var("FISH_BUILD_VERSION") {
|
||||||
return var;
|
return var;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,22 @@ if [ "$FISH_CHECK_LINT" = false ]; then
|
|||||||
lint=false
|
lint=false
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
check_dependency_versions=false
|
||||||
|
if [ "${FISH_CHECK_DEPENDENCY_VERSIONS:-false}" != false ]; then
|
||||||
|
check_dependency_versions=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if $check_dependency_versions; then
|
||||||
|
command -v curl
|
||||||
|
command -v jq
|
||||||
|
command -v rustup
|
||||||
|
command -v uv
|
||||||
|
sort --version-sort </dev/null
|
||||||
|
# To match existing behavior, only check Rust/dockerfiles for now.
|
||||||
|
# TODO: remove this from this script.
|
||||||
|
updatecli diff --config=updatecli.d/docker.yml --config=updatecli.d/rust.yml
|
||||||
|
fi
|
||||||
|
|
||||||
cargo_args=$FISH_CHECK_CARGO_ARGS
|
cargo_args=$FISH_CHECK_CARGO_ARGS
|
||||||
target_triple=$FISH_CHECK_TARGET_TRIPLE
|
target_triple=$FISH_CHECK_TARGET_TRIPLE
|
||||||
if [ -n "$target_triple" ]; then
|
if [ -n "$target_triple" ]; then
|
||||||
@@ -22,8 +38,8 @@ cargo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cleanup () {
|
cleanup () {
|
||||||
if [ -n "$template_file" ] && [ -e "$template_file" ]; then
|
if [ -n "$gettext_template_dir" ] && [ -e "$gettext_template_dir" ]; then
|
||||||
rm "$template_file"
|
rm -r "$gettext_template_dir"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,9 +59,20 @@ fi
|
|||||||
# Currently, all builds are debug builds.
|
# Currently, all builds are debug builds.
|
||||||
build_dir="$target_dir/debug"
|
build_dir="$target_dir/debug"
|
||||||
|
|
||||||
template_file=$(mktemp)
|
if [ -n "$FISH_TEST_MAX_CONCURRENCY" ]; then
|
||||||
FISH_GETTEXT_EXTRACTION_FILE=$template_file cargo build --workspace --all-targets --features=gettext-extract
|
export RUST_TEST_THREADS="$FISH_TEST_MAX_CONCURRENCY"
|
||||||
|
export CARGO_BUILD_JOBS="$FISH_TEST_MAX_CONCURRENCY"
|
||||||
|
fi
|
||||||
|
|
||||||
|
gettext_template_dir=$(mktemp -d)
|
||||||
|
(
|
||||||
|
export FISH_GETTEXT_EXTRACTION_DIR="$gettext_template_dir"
|
||||||
|
cargo build --workspace --all-targets --features=gettext-extract
|
||||||
|
)
|
||||||
if $lint; then
|
if $lint; then
|
||||||
|
if command -v cargo-deny >/dev/null; then
|
||||||
|
cargo deny --all-features --locked --exclude-dev check licenses
|
||||||
|
fi
|
||||||
PATH="$build_dir:$PATH" "$workspace_root/build_tools/style.fish" --all --check
|
PATH="$build_dir:$PATH" "$workspace_root/build_tools/style.fish" --all --check
|
||||||
for features in "" --no-default-features; do
|
for features in "" --no-default-features; do
|
||||||
cargo clippy --workspace --all-targets $features
|
cargo clippy --workspace --all-targets $features
|
||||||
@@ -54,9 +81,9 @@ fi
|
|||||||
cargo test --no-default-features --workspace --all-targets
|
cargo test --no-default-features --workspace --all-targets
|
||||||
cargo test --doc --workspace
|
cargo test --doc --workspace
|
||||||
if $lint; then
|
if $lint; then
|
||||||
cargo doc --workspace
|
cargo doc --workspace --no-deps
|
||||||
fi
|
fi
|
||||||
FISH_GETTEXT_EXTRACTION_FILE=$template_file "$workspace_root/tests/test_driver.py" "$build_dir"
|
FISH_GETTEXT_EXTRACTION_DIR=$gettext_template_dir "$workspace_root/tests/test_driver.py" "$build_dir"
|
||||||
|
|
||||||
exit
|
exit
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
#!/usr/bin/env fish
|
|
||||||
# Build a list of all sections in the html sphinx docs, separately by page,
|
|
||||||
# so it can be added to share/functions/help.fish
|
|
||||||
# Use like
|
|
||||||
# fish extract_help_sections.fish user_doc/html/{fish_for_bash_users.html,faq.html,interactive.html,language.html,tutorial.html}
|
|
||||||
# TODO: Currently `help` uses variable names we can't generate, so it needs to be touched up manually.
|
|
||||||
# Also this could easily be broken by changes in sphinx, ideally we'd have a way to let it print the section titles.
|
|
||||||
#
|
|
||||||
|
|
||||||
for file in $argv
|
|
||||||
set -l varname (string replace -r '.*/(.*).html' '$1' -- $file | string escape --style=var)pages
|
|
||||||
# Technically we can use any id in the document as an anchor, but listing them all is probably too much.
|
|
||||||
# Sphinx stores section titles (in a slug-ized form) in the id,
|
|
||||||
# and stores explicit section links in a `span` tag like
|
|
||||||
# `<span id="identifiers"></span>`
|
|
||||||
# We extract both separately.
|
|
||||||
set -l sections (string replace -rf '.*class="headerlink" href="#([^"]*)".*' '$1' <$file)
|
|
||||||
# Sections titled "id5" and such are internal cruft and shouldn't be offered.
|
|
||||||
set -a sections (string replace -rf '.*span id="([^"]*)".*' '$1' <$file | string match -rv 'id\d+')
|
|
||||||
|
|
||||||
set sections (printf '%s\n' $sections | sort -u)
|
|
||||||
echo set -l $varname $sections
|
|
||||||
end
|
|
||||||
@@ -19,28 +19,38 @@ begin
|
|||||||
echo ""
|
echo ""
|
||||||
end
|
end
|
||||||
|
|
||||||
set -g workspace_root (status dirname)/..
|
set -g workspace_root (path resolve (status dirname)/..)
|
||||||
|
|
||||||
set -l rust_extraction_file
|
set -l rust_extraction_dir
|
||||||
if set -l --query _flag_use_existing_template
|
if set -l --query _flag_use_existing_template
|
||||||
set rust_extraction_file $_flag_use_existing_template
|
set rust_extraction_dir $_flag_use_existing_template
|
||||||
else
|
else
|
||||||
set rust_extraction_file (mktemp)
|
set rust_extraction_dir (mktemp -d)
|
||||||
# We need to build to ensure that the proc macro for extracting strings runs.
|
# We need to build to ensure that the proc macro for extracting strings runs.
|
||||||
FISH_GETTEXT_EXTRACTION_FILE=$rust_extraction_file cargo check --features=gettext-extract
|
FISH_GETTEXT_EXTRACTION_DIR=$rust_extraction_dir cargo check --features=gettext-extract
|
||||||
or exit 1
|
or exit 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function mark_section
|
||||||
|
set -l section_name $argv[1]
|
||||||
|
echo 'msgid "fish-section-'$section_name'"'
|
||||||
|
echo 'msgstr ""'
|
||||||
|
echo ''
|
||||||
|
end
|
||||||
|
|
||||||
|
mark_section tier1-from-rust
|
||||||
|
|
||||||
# Get rid of duplicates and sort.
|
# Get rid of duplicates and sort.
|
||||||
msguniq --no-wrap --strict --sort-output $rust_extraction_file
|
find $rust_extraction_dir -type f -exec cat {} + | msguniq --no-wrap --sort-output
|
||||||
or exit 1
|
or exit 1
|
||||||
|
|
||||||
if not set -l --query _flag_use_existing_template
|
if not set -l --query _flag_use_existing_template
|
||||||
rm $rust_extraction_file
|
rm -r $rust_extraction_dir
|
||||||
end
|
end
|
||||||
|
|
||||||
function extract_fish_script_messages --argument-names regex
|
function extract_fish_script_messages_impl
|
||||||
|
set -l regex $argv[1]
|
||||||
|
set -e argv[1]
|
||||||
# Using xgettext causes more trouble than it helps.
|
# Using xgettext causes more trouble than it helps.
|
||||||
# This is due to handling of escaping in fish differing from formats xgettext understands
|
# This is due to handling of escaping in fish differing from formats xgettext understands
|
||||||
# (e.g. POSIX shell strings).
|
# (e.g. POSIX shell strings).
|
||||||
@@ -59,24 +69,74 @@ begin
|
|||||||
# 5. Double quotes are escaped, such that they are not interpreted as the start or end of
|
# 5. Double quotes are escaped, such that they are not interpreted as the start or end of
|
||||||
# a msgid.
|
# a msgid.
|
||||||
# 6. We transform the string into the format expected in a PO file.
|
# 6. We transform the string into the format expected in a PO file.
|
||||||
cat $share_dir/config.fish $share_dir/completions/*.fish $share_dir/functions/*.fish |
|
cat $argv |
|
||||||
string replace --filter --regex $regex '$1' |
|
string replace --filter --regex $regex '$1' |
|
||||||
string unescape |
|
string unescape |
|
||||||
sort -u |
|
sort -u |
|
||||||
sed -E -e 's_\\\\_\\\\\\\\_g' -e 's_"_\\\\"_g' -e 's_^(.*)$_msgid "\1"\nmsgstr ""\n_'
|
sed -E -e 's_\\\\_\\\\\\\\_g' -e 's_"_\\\\"_g' -e 's_^(.*)$_msgid "\1"\nmsgstr ""\n_'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function extract_fish_script_messages
|
||||||
|
set -l tier $argv[1]
|
||||||
|
set -e argv[1]
|
||||||
|
if not set -q argv[1]
|
||||||
|
return
|
||||||
|
end
|
||||||
|
# This regex handles explicit requests to translate a message. These are more important to translate
|
||||||
|
# than messages which should be implicitly translated.
|
||||||
|
set -l explicit_regex '.*\( *_ (([\'"]).+?(?<!\\\\)\\2) *\).*'
|
||||||
|
mark_section "$tier-from-script-explicitly-added"
|
||||||
|
extract_fish_script_messages_impl $explicit_regex $argv
|
||||||
|
|
||||||
|
# This regex handles descriptions for `complete` and `function` statements. These messages are not
|
||||||
|
# particularly important to translate. Hence the "implicit" label.
|
||||||
|
set -l implicit_regex '^(?:\s|and |or )*(?:complete|function).*? (?:-d|--description) (([\'"]).+?(?<!\\\\)\\2).*'
|
||||||
|
mark_section "$tier-from-script-implicitly-added"
|
||||||
|
extract_fish_script_messages_impl $implicit_regex $argv
|
||||||
|
end
|
||||||
|
|
||||||
set -g share_dir $workspace_root/share
|
set -g share_dir $workspace_root/share
|
||||||
|
|
||||||
# This regex handles explicit requests to translate a message. These are more important to translate
|
set -l tier1 $share_dir/config.fish
|
||||||
# than messages which should be implicitly translated.
|
set -l tier2
|
||||||
set -l explicit_regex '.*\( *_ (([\'"]).+?(?<!\\\\)\\2) *\).*'
|
set -l tier3
|
||||||
extract_fish_script_messages $explicit_regex
|
|
||||||
|
|
||||||
# This regex handles descriptions for `complete` and `function` statements. These messages are not
|
for file in $share_dir/completions/*.fish $share_dir/functions/*.fish
|
||||||
# particularly important to translate. Hence the "implicit" label.
|
# set -l tier (string match -r '^# localization: .*' <$file)
|
||||||
set -l implicit_regex '^(?:\s|and |or )*(?:complete|function).*? (?:-d|--description) (([\'"]).+?(?<!\\\\)\\2).*'
|
set -l tier (string replace -rf -m1 \
|
||||||
extract_fish_script_messages $implicit_regex
|
'^# localization: (.*)$' '$1' <$file)
|
||||||
|
if set -q tier[1]
|
||||||
|
switch "$tier"
|
||||||
|
case tier1 tier2 tier3
|
||||||
|
set -a $tier $file
|
||||||
|
case 'skip*'
|
||||||
|
case '*'
|
||||||
|
echo >&2 "$file:1 unexpected localization tier: $tier"
|
||||||
|
exit 1
|
||||||
|
end
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
set -l dirname (path basename (path dirname $file))
|
||||||
|
set -l command_name (path basename --no-extension $file)
|
||||||
|
if test $dirname = functions &&
|
||||||
|
string match -q -- 'fish_*' $command_name
|
||||||
|
set -a tier1 $file
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
if test $dirname != completions
|
||||||
|
echo >&2 "$file:1 missing localization tier for function file"
|
||||||
|
exit 1
|
||||||
|
end
|
||||||
|
if test -e $workspace_root/doc_src/cmds/$command_name.rst
|
||||||
|
set -a tier1 $file
|
||||||
|
else
|
||||||
|
set -a tier3 $file
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
extract_fish_script_messages tier1 $tier1
|
||||||
|
extract_fish_script_messages tier2 $tier2
|
||||||
|
extract_fish_script_messages tier3 $tier3
|
||||||
end |
|
end |
|
||||||
# At this point, all extracted strings have been written to stdout,
|
# At this point, all extracted strings have been written to stdout,
|
||||||
# starting with the ones taken from the Rust sources,
|
# starting with the ones taken from the Rust sources,
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ git_permission_failed=0
|
|||||||
|
|
||||||
# First see if there is a version file (included in release tarballs),
|
# First see if there is a version file (included in release tarballs),
|
||||||
# then try git-describe, then default.
|
# then try git-describe, then default.
|
||||||
if test -f version
|
if test -f "$FISH_BASE_DIR"/version
|
||||||
then
|
then
|
||||||
VN=$(cat version) || VN="$DEF_VER"
|
VN=$(cat "$FISH_BASE_DIR"/version) || VN="$DEF_VER"
|
||||||
else
|
else
|
||||||
if VN=$(git -C "$FISH_BASE_DIR" describe --always --dirty 2>/dev/null); then
|
if VN=$(git -C "$FISH_BASE_DIR" describe --always --dirty 2>/dev/null); then
|
||||||
:
|
:
|
||||||
|
|||||||
@@ -24,16 +24,12 @@ SIGN=
|
|||||||
NOTARIZE=
|
NOTARIZE=
|
||||||
|
|
||||||
ARM64_DEPLOY_TARGET='MACOSX_DEPLOYMENT_TARGET=11.0'
|
ARM64_DEPLOY_TARGET='MACOSX_DEPLOYMENT_TARGET=11.0'
|
||||||
X86_64_DEPLOY_TARGET='MACOSX_DEPLOYMENT_TARGET=10.9'
|
X86_64_DEPLOY_TARGET='MACOSX_DEPLOYMENT_TARGET=10.12'
|
||||||
|
cmake_args=()
|
||||||
|
|
||||||
# As of this writing, the most recent Rust release supports macOS back to 10.12.
|
while getopts "c:sf:i:p:e:nj:" opt; do
|
||||||
# The first supported version of macOS on arm64 is 10.15, so any Rust is fine for arm64.
|
|
||||||
# We wish to support back to 10.9 on x86-64; the last version of Rust to support that is
|
|
||||||
# version 1.73.0.
|
|
||||||
RUST_VERSION_X86_64=1.70.0
|
|
||||||
|
|
||||||
while getopts "sf:i:p:e:nj:" opt; do
|
|
||||||
case $opt in
|
case $opt in
|
||||||
|
c) cmake_args+=("$OPTARG");;
|
||||||
s) SIGN=1;;
|
s) SIGN=1;;
|
||||||
f) P12_APP_FILE=$(realpath "$OPTARG");;
|
f) P12_APP_FILE=$(realpath "$OPTARG");;
|
||||||
i) P12_INSTALL_FILE=$(realpath "$OPTARG");;
|
i) P12_INSTALL_FILE=$(realpath "$OPTARG");;
|
||||||
@@ -65,42 +61,37 @@ OUTPUT_PATH=${FISH_ARTEFACT_PATH:-~/fish_built}
|
|||||||
|
|
||||||
mkdir -p "$PKGDIR/build_x86_64" "$PKGDIR/build_arm64" "$PKGDIR/root" "$PKGDIR/intermediates" "$PKGDIR/dst"
|
mkdir -p "$PKGDIR/build_x86_64" "$PKGDIR/build_arm64" "$PKGDIR/root" "$PKGDIR/intermediates" "$PKGDIR/dst"
|
||||||
|
|
||||||
|
do_cmake() {
|
||||||
|
cmake \
|
||||||
|
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||||
|
-DCMAKE_EXE_LINKER_FLAGS="-Wl,-ld_classic" \
|
||||||
|
-DCMAKE_OSX_ARCHITECTURES='arm64;x86_64' \
|
||||||
|
-DFISH_USE_SYSTEM_PCRE2=OFF \
|
||||||
|
"${cmake_args[@]}" \
|
||||||
|
"$@" \
|
||||||
|
"$SRC_DIR"
|
||||||
|
}
|
||||||
|
|
||||||
# Build and install for arm64.
|
# Build and install for arm64.
|
||||||
# Pass FISH_USE_SYSTEM_PCRE2=OFF because a system PCRE2 on macOS will not be signed by fish,
|
# Pass FISH_USE_SYSTEM_PCRE2=OFF because a system PCRE2 on macOS will not be signed by fish,
|
||||||
# and will probably not be built universal, so the package will fail to validate/run on other systems.
|
# and will probably not be built universal, so the package will fail to validate/run on other systems.
|
||||||
# Note CMAKE_OSX_ARCHITECTURES is still relevant for the Mac app.
|
# Note CMAKE_OSX_ARCHITECTURES is still relevant for the Mac app.
|
||||||
{ cd "$PKGDIR/build_arm64" \
|
{ cd "$PKGDIR/build_arm64" \
|
||||||
&& cmake \
|
&& do_cmake -DRust_CARGO_TARGET=aarch64-apple-darwin \
|
||||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
|
||||||
-DCMAKE_EXE_LINKER_FLAGS="-Wl,-ld_classic" \
|
|
||||||
-DRust_CARGO_TARGET=aarch64-apple-darwin \
|
|
||||||
-DCMAKE_OSX_ARCHITECTURES='arm64;x86_64' \
|
|
||||||
-DFISH_USE_SYSTEM_PCRE2=OFF \
|
|
||||||
"$SRC_DIR" \
|
|
||||||
&& env $ARM64_DEPLOY_TARGET make VERBOSE=1 -j 12 \
|
&& env $ARM64_DEPLOY_TARGET make VERBOSE=1 -j 12 \
|
||||||
&& env DESTDIR="$PKGDIR/root/" $ARM64_DEPLOY_TARGET make install;
|
&& env DESTDIR="$PKGDIR/root/" $ARM64_DEPLOY_TARGET make install;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Build for x86-64 but do not install; instead we will make some fat binaries inside the root.
|
# Build for x86-64 but do not install; instead we will make a fat binary inside the root.
|
||||||
# Set RUST_VERSION_X86_64 to the last version of Rust that supports macOS 10.9.
|
|
||||||
{ cd "$PKGDIR/build_x86_64" \
|
{ cd "$PKGDIR/build_x86_64" \
|
||||||
&& cmake \
|
&& do_cmake -DRust_CARGO_TARGET=x86_64-apple-darwin \
|
||||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
|
||||||
-DCMAKE_EXE_LINKER_FLAGS="-Wl,-ld_classic" \
|
|
||||||
-DRust_TOOLCHAIN="$RUST_VERSION_X86_64" \
|
|
||||||
-DRust_CARGO_TARGET=x86_64-apple-darwin \
|
|
||||||
-DRust_COMPILER="$(rustup +$RUST_VERSION_X86_64 which rustc)" \
|
|
||||||
-DRust_CARGO="$(rustup +$RUST_VERSION_X86_64 which cargo)" \
|
|
||||||
-DCMAKE_OSX_ARCHITECTURES='arm64;x86_64' \
|
|
||||||
-DFISH_USE_SYSTEM_PCRE2=OFF "$SRC_DIR" \
|
|
||||||
&& env $X86_64_DEPLOY_TARGET make VERBOSE=1 -j 12; }
|
&& env $X86_64_DEPLOY_TARGET make VERBOSE=1 -j 12; }
|
||||||
|
|
||||||
# Fatten them up.
|
# Fatten it up.
|
||||||
for FILE in "$PKGDIR"/root/usr/local/bin/*; do
|
FILE=$PKGDIR/root/usr/local/bin/fish
|
||||||
X86_FILE="$PKGDIR/build_x86_64/$(basename "$FILE")"
|
X86_FILE=$PKGDIR/build_x86_64/$(basename "$FILE")
|
||||||
rcodesign macho-universal-create --output "$FILE" "$FILE" "$X86_FILE"
|
rcodesign macho-universal-create --output "$FILE" "$FILE" "$X86_FILE"
|
||||||
chmod 755 "$FILE"
|
chmod 755 "$FILE"
|
||||||
done
|
|
||||||
|
|
||||||
if test -n "$SIGN"; then
|
if test -n "$SIGN"; then
|
||||||
echo "Signing executables"
|
echo "Signing executables"
|
||||||
@@ -113,9 +104,7 @@ if test -n "$SIGN"; then
|
|||||||
if [ -n "$ENTITLEMENTS_FILE" ]; then
|
if [ -n "$ENTITLEMENTS_FILE" ]; then
|
||||||
ARGS+=(--entitlements-xml-file "$ENTITLEMENTS_FILE")
|
ARGS+=(--entitlements-xml-file "$ENTITLEMENTS_FILE")
|
||||||
fi
|
fi
|
||||||
for FILE in "$PKGDIR"/root/usr/local/bin/*; do
|
(set +x; rcodesign sign "${ARGS[@]}" "$PKGDIR"/root/usr/local/bin/fish)
|
||||||
(set +x; rcodesign sign "${ARGS[@]}" "$FILE")
|
|
||||||
done
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
pkgbuild --scripts "$SRC_DIR/build_tools/osx_package_scripts" --root "$PKGDIR/root/" --identifier 'com.ridiculousfish.fish-shell-pkg' --version "$VERSION" "$PKGDIR/intermediates/fish.pkg"
|
pkgbuild --scripts "$SRC_DIR/build_tools/osx_package_scripts" --root "$PKGDIR/root/" --identifier 'com.ridiculousfish.fish-shell-pkg' --version "$VERSION" "$PKGDIR/intermediates/fish.pkg"
|
||||||
@@ -136,15 +125,13 @@ fi
|
|||||||
(cd "$PKGDIR/build_arm64" && env $ARM64_DEPLOY_TARGET make -j 12 fish_macapp)
|
(cd "$PKGDIR/build_arm64" && env $ARM64_DEPLOY_TARGET make -j 12 fish_macapp)
|
||||||
(cd "$PKGDIR/build_x86_64" && env $X86_64_DEPLOY_TARGET make -j 12 fish_macapp)
|
(cd "$PKGDIR/build_x86_64" && env $X86_64_DEPLOY_TARGET make -j 12 fish_macapp)
|
||||||
|
|
||||||
# Make the app's /usr/local/bin binaries universal. Note fish.app/Contents/MacOS/fish already is, courtesy of CMake.
|
# Make the app's /usr/local/bin/fish binary universal. Note fish.app/Contents/MacOS/fish already is, courtesy of CMake.
|
||||||
cd "$PKGDIR/build_arm64"
|
cd "$PKGDIR/build_arm64"
|
||||||
for FILE in fish.app/Contents/Resources/base/usr/local/bin/*; do
|
FILE=fish.app/Contents/Resources/base/usr/local/bin/fish
|
||||||
X86_FILE="$PKGDIR/build_x86_64/fish.app/Contents/Resources/base/usr/local/bin/$(basename "$FILE")"
|
X86_FILE=$PKGDIR/build_x86_64/fish.app/Contents/Resources/base/usr/local/bin/$(basename "$FILE")
|
||||||
rcodesign macho-universal-create --output "$FILE" "$FILE" "$X86_FILE"
|
rcodesign macho-universal-create --output "$FILE" "$FILE" "$X86_FILE"
|
||||||
|
# macho-universal-create screws up the permissions.
|
||||||
# macho-universal-create screws up the permissions.
|
chmod 755 "$FILE"
|
||||||
chmod 755 "$FILE"
|
|
||||||
done
|
|
||||||
|
|
||||||
if test -n "$SIGN"; then
|
if test -n "$SIGN"; then
|
||||||
echo "Signing app"
|
echo "Signing app"
|
||||||
|
|||||||
@@ -1,79 +1,23 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
# Script to generate a tarball
|
# Script to generate a tarball
|
||||||
# We use git to output a tree. But we also want to build the user documentation
|
|
||||||
# and put that in the tarball, so that nobody needs to have sphinx installed
|
|
||||||
# to build it.
|
|
||||||
# Outputs to $FISH_ARTEFACT_PATH or ~/fish_built by default
|
# Outputs to $FISH_ARTEFACT_PATH or ~/fish_built by default
|
||||||
|
|
||||||
# Exit on error
|
# Exit on error
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# We will generate a tarball with a prefix "fish-VERSION"
|
|
||||||
# git can do that automatically for us via git-archive
|
|
||||||
# but to get the documentation in, we need to make a symlink called "fish-VERSION"
|
|
||||||
# and tar from that, so that the documentation gets the right prefix
|
|
||||||
|
|
||||||
# Use Ninja if available, as it automatically parallelises
|
|
||||||
BUILD_TOOL="make"
|
|
||||||
BUILD_GENERATOR="Unix Makefiles"
|
|
||||||
if command -v ninja >/dev/null; then
|
|
||||||
BUILD_TOOL="ninja"
|
|
||||||
BUILD_GENERATOR="Ninja"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# We need GNU tar as that supports the --mtime and --transform options
|
|
||||||
TAR=notfound
|
|
||||||
for try in tar gtar gnutar; do
|
|
||||||
if $try -Pcf /dev/null --mtime now /dev/null >/dev/null 2>&1; then
|
|
||||||
TAR=$try
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ "$TAR" = "notfound" ]; then
|
|
||||||
echo 'No suitable tar (supporting --mtime) found as tar/gtar/gnutar in PATH'
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Get the current directory, which we'll use for symlinks
|
|
||||||
wd="$PWD"
|
|
||||||
|
|
||||||
# Get the version
|
# Get the version
|
||||||
VERSION=$(build_tools/git_version_gen.sh --stdout 2>/dev/null)
|
VERSION=$(build_tools/git_version_gen.sh --stdout 2>/dev/null)
|
||||||
|
|
||||||
# The name of the prefix, which is the directory that you get when you untar
|
prefix=fish-$VERSION
|
||||||
prefix="fish-$VERSION"
|
path=${FISH_ARTEFACT_PATH:-~/fish_built}/$prefix.tar.xz
|
||||||
|
|
||||||
# The path where we will output the tar file
|
git archive \
|
||||||
# Defaults to ~/fish_built
|
--prefix="$prefix/" \
|
||||||
path=${FISH_ARTEFACT_PATH:-~/fish_built}/$prefix.tar
|
--add-virtual-file="$prefix/version:$VERSION" \
|
||||||
|
HEAD |
|
||||||
# Clean up stuff we've written before
|
xz >"$path"
|
||||||
rm -f "$path" "$path".xz
|
|
||||||
|
|
||||||
# git starts the archive
|
|
||||||
git archive --format=tar --prefix="$prefix"/ HEAD > "$path"
|
|
||||||
|
|
||||||
# tarball out the documentation, generate a version file
|
|
||||||
PREFIX_TMPDIR=$(mktemp -d)
|
|
||||||
cd "$PREFIX_TMPDIR"
|
|
||||||
echo "$VERSION" > version
|
|
||||||
cmake -G "$BUILD_GENERATOR" -DCMAKE_BUILD_TYPE=Debug "$wd"
|
|
||||||
$BUILD_TOOL doc
|
|
||||||
|
|
||||||
TAR_APPEND="$TAR --append --file=$path --mtime=now --owner=0 --group=0 \
|
|
||||||
--mode=g+w,a+rX --transform s/^/$prefix\//"
|
|
||||||
$TAR_APPEND --no-recursion user_doc
|
|
||||||
$TAR_APPEND user_doc/html user_doc/man
|
|
||||||
$TAR_APPEND version
|
|
||||||
|
|
||||||
cd -
|
|
||||||
rm -r "$PREFIX_TMPDIR"
|
|
||||||
|
|
||||||
# xz it
|
|
||||||
xz "$path"
|
|
||||||
|
|
||||||
# Output what we did, and the sha256 hash
|
# Output what we did, and the sha256 hash
|
||||||
echo "Tarball written to $path".xz
|
echo "Tarball written to $path"
|
||||||
openssl dgst -sha256 "$path".xz
|
openssl dgst -sha256 "$path"
|
||||||
|
|||||||
@@ -11,37 +11,38 @@ mkdir -p "$relnotes_tmp/fake-workspace" "$relnotes_tmp/out"
|
|||||||
cp -r doc_src CONTRIBUTING.rst README.rst "$relnotes_tmp/fake-workspace"
|
cp -r doc_src CONTRIBUTING.rst README.rst "$relnotes_tmp/fake-workspace"
|
||||||
)
|
)
|
||||||
version=$(sed 's,^fish \(\S*\) .*,\1,; 1q' "$workspace_root/CHANGELOG.rst")
|
version=$(sed 's,^fish \(\S*\) .*,\1,; 1q' "$workspace_root/CHANGELOG.rst")
|
||||||
previous_version=$(
|
add_stats=false
|
||||||
cd "$workspace_root"
|
# Skip on shallow clone (CI) for now.
|
||||||
awk <CHANGELOG.rst '
|
if test -z "$CI" || [ "$(git -C "$workspace_root" tag | wc -l)" -gt 1 ]; then {
|
||||||
( /^fish \S*\.\S*\.\S* \(released .*\)$/ &&
|
previous_version=$(
|
||||||
NR > 1 &&
|
cd "$workspace_root"
|
||||||
# Skip tags that have not been created yet..
|
git for-each-ref --format='%(objecttype) %(refname:strip=2)' refs/tags |
|
||||||
system("git rev-parse --verify >/dev/null --quiet refs/tags/"$2) == 0 \
|
awk '/tag/ {print $2}' | sort --version-sort |
|
||||||
) {
|
grep -vxF "$(git describe)" | tail -1
|
||||||
print $2; ok = 1; exit
|
)
|
||||||
}
|
minor_version=${version%.*}
|
||||||
END { exit !ok }
|
previous_minor_version=${previous_version%.*}
|
||||||
'
|
if [ "$minor_version" != "$previous_minor_version" ]; then
|
||||||
)
|
add_stats=true
|
||||||
minor_version=${version%.*}
|
fi
|
||||||
previous_minor_version=${previous_version%.*}
|
} fi
|
||||||
{
|
{
|
||||||
sed -n 1,2p <"$workspace_root/CHANGELOG.rst"
|
sed -n 1,2p <"$workspace_root/CHANGELOG.rst"
|
||||||
|
if $add_stats; then {
|
||||||
ListCommitters() {
|
ExtractCommitters() {
|
||||||
comm "$@" "$relnotes_tmp/committers-then" "$relnotes_tmp/committers-now"
|
git log "$1" --format="%aN"
|
||||||
}
|
trailers='Co-authored-by|Signed-off-by'
|
||||||
(
|
git log "$1" --format="%b" | sed -En "/^($trailers):\s*/{s///;s/\s*<.*//;p}"
|
||||||
cd "$workspace_root"
|
}
|
||||||
git log "$previous_version" --format="%aN" | sort -u >"$relnotes_tmp/committers-then"
|
ListCommitters() {
|
||||||
git log "$previous_version".. --format="%aN" | sort -u >"$relnotes_tmp/committers-now"
|
comm "$@" "$relnotes_tmp/committers-then" "$relnotes_tmp/committers-now"
|
||||||
ListCommitters -13 >"$relnotes_tmp/committers-new"
|
}
|
||||||
ListCommitters -12 >"$relnotes_tmp/committers-returning"
|
|
||||||
)
|
|
||||||
if [ "$minor_version" != "$previous_minor_version" ]; then
|
|
||||||
(
|
(
|
||||||
cd "$workspace_root"
|
cd "$workspace_root"
|
||||||
|
ExtractCommitters "$previous_version" | sort -u >"$relnotes_tmp/committers-then"
|
||||||
|
ExtractCommitters "$previous_version".. | sort -u >"$relnotes_tmp/committers-now"
|
||||||
|
ListCommitters -13 >"$relnotes_tmp/committers-new"
|
||||||
|
ListCommitters -12 >"$relnotes_tmp/committers-returning"
|
||||||
num_commits=$(git log --no-merges --format=%H "$previous_version".. | wc -l)
|
num_commits=$(git log --no-merges --format=%H "$previous_version".. | wc -l)
|
||||||
num_authors=$(wc -l <"$relnotes_tmp/committers-now")
|
num_authors=$(wc -l <"$relnotes_tmp/committers-now")
|
||||||
num_new_authors=$(wc -l <"$relnotes_tmp/committers-new")
|
num_new_authors=$(wc -l <"$relnotes_tmp/committers-new")
|
||||||
@@ -51,18 +52,18 @@ previous_minor_version=${previous_version%.*}
|
|||||||
echo
|
echo
|
||||||
echo
|
echo
|
||||||
)
|
)
|
||||||
fi
|
} fi
|
||||||
|
|
||||||
printf %s "$(awk <"$workspace_root/CHANGELOG.rst" '
|
printf '%s\n' "$(awk <"$workspace_root/CHANGELOG.rst" '
|
||||||
NR <= 2 || /^\.\. ignore / { next }
|
NR <= 2 || /^\.\. ignore / { next }
|
||||||
/^===/ { exit }
|
/^===/ { exit }
|
||||||
{ print }
|
{ print }
|
||||||
' | sed '$d')" |
|
' | sed '$d')" |
|
||||||
sed -e '$s/^----*$//' # Remove spurious transitions at the end of the document.
|
sed -e '$s/^----*$//' # Remove spurious transitions at the end of the document.
|
||||||
|
|
||||||
if [ "$minor_version" != "$previous_minor_version" ]; then
|
if $add_stats; then {
|
||||||
JoinEscaped() {
|
JoinEscaped() {
|
||||||
sed 's/\S/\\&/g' |
|
LC_CTYPE=C.UTF-8 sed 's/\S/\\&/g' |
|
||||||
awk '
|
awk '
|
||||||
NR != 1 { printf ",\n" }
|
NR != 1 { printf ",\n" }
|
||||||
{ printf "%s", $0 }
|
{ printf "%s", $0 }
|
||||||
@@ -79,13 +80,18 @@ previous_minor_version=${previous_version%.*}
|
|||||||
echo
|
echo
|
||||||
printf "Welcome back our returning committers: "
|
printf "Welcome back our returning committers: "
|
||||||
JoinEscaped <"$relnotes_tmp/committers-returning"
|
JoinEscaped <"$relnotes_tmp/committers-returning"
|
||||||
fi
|
} fi
|
||||||
echo
|
echo
|
||||||
echo "---"
|
echo "---"
|
||||||
echo
|
echo
|
||||||
echo "*Download links: To download the source code for fish, we suggest the file named \"fish-$version.tar.xz\". The file downloaded from \"Source code (tar.gz)\" will not build correctly.*"
|
echo 'Download links:'
|
||||||
|
echo 'To download the source code for fish, we suggest the file named ``fish-'"$version"'.tar.xz``.'
|
||||||
|
echo 'The file downloaded from ``Source code (tar.gz)`` will not build correctly.'
|
||||||
|
echo 'A GPG signature using `this key <'"${FISH_GPG_PUBLIC_KEY_URL:-???}"'>`__ is available as ``fish-'"$version"'.tar.xz.asc``.'
|
||||||
echo
|
echo
|
||||||
echo "*The files called fish-$version-linux-\*.tar.xz are experimental packages containing a single standalone ``fish`` binary for any Linux with the given CPU architecture.*"
|
echo 'The files called ``fish-'"$version"'-linux-*.tar.xz`` contain'
|
||||||
|
echo '`standalone fish binaries <https://github.com/fish-shell/fish-shell/?tab=readme-ov-file#building-fish-with-cargo>`__'
|
||||||
|
echo 'for any Linux with the given CPU architecture.'
|
||||||
} >"$relnotes_tmp/fake-workspace"/CHANGELOG.rst
|
} >"$relnotes_tmp/fake-workspace"/CHANGELOG.rst
|
||||||
|
|
||||||
sphinx-build >&2 -j auto \
|
sphinx-build >&2 -j auto \
|
||||||
@@ -93,7 +99,7 @@ sphinx-build >&2 -j auto \
|
|||||||
-d "$relnotes_tmp/doctree" "$relnotes_tmp/fake-workspace/doc_src" "$relnotes_tmp/out" \
|
-d "$relnotes_tmp/doctree" "$relnotes_tmp/fake-workspace/doc_src" "$relnotes_tmp/out" \
|
||||||
-D markdown_http_base="https://fishshell.com/docs/$minor_version" \
|
-D markdown_http_base="https://fishshell.com/docs/$minor_version" \
|
||||||
-D markdown_uri_doc_suffix=".html" \
|
-D markdown_uri_doc_suffix=".html" \
|
||||||
-D markdown_github_flavored=1 \
|
-D markdown_flavor=github \
|
||||||
"$@"
|
"$@"
|
||||||
|
|
||||||
# Skip changelog header
|
# Skip changelog header
|
||||||
|
|||||||
@@ -18,11 +18,18 @@ fi
|
|||||||
[ -n "$version" ]
|
[ -n "$version" ]
|
||||||
|
|
||||||
for tool in \
|
for tool in \
|
||||||
|
cmake \
|
||||||
bundle \
|
bundle \
|
||||||
|
diff \
|
||||||
gh \
|
gh \
|
||||||
|
gpg \
|
||||||
jq \
|
jq \
|
||||||
|
ninja \
|
||||||
ruby \
|
ruby \
|
||||||
|
tar \
|
||||||
timeout \
|
timeout \
|
||||||
|
uv \
|
||||||
|
xz \
|
||||||
; do
|
; do
|
||||||
if ! command -v "$tool" >/dev/null; then
|
if ! command -v "$tool" >/dev/null; then
|
||||||
echo >&2 "$0: missing command: $1"
|
echo >&2 "$0: missing command: $1"
|
||||||
@@ -30,8 +37,14 @@ for tool in \
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
committer=$(git var GIT_AUTHOR_IDENT)
|
||||||
|
committer=${committer% *} # strip timezone
|
||||||
|
committer=${committer% *} # strip timestamp
|
||||||
|
gpg --local-user="$committer" --sign </dev/null >/dev/null
|
||||||
|
|
||||||
repo_root="$(dirname "$0")/.."
|
repo_root="$(dirname "$0")/.."
|
||||||
fish_site=$repo_root/../fish-site
|
fish_site=$repo_root/../fish-site
|
||||||
|
fish_site_repo=git@github.com:$repository_owner/fish-site
|
||||||
|
|
||||||
for path in . "$fish_site"
|
for path in . "$fish_site"
|
||||||
do
|
do
|
||||||
@@ -42,6 +55,13 @@ do
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
(
|
||||||
|
cd "$fish_site"
|
||||||
|
[ "$(git rev-parse HEAD)" = \
|
||||||
|
"$(git ls-remote "$fish_site_repo" refs/heads/master |
|
||||||
|
awk '{print $1}')" ]
|
||||||
|
)
|
||||||
|
|
||||||
if git tag | grep -qxF "$version"; then
|
if git tag | grep -qxF "$version"; then
|
||||||
echo >&2 "$0: tag $version already exists"
|
echo >&2 "$0: tag $version already exists"
|
||||||
exit 1
|
exit 1
|
||||||
@@ -66,6 +86,22 @@ sed -i \
|
|||||||
CommitVersion() {
|
CommitVersion() {
|
||||||
sed -i "s/^version = \".*\"/version = \"$1\"/g" Cargo.toml
|
sed -i "s/^version = \".*\"/version = \"$1\"/g" Cargo.toml
|
||||||
cargo fetch --offline
|
cargo fetch --offline
|
||||||
|
if [ "$1" = "$version" ]; then
|
||||||
|
# debchange is a Debian script to manage the Debian changelog, but
|
||||||
|
# it's too annoying to install everywhere. Just do it by hand.
|
||||||
|
cat - contrib/debian/changelog > contrib/debian/changelog.new <<EOF
|
||||||
|
fish (${version}-1) stable; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version $version.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/$version for details.
|
||||||
|
|
||||||
|
-- $committer $(date -R)
|
||||||
|
|
||||||
|
EOF
|
||||||
|
mv contrib/debian/changelog.new contrib/debian/changelog
|
||||||
|
git add contrib/debian/changelog
|
||||||
|
fi
|
||||||
git add CHANGELOG.rst Cargo.toml Cargo.lock
|
git add CHANGELOG.rst Cargo.toml Cargo.lock
|
||||||
git commit -m "$2
|
git commit -m "$2
|
||||||
|
|
||||||
@@ -74,8 +110,8 @@ Created by ./build_tools/release.sh $version"
|
|||||||
|
|
||||||
CommitVersion "$version" "Release $version"
|
CommitVersion "$version" "Release $version"
|
||||||
|
|
||||||
# N.B. this is not GPG-signed.
|
git -c "user.signingKey=$committer" \
|
||||||
git tag --annotate --message="Release $version" $version
|
tag --sign --message="Release $version" $version
|
||||||
|
|
||||||
git push $remote $version
|
git push $remote $version
|
||||||
|
|
||||||
@@ -100,13 +136,21 @@ done
|
|||||||
# Update fishshell.com
|
# Update fishshell.com
|
||||||
tag_oid=$(git rev-parse "$version")
|
tag_oid=$(git rev-parse "$version")
|
||||||
tmpdir=$(mktemp -d)
|
tmpdir=$(mktemp -d)
|
||||||
|
fish_tar_xz=fish-$version.tar.xz
|
||||||
|
(
|
||||||
|
local_tarball=$tmpdir/local-tarball
|
||||||
|
mkdir "$local_tarball"
|
||||||
|
FISH_ARTEFACT_PATH=$local_tarball ./build_tools/make_tarball.sh
|
||||||
|
cd "$local_tarball"
|
||||||
|
tar xf "$fish_tar_xz"
|
||||||
|
)
|
||||||
# TODO This works on draft releases only if "gh" is configured to
|
# TODO This works on draft releases only if "gh" is configured to
|
||||||
# have write access to the fish-shell repository. Unless we are fine
|
# have write access to the fish-shell repository. Unless we are fine
|
||||||
# publishing the release at this point, we should at least fail if
|
# publishing the release at this point, we should at least fail if
|
||||||
# "gh" doesn't have write access.
|
# "gh" doesn't have write access.
|
||||||
while ! \
|
while ! \
|
||||||
gh release download "$version" --dir="$tmpdir" \
|
gh release download "$version" --dir="$tmpdir" \
|
||||||
--pattern="fish-$version.tar.xz"
|
--pattern="$fish_tar_xz"
|
||||||
do
|
do
|
||||||
TIMEOUT=30 gh run watch "$run_id" ||:
|
TIMEOUT=30 gh run watch "$run_id" ||:
|
||||||
sleep 5
|
sleep 5
|
||||||
@@ -114,10 +158,26 @@ done
|
|||||||
actual_tag_oid=$(git ls-remote "$remote" |
|
actual_tag_oid=$(git ls-remote "$remote" |
|
||||||
awk '$2 == "refs/tags/'"$version"'" { print $1 }')
|
awk '$2 == "refs/tags/'"$version"'" { print $1 }')
|
||||||
[ "$tag_oid" = "$actual_tag_oid" ]
|
[ "$tag_oid" = "$actual_tag_oid" ]
|
||||||
( cd "$tmpdir" && tar xf fish-$version.tar.xz )
|
|
||||||
|
(
|
||||||
|
cd "$tmpdir"
|
||||||
|
tar xf "$fish_tar_xz"
|
||||||
|
diff -ur "fish-$version" "local-tarball/fish-$version"
|
||||||
|
gpg --local-user="$committer" --sign --detach --armor \
|
||||||
|
"$fish_tar_xz"
|
||||||
|
gh release upload "$version" "$fish_tar_xz.asc"
|
||||||
|
)
|
||||||
|
|
||||||
|
(
|
||||||
|
cd "$tmpdir/local-tarball/fish-$version"
|
||||||
|
uv --no-managed-python venv
|
||||||
|
. .venv/bin/activate
|
||||||
|
cmake -GNinja -DCMAKE_BUILD_TYPE=Debug .
|
||||||
|
ninja doc
|
||||||
|
)
|
||||||
CopyDocs() {
|
CopyDocs() {
|
||||||
rm -rf "$fish_site/site/docs/$1"
|
rm -rf "$fish_site/site/docs/$1"
|
||||||
cp -r "$tmpdir/fish-$version/user_doc/html" "$fish_site/site/docs/$1"
|
cp -r "$tmpdir/local-tarball/fish-$version/user_doc/html" "$fish_site/site/docs/$1"
|
||||||
git -C $fish_site add "site/docs/$1"
|
git -C $fish_site add "site/docs/$1"
|
||||||
}
|
}
|
||||||
minor_version=${version%.*}
|
minor_version=${version%.*}
|
||||||
@@ -136,7 +196,10 @@ rm -rf "$tmpdir"
|
|||||||
cd "$fish_site"
|
cd "$fish_site"
|
||||||
make
|
make
|
||||||
git add -u
|
git add -u
|
||||||
! git ls-files --others --exclude-standard | grep .
|
git add docs
|
||||||
|
if git ls-files --others --exclude-standard | grep .; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
git commit --message="$(printf %s "\
|
git commit --message="$(printf %s "\
|
||||||
| Release $version (docs)
|
| Release $version (docs)
|
||||||
|
|
|
|
||||||
@@ -144,15 +207,21 @@ rm -rf "$tmpdir"
|
|||||||
" | sed 's,^\s*| \?,,')"
|
" | sed 's,^\s*| \?,,')"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Approve macos-codesign
|
gh_api_repo() {
|
||||||
# TODO what if current user can't approve?
|
path=$1
|
||||||
gh_pending_deployments() {
|
shift
|
||||||
command gh api \
|
command gh api \
|
||||||
-H "Accept: application/vnd.github+json" \
|
-H "Accept: application/vnd.github+json" \
|
||||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||||
"/repos/$repository_owner/fish-shell/actions/runs/$run_id/pending_deployments" \
|
"/repos/$repository_owner/fish-shell/$path" \
|
||||||
"$@"
|
"$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Approve macos-codesign
|
||||||
|
# TODO what if current user can't approve?
|
||||||
|
gh_pending_deployments() {
|
||||||
|
gh_api_repo "actions/runs/$run_id/pending_deployments" "$@"
|
||||||
|
}
|
||||||
while {
|
while {
|
||||||
environment_id=$(gh_pending_deployments | jq .[].environment.id)
|
environment_id=$(gh_pending_deployments | jq .[].environment.id)
|
||||||
[ -z "$environment_id" ]
|
[ -z "$environment_id" ]
|
||||||
@@ -167,7 +236,7 @@ echo '
|
|||||||
"comment": "Approved via ./build_tools/release.sh"
|
"comment": "Approved via ./build_tools/release.sh"
|
||||||
}
|
}
|
||||||
' |
|
' |
|
||||||
gh_pending_deployments -XPOST --input=-
|
gh_pending_deployments --method POST --input=-
|
||||||
|
|
||||||
# Await completion.
|
# Await completion.
|
||||||
gh run watch "$run_id"
|
gh run watch "$run_id"
|
||||||
@@ -184,7 +253,10 @@ done
|
|||||||
cd "$fish_site"
|
cd "$fish_site"
|
||||||
make new-release
|
make new-release
|
||||||
git add -u
|
git add -u
|
||||||
! git ls-files --others --exclude-standard | grep .
|
git add docs
|
||||||
|
if git ls-files --others --exclude-standard | grep .; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
git commit --message="$(printf %s "\
|
git commit --message="$(printf %s "\
|
||||||
| Release $version (release list update)
|
| Release $version (release list update)
|
||||||
|
|
|
|
||||||
@@ -192,12 +264,14 @@ done
|
|||||||
" | sed 's,^\s*| \?,,')"
|
" | sed 's,^\s*| \?,,')"
|
||||||
# This takes care to support remote names that are different from
|
# This takes care to support remote names that are different from
|
||||||
# fish-shell remote name. Also, support detached HEAD state.
|
# fish-shell remote name. Also, support detached HEAD state.
|
||||||
git push git@github.com:$repository_owner/fish-site HEAD:master
|
git push "$fish_site_repo" HEAD:master
|
||||||
|
git fetch "$fish_site_repo" \
|
||||||
|
"$(git rev-parse HEAD):refs/remotes/origin/master"
|
||||||
)
|
)
|
||||||
|
|
||||||
if [ -n "$integration_branch" ]; then
|
if [ -n "$integration_branch" ]; then {
|
||||||
git push $remote "$version^{commit}":refs/heads/$integration_branch
|
git push $remote "$version^{commit}":refs/heads/$integration_branch
|
||||||
else
|
} else {
|
||||||
changelog=$(cat - CHANGELOG.rst <<EOF
|
changelog=$(cat - CHANGELOG.rst <<EOF
|
||||||
fish ?.?.? (released ???)
|
fish ?.?.? (released ???)
|
||||||
=========================
|
=========================
|
||||||
@@ -207,23 +281,31 @@ EOF
|
|||||||
printf %s\\n "$changelog" >CHANGELOG.rst
|
printf %s\\n "$changelog" >CHANGELOG.rst
|
||||||
CommitVersion ${version}-snapshot "start new cycle"
|
CommitVersion ${version}-snapshot "start new cycle"
|
||||||
git push $remote HEAD:master
|
git push $remote HEAD:master
|
||||||
fi
|
|
||||||
|
|
||||||
# TODO This can currently require a TTY for editing and password
|
|
||||||
# prompts.
|
|
||||||
if [ "$repository_owner" = fish-shell ]; then {
|
|
||||||
mail=$(mktemp)
|
|
||||||
cat >$mail <<EOF
|
|
||||||
From: $(git var GIT_AUTHOR_IDENT | sed 's/ [0-9]* +[0-9]*$//')
|
|
||||||
Subject: fish $version released
|
|
||||||
|
|
||||||
See https://github.com/fish-shell/fish-shell/releases/tag/$version
|
|
||||||
EOF
|
|
||||||
git send-email --suppress-cc=all --confirm=always $mail \
|
|
||||||
--to="fish-users Mailing List <fish-users@lists.sourceforge.net>"
|
|
||||||
rm $mail
|
|
||||||
} fi
|
} fi
|
||||||
|
|
||||||
|
milestone_version="$(
|
||||||
|
if echo "$version" | grep -q '\.0$'; then
|
||||||
|
echo "$minor_version"
|
||||||
|
else
|
||||||
|
echo "$version"
|
||||||
|
fi
|
||||||
|
)"
|
||||||
|
milestone_number() {
|
||||||
|
gh_api_repo milestones?state=open |
|
||||||
|
jq --arg name "fish $1" '
|
||||||
|
.[] | select(.title == $name) | .number
|
||||||
|
'
|
||||||
|
}
|
||||||
|
gh_api_repo milestones/"$(milestone_number "$milestone_version")" \
|
||||||
|
--method PATCH --raw-field state=closed
|
||||||
|
|
||||||
|
next_minor_version=$(echo "$minor_version" |
|
||||||
|
awk -F. '{ printf "%s.%s", $1, $2+1 }')
|
||||||
|
if [ -z "$(milestone_number "$next_minor_version")" ]; then
|
||||||
|
gh_api_repo milestones --method POST \
|
||||||
|
--raw-field title="fish $next_minor_version"
|
||||||
|
fi
|
||||||
|
|
||||||
exit
|
exit
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ if test $all = yes
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
set fish_files $workspace_root/{benchmarks,build_tools,etc,share}/**.fish
|
set fish_files $workspace_root/{benchmarks,build_tools,etc,share}/**.fish
|
||||||
set python_files {doc_src,share,tests}/**.py
|
set python_files $workspace_root
|
||||||
else
|
else
|
||||||
# Format the files specified as arguments.
|
# Format the files specified as arguments.
|
||||||
set -l files $argv
|
set -l files $argv
|
||||||
@@ -58,6 +58,11 @@ set -l green (set_color green)
|
|||||||
set -l yellow (set_color yellow)
|
set -l yellow (set_color yellow)
|
||||||
set -l normal (set_color normal)
|
set -l normal (set_color normal)
|
||||||
|
|
||||||
|
function die -V red -V normal
|
||||||
|
echo $red$argv[1]$normal
|
||||||
|
exit 1
|
||||||
|
end
|
||||||
|
|
||||||
if set -q fish_files[1]
|
if set -q fish_files[1]
|
||||||
if not type -q fish_indent
|
if not type -q fish_indent
|
||||||
echo
|
echo
|
||||||
@@ -66,58 +71,52 @@ if set -q fish_files[1]
|
|||||||
end
|
end
|
||||||
echo === Running "$green"fish_indent"$normal"
|
echo === Running "$green"fish_indent"$normal"
|
||||||
if set -l -q _flag_check
|
if set -l -q _flag_check
|
||||||
if not fish_indent --check -- $fish_files
|
fish_indent --check -- $fish_files
|
||||||
echo $red"Fish files are not formatted correctly."$normal
|
or die "Fish files are not formatted correctly."
|
||||||
exit 1
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
fish_indent -w -- $fish_files
|
fish_indent -w -- $fish_files
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if set -q python_files[1]
|
if set -q python_files[1]
|
||||||
if not type -q black
|
if not type -q ruff
|
||||||
echo
|
echo
|
||||||
echo $yellow'Please install `black` to style python'$normal
|
echo $yellow'Please install `ruff` to style python'$normal
|
||||||
exit 127
|
exit 127
|
||||||
end
|
end
|
||||||
echo === Running "$green"black"$normal"
|
echo === Running "$green"ruff format"$normal"
|
||||||
if set -l -q _flag_check
|
if set -l -q _flag_check
|
||||||
if not black --check $python_files
|
ruff format --check $python_files
|
||||||
echo $red"Python files are not formatted correctly."$normal
|
or die "Python files are not formatted correctly."
|
||||||
exit 1
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
black $python_files
|
ruff format $python_files
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if not cargo fmt --version >/dev/null
|
if test $all = yes; or set -q rust_files[1]
|
||||||
echo
|
if not cargo fmt --version >/dev/null
|
||||||
echo $yellow'Please install "rustfmt" to style Rust, e.g. via:'
|
echo
|
||||||
echo "rustup component add rustfmt"$normal
|
echo $yellow'Please install "rustfmt" to style Rust, e.g. via:'
|
||||||
exit 127
|
echo "rustup component add rustfmt"$normal
|
||||||
end
|
exit 127
|
||||||
echo === Running "$green"rustfmt"$normal"
|
|
||||||
if set -l -q _flag_check
|
|
||||||
if set -l -q _flag_all
|
|
||||||
if not cargo fmt --check
|
|
||||||
echo $red"Rust files are not formatted correctly."$normal
|
|
||||||
exit 1
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if set -q rust_files[1]
|
|
||||||
if not rustfmt --check --files-with-diff $rust_files
|
|
||||||
echo $red"Rust files are not formatted correctly."
|
|
||||||
exit 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
else
|
|
||||||
if set -l -q _flag_all
|
set -l edition_spec string match -r '^edition\s*=.*'
|
||||||
cargo fmt
|
test "$($edition_spec <Cargo.toml)" = "$($edition_spec <.rustfmt.toml)"
|
||||||
|
or die "Cargo.toml and .rustfmt.toml use different editions"
|
||||||
|
|
||||||
|
echo === Running "$green"rustfmt"$normal"
|
||||||
|
if set -l -q _flag_check
|
||||||
|
if test $all = yes
|
||||||
|
cargo fmt --all --check
|
||||||
|
else
|
||||||
|
rustfmt --check --files-with-diff $rust_files
|
||||||
|
end
|
||||||
|
or die "Rust files are not formatted correctly."
|
||||||
else
|
else
|
||||||
if set -q rust_files[1]
|
if test $all = yes
|
||||||
|
cargo fmt --all
|
||||||
|
else
|
||||||
rustfmt $rust_files
|
rustfmt $rust_files
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
22
build_tools/supported_ubuntu_versions.py
Executable file
22
build_tools/supported_ubuntu_versions.py
Executable file
@@ -0,0 +1,22 @@
|
|||||||
|
# /// script
|
||||||
|
# requires-python = ">=3.5"
|
||||||
|
# dependencies = [
|
||||||
|
# "launchpadlib",
|
||||||
|
# ]
|
||||||
|
# ///
|
||||||
|
|
||||||
|
from launchpadlib.launchpad import Launchpad
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
launchpad = Launchpad.login_anonymously(
|
||||||
|
"fish shell build script", "production", "~/.cache", version="devel"
|
||||||
|
)
|
||||||
|
ubu = launchpad.projects("ubuntu")
|
||||||
|
print(
|
||||||
|
"\n".join(
|
||||||
|
x["name"]
|
||||||
|
for x in ubu.series.entries
|
||||||
|
if x["supported"] == True
|
||||||
|
and x["name"] not in ("trusty", "xenial", "bionic", "focal")
|
||||||
|
)
|
||||||
|
)
|
||||||
33
build_tools/update-dependencies.sh
Executable file
33
build_tools/update-dependencies.sh
Executable file
@@ -0,0 +1,33 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
command -v curl
|
||||||
|
command -v gcloud
|
||||||
|
command -v jq
|
||||||
|
command -v rustup
|
||||||
|
command -v updatecli
|
||||||
|
command -v uv
|
||||||
|
sort --version-sort </dev/null
|
||||||
|
|
||||||
|
uv lock --check
|
||||||
|
|
||||||
|
updatecli "${@:-apply}"
|
||||||
|
|
||||||
|
uv lock # Python version constraints may have changed.
|
||||||
|
uv lock --upgrade --exclude-newer="$(date --date='7 days ago' --iso-8601)"
|
||||||
|
|
||||||
|
from_gh() {
|
||||||
|
repo=$1
|
||||||
|
path=$2
|
||||||
|
out_dir=$3
|
||||||
|
contents=$(curl -fsS https://raw.githubusercontent.com/"${repo}"/refs/heads/master/"${path}")
|
||||||
|
printf '%s\n' >"$out_dir/$(basename "$path")" "$contents"
|
||||||
|
}
|
||||||
|
from_gh ridiculousfish/widecharwidth widechar_width.rs crates/widecharwidth/src/
|
||||||
|
from_gh ridiculousfish/littlecheck littlecheck/littlecheck.py tests/
|
||||||
|
|
||||||
|
# Update Cargo.lock
|
||||||
|
cargo update
|
||||||
|
# Update Cargo.toml and Cargo.lock
|
||||||
|
cargo +nightly -Zunstable-options update --breaking
|
||||||
@@ -9,33 +9,32 @@
|
|||||||
# For developers:
|
# For developers:
|
||||||
# - Run with no args to update all PO files after making changes to Rust/fish sources.
|
# - Run with no args to update all PO files after making changes to Rust/fish sources.
|
||||||
# For translators:
|
# For translators:
|
||||||
# - Specify the language you want to work on as an argument, which must be a file in the po/
|
# - Specify the language you want to work on as an argument, which must be a file in the
|
||||||
# directory. You can specify a language which does not have translations yet by specifying the
|
# localization/po/ directory. You can specify a language which does not have translations
|
||||||
# name of a file which does not yet exist. Make sure to follow the naming convention.
|
# yet by specifying the name of a file which does not yet exist.
|
||||||
|
# Make sure to follow the naming convention.
|
||||||
# For testing:
|
# For testing:
|
||||||
# - Specify `--dry-run` to see if any updates to the PO files would by applied by this script.
|
# - Specify `--dry-run` to see if any updates to the PO files would by applied by this script.
|
||||||
# If this flag is specified, the script will exit with an error if there are outstanding
|
# If this flag is specified, the script will exit with an error if there are outstanding
|
||||||
# changes, and will display the diff. Do not specify other flags if `--dry-run` is specified.
|
# changes, and will display the diff. Do not specify other flags if `--dry-run` is specified.
|
||||||
#
|
#
|
||||||
# Specify `--use-existing-template=FILE` to prevent running cargo for extracting an up-to-date
|
# Specify `--use-existing-template=DIR` to prevent running cargo for extracting an up-to-date
|
||||||
# version of the localized strings. This flag is intended for testing setups which make it
|
# version of the localized strings. This flag is intended for testing setups which make it
|
||||||
# inconvenient to run cargo here, but run it in an earlier step to ensure up-to-date values.
|
# inconvenient to run cargo here, but run it in an earlier step to ensure up-to-date values.
|
||||||
# This argument is passed on to the `fish_xgettext.fish` script and has no other uses.
|
# This argument is passed on to the `fish_xgettext.fish` script and has no other uses.
|
||||||
# `FILE` must be the path to a gettext template file generated from our compilation process.
|
# `DIR` must be the path to a gettext template file generated from our compilation process.
|
||||||
# It can be obtained by running:
|
# It can be obtained by running:
|
||||||
# set -l FILE (mktemp)
|
# set -l DIR (mktemp -d)
|
||||||
# FISH_GETTEXT_EXTRACTION_FILE=$FILE cargo check --features=gettext-extract
|
# FISH_GETTEXT_EXTRACTION_DIR=$DIR cargo check --features=gettext-extract
|
||||||
|
|
||||||
# The sort utility is locale-sensitive.
|
# The sort utility is locale-sensitive.
|
||||||
# Ensure that sorting output is consistent by setting LC_ALL here.
|
# Ensure that sorting output is consistent by setting LC_ALL here.
|
||||||
set -gx LC_ALL C.UTF-8
|
set -gx LC_ALL C.UTF-8
|
||||||
|
|
||||||
set -l build_tools (status dirname)
|
set -l build_tools (status dirname)
|
||||||
set -g tmpdir
|
set -l po_dir $build_tools/../localization/po
|
||||||
set -l po_dir $build_tools/../po
|
|
||||||
|
|
||||||
set -l extract
|
set -l extract
|
||||||
set -l po
|
|
||||||
|
|
||||||
argparse dry-run use-existing-template= -- $argv
|
argparse dry-run use-existing-template= -- $argv
|
||||||
or exit $status
|
or exit $status
|
||||||
@@ -46,8 +45,8 @@ if test -z $argv[1]
|
|||||||
else
|
else
|
||||||
set -l po_dir_id (stat --format='%d:%i' -- $po_dir)
|
set -l po_dir_id (stat --format='%d:%i' -- $po_dir)
|
||||||
for arg in $argv
|
for arg in $argv
|
||||||
set -l arg_dir_id (stat --format='%d:%i' -- (dirname $arg))
|
set -l arg_dir_id (stat --format='%d:%i' -- (dirname $arg) 2>/dev/null)
|
||||||
if test $po_dir_id != $arg_dir_id
|
if test $po_dir_id != "$arg_dir_id"
|
||||||
echo "Argument $arg is not a file in the directory $(realpath $po_dir)."
|
echo "Argument $arg is not a file in the directory $(realpath $po_dir)."
|
||||||
echo "Non-option arguments must specify paths to files in this directory."
|
echo "Non-option arguments must specify paths to files in this directory."
|
||||||
echo ""
|
echo ""
|
||||||
@@ -91,33 +90,65 @@ if set -l --query extract
|
|||||||
end
|
end
|
||||||
|
|
||||||
if set -l --query _flag_dry_run
|
if set -l --query _flag_dry_run
|
||||||
# On a dry run, we do not modify po/ but write to a temporary directory instead and check if
|
# On a dry run, we do not modify localization/po/ but write to a temporary directory instead
|
||||||
# there is a difference between po/ and the tmpdir after re-generating the PO files.
|
# and check if there is a difference between localization/po/ and the tmpdir after re-generating
|
||||||
|
# the PO files.
|
||||||
set -g tmpdir (mktemp -d)
|
set -g tmpdir (mktemp -d)
|
||||||
|
|
||||||
# Ensure tmpdir has the same initial state as the po dir.
|
# Ensure tmpdir has the same initial state as the po dir.
|
||||||
cp -r $po_dir/* $tmpdir
|
cp -r $po_dir/* $tmpdir
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# This is used to identify lines which should be set here via $header_lines.
|
||||||
|
# Make sure that this prefix does not appear elsewhere in the file and only contains characters
|
||||||
|
# without special meaning in a sed pattern.
|
||||||
|
set -g header_prefix "# fish-note-sections: "
|
||||||
|
|
||||||
|
function print_header
|
||||||
|
set -l header_lines \
|
||||||
|
"Translations are divided into sections, each starting with a fish-section-* pseudo-message." \
|
||||||
|
"The first few sections are more important." \
|
||||||
|
"Ignore the tier3 sections unless you have a lot of time."
|
||||||
|
for line in $header_lines
|
||||||
|
printf '%s%s\n' $header_prefix $line
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function merge_po_files --argument-names template_file po_file
|
||||||
|
msgmerge --no-wrap --update --no-fuzzy-matching --backup=none --quiet \
|
||||||
|
$po_file $template_file
|
||||||
|
or cleanup_exit
|
||||||
|
set -l new_po_file (mktemp) # TODO Remove on failure.
|
||||||
|
# Remove obsolete messages instead of keeping them as #~ entries.
|
||||||
|
and msgattrib --no-wrap --no-obsolete -o $new_po_file $po_file
|
||||||
|
or cleanup_exit
|
||||||
|
|
||||||
|
begin
|
||||||
|
print_header
|
||||||
|
# Paste PO file without old header lines.
|
||||||
|
sed '/^'$header_prefix'/d' $new_po_file
|
||||||
|
end >$po_file
|
||||||
|
rm $new_po_file
|
||||||
|
end
|
||||||
|
|
||||||
for po_file in $po_files
|
for po_file in $po_files
|
||||||
if set --query tmpdir[1]
|
if set --query tmpdir[1]
|
||||||
set po_file $tmpdir/(basename $po_file)
|
set po_file $tmpdir/(basename $po_file)
|
||||||
end
|
end
|
||||||
if set -l --query po
|
if test -e $po_file
|
||||||
if test -e $po_file
|
merge_po_files $template_file $po_file
|
||||||
msgmerge --no-wrap --update --no-fuzzy-matching --backup=none --quiet $po_file $template_file
|
else
|
||||||
and msgattrib --no-wrap --no-obsolete -o $po_file $po_file
|
begin
|
||||||
or cleanup_exit
|
print_header
|
||||||
else
|
cat $template_file
|
||||||
cp $template_file $po_file
|
end >$po_file
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if set -g --query tmpdir[1]
|
if set -g --query tmpdir[1]
|
||||||
diff -ur $po_dir $tmpdir
|
diff -ur $po_dir $tmpdir
|
||||||
or begin
|
or begin
|
||||||
echo ERROR: translations in ./po/ are stale. Try running build_tools/update_translations.fish
|
echo ERROR: translations in localization/po/ are stale. Try running build_tools/update_translations.fish
|
||||||
cleanup_exit
|
cleanup_exit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
16
build_tools/version-available-in-debian.sh
Executable file
16
build_tools/version-available-in-debian.sh
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
channel=$1 # e.g. stable, testing
|
||||||
|
package=$2 # e.g. rustc, sphinx
|
||||||
|
|
||||||
|
codename=$(
|
||||||
|
curl -fsS https://ftp.debian.org/debian/dists/"${channel}"/Release |
|
||||||
|
grep '^Codename:' | cut -d' ' -f2)
|
||||||
|
curl -fsS https://sources.debian.org/api/src/"${package}"/ |
|
||||||
|
jq -r --arg codename "${codename}" '
|
||||||
|
.versions[] | select(.suites[] == $codename) | .version' |
|
||||||
|
sed 's/^\([0-9]\+\.[0-9]\+\).*/\1/' |
|
||||||
|
sort --version-sort |
|
||||||
|
tail -1
|
||||||
@@ -12,11 +12,21 @@ set(SPHINX_BUILD_DIR "${SPHINX_ROOT_DIR}/build")
|
|||||||
set(SPHINX_HTML_DIR "${SPHINX_ROOT_DIR}/html")
|
set(SPHINX_HTML_DIR "${SPHINX_ROOT_DIR}/html")
|
||||||
set(SPHINX_MANPAGE_DIR "${SPHINX_ROOT_DIR}/man")
|
set(SPHINX_MANPAGE_DIR "${SPHINX_ROOT_DIR}/man")
|
||||||
|
|
||||||
# sphinx-docs uses fish_indent for highlighting.
|
set(FISH_INDENT_FOR_BUILDING_DOCS "" CACHE FILEPATH "Path to fish_indent executable for building HTML docs")
|
||||||
# Prepend the output dir of fish_indent to PATH.
|
|
||||||
|
if(FISH_INDENT_FOR_BUILDING_DOCS)
|
||||||
|
get_filename_component(FISH_INDENT_DIR "${FISH_INDENT_FOR_BUILDING_DOCS}" DIRECTORY)
|
||||||
|
set(SPHINX_HTML_FISH_INDENT_PATH ${FISH_INDENT_DIR})
|
||||||
|
set(SPHINX_HTML_FISH_INDENT_DEP)
|
||||||
|
else()
|
||||||
|
set(SPHINX_HTML_FISH_INDENT_PATH ${CMAKE_BINARY_DIR})
|
||||||
|
set(SPHINX_HTML_FISH_INDENT_DEP fish_indent)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_custom_target(sphinx-docs
|
add_custom_target(sphinx-docs
|
||||||
mkdir -p ${SPHINX_HTML_DIR}/_static/
|
mkdir -p ${SPHINX_HTML_DIR}/_static/
|
||||||
COMMAND env PATH="${CMAKE_BINARY_DIR}:$$PATH"
|
COMMAND env FISH_BUILD_VERSION_FILE=${CMAKE_CURRENT_BINARY_DIR}/${FBVF}
|
||||||
|
PATH="${SPHINX_HTML_FISH_INDENT_PATH}:$$PATH"
|
||||||
${SPHINX_EXECUTABLE}
|
${SPHINX_EXECUTABLE}
|
||||||
-j auto
|
-j auto
|
||||||
-q -b html
|
-q -b html
|
||||||
@@ -24,10 +34,12 @@ add_custom_target(sphinx-docs
|
|||||||
-d "${SPHINX_ROOT_DIR}/.doctrees-html"
|
-d "${SPHINX_ROOT_DIR}/.doctrees-html"
|
||||||
"${SPHINX_SRC_DIR}"
|
"${SPHINX_SRC_DIR}"
|
||||||
"${SPHINX_HTML_DIR}"
|
"${SPHINX_HTML_DIR}"
|
||||||
DEPENDS ${SPHINX_SRC_DIR}/fish_indent_lexer.py fish_indent
|
DEPENDS
|
||||||
|
CHECK-FISH-BUILD-VERSION-FILE
|
||||||
|
${SPHINX_SRC_DIR}/fish_indent_lexer.py
|
||||||
|
${SPHINX_HTML_FISH_INDENT_DEP}
|
||||||
COMMENT "Building HTML documentation with Sphinx")
|
COMMENT "Building HTML documentation with Sphinx")
|
||||||
|
|
||||||
# sphinx-manpages needs the fish_indent binary for the version number
|
|
||||||
add_custom_target(sphinx-manpages
|
add_custom_target(sphinx-manpages
|
||||||
env FISH_BUILD_VERSION_FILE=${CMAKE_CURRENT_BINARY_DIR}/${FBVF}
|
env FISH_BUILD_VERSION_FILE=${CMAKE_CURRENT_BINARY_DIR}/${FBVF}
|
||||||
${SPHINX_EXECUTABLE}
|
${SPHINX_EXECUTABLE}
|
||||||
@@ -36,51 +48,36 @@ add_custom_target(sphinx-manpages
|
|||||||
-c "${SPHINX_SRC_DIR}"
|
-c "${SPHINX_SRC_DIR}"
|
||||||
-d "${SPHINX_ROOT_DIR}/.doctrees-man"
|
-d "${SPHINX_ROOT_DIR}/.doctrees-man"
|
||||||
"${SPHINX_SRC_DIR}"
|
"${SPHINX_SRC_DIR}"
|
||||||
# TODO: This only works if we only have section 1 manpages.
|
|
||||||
"${SPHINX_MANPAGE_DIR}/man1"
|
"${SPHINX_MANPAGE_DIR}/man1"
|
||||||
DEPENDS CHECK-FISH-BUILD-VERSION-FILE
|
DEPENDS CHECK-FISH-BUILD-VERSION-FILE
|
||||||
COMMENT "Building man pages with Sphinx")
|
COMMENT "Building man pages with Sphinx")
|
||||||
|
|
||||||
if(SPHINX_EXECUTABLE)
|
if(NOT DEFINED WITH_DOCS) # Don't check for legacy options if the new one is defined, to help bisecting.
|
||||||
option(BUILD_DOCS "build documentation (requires Sphinx)" ON)
|
if(DEFINED BUILD_DOCS)
|
||||||
else(SPHINX_EXECUTABLE)
|
message(FATAL_ERROR "the BUILD_DOCS option is no longer supported, use -DWITH_DOCS=ON|OFF")
|
||||||
option(BUILD_DOCS "build documentation (requires Sphinx)" OFF)
|
endif()
|
||||||
endif(SPHINX_EXECUTABLE)
|
if(DEFINED INSTALL_DOCS)
|
||||||
|
message(FATAL_ERROR "the INSTALL_DOCS option is no longer supported, use -DWITH_DOCS=ON|OFF")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
if(BUILD_DOCS AND NOT SPHINX_EXECUTABLE)
|
if(SPHINX_EXECUTABLE)
|
||||||
|
option(WITH_DOCS "build documentation (requires Sphinx)" ON)
|
||||||
|
else()
|
||||||
|
option(WITH_DOCS "build documentation (requires Sphinx)" OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_DOCS AND NOT SPHINX_EXECUTABLE)
|
||||||
message(FATAL_ERROR "build documentation selected, but sphinx-build could not be found")
|
message(FATAL_ERROR "build documentation selected, but sphinx-build could not be found")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/user_doc/html
|
add_feature_info(Documentation WITH_DOCS "user manual and documentation")
|
||||||
AND IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/user_doc/man)
|
|
||||||
set(HAVE_PREBUILT_DOCS TRUE)
|
|
||||||
else()
|
|
||||||
set(HAVE_PREBUILT_DOCS FALSE)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(BUILD_DOCS OR HAVE_PREBUILT_DOCS)
|
if(WITH_DOCS)
|
||||||
set(INSTALL_DOCS ON)
|
|
||||||
else()
|
|
||||||
set(INSTALL_DOCS OFF)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_feature_info(Documentation INSTALL_DOCS "user manual and documentation")
|
|
||||||
|
|
||||||
if(BUILD_DOCS)
|
|
||||||
configure_file("${SPHINX_SRC_DIR}/conf.py" "${SPHINX_BUILD_DIR}/conf.py" @ONLY)
|
configure_file("${SPHINX_SRC_DIR}/conf.py" "${SPHINX_BUILD_DIR}/conf.py" @ONLY)
|
||||||
add_custom_target(doc ALL
|
add_custom_target(doc ALL
|
||||||
DEPENDS sphinx-docs sphinx-manpages)
|
DEPENDS sphinx-docs sphinx-manpages)
|
||||||
|
|
||||||
# Group docs targets into a DocsTargets folder
|
# Group docs targets into a DocsTargets folder
|
||||||
set_property(TARGET doc sphinx-docs sphinx-manpages
|
set_property(TARGET doc sphinx-docs sphinx-manpages
|
||||||
PROPERTY FOLDER cmake/DocTargets)
|
PROPERTY FOLDER cmake/DocTargets)
|
||||||
|
endif()
|
||||||
elseif(HAVE_PREBUILT_DOCS)
|
|
||||||
if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)
|
|
||||||
# Out of tree build - link the prebuilt documentation to the build tree
|
|
||||||
add_custom_target(link_doc ALL)
|
|
||||||
add_custom_command(TARGET link_doc
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/user_doc ${CMAKE_CURRENT_BINARY_DIR}/user_doc
|
|
||||||
POST_BUILD)
|
|
||||||
endif()
|
|
||||||
endif(BUILD_DOCS)
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
set(CMAKE_INSTALL_MESSAGE NEVER)
|
set(CMAKE_INSTALL_MESSAGE NEVER)
|
||||||
|
|
||||||
set(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fish ${CMAKE_CURRENT_BINARY_DIR}/fish_indent ${CMAKE_CURRENT_BINARY_DIR}/fish_key_reader)
|
|
||||||
|
|
||||||
set(prefix ${CMAKE_INSTALL_PREFIX})
|
set(prefix ${CMAKE_INSTALL_PREFIX})
|
||||||
set(bindir ${CMAKE_INSTALL_BINDIR})
|
set(bindir ${CMAKE_INSTALL_BINDIR})
|
||||||
set(sysconfdir ${CMAKE_INSTALL_SYSCONFDIR})
|
set(sysconfdir ${CMAKE_INSTALL_SYSCONFDIR})
|
||||||
@@ -75,22 +73,30 @@ function(FISH_TRY_CREATE_DIRS)
|
|||||||
endforeach()
|
endforeach()
|
||||||
endfunction(FISH_TRY_CREATE_DIRS)
|
endfunction(FISH_TRY_CREATE_DIRS)
|
||||||
|
|
||||||
install(PROGRAMS ${PROGRAMS}
|
install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fish
|
||||||
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ
|
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ
|
||||||
GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
|
GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
|
||||||
DESTINATION ${bindir})
|
DESTINATION ${bindir})
|
||||||
|
|
||||||
|
if(NOT IS_ABSOLUTE ${bindir})
|
||||||
|
set(abs_bindir "\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${bindir}")
|
||||||
|
else()
|
||||||
|
set(abs_bindir "\$ENV{DESTDIR}${bindir}")
|
||||||
|
endif()
|
||||||
|
install(CODE "file(CREATE_LINK ${abs_bindir}/fish ${abs_bindir}/fish_indent)")
|
||||||
|
install(CODE "file(CREATE_LINK ${abs_bindir}/fish ${abs_bindir}/fish_key_reader)")
|
||||||
|
|
||||||
fish_create_dirs(${sysconfdir}/fish/conf.d ${sysconfdir}/fish/completions
|
fish_create_dirs(${sysconfdir}/fish/conf.d ${sysconfdir}/fish/completions
|
||||||
${sysconfdir}/fish/functions)
|
${sysconfdir}/fish/functions)
|
||||||
install(FILES etc/config.fish DESTINATION ${sysconfdir}/fish/)
|
install(FILES etc/config.fish DESTINATION ${sysconfdir}/fish/)
|
||||||
|
|
||||||
fish_create_dirs(${rel_datadir}/fish ${rel_datadir}/fish/completions
|
fish_create_dirs(${rel_datadir}/fish ${rel_datadir}/fish/completions
|
||||||
${rel_datadir}/fish/functions ${rel_datadir}/fish/groff
|
${rel_datadir}/fish/functions
|
||||||
${rel_datadir}/fish/man/man1 ${rel_datadir}/fish/tools
|
${rel_datadir}/fish/man/man1 ${rel_datadir}/fish/tools
|
||||||
${rel_datadir}/fish/tools/web_config
|
${rel_datadir}/fish/tools/web_config
|
||||||
${rel_datadir}/fish/tools/web_config/js
|
${rel_datadir}/fish/tools/web_config/js
|
||||||
${rel_datadir}/fish/tools/web_config/sample_prompts
|
${rel_datadir}/fish/prompts
|
||||||
${rel_datadir}/fish/tools/web_config/themes
|
${rel_datadir}/fish/themes
|
||||||
)
|
)
|
||||||
|
|
||||||
configure_file(share/__fish_build_paths.fish.in share/__fish_build_paths.fish)
|
configure_file(share/__fish_build_paths.fish.in share/__fish_build_paths.fish)
|
||||||
@@ -125,9 +131,6 @@ install(DIRECTORY share/functions/
|
|||||||
DESTINATION ${rel_datadir}/fish/functions
|
DESTINATION ${rel_datadir}/fish/functions
|
||||||
FILES_MATCHING PATTERN "*.fish")
|
FILES_MATCHING PATTERN "*.fish")
|
||||||
|
|
||||||
install(DIRECTORY share/groff
|
|
||||||
DESTINATION ${rel_datadir}/fish)
|
|
||||||
|
|
||||||
# CONDEMNED_PAGE is managed by the conditional above
|
# CONDEMNED_PAGE is managed by the conditional above
|
||||||
# Building the man pages is optional: if sphinx isn't installed, they're not built
|
# Building the man pages is optional: if sphinx isn't installed, they're not built
|
||||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/user_doc/man/man1/
|
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/user_doc/man/man1/
|
||||||
@@ -136,7 +139,7 @@ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/user_doc/man/man1/
|
|||||||
PATTERN "*.1"
|
PATTERN "*.1"
|
||||||
PATTERN ${CONDEMNED_PAGE} EXCLUDE)
|
PATTERN ${CONDEMNED_PAGE} EXCLUDE)
|
||||||
|
|
||||||
install(PROGRAMS share/tools/create_manpage_completions.py share/tools/deroff.py
|
install(PROGRAMS share/tools/create_manpage_completions.py
|
||||||
DESTINATION ${rel_datadir}/fish/tools/)
|
DESTINATION ${rel_datadir}/fish/tools/)
|
||||||
|
|
||||||
install(DIRECTORY share/tools/web_config
|
install(DIRECTORY share/tools/web_config
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(rust_profile $<IF:$<CONFIG:Debug>,debug,$<IF:$<CONFIG:RelWithDebInfo>,release-with-debug,release>>)
|
set(rust_profile $<IF:$<CONFIG:Debug>,debug,$<IF:$<CONFIG:RelWithDebInfo>,release-with-debug,release>>)
|
||||||
set(rust_debugflags "$<$<CONFIG:Debug>:-g>$<$<CONFIG:RelWithDebInfo>:-g>")
|
|
||||||
|
|
||||||
option(WITH_GETTEXT "Build with gettext localization support. Requires `msgfmt` to work." ON)
|
option(WITH_GETTEXT "Build with gettext localization support. Requires `msgfmt` to work." ON)
|
||||||
# Enable gettext feature unless explicitly disabled.
|
# Enable gettext feature unless explicitly disabled.
|
||||||
@@ -28,19 +27,3 @@ if(NOT DEFINED WITH_GETTEXT OR "${WITH_GETTEXT}")
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
list(JOIN FISH_CARGO_FEATURES_LIST , FISH_CARGO_FEATURES)
|
list(JOIN FISH_CARGO_FEATURES_LIST , FISH_CARGO_FEATURES)
|
||||||
|
|
||||||
# Tell Cargo where our build directory is so it can find Cargo.toml.
|
|
||||||
set(VARS_FOR_CARGO
|
|
||||||
"FISH_BUILD_DIR=${CMAKE_BINARY_DIR}"
|
|
||||||
"PREFIX=${CMAKE_INSTALL_PREFIX}"
|
|
||||||
# Cheesy so we can tell cmake was used to build
|
|
||||||
"CMAKE=1"
|
|
||||||
"DOCDIR=${CMAKE_INSTALL_FULL_DOCDIR}"
|
|
||||||
"DATADIR=${CMAKE_INSTALL_FULL_DATADIR}"
|
|
||||||
"SYSCONFDIR=${CMAKE_INSTALL_FULL_SYSCONFDIR}"
|
|
||||||
"BINDIR=${CMAKE_INSTALL_FULL_BINDIR}"
|
|
||||||
"CARGO_TARGET_DIR=${FISH_RUST_BUILD_DIR}"
|
|
||||||
"CARGO_BUILD_RUSTC=${Rust_COMPILER}"
|
|
||||||
"${FISH_PCRE2_BUILDFLAG}"
|
|
||||||
"RUSTFLAGS=$ENV{RUSTFLAGS} ${rust_debugflags}"
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -57,7 +57,15 @@ endif()
|
|||||||
add_custom_target(fish_run_tests
|
add_custom_target(fish_run_tests
|
||||||
# TODO: This should be replaced with a unified solution, possibly build_tools/check.sh.
|
# TODO: This should be replaced with a unified solution, possibly build_tools/check.sh.
|
||||||
COMMAND ${CMAKE_SOURCE_DIR}/tests/test_driver.py ${max_concurrency_flag} ${CMAKE_CURRENT_BINARY_DIR}
|
COMMAND ${CMAKE_SOURCE_DIR}/tests/test_driver.py ${max_concurrency_flag} ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
COMMAND env ${VARS_FOR_CARGO} cargo test --no-default-features ${CARGO_FLAGS} --workspace --target-dir ${rust_target_dir} ${cargo_test_flags}
|
COMMAND env ${VARS_FOR_CARGO}
|
||||||
|
${Rust_CARGO}
|
||||||
|
test
|
||||||
|
--no-default-features
|
||||||
|
--features=${FISH_CARGO_FEATURES}
|
||||||
|
${CARGO_FLAGS}
|
||||||
|
--workspace
|
||||||
|
--target-dir ${rust_target_dir}
|
||||||
|
${cargo_test_flags}
|
||||||
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
|
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
|
||||||
DEPENDS fish fish_indent fish_key_reader fish_test_helper
|
DEPENDS fish fish_indent fish_key_reader fish_test_helper
|
||||||
USES_TERMINAL
|
USES_TERMINAL
|
||||||
|
|||||||
480
contrib/debian/changelog
Normal file
480
contrib/debian/changelog
Normal file
@@ -0,0 +1,480 @@
|
|||||||
|
fish (4.3.2-1) stable; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 4.3.2.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/4.3.2 for details.
|
||||||
|
|
||||||
|
-- Johannes Altmanninger <aclopte@gmail.com> Tue, 30 Dec 2025 17:21:04 +0100
|
||||||
|
|
||||||
|
fish (4.3.1-1) stable; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 4.3.1.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/4.3.1 for details.
|
||||||
|
|
||||||
|
-- Johannes Altmanninger <aclopte@gmail.com> Sun, 28 Dec 2025 16:54:44 +0100
|
||||||
|
|
||||||
|
fish (4.3.0-1) stable; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 4.3.0.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/4.3.0 for details.
|
||||||
|
|
||||||
|
-- Johannes Altmanninger <aclopte@gmail.com> Sun, 28 Dec 2025 10:20:47 +0100
|
||||||
|
|
||||||
|
fish (4.2.1-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 4.2.1.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/4.2.1 for details.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Thu, 13 Nov 2025 20:42:43 +0800
|
||||||
|
|
||||||
|
fish (4.2.0-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 4.2.0.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/4.2.0 for details.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Mon, 10 Nov 2025 19:29:03 +0800
|
||||||
|
|
||||||
|
fish (4.1.2-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 4.1.2.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/4.1.2 for details.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Wed, 08 Oct 2025 13:46:45 +0800
|
||||||
|
|
||||||
|
fish (4.1.1-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 4.1.1.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/4.1.1 for details.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Fri, 03 Oct 2025 16:43:43 +0800
|
||||||
|
|
||||||
|
fish (4.0.8-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 4.0.8.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/4.0.8 for details.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Thu, 18 Sep 2025 22:17:43 +0800
|
||||||
|
|
||||||
|
fish (4.0.6-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 4.0.6.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/4.0.6 for details.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Wed, 17 Sep 2025 12:27:09 +0800
|
||||||
|
|
||||||
|
fish (4.0.2-2) testing; urgency=medium
|
||||||
|
|
||||||
|
* Fix tests on Debian.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Sun, 20 Apr 2025 23:08:14 +0800
|
||||||
|
|
||||||
|
fish (4.0.2-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 4.0.2.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/4.0.2 for details.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Sun, 20 Apr 2025 21:24:18 +0800
|
||||||
|
|
||||||
|
fish (4.0.1-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 4.0.1.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Thu, 13 Mar 2025 11:30:21 +0800
|
||||||
|
|
||||||
|
fish (4.0.0-2) testing; urgency=medium
|
||||||
|
|
||||||
|
* Fix tests on Debian.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Thu, 27 Feb 2025 21:50:33 +0800
|
||||||
|
|
||||||
|
fish (4.0.0-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 4.0.0.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/4.0.0 for details.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Thu, 27 Feb 2025 19:22:30 +0800
|
||||||
|
|
||||||
|
fish (4.0.1-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new beta version 4.0b1.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/4.0b1 for details.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Tue, 17 Dec 2024 23:42:25 +0800
|
||||||
|
|
||||||
|
fish (3.7.1-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 3.7.1.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/3.7.1 for details.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Tue, 19 Mar 2024 13:26:22 +0800
|
||||||
|
|
||||||
|
fish (3.7.0-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 3.7.0.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/3.7.0 for details.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Mon, 01 Jan 2024 23:32:55 +0800
|
||||||
|
|
||||||
|
fish (3.6.4-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 3.6.4.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/3.6.4 for details.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Tue, 05 Dec 2023 22:34:09 +0800
|
||||||
|
|
||||||
|
fish (3.6.3-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 3.6.3.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/3.6.3 for details.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Tue, 05 Dec 2023 00:11:12 +0800
|
||||||
|
|
||||||
|
fish (3.6.2-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 3.6.2.
|
||||||
|
* Includes a fix for CVE-2023-49284.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/3.6.2 for details.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Mon, 04 Dec 2023 23:16:42 +0800
|
||||||
|
|
||||||
|
fish (3.6.1-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 3.6.1.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/3.6.1 for
|
||||||
|
significant changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Sat, 25 Mar 2023 17:22:12 +0800
|
||||||
|
|
||||||
|
fish (3.6.0-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 3.6.0.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/3.6.0 for
|
||||||
|
significant changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Sat, 07 Jan 2023 22:41:32 +0800
|
||||||
|
|
||||||
|
fish (3.5.1-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 3.5.1.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/3.5.1 for
|
||||||
|
significant changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Wed, 20 Jul 2022 21:54:09 +0800
|
||||||
|
|
||||||
|
fish (3.5.0-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 3.5.0.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/3.5.0 for
|
||||||
|
significant changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Thu, 16 Jun 2022 19:45:33 +0800
|
||||||
|
|
||||||
|
fish (3.4.0-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 3.4.0.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/3.4.0 for
|
||||||
|
significant changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Sat, 12 Mar 2022 23:24:22 +0800
|
||||||
|
|
||||||
|
fish (3.3.1-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 3.3.1.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/3.3.1 for
|
||||||
|
significant changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Tue, 06 Jul 2021 23:22:36 +0800
|
||||||
|
|
||||||
|
fish (3.3.0-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 3.3.0.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/3.3.0 for
|
||||||
|
significant changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Mon, 28 Jun 2021 23:06:36 +0800
|
||||||
|
|
||||||
|
fish (3.2.2-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 3.2.2.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/3.2.2 for
|
||||||
|
significant changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Wed, 07 Apr 2021 21:10:54 +0800
|
||||||
|
|
||||||
|
fish (3.2.1-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 3.2.1.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/3.2.1 for
|
||||||
|
significant changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Thu, 18 Mar 2021 12:08:13 +0800
|
||||||
|
|
||||||
|
fish (3.2.0-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 3.2.0.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/3.2.0 for
|
||||||
|
significant changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Mon, 01 Mar 2021 21:22:39 +0800
|
||||||
|
|
||||||
|
fish (3.1.2-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 3.1.2.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/3.1.2 for
|
||||||
|
significant changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Wed, 29 Apr 2020 11:22:35 +0800
|
||||||
|
|
||||||
|
fish (3.1.1-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 3.1.1.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/3.1.1 for
|
||||||
|
significant changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Mon, 27 Apr 2020 22:45:35 +0800
|
||||||
|
|
||||||
|
fish (3.1.0-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 3.1.0.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/3.1.0 for
|
||||||
|
significant changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Wed, 12 Feb 2020 22:34:53 +0800
|
||||||
|
|
||||||
|
fish (3.1.1-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new beta version 3.1b1.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/3.1b1 for
|
||||||
|
significant changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Sun, 26 Jan 2020 21:42:46 +0800
|
||||||
|
|
||||||
|
fish (3.0.2-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 3.0.2.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/3.0.2 for
|
||||||
|
significant changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Tue, 19 Feb 2019 21:45:05 +0800
|
||||||
|
|
||||||
|
fish (3.0.1-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 3.0.1.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/3.0.1 for
|
||||||
|
significant changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Mon, 11 Feb 2019 20:23:55 +0800
|
||||||
|
|
||||||
|
fish (3.0.0-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 3.0.0.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/3.0.0 for
|
||||||
|
significant changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Fri, 28 Dec 2018 21:10:28 +0800
|
||||||
|
|
||||||
|
fish (3.0.1-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new beta version 3.0b1.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/3.0b1 for
|
||||||
|
significant changes, which includes backward incompatibility.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Tue, 11 Dec 2018 22:59:15 +0800
|
||||||
|
|
||||||
|
fish (2.7.1-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new bug fix version 2.7.1. On all Linux platforms, this is
|
||||||
|
release will behave identically to 2.7.0.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Sat, 23 Dec 2017 00:43:12 +0800
|
||||||
|
|
||||||
|
fish (2.7.0-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 2.7.0.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/2.7.0 for
|
||||||
|
significant changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Thu, 23 Nov 2017 18:38:21 +0800
|
||||||
|
|
||||||
|
fish (2.7.1-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new beta version 2.7b1.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/2.7b1 for
|
||||||
|
significant changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Tue, 31 Oct 2017 20:32:29 +0800
|
||||||
|
|
||||||
|
fish (2.6.0-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Relase of new version 2.6.0.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/2.6.0 for
|
||||||
|
significant changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Sat, 03 Jun 2017 20:51:50 +0800
|
||||||
|
|
||||||
|
fish (2.6b1-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new beta version 2.6b1.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/2.6b1 for
|
||||||
|
significant changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Sun, 14 May 2017 10:47:39 +0800
|
||||||
|
|
||||||
|
fish (2.5.0-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 2.5.0.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/2.5.0 for
|
||||||
|
significant changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Fri, 03 Feb 2017 09:52:57 +0800
|
||||||
|
|
||||||
|
fish (2.5b1-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new beta version 2.5b1.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/2.5b1 for
|
||||||
|
significant changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Sat, 14 Jan 2017 08:49:34 +0800
|
||||||
|
|
||||||
|
fish (2.4.0-2) testing; urgency=medium
|
||||||
|
|
||||||
|
* Change recommendation of xdg-utils to suggestion (closes
|
||||||
|
https://github.com/fish-shell/fish-shell/issues/3534).
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Wed, 09 Nov 2016 22:56:16 +0800
|
||||||
|
|
||||||
|
fish (2.4.0-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 2.4.0.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/2.4.0 for
|
||||||
|
significant changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Tue, 08 Nov 2016 11:29:57 +0800
|
||||||
|
|
||||||
|
fish (2.4b1-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new beta version 2.4b1.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/2.4b1 for
|
||||||
|
significant changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Tue, 18 Oct 2016 22:25:26 +0800
|
||||||
|
|
||||||
|
fish (2.3.1-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 2.3.1.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Sun, 03 Jul 2016 21:21:51 +0800
|
||||||
|
|
||||||
|
fish (2.3.0-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 2.3.0.
|
||||||
|
|
||||||
|
See http://fishshell.com/release_notes.html for significant changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Sat, 21 May 2016 06:59:54 +0800
|
||||||
|
|
||||||
|
fish (2.3b2-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new beta version 2.3b2.
|
||||||
|
|
||||||
|
See https://github.com/fish-shell/fish-shell/releases/tag/2.3b2 for
|
||||||
|
significant changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Thu, 05 May 2016 06:22:37 +0800
|
||||||
|
|
||||||
|
fish (2.3.1-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new beta version 2.3b1.
|
||||||
|
|
||||||
|
See http://github.com/fish-shell/fish-shell/releases/tag/2.3b1 for
|
||||||
|
significant changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Tue, 19 Apr 2016 21:07:17 +0800
|
||||||
|
|
||||||
|
fish (2.2.0-2) testing; urgency=medium
|
||||||
|
|
||||||
|
* Binary rebuild only to resynchronise repository state.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Mon, 15 Feb 2016 22:45:05 +0800
|
||||||
|
|
||||||
|
fish (2.2.0-1) testing; urgency=medium
|
||||||
|
|
||||||
|
* Release of new version 2.2.0.
|
||||||
|
|
||||||
|
See http://fishshell.com/release_notes.html for significant changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Sun, 12 Jul 2015 18:52:29 +0800
|
||||||
|
|
||||||
|
fish (2.2b1-1) testing; urgency=low
|
||||||
|
|
||||||
|
* Release of new beta version 2.2b1.
|
||||||
|
|
||||||
|
See http://fishshell.com/staging/release_notes.html for significant
|
||||||
|
changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Thu, 07 May 2015 14:48:21 +0800
|
||||||
|
|
||||||
|
fish (2.1.1-1) unstable; urgency=high
|
||||||
|
|
||||||
|
* Release of new version 2.1.1.
|
||||||
|
|
||||||
|
See http://fishshell.com/release_notes.html for significant changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Sun, 07 Sep 2014 17:06:31 +0800
|
||||||
|
|
||||||
|
fish (2.1.0-1) unstable; urgency=low
|
||||||
|
|
||||||
|
* Release of new version 2.1.0.
|
||||||
|
|
||||||
|
See http://fishshell.com/staging/release_notes.html for significant
|
||||||
|
changes.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Sat, 19 Oct 2013 14:35:23 +0800
|
||||||
|
|
||||||
|
fish (2.0.0-0) unstable; urgency=low
|
||||||
|
|
||||||
|
* Initial release of fish 2.0.0.
|
||||||
|
|
||||||
|
-- David Adam <zanchey@ucc.gu.uwa.edu.au> Thu, 19 Jul 2012 23:17:58 +0800
|
||||||
@@ -3,32 +3,31 @@ Section: shells
|
|||||||
Priority: optional
|
Priority: optional
|
||||||
Maintainer: ridiculous_fish <corydoras@ridiculousfish.com>
|
Maintainer: ridiculous_fish <corydoras@ridiculousfish.com>
|
||||||
Uploaders: David Adam <zanchey@ucc.gu.uwa.edu.au>
|
Uploaders: David Adam <zanchey@ucc.gu.uwa.edu.au>
|
||||||
Build-Depends: debhelper (>= 12),
|
Build-Depends: debhelper-compat (= 13),
|
||||||
cargo (>= 0.66) | cargo-mozilla (>= 0.66),
|
# -web is for Debian's updated version, -X.Y is for Ubuntu's backported versions
|
||||||
cmake (>= 3.15.0) | cmake-mozilla (>= 3.15.0),
|
cargo (>= 1.85) | cargo-web (>= 1.85) | cargo-1.85,
|
||||||
|
cmake (>= 3.15.0),
|
||||||
gettext,
|
gettext,
|
||||||
libpcre2-dev,
|
libpcre2-dev,
|
||||||
rustc (>= 1.70),
|
rustc (>= 1.85) | rustc-web (>= 1.85) | rustc-1.85,
|
||||||
|
sphinx-doc,
|
||||||
# Test dependencies
|
# Test dependencies
|
||||||
locales-all,
|
locales-all,
|
||||||
ncurses-base,
|
man-db,
|
||||||
python3
|
python3
|
||||||
Standards-Version: 4.1.5
|
# 4.6.2 is Debian 12/Ubuntu Noble 24.04; Ubuntu Jammy is 4.6.0.1
|
||||||
|
Standards-Version: 4.6.2
|
||||||
Homepage: https://fishshell.com/
|
Homepage: https://fishshell.com/
|
||||||
Vcs-Git: https://github.com/fish-shell/fish-shell.git
|
Vcs-Git: https://github.com/fish-shell/fish-shell.git
|
||||||
Vcs-Browser: https://github.com/fish-shell/fish-shell
|
Vcs-Browser: https://github.com/fish-shell/fish-shell
|
||||||
|
|
||||||
Package: fish
|
Package: fish
|
||||||
Architecture: any
|
Architecture: any
|
||||||
# for col and lock - bsdmainutils is required in Ubuntu focal
|
# for col and lock
|
||||||
Depends: bsdextrautils | bsdmainutils,
|
Depends: bsdextrautils,
|
||||||
file,
|
file,
|
||||||
# for the msgfmt command
|
|
||||||
gettext-base,
|
|
||||||
# for man
|
# for man
|
||||||
man-db,
|
man-db,
|
||||||
# for terminal definitions
|
|
||||||
ncurses-base,
|
|
||||||
# for kill
|
# for kill
|
||||||
procps,
|
procps,
|
||||||
python3 (>=3.5),
|
python3 (>=3.5),
|
||||||
@@ -17,11 +17,11 @@ Files: share/tools/web_config/js/alpine.js
|
|||||||
Copyright: 2019-2021 Caleb Porzio and contributors
|
Copyright: 2019-2021 Caleb Porzio and contributors
|
||||||
License: MIT
|
License: MIT
|
||||||
|
|
||||||
Files: share/tools/web_config/themes/Dracula.theme
|
Files: share/themes/Dracula.theme
|
||||||
Copyright: 2018 Dracula Team
|
Copyright: 2018 Dracula Team
|
||||||
License: MIT
|
License: MIT
|
||||||
|
|
||||||
Files: share/tools/web_config/themes/Nord.theme
|
Files: share/themes/Nord.theme
|
||||||
Copyright: 2016-2024 Sven Greb
|
Copyright: 2016-2024 Sven Greb
|
||||||
License: MIT
|
License: MIT
|
||||||
|
|
||||||
@@ -1,20 +1,25 @@
|
|||||||
#!/usr/bin/make -f
|
#!/usr/bin/make -f
|
||||||
# -*- makefile -*-
|
# -*- makefile -*-
|
||||||
|
|
||||||
# Uncomment this to turn on verbose mode.
|
ifeq (,$(filter terse,$(DEB_BUILD_OPTIONS)))
|
||||||
export DH_VERBOSE=1
|
export DH_VERBOSE=1
|
||||||
|
# VERBOSE to satisfy Debian policy 4.9, introduced in version 4.2.0
|
||||||
|
export CARGO_TERM_VERBOSE=true
|
||||||
|
endif
|
||||||
# The LTO profile sets CFLAGS/CXXFLAGS which confuse the compilation process; disable it
|
# The LTO profile sets CFLAGS/CXXFLAGS which confuse the compilation process; disable it
|
||||||
# LTO is still performed by rustc based on Cargo.toml
|
# LTO is still performed by rustc based on Cargo.toml
|
||||||
export DEB_BUILD_MAINT_OPTIONS=optimize=-lto
|
export DEB_BUILD_MAINT_OPTIONS=optimize=-lto
|
||||||
|
|
||||||
%:
|
%:
|
||||||
dh $@
|
dh $@ --buildsystem=cmake --builddirectory=build
|
||||||
|
|
||||||
# Setting the build system is still required, because otherwise the GNUmakefile gets picked up
|
# Setting the build system is still required, because otherwise the GNUmakefile gets picked up
|
||||||
override_dh_auto_configure:
|
override_dh_auto_configure:
|
||||||
ln -s cargo-vendor/vendor vendor
|
ln -s cargo-vendor/vendor vendor
|
||||||
ln -s cargo-vendor/.cargo .cargo
|
ln -s cargo-vendor/.cargo .cargo
|
||||||
dh_auto_configure --buildsystem=cmake -- -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
dh_auto_configure -- -DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||||
|
-DRust_CARGO=$$(command -v cargo-1.85 || command -v cargo) \
|
||||||
|
-DRust_COMPILER=$$(command -v rustc-1.85 || command -v rustc)
|
||||||
|
|
||||||
override_dh_clean:
|
override_dh_clean:
|
||||||
dh_clean --exclude=Cargo.toml.orig
|
dh_clean --exclude=Cargo.toml.orig
|
||||||
@@ -22,4 +27,4 @@ override_dh_clean:
|
|||||||
-unlink vendor
|
-unlink vendor
|
||||||
|
|
||||||
override_dh_auto_test:
|
override_dh_auto_test:
|
||||||
make fish_run_tests
|
cd build && make fish_run_tests
|
||||||
@@ -4,6 +4,7 @@ edition.workspace = true
|
|||||||
rust-version.workspace = true
|
rust-version.workspace = true
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
repository.workspace = true
|
repository.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rsconf.workspace = true
|
rsconf.workspace = true
|
||||||
|
|||||||
@@ -1,4 +1,21 @@
|
|||||||
use std::{borrow::Cow, env, path::Path};
|
use std::{borrow::Cow, env, os::unix::ffi::OsStrExt, path::Path};
|
||||||
|
|
||||||
|
pub fn env_var(name: &str) -> Option<String> {
|
||||||
|
let err = match env::var(name) {
|
||||||
|
Ok(p) => return Some(p),
|
||||||
|
Err(err) => err,
|
||||||
|
};
|
||||||
|
use env::VarError::*;
|
||||||
|
match err {
|
||||||
|
NotPresent => None,
|
||||||
|
NotUnicode(os_string) => {
|
||||||
|
panic!(
|
||||||
|
"Environment variable {name} is not valid Unicode: {:?}",
|
||||||
|
os_string.as_bytes()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn workspace_root() -> &'static Path {
|
pub fn workspace_root() -> &'static Path {
|
||||||
let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
|
let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
|
||||||
@@ -12,8 +29,7 @@ fn cargo_target_dir() -> Cow<'static, Path> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn fish_build_dir() -> Cow<'static, Path> {
|
pub fn fish_build_dir() -> Cow<'static, Path> {
|
||||||
// FISH_BUILD_DIR is set by CMake, if we are using it.
|
option_env!("FISH_CMAKE_BINARY_DIR")
|
||||||
option_env!("FISH_BUILD_DIR")
|
|
||||||
.map(|d| Cow::Borrowed(Path::new(d)))
|
.map(|d| Cow::Borrowed(Path::new(d)))
|
||||||
.unwrap_or(cargo_target_dir())
|
.unwrap_or(cargo_target_dir())
|
||||||
}
|
}
|
||||||
@@ -29,3 +45,41 @@ pub fn rebuild_if_paths_changed<P: AsRef<Path>, I: IntoIterator<Item = P>>(paths
|
|||||||
rsconf::rebuild_if_path_changed(path.as_ref().to_str().unwrap());
|
rsconf::rebuild_if_path_changed(path.as_ref().to_str().unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn rebuild_if_embedded_path_changed<P: AsRef<Path>>(path: P) {
|
||||||
|
// Not necessary in debug builds, where rust-embed reads from the filesystem.
|
||||||
|
if cfg!(any(not(debug_assertions), windows)) {
|
||||||
|
rebuild_if_path_changed(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Target OS for compiling our crates, as opposed to the build script.
|
||||||
|
pub fn target_os() -> String {
|
||||||
|
env_var("CARGO_CFG_TARGET_OS").unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn target_os_is_apple() -> bool {
|
||||||
|
matches!(target_os().as_str(), "ios" | "macos")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Detect if we're being compiled for a BSD-derived OS, allowing targeting code conditionally with
|
||||||
|
/// `#[cfg(bsd)]`.
|
||||||
|
///
|
||||||
|
/// Rust offers fine-grained conditional compilation per-os for the popular operating systems, but
|
||||||
|
/// doesn't necessarily include less-popular forks nor does it group them into families more
|
||||||
|
/// specific than "windows" vs "unix" so we can conditionally compile code for BSD systems.
|
||||||
|
pub fn target_os_is_bsd() -> bool {
|
||||||
|
let target_os = target_os();
|
||||||
|
let is_bsd = target_os.ends_with("bsd") || target_os == "dragonfly";
|
||||||
|
if matches!(
|
||||||
|
target_os.as_str(),
|
||||||
|
"dragonfly" | "freebsd" | "netbsd" | "openbsd"
|
||||||
|
) {
|
||||||
|
assert!(is_bsd, "Target incorrectly detected as not BSD!");
|
||||||
|
}
|
||||||
|
is_bsd
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn target_os_is_cygwin() -> bool {
|
||||||
|
target_os() == "cygwin"
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ edition.workspace = true
|
|||||||
rust-version.workspace = true
|
rust-version.workspace = true
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
repository.workspace = true
|
repository.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
fish-build-helper.workspace = true
|
fish-build-helper.workspace = true
|
||||||
|
|||||||
@@ -1,53 +1,62 @@
|
|||||||
#[cfg(not(clippy))]
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mandir = fish_build_helper::fish_build_dir().join("fish-man");
|
let man_dir = fish_build_helper::fish_build_dir().join("fish-man");
|
||||||
let sec1dir = mandir.join("man1");
|
let sec1_dir = man_dir.join("man1");
|
||||||
// Running `cargo clippy` on a clean build directory panics, because when rust-embed tries to
|
// Running `cargo clippy` on a clean build directory panics, because when rust-embed
|
||||||
// embed a directory which does not exist it will panic.
|
// tries to embed a directory which does not exist it will panic.
|
||||||
let _ = std::fs::create_dir_all(sec1dir.to_str().unwrap());
|
let _ = std::fs::create_dir_all(&sec1_dir);
|
||||||
|
if !cfg!(clippy) {
|
||||||
#[cfg(not(clippy))]
|
build_man(&man_dir, &sec1_dir);
|
||||||
build_man(&mandir);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(clippy))]
|
fn build_man(man_dir: &Path, sec1_dir: &Path) {
|
||||||
fn build_man(man_dir: &Path) {
|
use fish_build_helper::{env_var, workspace_root};
|
||||||
use std::{
|
use std::{
|
||||||
env,
|
ffi::OsStr,
|
||||||
process::{Command, Stdio},
|
process::{Command, Stdio},
|
||||||
};
|
};
|
||||||
|
|
||||||
use fish_build_helper::workspace_root;
|
|
||||||
|
|
||||||
let workspace_root = workspace_root();
|
let workspace_root = workspace_root();
|
||||||
|
let doc_src_dir = workspace_root.join("doc_src");
|
||||||
|
|
||||||
let man_str = man_dir.to_str().unwrap();
|
fish_build_helper::rebuild_if_paths_changed([
|
||||||
|
&workspace_root.join("CHANGELOG.rst"),
|
||||||
|
&workspace_root.join("CONTRIBUTING.rst"),
|
||||||
|
&doc_src_dir,
|
||||||
|
]);
|
||||||
|
|
||||||
let sec1_dir = man_dir.join("man1");
|
let args: &[&OsStr] = {
|
||||||
let sec1_str = sec1_dir.to_str().unwrap();
|
fn as_os_str<S: AsRef<OsStr> + ?Sized>(s: &S) -> &OsStr {
|
||||||
|
s.as_ref()
|
||||||
let docsrc_dir = workspace_root.join("doc_src");
|
}
|
||||||
let docsrc_str = docsrc_dir.to_str().unwrap();
|
macro_rules! as_os_strs {
|
||||||
|
( [ $( $x:expr, )* ] ) => {
|
||||||
let sphinx_doc_sources = [
|
&[
|
||||||
workspace_root.join("CHANGELOG.rst"),
|
$( as_os_str($x), )*
|
||||||
workspace_root.join("CONTRIBUTING.rst"),
|
]
|
||||||
docsrc_dir.clone(),
|
}
|
||||||
];
|
}
|
||||||
fish_build_helper::rebuild_if_paths_changed(sphinx_doc_sources);
|
as_os_strs!([
|
||||||
|
"-j",
|
||||||
let args = &[
|
"auto",
|
||||||
"-j", "auto", "-q", "-b", "man", "-c", docsrc_str,
|
"-q",
|
||||||
// doctree path - put this *above* the man1 dir to exclude it.
|
"-b",
|
||||||
// this is ~6M
|
"man",
|
||||||
"-d", man_str, docsrc_str, sec1_str,
|
"-c",
|
||||||
];
|
&doc_src_dir,
|
||||||
let _ = std::fs::create_dir_all(sec1_str);
|
// doctree path - put this *above* the man1 dir to exclude it.
|
||||||
|
// this is ~6M
|
||||||
|
"-d",
|
||||||
|
&man_dir,
|
||||||
|
&doc_src_dir,
|
||||||
|
&sec1_dir,
|
||||||
|
])
|
||||||
|
};
|
||||||
|
|
||||||
rsconf::rebuild_if_env_changed("FISH_BUILD_DOCS");
|
rsconf::rebuild_if_env_changed("FISH_BUILD_DOCS");
|
||||||
if env::var("FISH_BUILD_DOCS") == Ok("0".to_string()) {
|
if env_var("FISH_BUILD_DOCS") == Some("0".to_string()) {
|
||||||
rsconf::warn!("Skipping man pages because $FISH_BUILD_DOCS is set to 0");
|
rsconf::warn!("Skipping man pages because $FISH_BUILD_DOCS is set to 0");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -57,18 +66,24 @@ fn build_man(man_dir: &Path) {
|
|||||||
// - if we skipped the docs with sphinx not installed, installing it would not then build the docs.
|
// - if we skipped the docs with sphinx not installed, installing it would not then build the docs.
|
||||||
// That means you need to explicitly set $FISH_BUILD_DOCS=0 (`FISH_BUILD_DOCS=0 cargo install --path .`),
|
// That means you need to explicitly set $FISH_BUILD_DOCS=0 (`FISH_BUILD_DOCS=0 cargo install --path .`),
|
||||||
// which is unfortunate - but the docs are pretty important because they're also used for --help.
|
// which is unfortunate - but the docs are pretty important because they're also used for --help.
|
||||||
let sphinx_build = match Command::new("sphinx-build")
|
let sphinx_build = match Command::new(option_env!("FISH_SPHINX").unwrap_or("sphinx-build"))
|
||||||
.args(args)
|
.args(args)
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.stderr(Stdio::piped())
|
.stderr(Stdio::piped())
|
||||||
.spawn()
|
.spawn()
|
||||||
{
|
{
|
||||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
|
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
|
||||||
if env::var("FISH_BUILD_DOCS") == Ok("1".to_string()) {
|
if env_var("FISH_BUILD_DOCS") == Some("1".to_string()) {
|
||||||
panic!("Could not find sphinx-build to build man pages.\nInstall sphinx or disable building the docs by setting $FISH_BUILD_DOCS=0.");
|
panic!(
|
||||||
|
"Could not find sphinx-build required to build man pages.\n\
|
||||||
|
Install Sphinx or disable building the docs by setting $FISH_BUILD_DOCS=0."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
rsconf::warn!("Cannot find sphinx-build to build man pages.");
|
rsconf::warn!(
|
||||||
rsconf::warn!("If you install it now you need to run `cargo clean` and rebuild, or set $FISH_BUILD_DOCS=1 explicitly.");
|
"Could not find sphinx-build required to build man pages. \
|
||||||
|
If you install Sphinx now, you need to trigger a rebuild to include man pages. \
|
||||||
|
For example by running `touch doc_src` followed by the build command."
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|||||||
15
crates/common/Cargo.toml
Normal file
15
crates/common/Cargo.toml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
[package]
|
||||||
|
name = "fish-common"
|
||||||
|
edition.workspace = true
|
||||||
|
rust-version.workspace = true
|
||||||
|
version = "0.0.0"
|
||||||
|
repository.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libc.workspace = true
|
||||||
|
nix.workspace = true
|
||||||
|
once_cell.workspace = true
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
60
crates/common/src/lib.rs
Normal file
60
crates/common/src/lib.rs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
use libc::STDIN_FILENO;
|
||||||
|
use once_cell::sync::OnceCell;
|
||||||
|
use std::env;
|
||||||
|
use std::os::unix::ffi::OsStrExt;
|
||||||
|
|
||||||
|
// These are in the Unicode private-use range. We really shouldn't use this
|
||||||
|
// range but have little choice in the matter given how our lexer/parser works.
|
||||||
|
// We can't use non-characters for these two ranges because there are only 66 of
|
||||||
|
// them and we need at least 256 + 64.
|
||||||
|
//
|
||||||
|
// If sizeof(wchar_t))==4 we could avoid using private-use chars; however, that
|
||||||
|
// would result in fish having different behavior on machines with 16 versus 32
|
||||||
|
// bit wchar_t. It's better that fish behave the same on both types of systems.
|
||||||
|
//
|
||||||
|
// Note: We don't use the highest 8 bit range (0xF800 - 0xF8FF) because we know
|
||||||
|
// of at least one use of a codepoint in that range: the Apple symbol (0xF8FF)
|
||||||
|
// on Mac OS X. See http://www.unicode.org/faq/private_use.html.
|
||||||
|
pub const ENCODE_DIRECT_BASE: char = '\u{F600}';
|
||||||
|
pub const ENCODE_DIRECT_END: char = char_offset(ENCODE_DIRECT_BASE, 256);
|
||||||
|
|
||||||
|
pub const fn char_offset(base: char, offset: u32) -> char {
|
||||||
|
match char::from_u32(base as u32 + offset) {
|
||||||
|
Some(c) => c,
|
||||||
|
None => panic!("not a valid char"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn subslice_position<T: Eq>(a: &[T], b: &[T]) -> Option<usize> {
|
||||||
|
if b.is_empty() {
|
||||||
|
return Some(0);
|
||||||
|
}
|
||||||
|
a.windows(b.len()).position(|aw| aw == b)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This function attempts to distinguish between a console session (at the actual login vty) and a
|
||||||
|
/// session within a terminal emulator inside a desktop environment or over SSH. Unfortunately
|
||||||
|
/// there are few values of $TERM that we can interpret as being exclusively console sessions, and
|
||||||
|
/// most common operating systems do not use them. The value is cached for the duration of the fish
|
||||||
|
/// session. We err on the side of assuming it's not a console session. This approach isn't
|
||||||
|
/// bullet-proof and that's OK.
|
||||||
|
pub fn is_console_session() -> bool {
|
||||||
|
static IS_CONSOLE_SESSION: OnceCell<bool> = OnceCell::new();
|
||||||
|
// TODO(terminal-workaround)
|
||||||
|
*IS_CONSOLE_SESSION.get_or_init(|| {
|
||||||
|
nix::unistd::ttyname(unsafe { std::os::fd::BorrowedFd::borrow_raw(STDIN_FILENO) })
|
||||||
|
.is_ok_and(|buf| {
|
||||||
|
// Check if the tty matches /dev/(console|dcons|tty[uv\d])
|
||||||
|
let is_console_tty = match buf.as_os_str().as_bytes() {
|
||||||
|
b"/dev/console" => true,
|
||||||
|
b"/dev/dcons" => true,
|
||||||
|
bytes => bytes.strip_prefix(b"/dev/tty").is_some_and(|rest| {
|
||||||
|
matches!(rest.first(), Some(b'u' | b'v' | b'0'..=b'9'))
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
// and that $TERM is simple, e.g. `xterm` or `vt100`, not `xterm-something` or `sun-color`.
|
||||||
|
is_console_tty && env::var_os("TERM").is_none_or(|t| !t.as_bytes().contains(&b'-'))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
22
crates/fallback/Cargo.toml
Normal file
22
crates/fallback/Cargo.toml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
[package]
|
||||||
|
name = "fish-fallback"
|
||||||
|
edition.workspace = true
|
||||||
|
rust-version.workspace = true
|
||||||
|
version = "0.0.0"
|
||||||
|
repository.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
fish-common.workspace = true
|
||||||
|
fish-wchar.workspace = true
|
||||||
|
fish-widecharwidth.workspace = true
|
||||||
|
libc.workspace = true
|
||||||
|
once_cell.workspace = true
|
||||||
|
widestring.workspace = true
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
fish-build-helper.workspace = true
|
||||||
|
rsconf.workspace = true
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
5
crates/fallback/build.rs
Normal file
5
crates/fallback/build.rs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
use fish_build_helper::target_os_is_cygwin;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
rsconf::declare_cfg("cygwin", target_os_is_cygwin())
|
||||||
|
}
|
||||||
@@ -3,8 +3,8 @@
|
|||||||
//!
|
//!
|
||||||
//! Many of these functions are more or less broken and incomplete.
|
//! Many of these functions are more or less broken and incomplete.
|
||||||
|
|
||||||
use crate::wchar::prelude::*;
|
use fish_wchar::prelude::*;
|
||||||
use crate::widecharwidth::{WcLookupTable, WcWidth};
|
use fish_widecharwidth::{WcLookupTable, WcWidth};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::sync::atomic::{AtomicIsize, Ordering};
|
use std::sync::atomic::{AtomicIsize, Ordering};
|
||||||
@@ -30,8 +30,8 @@
|
|||||||
/// A safe wrapper around the system `wcwidth()` function
|
/// A safe wrapper around the system `wcwidth()` function
|
||||||
#[cfg(not(cygwin))]
|
#[cfg(not(cygwin))]
|
||||||
pub fn wcwidth(c: char) -> isize {
|
pub fn wcwidth(c: char) -> isize {
|
||||||
extern "C" {
|
unsafe extern "C" {
|
||||||
pub fn wcwidth(c: libc::wchar_t) -> libc::c_int;
|
pub unsafe fn wcwidth(c: libc::wchar_t) -> libc::c_int;
|
||||||
}
|
}
|
||||||
|
|
||||||
const _: () = assert!(std::mem::size_of::<libc::wchar_t>() >= std::mem::size_of::<char>());
|
const _: () = assert!(std::mem::size_of::<libc::wchar_t>() >= std::mem::size_of::<char>());
|
||||||
@@ -46,7 +46,7 @@ pub fn fish_wcwidth(c: char) -> isize {
|
|||||||
// in the console session, but knows nothing about the capabilities of other terminal emulators
|
// in the console session, but knows nothing about the capabilities of other terminal emulators
|
||||||
// or ttys. Use it from the start only if we are logged in to the physical console.
|
// or ttys. Use it from the start only if we are logged in to the physical console.
|
||||||
#[cfg(not(cygwin))]
|
#[cfg(not(cygwin))]
|
||||||
if crate::common::is_console_session() {
|
if fish_common::is_console_session() {
|
||||||
return wcwidth(c);
|
return wcwidth(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,21 +116,36 @@ pub fn wcscasecmp(lhs: &wstr, rhs: &wstr) -> cmp::Ordering {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Compare two wide strings in a case-insensitive fashion
|
/// Compare two wide strings in a case-insensitive fashion
|
||||||
pub fn wcscasecmp_fuzzy(lhs: &wstr, rhs: &wstr, canonicalize: fn(char) -> char) -> cmp::Ordering {
|
pub fn wcscasecmp_fuzzy(
|
||||||
use std::char::ToLowercase;
|
lhs: &wstr,
|
||||||
use widestring::utfstr::CharsUtf32;
|
rhs: &wstr,
|
||||||
|
extra_canonicalization: fn(char) -> char,
|
||||||
|
) -> cmp::Ordering {
|
||||||
|
lowercase(lhs.chars())
|
||||||
|
.map(extra_canonicalization)
|
||||||
|
.cmp(lowercase(rhs.chars()).map(extra_canonicalization))
|
||||||
|
}
|
||||||
|
|
||||||
/// This struct streams the underlying lowercase chars of a `UTF32String` without allocating.
|
pub fn lowercase(chars: impl Iterator<Item = char>) -> impl Iterator<Item = char> {
|
||||||
///
|
lowercase_impl(chars, |c| c.to_lowercase())
|
||||||
/// `char::to_lowercase()` returns an iterator of chars and we sometimes need to cmp the last
|
}
|
||||||
/// char of one char's `to_lowercase()` with the first char of the other char's
|
pub fn lowercase_rev(chars: impl DoubleEndedIterator<Item = char>) -> impl Iterator<Item = char> {
|
||||||
/// `to_lowercase()`. This makes that possible.
|
lowercase_impl(chars.rev(), |c| c.to_lowercase().rev())
|
||||||
struct ToLowerBuffer<'a, Canonicalize: Fn(char) -> char> {
|
}
|
||||||
|
fn lowercase_impl<ToLowercase: Iterator<Item = char>>(
|
||||||
|
chars: impl Iterator<Item = char>,
|
||||||
|
to_lowercase: fn(char) -> ToLowercase,
|
||||||
|
) -> impl Iterator<Item = char> {
|
||||||
|
/// This struct streams the underlying lowercase chars of a string without allocating.
|
||||||
|
struct ToLowerBuffer<Chars: Iterator<Item = char>, ToLowercase: Iterator<Item = char>> {
|
||||||
|
to_lowercase: fn(char) -> ToLowercase,
|
||||||
current: ToLowercase,
|
current: ToLowercase,
|
||||||
chars: std::iter::Map<CharsUtf32<'a>, Canonicalize>,
|
chars: Chars,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Canonicalize: Fn(char) -> char> Iterator for ToLowerBuffer<'a, Canonicalize> {
|
impl<Chars: Iterator<Item = char>, ToLowercase: Iterator<Item = char>> Iterator
|
||||||
|
for ToLowerBuffer<Chars, ToLowercase>
|
||||||
|
{
|
||||||
type Item = char;
|
type Item = char;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
@@ -138,45 +153,53 @@ fn next(&mut self) -> Option<Self::Item> {
|
|||||||
return Some(c);
|
return Some(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.current = self.chars.next()?.to_lowercase();
|
self.current = (self.to_lowercase)(self.chars.next()?);
|
||||||
self.current.next()
|
self.current.next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Canonicalize: Fn(char) -> char> ToLowerBuffer<'a, Canonicalize> {
|
impl<Chars: Iterator<Item = char>, ToLowercase: Iterator<Item = char>>
|
||||||
pub fn new(mut chars: std::iter::Map<CharsUtf32<'a>, Canonicalize>) -> Self {
|
ToLowerBuffer<Chars, ToLowercase>
|
||||||
|
{
|
||||||
|
pub fn new(mut chars: Chars, to_lowercase: fn(char) -> ToLowercase) -> Self {
|
||||||
Self {
|
Self {
|
||||||
current: chars.next().map(|c| c.to_lowercase()).unwrap_or_else(|| {
|
to_lowercase,
|
||||||
let mut empty = 'a'.to_lowercase();
|
current: chars.next().map_or_else(
|
||||||
let _ = empty.next();
|
|| {
|
||||||
debug_assert!(empty.next().is_none());
|
let mut empty = to_lowercase('a');
|
||||||
empty
|
let _ = empty.next();
|
||||||
}),
|
debug_assert!(empty.next().is_none());
|
||||||
|
empty
|
||||||
|
},
|
||||||
|
to_lowercase,
|
||||||
|
),
|
||||||
chars,
|
chars,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ToLowerBuffer::new(chars, to_lowercase)
|
||||||
let lhs = ToLowerBuffer::new(lhs.chars().map(canonicalize));
|
|
||||||
let rhs = ToLowerBuffer::new(rhs.chars().map(canonicalize));
|
|
||||||
lhs.cmp(rhs)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[cfg(test)]
|
||||||
fn test_wcscasecmp() {
|
mod tests {
|
||||||
|
use super::wcscasecmp;
|
||||||
|
use fish_wchar::prelude::*;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
// Comparison with empty
|
#[test]
|
||||||
assert_eq!(wcscasecmp(L!("a"), L!("")), Ordering::Greater);
|
fn test_wcscasecmp() {
|
||||||
assert_eq!(wcscasecmp(L!(""), L!("a")), Ordering::Less);
|
// Comparison with empty
|
||||||
assert_eq!(wcscasecmp(L!(""), L!("")), Ordering::Equal);
|
assert_eq!(wcscasecmp(L!("a"), L!("")), Ordering::Greater);
|
||||||
|
assert_eq!(wcscasecmp(L!(""), L!("a")), Ordering::Less);
|
||||||
|
assert_eq!(wcscasecmp(L!(""), L!("")), Ordering::Equal);
|
||||||
|
|
||||||
// Basic comparison
|
// Basic comparison
|
||||||
assert_eq!(wcscasecmp(L!("A"), L!("a")), Ordering::Equal);
|
assert_eq!(wcscasecmp(L!("A"), L!("a")), Ordering::Equal);
|
||||||
assert_eq!(wcscasecmp(L!("B"), L!("a")), Ordering::Greater);
|
assert_eq!(wcscasecmp(L!("B"), L!("a")), Ordering::Greater);
|
||||||
assert_eq!(wcscasecmp(L!("A"), L!("B")), Ordering::Less);
|
assert_eq!(wcscasecmp(L!("A"), L!("B")), Ordering::Less);
|
||||||
|
|
||||||
// Multi-byte comparison
|
// Multi-byte comparison
|
||||||
assert_eq!(wcscasecmp(L!("İ"), L!("i\u{307}")), Ordering::Equal);
|
assert_eq!(wcscasecmp(L!("İ"), L!("i\u{307}")), Ordering::Equal);
|
||||||
assert_eq!(wcscasecmp(L!("ia"), L!("İa")), Ordering::Less);
|
assert_eq!(wcscasecmp(L!("ia"), L!("İa")), Ordering::Less);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -4,13 +4,18 @@ edition.workspace = true
|
|||||||
rust-version.workspace = true
|
rust-version.workspace = true
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
repository.workspace = true
|
repository.workspace = true
|
||||||
|
license.workspace = true
|
||||||
description = "proc-macro for extracting strings for gettext translation"
|
description = "proc-macro for extracting strings for gettext translation"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
proc-macro = true
|
proc-macro = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
fish-tempfile.workspace = true
|
||||||
proc-macro2.workspace = true
|
proc-macro2.workspace = true
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
rsconf.workspace = true
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|||||||
3
crates/gettext-extraction/build.rs
Normal file
3
crates/gettext-extraction/build.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fn main() {
|
||||||
|
rsconf::rebuild_if_env_changed("FISH_GETTEXT_EXTRACTION_DIR");
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
extern crate proc_macro;
|
extern crate proc_macro;
|
||||||
|
use fish_tempfile::random_filename;
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use std::{ffi::OsString, fs::OpenOptions, io::Write};
|
use std::{ffi::OsString, io::Write, path::PathBuf};
|
||||||
|
|
||||||
fn unescape_multiline_rust_string(s: String) -> String {
|
fn unescape_multiline_rust_string(s: String) -> String {
|
||||||
if !s.contains('\n') {
|
if !s.contains('\n') {
|
||||||
@@ -42,15 +43,14 @@ enum State {
|
|||||||
unescaped
|
unescaped
|
||||||
}
|
}
|
||||||
|
|
||||||
fn append_po_entry_to_file(message: &TokenStream, file_name: &OsString) {
|
// Each entry is written to a fresh file to avoid race conditions arising when there are multiple
|
||||||
let mut file = OpenOptions::new()
|
// unsynchronized writers to the same file.
|
||||||
.create(true)
|
fn write_po_entry_to_file(message: &TokenStream, dir: &OsString) {
|
||||||
.append(true)
|
|
||||||
.open(file_name)
|
|
||||||
.unwrap_or_else(|e| panic!("Could not open file {file_name:?}: {e}"));
|
|
||||||
let message_string = unescape_multiline_rust_string(message.to_string());
|
let message_string = unescape_multiline_rust_string(message.to_string());
|
||||||
if message_string.contains('\n') {
|
if message_string.contains('\n') {
|
||||||
panic!("Gettext strings may not contain unescaped newlines. Unescaped newline found in '{message_string}'")
|
panic!(
|
||||||
|
"Gettext strings may not contain unescaped newlines. Unescaped newline found in '{message_string}'"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
// Crude check for format strings. This might result in false positives.
|
// Crude check for format strings. This might result in false positives.
|
||||||
let format_string_annotation = if message_string.contains('%') {
|
let format_string_annotation = if message_string.contains('%') {
|
||||||
@@ -59,48 +59,58 @@ fn append_po_entry_to_file(message: &TokenStream, file_name: &OsString) {
|
|||||||
""
|
""
|
||||||
};
|
};
|
||||||
let po_entry = format!("{format_string_annotation}msgid {message_string}\nmsgstr \"\"\n\n");
|
let po_entry = format!("{format_string_annotation}msgid {message_string}\nmsgstr \"\"\n\n");
|
||||||
|
|
||||||
|
let dir = PathBuf::from(dir);
|
||||||
|
let (path, result) =
|
||||||
|
fish_tempfile::create_file_with_retry(|| dir.join(random_filename(OsString::new())));
|
||||||
|
let mut file = result.unwrap_or_else(|e| {
|
||||||
|
panic!("Failed to create temporary file {path:?}:\n{e}");
|
||||||
|
});
|
||||||
file.write_all(po_entry.as_bytes()).unwrap();
|
file.write_all(po_entry.as_bytes()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The `message` is passed through unmodified.
|
/// The `message` is passed through unmodified.
|
||||||
/// If `FISH_GETTEXT_EXTRACTION_FILE` is defined in the environment,
|
/// If `FISH_GETTEXT_EXTRACTION_DIR` is defined in the environment,
|
||||||
/// this file is used to write the message,
|
/// the message ID is written into a new file in this directory,
|
||||||
/// so that it can then be used for generating gettext PO files.
|
/// so that it can then be used for generating gettext PO files.
|
||||||
/// The `message` must be a string literal.
|
/// The `message` must be a string literal.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// This macro panics if the `FISH_GETTEXT_EXTRACTION_FILE` variable is set and `message` has an
|
/// This macro panics if the `FISH_GETTEXT_EXTRACTION_DIR` variable is set and `message` has an
|
||||||
/// unexpected format.
|
/// unexpected format.
|
||||||
/// Note that for example `concat!(...)` cannot be passed to this macro, because expansion works
|
/// Note that for example `concat!(...)` cannot be passed to this macro, because expansion works
|
||||||
/// outside in, meaning this macro would still see the `concat!` macro invocation, instead of a
|
/// outside in, meaning this macro would still see the `concat!` macro invocation, instead of a
|
||||||
/// string literal.
|
/// string literal.
|
||||||
#[proc_macro]
|
#[proc_macro]
|
||||||
pub fn gettext_extract(message: TokenStream) -> TokenStream {
|
pub fn gettext_extract(message: TokenStream) -> TokenStream {
|
||||||
if let Some(file_path) = std::env::var_os("FISH_GETTEXT_EXTRACTION_FILE") {
|
if let Some(dir_path) = std::env::var_os("FISH_GETTEXT_EXTRACTION_DIR") {
|
||||||
let pm2_message = proc_macro2::TokenStream::from(message.clone());
|
let pm2_message = proc_macro2::TokenStream::from(message.clone());
|
||||||
let mut token_trees = pm2_message.into_iter();
|
let mut token_trees = pm2_message.into_iter();
|
||||||
let first_token = token_trees
|
let first_token = token_trees
|
||||||
.next()
|
.next()
|
||||||
.expect("gettext_extract got empty token stream. Expected one token.");
|
.expect("gettext_extract got empty token stream. Expected one token.");
|
||||||
if token_trees.next().is_some() {
|
if token_trees.next().is_some() {
|
||||||
panic!("Invalid number of tokens passed to gettext_extract. Expected one token, but got more.")
|
panic!(
|
||||||
|
"Invalid number of tokens passed to gettext_extract. Expected one token, but got more."
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if let proc_macro2::TokenTree::Group(group) = first_token {
|
let proc_macro2::TokenTree::Group(group) = first_token else {
|
||||||
let mut group_tokens = group.stream().into_iter();
|
|
||||||
let first_group_token = group_tokens
|
|
||||||
.next()
|
|
||||||
.expect("gettext_extract expected one group token but got none.");
|
|
||||||
if group_tokens.next().is_some() {
|
|
||||||
panic!("Invalid number of tokens in group passed to gettext_extract. Expected one token, but got more.")
|
|
||||||
}
|
|
||||||
if let proc_macro2::TokenTree::Literal(_) = first_group_token {
|
|
||||||
append_po_entry_to_file(&message, &file_path);
|
|
||||||
} else {
|
|
||||||
panic!("Expected literal in gettext_extract, but got: {first_group_token:?}");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
panic!("Expected group in gettext_extract, but got: {first_token:?}");
|
panic!("Expected group in gettext_extract, but got: {first_token:?}");
|
||||||
|
};
|
||||||
|
let mut group_tokens = group.stream().into_iter();
|
||||||
|
let first_group_token = group_tokens
|
||||||
|
.next()
|
||||||
|
.expect("gettext_extract expected one group token but got none.");
|
||||||
|
if group_tokens.next().is_some() {
|
||||||
|
panic!(
|
||||||
|
"Invalid number of tokens in group passed to gettext_extract. Expected one token, but got more."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if let proc_macro2::TokenTree::Literal(_) = first_group_token {
|
||||||
|
write_po_entry_to_file(&message, &dir_path);
|
||||||
|
} else {
|
||||||
|
panic!("Expected literal in gettext_extract, but got: {first_group_token:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
message
|
message
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ edition.workspace = true
|
|||||||
rust-version.workspace = true
|
rust-version.workspace = true
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
repository.workspace = true
|
repository.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
phf.workspace = true
|
phf.workspace = true
|
||||||
|
|||||||
@@ -1,16 +1,21 @@
|
|||||||
use std::{
|
use std::{
|
||||||
env,
|
|
||||||
ffi::OsStr,
|
ffi::OsStr,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
process::Command,
|
process::Command,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use fish_build_helper::env_var;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let cache_dir =
|
let cache_dir =
|
||||||
PathBuf::from(fish_build_helper::fish_build_dir()).join("fish-localization-map-cache");
|
PathBuf::from(fish_build_helper::fish_build_dir()).join("fish-localization-map-cache");
|
||||||
embed_localizations(&cache_dir);
|
embed_localizations(&cache_dir);
|
||||||
|
|
||||||
fish_build_helper::rebuild_if_path_changed(fish_build_helper::workspace_root().join("po"));
|
fish_build_helper::rebuild_if_path_changed(
|
||||||
|
fish_build_helper::workspace_root()
|
||||||
|
.join("localization")
|
||||||
|
.join("po"),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn embed_localizations(cache_dir: &Path) {
|
fn embed_localizations(cache_dir: &Path) {
|
||||||
@@ -20,36 +25,37 @@ fn embed_localizations(cache_dir: &Path) {
|
|||||||
io::{BufWriter, Write},
|
io::{BufWriter, Write},
|
||||||
};
|
};
|
||||||
|
|
||||||
let po_dir = fish_build_helper::workspace_root().join("po");
|
let po_dir = fish_build_helper::workspace_root()
|
||||||
|
.join("localization")
|
||||||
|
.join("po");
|
||||||
|
|
||||||
// Ensure that the directory is created, because clippy cannot compile the code if the
|
// Ensure that the directory is created, because clippy cannot compile the code if the
|
||||||
// directory does not exist.
|
// directory does not exist.
|
||||||
std::fs::create_dir_all(cache_dir).unwrap();
|
std::fs::create_dir_all(cache_dir).unwrap();
|
||||||
|
|
||||||
let localization_map_path =
|
let localization_map_path =
|
||||||
Path::new(&env::var("OUT_DIR").unwrap()).join("localization_maps.rs");
|
Path::new(&env_var("OUT_DIR").unwrap()).join("localization_maps.rs");
|
||||||
let mut localization_map_file = BufWriter::new(File::create(&localization_map_path).unwrap());
|
let mut localization_map_file = BufWriter::new(File::create(&localization_map_path).unwrap());
|
||||||
|
|
||||||
// This will become a map which maps from language identifiers to maps containing localizations
|
// This will become a map which maps from language identifiers to maps containing localizations
|
||||||
// for the respective language.
|
// for the respective language.
|
||||||
let mut catalogs = phf_codegen::Map::new();
|
let mut catalogs = phf_codegen::Map::new();
|
||||||
|
|
||||||
match Command::new("msgfmt").arg("-h").status() {
|
match Command::new("msgfmt").arg("-h").output() {
|
||||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
|
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
|
||||||
rsconf::warn!(
|
rsconf::warn!(
|
||||||
"Cannot find msgfmt to build gettext message catalogs. Localization will not work."
|
"Could not find msgfmt required to build message catalogs. \
|
||||||
);
|
Localization will not work. \
|
||||||
rsconf::warn!(
|
If you install gettext now, you need to trigger a rebuild to include localization support. \
|
||||||
"If you install it now you need to trigger a rebuild to get localization support."
|
For example by running `touch localization/po` followed by the build command."
|
||||||
);
|
|
||||||
rsconf::warn!(
|
|
||||||
"One way to achieve that is running `touch po` followed by the build command."
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
panic!("Error when trying to run `msgfmt -h`: {e:?}");
|
panic!("Error when trying to run `msgfmt -h`: {e:?}");
|
||||||
}
|
}
|
||||||
Ok(_) => {
|
Ok(output) => {
|
||||||
|
let has_check_format =
|
||||||
|
String::from_utf8_lossy(&output.stdout).contains("--check-format");
|
||||||
for dir_entry_result in po_dir.read_dir().unwrap() {
|
for dir_entry_result in po_dir.read_dir().unwrap() {
|
||||||
let dir_entry = dir_entry_result.unwrap();
|
let dir_entry = dir_entry_result.unwrap();
|
||||||
let po_file_path = dir_entry.path();
|
let po_file_path = dir_entry.path();
|
||||||
@@ -91,13 +97,32 @@ fn embed_localizations(cache_dir: &Path) {
|
|||||||
// Generate the map file.
|
// Generate the map file.
|
||||||
|
|
||||||
// Try to create new MO data and load it into `mo_data`.
|
// Try to create new MO data and load it into `mo_data`.
|
||||||
let output = Command::new("msgfmt")
|
let mut tmp_mo_file = None;
|
||||||
.arg("--check-format")
|
let output = {
|
||||||
.arg("--output-file=-")
|
let mut cmd = &mut Command::new("msgfmt");
|
||||||
|
if has_check_format {
|
||||||
|
cmd = cmd.arg("--check-format");
|
||||||
|
} else {
|
||||||
|
tmp_mo_file = Some(cache_dir.join("messages.mo"));
|
||||||
|
};
|
||||||
|
cmd.arg(format!(
|
||||||
|
"--output-file={}",
|
||||||
|
tmp_mo_file
|
||||||
|
.as_ref()
|
||||||
|
.map_or("-", |path| path.to_str().unwrap())
|
||||||
|
))
|
||||||
.arg(&po_file_path)
|
.arg(&po_file_path)
|
||||||
.output()
|
.output()
|
||||||
.unwrap();
|
.unwrap()
|
||||||
let mo_data = output.stdout;
|
};
|
||||||
|
if !output.status.success() {
|
||||||
|
panic!(
|
||||||
|
"msgfmt failed:\n{}",
|
||||||
|
String::from_utf8(output.stderr).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let mo_data =
|
||||||
|
tmp_mo_file.map_or(output.stdout, |path| std::fs::read(path).unwrap());
|
||||||
|
|
||||||
// Extract map from MO data.
|
// Extract map from MO data.
|
||||||
let language_localizations = parse_mo_file(&mo_data).unwrap();
|
let language_localizations = parse_mo_file(&mo_data).unwrap();
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ edition.workspace = true
|
|||||||
rust-version.workspace = true
|
rust-version.workspace = true
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
repository.workspace = true
|
repository.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|||||||
15
crates/gettext/Cargo.toml
Normal file
15
crates/gettext/Cargo.toml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
[package]
|
||||||
|
name = "fish-gettext"
|
||||||
|
edition.workspace = true
|
||||||
|
rust-version.workspace = true
|
||||||
|
version = "0.0.0"
|
||||||
|
repository.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
fish-gettext-maps.workspace = true
|
||||||
|
once_cell.workspace = true
|
||||||
|
phf.workspace = true
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
268
crates/gettext/src/lib.rs
Normal file
268
crates/gettext/src/lib.rs
Normal file
@@ -0,0 +1,268 @@
|
|||||||
|
use fish_gettext_maps::CATALOGS;
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use std::{collections::HashSet, sync::Mutex};
|
||||||
|
|
||||||
|
type Catalog = &'static phf::Map<&'static str, &'static str>;
|
||||||
|
|
||||||
|
pub struct SetLanguageLints<'a> {
|
||||||
|
pub duplicates: Vec<&'a str>,
|
||||||
|
pub non_existing: Vec<&'a str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||||
|
pub enum LanguagePrecedenceOrigin {
|
||||||
|
Default,
|
||||||
|
LocaleVariable(LocaleVariable),
|
||||||
|
LanguageEnvVar,
|
||||||
|
StatusLanguage,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||||
|
pub enum LocaleVariable {
|
||||||
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
|
LANG,
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
LC_MESSAGES,
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
LC_ALL,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LocaleVariable {
|
||||||
|
fn as_language_precedence_origin(&self) -> LanguagePrecedenceOrigin {
|
||||||
|
LanguagePrecedenceOrigin::LocaleVariable(*self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_str(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::LANG => "LANG",
|
||||||
|
Self::LC_MESSAGES => "LC_MESSAGES",
|
||||||
|
Self::LC_ALL => "LC_ALL",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for LocaleVariable {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", self.as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct InternalLocalizationState {
|
||||||
|
precedence_origin: LanguagePrecedenceOrigin,
|
||||||
|
language_precedence: Vec<(String, Catalog)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PublicLocalizationState {
|
||||||
|
pub precedence_origin: LanguagePrecedenceOrigin,
|
||||||
|
pub language_precedence: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stores the current localization status.
|
||||||
|
/// `is_active` indicates whether localization is currently active, and the reason if it is
|
||||||
|
/// not.
|
||||||
|
/// The `origin` indicates where the values in `language_precedence` were taken from.
|
||||||
|
/// `language_precedence` stores the catalogs in the order they should be used.
|
||||||
|
///
|
||||||
|
/// This struct should be updated when the relevant variables change or `status language` is used
|
||||||
|
/// to modify the localization state.
|
||||||
|
static LOCALIZATION_STATE: Lazy<Mutex<InternalLocalizationState>> =
|
||||||
|
Lazy::new(|| Mutex::new(InternalLocalizationState::new()));
|
||||||
|
|
||||||
|
impl InternalLocalizationState {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
precedence_origin: LanguagePrecedenceOrigin::Default,
|
||||||
|
language_precedence: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_public(&self) -> PublicLocalizationState {
|
||||||
|
PublicLocalizationState {
|
||||||
|
precedence_origin: self.precedence_origin,
|
||||||
|
language_precedence: self
|
||||||
|
.language_precedence
|
||||||
|
.iter()
|
||||||
|
.map(|(lang, _)| lang.to_owned())
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_from_env(
|
||||||
|
&mut self,
|
||||||
|
message_locale: Option<(LocaleVariable, String)>,
|
||||||
|
language_var: Option<Vec<String>>,
|
||||||
|
) {
|
||||||
|
// Do not override values set via `status language`.
|
||||||
|
if self.precedence_origin == LanguagePrecedenceOrigin::StatusLanguage {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((precedence_origin, locale)) = &message_locale {
|
||||||
|
// Regular locale names start with lowercase letters (`ll_CC`, followed by some suffix).
|
||||||
|
// The C or POSIX locale is special, and often used to disable localization.
|
||||||
|
// Their names are upper-case, but variants with suffixes (`C.UTF-8`) exist.
|
||||||
|
// To ensure that such variants are accounted for, we match on prefixes of the
|
||||||
|
// locale name.
|
||||||
|
// https://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap07.html#tag_07_02
|
||||||
|
fn is_c_locale(locale: &str) -> bool {
|
||||||
|
locale.starts_with('C') || locale.starts_with("POSIX")
|
||||||
|
}
|
||||||
|
if is_c_locale(locale) {
|
||||||
|
self.precedence_origin =
|
||||||
|
LanguagePrecedenceOrigin::LocaleVariable(*precedence_origin);
|
||||||
|
self.language_precedence.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let (precedence_origin, language_list) = if let Some(list) = language_var {
|
||||||
|
(LanguagePrecedenceOrigin::LanguageEnvVar, list)
|
||||||
|
} else if let Some((precedence_origin, locale)) = message_locale {
|
||||||
|
let mut normalized_name = String::new();
|
||||||
|
// Strip off encoding and modifier. (We always expect UTF-8 and don't support modifiers.)
|
||||||
|
for c in locale.chars() {
|
||||||
|
if c.is_alphabetic() || c == '_' {
|
||||||
|
normalized_name.push(c);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// At this point, the normalized_name should have the shape `ll` or `ll_CC`.
|
||||||
|
(
|
||||||
|
precedence_origin.as_language_precedence_origin(),
|
||||||
|
vec![normalized_name],
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(LanguagePrecedenceOrigin::Default, vec![])
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut seen_languages = HashSet::new();
|
||||||
|
self.language_precedence = language_list
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(|lang| find_existing_catalogs(&lang))
|
||||||
|
.filter(|(lang, _)| seen_languages.insert(lang.to_owned()))
|
||||||
|
.collect();
|
||||||
|
self.precedence_origin = precedence_origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_from_status_language_builtin<'a, 'b: 'a, S: AsRef<str> + 'a>(
|
||||||
|
&mut self,
|
||||||
|
langs: &'b [S],
|
||||||
|
) -> SetLanguageLints<'a> {
|
||||||
|
let mut seen = HashSet::new();
|
||||||
|
let mut duplicates = vec![];
|
||||||
|
for lang in langs {
|
||||||
|
let lang = lang.as_ref();
|
||||||
|
if !seen.insert(lang) {
|
||||||
|
duplicates.push(lang)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut existing_langs = vec![];
|
||||||
|
let mut non_existing = vec![];
|
||||||
|
for lang in langs {
|
||||||
|
let lang = lang.as_ref();
|
||||||
|
if let Some(catalog) = CATALOGS.get(lang) {
|
||||||
|
existing_langs.push((lang.to_owned(), *catalog));
|
||||||
|
} else {
|
||||||
|
non_existing.push(lang);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut seen = HashSet::new();
|
||||||
|
let unique_langs = existing_langs
|
||||||
|
.into_iter()
|
||||||
|
.filter(|(lang, _)| seen.insert(lang.to_owned()))
|
||||||
|
.collect();
|
||||||
|
self.language_precedence = unique_langs;
|
||||||
|
self.precedence_origin = LanguagePrecedenceOrigin::StatusLanguage;
|
||||||
|
|
||||||
|
SetLanguageLints {
|
||||||
|
duplicates,
|
||||||
|
non_existing,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tries to find catalogs for `language`.
|
||||||
|
/// `language` must be an ISO 639 language code, optionally followed by an underscore and an ISO
|
||||||
|
/// 3166 country/territory code.
|
||||||
|
/// Uses the catalog with the exact same name as `language` if it exists.
|
||||||
|
/// If a country code is present (`ll_CC`), only the catalog named `ll` will be considered as a fallback.
|
||||||
|
/// If no country code is present (`ll`), all catalogs whose names start with `ll_` will be used in
|
||||||
|
/// arbitrary order.
|
||||||
|
fn find_existing_catalogs(language: &str) -> Vec<(String, Catalog)> {
|
||||||
|
// Try the exact name first.
|
||||||
|
// If there already is a corresponding catalog return the language.
|
||||||
|
if let Some(catalog) = CATALOGS.get(language) {
|
||||||
|
return vec![(language.to_owned(), catalog)];
|
||||||
|
}
|
||||||
|
let language_without_country_code = language.split_once('_').map_or(language, |(ll, _cc)| ll);
|
||||||
|
if language == language_without_country_code {
|
||||||
|
// We have `ll` format. In this case, try to find any catalog whose name starts with `ll_`.
|
||||||
|
// Note that it is important to include the underscore in the pattern, otherwise `ll` might
|
||||||
|
// fall back to `llx_CC`, where `llx` is a 3-letter language identifier.
|
||||||
|
let ll_prefix = format!("{language}_");
|
||||||
|
let mut lang_catalogs = vec![];
|
||||||
|
for (&lang_name, &catalog) in CATALOGS.entries() {
|
||||||
|
if lang_name.starts_with(&ll_prefix) {
|
||||||
|
lang_catalogs.push((lang_name.to_owned(), catalog));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lang_catalogs
|
||||||
|
} else {
|
||||||
|
// If `language` contained a country code, we only try to fall back to a catalog
|
||||||
|
// without a country code.
|
||||||
|
if let Some(catalog) = CATALOGS.get(language_without_country_code) {
|
||||||
|
vec![(language_without_country_code.to_owned(), catalog)]
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_from_env(
|
||||||
|
locale: Option<(LocaleVariable, String)>,
|
||||||
|
language_var: Option<Vec<String>>,
|
||||||
|
) {
|
||||||
|
let mut localization_state = LOCALIZATION_STATE.lock().unwrap();
|
||||||
|
localization_state.update_from_env(locale, language_var);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_from_status_language_builtin<'a, 'b: 'a, S: AsRef<str> + 'a>(
|
||||||
|
langs: &'b [S],
|
||||||
|
) -> SetLanguageLints<'a> {
|
||||||
|
let mut localization_state = LOCALIZATION_STATE.lock().unwrap();
|
||||||
|
localization_state.update_from_status_language_builtin(langs)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unset_from_status_language_builtin(
|
||||||
|
locale: Option<(LocaleVariable, String)>,
|
||||||
|
language_var: Option<Vec<String>>,
|
||||||
|
) {
|
||||||
|
let mut localization_state = LOCALIZATION_STATE.lock().unwrap();
|
||||||
|
localization_state.precedence_origin = LanguagePrecedenceOrigin::Default;
|
||||||
|
localization_state.update_from_env(locale, language_var);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn status_language() -> PublicLocalizationState {
|
||||||
|
let localization_state = LOCALIZATION_STATE.lock().unwrap();
|
||||||
|
localization_state.to_public()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gettext(message_str: &'static str) -> Option<&'static str> {
|
||||||
|
let localization_state = LOCALIZATION_STATE.lock().unwrap();
|
||||||
|
|
||||||
|
// Use the localization from the highest-precedence language that has one available.
|
||||||
|
for (_, catalog) in localization_state.language_precedence.iter() {
|
||||||
|
if let Some(localized_str) = catalog.get(message_str) {
|
||||||
|
return Some(localized_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn list_available_languages() -> Vec<&'static str> {
|
||||||
|
let mut langs: Vec<_> = CATALOGS.entries().map(|(&lang, _)| lang).collect();
|
||||||
|
langs.sort();
|
||||||
|
langs
|
||||||
|
}
|
||||||
@@ -15,7 +15,7 @@ pub enum Arg<'a> {
|
|||||||
#[cfg(feature = "widestring")]
|
#[cfg(feature = "widestring")]
|
||||||
WString(WString),
|
WString(WString),
|
||||||
UInt(u64),
|
UInt(u64),
|
||||||
SInt(i64, u8), // signed integers track their width as the number of bits
|
SInt(i64),
|
||||||
Float(f64),
|
Float(f64),
|
||||||
USizeRef(&'a mut usize), // for use with %n
|
USizeRef(&'a mut usize), // for use with %n
|
||||||
}
|
}
|
||||||
@@ -59,7 +59,7 @@ pub fn as_str<'s>(&'s self, storage: &'s mut String) -> Result<&'s str, Error>
|
|||||||
pub fn as_uint(&self) -> Result<u64, Error> {
|
pub fn as_uint(&self) -> Result<u64, Error> {
|
||||||
match *self {
|
match *self {
|
||||||
Arg::UInt(u) => Ok(u),
|
Arg::UInt(u) => Ok(u),
|
||||||
Arg::SInt(i, _w) => i.try_into().map_err(|_| Error::Overflow),
|
Arg::SInt(i) => i.try_into().map_err(|_| Error::Overflow),
|
||||||
_ => Err(Error::BadArgType),
|
_ => Err(Error::BadArgType),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -68,25 +68,18 @@ pub fn as_uint(&self) -> Result<u64, Error> {
|
|||||||
pub fn as_sint(&self) -> Result<i64, Error> {
|
pub fn as_sint(&self) -> Result<i64, Error> {
|
||||||
match *self {
|
match *self {
|
||||||
Arg::UInt(u) => u.try_into().map_err(|_| Error::Overflow),
|
Arg::UInt(u) => u.try_into().map_err(|_| Error::Overflow),
|
||||||
Arg::SInt(i, _w) => Ok(i),
|
Arg::SInt(i) => Ok(i),
|
||||||
_ => Err(Error::BadArgType),
|
_ => Err(Error::BadArgType),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is a signed value, then return the sign (true if negative) and the magnitude,
|
/// Unwraps [`Arg::UInt`] to [`u64`].
|
||||||
// masked to the value's width. This allows for e.g. -1 to be returned as 0xFF, 0xFFFF, etc.
|
/// Unwraps [`Arg::SInt`] and casts the [`i64`] to [`u64`].
|
||||||
// depending on the original width.
|
/// Calling this on other variants of `[Arg]` is an error.
|
||||||
// If this is an unsigned value, simply return (false, u64).
|
pub fn as_wrapping_sint(&self) -> Result<u64, Error> {
|
||||||
pub fn as_wrapping_sint(&self) -> Result<(bool, u64), Error> {
|
|
||||||
match *self {
|
match *self {
|
||||||
Arg::UInt(u) => Ok((false, u)),
|
Arg::UInt(u) => Ok(u),
|
||||||
Arg::SInt(i, w) => {
|
Arg::SInt(i) => Ok(i as u64),
|
||||||
// Need to shift twice in case w is 64.
|
|
||||||
debug_assert!(w > 0);
|
|
||||||
let mask = ((1u64 << (w - 1)) << 1).wrapping_sub(1);
|
|
||||||
let ui = (i as u64) & mask;
|
|
||||||
Ok((i < 0, ui))
|
|
||||||
}
|
|
||||||
_ => Err(Error::BadArgType),
|
_ => Err(Error::BadArgType),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,7 +90,7 @@ pub fn as_float(&self) -> Result<f64, Error> {
|
|||||||
match *self {
|
match *self {
|
||||||
Arg::Float(f) => Ok(f),
|
Arg::Float(f) => Ok(f),
|
||||||
Arg::UInt(u) => Ok(u as f64),
|
Arg::UInt(u) => Ok(u as f64),
|
||||||
Arg::SInt(i, _w) => Ok(i as f64),
|
Arg::SInt(i) => Ok(i as f64),
|
||||||
_ => Err(Error::BadArgType),
|
_ => Err(Error::BadArgType),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -181,7 +174,7 @@ macro_rules! impl_to_arg {
|
|||||||
$(
|
$(
|
||||||
impl<'a> ToArg<'a> for $t {
|
impl<'a> ToArg<'a> for $t {
|
||||||
fn to_arg(self) -> Arg<'a> {
|
fn to_arg(self) -> Arg<'a> {
|
||||||
Arg::SInt(self as i64, <$t>::BITS as u8)
|
Arg::SInt(self as i64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
@@ -211,8 +204,6 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_to_arg() {
|
fn test_to_arg() {
|
||||||
const SIZE_WIDTH: u8 = isize::BITS as u8;
|
|
||||||
|
|
||||||
assert!(matches!("test".to_arg(), Arg::Str("test")));
|
assert!(matches!("test".to_arg(), Arg::Str("test")));
|
||||||
assert!(matches!(String::from("test").to_arg(), Arg::Str(_)));
|
assert!(matches!(String::from("test").to_arg(), Arg::Str(_)));
|
||||||
#[cfg(feature = "widestring")]
|
#[cfg(feature = "widestring")]
|
||||||
@@ -224,17 +215,17 @@ fn test_to_arg() {
|
|||||||
assert!(matches!('x'.to_arg(), Arg::UInt(120)));
|
assert!(matches!('x'.to_arg(), Arg::UInt(120)));
|
||||||
let mut usize_val: usize = 0;
|
let mut usize_val: usize = 0;
|
||||||
assert!(matches!((&mut usize_val).to_arg(), Arg::USizeRef(_)));
|
assert!(matches!((&mut usize_val).to_arg(), Arg::USizeRef(_)));
|
||||||
assert!(matches!(42i8.to_arg(), Arg::SInt(42, 8)));
|
assert!(matches!(42i8.to_arg(), Arg::SInt(42)));
|
||||||
assert!(matches!(42i16.to_arg(), Arg::SInt(42, 16)));
|
assert!(matches!(42i16.to_arg(), Arg::SInt(42)));
|
||||||
assert!(matches!(42i32.to_arg(), Arg::SInt(42, 32)));
|
assert!(matches!(42i32.to_arg(), Arg::SInt(42)));
|
||||||
assert!(matches!(42i64.to_arg(), Arg::SInt(42, 64)));
|
assert!(matches!(42i64.to_arg(), Arg::SInt(42)));
|
||||||
assert!(matches!(42isize.to_arg(), Arg::SInt(42, SIZE_WIDTH)));
|
assert!(matches!(42isize.to_arg(), Arg::SInt(42)));
|
||||||
|
|
||||||
assert_eq!((-42i8).to_arg(), Arg::SInt(-42, 8));
|
assert_eq!((-42i8).to_arg(), Arg::SInt(-42));
|
||||||
assert_eq!((-42i16).to_arg(), Arg::SInt(-42, 16));
|
assert_eq!((-42i16).to_arg(), Arg::SInt(-42));
|
||||||
assert_eq!((-42i32).to_arg(), Arg::SInt(-42, 32));
|
assert_eq!((-42i32).to_arg(), Arg::SInt(-42));
|
||||||
assert_eq!((-42i64).to_arg(), Arg::SInt(-42, 64));
|
assert_eq!((-42i64).to_arg(), Arg::SInt(-42));
|
||||||
assert_eq!((-42isize).to_arg(), Arg::SInt(-42, SIZE_WIDTH));
|
assert_eq!((-42isize).to_arg(), Arg::SInt(-42));
|
||||||
|
|
||||||
assert!(matches!(42u8.to_arg(), Arg::UInt(42)));
|
assert!(matches!(42u8.to_arg(), Arg::UInt(42)));
|
||||||
assert!(matches!(42u16.to_arg(), Arg::UInt(42)));
|
assert!(matches!(42u16.to_arg(), Arg::UInt(42)));
|
||||||
@@ -242,7 +233,7 @@ fn test_to_arg() {
|
|||||||
assert!(matches!(42u64.to_arg(), Arg::UInt(42)));
|
assert!(matches!(42u64.to_arg(), Arg::UInt(42)));
|
||||||
assert!(matches!(42usize.to_arg(), Arg::UInt(42)));
|
assert!(matches!(42usize.to_arg(), Arg::UInt(42)));
|
||||||
|
|
||||||
let ptr = &42f32 as *const f32;
|
let ptr = std::ptr::from_ref(&42f32);
|
||||||
assert!(matches!(ptr.to_arg(), Arg::UInt(_)));
|
assert!(matches!(ptr.to_arg(), Arg::UInt(_)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
use super::locale::Locale;
|
use super::locale::Locale;
|
||||||
use super::printf_impl::{pad, ConversionSpec, Error, ModifierFlags};
|
use super::printf_impl::{ConversionSpec, Error, ModifierFlags, pad};
|
||||||
use decimal::{Decimal, DigitLimit, DIGIT_WIDTH};
|
use decimal::{DIGIT_WIDTH, Decimal, DigitLimit};
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
@@ -279,7 +279,6 @@ fn format_a(mut y: f64, params: FormatParams<'_, impl Write>) -> Result<usize, E
|
|||||||
|
|
||||||
// Compute the number of hex digits in the mantissa after the decimal.
|
// Compute the number of hex digits in the mantissa after the decimal.
|
||||||
// -1 for leading 1 bit (we are to the range [1, 2)), then divide by 4, rounding up.
|
// -1 for leading 1 bit (we are to the range [1, 2)), then divide by 4, rounding up.
|
||||||
#[allow(unknown_lints)] // for old clippy
|
|
||||||
#[allow(clippy::manual_div_ceil)]
|
#[allow(clippy::manual_div_ceil)]
|
||||||
const MANTISSA_HEX_DIGITS: usize = (MANTISSA_BITS - 1 + 3) / 4;
|
const MANTISSA_HEX_DIGITS: usize = (MANTISSA_BITS - 1 + 3) / 4;
|
||||||
if had_prec && prec < MANTISSA_HEX_DIGITS {
|
if had_prec && prec < MANTISSA_HEX_DIGITS {
|
||||||
|
|||||||
@@ -4,9 +4,8 @@
|
|||||||
|
|
||||||
mod fmt_fp;
|
mod fmt_fp;
|
||||||
mod printf_impl;
|
mod printf_impl;
|
||||||
pub use printf_impl::{sprintf_locale, Error, FormatString};
|
pub use printf_impl::{Error, FormatString, sprintf_locale};
|
||||||
pub mod locale;
|
pub mod locale;
|
||||||
pub use locale::{Locale, C_LOCALE, EN_US_LOCALE};
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|||||||
@@ -66,11 +66,7 @@ fn next_group_size(&self, digits_left: usize) -> usize {
|
|||||||
// Divide remaining digits by repeat_group.
|
// Divide remaining digits by repeat_group.
|
||||||
// Apply any remainder to the first group.
|
// Apply any remainder to the first group.
|
||||||
let res = (digits_left - accum) % (repeat_group as usize);
|
let res = (digits_left - accum) % (repeat_group as usize);
|
||||||
if res > 0 {
|
if res > 0 { res } else { repeat_group as usize }
|
||||||
res
|
|
||||||
} else {
|
|
||||||
repeat_group as usize
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,86 +118,91 @@ pub fn separator_count(&self, digits_count: usize) -> usize {
|
|||||||
group_repeat: true,
|
group_repeat: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[cfg(test)]
|
||||||
fn test_apply_grouping() {
|
mod tests {
|
||||||
let input = "123456789";
|
use super::{C_LOCALE, EN_US_LOCALE, Locale};
|
||||||
let mut result: String;
|
|
||||||
|
|
||||||
// en_US has commas.
|
#[test]
|
||||||
assert_eq!(EN_US_LOCALE.thousands_sep, Some(','));
|
fn test_apply_grouping() {
|
||||||
result = EN_US_LOCALE.apply_grouping(input);
|
let input = "123456789";
|
||||||
assert_eq!(result, "123,456,789");
|
let mut result: String;
|
||||||
|
|
||||||
// Test weird locales.
|
// en_US has commas.
|
||||||
let input: &str = "1234567890123456";
|
assert_eq!(EN_US_LOCALE.thousands_sep, Some(','));
|
||||||
let mut locale: Locale = C_LOCALE;
|
result = EN_US_LOCALE.apply_grouping(input);
|
||||||
locale.thousands_sep = Some('!');
|
assert_eq!(result, "123,456,789");
|
||||||
|
|
||||||
locale.grouping = [5, 3, 1, 0];
|
// Test weird locales.
|
||||||
locale.group_repeat = false;
|
let input: &str = "1234567890123456";
|
||||||
result = locale.apply_grouping(input);
|
let mut locale: Locale = C_LOCALE;
|
||||||
assert_eq!(result, "1234567!8!901!23456");
|
locale.thousands_sep = Some('!');
|
||||||
|
|
||||||
// group_repeat doesn't matter because trailing group is 0
|
locale.grouping = [5, 3, 1, 0];
|
||||||
locale.grouping = [5, 3, 1, 0];
|
locale.group_repeat = false;
|
||||||
locale.group_repeat = true;
|
result = locale.apply_grouping(input);
|
||||||
result = locale.apply_grouping(input);
|
assert_eq!(result, "1234567!8!901!23456");
|
||||||
assert_eq!(result, "1234567!8!901!23456");
|
|
||||||
|
|
||||||
locale.grouping = [5, 3, 1, 2];
|
// group_repeat doesn't matter because trailing group is 0
|
||||||
locale.group_repeat = false;
|
locale.grouping = [5, 3, 1, 0];
|
||||||
result = locale.apply_grouping(input);
|
locale.group_repeat = true;
|
||||||
assert_eq!(result, "12345!67!8!901!23456");
|
result = locale.apply_grouping(input);
|
||||||
|
assert_eq!(result, "1234567!8!901!23456");
|
||||||
|
|
||||||
locale.grouping = [5, 3, 1, 2];
|
locale.grouping = [5, 3, 1, 2];
|
||||||
locale.group_repeat = true;
|
locale.group_repeat = false;
|
||||||
result = locale.apply_grouping(input);
|
result = locale.apply_grouping(input);
|
||||||
assert_eq!(result, "1!23!45!67!8!901!23456");
|
assert_eq!(result, "12345!67!8!901!23456");
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
locale.grouping = [5, 3, 1, 2];
|
||||||
#[should_panic]
|
locale.group_repeat = true;
|
||||||
fn test_thousands_grouping_length_panics_if_no_sep() {
|
result = locale.apply_grouping(input);
|
||||||
// We should panic if we try to group with no thousands separator.
|
assert_eq!(result, "1!23!45!67!8!901!23456");
|
||||||
assert_eq!(C_LOCALE.thousands_sep, None);
|
|
||||||
C_LOCALE.apply_grouping("123");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_thousands_grouping_length() {
|
|
||||||
fn validate_grouping_length_hint(locale: Locale, mut input: &str) {
|
|
||||||
loop {
|
|
||||||
let expected = locale.separator_count(input.len()) + input.len();
|
|
||||||
let actual = locale.apply_grouping(input).len();
|
|
||||||
assert_eq!(expected, actual);
|
|
||||||
if input.is_empty() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
input = &input[1..];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
validate_grouping_length_hint(EN_US_LOCALE, "123456789");
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn test_thousands_grouping_length_panics_if_no_sep() {
|
||||||
|
// We should panic if we try to group with no thousands separator.
|
||||||
|
assert_eq!(C_LOCALE.thousands_sep, None);
|
||||||
|
C_LOCALE.apply_grouping("123");
|
||||||
|
}
|
||||||
|
|
||||||
// Test weird locales.
|
#[test]
|
||||||
let input = "1234567890123456";
|
fn test_thousands_grouping_length() {
|
||||||
let mut locale: Locale = C_LOCALE;
|
fn validate_grouping_length_hint(locale: Locale, mut input: &str) {
|
||||||
locale.thousands_sep = Some('!');
|
loop {
|
||||||
|
let expected = locale.separator_count(input.len()) + input.len();
|
||||||
|
let actual = locale.apply_grouping(input).len();
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
if input.is_empty() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
input = &input[1..];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
locale.grouping = [5, 3, 1, 0];
|
validate_grouping_length_hint(EN_US_LOCALE, "123456789");
|
||||||
locale.group_repeat = false;
|
|
||||||
validate_grouping_length_hint(locale, input);
|
|
||||||
|
|
||||||
// group_repeat doesn't matter because trailing group is 0
|
// Test weird locales.
|
||||||
locale.grouping = [5, 3, 1, 0];
|
let input = "1234567890123456";
|
||||||
locale.group_repeat = true;
|
let mut locale: Locale = C_LOCALE;
|
||||||
validate_grouping_length_hint(locale, input);
|
locale.thousands_sep = Some('!');
|
||||||
|
|
||||||
locale.grouping = [5, 3, 1, 2];
|
locale.grouping = [5, 3, 1, 0];
|
||||||
locale.group_repeat = false;
|
locale.group_repeat = false;
|
||||||
validate_grouping_length_hint(locale, input);
|
validate_grouping_length_hint(locale, input);
|
||||||
|
|
||||||
locale.grouping = [5, 3, 1, 2];
|
// group_repeat doesn't matter because trailing group is 0
|
||||||
locale.group_repeat = true;
|
locale.grouping = [5, 3, 1, 0];
|
||||||
validate_grouping_length_hint(locale, input);
|
locale.group_repeat = true;
|
||||||
|
validate_grouping_length_hint(locale, input);
|
||||||
|
|
||||||
|
locale.grouping = [5, 3, 1, 2];
|
||||||
|
locale.group_repeat = false;
|
||||||
|
validate_grouping_length_hint(locale, input);
|
||||||
|
|
||||||
|
locale.grouping = [5, 3, 1, 2];
|
||||||
|
locale.group_repeat = true;
|
||||||
|
validate_grouping_length_hint(locale, input);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -472,7 +472,7 @@ pub fn sprintf_locale(
|
|||||||
// If someone passes us a negative value, format it with the width
|
// If someone passes us a negative value, format it with the width
|
||||||
// we were given.
|
// we were given.
|
||||||
let lower = conv_spec.is_lower();
|
let lower = conv_spec.is_lower();
|
||||||
let (_, uint) = arg.as_wrapping_sint()?;
|
let uint = arg.as_wrapping_sint()?;
|
||||||
if uint != 0 {
|
if uint != 0 {
|
||||||
if flags.alt_form {
|
if flags.alt_form {
|
||||||
prefix = if lower { "0x" } else { "0X" };
|
prefix = if lower { "0x" } else { "0X" };
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use crate::arg::ToArg;
|
use crate::arg::ToArg;
|
||||||
use crate::locale::{Locale, C_LOCALE, EN_US_LOCALE};
|
use crate::locale::{C_LOCALE, EN_US_LOCALE, Locale};
|
||||||
use crate::{sprintf_locale, Error, FormatString};
|
use crate::{Error, FormatString, sprintf_locale};
|
||||||
use libc::c_char;
|
|
||||||
use std::f64::consts::{E, PI, TAU};
|
use std::f64::consts::{E, PI, TAU};
|
||||||
|
use std::ffi::CStr;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
// sprintf, checking length
|
// sprintf, checking length
|
||||||
@@ -77,7 +77,7 @@ fn write_str(&mut self, _s: &str) -> fmt::Result {
|
|||||||
#[test]
|
#[test]
|
||||||
fn smoke() {
|
fn smoke() {
|
||||||
assert_fmt!("Hello, %s!", "world" => "Hello, world!");
|
assert_fmt!("Hello, %s!", "world" => "Hello, world!");
|
||||||
assert_fmt!("Hello, %ls!", "world" => "Hello, world!");
|
assert_fmt!("Hello, %ls!", "world" => "Hello, world!"); // length modifier
|
||||||
assert_fmt!("Hello, world! %d %%%%", 3 => "Hello, world! 3 %%");
|
assert_fmt!("Hello, world! %d %%%%", 3 => "Hello, world! 3 %%");
|
||||||
assert_fmt!("" => "");
|
assert_fmt!("" => "");
|
||||||
}
|
}
|
||||||
@@ -225,7 +225,7 @@ fn test_int() {
|
|||||||
assert_fmt!("%d", -123 => "-123");
|
assert_fmt!("%d", -123 => "-123");
|
||||||
assert_fmt!("~%d~", 148 => "~148~");
|
assert_fmt!("~%d~", 148 => "~148~");
|
||||||
assert_fmt!("00%dxx", -91232 => "00-91232xx");
|
assert_fmt!("00%dxx", -91232 => "00-91232xx");
|
||||||
assert_fmt!("%x", -9232 => "ffffdbf0");
|
assert_fmt!("%x", -9232 => "ffffffffffffdbf0");
|
||||||
assert_fmt!("%X", 432 => "1B0");
|
assert_fmt!("%X", 432 => "1B0");
|
||||||
assert_fmt!("%09X", 432 => "0000001B0");
|
assert_fmt!("%09X", 432 => "0000001B0");
|
||||||
assert_fmt!("%9X", 432 => " 1B0");
|
assert_fmt!("%9X", 432 => " 1B0");
|
||||||
@@ -234,6 +234,7 @@ fn test_int() {
|
|||||||
assert_fmt!("%2o", 4 => " 4");
|
assert_fmt!("%2o", 4 => " 4");
|
||||||
assert_fmt!("% 12d", -4 => " -4");
|
assert_fmt!("% 12d", -4 => " -4");
|
||||||
assert_fmt!("% 12d", 48 => " 48");
|
assert_fmt!("% 12d", 48 => " 48");
|
||||||
|
// with length modifier
|
||||||
assert_fmt!("%ld", -4_i64 => "-4");
|
assert_fmt!("%ld", -4_i64 => "-4");
|
||||||
assert_fmt!("%lld", -4_i64 => "-4");
|
assert_fmt!("%lld", -4_i64 => "-4");
|
||||||
assert_fmt!("%lX", -4_i64 => "FFFFFFFFFFFFFFFC");
|
assert_fmt!("%lX", -4_i64 => "FFFFFFFFFFFFFFFC");
|
||||||
@@ -248,6 +249,7 @@ fn test_int() {
|
|||||||
assert_fmt!("%9X", 492 => " 1EC");
|
assert_fmt!("%9X", 492 => " 1EC");
|
||||||
assert_fmt!("% 12u", 4 => " 4");
|
assert_fmt!("% 12u", 4 => " 4");
|
||||||
assert_fmt!("% 12u", 48 => " 48");
|
assert_fmt!("% 12u", 48 => " 48");
|
||||||
|
// with length modifier
|
||||||
assert_fmt!("%lu", 4_u64 => "4");
|
assert_fmt!("%lu", 4_u64 => "4");
|
||||||
assert_fmt!("%llu", 4_u64 => "4");
|
assert_fmt!("%llu", 4_u64 => "4");
|
||||||
assert_fmt!("%lX", 4_u64 => "4");
|
assert_fmt!("%lX", 4_u64 => "4");
|
||||||
@@ -414,6 +416,7 @@ fn test_float() {
|
|||||||
assert_fmt1!("%f", 0.0, "0.000000");
|
assert_fmt1!("%f", 0.0, "0.000000");
|
||||||
assert_fmt1!("%g", 0.0, "0");
|
assert_fmt1!("%g", 0.0, "0");
|
||||||
assert_fmt1!("%#g", 0.0, "0.00000");
|
assert_fmt1!("%#g", 0.0, "0.00000");
|
||||||
|
// with length modifier
|
||||||
assert_fmt1!("%la", 0.0, "0x0p+0");
|
assert_fmt1!("%la", 0.0, "0x0p+0");
|
||||||
assert_fmt1!("%le", 0.0, "0.000000e+00");
|
assert_fmt1!("%le", 0.0, "0.000000e+00");
|
||||||
assert_fmt1!("%lf", 0.0, "0.000000");
|
assert_fmt1!("%lf", 0.0, "0.000000");
|
||||||
@@ -430,7 +433,7 @@ fn test_float() {
|
|||||||
assert_fmt1!("%.4f", 1.03125, "1.0312"); /* 0x1.08p0 */
|
assert_fmt1!("%.4f", 1.03125, "1.0312"); /* 0x1.08p0 */
|
||||||
assert_fmt1!("%.2f", 1.375, "1.38");
|
assert_fmt1!("%.2f", 1.375, "1.38");
|
||||||
assert_fmt1!("%.1f", 1.375, "1.4");
|
assert_fmt1!("%.1f", 1.375, "1.4");
|
||||||
assert_fmt1!("%.1lf", 1.375, "1.4");
|
assert_fmt1!("%.1lf", 1.375, "1.4"); // length modifier
|
||||||
assert_fmt1!("%.15f", 1.1, "1.100000000000000");
|
assert_fmt1!("%.15f", 1.1, "1.100000000000000");
|
||||||
assert_fmt1!("%.16f", 1.1, "1.1000000000000001");
|
assert_fmt1!("%.16f", 1.1, "1.1000000000000001");
|
||||||
assert_fmt1!("%.17f", 1.1, "1.10000000000000009");
|
assert_fmt1!("%.17f", 1.1, "1.10000000000000009");
|
||||||
@@ -755,8 +758,8 @@ fn test_errors() {
|
|||||||
sprintf_err!("%1", => BadFormatString);
|
sprintf_err!("%1", => BadFormatString);
|
||||||
sprintf_err!("%%%k", => BadFormatString);
|
sprintf_err!("%%%k", => BadFormatString);
|
||||||
sprintf_err!("%B", => BadFormatString);
|
sprintf_err!("%B", => BadFormatString);
|
||||||
sprintf_err!("%lC", 'q' => BadFormatString);
|
sprintf_err!("%lC", 'q' => BadFormatString); // length modifier
|
||||||
sprintf_err!("%lS", 'q' => BadFormatString);
|
sprintf_err!("%lS", 'q' => BadFormatString); // length modifier
|
||||||
sprintf_err!("%d", => MissingArg);
|
sprintf_err!("%d", => MissingArg);
|
||||||
sprintf_err!("%d %u", 1 => MissingArg);
|
sprintf_err!("%d %u", 1 => MissingArg);
|
||||||
sprintf_err!("%*d", 5 => MissingArg);
|
sprintf_err!("%*d", 5 => MissingArg);
|
||||||
@@ -852,25 +855,20 @@ fn test_float_hex_prec() {
|
|||||||
// Note that our hex float formatting rounds according to the rounding mode,
|
// Note that our hex float formatting rounds according to the rounding mode,
|
||||||
// while libc may not; as a result we may differ in the last digit. So this
|
// while libc may not; as a result we may differ in the last digit. So this
|
||||||
// requires manual comparison.
|
// requires manual comparison.
|
||||||
let mut c_storage = [0u8; 256];
|
|
||||||
let c_storage_ptr = c_storage.as_mut_ptr() as *mut c_char;
|
|
||||||
let mut rust_str = String::with_capacity(256);
|
let mut rust_str = String::with_capacity(256);
|
||||||
|
|
||||||
let c_fmt = b"%.*a\0".as_ptr() as *const c_char;
|
let mut c_storage = [0u8; 256];
|
||||||
|
let mut libc_sprintf = libc_sprintf_one_float_with_precision(&mut c_storage, c"%.*a");
|
||||||
|
|
||||||
let mut failed = false;
|
let mut failed = false;
|
||||||
for sign in [1.0, -1.0].into_iter() {
|
for sign in [1.0, -1.0].into_iter() {
|
||||||
for mut v in [0.0, 0.5, 1.0, 1.5, PI, TAU, E].into_iter() {
|
for mut v in [0.0, 0.5, 1.0, 1.5, PI, TAU, E].into_iter() {
|
||||||
v *= sign;
|
v *= sign;
|
||||||
for preci in 1..=200_i32 {
|
for preci in 1..=200_usize {
|
||||||
rust_str.clear();
|
rust_str.clear();
|
||||||
crate::sprintf!(=> &mut rust_str, "%.*a", preci, v);
|
crate::sprintf!(=> &mut rust_str, "%.*a", preci, v);
|
||||||
|
|
||||||
let printf_str = unsafe {
|
let printf_str = libc_sprintf(preci, v);
|
||||||
let len = libc::snprintf(c_storage_ptr, c_storage.len(), c_fmt, preci, v);
|
|
||||||
assert!(len >= 0);
|
|
||||||
let sl = std::slice::from_raw_parts(c_storage_ptr as *const u8, len as usize);
|
|
||||||
std::str::from_utf8(sl).unwrap()
|
|
||||||
};
|
|
||||||
if rust_str != printf_str {
|
if rust_str != printf_str {
|
||||||
println!(
|
println!(
|
||||||
"Our printf and libc disagree on hex formatting of float: {v}
|
"Our printf and libc disagree on hex formatting of float: {v}
|
||||||
@@ -886,14 +884,33 @@ fn test_float_hex_prec() {
|
|||||||
assert!(!failed);
|
assert!(!failed);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_exhaustive(rust_fmt: &str, c_fmt: *const c_char) {
|
fn libc_sprintf_one_float_with_precision<'a>(
|
||||||
|
storage: &'a mut [u8],
|
||||||
|
fmt: &'a CStr,
|
||||||
|
) -> impl FnMut(usize, f64) -> &'a str {
|
||||||
|
|preci, float_val| unsafe {
|
||||||
|
let storage_ptr = storage.as_mut_ptr();
|
||||||
|
let len = libc::snprintf(
|
||||||
|
storage_ptr.cast(),
|
||||||
|
storage.len(),
|
||||||
|
fmt.as_ptr(),
|
||||||
|
preci,
|
||||||
|
float_val,
|
||||||
|
);
|
||||||
|
assert!(len >= 0);
|
||||||
|
let sl = std::slice::from_raw_parts(storage_ptr, len as usize);
|
||||||
|
std::str::from_utf8(sl).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_exhaustive(rust_fmt: &str, c_fmt: &CStr) {
|
||||||
// "There's only 4 billion floats so test them all."
|
// "There's only 4 billion floats so test them all."
|
||||||
// This tests a format string expected to be of the form "%.*g" or "%.*e".
|
// This tests a format string expected to be of the form "%.*g" or "%.*e".
|
||||||
// That is, it takes a precision and a double.
|
// That is, it takes a precision and a double.
|
||||||
println!("Testing {rust_fmt}");
|
println!("Testing {rust_fmt}");
|
||||||
let mut rust_str = String::with_capacity(128);
|
let mut rust_str = String::with_capacity(128);
|
||||||
let mut c_storage = [0u8; 128];
|
let mut c_storage = [0u8; 128];
|
||||||
let c_storage_ptr = c_storage.as_mut_ptr() as *mut c_char;
|
let mut libc_sprintf = libc_sprintf_one_float_with_precision(&mut c_storage, c_fmt);
|
||||||
|
|
||||||
for i in 0..=u32::MAX {
|
for i in 0..=u32::MAX {
|
||||||
if i % 1000000 == 0 {
|
if i % 1000000 == 0 {
|
||||||
@@ -905,12 +922,7 @@ fn test_exhaustive(rust_fmt: &str, c_fmt: *const c_char) {
|
|||||||
rust_str.clear();
|
rust_str.clear();
|
||||||
crate::sprintf!(=> &mut rust_str, rust_fmt, preci, ff);
|
crate::sprintf!(=> &mut rust_str, rust_fmt, preci, ff);
|
||||||
|
|
||||||
let printf_str = unsafe {
|
let printf_str = libc_sprintf(preci, ff);
|
||||||
let len = libc::snprintf(c_storage_ptr, c_storage.len(), c_fmt, preci, ff);
|
|
||||||
assert!(len >= 0);
|
|
||||||
let sl = std::slice::from_raw_parts(c_storage_ptr as *const u8, len as usize);
|
|
||||||
std::str::from_utf8(sl).unwrap()
|
|
||||||
};
|
|
||||||
if rust_str != printf_str {
|
if rust_str != printf_str {
|
||||||
println!(
|
println!(
|
||||||
"Rust and libc disagree on formatting float {i:x}: {ff}\n
|
"Rust and libc disagree on formatting float {i:x}: {ff}\n
|
||||||
@@ -929,19 +941,19 @@ fn test_exhaustive(rust_fmt: &str, c_fmt: *const c_char) {
|
|||||||
#[ignore]
|
#[ignore]
|
||||||
fn test_float_g_exhaustive() {
|
fn test_float_g_exhaustive() {
|
||||||
// To run: cargo test test_float_g_exhaustive --release -- --ignored --nocapture
|
// To run: cargo test test_float_g_exhaustive --release -- --ignored --nocapture
|
||||||
test_exhaustive("%.*g", b"%.*g\0".as_ptr() as *const c_char);
|
test_exhaustive("%.*g", c"%.*g");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
#[ignore]
|
||||||
fn test_float_e_exhaustive() {
|
fn test_float_e_exhaustive() {
|
||||||
// To run: cargo test test_float_e_exhaustive --release -- --ignored --nocapture
|
// To run: cargo test test_float_e_exhaustive --release -- --ignored --nocapture
|
||||||
test_exhaustive("%.*e", b"%.*e\0".as_ptr() as *const c_char);
|
test_exhaustive("%.*e", c"%.*e");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
#[ignore]
|
||||||
fn test_float_f_exhaustive() {
|
fn test_float_f_exhaustive() {
|
||||||
// To run: cargo test test_float_f_exhaustive --release -- --ignored --nocapture
|
// To run: cargo test test_float_f_exhaustive --release -- --ignored --nocapture
|
||||||
test_exhaustive("%.*f", b"%.*f\0".as_ptr() as *const c_char);
|
test_exhaustive("%.*f", c"%.*f");
|
||||||
}
|
}
|
||||||
|
|||||||
14
crates/tempfile/Cargo.toml
Normal file
14
crates/tempfile/Cargo.toml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
[package]
|
||||||
|
name = "fish-tempfile"
|
||||||
|
edition.workspace = true
|
||||||
|
rust-version.workspace = true
|
||||||
|
version = "0.0.0"
|
||||||
|
repository.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
nix = { workspace = true, features = ["fs", "feature"] }
|
||||||
|
rand.workspace = true
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
171
crates/tempfile/src/lib.rs
Normal file
171
crates/tempfile/src/lib.rs
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
use std::{
|
||||||
|
ffi::OsString,
|
||||||
|
fs::{File, OpenOptions},
|
||||||
|
io::ErrorKind,
|
||||||
|
path::PathBuf,
|
||||||
|
};
|
||||||
|
|
||||||
|
use rand::distr::{Alphanumeric, Distribution};
|
||||||
|
|
||||||
|
pub struct TempFile {
|
||||||
|
file: File,
|
||||||
|
path: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TempFile {
|
||||||
|
pub fn get(&self) -> &File {
|
||||||
|
&self.file
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_mut(&mut self) -> &mut File {
|
||||||
|
&mut self.file
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn path(&self) -> &PathBuf {
|
||||||
|
&self.path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TempFile {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = std::fs::remove_file(&self.path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TempDir {
|
||||||
|
path: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TempDir {
|
||||||
|
pub fn path(&self) -> &PathBuf {
|
||||||
|
&self.path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TempDir {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = std::fs::remove_dir_all(&self.path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a random filename with the given prefix.
|
||||||
|
/// Appends a random sequence of alphanumeric ASCII characters.
|
||||||
|
pub fn random_filename(mut prefix: OsString) -> OsString {
|
||||||
|
let mut rng = rand::rng();
|
||||||
|
let suffix_length = 10;
|
||||||
|
let random_part: String = Alphanumeric
|
||||||
|
.sample_iter(&mut rng)
|
||||||
|
.take(suffix_length)
|
||||||
|
.map(char::from)
|
||||||
|
.collect();
|
||||||
|
assert_eq!(random_part.len(), suffix_length);
|
||||||
|
prefix.push(random_part);
|
||||||
|
prefix
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tries to create a new file at the path returned by `generate_path`.
|
||||||
|
/// If a file already exists at this path, `generate_path` will be called again and file creation
|
||||||
|
/// will be retried. This is repeated until a new file is created, or an error occurs.
|
||||||
|
pub fn create_file_with_retry(
|
||||||
|
generate_path: impl Fn() -> PathBuf,
|
||||||
|
) -> (PathBuf, std::io::Result<File>) {
|
||||||
|
loop {
|
||||||
|
let path = generate_path();
|
||||||
|
match OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.write(true)
|
||||||
|
.create_new(true)
|
||||||
|
.open(&path)
|
||||||
|
{
|
||||||
|
Ok(file) => {
|
||||||
|
return (path, Ok(file));
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
if e.kind() != ErrorKind::AlreadyExists {
|
||||||
|
return (path, Err(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tries to create a new temporary file in the operating system's default location for temporary
|
||||||
|
/// files.
|
||||||
|
/// On success, a [`TempFile`] is returned.
|
||||||
|
/// When this struct is dropped, the backing file will be deleted.
|
||||||
|
pub fn new_file() -> std::io::Result<TempFile> {
|
||||||
|
let (path, result) = create_file_with_retry(|| {
|
||||||
|
std::env::temp_dir().join(random_filename(OsString::from("fish_tmp_")))
|
||||||
|
});
|
||||||
|
let file = result?;
|
||||||
|
Ok(TempFile { file, path })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tries to create a new temporary directory using `mkdtemp`.
|
||||||
|
/// On success, a [`TempDir`] is returned.
|
||||||
|
/// When this struct is dropped, the backing directory, including all its contents, will be deleted.
|
||||||
|
pub fn new_dir() -> std::io::Result<TempDir> {
|
||||||
|
let template = std::env::temp_dir().join("fish_tmp_XXXXXX");
|
||||||
|
let path = nix::unistd::mkdtemp(&template)?;
|
||||||
|
Ok(TempDir { path })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::{
|
||||||
|
fs::File,
|
||||||
|
io::{Read, Seek, Write},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn create_tempfile() {
|
||||||
|
super::new_file().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "file should no longer exist")]
|
||||||
|
fn use_tempfile() {
|
||||||
|
let mut tempfile = super::new_file().unwrap();
|
||||||
|
let expected_content = "test";
|
||||||
|
{
|
||||||
|
let file = tempfile.get_mut();
|
||||||
|
file.write_all(expected_content.as_bytes()).unwrap();
|
||||||
|
file.seek(std::io::SeekFrom::Start(0)).unwrap();
|
||||||
|
}
|
||||||
|
let mut actual_content = String::new();
|
||||||
|
{
|
||||||
|
let mut file = tempfile.get();
|
||||||
|
file.read_to_string(&mut actual_content).unwrap();
|
||||||
|
}
|
||||||
|
let path = tempfile.path().to_owned();
|
||||||
|
drop(tempfile);
|
||||||
|
assert_eq!(expected_content, actual_content);
|
||||||
|
File::open(&path).expect("file should no longer exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn create_tempdir() {
|
||||||
|
super::new_dir().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "file should no longer exist")]
|
||||||
|
fn use_tempdir() {
|
||||||
|
let tempdir = super::new_dir().unwrap();
|
||||||
|
let file_path = tempdir.path().join("foo");
|
||||||
|
let expected_content = "test";
|
||||||
|
{
|
||||||
|
let mut file = File::create(&file_path).unwrap();
|
||||||
|
file.write_all(expected_content.as_bytes()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut file = File::open(&file_path).unwrap();
|
||||||
|
let mut actual_content = String::new();
|
||||||
|
file.read_to_string(&mut actual_content).unwrap();
|
||||||
|
assert_eq!(expected_content, actual_content);
|
||||||
|
}
|
||||||
|
drop(tempdir);
|
||||||
|
File::open(&file_path).expect("file should no longer exist");
|
||||||
|
}
|
||||||
|
}
|
||||||
14
crates/wchar/Cargo.toml
Normal file
14
crates/wchar/Cargo.toml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
[package]
|
||||||
|
name = "fish-wchar"
|
||||||
|
edition.workspace = true
|
||||||
|
rust-version.workspace = true
|
||||||
|
version = "0.0.0"
|
||||||
|
repository.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
fish-common.workspace = true
|
||||||
|
widestring.workspace = true
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
@@ -1,11 +1,51 @@
|
|||||||
use std::{iter, slice};
|
//! Support for wide strings.
|
||||||
|
//!
|
||||||
|
//! There are two wide string types that are commonly used:
|
||||||
|
//! - wstr: a string slice without a nul terminator. Like `&str` but wide chars.
|
||||||
|
//! - WString: an owning string without a nul terminator. Like `String` but wide chars.
|
||||||
|
|
||||||
use crate::{
|
use fish_common::{ENCODE_DIRECT_BASE, ENCODE_DIRECT_END, subslice_position};
|
||||||
common::subslice_position,
|
use std::{iter, slice};
|
||||||
wchar::{wstr, WString},
|
pub use widestring::{Utf32Str as wstr, Utf32String as WString, utfstr::CharsUtf32};
|
||||||
L,
|
|
||||||
};
|
pub mod prelude {
|
||||||
use widestring::utfstr::CharsUtf32;
|
pub use crate::{IntoCharIter, L, ToWString, WExt, WString, wstr};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a wstr string slice, like the "L" prefix of C++.
|
||||||
|
/// The result is of type wstr.
|
||||||
|
/// It is NOT nul-terminated.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! L {
|
||||||
|
($string:expr) => {
|
||||||
|
widestring::utf32str!($string)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Encode a literal byte in a UTF-32 character. This is required for e.g. the echo builtin, whose
|
||||||
|
/// escape sequences can be used to construct raw byte sequences which are then interpreted as e.g.
|
||||||
|
/// UTF-8 by the terminal. If we were to interpret each of those bytes as a codepoint and encode it
|
||||||
|
/// as a UTF-32 character, printing them would result in several characters instead of one UTF-8
|
||||||
|
/// character.
|
||||||
|
///
|
||||||
|
/// See <https://github.com/fish-shell/fish-shell/issues/1894>.
|
||||||
|
pub fn encode_byte_to_char(byte: u8) -> char {
|
||||||
|
char::from_u32(u32::from(ENCODE_DIRECT_BASE) + u32::from(byte))
|
||||||
|
.expect("private-use codepoint should be valid char")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decode a literal byte from a UTF-32 character.
|
||||||
|
pub fn decode_byte_from_char(c: char) -> Option<u8> {
|
||||||
|
if c >= ENCODE_DIRECT_BASE && c < ENCODE_DIRECT_END {
|
||||||
|
Some(
|
||||||
|
(u32::from(c) - u32::from(ENCODE_DIRECT_BASE))
|
||||||
|
.try_into()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Helpers to convert things to widestring.
|
/// Helpers to convert things to widestring.
|
||||||
/// This is like std::string::ToString.
|
/// This is like std::string::ToString.
|
||||||
@@ -56,44 +96,26 @@ fn to_wstring(&self) -> WString {
|
|||||||
macro_rules! impl_to_wstring_unsigned {
|
macro_rules! impl_to_wstring_unsigned {
|
||||||
($($t:ty), *) => {
|
($($t:ty), *) => {
|
||||||
$(
|
$(
|
||||||
impl ToWString for $t {
|
impl ToWString for $t {
|
||||||
fn to_wstring(&self) -> WString {
|
fn to_wstring(&self) -> WString {
|
||||||
to_wstring_impl(*self as u64, false)
|
to_wstring_impl(*self as u64, false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
)*
|
||||||
)*
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_to_wstring_unsigned!(u8, u16, u32, u64, u128, usize);
|
impl_to_wstring_unsigned!(u8, u16, u32, u64, u128, usize);
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_to_wstring() {
|
|
||||||
assert_eq!(0_u64.to_wstring(), "0");
|
|
||||||
assert_eq!(1_u64.to_wstring(), "1");
|
|
||||||
assert_eq!(0_i64.to_wstring(), "0");
|
|
||||||
assert_eq!(1_i64.to_wstring(), "1");
|
|
||||||
assert_eq!((-1_i64).to_wstring(), "-1");
|
|
||||||
assert_eq!((-5_i64).to_wstring(), "-5");
|
|
||||||
let mut val: i64 = 1;
|
|
||||||
loop {
|
|
||||||
assert_eq!(val.to_wstring(), val.to_string());
|
|
||||||
let Some(next) = val.checked_mul(-3) else {
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
val = next;
|
|
||||||
}
|
|
||||||
assert_eq!(u64::MAX.to_wstring(), "18446744073709551615");
|
|
||||||
assert_eq!(i64::MIN.to_wstring(), "-9223372036854775808");
|
|
||||||
assert_eq!(i64::MAX.to_wstring(), "9223372036854775807");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A trait for a thing that can produce a double-ended, cloneable
|
/// A trait for a thing that can produce a double-ended, cloneable
|
||||||
/// iterator of chars.
|
/// iterator of chars.
|
||||||
/// Common implementations include char, &str, &wstr, &WString.
|
/// Common implementations include char, &str, &wstr, &WString.
|
||||||
pub trait IntoCharIter {
|
pub trait IntoCharIter {
|
||||||
type Iter: DoubleEndedIterator<Item = char> + Clone;
|
type Iter: DoubleEndedIterator<Item = char> + Clone;
|
||||||
fn chars(self) -> Self::Iter;
|
fn chars(self) -> Self::Iter;
|
||||||
|
fn extend_wstring(&self, _out: &mut WString) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoCharIter for char {
|
impl IntoCharIter for char {
|
||||||
@@ -110,12 +132,23 @@ fn chars(self) -> Self::Iter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> IntoCharIter for &'a String {
|
||||||
|
type Iter = std::str::Chars<'a>;
|
||||||
|
fn chars(self) -> Self::Iter {
|
||||||
|
str::chars(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> IntoCharIter for &'a [char] {
|
impl<'a> IntoCharIter for &'a [char] {
|
||||||
type Iter = iter::Copied<slice::Iter<'a, char>>;
|
type Iter = iter::Copied<slice::Iter<'a, char>>;
|
||||||
|
|
||||||
fn chars(self) -> Self::Iter {
|
fn chars(self) -> Self::Iter {
|
||||||
self.iter().copied()
|
self.iter().copied()
|
||||||
}
|
}
|
||||||
|
fn extend_wstring(&self, out: &mut WString) -> bool {
|
||||||
|
out.push_utfstr(wstr::from_char_slice(self));
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> IntoCharIter for &'a wstr {
|
impl<'a> IntoCharIter for &'a wstr {
|
||||||
@@ -123,6 +156,9 @@ impl<'a> IntoCharIter for &'a wstr {
|
|||||||
fn chars(self) -> Self::Iter {
|
fn chars(self) -> Self::Iter {
|
||||||
wstr::chars(self)
|
wstr::chars(self)
|
||||||
}
|
}
|
||||||
|
fn extend_wstring(&self, out: &mut WString) -> bool {
|
||||||
|
self.as_char_slice().extend_wstring(out)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> IntoCharIter for &'a WString {
|
impl<'a> IntoCharIter for &'a WString {
|
||||||
@@ -130,6 +166,9 @@ impl<'a> IntoCharIter for &'a WString {
|
|||||||
fn chars(self) -> Self::Iter {
|
fn chars(self) -> Self::Iter {
|
||||||
wstr::chars(self)
|
wstr::chars(self)
|
||||||
}
|
}
|
||||||
|
fn extend_wstring(&self, out: &mut WString) -> bool {
|
||||||
|
self.as_char_slice().extend_wstring(out)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also support `str.chars()` itself.
|
// Also support `str.chars()` itself.
|
||||||
@@ -148,6 +187,23 @@ fn chars(self) -> Self::Iter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a: 'b, 'b> IntoCharIter for &'b std::borrow::Cow<'a, str> {
|
||||||
|
type Iter = std::str::Chars<'b>;
|
||||||
|
fn chars(self) -> Self::Iter {
|
||||||
|
str::chars(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a: 'b, 'b> IntoCharIter for &'b std::borrow::Cow<'a, wstr> {
|
||||||
|
type Iter = CharsUtf32<'b>;
|
||||||
|
fn chars(self) -> Self::Iter {
|
||||||
|
wstr::chars(self)
|
||||||
|
}
|
||||||
|
fn extend_wstring(&self, out: &mut WString) -> bool {
|
||||||
|
self.as_char_slice().extend_wstring(out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Return true if `prefix` is a prefix of `contents`.
|
/// Return true if `prefix` is a prefix of `contents`.
|
||||||
fn iter_prefixes_iter<Prefix, Contents>(prefix: Prefix, mut contents: Contents) -> bool
|
fn iter_prefixes_iter<Prefix, Contents>(prefix: Prefix, mut contents: Contents) -> bool
|
||||||
where
|
where
|
||||||
@@ -178,10 +234,10 @@ fn next(&mut self) -> Option<Self::Item> {
|
|||||||
if let Some(idx) = chars.iter().position(|c| *c == self.split) {
|
if let Some(idx) = chars.iter().position(|c| *c == self.split) {
|
||||||
let (prefix, rest) = chars.split_at(idx);
|
let (prefix, rest) = chars.split_at(idx);
|
||||||
self.chars = Some(&rest[1..]);
|
self.chars = Some(&rest[1..]);
|
||||||
return Some(wstr::from_char_slice(prefix));
|
Some(wstr::from_char_slice(prefix))
|
||||||
} else {
|
} else {
|
||||||
self.chars = None;
|
self.chars = None;
|
||||||
return Some(wstr::from_char_slice(chars));
|
Some(wstr::from_char_slice(chars))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -324,8 +380,28 @@ fn as_char_slice(&self) -> &[char] {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::wchar::L;
|
|
||||||
/// Write some tests.
|
#[test]
|
||||||
|
fn test_to_wstring() {
|
||||||
|
assert_eq!(0_u64.to_wstring(), "0");
|
||||||
|
assert_eq!(1_u64.to_wstring(), "1");
|
||||||
|
assert_eq!(0_i64.to_wstring(), "0");
|
||||||
|
assert_eq!(1_i64.to_wstring(), "1");
|
||||||
|
assert_eq!((-1_i64).to_wstring(), "-1");
|
||||||
|
assert_eq!((-5_i64).to_wstring(), "-5");
|
||||||
|
let mut val: i64 = 1;
|
||||||
|
loop {
|
||||||
|
assert_eq!(val.to_wstring(), val.to_string());
|
||||||
|
let Some(next) = val.checked_mul(-3) else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
val = next;
|
||||||
|
}
|
||||||
|
assert_eq!(u64::MAX.to_wstring(), "18446744073709551615");
|
||||||
|
assert_eq!(i64::MIN.to_wstring(), "-9223372036854775808");
|
||||||
|
assert_eq!(i64::MAX.to_wstring(), "9223372036854775807");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_find_char() {
|
fn test_find_char() {
|
||||||
assert_eq!(Some(0), L!("abc").find_char('a'));
|
assert_eq!(Some(0), L!("abc").find_char('a'));
|
||||||
10
crates/widecharwidth/Cargo.toml
Normal file
10
crates/widecharwidth/Cargo.toml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "fish-widecharwidth"
|
||||||
|
edition.workspace = true
|
||||||
|
rust-version.workspace = true
|
||||||
|
version = "0.0.0"
|
||||||
|
repository.workspace = true
|
||||||
|
license = "CC0-1.0"
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* widechar_width.rs for Unicode 16.0.0
|
* widechar_width.rs for Unicode 17.0.0
|
||||||
* See https://github.com/ridiculousfish/widecharwidth/
|
* See https://github.com/ridiculousfish/widecharwidth/
|
||||||
*
|
*
|
||||||
* SHA1 file hashes:
|
* SHA1 file hashes:
|
||||||
@@ -11,11 +11,11 @@
|
|||||||
* The other hashes are simple `sha1sum` style hashes.
|
* The other hashes are simple `sha1sum` style hashes.
|
||||||
* )
|
* )
|
||||||
*
|
*
|
||||||
* generate.py: 2747bb9402d8eeeca8e566ff947f14308511ecb1
|
* generate.py: b35da43f176cc0d5880c67356ebb064048c5bac4
|
||||||
* template.js: 7921c1fe6bcb4ce17108929b599bfda097caedb7
|
* template.js: c455e7c973da323c43c98d6975fb8b024bf118f1
|
||||||
* UnicodeData.txt: 91df83276154240bcedef82a09bde77aa182cf8d
|
* UnicodeData.txt: 50dffef1b7d1f97b72e4c2adceb9b2245f0f34ba
|
||||||
* EastAsianWidth.txt: 0885c0fc1c21eb58954a3bfb785d78559b361d92
|
* EastAsianWidth.txt: 2cadc5034b6206ad84b75898a1d4186bb38fc12b
|
||||||
* emoji-data.txt: 1df2f8329dd9f5c238674807de736f316c6b9d87
|
* emoji-data.txt: 3d123e12f70f63e609c4281ce83dfdd9ac7443d2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
type R = (u32, u32);
|
type R = (u32, u32);
|
||||||
@@ -215,7 +215,8 @@ pub enum WcWidth {
|
|||||||
(0x01A55, 0x01A5E),
|
(0x01A55, 0x01A5E),
|
||||||
(0x01A60, 0x01A7C),
|
(0x01A60, 0x01A7C),
|
||||||
(0x01A7F, 0x01A7F),
|
(0x01A7F, 0x01A7F),
|
||||||
(0x01AB0, 0x01ACE),
|
(0x01AB0, 0x01ADD),
|
||||||
|
(0x01AE0, 0x01AEB),
|
||||||
(0x01B00, 0x01B04),
|
(0x01B00, 0x01B04),
|
||||||
(0x01B34, 0x01B44),
|
(0x01B34, 0x01B44),
|
||||||
(0x01B6B, 0x01B73),
|
(0x01B6B, 0x01B73),
|
||||||
@@ -281,7 +282,7 @@ pub enum WcWidth {
|
|||||||
(0x10D24, 0x10D27),
|
(0x10D24, 0x10D27),
|
||||||
(0x10D69, 0x10D6D),
|
(0x10D69, 0x10D6D),
|
||||||
(0x10EAB, 0x10EAC),
|
(0x10EAB, 0x10EAC),
|
||||||
(0x10EFC, 0x10EFF),
|
(0x10EFA, 0x10EFF),
|
||||||
(0x10F46, 0x10F50),
|
(0x10F46, 0x10F50),
|
||||||
(0x10F82, 0x10F85),
|
(0x10F82, 0x10F85),
|
||||||
(0x11000, 0x11002),
|
(0x11000, 0x11002),
|
||||||
@@ -343,6 +344,7 @@ pub enum WcWidth {
|
|||||||
(0x11A47, 0x11A47),
|
(0x11A47, 0x11A47),
|
||||||
(0x11A51, 0x11A5B),
|
(0x11A51, 0x11A5B),
|
||||||
(0x11A8A, 0x11A99),
|
(0x11A8A, 0x11A99),
|
||||||
|
(0x11B60, 0x11B67),
|
||||||
(0x11C2F, 0x11C36),
|
(0x11C2F, 0x11C36),
|
||||||
(0x11C38, 0x11C3F),
|
(0x11C38, 0x11C3F),
|
||||||
(0x11C92, 0x11CA7),
|
(0x11C92, 0x11CA7),
|
||||||
@@ -397,6 +399,10 @@ pub enum WcWidth {
|
|||||||
(0x1E2EC, 0x1E2EF),
|
(0x1E2EC, 0x1E2EF),
|
||||||
(0x1E4EC, 0x1E4EF),
|
(0x1E4EC, 0x1E4EF),
|
||||||
(0x1E5EE, 0x1E5EF),
|
(0x1E5EE, 0x1E5EF),
|
||||||
|
(0x1E6E3, 0x1E6E3),
|
||||||
|
(0x1E6E6, 0x1E6E6),
|
||||||
|
(0x1E6EE, 0x1E6EF),
|
||||||
|
(0x1E6F5, 0x1E6F5),
|
||||||
(0x1E8D0, 0x1E8D6),
|
(0x1E8D0, 0x1E8D6),
|
||||||
(0x1E944, 0x1E94A),
|
(0x1E944, 0x1E94A),
|
||||||
(0xE0100, 0xE01EF),
|
(0xE0100, 0xE01EF),
|
||||||
@@ -434,10 +440,10 @@ pub enum WcWidth {
|
|||||||
(0x0FF01, 0x0FF60),
|
(0x0FF01, 0x0FF60),
|
||||||
(0x0FFE0, 0x0FFE6),
|
(0x0FFE0, 0x0FFE6),
|
||||||
(0x16FE0, 0x16FE4),
|
(0x16FE0, 0x16FE4),
|
||||||
(0x16FF0, 0x16FF1),
|
(0x16FF0, 0x16FF6),
|
||||||
(0x17000, 0x187F7),
|
(0x17000, 0x18CD5),
|
||||||
(0x18800, 0x18CD5),
|
(0x18CFF, 0x18D1E),
|
||||||
(0x18CFF, 0x18D08),
|
(0x18D80, 0x18DF2),
|
||||||
(0x1AFF0, 0x1AFF3),
|
(0x1AFF0, 0x1AFF3),
|
||||||
(0x1AFF5, 0x1AFFB),
|
(0x1AFF5, 0x1AFFB),
|
||||||
(0x1AFFD, 0x1AFFE),
|
(0x1AFFD, 0x1AFFE),
|
||||||
@@ -461,7 +467,7 @@ pub enum WcWidth {
|
|||||||
(0x1F57A, 0x1F57A),
|
(0x1F57A, 0x1F57A),
|
||||||
(0x1F5A4, 0x1F5A4),
|
(0x1F5A4, 0x1F5A4),
|
||||||
(0x1F6D1, 0x1F6D2),
|
(0x1F6D1, 0x1F6D2),
|
||||||
(0x1F6D5, 0x1F6D7),
|
(0x1F6D5, 0x1F6D8),
|
||||||
(0x1F6DC, 0x1F6DF),
|
(0x1F6DC, 0x1F6DF),
|
||||||
(0x1F6F4, 0x1F6FC),
|
(0x1F6F4, 0x1F6FC),
|
||||||
(0x1F7E0, 0x1F7EB),
|
(0x1F7E0, 0x1F7EB),
|
||||||
@@ -473,11 +479,12 @@ pub enum WcWidth {
|
|||||||
(0x1F985, 0x1F9BF),
|
(0x1F985, 0x1F9BF),
|
||||||
(0x1F9C1, 0x1F9FF),
|
(0x1F9C1, 0x1F9FF),
|
||||||
(0x1FA70, 0x1FA7C),
|
(0x1FA70, 0x1FA7C),
|
||||||
(0x1FA80, 0x1FA89),
|
(0x1FA80, 0x1FA8A),
|
||||||
(0x1FA8F, 0x1FAC6),
|
(0x1FA8E, 0x1FAC6),
|
||||||
(0x1FACE, 0x1FADC),
|
(0x1FAC8, 0x1FAC8),
|
||||||
(0x1FADF, 0x1FAE9),
|
(0x1FACD, 0x1FADC),
|
||||||
(0x1FAF0, 0x1FAF8),
|
(0x1FADF, 0x1FAEA),
|
||||||
|
(0x1FAEF, 0x1FAF8),
|
||||||
(0x20000, 0x2FFFD),
|
(0x20000, 0x2FFFD),
|
||||||
(0x30000, 0x3FFFD),
|
(0x30000, 0x3FFFD),
|
||||||
];
|
];
|
||||||
@@ -688,7 +695,6 @@ pub enum WcWidth {
|
|||||||
(0x0085C, 0x0085D),
|
(0x0085C, 0x0085D),
|
||||||
(0x0085F, 0x0085F),
|
(0x0085F, 0x0085F),
|
||||||
(0x0086B, 0x0086F),
|
(0x0086B, 0x0086F),
|
||||||
(0x0088F, 0x0088F),
|
|
||||||
(0x00892, 0x00896),
|
(0x00892, 0x00896),
|
||||||
(0x00984, 0x00984),
|
(0x00984, 0x00984),
|
||||||
(0x0098D, 0x0098E),
|
(0x0098D, 0x0098E),
|
||||||
@@ -772,7 +778,7 @@ pub enum WcWidth {
|
|||||||
(0x00C49, 0x00C49),
|
(0x00C49, 0x00C49),
|
||||||
(0x00C4E, 0x00C54),
|
(0x00C4E, 0x00C54),
|
||||||
(0x00C57, 0x00C57),
|
(0x00C57, 0x00C57),
|
||||||
(0x00C5B, 0x00C5C),
|
(0x00C5B, 0x00C5B),
|
||||||
(0x00C5E, 0x00C5F),
|
(0x00C5E, 0x00C5F),
|
||||||
(0x00C64, 0x00C65),
|
(0x00C64, 0x00C65),
|
||||||
(0x00C70, 0x00C76),
|
(0x00C70, 0x00C76),
|
||||||
@@ -784,7 +790,7 @@ pub enum WcWidth {
|
|||||||
(0x00CC5, 0x00CC5),
|
(0x00CC5, 0x00CC5),
|
||||||
(0x00CC9, 0x00CC9),
|
(0x00CC9, 0x00CC9),
|
||||||
(0x00CCE, 0x00CD4),
|
(0x00CCE, 0x00CD4),
|
||||||
(0x00CD7, 0x00CDC),
|
(0x00CD7, 0x00CDB),
|
||||||
(0x00CDF, 0x00CDF),
|
(0x00CDF, 0x00CDF),
|
||||||
(0x00CE4, 0x00CE5),
|
(0x00CE4, 0x00CE5),
|
||||||
(0x00CF0, 0x00CF0),
|
(0x00CF0, 0x00CF0),
|
||||||
@@ -880,7 +886,8 @@ pub enum WcWidth {
|
|||||||
(0x01A8A, 0x01A8F),
|
(0x01A8A, 0x01A8F),
|
||||||
(0x01A9A, 0x01A9F),
|
(0x01A9A, 0x01A9F),
|
||||||
(0x01AAE, 0x01AAF),
|
(0x01AAE, 0x01AAF),
|
||||||
(0x01ACF, 0x01AFF),
|
(0x01ADE, 0x01ADF),
|
||||||
|
(0x01AEC, 0x01AFF),
|
||||||
(0x01B4D, 0x01B4D),
|
(0x01B4D, 0x01B4D),
|
||||||
(0x01BF4, 0x01BFB),
|
(0x01BF4, 0x01BFB),
|
||||||
(0x01C38, 0x01C3A),
|
(0x01C38, 0x01C3A),
|
||||||
@@ -909,13 +916,12 @@ pub enum WcWidth {
|
|||||||
(0x02072, 0x02073),
|
(0x02072, 0x02073),
|
||||||
(0x0208F, 0x0208F),
|
(0x0208F, 0x0208F),
|
||||||
(0x0209D, 0x0209F),
|
(0x0209D, 0x0209F),
|
||||||
(0x020C1, 0x020CF),
|
(0x020C2, 0x020CF),
|
||||||
(0x020F1, 0x020FF),
|
(0x020F1, 0x020FF),
|
||||||
(0x0218C, 0x0218F),
|
(0x0218C, 0x0218F),
|
||||||
(0x0242A, 0x0243F),
|
(0x0242A, 0x0243F),
|
||||||
(0x0244B, 0x0245F),
|
(0x0244B, 0x0245F),
|
||||||
(0x02B74, 0x02B75),
|
(0x02B74, 0x02B75),
|
||||||
(0x02B96, 0x02B96),
|
|
||||||
(0x02CF4, 0x02CF8),
|
(0x02CF4, 0x02CF8),
|
||||||
(0x02D26, 0x02D26),
|
(0x02D26, 0x02D26),
|
||||||
(0x02D28, 0x02D2C),
|
(0x02D28, 0x02D2C),
|
||||||
@@ -948,10 +954,7 @@ pub enum WcWidth {
|
|||||||
(0x0A4C7, 0x0A4CF),
|
(0x0A4C7, 0x0A4CF),
|
||||||
(0x0A62C, 0x0A63F),
|
(0x0A62C, 0x0A63F),
|
||||||
(0x0A6F8, 0x0A6FF),
|
(0x0A6F8, 0x0A6FF),
|
||||||
(0x0A7CE, 0x0A7CF),
|
(0x0A7DD, 0x0A7F0),
|
||||||
(0x0A7D2, 0x0A7D2),
|
|
||||||
(0x0A7D4, 0x0A7D4),
|
|
||||||
(0x0A7DD, 0x0A7F1),
|
|
||||||
(0x0A82D, 0x0A82F),
|
(0x0A82D, 0x0A82F),
|
||||||
(0x0A83A, 0x0A83F),
|
(0x0A83A, 0x0A83F),
|
||||||
(0x0A878, 0x0A87F),
|
(0x0A878, 0x0A87F),
|
||||||
@@ -988,9 +991,6 @@ pub enum WcWidth {
|
|||||||
(0x0FB3F, 0x0FB3F),
|
(0x0FB3F, 0x0FB3F),
|
||||||
(0x0FB42, 0x0FB42),
|
(0x0FB42, 0x0FB42),
|
||||||
(0x0FB45, 0x0FB45),
|
(0x0FB45, 0x0FB45),
|
||||||
(0x0FBC3, 0x0FBD2),
|
|
||||||
(0x0FD90, 0x0FD91),
|
|
||||||
(0x0FDC8, 0x0FDCE),
|
|
||||||
(0x0FE1A, 0x0FE1F),
|
(0x0FE1A, 0x0FE1F),
|
||||||
(0x0FE53, 0x0FE53),
|
(0x0FE53, 0x0FE53),
|
||||||
(0x0FE67, 0x0FE67),
|
(0x0FE67, 0x0FE67),
|
||||||
@@ -1060,7 +1060,7 @@ pub enum WcWidth {
|
|||||||
(0x108F6, 0x108FA),
|
(0x108F6, 0x108FA),
|
||||||
(0x1091C, 0x1091E),
|
(0x1091C, 0x1091E),
|
||||||
(0x1093A, 0x1093E),
|
(0x1093A, 0x1093E),
|
||||||
(0x10940, 0x1097F),
|
(0x1095A, 0x1097F),
|
||||||
(0x109B8, 0x109BB),
|
(0x109B8, 0x109BB),
|
||||||
(0x109D0, 0x109D1),
|
(0x109D0, 0x109D1),
|
||||||
(0x10A04, 0x10A04),
|
(0x10A04, 0x10A04),
|
||||||
@@ -1092,7 +1092,8 @@ pub enum WcWidth {
|
|||||||
(0x10EAA, 0x10EAA),
|
(0x10EAA, 0x10EAA),
|
||||||
(0x10EAE, 0x10EAF),
|
(0x10EAE, 0x10EAF),
|
||||||
(0x10EB2, 0x10EC1),
|
(0x10EB2, 0x10EC1),
|
||||||
(0x10EC5, 0x10EFB),
|
(0x10EC8, 0x10ECF),
|
||||||
|
(0x10ED9, 0x10EF9),
|
||||||
(0x10F28, 0x10F2F),
|
(0x10F28, 0x10F2F),
|
||||||
(0x10F5A, 0x10F6F),
|
(0x10F5A, 0x10F6F),
|
||||||
(0x10F8A, 0x10FAF),
|
(0x10F8A, 0x10FAF),
|
||||||
@@ -1175,7 +1176,8 @@ pub enum WcWidth {
|
|||||||
(0x11A48, 0x11A4F),
|
(0x11A48, 0x11A4F),
|
||||||
(0x11AA3, 0x11AAF),
|
(0x11AA3, 0x11AAF),
|
||||||
(0x11AF9, 0x11AFF),
|
(0x11AF9, 0x11AFF),
|
||||||
(0x11B0A, 0x11BBF),
|
(0x11B0A, 0x11B5F),
|
||||||
|
(0x11B68, 0x11BBF),
|
||||||
(0x11BE2, 0x11BEF),
|
(0x11BE2, 0x11BEF),
|
||||||
(0x11BFA, 0x11BFF),
|
(0x11BFA, 0x11BFF),
|
||||||
(0x11C09, 0x11C09),
|
(0x11C09, 0x11C09),
|
||||||
@@ -1197,7 +1199,9 @@ pub enum WcWidth {
|
|||||||
(0x11D8F, 0x11D8F),
|
(0x11D8F, 0x11D8F),
|
||||||
(0x11D92, 0x11D92),
|
(0x11D92, 0x11D92),
|
||||||
(0x11D99, 0x11D9F),
|
(0x11D99, 0x11D9F),
|
||||||
(0x11DAA, 0x11EDF),
|
(0x11DAA, 0x11DAF),
|
||||||
|
(0x11DDC, 0x11DDF),
|
||||||
|
(0x11DEA, 0x11EDF),
|
||||||
(0x11EF9, 0x11EFF),
|
(0x11EF9, 0x11EFF),
|
||||||
(0x11F11, 0x11F11),
|
(0x11F11, 0x11F11),
|
||||||
(0x11F3B, 0x11F3D),
|
(0x11F3B, 0x11F3D),
|
||||||
@@ -1226,17 +1230,19 @@ pub enum WcWidth {
|
|||||||
(0x16B78, 0x16B7C),
|
(0x16B78, 0x16B7C),
|
||||||
(0x16B90, 0x16D3F),
|
(0x16B90, 0x16D3F),
|
||||||
(0x16D7A, 0x16E3F),
|
(0x16D7A, 0x16E3F),
|
||||||
(0x16E9B, 0x16EFF),
|
(0x16E9B, 0x16E9F),
|
||||||
|
(0x16EB9, 0x16EBA),
|
||||||
|
(0x16ED4, 0x16EFF),
|
||||||
(0x16F4B, 0x16F4E),
|
(0x16F4B, 0x16F4E),
|
||||||
(0x16F88, 0x16F8E),
|
(0x16F88, 0x16F8E),
|
||||||
(0x16FA0, 0x16FDF),
|
(0x16FA0, 0x16FDF),
|
||||||
(0x16FE5, 0x16FEF),
|
(0x16FE5, 0x16FEF),
|
||||||
(0x16FF2, 0x16FFF),
|
(0x16FF7, 0x16FFF),
|
||||||
(0x17001, 0x187F6),
|
(0x17001, 0x187FE),
|
||||||
(0x187F8, 0x187FF),
|
|
||||||
(0x18CD6, 0x18CFE),
|
(0x18CD6, 0x18CFE),
|
||||||
(0x18D01, 0x18D07),
|
(0x18D01, 0x18D1D),
|
||||||
(0x18D09, 0x1AFEF),
|
(0x18D1F, 0x18D7F),
|
||||||
|
(0x18DF3, 0x1AFEF),
|
||||||
(0x1AFF4, 0x1AFF4),
|
(0x1AFF4, 0x1AFF4),
|
||||||
(0x1AFFC, 0x1AFFC),
|
(0x1AFFC, 0x1AFFC),
|
||||||
(0x1AFFF, 0x1AFFF),
|
(0x1AFFF, 0x1AFFF),
|
||||||
@@ -1251,8 +1257,10 @@ pub enum WcWidth {
|
|||||||
(0x1BC89, 0x1BC8F),
|
(0x1BC89, 0x1BC8F),
|
||||||
(0x1BC9A, 0x1BC9B),
|
(0x1BC9A, 0x1BC9B),
|
||||||
(0x1BCA4, 0x1CBFF),
|
(0x1BCA4, 0x1CBFF),
|
||||||
(0x1CCFA, 0x1CCFF),
|
(0x1CCFD, 0x1CCFF),
|
||||||
(0x1CEB4, 0x1CEFF),
|
(0x1CEB4, 0x1CEB9),
|
||||||
|
(0x1CED1, 0x1CEDF),
|
||||||
|
(0x1CEF1, 0x1CEFF),
|
||||||
(0x1CF2E, 0x1CF2F),
|
(0x1CF2E, 0x1CF2F),
|
||||||
(0x1CF47, 0x1CF4F),
|
(0x1CF47, 0x1CF4F),
|
||||||
(0x1CFC4, 0x1CFFF),
|
(0x1CFC4, 0x1CFFF),
|
||||||
@@ -1305,7 +1313,10 @@ pub enum WcWidth {
|
|||||||
(0x1E300, 0x1E4CF),
|
(0x1E300, 0x1E4CF),
|
||||||
(0x1E4FA, 0x1E5CF),
|
(0x1E4FA, 0x1E5CF),
|
||||||
(0x1E5FB, 0x1E5FE),
|
(0x1E5FB, 0x1E5FE),
|
||||||
(0x1E600, 0x1E7DF),
|
(0x1E600, 0x1E6BF),
|
||||||
|
(0x1E6DF, 0x1E6DF),
|
||||||
|
(0x1E6F6, 0x1E6FD),
|
||||||
|
(0x1E700, 0x1E7DF),
|
||||||
(0x1E7E7, 0x1E7E7),
|
(0x1E7E7, 0x1E7E7),
|
||||||
(0x1E7EC, 0x1E7EC),
|
(0x1E7EC, 0x1E7EC),
|
||||||
(0x1E7EF, 0x1E7EF),
|
(0x1E7EF, 0x1E7EF),
|
||||||
@@ -1363,10 +1374,9 @@ pub enum WcWidth {
|
|||||||
(0x1F249, 0x1F24F),
|
(0x1F249, 0x1F24F),
|
||||||
(0x1F252, 0x1F25F),
|
(0x1F252, 0x1F25F),
|
||||||
(0x1F266, 0x1F2FF),
|
(0x1F266, 0x1F2FF),
|
||||||
(0x1F6D8, 0x1F6DB),
|
(0x1F6D9, 0x1F6DB),
|
||||||
(0x1F6ED, 0x1F6EF),
|
(0x1F6ED, 0x1F6EF),
|
||||||
(0x1F6FD, 0x1F6FF),
|
(0x1F6FD, 0x1F6FF),
|
||||||
(0x1F777, 0x1F77A),
|
|
||||||
(0x1F7DA, 0x1F7DF),
|
(0x1F7DA, 0x1F7DF),
|
||||||
(0x1F7EC, 0x1F7EF),
|
(0x1F7EC, 0x1F7EF),
|
||||||
(0x1F7F1, 0x1F7FF),
|
(0x1F7F1, 0x1F7FF),
|
||||||
@@ -1376,25 +1386,26 @@ pub enum WcWidth {
|
|||||||
(0x1F888, 0x1F88F),
|
(0x1F888, 0x1F88F),
|
||||||
(0x1F8AE, 0x1F8AF),
|
(0x1F8AE, 0x1F8AF),
|
||||||
(0x1F8BC, 0x1F8BF),
|
(0x1F8BC, 0x1F8BF),
|
||||||
(0x1F8C2, 0x1F8FF),
|
(0x1F8C2, 0x1F8CF),
|
||||||
(0x1FA54, 0x1FA5F),
|
(0x1F8D9, 0x1F8FF),
|
||||||
|
(0x1FA58, 0x1FA5F),
|
||||||
(0x1FA6E, 0x1FA6F),
|
(0x1FA6E, 0x1FA6F),
|
||||||
(0x1FA7D, 0x1FA7F),
|
(0x1FA7D, 0x1FA7F),
|
||||||
(0x1FA8A, 0x1FA8E),
|
(0x1FA8B, 0x1FA8D),
|
||||||
(0x1FAC7, 0x1FACD),
|
(0x1FAC7, 0x1FAC7),
|
||||||
|
(0x1FAC9, 0x1FACC),
|
||||||
(0x1FADD, 0x1FADE),
|
(0x1FADD, 0x1FADE),
|
||||||
(0x1FAEA, 0x1FAEF),
|
(0x1FAEB, 0x1FAEE),
|
||||||
(0x1FAF9, 0x1FAFF),
|
(0x1FAF9, 0x1FAFF),
|
||||||
(0x1FB93, 0x1FB93),
|
(0x1FB93, 0x1FB93),
|
||||||
(0x1FBFA, 0x1FFFD),
|
(0x1FBFB, 0x1FFFD),
|
||||||
(0x20001, 0x2A6DE),
|
(0x20001, 0x2A6DE),
|
||||||
(0x2A6E0, 0x2A6FF),
|
(0x2A6E0, 0x2A6FF),
|
||||||
(0x2A701, 0x2B738),
|
(0x2A701, 0x2B73E),
|
||||||
(0x2B73A, 0x2B73F),
|
|
||||||
(0x2B741, 0x2B81C),
|
(0x2B741, 0x2B81C),
|
||||||
(0x2B81E, 0x2B81F),
|
(0x2B81E, 0x2B81F),
|
||||||
(0x2B821, 0x2CEA0),
|
(0x2B821, 0x2CEAC),
|
||||||
(0x2CEA2, 0x2CEAF),
|
(0x2CEAE, 0x2CEAF),
|
||||||
(0x2CEB1, 0x2EBDF),
|
(0x2CEB1, 0x2EBDF),
|
||||||
(0x2EBE1, 0x2EBEF),
|
(0x2EBE1, 0x2EBEF),
|
||||||
(0x2EBF1, 0x2EE5C),
|
(0x2EBF1, 0x2EE5C),
|
||||||
@@ -1403,7 +1414,8 @@ pub enum WcWidth {
|
|||||||
(0x30001, 0x31349),
|
(0x30001, 0x31349),
|
||||||
(0x3134B, 0x3134F),
|
(0x3134B, 0x3134F),
|
||||||
(0x31351, 0x323AE),
|
(0x31351, 0x323AE),
|
||||||
(0x323B0, 0x3FFFD),
|
(0x323B1, 0x33478),
|
||||||
|
(0x3347A, 0x3FFFD),
|
||||||
(0x40000, 0x4FFFD),
|
(0x40000, 0x4FFFD),
|
||||||
(0x50000, 0x5FFFD),
|
(0x50000, 0x5FFFD),
|
||||||
(0x60000, 0x6FFFD),
|
(0x60000, 0x6FFFD),
|
||||||
@@ -1515,7 +1527,7 @@ pub enum WcWidth {
|
|||||||
fn in_table(arr: &[R], c: u32) -> bool {
|
fn in_table(arr: &[R], c: u32) -> bool {
|
||||||
arr.binary_search_by(|(start, end)| {
|
arr.binary_search_by(|(start, end)| {
|
||||||
if c >= *start && c <= *end {
|
if c >= *start && c <= *end {
|
||||||
std::cmp::Ordering::Equal
|
core::cmp::Ordering::Equal
|
||||||
} else {
|
} else {
|
||||||
start.cmp(&c)
|
start.cmp(&c)
|
||||||
}
|
}
|
||||||
1
debian/compat
vendored
1
debian/compat
vendored
@@ -1 +0,0 @@
|
|||||||
12
|
|
||||||
@@ -6,9 +6,12 @@ allow = [
|
|||||||
"BSD-2-Clause",
|
"BSD-2-Clause",
|
||||||
"BSD-3-Clause",
|
"BSD-3-Clause",
|
||||||
"BSL-1.0",
|
"BSL-1.0",
|
||||||
|
"CC0-1.0",
|
||||||
"GPL-2.0",
|
"GPL-2.0",
|
||||||
|
"GPL-2.0-only",
|
||||||
"ISC",
|
"ISC",
|
||||||
"LGPL-2.0",
|
"LGPL-2.0",
|
||||||
|
"LGPL-2.0-or-later",
|
||||||
"MIT",
|
"MIT",
|
||||||
"MPL-2.0",
|
"MPL-2.0",
|
||||||
"PSF-2.0",
|
"PSF-2.0",
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ The work will **proceed on master**: no long-lived branches. Tests and CI contin
|
|||||||
|
|
||||||
The Rust code will initially resemble the replaced C++. Fidelity to existing code is more important than Rust idiomaticity, to aid review and bisecting. But don't take this to extremes - use judgement.
|
The Rust code will initially resemble the replaced C++. Fidelity to existing code is more important than Rust idiomaticity, to aid review and bisecting. But don't take this to extremes - use judgement.
|
||||||
|
|
||||||
The port will proceed "outside in." We'll start with leaf components (e.g. builtins) and proceed towards the core. Some components will have both a Rust and C++ implementation (e.g. FLOG), in other cases we'll change the existing C++ to invoke the new Rust implementations (builtins).
|
The port will proceed "outside in." We'll start with leaf components (e.g. builtins) and proceed towards the core. Some components will have both a Rust and C++ implementation (e.g. flog), in other cases we'll change the existing C++ to invoke the new Rust implementations (builtins).
|
||||||
|
|
||||||
After porting the C++, we'll replace CMake.
|
After porting the C++, we'll replace CMake.
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ We use forks of the last two - see the [FFI section](#ffi) below. No special act
|
|||||||
|
|
||||||
### Build Dependencies
|
### Build Dependencies
|
||||||
|
|
||||||
fish-shell currently depends on Rust 1.70 or later. To install Rust, follow https://rustup.rs.
|
fish-shell currently depends on Rust 1.85 or later. To install Rust, follow https://rustup.rs.
|
||||||
|
|
||||||
### Build via CMake
|
### Build via CMake
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ The basic development loop for this port:
|
|||||||
- Do this even if it results in less idiomatic Rust, but avoid being super-dogmatic either way.
|
- Do this even if it results in less idiomatic Rust, but avoid being super-dogmatic either way.
|
||||||
- One technique is to paste the C++ into the Rust code, commented out, and go line by line.
|
- One technique is to paste the C++ into the Rust code, commented out, and go line by line.
|
||||||
4. Decide whether any existing C++ callers should invoke the Rust implementation, or whether we should keep the C++ one.
|
4. Decide whether any existing C++ callers should invoke the Rust implementation, or whether we should keep the C++ one.
|
||||||
- Utility functions may have both a Rust and C++ implementation. An example is `FLOG` where interop is too hard.
|
- Utility functions may have both a Rust and C++ implementation. An example is `flog` where interop is too hard.
|
||||||
- Major components (e.g. builtin implementations) should _not_ be duplicated; instead the Rust should call C++ or vice-versa.
|
- Major components (e.g. builtin implementations) should _not_ be duplicated; instead the Rust should call C++ or vice-versa.
|
||||||
5. Remember to run `cargo fmt` and `cargo clippy` to keep the codebase somewhat clean (otherwise CI will fail). If you use rust-analyzer, you can run clippy automatically by setting `rust-analyzer.checkOnSave.command = "clippy"`.
|
5. Remember to run `cargo fmt` and `cargo clippy` to keep the codebase somewhat clean (otherwise CI will fail). If you use rust-analyzer, you can run clippy automatically by setting `rust-analyzer.checkOnSave.command = "clippy"`.
|
||||||
|
|
||||||
@@ -93,7 +93,7 @@ None of the Rust string types are nul-terminated. We're taking this opportunity
|
|||||||
One may create a `&wstr` from a string literal using the `wchar::L!` macro:
|
One may create a `&wstr` from a string literal using the `wchar::L!` macro:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use crate::wchar::prelude::*;
|
use crate::prelude::*;
|
||||||
// This imports wstr, the L! macro, WString, a ToWString trait that supplies .to_wstring() along with other things
|
// This imports wstr, the L! macro, WString, a ToWString trait that supplies .to_wstring() along with other things
|
||||||
|
|
||||||
fn get_shell_name() -> &'static wstr {
|
fn get_shell_name() -> &'static wstr {
|
||||||
@@ -116,7 +116,7 @@ fn get_shell_name() -> &'static wstr {
|
|||||||
#### The wchar prelude
|
#### The wchar prelude
|
||||||
|
|
||||||
We have a prelude to make working with these string types a whole lot more ergonomic. In particular `WExt` supplies the null-terminated-compatible `.char_at(usize)`,
|
We have a prelude to make working with these string types a whole lot more ergonomic. In particular `WExt` supplies the null-terminated-compatible `.char_at(usize)`,
|
||||||
and a whole lot more methods that makes porting C++ code easier. It is also preferred to use char-based-methods like `.char_count()` and `.slice_{from,to}()`
|
and a whole lot more methods that makes porting C++ code easier. It is also preferred to use char-based-methods like `.char_count()` and `.slice_{from,to}()`
|
||||||
of the `WExt` trait over directly calling `.len()` and `[usize..]/[..usize]`, as that makes the code compatible with a potential future change to UTF8-strings.
|
of the `WExt` trait over directly calling `.len()` and `[usize..]/[..usize]`, as that makes the code compatible with a potential future change to UTF8-strings.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
@@ -144,7 +144,7 @@ These types should be confined to the FFI modules, in particular `wchar_ffi`. Th
|
|||||||
|
|
||||||
### Format strings
|
### Format strings
|
||||||
|
|
||||||
Rust's builtin `std::fmt` modules do not accept runtime-provided format strings, so we mostly won't use them, except perhaps for FLOG / other non-translated text.
|
Rust's builtin `std::fmt` modules do not accept runtime-provided format strings, so we mostly won't use them, except perhaps for flog / other non-translated text.
|
||||||
|
|
||||||
Instead we'll continue to use printf-style strings, with a Rust printf implementation.
|
Instead we'll continue to use printf-style strings, with a Rust printf implementation.
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
.. _cmd-_:
|
|
||||||
|
|
||||||
_ - call fish's translations
|
_ - call fish's translations
|
||||||
============================
|
============================
|
||||||
|
|
||||||
@@ -25,6 +23,8 @@ If other programs launched via fish should respect these locale variables they h
|
|||||||
|
|
||||||
For :envvar:`LANGUAGE` you can use a list, or use colons to separate multiple languages.
|
For :envvar:`LANGUAGE` you can use a list, or use colons to separate multiple languages.
|
||||||
|
|
||||||
|
If the :ref:`status language set <status-language>` command was used, its arguments specify the language precedence, and the environment variables are ignored.
|
||||||
|
|
||||||
Options
|
Options
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
.. _cmd-abbr:
|
|
||||||
|
|
||||||
abbr - manage fish abbreviations
|
abbr - manage fish abbreviations
|
||||||
================================
|
================================
|
||||||
|
|
||||||
@@ -10,8 +8,8 @@ Synopsis
|
|||||||
|
|
||||||
abbr --add NAME [--position command | anywhere] [-r | --regex PATTERN] [-c | --command COMMAND]
|
abbr --add NAME [--position command | anywhere] [-r | --regex PATTERN] [-c | --command COMMAND]
|
||||||
[--set-cursor[=MARKER]] ([-f | --function FUNCTION] | EXPANSION)
|
[--set-cursor[=MARKER]] ([-f | --function FUNCTION] | EXPANSION)
|
||||||
abbr --erase NAME ...
|
abbr --erase [ [-c | --command COMMAND]... ] NAME ...
|
||||||
abbr --rename OLD_WORD NEW_WORD
|
abbr --rename [ [-c | --command COMMAND]... ] OLD_WORD NEW_WORD
|
||||||
abbr --show
|
abbr --show
|
||||||
abbr --list
|
abbr --list
|
||||||
abbr --query NAME ...
|
abbr --query NAME ...
|
||||||
@@ -48,7 +46,7 @@ Combining these features, it is possible to create custom syntaxes, where a regu
|
|||||||
|
|
||||||
> abbr >> ~/.config/fish/config.fish
|
> abbr >> ~/.config/fish/config.fish
|
||||||
> abbr --erase (abbr --list)
|
> abbr --erase (abbr --list)
|
||||||
|
|
||||||
Alternatively you can keep them in a separate :ref:`configuration file <configuration>` by doing something like the following::
|
Alternatively you can keep them in a separate :ref:`configuration file <configuration>` by doing something like the following::
|
||||||
|
|
||||||
> abbr > ~/.config/fish/conf.d/myabbrs.fish
|
> abbr > ~/.config/fish/conf.d/myabbrs.fish
|
||||||
@@ -136,9 +134,10 @@ Other subcommands
|
|||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
abbr --rename OLD_NAME NEW_NAME
|
abbr --rename [ [-c | --command COMMAND]... ] OLD_NAME NEW_NAME
|
||||||
|
|
||||||
Renames an abbreviation, from *OLD_NAME* to *NEW_NAME*
|
Renames an abbreviation, from *OLD_NAME* to *NEW_NAME*.
|
||||||
|
For command-specific abbreviations, the ``--command`` options must be provided to disambiguate which abbreviation to rename.
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
@@ -154,9 +153,10 @@ Prints the names of all abbreviation
|
|||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
abbr [-e | --erase] NAME
|
abbr [-e | --erase] [ [-c | --command COMMAND]... ] NAME ...
|
||||||
|
|
||||||
Erases the abbreviation with the given name
|
Erases the abbreviation with the given name.
|
||||||
|
For command-specific abbreviations, the ``--command`` options must be provided to disambiguate which abbreviation to rename.
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
.. _cmd-alias:
|
|
||||||
|
|
||||||
alias - create a function
|
alias - create a function
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
@@ -48,12 +46,12 @@ The following code will create ``rmi``, which runs ``rm`` with additional argume
|
|||||||
::
|
::
|
||||||
|
|
||||||
alias rmi="rm -i"
|
alias rmi="rm -i"
|
||||||
|
|
||||||
# This is equivalent to entering the following function:
|
# This is equivalent to entering the following function:
|
||||||
function rmi --wraps rm --description 'alias rmi=rm -i'
|
function rmi --wraps rm --description 'alias rmi=rm -i'
|
||||||
rm -i $argv
|
rm -i $argv
|
||||||
end
|
end
|
||||||
|
|
||||||
``alias`` sometimes requires escaping, as you can see here::
|
``alias`` sometimes requires escaping, as you can see here::
|
||||||
|
|
||||||
# This needs to have the spaces escaped or "Chrome.app..."
|
# This needs to have the spaces escaped or "Chrome.app..."
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
.. _cmd-and:
|
|
||||||
|
|
||||||
and - conditionally execute a command
|
and - conditionally execute a command
|
||||||
=====================================
|
=====================================
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
.. _cmd-argparse:
|
|
||||||
|
|
||||||
argparse - parse options passed to a fish script or function
|
argparse - parse options passed to a fish script or function
|
||||||
============================================================
|
============================================================
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
.. _cmd-begin:
|
|
||||||
|
|
||||||
begin - start a new block of code
|
begin - start a new block of code
|
||||||
=================================
|
=================================
|
||||||
|
|
||||||
@@ -35,10 +33,10 @@ The following code sets a number of variables inside of a block scope. Since the
|
|||||||
|
|
||||||
begin
|
begin
|
||||||
set -l PIRATE Yarrr
|
set -l PIRATE Yarrr
|
||||||
|
|
||||||
...
|
...
|
||||||
end
|
end
|
||||||
|
|
||||||
echo $PIRATE
|
echo $PIRATE
|
||||||
# This will not output anything, since the PIRATE variable
|
# This will not output anything, since the PIRATE variable
|
||||||
# went out of scope at the end of the block
|
# went out of scope at the end of the block
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
.. _cmd-bg:
|
|
||||||
|
|
||||||
bg - send jobs to background
|
bg - send jobs to background
|
||||||
============================
|
============================
|
||||||
|
|
||||||
@@ -42,6 +40,6 @@ The typical use is to run something, stop it with ctrl-z, and then continue it i
|
|||||||
|
|
||||||
If only 123 and 789 exist, it will still background them and print an error about 456.
|
If only 123 and 789 exist, it will still background them and print an error about 456.
|
||||||
|
|
||||||
``bg 123 banana`` or ``bg banana 123`` will complain that "banana" is not a valid job specifier.
|
``bg 123 banana`` or ``bg banana 123`` will complain that "banana" is not a valid process ID.
|
||||||
|
|
||||||
``bg %2`` will background job 2.
|
``bg %2`` will background job 2.
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
.. _cmd-bind:
|
|
||||||
|
|
||||||
bind - handle fish key bindings
|
bind - handle fish key bindings
|
||||||
===============================
|
===============================
|
||||||
Synopsis
|
Synopsis
|
||||||
@@ -147,12 +145,17 @@ The following special input functions are available:
|
|||||||
``backward-kill-line``
|
``backward-kill-line``
|
||||||
move everything from the beginning of the line to the cursor to the killring
|
move everything from the beginning of the line to the cursor to the killring
|
||||||
|
|
||||||
|
.. _cmd-bind-backward-kill-path-component:
|
||||||
|
|
||||||
``backward-kill-path-component``
|
``backward-kill-path-component``
|
||||||
move one path component to the left of the cursor to the killring. A path component is everything likely to belong to a path component, i.e. not any of the following: `/={,}'\":@ |;<>&`, plus newlines and tabs.
|
move one path component to the left of the cursor to the killring. A path component is everything likely to belong to a path component, i.e. not any of the following: `/={,}'\":@ |;<>&`, plus newlines and tabs.
|
||||||
|
|
||||||
``backward-kill-word``
|
``backward-kill-word``
|
||||||
move the word to the left of the cursor to the killring. The "word" here is everything up to punctuation or whitespace.
|
move the word to the left of the cursor to the killring. The "word" here is everything up to punctuation or whitespace.
|
||||||
|
|
||||||
|
``backward-path-component``
|
||||||
|
move one :ref:`path component <cmd-bind-backward-kill-path-component>` to the left.
|
||||||
|
|
||||||
``backward-word``
|
``backward-word``
|
||||||
move one word to the left
|
move one word to the left
|
||||||
|
|
||||||
@@ -243,6 +246,9 @@ The following special input functions are available:
|
|||||||
commandline, does not accept the current autosuggestion (if any). Does not change the selected item in the completion pager,
|
commandline, does not accept the current autosuggestion (if any). Does not change the selected item in the completion pager,
|
||||||
if shown.
|
if shown.
|
||||||
|
|
||||||
|
``forward-path-component``
|
||||||
|
move one :ref:`path component <cmd-bind-backward-kill-path-component>` to the right; or if at the end of the commandline, accept a path component from the current autosuggestion.
|
||||||
|
|
||||||
``forward-single-char``
|
``forward-single-char``
|
||||||
move one character to the right; or if at the end of the commandline, accept a single char from the current autosuggestion.
|
move one character to the right; or if at the end of the commandline, accept a single char from the current autosuggestion.
|
||||||
|
|
||||||
@@ -310,6 +316,9 @@ The following special input functions are available:
|
|||||||
``kill-line``
|
``kill-line``
|
||||||
move everything from the cursor to the end of the line to the killring
|
move everything from the cursor to the end of the line to the killring
|
||||||
|
|
||||||
|
``kill-path-component``
|
||||||
|
move one :ref:`path component <cmd-bind-backward-kill-path-component>` to the killring.
|
||||||
|
|
||||||
``kill-selection``
|
``kill-selection``
|
||||||
move the selected text to the killring
|
move the selected text to the killring
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
.. _cmd-block:
|
|
||||||
|
|
||||||
block - temporarily block delivery of events
|
block - temporarily block delivery of events
|
||||||
============================================
|
============================================
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user