mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-21 23:01:05 +00:00
feat: tasks without progress (#3131)
This commit is contained in:
parent
eb537733a2
commit
d7df581b67
127 changed files with 1876 additions and 1157 deletions
192
Cargo.lock
generated
192
Cargo.lock
generated
|
|
@ -343,10 +343,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.34"
|
||||
version = "1.2.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc"
|
||||
checksum = "590f9024a68a8c40351881787f1934dc11afd69090f5edb6831464694d836ea3"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"jobserver",
|
||||
"libc",
|
||||
"shlex",
|
||||
|
|
@ -652,9 +653,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.4.0"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
|
||||
checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc"
|
||||
dependencies = [
|
||||
"powerfmt",
|
||||
]
|
||||
|
|
@ -873,6 +874,12 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e178e4fba8a2726903f6ba98a6d221e76f9c12c650d5dc0e6afdc50677b49650"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.2"
|
||||
|
|
@ -1025,7 +1032,7 @@ dependencies = [
|
|||
"cfg-if",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"wasi 0.14.2+wasi-0.2.4",
|
||||
"wasi 0.14.3+wasi-0.2.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1053,8 +1060,8 @@ dependencies = [
|
|||
"aho-corasick",
|
||||
"bstr",
|
||||
"log",
|
||||
"regex-automata 0.4.10",
|
||||
"regex-syntax 0.8.6",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1076,6 +1083,17 @@ dependencies = [
|
|||
"allocator-api2",
|
||||
"equivalent",
|
||||
"foldhash 0.1.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"equivalent",
|
||||
"foldhash 0.2.0",
|
||||
"serde",
|
||||
]
|
||||
|
||||
|
|
@ -1117,9 +1135,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
|||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.25.6"
|
||||
version = "0.25.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a"
|
||||
checksum = "1c6a3ce16143778e24df6f95365f12ed105425b22abefd289dd88a64bab59605"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"byteorder-lite",
|
||||
|
|
@ -1127,6 +1145,7 @@ dependencies = [
|
|||
"exr",
|
||||
"gif",
|
||||
"image-webp",
|
||||
"moxcms",
|
||||
"num-traits",
|
||||
"png",
|
||||
"qoi",
|
||||
|
|
@ -1159,7 +1178,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
"hashbrown 0.15.5",
|
||||
"serde",
|
||||
]
|
||||
|
||||
|
|
@ -1390,7 +1409,7 @@ version = "0.12.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
"hashbrown 0.15.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1399,7 +1418,7 @@ version = "0.16.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86ea4e65087ff52f3862caff188d489f1fab49a0cb09e01b2e3f1a617b10aaed"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
"hashbrown 0.15.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1432,11 +1451,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "matchers"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
|
||||
checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
|
||||
dependencies = [
|
||||
"regex-automata 0.1.10",
|
||||
"regex-automata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1484,9 +1503,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "mlua"
|
||||
version = "0.11.2"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab2fea92b2adabd51808311b101551d6e3f8602b65e9fae51f7ad5b3d500f4cd"
|
||||
checksum = "5b3dd94c3c4dea0049b22296397040840a8f6b5b5229f438434ba82df402b42d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bstr",
|
||||
|
|
@ -1531,6 +1550,16 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "moxcms"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddd32fa8935aeadb8a8a6b6b351e40225570a37c43de67690383d87ef170cd08"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"pxfm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "new_debug_unreachable"
|
||||
version = "1.0.6"
|
||||
|
|
@ -1579,12 +1608,11 @@ checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d"
|
|||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.46.0"
|
||||
version = "0.50.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
|
||||
checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399"
|
||||
dependencies = [
|
||||
"overload",
|
||||
"winapi",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1764,12 +1792,6 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "overload"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||
|
||||
[[package]]
|
||||
name = "palette"
|
||||
version = "0.7.6"
|
||||
|
|
@ -1867,11 +1889,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "png"
|
||||
version = "0.17.16"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526"
|
||||
checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.9.3",
|
||||
"crc32fast",
|
||||
"fdeflate",
|
||||
"flate2",
|
||||
|
|
@ -1943,6 +1965,15 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pxfm"
|
||||
version = "0.1.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e790881194f6f6e86945f0a42a6981977323669aeb6c40e9c7ec253133b96f8"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "qoi"
|
||||
version = "0.4.1"
|
||||
|
|
@ -2170,17 +2201,8 @@ checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912"
|
|||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata 0.4.10",
|
||||
"regex-syntax 0.8.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
||||
dependencies = [
|
||||
"regex-syntax 0.6.29",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2191,15 +2213,9 @@ checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6"
|
|||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax 0.8.6",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.6"
|
||||
|
|
@ -2273,9 +2289,9 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
|||
|
||||
[[package]]
|
||||
name = "safe_arch"
|
||||
version = "0.9.2"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fb5032219cc30e5bb98749b19a18ceb2cf15e24ba8d517a7e64dff4f1f1eca5"
|
||||
checksum = "96b02de82ddbe1b636e6170c21be622223aea188ef2e139be0a5b219ec215323"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
|
@ -2525,7 +2541,7 @@ dependencies = [
|
|||
"once_cell",
|
||||
"onig",
|
||||
"plist",
|
||||
"regex-syntax 0.8.6",
|
||||
"regex-syntax",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
|
|
@ -2640,12 +2656,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.41"
|
||||
version = "0.3.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"
|
||||
checksum = "8ca967379f9d8eb8058d86ed467d81d03e81acd45757e4ca341c24affbe8e8e3"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"itoa",
|
||||
"libc",
|
||||
"num-conv",
|
||||
"num_threads",
|
||||
|
|
@ -2657,15 +2672,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.4"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
|
||||
checksum = "a9108bb380861b07264b950ded55a44a14a4adc68b9f5efd85aafc3aa4d40a68"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.22"
|
||||
version = "0.2.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49"
|
||||
checksum = "7182799245a7264ce590b349d90338f1c1affad93d2639aed5f8f69c090b334c"
|
||||
dependencies = [
|
||||
"num-conv",
|
||||
"time-core",
|
||||
|
|
@ -2856,14 +2871,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.19"
|
||||
version = "0.3.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
|
||||
checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5"
|
||||
dependencies = [
|
||||
"matchers",
|
||||
"nu-ansi-term",
|
||||
"once_cell",
|
||||
"regex",
|
||||
"regex-automata",
|
||||
"sharded-slab",
|
||||
"smallvec",
|
||||
"thread_local",
|
||||
|
|
@ -3048,11 +3063,11 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
|||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.14.2+wasi-0.2.4"
|
||||
version = "0.14.3+wasi-0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
|
||||
checksum = "6a51ae83037bdd272a9e28ce236db8c07016dd0d50c27038b3f407533c030c95"
|
||||
dependencies = [
|
||||
"wit-bindgen-rt",
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3133,9 +3148,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wide"
|
||||
version = "0.7.34"
|
||||
version = "0.7.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a0ab08c041f0cbb00a12fd091b2877dcec2311f90f87a88391d4b0961ffb4fe"
|
||||
checksum = "0ce5da8ecb62bcd8ec8b7ea19f69a51275e91299be594ea5cc6ef7819e16cd03"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"safe_arch",
|
||||
|
|
@ -3284,6 +3299,15 @@ dependencies = [
|
|||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
|
|
@ -3447,13 +3471,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rt"
|
||||
version = "0.39.0"
|
||||
name = "wit-bindgen"
|
||||
version = "0.45.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
|
||||
dependencies = [
|
||||
"bitflags 2.9.3",
|
||||
]
|
||||
checksum = "052283831dbae3d879dc7f51f3d92703a316ca49f91540417d38591826127814"
|
||||
|
||||
[[package]]
|
||||
name = "wyz"
|
||||
|
|
@ -3471,7 +3492,7 @@ dependencies = [
|
|||
"anyhow",
|
||||
"crossterm 0.29.0",
|
||||
"futures",
|
||||
"hashbrown",
|
||||
"hashbrown 0.16.0",
|
||||
"libc",
|
||||
"mlua",
|
||||
"paste",
|
||||
|
|
@ -3522,7 +3543,7 @@ name = "yazi-binding"
|
|||
version = "25.6.11"
|
||||
dependencies = [
|
||||
"ansi-to-tui",
|
||||
"hashbrown",
|
||||
"hashbrown 0.16.0",
|
||||
"mlua",
|
||||
"paste",
|
||||
"ratatui",
|
||||
|
|
@ -3546,7 +3567,7 @@ dependencies = [
|
|||
"clap_complete_fig",
|
||||
"clap_complete_nushell",
|
||||
"futures",
|
||||
"hashbrown",
|
||||
"hashbrown 0.16.0",
|
||||
"regex",
|
||||
"serde",
|
||||
"vergen-gitcl",
|
||||
|
|
@ -3604,7 +3625,7 @@ dependencies = [
|
|||
"crossterm 0.29.0",
|
||||
"dirs",
|
||||
"globset",
|
||||
"hashbrown",
|
||||
"hashbrown 0.16.0",
|
||||
"indexmap",
|
||||
"ratatui",
|
||||
"regex",
|
||||
|
|
@ -3624,7 +3645,7 @@ version = "25.6.11"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"crossterm 0.29.0",
|
||||
"hashbrown",
|
||||
"hashbrown 0.16.0",
|
||||
"indexmap",
|
||||
"parking_lot",
|
||||
"ratatui",
|
||||
|
|
@ -3652,7 +3673,7 @@ name = "yazi-dds"
|
|||
version = "25.6.11"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"hashbrown",
|
||||
"hashbrown 0.16.0",
|
||||
"mlua",
|
||||
"ordered-float 5.0.0",
|
||||
"parking_lot",
|
||||
|
|
@ -3735,7 +3756,7 @@ dependencies = [
|
|||
"dirs",
|
||||
"foldhash 0.2.0",
|
||||
"futures",
|
||||
"hashbrown",
|
||||
"hashbrown 0.16.0",
|
||||
"libc",
|
||||
"objc",
|
||||
"parking_lot",
|
||||
|
|
@ -3767,8 +3788,9 @@ dependencies = [
|
|||
"anyhow",
|
||||
"bitflags 2.9.3",
|
||||
"crossterm 0.29.0",
|
||||
"hashbrown",
|
||||
"hashbrown 0.16.0",
|
||||
"mlua",
|
||||
"ordered-float 5.0.0",
|
||||
"serde",
|
||||
"tokio",
|
||||
"yazi-binding",
|
||||
|
|
@ -3786,7 +3808,7 @@ dependencies = [
|
|||
"anyhow",
|
||||
"crossterm 0.29.0",
|
||||
"futures",
|
||||
"hashbrown",
|
||||
"hashbrown 0.16.0",
|
||||
"libc",
|
||||
"mlua",
|
||||
"parking_lot",
|
||||
|
|
@ -3841,9 +3863,11 @@ dependencies = [
|
|||
"anyhow",
|
||||
"async-priority-channel",
|
||||
"futures",
|
||||
"hashbrown",
|
||||
"hashbrown 0.16.0",
|
||||
"libc",
|
||||
"lru 0.16.0",
|
||||
"mlua",
|
||||
"ordered-float 5.0.0",
|
||||
"parking_lot",
|
||||
"scopeguard",
|
||||
"tokio",
|
||||
|
|
@ -3867,7 +3891,7 @@ dependencies = [
|
|||
"crossterm 0.29.0",
|
||||
"foldhash 0.2.0",
|
||||
"futures",
|
||||
"hashbrown",
|
||||
"hashbrown 0.16.0",
|
||||
"libc",
|
||||
"memchr",
|
||||
"ordered-float 5.0.0",
|
||||
|
|
@ -3898,7 +3922,7 @@ name = "yazi-watcher"
|
|||
version = "25.6.11"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"hashbrown",
|
||||
"hashbrown 0.16.0",
|
||||
"notify",
|
||||
"parking_lot",
|
||||
"tokio",
|
||||
|
|
|
|||
|
|
@ -31,11 +31,11 @@ dirs = "6.0.0"
|
|||
foldhash = "0.2.0"
|
||||
futures = "0.3.31"
|
||||
globset = "0.4.16"
|
||||
hashbrown = { version = "0.15.5", features = [ "serde" ] }
|
||||
hashbrown = { version = "0.16.0", features = [ "serde" ] }
|
||||
indexmap = { version = "2.11.0", features = [ "serde" ] }
|
||||
libc = "0.2.175"
|
||||
lru = "0.16.0"
|
||||
mlua = { version = "0.11.2", features = [ "anyhow", "async", "error-send", "lua54", "macros", "serde" ] }
|
||||
mlua = { version = "0.11.3", features = [ "anyhow", "async", "error-send", "lua54", "macros", "serde" ] }
|
||||
objc = "0.2.7"
|
||||
ordered-float = { version = "5.0.0", features = [ "serde" ] }
|
||||
parking_lot = "0.12.4"
|
||||
|
|
|
|||
|
|
@ -15,12 +15,10 @@ pub struct Ctx<'a> {
|
|||
impl Deref for Ctx<'_> {
|
||||
type Target = Core;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target { self.core }
|
||||
}
|
||||
|
||||
impl DerefMut for Ctx<'_> {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut Self::Target { self.core }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ impl Deref for Core {
|
|||
}
|
||||
|
||||
impl Core {
|
||||
#[inline]
|
||||
pub(super) fn make(inner: &yazi_core::Core) -> mlua::Result<AnyUserData> {
|
||||
Lives::scoped_userdata(Self {
|
||||
inner: inner.into(),
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ impl AsRef<yazi_fs::File> for File {
|
|||
}
|
||||
|
||||
impl File {
|
||||
#[inline]
|
||||
pub(super) fn make(
|
||||
idx: usize,
|
||||
folder: &yazi_core::tab::Folder,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ impl Deref for Files {
|
|||
}
|
||||
|
||||
impl Files {
|
||||
#[inline]
|
||||
pub(super) fn make(
|
||||
window: Range<usize>,
|
||||
folder: &yazi_core::tab::Folder,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ impl Deref for Filter {
|
|||
}
|
||||
|
||||
impl Filter {
|
||||
#[inline]
|
||||
pub(super) fn make(inner: &yazi_fs::Filter) -> mlua::Result<AnyUserData> {
|
||||
Lives::scoped_userdata(Self { inner: inner.into() })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ impl Deref for Finder {
|
|||
}
|
||||
|
||||
impl Finder {
|
||||
#[inline]
|
||||
pub(super) fn make(inner: &yazi_core::tab::Finder) -> mlua::Result<AnyUserData> {
|
||||
Lives::scoped_userdata(Self { inner: inner.into() })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ impl Deref for Folder {
|
|||
}
|
||||
|
||||
impl Folder {
|
||||
#[inline]
|
||||
pub(super) fn make(
|
||||
window: Option<Range<usize>>,
|
||||
inner: &yazi_core::tab::Folder,
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ impl Lives {
|
|||
result
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn scoped_userdata<T>(data: T) -> mlua::Result<AnyUserData>
|
||||
where
|
||||
T: UserData + 'static,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ impl Deref for Mode {
|
|||
}
|
||||
|
||||
impl Mode {
|
||||
#[inline]
|
||||
pub(super) fn make(inner: &yazi_core::tab::Mode) -> mlua::Result<AnyUserData> {
|
||||
Lives::scoped_userdata(Self { inner: inner.into() })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ impl Deref for Preference {
|
|||
}
|
||||
|
||||
impl Preference {
|
||||
#[inline]
|
||||
pub(super) fn make(inner: &yazi_core::tab::Preference) -> mlua::Result<AnyUserData> {
|
||||
Lives::scoped_userdata(Self { inner: inner.into(), v_sort_by: None, v_linemode: None })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ impl Deref for Preview {
|
|||
}
|
||||
|
||||
impl Preview {
|
||||
#[inline]
|
||||
pub(super) fn make(tab: &yazi_core::tab::Tab) -> mlua::Result<AnyUserData> {
|
||||
Lives::scoped_userdata(Self { tab: tab.into(), v_folder: None })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ use crate::lives::PtrCell;
|
|||
pub(super) struct Selected;
|
||||
|
||||
impl Selected {
|
||||
#[inline]
|
||||
pub(super) fn make(inner: &yazi_core::tab::Selected) -> mlua::Result<AnyUserData> {
|
||||
let inner = PtrCell::from(inner);
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ impl Deref for Tab {
|
|||
}
|
||||
|
||||
impl Tab {
|
||||
#[inline]
|
||||
pub(super) fn make(inner: &yazi_core::tab::Tab) -> mlua::Result<AnyUserData> {
|
||||
Lives::scoped_userdata(Self {
|
||||
inner: inner.into(),
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ impl Deref for Tabs {
|
|||
}
|
||||
|
||||
impl Tabs {
|
||||
#[inline]
|
||||
pub(super) fn make(inner: &yazi_core::mgr::Tabs) -> mlua::Result<AnyUserData> {
|
||||
Lives::scoped_userdata(Self { inner: inner.into() })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,15 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use mlua::{AnyUserData, LuaSerdeExt, UserData, UserDataFields, Value};
|
||||
use yazi_binding::cached_field;
|
||||
use yazi_binding::{cached_field, deprecate};
|
||||
use yazi_plugin::runtime::SER_OPT;
|
||||
|
||||
use super::{Lives, PtrCell};
|
||||
|
||||
pub(super) struct Tasks {
|
||||
inner: PtrCell<yazi_core::tasks::Tasks>,
|
||||
|
||||
v_summary: Option<Value>,
|
||||
v_progress: Option<Value>,
|
||||
}
|
||||
|
||||
|
|
@ -18,14 +20,27 @@ impl Deref for Tasks {
|
|||
}
|
||||
|
||||
impl Tasks {
|
||||
#[inline]
|
||||
pub(super) fn make(inner: &yazi_core::tasks::Tasks) -> mlua::Result<AnyUserData> {
|
||||
Lives::scoped_userdata(Self { inner: inner.into(), v_progress: None })
|
||||
Lives::scoped_userdata(Self { inner: inner.into(), v_summary: None, v_progress: None })
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Tasks {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
cached_field!(fields, progress, |lua, me| lua.to_value(&me.progress));
|
||||
cached_field!(fields, summary, |lua, me| lua.to_value_with(&me.summary, SER_OPT));
|
||||
|
||||
cached_field!(fields, progress, |lua, me| {
|
||||
deprecate!(
|
||||
lua,
|
||||
"`cx.tasks.progress` is deprecated, use `cx.tasks.summary` instead, in your {}"
|
||||
);
|
||||
lua.create_table_from([
|
||||
("total", me.summary.total),
|
||||
("succ", me.summary.success),
|
||||
("fail", me.summary.failed),
|
||||
("found", 0),
|
||||
("processed", 0),
|
||||
])
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ impl Deref for Yanked {
|
|||
}
|
||||
|
||||
impl Yanked {
|
||||
#[inline]
|
||||
pub(super) fn make(inner: &yazi_core::mgr::Yanked) -> mlua::Result<AnyUserData> {
|
||||
let inner = PtrCell::from(inner);
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ impl Actor for Arrow {
|
|||
let tasks = &mut cx.tasks;
|
||||
|
||||
let old = tasks.cursor;
|
||||
tasks.cursor = opt.step.add(tasks.cursor, tasks.summaries.len(), Tasks::limit());
|
||||
tasks.cursor = opt.step.add(tasks.cursor, tasks.snaps.len(), Tasks::limit());
|
||||
|
||||
succ!(render!(tasks.cursor != old));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ impl Actor for Cancel {
|
|||
succ!();
|
||||
}
|
||||
|
||||
tasks.summaries = tasks.paginate();
|
||||
tasks.snaps = tasks.paginate();
|
||||
act!(tasks:arrow, cx)?;
|
||||
succ!(render!());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ impl Actor for Close {
|
|||
}
|
||||
|
||||
tasks.visible = false;
|
||||
tasks.summaries = Vec::new();
|
||||
tasks.snaps = Vec::new();
|
||||
|
||||
act!(tasks:arrow, cx)?;
|
||||
succ!(render!());
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ impl Actor for Show {
|
|||
}
|
||||
|
||||
tasks.visible = true;
|
||||
tasks.summaries = tasks.paginate();
|
||||
tasks.snaps = tasks.paginate();
|
||||
|
||||
act!(tasks:arrow, cx)?;
|
||||
succ!(render!());
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ ansi-to-tui = { workspace = true }
|
|||
anyhow = { workspace = true }
|
||||
base64 = { workspace = true }
|
||||
crossterm = { workspace = true }
|
||||
image = { version = "0.25.6", default-features = false, features = [ "avif", "bmp", "dds", "exr", "ff", "gif", "hdr", "ico", "jpeg", "png", "pnm", "qoi", "tga", "webp" ] }
|
||||
image = { version = "0.25.7", default-features = false, features = [ "avif", "bmp", "dds", "exr", "ff", "gif", "hdr", "ico", "jpeg", "png", "pnm", "qoi", "tga", "webp" ] }
|
||||
palette = { version = "0.7.6", default-features = false }
|
||||
quantette = { version = "0.3.0", default-features = false }
|
||||
ratatui = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ impl KgpOld {
|
|||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn image_erase(_: Rect) -> Result<()> {
|
||||
let mut w = TTY.lockout();
|
||||
write!(w, "{START}_Gq=2,a=d,d=A{ESCAPE}\\{CLOSE}")?;
|
||||
|
|
|
|||
|
|
@ -85,7 +85,6 @@ impl Image {
|
|||
.unwrap_or(rect)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn filter() -> FilterType {
|
||||
match YAZI.preview.image_filter.as_str() {
|
||||
"nearest" => FilterType::Nearest,
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ impl Deref for Cha {
|
|||
|
||||
impl Cha {
|
||||
pub fn install(lua: &Lua) -> mlua::Result<()> {
|
||||
#[inline]
|
||||
fn parse_time(f: Option<f64>) -> mlua::Result<Option<SystemTime>> {
|
||||
Ok(match f {
|
||||
Some(n) if n >= 0.0 => Some(SystemTime::UNIX_EPOCH + Duration::from_secs_f64(n)),
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ impl Default for Area {
|
|||
}
|
||||
|
||||
impl Area {
|
||||
#[inline]
|
||||
pub fn size(self) -> ratatui::layout::Size {
|
||||
match self {
|
||||
Self::Pos(pos) => {
|
||||
|
|
@ -27,7 +26,6 @@ impl Area {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn inner(self, padding: ratatui::widgets::Padding) -> Self {
|
||||
match self {
|
||||
Self::Pos(mut pos) => {
|
||||
|
|
@ -38,7 +36,6 @@ impl Area {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn transform(
|
||||
self,
|
||||
f: impl FnOnce(yazi_config::popup::Position) -> ratatui::layout::Rect,
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ impl UserData for Clear {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
const fn is_overlapping(a: ratatui::layout::Rect, b: ratatui::layout::Rect) -> bool {
|
||||
a.x < b.x + b.width && a.x + a.width > b.x && a.y < b.y + b.height && a.y + a.height > b.y
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,7 +78,6 @@ impl Table {
|
|||
table.render(rect, buf, &mut self.state);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize { self.rows.len() }
|
||||
|
||||
pub fn select(&mut self, idx: Option<usize>) {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ impl Error {
|
|||
lua.globals().raw_set("Error", lua.create_table_from([("custom", new)])?)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn custom(msg: impl Into<SStr>) -> Self { Self::Custom(msg.into()) }
|
||||
|
||||
pub fn into_string(self) -> SStr {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ pub struct Id(pub yazi_shared::Id);
|
|||
impl Deref for Id {
|
||||
type Target = yazi_shared::Id;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target { &self.0 }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ where
|
|||
I: Iterator<Item = T> + 'static,
|
||||
T: IntoLua + 'static,
|
||||
{
|
||||
#[inline]
|
||||
pub fn new(iter: I, len: Option<usize>) -> Self { Self { iter, len, count: 0, cache: vec![] } }
|
||||
}
|
||||
|
||||
|
|
@ -22,7 +21,6 @@ where
|
|||
I: Iterator<Item = T> + 'static,
|
||||
T: FromLua + 'static,
|
||||
{
|
||||
#[inline]
|
||||
pub fn into_iter(self, lua: &Lua) -> impl Iterator<Item = mlua::Result<T>> {
|
||||
self
|
||||
.cache
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ impl Dependency {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn identical(&self, other: &Self) -> bool {
|
||||
self.parent == other.parent && self.child == other.child
|
||||
}
|
||||
|
|
|
|||
|
|
@ -138,10 +138,8 @@ impl Package {
|
|||
Local::write(Self::toml(), s).await.context("Failed to write package.toml")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn toml() -> PathBuf { Xdg::config_dir().join("package.toml") }
|
||||
|
||||
#[inline]
|
||||
fn identical(&self, other: &Dependency) -> Option<&Dependency> {
|
||||
self.plugins.iter().chain(&self.flavors).find(|d| d.identical(other))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ pub struct Keymap {
|
|||
}
|
||||
|
||||
impl Keymap {
|
||||
#[inline]
|
||||
pub fn get(&self, layer: Layer) -> &[Chord] {
|
||||
match layer {
|
||||
Layer::App => &[],
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ pub struct OpenerRule {
|
|||
}
|
||||
|
||||
impl OpenerRule {
|
||||
#[inline]
|
||||
pub fn desc(&self) -> String {
|
||||
if !self.desc.is_empty() {
|
||||
self.desc.clone()
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ pub struct Pattern {
|
|||
}
|
||||
|
||||
impl Pattern {
|
||||
#[inline]
|
||||
pub fn match_url(&self, url: impl AsRef<UrlBuf>, is_dir: bool) -> bool {
|
||||
let url = url.as_ref();
|
||||
|
||||
|
|
@ -42,7 +41,6 @@ impl Pattern {
|
|||
self.inner.is_match(path)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn match_mime(&self, mime: impl AsRef<str>) -> bool {
|
||||
self.is_star || (!mime.as_ref().is_empty() && self.inner.is_match(mime.as_ref()))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -176,7 +176,6 @@ impl ConfirmCfg {
|
|||
}
|
||||
|
||||
impl PickCfg {
|
||||
#[inline]
|
||||
fn max_height(len: usize) -> u16 {
|
||||
YAZI.pick.open_offset.height.min(YAZI.pick.border().saturating_add(len as u16))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ pub struct Position {
|
|||
}
|
||||
|
||||
impl Position {
|
||||
#[inline]
|
||||
pub const fn new(origin: Origin, offset: Offset) -> Self { Self { origin, offset } }
|
||||
|
||||
pub fn rect(&self, WindowSize { columns, rows, .. }: WindowSize) -> Rect {
|
||||
|
|
|
|||
|
|
@ -3,17 +3,14 @@ use crate::{Yazi, keymap::Keymap, theme::Theme};
|
|||
pub(crate) struct Preset;
|
||||
|
||||
impl Preset {
|
||||
#[inline]
|
||||
pub(super) fn yazi() -> Result<Yazi, toml::de::Error> {
|
||||
toml::from_str(&yazi_macro::config_preset!("yazi"))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn keymap() -> Result<Keymap, toml::de::Error> {
|
||||
toml::from_str(&yazi_macro::config_preset!("keymap"))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn theme(light: bool) -> Result<Theme, toml::de::Error> {
|
||||
toml::from_str(&if light {
|
||||
yazi_macro::theme_preset!("light")
|
||||
|
|
|
|||
|
|
@ -29,15 +29,12 @@ pub struct Preview {
|
|||
}
|
||||
|
||||
impl Preview {
|
||||
#[inline]
|
||||
pub fn tmpfile(&self, prefix: &str) -> PathBuf {
|
||||
self.cache_dir.join(format!("{prefix}-{}", timestamp_us()))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn indent(&self) -> SStr { Self::indent_with(self.tab_size as usize) }
|
||||
|
||||
#[inline]
|
||||
pub fn indent_with(n: usize) -> SStr {
|
||||
if let Some(s) = TABS.get(n) { Cow::Borrowed(s) } else { Cow::Owned(" ".repeat(n)) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,7 +76,6 @@ impl From<Style> for ratatui::style::Modifier {
|
|||
}
|
||||
|
||||
impl Style {
|
||||
#[inline]
|
||||
pub fn derive(self, other: ratatui::style::Style) -> ratatui::style::Style {
|
||||
ratatui::style::Style::from(self).patch(other)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,12 +69,10 @@ impl Icon {
|
|||
self.conds.iter().find(|(c, _)| c.eval(f) == Some(true)).map(|(_, i)| i)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn match_by_glob(&self, file: &File) -> Option<&I> {
|
||||
self.globs.iter().find(|(p, _)| p.match_url(&file.url, file.is_dir())).map(|(_, i)| i)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn match_by_name(&self, file: &File) -> Option<&I> {
|
||||
let name = file.name()?.to_str()?;
|
||||
if file.is_dir() {
|
||||
|
|
@ -88,7 +86,6 @@ impl Icon {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn match_by_ext(&self, file: &File) -> Option<&I> {
|
||||
let ext = file.url.ext()?.to_str()?;
|
||||
self.exts.get(ext).or_else(|| self.exts.get(&ext.to_ascii_lowercase()))
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ pub enum Is {
|
|||
}
|
||||
|
||||
impl Is {
|
||||
#[inline]
|
||||
pub fn check(&self, cha: &Cha) -> bool {
|
||||
match self {
|
||||
Self::None => true,
|
||||
|
|
|
|||
|
|
@ -16,30 +16,23 @@ pub struct Cmp {
|
|||
|
||||
impl Cmp {
|
||||
// --- Cands
|
||||
#[inline]
|
||||
pub fn window(&self) -> &[CmpItem] {
|
||||
let end = (self.offset + self.limit()).min(self.cands.len());
|
||||
&self.cands[self.offset..end]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn selected(&self) -> Option<&CmpItem> { self.cands.get(self.cursor) }
|
||||
|
||||
// --- Cursor
|
||||
#[inline]
|
||||
pub fn rel_cursor(&self) -> usize { self.cursor - self.offset }
|
||||
}
|
||||
|
||||
impl Scrollable for Cmp {
|
||||
#[inline]
|
||||
fn total(&self) -> usize { self.cands.len() }
|
||||
|
||||
#[inline]
|
||||
fn limit(&self) -> usize { self.cands.len().min(10) }
|
||||
|
||||
#[inline]
|
||||
fn cursor_mut(&mut self) -> &mut usize { &mut self.cursor }
|
||||
|
||||
#[inline]
|
||||
fn offset_mut(&mut self) -> &mut usize { &mut self.offset }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ impl Core {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn cursor(&self) -> Option<(Position, SetCursorStyle)> {
|
||||
if self.input.visible {
|
||||
let Rect { x, y, .. } = self.mgr.area(self.input.position);
|
||||
|
|
@ -46,7 +45,6 @@ impl Core {
|
|||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn layer(&self) -> Layer {
|
||||
if self.which.visible {
|
||||
Layer::Which
|
||||
|
|
|
|||
|
|
@ -64,7 +64,6 @@ impl Help {
|
|||
|
||||
impl Help {
|
||||
// --- Keyword
|
||||
#[inline]
|
||||
pub fn keyword(&self) -> Option<String> {
|
||||
self
|
||||
.in_filter
|
||||
|
|
@ -75,14 +74,12 @@ impl Help {
|
|||
}
|
||||
|
||||
// --- Bindings
|
||||
#[inline]
|
||||
pub fn window(&self) -> &[&Chord] {
|
||||
let end = (self.offset + self.limit()).min(self.bindings.len());
|
||||
&self.bindings[self.offset..end]
|
||||
}
|
||||
|
||||
// --- Cursor
|
||||
#[inline]
|
||||
pub fn cursor(&self) -> Option<(u16, u16)> {
|
||||
if !self.visible || self.in_filter.is_none() {
|
||||
return None;
|
||||
|
|
@ -93,10 +90,8 @@ impl Help {
|
|||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn rel_cursor(&self) -> usize { self.cursor - self.offset }
|
||||
|
||||
#[inline]
|
||||
pub fn cursor_shape(&self) -> SetCursorStyle {
|
||||
if YAZI.input.cursor_blink {
|
||||
SetCursorStyle::BlinkingBlock
|
||||
|
|
@ -107,15 +102,11 @@ impl Help {
|
|||
}
|
||||
|
||||
impl Scrollable for Help {
|
||||
#[inline]
|
||||
fn total(&self) -> usize { self.bindings.len() }
|
||||
|
||||
#[inline]
|
||||
fn limit(&self) -> usize { Dimension::available().rows.saturating_sub(HELP_MARGIN) as usize }
|
||||
|
||||
#[inline]
|
||||
fn cursor_mut(&mut self) -> &mut usize { &mut self.cursor }
|
||||
|
||||
#[inline]
|
||||
fn offset_mut(&mut self) -> &mut usize { &mut self.offset }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,32 +6,26 @@ use yazi_shared::{MIME_DIR, pool::{InternStr, Symbol}, url::{Url, UrlBufCov, Url
|
|||
pub struct Mimetype(HashMap<UrlBufCov, Symbol<str>>);
|
||||
|
||||
impl Mimetype {
|
||||
#[inline]
|
||||
pub fn by_url<'a>(&self, url: impl Into<Url<'a>>) -> Option<&str> {
|
||||
self.0.get(&UrlCov::new(url)).map(|s| s.as_ref())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn by_url_owned<'a>(&self, url: impl Into<Url<'a>>) -> Option<Symbol<str>> {
|
||||
self.0.get(&UrlCov::new(url)).cloned()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn by_file(&self, file: &File) -> Option<&str> {
|
||||
if file.is_dir() { Some(MIME_DIR) } else { self.by_url(&file.url) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn by_file_owned(&self, file: &File) -> Option<Symbol<str>> {
|
||||
if file.is_dir() { Some(MIME_DIR.intern()) } else { self.by_url_owned(&file.url) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn contains<'a>(&self, url: impl Into<Url<'a>>) -> bool {
|
||||
self.0.contains_key(&UrlCov::new(url))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn extend(&mut self, iter: impl IntoIterator<Item = (UrlBufCov, Symbol<str>)>) {
|
||||
self.0.extend(iter);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@ impl Yanked {
|
|||
self.revision += 1;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn contains<'a>(&self, url: impl Into<Url<'a>>) -> bool {
|
||||
self.urls.contains(&UrlCov::new(url))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ impl From<NotifyOpt> for Message {
|
|||
}
|
||||
|
||||
impl Message {
|
||||
#[inline]
|
||||
pub fn height(&self, width: u16) -> usize {
|
||||
let lines = ratatui::widgets::Paragraph::new(self.content.as_str())
|
||||
.wrap(ratatui::widgets::Wrap { trim: false })
|
||||
|
|
|
|||
|
|
@ -17,27 +17,21 @@ pub struct Pick {
|
|||
}
|
||||
|
||||
impl Pick {
|
||||
#[inline]
|
||||
pub fn title(&self) -> &str { &self.title }
|
||||
|
||||
#[inline]
|
||||
pub fn window(&self) -> impl Iterator<Item = (usize, &str)> {
|
||||
self.items.iter().map(AsRef::as_ref).enumerate().skip(self.offset).take(self.limit())
|
||||
}
|
||||
}
|
||||
|
||||
impl Scrollable for Pick {
|
||||
#[inline]
|
||||
fn total(&self) -> usize { self.items.len() }
|
||||
|
||||
#[inline]
|
||||
fn limit(&self) -> usize {
|
||||
self.position.offset.height.saturating_sub(YAZI.pick.border()) as usize
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn cursor_mut(&mut self) -> &mut usize { &mut self.cursor }
|
||||
|
||||
#[inline]
|
||||
fn offset_mut(&mut self) -> &mut usize { &mut self.offset }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,28 +30,22 @@ impl Spot {
|
|||
self.ct = Some(isolate::spot(&spotter.run, file, mime, self.skip));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn visible(&self) -> bool { self.lock.is_some() }
|
||||
|
||||
#[inline]
|
||||
pub fn abort(&mut self) { self.ct.take().map(|ct| ct.cancel()); }
|
||||
|
||||
#[inline]
|
||||
pub fn reset(&mut self) {
|
||||
self.abort();
|
||||
render!(self.lock.take().is_some());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn same_url(&self, url: &UrlBuf) -> bool { self.lock.as_ref().is_some_and(|l| *url == l.url) }
|
||||
|
||||
#[inline]
|
||||
pub fn same_file(&self, file: &File, mime: &str) -> bool {
|
||||
self.same_url(&file.url)
|
||||
&& self.lock.as_ref().is_some_and(|l| file.cha.hits(l.cha) && mime == l.mime)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn same_lock(&self, file: &File, mime: &str) -> bool {
|
||||
self.same_file(file, mime) && self.lock.as_ref().is_some_and(|l| self.skip == l.skip)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,7 +76,6 @@ impl Finder {
|
|||
}
|
||||
|
||||
impl Finder {
|
||||
#[inline]
|
||||
pub fn matched_idx(&self, folder: &Folder, urn: &Urn) -> Option<u8> {
|
||||
if self.lock == *folder { self.matched.get(urn).copied() } else { None }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,7 +119,6 @@ impl Folder {
|
|||
self.arrow(new - self.cursor as isize)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn repos(&mut self, urn: Option<&Urn>) -> bool {
|
||||
if let Some(u) = urn {
|
||||
self.hover(u)
|
||||
|
|
@ -177,18 +176,13 @@ impl Folder {
|
|||
}
|
||||
|
||||
impl Scrollable for Folder {
|
||||
#[inline]
|
||||
fn total(&self) -> usize { self.files.len() }
|
||||
|
||||
#[inline]
|
||||
fn limit(&self) -> usize { LAYOUT.get().limit() }
|
||||
|
||||
#[inline]
|
||||
fn scrolloff(&self) -> usize { (self.limit() / 2).min(YAZI.mgr.scrolloff.get() as usize) }
|
||||
|
||||
#[inline]
|
||||
fn cursor_mut(&mut self) -> &mut usize { &mut self.cursor }
|
||||
|
||||
#[inline]
|
||||
fn offset_mut(&mut self) -> &mut usize { &mut self.offset }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,17 +11,14 @@ pub struct History(HashMap<UrlBuf, Folder>);
|
|||
impl Deref for History {
|
||||
type Target = HashMap<UrlBuf, Folder>;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target { &self.0 }
|
||||
}
|
||||
|
||||
impl DerefMut for History {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
|
||||
}
|
||||
|
||||
impl History {
|
||||
#[inline]
|
||||
pub fn remove_or<'a>(&mut self, url: impl Into<Url<'a>>) -> Folder {
|
||||
let url = url.into();
|
||||
self.0.remove(&url).unwrap_or_else(|| Folder::from(url))
|
||||
|
|
|
|||
|
|
@ -27,13 +27,10 @@ impl Mode {
|
|||
}
|
||||
|
||||
impl Mode {
|
||||
#[inline]
|
||||
pub fn is_select(&self) -> bool { matches!(self, Mode::Select(..)) }
|
||||
|
||||
#[inline]
|
||||
pub fn is_unset(&self) -> bool { matches!(self, Mode::Unset(..)) }
|
||||
|
||||
#[inline]
|
||||
pub fn is_visual(&self) -> bool { matches!(self, Mode::Select(..) | Mode::Unset(..)) }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -68,35 +68,29 @@ impl Preview {
|
|||
}));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn abort(&mut self) {
|
||||
self.previewer_ct.take().map(|ct| ct.cancel());
|
||||
Highlighter::abort();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn reset(&mut self) {
|
||||
self.abort();
|
||||
ADAPTOR.get().image_hide().ok();
|
||||
render!(self.lock.take().is_some())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn reset_image(&mut self) {
|
||||
self.abort();
|
||||
ADAPTOR.get().image_hide().ok();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn same_url(&self, url: &UrlBuf) -> bool { matches!(&self.lock, Some(l) if l.url == *url) }
|
||||
|
||||
#[inline]
|
||||
pub fn same_file(&self, file: &File, mime: &str) -> bool {
|
||||
self.same_url(&file.url)
|
||||
&& matches!(&self.lock , Some(l) if l.cha.hits(file.cha) && l.mime == mime && *l.area == LAYOUT.get().preview)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn same_lock(&self, file: &File, mime: &str) -> bool {
|
||||
self.same_file(file, mime) && matches!(&self.lock, Some(l) if l.skip == self.skip)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,21 +12,16 @@ pub struct Selected {
|
|||
}
|
||||
|
||||
impl Selected {
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize { self.inner.len() }
|
||||
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool { self.inner.is_empty() }
|
||||
|
||||
#[inline]
|
||||
pub fn values(&self) -> impl Iterator<Item = &UrlBuf> { self.inner.keys().map(Deref::deref) }
|
||||
|
||||
#[inline]
|
||||
pub fn contains<'a>(&self, url: impl Into<Url<'a>>) -> bool {
|
||||
self.inner.contains_key(&UrlCov::new(url))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn add<'a>(&mut self, url: impl Into<Url<'a>>) -> bool { self.add_same([url]) == 1 }
|
||||
|
||||
pub fn add_many<'a, I, T>(&mut self, urls: I) -> usize
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@ use yazi_parser::app::PluginOpt;
|
|||
use super::Tasks;
|
||||
|
||||
impl Tasks {
|
||||
#[inline]
|
||||
pub fn plugin_micro(&self, opt: PluginOpt) { self.scheduler.plugin_micro(opt); }
|
||||
|
||||
#[inline]
|
||||
pub fn plugin_macro(&self, opt: PluginOpt) { self.scheduler.plugin_macro(opt); }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ use std::{sync::Arc, time::Duration};
|
|||
use parking_lot::Mutex;
|
||||
use tokio::{task::JoinHandle, time::sleep};
|
||||
use yazi_adapter::Dimension;
|
||||
use yazi_parser::app::TasksProgress;
|
||||
use yazi_parser::app::TaskSummary;
|
||||
use yazi_proxy::AppProxy;
|
||||
use yazi_scheduler::{Ongoing, Scheduler, TaskSummary};
|
||||
use yazi_scheduler::{Ongoing, Scheduler, TaskSnap};
|
||||
|
||||
use super::{TASKS_BORDER, TASKS_PADDING, TASKS_PERCENT};
|
||||
|
||||
|
|
@ -13,10 +13,10 @@ pub struct Tasks {
|
|||
pub scheduler: Arc<Scheduler>,
|
||||
handle: JoinHandle<()>,
|
||||
|
||||
pub visible: bool,
|
||||
pub cursor: usize,
|
||||
pub progress: TasksProgress,
|
||||
pub summaries: Vec<TaskSummary>,
|
||||
pub visible: bool,
|
||||
pub cursor: usize,
|
||||
pub snaps: Vec<TaskSnap>,
|
||||
pub summary: TaskSummary,
|
||||
}
|
||||
|
||||
impl Tasks {
|
||||
|
|
@ -25,14 +25,14 @@ impl Tasks {
|
|||
let ongoing = scheduler.ongoing.clone();
|
||||
|
||||
let handle = tokio::spawn(async move {
|
||||
let mut last = TasksProgress::default();
|
||||
let mut last = TaskSummary::default();
|
||||
loop {
|
||||
sleep(Duration::from_millis(500)).await;
|
||||
|
||||
let new = ongoing.lock().progress();
|
||||
let new = ongoing.lock().summary();
|
||||
if last != new {
|
||||
last = new;
|
||||
AppProxy::update_progress(new);
|
||||
AppProxy::update_summary(new);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -43,8 +43,8 @@ impl Tasks {
|
|||
|
||||
visible: false,
|
||||
cursor: 0,
|
||||
progress: Default::default(),
|
||||
summaries: Default::default(),
|
||||
snaps: Default::default(),
|
||||
summary: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -53,16 +53,14 @@ impl Tasks {
|
|||
self.handle.abort();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn limit() -> usize {
|
||||
(Dimension::available().rows * TASKS_PERCENT / 100).saturating_sub(TASKS_BORDER + TASKS_PADDING)
|
||||
as usize
|
||||
}
|
||||
|
||||
pub fn paginate(&self) -> Vec<TaskSummary> {
|
||||
pub fn paginate(&self) -> Vec<TaskSnap> {
|
||||
self.ongoing().lock().values().take(Self::limit()).map(Into::into).collect()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn ongoing(&self) -> &Arc<Mutex<Ongoing>> { &self.scheduler.ongoing }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -156,12 +156,10 @@ impl Client {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn push<'a>(payload: impl Into<Payload<'a>>) -> Result<()> {
|
||||
Ok(QUEUE_TX.send(try_format!("{}\n", payload.into())?)?)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn able(&self, ability: &str) -> bool { self.abilities.contains(ability) }
|
||||
|
||||
async fn connect(server: &mut Option<JoinHandle<()>>) -> (ClientReader, ClientWriter) {
|
||||
|
|
@ -201,9 +199,7 @@ impl Client {
|
|||
}
|
||||
|
||||
impl Peer {
|
||||
#[inline]
|
||||
pub(super) fn new(abilities: &HashSet<String>) -> Self { Self { abilities: abilities.clone() } }
|
||||
|
||||
#[inline]
|
||||
pub(super) fn able(&self, ability: &str) -> bool { self.abilities.contains(ability) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,7 +90,6 @@ impl Ember<'static> {
|
|||
}
|
||||
|
||||
impl<'a> Ember<'a> {
|
||||
#[inline]
|
||||
pub fn kind(&self) -> &str {
|
||||
match self {
|
||||
Self::Hi(_) => "hi",
|
||||
|
|
@ -111,12 +110,10 @@ impl<'a> Ember<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn with_receiver(self, receiver: Id) -> Payload<'a> {
|
||||
Payload::new(self).with_receiver(receiver)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn with_sender(self, sender: Id) -> Payload<'a> { Payload::new(self).with_sender(sender) }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -137,7 +137,6 @@ impl Pubsub {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn any_remote_own(kind: &str) -> bool {
|
||||
REMOTE.read().contains_key(kind) // Own remote abilities
|
||||
|| PEERS.read().values().any(|p| p.able(kind)) // Remote peers' abilities
|
||||
|
|
|
|||
|
|
@ -17,21 +17,18 @@ static DELETE_TX: Mutex<Option<mpsc::UnboundedSender<UrlBuf>>> = Mutex::new(None
|
|||
pub struct Pump;
|
||||
|
||||
impl Pump {
|
||||
#[inline]
|
||||
pub fn push_move(from: UrlBuf, to: UrlBuf) {
|
||||
if let Some(tx) = &*MOVE_TX.lock() {
|
||||
tx.send(BodyMoveItem { from, to }).ok();
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn push_trash(target: UrlBuf) {
|
||||
if let Some(tx) = &*TRASH_TX.lock() {
|
||||
tx.send(target).ok();
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn push_delete(target: UrlBuf) {
|
||||
if let Some(tx) = &*DELETE_TX.lock() {
|
||||
tx.send(target).ok();
|
||||
|
|
|
|||
|
|
@ -227,7 +227,6 @@ impl Sendable {
|
|||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn key_to_value(lua: &Lua, key: DataKey) -> mlua::Result<Value> {
|
||||
match key {
|
||||
DataKey::Url(u) => yazi_binding::Url::new(u).into_lua(lua),
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ tokio-stream = { workspace = true }
|
|||
# Logging
|
||||
tracing = { workspace = true }
|
||||
tracing-appender = "0.2.3"
|
||||
tracing-subscriber = { version = "0.3.19", features = [ "env-filter" ] }
|
||||
tracing-subscriber = { version = "0.3.20", features = [ "env-filter" ] }
|
||||
|
||||
[target."cfg(unix)".dependencies]
|
||||
libc = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -12,5 +12,5 @@ yazi_macro::mod_flat!(
|
|||
resume
|
||||
stop
|
||||
update_notify
|
||||
update_progress
|
||||
update_summary
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,23 +1,23 @@
|
|||
use anyhow::Result;
|
||||
use yazi_actor::Ctx;
|
||||
use yazi_macro::{act, render, succ};
|
||||
use yazi_parser::app::UpdateProgressOpt;
|
||||
use yazi_parser::app::UpdateSummaryOpt;
|
||||
use yazi_shared::event::Data;
|
||||
|
||||
use crate::app::App;
|
||||
|
||||
impl App {
|
||||
pub(crate) fn update_progress(&mut self, opt: UpdateProgressOpt) -> Result<Data> {
|
||||
pub(crate) fn update_summary(&mut self, opt: UpdateSummaryOpt) -> Result<Data> {
|
||||
// Update the progress of all tasks.
|
||||
let tasks = &mut self.core.tasks;
|
||||
let progressed = tasks.progress != opt.progress;
|
||||
tasks.progress = opt.progress;
|
||||
let progressed = tasks.summary != opt.summary;
|
||||
tasks.summary = opt.summary;
|
||||
|
||||
// If the task manager is visible, update the summaries with a complete render.
|
||||
// If the task manager is visible, update the snaps with a full render.
|
||||
if tasks.visible {
|
||||
let new = tasks.paginate();
|
||||
if tasks.summaries != new {
|
||||
tasks.summaries = new;
|
||||
if tasks.snaps != new {
|
||||
tasks.snaps = new;
|
||||
let cx = &mut Ctx::active(&mut self.core);
|
||||
act!(tasks:arrow, cx)?;
|
||||
succ!(render!());
|
||||
|
|
@ -26,7 +26,7 @@ impl App {
|
|||
|
||||
if !progressed {
|
||||
succ!()
|
||||
} else if tasks.progress.total == 0 {
|
||||
} else if tasks.summary.total == 0 {
|
||||
succ!(render!())
|
||||
} else {
|
||||
act!(render_partially, self)
|
||||
|
|
@ -44,7 +44,7 @@ impl<'a> Executor<'a> {
|
|||
on!(plugin);
|
||||
on!(plugin_do);
|
||||
on!(update_notify);
|
||||
on!(update_progress);
|
||||
on!(update_summary);
|
||||
on!(resize);
|
||||
on!(stop);
|
||||
on!(resume);
|
||||
|
|
|
|||
|
|
@ -10,10 +10,8 @@ pub(super) struct Router<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Router<'a> {
|
||||
#[inline]
|
||||
pub(super) fn new(app: &'a mut App) -> Self { Self { app } }
|
||||
|
||||
#[inline]
|
||||
pub(super) fn route(&mut self, key: Key) -> Result<bool> {
|
||||
let core = &mut self.app.core;
|
||||
let layer = core.layer();
|
||||
|
|
@ -36,7 +34,6 @@ impl<'a> Router<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn matches(&mut self, layer: Layer, key: Key) -> bool {
|
||||
for chord @ Chord { on, .. } in KEYMAP.get(layer) {
|
||||
if on.is_empty() || on[0] != key {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ impl Signals {
|
|||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[inline]
|
||||
fn handle_sys(n: libc::c_int) -> bool {
|
||||
use libc::{SIGCONT, SIGHUP, SIGINT, SIGQUIT, SIGSTOP, SIGTERM, SIGTSTP};
|
||||
use tracing::error;
|
||||
|
|
@ -55,7 +54,6 @@ impl Signals {
|
|||
#[inline]
|
||||
fn handle_sys(_: ()) -> bool { unreachable!() }
|
||||
|
||||
#[inline]
|
||||
fn handle_term(event: CrosstermEvent) {
|
||||
match event {
|
||||
CrosstermEvent::Key(key @ KeyEvent { kind: KeyEventKind::Press, .. }) => {
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ impl Widget for Tasks<'_> {
|
|||
block.render(area, buf);
|
||||
|
||||
let tasks = &self.core.tasks;
|
||||
let items = tasks.summaries.iter().take(inner.height as usize).enumerate().map(|(i, v)| {
|
||||
let items = tasks.snaps.iter().take(inner.height as usize).enumerate().map(|(i, v)| {
|
||||
let mut item =
|
||||
Text::from_iter(textwrap::wrap(&v.name, inner.width as usize).into_iter().map(Line::from));
|
||||
if i == tasks.cursor {
|
||||
|
|
|
|||
|
|
@ -136,7 +136,6 @@ impl Term {
|
|||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn can_partial(&mut self) -> bool {
|
||||
self.inner.autoresize().is_ok() && self.last_area == self.inner.get_frame().area()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::{fs::{FileType, Metadata}, time::SystemTime};
|
||||
|
||||
use yazi_macro::{unix_either, win_either};
|
||||
use yazi_shared::url::UrlBuf;
|
||||
use yazi_shared::url::{Url, UrlBuf};
|
||||
|
||||
use super::ChaKind;
|
||||
use crate::provider;
|
||||
|
|
@ -53,17 +53,20 @@ impl Default for Cha {
|
|||
|
||||
impl Cha {
|
||||
#[inline]
|
||||
pub fn new(url: &UrlBuf, meta: Metadata) -> Self {
|
||||
pub fn new<'a>(url: impl Into<Url<'a>>, meta: Metadata) -> Self {
|
||||
Self::from_just_meta(&meta).attach(ChaKind::hidden(url, &meta))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn from_url(url: &UrlBuf) -> std::io::Result<Self> {
|
||||
pub async fn from_url<'a>(url: impl Into<Url<'a>>) -> std::io::Result<Self> {
|
||||
let url = url.into();
|
||||
Ok(Self::from_follow(url, provider::symlink_metadata(url).await?).await)
|
||||
}
|
||||
|
||||
pub async fn from_follow(url: &UrlBuf, mut meta: Metadata) -> Self {
|
||||
pub async fn from_follow<'a>(url: impl Into<Url<'a>>, mut meta: Metadata) -> Self {
|
||||
let url = url.into();
|
||||
let mut attached = ChaKind::hidden(url, &meta);
|
||||
|
||||
if meta.is_symlink() {
|
||||
attached |= ChaKind::LINK;
|
||||
meta = provider::metadata(url).await.unwrap_or(meta);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::fs::Metadata;
|
||||
|
||||
use bitflags::bitflags;
|
||||
use yazi_shared::url::UrlBuf;
|
||||
use yazi_shared::url::Url;
|
||||
|
||||
bitflags! {
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
|
|
@ -20,11 +20,11 @@ bitflags! {
|
|||
|
||||
impl ChaKind {
|
||||
#[inline]
|
||||
pub(super) fn hidden(_url: &UrlBuf, _meta: &Metadata) -> Self {
|
||||
pub(super) fn hidden<'a>(_url: impl Into<Url<'a>>, _meta: &Metadata) -> Self {
|
||||
let mut me = Self::empty();
|
||||
|
||||
#[cfg(unix)]
|
||||
if _url.urn().is_hidden() {
|
||||
if _url.into().urn().is_hidden() {
|
||||
me |= Self::HIDDEN;
|
||||
}
|
||||
#[cfg(windows)]
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ pub struct File {
|
|||
impl Deref for File {
|
||||
type Target = Cha;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target { &self.cha }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,38 +31,38 @@ pub fn copy_with_progress(
|
|||
to: &UrlBuf,
|
||||
cha: Cha,
|
||||
) -> mpsc::Receiver<Result<u64, io::Error>> {
|
||||
let (tx, rx) = mpsc::channel(1);
|
||||
let (tick_tx, mut tick_rx) = oneshot::channel();
|
||||
let (prog_tx, prog_rx) = mpsc::channel(1);
|
||||
let (done_tx, mut done_rx) = oneshot::channel();
|
||||
|
||||
tokio::spawn({
|
||||
let (from, to) = (from.clone(), to.clone());
|
||||
async move {
|
||||
tick_tx.send(provider::copy(&from, &to, cha).await).ok();
|
||||
done_tx.send(provider::copy(&from, &to, cha).await).ok();
|
||||
}
|
||||
});
|
||||
|
||||
tokio::spawn({
|
||||
let (tx, to) = (tx.clone(), to.clone());
|
||||
let (prog_tx, to) = (prog_tx.clone(), to.clone());
|
||||
async move {
|
||||
let mut last = 0;
|
||||
let mut exit = None;
|
||||
let mut done = None;
|
||||
loop {
|
||||
select! {
|
||||
res = &mut tick_rx => exit = Some(res.unwrap()),
|
||||
_ = tx.closed() => break,
|
||||
_ = time::sleep(time::Duration::from_secs(3)) => (),
|
||||
res = &mut done_rx => done = Some(res.unwrap()),
|
||||
_ = prog_tx.closed() => break,
|
||||
_ = time::sleep(time::Duration::from_secs(3)) => {},
|
||||
}
|
||||
|
||||
match exit {
|
||||
match done {
|
||||
Some(Ok(len)) => {
|
||||
if len > last {
|
||||
tx.send(Ok(len - last)).await.ok();
|
||||
prog_tx.send(Ok(len - last)).await.ok();
|
||||
}
|
||||
tx.send(Ok(0)).await.ok();
|
||||
prog_tx.send(Ok(0)).await.ok();
|
||||
break;
|
||||
}
|
||||
Some(Err(e)) => {
|
||||
tx.send(Err(e)).await.ok();
|
||||
prog_tx.send(Err(e)).await.ok();
|
||||
break;
|
||||
}
|
||||
None => {}
|
||||
|
|
@ -70,14 +70,14 @@ pub fn copy_with_progress(
|
|||
|
||||
let len = provider::symlink_metadata(&to).await.map(|m| m.len()).unwrap_or(0);
|
||||
if len > last {
|
||||
tx.send(Ok(len - last)).await.ok();
|
||||
prog_tx.send(Ok(len - last)).await.ok();
|
||||
last = len;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
rx
|
||||
prog_rx
|
||||
}
|
||||
|
||||
pub async fn remove_dir_clean(dir: &UrlBuf) {
|
||||
|
|
|
|||
|
|
@ -38,13 +38,11 @@ impl Partition {
|
|||
}
|
||||
|
||||
impl Partition {
|
||||
#[inline]
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
pub(super) fn new(name: &std::ffi::OsStr) -> Self {
|
||||
Self { src: std::path::Path::new("/dev/").join(name).into(), ..Default::default() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(target_os = "linux")]
|
||||
pub(super) fn dev_name(&self, full: bool) -> Option<&std::ffi::OsStr> {
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ impl Deref for Partitions {
|
|||
}
|
||||
|
||||
impl Partitions {
|
||||
#[inline]
|
||||
#[cfg(unix)]
|
||||
pub fn by_dev(&self, dev: libc::dev_t) -> Option<&Partition> {
|
||||
self.inner.iter().find(|p| p.rdev == Some(dev))
|
||||
|
|
|
|||
|
|
@ -202,6 +202,25 @@ impl Local {
|
|||
tokio::fs::rename(from, to).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn symlink<P, Q, F>(original: P, link: Q, _is_dir: F) -> io::Result<()>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
Q: AsRef<Path>,
|
||||
F: AsyncFnOnce() -> io::Result<bool>,
|
||||
{
|
||||
#[cfg(unix)]
|
||||
{
|
||||
tokio::fs::symlink(original, link).await
|
||||
}
|
||||
#[cfg(windows)]
|
||||
if _is_dir().await? {
|
||||
Self::symlink_dir(original, link).await
|
||||
} else {
|
||||
Self::symlink_file(original, link).await
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn symlink_dir<P, Q>(original: P, link: Q) -> io::Result<()>
|
||||
where
|
||||
|
|
|
|||
|
|
@ -229,6 +229,19 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn symlink<'a, U, F>(original: &Path, link: U, is_dir: F) -> io::Result<()>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
F: AsyncFnOnce() -> io::Result<bool>,
|
||||
{
|
||||
if let Some(link) = link.into().as_path() {
|
||||
Local::symlink(original, link, is_dir).await
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::Unsupported, "Unsupported filesystem"))
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn symlink_dir<'a, U>(original: &Path, link: U) -> io::Result<()>
|
||||
where
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ pub enum RwFile {
|
|||
}
|
||||
|
||||
impl RwFile {
|
||||
#[inline]
|
||||
pub fn reader(self) -> Box<dyn BufRead> {
|
||||
match self {
|
||||
RwFile::Local(local) => Box::new(local.reader()),
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ pub enum FolderStage {
|
|||
}
|
||||
|
||||
impl FolderStage {
|
||||
#[inline]
|
||||
pub fn is_loading(self) -> bool { self == Self::Loading }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,10 +21,11 @@ yazi-macro = { path = "../yazi-macro", version = "25.6.11" }
|
|||
yazi-shared = { path = "../yazi-shared", version = "25.6.11" }
|
||||
|
||||
# External dependencies
|
||||
anyhow = { workspace = true }
|
||||
bitflags = { workspace = true }
|
||||
crossterm = { workspace = true }
|
||||
hashbrown = { workspace = true }
|
||||
mlua = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
bitflags = { workspace = true }
|
||||
crossterm = { workspace = true }
|
||||
hashbrown = { workspace = true }
|
||||
mlua = { workspace = true }
|
||||
ordered-float = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
yazi_macro::mod_flat!(deprecate mouse notify plugin stop update_progress);
|
||||
yazi_macro::mod_flat!(deprecate mouse notify plugin stop update_summary);
|
||||
|
|
|
|||
|
|
@ -1,30 +0,0 @@
|
|||
use anyhow::bail;
|
||||
use serde::Serialize;
|
||||
use yazi_shared::event::CmdCow;
|
||||
|
||||
pub struct UpdateProgressOpt {
|
||||
pub progress: TasksProgress,
|
||||
}
|
||||
|
||||
impl TryFrom<CmdCow> for UpdateProgressOpt {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(mut c: CmdCow) -> Result<Self, Self::Error> {
|
||||
let Some(progress) = c.take_any("progress") else {
|
||||
bail!("Invalid 'progress' in UpdateProgressOpt");
|
||||
};
|
||||
|
||||
Ok(Self { progress })
|
||||
}
|
||||
}
|
||||
|
||||
// --- Progress
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize)]
|
||||
pub struct TasksProgress {
|
||||
pub total: u32,
|
||||
pub succ: u32,
|
||||
pub fail: u32,
|
||||
|
||||
pub found: u64,
|
||||
pub processed: u64,
|
||||
}
|
||||
29
yazi-parser/src/app/update_summary.rs
Normal file
29
yazi-parser/src/app/update_summary.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
use anyhow::bail;
|
||||
use ordered_float::OrderedFloat;
|
||||
use serde::Serialize;
|
||||
use yazi_shared::event::CmdCow;
|
||||
|
||||
pub struct UpdateSummaryOpt {
|
||||
pub summary: TaskSummary,
|
||||
}
|
||||
|
||||
impl TryFrom<CmdCow> for UpdateSummaryOpt {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(mut c: CmdCow) -> Result<Self, Self::Error> {
|
||||
let Some(summary) = c.take_any("summary") else {
|
||||
bail!("Invalid 'summary' in UpdateProgressOpt");
|
||||
};
|
||||
|
||||
Ok(Self { summary })
|
||||
}
|
||||
}
|
||||
|
||||
// --- Progress
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize)]
|
||||
pub struct TaskSummary {
|
||||
pub total: u32,
|
||||
pub success: u32,
|
||||
pub failed: u32,
|
||||
pub percent: Option<OrderedFloat<f32>>,
|
||||
}
|
||||
|
|
@ -62,7 +62,6 @@ impl TryFrom<Table> for SpotLock {
|
|||
}
|
||||
|
||||
impl SpotLock {
|
||||
#[inline]
|
||||
pub fn len(&self) -> Option<usize> { Some(self.table()?.len()) }
|
||||
|
||||
pub fn select(&mut self, idx: Option<usize>) {
|
||||
|
|
|
|||
|
|
@ -22,25 +22,25 @@ end
|
|||
function Progress:reflow() return { self } end
|
||||
|
||||
function Progress:redraw()
|
||||
local progress = cx.tasks.progress
|
||||
if progress.total == 0 then
|
||||
local summary = cx.tasks.summary
|
||||
if summary.total == 0 then
|
||||
return {}
|
||||
end
|
||||
|
||||
local gauge = ui.Gauge():area(self._area)
|
||||
if progress.fail == 0 then
|
||||
if summary.failed == 0 then
|
||||
gauge = gauge:gauge_style(th.status.progress_normal)
|
||||
else
|
||||
gauge = gauge:gauge_style(th.status.progress_error)
|
||||
end
|
||||
|
||||
local percent = 99
|
||||
if progress.found ~= 0 then
|
||||
percent = math.min(99, ya.round(progress.processed * 100 / progress.found))
|
||||
local label, percent = "", summary.percent
|
||||
if percent then
|
||||
label = string.format("%3d%%, ", math.floor(percent))
|
||||
else
|
||||
percent = 99
|
||||
end
|
||||
|
||||
local left = progress.total - progress.succ
|
||||
return gauge
|
||||
:percent(percent)
|
||||
:label(ui.Span(string.format("%3d%%, %d left", percent, left)):style(th.status.progress_label))
|
||||
label = label .. string.format("%d left", summary.total - summary.success)
|
||||
return gauge:percent(percent):label(ui.Span(label):style(th.status.progress_label))
|
||||
end
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@ function ya.clamp(min, x, max)
|
|||
end
|
||||
end
|
||||
|
||||
function ya.round(x) return x >= 0 and math.floor(x + 0.5) or math.ceil(x - 0.5) end
|
||||
|
||||
function ya.list_merge(a, b)
|
||||
for _, v in ipairs(b) do
|
||||
a[#a + 1] = v
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ impl UserData for ImageFormat {
|
|||
F::Farbfeld => "Farbfeld",
|
||||
F::Avif => "AVIF",
|
||||
F::Qoi => "QOI",
|
||||
F::Pcx => "PCX",
|
||||
_ => "Unknown",
|
||||
})
|
||||
});
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ fn cha(lua: &Lua) -> mlua::Result<Function> {
|
|||
};
|
||||
|
||||
match meta {
|
||||
Ok(m) => Cha(yazi_fs::cha::Cha::new(&url, m)).into_lua_multi(&lua),
|
||||
Ok(m) => Cha(yazi_fs::cha::Cha::new(&*url, m)).into_lua_multi(&lua),
|
||||
Err(e) => (Value::Nil, Error::Io(e)).into_lua_multi(&lua),
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use yazi_binding::{Composer, ComposerGet, ComposerSet, Url};
|
|||
use yazi_boot::ARGS;
|
||||
use yazi_config::YAZI;
|
||||
|
||||
pub const OPTS: SerializeOptions =
|
||||
pub const SER_OPT: SerializeOptions =
|
||||
SerializeOptions::new().serialize_none_to_null(false).serialize_unit_to_null(false);
|
||||
|
||||
pub fn compose() -> Composer<ComposerGet, ComposerSet> {
|
||||
|
|
@ -44,20 +44,20 @@ fn mgr() -> Composer<ComposerGet, ComposerSet> {
|
|||
fn get(lua: &Lua, key: &[u8]) -> mlua::Result<Value> {
|
||||
let m = &YAZI.mgr;
|
||||
match key {
|
||||
b"ratio" => lua.to_value_with(&m.ratio, OPTS)?,
|
||||
b"ratio" => lua.to_value_with(&m.ratio, SER_OPT)?,
|
||||
|
||||
b"sort_by" => lua.to_value_with(&m.sort_by, OPTS)?,
|
||||
b"sort_sensitive" => lua.to_value_with(&m.sort_sensitive, OPTS)?,
|
||||
b"sort_reverse" => lua.to_value_with(&m.sort_reverse, OPTS)?,
|
||||
b"sort_dir_first" => lua.to_value_with(&m.sort_dir_first, OPTS)?,
|
||||
b"sort_translit" => lua.to_value_with(&m.sort_translit, OPTS)?,
|
||||
b"sort_by" => lua.to_value_with(&m.sort_by, SER_OPT)?,
|
||||
b"sort_sensitive" => lua.to_value_with(&m.sort_sensitive, SER_OPT)?,
|
||||
b"sort_reverse" => lua.to_value_with(&m.sort_reverse, SER_OPT)?,
|
||||
b"sort_dir_first" => lua.to_value_with(&m.sort_dir_first, SER_OPT)?,
|
||||
b"sort_translit" => lua.to_value_with(&m.sort_translit, SER_OPT)?,
|
||||
|
||||
b"linemode" => lua.to_value_with(&m.linemode, OPTS)?,
|
||||
b"show_hidden" => lua.to_value_with(&m.show_hidden, OPTS)?,
|
||||
b"show_symlink" => lua.to_value_with(&m.show_symlink, OPTS)?,
|
||||
b"scrolloff" => lua.to_value_with(&m.scrolloff, OPTS)?,
|
||||
b"mouse_events" => lua.to_value_with(&m.mouse_events, OPTS)?,
|
||||
b"title_format" => lua.to_value_with(&m.title_format, OPTS)?,
|
||||
b"linemode" => lua.to_value_with(&m.linemode, SER_OPT)?,
|
||||
b"show_hidden" => lua.to_value_with(&m.show_hidden, SER_OPT)?,
|
||||
b"show_symlink" => lua.to_value_with(&m.show_symlink, SER_OPT)?,
|
||||
b"scrolloff" => lua.to_value_with(&m.scrolloff, SER_OPT)?,
|
||||
b"mouse_events" => lua.to_value_with(&m.mouse_events, SER_OPT)?,
|
||||
b"title_format" => lua.to_value_with(&m.title_format, SER_OPT)?,
|
||||
_ => return Ok(Value::Nil),
|
||||
}
|
||||
.into_lua(lua)
|
||||
|
|
@ -81,19 +81,19 @@ fn preview() -> Composer<ComposerGet, ComposerSet> {
|
|||
fn get(lua: &Lua, key: &[u8]) -> mlua::Result<Value> {
|
||||
let p = &YAZI.preview;
|
||||
match key {
|
||||
b"wrap" => lua.to_value_with(&p.wrap, OPTS)?,
|
||||
b"tab_size" => lua.to_value_with(&p.tab_size, OPTS)?,
|
||||
b"max_width" => lua.to_value_with(&p.max_width, OPTS)?,
|
||||
b"max_height" => lua.to_value_with(&p.max_height, OPTS)?,
|
||||
b"wrap" => lua.to_value_with(&p.wrap, SER_OPT)?,
|
||||
b"tab_size" => lua.to_value_with(&p.tab_size, SER_OPT)?,
|
||||
b"max_width" => lua.to_value_with(&p.max_width, SER_OPT)?,
|
||||
b"max_height" => lua.to_value_with(&p.max_height, SER_OPT)?,
|
||||
|
||||
b"cache_dir" => lua.to_value_with(&p.cache_dir, OPTS)?,
|
||||
b"cache_dir" => lua.to_value_with(&p.cache_dir, SER_OPT)?,
|
||||
|
||||
b"image_delay" => lua.to_value_with(&p.image_delay, OPTS)?,
|
||||
b"image_filter" => lua.to_value_with(&p.image_filter, OPTS)?,
|
||||
b"image_quality" => lua.to_value_with(&p.image_quality, OPTS)?,
|
||||
b"image_delay" => lua.to_value_with(&p.image_delay, SER_OPT)?,
|
||||
b"image_filter" => lua.to_value_with(&p.image_filter, SER_OPT)?,
|
||||
b"image_quality" => lua.to_value_with(&p.image_quality, SER_OPT)?,
|
||||
|
||||
b"ueberzug_scale" => lua.to_value_with(&p.ueberzug_scale, OPTS)?,
|
||||
b"ueberzug_offset" => lua.to_value_with(&p.ueberzug_offset, OPTS)?,
|
||||
b"ueberzug_scale" => lua.to_value_with(&p.ueberzug_scale, SER_OPT)?,
|
||||
b"ueberzug_offset" => lua.to_value_with(&p.ueberzug_offset, SER_OPT)?,
|
||||
_ => return Ok(Value::Nil),
|
||||
}
|
||||
.into_lua(lua)
|
||||
|
|
@ -108,14 +108,14 @@ fn tasks() -> Composer<ComposerGet, ComposerSet> {
|
|||
fn get(lua: &Lua, key: &[u8]) -> mlua::Result<Value> {
|
||||
let t = &YAZI.tasks;
|
||||
match key {
|
||||
b"micro_workers" => lua.to_value_with(&t.micro_workers, OPTS)?,
|
||||
b"macro_workers" => lua.to_value_with(&t.macro_workers, OPTS)?,
|
||||
b"bizarre_retry" => lua.to_value_with(&t.bizarre_retry, OPTS)?,
|
||||
b"micro_workers" => lua.to_value_with(&t.micro_workers, SER_OPT)?,
|
||||
b"macro_workers" => lua.to_value_with(&t.macro_workers, SER_OPT)?,
|
||||
b"bizarre_retry" => lua.to_value_with(&t.bizarre_retry, SER_OPT)?,
|
||||
|
||||
b"image_alloc" => lua.to_value_with(&t.image_alloc, OPTS)?,
|
||||
b"image_bound" => lua.to_value_with(&t.image_bound, OPTS)?,
|
||||
b"image_alloc" => lua.to_value_with(&t.image_alloc, SER_OPT)?,
|
||||
b"image_bound" => lua.to_value_with(&t.image_bound, SER_OPT)?,
|
||||
|
||||
b"suppress_preload" => lua.to_value_with(&t.suppress_preload, OPTS)?,
|
||||
b"suppress_preload" => lua.to_value_with(&t.suppress_preload, SER_OPT)?,
|
||||
_ => return Ok(Value::Nil),
|
||||
}
|
||||
.into_lua(lua)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use mlua::{Function, IntoLuaMulti, Lua, LuaSerdeExt, Value};
|
|||
use yazi_binding::Error;
|
||||
|
||||
use super::Utils;
|
||||
use crate::runtime::OPTS;
|
||||
use crate::runtime::SER_OPT;
|
||||
|
||||
impl Utils {
|
||||
pub(super) fn json_encode(lua: &Lua) -> mlua::Result<Function> {
|
||||
|
|
@ -17,7 +17,7 @@ impl Utils {
|
|||
pub(super) fn json_decode(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|lua, s: mlua::String| async move {
|
||||
match serde_json::from_slice::<serde_json::Value>(&s.as_bytes()) {
|
||||
Ok(v) => lua.to_value_with(&v, OPTS)?.into_lua_multi(&lua),
|
||||
Ok(v) => lua.to_value_with(&v, SER_OPT)?.into_lua_multi(&lua),
|
||||
Err(e) => (Value::Nil, Error::Serde(e)).into_lua_multi(&lua),
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::time::Duration;
|
|||
|
||||
use tokio::sync::oneshot;
|
||||
use yazi_macro::{emit, relay};
|
||||
use yazi_parser::app::{NotifyLevel, NotifyOpt, PluginOpt, TasksProgress};
|
||||
use yazi_parser::app::{NotifyLevel, NotifyOpt, PluginOpt, TaskSummary};
|
||||
|
||||
pub struct AppProxy;
|
||||
|
||||
|
|
@ -51,7 +51,7 @@ impl AppProxy {
|
|||
emit!(Call(relay!(app:plugin_do).with_any("opt", opt)));
|
||||
}
|
||||
|
||||
pub fn update_progress(progress: TasksProgress) {
|
||||
emit!(Call(relay!(app:update_progress).with_any("progress", progress)));
|
||||
pub fn update_summary(summary: TaskSummary) {
|
||||
emit!(Call(relay!(app:update_summary).with_any("summary", summary)));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ async-priority-channel = "0.2.0"
|
|||
futures = { workspace = true }
|
||||
hashbrown = { workspace = true }
|
||||
lru = { workspace = true }
|
||||
mlua = { workspace = true }
|
||||
ordered-float = { workspace = true }
|
||||
parking_lot = { workspace = true }
|
||||
scopeguard = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -1,140 +1,31 @@
|
|||
use std::{borrow::Cow, collections::VecDeque};
|
||||
|
||||
use anyhow::{Result, anyhow, bail};
|
||||
use anyhow::{Result, anyhow};
|
||||
use tokio::{io::{self, ErrorKind::{AlreadyExists, NotFound}}, sync::mpsc};
|
||||
use tracing::warn;
|
||||
use yazi_config::YAZI;
|
||||
use yazi_fs::{SizeCalculator, cha::Cha, copy_with_progress, maybe_exists, ok_or_not_found, path::{path_relative_to, skip_url}, provider::{self, DirEntry}};
|
||||
use yazi_shared::{Id, url::{UrlBuf, UrlCow}};
|
||||
use yazi_fs::{cha::Cha, copy_with_progress, maybe_exists, ok_or_not_found, path::{path_relative_to, skip_url}, provider::{self, DirEntry}};
|
||||
use yazi_shared::url::{Url, UrlBuf, UrlCow};
|
||||
|
||||
use super::{FileIn, FileInDelete, FileInHardlink, FileInLink, FileInPaste, FileInTrash};
|
||||
use crate::{LOW, NORMAL, TaskOp, TaskProg};
|
||||
use super::{FileInDelete, FileInHardlink, FileInLink, FileInPaste, FileInTrash};
|
||||
use crate::{LOW, NORMAL, TaskIn, TaskOp, TaskOps, file::{FileOutDelete, FileOutDeleteDo, FileOutHardlink, FileOutHardlinkDo, FileOutLink, FileOutPaste, FileOutPasteDo, FileOutTrash}};
|
||||
|
||||
pub struct File {
|
||||
r#macro: async_priority_channel::Sender<TaskOp, u8>,
|
||||
prog: mpsc::UnboundedSender<TaskProg>,
|
||||
pub(crate) struct File {
|
||||
ops: TaskOps,
|
||||
r#macro: async_priority_channel::Sender<TaskIn, u8>,
|
||||
}
|
||||
|
||||
impl File {
|
||||
pub fn new(
|
||||
r#macro: async_priority_channel::Sender<TaskOp, u8>,
|
||||
prog: mpsc::UnboundedSender<TaskProg>,
|
||||
pub(crate) fn new(
|
||||
tx: &mpsc::UnboundedSender<TaskOp>,
|
||||
r#macro: &async_priority_channel::Sender<TaskIn, u8>,
|
||||
) -> Self {
|
||||
Self { r#macro, prog }
|
||||
Self { ops: tx.into(), r#macro: r#macro.clone() }
|
||||
}
|
||||
|
||||
pub async fn work(&self, r#in: FileIn) -> Result<()> {
|
||||
match r#in {
|
||||
FileIn::Paste(mut task) => {
|
||||
ok_or_not_found(provider::remove_file(&task.to).await)?;
|
||||
let mut it = copy_with_progress(&task.from, &task.to, task.cha.unwrap());
|
||||
|
||||
while let Some(res) = it.recv().await {
|
||||
match res {
|
||||
Ok(0) => {
|
||||
if task.cut {
|
||||
provider::remove_file(&task.from).await.ok();
|
||||
}
|
||||
break;
|
||||
}
|
||||
Ok(n) => self.prog.send(TaskProg::Adv(task.id, 0, n))?,
|
||||
Err(e) if e.kind() == NotFound => {
|
||||
warn!("Paste task partially done: {task:?}");
|
||||
break;
|
||||
}
|
||||
// Operation not permitted (os error 1)
|
||||
// Attribute not found (os error 93)
|
||||
Err(e)
|
||||
if task.retry < YAZI.tasks.bizarre_retry
|
||||
&& matches!(e.raw_os_error(), Some(1) | Some(93)) =>
|
||||
{
|
||||
task.retry += 1;
|
||||
self.log(task.id, format!("Paste task retry: {task:?}"))?;
|
||||
self.queue(FileIn::Paste(task), LOW).await?;
|
||||
return Ok(());
|
||||
}
|
||||
Err(e) => Err(e)?,
|
||||
}
|
||||
}
|
||||
self.prog.send(TaskProg::Adv(task.id, 1, 0))?;
|
||||
}
|
||||
FileIn::Link(task) => {
|
||||
let cha = task.cha.unwrap();
|
||||
|
||||
let src: Cow<_> = if task.resolve {
|
||||
match provider::read_link(&task.from).await {
|
||||
Ok(p) => p.into(),
|
||||
Err(e) if e.kind() == NotFound => {
|
||||
warn!("Link task partially done: {task:?}");
|
||||
return Ok(self.prog.send(TaskProg::Adv(task.id, 1, cha.len))?);
|
||||
}
|
||||
Err(e) => Err(e)?,
|
||||
}
|
||||
} else if task.from.scheme.covariant(&task.to.scheme) {
|
||||
task.from.loc.as_path().into()
|
||||
} else {
|
||||
bail!("Source and target must be on the same filesystem: {task:?}")
|
||||
};
|
||||
|
||||
let src = if task.relative {
|
||||
path_relative_to(provider::canonicalize(task.to.parent().unwrap()).await?.loc, &src)?
|
||||
} else {
|
||||
src
|
||||
};
|
||||
|
||||
ok_or_not_found(provider::remove_file(&task.to).await)?;
|
||||
if cha.is_dir() {
|
||||
provider::symlink_dir(&src, &task.to).await?;
|
||||
} else {
|
||||
provider::symlink_file(&src, &task.to).await?;
|
||||
}
|
||||
|
||||
if task.delete {
|
||||
provider::remove_file(&task.from).await.ok();
|
||||
}
|
||||
self.prog.send(TaskProg::Adv(task.id, 1, cha.len))?;
|
||||
}
|
||||
FileIn::Hardlink(task) => {
|
||||
let cha = task.cha.unwrap();
|
||||
let src = if !task.follow {
|
||||
UrlCow::from(&task.from)
|
||||
} else if let Ok(p) = provider::canonicalize(&task.from).await {
|
||||
UrlCow::from(p)
|
||||
} else {
|
||||
UrlCow::from(&task.from)
|
||||
};
|
||||
|
||||
ok_or_not_found(provider::remove_file(&task.to).await)?;
|
||||
match provider::hard_link(&src, &task.to).await {
|
||||
Err(e) if e.kind() == NotFound => {
|
||||
warn!("Hardlink task partially done: {task:?}");
|
||||
}
|
||||
v => v?,
|
||||
}
|
||||
|
||||
self.prog.send(TaskProg::Adv(task.id, 1, cha.len))?;
|
||||
}
|
||||
FileIn::Delete(task) => {
|
||||
if let Err(e) = provider::remove_file(&task.target).await
|
||||
&& e.kind() != NotFound
|
||||
&& maybe_exists(&task.target).await
|
||||
{
|
||||
self.fail(task.id, format!("Delete task failed: {task:?}, {e}"))?;
|
||||
Err(e)?
|
||||
}
|
||||
self.prog.send(TaskProg::Adv(task.id, 1, task.length))?
|
||||
}
|
||||
FileIn::Trash(task) => {
|
||||
provider::trash(&task.target).await?;
|
||||
self.prog.send(TaskProg::Adv(task.id, 1, task.length))?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn paste(&self, mut task: FileInPaste) -> Result<()> {
|
||||
pub(crate) async fn paste(&self, mut task: FileInPaste) -> Result<(), FileOutPaste> {
|
||||
if task.cut && ok_or_not_found(provider::rename(&task.from, &task.to).await).is_ok() {
|
||||
return self.succ(task.id);
|
||||
return Ok(self.ops.out(task.id, FileOutPaste::Init));
|
||||
}
|
||||
|
||||
if task.cha.is_none() {
|
||||
|
|
@ -144,14 +35,14 @@ impl File {
|
|||
let cha = task.cha.unwrap();
|
||||
if !cha.is_dir() {
|
||||
let id = task.id;
|
||||
self.prog.send(TaskProg::New(id, cha.len))?;
|
||||
|
||||
if cha.is_orphan() || (cha.is_link() && !task.follow) {
|
||||
self.queue(FileIn::Link(task.into()), NORMAL).await?;
|
||||
self.ops.out(id, FileOutPaste::New(0));
|
||||
self.queue(task.into_link(), NORMAL);
|
||||
} else {
|
||||
self.queue(FileIn::Paste(task), LOW).await?;
|
||||
self.ops.out(id, FileOutPaste::New(cha.len));
|
||||
self.queue(task, LOW);
|
||||
}
|
||||
return self.succ(id);
|
||||
return Ok(self.ops.out(id, FileOutPaste::Init));
|
||||
}
|
||||
|
||||
macro_rules! continue_unless_ok {
|
||||
|
|
@ -159,8 +50,7 @@ impl File {
|
|||
match $result {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
self.prog.send(TaskProg::New(task.id, 0))?;
|
||||
self.fail(task.id, format!("An error occurred while pasting: {e}"))?;
|
||||
self.ops.out(task.id, FileOutPaste::Deform(e.to_string()));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
|
@ -189,30 +79,93 @@ impl File {
|
|||
}
|
||||
|
||||
let to = dest.join(from.name().unwrap());
|
||||
self.prog.send(TaskProg::New(task.id, cha.len))?;
|
||||
|
||||
if cha.is_orphan() || (cha.is_link() && !task.follow) {
|
||||
self.queue(FileIn::Link(task.spawn(from, to, cha).into()), NORMAL).await?;
|
||||
self.ops.out(task.id, FileOutPaste::New(0));
|
||||
self.queue(task.spawn(from, to, cha).into_link(), NORMAL);
|
||||
} else {
|
||||
self.queue(FileIn::Paste(task.spawn(from, to, cha)), LOW).await?;
|
||||
self.ops.out(task.id, FileOutPaste::New(cha.len));
|
||||
self.queue(task.spawn(from, to, cha), LOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.succ(task.id)
|
||||
|
||||
Ok(self.ops.out(task.id, FileOutPaste::Init))
|
||||
}
|
||||
|
||||
pub async fn link(&self, mut task: FileInLink) -> Result<()> {
|
||||
let id = task.id;
|
||||
if task.cha.is_none() {
|
||||
task.cha = Some(Self::cha(&task.from, false).await?);
|
||||
pub(crate) async fn paste_do(&self, mut task: FileInPaste) -> Result<(), FileOutPasteDo> {
|
||||
ok_or_not_found(provider::remove_file(&task.to).await)?;
|
||||
let mut it = copy_with_progress(&task.from, &task.to, task.cha.unwrap());
|
||||
|
||||
while let Some(res) = it.recv().await {
|
||||
match res {
|
||||
Ok(0) => {
|
||||
if task.cut {
|
||||
provider::remove_file(&task.from).await.ok();
|
||||
}
|
||||
break;
|
||||
}
|
||||
Ok(n) => self.ops.out(task.id, FileOutPasteDo::Adv(n)),
|
||||
Err(e) if e.kind() == NotFound => {
|
||||
warn!("Paste task partially done: {task:?}");
|
||||
break;
|
||||
}
|
||||
// Operation not permitted (os error 1)
|
||||
// Attribute not found (os error 93)
|
||||
Err(e)
|
||||
if task.retry < YAZI.tasks.bizarre_retry
|
||||
&& matches!(e.raw_os_error(), Some(1) | Some(93)) =>
|
||||
{
|
||||
task.retry += 1;
|
||||
self.ops.out(task.id, FileOutPasteDo::Log(format!("Retrying due to error: {e}")));
|
||||
return Ok(self.queue(task, LOW));
|
||||
}
|
||||
Err(e) => Err(e)?,
|
||||
}
|
||||
}
|
||||
|
||||
self.prog.send(TaskProg::New(id, task.cha.unwrap().len))?;
|
||||
self.queue(FileIn::Link(task), NORMAL).await?;
|
||||
self.succ(id)
|
||||
Ok(self.ops.out(task.id, FileOutPasteDo::Succ))
|
||||
}
|
||||
|
||||
pub async fn hardlink(&self, mut task: FileInHardlink) -> Result<()> {
|
||||
pub(crate) fn link(&self, task: FileInLink) -> Result<(), FileOutLink> {
|
||||
Ok(self.queue(task, NORMAL))
|
||||
}
|
||||
|
||||
pub(crate) async fn link_do(&self, task: FileInLink) -> Result<(), FileOutLink> {
|
||||
let src: Cow<_> = if task.resolve {
|
||||
match provider::read_link(&task.from).await {
|
||||
Ok(p) => p.into(),
|
||||
Err(e) if e.kind() == NotFound => {
|
||||
return Ok(self.ops.out(task.id, FileOutLink::Succ));
|
||||
}
|
||||
Err(e) => Err(e)?,
|
||||
}
|
||||
} else if task.from.scheme.covariant(&task.to.scheme) {
|
||||
task.from.loc.as_path().into()
|
||||
} else {
|
||||
Err(anyhow!("Source and target must be on the same filesystem: {task:?}"))?
|
||||
};
|
||||
|
||||
let src = if task.relative {
|
||||
path_relative_to(provider::canonicalize(task.to.parent().unwrap()).await?.loc, &src)?
|
||||
} else {
|
||||
src
|
||||
};
|
||||
|
||||
ok_or_not_found(provider::remove_file(&task.to).await)?;
|
||||
provider::symlink(&src, &task.to, async || {
|
||||
Ok(match task.cha {
|
||||
Some(cha) => cha.is_dir(),
|
||||
None => Self::cha(&task.from, task.resolve).await?.is_dir(),
|
||||
})
|
||||
})
|
||||
.await?;
|
||||
|
||||
if task.delete {
|
||||
provider::remove_file(&task.from).await.ok();
|
||||
}
|
||||
Ok(self.ops.out(task.id, FileOutLink::Succ))
|
||||
}
|
||||
|
||||
pub(crate) async fn hardlink(&self, mut task: FileInHardlink) -> Result<(), FileOutHardlink> {
|
||||
if task.cha.is_none() {
|
||||
task.cha = Some(Self::cha(&task.from, task.follow).await?);
|
||||
}
|
||||
|
|
@ -220,9 +173,10 @@ impl File {
|
|||
let cha = task.cha.unwrap();
|
||||
if !cha.is_dir() {
|
||||
let id = task.id;
|
||||
self.prog.send(TaskProg::New(id, cha.len))?;
|
||||
self.queue(FileIn::Hardlink(task), NORMAL).await?;
|
||||
return self.succ(id);
|
||||
self.ops.out(id, FileOutHardlink::New);
|
||||
self.queue(task, NORMAL);
|
||||
self.ops.out(id, FileOutHardlink::Init);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
macro_rules! continue_unless_ok {
|
||||
|
|
@ -230,8 +184,7 @@ impl File {
|
|||
match $result {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
self.prog.send(TaskProg::New(task.id, 0))?;
|
||||
self.fail(task.id, format!("An error occurred while hardlinking: {e}"))?;
|
||||
self.ops.out(task.id, FileOutHardlink::Deform(e.to_string()));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
|
@ -260,21 +213,38 @@ impl File {
|
|||
}
|
||||
|
||||
let to = dest.join(from.name().unwrap());
|
||||
self.prog.send(TaskProg::New(task.id, cha.len))?;
|
||||
self.queue(FileIn::Hardlink(task.spawn(from, to, cha)), NORMAL).await?;
|
||||
self.ops.out(task.id, FileOutHardlink::New);
|
||||
self.queue(task.spawn(from, to, cha), NORMAL);
|
||||
}
|
||||
}
|
||||
self.succ(task.id)
|
||||
|
||||
Ok(self.ops.out(task.id, FileOutHardlink::Init))
|
||||
}
|
||||
|
||||
pub async fn delete(&self, mut task: FileInDelete) -> Result<()> {
|
||||
pub(crate) async fn hardlink_do(&self, task: FileInHardlink) -> Result<(), FileOutHardlinkDo> {
|
||||
let src = if !task.follow {
|
||||
UrlCow::from(&task.from)
|
||||
} else if let Ok(p) = provider::canonicalize(&task.from).await {
|
||||
UrlCow::from(p)
|
||||
} else {
|
||||
UrlCow::from(&task.from)
|
||||
};
|
||||
|
||||
ok_or_not_found(provider::remove_file(&task.to).await)?;
|
||||
ok_or_not_found(provider::hard_link(&src, &task.to).await)?;
|
||||
|
||||
Ok(self.ops.out(task.id, FileOutHardlinkDo::Succ))
|
||||
}
|
||||
|
||||
pub(crate) async fn delete(&self, mut task: FileInDelete) -> Result<(), FileOutDelete> {
|
||||
let meta = provider::symlink_metadata(&task.target).await?;
|
||||
if !meta.is_dir() {
|
||||
let id = task.id;
|
||||
task.length = meta.len();
|
||||
self.prog.send(TaskProg::New(id, meta.len()))?;
|
||||
self.queue(FileIn::Delete(task), NORMAL).await?;
|
||||
return self.succ(id);
|
||||
self.ops.out(id, FileOutDelete::New(meta.len()));
|
||||
self.queue(task, NORMAL);
|
||||
self.ops.out(id, FileOutDelete::Init);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut dirs = VecDeque::from([task.target]);
|
||||
|
|
@ -291,24 +261,36 @@ impl File {
|
|||
|
||||
task.target = entry.url();
|
||||
task.length = meta.len();
|
||||
self.prog.send(TaskProg::New(task.id, meta.len()))?;
|
||||
self.queue(FileIn::Delete(task.clone()), NORMAL).await?;
|
||||
self.ops.out(task.id, FileOutDelete::New(meta.len()));
|
||||
self.queue(task.clone(), NORMAL);
|
||||
}
|
||||
}
|
||||
self.succ(task.id)
|
||||
|
||||
Ok(self.ops.out(task.id, FileOutDelete::Init))
|
||||
}
|
||||
|
||||
pub async fn trash(&self, mut task: FileInTrash) -> Result<()> {
|
||||
let id = task.id;
|
||||
task.length = SizeCalculator::total(&task.target).await?;
|
||||
pub(crate) async fn delete_do(&self, task: FileInDelete) -> Result<(), FileOutDeleteDo> {
|
||||
match provider::remove_file(&task.target).await {
|
||||
Ok(()) => {}
|
||||
Err(e) if e.kind() == NotFound => {}
|
||||
Err(_) if !maybe_exists(&task.target).await => {}
|
||||
Err(e) => Err(e)?,
|
||||
}
|
||||
Ok(self.ops.out(task.id, FileOutDeleteDo::Succ(task.length)))
|
||||
}
|
||||
|
||||
self.prog.send(TaskProg::New(id, task.length))?;
|
||||
self.queue(FileIn::Trash(task), LOW).await?;
|
||||
self.succ(id)
|
||||
pub(crate) fn trash(&self, task: FileInTrash) -> Result<(), FileOutTrash> {
|
||||
Ok(self.queue(task, LOW))
|
||||
}
|
||||
|
||||
pub(crate) async fn trash_do(&self, task: FileInTrash) -> Result<(), FileOutTrash> {
|
||||
provider::trash(&task.target).await?;
|
||||
Ok(self.ops.out(task.id, FileOutTrash::Succ))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
async fn cha(url: &UrlBuf, follow: bool) -> io::Result<Cha> {
|
||||
async fn cha<'a>(url: impl Into<Url<'a>>, follow: bool) -> io::Result<Cha> {
|
||||
let url = url.into();
|
||||
let meta = provider::symlink_metadata(url).await?;
|
||||
Ok(if follow { Cha::from_follow(url, meta).await } else { Cha::new(url, meta) })
|
||||
}
|
||||
|
|
@ -325,18 +307,7 @@ impl File {
|
|||
|
||||
impl File {
|
||||
#[inline]
|
||||
fn succ(&self, id: Id) -> Result<()> { Ok(self.prog.send(TaskProg::Succ(id))?) }
|
||||
|
||||
#[inline]
|
||||
fn fail(&self, id: Id, reason: String) -> Result<()> {
|
||||
Ok(self.prog.send(TaskProg::Fail(id, reason))?)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn log(&self, id: Id, line: String) -> Result<()> { Ok(self.prog.send(TaskProg::Log(id, line))?) }
|
||||
|
||||
#[inline]
|
||||
async fn queue(&self, r#in: impl Into<TaskOp>, priority: u8) -> Result<()> {
|
||||
self.r#macro.send(r#in.into(), priority).await.map_err(|_| anyhow!("Failed to send task"))
|
||||
fn queue(&self, r#in: impl Into<TaskIn>, priority: u8) {
|
||||
_ = self.r#macro.try_send(r#in.into(), priority);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,37 +1,16 @@
|
|||
use yazi_fs::cha::Cha;
|
||||
use yazi_shared::{Id, url::UrlBuf};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum FileIn {
|
||||
Paste(FileInPaste),
|
||||
Link(FileInLink),
|
||||
Hardlink(FileInHardlink),
|
||||
Delete(FileInDelete),
|
||||
Trash(FileInTrash),
|
||||
}
|
||||
|
||||
impl FileIn {
|
||||
pub fn id(&self) -> Id {
|
||||
match self {
|
||||
Self::Paste(r#in) => r#in.id,
|
||||
Self::Link(r#in) => r#in.id,
|
||||
Self::Hardlink(r#in) => r#in.id,
|
||||
Self::Delete(r#in) => r#in.id,
|
||||
Self::Trash(r#in) => r#in.id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Paste
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FileInPaste {
|
||||
pub id: Id,
|
||||
pub from: UrlBuf,
|
||||
pub to: UrlBuf,
|
||||
pub cha: Option<Cha>,
|
||||
pub cut: bool,
|
||||
pub follow: bool,
|
||||
pub retry: u8,
|
||||
pub(crate) struct FileInPaste {
|
||||
pub(crate) id: Id,
|
||||
pub(crate) from: UrlBuf,
|
||||
pub(crate) to: UrlBuf,
|
||||
pub(crate) cha: Option<Cha>,
|
||||
pub(crate) cut: bool,
|
||||
pub(crate) follow: bool,
|
||||
pub(crate) retry: u8,
|
||||
}
|
||||
|
||||
impl FileInPaste {
|
||||
|
|
@ -46,42 +25,40 @@ impl FileInPaste {
|
|||
retry: self.retry,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Link
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FileInLink {
|
||||
pub id: Id,
|
||||
pub from: UrlBuf,
|
||||
pub to: UrlBuf,
|
||||
pub cha: Option<Cha>,
|
||||
pub resolve: bool,
|
||||
pub relative: bool,
|
||||
pub delete: bool,
|
||||
}
|
||||
|
||||
impl From<FileInPaste> for FileInLink {
|
||||
fn from(value: FileInPaste) -> Self {
|
||||
Self {
|
||||
id: value.id,
|
||||
from: value.from,
|
||||
to: value.to,
|
||||
cha: value.cha,
|
||||
pub(super) fn into_link(self) -> FileInLink {
|
||||
FileInLink {
|
||||
id: self.id,
|
||||
from: self.from,
|
||||
to: self.to,
|
||||
cha: self.cha,
|
||||
resolve: true,
|
||||
relative: false,
|
||||
delete: value.cut,
|
||||
delete: self.cut,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Link
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct FileInLink {
|
||||
pub(crate) id: Id,
|
||||
pub(crate) from: UrlBuf,
|
||||
pub(crate) to: UrlBuf,
|
||||
pub(crate) cha: Option<Cha>,
|
||||
pub(crate) resolve: bool,
|
||||
pub(crate) relative: bool,
|
||||
pub(crate) delete: bool,
|
||||
}
|
||||
|
||||
// --- Hardlink
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FileInHardlink {
|
||||
pub id: Id,
|
||||
pub from: UrlBuf,
|
||||
pub to: UrlBuf,
|
||||
pub cha: Option<Cha>,
|
||||
pub follow: bool,
|
||||
pub(crate) struct FileInHardlink {
|
||||
pub(crate) id: Id,
|
||||
pub(crate) from: UrlBuf,
|
||||
pub(crate) to: UrlBuf,
|
||||
pub(crate) cha: Option<Cha>,
|
||||
pub(crate) follow: bool,
|
||||
}
|
||||
|
||||
impl FileInHardlink {
|
||||
|
|
@ -92,16 +69,15 @@ impl FileInHardlink {
|
|||
|
||||
// --- Delete
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FileInDelete {
|
||||
pub id: Id,
|
||||
pub target: UrlBuf,
|
||||
pub length: u64,
|
||||
pub(crate) struct FileInDelete {
|
||||
pub(crate) id: Id,
|
||||
pub(crate) target: UrlBuf,
|
||||
pub(crate) length: u64,
|
||||
}
|
||||
|
||||
// --- Trash
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FileInTrash {
|
||||
pub id: Id,
|
||||
pub target: UrlBuf,
|
||||
pub length: u64,
|
||||
pub(crate) struct FileInTrash {
|
||||
pub(crate) id: Id,
|
||||
pub(crate) target: UrlBuf,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
#![allow(clippy::module_inception)]
|
||||
|
||||
yazi_macro::mod_flat!(file out r#in);
|
||||
yazi_macro::mod_flat!(file out progress r#in);
|
||||
|
|
|
|||
|
|
@ -1,23 +1,250 @@
|
|||
use crate::{Task, TaskProg};
|
||||
|
||||
// --- Paste
|
||||
#[derive(Debug)]
|
||||
pub enum FileOut {
|
||||
Paste(FileOutPaste),
|
||||
Link(FileOutLink),
|
||||
Hardlink(FileOutHardlink),
|
||||
Delete(FileOutDelete),
|
||||
Trash(FileOutTrash),
|
||||
pub(crate) enum FileOutPaste {
|
||||
New(u64),
|
||||
Init,
|
||||
Deform(String),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FileOutPaste;
|
||||
impl From<std::io::Error> for FileOutPaste {
|
||||
fn from(value: std::io::Error) -> Self { Self::Deform(value.to_string()) }
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FileOutLink;
|
||||
impl FileOutPaste {
|
||||
pub(crate) fn reduce(self, task: &mut Task) {
|
||||
let TaskProg::FilePaste(prog) = &mut task.prog else { return };
|
||||
match self {
|
||||
Self::New(bytes) => {
|
||||
prog.total_files += 1;
|
||||
prog.total_bytes += bytes;
|
||||
}
|
||||
Self::Init => {
|
||||
prog.collected = true;
|
||||
}
|
||||
Self::Deform(reason) => {
|
||||
prog.total_files += 1;
|
||||
prog.failed_files += 1;
|
||||
task.log(reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- PasteDo
|
||||
#[derive(Debug)]
|
||||
pub struct FileOutHardlink;
|
||||
pub(crate) enum FileOutPasteDo {
|
||||
Adv(u64),
|
||||
Log(String),
|
||||
Succ,
|
||||
Fail(String),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FileOutDelete;
|
||||
impl From<std::io::Error> for FileOutPasteDo {
|
||||
fn from(value: std::io::Error) -> Self { Self::Fail(value.to_string()) }
|
||||
}
|
||||
|
||||
impl FileOutPasteDo {
|
||||
pub(crate) fn reduce(self, task: &mut Task) {
|
||||
let TaskProg::FilePaste(prog) = &mut task.prog else { return };
|
||||
match self {
|
||||
Self::Adv(size) => {
|
||||
prog.processed_bytes += size;
|
||||
}
|
||||
Self::Log(line) => {
|
||||
task.log(line);
|
||||
}
|
||||
Self::Succ => {
|
||||
prog.success_files += 1;
|
||||
}
|
||||
Self::Fail(reason) => {
|
||||
prog.failed_files += 1;
|
||||
task.log(reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Link
|
||||
#[derive(Debug)]
|
||||
pub struct FileOutTrash;
|
||||
pub(crate) enum FileOutLink {
|
||||
Succ,
|
||||
Fail(String),
|
||||
}
|
||||
|
||||
impl From<anyhow::Error> for FileOutLink {
|
||||
fn from(value: anyhow::Error) -> Self { Self::Fail(value.to_string()) }
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for FileOutLink {
|
||||
fn from(value: std::io::Error) -> Self { Self::Fail(value.to_string()) }
|
||||
}
|
||||
|
||||
impl FileOutLink {
|
||||
pub(crate) fn reduce(self, task: &mut Task) {
|
||||
if let TaskProg::FileLink(prog) = &mut task.prog {
|
||||
match self {
|
||||
Self::Succ => {
|
||||
prog.state = Some(true);
|
||||
}
|
||||
Self::Fail(reason) => {
|
||||
prog.state = Some(false);
|
||||
task.log(reason);
|
||||
}
|
||||
}
|
||||
} else if let TaskProg::FilePaste(prog) = &mut task.prog {
|
||||
match self {
|
||||
Self::Succ => {
|
||||
prog.success_files += 1;
|
||||
}
|
||||
Self::Fail(reason) => {
|
||||
prog.failed_files += 1;
|
||||
task.log(reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Hardlink
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum FileOutHardlink {
|
||||
New,
|
||||
Init,
|
||||
Deform(String),
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for FileOutHardlink {
|
||||
fn from(value: std::io::Error) -> Self { Self::Deform(value.to_string()) }
|
||||
}
|
||||
|
||||
impl FileOutHardlink {
|
||||
pub(crate) fn reduce(self, task: &mut Task) {
|
||||
let TaskProg::FileHardlink(prog) = &mut task.prog else { return };
|
||||
match self {
|
||||
Self::New => {
|
||||
prog.total += 1;
|
||||
}
|
||||
Self::Init => {
|
||||
prog.collected = true;
|
||||
}
|
||||
Self::Deform(reason) => {
|
||||
prog.total += 1;
|
||||
prog.failed += 1;
|
||||
task.log(reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- HardlinkDo
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum FileOutHardlinkDo {
|
||||
Succ,
|
||||
Fail(String),
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for FileOutHardlinkDo {
|
||||
fn from(value: std::io::Error) -> Self { Self::Fail(value.to_string()) }
|
||||
}
|
||||
|
||||
impl FileOutHardlinkDo {
|
||||
pub(crate) fn reduce(self, task: &mut Task) {
|
||||
let TaskProg::FileHardlink(prog) = &mut task.prog else { return };
|
||||
match self {
|
||||
Self::Succ => {
|
||||
prog.success += 1;
|
||||
}
|
||||
Self::Fail(reason) => {
|
||||
prog.failed += 1;
|
||||
task.log(reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Delete
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum FileOutDelete {
|
||||
New(u64),
|
||||
Init,
|
||||
Deform(String),
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for FileOutDelete {
|
||||
fn from(value: std::io::Error) -> Self { Self::Deform(value.to_string()) }
|
||||
}
|
||||
|
||||
impl FileOutDelete {
|
||||
pub(crate) fn reduce(self, task: &mut Task) {
|
||||
let TaskProg::FileDelete(prog) = &mut task.prog else { return };
|
||||
match self {
|
||||
Self::New(size) => {
|
||||
prog.total_files += 1;
|
||||
prog.total_bytes += size;
|
||||
}
|
||||
Self::Init => {
|
||||
prog.collected = true;
|
||||
}
|
||||
Self::Deform(reason) => {
|
||||
prog.total_files += 1;
|
||||
prog.failed_files += 1;
|
||||
task.log(reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- DeleteDo
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum FileOutDeleteDo {
|
||||
Succ(u64),
|
||||
Fail(String),
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for FileOutDeleteDo {
|
||||
fn from(value: std::io::Error) -> Self { Self::Fail(value.to_string()) }
|
||||
}
|
||||
|
||||
impl FileOutDeleteDo {
|
||||
pub(crate) fn reduce(self, task: &mut Task) {
|
||||
let TaskProg::FileDelete(prog) = &mut task.prog else { return };
|
||||
match self {
|
||||
Self::Succ(size) => {
|
||||
prog.success_files += 1;
|
||||
prog.processed_bytes += size;
|
||||
}
|
||||
Self::Fail(reason) => {
|
||||
prog.failed_files += 1;
|
||||
task.log(reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Trash
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum FileOutTrash {
|
||||
Succ,
|
||||
Fail(String),
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for FileOutTrash {
|
||||
fn from(value: std::io::Error) -> Self { Self::Fail(value.to_string()) }
|
||||
}
|
||||
|
||||
impl FileOutTrash {
|
||||
pub(crate) fn reduce(self, task: &mut Task) {
|
||||
let TaskProg::FileTrash(prog) = &mut task.prog else { return };
|
||||
match self {
|
||||
Self::Succ => {
|
||||
prog.state = Some(true);
|
||||
}
|
||||
Self::Fail(reason) => {
|
||||
prog.state = Some(false);
|
||||
task.log(reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue