mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-21 23:01:05 +00:00
Compare commits
901 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9accf929f4 | ||
|
|
6aa75594db | ||
|
|
60d94608cb | ||
|
|
52640fcece | ||
|
|
b25ae9f82d | ||
|
|
4dab480347 | ||
|
|
d39637f40c | ||
|
|
ddc6632505 | ||
|
|
6d84921e70 | ||
|
|
dbb0cc0d55 | ||
|
|
aa850f9a3b | ||
|
|
c92c4aba88 | ||
|
|
6e0aaee822 | ||
|
|
b8ceaea940 | ||
|
|
21550a7eb5 | ||
|
|
39527f488f | ||
|
|
de611b0e6b | ||
|
|
ef654f4420 | ||
|
|
2a106aa231 | ||
|
|
b1ee2e72ff | ||
|
|
581886a355 | ||
|
|
4f45ddb514 | ||
|
|
0ba1811af3 | ||
|
|
feeea673f1 | ||
|
|
ef5db6e257 | ||
|
|
0daa5df644 | ||
|
|
6144d2748e | ||
|
|
84a5be0b6a | ||
|
|
ab8d634f8e | ||
|
|
85132ff343 | ||
|
|
53d36b5186 | ||
|
|
446a5721bf | ||
|
|
f1e93d7f52 | ||
|
|
b37be0529a | ||
|
|
9b920ed2e3 | ||
|
|
07a5deb109 | ||
|
|
4086fbb166 | ||
|
|
9cfeb67db7 | ||
|
|
f6113d3865 | ||
|
|
ea7fa2127c | ||
|
|
8a4b0b208e | ||
|
|
9bdd6777e4 | ||
|
|
8e80798984 | ||
|
|
e892bf7d90 | ||
|
|
601cb10b32 | ||
|
|
6c30430666 | ||
|
|
7a51626505 | ||
|
|
cf8b54179e | ||
|
|
f7fea2b19a | ||
|
|
d9cd1907d9 | ||
|
|
5d643ee01a | ||
|
|
c037855c4f | ||
|
|
3f5cc47a48 | ||
|
|
fde563380b | ||
|
|
247f925e53 | ||
|
|
22fb9e0d09 | ||
|
|
92b9ea3794 | ||
|
|
3968c4799c | ||
|
|
aa526434f0 | ||
|
|
10fc76db07 | ||
|
|
5ad1e003f2 | ||
|
|
62dd22b8da | ||
|
|
740d891989 | ||
|
|
1caa5807c6 | ||
|
|
c4c533e3ef | ||
|
|
88848932fc | ||
|
|
a2996908de | ||
|
|
4a2e5addcd | ||
|
|
369c47539c | ||
|
|
d1a27bca1f | ||
|
|
ae4c138f49 | ||
|
|
463150848d | ||
|
|
80a54c3dd5 | ||
|
|
9abbc12212 | ||
|
|
74d903a49a | ||
|
|
f6408656b4 | ||
|
|
354cdef907 | ||
|
|
ec178fdb52 | ||
|
|
4bb4f37555 | ||
|
|
0cedbd9c7b | ||
|
|
ad655eda52 | ||
|
|
4857d46918 | ||
|
|
6b143c1f4d | ||
|
|
4225c34fea | ||
|
|
607bc0dd2b | ||
|
|
2514725e56 | ||
|
|
935eb6b298 | ||
|
|
b67798ea19 | ||
|
|
5b2dd41e64 | ||
|
|
e2fae151a5 | ||
|
|
5c05350d52 | ||
|
|
d4924ebcad | ||
|
|
c703332b4b | ||
|
|
7b61eb1595 | ||
|
|
a246e9c7c0 | ||
|
|
cc2414728c | ||
|
|
6a1ddb71e0 | ||
|
|
da96795303 | ||
|
|
de01a56ac5 | ||
|
|
d22c96b69c | ||
|
|
fa1ee46edc | ||
|
|
3534ba0705 | ||
|
|
e4829372db | ||
|
|
1be991ec72 | ||
|
|
dee27a2377 | ||
|
|
8932ddd66d | ||
|
|
741f84e22b | ||
|
|
f10b8910ad | ||
|
|
dbf81deeab | ||
|
|
be91b4111c | ||
|
|
9648d8a43b | ||
|
|
b92b576ce1 | ||
|
|
0efeaf5f64 | ||
|
|
0a83f0bd27 | ||
|
|
3cdc3ecb70 | ||
|
|
884c265de1 | ||
|
|
05aeae3b09 | ||
|
|
9eb4d03a44 | ||
|
|
0bb6379a2a | ||
|
|
8b773a62a5 | ||
|
|
16aa3cd0fc | ||
|
|
d84f0b1265 | ||
|
|
e49cdfe220 | ||
|
|
9af792ef69 | ||
|
|
578016e00f | ||
|
|
7f339381f1 | ||
|
|
31cfc58188 | ||
|
|
c0f96f553b | ||
|
|
13bdb164a4 | ||
|
|
c3bc4fecad | ||
|
|
98b1614016 | ||
|
|
a8a4b684a1 | ||
|
|
30ec603441 | ||
|
|
1a121bbfb0 | ||
|
|
0aeeb3b0f7 | ||
|
|
dc66f79cef | ||
|
|
6757fed5aa | ||
|
|
339002ee48 | ||
|
|
a015d4a7ef | ||
|
|
dfdb235d74 | ||
|
|
1ea0ea072c | ||
|
|
eaeda8b4fa | ||
|
|
cfd9a22125 | ||
|
|
6d942ea011 | ||
|
|
583345296f | ||
|
|
24c60419bb | ||
|
|
e0911f2507 | ||
|
|
6150571738 | ||
|
|
592e70a1c9 | ||
|
|
06c665a086 | ||
|
|
92880b844b | ||
|
|
face6aed40 | ||
|
|
afc694c122 | ||
|
|
49b8324bbf | ||
|
|
4e0acf8cbf | ||
|
|
d17e7e14cd | ||
|
|
e6d995710f | ||
|
|
ca4cc59413 | ||
|
|
97d0c6bb23 | ||
|
|
a38a5e6377 | ||
|
|
756964b10a | ||
|
|
8a909697f8 | ||
|
|
798d38e494 | ||
|
|
0fc343b95a | ||
|
|
0c8c973e6c | ||
|
|
41e5717930 | ||
|
|
babc80d842 | ||
|
|
233d721e7c | ||
|
|
16d20e2171 | ||
|
|
b1dd185692 | ||
|
|
ebedab3e29 | ||
|
|
83674f19b4 | ||
|
|
c6e1702c61 | ||
|
|
30ac041d9e | ||
|
|
c9327ca851 | ||
|
|
3c39a326ab | ||
|
|
e611de5284 | ||
|
|
81c66a645f | ||
|
|
a6fcbb04df | ||
|
|
0000141700 | ||
|
|
456b88d660 | ||
|
|
f31147d246 | ||
|
|
faf33e1b03 | ||
|
|
77d36ff5a5 | ||
|
|
c5a3e42986 | ||
|
|
366fca6b10 | ||
|
|
2f66561a82 | ||
|
|
8c81172a19 | ||
|
|
6e3c96289e | ||
|
|
329c5d28f0 | ||
|
|
e7cd66370f | ||
|
|
e9eb8b9155 | ||
|
|
80b3b8465d | ||
|
|
5fe58ba2b1 | ||
|
|
ac7718c226 | ||
|
|
85a99937a1 | ||
|
|
55ef88b726 | ||
|
|
396f634bb8 | ||
|
|
9ae8b90d23 | ||
|
|
d2e9e72684 | ||
|
|
c569263a50 | ||
|
|
205b7fe11f | ||
|
|
dccc9b2c2a | ||
|
|
c6e03e91d2 | ||
|
|
c7739c5941 | ||
|
|
878b74acb7 | ||
|
|
44e244b9d6 | ||
|
|
d910104c00 | ||
|
|
d0adb9c015 | ||
|
|
0fb652d2ec | ||
|
|
76196aab70 | ||
|
|
ade1025a74 | ||
|
|
81ccdd8b64 | ||
|
|
0b8aaba29b | ||
|
|
8c2a6dba90 | ||
|
|
a8f2498471 | ||
|
|
3561867b99 | ||
|
|
329c80cbee | ||
|
|
a1fb206a59 | ||
|
|
2d55c9427d | ||
|
|
c725c91df1 | ||
|
|
449450d0db | ||
|
|
76fe6d7244 | ||
|
|
e5ee31cb7e | ||
|
|
a08b345a02 | ||
|
|
d3ad1c0920 | ||
|
|
9cd742811a | ||
|
|
f9abe886cc | ||
|
|
577065cbd0 | ||
|
|
4b56e73235 | ||
|
|
cc8f9a7177 | ||
|
|
587950bb5b | ||
|
|
97c63e2708 | ||
|
|
604b86612a | ||
|
|
b766cff69f | ||
|
|
a3e9ea0d16 | ||
|
|
564b885196 | ||
|
|
440e67164a | ||
|
|
ff5f656a31 | ||
|
|
c11ed02760 | ||
|
|
641bc6ff47 | ||
|
|
157156b5b8 | ||
|
|
b16c4894dc | ||
|
|
4b08e8d899 | ||
|
|
4e32044450 | ||
|
|
782ecb16b2 | ||
|
|
46569a1f48 | ||
|
|
e067a705ac | ||
|
|
c68e2df8c0 | ||
|
|
554cb52cc5 | ||
|
|
cd6881c9fe | ||
|
|
149a5feffb | ||
|
|
d8b0425a10 | ||
|
|
4d39194cd8 | ||
|
|
879ed49996 | ||
|
|
7b36b7fe14 | ||
|
|
25d5554a9a | ||
|
|
51635996e0 | ||
|
|
d905cbf2d7 | ||
|
|
6b09f2b665 | ||
|
|
9f39363dd4 | ||
|
|
f3e029ec25 | ||
|
|
86f0885737 | ||
|
|
9a804bac9c | ||
|
|
c0c0877d42 | ||
|
|
e9742cb809 | ||
|
|
8f9cce126c | ||
|
|
ba99ce4f8f | ||
|
|
4e3ac54c8e | ||
|
|
30c0279570 | ||
|
|
ece59974fe | ||
|
|
6cfa92f112 | ||
|
|
7deeaa4356 | ||
|
|
a3fc9a0ec7 | ||
|
|
4a3710b1c4 | ||
|
|
f0502a46b7 | ||
|
|
01fd967fa3 | ||
|
|
3713478753 | ||
|
|
fa0e7e62c1 | ||
|
|
81a0cf4a1e | ||
|
|
021d86f0d1 | ||
|
|
e795d6cf42 | ||
|
|
3c42195bac | ||
|
|
49910fcfe7 | ||
|
|
b997e56a60 | ||
|
|
cfc7238638 | ||
|
|
d670da80d3 | ||
|
|
d7df581b67 | ||
|
|
eb537733a2 | ||
|
|
8a0265ad64 | ||
|
|
dd7afaa64a | ||
|
|
c2a94daad6 | ||
|
|
12172b7301 | ||
|
|
c27ef58116 | ||
|
|
0054cf0b87 | ||
|
|
84907297a0 | ||
|
|
7a9bfff95d | ||
|
|
ae75fc0f7b | ||
|
|
fe9ce240b5 | ||
|
|
a41931275c | ||
|
|
3ca33c1f84 | ||
|
|
9810196565 | ||
|
|
2ec3a6c645 | ||
|
|
1bfcbc1664 | ||
|
|
a9bfeeeaad | ||
|
|
a109aa92e7 | ||
|
|
292d37ccde | ||
|
|
41b00c8d4e | ||
|
|
0b45ed868f | ||
|
|
d5f225bc4a | ||
|
|
da97e5a8b4 | ||
|
|
9adc00c3a9 | ||
|
|
9c1f303f2c | ||
|
|
9535caad5b | ||
|
|
0e3cd8545c | ||
|
|
c2883f1e05 | ||
|
|
1f596a01fc | ||
|
|
bfe12c8052 | ||
|
|
74bd98031e | ||
|
|
c28d2e8180 | ||
|
|
0fd74ae44c | ||
|
|
5f8a1496fe | ||
|
|
548bb0d063 | ||
|
|
60a2382087 | ||
|
|
6366e46c23 | ||
|
|
c9c85130e1 | ||
|
|
18795320bb | ||
|
|
bc9dbd35e3 | ||
|
|
559a46e399 | ||
|
|
452b435b71 | ||
|
|
5f7c0e813f | ||
|
|
917e1f54a1 | ||
|
|
52ecb31f5a | ||
|
|
a426d449f4 | ||
|
|
ec7eb3e416 | ||
|
|
39f50c898b | ||
|
|
ffdd74b6ab | ||
|
|
4ff7dae721 | ||
|
|
5a66559d1c | ||
|
|
8657e6b6f5 | ||
|
|
a8a1b5625b | ||
|
|
8ef28ec678 | ||
|
|
e16c0da547 | ||
|
|
2768fd22b1 | ||
|
|
2d1cf621db | ||
|
|
9d05946f4b | ||
|
|
590d336716 | ||
|
|
e218f1d8bb | ||
|
|
1ed244a0a5 | ||
|
|
ab0fe93150 | ||
|
|
3a9591a3d9 | ||
|
|
f5d0f47b51 | ||
|
|
1a6abae974 | ||
|
|
750ca0c0d4 | ||
|
|
a0ce7c0ae7 | ||
|
|
002b742cd9 | ||
|
|
ec90f26ac3 | ||
|
|
c8148d2d75 | ||
|
|
a0ab614108 | ||
|
|
56a4e87d7e | ||
|
|
a076ff8c82 | ||
|
|
52d37fa25d | ||
|
|
51560c30b7 | ||
|
|
917fee939f | ||
|
|
aae3f9ea4a | ||
|
|
0eec8fc80e | ||
|
|
414d46fd16 | ||
|
|
0752b53298 | ||
|
|
693dff25e3 | ||
|
|
c0615e5f45 | ||
|
|
b637c32ef7 | ||
|
|
d55e002d5a | ||
|
|
145349b0e6 | ||
|
|
20446544ef | ||
|
|
f866d75ef0 | ||
|
|
2d95221f59 | ||
|
|
d5038eeed5 | ||
|
|
b65a88075a | ||
|
|
4fdc0f120f | ||
|
|
4076e35a2f | ||
|
|
e6471b7fe0 | ||
|
|
5cb6e1f224 | ||
|
|
8a4d495132 | ||
|
|
d7716cab44 | ||
|
|
74a8ea9bc0 | ||
|
|
622ba09a80 | ||
|
|
c6fcb4f799 | ||
|
|
546920e049 | ||
|
|
b6ae5d3ca9 | ||
|
|
70e459a011 | ||
|
|
358524347f | ||
|
|
746c7f5ce9 | ||
|
|
ffc635e434 | ||
|
|
e257581fe7 | ||
|
|
464acfe47b | ||
|
|
9a0ef6bb20 | ||
|
|
5a4e6e4068 | ||
|
|
cea2628a19 | ||
|
|
55f69fbfee | ||
|
|
ea90b0477e | ||
|
|
41cba40072 | ||
|
|
3ae7673274 | ||
|
|
4e2a8bdf51 | ||
|
|
db60951783 | ||
|
|
ca96c5bd98 | ||
|
|
c53865788a | ||
|
|
a201c93419 | ||
|
|
5da39722e4 | ||
|
|
37e8747c01 | ||
|
|
01a13fd664 | ||
|
|
9037f8b8c0 | ||
|
|
d6a01a63ef | ||
|
|
8ed569b729 | ||
|
|
13a515c0ed | ||
|
|
9d92cdbf79 | ||
|
|
fbf8345d90 | ||
|
|
eba9f1e4f0 | ||
|
|
54687181b3 | ||
|
|
2c99075ffa | ||
|
|
6a9e7da8a3 | ||
|
|
5ffe74109c | ||
|
|
9e9ebf0745 | ||
|
|
bfad57d86f | ||
|
|
a29dbb9f06 | ||
|
|
7169e19ff0 | ||
|
|
8327826217 | ||
|
|
6bd7a8039a | ||
|
|
0b90a7268a | ||
|
|
88bbbac7dd | ||
|
|
ce23dcd81b | ||
|
|
c38be35250 | ||
|
|
510cb14ab6 | ||
|
|
56d6e4a71e | ||
|
|
d2cc73c927 | ||
|
|
af92b92da8 | ||
|
|
bef481057a | ||
|
|
ca4fe2ced7 | ||
|
|
7cc250180f | ||
|
|
99ea3b74c4 | ||
|
|
2e5f5ae5a6 | ||
|
|
86f465902e | ||
|
|
2e1156f267 | ||
|
|
0082d1181a | ||
|
|
be00881403 | ||
|
|
fd007ab023 | ||
|
|
9565c1b6fd | ||
|
|
3c9f619b84 | ||
|
|
b725b86be1 | ||
|
|
1765aba684 | ||
|
|
8488ae8394 | ||
|
|
0ada74efbe | ||
|
|
a25bbe2e9d | ||
|
|
0d9e3dc17e | ||
|
|
ad09fb89d9 | ||
|
|
aedfe766c5 | ||
|
|
31fccd4052 | ||
|
|
4bef557b7f | ||
|
|
e138364102 | ||
|
|
83f4deecfe | ||
|
|
913a92d610 | ||
|
|
1a2a18e333 | ||
|
|
db0300c902 | ||
|
|
570c6d308b | ||
|
|
7632163678 | ||
|
|
c5808a0db4 | ||
|
|
8b3ce1838a | ||
|
|
324a439c73 | ||
|
|
abfbd1cd9f | ||
|
|
faee35fc44 | ||
|
|
a0c6842626 | ||
|
|
76adb97e22 | ||
|
|
c8bf2c507a | ||
|
|
22980cf000 | ||
|
|
119cc9c2a1 | ||
|
|
31177fd1fd | ||
|
|
ece635d6b8 | ||
|
|
a2bbd29289 | ||
|
|
dc46e90b0a | ||
|
|
3dc6d82b98 | ||
|
|
68cd02816d | ||
|
|
3606bc7a1f | ||
|
|
51de941f79 | ||
|
|
2d210ae557 | ||
|
|
3082cad16c | ||
|
|
38d5b2fc87 | ||
|
|
46125eda6e | ||
|
|
4e32cd91ca | ||
|
|
94ff413e23 | ||
|
|
541d849157 | ||
|
|
66f015de95 | ||
|
|
57ef8f9ebd | ||
|
|
84d71bfa39 | ||
|
|
2a6cad455f | ||
|
|
20c99c6a06 | ||
|
|
6b0a5306c2 | ||
|
|
950750f66e | ||
|
|
953d567c63 | ||
|
|
235f6888d4 | ||
|
|
68e892694d | ||
|
|
133c6ebc9d | ||
|
|
f11f77d7b9 | ||
|
|
6ca27597f9 | ||
|
|
36ed32d2c3 | ||
|
|
7b4c4eae40 | ||
|
|
2410bb9671 | ||
|
|
52a5ab59e9 | ||
|
|
7f17ecd547 | ||
|
|
f75194b7cf | ||
|
|
4465101089 | ||
|
|
1ddbbfea71 | ||
|
|
3ec832b9d8 | ||
|
|
f25ef0f07b | ||
|
|
22c8f370dc | ||
|
|
38e45c647b | ||
|
|
b9416d8a04 | ||
|
|
077faacc9a | ||
|
|
f506849fb5 | ||
|
|
e2c841cca4 | ||
|
|
a4dde6a848 | ||
|
|
ce9092e73e | ||
|
|
89d4ceb5bb | ||
|
|
498623191a | ||
|
|
d75a5d6628 | ||
|
|
793c90f021 | ||
|
|
17ff1e8812 | ||
|
|
a8477059fd | ||
|
|
633e68e73e | ||
|
|
b1d2be067f | ||
|
|
e9fcab3b37 | ||
|
|
0c100ae5a6 | ||
|
|
b236f34d31 | ||
|
|
4e96341f51 | ||
|
|
7f1e9b83fd | ||
|
|
1cc9b2475c | ||
|
|
c41f2e21e0 | ||
|
|
74ce17ebbe | ||
|
|
77624ba6dc | ||
|
|
c061397a09 | ||
|
|
da36cd6ab8 | ||
|
|
af9a875512 | ||
|
|
29284613a0 | ||
|
|
a4f8e86471 | ||
|
|
cc568ee1fe | ||
|
|
abb43251fa | ||
|
|
456935658a | ||
|
|
1f4d0eafb5 | ||
|
|
245fb030df | ||
|
|
b4ca02f703 | ||
|
|
5058cf2294 | ||
|
|
ed3c9c4f3c | ||
|
|
7bd79521da | ||
|
|
cd338d0d1b | ||
|
|
e37d8d6bc1 | ||
|
|
ebaf2c29c1 | ||
|
|
3e1c8950f2 | ||
|
|
6c94227d40 | ||
|
|
63eb82aa72 | ||
|
|
6a5fa714ae | ||
|
|
098f7396d8 | ||
|
|
5c88f26896 | ||
|
|
856f37b5b3 | ||
|
|
b495f78dfe | ||
|
|
1e0c5ff61c | ||
|
|
6bc4a0295d | ||
|
|
ba62b407bd | ||
|
|
2eed881f12 | ||
|
|
7dd4454bf1 | ||
|
|
21f6a92ea3 | ||
|
|
05ecbca994 | ||
|
|
7d993c1517 | ||
|
|
40fea8521e | ||
|
|
ef599a160a | ||
|
|
00e8adc3de | ||
|
|
fd21452aa4 | ||
|
|
2770e0259c | ||
|
|
94128b45fc | ||
|
|
9117fe262f | ||
|
|
d754ac5dac | ||
|
|
2a4a398342 | ||
|
|
7d3e58951c | ||
|
|
50a81bea31 | ||
|
|
d746ae8338 | ||
|
|
5bd71bf225 | ||
|
|
783e95b1f2 | ||
|
|
5cfcab305e | ||
|
|
f0176992f5 | ||
|
|
87bfd8e2aa | ||
|
|
9e6a801073 | ||
|
|
8800bae0aa | ||
|
|
635bb4be55 | ||
|
|
54918b506f | ||
|
|
63ad28930f | ||
|
|
c96b1d3aa1 | ||
|
|
f4eef99f7e | ||
|
|
6e1948e7e1 | ||
|
|
c1048debc5 | ||
|
|
196a46cc5e | ||
|
|
c78f39b50f | ||
|
|
a64e8a8b59 | ||
|
|
ccf466d881 | ||
|
|
61cab0f30a | ||
|
|
22757199f9 | ||
|
|
0b340b67d5 | ||
|
|
7498b97251 | ||
|
|
a743488476 | ||
|
|
62ac224cff | ||
|
|
b8b3ab9be3 | ||
|
|
de93e6208d | ||
|
|
6308873f0b | ||
|
|
8ec944dbd3 | ||
|
|
adb1426539 | ||
|
|
3bd625a8af | ||
|
|
9d3c0c72fe | ||
|
|
11cf555b47 | ||
|
|
fbf9b3d1ed | ||
|
|
c7d9265d25 | ||
|
|
2771aef677 | ||
|
|
b4d1174f46 | ||
|
|
d3f572a8c7 | ||
|
|
4bd8b0b446 | ||
|
|
20dc0550bc | ||
|
|
91665b7713 | ||
|
|
4194befb88 | ||
|
|
d72f90356b | ||
|
|
37292adfde | ||
|
|
5e48df5126 | ||
|
|
ab04ce5d77 | ||
|
|
4026cebd88 | ||
|
|
1277b01758 | ||
|
|
805597268a | ||
|
|
99d6c81fbb | ||
|
|
870b0504e9 | ||
|
|
87f7fb6b3b | ||
|
|
0f9a3195b7 | ||
|
|
22e7d579d2 | ||
|
|
202751b46a | ||
|
|
e965b865b9 | ||
|
|
1f32601dc4 | ||
|
|
af565fbc40 | ||
|
|
c65bdb3b09 | ||
|
|
00486521b8 | ||
|
|
4ff4038b41 | ||
|
|
fd8871d878 | ||
|
|
a9a8a190a4 | ||
|
|
baf062f3b1 | ||
|
|
6001f3c619 | ||
|
|
81ce040443 | ||
|
|
362fbebcc5 | ||
|
|
6086134d41 | ||
|
|
565f9cc898 | ||
|
|
5531874a9a | ||
|
|
441ebcb764 | ||
|
|
0baccdc9aa | ||
|
|
a510673123 | ||
|
|
e3c91115a2 | ||
|
|
c6687237e1 | ||
|
|
81b8c89ec1 | ||
|
|
5eabd7d897 | ||
|
|
e3507205fb | ||
|
|
4dd24f779c | ||
|
|
ef1a31a274 | ||
|
|
96bcd820b8 | ||
|
|
56f9a6a1eb | ||
|
|
60cfa7dba9 | ||
|
|
81fd949016 | ||
|
|
e8c1d625ac | ||
|
|
35d781e240 | ||
|
|
0e118b5b3a | ||
|
|
16881aab2f | ||
|
|
24a77d8a5f | ||
|
|
11c5f3fed4 | ||
|
|
df78827af5 | ||
|
|
53043313ba | ||
|
|
a6c9c93d58 | ||
|
|
e58cf555da | ||
|
|
0824e11cd2 | ||
|
|
17a1169ea2 | ||
|
|
097e5abb82 | ||
|
|
3e8ac856cf | ||
|
|
1acd7ca80f | ||
|
|
43b5ae0e6c | ||
|
|
35c3c9e0f7 | ||
|
|
13e307eab2 | ||
|
|
da1b2365b9 | ||
|
|
c84917c5e8 | ||
|
|
2014aee646 | ||
|
|
558d97d084 | ||
|
|
064517665d | ||
|
|
dcbe7873cd | ||
|
|
87b159fb9d | ||
|
|
491f8b8fb1 | ||
|
|
3321f47d46 | ||
|
|
3150fb10f7 | ||
|
|
8c5d8aa589 | ||
|
|
034c28bacb | ||
|
|
a96c60ce6a | ||
|
|
e1773b11f1 | ||
|
|
40211df219 | ||
|
|
a7b9275c06 | ||
|
|
e6912da7d1 | ||
|
|
3e4973dbbf | ||
|
|
70fbe41cc2 | ||
|
|
9f8109e02e | ||
|
|
e2816716a0 | ||
|
|
ae53ef4443 | ||
|
|
c4ffdc08bb | ||
|
|
5b66192332 | ||
|
|
631afd09ee | ||
|
|
1a1820cf77 | ||
|
|
ac196f211e | ||
|
|
e858d11ce0 | ||
|
|
7222e178a3 | ||
|
|
dfe2884110 | ||
|
|
28083d805e | ||
|
|
49639aa34c | ||
|
|
0acf5c288e | ||
|
|
276f69128d | ||
|
|
2453539fb5 | ||
|
|
bc68d1eb01 | ||
|
|
61c0db8630 | ||
|
|
b87361023f | ||
|
|
3ee1209d3c | ||
|
|
d20b3d8408 | ||
|
|
9483798459 | ||
|
|
0cdaff98d0 | ||
|
|
7c445cef1f | ||
|
|
e3c653154f | ||
|
|
322f5fc230 | ||
|
|
ff04e2d21f | ||
|
|
e940d81d2a | ||
|
|
f2dca99e43 | ||
|
|
5f4779cc90 | ||
|
|
3a2dd30166 | ||
|
|
fdd574997b | ||
|
|
907ac09e34 | ||
|
|
a0a2331b3b | ||
|
|
69e7c8ff0d | ||
|
|
598104492b | ||
|
|
b280d79f76 | ||
|
|
ddb8ce530f | ||
|
|
90b1e525b8 | ||
|
|
caacd15110 | ||
|
|
cd7209c040 | ||
|
|
58ba459b63 | ||
|
|
9cf85c09d2 | ||
|
|
69c20d4dd3 | ||
|
|
c9d74360bf | ||
|
|
0601079023 | ||
|
|
91da9d19cf | ||
|
|
4fa37cb3cd | ||
|
|
92112de1c0 | ||
|
|
573ca5287f | ||
|
|
46f42b2f0c | ||
|
|
0f106b591c | ||
|
|
99a3b3a043 | ||
|
|
374c6a8891 | ||
|
|
4112bf451f | ||
|
|
c43db9cf56 | ||
|
|
77d1817771 | ||
|
|
fc304ca043 | ||
|
|
c75960eae6 | ||
|
|
62fcf27dfb | ||
|
|
71d6b0d9f2 | ||
|
|
a39409e699 | ||
|
|
44f45fd8e1 | ||
|
|
ce944bca88 | ||
|
|
dac72eb39a | ||
|
|
b066652b65 | ||
|
|
36381e676f | ||
|
|
17c7003426 | ||
|
|
4150f4014c | ||
|
|
3bb867c5bd | ||
|
|
5f923e8706 | ||
|
|
c8add31606 | ||
|
|
0954f9c58c | ||
|
|
6e94776781 | ||
|
|
e02b030258 | ||
|
|
407ad266e9 | ||
|
|
a9d2d9cd2b | ||
|
|
1e08e09899 | ||
|
|
5df6873957 | ||
|
|
f865910481 | ||
|
|
52681b19e4 | ||
|
|
cda7d3f2ea | ||
|
|
cc50f94de6 | ||
|
|
516cd23635 | ||
|
|
d2ebadb631 | ||
|
|
3fdbbfe915 | ||
|
|
3533ac20f7 | ||
|
|
9b7821a161 | ||
|
|
9d1fab84ef | ||
|
|
7a380c2f0f | ||
|
|
c7b002581a | ||
|
|
bb29e238b5 | ||
|
|
4257b95e8d | ||
|
|
23a56c24a4 | ||
|
|
f024ce03e7 | ||
|
|
c086f2f34d | ||
|
|
df1f094a28 | ||
|
|
152b9ea75e | ||
|
|
af0fb5955b | ||
|
|
4a0522640d | ||
|
|
a9eb218a5b | ||
|
|
66e83f3e18 | ||
|
|
093c13ac22 | ||
|
|
bba32ed0b2 | ||
|
|
640efcee26 | ||
|
|
d6081fbe6f | ||
|
|
f0cb365839 | ||
|
|
67fb66c2e2 | ||
|
|
ed6ae000d6 | ||
|
|
ec33085f67 | ||
|
|
ab88588c0e | ||
|
|
2cf722ed48 | ||
|
|
f5598ebb8a | ||
|
|
54eb0cc663 | ||
|
|
afa5936bf5 | ||
|
|
9d0ef9a5dc | ||
|
|
11547eefe0 | ||
|
|
3c88edbc4d | ||
|
|
987b1d5c49 | ||
|
|
1a1da216ca | ||
|
|
9961251248 | ||
|
|
626053da25 | ||
|
|
c64530b35b | ||
|
|
9a5b75662a | ||
|
|
f1cf136df4 | ||
|
|
696dcf2668 | ||
|
|
804662ef82 | ||
|
|
0c5d621348 | ||
|
|
505de05d66 | ||
|
|
f5a7aceac0 | ||
|
|
0f84717a1b | ||
|
|
b5b6c9642a | ||
|
|
f35712a768 | ||
|
|
2a35d30f38 | ||
|
|
794694e2d6 | ||
|
|
189cb81db3 | ||
|
|
1166f86523 | ||
|
|
94628cad9e | ||
|
|
9df256f7f4 | ||
|
|
5f8c20e2b5 | ||
|
|
2c84c48208 | ||
|
|
162218c345 | ||
|
|
e4d67121f8 | ||
|
|
add801f28e | ||
|
|
95e960a64a | ||
|
|
46cd42f923 | ||
|
|
b81b707a3e | ||
|
|
4c46862506 | ||
|
|
2eec94652a | ||
|
|
1ab3df6850 | ||
|
|
061faea1c5 | ||
|
|
5f21998665 | ||
|
|
58e5d2280a | ||
|
|
f2b7f3eaf7 | ||
|
|
d9ecffd19e | ||
|
|
f41e3c8d8b | ||
|
|
0ebfacb677 | ||
|
|
7177317465 | ||
|
|
a68e151194 | ||
|
|
bf1c325d00 | ||
|
|
c2affae3a9 | ||
|
|
0ff4835f8d | ||
|
|
5a83577259 | ||
|
|
65afe6027a | ||
|
|
f2329a3b35 | ||
|
|
50ae6ebe39 | ||
|
|
2683b1d6a2 | ||
|
|
dcd23f2cd3 | ||
|
|
f0108dba40 | ||
|
|
28dfe728ab | ||
|
|
07342a29ef | ||
|
|
c1e1f26c4c | ||
|
|
eed82c1386 | ||
|
|
6ff42c1a6d | ||
|
|
0ffba5c648 | ||
|
|
386dd4c9c1 | ||
|
|
faa1d9f37b | ||
|
|
fdecf629a6 | ||
|
|
668279814c | ||
|
|
8d741eb62a | ||
|
|
aee65bc4d1 | ||
|
|
0e26f5d3c7 | ||
|
|
2fdc0dd7bf | ||
|
|
36b3ffafc1 | ||
|
|
a9cf8002d6 | ||
|
|
28972ff54d | ||
|
|
bdb28f7691 | ||
|
|
4c35f26e1f | ||
|
|
0016876dc9 | ||
|
|
3a09155328 | ||
|
|
9dd07017b0 | ||
|
|
d01e18067c | ||
|
|
681612f976 | ||
|
|
42a0fcd5cf | ||
|
|
bf91f35d3e | ||
|
|
2febbee595 | ||
|
|
1a3565963c | ||
|
|
8456d3a7dc | ||
|
|
8fc8770c28 |
1603 changed files with 80877 additions and 22937 deletions
16
.cargo/config.toml
Normal file
16
.cargo/config.toml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
[env]
|
||||
MACOSX_DEPLOYMENT_TARGET = "10.12"
|
||||
JEMALLOC_SYS_WITH_LG_PAGE = "16"
|
||||
|
||||
# environment variable for tikv-jemalloc-sys
|
||||
#
|
||||
# https://jemalloc.net/jemalloc.3.html#opt.narenas
|
||||
# narenas is the maximum number of arenas to use for automatic multiplexing
|
||||
# of threads and arenas. The default is four times the number of CPUs,
|
||||
# or one if there is a single CPU.
|
||||
#
|
||||
# Improve memory efficiency by reducing fragmentation and ensuring all threads allocate from the same pool
|
||||
JEMALLOC_SYS_WITH_MALLOC_CONF = "narenas:1"
|
||||
|
||||
[target.aarch64-apple-darwin]
|
||||
rustflags = [ "-Ctarget-cpu=apple-m1" ]
|
||||
56
.github/DISCUSSION_TEMPLATE/1-q-a.yml
vendored
Normal file
56
.github/DISCUSSION_TEMPLATE/1-q-a.yml
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
body:
|
||||
- type: dropdown
|
||||
id: os
|
||||
attributes:
|
||||
label: What system are you running Yazi on?
|
||||
options:
|
||||
- Linux X11
|
||||
- Linux Wayland
|
||||
- macOS
|
||||
- Windows
|
||||
- Windows WSL
|
||||
- FreeBSD X11
|
||||
- FreeBSD Wayland
|
||||
- Android
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: terminal
|
||||
attributes:
|
||||
label: What terminal are you running Yazi in?
|
||||
placeholder: "ex: kitty v0.32.2"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: env
|
||||
attributes:
|
||||
label: "`ya env` output"
|
||||
description: Run `ya env` and paste the environment information here.
|
||||
render: Shell
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Describe the question
|
||||
description: A clear and concise description of what the question is
|
||||
placeholder: Tell us what you want to know
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: other
|
||||
attributes:
|
||||
label: Anything else?
|
||||
description: |
|
||||
Add any other context about the problem here. You can attach screenshots by clicking
|
||||
this area to highlight it and then drag the files in.
|
||||
- type: checkboxes
|
||||
id: checklist
|
||||
attributes:
|
||||
label: Checklist
|
||||
description: Before submitting the post, please make sure you have completed the following
|
||||
options:
|
||||
- label: I have read all the documentation
|
||||
required: true
|
||||
- label: I have searched the existing discussions/issues
|
||||
required: true
|
||||
61
.github/ISSUE_TEMPLATE/bug.yml
vendored
61
.github/ISSUE_TEMPLATE/bug.yml
vendored
|
|
@ -1,4 +1,4 @@
|
|||
name: Bug Report
|
||||
name: 🐞 Bug Report
|
||||
description: Create a report to help us improve
|
||||
labels: [bug]
|
||||
assignees: []
|
||||
|
|
@ -13,6 +13,9 @@ body:
|
|||
- macOS
|
||||
- Windows
|
||||
- Windows WSL
|
||||
- FreeBSD X11
|
||||
- FreeBSD Wayland
|
||||
- Android
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
|
|
@ -22,29 +25,12 @@ body:
|
|||
placeholder: "ex: kitty v0.32.2"
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: tried_main
|
||||
attributes:
|
||||
label: Did you try the latest code to see if this problem got fixed?
|
||||
options:
|
||||
- Tried, but the problem still
|
||||
- Not tried, and I'll explain why below
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: debug
|
||||
id: env
|
||||
attributes:
|
||||
label: "`yazi --debug` output"
|
||||
description: Please do a `yazi --debug` and paste the output here.
|
||||
value: |
|
||||
<details>
|
||||
|
||||
<!-- Paste the output between the backticks below: -->
|
||||
```sh
|
||||
|
||||
```
|
||||
|
||||
</details>
|
||||
label: "`ya env` output"
|
||||
description: Run `ya env` and paste the environment information here.
|
||||
render: Shell
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
|
|
@ -56,28 +42,14 @@ body:
|
|||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected
|
||||
id: reproducer
|
||||
attributes:
|
||||
label: Expected Behavior
|
||||
description: A clear and concise description of what you expected to happen
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: to_repro
|
||||
attributes:
|
||||
label: To Reproduce
|
||||
description: Steps to reproduce the behavior
|
||||
label: Minimal reproducer
|
||||
description: A [minimal reproducer](https://stackoverflow.com/help/minimal-reproducible-example) is required, otherwise the issue might be closed without further notice.
|
||||
placeholder: |
|
||||
Please include as much information as possible that can help to reproduce and understand the issue.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: config
|
||||
attributes:
|
||||
label: Configuration
|
||||
description: |
|
||||
Please include the relevant section(s) of your `yazi.toml`, `keymap.toml`, or `theme.toml` configuration file.
|
||||
You can enter "no config" if the issue happens without you having made a config file.
|
||||
- type: textarea
|
||||
id: other
|
||||
attributes:
|
||||
|
|
@ -85,3 +57,14 @@ body:
|
|||
description: |
|
||||
Add any other context about the problem here. You can attach screenshots by clicking
|
||||
this area to highlight it and then drag the files in.
|
||||
- type: checkboxes
|
||||
id: checklist
|
||||
attributes:
|
||||
label: Checklist
|
||||
description: Before submitting the issue, please make sure you have completed the following
|
||||
options:
|
||||
- label: I tried the [latest nightly build](https://yazi-rs.github.io/docs/installation#binaries), and the issue is still reproducible
|
||||
required: true
|
||||
- label: I updated the environment information (`ya env`) field to the nightly that I tried
|
||||
required: true
|
||||
- label: I can reproduce it after disabling all custom configs/plugins (`mv ~/.config/yazi ~/.config/yazi-backup`)
|
||||
|
|
|
|||
14
.github/ISSUE_TEMPLATE/config.yml
vendored
14
.github/ISSUE_TEMPLATE/config.yml
vendored
|
|
@ -1,8 +1,14 @@
|
|||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Discord server / Telegram group
|
||||
- name: 🚧 Build Issues
|
||||
url: https://github.com/sxyazi/yazi/discussions/new?category=3-build-issues
|
||||
about: If you have issues building Yazi from source code
|
||||
- name: 📝 Documentation Improvement
|
||||
url: https://github.com/yazi-rs/yazi-rs.github.io
|
||||
about: If you'd like to help improve the documentation
|
||||
- name: 💬 GitHub Discussions
|
||||
url: https://github.com/sxyazi/yazi/discussions/new?category=1-q-a
|
||||
about: When you have questions that are not bug reports or feature requests
|
||||
- name: 🌐 Discord Server / Telegram Group
|
||||
url: https://github.com/sxyazi/yazi#discussion
|
||||
about: If you'd prefer more realtime conversation with the community
|
||||
- name: GitHub Discussions
|
||||
url: https://github.com/sxyazi/yazi/discussions
|
||||
about: When you have questions that are not bug reports or feature requests
|
||||
|
|
|
|||
20
.github/ISSUE_TEMPLATE/feature.yml
vendored
20
.github/ISSUE_TEMPLATE/feature.yml
vendored
|
|
@ -1,8 +1,16 @@
|
|||
name: Feature Request
|
||||
name: 💡 Feature Request
|
||||
description: Suggest an idea for this project
|
||||
labels: [feature]
|
||||
assignees: []
|
||||
body:
|
||||
- type: textarea
|
||||
id: env
|
||||
attributes:
|
||||
label: "`ya env` output"
|
||||
description: Run `ya env` and paste the environment information here.
|
||||
render: Shell
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: problem
|
||||
attributes:
|
||||
|
|
@ -29,3 +37,13 @@ body:
|
|||
attributes:
|
||||
label: Additional context
|
||||
description: Add any other context or screenshots about the feature request here.
|
||||
- type: checkboxes
|
||||
id: checklist
|
||||
attributes:
|
||||
label: Checklist
|
||||
description: Before submitting the issue, please make sure you have completed the following
|
||||
options:
|
||||
- label: I have searched the existing issues/discussions
|
||||
required: true
|
||||
- label: The [latest nightly build](https://yazi-rs.github.io/docs/installation/#binaries) doesn't already have this feature
|
||||
required: true
|
||||
|
|
|
|||
15
.github/dependabot.yml
vendored
Normal file
15
.github/dependabot.yml
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
commit-message:
|
||||
prefix: "ci"
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/scripts/validate-form"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
commit-message:
|
||||
prefix: "ci"
|
||||
24
.github/pull_request_template.md
vendored
Normal file
24
.github/pull_request_template.md
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
## Which issue does this PR resolve?
|
||||
|
||||
<!--
|
||||
For any fixes and enhancements, we usually require an associated issue to be filed where clearly detailed your proposed changes and why they are necessary, which ensures we are aligned and reduces the risk of re-work.
|
||||
|
||||
You can use GitHub syntax to link an issue to this PR, such as `Resolves #1000`, which indicates this PR will resolve issue #1000.
|
||||
-->
|
||||
|
||||
Resolves #
|
||||
|
||||
## Rationale of this PR
|
||||
|
||||
<!--
|
||||
A clear and concise description of the rationale of the changes, to help our reviewers understand your intent and why it is necessary.
|
||||
|
||||
If it has already been detailed in the associated issue, please skip this section.
|
||||
-->
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] I have read [CONTRIBUTING.md](https://github.com/sxyazi/yazi/blob/main/CONTRIBUTING.md)
|
||||
- [ ] I confirm this PR follows the [AI Policy](https://github.com/sxyazi/yazi/blob/main/CONTRIBUTING.md#ai-policy)
|
||||
|
||||
<!-- AI bots are not allowed to open PRs in this repository. All PRs must be made by humans and comply with the AI policy. -->
|
||||
13
.github/workflows/cachix.yml
vendored
13
.github/workflows/cachix.yml
vendored
|
|
@ -1,8 +1,11 @@
|
|||
name: Cachix
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
branches: [main]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
|
|
@ -12,13 +15,13 @@ jobs:
|
|||
os: [ubuntu-latest, macos-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@v25
|
||||
uses: cachix/install-nix-action@v31
|
||||
|
||||
- name: Authenticate with Cachix
|
||||
uses: cachix/cachix-action@v14
|
||||
uses: cachix/cachix-action@v17
|
||||
with:
|
||||
name: yazi
|
||||
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||
|
|
|
|||
31
.github/workflows/check.yml
vendored
31
.github/workflows/check.yml
vendored
|
|
@ -6,19 +6,26 @@ on:
|
|||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
env:
|
||||
SCCACHE_GHA_ENABLED: true
|
||||
RUSTC_WRAPPER: sccache
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
clippy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- name: Setup Rust toolchain
|
||||
run: |
|
||||
rustup toolchain install stable --profile minimal
|
||||
rustup component add clippy
|
||||
|
||||
- name: Setup Rust cache
|
||||
uses: Swatinem/rust-cache@v2
|
||||
- name: Setup sccache
|
||||
uses: mozilla-actions/sccache-action@v0.0.10
|
||||
|
||||
- name: Clippy
|
||||
run: cargo clippy --all
|
||||
|
|
@ -27,15 +34,25 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Setup Rust toolchain
|
||||
run: |
|
||||
rustup toolchain install nightly --profile minimal
|
||||
rustup component add rustfmt --toolchain nightly
|
||||
|
||||
- name: Setup Rust cache
|
||||
uses: Swatinem/rust-cache@v2
|
||||
- name: Setup sccache
|
||||
uses: mozilla-actions/sccache-action@v0.0.10
|
||||
|
||||
- name: Rustfmt
|
||||
run: cargo +nightly fmt --all -- --check
|
||||
run: find . -name '*.rs' -not -path './target/*' -exec rustfmt +nightly --check {} +
|
||||
|
||||
stylua:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: JohnnyMorganz/stylua-action@v5
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
version: latest
|
||||
args: --color always --check .
|
||||
|
|
|
|||
260
.github/workflows/draft.yml
vendored
Normal file
260
.github/workflows/draft.yml
vendored
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
name: Draft
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
tags: ["v[0-9]+.[0-9]+.[0-9]+"]
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
SCCACHE_GHA_ENABLED: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build-unix:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
target: x86_64-unknown-linux-gnu
|
||||
- os: ubuntu-latest
|
||||
target: aarch64-unknown-linux-gnu
|
||||
gcc: gcc-aarch64-linux-gnu
|
||||
- os: ubuntu-latest
|
||||
target: i686-unknown-linux-gnu
|
||||
gcc: gcc-i686-linux-gnu
|
||||
- os: ubuntu-latest
|
||||
target: riscv64gc-unknown-linux-gnu
|
||||
gcc: gcc-riscv64-linux-gnu
|
||||
- os: ubuntu-latest
|
||||
target: sparc64-unknown-linux-gnu
|
||||
gcc: gcc-sparc64-linux-gnu
|
||||
- os: macos-latest
|
||||
target: x86_64-apple-darwin
|
||||
- os: macos-latest
|
||||
target: aarch64-apple-darwin
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
|
||||
CARGO_TARGET_I686_UNKNOWN_LINUX_GNU_LINKER: i686-linux-gnu-gcc
|
||||
CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_LINKER: riscv64-linux-gnu-gcc
|
||||
CARGO_TARGET_SPARC64_UNKNOWN_LINUX_GNU_LINKER: sparc64-linux-gnu-gcc
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- name: Install gcc
|
||||
if: matrix.gcc != ''
|
||||
run: sudo apt update && sudo apt install -yq ${{ matrix.gcc }}
|
||||
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
|
||||
- name: Setup sccache
|
||||
uses: mozilla-actions/sccache-action@v0.0.10
|
||||
|
||||
- name: Build
|
||||
run: ./scripts/build.sh ${{ matrix.target }}
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: ${{ matrix.target }}
|
||||
path: |
|
||||
yazi-${{ matrix.target }}.zip
|
||||
yazi-${{ matrix.target }}.deb
|
||||
|
||||
build-windows:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- os: windows-latest
|
||||
target: x86_64-pc-windows-msvc
|
||||
- os: windows-latest
|
||||
target: aarch64-pc-windows-msvc
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
RUSTC_WRAPPER: sccache
|
||||
YAZI_GEN_COMPLETIONS: true
|
||||
CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_LINKER: lld-link.exe
|
||||
CARGO_TARGET_AARCH64_PC_WINDOWS_MSVC_LINKER: lld-link.exe
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
|
||||
- name: Setup sccache
|
||||
uses: mozilla-actions/sccache-action@v0.0.10
|
||||
|
||||
- name: Build
|
||||
run: cargo build --profile release-windows --locked --target ${{ matrix.target }}
|
||||
|
||||
- name: Pack artifact
|
||||
env:
|
||||
TARGET_NAME: yazi-${{ matrix.target }}
|
||||
run: |
|
||||
New-Item -ItemType Directory -Path "${env:TARGET_NAME}\completions"
|
||||
Copy-Item -Path "target\${{ matrix.target }}\release-windows\ya.exe" -Destination ${env:TARGET_NAME}
|
||||
Copy-Item -Path "target\${{ matrix.target }}\release-windows\yazi.exe" -Destination ${env:TARGET_NAME}
|
||||
Copy-Item -Path "yazi-cli\completions\*" -Destination "${env:TARGET_NAME}\completions"
|
||||
Copy-Item -Path "yazi-boot\completions\*" -Destination "${env:TARGET_NAME}\completions"
|
||||
Copy-Item -Path "README.md", "LICENSE" -Destination ${env:TARGET_NAME}
|
||||
Compress-Archive -Path ${env:TARGET_NAME} -DestinationPath "${env:TARGET_NAME}.zip"
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: ${{ matrix.target }}
|
||||
path: yazi-${{ matrix.target }}.zip
|
||||
|
||||
build-musl:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- target: x86_64-unknown-linux-musl
|
||||
- target: aarch64-unknown-linux-musl
|
||||
container:
|
||||
image: docker://ghcr.io/cross-rs/${{ matrix.target }}:edge
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
|
||||
- name: Setup sccache
|
||||
uses: mozilla-actions/sccache-action@v0.0.10
|
||||
|
||||
- name: Build
|
||||
run: ./scripts/build.sh ${{ matrix.target }}
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: ${{ matrix.target }}
|
||||
path: |
|
||||
yazi-${{ matrix.target }}.zip
|
||||
yazi-${{ matrix.target }}.deb
|
||||
|
||||
build-snap:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
arch: amd64
|
||||
- os: ubuntu-24.04-arm
|
||||
arch: arm64
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup LXD
|
||||
uses: canonical/setup-lxd@v1
|
||||
|
||||
- name: Setup snapcraft
|
||||
run: sudo snap install --classic snapcraft
|
||||
|
||||
- name: Build snap
|
||||
run: snapcraft --verbose
|
||||
|
||||
- name: Rename snap
|
||||
run: mv yazi_*.snap yazi-${{ matrix.arch }}.snap
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: snap-${{ matrix.arch }}
|
||||
path: yazi-${{ matrix.arch }}.snap
|
||||
|
||||
snap:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build-snap]
|
||||
steps:
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
pattern: snap-*
|
||||
merge-multiple: true
|
||||
|
||||
- name: Setup snapcraft
|
||||
run: sudo snap install --classic snapcraft
|
||||
|
||||
- name: Push snap to candidate channel
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
env:
|
||||
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_TOKEN }}
|
||||
run: |
|
||||
parallel 'snapcraft upload -v --release latest/candidate {}' ::: yazi-*.snap || true
|
||||
|
||||
- name: Push snap to edge channel
|
||||
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
||||
env:
|
||||
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_TOKEN }}
|
||||
run: |
|
||||
parallel 'snapcraft upload -v --release latest/edge {}' ::: yazi-*.snap || true
|
||||
|
||||
draft:
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
permissions:
|
||||
contents: write
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build-unix, build-windows, build-musl, build-snap]
|
||||
steps:
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
merge-multiple: true
|
||||
|
||||
- name: Draft
|
||||
uses: softprops/action-gh-release@v3
|
||||
with:
|
||||
draft: true
|
||||
files: |
|
||||
yazi-*.zip
|
||||
yazi-*.deb
|
||||
yazi-*.snap
|
||||
generate_release_notes: true
|
||||
|
||||
nightly:
|
||||
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
||||
permissions:
|
||||
contents: write
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build-unix, build-windows, build-musl, build-snap]
|
||||
steps:
|
||||
- run: |
|
||||
echo 'NIGHTLY_BODY<<EOF' >> $GITHUB_ENV
|
||||
echo "From commit: ${GITHUB_SHA:0:8}" >> $GITHUB_ENV
|
||||
echo "Generated on: $(date -u +"%Y-%m-%d %H:%M") UTC" >> $GITHUB_ENV
|
||||
echo "Nightly changelog: https://github.com/sxyazi/yazi/blob/main/CHANGELOG.md#unreleased" >> $GITHUB_ENV
|
||||
echo "EOF" >> $GITHUB_ENV
|
||||
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
merge-multiple: true
|
||||
|
||||
- name: Update the tag
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git tag --force nightly && git push --force origin tag nightly
|
||||
|
||||
- name: Nightly
|
||||
uses: softprops/action-gh-release@v3
|
||||
with:
|
||||
tag_name: nightly
|
||||
prerelease: true
|
||||
files: |
|
||||
yazi-*.zip
|
||||
yazi-*.deb
|
||||
yazi-*.snap
|
||||
name: Nightly Build
|
||||
body: ${{ env.NIGHTLY_BODY }}
|
||||
target_commitish: ${{ github.sha }}
|
||||
4
.github/workflows/lock.yml
vendored
4
.github/workflows/lock.yml
vendored
|
|
@ -16,14 +16,14 @@ jobs:
|
|||
pull-requests: write
|
||||
discussions: write
|
||||
steps:
|
||||
- uses: dessant/lock-threads@v5
|
||||
- uses: dessant/lock-threads@v6
|
||||
with:
|
||||
issue-inactive-days: "30"
|
||||
issue-comment: >
|
||||
I'm going to lock this issue because it has been closed for _30 days_. ⏳
|
||||
|
||||
This helps our maintainers find and focus on the active issues.
|
||||
If you have found a problem that seems similar to this, please open a new
|
||||
If you have found a problem that seems similar to this, please file a new
|
||||
issue and complete the issue template so we can capture all the details
|
||||
necessary to investigate further.
|
||||
pr-inactive-days: "30"
|
||||
|
|
|
|||
37
.github/workflows/publish.yml
vendored
Normal file
37
.github/workflows/publish.yml
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
name: Publish
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
winget:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
merge-multiple: true
|
||||
|
||||
- name: Publish to Winget
|
||||
uses: vedantmgoyal9/winget-releaser@main
|
||||
with:
|
||||
identifier: sxyazi.yazi
|
||||
installers-regex: 'yazi-(x86_64|aarch64)-pc-windows-msvc\.zip$'
|
||||
token: ${{ secrets.WINGET_TOKEN }}
|
||||
|
||||
snapcraft:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
merge-multiple: true
|
||||
|
||||
- name: Promote snap to stable
|
||||
env:
|
||||
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_TOKEN }}
|
||||
run: |
|
||||
sudo snap install --classic snapcraft
|
||||
snapcraft promote yazi --from-channel latest/candidate --to-channel latest/stable --yes
|
||||
144
.github/workflows/release.yml
vendored
144
.github/workflows/release.yml
vendored
|
|
@ -1,144 +0,0 @@
|
|||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v[0-9]+.[0-9]+.[0-9]+"
|
||||
|
||||
jobs:
|
||||
build-unix:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
target: x86_64-unknown-linux-gnu
|
||||
- os: ubuntu-latest
|
||||
target: aarch64-unknown-linux-gnu
|
||||
- os: macos-latest
|
||||
target: x86_64-apple-darwin
|
||||
- os: macos-latest
|
||||
target: aarch64-apple-darwin
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install gcc-aarch64-linux-gnu
|
||||
if: matrix.target == 'aarch64-unknown-linux-gnu'
|
||||
run: sudo apt-get update && sudo apt-get install -yq gcc-aarch64-linux-gnu
|
||||
|
||||
- name: Build
|
||||
run: ./scripts/build.sh ${{ matrix.target }}
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: yazi-${{ matrix.target }}.zip
|
||||
path: yazi-${{ matrix.target }}.zip
|
||||
|
||||
build-windows:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- os: windows-latest
|
||||
target: x86_64-pc-windows-msvc
|
||||
- os: windows-latest
|
||||
target: aarch64-pc-windows-msvc
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Rust toolchain
|
||||
run: rustup toolchain install stable --profile minimal
|
||||
|
||||
- name: Add target
|
||||
run: rustup target add ${{ matrix.target }}
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
YAZI_GEN_COMPLETIONS: true
|
||||
run: |
|
||||
cargo build -p yazi-cli --release --locked --target ${{ matrix.target }}
|
||||
cargo build -p yazi-fm --release --locked --target ${{ matrix.target }}
|
||||
|
||||
- name: Pack artifact
|
||||
if: matrix.os == 'windows-latest'
|
||||
env:
|
||||
TARGET_NAME: yazi-${{ matrix.target }}
|
||||
run: |
|
||||
New-Item -ItemType Directory -Path ${env:TARGET_NAME}
|
||||
Copy-Item -Path "target\${{ matrix.target }}\release\ya.exe" -Destination ${env:TARGET_NAME}
|
||||
Copy-Item -Path "target\${{ matrix.target }}\release\yazi.exe" -Destination ${env:TARGET_NAME}
|
||||
Copy-Item -Path "yazi-boot\completions" -Destination ${env:TARGET_NAME} -Recurse
|
||||
Copy-Item -Path "README.md", "LICENSE" -Destination ${env:TARGET_NAME}
|
||||
Compress-Archive -Path ${env:TARGET_NAME} -DestinationPath "${env:TARGET_NAME}.zip"
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: yazi-${{ matrix.target }}.zip
|
||||
path: yazi-${{ matrix.target }}.zip
|
||||
|
||||
build-musl:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- target: x86_64-unknown-linux-musl
|
||||
image: rust-musl-cross:x86_64-musl
|
||||
- target: aarch64-unknown-linux-musl
|
||||
image: rust-musl-cross:aarch64-musl
|
||||
container:
|
||||
image: docker://ghcr.io/rust-cross/${{ matrix.image }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Build
|
||||
run: ./scripts/build.sh ${{ matrix.target }}
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: yazi-${{ matrix.target }}.zip
|
||||
path: yazi-${{ matrix.target }}.zip
|
||||
|
||||
build-snap:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
target: x86_64-unknown-linux-gnu
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Build snap
|
||||
uses: snapcore/action-build@v1
|
||||
|
||||
- name: Build
|
||||
run: mv yazi_*.snap yazi-${{ matrix.target }}.snap
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: yazi-${{ matrix.target }}.snap
|
||||
path: yazi-${{ matrix.target }}.snap
|
||||
|
||||
release:
|
||||
permissions:
|
||||
contents: write
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build-unix, build-windows, build-musl, build-snap]
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
merge-multiple: true
|
||||
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
draft: true
|
||||
files: |
|
||||
yazi-*.zip
|
||||
yazi-*.snap
|
||||
generate_release_notes: true
|
||||
13
.github/workflows/test.yml
vendored
13
.github/workflows/test.yml
vendored
|
|
@ -7,8 +7,13 @@ on:
|
|||
branches: [main]
|
||||
|
||||
env:
|
||||
SCCACHE_GHA_ENABLED: true
|
||||
RUSTC_WRAPPER: sccache
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
test:
|
||||
strategy:
|
||||
|
|
@ -16,16 +21,16 @@ jobs:
|
|||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- name: Setup Rust toolchain
|
||||
run: rustup toolchain install stable --profile minimal
|
||||
|
||||
- name: Setup Rust cache
|
||||
uses: Swatinem/rust-cache@v2
|
||||
- name: Setup sccache
|
||||
uses: mozilla-actions/sccache-action@v0.0.10
|
||||
|
||||
- name: Build
|
||||
run: cargo build --verbose
|
||||
|
||||
- name: Test
|
||||
run: cargo test --verbose
|
||||
run: cargo test --workspace --verbose
|
||||
|
|
|
|||
34
.github/workflows/validate-issue.yml
vendored
Normal file
34
.github/workflows/validate-issue.yml
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
name: Validate Issue
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [opened, edited]
|
||||
schedule:
|
||||
- cron: "20 * * * *"
|
||||
|
||||
jobs:
|
||||
check-version:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
cd scripts/validate-form
|
||||
npm ci
|
||||
|
||||
- name: Validate Issue
|
||||
uses: actions/github-script@v9
|
||||
with:
|
||||
script: |
|
||||
const script = require('./scripts/validate-form/main.js')
|
||||
await script({github, context, core})
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
36
.github/workflows/validate-pr.yml
vendored
Normal file
36
.github/workflows/validate-pr.yml
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
name: Validate PR
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, edited, reopened, synchronize]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
jobs:
|
||||
check-list:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ github.event.repository.default_branch }}
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
cd scripts/validate-form
|
||||
npm ci
|
||||
|
||||
- name: Validate PR
|
||||
uses: actions/github-script@v9
|
||||
with:
|
||||
script: |
|
||||
const script = require('./scripts/validate-form/main.js')
|
||||
await script({github, context, core})
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -1,5 +1,6 @@
|
|||
target/
|
||||
yazi-config/completions
|
||||
yazi-*/completions
|
||||
node_modules/
|
||||
|
||||
.DS_Store
|
||||
|
||||
|
|
@ -9,3 +10,5 @@ result-*
|
|||
|
||||
.idea/
|
||||
.vscode/
|
||||
|
||||
*.snap
|
||||
|
|
|
|||
9
.luarc.json
Normal file
9
.luarc.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"$schema": "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json",
|
||||
"runtime.version": "Lua 5.5",
|
||||
"runtime.special": {
|
||||
"fail": "error"
|
||||
},
|
||||
"workspace.library": ["~/.config/yazi/plugins/types.yazi/"],
|
||||
"diagnostics.disable": ["redefined-local"]
|
||||
}
|
||||
1785
CHANGELOG.md
Normal file
1785
CHANGELOG.md
Normal file
File diff suppressed because it is too large
Load diff
76
CODE_OF_CONDUCT.md
Normal file
76
CODE_OF_CONDUCT.md
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
# Code of Conduct
|
||||
|
||||
## Goal
|
||||
|
||||
Our goal is to create a welcoming and safe space where anyone can contribute and seek help for this project in a respectful, collaborative
|
||||
and harassment-free way.
|
||||
|
||||
All contributions are welcome and encourage everyone to participate regardless of age, body size, disability, ethnicity, sex characteristics,
|
||||
gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion,
|
||||
or sexual identity and orientation.
|
||||
|
||||
## Standards
|
||||
|
||||
Our standards are as follows:
|
||||
|
||||
- Respect different viewpoints and opinions
|
||||
- Do not harass, attack, or discriminate against others for any reason. We have zero tolerance for harassment
|
||||
- Communicate professionally and constructively. Do not post spam or go off-topic
|
||||
- Assume goodwill in conversations. Misunderstandings happen, so give others the benefit of the doubt before jumping to conclusions
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
- Trolling, insulting or derogatory comments, and personal attacks
|
||||
- Harassing or bullying another person
|
||||
- Publishing others' private information without their explicit permission
|
||||
- Posting things unrelated to the topic being discussed
|
||||
- Other conduct that could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported here: https://discord.com/users/638378964804698112
|
||||
All reporters are guaranteed privacy, and your reports will always be kept private and secure.
|
||||
|
||||
All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate.
|
||||
The following is a list of consequences that you may face if you are found to be breaking the terms of the CoC.
|
||||
|
||||
### 1. Correction
|
||||
|
||||
A private warning with an explanation as to why the behavior was not appropriate.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
A private or public warning with consequences for continued behavior.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
A temporary ban from any sort of interaction or public communication with the community for a specified period of time.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
A permanent ban from any sort of public interaction within the community.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the
|
||||
community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official
|
||||
social media account, or acting as an appointed representative at an online or offline event.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.1, available at
|
||||
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
|
||||
|
||||
Community Impact Guidelines were inspired by
|
||||
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
|
||||
[https://www.contributor-covenant.org/translations][translations].
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
||||
[Mozilla CoC]: https://github.com/mozilla/diversity
|
||||
[FAQ]: https://www.contributor-covenant.org/faq
|
||||
[translations]: https://www.contributor-covenant.org/translations
|
||||
174
CONTRIBUTING.md
Normal file
174
CONTRIBUTING.md
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
# Contributing to Yazi
|
||||
|
||||
Thank you for your interest in contributing to Yazi! We welcome contributions in the form of bug reports, feature requests, documentation improvements, and code changes.
|
||||
|
||||
This guide will help you understand how to contribute to the project.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Getting Started](#getting-started)
|
||||
2. [Project Structure](#project-structure)
|
||||
3. [Development Setup](#development-setup)
|
||||
4. [How to Contribute](#how-to-contribute)
|
||||
5. [Pull Requests](#pull-requests)
|
||||
6. [AI Policy](#ai-policy)
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Before you begin, ensure you have met the following requirements:
|
||||
|
||||
- Rust installed on your machine. You can download it from [rustup.rs](https://rustup.rs).
|
||||
- Familiarity with Git and GitHub.
|
||||
|
||||
### Fork the Repository
|
||||
|
||||
1. Fork the [Yazi repository](https://github.com/sxyazi/yazi) to your GitHub account.
|
||||
2. Clone your fork to your local machine:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/<your-username>/yazi.git
|
||||
```
|
||||
|
||||
3. Set up the upstream remote:
|
||||
```sh
|
||||
git remote add upstream https://github.com/sxyazi/yazi.git
|
||||
```
|
||||
|
||||
## Project Structure
|
||||
|
||||
A brief overview of the project's structure:
|
||||
|
||||
```sh
|
||||
.
|
||||
├── assets/ # Assets like images and fonts
|
||||
├── nix/ # Nix-related configurations
|
||||
├── scripts/ # Helper scripts used by CI/CD
|
||||
├── snap/ # Snapcraft configuration
|
||||
├── yazi-adapter/ # Yazi image adapter
|
||||
├── yazi-binding/ # Yazi Lua bindings
|
||||
├── yazi-boot/ # Yazi bootstrapper
|
||||
├── yazi-cli/ # Yazi command-line interface
|
||||
├── yazi-codegen/ # Yazi code generator
|
||||
├── yazi-config/ # Yazi configuration file parser
|
||||
├── yazi-core/ # Yazi core logic
|
||||
├── yazi-dds/ # Yazi data distribution service
|
||||
├── yazi-ffi/ # Yazi foreign function interface
|
||||
├── yazi-fm/ # Yazi file manager
|
||||
├── yazi-fs/ # Yazi file system
|
||||
├── yazi-macro/ # Yazi macros
|
||||
├── yazi-plugin/ # Yazi plugin system
|
||||
├── yazi-proxy/ # Yazi event proxy
|
||||
├── yazi-scheduler/ # Yazi task scheduler
|
||||
├── yazi-shared/ # Yazi shared library
|
||||
├── yazi-term/ # Yazi terminal extensions
|
||||
├── yazi-widgets/ # Yazi user interface widgets
|
||||
├── .github/ # GitHub-specific files and workflows
|
||||
├── Cargo.toml # Rust workflow configuration
|
||||
└── README.md # Project overview
|
||||
```
|
||||
|
||||
## Development Setup
|
||||
|
||||
1. Ensure the latest stable Rust is installed:
|
||||
|
||||
```sh
|
||||
rustc --version
|
||||
cargo --version
|
||||
```
|
||||
|
||||
2. Build the project:
|
||||
|
||||
```sh
|
||||
cargo build
|
||||
```
|
||||
|
||||
3. Run the tests:
|
||||
|
||||
```sh
|
||||
cargo test --workspace --verbose
|
||||
```
|
||||
|
||||
4. Format the code (requires `rustfmt` nightly):
|
||||
|
||||
```sh
|
||||
rustup component add rustfmt --toolchain nightly
|
||||
rustfmt +nightly **/*.rs
|
||||
```
|
||||
|
||||
## How to Contribute
|
||||
|
||||
### Reporting Bugs
|
||||
|
||||
If you encounter a bug and have found a way to reliably reproduce it on the latest `main` branch, please file a [bug report](https://github.com/sxyazi/yazi/issues/new?template=bug.yml) with a [minimal reproducer](https://stackoverflow.com/help/minimal-reproducible-example).
|
||||
|
||||
### Suggesting Features
|
||||
|
||||
If you want to request a feature, please file a [feature request](https://github.com/sxyazi/yazi/issues/new?template=feature.yml). Please make sure to search for existing issues and discussions before submitting.
|
||||
|
||||
### Improving Documentation
|
||||
|
||||
Yazi's documentation placed at [yazi-rs/yazi-rs.github.io](https://github.com/yazi-rs/yazi-rs.github.io), contributions related to documentation need to be made there.
|
||||
|
||||
### Improving Icons
|
||||
|
||||
Yazi's icon originates from [`nvim-web-devicons`](https://github.com/nvim-tree/nvim-web-devicons), and it is periodically grabbed and updated with the latest changes from upstream via [`generate.lua`](https://github.com/sxyazi/yazi/blob/main/scripts/icons/generate.lua).
|
||||
|
||||
Contributions related to the icon should be made upstream to facilitate easier automation of this process.
|
||||
|
||||
### Submitting Code Changes
|
||||
|
||||
1. Create a new branch for your changes:
|
||||
|
||||
```sh
|
||||
git checkout -b your-branch-name
|
||||
```
|
||||
|
||||
2. Make your changes. Ensure that your code follows the project's [coding style](https://github.com/sxyazi/yazi/blob/main/rustfmt.toml) and passes all tests.
|
||||
3. Commit your changes with a descriptive commit message:
|
||||
|
||||
```sh
|
||||
git commit -m "feat: an awesome feature"
|
||||
```
|
||||
|
||||
4. Push your changes to your fork:
|
||||
|
||||
```sh
|
||||
git push origin your-branch-name
|
||||
```
|
||||
|
||||
## Pull Requests
|
||||
|
||||
If you have an idea, before raising a pull request, we encourage you to file an issue to propose it, ensuring that we are aligned and reducing the risk of re-work.
|
||||
|
||||
We want you to succeed, and it can be discouraging to find that a lot of re-work is needed.
|
||||
|
||||
### Process
|
||||
|
||||
1. Ensure your fork is up-to-date with the upstream repository:
|
||||
|
||||
```sh
|
||||
git fetch upstream
|
||||
git checkout main
|
||||
git merge upstream/main
|
||||
```
|
||||
|
||||
2. Rebase your feature branch onto the `main` branch:
|
||||
|
||||
```sh
|
||||
git checkout your-branch-name
|
||||
git rebase main
|
||||
```
|
||||
|
||||
3. Create a pull request to the `main` branch of the upstream repository. Follow the pull request template and ensure that:
|
||||
- Your code passes all tests and lints.
|
||||
- Your pull request description clearly explains the changes and why they are needed.
|
||||
4. Address any review comments. Make sure to push updates to the same branch on your fork.
|
||||
|
||||
## AI Policy
|
||||
|
||||
1. All issue, PR, and discussion descriptions must be written by humans, not AI.
|
||||
2. Any use of AI must be disclosed. You must declare which model you used and the extent of AI assistance.
|
||||
3. Any AI-generated code must be reviewed, tested, and simplified by a human before publishing. This requires you to fully understand how it interacts with the greater system without AI assistance.
|
||||
4. Any AI tools used must explicitly state they do not assert copyright over the work.
|
||||
4801
Cargo.lock
generated
4801
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
91
Cargo.toml
91
Cargo.toml
|
|
@ -1,10 +1,97 @@
|
|||
[workspace]
|
||||
resolver = "2"
|
||||
resolver = "3"
|
||||
members = [ "yazi-*" ]
|
||||
default-members = [ "yazi-fm" ]
|
||||
default-members = [ "yazi-fm", "yazi-cli" ]
|
||||
|
||||
[workspace.package]
|
||||
edition = "2024"
|
||||
version = "26.5.6"
|
||||
license = "MIT"
|
||||
authors = [ "sxyazi <sxyazi@gmail.com>" ]
|
||||
homepage = "https://yazi-rs.github.io"
|
||||
repository = "https://github.com/sxyazi/yazi"
|
||||
rust-version = "1.95.0"
|
||||
|
||||
[profile.dev]
|
||||
debug = "line-tables-only"
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
lto = true
|
||||
panic = "abort"
|
||||
strip = true
|
||||
|
||||
[profile.release-windows]
|
||||
inherits = "release"
|
||||
panic = "unwind"
|
||||
|
||||
[profile.dev-opt]
|
||||
inherits = "release"
|
||||
codegen-units = 256
|
||||
incremental = true
|
||||
lto = false
|
||||
|
||||
[profile.dev.package."*"]
|
||||
debug = false
|
||||
|
||||
[workspace.dependencies]
|
||||
ansi-to-tui = "8.0.1"
|
||||
anyhow = "1.0.104"
|
||||
arc-swap = { version = "1.9.2", features = [ "serde" ] }
|
||||
base64 = "0.22.1"
|
||||
bitflags = { version = "2.13.1", features = [ "serde" ] }
|
||||
chrono = "0.4.45"
|
||||
clap = { version = "4.6.2", features = [ "derive" ] }
|
||||
compact_str = { version = "0.10.0", features = [ "serde" ] }
|
||||
core-foundation-sys = "0.8.7"
|
||||
data-encoding = "2.11.0"
|
||||
dirs = "6.0.0"
|
||||
dyn-clone = "1.0.20"
|
||||
either = { version = "1.16.0" }
|
||||
foldhash = "0.2.0"
|
||||
futures = "0.3.33"
|
||||
globset = "0.4.19"
|
||||
hashbrown = { version = "0.17.1", features = [ "serde" ] }
|
||||
image = { version = "0.25.10", default-features = false, features = [ "avif", "bmp", "dds", "exr", "ff", "gif", "hdr", "ico", "jpeg", "png", "pnm", "qoi", "tga", "tiff", "webp" ] }
|
||||
indexmap = { version = "2.14.0", features = [ "serde" ] }
|
||||
inventory = "0.3.24"
|
||||
libc = "0.2.186"
|
||||
lru = "0.18.1"
|
||||
mlua = { version = "0.12.0", features = [ "anyhow", "async", "error-send", "lua55", "macros", "serde" ] }
|
||||
objc2 = "0.6.4"
|
||||
ordered-float = { version = "5.3.0", features = [ "serde" ] }
|
||||
parking_lot = "0.12.5"
|
||||
paste = "1.0.15"
|
||||
percent-encoding = "2.3.2"
|
||||
rand = { version = "0.10.2", default-features = false, features = [ "std", "sys_rng" ] }
|
||||
ratatui-core = { version = "0.1.2", default-features = false, features = [ "std", "layout-cache", "serde", "underline-color" ] }
|
||||
ratatui-widgets = { version = "0.3.2", default-features = false, features = [ "std", "unstable-rendered-line-info" ] }
|
||||
regex = "1.13.1"
|
||||
russh = { version = "0.62.2", default-features = false, features = [ "ring", "rsa" ] }
|
||||
scopeguard = "1.2.0"
|
||||
serde = { version = "1.0.229", features = [ "derive" ] }
|
||||
serde_json = "1.0.151"
|
||||
serde_with = "3.21.0"
|
||||
strum = { version = "0.28.0", features = [ "derive" ] }
|
||||
syntect = { version = "5.3.0", default-features = false, features = [ "parsing", "plist-load", "regex-onig" ] }
|
||||
thiserror = "2.0.19"
|
||||
tokio = { version = "1.53.0", features = [ "full" ] }
|
||||
tokio-stream = "0.1.18"
|
||||
tokio-util = "0.7.18"
|
||||
toml = { version = "1.1.3" }
|
||||
tracing = { version = "0.1.44", features = [ "max_level_debug", "release_max_level_debug" ] }
|
||||
twox-hash = { version = "2.1.3", default-features = false, features = [ "std", "random", "xxhash3_128" ] }
|
||||
typed-path = "0.12.3"
|
||||
unicode-width = { version = "0.2.2", default-features = false }
|
||||
uzers = "0.12.2"
|
||||
|
||||
[workspace.lints.clippy]
|
||||
format_push_string = "warn"
|
||||
if_same_then_else = "allow"
|
||||
implicit_clone = "warn"
|
||||
len_without_is_empty = "allow"
|
||||
missing_safety_doc = "allow"
|
||||
module_inception = "allow"
|
||||
option_map_unit_fn = "allow"
|
||||
unit_arg = "allow"
|
||||
use_self = "warn"
|
||||
|
|
|
|||
21
LICENSE-ICONS
Normal file
21
LICENSE-ICONS
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2023 nvim-tree
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
82
README.md
82
README.md
|
|
@ -1,5 +1,9 @@
|
|||
<div align="center">
|
||||
<img src="assets/logo.png" alt="Yazi logo" width="20%">
|
||||
<sup>Special thanks to:</sup><br>
|
||||
|
||||
| <a href="https://go.warp.dev/yazi" target="_blank"><img alt="Warp sponsorship" width=350 src="https://github.com/warpdotdev/brand-assets/blob/main/Github/Sponsor/Warp-Github-LG-02.png"><br><b>Warp, built for coding with multiple AI agents</b><br><sup>Available for macOS, Linux and Windows</sup></a> |
|
||||
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
|
||||
</div>
|
||||
|
||||
## Yazi - ⚡️ Blazing Fast Terminal File Manager
|
||||
|
|
@ -10,20 +14,26 @@ Yazi (means "duck") is a terminal file manager written in Rust, based on non-blo
|
|||
|
||||
- 🚀 **Full Asynchronous Support**: All I/O operations are asynchronous, CPU tasks are spread across multiple threads, making the most of available resources.
|
||||
- 💪 **Powerful Async Task Scheduling and Management**: Provides real-time progress updates, task cancellation, and internal task priority assignment.
|
||||
- 🖼️ **Built-in Support for Multiple Image Protocols**: Also integrated with Überzug++, covering almost all terminals.
|
||||
- 🖼️ **Built-in Support for Multiple Image Protocols**: Also integrated with Überzug++ and Chafa, covering almost all terminals.
|
||||
- 🌟 **Built-in Code Highlighting and Image Decoding**: Combined with the pre-loading mechanism, greatly accelerates image and normal file loading.
|
||||
- 🔌 **Concurrent Plugin System**: UI plugins (rewriting most of the UI), functional plugins, custom previewer, and custom preloader; Just some pieces of Lua.
|
||||
- 🔌 **Concurrent Plugin System**: UI plugins (rewriting most of the UI), functional plugins, custom previewer/preloader/spotter/fetcher; Just some pieces of Lua.
|
||||
- ☁️ **Virtual Filesystem**: Remote file management, custom search engines.
|
||||
- 📡 **Data Distribution Service**: Built on a client-server architecture (no additional server process required), integrated with a Lua-based publish-subscribe model, achieving cross-instance communication and state persistence.
|
||||
- 🧰 Integration with fd, rg, fzf, zoxide
|
||||
- 💫 Vim-like input/select/which/notify component, auto-completion for cd paths
|
||||
- 🏷️ Multi-Tab Support, Cross-directory selection, Scrollable Preview (for videos, PDFs, archives, directories, code, etc.)
|
||||
- 🔄 Bulk Renaming, Visual Mode, File Chooser
|
||||
- 🎨 Theme System, Custom Layouts, Trash Bin, CSI u
|
||||
- 📦 **Package Manager**: Install plugins and themes with one command, keeping them up-to-date, or pin them to a specific version.
|
||||
- 🧰 Integration with ripgrep, fd, fzf, zoxide
|
||||
- 💫 Vim-like input/pick/confirm/which/notify component, auto-completion for cd paths
|
||||
- 🏷️ Multi-Tab Support, Cross-directory selection, Scrollable Preview (for videos, PDFs, archives, code, directories, etc.)
|
||||
- 🔄 Bulk Rename/Create, Archive Extraction, Visual Mode, File Chooser, [Git Integration](https://github.com/yazi-rs/plugins/tree/main/git.yazi), [Mount Manager](https://github.com/yazi-rs/plugins/tree/main/mount.yazi)
|
||||
- 🎨 Theme System, Mouse Support, Drag and Drop, Trash Bin, Custom Layouts, CSI u, OSC 52
|
||||
- ... and more!
|
||||
|
||||
https://github.com/sxyazi/yazi/assets/17523360/92ff23fa-0cd5-4f04-b387-894c12265cc7
|
||||
|
||||
⚠️ Note: Yazi is currently in heavy development and may be unstable. The API is subject to change without prior notice.
|
||||
## Project status
|
||||
|
||||
Public beta, can be used as a daily driver.
|
||||
|
||||
Yazi is currently in heavy development, expect breaking changes.
|
||||
|
||||
## Documentation
|
||||
|
||||
|
|
@ -37,24 +47,48 @@ https://github.com/sxyazi/yazi/assets/17523360/92ff23fa-0cd5-4f04-b387-894c12265
|
|||
|
||||
## Image Preview
|
||||
|
||||
| Platform | Protocol | Support |
|
||||
| ----------------- | ----------------------------------------------------------------------------------------------------- | --------------------- |
|
||||
| kitty | [Kitty unicode placeholders](https://sw.kovidgoyal.net/kitty/graphics-protocol/#unicode-placeholders) | ✅ Built-in |
|
||||
| Konsole | [Kitty old protocol](https://github.com/sxyazi/yazi/blob/main/yazi-adaptor/src/kitty_old.rs) | ✅ Built-in |
|
||||
| iTerm2 | [Inline images protocol](https://iterm2.com/documentation-images.html) | ✅ Built-in |
|
||||
| WezTerm | [Inline images protocol](https://iterm2.com/documentation-images.html) | ✅ Built-in |
|
||||
| Mintty (Git Bash) | [Inline images protocol](https://iterm2.com/documentation-images.html) | ✅ Built-in |
|
||||
| foot | [Sixel graphics format](https://www.vt100.net/docs/vt3xx-gp/chapter14.html) | ✅ Built-in |
|
||||
| Ghostty | [Kitty old protocol](https://github.com/sxyazi/yazi/blob/main/yazi-adaptor/src/kitty_old.rs) | ✅ Built-in |
|
||||
| Black Box | [Sixel graphics format](https://www.vt100.net/docs/vt3xx-gp/chapter14.html) | ✅ Built-in |
|
||||
| VSCode | [Inline images protocol](https://iterm2.com/documentation-images.html) | ✅ Built-in |
|
||||
| Tabby | [Inline images protocol](https://iterm2.com/documentation-images.html) | ✅ Built-in |
|
||||
| Hyper | [Inline images protocol](https://iterm2.com/documentation-images.html) | ✅ Built-in |
|
||||
| X11 / Wayland | Window system protocol | ☑️ Überzug++ required |
|
||||
| Fallback | [Chafa](https://hpjansson.org/chafa/) | ☑️ Überzug++ required |
|
||||
| Platform | Protocol | Support |
|
||||
| ---------------------------------------------------------------------------- | -------------------------------------- | -------------------------------------- |
|
||||
| [kitty](https://github.com/kovidgoyal/kitty) (>= 0.28.0) | [Kitty unicode placeholders][kgp] | ✅ Built-in |
|
||||
| [iTerm2](https://iterm2.com) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [WezTerm](https://github.com/wez/wezterm) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [Konsole](https://invent.kde.org/utilities/konsole) | [Kitty old protocol][kgp-old] | ✅ Built-in |
|
||||
| [foot](https://codeberg.org/dnkl/foot) | [Sixel graphics format][sixel] | ✅ Built-in |
|
||||
| [Ghostty](https://github.com/ghostty-org/ghostty) | [Kitty unicode placeholders][kgp] | ✅ Built-in |
|
||||
| [Windows Terminal](https://github.com/microsoft/terminal) (>= v1.22.10352.0) | [Sixel graphics format][sixel] | ✅ Built-in |
|
||||
| [st with Sixel patch](https://github.com/bakkeby/st-flexipatch) | [Sixel graphics format][sixel] | ✅ Built-in |
|
||||
| [Warp](https://www.warp.dev) (macOS/Linux only) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [Tabby](https://github.com/Eugeny/tabby) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [VSCode](https://github.com/microsoft/vscode) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [Rio](https://github.com/raphamorim/rio) (>= 0.3.9) | [Kitty unicode placeholders][kgp] | ✅ Built-in |
|
||||
| [Black Box](https://gitlab.gnome.org/raggesilver/blackbox) | [Sixel graphics format][sixel] | ✅ Built-in |
|
||||
| [Bobcat](https://github.com/ismail-yilmaz/Bobcat) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| X11 / Wayland | Window system protocol | ☑️ [Überzug++][ueberzug] required |
|
||||
| Fallback | [ASCII art (Unicode block)][ascii-art] | ☑️ [Chafa][chafa] required (>= 1.16.0) |
|
||||
|
||||
See https://yazi-rs.github.io/docs/image-preview for details.
|
||||
|
||||
<!-- Protocols -->
|
||||
|
||||
[kgp]: https://sw.kovidgoyal.net/kitty/graphics-protocol/#unicode-placeholders
|
||||
[kgp-old]: https://github.com/sxyazi/yazi/blob/main/yazi-adapter/src/drivers/kgp_old.rs
|
||||
[iip]: https://iterm2.com/documentation-images.html
|
||||
[sixel]: https://www.vt100.net/docs/vt3xx-gp/chapter14.html
|
||||
[ascii-art]: https://en.wikipedia.org/wiki/ASCII_art
|
||||
|
||||
<!-- Dependencies -->
|
||||
|
||||
[ueberzug]: https://github.com/jstkdng/ueberzugpp
|
||||
[chafa]: https://hpjansson.org/chafa/
|
||||
|
||||
## Special Thanks
|
||||
|
||||
<img alt="RustRover logo" align="right" width="200" src="https://resources.jetbrains.com/storage/products/company/brand/logos/RustRover.svg">
|
||||
|
||||
Thanks to RustRover team for providing open-source licenses to support the maintenance of Yazi.
|
||||
|
||||
Active code contributors can contact @sxyazi to get a license (if any are still available).
|
||||
|
||||
## License
|
||||
|
||||
Yazi is MIT-licensed. For more information check the [LICENSE](LICENSE) file.
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
[Desktop Entry]
|
||||
Name=Yazi
|
||||
Name=Yazi File Manager
|
||||
Icon=yazi
|
||||
Comment=Blazing fast terminal file manager written in Rust, based on async I/O
|
||||
Terminal=true
|
||||
TryExec=yazi
|
||||
Exec=yazi %u
|
||||
Exec=yazi %f
|
||||
Type=Application
|
||||
MimeType=inode/directory
|
||||
Categories=Utility;Core;System;FileTools;FileManager;ConsoleOnly
|
||||
Categories=System;FileManager;FileTools;ConsoleOnly
|
||||
Keywords=File;Manager;Explorer;Browser;Launcher
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
{"version":"0.2","flagWords":[],"language":"en","words":["Punct","KEYMAP","splitn","crossterm","YAZI","unar","peekable","ratatui","syntect","pbpaste","pbcopy","ffmpegthumbnailer","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","nvim","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp","️ Überzug","️ Überzug","Konsole","Alacritty","Überzug","pkgs","paru","unarchiver","pdftoppm","poppler","prebuild","singlefile","jpegopt","EXIF","rustfmt","mktemp","nanos","xclip","xsel","natord","Mintty","nixos","nixpkgs","SIGTSTP","SIGCONT","SIGCONT","mlua","nonstatic","userdata","metatable","natsort","backstack","luajit","Succ","Succ","cand","fileencoding","foldmethod","lightgreen","darkgray","lightred","lightyellow","lightcyan","nushell","msvc","aarch","linemode","sxyazi","rsplit","ZELLIJ","bitflags","bitflags","USERPROFILE","Neovim","vergen","gitcl","Renderable","preloaders","prec","imagesize","Upserting","prio","Ghostty","Catmull","Lanczos","cmds","unyank","scrolloff","headsup","unsub","uzers","scopeguard","SPDLOG","globset","filetime"]}
|
||||
{"flagWords":[],"version":"0.2","language":"en","words":["Punct","KEYMAP","splitn","crossterm","YAZI","peekable","ratatui","syntect","pbpaste","pbcopy","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp","Konsole","Überzug","pkgs","pdftoppm","poppler","singlefile","jpegopt","EXIF","rustfmt","mktemp","nanos","xclip","xsel","natord","Mintty","nixos","nixpkgs","SIGTSTP","SIGCONT","SIGCONT","mlua","nonstatic","userdata","metatable","natsort","backstack","luajit","Succ","Succ","cand","fileencoding","foldmethod","lightgreen","darkgray","lightred","lightyellow","lightcyan","nushell","msvc","aarch","linemode","sxyazi","rsplit","ZELLIJ","bitflags","bitflags","USERPROFILE","Neovim","vergen","gitcl","Renderable","preloaders","prec","Upserting","prio","Ghostty","Catmull","Lanczos","cmds","unyank","scrolloff","headsup","unsub","uzers","scopeguard","SPDLOG","globset","filetime","magick","magick","prefetcher","Prework","prefetchers","PREWORKERS","conds","translit","rxvt","Urxvt","realpath","realname","REPARSE","hardlink","hardlinking","nlink","nlink","linemodes","SIGSTOP","sevenzip","rsplitn","replacen","DECSET","DECRQM","repeek","cwds","tcsi","Hyprland","Wayfire","SWAYSOCK","btime","nsec","codegen","gethostname","fchmod","fdfind","Rustc","rustc","ffprobe","vframes","luma","obase","outln","errln","tmtheme","twox","cfgs","fstype","objc","rdev","runloop","exfat","rclone","DECRQSS","DECSCUSR","libvterm","Uninit","lockin","rposition","resvg","foldhash","tilded","futs","chdir","hashbrown","JEMALLOC","RUSTFLAGS","RDONLY","GETPATH","fcntl","casefold","inodes","Splatable","casefied","thiserror","memchr","memmem","russh","deadpool","keepalive","nodelay","publickey","deadpool","initing","treelize","TOCTOU","fellback","watchee","Textlike","sstr","pointee","writef","wakeup","nonblocking","sigwinch","timespec","termios","tcgetattr","tcsetattr","tcgetwinsize","rustix","codepoint","codepoints","Raterm","mimetypes","Mimelist","renderables","redrawer","Padable"]}
|
||||
21
flake.lock
generated
21
flake.lock
generated
|
|
@ -5,11 +5,11 @@
|
|||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1694529238,
|
||||
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -20,11 +20,11 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1701174899,
|
||||
"narHash": "sha256-1W+FMe8mWsJKXoBc+QgKmEeRj33kTFnPq7XCjU+bfnA=",
|
||||
"lastModified": 1783279667,
|
||||
"narHash": "sha256-/NAkDSsve+GNM0Bt6tleJdCGfsTlK89nPjkVOzZMo0s=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "010c7296f3b19a58b206fdf7d68d75a5b0a09e9e",
|
||||
"rev": "f205b5574fd0cb7da5b702a2da51507b7f4fdd1b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -43,19 +43,16 @@
|
|||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"flake-utils": [
|
||||
"flake-utils"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1701224160,
|
||||
"narHash": "sha256-qnMmxNMKmd6Soel0cfauyMJ+LzuZbvmiDQPSIuTbQ+M=",
|
||||
"lastModified": 1783320166,
|
||||
"narHash": "sha256-l7C/OsjcnWDOk2K3ssj+SBduwL67LashjBqis9+t468=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "4a080e26d55eaedb95ab1bf8eeaeb84149c10f12",
|
||||
"rev": "20ee15370c9256669d66968b89ee20a4b0a4e673",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
|||
93
flake.nix
93
flake.nix
|
|
@ -4,51 +4,68 @@
|
|||
flake-utils.url = "github:numtide/flake-utils";
|
||||
rust-overlay = {
|
||||
url = "github:oxalica/rust-overlay";
|
||||
inputs = {
|
||||
nixpkgs.follows = "nixpkgs";
|
||||
flake-utils.follows = "flake-utils";
|
||||
};
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, flake-utils, rust-overlay, ... }@inputs:
|
||||
let
|
||||
# Nixpkgs overlays
|
||||
overlays = [
|
||||
rust-overlay.overlays.default
|
||||
(final: prev: {
|
||||
rustToolchain = final.rust-bin.stable.latest.default.override {
|
||||
extensions = [ "rust-src" ];
|
||||
outputs =
|
||||
{
|
||||
self,
|
||||
nixpkgs,
|
||||
rust-overlay,
|
||||
flake-utils,
|
||||
...
|
||||
}:
|
||||
flake-utils.lib.eachDefaultSystem (
|
||||
system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
overlays = [ rust-overlay.overlays.default ];
|
||||
};
|
||||
toolchain = pkgs.rust-bin.stable.latest.default;
|
||||
rustPlatform = pkgs.makeRustPlatform {
|
||||
cargo = toolchain;
|
||||
rustc = toolchain;
|
||||
};
|
||||
|
||||
rev = self.shortRev or self.dirtyShortRev or "dirty";
|
||||
date = self.lastModifiedDate or self.lastModified or "19700101";
|
||||
version =
|
||||
(builtins.fromTOML (builtins.readFile ./Cargo.toml)).workspace.package.version
|
||||
+ "pre${builtins.substring 0 8 date}_${rev}";
|
||||
in
|
||||
{
|
||||
packages = {
|
||||
yazi-unwrapped = pkgs.callPackage ./nix/yazi-unwrapped.nix {
|
||||
inherit
|
||||
version
|
||||
rev
|
||||
date
|
||||
rustPlatform
|
||||
;
|
||||
};
|
||||
})
|
||||
];
|
||||
in
|
||||
flake-utils.lib.eachDefaultSystem
|
||||
(system:
|
||||
let
|
||||
pkgs = import nixpkgs { inherit system overlays; };
|
||||
versionSuffix = "pre${
|
||||
builtins.substring 0 8
|
||||
(self.lastModifiedDate or self.lastModified or "19700101")
|
||||
}_${self.shortRev or "dirty"}";
|
||||
version = (builtins.fromTOML
|
||||
(builtins.readFile ./yazi-fm/Cargo.toml)).package.version
|
||||
+ versionSuffix;
|
||||
yazi = pkgs.callPackage ./nix/yazi.nix { inherit version; };
|
||||
in
|
||||
{
|
||||
packages.default = yazi;
|
||||
packages.yazi = yazi;
|
||||
yazi = pkgs.callPackage ./nix/yazi.nix {
|
||||
inherit (self.packages.${system}) yazi-unwrapped;
|
||||
};
|
||||
default = self.packages.${system}.yazi;
|
||||
};
|
||||
|
||||
formatter = pkgs.nixpkgs-fmt;
|
||||
devShells = {
|
||||
default = pkgs.callPackage ./nix/shell.nix {
|
||||
inherit toolchain;
|
||||
inherit (self.packages.${system}) yazi yazi-unwrapped;
|
||||
};
|
||||
};
|
||||
|
||||
devShells.default = import ./nix/shell.nix { inherit pkgs inputs; };
|
||||
})
|
||||
formatter = pkgs.nixfmt-tree;
|
||||
}
|
||||
)
|
||||
// {
|
||||
overlays = rec {
|
||||
default = yazi;
|
||||
yazi = final: prev: {
|
||||
yazi = self.packages."${final.system}".yazi;
|
||||
overlays = {
|
||||
default = self.overlays.yazi;
|
||||
yazi = _: prev: {
|
||||
inherit (self.packages.${prev.stdenv.system}) yazi yazi-unwrapped;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,26 +1,25 @@
|
|||
{ pkgs, ... }:
|
||||
{
|
||||
mkShell,
|
||||
yazi,
|
||||
toolchain,
|
||||
cspell,
|
||||
yazi-unwrapped,
|
||||
}:
|
||||
|
||||
pkgs.mkShell {
|
||||
packages = with pkgs; [
|
||||
rustToolchain
|
||||
rust-analyzer
|
||||
|
||||
nodePackages.cspell
|
||||
|
||||
file
|
||||
jq
|
||||
poppler_utils
|
||||
unar
|
||||
ffmpegthumbnailer
|
||||
fd
|
||||
ripgrep
|
||||
fzf
|
||||
zoxide
|
||||
mkShell {
|
||||
packages = yazi.passthru.runtimePaths ++ [
|
||||
(toolchain.override {
|
||||
extensions = [
|
||||
"rust-src"
|
||||
"rustfmt"
|
||||
"rust-analyzer"
|
||||
"clippy"
|
||||
];
|
||||
})
|
||||
cspell
|
||||
];
|
||||
|
||||
buildInputs = with pkgs;
|
||||
lib.optionals stdenv.isDarwin
|
||||
(with darwin.apple_sdk.frameworks; [ Foundation ]);
|
||||
inputsFrom = [ yazi-unwrapped ];
|
||||
|
||||
env = { RUST_BACKTRACE = "1"; };
|
||||
env.RUST_BACKTRACE = "1";
|
||||
}
|
||||
|
|
|
|||
88
nix/yazi-unwrapped.nix
Normal file
88
nix/yazi-unwrapped.nix
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
{
|
||||
rustPlatform,
|
||||
version ? "git",
|
||||
rev ? "unknown",
|
||||
date ? "19700101",
|
||||
lib,
|
||||
|
||||
installShellFiles,
|
||||
fetchFromGitHub,
|
||||
rust-jemalloc-sys,
|
||||
|
||||
imagemagick,
|
||||
}:
|
||||
let
|
||||
src = lib.fileset.toSource {
|
||||
root = ../.;
|
||||
fileset = lib.fileset.unions [
|
||||
../assets
|
||||
../Cargo.toml
|
||||
../Cargo.lock
|
||||
(lib.fileset.fromSource (lib.sources.sourceByRegex ../. [ "^yazi-.*" ]))
|
||||
];
|
||||
};
|
||||
in
|
||||
rustPlatform.buildRustPackage (finalAttrs: {
|
||||
pname = "yazi";
|
||||
inherit version src;
|
||||
|
||||
cargoLock = {
|
||||
lockFile = "${src}/Cargo.lock";
|
||||
};
|
||||
|
||||
env = {
|
||||
YAZI_GEN_COMPLETIONS = true;
|
||||
VERGEN_GIT_SHA = rev;
|
||||
VERGEN_BUILD_DATE = builtins.concatStringsSep "-" (builtins.match "(.{4})(.{2})(.{2}).*" date);
|
||||
};
|
||||
|
||||
nativeBuildInputs = [
|
||||
installShellFiles
|
||||
imagemagick
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
rust-jemalloc-sys
|
||||
];
|
||||
|
||||
postInstall = ''
|
||||
installShellCompletion --cmd yazi \
|
||||
--bash ./yazi-boot/completions/yazi.bash \
|
||||
--fish ./yazi-boot/completions/yazi.fish \
|
||||
--zsh ./yazi-boot/completions/_yazi
|
||||
|
||||
installShellCompletion --cmd ya \
|
||||
--bash ./yazi-cli/completions/ya.bash \
|
||||
--fish ./yazi-cli/completions/ya.fish \
|
||||
--zsh ./yazi-cli/completions/_ya
|
||||
|
||||
# Resize logo
|
||||
for RES in 16 24 32 48 64 128 256; do
|
||||
mkdir -p $out/share/icons/hicolor/"$RES"x"$RES"/apps
|
||||
magick assets/logo.png -resize "$RES"x"$RES" $out/share/icons/hicolor/"$RES"x"$RES"/apps/yazi.png
|
||||
done
|
||||
|
||||
installManPage ${finalAttrs.passthru.srcs.man_src}/yazi{.1,-config.5}
|
||||
|
||||
mkdir -p $out/share/applications
|
||||
install -m644 assets/yazi.desktop $out/share/applications/
|
||||
'';
|
||||
|
||||
passthru.srcs = {
|
||||
man_src = fetchFromGitHub {
|
||||
name = "manpages"; # needed to ensure name is unique
|
||||
owner = "yazi-rs";
|
||||
repo = "manpages";
|
||||
rev = "8950e968f4a1ad0b83d5836ec54a070855068dbf";
|
||||
hash = "sha256-kEVXejDg4ChFoMNBvKlwdFEyUuTcY2VuK9j0PdafKus=";
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
meta = {
|
||||
description = "Blazing fast terminal file manager written in Rust, based on async I/O";
|
||||
homepage = "https://github.com/sxyazi/yazi";
|
||||
license = lib.licenses.mit;
|
||||
mainProgram = "yazi";
|
||||
};
|
||||
})
|
||||
169
nix/yazi.nix
169
nix/yazi.nix
|
|
@ -1,82 +1,109 @@
|
|||
{ makeRustPlatform
|
||||
, rustToolchain
|
||||
, version ? "git"
|
||||
, lib
|
||||
{
|
||||
lib,
|
||||
formats,
|
||||
runCommand,
|
||||
makeWrapper,
|
||||
|
||||
, makeWrapper
|
||||
, installShellFiles
|
||||
, stdenv
|
||||
, darwin
|
||||
runtimeDeps ? (ps: ps),
|
||||
|
||||
, withFile ? true
|
||||
, file
|
||||
, withJq ? true
|
||||
, jq
|
||||
, withPoppler ? true
|
||||
, poppler_utils
|
||||
, withUnar ? true
|
||||
, unar
|
||||
, withFfmpegthumbnailer ? true
|
||||
, ffmpegthumbnailer
|
||||
, withFd ? true
|
||||
, fd
|
||||
, withRipgrep ? true
|
||||
, ripgrep
|
||||
, withFzf ? true
|
||||
, fzf
|
||||
, withZoxide ? true
|
||||
, zoxide
|
||||
, imagemagick
|
||||
# deps
|
||||
file,
|
||||
yazi-unwrapped,
|
||||
|
||||
# default optional deps
|
||||
jq,
|
||||
poppler-utils,
|
||||
_7zz,
|
||||
ffmpeg,
|
||||
fd,
|
||||
ripgrep,
|
||||
resvg,
|
||||
fzf,
|
||||
zoxide,
|
||||
imagemagick,
|
||||
chafa,
|
||||
|
||||
settings ? { },
|
||||
plugins ? { },
|
||||
flavors ? { },
|
||||
initLua ? null,
|
||||
}:
|
||||
let
|
||||
inherit (lib)
|
||||
concatStringsSep
|
||||
concatMapStringsSep
|
||||
optionalString
|
||||
makeBinPath
|
||||
mapAttrsToList
|
||||
;
|
||||
|
||||
(makeRustPlatform { cargo = rustToolchain; rustc = rustToolchain; }).buildRustPackage {
|
||||
pname = "yazi";
|
||||
inherit version;
|
||||
defaultDeps = [
|
||||
jq
|
||||
poppler-utils
|
||||
_7zz
|
||||
ffmpeg
|
||||
fd
|
||||
ripgrep
|
||||
resvg
|
||||
fzf
|
||||
zoxide
|
||||
imagemagick
|
||||
chafa
|
||||
];
|
||||
runtimePaths = [ file ] ++ (runtimeDeps defaultDeps);
|
||||
|
||||
src = ../.;
|
||||
YAZI_GEN_COMPLETIONS = true;
|
||||
settingsFormat = formats.toml { };
|
||||
|
||||
cargoLock.lockFile = ../Cargo.lock;
|
||||
files = [
|
||||
"yazi"
|
||||
"theme"
|
||||
"keymap"
|
||||
];
|
||||
|
||||
nativeBuildInputs = [ makeWrapper installShellFiles imagemagick ];
|
||||
buildInputs = lib.optionals stdenv.isDarwin (
|
||||
with darwin.apple_sdk.frameworks; [ Foundation ]
|
||||
);
|
||||
configHome =
|
||||
if (settings == { } && initLua == null && plugins == { } && flavors == { }) then
|
||||
null
|
||||
else
|
||||
runCommand "YAZI_CONFIG_HOME" { } ''
|
||||
mkdir -p $out
|
||||
${concatMapStringsSep "\n" (
|
||||
name:
|
||||
optionalString (settings ? ${name} && settings.${name} != { }) ''
|
||||
ln -s ${settingsFormat.generate "${name}.toml" settings.${name}} $out/${name}.toml
|
||||
''
|
||||
) files}
|
||||
|
||||
postInstall = with lib;
|
||||
let
|
||||
runtimePaths = [ ]
|
||||
++ optional withFile file
|
||||
++ optional withJq jq
|
||||
++ optional withPoppler poppler_utils
|
||||
++ optional withUnar unar
|
||||
++ optional withFfmpegthumbnailer ffmpegthumbnailer
|
||||
++ optional withFd fd
|
||||
++ optional withRipgrep ripgrep
|
||||
++ optional withFzf fzf
|
||||
++ optional withZoxide zoxide;
|
||||
in
|
||||
''
|
||||
wrapProgram $out/bin/yazi \
|
||||
--prefix PATH : "${makeBinPath runtimePaths}"
|
||||
installShellCompletion --cmd yazi \
|
||||
--bash ./yazi-boot/completions/yazi.bash \
|
||||
--fish ./yazi-boot/completions/yazi.fish \
|
||||
--zsh ./yazi-boot/completions/_yazi
|
||||
mkdir $out/plugins
|
||||
${optionalString (plugins != { }) ''
|
||||
${concatStringsSep "\n" (
|
||||
mapAttrsToList (name: value: "ln -s ${value} $out/plugins/${name}") plugins
|
||||
)}
|
||||
''}
|
||||
|
||||
# Resize logo
|
||||
for RES in 16 24 32 48 64 128 256; do
|
||||
mkdir -p $out/share/icons/hicolor/"$RES"x"$RES"/apps
|
||||
convert assets/logo.png -resize "$RES"x"$RES" $out/share/icons/hicolor/"$RES"x"$RES"/apps/yazi.png
|
||||
done
|
||||
mkdir $out/flavors
|
||||
${optionalString (flavors != { }) ''
|
||||
${concatStringsSep "\n" (
|
||||
mapAttrsToList (name: value: "ln -s ${value} $out/flavors/${name}") flavors
|
||||
)}
|
||||
''}
|
||||
|
||||
mkdir -p $out/share/applications
|
||||
install -m644 assets/yazi.desktop $out/share/applications/
|
||||
'';
|
||||
|
||||
meta = with lib; {
|
||||
description = "Blazing fast terminal file manager written in Rust, based on async I/O";
|
||||
homepage = "https://github.com/sxyazi/yazi";
|
||||
license = licenses.mit;
|
||||
};
|
||||
}
|
||||
${optionalString (initLua != null) "ln -s ${initLua} $out/init.lua"}
|
||||
'';
|
||||
in
|
||||
runCommand yazi-unwrapped.name
|
||||
{
|
||||
inherit (yazi-unwrapped) pname version meta;
|
||||
|
||||
nativeBuildInputs = [ makeWrapper ];
|
||||
|
||||
passthru.runtimePaths = runtimePaths;
|
||||
}
|
||||
''
|
||||
mkdir -p $out/bin
|
||||
ln -s ${yazi-unwrapped}/share $out/share
|
||||
ln -s ${yazi-unwrapped}/bin/ya $out/bin/ya
|
||||
makeWrapper ${yazi-unwrapped}/bin/yazi $out/bin/yazi \
|
||||
--prefix PATH : "${makeBinPath runtimePaths}" \
|
||||
${optionalString (configHome != null) "--set YAZI_CONFIG_HOME ${configHome}"}
|
||||
''
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
color = "Never"
|
||||
condense_wildcard_suffixes = true
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
enum_discrim_align_threshold = 99
|
||||
fn_single_line = true
|
||||
format_code_in_doc_comments = false
|
||||
|
|
@ -10,7 +10,7 @@ format_macro_bodies = true
|
|||
format_strings = false
|
||||
hard_tabs = true
|
||||
hex_literal_case = "Lower"
|
||||
hide_parse_errors = true
|
||||
show_parse_errors = false
|
||||
imports_indent = "Visual"
|
||||
imports_layout = "Horizontal"
|
||||
imports_granularity = "Crate"
|
||||
|
|
@ -27,5 +27,5 @@ unstable_features = true
|
|||
use_field_init_shorthand = true
|
||||
use_small_heuristics = "Max"
|
||||
use_try_shorthand = true
|
||||
version = "Two"
|
||||
style_edition = "2024"
|
||||
wrap_comments = true
|
||||
|
|
|
|||
|
|
@ -1,32 +1,34 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
export ARTIFACT_NAME="yazi-$1"
|
||||
export YAZI_GEN_COMPLETIONS=1
|
||||
export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=/usr/bin/aarch64-linux-gnu-gcc
|
||||
|
||||
# Setup Rust toolchain
|
||||
if [[ "$1" == *-musl ]]; then
|
||||
rustup target add "$1"
|
||||
else
|
||||
rustup toolchain install stable --profile minimal --target "$1"
|
||||
# Build the target
|
||||
git config --global --add safe.directory "*"
|
||||
cargo build --release --locked --target "$1"
|
||||
|
||||
# Copy the binaries to a known location
|
||||
mkdir -p "target/release"
|
||||
cp "target/$1/release/ya" "target/release/ya"
|
||||
cp "target/$1/release/yazi" "target/release/yazi"
|
||||
|
||||
# Package deb
|
||||
if [[ "$ARTIFACT_NAME" == *-linux-* ]] && { [[ "$ARTIFACT_NAME" == *-aarch64-* ]] || [[ "$ARTIFACT_NAME" == *-x86_64-* ]]; }; then
|
||||
cargo install cargo-deb
|
||||
cargo deb -p yazi-packing --no-build --target "$1" -o "$ARTIFACT_NAME.deb"
|
||||
fi
|
||||
|
||||
# Build for the target
|
||||
cargo build -p yazi-cli --release --locked --target "$1"
|
||||
cargo build -p yazi-fm --release --locked --target "$1"
|
||||
|
||||
# Create the artifact
|
||||
mkdir -p "$ARTIFACT_NAME/completions"
|
||||
cp "target/$1/release/ya" "$ARTIFACT_NAME"
|
||||
cp "target/$1/release/yazi" "$ARTIFACT_NAME"
|
||||
cp "target/release/ya" "$ARTIFACT_NAME"
|
||||
cp "target/release/yazi" "$ARTIFACT_NAME"
|
||||
cp yazi-cli/completions/* "$ARTIFACT_NAME/completions"
|
||||
cp yazi-boot/completions/* "$ARTIFACT_NAME/completions"
|
||||
cp README.md LICENSE "$ARTIFACT_NAME"
|
||||
|
||||
# Zip the artifact
|
||||
if ! command -v zip &> /dev/null
|
||||
then
|
||||
sudo apt-get update && sudo apt-get install -yq zip
|
||||
if ! command -v zip &> /dev/null; then
|
||||
apt-get update && apt-get install -yq zip
|
||||
fi
|
||||
zip -r "$ARTIFACT_NAME.zip" "$ARTIFACT_NAME"
|
||||
|
|
|
|||
|
|
@ -1,13 +1,20 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
cd $SCRIPT_DIR/..
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cd "$SCRIPT_DIR/.."
|
||||
|
||||
echo "Bumping version: $1"
|
||||
|
||||
TOML_FILES="$(git ls-files '*Cargo.toml')"
|
||||
perl -pi -e "s/^version .*= .*\$/version = \"$1\"/" -- $TOML_FILES
|
||||
perl -pi -e "s/^(yazi-[a-z]+)\\s*=\\s*{.*\$/\\1 = { path = \"..\/\\1\", version = \"$1\" }/" -- $TOML_FILES
|
||||
perl -pi -e 's/^version .*= .*$/version = "'"$1"'"/' -- $TOML_FILES
|
||||
perl -pi -e 's/^(yazi-[a-z]+)\s*=\s*{.*$/\1 = { path = "..\/\1", version = "'"$1"'" }/' -- $TOML_FILES
|
||||
|
||||
ESLINT_USE_FLAT_CONFIG=true eslint -c ~/.config/rules/eslint/eslint.config.cjs --fix -- $TOML_FILES
|
||||
# Insert "## [v$1]" after "## [Unreleased]"
|
||||
perl -0777 -pe "s/^(## \[Unreleased\]\s*)/\\1## [v$1]\n\n/m" -i CHANGELOG.md
|
||||
# Determine previous version and append compare link
|
||||
prev_ver=$(grep -oE '^\[v[0-9][^]]+\]' CHANGELOG.md | tail -n1 | tr -d '[]')
|
||||
link="\[v$1\]: https://github.com/sxyazi/yazi/compare/$prev_ver...v$1"
|
||||
perl -pi -e 's{(\['"$prev_ver"'\]:[^\n]+\n)}{$1'"$link"'\n}s' CHANGELOG.md
|
||||
|
||||
eslint -c ~/.config/rules/eslint/eslint.config.js --fix -- $TOML_FILES
|
||||
|
|
|
|||
51
scripts/icons/generate.lua
Normal file
51
scripts/icons/generate.lua
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
local dark = {
|
||||
icons_by_filename = require("default.icons_by_filename"),
|
||||
icons_by_file_extension = require("default.icons_by_file_extension"),
|
||||
}
|
||||
local light = {
|
||||
icons_by_filename = require("light.icons_by_filename"),
|
||||
icons_by_file_extension = require("light.icons_by_file_extension"),
|
||||
}
|
||||
|
||||
function rearrange(by)
|
||||
local map = {}
|
||||
local source = by == "exts" and "icons_by_file_extension" or "icons_by_filename"
|
||||
for k, v in pairs(dark[source]) do
|
||||
map[k] = map[k] or {}
|
||||
map[k].icon = v.icon
|
||||
map[k].fg_dark = v.color:lower()
|
||||
end
|
||||
for k, v in pairs(light[source]) do
|
||||
map[k].fg_light = v.color:lower()
|
||||
end
|
||||
return map
|
||||
end
|
||||
|
||||
function dump(map)
|
||||
local list = {}
|
||||
for k, v in pairs(map) do
|
||||
list[#list + 1] = { name = k, text = v.icon, fg_dark = v.fg_dark, fg_light = v.fg_light }
|
||||
end
|
||||
table.sort(list, function(a, b) return a.name:lower() < b.name:lower() end)
|
||||
local dark, light = "", ""
|
||||
for _, v in ipairs(list) do
|
||||
-- stylua: ignore
|
||||
dark = dark .. string.format('\t{ name = "%s", text = "%s", fg = "%s" },\n', v.name, v.text, v.fg_dark)
|
||||
light = light .. string.format('\t{ name = "%s", text = "%s", fg = "%s" },\n', v.name, v.text, v.fg_light)
|
||||
end
|
||||
return dark, light
|
||||
end
|
||||
|
||||
function save(typ, files, exts)
|
||||
local p = string.format("../../yazi-config/preset/theme-%s.toml", typ)
|
||||
local s = io.open(p, "r"):read("*a")
|
||||
s = s:gsub("files = %[\n(.-)\n%]", string.format("files = [\n%s]", files))
|
||||
s = s:gsub("exts = %[\n(.-)\n%]", string.format("exts = [\n%s]", exts))
|
||||
io.open(p, "w"):write(s)
|
||||
end
|
||||
|
||||
local dark_files, light_files = dump(rearrange("files"))
|
||||
local dark_exts, light_exts = dump(rearrange("exts"))
|
||||
|
||||
save("dark", dark_files, dark_exts)
|
||||
save("light", light_files, light_exts)
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
cargo publish -p yazi-shared
|
||||
cargo publish -p yazi-config
|
||||
cargo publish -p yazi-proxy
|
||||
cargo publish -p yazi-adaptor
|
||||
cargo publish -p yazi-boot
|
||||
cargo publish -p yazi-scheduler
|
||||
cargo publish -p yazi-plugin
|
||||
cargo publish -p yazi-core
|
||||
cargo publish -p yazi-fm
|
||||
269
scripts/validate-form/main.js
Normal file
269
scripts/validate-form/main.js
Normal file
|
|
@ -0,0 +1,269 @@
|
|||
const LABEL_NAME = "needs info"
|
||||
const RE_VERSION = /Yazi\s+Version\s*:\s\d+\.\d+\.\d+\s\(/gm
|
||||
const RE_DEPENDENCIES = /Dependencies\s+[/a-z]+\s*:\s/gm
|
||||
const RE_CHECKLIST = /#{3}\s+Checklist\s+(?:^-\s+\[x]\s+.+?(?:\n|\r\n|$)){2}/gm
|
||||
const RE_PR_CHECKLIST = /#{2}\s+Checklist\s+(?:^-\s+\[x]\s+.+?(?:\n|\r\n|$)){2}/gm
|
||||
|
||||
function pullRequestBody(content) {
|
||||
if (RE_PR_CHECKLIST.test(content)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return "All required checklist items must be checked in the PR description."
|
||||
}
|
||||
|
||||
function bugReportBody(creator, content, hash) {
|
||||
if (RE_DEPENDENCIES.test(content) && RE_CHECKLIST.test(content) && new RegExp(` \\(${hash}[a-f0-9]? `).test(content)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return `Hey @${creator}, thank you for opening the issue to help improve Yazi, appreciate it!
|
||||
|
||||
I noticed that you did not correctly follow the issue template. Please ensure that:
|
||||
|
||||
- The bug can still be reproduced on the [newest nightly build](https://yazi-rs.github.io/docs/installation/#binaries).
|
||||
- The environment info (\`ya env\`) is updated for the newest nightly.
|
||||
- The non-optional items in the checklist are checked.
|
||||
|
||||
Issues with \`${LABEL_NAME}\` will be marked ready once edited with the proper content, or closed after 2 days of inactivity.
|
||||
|
||||
Our maintainers work on Yazi in their free time, this helps them work efficiently, understand your setup quickly, and find a more appropriate solution. Thanks for your understanding! 🙏
|
||||
`
|
||||
}
|
||||
|
||||
function featureRequestBody(creator, content) {
|
||||
if (RE_VERSION.test(content) && RE_DEPENDENCIES.test(content) && RE_CHECKLIST.test(content)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return `Hey @${creator}, thank you for opening the issue to help improve Yazi, appreciate it!
|
||||
|
||||
I noticed that you did not correctly follow the issue template. Please ensure that:
|
||||
|
||||
- The requested feature does not exist in the [newest nightly build](https://yazi-rs.github.io/docs/installation/#binaries).
|
||||
- The environment info (\`ya env\`) is updated for the newest nightly.
|
||||
- The non-optional items in the checklist are checked.
|
||||
|
||||
Issues with \`${LABEL_NAME}\` will be marked ready once edited with the proper content, or closed after 2 days of inactivity.
|
||||
|
||||
Our maintainers work on Yazi in their free time, this helps them work efficiently, understand your setup quickly, and find a more appropriate solution. Thanks for your understanding! 🙏
|
||||
`
|
||||
}
|
||||
|
||||
function skipValidation(context) {
|
||||
const login = context.payload.issue?.user?.login || context.payload.pull_request?.user?.login
|
||||
const owner = context.payload.repository?.owner?.login || context.repo.owner
|
||||
return !!login && login === owner
|
||||
}
|
||||
|
||||
module.exports = async ({ github, context, core }) => {
|
||||
async function nightlyHash() {
|
||||
try {
|
||||
const { data: tagRef } = await github.rest.git.getRef({ owner: "sxyazi", repo: "yazi", ref: "tags/nightly" })
|
||||
return tagRef.object.sha.slice(0, 7)
|
||||
} catch (e) {
|
||||
if (e.status === 404) {
|
||||
core.error("Nightly tag not found")
|
||||
} else {
|
||||
core.error(`Error fetching nightly version: ${e.message}`)
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
async function hasLabel(id, label) {
|
||||
try {
|
||||
const { data: labels } = await github.rest.issues.listLabelsOnIssue({
|
||||
...context.repo,
|
||||
issue_number: id,
|
||||
})
|
||||
return labels.some(l => l.name === label)
|
||||
} catch (e) {
|
||||
core.error(`Error checking labels: ${e.message}`)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
async function lastLabeledAt(id) {
|
||||
try {
|
||||
const { data: events } = await github.rest.issues.listEvents({
|
||||
...context.repo,
|
||||
issue_number: id,
|
||||
per_page: 100,
|
||||
})
|
||||
|
||||
const all = events.filter(v => v.event === "labeled" && v.label?.name === LABEL_NAME)
|
||||
return all.at(-1)?.created_at
|
||||
} catch (e) {
|
||||
core.error(`Error getting label timestamp: ${e.message}`)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
async function removedLabelManually(id) {
|
||||
try {
|
||||
const { data: events } = await github.rest.issues.listEvents({
|
||||
...context.repo,
|
||||
issue_number: id,
|
||||
per_page: 100,
|
||||
})
|
||||
|
||||
const all = events.filter(v => v.event === "unlabeled" && v.label?.name === LABEL_NAME)
|
||||
return all.length === 0 ? false : !all.at(-1).actor.login.endsWith("[bot]")
|
||||
} catch (e) {
|
||||
core.error(`Error checking label removal history: ${e.message}`)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
async function updateLabels(id, mark, body) {
|
||||
try {
|
||||
const marked = await hasLabel(id, LABEL_NAME)
|
||||
|
||||
if (!mark && marked) {
|
||||
await github.rest.issues.removeLabel({
|
||||
...context.repo,
|
||||
issue_number: id,
|
||||
name: LABEL_NAME,
|
||||
})
|
||||
await hideOldComments(id)
|
||||
} else if (mark && !marked && !await removedLabelManually(id)) {
|
||||
await github.rest.issues.addLabels({
|
||||
...context.repo,
|
||||
issue_number: id,
|
||||
labels: [LABEL_NAME],
|
||||
})
|
||||
await hideOldComments(id)
|
||||
await github.rest.issues.createComment({
|
||||
...context.repo,
|
||||
issue_number: id,
|
||||
body,
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
core.error(`Error updating labels: ${e.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
async function hideOldComments(id) {
|
||||
try {
|
||||
const comments = await github.paginate(github.rest.issues.listComments, {
|
||||
...context.repo,
|
||||
issue_number: id,
|
||||
per_page: 100,
|
||||
})
|
||||
|
||||
for (const c of comments) {
|
||||
const byBot = c.user?.login?.endsWith("[bot]") || c.user?.type === "Bot"
|
||||
const contains = c?.body?.includes("or closed after 2 days of inactivity")
|
||||
if (!byBot || !contains || !c.node_id) continue
|
||||
|
||||
try {
|
||||
await github.graphql(
|
||||
`mutation($subjectId: ID!, $classifier: ReportedContentClassifiers!) {
|
||||
minimizeComment(input: {subjectId: $subjectId, classifier: $classifier}) {
|
||||
minimizedComment { isMinimized }
|
||||
}
|
||||
}`,
|
||||
{ subjectId: c.node_id, classifier: "OUTDATED" },
|
||||
)
|
||||
} catch (e) {
|
||||
core.error(`Error minimizing comment ${c.id}: ${e.message}`)
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
core.error(`Error listing comments: ${e.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
async function closeOldIssues() {
|
||||
try {
|
||||
const { data: issues } = await github.rest.issues.listForRepo({
|
||||
...context.repo,
|
||||
state: "open",
|
||||
labels: LABEL_NAME,
|
||||
})
|
||||
|
||||
const now = new Date()
|
||||
const twoDaysAgo = new Date(now - 2 * 24 * 60 * 60 * 1000)
|
||||
|
||||
for (const issue of issues) {
|
||||
const markedAt = new Date(await lastLabeledAt(issue.number) || issue.created_at)
|
||||
if (markedAt < twoDaysAgo) {
|
||||
await github.rest.issues.update({
|
||||
...context.repo,
|
||||
issue_number: issue.number,
|
||||
state: "closed",
|
||||
state_reason: "not_planned",
|
||||
})
|
||||
await github.rest.issues.createComment({
|
||||
...context.repo,
|
||||
issue_number: issue.number,
|
||||
body: `This issue has been automatically closed because it was marked as \`${LABEL_NAME}\` for more than 2 days without updates.
|
||||
If the problem persists, please file a new issue and complete the issue template so we can capture all the details necessary to investigate further.`,
|
||||
})
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
core.error(`Error checking old issues: ${e.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
async function closeUnsupportedIssue(id) {
|
||||
try {
|
||||
await github.rest.issues.update({
|
||||
...context.repo,
|
||||
issue_number: id,
|
||||
state: "closed",
|
||||
state_reason: "not_planned",
|
||||
})
|
||||
await github.rest.issues.createComment({
|
||||
...context.repo,
|
||||
issue_number: id,
|
||||
body: `Unsupported issue template.
|
||||
Either the [Bug Report](https://github.com/sxyazi/yazi/issues/new?template=bug.yml) or [Feature Request](https://github.com/sxyazi/yazi/issues/new?template=feature.yml) template should be used.`,
|
||||
})
|
||||
} catch (e) {
|
||||
core.error(`Error closing unsupported issue: ${e.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
if (context.eventName === "schedule") {
|
||||
await closeOldIssues()
|
||||
return
|
||||
}
|
||||
|
||||
if (skipValidation(context)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (context.eventName === "issues") {
|
||||
const id = context.payload.issue.number
|
||||
const content = context.payload.issue.body || ""
|
||||
const creator = context.payload.issue.user.login
|
||||
|
||||
const hash = await nightlyHash()
|
||||
if (!hash) return
|
||||
|
||||
if (await hasLabel(id, "bug")) {
|
||||
const body = bugReportBody(creator, content, hash)
|
||||
await updateLabels(id, !!body, body)
|
||||
} else if (await hasLabel(id, "feature")) {
|
||||
const body = featureRequestBody(creator, content)
|
||||
await updateLabels(id, !!body, body)
|
||||
} else if (context.payload.action === "opened") {
|
||||
await closeUnsupportedIssue(id)
|
||||
}
|
||||
} else if (context.eventName === "pull_request" || context.eventName === "pull_request_target") {
|
||||
const content = context.payload.pull_request.body || ""
|
||||
|
||||
const body = pullRequestBody(content)
|
||||
if (body) {
|
||||
core.setFailed(body)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await main()
|
||||
}
|
||||
256
scripts/validate-form/package-lock.json
generated
Normal file
256
scripts/validate-form/package-lock.json
generated
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
{
|
||||
"name": "validate-form",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "validate-form",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@actions/core": "^3.0.1",
|
||||
"@actions/github": "^9.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/core": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-3.0.1.tgz",
|
||||
"integrity": "sha512-a6d/Nwahm9fliVGRhdhofo40HjHQasUPusmc7vBfyky+7Z+P2A1J68zyFVaNcEclc/Se+eO595oAr5nwEIoIUA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/exec": "^3.0.0",
|
||||
"@actions/http-client": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/exec": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-3.0.0.tgz",
|
||||
"integrity": "sha512-6xH/puSoNBXb72VPlZVm7vQ+svQpFyA96qdDBvhB8eNZOE8LtPf9L4oAsfzK/crCL8YZ+19fKYVnM63Sl+Xzlw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/io": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/github": {
|
||||
"version": "9.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/github/-/github-9.1.1.tgz",
|
||||
"integrity": "sha512-tL5JbYOBZHc0ngEnCsaDcryUizIUIlQyIMwy1Wkx93H5HzbBJ7TbiPx2PnFjBwZW0Vh05JmfFZhecE6gglYegA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/http-client": "^3.0.2",
|
||||
"@octokit/core": "^7.0.6",
|
||||
"@octokit/plugin-paginate-rest": "^14.0.0",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^17.0.0",
|
||||
"@octokit/request": "^10.0.7",
|
||||
"@octokit/request-error": "^7.1.0",
|
||||
"undici": "^6.23.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/github/node_modules/@actions/http-client": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-3.0.2.tgz",
|
||||
"integrity": "sha512-JP38FYYpyqvUsz+Igqlc/JG6YO9PaKuvqjM3iGvaLqFnJ7TFmcLyy2IDrY0bI0qCQug8E9K+elv5ZNfw62ZJzA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tunnel": "^0.0.6",
|
||||
"undici": "^6.23.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/http-client": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-4.0.1.tgz",
|
||||
"integrity": "sha512-+Nvd1ImaOZBSoPbsUtEhv+1z99H12xzncCkz0a3RuehINE81FZSe2QTj3uvAPTcJX/SCzUQHQ0D1GrPMbrPitg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tunnel": "^0.0.6",
|
||||
"undici": "^6.23.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/io": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@actions/io/-/io-3.0.2.tgz",
|
||||
"integrity": "sha512-nRBchcMM+QK1pdjO7/idu86rbJI5YHUKCvKs0KxnSYbVe3F51UfGxuZX4Qy/fWlp6l7gWFwIkrOzN+oUK03kfw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@octokit/auth-token": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-6.0.0.tgz",
|
||||
"integrity": "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/core": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.6.tgz",
|
||||
"integrity": "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/auth-token": "^6.0.0",
|
||||
"@octokit/graphql": "^9.0.3",
|
||||
"@octokit/request": "^10.0.6",
|
||||
"@octokit/request-error": "^7.0.2",
|
||||
"@octokit/types": "^16.0.0",
|
||||
"before-after-hook": "^4.0.0",
|
||||
"universal-user-agent": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/endpoint": {
|
||||
"version": "11.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.3.tgz",
|
||||
"integrity": "sha512-FWFlNxghg4HrXkD3ifYbS/IdL/mDHjh9QcsNyhQjN8dplUoZbejsdpmuqdA76nxj2xoWPs7p8uX2SNr9rYu0Ag==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^16.0.0",
|
||||
"universal-user-agent": "^7.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/graphql": {
|
||||
"version": "9.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-9.0.3.tgz",
|
||||
"integrity": "sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/request": "^10.0.6",
|
||||
"@octokit/types": "^16.0.0",
|
||||
"universal-user-agent": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/openapi-types": {
|
||||
"version": "27.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-27.0.0.tgz",
|
||||
"integrity": "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@octokit/plugin-paginate-rest": {
|
||||
"version": "14.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-14.0.0.tgz",
|
||||
"integrity": "sha512-fNVRE7ufJiAA3XUrha2omTA39M6IXIc6GIZLvlbsm8QOQCYvpq/LkMNGyFlB1d8hTDzsAXa3OKtybdMAYsV/fw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^16.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@octokit/core": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/plugin-rest-endpoint-methods": {
|
||||
"version": "17.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-17.0.0.tgz",
|
||||
"integrity": "sha512-B5yCyIlOJFPqUUeiD0cnBJwWJO8lkJs5d8+ze9QDP6SvfiXSz1BF+91+0MeI1d2yxgOhU/O+CvtiZ9jSkHhFAw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^16.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@octokit/core": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request": {
|
||||
"version": "10.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.8.tgz",
|
||||
"integrity": "sha512-SJZNwY9pur9Agf7l87ywFi14W+Hd9Jg6Ifivsd33+/bGUQIjNujdFiXII2/qSlN2ybqUHfp5xpekMEjIBTjlSw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/endpoint": "^11.0.3",
|
||||
"@octokit/request-error": "^7.0.2",
|
||||
"@octokit/types": "^16.0.0",
|
||||
"fast-content-type-parse": "^3.0.0",
|
||||
"json-with-bigint": "^3.5.3",
|
||||
"universal-user-agent": "^7.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request-error": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.1.0.tgz",
|
||||
"integrity": "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^16.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/types": {
|
||||
"version": "16.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-16.0.0.tgz",
|
||||
"integrity": "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^27.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/before-after-hook": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz",
|
||||
"integrity": "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/fast-content-type-parse": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-3.0.0.tgz",
|
||||
"integrity": "sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/fastify"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/fastify"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/json-with-bigint": {
|
||||
"version": "3.5.8",
|
||||
"resolved": "https://registry.npmjs.org/json-with-bigint/-/json-with-bigint-3.5.8.tgz",
|
||||
"integrity": "sha512-eq/4KP6K34kwa7TcFdtvnftvHCD9KvHOGGICWwMFc4dOOKF5t4iYqnfLK8otCRCRv06FXOzGGyqE8h8ElMvvdw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tunnel": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
|
||||
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.6.11 <=0.7.0 || >=0.7.3"
|
||||
}
|
||||
},
|
||||
"node_modules/undici": {
|
||||
"version": "6.27.0",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-6.27.0.tgz",
|
||||
"integrity": "sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18.17"
|
||||
}
|
||||
},
|
||||
"node_modules/universal-user-agent": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz",
|
||||
"integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==",
|
||||
"license": "ISC"
|
||||
}
|
||||
}
|
||||
}
|
||||
12
scripts/validate-form/package.json
Normal file
12
scripts/validate-form/package.json
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"name": "validate-form",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@actions/core": "^3.0.1",
|
||||
"@actions/github": "^9.1.1"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
name: yazi
|
||||
base: core22
|
||||
base: core24
|
||||
adopt-info: yazi
|
||||
summary: Blazing fast terminal file manager written in Rust, based on async I/O.
|
||||
description: |
|
||||
|
|
@ -9,25 +9,157 @@ license: MIT
|
|||
grade: stable
|
||||
confinement: classic
|
||||
|
||||
architectures:
|
||||
- amd64
|
||||
# - arm64
|
||||
platforms:
|
||||
amd64:
|
||||
arm64:
|
||||
|
||||
apps:
|
||||
yazi:
|
||||
command: yazi
|
||||
environment:
|
||||
PATH: $SNAP/bin:$PATH
|
||||
PATH: $SNAP/bin:$SNAP/usr/bin:$PATH
|
||||
ya:
|
||||
command: ya
|
||||
environment:
|
||||
PATH: $SNAP/bin:$SNAP/usr/bin:$PATH
|
||||
|
||||
parts:
|
||||
yazi:
|
||||
plugin: rust
|
||||
source: https://github.com/sxyazi/yazi.git
|
||||
stage-snaps:
|
||||
- jq
|
||||
stage-packages:
|
||||
- 7zip-standalone
|
||||
- chafa
|
||||
- fd-find
|
||||
- ffmpeg
|
||||
# - fzf
|
||||
- libglu1-mesa
|
||||
- libglut3.12
|
||||
- poppler-utils
|
||||
- ripgrep
|
||||
- wl-clipboard
|
||||
- xclip
|
||||
- zoxide
|
||||
override-build: |
|
||||
craftctl default
|
||||
craftctl set version=$(git describe --tags --abbrev=0)
|
||||
cargo install fd-find --root $CRAFT_PART_INSTALL
|
||||
cargo install ripgrep --root $CRAFT_PART_INSTALL
|
||||
cargo install zoxide --root $CRAFT_PART_INSTALL
|
||||
git clone --depth 1 https://github.com/junegunn/fzf.git fzf
|
||||
fzf/install --bin && mv fzf/bin/fzf $CRAFT_PART_INSTALL/bin/
|
||||
build-attributes:
|
||||
- enable-patchelf
|
||||
organize:
|
||||
# Ubuntu's `fd` package installs a binary named `fdfind`. Rename it in the snap.
|
||||
usr/bin/fdfind: usr/bin/fd
|
||||
prime:
|
||||
# Remove unused items bought in by dependency packages
|
||||
- -usr/bin/fc-*
|
||||
- -usr/bin/ffplay
|
||||
- -usr/bin/pdfattach
|
||||
- -usr/bin/pdfdetach
|
||||
- -usr/bin/pdffonts
|
||||
- -usr/bin/pdfimages
|
||||
- -usr/bin/pdfinfo
|
||||
- -usr/bin/pdfseparate
|
||||
- -usr/bin/pdfsig
|
||||
- -usr/bin/pdftocairo
|
||||
- -usr/bin/pdftohtml
|
||||
- -usr/bin/pdftops
|
||||
- -usr/bin/pdftotext
|
||||
- -usr/bin/pdfunite
|
||||
# Remove unused libraries identified by snapcraft's linter
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libabsl_bad_*
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libabsl_civil_time.so.*
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libabsl_cord*
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libabsl_examine_stack.so.*
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libabsl_exponential_biased.so.*
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libabsl_failure_signal_handler.so.*
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libabsl_flags*
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libabsl_hash*
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libabsl_log_severity.so.*
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libabsl_periodic_sampler.so.*
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libabsl_random*
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libabsl_raw_hash_set.so.*
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libabsl_scoped_set_env.so.*
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libabsl_statusor.so.*
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libabsl_status.so.*
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libabsl_strerror.so.*
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libabsl_str_format_internal.so.*
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libcaca++.so.0.99.20
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libcjson_utils.so.1.7.17
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libfftw3_omp.so.3.6.10
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libfftw3_threads.so.3.6.10
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libflite_cmu_grapheme_lang.so.2.2
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libflite_cmu_grapheme_lex.so.2.2
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libflite_cmu_indic_lang.so.2.2
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libflite_cmu_indic_lex.so.2.2
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libflite_cmu_time_awb.so.2.2
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libfreebl3.so
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libfreeblpriv3.so
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libGLX_mesa.so.0.0.0
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libhwy_contrib.so.1.0.7
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libhwy_test.so.1.0.7
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libicui18n.so.74.2
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libicuio.so.74.2
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libicutest.so.74.2
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libicutu.so.74.2
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libjacknet.so.0.1.0
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libjackserver.so.0.1.0
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libnssckbi.so
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libnssdbm3.so
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libpulse-simple.so.0.1.1
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libsoftokn3.so
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libsphinxad.so.3.0.0
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libssl3.so
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libtheora.so.0.3.10
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libxcb-dri2.so.0.0.0
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libxcb-glx.so.0.0.0
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libxcb-present.so.0.0.0
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libxcb-sync.so.1.0.0
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libxshmfence.so.1.0.0
|
||||
- -usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libzvbi-chains.so.0.0.0
|
||||
|
||||
# The Ubuntu `imagemagick` package does not ship a `magick` binary,
|
||||
# which `yazi` looks for. Building the package oursleves yields the
|
||||
# expected binary without much overhead, and works across platforms.
|
||||
magick:
|
||||
plugin: autotools
|
||||
source: https://github.com/ImageMagick/ImageMagick.git
|
||||
source-type: git
|
||||
source-tag: 7.1.2-0
|
||||
source-depth: 1
|
||||
stage-packages:
|
||||
- libgomp1
|
||||
autotools-configure-parameters:
|
||||
- --prefix=/usr
|
||||
build-attributes:
|
||||
- enable-patchelf
|
||||
organize:
|
||||
# `libgomp1` installs libgomp into the multiarch directory, but the
|
||||
# `magick` binary's RPATH only searches `$ORIGIN/../lib` (i.e. usr/lib).
|
||||
# Move it alongside the Magick libraries so the bundled binary can load
|
||||
# it at runtime; otherwise magick fails with:
|
||||
# "libgomp.so.1: cannot open shared object file: No such file or directory"
|
||||
usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libgomp.so*: usr/lib/
|
||||
prime:
|
||||
- usr/bin/magick
|
||||
- usr/lib/libgomp.so*
|
||||
- usr/lib/libMagickCore-7.Q16HDRI.so*
|
||||
- usr/lib/libMagickWand-7.Q16HDRI.so*
|
||||
|
||||
cleanup:
|
||||
after: [yazi, magick]
|
||||
plugin: nil
|
||||
build-packages:
|
||||
- patchelf
|
||||
build-snaps:
|
||||
- core24
|
||||
override-prime: |
|
||||
# Ubuntu's /usr/bin/7zz is a simple bash wrapper that just exec's
|
||||
# /usr/lib/7zip/7zz - this just shortcuts that and places the actual
|
||||
# executable at $SNAP/usr/bin/7zz.
|
||||
mv $CRAFT_PRIME/usr/lib/7zip/7zz $CRAFT_PRIME/usr/bin/7zz
|
||||
|
||||
# Ensure we don't ship duplicates of files that exist in the core24
|
||||
# snap.
|
||||
cd /snap/core24/current
|
||||
find . -type f,l -exec rm -rf "${CRAFT_PRIME}/{}" \;
|
||||
|
|
|
|||
7
stylua.toml
Normal file
7
stylua.toml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
syntax = "Lua54"
|
||||
indent_width = 2
|
||||
call_parentheses = "NoSingleTable"
|
||||
collapse_simple_statement = "FunctionOnly"
|
||||
|
||||
[sort_requires]
|
||||
enabled = true
|
||||
58
yazi-actor/Cargo.toml
Normal file
58
yazi-actor/Cargo.toml
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
[package]
|
||||
name = "yazi-actor"
|
||||
description = "Yazi actor model"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
authors.workspace = true
|
||||
homepage.workspace = true
|
||||
repository.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[features]
|
||||
default = [ "vendored-lua" ]
|
||||
vendored-lua = [ "mlua/vendored" ]
|
||||
|
||||
[dependencies]
|
||||
yazi-binding = { path = "../yazi-binding", version = "26.5.6" }
|
||||
yazi-boot = { path = "../yazi-boot", version = "26.5.6" }
|
||||
yazi-config = { path = "../yazi-config", version = "26.5.6" }
|
||||
yazi-core = { path = "../yazi-core", version = "26.5.6" }
|
||||
yazi-dds = { path = "../yazi-dds", version = "26.5.6" }
|
||||
yazi-emulator = { path = "../yazi-emulator", version = "26.5.6" }
|
||||
yazi-fs = { path = "../yazi-fs", version = "26.5.6" }
|
||||
yazi-macro = { path = "../yazi-macro", version = "26.5.6" }
|
||||
yazi-parser = { path = "../yazi-parser", version = "26.5.6" }
|
||||
yazi-plugin = { path = "../yazi-plugin", version = "26.5.6" }
|
||||
yazi-proxy = { path = "../yazi-proxy", version = "26.5.6" }
|
||||
yazi-runner = { path = "../yazi-runner", version = "26.5.6" }
|
||||
yazi-scheduler = { path = "../yazi-scheduler", version = "26.5.6" }
|
||||
yazi-shared = { path = "../yazi-shared", version = "26.5.6" }
|
||||
yazi-shim = { path = "../yazi-shim", version = "26.5.6" }
|
||||
yazi-term = { path = "../yazi-term", version = "26.5.6" }
|
||||
yazi-tty = { path = "../yazi-tty", version = "26.5.9" }
|
||||
yazi-tui = { path = "../yazi-tui", version = "26.5.6" }
|
||||
yazi-vfs = { path = "../yazi-vfs", version = "26.5.6" }
|
||||
yazi-watcher = { path = "../yazi-watcher", version = "26.5.6" }
|
||||
yazi-widgets = { path = "../yazi-widgets", version = "26.5.6" }
|
||||
|
||||
# External dependencies
|
||||
anyhow = { workspace = true }
|
||||
either = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
hashbrown = { workspace = true }
|
||||
indexmap = { workspace = true }
|
||||
inventory = { workspace = true }
|
||||
mlua = { workspace = true }
|
||||
paste = { workspace = true }
|
||||
ratatui-core = { workspace = true }
|
||||
scopeguard = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
tokio-stream = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
|
||||
[target."cfg(unix)".dependencies]
|
||||
libc = { workspace = true }
|
||||
5
yazi-actor/README.md
Normal file
5
yazi-actor/README.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# yazi-actor
|
||||
|
||||
This crate is part of [Yazi][source], and it is not supposed to be used outside, as there are no guarantees about the stability of its API.
|
||||
|
||||
[source]: https://github.com/sxyazi/yazi
|
||||
15
yazi-actor/src/actor.rs
Normal file
15
yazi-actor/src/actor.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
use anyhow::Result;
|
||||
use yazi_parser::spark::SparkKind;
|
||||
use yazi_shared::data::Data;
|
||||
|
||||
use crate::Ctx;
|
||||
|
||||
pub trait Actor {
|
||||
type Form;
|
||||
|
||||
const NAME: &str;
|
||||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data>;
|
||||
|
||||
fn hook(_cx: &Ctx, _form: &Self::Form) -> Option<SparkKind> { None }
|
||||
}
|
||||
42
yazi-actor/src/app/accept_payload.rs
Normal file
42
yazi-actor/src/app/accept_payload.rs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
use anyhow::Result;
|
||||
use mlua::IntoLua;
|
||||
use tracing::error;
|
||||
use yazi_actor::lives::Lives;
|
||||
use yazi_binding::runtime_scope;
|
||||
use yazi_dds::{LOCAL, Payload, REMOTE};
|
||||
use yazi_macro::succ;
|
||||
use yazi_plugin::LUA;
|
||||
use yazi_shared::data::Data;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct AcceptPayload;
|
||||
|
||||
impl Actor for AcceptPayload {
|
||||
type Form = Payload<'static>;
|
||||
|
||||
const NAME: &str = "accept_payload";
|
||||
|
||||
fn act(cx: &mut Ctx, payload: Payload) -> Result<Data> {
|
||||
let kind = payload.body.kind();
|
||||
let lock = if payload.receiver == 0 || payload.receiver != payload.sender {
|
||||
REMOTE.read()
|
||||
} else {
|
||||
LOCAL.read()
|
||||
};
|
||||
|
||||
let Some(handlers) = lock.get(kind).filter(|&m| !m.is_empty()).cloned() else { succ!() };
|
||||
drop(lock);
|
||||
|
||||
let kind = kind.to_owned();
|
||||
succ!(Lives::scope(cx.core, |_| {
|
||||
let body = payload.body.into_lua(&LUA)?;
|
||||
for (id, cb) in handlers {
|
||||
if let Err(e) = runtime_scope!(LUA, &id, cb.call::<()>(body.clone())) {
|
||||
error!("Failed to run `{kind}` event handler in your `{id}` plugin: {e}");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})?);
|
||||
}
|
||||
}
|
||||
32
yazi-actor/src/app/bootstrap.rs
Normal file
32
yazi-actor/src/app/bootstrap.rs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
use anyhow::Result;
|
||||
use yazi_actor::Ctx;
|
||||
use yazi_boot::BOOT;
|
||||
use yazi_core::mgr::CdSource;
|
||||
use yazi_macro::{act, succ};
|
||||
use yazi_parser::VoidForm;
|
||||
use yazi_shared::{data::Data, strand::StrandLike, url::UrlLike};
|
||||
|
||||
use crate::Actor;
|
||||
|
||||
pub struct Bootstrap;
|
||||
|
||||
impl Actor for Bootstrap {
|
||||
type Form = VoidForm;
|
||||
|
||||
const NAME: &str = "bootstrap";
|
||||
|
||||
fn act(cx: &mut Ctx, _: Self::Form) -> Result<Data> {
|
||||
cx.mgr.tabs.resize_with(BOOT.files.len(), Default::default);
|
||||
|
||||
for (i, file) in BOOT.files.iter().enumerate().rev() {
|
||||
cx.tab = i;
|
||||
if file.is_empty() {
|
||||
act!(mgr:cd, cx, (BOOT.cwds[i].clone(), CdSource::Tab))?;
|
||||
} else if let Ok(u) = BOOT.cwds[i].try_join(file) {
|
||||
act!(mgr:reveal, cx, (u, CdSource::Tab))?;
|
||||
}
|
||||
}
|
||||
|
||||
succ!();
|
||||
}
|
||||
}
|
||||
24
yazi-actor/src/app/deprecate.rs
Normal file
24
yazi-actor/src/app/deprecate.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
use anyhow::Result;
|
||||
use yazi_core::notify::{MessageLevel, MessageOpt};
|
||||
use yazi_macro::act;
|
||||
use yazi_parser::app::DeprecateForm;
|
||||
use yazi_shared::data::Data;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct Deprecate;
|
||||
|
||||
impl Actor for Deprecate {
|
||||
type Form = DeprecateForm;
|
||||
|
||||
const NAME: &str = "deprecate";
|
||||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
act!(notify:push, cx, MessageOpt {
|
||||
title: "Deprecated API".to_owned(),
|
||||
content: form.content.into_owned(),
|
||||
level: MessageLevel::Warn,
|
||||
timeout: std::time::Duration::from_secs(20),
|
||||
})
|
||||
}
|
||||
}
|
||||
43
yazi-actor/src/app/dnd.rs
Normal file
43
yazi-actor/src/app/dnd.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
use anyhow::Result;
|
||||
use mlua::{ObjectLike, Table};
|
||||
use tracing::error;
|
||||
use yazi_actor::lives::Lives;
|
||||
use yazi_binding::runtime_scope;
|
||||
use yazi_macro::succ;
|
||||
use yazi_parser::app::DndForm;
|
||||
use yazi_plugin::LUA;
|
||||
use yazi_shared::data::Data;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct Dnd;
|
||||
|
||||
impl Actor for Dnd {
|
||||
type Form = DndForm;
|
||||
|
||||
const NAME: &str = "dnd";
|
||||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
let Some(size) = cx.term.as_ref().and_then(|t| t.size().ok()) else { succ!() };
|
||||
let area = yazi_binding::elements::Rect::from(size);
|
||||
|
||||
let result = Lives::scope(cx.core, move |_| {
|
||||
runtime_scope!(LUA, "root", {
|
||||
let root = LUA.globals().raw_get::<Table>("Root")?.call_method::<Table>("new", area)?;
|
||||
|
||||
if form.event.is_drag() {
|
||||
root.call_method::<()>("drag", form.event)?;
|
||||
} else {
|
||||
root.call_method::<()>("drop", form.event)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
});
|
||||
|
||||
if let Err(ref e) = result {
|
||||
error!("{e}");
|
||||
}
|
||||
succ!(result?);
|
||||
}
|
||||
}
|
||||
17
yazi-actor/src/app/focus.rs
Normal file
17
yazi-actor/src/app/focus.rs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
use anyhow::Result;
|
||||
use yazi_actor::Ctx;
|
||||
use yazi_macro::act;
|
||||
use yazi_parser::VoidForm;
|
||||
use yazi_shared::data::Data;
|
||||
|
||||
use crate::Actor;
|
||||
|
||||
pub struct Focus;
|
||||
|
||||
impl Actor for Focus {
|
||||
type Form = VoidForm;
|
||||
|
||||
const NAME: &str = "focus";
|
||||
|
||||
fn act(cx: &mut Ctx, _: Self::Form) -> Result<Data> { act!(mgr:refresh, cx) }
|
||||
}
|
||||
24
yazi-actor/src/app/lua.rs
Normal file
24
yazi-actor/src/app/lua.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
use anyhow::Result;
|
||||
use yazi_binding::runtime_scope;
|
||||
use yazi_macro::succ;
|
||||
use yazi_parser::app::LuaForm;
|
||||
use yazi_plugin::LUA;
|
||||
use yazi_shared::data::{Data, Sendable};
|
||||
|
||||
use crate::{Actor, Ctx, lives::Lives};
|
||||
|
||||
pub struct Lua;
|
||||
|
||||
impl Actor for Lua {
|
||||
type Form = LuaForm;
|
||||
|
||||
const NAME: &str = "lua";
|
||||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
let chunk = LUA.load(&*form.code).set_name("anonymous");
|
||||
let result = Lives::scope(cx.core, |_| {
|
||||
runtime_scope!(LUA, "inline", Sendable::value_to_data(&LUA, chunk.eval()?))
|
||||
});
|
||||
succ!(result?);
|
||||
}
|
||||
}
|
||||
19
yazi-actor/src/app/mod.rs
Normal file
19
yazi-actor/src/app/mod.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
yazi_macro::mod_flat!(
|
||||
accept_payload
|
||||
bootstrap
|
||||
deprecate
|
||||
dnd
|
||||
focus
|
||||
lua
|
||||
mouse
|
||||
plugin
|
||||
plugin_do
|
||||
quit
|
||||
reflow
|
||||
resize
|
||||
resume
|
||||
stop
|
||||
theme
|
||||
title
|
||||
update_progress
|
||||
);
|
||||
52
yazi-actor/src/app/mouse.rs
Normal file
52
yazi-actor/src/app/mouse.rs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
use anyhow::Result;
|
||||
use mlua::{ObjectLike, Table};
|
||||
use tracing::error;
|
||||
use yazi_actor::lives::Lives;
|
||||
use yazi_binding::runtime_scope;
|
||||
use yazi_macro::succ;
|
||||
use yazi_parser::app::MouseForm;
|
||||
use yazi_plugin::LUA;
|
||||
use yazi_shared::data::Data;
|
||||
use yazi_term::event::MouseEventKind;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct Mouse;
|
||||
|
||||
impl Actor for Mouse {
|
||||
type Form = MouseForm;
|
||||
|
||||
const NAME: &str = "mouse";
|
||||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
let Some(size) = cx.term.as_ref().and_then(|t| t.size().ok()) else { succ!() };
|
||||
let area = yazi_binding::elements::Rect::from(size);
|
||||
|
||||
let result = Lives::scope(cx.core, move |_| {
|
||||
runtime_scope!(LUA, "root", {
|
||||
let root = LUA.globals().raw_get::<Table>("Root")?.call_method::<Table>("new", area)?;
|
||||
|
||||
match form.event.kind {
|
||||
MouseEventKind::Down(_) => root.call_method("click", (form.event, false))?,
|
||||
MouseEventKind::Up(_) => root.call_method("click", (form.event, true))?,
|
||||
|
||||
MouseEventKind::ScrollDown => root.call_method("scroll", (form.event, 1))?,
|
||||
MouseEventKind::ScrollUp => root.call_method("scroll", (form.event, -1))?,
|
||||
|
||||
MouseEventKind::ScrollRight => root.call_method("touch", (form.event, 1))?,
|
||||
MouseEventKind::ScrollLeft => root.call_method("touch", (form.event, -1))?,
|
||||
|
||||
MouseEventKind::Moved => root.call_method("move", form.event)?,
|
||||
MouseEventKind::Drag(_) => root.call_method("drag", form.event)?,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
});
|
||||
|
||||
if let Err(ref e) = result {
|
||||
error!("{e}");
|
||||
}
|
||||
succ!(result?);
|
||||
}
|
||||
}
|
||||
40
yazi-actor/src/app/plugin.rs
Normal file
40
yazi-actor/src/app/plugin.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
use anyhow::Result;
|
||||
use yazi_core::app::PluginMode;
|
||||
use yazi_macro::{act, succ};
|
||||
use yazi_parser::app::PluginForm;
|
||||
use yazi_proxy::AppProxy;
|
||||
use yazi_runner::loader::LOADER;
|
||||
use yazi_scheduler::NotifyProxy;
|
||||
use yazi_shared::data::Data;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct Plugin;
|
||||
|
||||
impl Actor for Plugin {
|
||||
type Form = PluginForm;
|
||||
|
||||
const NAME: &str = "plugin";
|
||||
|
||||
fn act(cx: &mut Ctx, Self::Form { mut opt }: Self::Form) -> Result<Data> {
|
||||
let mut hits = false;
|
||||
if let Some(chunk) = LOADER.read().get(&*opt.id) {
|
||||
hits = true;
|
||||
opt.mode = opt.mode.auto_then(chunk.sync_entry);
|
||||
}
|
||||
|
||||
if opt.mode == PluginMode::Async {
|
||||
succ!(cx.core.tasks.scheduler.plugin_entry(opt.into()));
|
||||
} else if opt.mode == PluginMode::Sync && hits {
|
||||
return act!(app:plugin_do, cx, opt);
|
||||
}
|
||||
|
||||
tokio::spawn(async move {
|
||||
match LOADER.ensure(&opt.id, |_| ()).await {
|
||||
Ok(()) => AppProxy::plugin_do(opt),
|
||||
Err(e) => NotifyProxy::push_error("Plugin load failed", e.to_string()),
|
||||
}
|
||||
});
|
||||
succ!();
|
||||
}
|
||||
}
|
||||
58
yazi-actor/src/app/plugin_do.rs
Normal file
58
yazi-actor/src/app/plugin_do.rs
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
use anyhow::Result;
|
||||
use mlua::ObjectLike;
|
||||
use scopeguard::defer;
|
||||
use tracing::{error, warn};
|
||||
use yazi_binding::runtime_mut;
|
||||
use yazi_core::app::PluginMode;
|
||||
use yazi_macro::succ;
|
||||
use yazi_parser::app::PluginForm;
|
||||
use yazi_plugin::LUA;
|
||||
use yazi_runner::{entry::EntryJob, loader::{LOADER, Loader}};
|
||||
use yazi_scheduler::NotifyProxy;
|
||||
use yazi_shared::data::Data;
|
||||
|
||||
use crate::{Actor, Ctx, lives::Lives};
|
||||
|
||||
pub struct PluginDo;
|
||||
|
||||
impl Actor for PluginDo {
|
||||
type Form = PluginForm;
|
||||
|
||||
const NAME: &str = "plugin_do";
|
||||
|
||||
fn act(cx: &mut Ctx, Self::Form { opt }: Self::Form) -> Result<Data> {
|
||||
let loader = LOADER.read();
|
||||
let Some(chunk) = loader.get(&*opt.id) else {
|
||||
succ!(warn!("plugin `{}` not found", opt.id));
|
||||
};
|
||||
|
||||
if let Err(e) = Loader::compatible_or_error(&opt.id, chunk) {
|
||||
succ!(NotifyProxy::push_error("Incompatible plugin", e.to_string()));
|
||||
}
|
||||
|
||||
if opt.mode.auto_then(chunk.sync_entry) != PluginMode::Sync {
|
||||
succ!(cx.core.tasks.scheduler.plugin_entry(opt.into()));
|
||||
}
|
||||
|
||||
let blocking = runtime_mut!(LUA)?.critical_push(&opt.id, true);
|
||||
defer! { _ = runtime_mut!(LUA).map(|mut r| r.critical_pop(blocking)) }
|
||||
|
||||
let plugin = match LOADER.load_chunk(&LUA, &opt.id, chunk) {
|
||||
Ok(t) => t,
|
||||
Err(e) => succ!(warn!("{e}")),
|
||||
};
|
||||
drop(loader);
|
||||
|
||||
let result = Lives::scope(cx.core, |_| {
|
||||
if let Some(cb) = opt.callback {
|
||||
cb(&LUA, plugin)
|
||||
} else {
|
||||
plugin.call_method("entry", EntryJob { args: opt.args, ..Default::default() })
|
||||
}
|
||||
});
|
||||
if let Err(ref e) = result {
|
||||
error!("Sync plugin `{}` failed: {e}", opt.id);
|
||||
}
|
||||
succ!(result?);
|
||||
}
|
||||
}
|
||||
50
yazi-actor/src/app/quit.rs
Normal file
50
yazi-actor/src/app/quit.rs
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
use std::process;
|
||||
|
||||
use anyhow::Result;
|
||||
use yazi_boot::ARGS;
|
||||
use yazi_fs::engine::{Engine, local::Local};
|
||||
use yazi_parser::app::QuitForm;
|
||||
use yazi_shared::{data::Data, strand::{StrandBuf, StrandLike, ToStrand}};
|
||||
use yazi_tui::Raterm;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct Quit;
|
||||
|
||||
impl Actor for Quit {
|
||||
type Form = QuitForm;
|
||||
|
||||
const NAME: &str = "quit";
|
||||
|
||||
fn act(cx: &mut Ctx, Self::Form { opt }: Self::Form) -> Result<Data> {
|
||||
cx.tasks.shutdown();
|
||||
cx.mgr.shutdown();
|
||||
|
||||
futures::executor::block_on(async {
|
||||
_ = futures::join!(
|
||||
yazi_dds::shutdown(),
|
||||
yazi_dds::STATE.drain(),
|
||||
Self::cwd_to_file(cx, opt.no_cwd_file),
|
||||
Self::selected_to_file(opt.selected)
|
||||
);
|
||||
});
|
||||
|
||||
Raterm::stop();
|
||||
process::exit(opt.code);
|
||||
}
|
||||
}
|
||||
|
||||
impl Quit {
|
||||
async fn cwd_to_file(cx: &Ctx<'_>, no: bool) {
|
||||
if let Some(p) = ARGS.cwd_file.as_ref().filter(|_| !no) {
|
||||
let cwd = cx.mgr.cwd().to_strand();
|
||||
Local::regular(p).write(cwd.encoded_bytes()).await.ok();
|
||||
}
|
||||
}
|
||||
|
||||
async fn selected_to_file(selected: Option<StrandBuf>) {
|
||||
if let (Some(s), Some(p)) = (selected, &ARGS.chooser_file) {
|
||||
Local::regular(p).write(s.encoded_bytes()).await.ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
54
yazi-actor/src/app/reflow.rs
Normal file
54
yazi-actor/src/app/reflow.rs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
use anyhow::Result;
|
||||
use mlua::{LuaString, Value};
|
||||
use ratatui_core::layout::Position;
|
||||
use tracing::error;
|
||||
use yazi_actor::lives::Lives;
|
||||
use yazi_config::LAYOUT;
|
||||
use yazi_macro::{render, succ};
|
||||
use yazi_parser::app::ReflowForm;
|
||||
use yazi_shared::data::Data;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct Reflow;
|
||||
|
||||
impl Actor for Reflow {
|
||||
type Form = ReflowForm;
|
||||
|
||||
const NAME: &str = "reflow";
|
||||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
let Some(size) = cx.term.as_ref().and_then(|t| t.size().ok()) else { succ!() };
|
||||
let mut layout = LAYOUT.get();
|
||||
|
||||
let result = Lives::scope(cx.core, |_| {
|
||||
let comps = (form.reflow)((Position::ORIGIN, size).into())?;
|
||||
|
||||
for v in comps.sequence_values::<Value>() {
|
||||
let Value::Table(t) = v? else {
|
||||
error!("`reflow()` must return a table of components");
|
||||
continue;
|
||||
};
|
||||
|
||||
let id: LuaString = t.get("_id")?;
|
||||
match &*id.as_bytes() {
|
||||
b"current" => layout.current = *t.raw_get::<yazi_binding::elements::Rect>("_area")?,
|
||||
b"preview" => layout.preview = *t.raw_get::<yazi_binding::elements::Rect>("_area")?,
|
||||
b"progress" => layout.progress = *t.raw_get::<yazi_binding::elements::Rect>("_area")?,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
|
||||
if layout != LAYOUT.get() {
|
||||
LAYOUT.set(layout);
|
||||
render!();
|
||||
}
|
||||
|
||||
if let Err(ref e) = result {
|
||||
error!("Failed to `reflow()` the `Root` component:\n{e}");
|
||||
}
|
||||
succ!();
|
||||
}
|
||||
}
|
||||
25
yazi-actor/src/app/resize.rs
Normal file
25
yazi-actor/src/app/resize.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
use anyhow::Result;
|
||||
use yazi_actor::Ctx;
|
||||
use yazi_macro::act;
|
||||
use yazi_parser::app::ReflowForm;
|
||||
use yazi_shared::data::Data;
|
||||
|
||||
use crate::Actor;
|
||||
|
||||
pub struct Resize;
|
||||
|
||||
impl Actor for Resize {
|
||||
type Form = ReflowForm;
|
||||
|
||||
const NAME: &str = "resize";
|
||||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
act!(app:reflow, cx, form)?;
|
||||
|
||||
cx.current_mut().arrow(0);
|
||||
cx.parent_mut().map(|f| f.arrow(0));
|
||||
cx.current_mut().sync_page(true);
|
||||
|
||||
act!(mgr:peek, cx)
|
||||
}
|
||||
}
|
||||
29
yazi-actor/src/app/resume.rs
Normal file
29
yazi-actor/src/app/resume.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
use anyhow::Result;
|
||||
use yazi_macro::{act, render, succ};
|
||||
use yazi_parser::app::ReflowForm;
|
||||
use yazi_shared::data::Data;
|
||||
use yazi_tui::Raterm;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct Resume;
|
||||
|
||||
impl Actor for Resume {
|
||||
type Form = ReflowForm;
|
||||
|
||||
const NAME: &str = "resume";
|
||||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
cx.active_mut().preview.reset();
|
||||
|
||||
drop(cx.term.take());
|
||||
*cx.term = Some(Raterm::start()?);
|
||||
|
||||
// While the app resumes, it's possible that the terminal size has changed.
|
||||
// We need to trigger a resize, and render the UI based on the resized area.
|
||||
act!(app:resize, cx, form.reflow)?;
|
||||
|
||||
act!(app:title, cx).ok();
|
||||
succ!(render!());
|
||||
}
|
||||
}
|
||||
22
yazi-actor/src/app/stop.rs
Normal file
22
yazi-actor/src/app/stop.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
use anyhow::Result;
|
||||
use yazi_macro::succ;
|
||||
use yazi_parser::VoidForm;
|
||||
use yazi_shared::data::Data;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct Stop;
|
||||
|
||||
impl Actor for Stop {
|
||||
type Form = VoidForm;
|
||||
|
||||
const NAME: &str = "stop";
|
||||
|
||||
fn act(cx: &mut Ctx, _: Self::Form) -> Result<Data> {
|
||||
cx.active_mut().preview.reset_image();
|
||||
|
||||
*cx.term = None;
|
||||
|
||||
succ!();
|
||||
}
|
||||
}
|
||||
25
yazi-actor/src/app/theme.rs
Normal file
25
yazi-actor/src/app/theme.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
use anyhow::Result;
|
||||
use yazi_actor::Ctx;
|
||||
use yazi_config::{THEME, build_flavor};
|
||||
use yazi_emulator::EMULATOR;
|
||||
use yazi_macro::{render, succ};
|
||||
use yazi_parser::VoidForm;
|
||||
use yazi_shared::data::Data;
|
||||
use yazi_shim::serde::Overlay;
|
||||
|
||||
use crate::Actor;
|
||||
|
||||
pub struct Theme;
|
||||
|
||||
impl Actor for Theme {
|
||||
type Form = VoidForm;
|
||||
|
||||
const NAME: &str = "theme";
|
||||
|
||||
fn act(_cx: &mut Ctx, _: Self::Form) -> Result<Data> {
|
||||
THEME.overlay(build_flavor(EMULATOR.light, true)?);
|
||||
yazi_plugin::theme::reset()?;
|
||||
|
||||
succ!(render!());
|
||||
}
|
||||
}
|
||||
32
yazi-actor/src/app/title.rs
Normal file
32
yazi-actor/src/app/title.rs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
use anyhow::Result;
|
||||
use yazi_actor::Ctx;
|
||||
use yazi_macro::{succ, writef};
|
||||
use yazi_parser::{app::TitleForm, spark::SparkKind};
|
||||
use yazi_shared::{Source, data::Data};
|
||||
use yazi_tty::{TTY, sequence::SetTitle};
|
||||
use yazi_tui::RatermState;
|
||||
|
||||
use crate::Actor;
|
||||
|
||||
pub struct Title;
|
||||
|
||||
impl Actor for Title {
|
||||
type Form = TitleForm;
|
||||
|
||||
const NAME: &str = "title";
|
||||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
let s = form.value.unwrap_or_else(|| format!("Yazi: {}", cx.tab().name()).into());
|
||||
writef!(TTY.writer(), "{}", SetTitle(&s))?;
|
||||
|
||||
yazi_tui::STATE.set(RatermState { title: !s.is_empty(), ..yazi_tui::STATE.get() });
|
||||
succ!()
|
||||
}
|
||||
|
||||
fn hook(cx: &Ctx, _form: &Self::Form) -> Option<SparkKind> {
|
||||
match cx.source() {
|
||||
Source::Ind => Some(SparkKind::IndAppTitle),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
40
yazi-actor/src/app/update_progress.rs
Normal file
40
yazi-actor/src/app/update_progress.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
use anyhow::Result;
|
||||
use yazi_actor::Ctx;
|
||||
use yazi_macro::{act, render, render_partial, succ};
|
||||
use yazi_parser::app::UpdateProgressForm;
|
||||
use yazi_shared::data::Data;
|
||||
|
||||
use crate::Actor;
|
||||
|
||||
pub struct UpdateProgress;
|
||||
|
||||
impl Actor for UpdateProgress {
|
||||
type Form = UpdateProgressForm;
|
||||
|
||||
const NAME: &str = "update_progress";
|
||||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
// Update the progress of all tasks.
|
||||
let tasks = &mut cx.tasks;
|
||||
let progressed = tasks.summary != form.summary;
|
||||
tasks.summary = form.summary;
|
||||
|
||||
// If the task manager is visible, update the snaps with a full render.
|
||||
if tasks.visible {
|
||||
let new = tasks.paginate();
|
||||
if tasks.snaps != new {
|
||||
tasks.snaps = new;
|
||||
act!(tasks:arrow, cx)?;
|
||||
succ!(render!());
|
||||
}
|
||||
}
|
||||
|
||||
if !progressed {
|
||||
succ!()
|
||||
} else if tasks.summary.total == 0 {
|
||||
succ!(render!())
|
||||
} else {
|
||||
succ!(render_partial!())
|
||||
}
|
||||
}
|
||||
}
|
||||
19
yazi-actor/src/cmp/arrow.rs
Normal file
19
yazi-actor/src/cmp/arrow.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
use anyhow::Result;
|
||||
use yazi_macro::{render, succ};
|
||||
use yazi_parser::ArrowForm;
|
||||
use yazi_shared::data::Data;
|
||||
use yazi_widgets::Scrollable;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct Arrow;
|
||||
|
||||
impl Actor for Arrow {
|
||||
type Form = ArrowForm;
|
||||
|
||||
const NAME: &str = "arrow";
|
||||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
succ!(render!(cx.cmp.scroll(form.step)));
|
||||
}
|
||||
}
|
||||
47
yazi-actor/src/cmp/close.rs
Normal file
47
yazi-actor/src/cmp/close.rs
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
use std::mem;
|
||||
|
||||
use anyhow::Result;
|
||||
use yazi_macro::{act, render, succ};
|
||||
use yazi_parser::cmp::CloseForm;
|
||||
use yazi_shared::data::Data;
|
||||
use yazi_widgets::input::parser::CompleteOpt;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct Close;
|
||||
|
||||
impl Actor for Close {
|
||||
type Form = CloseForm;
|
||||
|
||||
const NAME: &str = "close";
|
||||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
if form.submit && cx.cmp.visible {
|
||||
Self::flush_last_input(cx)?;
|
||||
}
|
||||
|
||||
let cmp = &mut cx.cmp;
|
||||
if let Some(item) = cmp.selected().filter(|_| form.submit).cloned() {
|
||||
return act!(input:complete, cx, CompleteOpt { name: item.name, is_dir: item.is_dir, ticket: cmp.ticket });
|
||||
}
|
||||
|
||||
cmp.caches.clear();
|
||||
cmp.ticket = Default::default();
|
||||
cmp.handle.take().map(|h| h.abort());
|
||||
succ!(render!(mem::replace(&mut cmp.visible, false)));
|
||||
}
|
||||
}
|
||||
|
||||
impl Close {
|
||||
fn flush_last_input(cx: &mut Ctx) -> Result<Data> {
|
||||
let Some(guard) = cx.input.lock() else { succ!() };
|
||||
if cx.cmp.ticket == guard.ticket.current() {
|
||||
succ!();
|
||||
}
|
||||
|
||||
let before = guard.partition().0.to_owned();
|
||||
drop(guard);
|
||||
|
||||
act!(cmp:trigger, cx, before)
|
||||
}
|
||||
}
|
||||
1
yazi-actor/src/cmp/mod.rs
Normal file
1
yazi-actor/src/cmp/mod.rs
Normal file
|
|
@ -0,0 +1 @@
|
|||
yazi_macro::mod_flat!(arrow close show trigger);
|
||||
76
yazi-actor/src/cmp/show.rs
Normal file
76
yazi-actor/src/cmp/show.rs
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
use std::{mem, ops::ControlFlow};
|
||||
|
||||
use anyhow::Result;
|
||||
use yazi_core::cmp::CmpItem;
|
||||
use yazi_macro::{render, succ};
|
||||
use yazi_parser::cmp::ShowForm;
|
||||
use yazi_shared::{data::Data, path::{DynPath, PathDyn}, strand::StrandLike};
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
const LIMIT: usize = 30;
|
||||
|
||||
pub struct Show;
|
||||
|
||||
impl Actor for Show {
|
||||
type Form = ShowForm;
|
||||
|
||||
const NAME: &str = "show";
|
||||
|
||||
fn act(cx: &mut Ctx, Self::Form { opt }: Self::Form) -> Result<Data> {
|
||||
let cmp = &mut cx.cmp;
|
||||
if cmp.ticket != opt.ticket {
|
||||
succ!();
|
||||
}
|
||||
|
||||
if !opt.cache.is_empty() {
|
||||
cmp.caches.insert(opt.cache_name.clone(), opt.cache);
|
||||
}
|
||||
let Some(cache) = cmp.caches.get(&opt.cache_name) else {
|
||||
succ!();
|
||||
};
|
||||
|
||||
cmp.matches = Self::match_candidates(opt.word.dyn_path(), cache);
|
||||
if cmp.matches.is_empty() {
|
||||
succ!(render!(mem::replace(&mut cmp.visible, false)));
|
||||
}
|
||||
|
||||
cmp.offset = 0;
|
||||
cmp.cursor = 0;
|
||||
cmp.visible = true;
|
||||
succ!(render!());
|
||||
}
|
||||
}
|
||||
|
||||
impl Show {
|
||||
fn match_candidates(word: PathDyn, cache: &[CmpItem]) -> Vec<CmpItem> {
|
||||
let smart = !word.encoded_bytes().iter().any(|&b| b.is_ascii_uppercase());
|
||||
|
||||
let flow = cache.iter().try_fold((Vec::new(), Vec::new()), |(mut exact, mut fuzzy), item| {
|
||||
let starts_with = if smart {
|
||||
item.name.starts_with_ignore_ascii_case(word)
|
||||
} else {
|
||||
item.name.starts_with(word)
|
||||
};
|
||||
|
||||
if starts_with {
|
||||
exact.push(item);
|
||||
if exact.len() >= LIMIT {
|
||||
return ControlFlow::Break((exact, fuzzy));
|
||||
}
|
||||
} else if fuzzy.len() < LIMIT - exact.len() && item.name.contains(word) {
|
||||
// Here we don't break the control flow, since we want more exact matching.
|
||||
fuzzy.push(item)
|
||||
}
|
||||
ControlFlow::Continue((exact, fuzzy))
|
||||
});
|
||||
|
||||
let (exact, fuzzy) = match flow {
|
||||
ControlFlow::Continue(v) => v,
|
||||
ControlFlow::Break(v) => v,
|
||||
};
|
||||
|
||||
let it = fuzzy.into_iter().take(LIMIT - exact.len());
|
||||
exact.into_iter().chain(it).cloned().collect()
|
||||
}
|
||||
}
|
||||
155
yazi-actor/src/cmp/trigger.rs
Normal file
155
yazi-actor/src/cmp/trigger.rs
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
use std::{io, mem};
|
||||
|
||||
use anyhow::Result;
|
||||
use yazi_core::cmp::{CmpItem, CmpOpt};
|
||||
use yazi_fs::{engine::{DirReader, FileHolder}, path::clean_url};
|
||||
use yazi_macro::{act, render, succ};
|
||||
use yazi_parser::cmp::TriggerForm;
|
||||
use yazi_proxy::CmpProxy;
|
||||
use yazi_shared::{AnyAsciiChar, BytePredictor, data::Data, natsort, path::{DynPath, PathBufDyn, PathLike}, spec::Spec, strand::{AsStrand, StrandLike}, url::{UrlBuf, UrlCow, UrlLike}};
|
||||
use yazi_vfs::engine;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct Trigger;
|
||||
|
||||
impl Actor for Trigger {
|
||||
type Form = TriggerForm;
|
||||
|
||||
const NAME: &str = "trigger";
|
||||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
if form.ticket.is_some_and(|t| t != cx.cmp.ticket) {
|
||||
succ!();
|
||||
} else if form.ticket.is_none() {
|
||||
cx.cmp.ticket = cx.input.lock().map(|g| g.ticket.current()).unwrap_or_default();
|
||||
}
|
||||
|
||||
cx.cmp.handle.take().map(|h| h.abort());
|
||||
let Some((parent, word)) = Self::split_url(&form.word) else {
|
||||
return act!(cmp:close, cx, false);
|
||||
};
|
||||
|
||||
let ticket = cx.cmp.ticket;
|
||||
if cx.cmp.caches.contains_key(&parent) {
|
||||
return act!(cmp:show, cx, CmpOpt { cache: vec![], cache_name: parent, word, ticket });
|
||||
}
|
||||
|
||||
cx.cmp.handle = Some(tokio::spawn(async move {
|
||||
let mut dir = engine::read_dir(&parent).await?;
|
||||
let mut cache = vec![];
|
||||
|
||||
// "/" is both a directory separator and the root directory per se
|
||||
// As there's no parent directory for the FS root, it is a special case
|
||||
if parent.loc() == "/" {
|
||||
cache.push(CmpItem { name: Default::default(), is_dir: true });
|
||||
}
|
||||
|
||||
while let Ok(Some(ent)) = dir.next().await {
|
||||
if let Ok(ft) = ent.file_type().await {
|
||||
cache.push(CmpItem { name: ent.name().into_owned(), is_dir: ft.is_dir() });
|
||||
}
|
||||
}
|
||||
|
||||
if !cache.is_empty() {
|
||||
cache
|
||||
.sort_unstable_by(|a, b| natsort(a.name.encoded_bytes(), b.name.encoded_bytes(), true));
|
||||
CmpProxy::show(CmpOpt { cache, cache_name: parent, word, ticket });
|
||||
}
|
||||
|
||||
Ok::<_, io::Error>(())
|
||||
}));
|
||||
|
||||
succ!(render!(mem::replace(&mut cx.cmp.visible, false)));
|
||||
}
|
||||
}
|
||||
|
||||
impl Trigger {
|
||||
fn split_url(s: &str) -> Option<(UrlBuf, PathBufDyn)> {
|
||||
let (spec, path) = Spec::parse(s.as_bytes()).ok()?;
|
||||
if path.is_empty() && !AnyAsciiChar::SEP.predicate(s.bytes().last()?) {
|
||||
return None; // We don't complete a `sftp://test`, but `sftp://test/`
|
||||
}
|
||||
|
||||
// Spec
|
||||
let spec = spec.zeroed();
|
||||
if spec.kind.is_local() && path.as_strand() == "~" {
|
||||
return None; // We don't complete a `~`, but `~/`
|
||||
}
|
||||
|
||||
// Child
|
||||
let child = path.rsplit_pred(AnyAsciiChar::SEP).map_or(path.dyn_path(), |(_, c)| c).to_owned();
|
||||
|
||||
// Parent
|
||||
let url = UrlCow::try_from((spec.clone().zeroed(), path)).ok()?;
|
||||
let abs = if let Some(u) = engine::try_absolute(&url) { u } else { url };
|
||||
let parent = abs.loc().try_strip_suffix(&child).ok()?;
|
||||
|
||||
Some((clean_url(UrlCow::try_from((spec, parent)).ok()?), child))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use yazi_fs::CWD;
|
||||
use yazi_shared::url::UrlLike;
|
||||
|
||||
use super::*;
|
||||
|
||||
fn compare(s: &str, parent: &str, child: &str) {
|
||||
let (mut p, c) = Trigger::split_url(s).unwrap();
|
||||
if let Ok(u) = p.try_strip_prefix(yazi_fs::CWD.load().as_ref()) {
|
||||
p = UrlBuf::Regular(u.as_os().unwrap().into());
|
||||
}
|
||||
assert_eq!((p, c.to_str().unwrap()), (parent.parse().unwrap(), child));
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn test_split() {
|
||||
yazi_shared::init_tests();
|
||||
yazi_config::init_tests();
|
||||
yazi_fs::init();
|
||||
|
||||
assert_eq!(Trigger::split_url(""), None);
|
||||
assert_eq!(Trigger::split_url("sftp://vps"), None);
|
||||
compare(" ", "", " ");
|
||||
|
||||
compare("/", "/", "");
|
||||
compare("//", "/", "");
|
||||
compare("///", "/", "");
|
||||
|
||||
compare("/foo", "/", "foo");
|
||||
compare("//foo", "/", "foo");
|
||||
compare("///foo", "/", "foo");
|
||||
|
||||
compare("/foo/", "/foo/", "");
|
||||
compare("//foo/", "/foo/", "");
|
||||
compare("/foo/bar", "/foo/", "bar");
|
||||
compare("///foo/bar", "/foo/", "bar");
|
||||
|
||||
CWD.set(&"sftp://vps".parse::<UrlBuf>().unwrap(), || {});
|
||||
compare("sftp://vps/a", "sftp://vps/.", "a");
|
||||
compare("sftp://vps//a", "sftp://vps//", "a");
|
||||
compare("test-scope://aws/a", "test-scope://aws/.", "a");
|
||||
compare("test-scope://aws//a", "test-scope://aws//", "a");
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[test]
|
||||
fn test_split() {
|
||||
yazi_shared::init_tests();
|
||||
yazi_config::init_tests();
|
||||
yazi_fs::init();
|
||||
compare("foo", "", "foo");
|
||||
|
||||
compare(r"foo\", r"foo\", "");
|
||||
compare(r"foo\bar", r"foo\", "bar");
|
||||
compare(r"foo\bar\", r"foo\bar\", "");
|
||||
|
||||
compare(r"C:\", r"C:\", "");
|
||||
compare(r"C:\foo", r"C:\", "foo");
|
||||
compare(r"C:\foo\", r"C:\foo\", "");
|
||||
compare(r"C:\foo\bar", r"C:\foo\", "bar");
|
||||
}
|
||||
}
|
||||
26
yazi-actor/src/confirm/arrow.rs
Normal file
26
yazi-actor/src/confirm/arrow.rs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
use anyhow::Result;
|
||||
use yazi_macro::{render, succ};
|
||||
use yazi_parser::ArrowForm;
|
||||
use yazi_shared::data::Data;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct Arrow;
|
||||
|
||||
impl Actor for Arrow {
|
||||
type Form = ArrowForm;
|
||||
|
||||
const NAME: &str = "arrow";
|
||||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
let confirm = &mut cx.core.confirm;
|
||||
|
||||
let area = cx.core.mgr.area(confirm.position);
|
||||
let len = confirm.list.line_count(area.width);
|
||||
|
||||
let old = confirm.offset;
|
||||
confirm.offset = form.step.add(confirm.offset, len, area.height as _, 0, 0);
|
||||
|
||||
succ!(render!(old != confirm.offset));
|
||||
}
|
||||
}
|
||||
20
yazi-actor/src/confirm/close.rs
Normal file
20
yazi-actor/src/confirm/close.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
use anyhow::Result;
|
||||
use yazi_macro::{render, succ};
|
||||
use yazi_parser::confirm::CloseForm;
|
||||
use yazi_shared::data::Data;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct Close;
|
||||
|
||||
impl Actor for Close {
|
||||
type Form = CloseForm;
|
||||
|
||||
const NAME: &str = "close";
|
||||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
cx.confirm.token.complete(form.submit);
|
||||
cx.confirm.visible = false;
|
||||
succ!(render!());
|
||||
}
|
||||
}
|
||||
1
yazi-actor/src/confirm/mod.rs
Normal file
1
yazi-actor/src/confirm/mod.rs
Normal file
|
|
@ -0,0 +1 @@
|
|||
yazi_macro::mod_flat!(arrow close show);
|
||||
31
yazi-actor/src/confirm/show.rs
Normal file
31
yazi-actor/src/confirm/show.rs
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
use anyhow::Result;
|
||||
use yazi_macro::{act, render, succ};
|
||||
use yazi_parser::confirm::ShowForm;
|
||||
use yazi_shared::data::Data;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct Show;
|
||||
|
||||
impl Actor for Show {
|
||||
type Form = ShowForm;
|
||||
|
||||
const NAME: &str = "show";
|
||||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
act!(confirm:close, cx)?;
|
||||
|
||||
let confirm = &mut cx.confirm;
|
||||
confirm.title = form.cfg.title;
|
||||
confirm.body = form.cfg.body;
|
||||
confirm.list = form.cfg.list;
|
||||
|
||||
confirm.position = form.cfg.position;
|
||||
confirm.offset = 0;
|
||||
|
||||
confirm.token = form.token;
|
||||
confirm.visible = true;
|
||||
|
||||
succ!(render!());
|
||||
}
|
||||
}
|
||||
123
yazi-actor/src/context.rs
Normal file
123
yazi-actor/src/context.rs
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use anyhow::{Result, anyhow};
|
||||
use yazi_core::{Core, mgr::Tabs, tab::{Folder, Tab}};
|
||||
use yazi_fs::file::File;
|
||||
use yazi_shared::{Source, event::Action, id::Id, url::UrlBuf};
|
||||
use yazi_tui::Raterm;
|
||||
|
||||
pub struct Ctx<'a> {
|
||||
pub core: &'a mut Core,
|
||||
pub term: &'a mut Option<Raterm>,
|
||||
pub tab: usize,
|
||||
pub level: usize,
|
||||
pub source: Source,
|
||||
#[cfg(debug_assertions)]
|
||||
pub backtrace: Vec<&'static str>,
|
||||
}
|
||||
|
||||
impl Deref for Ctx<'_> {
|
||||
type Target = Core;
|
||||
|
||||
fn deref(&self) -> &Self::Target { self.core }
|
||||
}
|
||||
|
||||
impl DerefMut for Ctx<'_> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target { self.core }
|
||||
}
|
||||
|
||||
impl<'a> Ctx<'a> {
|
||||
pub fn new(action: &Action, core: &'a mut Core, term: &'a mut Option<Raterm>) -> Result<Self> {
|
||||
let tab = if let Ok(id) = action.get::<Id>("tab") {
|
||||
core
|
||||
.mgr
|
||||
.tabs
|
||||
.iter()
|
||||
.position(|t| t.id == id)
|
||||
.ok_or_else(|| anyhow!("Tab with id {id} not found"))?
|
||||
} else {
|
||||
core.mgr.tabs.cursor
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
core,
|
||||
term,
|
||||
tab,
|
||||
level: 0,
|
||||
source: action.source,
|
||||
#[cfg(debug_assertions)]
|
||||
backtrace: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
pub fn renew<'b>(cx: &'a mut Ctx<'b>) -> Self {
|
||||
let tab = cx.core.mgr.tabs.cursor;
|
||||
Self {
|
||||
core: cx.core,
|
||||
term: cx.term,
|
||||
tab,
|
||||
level: cx.level,
|
||||
source: cx.source,
|
||||
#[cfg(debug_assertions)]
|
||||
backtrace: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn active(core: &'a mut Core, term: &'a mut Option<Raterm>) -> Self {
|
||||
let tab = core.mgr.tabs.cursor;
|
||||
Self {
|
||||
core,
|
||||
term,
|
||||
tab,
|
||||
level: 0,
|
||||
source: Source::Unknown,
|
||||
#[cfg(debug_assertions)]
|
||||
backtrace: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Ctx<'a> {
|
||||
#[inline]
|
||||
pub fn tabs(&self) -> &Tabs { &self.mgr.tabs }
|
||||
|
||||
#[inline]
|
||||
pub fn tabs_mut(&mut self) -> &mut Tabs { &mut self.mgr.tabs }
|
||||
|
||||
#[inline]
|
||||
pub fn tab(&self) -> &Tab { &self.tabs()[self.tab] }
|
||||
|
||||
#[inline]
|
||||
pub fn tab_mut(&mut self) -> &mut Tab { &mut self.core.mgr.tabs[self.tab] }
|
||||
|
||||
#[inline]
|
||||
pub fn cwd(&self) -> &UrlBuf { self.tab().cwd() }
|
||||
|
||||
#[inline]
|
||||
pub fn parent(&self) -> Option<&Folder> { self.tab().parent.as_ref() }
|
||||
|
||||
#[inline]
|
||||
pub fn parent_mut(&mut self) -> Option<&mut Folder> { self.tab_mut().parent.as_mut() }
|
||||
|
||||
#[inline]
|
||||
pub fn current(&self) -> &Folder { &self.tab().current }
|
||||
|
||||
#[inline]
|
||||
pub fn current_mut(&mut self) -> &mut Folder { &mut self.tab_mut().current }
|
||||
|
||||
#[inline]
|
||||
pub fn hovered(&self) -> Option<&File> { self.tab().hovered() }
|
||||
|
||||
#[inline]
|
||||
pub fn hovered_url(&self) -> Option<&UrlBuf> { self.tab().hovered_url() }
|
||||
|
||||
#[inline]
|
||||
pub fn hovered_folder(&self) -> Option<&Folder> { self.tab().hovered_folder() }
|
||||
|
||||
#[inline]
|
||||
pub fn hovered_folder_mut(&mut self) -> Option<&mut Folder> {
|
||||
self.tab_mut().hovered_folder_mut()
|
||||
}
|
||||
|
||||
pub fn source(&self) -> Source { if self.level != 1 { Source::Ind } else { self.source } }
|
||||
}
|
||||
1
yazi-actor/src/core/mod.rs
Normal file
1
yazi-actor/src/core/mod.rs
Normal file
|
|
@ -0,0 +1 @@
|
|||
yazi_macro::mod_flat!(preflight);
|
||||
37
yazi-actor/src/core/preflight.rs
Normal file
37
yazi-actor/src/core/preflight.rs
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
use anyhow::Result;
|
||||
use mlua::{ErrorContext, ExternalError, IntoLua, Value};
|
||||
use yazi_binding::runtime_scope;
|
||||
use yazi_dds::LOCAL;
|
||||
use yazi_parser::spark::{Spark, SparkKind};
|
||||
use yazi_plugin::LUA;
|
||||
|
||||
use crate::{Ctx, lives::Lives};
|
||||
|
||||
pub struct Preflight;
|
||||
|
||||
impl Preflight {
|
||||
pub fn act<'a>(cx: &mut Ctx, opt: (SparkKind, Spark<'a>)) -> Result<Spark<'a>> {
|
||||
let kind = opt.0;
|
||||
let Some(handlers) = LOCAL.read().get(kind.into()).filter(|&m| !m.is_empty()).cloned() else {
|
||||
return Ok(opt.1);
|
||||
};
|
||||
|
||||
Ok(Lives::scope(cx.core, |_| {
|
||||
let mut body = opt.1.into_lua(&LUA)?;
|
||||
for (id, cb) in handlers {
|
||||
match runtime_scope!(LUA, &id, cb.call::<Value>(&body)) {
|
||||
Ok(Value::Nil) => {
|
||||
Err(format!("`{kind}` event cancelled by `{id}` plugin on preflight").into_lua_err())?
|
||||
}
|
||||
Ok(v) => body = v,
|
||||
Err(e) => Err(
|
||||
format!("Failed to run `{kind}` event handler in `{id}` plugin: {e}").into_lua_err(),
|
||||
)?,
|
||||
};
|
||||
}
|
||||
|
||||
Spark::from_lua(&LUA, kind, body)
|
||||
.with_context(|e| format!("Unexpected return type from `{kind}` event handlers: {e}"))
|
||||
})?)
|
||||
}
|
||||
}
|
||||
19
yazi-actor/src/help/arrow.rs
Normal file
19
yazi-actor/src/help/arrow.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
use anyhow::Result;
|
||||
use yazi_macro::{render, succ};
|
||||
use yazi_parser::ArrowForm;
|
||||
use yazi_shared::data::Data;
|
||||
use yazi_widgets::Scrollable;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct Arrow;
|
||||
|
||||
impl Actor for Arrow {
|
||||
type Form = ArrowForm;
|
||||
|
||||
const NAME: &str = "arrow";
|
||||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
succ!(render!(cx.help.scroll(form.step)));
|
||||
}
|
||||
}
|
||||
25
yazi-actor/src/help/close.rs
Normal file
25
yazi-actor/src/help/close.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
use anyhow::Result;
|
||||
use yazi_macro::{emit, render, succ};
|
||||
use yazi_parser::help::CloseForm;
|
||||
use yazi_shared::data::Data;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct Close;
|
||||
|
||||
impl Actor for Close {
|
||||
type Form = CloseForm;
|
||||
|
||||
const NAME: &str = "close";
|
||||
|
||||
fn act(cx: &mut Ctx, opt: Self::Form) -> Result<Data> {
|
||||
let help = &mut cx.help;
|
||||
|
||||
if let Some(chord) = help.bindings.get(help.cursor).filter(|_| opt.submit) {
|
||||
emit!(Seq(chord.to_seq(help.layer)));
|
||||
}
|
||||
|
||||
help.visible = false;
|
||||
succ!(render!());
|
||||
}
|
||||
}
|
||||
24
yazi-actor/src/help/escape.rs
Normal file
24
yazi-actor/src/help/escape.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
use anyhow::Result;
|
||||
use yazi_macro::{act, render, succ};
|
||||
use yazi_parser::VoidForm;
|
||||
use yazi_shared::data::Data;
|
||||
use yazi_widgets::input::InputMode;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct Escape;
|
||||
|
||||
impl Actor for Escape {
|
||||
type Form = VoidForm;
|
||||
|
||||
const NAME: &str = "escape";
|
||||
|
||||
fn act(cx: &mut Ctx, _: Self::Form) -> Result<Data> {
|
||||
if cx.help.input.mode() == InputMode::Normal {
|
||||
return act!(help:close, cx);
|
||||
}
|
||||
|
||||
act!(escape, cx.help.input)?;
|
||||
succ!(render!());
|
||||
}
|
||||
}
|
||||
1
yazi-actor/src/help/mod.rs
Normal file
1
yazi-actor/src/help/mod.rs
Normal file
|
|
@ -0,0 +1 @@
|
|||
yazi_macro::mod_flat!(arrow close escape toggle);
|
||||
39
yazi-actor/src/help/toggle.rs
Normal file
39
yazi-actor/src/help/toggle.rs
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
use anyhow::Result;
|
||||
use ratatui_core::layout::Margin;
|
||||
use yazi_config::popup::Help;
|
||||
use yazi_macro::{render, succ};
|
||||
use yazi_parser::help::ToggleForm;
|
||||
use yazi_shared::data::Data;
|
||||
use yazi_widgets::input::Input;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct Toggle;
|
||||
|
||||
impl Actor for Toggle {
|
||||
type Form = ToggleForm;
|
||||
|
||||
const NAME: &str = "toggle";
|
||||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
let position = Help::position();
|
||||
let area = cx.mgr.area(position);
|
||||
let input_area = area.inner(Margin::new(1, 1));
|
||||
|
||||
let help = &mut cx.help;
|
||||
help.visible = true;
|
||||
help.layer = form.layer;
|
||||
help.position = position;
|
||||
help.height = area.height;
|
||||
|
||||
help.input = Input::default();
|
||||
help.input.repos(input_area);
|
||||
|
||||
help.keyword.clear();
|
||||
help.offset = 0;
|
||||
help.cursor = 0;
|
||||
help.filter_apply();
|
||||
|
||||
succ!(render!());
|
||||
}
|
||||
}
|
||||
47
yazi-actor/src/input/close.rs
Normal file
47
yazi-actor/src/input/close.rs
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
use anyhow::Result;
|
||||
use yazi_core::input::InputMutGuard;
|
||||
use yazi_macro::{act, render, succ};
|
||||
use yazi_parser::{input::CloseForm, spark::SparkKind};
|
||||
use yazi_shared::{Source, data::Data};
|
||||
use yazi_widgets::input::InputEvent;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct Close;
|
||||
|
||||
impl Actor for Close {
|
||||
type Form = CloseForm;
|
||||
|
||||
const NAME: &str = "close";
|
||||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
let Some(mut guard) = cx.input.lock_mut() else {
|
||||
succ!();
|
||||
};
|
||||
|
||||
guard.ticket.next();
|
||||
if let Some(cb) = guard.cb.take() {
|
||||
let value = guard.value().to_owned();
|
||||
cb(if form.submit { InputEvent::Submit(value) } else { InputEvent::Cancel(value) });
|
||||
}
|
||||
|
||||
if form.submit
|
||||
&& let InputMutGuard::Main(input) = guard
|
||||
{
|
||||
input.histories.remember(&input.main.history.name, input.main.value());
|
||||
}
|
||||
|
||||
cx.input.main.visible = false;
|
||||
|
||||
act!(cmp:close, cx)?;
|
||||
succ!(render!());
|
||||
}
|
||||
|
||||
fn hook(cx: &Ctx, _form: &Self::Form) -> Option<SparkKind> {
|
||||
match cx.source() {
|
||||
Source::Key => Some(SparkKind::KeyInputClose),
|
||||
Source::Ind => Some(SparkKind::IndInputClose),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
26
yazi-actor/src/input/complete.rs
Normal file
26
yazi-actor/src/input/complete.rs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
use anyhow::Result;
|
||||
use yazi_macro::{act, succ};
|
||||
use yazi_shared::data::Data;
|
||||
use yazi_widgets::input::parser::CompleteOpt;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct Complete;
|
||||
|
||||
impl Actor for Complete {
|
||||
type Form = CompleteOpt;
|
||||
|
||||
const NAME: &str = "complete";
|
||||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
let Some(mut guard) = cx.input.lock_mut() else {
|
||||
succ!();
|
||||
};
|
||||
|
||||
if guard.ticket.current() != form.ticket {
|
||||
succ!();
|
||||
}
|
||||
|
||||
act!(complete, guard, form)
|
||||
}
|
||||
}
|
||||
34
yazi-actor/src/input/escape.rs
Normal file
34
yazi-actor/src/input/escape.rs
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
use anyhow::Result;
|
||||
use yazi_macro::{act, render, succ};
|
||||
use yazi_parser::VoidForm;
|
||||
use yazi_shared::data::Data;
|
||||
use yazi_widgets::input::InputOp;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct Escape;
|
||||
|
||||
impl Actor for Escape {
|
||||
type Form = VoidForm;
|
||||
|
||||
const NAME: &str = "escape";
|
||||
|
||||
fn act(cx: &mut Ctx, _: Self::Form) -> Result<Data> {
|
||||
use yazi_widgets::input::InputMode as M;
|
||||
let Some(mut guard) = cx.input.lock_mut() else {
|
||||
succ!();
|
||||
};
|
||||
|
||||
let (mode, op) = (guard.snap().mode, guard.snap().op);
|
||||
act!(escape, guard)?;
|
||||
|
||||
drop(guard);
|
||||
match mode {
|
||||
M::Normal if op == InputOp::None => act!(input:close, cx),
|
||||
M::Insert => act!(cmp:close, cx),
|
||||
M::Normal | M::Replace => Ok(().into()),
|
||||
}?;
|
||||
|
||||
succ!(render!());
|
||||
}
|
||||
}
|
||||
1
yazi-actor/src/input/mod.rs
Normal file
1
yazi-actor/src/input/mod.rs
Normal file
|
|
@ -0,0 +1 @@
|
|||
yazi_macro::mod_flat!(close complete escape recall remember show);
|
||||
32
yazi-actor/src/input/recall.rs
Normal file
32
yazi-actor/src/input/recall.rs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
use anyhow::Result;
|
||||
use yazi_core::input::InputMutGuard;
|
||||
use yazi_macro::succ;
|
||||
use yazi_parser::input::RecallForm;
|
||||
use yazi_shared::data::Data;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct Recall;
|
||||
|
||||
impl Actor for Recall {
|
||||
type Form = RecallForm;
|
||||
|
||||
const NAME: &str = "recall";
|
||||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
let Some(input) = cx.input.lock_mut() else {
|
||||
succ!();
|
||||
};
|
||||
|
||||
match input {
|
||||
InputMutGuard::Main(input) => {
|
||||
let entries = input.histories.get(&input.main.history.name);
|
||||
input.main.recall(entries, form.step)
|
||||
}
|
||||
InputMutGuard::Alt(input, mut guard) => {
|
||||
let entries = input.histories.get(&guard.history.name);
|
||||
guard.recall(entries, form.step)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
33
yazi-actor/src/input/remember.rs
Normal file
33
yazi-actor/src/input/remember.rs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
use anyhow::Result;
|
||||
use yazi_core::input::InputMutGuard;
|
||||
use yazi_macro::succ;
|
||||
use yazi_parser::VoidForm;
|
||||
use yazi_shared::data::Data;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct Remember;
|
||||
|
||||
impl Actor for Remember {
|
||||
type Form = VoidForm;
|
||||
|
||||
const NAME: &str = "remember";
|
||||
|
||||
fn act(cx: &mut Ctx, _: Self::Form) -> Result<Data> {
|
||||
let Some(mut input) = cx.input.lock_mut() else {
|
||||
succ!();
|
||||
};
|
||||
|
||||
match &mut input {
|
||||
InputMutGuard::Main(input) => {
|
||||
input.histories.remember(&input.main.history.name, input.main.value());
|
||||
}
|
||||
InputMutGuard::Alt(input, guard) => {
|
||||
input.histories.remember(&guard.history.name, guard.value());
|
||||
}
|
||||
}
|
||||
|
||||
input.history.take();
|
||||
succ!();
|
||||
}
|
||||
}
|
||||
36
yazi-actor/src/input/show.rs
Normal file
36
yazi-actor/src/input/show.rs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
use std::ops::DerefMut;
|
||||
|
||||
use anyhow::Result;
|
||||
use yazi_config::{THEME, YAZI};
|
||||
use yazi_macro::{act, render, succ};
|
||||
use yazi_parser::input::ShowForm;
|
||||
use yazi_shared::data::Data;
|
||||
use yazi_shim::ratatui::Padable;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct Show;
|
||||
|
||||
impl Actor for Show {
|
||||
type Form = ShowForm;
|
||||
|
||||
const NAME: &str = "show";
|
||||
|
||||
fn act(cx: &mut Ctx, Self::Form { mut opt }: Self::Form) -> Result<Data> {
|
||||
act!(input:close, cx)?;
|
||||
|
||||
let area = cx.mgr.area(opt.position).padding(cx.input.padding());
|
||||
let input = &mut cx.input;
|
||||
input.main.name = opt.name.clone();
|
||||
input.main.title = opt.title.clone();
|
||||
input.main.position = opt.position;
|
||||
input.main.visible = true;
|
||||
|
||||
opt.styles = (&THEME.input).into();
|
||||
opt.blinking = YAZI.input.cursor_blink;
|
||||
*input.main.deref_mut() = yazi_widgets::input::Input::new(opt)?;
|
||||
input.main.repos(area);
|
||||
|
||||
succ!(render!());
|
||||
}
|
||||
}
|
||||
7
yazi-actor/src/lib.rs
Normal file
7
yazi-actor/src/lib.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
extern crate self as yazi_actor;
|
||||
|
||||
yazi_macro::mod_pub!(app cmp confirm core help input lives mgr notify pick spot tasks which);
|
||||
|
||||
yazi_macro::mod_flat!(actor context);
|
||||
|
||||
pub fn init() { lives::init(); }
|
||||
29
yazi-actor/src/lives/behavior.rs
Normal file
29
yazi-actor/src/lives/behavior.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use mlua::{AnyUserData, UserData, UserDataMethods};
|
||||
|
||||
use super::{Lives, PtrCell};
|
||||
|
||||
pub(super) struct Behavior {
|
||||
inner: PtrCell<yazi_scheduler::Behavior>,
|
||||
}
|
||||
|
||||
impl Deref for Behavior {
|
||||
type Target = yazi_scheduler::Behavior;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl Behavior {
|
||||
pub(super) fn make(inner: &yazi_scheduler::Behavior) -> mlua::Result<AnyUserData> {
|
||||
let inner = PtrCell::from(inner);
|
||||
|
||||
Lives::scoped_userdata(Self { inner })
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Behavior {
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_method("reset", |_, me, ()| Ok(me.reset()));
|
||||
}
|
||||
}
|
||||
71
yazi-actor/src/lives/core.rs
Normal file
71
yazi-actor/src/lives/core.rs
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use mlua::{AnyUserData, IntoLua, LuaString, MetaMethod, UserData, UserDataMethods, UserDataRef, Value};
|
||||
use paste::paste;
|
||||
|
||||
use super::{Lives, PtrCell};
|
||||
|
||||
pub(super) type CoreRef = UserDataRef<Core>;
|
||||
|
||||
pub(super) struct Core {
|
||||
inner: PtrCell<yazi_core::Core>,
|
||||
|
||||
c_active: Option<Value>,
|
||||
c_tabs: Option<Value>,
|
||||
c_tasks: Option<Value>,
|
||||
c_yanked: Option<Value>,
|
||||
c_input: Option<Value>,
|
||||
c_which: Option<Value>,
|
||||
c_layer: Option<Value>,
|
||||
}
|
||||
|
||||
impl Deref for Core {
|
||||
type Target = yazi_core::Core;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl Core {
|
||||
pub(super) fn make(inner: &yazi_core::Core) -> mlua::Result<AnyUserData> {
|
||||
Lives::scoped_userdata(Self {
|
||||
inner: inner.into(),
|
||||
|
||||
c_active: None,
|
||||
c_tabs: None,
|
||||
c_tasks: None,
|
||||
c_yanked: None,
|
||||
c_input: None,
|
||||
c_which: None,
|
||||
c_layer: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Core {
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_meta_method_mut(MetaMethod::Index, |lua, me, key: LuaString| {
|
||||
macro_rules! reuse {
|
||||
($key:ident, $value:expr) => {
|
||||
match paste! { &me.[<c_ $key>] } {
|
||||
Some(v) => v.clone(),
|
||||
None => {
|
||||
let v = $value?.into_lua(lua)?;
|
||||
paste! { me.[<c_ $key>] = Some(v.clone()); };
|
||||
v
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
Ok(match &*key.as_bytes() {
|
||||
b"active" => reuse!(active, super::Tab::make(me.active())),
|
||||
b"tabs" => reuse!(tabs, super::Tabs::make(&me.mgr.tabs)),
|
||||
b"tasks" => reuse!(tasks, super::Tasks::make(&me.tasks)),
|
||||
b"yanked" => reuse!(yanked, super::Yanked::make(&me.mgr.yanked)),
|
||||
b"input" => reuse!(input, super::Input::make(&me.input)),
|
||||
b"which" => reuse!(which, super::Which::make(&me.which)),
|
||||
b"layer" => reuse!(layer, Ok::<_, mlua::Error>(me.layer())),
|
||||
_ => Value::Nil,
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
47
yazi-actor/src/lives/entries.rs
Normal file
47
yazi-actor/src/lives/entries.rs
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
use std::ops::{Deref, Range};
|
||||
|
||||
use mlua::{AnyUserData, MetaMethod, UserData, UserDataFields, UserDataMethods};
|
||||
use yazi_shim::mlua::UserDataFieldsExt;
|
||||
|
||||
use super::{File, Filter, Lives, PtrCell};
|
||||
|
||||
pub(super) struct Entries {
|
||||
window: Range<usize>,
|
||||
folder: PtrCell<yazi_core::tab::Folder>,
|
||||
tab: PtrCell<yazi_core::tab::Tab>,
|
||||
}
|
||||
|
||||
impl Deref for Entries {
|
||||
type Target = yazi_fs::Entries;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.folder.entries }
|
||||
}
|
||||
|
||||
impl Entries {
|
||||
pub(super) fn make(
|
||||
window: Range<usize>,
|
||||
folder: &yazi_core::tab::Folder,
|
||||
tab: &yazi_core::tab::Tab,
|
||||
) -> mlua::Result<AnyUserData> {
|
||||
Lives::scoped_userdata(Self { window, folder: folder.into(), tab: tab.into() })
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Entries {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_static_field("filter", |_, me| me.filter().map(Filter::make).transpose());
|
||||
}
|
||||
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_meta_method(MetaMethod::Len, |_, me, ()| Ok(me.window.end - me.window.start));
|
||||
|
||||
methods.add_meta_method(MetaMethod::Index, |_, me, mut idx: usize| {
|
||||
idx += me.window.start;
|
||||
if idx > me.window.end || idx == 0 {
|
||||
Ok(None)
|
||||
} else {
|
||||
Some(File::make(idx - 1, &me.folder, &me.tab)).transpose()
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
157
yazi-actor/src/lives/file.rs
Normal file
157
yazi-actor/src/lives/file.rs
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
use std::{ops::Deref, ptr};
|
||||
|
||||
use mlua::{AnyUserData, IntoLua, UserData, UserDataFields, UserDataMethods};
|
||||
use yazi_binding::{Range, style::Style};
|
||||
use yazi_config::THEME;
|
||||
use yazi_fs::file::FileInventory;
|
||||
use yazi_shared::{path::DynPath, url::UrlLike};
|
||||
|
||||
use super::{FILE_CACHE, Lives};
|
||||
use crate::lives::{CoreRef, PtrCell};
|
||||
|
||||
pub(super) struct File {
|
||||
idx: usize,
|
||||
folder: PtrCell<yazi_core::tab::Folder>,
|
||||
tab: PtrCell<yazi_core::tab::Tab>,
|
||||
}
|
||||
|
||||
impl Deref for File {
|
||||
type Target = yazi_fs::file::File;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.folder.entries[self.idx] }
|
||||
}
|
||||
|
||||
impl AsRef<yazi_fs::file::File> for File {
|
||||
fn as_ref(&self) -> &yazi_fs::file::File { self }
|
||||
}
|
||||
|
||||
impl File {
|
||||
pub(super) fn make(
|
||||
idx: usize,
|
||||
folder: &yazi_core::tab::Folder,
|
||||
tab: &yazi_core::tab::Tab,
|
||||
) -> mlua::Result<AnyUserData> {
|
||||
use hashbrown::hash_map::Entry;
|
||||
|
||||
Ok(
|
||||
match unsafe { (*FILE_CACHE.get()).assume_init_mut() }.entry(PtrCell(&folder.entries[idx])) {
|
||||
Entry::Occupied(oe) => oe.into_mut().clone(),
|
||||
Entry::Vacant(ve) => {
|
||||
let ud = Lives::scoped_userdata(Self { idx, folder: folder.into(), tab: tab.into() })?;
|
||||
ve.insert(ud.clone());
|
||||
ud
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_hovered(&self) -> bool { self.idx == self.folder.cursor }
|
||||
}
|
||||
|
||||
impl UserData for File {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
yazi_binding::impl_file_fields!(fields);
|
||||
|
||||
fields.add_field_method_get("idx", |_, me| Ok(me.idx + 1));
|
||||
fields.add_field_method_get("is_hovered", |_, me| Ok(me.is_hovered()));
|
||||
fields.add_field_method_get("in_current", |_, me| Ok(ptr::eq(&*me.folder, &me.tab.current)));
|
||||
fields.add_field_method_get("in_preview", |_, me| {
|
||||
Ok(me.idx == me.folder.cursor && me.tab.hovered().is_some_and(|f| f.url == me.folder.url))
|
||||
});
|
||||
}
|
||||
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
yazi_binding::impl_file_methods!(methods);
|
||||
|
||||
methods.add_method("icon", |lua, me, ()| {
|
||||
yazi_binding::deprecate!(
|
||||
lua,
|
||||
"{}: `File:icon()` is deprecated, use `th.icon:match(file)` instead"
|
||||
);
|
||||
// TODO: use a cache
|
||||
Ok(yazi_config::THEME.icon.matches(me, me.is_hovered()))
|
||||
});
|
||||
methods.add_method("size", |_, me, ()| {
|
||||
Ok(if me.is_dir() {
|
||||
me.folder.entries.sizes.get(&me.entry_key()).copied()
|
||||
} else {
|
||||
Some(me.len)
|
||||
})
|
||||
});
|
||||
methods.add_method("mime", |lua, me, ()| {
|
||||
let core: CoreRef = lua.named_registry_value("cx")?;
|
||||
core.mgr.mimetype.get(&me.url).map(|s| lua.create_string(s)).transpose()
|
||||
});
|
||||
methods.add_method("prefix", |lua, me, ()| {
|
||||
if !me.url.has_trail() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mut comp = me.url.try_strip_prefix(me.url.trail()).unwrap_or(me.url.loc()).components();
|
||||
comp.next_back();
|
||||
Some(lua.create_string(comp.dyn_path().encoded_bytes())).transpose()
|
||||
});
|
||||
methods.add_method("style", |lua, me, ()| {
|
||||
let core: CoreRef = lua.named_registry_value("cx")?;
|
||||
let mime = core.mgr.mimetype.get(&me.url).unwrap_or_default();
|
||||
Ok(THEME.filetype.match_style(me, mime).map(Style::from))
|
||||
});
|
||||
methods.add_method("is_yanked", |lua, me, ()| {
|
||||
let core: CoreRef = lua.named_registry_value("cx")?;
|
||||
Ok(if !core.mgr.yanked.contains(&me.url) {
|
||||
0u8
|
||||
} else if core.mgr.yanked.cut {
|
||||
2u8
|
||||
} else {
|
||||
1u8
|
||||
})
|
||||
});
|
||||
methods.add_method("is_marked", |_, me, ()| {
|
||||
let Some(visual) = me.tab.mode.visual() else {
|
||||
return Ok(0u8);
|
||||
};
|
||||
if !visual.contains(me.idx, me.tab.current.cursor, me.folder.entries.len()) {
|
||||
return Ok(0u8);
|
||||
}
|
||||
if me.folder.url != me.tab.current.url {
|
||||
return Ok(0u8);
|
||||
}
|
||||
Ok(if me.tab.mode.is_select() { 1u8 } else { 2u8 })
|
||||
});
|
||||
methods.add_method("is_selected", |_, me, ()| Ok(me.tab.selected.contains(&me.url)));
|
||||
methods.add_method("found", |lua, me, ()| {
|
||||
let core: CoreRef = lua.named_registry_value("cx")?;
|
||||
let Some(finder) = &core.active().finder else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let Some(idx) = finder.matched_idx(&me.folder, me.entry_key()) else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
lua.create_sequence_from([idx.into_lua(lua)?, finder.matched.len().into_lua(lua)?]).map(Some)
|
||||
});
|
||||
methods.add_method("highlights", |lua, me, ()| {
|
||||
let core: CoreRef = lua.named_registry_value("cx")?;
|
||||
let Some(finder) = &core.active().finder else {
|
||||
return Ok(None);
|
||||
};
|
||||
if me.folder.url != me.tab.current.url {
|
||||
return Ok(None);
|
||||
}
|
||||
let Some(Some(h)) = me.url.name().map(|s| finder.filter.highlighted(s)) else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
lua.create_sequence_from(h.into_iter().map(Range::from)).map(Some)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
inventory::submit! {
|
||||
FileInventory {
|
||||
register: |_| {},
|
||||
borrow: |ud, f| f(&*ud.borrow::<File>()?),
|
||||
}
|
||||
}
|
||||
27
yazi-actor/src/lives/filter.rs
Normal file
27
yazi-actor/src/lives/filter.rs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use mlua::{AnyUserData, MetaMethod, UserData, UserDataMethods};
|
||||
|
||||
use super::{Lives, PtrCell};
|
||||
|
||||
pub(super) struct Filter {
|
||||
inner: PtrCell<yazi_fs::Filter>,
|
||||
}
|
||||
|
||||
impl Deref for Filter {
|
||||
type Target = yazi_fs::Filter;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl Filter {
|
||||
pub(super) fn make(inner: &yazi_fs::Filter) -> mlua::Result<AnyUserData> {
|
||||
Lives::scoped_userdata(Self { inner: inner.into() })
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Filter {
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_meta_method(MetaMethod::ToString, |_, me, ()| Ok(me.to_string()));
|
||||
}
|
||||
}
|
||||
27
yazi-actor/src/lives/finder.rs
Normal file
27
yazi-actor/src/lives/finder.rs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use mlua::{AnyUserData, MetaMethod, UserData, UserDataMethods};
|
||||
|
||||
use super::{Lives, PtrCell};
|
||||
|
||||
pub(super) struct Finder {
|
||||
inner: PtrCell<yazi_core::tab::Finder>,
|
||||
}
|
||||
|
||||
impl Deref for Finder {
|
||||
type Target = yazi_core::tab::Finder;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl Finder {
|
||||
pub(super) fn make(inner: &yazi_core::tab::Finder) -> mlua::Result<AnyUserData> {
|
||||
Lives::scoped_userdata(Self { inner: inner.into() })
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Finder {
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_meta_method(MetaMethod::ToString, |_, me, ()| Ok(me.filter.to_string()));
|
||||
}
|
||||
}
|
||||
52
yazi-actor/src/lives/folder.rs
Normal file
52
yazi-actor/src/lives/folder.rs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
use std::ops::{Deref, Range};
|
||||
|
||||
use mlua::{AnyUserData, UserData, UserDataFields};
|
||||
use yazi_config::LAYOUT;
|
||||
use yazi_shim::mlua::UserDataFieldsExt;
|
||||
|
||||
use super::{Entries, File, Lives, PtrCell};
|
||||
|
||||
pub(super) struct Folder {
|
||||
window: Range<usize>,
|
||||
inner: PtrCell<yazi_core::tab::Folder>,
|
||||
tab: PtrCell<yazi_core::tab::Tab>,
|
||||
}
|
||||
|
||||
impl Deref for Folder {
|
||||
type Target = yazi_core::tab::Folder;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl Folder {
|
||||
pub(super) fn make(
|
||||
window: Option<Range<usize>>,
|
||||
inner: &yazi_core::tab::Folder,
|
||||
tab: &yazi_core::tab::Tab,
|
||||
) -> mlua::Result<AnyUserData> {
|
||||
let window = match window {
|
||||
Some(w) => w,
|
||||
None => {
|
||||
let limit = LAYOUT.get().preview.height as usize;
|
||||
inner.offset..inner.entries.len().min(inner.offset + limit)
|
||||
}
|
||||
};
|
||||
|
||||
Lives::scoped_userdata(Self { window, inner: inner.into(), tab: tab.into() })
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Folder {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_cached_field("cwd", |_, me| Ok(me.url.clone()));
|
||||
fields.add_static_field("files", |_, me| Entries::make(0..me.entries.len(), me, &me.tab));
|
||||
fields.add_cached_field("stage", |_, me| Ok(me.stage.clone()));
|
||||
fields.add_static_field("window", |_, me| Entries::make(me.window.clone(), me, &me.tab));
|
||||
|
||||
fields.add_field_method_get("offset", |_, me| Ok(me.offset));
|
||||
fields.add_field_method_get("cursor", |_, me| Ok(me.cursor));
|
||||
fields.add_static_field("hovered", |_, me| {
|
||||
me.hovered().map(|_| File::make(me.cursor, me, &me.tab)).transpose()
|
||||
});
|
||||
}
|
||||
}
|
||||
29
yazi-actor/src/lives/input.rs
Normal file
29
yazi-actor/src/lives/input.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use mlua::{AnyUserData, UserData, UserDataFields};
|
||||
use yazi_shim::mlua::UserDataFieldsExt;
|
||||
|
||||
use super::{Lives, PtrCell};
|
||||
use crate::lives::InputAlt;
|
||||
|
||||
pub(super) struct Input {
|
||||
inner: PtrCell<yazi_core::input::Input>,
|
||||
}
|
||||
|
||||
impl Deref for Input {
|
||||
type Target = yazi_core::input::Input;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl Input {
|
||||
pub(super) fn make(inner: &yazi_core::input::Input) -> mlua::Result<AnyUserData> {
|
||||
Lives::scoped_userdata(Self { inner: inner.into() })
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Input {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_cached_field("alt", |_, me| me.alt.as_ref().map(InputAlt::make).transpose());
|
||||
}
|
||||
}
|
||||
26
yazi-actor/src/lives/input_alt.rs
Normal file
26
yazi-actor/src/lives/input_alt.rs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use mlua::{AnyUserData, UserData, UserDataFields};
|
||||
use yazi_shim::mlua::UserDataFieldsExt;
|
||||
|
||||
use super::{Lives, PtrCell};
|
||||
|
||||
pub(super) struct InputAlt(PtrCell<yazi_core::input::InputAlt>);
|
||||
|
||||
impl Deref for InputAlt {
|
||||
type Target = yazi_core::input::InputAlt;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.0 }
|
||||
}
|
||||
|
||||
impl InputAlt {
|
||||
pub(super) fn make(inner: &yazi_core::input::InputAlt) -> mlua::Result<AnyUserData> {
|
||||
Lives::scoped_userdata(Self(inner.into()))
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for InputAlt {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_cached_field("value", |lua, me| lua.create_string(me.lock().value()));
|
||||
}
|
||||
}
|
||||
51
yazi-actor/src/lives/lives.rs
Normal file
51
yazi-actor/src/lives/lives.rs
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
use std::mem::MaybeUninit;
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use mlua::{AnyUserData, UserData};
|
||||
use scopeguard::defer;
|
||||
use tracing::error;
|
||||
use yazi_plugin::LUA;
|
||||
|
||||
use super::{Core, PtrCell};
|
||||
use crate::lives::MutCell;
|
||||
|
||||
pub(super) static TO_DESTROY: MutCell<Vec<AnyUserData>> = MutCell::new(Vec::new());
|
||||
pub(super) static FILE_CACHE: MutCell<
|
||||
MaybeUninit<HashMap<PtrCell<yazi_fs::file::File>, AnyUserData>>,
|
||||
> = MutCell::new(MaybeUninit::uninit());
|
||||
|
||||
pub struct Lives;
|
||||
|
||||
impl Lives {
|
||||
pub fn scope<T, F>(core: &mut yazi_core::Core, f: F) -> mlua::Result<T>
|
||||
where
|
||||
F: FnOnce(&mut yazi_core::Core) -> mlua::Result<T>,
|
||||
{
|
||||
defer! {
|
||||
unsafe {
|
||||
(*FILE_CACHE.get()).assume_init_mut().clear();
|
||||
for ud in (*TO_DESTROY.get()).drain(..) {
|
||||
ud.destroy().expect("failed to destruct scoped userdata");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LUA.set_named_registry_value("cx", Core::make(core)?)?;
|
||||
LUA.globals().raw_set("cx", Core::make(core)?)?;
|
||||
let result = f(core);
|
||||
|
||||
if let Err(ref e) = result {
|
||||
error!("{e}");
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub(crate) fn scoped_userdata<T>(data: T) -> mlua::Result<AnyUserData>
|
||||
where
|
||||
T: UserData + 'static,
|
||||
{
|
||||
let ud = LUA.create_userdata(data)?;
|
||||
unsafe { &mut *TO_DESTROY.get() }.push(ud.clone());
|
||||
Ok(ud)
|
||||
}
|
||||
}
|
||||
5
yazi-actor/src/lives/mod.rs
Normal file
5
yazi-actor/src/lives/mod.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
yazi_macro::mod_flat!(behavior core entries file filter finder folder input input_alt lives mode mut_cell preference preview ptr selected tab tabs task tasks which yanked);
|
||||
|
||||
pub(super) fn init() {
|
||||
unsafe { FILE_CACHE.get().write(std::mem::MaybeUninit::new(<_>::default())) };
|
||||
}
|
||||
38
yazi-actor/src/lives/mode.rs
Normal file
38
yazi-actor/src/lives/mode.rs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use mlua::{AnyUserData, MetaMethod, UserData, UserDataFields, UserDataMethods};
|
||||
use yazi_binding::deprecate;
|
||||
|
||||
use super::{Lives, PtrCell};
|
||||
|
||||
pub(super) struct Mode {
|
||||
inner: PtrCell<yazi_core::tab::Mode>,
|
||||
}
|
||||
|
||||
impl Deref for Mode {
|
||||
type Target = yazi_core::tab::Mode;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl Mode {
|
||||
pub(super) fn make(inner: &yazi_core::tab::Mode) -> mlua::Result<AnyUserData> {
|
||||
Lives::scoped_userdata(Self { inner: inner.into() })
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Mode {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("is_normal", |_, me| Ok(me.is_normal()));
|
||||
fields.add_field_method_get("is_select", |_, me| Ok(me.is_select()));
|
||||
fields.add_field_method_get("is_unset", |_, me| Ok(me.is_unset()));
|
||||
fields.add_field_method_get("is_visual", |lua, me| {
|
||||
deprecate!(lua, "{}: `mode.is_visual` is deprecated, use `not mode.is_normal` instead. \nSee #4101 for more details: https://github.com/sxyazi/yazi/pull/4101.");
|
||||
Ok(!me.is_normal())
|
||||
});
|
||||
}
|
||||
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_meta_method(MetaMethod::ToString, |_, me, ()| Ok(me.to_string()));
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue