mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-21 23:01:05 +00:00
refactor: invert the dependency relationship between yazi-fs and yazi-vfs (#3215)
This commit is contained in:
parent
25d5554a9a
commit
7b36b7fe14
83 changed files with 662 additions and 554 deletions
213
Cargo.lock
generated
213
Cargo.lock
generated
|
|
@ -4,9 +4,9 @@ version = 4
|
|||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.24.2"
|
||||
version = "0.25.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
|
||||
checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
|
@ -244,9 +244,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.75"
|
||||
version = "0.3.76"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
|
||||
checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cfg-if",
|
||||
|
|
@ -254,7 +254,7 @@ dependencies = [
|
|||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
"windows-targets 0.52.6",
|
||||
"windows-link 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -459,9 +459,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.38"
|
||||
version = "1.2.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9"
|
||||
checksum = "e1354349954c6fc9cb0deab020f27f783cf0b604e8bb754dc4658ecf0d29c35f"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"jobserver",
|
||||
|
|
@ -1008,7 +1008,7 @@ dependencies = [
|
|||
"libc",
|
||||
"option-ext",
|
||||
"redox_users",
|
||||
"windows-sys 0.61.0",
|
||||
"windows-sys 0.61.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1154,7 +1154,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.61.0",
|
||||
"windows-sys 0.61.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1437,9 +1437,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.31.1"
|
||||
version = "0.32.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||
checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7"
|
||||
|
||||
[[package]]
|
||||
name = "globset"
|
||||
|
|
@ -1561,7 +1561,7 @@ dependencies = [
|
|||
"js-sys",
|
||||
"log",
|
||||
"wasm-bindgen",
|
||||
"windows-core 0.62.0",
|
||||
"windows-core 0.62.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1779,9 +1779,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.80"
|
||||
version = "0.3.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "852f13bec5eba4ba9afbeb93fd7c13fe56147f055939ae21c43a29a0ecb2702e"
|
||||
checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
|
|
@ -1969,9 +1969,9 @@ checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
|
|||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.5"
|
||||
version = "2.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
|
||||
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
|
|
@ -2268,9 +2268,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.7"
|
||||
version = "0.37.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
|
||||
checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
|
@ -2396,10 +2396,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pageant"
|
||||
version = "0.0.3"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bdd27df01428302f915ea74737fe88170dd1bab4cbd00ff9548ca85618fcd4e4"
|
||||
checksum = "bb28bd89a207e5cad59072ac4b364b08459d05f90ccfbcdaa920a95857d94430"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"delegate",
|
||||
"futures",
|
||||
|
|
@ -2407,7 +2408,7 @@ dependencies = [
|
|||
"rand 0.8.5",
|
||||
"thiserror 1.0.69",
|
||||
"tokio",
|
||||
"windows 0.58.0",
|
||||
"windows 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2913,9 +2914,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.11.2"
|
||||
version = "1.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912"
|
||||
checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
|
|
@ -2925,9 +2926,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.10"
|
||||
version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6"
|
||||
checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
|
|
@ -2993,9 +2994,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "russh"
|
||||
version = "0.54.3"
|
||||
version = "0.54.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00897b69ab623d39b396af89f1acbb775fb5a730f0db91833da297d5a6cd3f8d"
|
||||
checksum = "54b1296a0e9d970321e59d77367b8d1511311445f3dd5d42f24e7d9a1706cf51"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"base64ct",
|
||||
|
|
@ -3122,7 +3123,7 @@ dependencies = [
|
|||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.11.0",
|
||||
"windows-sys 0.61.0",
|
||||
"windows-sys 0.61.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3203,9 +3204,9 @@ checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.226"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd"
|
||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
"serde_derive",
|
||||
|
|
@ -3223,18 +3224,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.226"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4"
|
||||
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.226"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33"
|
||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -3502,12 +3503,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syntect"
|
||||
version = "5.2.0"
|
||||
version = "5.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "874dcfa363995604333cf947ae9f751ca3af4522c60886774c4963943b4746b1"
|
||||
checksum = "656b45c05d95a5704399aeef6bd0ddec7b2b3531b7c9e900abbf7c4d2190c925"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"bitflags 1.3.2",
|
||||
"flate2",
|
||||
"fnv",
|
||||
"once_cell",
|
||||
|
|
@ -3517,7 +3517,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror 2.0.16",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
|
|
@ -4065,9 +4065,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.103"
|
||||
version = "0.2.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab10a69fbd0a177f5f649ad4d8d3305499c42bab9aef2f7ff592d0ec8f833819"
|
||||
checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
|
|
@ -4078,9 +4078,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.103"
|
||||
version = "0.2.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bb702423545a6007bbc368fde243ba47ca275e549c8a28617f56f6ba53b1d1c"
|
||||
checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
|
|
@ -4092,9 +4092,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.53"
|
||||
version = "0.4.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0b221ff421256839509adbb55998214a70d829d3a28c69b4a6672e9d2a42f67"
|
||||
checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
|
|
@ -4105,9 +4105,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.103"
|
||||
version = "0.2.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc65f4f411d91494355917b605e1480033152658d71f722a90647f56a70c88a0"
|
||||
checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
|
|
@ -4115,9 +4115,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.103"
|
||||
version = "0.2.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffc003a991398a8ee604a401e194b6b3a39677b3173d6e74495eb51b82e99a32"
|
||||
checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -4128,18 +4128,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.103"
|
||||
version = "0.2.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "293c37f4efa430ca14db3721dfbe48d8c33308096bd44d80ebaa775ab71ba1cf"
|
||||
checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.80"
|
||||
version = "0.3.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbe734895e869dc429d78c4b433f8d17d95f8d05317440b4fad5ab2d33e596dc"
|
||||
checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
|
|
@ -4195,7 +4195,7 @@ version = "0.1.11"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.0",
|
||||
"windows-sys 0.61.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -4216,12 +4216,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.58.0"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6"
|
||||
checksum = "7f919aee0a93304be7f62e8e5027811bbba96bcb1de84d6618be56e43f8a32a1"
|
||||
dependencies = [
|
||||
"windows-core 0.58.0",
|
||||
"windows-targets 0.52.6",
|
||||
"windows-core 0.59.0",
|
||||
"windows-targets 0.53.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -4238,25 +4238,25 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.58.0"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"
|
||||
checksum = "810ce18ed2112484b0d4e15d022e5f598113e220c53e373fb31e67e21670c1ce"
|
||||
dependencies = [
|
||||
"windows-implement 0.58.0",
|
||||
"windows-interface 0.58.0",
|
||||
"windows-result 0.2.0",
|
||||
"windows-strings 0.1.0",
|
||||
"windows-targets 0.52.6",
|
||||
"windows-implement 0.59.0",
|
||||
"windows-interface 0.59.2",
|
||||
"windows-result 0.3.4",
|
||||
"windows-strings 0.3.1",
|
||||
"windows-targets 0.53.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.62.0"
|
||||
version = "0.62.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57fe7168f7de578d2d8a05b07fd61870d2e73b4020e9f49aa00da8471723497c"
|
||||
checksum = "6844ee5416b285084d3d3fffd743b925a6c9385455f64f6d4fa3031c4c2749a9"
|
||||
dependencies = [
|
||||
"windows-implement 0.60.0",
|
||||
"windows-interface 0.59.1",
|
||||
"windows-implement 0.60.1",
|
||||
"windows-interface 0.59.2",
|
||||
"windows-link 0.2.0",
|
||||
"windows-result 0.4.0",
|
||||
"windows-strings 0.5.0",
|
||||
|
|
@ -4275,9 +4275,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.58.0"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
|
||||
checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -4286,9 +4286,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.60.0"
|
||||
version = "0.60.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
|
||||
checksum = "edb307e42a74fb6de9bf3a02d9712678b22399c87e6fa869d6dfcd8c1b7754e0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -4308,20 +4308,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.58.0"
|
||||
version = "0.59.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.59.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
|
||||
checksum = "c0abd1ddbc6964ac14db11c7213d6532ef34bd9aa042c2e5935f59d7908b46a5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -4351,11 +4340,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.2.0"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
|
||||
checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
"windows-link 0.1.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -4369,12 +4358,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.1.0"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
|
||||
checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319"
|
||||
dependencies = [
|
||||
"windows-result 0.2.0",
|
||||
"windows-targets 0.52.6",
|
||||
"windows-link 0.1.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -4410,14 +4398,14 @@ version = "0.60.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
|
||||
dependencies = [
|
||||
"windows-targets 0.53.3",
|
||||
"windows-targets 0.53.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.61.0"
|
||||
version = "0.61.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa"
|
||||
checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f"
|
||||
dependencies = [
|
||||
"windows-link 0.2.0",
|
||||
]
|
||||
|
|
@ -4440,11 +4428,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.53.3"
|
||||
version = "0.53.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91"
|
||||
checksum = "2d42b7b7f66d2a06854650af09cfdf8713e427a439c97ad65a6375318033ac4b"
|
||||
dependencies = [
|
||||
"windows-link 0.1.3",
|
||||
"windows-link 0.2.0",
|
||||
"windows_aarch64_gnullvm 0.53.0",
|
||||
"windows_aarch64_msvc 0.53.0",
|
||||
"windows_i686_gnu 0.53.0",
|
||||
|
|
@ -4609,6 +4597,7 @@ dependencies = [
|
|||
"yazi-scheduler",
|
||||
"yazi-shared",
|
||||
"yazi-term",
|
||||
"yazi-vfs",
|
||||
"yazi-watcher",
|
||||
"yazi-widgets",
|
||||
]
|
||||
|
|
@ -4704,7 +4693,6 @@ dependencies = [
|
|||
"yazi-fs",
|
||||
"yazi-macro",
|
||||
"yazi-shared",
|
||||
"yazi-vfs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -4736,7 +4724,6 @@ dependencies = [
|
|||
"yazi-macro",
|
||||
"yazi-shared",
|
||||
"yazi-term",
|
||||
"yazi-vfs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -4764,6 +4751,7 @@ dependencies = [
|
|||
"yazi-proxy",
|
||||
"yazi-scheduler",
|
||||
"yazi-shared",
|
||||
"yazi-vfs",
|
||||
"yazi-watcher",
|
||||
"yazi-widgets",
|
||||
]
|
||||
|
|
@ -4853,16 +4841,13 @@ dependencies = [
|
|||
"arc-swap",
|
||||
"bitflags 2.9.4",
|
||||
"core-foundation-sys",
|
||||
"deadpool",
|
||||
"dirs",
|
||||
"foldhash 0.2.0",
|
||||
"futures",
|
||||
"hashbrown 0.16.0",
|
||||
"libc",
|
||||
"objc",
|
||||
"parking_lot",
|
||||
"regex",
|
||||
"russh",
|
||||
"scopeguard",
|
||||
"serde",
|
||||
"tokio",
|
||||
|
|
@ -4870,12 +4855,10 @@ dependencies = [
|
|||
"trash",
|
||||
"twox-hash",
|
||||
"uzers",
|
||||
"windows-sys 0.61.0",
|
||||
"windows-sys 0.61.1",
|
||||
"yazi-ffi",
|
||||
"yazi-macro",
|
||||
"yazi-sftp",
|
||||
"yazi-shared",
|
||||
"yazi-vfs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -4928,7 +4911,7 @@ dependencies = [
|
|||
"twox-hash",
|
||||
"unicode-width 0.2.0",
|
||||
"uzers",
|
||||
"windows-sys 0.61.0",
|
||||
"windows-sys 0.61.1",
|
||||
"yazi-adapter",
|
||||
"yazi-binding",
|
||||
"yazi-boot",
|
||||
|
|
@ -4940,6 +4923,7 @@ dependencies = [
|
|||
"yazi-prebuilt",
|
||||
"yazi-proxy",
|
||||
"yazi-shared",
|
||||
"yazi-vfs",
|
||||
"yazi-widgets",
|
||||
]
|
||||
|
||||
|
|
@ -4987,6 +4971,7 @@ dependencies = [
|
|||
"yazi-plugin",
|
||||
"yazi-proxy",
|
||||
"yazi-shared",
|
||||
"yazi-vfs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5018,7 +5003,7 @@ dependencies = [
|
|||
"serde",
|
||||
"tokio",
|
||||
"uzers",
|
||||
"windows-sys 0.61.0",
|
||||
"windows-sys 0.61.1",
|
||||
"yazi-macro",
|
||||
]
|
||||
|
||||
|
|
@ -5030,7 +5015,7 @@ dependencies = [
|
|||
"libc",
|
||||
"parking_lot",
|
||||
"tracing",
|
||||
"windows-sys 0.61.0",
|
||||
"windows-sys 0.61.1",
|
||||
"yazi-macro",
|
||||
"yazi-shared",
|
||||
]
|
||||
|
|
@ -5039,13 +5024,20 @@ dependencies = [
|
|||
name = "yazi-vfs"
|
||||
version = "25.9.15"
|
||||
dependencies = [
|
||||
"dirs",
|
||||
"anyhow",
|
||||
"deadpool",
|
||||
"futures",
|
||||
"hashbrown 0.16.0",
|
||||
"parking_lot",
|
||||
"russh",
|
||||
"serde",
|
||||
"tokio",
|
||||
"toml 0.9.7",
|
||||
"tracing",
|
||||
"uzers",
|
||||
"yazi-fs",
|
||||
"yazi-macro",
|
||||
"yazi-sftp",
|
||||
"yazi-shared",
|
||||
]
|
||||
|
||||
|
|
@ -5065,6 +5057,7 @@ dependencies = [
|
|||
"yazi-fs",
|
||||
"yazi-macro",
|
||||
"yazi-shared",
|
||||
"yazi-vfs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -41,12 +41,12 @@ ordered-float = { version = "5.0.0", features = [ "serde" ] }
|
|||
parking_lot = "0.12.4"
|
||||
paste = "1.0.15"
|
||||
ratatui = { version = "0.29.0", features = [ "unstable-rendered-line-info", "unstable-widget-ref" ] }
|
||||
regex = "1.11.2"
|
||||
russh = { version = "0.54.3", default-features = false, features = [ "ring", "rsa" ] }
|
||||
regex = "1.11.3"
|
||||
russh = { version = "0.54.4", default-features = false, features = [ "ring", "rsa" ] }
|
||||
scopeguard = "1.2.0"
|
||||
serde = { version = "1.0.226", features = [ "derive" ] }
|
||||
serde = { version = "1.0.228", features = [ "derive" ] }
|
||||
serde_json = "1.0.145"
|
||||
syntect = { version = "5.2.0", default-features = false, features = [ "parsing", "plist-load", "regex-onig" ] }
|
||||
syntect = { version = "5.3.0", default-features = false, features = [ "parsing", "plist-load", "regex-onig" ] }
|
||||
tokio = { version = "1.47.1", features = [ "full" ] }
|
||||
tokio-stream = "0.1.17"
|
||||
tokio-util = "0.7.16"
|
||||
|
|
|
|||
38
README.md
38
README.md
|
|
@ -52,25 +52,25 @@ Yazi is currently in heavy development, expect breaking changes.
|
|||
|
||||
## Image Preview
|
||||
|
||||
| Platform | Protocol | Support |
|
||||
| ---------------------------------------------------------------------------- | -------------------------------------- | --------------------------------- |
|
||||
| [kitty](https://github.com/kovidgoyal/kitty) (>= 0.28.0) | [Kitty unicode placeholders][kgp] | ✅ Built-in |
|
||||
| [iTerm2](https://iterm2.com) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [WezTerm](https://github.com/wez/wezterm) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [Konsole](https://invent.kde.org/utilities/konsole) | [Kitty old protocol][kgp-old] | ✅ Built-in |
|
||||
| [foot](https://codeberg.org/dnkl/foot) | [Sixel graphics format][sixel] | ✅ Built-in |
|
||||
| [Ghostty](https://github.com/ghostty-org/ghostty) | [Kitty unicode placeholders][kgp] | ✅ Built-in |
|
||||
| [Windows Terminal](https://github.com/microsoft/terminal) (>= v1.22.10352.0) | [Sixel graphics format][sixel] | ✅ Built-in |
|
||||
| [st with Sixel patch](https://github.com/bakkeby/st-flexipatch) | [Sixel graphics format][sixel] | ✅ Built-in |
|
||||
| [Warp](https://www.warp.dev) (macOS/Linux only) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [Tabby](https://github.com/Eugeny/tabby) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [VSCode](https://github.com/microsoft/vscode) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [Rio](https://github.com/raphamorim/rio) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [Black Box](https://gitlab.gnome.org/raggesilver/blackbox) | [Sixel graphics format][sixel] | ✅ Built-in |
|
||||
| [Hyper](https://github.com/vercel/hyper) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [Bobcat](https://github.com/ismail-yilmaz/Bobcat) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| X11 / Wayland | Window system protocol | ☑️ [Überzug++][ueberzug] required |
|
||||
| Fallback | [ASCII art (Unicode block)][ascii-art] | ☑️ [Chafa][chafa] required |
|
||||
| Platform | Protocol | Support |
|
||||
| ---------------------------------------------------------------------------- | -------------------------------------- | ---------------------------------------- |
|
||||
| [kitty](https://github.com/kovidgoyal/kitty) (>= 0.28.0) | [Kitty unicode placeholders][kgp] | ✅ Built-in |
|
||||
| [iTerm2](https://iterm2.com) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [WezTerm](https://github.com/wez/wezterm) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [Konsole](https://invent.kde.org/utilities/konsole) | [Kitty old protocol][kgp-old] | ✅ Built-in |
|
||||
| [foot](https://codeberg.org/dnkl/foot) | [Sixel graphics format][sixel] | ✅ Built-in |
|
||||
| [Ghostty](https://github.com/ghostty-org/ghostty) | [Kitty unicode placeholders][kgp] | ✅ Built-in |
|
||||
| [Windows Terminal](https://github.com/microsoft/terminal) (>= v1.22.10352.0) | [Sixel graphics format][sixel] | ✅ Built-in |
|
||||
| [st with Sixel patch](https://github.com/bakkeby/st-flexipatch) | [Sixel graphics format][sixel] | ✅ Built-in |
|
||||
| [Warp](https://www.warp.dev) (macOS/Linux only) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [Tabby](https://github.com/Eugeny/tabby) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [VSCode](https://github.com/microsoft/vscode) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [Rio](https://github.com/raphamorim/rio) | [Inline images protocol][iip] | ❌ Rio renders images at incorrect sizes |
|
||||
| [Black Box](https://gitlab.gnome.org/raggesilver/blackbox) | [Sixel graphics format][sixel] | ✅ Built-in |
|
||||
| [Hyper](https://github.com/vercel/hyper) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| [Bobcat](https://github.com/ismail-yilmaz/Bobcat) | [Inline images protocol][iip] | ✅ Built-in |
|
||||
| X11 / Wayland | Window system protocol | ☑️ [Überzug++][ueberzug] required |
|
||||
| Fallback | [ASCII art (Unicode block)][ascii-art] | ☑️ [Chafa][chafa] required |
|
||||
|
||||
See https://yazi-rs.github.io/docs/image-preview for details.
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ yazi-proxy = { path = "../yazi-proxy", version = "25.9.15" }
|
|||
yazi-scheduler = { path = "../yazi-scheduler", version = "25.9.15" }
|
||||
yazi-shared = { path = "../yazi-shared", version = "25.9.15" }
|
||||
yazi-term = { path = "../yazi-term", version = "25.9.15" }
|
||||
yazi-vfs = { path = "../yazi-vfs", version = "25.9.15" }
|
||||
yazi-watcher = { path = "../yazi-watcher", version = "25.9.15" }
|
||||
yazi-widgets = { path = "../yazi-widgets", version = "25.9.15" }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
use std::{ffi::OsString, mem, path::MAIN_SEPARATOR_STR};
|
||||
|
||||
use anyhow::Result;
|
||||
use yazi_fs::{CWD, path::expand_url, provider::{self, DirReader, FileHolder}};
|
||||
use yazi_fs::{CWD, path::expand_url, provider::{DirReader, FileHolder}};
|
||||
use yazi_macro::{act, render, succ};
|
||||
use yazi_parser::cmp::{CmpItem, ShowOpt, TriggerOpt};
|
||||
use yazi_proxy::CmpProxy;
|
||||
use yazi_shared::{OsStrSplit, event::Data, natsort, url::{UrlBuf, UrlCow, UrnBuf}};
|
||||
use yazi_vfs::provider;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
|
|
|
|||
|
|
@ -7,12 +7,13 @@ use scopeguard::defer;
|
|||
use tokio::io::AsyncWriteExt;
|
||||
use yazi_config::{YAZI, opener::OpenerRule};
|
||||
use yazi_dds::Pubsub;
|
||||
use yazi_fs::{File, FilesOp, max_common_root, maybe_exists, path::skip_url, provider::{self, FileBuilder, Provider, local::{Gate, Local}}};
|
||||
use yazi_fs::{File, FilesOp, max_common_root, path::skip_url, provider::{FileBuilder, Provider, local::{Gate, Local}}};
|
||||
use yazi_macro::{err, succ};
|
||||
use yazi_parser::VoidOpt;
|
||||
use yazi_proxy::{AppProxy, HIDER, TasksProxy};
|
||||
use yazi_shared::{OsStrJoin, event::Data, terminal_clear, url::{Component, UrlBuf}};
|
||||
use yazi_term::tty::TTY;
|
||||
use yazi_vfs::{VfsFile, maybe_exists, provider};
|
||||
use yazi_watcher::WATCHER;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use yazi_macro::{act, err, render, succ};
|
|||
use yazi_parser::mgr::CdOpt;
|
||||
use yazi_proxy::{CmpProxy, InputProxy, MgrProxy};
|
||||
use yazi_shared::{Debounce, errors::InputError, event::Data, url::UrlBuf};
|
||||
use yazi_vfs::VfsFile;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
use anyhow::{Result, bail};
|
||||
use yazi_config::popup::{ConfirmCfg, InputCfg};
|
||||
use yazi_fs::{File, FilesOp, maybe_exists, ok_or_not_found, provider};
|
||||
use yazi_fs::{File, FilesOp, ok_or_not_found};
|
||||
use yazi_macro::succ;
|
||||
use yazi_parser::mgr::CreateOpt;
|
||||
use yazi_proxy::{ConfirmProxy, InputProxy, MgrProxy};
|
||||
use yazi_shared::{event::Data, url::UrlBuf};
|
||||
use yazi_vfs::{VfsFile, maybe_exists, provider};
|
||||
use yazi_watcher::WATCHER;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use yazi_macro::{act, succ};
|
|||
use yazi_parser::mgr::{OpenDoOpt, OpenOpt};
|
||||
use yazi_proxy::{MgrProxy, PickProxy, TasksProxy};
|
||||
use yazi_shared::{MIME_DIR, event::Data, url::UrlBuf};
|
||||
use yazi_vfs::VfsFile;
|
||||
|
||||
use crate::{Actor, Ctx, mgr::Quit};
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use yazi_macro::{act, succ};
|
|||
use yazi_parser::VoidOpt;
|
||||
use yazi_shared::{event::Data, url::UrlBuf};
|
||||
use yazi_term::tty::TTY;
|
||||
use yazi_vfs::{VfsFiles, VfsFilesOp};
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
use anyhow::Result;
|
||||
use yazi_config::popup::{ConfirmCfg, InputCfg};
|
||||
use yazi_dds::Pubsub;
|
||||
use yazi_fs::{File, FilesOp, maybe_exists, ok_or_not_found, provider};
|
||||
use yazi_fs::{File, FilesOp, ok_or_not_found};
|
||||
use yazi_macro::{act, err, succ};
|
||||
use yazi_parser::mgr::RenameOpt;
|
||||
use yazi_proxy::{ConfirmProxy, InputProxy, MgrProxy};
|
||||
use yazi_shared::{Id, event::Data, url::UrlBuf};
|
||||
use yazi_vfs::{VfsFile, maybe_exists, provider};
|
||||
use yazi_watcher::WATCHER;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
|
|
|||
|
|
@ -156,9 +156,10 @@ macro_rules! impl_file_fields {
|
|||
$crate::cached_field!($fields, name, |lua, me| {
|
||||
me.name().map(|s| lua.create_string(s.as_encoded_bytes())).transpose()
|
||||
});
|
||||
$crate::cached_field!($fields, cache, |_, me| Ok(
|
||||
yazi_fs::provider::cache(&me.url).map($crate::Url::new)
|
||||
));
|
||||
$crate::cached_field!($fields, cache, |_, me| {
|
||||
use yazi_fs::FsUrl;
|
||||
Ok(me.url.cache().map($crate::Url::new))
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use yazi_config::YAZI;
|
||||
use yazi_vfs::local::Xdg;
|
||||
use yazi_fs::Xdg;
|
||||
|
||||
use super::Actions;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ use std::path::PathBuf;
|
|||
use futures::executor::block_on;
|
||||
use hashbrown::HashSet;
|
||||
use serde::Serialize;
|
||||
use yazi_fs::{CWD, path::expand_url, provider};
|
||||
use yazi_fs::{CWD, Xdg, path::expand_url};
|
||||
use yazi_shared::url::{UrlBuf, UrlCow, UrnBuf};
|
||||
use yazi_vfs::local::Xdg;
|
||||
use yazi_vfs::provider;
|
||||
|
||||
#[derive(Debug, Default, Serialize)]
|
||||
pub struct Boot {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ yazi-dds = { path = "../yazi-dds", version = "25.9.15" }
|
|||
yazi-fs = { path = "../yazi-fs", version = "25.9.15" }
|
||||
yazi-macro = { path = "../yazi-macro", version = "25.9.15" }
|
||||
yazi-shared = { path = "../yazi-shared", version = "25.9.15" }
|
||||
yazi-vfs = { path = "../yazi-vfs", version = "25.9.15" }
|
||||
|
||||
# External dependencies
|
||||
anyhow = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use anyhow::{Context, Result};
|
||||
use yazi_fs::{ok_or_not_found, provider::{DirReader, FileHolder, Provider, local::Local}, remove_dir_clean};
|
||||
use yazi_fs::{ok_or_not_found, provider::{DirReader, FileHolder, Provider, local::Local}};
|
||||
use yazi_macro::outln;
|
||||
|
||||
use super::Dependency;
|
||||
|
|
@ -35,7 +35,7 @@ impl Dependency {
|
|||
Err(e) => Err(e).context(format!("failed to read `{}`", assets.display()))?,
|
||||
};
|
||||
|
||||
remove_dir_clean(&assets.into()).await;
|
||||
Local.remove_dir_clean(assets).await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,8 @@ use std::{io::BufWriter, path::{Path, PathBuf}, str::FromStr};
|
|||
use anyhow::{Result, bail};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use twox_hash::XxHash3_128;
|
||||
use yazi_fs::provider::{DirReader, FileHolder, Provider, local::Local};
|
||||
use yazi_fs::{Xdg, provider::{DirReader, FileHolder, Provider, local::Local}};
|
||||
use yazi_shared::BytesExt;
|
||||
use yazi_vfs::local::Xdg;
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub(crate) struct Dependency {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::path::{Path, PathBuf};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use yazi_fs::{provider::{DirReader, FileHolder, Provider, local::Local}, remove_dir_clean};
|
||||
use yazi_fs::provider::{DirReader, FileHolder, Provider, local::Local};
|
||||
use yazi_macro::outln;
|
||||
|
||||
use super::Dependency;
|
||||
|
|
@ -30,7 +30,7 @@ impl Dependency {
|
|||
self.delete_sources().await?;
|
||||
}
|
||||
|
||||
remove_dir_clean(&to.into()).await;
|
||||
Local.remove_dir_clean(to).await;
|
||||
self.hash = self.hash().await?;
|
||||
res2?;
|
||||
res1?;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
yazi_macro::mod_flat!(add delete dependency deploy git hash install package upgrade);
|
||||
|
||||
use anyhow::Context;
|
||||
use yazi_vfs::local::Xdg;
|
||||
use yazi_fs::Xdg;
|
||||
|
||||
pub(super) fn init() -> anyhow::Result<()> {
|
||||
let root = Xdg::state_dir().join("packages");
|
||||
|
|
|
|||
|
|
@ -2,9 +2,8 @@ use std::{path::PathBuf, str::FromStr};
|
|||
|
||||
use anyhow::{Context, Result, bail};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use yazi_fs::provider::{Provider, local::Local};
|
||||
use yazi_fs::{Xdg, provider::{Provider, local::Local}};
|
||||
use yazi_macro::outln;
|
||||
use yazi_vfs::local::Xdg;
|
||||
|
||||
use super::Dependency;
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ yazi-fs = { path = "../yazi-fs", version = "25.9.15" }
|
|||
yazi-macro = { path = "../yazi-macro", version = "25.9.15" }
|
||||
yazi-shared = { path = "../yazi-shared", version = "25.9.15" }
|
||||
yazi-term = { path = "../yazi-term", version = "25.9.15" }
|
||||
yazi-vfs = { path = "../yazi-vfs", version = "25.9.15" }
|
||||
|
||||
# External dependencies
|
||||
anyhow = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
use anyhow::{Context, Result};
|
||||
use serde::Deserialize;
|
||||
use yazi_codegen::DeserializeOver1;
|
||||
use yazi_fs::ok_or_not_found;
|
||||
use yazi_fs::{Xdg, ok_or_not_found};
|
||||
use yazi_shared::Layer;
|
||||
use yazi_vfs::local::Xdg;
|
||||
|
||||
use super::{Chord, KeymapRules};
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,8 @@ use std::{borrow::Cow, path::PathBuf};
|
|||
use anyhow::{Context, Result, bail};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use yazi_codegen::DeserializeOver2;
|
||||
use yazi_fs::path::expand_url;
|
||||
use yazi_fs::{Xdg, path::expand_url};
|
||||
use yazi_shared::{SStr, timestamp_us, url::Url};
|
||||
use yazi_vfs::local::Xdg;
|
||||
|
||||
use super::PreviewWrap;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use anyhow::{Context, Result};
|
|||
use serde::{Deserialize, Serialize};
|
||||
use toml::Value;
|
||||
use yazi_codegen::DeserializeOver2;
|
||||
use yazi_vfs::local::Xdg;
|
||||
use yazi_fs::Xdg;
|
||||
|
||||
#[derive(Default, Deserialize, DeserializeOver2, Serialize)]
|
||||
pub struct Flavor {
|
||||
|
|
|
|||
|
|
@ -3,9 +3,8 @@ use std::path::PathBuf;
|
|||
use anyhow::{Context, Result, anyhow, bail};
|
||||
use serde::Deserialize;
|
||||
use yazi_codegen::{DeserializeOver1, DeserializeOver2};
|
||||
use yazi_fs::{ok_or_not_found, path::expand_url};
|
||||
use yazi_fs::{Xdg, ok_or_not_found, path::expand_url};
|
||||
use yazi_shared::url::UrlBuf;
|
||||
use yazi_vfs::local::Xdg;
|
||||
|
||||
use super::{Filetype, Flavor, Icon};
|
||||
use crate::Style;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
use anyhow::{Context, Result};
|
||||
use serde::Deserialize;
|
||||
use yazi_codegen::DeserializeOver1;
|
||||
use yazi_fs::ok_or_not_found;
|
||||
use yazi_vfs::local::Xdg;
|
||||
use yazi_fs::{Xdg, ok_or_not_found};
|
||||
|
||||
use crate::{mgr, open, opener, plugin, popup, preview, tasks, which};
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ yazi-plugin = { path = "../yazi-plugin", version = "25.9.15" }
|
|||
yazi-proxy = { path = "../yazi-proxy", version = "25.9.15" }
|
||||
yazi-scheduler = { path = "../yazi-scheduler", version = "25.9.15" }
|
||||
yazi-shared = { path = "../yazi-shared", version = "25.9.15" }
|
||||
yazi-vfs = { path = "../yazi-vfs", version = "25.9.15" }
|
||||
yazi-watcher = { path = "../yazi-watcher", version = "25.9.15" }
|
||||
yazi-widgets = { path = "../yazi-widgets", version = "25.9.15" }
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use yazi_macro::render;
|
|||
use yazi_parser::mgr::PreviewLock;
|
||||
use yazi_plugin::{external::Highlighter, isolate};
|
||||
use yazi_shared::{MIME_DIR, pool::{InternStr, Symbol}, url::UrlBuf};
|
||||
use yazi_vfs::{VfsFiles, VfsFilesOp};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Preview {
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ use anyhow::Context;
|
|||
use crossterm::style::{Color, Print, ResetColor, SetForegroundColor};
|
||||
use tracing_appender::non_blocking::WorkerGuard;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
use yazi_fs::Xdg;
|
||||
use yazi_shared::{LOG_LEVEL, RoCell};
|
||||
use yazi_vfs::local::Xdg;
|
||||
|
||||
static _GUARD: RoCell<WorkerGuard> = RoCell::new();
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ async fn main() -> anyhow::Result<()> {
|
|||
|
||||
yazi_config::init()?;
|
||||
|
||||
yazi_vfs::init();
|
||||
|
||||
yazi_adapter::init()?;
|
||||
|
||||
yazi_boot::init();
|
||||
|
|
|
|||
|
|
@ -11,22 +11,17 @@ repository = "https://github.com/sxyazi/yazi"
|
|||
[dependencies]
|
||||
yazi-ffi = { path = "../yazi-ffi", version = "25.9.15" }
|
||||
yazi-macro = { path = "../yazi-macro", version = "25.9.15" }
|
||||
yazi-sftp = { path = "../yazi-sftp", version = "0.1.0" }
|
||||
yazi-shared = { path = "../yazi-shared", version = "25.9.15" }
|
||||
yazi-vfs = { path = "../yazi-vfs", version = "25.9.15" }
|
||||
|
||||
# External dependencies
|
||||
anyhow = { workspace = true }
|
||||
arc-swap = "1.7.1"
|
||||
bitflags = { workspace = true }
|
||||
deadpool = { version = "0.12.3", default-features = false, features = [ "managed", "rt_tokio_1" ] }
|
||||
dirs = { workspace = true }
|
||||
foldhash = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
hashbrown = { workspace = true }
|
||||
parking_lot = { workspace = true }
|
||||
regex = { workspace = true }
|
||||
russh = { workspace = true }
|
||||
scopeguard = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
|
|
@ -38,7 +33,7 @@ libc = { workspace = true }
|
|||
uzers = { workspace = true }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
windows-sys = { version = "0.61.0", features = [ "Win32_Storage_FileSystem" ] }
|
||||
windows-sys = { version = "0.61.1", features = [ "Win32_Storage_FileSystem" ] }
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
core-foundation-sys = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use yazi_macro::{unix_either, win_either};
|
|||
use yazi_shared::url::Url;
|
||||
|
||||
use super::ChaKind;
|
||||
use crate::{cha::{ChaMode, ChaType}, provider};
|
||||
use crate::cha::{ChaMode, ChaType};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct Cha {
|
||||
|
|
@ -52,27 +52,6 @@ impl Cha {
|
|||
Self::from_bare(&meta).attach(ChaKind::hidden(name, &meta))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
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<'a, U>(url: U, mut cha: Self) -> Self
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
{
|
||||
let url: Url = url.into();
|
||||
let mut retain = cha.kind & (ChaKind::HIDDEN | ChaKind::SYSTEM);
|
||||
|
||||
if cha.is_link() {
|
||||
retain |= ChaKind::FOLLOW;
|
||||
cha = provider::metadata(url).await.unwrap_or(cha);
|
||||
}
|
||||
|
||||
cha.attach(retain)
|
||||
}
|
||||
|
||||
pub fn from_dummy<'a, U>(_url: U, r#type: Option<ChaType>) -> Self
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
|
|
@ -140,7 +119,7 @@ impl Cha {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn attach(mut self, kind: ChaKind) -> Self {
|
||||
pub fn attach(mut self, kind: ChaKind) -> Self {
|
||||
self.kind |= kind;
|
||||
self
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::{env::{current_dir, set_current_dir}, ops::Deref, path::PathBuf, sync::
|
|||
use arc_swap::ArcSwap;
|
||||
use yazi_shared::{RoCell, url::UrlBuf};
|
||||
|
||||
use crate::provider;
|
||||
use crate::FsUrl;
|
||||
|
||||
pub static CWD: RoCell<Cwd> = RoCell::new();
|
||||
|
||||
|
|
@ -30,7 +30,7 @@ impl Default for Cwd {
|
|||
impl Cwd {
|
||||
pub fn path(&self) -> PathBuf {
|
||||
let url = self.0.load();
|
||||
provider::cache(url.as_ref()).unwrap_or_else(|| url.loc.to_path())
|
||||
url.cache().unwrap_or_else(|| url.loc.to_path())
|
||||
}
|
||||
|
||||
pub fn set(&self, url: &UrlBuf) -> bool {
|
||||
|
|
@ -71,7 +71,7 @@ impl Cwd {
|
|||
|
||||
fn ensure_cache(&self) -> PathBuf {
|
||||
let url = self.0.load();
|
||||
if let Some(p) = provider::cache(url.as_ref()) {
|
||||
if let Some(p) = url.cache() {
|
||||
std::fs::create_dir_all(&p).ok();
|
||||
p
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
use std::{ffi::OsStr, hash::{BuildHasher, Hash, Hasher}, ops::Deref, path::{Path, PathBuf}};
|
||||
|
||||
use anyhow::Result;
|
||||
use yazi_shared::url::{Uri, UrlBuf, UrlCow, Urn};
|
||||
use yazi_shared::url::{Uri, UrlBuf, Urn};
|
||||
|
||||
use crate::{cha::{Cha, ChaType}, provider};
|
||||
use crate::cha::{Cha, ChaType};
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct File {
|
||||
|
|
@ -19,22 +18,6 @@ impl Deref for File {
|
|||
}
|
||||
|
||||
impl File {
|
||||
#[inline]
|
||||
pub async fn new(url: impl Into<UrlCow<'_>>) -> Result<Self> {
|
||||
let url = url.into();
|
||||
let cha = provider::symlink_metadata(&url).await?;
|
||||
Ok(Self::from_follow(url.into_owned(), cha).await)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn from_follow(url: UrlBuf, cha: Cha) -> Self {
|
||||
let link_to = if cha.is_link() { provider::read_link(&url).await.ok() } else { None };
|
||||
|
||||
let cha = Cha::from_follow(&url, cha).await;
|
||||
|
||||
Self { url, cha, link_to }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_dummy(url: impl Into<UrlBuf>, r#type: Option<ChaType>) -> Self {
|
||||
let url = url.into();
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
use std::{mem, ops::{Deref, DerefMut, Not}};
|
||||
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use tokio::{select, sync::mpsc::{self, UnboundedReceiver}};
|
||||
use yazi_shared::{Id, url::{UrlBuf, Urn, UrnBuf}};
|
||||
use yazi_shared::{Id, url::{Urn, UrnBuf}};
|
||||
|
||||
use super::{FilesSorter, Filter};
|
||||
use crate::{FILES_TICKET, File, FilesOp, SortBy, cha::Cha, mounts::PARTITIONS, provider::{self, DirEntry, DirReader, FileHolder}};
|
||||
use crate::{FILES_TICKET, File, SortBy};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Files {
|
||||
|
|
@ -35,70 +34,6 @@ impl DerefMut for Files {
|
|||
impl Files {
|
||||
pub fn new(show_hidden: bool) -> Self { Self { show_hidden, ..Default::default() } }
|
||||
|
||||
pub async fn from_dir(dir: &UrlBuf) -> std::io::Result<UnboundedReceiver<File>> {
|
||||
let mut it = provider::read_dir(dir).await?;
|
||||
let (tx, rx) = mpsc::unbounded_channel();
|
||||
|
||||
tokio::spawn(async move {
|
||||
while let Ok(Some(ent)) = it.next().await {
|
||||
select! {
|
||||
_ = tx.closed() => break,
|
||||
result = ent.metadata() => {
|
||||
let url = ent.url();
|
||||
_ = tx.send(match result {
|
||||
Ok(cha) => File::from_follow(url, cha).await,
|
||||
Err(_) => File::from_dummy(url, ent.file_type().await.ok())
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
Ok(rx)
|
||||
}
|
||||
|
||||
pub async fn from_dir_bulk(dir: &UrlBuf) -> std::io::Result<Vec<File>> {
|
||||
let mut it = provider::read_dir(dir).await?;
|
||||
let mut entries = Vec::with_capacity(5000);
|
||||
while let Ok(Some(entry)) = it.next().await {
|
||||
entries.push(entry);
|
||||
}
|
||||
|
||||
let (first, rest) = entries.split_at(entries.len() / 3);
|
||||
let (second, third) = rest.split_at(entries.len() / 3);
|
||||
async fn go(entries: &[DirEntry]) -> Vec<File> {
|
||||
let mut files = Vec::with_capacity(entries.len());
|
||||
for ent in entries {
|
||||
let url = ent.url();
|
||||
files.push(match ent.metadata().await {
|
||||
Ok(cha) => File::from_follow(url, cha).await,
|
||||
Err(_) => File::from_dummy(url, ent.file_type().await.ok()),
|
||||
});
|
||||
}
|
||||
files
|
||||
}
|
||||
|
||||
Ok(
|
||||
futures::future::join_all([go(first), go(second), go(third)])
|
||||
.await
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn assert_stale(dir: &UrlBuf, cha: Cha) -> Option<Cha> {
|
||||
use std::io::ErrorKind;
|
||||
match Cha::from_url(dir).await {
|
||||
Ok(c) if !c.is_dir() => FilesOp::issue_error(dir, ErrorKind::NotADirectory).await,
|
||||
Ok(c) if c.hits(cha) && PARTITIONS.read().heuristic(cha) => {}
|
||||
Ok(c) => return Some(c),
|
||||
Err(e) => FilesOp::issue_error(dir, e.kind()).await,
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl Files {
|
||||
pub fn update_full(&mut self, files: Vec<File>) {
|
||||
self.ticket = FILES_TICKET.next();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,21 +1,5 @@
|
|||
use anyhow::Result;
|
||||
use tokio::{io, select, sync::{mpsc, oneshot}, time};
|
||||
use yazi_shared::url::{Component, Url, UrlBuf};
|
||||
|
||||
use crate::{cha::Cha, provider::{self, DirReader, FileHolder}};
|
||||
|
||||
#[inline]
|
||||
pub async fn maybe_exists<'a>(url: impl Into<Url<'a>>) -> bool {
|
||||
match provider::symlink_metadata(url).await {
|
||||
Ok(_) => true,
|
||||
Err(e) => e.kind() != io::ErrorKind::NotFound,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn must_be_dir<'a>(url: impl Into<Url<'a>>) -> bool {
|
||||
provider::metadata(url).await.is_ok_and(|m| m.is_dir())
|
||||
}
|
||||
use tokio::io;
|
||||
use yazi_shared::url::{Component, UrlBuf};
|
||||
|
||||
#[inline]
|
||||
pub fn ok_or_not_found<T: Default>(result: io::Result<T>) -> io::Result<T> {
|
||||
|
|
@ -26,74 +10,6 @@ pub fn ok_or_not_found<T: Default>(result: io::Result<T>) -> io::Result<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn copy_with_progress(
|
||||
from: &UrlBuf,
|
||||
to: &UrlBuf,
|
||||
cha: Cha,
|
||||
) -> mpsc::Receiver<Result<u64, io::Error>> {
|
||||
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 {
|
||||
done_tx.send(provider::copy(&from, &to, cha).await).ok();
|
||||
}
|
||||
});
|
||||
|
||||
tokio::spawn({
|
||||
let (prog_tx, to) = (prog_tx.clone(), to.clone());
|
||||
async move {
|
||||
let mut last = 0;
|
||||
let mut done = None;
|
||||
loop {
|
||||
select! {
|
||||
res = &mut done_rx => done = Some(res.unwrap()),
|
||||
_ = prog_tx.closed() => break,
|
||||
_ = time::sleep(time::Duration::from_secs(3)) => {},
|
||||
}
|
||||
|
||||
match done {
|
||||
Some(Ok(len)) => {
|
||||
if len > last {
|
||||
prog_tx.send(Ok(len - last)).await.ok();
|
||||
}
|
||||
prog_tx.send(Ok(0)).await.ok();
|
||||
break;
|
||||
}
|
||||
Some(Err(e)) => {
|
||||
prog_tx.send(Err(e)).await.ok();
|
||||
break;
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
let len = provider::symlink_metadata(&to).await.map(|m| m.len).unwrap_or(0);
|
||||
if len > last {
|
||||
prog_tx.send(Ok(len - last)).await.ok();
|
||||
last = len;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
prog_rx
|
||||
}
|
||||
|
||||
pub async fn remove_dir_clean(dir: &UrlBuf) {
|
||||
let Ok(mut it) = provider::read_dir(dir).await else { return };
|
||||
|
||||
while let Ok(Some(ent)) = it.next().await {
|
||||
if ent.file_type().await.is_ok_and(|t| t.is_dir()) {
|
||||
let url = ent.url();
|
||||
Box::pin(remove_dir_clean(&url)).await;
|
||||
provider::remove_dir(&url).await.ok();
|
||||
}
|
||||
}
|
||||
|
||||
provider::remove_dir(dir).await.ok();
|
||||
}
|
||||
|
||||
// Find the max common root in a list of urls
|
||||
// e.g. /a/b/c, /a/b/d -> /a/b
|
||||
// /aa/bb/cc, /aa/dd/ee -> /aa
|
||||
|
|
@ -138,7 +54,8 @@ pub fn max_common_root(urls: &[UrlBuf]) -> usize {
|
|||
fn test_max_common_root() {
|
||||
fn assert(input: &[&str], expected: &str) {
|
||||
use std::{ffi::OsStr, str::FromStr};
|
||||
let urls: Vec<_> = input.iter().copied().map(UrlBuf::from_str).collect::<Result<_>>().unwrap();
|
||||
let urls: Vec<_> =
|
||||
input.iter().copied().map(UrlBuf::from_str).collect::<Result<_, _>>().unwrap();
|
||||
|
||||
let mut comp = urls[0].components();
|
||||
for _ in 0..comp.clone().count() - max_common_root(&urls) {
|
||||
|
|
|
|||
|
|
@ -2,12 +2,10 @@
|
|||
|
||||
yazi_macro::mod_pub!(cha mounts provider path);
|
||||
|
||||
yazi_macro::mod_flat!(cwd file files filter fns op sorter sorting stage);
|
||||
yazi_macro::mod_flat!(cwd file files filter fns op sorter sorting stage url xdg);
|
||||
|
||||
pub fn init() {
|
||||
CWD.init(<_>::default());
|
||||
|
||||
mounts::init();
|
||||
|
||||
provider::init();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use yazi_macro::relay;
|
|||
use yazi_shared::{Id, Ids, url::{UrlBuf, UrnBuf}};
|
||||
|
||||
use super::File;
|
||||
use crate::{cha::Cha, maybe_exists};
|
||||
use crate::cha::Cha;
|
||||
|
||||
pub static FILES_TICKET: Ids = Ids::new();
|
||||
|
||||
|
|
@ -121,17 +121,6 @@ impl FilesOp {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn issue_error(cwd: &UrlBuf, kind: std::io::ErrorKind) {
|
||||
use std::io::ErrorKind;
|
||||
if kind != ErrorKind::NotFound {
|
||||
Self::IOErr(cwd.clone(), kind).emit();
|
||||
} else if maybe_exists(cwd).await {
|
||||
Self::IOErr(cwd.clone(), kind).emit();
|
||||
} else if let Some((p, n)) = cwd.pair() {
|
||||
Self::Deleting(p.into(), [n.into()].into()).emit();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn diff_recoverable(&self, contains: impl Fn(&UrlBuf) -> bool) -> (Vec<UrlBuf>, Vec<UrlBuf>) {
|
||||
match self {
|
||||
Self::Deleting(cwd, urns) => (urns.iter().map(|u| cwd.join(u)).collect(), vec![]),
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
use std::{borrow::Cow, ffi::{OsStr, OsString}, future::Future, io};
|
||||
use std::{borrow::Cow, ffi::OsStr};
|
||||
|
||||
use yazi_shared::url::UrlBuf;
|
||||
|
||||
use crate::provider;
|
||||
|
||||
pub fn skip_url(url: &UrlBuf, n: usize) -> Cow<'_, OsStr> {
|
||||
let mut it = url.components();
|
||||
for _ in 0..n {
|
||||
|
|
@ -14,56 +12,9 @@ pub fn skip_url(url: &UrlBuf, n: usize) -> Cow<'_, OsStr> {
|
|||
it.os_str()
|
||||
}
|
||||
|
||||
pub async fn unique_name<F>(u: UrlBuf, append: F) -> io::Result<UrlBuf>
|
||||
where
|
||||
F: Future<Output = bool>,
|
||||
{
|
||||
match provider::symlink_metadata(&u).await {
|
||||
Ok(_) => _unique_name(u, append.await).await,
|
||||
Err(e) if e.kind() == io::ErrorKind::NotFound => Ok(u),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
async fn _unique_name(mut url: UrlBuf, append: bool) -> io::Result<UrlBuf> {
|
||||
let Some(stem) = url.stem().map(|s| s.to_owned()) else {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidInput, "empty file stem"));
|
||||
};
|
||||
|
||||
let dot_ext = url.ext().map_or_else(OsString::new, |e| {
|
||||
let mut s = OsString::with_capacity(e.len() + 1);
|
||||
s.push(".");
|
||||
s.push(e);
|
||||
s
|
||||
});
|
||||
|
||||
let mut i = 1u64;
|
||||
let mut name = OsString::with_capacity(stem.len() + dot_ext.len() + 5);
|
||||
loop {
|
||||
name.clear();
|
||||
name.push(&stem);
|
||||
|
||||
if append {
|
||||
name.push(&dot_ext);
|
||||
name.push(format!("_{i}"));
|
||||
} else {
|
||||
name.push(format!("_{i}"));
|
||||
name.push(&dot_ext);
|
||||
}
|
||||
|
||||
url.set_name(&name);
|
||||
match provider::symlink_metadata(&url).await {
|
||||
Ok(_) => i += 1,
|
||||
Err(e) if e.kind() == io::ErrorKind::NotFound => break,
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(url)
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn backslash_to_slash(p: &std::path::Path) -> Cow<'_, std::path::Path> {
|
||||
use std::{ffi::OsString, path::PathBuf};
|
||||
let bytes = p.as_os_str().as_encoded_bytes();
|
||||
|
||||
// Fast path to skip if there are no backslashes
|
||||
|
|
@ -80,7 +31,7 @@ pub fn backslash_to_slash(p: &std::path::Path) -> Cow<'_, std::path::Path> {
|
|||
for &b in rest {
|
||||
out.push(if b == b'\\' { b'/' } else { b });
|
||||
}
|
||||
Cow::Owned(std::path::PathBuf::from(unsafe { OsString::from_encoded_bytes_unchecked(out) }))
|
||||
Cow::Owned(PathBuf::from(unsafe { OsString::from_encoded_bytes_unchecked(out) }))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@ impl FileBuilder for Gate {
|
|||
self
|
||||
}
|
||||
|
||||
fn cha(&mut self, cha: Cha) -> &mut Self {
|
||||
fn cha(&mut self, _cha: Cha) -> &mut Self {
|
||||
#[cfg(unix)]
|
||||
self.0.mode(cha.mode.bits() as _);
|
||||
self.0.mode(_cha.mode.bits() as _);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::fs::{FileTimes, Permissions};
|
||||
use std::fs::FileTimes;
|
||||
|
||||
use crate::cha::Cha;
|
||||
|
||||
|
|
@ -31,10 +31,10 @@ impl From<Cha> for FileTimes {
|
|||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
impl From<Cha> for Permissions {
|
||||
impl From<Cha> for std::fs::Permissions {
|
||||
fn from(cha: Cha) -> Self {
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
Permissions::from_mode(cha.mode.bits() as _)
|
||||
std::fs::Permissions::from_mode(cha.mode.bits() as _)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
yazi_macro::mod_pub!(local sftp);
|
||||
yazi_macro::mod_pub!(local);
|
||||
|
||||
yazi_macro::mod_flat!(calculator dir_entry gate provider providers read_dir rw_file traits);
|
||||
|
||||
pub fn init() { sftp::init(); }
|
||||
yazi_macro::mod_flat!(traits);
|
||||
|
|
|
|||
|
|
@ -142,6 +142,30 @@ pub trait Provider {
|
|||
}
|
||||
}
|
||||
|
||||
fn remove_dir_clean<P>(&self, root: P) -> impl Future<Output = ()>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let root = root.as_ref().to_path_buf();
|
||||
|
||||
async move {
|
||||
let mut stack = vec![(root, false)];
|
||||
|
||||
while let Some((dir, visited)) = stack.pop() {
|
||||
if visited {
|
||||
self.remove_dir(&dir).await.ok();
|
||||
} else if let Ok(mut it) = self.read_dir(&dir).await {
|
||||
stack.push((dir, true));
|
||||
while let Ok(Some(ent)) = it.next().await {
|
||||
if ent.file_type().await.is_ok_and(|t| t.is_dir()) {
|
||||
stack.push((ent.path(), false));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_file<P>(&self, path: P) -> impl Future<Output = io::Result<()>>
|
||||
where
|
||||
P: AsRef<Path>;
|
||||
|
|
|
|||
32
yazi-fs/src/url.rs
Normal file
32
yazi-fs/src/url.rs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use twox_hash::XxHash3_128;
|
||||
use yazi_shared::{scheme::SchemeRef, url::{Url, UrlBuf}};
|
||||
|
||||
use crate::Xdg;
|
||||
|
||||
pub trait FsUrl {
|
||||
fn cache(&self) -> Option<PathBuf>;
|
||||
}
|
||||
|
||||
impl FsUrl for Url<'_> {
|
||||
fn cache(&self) -> Option<PathBuf> {
|
||||
match self.scheme {
|
||||
SchemeRef::Regular | SchemeRef::Search(_) => None,
|
||||
SchemeRef::Archive(name) => Some(
|
||||
Xdg::cache_dir()
|
||||
.join(format!("archive-{}", yazi_shared::url::Encode::domain(name)))
|
||||
.join(format!("{:x}", XxHash3_128::oneshot(self.loc.bytes()))),
|
||||
),
|
||||
SchemeRef::Sftp(name) => Some(
|
||||
Xdg::cache_dir()
|
||||
.join(format!("sftp-{}", yazi_shared::url::Encode::domain(name)))
|
||||
.join(format!("{:x}", XxHash3_128::oneshot(self.loc.bytes()))),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FsUrl for UrlBuf {
|
||||
fn cache(&self) -> Option<PathBuf> { self.as_url().cache() }
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@ yazi-macro = { path = "../yazi-macro", version = "25.9.15" }
|
|||
yazi-parser = { path = "../yazi-parser", version = "25.9.15" }
|
||||
yazi-proxy = { path = "../yazi-proxy", version = "25.9.15" }
|
||||
yazi-shared = { path = "../yazi-shared", version = "25.9.15" }
|
||||
yazi-vfs = { path = "../yazi-vfs", version = "25.9.15" }
|
||||
yazi-widgets = { path = "../yazi-widgets", version = "25.9.15" }
|
||||
|
||||
# External dependencies
|
||||
|
|
@ -49,7 +50,7 @@ libc = { workspace = true }
|
|||
uzers = { workspace = true }
|
||||
|
||||
[target."cfg(windows)".dependencies]
|
||||
windows-sys = { version = "0.61.0", features = [ "Win32_System_JobObjects" ] }
|
||||
windows-sys = { version = "0.61.1", features = [ "Win32_System_JobObjects" ] }
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
crossterm = { workspace = true, features = [ "use-dev-tty", "libc" ] }
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ local M = {}
|
|||
|
||||
local function match_mimetype(line)
|
||||
for _, pat in ipairs(TYPE_PATS) do
|
||||
local typ, sub = line:match(string.format("(%s/)([+-.a-z0-9]+)%%s+$", pat))
|
||||
local typ, sub = line:match(string.format("(%s/)([+-.a-zA-Z0-9]+)%%s+$", pat))
|
||||
if not sub then
|
||||
elseif line:find(typ .. sub, 1, true) == 1 then
|
||||
return typ:gsub("^x%-", "", 1) .. sub:gsub("^x%-", "", 1):gsub("^vnd%.", "", 1)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use yazi_binding::Error;
|
|||
|
||||
pub enum SizeCalculator {
|
||||
Local(yazi_fs::provider::local::SizeCalculator),
|
||||
Remote(yazi_fs::provider::SizeCalculator),
|
||||
Remote(yazi_vfs::provider::SizeCalculator),
|
||||
}
|
||||
|
||||
impl UserData for SizeCalculator {
|
||||
|
|
|
|||
1
yazi-plugin/src/external/fd.rs
vendored
1
yazi-plugin/src/external/fd.rs
vendored
|
|
@ -4,6 +4,7 @@ use anyhow::Result;
|
|||
use tokio::{io::{AsyncBufReadExt, BufReader}, process::{Child, Command}, sync::mpsc::{self, UnboundedReceiver}};
|
||||
use yazi_fs::File;
|
||||
use yazi_shared::url::UrlBuf;
|
||||
use yazi_vfs::VfsFile;
|
||||
|
||||
pub struct FdOpt {
|
||||
pub cwd: UrlBuf,
|
||||
|
|
|
|||
1
yazi-plugin/src/external/rg.rs
vendored
1
yazi-plugin/src/external/rg.rs
vendored
|
|
@ -4,6 +4,7 @@ use anyhow::{Result, bail};
|
|||
use tokio::{io::{AsyncBufReadExt, BufReader}, process::Command, sync::mpsc::{self, UnboundedReceiver}};
|
||||
use yazi_fs::File;
|
||||
use yazi_shared::url::UrlBuf;
|
||||
use yazi_vfs::VfsFile;
|
||||
|
||||
pub struct RgOpt {
|
||||
pub cwd: UrlBuf,
|
||||
|
|
|
|||
1
yazi-plugin/src/external/rga.rs
vendored
1
yazi-plugin/src/external/rga.rs
vendored
|
|
@ -4,6 +4,7 @@ use anyhow::{Result, bail};
|
|||
use tokio::{io::{AsyncBufReadExt, BufReader}, process::Command, sync::mpsc::{self, UnboundedReceiver}};
|
||||
use yazi_fs::File;
|
||||
use yazi_shared::url::UrlBuf;
|
||||
use yazi_vfs::VfsFile;
|
||||
|
||||
pub struct RgaOpt {
|
||||
pub cwd: UrlBuf,
|
||||
|
|
|
|||
|
|
@ -3,8 +3,9 @@ use std::str::FromStr;
|
|||
use mlua::{ExternalError, Function, IntoLua, IntoLuaMulti, Lua, Table, Value};
|
||||
use yazi_binding::{Cha, Composer, ComposerGet, ComposerSet, Error, File, Url, UrlRef};
|
||||
use yazi_config::Pattern;
|
||||
use yazi_fs::{mounts::PARTITIONS, provider::{self, DirReader, FileHolder}, remove_dir_clean};
|
||||
use yazi_fs::{mounts::PARTITIONS, provider::{DirReader, FileHolder}};
|
||||
use yazi_shared::url::UrlCow;
|
||||
use yazi_vfs::{VfsFile, provider};
|
||||
|
||||
use crate::bindings::SizeCalculator;
|
||||
|
||||
|
|
@ -93,7 +94,7 @@ fn remove(lua: &Lua) -> mlua::Result<Function> {
|
|||
b"file" => provider::remove_file(&*url).await,
|
||||
b"dir" => provider::remove_dir(&*url).await,
|
||||
b"dir_all" => provider::remove_dir_all(&*url).await,
|
||||
b"dir_clean" => Ok(remove_dir_clean(&url).await),
|
||||
b"dir_clean" => provider::remove_dir_clean(&*url).await,
|
||||
_ => Err("Removal type must be 'file', 'dir', 'dir_all', or 'dir_clean'".into_lua_err())?,
|
||||
};
|
||||
|
||||
|
|
@ -148,9 +149,9 @@ fn read_dir(lua: &Lua) -> mlua::Result<Function> {
|
|||
fn calc_size(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|lua, url: UrlRef| async move {
|
||||
let it = if let Some(path) = url.as_path() {
|
||||
provider::local::SizeCalculator::new(path).await.map(SizeCalculator::Local)
|
||||
yazi_fs::provider::local::SizeCalculator::new(path).await.map(SizeCalculator::Local)
|
||||
} else {
|
||||
provider::SizeCalculator::new(&*url).await.map(SizeCalculator::Remote)
|
||||
yazi_vfs::provider::SizeCalculator::new(&*url).await.map(SizeCalculator::Remote)
|
||||
};
|
||||
|
||||
match it {
|
||||
|
|
@ -173,7 +174,7 @@ fn expand_url(lua: &Lua) -> mlua::Result<Function> {
|
|||
|
||||
fn unique_name(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|lua, url: UrlRef| async move {
|
||||
match yazi_fs::path::unique_name(url.clone(), async { false }).await {
|
||||
match yazi_vfs::unique_name(url.clone(), async { false }).await {
|
||||
Ok(u) => Url::new(u).into_lua_multi(&lua),
|
||||
Err(e) => (Value::Nil, Error::Io(e)).into_lua_multi(&lua),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ yazi-parser = { path = "../yazi-parser", version = "25.9.15" }
|
|||
yazi-plugin = { path = "../yazi-plugin", version = "25.9.15" }
|
||||
yazi-proxy = { path = "../yazi-proxy", version = "25.9.15" }
|
||||
yazi-shared = { path = "../yazi-shared", version = "25.9.15" }
|
||||
yazi-vfs = { path = "../yazi-vfs", version = "25.9.15" }
|
||||
|
||||
# External dependencies
|
||||
anyhow = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@ use anyhow::{Result, anyhow};
|
|||
use tokio::{io::{self, ErrorKind::{AlreadyExists, NotFound}}, sync::mpsc};
|
||||
use tracing::warn;
|
||||
use yazi_config::YAZI;
|
||||
use yazi_fs::{cha::Cha, copy_with_progress, maybe_exists, ok_or_not_found, path::{path_relative_to, skip_url}, provider::{self, DirEntry, DirReader, FileHolder}};
|
||||
use yazi_fs::{cha::Cha, ok_or_not_found, path::{path_relative_to, skip_url}, provider::{DirReader, FileHolder}};
|
||||
use yazi_shared::url::{Url, UrlBuf, UrlCow};
|
||||
use yazi_vfs::{VfsCha, copy_with_progress, maybe_exists, provider::{self, DirEntry}};
|
||||
|
||||
use super::{FileInDelete, FileInHardlink, FileInLink, FileInPaste, FileInTrash};
|
||||
use crate::{LOW, NORMAL, TaskIn, TaskOp, TaskOps, file::{FileOutDelete, FileOutDeleteDo, FileOutHardlink, FileOutHardlinkDo, FileOutLink, FileOutPaste, FileOutPasteDo, FileOutTrash}};
|
||||
|
|
|
|||
|
|
@ -8,9 +8,10 @@ use tokio::sync::mpsc;
|
|||
use tokio_util::sync::CancellationToken;
|
||||
use tracing::error;
|
||||
use yazi_config::Priority;
|
||||
use yazi_fs::{FilesOp, provider};
|
||||
use yazi_fs::FilesOp;
|
||||
use yazi_plugin::isolate;
|
||||
use yazi_shared::{event::CmdCow, url::UrlBuf};
|
||||
use yazi_vfs::provider;
|
||||
|
||||
use super::{PreworkInFetch, PreworkInLoad, PreworkInSize};
|
||||
use crate::{HIGH, NORMAL, TaskIn, TaskOp, TaskOps, prework::{PreworkOutFetch, PreworkOutLoad, PreworkOutSize}};
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::{borrow::Cow, ffi::OsString, process::Stdio};
|
|||
|
||||
use anyhow::{Result, bail};
|
||||
use tokio::process::{Child, Command};
|
||||
use yazi_fs::provider;
|
||||
use yazi_fs::FsUrl;
|
||||
use yazi_shared::url::UrlBuf;
|
||||
|
||||
pub(crate) struct ShellOpt {
|
||||
|
|
@ -30,7 +30,7 @@ pub(crate) async fn shell(opt: ShellOpt) -> Result<Child> {
|
|||
tokio::task::spawn_blocking(move || {
|
||||
let cwd: Cow<_> = if let Some(path) = opt.cwd.as_path() {
|
||||
path.into()
|
||||
} else if let Some(cache) = provider::cache(&opt.cwd) {
|
||||
} else if let Some(cache) = opt.cwd.cache() {
|
||||
std::fs::create_dir_all(&cache).ok();
|
||||
cache.into()
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -6,10 +6,10 @@ use parking_lot::Mutex;
|
|||
use tokio::{select, sync::{mpsc::{self, UnboundedReceiver}, oneshot}, task::JoinHandle};
|
||||
use yazi_config::{YAZI, plugin::{Fetcher, Preloader}};
|
||||
use yazi_dds::Pump;
|
||||
use yazi_fs::{must_be_dir, path::unique_name, provider, remove_dir_clean};
|
||||
use yazi_parser::{app::PluginOpt, tasks::ProcessExecOpt};
|
||||
use yazi_proxy::TasksProxy;
|
||||
use yazi_shared::{Id, Throttle, url::UrlBuf};
|
||||
use yazi_vfs::{must_be_dir, provider, unique_name};
|
||||
|
||||
use super::{Ongoing, TaskOp};
|
||||
use crate::{HIGH, LOW, NORMAL, TaskIn, TaskOps, TaskOut, file::{File, FileInDelete, FileInHardlink, FileInLink, FileInPaste, FileInTrash, FileOutDelete, FileOutHardlink, FileOutPaste, FileProgDelete, FileProgHardlink, FileProgLink, FileProgPaste, FileProgTrash}, plugin::{Plugin, PluginInEntry, PluginProgEntry}, prework::{Prework, PreworkInFetch, PreworkInLoad, PreworkInSize, PreworkProgFetch, PreworkProgLoad, PreworkProgSize}, process::{Process, ProcessInBg, ProcessInBlock, ProcessInOrphan, ProcessOutBg, ProcessOutBlock, ProcessOutOrphan, ProcessProgBg, ProcessProgBlock, ProcessProgOrphan}};
|
||||
|
|
@ -89,7 +89,7 @@ impl Scheduler {
|
|||
|
||||
move |canceled| async move {
|
||||
if !canceled {
|
||||
remove_dir_clean(&from).await;
|
||||
provider::remove_dir_clean(&from).await.ok();
|
||||
Pump::push_move(from, to);
|
||||
}
|
||||
ops.out(id, FileOutPaste::Clean);
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ crossterm = { workspace = true }
|
|||
foldhash = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
hashbrown = { workspace = true }
|
||||
memchr = "2.7.5"
|
||||
memchr = "2.7.6"
|
||||
ordered-float = { workspace = true }
|
||||
parking_lot = { workspace = true }
|
||||
percent-encoding = "2.3.2"
|
||||
|
|
@ -30,7 +30,7 @@ libc = { workspace = true }
|
|||
uzers = { workspace = true }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
windows-sys = { version = "0.61.0", features = [ "Win32_UI_Shell" ] }
|
||||
windows-sys = { version = "0.61.1", features = [ "Win32_UI_Shell" ] }
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
crossterm = { workspace = true, features = [ "use-dev-tty", "libc" ] }
|
||||
|
|
|
|||
|
|
@ -26,4 +26,4 @@ libc = { workspace = true }
|
|||
crossterm = { workspace = true, features = [ "use-dev-tty", "libc" ] }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
windows-sys = { version = "0.61.0", features = [ "Win32_Globalization", "Win32_Storage_FileSystem", "Win32_System_IO", "Win32_System_Console", "Win32_System_Threading", "Win32_Security" ] }
|
||||
windows-sys = { version = "0.61.1", features = [ "Win32_Globalization", "Win32_Storage_FileSystem", "Win32_System_IO", "Win32_System_Console", "Win32_System_Threading", "Win32_Security" ] }
|
||||
|
|
|
|||
|
|
@ -9,15 +9,22 @@ homepage = "https://yazi-rs.github.io"
|
|||
repository = "https://github.com/sxyazi/yazi"
|
||||
|
||||
[dependencies]
|
||||
yazi-fs = { path = "../yazi-fs", version = "25.9.15" }
|
||||
yazi-macro = { path = "../yazi-macro", version = "25.9.15" }
|
||||
yazi-sftp = { path = "../yazi-sftp", version = "0.1.0" }
|
||||
yazi-shared = { path = "../yazi-shared", version = "25.9.15" }
|
||||
|
||||
# External dependencies
|
||||
dirs = { workspace = true }
|
||||
hashbrown = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
toml = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
deadpool = { version = "0.12.3", default-features = false, features = [ "managed", "rt_tokio_1" ] }
|
||||
futures = { workspace = true }
|
||||
hashbrown = { workspace = true }
|
||||
parking_lot = { workspace = true }
|
||||
russh = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
toml = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
|
||||
[target."cfg(unix)".dependencies]
|
||||
uzers = { workspace = true }
|
||||
|
|
|
|||
37
yazi-vfs/src/cha.rs
Normal file
37
yazi-vfs/src/cha.rs
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
use std::io;
|
||||
|
||||
use yazi_fs::cha::{Cha, ChaKind};
|
||||
use yazi_shared::url::Url;
|
||||
|
||||
use crate::provider;
|
||||
|
||||
pub trait VfsCha: Sized {
|
||||
fn from_url<'a>(url: impl Into<Url<'a>>) -> impl Future<Output = io::Result<Self>>;
|
||||
|
||||
fn from_follow<'a, U>(url: U, cha: Self) -> impl Future<Output = Self>
|
||||
where
|
||||
U: Into<Url<'a>>;
|
||||
}
|
||||
|
||||
impl VfsCha for Cha {
|
||||
#[inline]
|
||||
async fn from_url<'a>(url: impl Into<Url<'a>>) -> io::Result<Self> {
|
||||
let url = url.into();
|
||||
Ok(Self::from_follow(url, provider::symlink_metadata(url).await?).await)
|
||||
}
|
||||
|
||||
async fn from_follow<'a, U>(url: U, mut cha: Self) -> Self
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
{
|
||||
let url: Url = url.into();
|
||||
let mut retain = cha.kind & (ChaKind::HIDDEN | ChaKind::SYSTEM);
|
||||
|
||||
if cha.is_link() {
|
||||
retain |= ChaKind::FOLLOW;
|
||||
cha = provider::metadata(url).await.unwrap_or(cha);
|
||||
}
|
||||
|
||||
cha.attach(retain)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,10 +3,10 @@ use std::io;
|
|||
use hashbrown::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::sync::OnceCell;
|
||||
use yazi_fs::Xdg;
|
||||
use yazi_macro::ok_or_not_found;
|
||||
|
||||
use super::Provider;
|
||||
use crate::local::Xdg;
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct Vfs {
|
||||
|
|
|
|||
29
yazi-vfs/src/file.rs
Normal file
29
yazi-vfs/src/file.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
use anyhow::Result;
|
||||
use yazi_fs::{File, cha::Cha};
|
||||
use yazi_shared::url::{UrlBuf, UrlCow};
|
||||
|
||||
use crate::{VfsCha, provider};
|
||||
|
||||
pub trait VfsFile: Sized {
|
||||
fn new<'a>(url: impl Into<UrlCow<'a>>) -> impl Future<Output = Result<Self>>;
|
||||
|
||||
fn from_follow(url: UrlBuf, cha: Cha) -> impl Future<Output = Self>;
|
||||
}
|
||||
|
||||
impl VfsFile for File {
|
||||
#[inline]
|
||||
async fn new<'a>(url: impl Into<UrlCow<'a>>) -> Result<Self> {
|
||||
let url = url.into();
|
||||
let cha = provider::symlink_metadata(&url).await?;
|
||||
Ok(Self::from_follow(url.into_owned(), cha).await)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
async fn from_follow(url: UrlBuf, cha: Cha) -> Self {
|
||||
let link_to = if cha.is_link() { provider::read_link(&url).await.ok() } else { None };
|
||||
|
||||
let cha = Cha::from_follow(&url, cha).await;
|
||||
|
||||
Self { url, cha, link_to }
|
||||
}
|
||||
}
|
||||
79
yazi-vfs/src/files.rs
Normal file
79
yazi-vfs/src/files.rs
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
use std::io;
|
||||
|
||||
use tokio::{select, sync::mpsc::{self, UnboundedReceiver}};
|
||||
use yazi_fs::{File, Files, FilesOp, cha::Cha, mounts::PARTITIONS, provider::{DirReader, FileHolder}};
|
||||
use yazi_shared::url::UrlBuf;
|
||||
|
||||
use crate::{VfsCha, VfsFile, VfsFilesOp, provider::{self, DirEntry}};
|
||||
|
||||
pub trait VfsFiles {
|
||||
fn from_dir(dir: &UrlBuf) -> impl Future<Output = io::Result<UnboundedReceiver<File>>>;
|
||||
|
||||
fn from_dir_bulk(dir: &UrlBuf) -> impl Future<Output = io::Result<Vec<File>>>;
|
||||
|
||||
fn assert_stale(dir: &UrlBuf, cha: Cha) -> impl Future<Output = Option<Cha>>;
|
||||
}
|
||||
|
||||
impl VfsFiles for Files {
|
||||
async fn from_dir(dir: &UrlBuf) -> std::io::Result<UnboundedReceiver<File>> {
|
||||
let mut it = provider::read_dir(dir).await?;
|
||||
let (tx, rx) = mpsc::unbounded_channel();
|
||||
|
||||
tokio::spawn(async move {
|
||||
while let Ok(Some(ent)) = it.next().await {
|
||||
select! {
|
||||
_ = tx.closed() => break,
|
||||
result = ent.metadata() => {
|
||||
let url = ent.url();
|
||||
_ = tx.send(match result {
|
||||
Ok(cha) => File::from_follow(url, cha).await,
|
||||
Err(_) => File::from_dummy(url, ent.file_type().await.ok())
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
Ok(rx)
|
||||
}
|
||||
|
||||
async fn from_dir_bulk(dir: &UrlBuf) -> std::io::Result<Vec<File>> {
|
||||
let mut it = provider::read_dir(dir).await?;
|
||||
let mut entries = Vec::with_capacity(5000);
|
||||
while let Ok(Some(entry)) = it.next().await {
|
||||
entries.push(entry);
|
||||
}
|
||||
|
||||
let (first, rest) = entries.split_at(entries.len() / 3);
|
||||
let (second, third) = rest.split_at(entries.len() / 3);
|
||||
async fn go(entries: &[DirEntry]) -> Vec<File> {
|
||||
let mut files = Vec::with_capacity(entries.len());
|
||||
for ent in entries {
|
||||
let url = ent.url();
|
||||
files.push(match ent.metadata().await {
|
||||
Ok(cha) => File::from_follow(url, cha).await,
|
||||
Err(_) => File::from_dummy(url, ent.file_type().await.ok()),
|
||||
});
|
||||
}
|
||||
files
|
||||
}
|
||||
|
||||
Ok(
|
||||
futures::future::join_all([go(first), go(second), go(third)])
|
||||
.await
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
||||
async fn assert_stale(dir: &UrlBuf, cha: Cha) -> Option<Cha> {
|
||||
use std::io::ErrorKind;
|
||||
match Cha::from_url(dir).await {
|
||||
Ok(c) if !c.is_dir() => FilesOp::issue_error(dir, ErrorKind::NotADirectory).await,
|
||||
Ok(c) if c.hits(cha) && PARTITIONS.read().heuristic(cha) => {}
|
||||
Ok(c) => return Some(c),
|
||||
Err(e) => FilesOp::issue_error(dir, e.kind()).await,
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
122
yazi-vfs/src/fns.rs
Normal file
122
yazi-vfs/src/fns.rs
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
use std::{ffi::OsString, io};
|
||||
|
||||
use tokio::{select, sync::{mpsc, oneshot}};
|
||||
use yazi_fs::cha::Cha;
|
||||
use yazi_shared::url::{Url, UrlBuf};
|
||||
|
||||
use crate::provider;
|
||||
|
||||
#[inline]
|
||||
pub async fn maybe_exists<'a>(url: impl Into<Url<'a>>) -> bool {
|
||||
match provider::symlink_metadata(url).await {
|
||||
Ok(_) => true,
|
||||
Err(e) => e.kind() != io::ErrorKind::NotFound,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn must_be_dir<'a>(url: impl Into<Url<'a>>) -> bool {
|
||||
provider::metadata(url).await.is_ok_and(|m| m.is_dir())
|
||||
}
|
||||
|
||||
pub async fn unique_name<F>(u: UrlBuf, append: F) -> io::Result<UrlBuf>
|
||||
where
|
||||
F: Future<Output = bool>,
|
||||
{
|
||||
match provider::symlink_metadata(&u).await {
|
||||
Ok(_) => _unique_name(u, append.await).await,
|
||||
Err(e) if e.kind() == io::ErrorKind::NotFound => Ok(u),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
async fn _unique_name(mut url: UrlBuf, append: bool) -> io::Result<UrlBuf> {
|
||||
let Some(stem) = url.stem().map(|s| s.to_owned()) else {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidInput, "empty file stem"));
|
||||
};
|
||||
|
||||
let dot_ext = url.ext().map_or_else(OsString::new, |e| {
|
||||
let mut s = OsString::with_capacity(e.len() + 1);
|
||||
s.push(".");
|
||||
s.push(e);
|
||||
s
|
||||
});
|
||||
|
||||
let mut i = 1u64;
|
||||
let mut name = OsString::with_capacity(stem.len() + dot_ext.len() + 5);
|
||||
loop {
|
||||
name.clear();
|
||||
name.push(&stem);
|
||||
|
||||
if append {
|
||||
name.push(&dot_ext);
|
||||
name.push(format!("_{i}"));
|
||||
} else {
|
||||
name.push(format!("_{i}"));
|
||||
name.push(&dot_ext);
|
||||
}
|
||||
|
||||
url.set_name(&name);
|
||||
match provider::symlink_metadata(&url).await {
|
||||
Ok(_) => i += 1,
|
||||
Err(e) if e.kind() == io::ErrorKind::NotFound => break,
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(url)
|
||||
}
|
||||
|
||||
pub fn copy_with_progress(
|
||||
from: &UrlBuf,
|
||||
to: &UrlBuf,
|
||||
cha: Cha,
|
||||
) -> mpsc::Receiver<Result<u64, io::Error>> {
|
||||
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 {
|
||||
done_tx.send(provider::copy(&from, &to, cha).await).ok();
|
||||
}
|
||||
});
|
||||
|
||||
tokio::spawn({
|
||||
let (prog_tx, to) = (prog_tx.clone(), to.clone());
|
||||
async move {
|
||||
let mut last = 0;
|
||||
let mut done = None;
|
||||
loop {
|
||||
select! {
|
||||
res = &mut done_rx => done = Some(res.unwrap()),
|
||||
_ = prog_tx.closed() => break,
|
||||
_ = tokio::time::sleep(std::time::Duration::from_secs(3)) => {},
|
||||
}
|
||||
|
||||
match done {
|
||||
Some(Ok(len)) => {
|
||||
if len > last {
|
||||
prog_tx.send(Ok(len - last)).await.ok();
|
||||
}
|
||||
prog_tx.send(Ok(0)).await.ok();
|
||||
break;
|
||||
}
|
||||
Some(Err(e)) => {
|
||||
prog_tx.send(Err(e)).await.ok();
|
||||
break;
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
let len = provider::symlink_metadata(&to).await.map(|m| m.len).unwrap_or(0);
|
||||
if len > last {
|
||||
prog_tx.send(Ok(len - last)).await.ok();
|
||||
last = len;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
prog_rx
|
||||
}
|
||||
|
|
@ -1 +1,5 @@
|
|||
yazi_macro::mod_pub!(config local);
|
||||
yazi_macro::mod_pub!(config provider);
|
||||
|
||||
yazi_macro::mod_flat!(cha file files fns op);
|
||||
|
||||
pub fn init() { provider::init(); }
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
yazi_macro::mod_flat!(xdg);
|
||||
23
yazi-vfs/src/op.rs
Normal file
23
yazi-vfs/src/op.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
use std::io;
|
||||
|
||||
use yazi_fs::FilesOp;
|
||||
use yazi_shared::url::UrlBuf;
|
||||
|
||||
use crate::maybe_exists;
|
||||
|
||||
pub trait VfsFilesOp {
|
||||
fn issue_error(cwd: &UrlBuf, kind: io::ErrorKind) -> impl Future<Output = ()>;
|
||||
}
|
||||
|
||||
impl VfsFilesOp for FilesOp {
|
||||
async fn issue_error(cwd: &UrlBuf, kind: std::io::ErrorKind) {
|
||||
use std::io::ErrorKind;
|
||||
if kind != ErrorKind::NotFound {
|
||||
Self::IOErr(cwd.clone(), kind).emit();
|
||||
} else if maybe_exists(cwd).await {
|
||||
Self::IOErr(cwd.clone(), kind).emit();
|
||||
} else if let Some((p, n)) = cwd.pair() {
|
||||
Self::Deleting(p.into(), [n.into()].into()).emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
use std::{collections::VecDeque, io, time::{Duration, Instant}};
|
||||
|
||||
use yazi_fs::provider::{DirReader, FileHolder};
|
||||
use yazi_shared::{Either, url::{Url, UrlBuf}};
|
||||
|
||||
use crate::provider::{self, DirReader, FileHolder, ReadDir};
|
||||
use super::ReadDir;
|
||||
|
||||
pub enum SizeCalculator {
|
||||
File(Option<u64>),
|
||||
|
|
@ -15,7 +16,7 @@ impl SizeCalculator {
|
|||
U: Into<Url<'a>>,
|
||||
{
|
||||
let url: Url = url.into();
|
||||
let cha = provider::symlink_metadata(url).await?;
|
||||
let cha = super::symlink_metadata(url).await?;
|
||||
Ok(if cha.is_dir() {
|
||||
Self::Dir(VecDeque::from([Either::Left(url.to_owned())]))
|
||||
} else {
|
||||
|
|
@ -59,7 +60,7 @@ impl SizeCalculator {
|
|||
let front = buf.front_mut()?;
|
||||
|
||||
if let Either::Left(p) = front {
|
||||
*front = match provider::read_dir(p).await {
|
||||
*front = match super::read_dir(p).await {
|
||||
Ok(it) => Either::Right(it),
|
||||
Err(_) => pop_and_continue!(),
|
||||
};
|
||||
|
|
@ -1,12 +1,11 @@
|
|||
use std::{borrow::Cow, ffi::OsStr, io, sync::Arc};
|
||||
|
||||
use yazi_fs::{cha::{Cha, ChaType}, provider::FileHolder};
|
||||
use yazi_shared::url::UrlBuf;
|
||||
|
||||
use crate::{cha::{Cha, ChaType}, provider::FileHolder};
|
||||
|
||||
pub enum DirEntry {
|
||||
Regular(super::local::DirEntry),
|
||||
Search((Arc<UrlBuf>, super::local::DirEntry)),
|
||||
Regular(yazi_fs::provider::local::DirEntry),
|
||||
Search((Arc<UrlBuf>, yazi_fs::provider::local::DirEntry)),
|
||||
Sftp((Arc<UrlBuf>, super::sftp::DirEntry)),
|
||||
}
|
||||
|
||||
|
|
@ -1,16 +1,15 @@
|
|||
use std::{io, path::Path};
|
||||
|
||||
use yazi_fs::{cha::Cha, provider::FileBuilder};
|
||||
use yazi_shared::scheme::SchemeRef;
|
||||
|
||||
use crate::{cha::Cha, provider::FileBuilder};
|
||||
|
||||
pub enum Gate {
|
||||
Local(super::local::Gate),
|
||||
Local(yazi_fs::provider::local::Gate),
|
||||
Sftp(super::sftp::Gate),
|
||||
}
|
||||
|
||||
impl From<super::local::Gate> for Gate {
|
||||
fn from(value: super::local::Gate) -> Self { Self::Local(value) }
|
||||
impl From<yazi_fs::provider::local::Gate> for Gate {
|
||||
fn from(value: yazi_fs::provider::local::Gate) -> Self { Self::Local(value) }
|
||||
}
|
||||
|
||||
impl From<super::sftp::Gate> for Gate {
|
||||
|
|
@ -54,7 +53,9 @@ impl FileBuilder for Gate {
|
|||
|
||||
async fn new(scheme: SchemeRef<'_>) -> io::Result<Self> {
|
||||
Ok(match scheme {
|
||||
SchemeRef::Regular | SchemeRef::Search(_) => super::local::Gate::new(scheme).await?.into(),
|
||||
SchemeRef::Regular | SchemeRef::Search(_) => {
|
||||
yazi_fs::provider::local::Gate::new(scheme).await?.into()
|
||||
}
|
||||
SchemeRef::Archive(_) => {
|
||||
Err(io::Error::new(io::ErrorKind::Unsupported, "Unsupported filesystem: archive"))?
|
||||
}
|
||||
5
yazi-vfs/src/provider/mod.rs
Normal file
5
yazi-vfs/src/provider/mod.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
yazi_macro::mod_pub!(sftp);
|
||||
|
||||
yazi_macro::mod_flat!(calculator dir_entry gate provider providers read_dir rw_file);
|
||||
|
||||
pub(super) fn init() { sftp::init(); }
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
use std::{io, path::{Path, PathBuf}};
|
||||
|
||||
use tokio::io::{BufReader, BufWriter};
|
||||
use twox_hash::XxHash3_128;
|
||||
use yazi_fs::{cha::Cha, provider::{Provider, local::Local}};
|
||||
use yazi_shared::{scheme::SchemeRef, url::{Url, UrlBuf, UrlCow}};
|
||||
use yazi_vfs::local::Xdg;
|
||||
|
||||
use crate::{cha::Cha, provider::{Provider, Providers, ReadDir, RwFile, local::{self, Local}}};
|
||||
use super::{Providers, ReadDir, RwFile};
|
||||
|
||||
pub async fn absolute<'a, U>(url: U) -> io::Result<UrlCow<'a>>
|
||||
where
|
||||
|
|
@ -15,33 +14,13 @@ where
|
|||
Providers::new(url).await?.absolute(url).await
|
||||
}
|
||||
|
||||
pub fn cache<'a, U>(url: U) -> Option<PathBuf>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
{
|
||||
let url: Url = url.into();
|
||||
match url.scheme {
|
||||
SchemeRef::Regular | SchemeRef::Search(_) => None,
|
||||
SchemeRef::Archive(name) => Some(
|
||||
Xdg::cache_dir()
|
||||
.join(format!("archive-{}", yazi_shared::url::Encode::domain(name)))
|
||||
.join(format!("{:x}", XxHash3_128::oneshot(url.loc.bytes()))),
|
||||
),
|
||||
SchemeRef::Sftp(name) => Some(
|
||||
Xdg::cache_dir()
|
||||
.join(format!("sftp-{}", yazi_shared::url::Encode::domain(name)))
|
||||
.join(format!("{:x}", XxHash3_128::oneshot(url.loc.bytes()))),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn calculate<'a, U>(url: U) -> io::Result<u64>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
{
|
||||
let url: Url = url.into();
|
||||
if let Some(path) = url.as_path() {
|
||||
local::SizeCalculator::total(path).await
|
||||
yazi_fs::provider::local::SizeCalculator::total(path).await
|
||||
} else {
|
||||
super::SizeCalculator::total(url).await
|
||||
}
|
||||
|
|
@ -149,7 +128,7 @@ where
|
|||
V: Into<Url<'a>>,
|
||||
{
|
||||
if let (Some(a), Some(b)) = (a.into().as_path(), b.into().as_path()) {
|
||||
local::identical(a, b).await
|
||||
yazi_fs::provider::local::identical(a, b).await
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::Unsupported, "Unsupported filesystem"))
|
||||
}
|
||||
|
|
@ -203,6 +182,14 @@ where
|
|||
Providers::new(url).await?.remove_dir_all(url.loc).await
|
||||
}
|
||||
|
||||
pub async fn remove_dir_clean<'a, U>(url: U) -> io::Result<()>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
{
|
||||
let url: Url = url.into();
|
||||
Ok(Providers::new(url).await?.remove_dir_clean(url.loc).await)
|
||||
}
|
||||
|
||||
pub async fn remove_file<'a, U>(url: U) -> io::Result<()>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
|
|
@ -1,10 +1,9 @@
|
|||
use std::{io, path::{Path, PathBuf}, sync::Arc};
|
||||
|
||||
use yazi_fs::{cha::Cha, provider::{Provider, local::Local}};
|
||||
use yazi_shared::{scheme::SchemeRef, url::{Url, UrlCow}};
|
||||
use yazi_vfs::config::{ProviderSftp, Vfs};
|
||||
|
||||
use super::local::Local;
|
||||
use crate::{cha::Cha, provider::Provider};
|
||||
use crate::config::{ProviderSftp, Vfs};
|
||||
|
||||
pub(super) struct Providers<'a>(Inner<'a>);
|
||||
|
||||
|
|
@ -1,12 +1,11 @@
|
|||
use std::{io, sync::Arc};
|
||||
|
||||
use yazi_fs::provider::DirReader;
|
||||
use yazi_shared::url::UrlBuf;
|
||||
|
||||
use crate::provider::DirReader;
|
||||
|
||||
pub enum ReadDir {
|
||||
Regular(super::local::ReadDir),
|
||||
Search((Arc<UrlBuf>, super::local::ReadDir)),
|
||||
Regular(yazi_fs::provider::local::ReadDir),
|
||||
Search((Arc<UrlBuf>, yazi_fs::provider::local::ReadDir)),
|
||||
Sftp((Arc<UrlBuf>, super::sftp::ReadDir)),
|
||||
}
|
||||
|
||||
|
|
@ -1,8 +1,7 @@
|
|||
use std::{io, pin::Pin};
|
||||
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
|
||||
use crate::cha::Cha;
|
||||
use yazi_fs::cha::Cha;
|
||||
|
||||
pub enum RwFile {
|
||||
Tokio(tokio::fs::File),
|
||||
|
|
@ -30,7 +29,7 @@ impl RwFile {
|
|||
.await?;
|
||||
}
|
||||
Self::Sftp(f) => {
|
||||
f.fsetstat(&cha.into()).await?;
|
||||
f.fsetstat(&super::sftp::Cha(cha).into()).await?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
use std::{io, path::Path};
|
||||
|
||||
use yazi_fs::{cha::Cha, provider::FileBuilder};
|
||||
use yazi_sftp::fs::{Attrs, Flags};
|
||||
use yazi_shared::scheme::SchemeRef;
|
||||
use yazi_vfs::config::{ProviderSftp, Vfs};
|
||||
|
||||
use crate::{cha::Cha, provider::FileBuilder};
|
||||
use crate::config::{ProviderSftp, Vfs};
|
||||
|
||||
pub struct Gate {
|
||||
sftp: super::Sftp,
|
||||
|
|
@ -84,7 +84,7 @@ impl FileBuilder for Gate {
|
|||
flags |= Flags::WRITE;
|
||||
}
|
||||
|
||||
let attrs = self.cha.map_or(Attrs::default(), Attrs::from);
|
||||
let attrs = self.cha.map(super::Cha).map_or(Attrs::default(), Attrs::from);
|
||||
|
||||
Ok(self.sftp.op().await?.open(&path, flags, &attrs).await?)
|
||||
}
|
||||
|
|
@ -1,13 +1,29 @@
|
|||
use std::{ffi::OsStr, io, time::{Duration, UNIX_EPOCH}};
|
||||
|
||||
use crate::cha::{Cha, ChaKind, ChaMode};
|
||||
use yazi_fs::cha::ChaKind;
|
||||
|
||||
pub(crate) struct Cha(pub(crate) yazi_fs::cha::Cha);
|
||||
|
||||
impl From<Cha> for yazi_sftp::fs::Attrs {
|
||||
fn from(cha: Cha) -> Self {
|
||||
Self {
|
||||
size: Some(cha.0.len),
|
||||
uid: Some(cha.0.uid),
|
||||
gid: Some(cha.0.gid),
|
||||
perm: Some(cha.0.mode.bits() as u32),
|
||||
atime: cha.0.atime_dur().ok().map(|d| d.as_secs() as u32),
|
||||
mtime: cha.0.mtime_dur().ok().map(|d| d.as_secs() as u32),
|
||||
extended: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&yazi_sftp::fs::DirEntry> for Cha {
|
||||
type Error = io::Error;
|
||||
|
||||
fn try_from(ent: &yazi_sftp::fs::DirEntry) -> Result<Self, Self::Error> {
|
||||
let mut cha = Self::try_from((ent.name().as_ref(), ent.attrs()))?;
|
||||
cha.nlink = ent.nlink().unwrap_or_default();
|
||||
cha.0.nlink = ent.nlink().unwrap_or_default();
|
||||
Ok(cha)
|
||||
}
|
||||
}
|
||||
|
|
@ -19,9 +35,9 @@ impl TryFrom<(&OsStr, &yazi_sftp::fs::Attrs)> for Cha {
|
|||
let kind =
|
||||
if name.as_encoded_bytes().starts_with(b".") { ChaKind::HIDDEN } else { ChaKind::empty() };
|
||||
|
||||
Ok(Cha {
|
||||
Ok(Cha(yazi_fs::cha::Cha {
|
||||
kind,
|
||||
mode: attrs.try_into()?,
|
||||
mode: ChaMode::try_from(attrs)?.0,
|
||||
len: attrs.size.unwrap_or(0),
|
||||
atime: attrs.atime.and_then(|t| UNIX_EPOCH.checked_add(Duration::from_secs(t as u64))),
|
||||
btime: None,
|
||||
|
|
@ -31,29 +47,19 @@ impl TryFrom<(&OsStr, &yazi_sftp::fs::Attrs)> for Cha {
|
|||
uid: attrs.uid.unwrap_or(0),
|
||||
gid: attrs.gid.unwrap_or(0),
|
||||
nlink: 0,
|
||||
})
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
// --- ChaMode
|
||||
pub(super) struct ChaMode(pub(super) yazi_fs::cha::ChaMode);
|
||||
|
||||
impl TryFrom<&yazi_sftp::fs::Attrs> for ChaMode {
|
||||
type Error = io::Error;
|
||||
|
||||
fn try_from(attrs: &yazi_sftp::fs::Attrs) -> Result<Self, Self::Error> {
|
||||
ChaMode::try_from(attrs.perm.unwrap_or_default() as u16)
|
||||
yazi_fs::cha::ChaMode::try_from(attrs.perm.unwrap_or_default() as u16)
|
||||
.map(Self)
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Cha> for yazi_sftp::fs::Attrs {
|
||||
fn from(cha: Cha) -> Self {
|
||||
Self {
|
||||
size: Some(cha.len),
|
||||
uid: Some(cha.uid),
|
||||
gid: Some(cha.gid),
|
||||
perm: Some(cha.mode.bits() as u32),
|
||||
atime: cha.atime_dur().ok().map(|d| d.as_secs() as u32),
|
||||
mtime: cha.mtime_dur().ok().map(|d| d.as_secs() as u32),
|
||||
extended: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@ yazi_macro::mod_flat!(gate metadata read_dir sftp);
|
|||
pub(super) static CONN: yazi_shared::RoCell<
|
||||
parking_lot::Mutex<
|
||||
hashbrown::HashMap<
|
||||
&'static yazi_vfs::config::ProviderSftp,
|
||||
&'static crate::config::ProviderSftp,
|
||||
&'static deadpool::managed::Pool<Sftp>,
|
||||
>,
|
||||
>,
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
use std::{borrow::Cow, ffi::OsStr, io, path::PathBuf};
|
||||
|
||||
use crate::{cha::{Cha, ChaMode, ChaType}, provider::{DirReader, FileHolder}};
|
||||
use yazi_fs::provider::{DirReader, FileHolder};
|
||||
|
||||
use super::{Cha, ChaMode};
|
||||
|
||||
pub struct ReadDir(pub(super) yazi_sftp::fs::ReadDir);
|
||||
|
||||
|
|
@ -20,9 +22,9 @@ impl FileHolder for DirEntry {
|
|||
|
||||
fn name(&self) -> Cow<'_, OsStr> { self.0.name() }
|
||||
|
||||
async fn metadata(&self) -> io::Result<Cha> { Cha::try_from(&self.0) }
|
||||
async fn metadata(&self) -> io::Result<yazi_fs::cha::Cha> { Ok(Cha::try_from(&self.0)?.0) }
|
||||
|
||||
async fn file_type(&self) -> io::Result<ChaType> {
|
||||
ChaMode::try_from(self.0.attrs()).map(Into::into)
|
||||
async fn file_type(&self) -> io::Result<yazi_fs::cha::ChaType> {
|
||||
Ok(ChaMode::try_from(self.0.attrs())?.0.into())
|
||||
}
|
||||
}
|
||||
|
|
@ -2,11 +2,12 @@ use std::{io, path::{Path, PathBuf}, sync::Arc};
|
|||
|
||||
use russh::keys::PrivateKeyWithHashAlg;
|
||||
use tokio::io::{BufReader, BufWriter};
|
||||
use yazi_fs::provider::{DirReader, FileBuilder, FileHolder, Provider, local::Local};
|
||||
use yazi_sftp::fs::{Attrs, Flags};
|
||||
use yazi_shared::{scheme::SchemeRef, url::{Url, UrlBuf, UrlCow}};
|
||||
use yazi_vfs::config::ProviderSftp;
|
||||
|
||||
use crate::{cha::Cha, provider::{DirReader, FileBuilder, FileHolder, Provider, local::Local}};
|
||||
use super::Cha;
|
||||
use crate::config::ProviderSftp;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Sftp {
|
||||
|
|
@ -76,12 +77,12 @@ impl Provider for Sftp {
|
|||
similar.map(|n| parent.join(n)).ok_or_else(|| io::Error::from(io::ErrorKind::NotFound))
|
||||
}
|
||||
|
||||
async fn copy<P, Q>(&self, from: P, to: Q, cha: Cha) -> io::Result<u64>
|
||||
async fn copy<P, Q>(&self, from: P, to: Q, cha: yazi_fs::cha::Cha) -> io::Result<u64>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
Q: AsRef<Path>,
|
||||
{
|
||||
let attrs = Attrs::from(cha);
|
||||
let attrs = Attrs::from(Cha(cha));
|
||||
|
||||
let op = self.op().await?;
|
||||
let from = op.open(&from, Flags::READ, &Attrs::default()).await?;
|
||||
|
|
@ -115,13 +116,13 @@ impl Provider for Sftp {
|
|||
Ok(self.op().await?.hardlink(&original, &link).await?)
|
||||
}
|
||||
|
||||
async fn metadata<P>(&self, path: P) -> io::Result<Cha>
|
||||
async fn metadata<P>(&self, path: P) -> io::Result<yazi_fs::cha::Cha>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let path = path.as_ref();
|
||||
let attrs = self.op().await?.stat(path).await?;
|
||||
(path.file_name().unwrap_or_default(), &attrs).try_into()
|
||||
Ok(Cha::try_from((path.file_name().unwrap_or_default(), &attrs))?.0)
|
||||
}
|
||||
|
||||
async fn read_dir<P>(&self, path: P) -> io::Result<Self::ReadDir>
|
||||
|
|
@ -169,13 +170,13 @@ impl Provider for Sftp {
|
|||
Ok(self.op().await?.symlink(&original, &link).await?)
|
||||
}
|
||||
|
||||
async fn symlink_metadata<P>(&self, path: P) -> io::Result<Cha>
|
||||
async fn symlink_metadata<P>(&self, path: P) -> io::Result<yazi_fs::cha::Cha>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let path = path.as_ref();
|
||||
let attrs = self.op().await?.lstat(path).await?;
|
||||
(path.file_name().unwrap_or_default(), &attrs).try_into()
|
||||
Ok(Cha::try_from((path.file_name().unwrap_or_default(), &attrs))?.0)
|
||||
}
|
||||
|
||||
async fn trash<P>(&self, _path: P) -> io::Result<()>
|
||||
|
|
@ -14,6 +14,7 @@ yazi-dds = { path = "../yazi-dds", version = "25.9.15" }
|
|||
yazi-fs = { path = "../yazi-fs", version = "25.9.15" }
|
||||
yazi-macro = { path = "../yazi-macro", version = "25.9.15" }
|
||||
yazi-shared = { path = "../yazi-shared", version = "25.9.15" }
|
||||
yazi-vfs = { path = "../yazi-vfs", version = "25.9.15" }
|
||||
|
||||
# Logging
|
||||
tracing = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use tokio::{pin, sync::{mpsc::{self, UnboundedReceiver}, watch}};
|
|||
use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream};
|
||||
use yazi_fs::{File, FilesOp, provider::local};
|
||||
use yazi_shared::url::UrlBuf;
|
||||
use yazi_vfs::VfsFile;
|
||||
|
||||
use crate::{LINKED, Linked, WATCHED, WATCHER, backend::Backend};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue