mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
Reformat
This commit is contained in:
parent
9fc3d9fa10
commit
d7d9ef12b3
8 changed files with 214 additions and 819 deletions
332
Cargo.lock
generated
332
Cargo.lock
generated
|
|
@ -1022,17 +1022,6 @@ dependencies = [
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "displaydoc"
|
|
||||||
version = "0.2.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "document-features"
|
name = "document-features"
|
||||||
version = "0.2.12"
|
version = "0.2.12"
|
||||||
|
|
@ -1297,15 +1286,6 @@ version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
|
checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "form_urlencoded"
|
|
||||||
version = "1.2.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
|
|
||||||
dependencies = [
|
|
||||||
"percent-encoding",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fsevent-sys"
|
name = "fsevent-sys"
|
||||||
version = "4.1.0"
|
version = "4.1.0"
|
||||||
|
|
@ -1472,19 +1452,6 @@ version = "0.32.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7"
|
checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "git2"
|
|
||||||
version = "0.19.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b903b73e45dc0c6c596f2d37eccece7c1c8bb6e4407b001096387c63d0d93724"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.10.0",
|
|
||||||
"libc",
|
|
||||||
"libgit2-sys",
|
|
||||||
"log",
|
|
||||||
"url",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "globset"
|
name = "globset"
|
||||||
version = "0.4.18"
|
version = "0.4.18"
|
||||||
|
|
@ -1655,135 +1622,12 @@ dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "icu_collections"
|
|
||||||
version = "2.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47"
|
|
||||||
dependencies = [
|
|
||||||
"displaydoc",
|
|
||||||
"potential_utf",
|
|
||||||
"yoke",
|
|
||||||
"zerofrom",
|
|
||||||
"zerovec",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "icu_locale_core"
|
|
||||||
version = "2.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a"
|
|
||||||
dependencies = [
|
|
||||||
"displaydoc",
|
|
||||||
"litemap",
|
|
||||||
"tinystr",
|
|
||||||
"writeable",
|
|
||||||
"zerovec",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "icu_normalizer"
|
|
||||||
version = "2.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979"
|
|
||||||
dependencies = [
|
|
||||||
"displaydoc",
|
|
||||||
"icu_collections",
|
|
||||||
"icu_normalizer_data",
|
|
||||||
"icu_properties",
|
|
||||||
"icu_provider",
|
|
||||||
"smallvec",
|
|
||||||
"zerovec",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "icu_normalizer_data"
|
|
||||||
version = "2.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "icu_properties"
|
|
||||||
version = "2.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b"
|
|
||||||
dependencies = [
|
|
||||||
"displaydoc",
|
|
||||||
"icu_collections",
|
|
||||||
"icu_locale_core",
|
|
||||||
"icu_properties_data",
|
|
||||||
"icu_provider",
|
|
||||||
"potential_utf",
|
|
||||||
"zerotrie",
|
|
||||||
"zerovec",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "icu_properties_data"
|
|
||||||
version = "2.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "icu_provider"
|
|
||||||
version = "2.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af"
|
|
||||||
dependencies = [
|
|
||||||
"displaydoc",
|
|
||||||
"icu_locale_core",
|
|
||||||
"stable_deref_trait",
|
|
||||||
"tinystr",
|
|
||||||
"writeable",
|
|
||||||
"yoke",
|
|
||||||
"zerofrom",
|
|
||||||
"zerotrie",
|
|
||||||
"zerovec",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ident_case"
|
name = "ident_case"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "idna"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
|
|
||||||
dependencies = [
|
|
||||||
"idna_adapter",
|
|
||||||
"smallvec",
|
|
||||||
"utf8_iter",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "idna_adapter"
|
|
||||||
version = "1.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
|
|
||||||
dependencies = [
|
|
||||||
"icu_normalizer",
|
|
||||||
"icu_properties",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ignore"
|
|
||||||
version = "0.4.23"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-deque",
|
|
||||||
"globset",
|
|
||||||
"log",
|
|
||||||
"memchr",
|
|
||||||
"regex-automata",
|
|
||||||
"same-file",
|
|
||||||
"walkdir",
|
|
||||||
"winapi-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "image"
|
name = "image"
|
||||||
version = "0.25.8"
|
version = "0.25.8"
|
||||||
|
|
@ -2088,18 +1932,6 @@ dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libgit2-sys"
|
|
||||||
version = "0.17.0+1.8.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "10472326a8a6477c3c20a64547b0059e4b0d086869eee31e6d7da728a8eb7224"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"libc",
|
|
||||||
"libz-sys",
|
|
||||||
"pkg-config",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libm"
|
name = "libm"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
|
|
@ -2116,18 +1948,6 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libz-sys"
|
|
||||||
version = "1.1.22"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"libc",
|
|
||||||
"pkg-config",
|
|
||||||
"vcpkg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.4.15"
|
version = "0.4.15"
|
||||||
|
|
@ -2140,12 +1960,6 @@ version = "0.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
|
checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "litemap"
|
|
||||||
version = "0.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "litrs"
|
name = "litrs"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
|
@ -2879,15 +2693,6 @@ dependencies = [
|
||||||
"universal-hash",
|
"universal-hash",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "potential_utf"
|
|
||||||
version = "0.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a"
|
|
||||||
dependencies = [
|
|
||||||
"zerovec",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "powerfmt"
|
name = "powerfmt"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
|
@ -3729,12 +3534,6 @@ dependencies = [
|
||||||
"sha2",
|
"sha2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "stable_deref_trait"
|
|
||||||
version = "1.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "static_assertions"
|
name = "static_assertions"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
|
@ -3786,17 +3585,6 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "synstructure"
|
|
||||||
version = "0.13.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syntect"
|
name = "syntect"
|
||||||
version = "5.3.0"
|
version = "5.3.0"
|
||||||
|
|
@ -3944,16 +3732,6 @@ dependencies = [
|
||||||
"time-core",
|
"time-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tinystr"
|
|
||||||
version = "0.8.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b"
|
|
||||||
dependencies = [
|
|
||||||
"displaydoc",
|
|
||||||
"zerovec",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.48.0"
|
version = "1.48.0"
|
||||||
|
|
@ -4242,30 +4020,12 @@ version = "0.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "url"
|
|
||||||
version = "2.5.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b"
|
|
||||||
dependencies = [
|
|
||||||
"form_urlencoded",
|
|
||||||
"idna",
|
|
||||||
"percent-encoding",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "urlencoding"
|
name = "urlencoding"
|
||||||
version = "2.1.3"
|
version = "2.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
|
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "utf8_iter"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "utf8parse"
|
name = "utf8parse"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
|
|
@ -4310,12 +4070,6 @@ version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
|
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vcpkg"
|
|
||||||
version = "0.2.15"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vergen"
|
name = "vergen"
|
||||||
version = "9.0.6"
|
version = "9.0.6"
|
||||||
|
|
@ -4874,12 +4628,6 @@ version = "0.46.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
|
checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "writeable"
|
|
||||||
version = "0.6.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wyz"
|
name = "wyz"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
|
|
@ -5164,9 +4912,7 @@ dependencies = [
|
||||||
"core-foundation-sys",
|
"core-foundation-sys",
|
||||||
"dirs",
|
"dirs",
|
||||||
"foldhash 0.2.0",
|
"foldhash 0.2.0",
|
||||||
"git2",
|
|
||||||
"hashbrown 0.16.0",
|
"hashbrown 0.16.0",
|
||||||
"ignore",
|
|
||||||
"libc",
|
"libc",
|
||||||
"objc2",
|
"objc2",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
|
|
@ -5414,30 +5160,6 @@ dependencies = [
|
||||||
"yazi-term",
|
"yazi-term",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "yoke"
|
|
||||||
version = "0.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc"
|
|
||||||
dependencies = [
|
|
||||||
"serde",
|
|
||||||
"stable_deref_trait",
|
|
||||||
"yoke-derive",
|
|
||||||
"zerofrom",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "yoke-derive"
|
|
||||||
version = "0.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
"synstructure",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.8.27"
|
version = "0.8.27"
|
||||||
|
|
@ -5458,66 +5180,12 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zerofrom"
|
|
||||||
version = "0.1.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5"
|
|
||||||
dependencies = [
|
|
||||||
"zerofrom-derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zerofrom-derive"
|
|
||||||
version = "0.1.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
"synstructure",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zeroize"
|
name = "zeroize"
|
||||||
version = "1.8.2"
|
version = "1.8.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
|
checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zerotrie"
|
|
||||||
version = "0.2.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595"
|
|
||||||
dependencies = [
|
|
||||||
"displaydoc",
|
|
||||||
"yoke",
|
|
||||||
"zerofrom",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zerovec"
|
|
||||||
version = "0.11.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b"
|
|
||||||
dependencies = [
|
|
||||||
"yoke",
|
|
||||||
"zerofrom",
|
|
||||||
"zerovec-derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zerovec-derive"
|
|
||||||
version = "0.11.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zune-core"
|
name = "zune-core"
|
||||||
version = "0.4.12"
|
version = "0.4.12"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = ["yazi-*"]
|
members = [ "yazi-*" ]
|
||||||
default-members = ["yazi-fm", "yazi-cli"]
|
default-members = [ "yazi-fm", "yazi-cli" ]
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,6 @@ impl Actor for Ignore {
|
||||||
const NAME: &str = "ignore";
|
const NAME: &str = "ignore";
|
||||||
|
|
||||||
fn act(cx: &mut Ctx, _: Self::Options) -> Result<Data> {
|
fn act(cx: &mut Ctx, _: Self::Options) -> Result<Data> {
|
||||||
let gitignores = YAZI.files.gitignores;
|
|
||||||
|
|
||||||
// Get the appropriate context string for matching exclude rules
|
// Get the appropriate context string for matching exclude rules
|
||||||
// For search directories, use "search://**" as the context
|
// For search directories, use "search://**" as the context
|
||||||
let cwd = cx.cwd();
|
let cwd = cx.cwd();
|
||||||
|
|
@ -32,20 +30,17 @@ impl Actor for Ignore {
|
||||||
let exclude_patterns = YAZI.files.excludes_for_context(&cwd_str);
|
let exclude_patterns = YAZI.files.excludes_for_context(&cwd_str);
|
||||||
|
|
||||||
// Create glob matcher function for compiled patterns
|
// Create glob matcher function for compiled patterns
|
||||||
let glob_matcher = {
|
let glob_matcher: Option<Arc<dyn Fn(&std::path::Path) -> Option<bool> + Send + Sync>> =
|
||||||
|
if !exclude_patterns.is_empty() {
|
||||||
let context = cwd_str.clone();
|
let context = cwd_str.clone();
|
||||||
Arc::new(move |path: &std::path::Path| YAZI.files.matches_path(path, &context))
|
Some(Arc::new(move |path: &std::path::Path| YAZI.files.matches_path(path, &context)))
|
||||||
};
|
|
||||||
|
|
||||||
// If gitignores is disabled but we have exclude patterns, apply them
|
|
||||||
if !gitignores && !exclude_patterns.is_empty() {
|
|
||||||
// Load ignore filter from exclude patterns only
|
|
||||||
let ignore_filter = if let Some(path) = cx.cwd().as_path() {
|
|
||||||
IgnoreFilter::from_patterns(path, &exclude_patterns, Some(glob_matcher.clone()))
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Load ignore filter from exclude patterns
|
||||||
|
let ignore_filter = IgnoreFilter::from_patterns(glob_matcher.clone());
|
||||||
|
|
||||||
let hovered = cx.hovered().map(|f| f.urn().to_owned());
|
let hovered = cx.hovered().map(|f| f.urn().to_owned());
|
||||||
let apply = |f: &mut Folder, filter: Option<IgnoreFilter>| {
|
let apply = |f: &mut Folder, filter: Option<IgnoreFilter>| {
|
||||||
// Always set the filter, even when loading
|
// Always set the filter, even when loading
|
||||||
|
|
@ -72,112 +67,14 @@ impl Actor for Ignore {
|
||||||
h.url.as_path().map(|p| p.display().to_string()).unwrap_or_default()
|
h.url.as_path().map(|p| p.display().to_string()).unwrap_or_default()
|
||||||
};
|
};
|
||||||
let hovered_excludes = YAZI.files.excludes_for_context(&hovered_str);
|
let hovered_excludes = YAZI.files.excludes_for_context(&hovered_str);
|
||||||
let hovered_matcher = {
|
let hovered_matcher: Option<Arc<dyn Fn(&std::path::Path) -> Option<bool> + Send + Sync>> =
|
||||||
|
if !hovered_excludes.is_empty() {
|
||||||
let context = hovered_str.clone();
|
let context = hovered_str.clone();
|
||||||
Arc::new(move |path: &std::path::Path| YAZI.files.matches_path(path, &context))
|
Some(Arc::new(move |path: &std::path::Path| YAZI.files.matches_path(path, &context)))
|
||||||
};
|
|
||||||
let hovered_filter = if let Some(path) = h.url.as_path() {
|
|
||||||
IgnoreFilter::from_patterns(path, &hovered_excludes, Some(hovered_matcher))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
if apply(h, hovered_filter) {
|
|
||||||
render!(h.repos(None));
|
|
||||||
act!(mgr:peek, cx, true)?;
|
|
||||||
} else if hovered.as_deref() != cx.hovered().map(|f| f.urn()) {
|
|
||||||
act!(mgr:peek, cx)?;
|
|
||||||
act!(mgr:watch, cx)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
succ!();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If gitignores is disabled and no exclude patterns, remove any ignore filter
|
|
||||||
if !gitignores {
|
|
||||||
let hovered = cx.hovered().map(|f| f.urn().to_owned());
|
|
||||||
let apply = |f: &mut Folder| {
|
|
||||||
// Always clear the filter, even when loading
|
|
||||||
let changed = f.files.set_ignore_filter(None);
|
|
||||||
if f.stage == FolderStage::Loading {
|
|
||||||
render!();
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
render_and!(changed && f.files.catchup_revision())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Apply to CWD and parent
|
|
||||||
if let (a, Some(b)) = (apply(cx.current_mut()), cx.parent_mut().map(apply))
|
|
||||||
&& (a | b)
|
|
||||||
{
|
|
||||||
act!(mgr:hover, cx)?;
|
|
||||||
act!(mgr:update_paged, cx)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply to hovered
|
|
||||||
if let Some(h) = cx.hovered_folder_mut()
|
|
||||||
&& apply(h)
|
|
||||||
{
|
|
||||||
render!(h.repos(None));
|
|
||||||
act!(mgr:peek, cx, true)?;
|
|
||||||
} else if hovered.as_deref() != cx.hovered().map(|f| f.urn()) {
|
|
||||||
act!(mgr:peek, cx)?;
|
|
||||||
act!(mgr:watch, cx)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
succ!();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load ignore filter from the current directory
|
|
||||||
let ignore_filter = if let Some(path) = cx.cwd().as_path() {
|
|
||||||
IgnoreFilter::from_dir(path, &exclude_patterns, gitignores, Some(glob_matcher.clone()))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let hovered = cx.hovered().map(|f| f.urn().to_owned());
|
|
||||||
let apply = |f: &mut Folder, filter: Option<IgnoreFilter>| {
|
|
||||||
// Always set the filter, even when loading, so files are filtered as they
|
|
||||||
// arrive
|
|
||||||
let changed = f.files.set_ignore_filter(filter);
|
|
||||||
if f.stage == FolderStage::Loading {
|
|
||||||
render!();
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
render_and!(changed && f.files.catchup_revision())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Apply to CWD
|
|
||||||
if apply(cx.current_mut(), ignore_filter.clone()) {
|
|
||||||
act!(mgr:hover, cx)?;
|
|
||||||
act!(mgr:update_paged, cx)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply to parent (they should use their own ignore file, so we don't apply the
|
|
||||||
// same filter) Parent folders will be updated when they become the current
|
|
||||||
// directory
|
|
||||||
|
|
||||||
// Apply to hovered
|
|
||||||
if let Some(h) = cx.hovered_folder_mut() {
|
|
||||||
// Load ignore filter for hovered directory if it's a directory
|
|
||||||
let hovered_str = if h.url.is_search() {
|
|
||||||
"search://**".to_string()
|
|
||||||
} else {
|
|
||||||
h.url.as_path().map(|p| p.display().to_string()).unwrap_or_default()
|
|
||||||
};
|
|
||||||
let hovered_excludes = YAZI.files.excludes_for_context(&hovered_str);
|
|
||||||
let hovered_matcher = {
|
|
||||||
let context = hovered_str.clone();
|
|
||||||
Arc::new(move |path: &std::path::Path| YAZI.files.matches_path(path, &context))
|
|
||||||
};
|
|
||||||
let hovered_filter = if let Some(path) = h.url.as_path() {
|
|
||||||
IgnoreFilter::from_dir(path, &hovered_excludes, gitignores, Some(hovered_matcher))
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
let hovered_filter = IgnoreFilter::from_patterns(hovered_matcher);
|
||||||
|
|
||||||
if apply(h, hovered_filter) {
|
if apply(h, hovered_filter) {
|
||||||
render!(h.repos(None));
|
render!(h.repos(None));
|
||||||
|
|
|
||||||
|
|
@ -16,26 +16,6 @@ scrolloff = 5
|
||||||
mouse_events = [ "click", "scroll" ]
|
mouse_events = [ "click", "scroll" ]
|
||||||
title_format = "Yazi: {cwd}"
|
title_format = "Yazi: {cwd}"
|
||||||
|
|
||||||
[files]
|
|
||||||
# Enable git ignore integration
|
|
||||||
# gitignores = false
|
|
||||||
|
|
||||||
# Context-specific exclude patterns
|
|
||||||
# Patterns are compiled into glob matchers for efficient matching
|
|
||||||
# Patterns starting with '!' negate (whitelist) previous matches
|
|
||||||
# excludes = [
|
|
||||||
# # SFTP temporary files
|
|
||||||
# { urn = "*.tmp", in = "sftp://**" },
|
|
||||||
# # Python cache in search results
|
|
||||||
# { urn = "/root/**/*.pyc", in = "search://**" },
|
|
||||||
# # Multiple patterns for /code directory (supports arrays)
|
|
||||||
# { urn = [".git", ".DS_Store", "__pycache__"], in = "/code/**" },
|
|
||||||
# # Negation: show target/ even if previously ignored
|
|
||||||
# { urn = "!target/", in = "/code/**" },
|
|
||||||
# # Fallback rule for all contexts
|
|
||||||
# { urn = ".DS_Store", in = "*" },
|
|
||||||
# ]
|
|
||||||
|
|
||||||
[preview]
|
[preview]
|
||||||
wrap = "no"
|
wrap = "no"
|
||||||
tab_size = 2
|
tab_size = 2
|
||||||
|
|
@ -46,7 +26,28 @@ image_delay = 30
|
||||||
image_filter = "triangle"
|
image_filter = "triangle"
|
||||||
image_quality = 75
|
image_quality = 75
|
||||||
ueberzug_scale = 1
|
ueberzug_scale = 1
|
||||||
ueberzug_offset = [0, 0, 0, 0]
|
ueberzug_offset = [ 0, 0, 0, 0 ]
|
||||||
|
|
||||||
|
|
||||||
|
[files]
|
||||||
|
# Context-specific exclude patterns
|
||||||
|
# Patterns are compiled into glob matchers for efficient matching
|
||||||
|
# Patterns starting with '!' negate (whitelist) previous matches
|
||||||
|
# Note: To match directories, use patterns like ".git/" or "**/.git/**"
|
||||||
|
# excludes = [
|
||||||
|
# # SFTP temporary files
|
||||||
|
# { urn = "*.tmp", in = "sftp://**" },
|
||||||
|
# # Python cache in search results
|
||||||
|
# { urn = "/root/**/*.pyc", in = "search://**" },
|
||||||
|
# # Multiple patterns for /code directory (supports arrays)
|
||||||
|
# { urn = [".git", ".DS_Store", "__pycache__"], in = "*" },
|
||||||
|
# # Exclude release and debug directories inside target/
|
||||||
|
# { urn = "release", in = "**/target" },
|
||||||
|
# # Exclude all json files from all contexts
|
||||||
|
# { urn = "*.json", in = "*" },
|
||||||
|
# # Negation: Show cspell.* even if it's excluded by a previous rule
|
||||||
|
# { urn = "!cspell*", in = "search://**" },
|
||||||
|
# ]
|
||||||
|
|
||||||
[opener]
|
[opener]
|
||||||
edit = [
|
edit = [
|
||||||
|
|
@ -75,7 +76,9 @@ reveal = [
|
||||||
{ run = "termux-open %d1", desc = "Reveal", for = "android" },
|
{ run = "termux-open %d1", desc = "Reveal", for = "android" },
|
||||||
{ run = "clear; exiftool %s1; echo 'Press enter to exit'; read _", desc = "Show EXIF", for = "unix", block = true },
|
{ run = "clear; exiftool %s1; echo 'Press enter to exit'; read _", desc = "Show EXIF", for = "unix", block = true },
|
||||||
]
|
]
|
||||||
extract = [{ run = "ya pub extract --list %s", desc = "Extract here" }]
|
extract = [
|
||||||
|
{ run = "ya pub extract --list %s", desc = "Extract here" },
|
||||||
|
]
|
||||||
download = [
|
download = [
|
||||||
{ run = "ya emit download --open %S", desc = "Download and open" },
|
{ run = "ya emit download --open %S", desc = "Download and open" },
|
||||||
{ run = "ya emit download %S", desc = "Download" },
|
{ run = "ya emit download %S", desc = "Download" },
|
||||||
|
|
@ -84,52 +87,24 @@ download = [
|
||||||
[open]
|
[open]
|
||||||
rules = [
|
rules = [
|
||||||
# Folder
|
# Folder
|
||||||
{ url = "*/", use = [
|
{ url = "*/", use = [ "edit", "open", "reveal" ] },
|
||||||
"edit",
|
|
||||||
"open",
|
|
||||||
"reveal",
|
|
||||||
] },
|
|
||||||
# Text
|
# Text
|
||||||
{ mime = "text/*", use = [
|
{ mime = "text/*", use = [ "edit", "reveal" ] },
|
||||||
"edit",
|
|
||||||
"reveal",
|
|
||||||
] },
|
|
||||||
# Image
|
# Image
|
||||||
{ mime = "image/*", use = [
|
{ mime = "image/*", use = [ "open", "reveal" ] },
|
||||||
"open",
|
|
||||||
"reveal",
|
|
||||||
] },
|
|
||||||
# Media
|
# Media
|
||||||
{ mime = "{audio,video}/*", use = [
|
{ mime = "{audio,video}/*", use = [ "play", "reveal" ] },
|
||||||
"play",
|
|
||||||
"reveal",
|
|
||||||
] },
|
|
||||||
# Archive
|
# Archive
|
||||||
{ mime = "application/{zip,rar,7z*,tar,gzip,xz,zstd,bzip*,lzma,compress,archive,cpio,arj,xar,ms-cab*}", use = [
|
{ mime = "application/{zip,rar,7z*,tar,gzip,xz,zstd,bzip*,lzma,compress,archive,cpio,arj,xar,ms-cab*}", use = [ "extract", "reveal" ] },
|
||||||
"extract",
|
|
||||||
"reveal",
|
|
||||||
] },
|
|
||||||
# JSON
|
# JSON
|
||||||
{ mime = "application/{json,ndjson}", use = [
|
{ mime = "application/{json,ndjson}", use = [ "edit", "reveal" ] },
|
||||||
"edit",
|
{ mime = "*/javascript", use = [ "edit", "reveal" ] },
|
||||||
"reveal",
|
|
||||||
] },
|
|
||||||
{ mime = "*/javascript", use = [
|
|
||||||
"edit",
|
|
||||||
"reveal",
|
|
||||||
] },
|
|
||||||
# Empty file
|
# Empty file
|
||||||
{ mime = "inode/empty", use = [
|
{ mime = "inode/empty", use = [ "edit", "reveal" ] },
|
||||||
"edit",
|
|
||||||
"reveal",
|
|
||||||
] },
|
|
||||||
# Virtual file system
|
# Virtual file system
|
||||||
{ mime = "vfs/{absent,stale}", use = "download" },
|
{ mime = "vfs/{absent,stale}", use = "download" },
|
||||||
# Fallback
|
# Fallback
|
||||||
{ url = "*", use = [
|
{ url = "*", use = [ "open", "reveal" ] },
|
||||||
"open",
|
|
||||||
"reveal",
|
|
||||||
] },
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[tasks]
|
[tasks]
|
||||||
|
|
@ -137,7 +112,7 @@ micro_workers = 10
|
||||||
macro_workers = 10
|
macro_workers = 10
|
||||||
bizarre_retry = 3
|
bizarre_retry = 3
|
||||||
image_alloc = 536870912 # 512MB
|
image_alloc = 536870912 # 512MB
|
||||||
image_bound = [10000, 10000]
|
image_bound = [ 10000, 10000 ]
|
||||||
suppress_preload = false
|
suppress_preload = false
|
||||||
|
|
||||||
[plugin]
|
[plugin]
|
||||||
|
|
@ -216,65 +191,65 @@ cursor_blink = false
|
||||||
# cd
|
# cd
|
||||||
cd_title = "Change directory:"
|
cd_title = "Change directory:"
|
||||||
cd_origin = "top-center"
|
cd_origin = "top-center"
|
||||||
cd_offset = [0, 2, 50, 3]
|
cd_offset = [ 0, 2, 50, 3 ]
|
||||||
|
|
||||||
# create
|
# create
|
||||||
create_title = ["Create:", "Create (dir):"]
|
create_title = [ "Create:", "Create (dir):" ]
|
||||||
create_origin = "top-center"
|
create_origin = "top-center"
|
||||||
create_offset = [0, 2, 50, 3]
|
create_offset = [ 0, 2, 50, 3 ]
|
||||||
|
|
||||||
# rename
|
# rename
|
||||||
rename_title = "Rename:"
|
rename_title = "Rename:"
|
||||||
rename_origin = "hovered"
|
rename_origin = "hovered"
|
||||||
rename_offset = [0, 1, 50, 3]
|
rename_offset = [ 0, 1, 50, 3 ]
|
||||||
|
|
||||||
# filter
|
# filter
|
||||||
filter_title = "Filter:"
|
filter_title = "Filter:"
|
||||||
filter_origin = "top-center"
|
filter_origin = "top-center"
|
||||||
filter_offset = [0, 2, 50, 3]
|
filter_offset = [ 0, 2, 50, 3 ]
|
||||||
|
|
||||||
# find
|
# find
|
||||||
find_title = ["Find next:", "Find previous:"]
|
find_title = [ "Find next:", "Find previous:" ]
|
||||||
find_origin = "top-center"
|
find_origin = "top-center"
|
||||||
find_offset = [0, 2, 50, 3]
|
find_offset = [ 0, 2, 50, 3 ]
|
||||||
|
|
||||||
# search
|
# search
|
||||||
search_title = "Search via {n}:"
|
search_title = "Search via {n}:"
|
||||||
search_origin = "top-center"
|
search_origin = "top-center"
|
||||||
search_offset = [0, 2, 50, 3]
|
search_offset = [ 0, 2, 50, 3 ]
|
||||||
|
|
||||||
# shell
|
# shell
|
||||||
shell_title = ["Shell:", "Shell (block):"]
|
shell_title = [ "Shell:", "Shell (block):" ]
|
||||||
shell_origin = "top-center"
|
shell_origin = "top-center"
|
||||||
shell_offset = [0, 2, 50, 3]
|
shell_offset = [ 0, 2, 50, 3 ]
|
||||||
|
|
||||||
[confirm]
|
[confirm]
|
||||||
# trash
|
# trash
|
||||||
trash_title = "Trash {n} selected file{s}?"
|
trash_title = "Trash {n} selected file{s}?"
|
||||||
trash_origin = "center"
|
trash_origin = "center"
|
||||||
trash_offset = [0, 0, 70, 20]
|
trash_offset = [ 0, 0, 70, 20 ]
|
||||||
|
|
||||||
# delete
|
# delete
|
||||||
delete_title = "Permanently delete {n} selected file{s}?"
|
delete_title = "Permanently delete {n} selected file{s}?"
|
||||||
delete_origin = "center"
|
delete_origin = "center"
|
||||||
delete_offset = [0, 0, 70, 20]
|
delete_offset = [ 0, 0, 70, 20 ]
|
||||||
|
|
||||||
# overwrite
|
# overwrite
|
||||||
overwrite_title = "Overwrite file?"
|
overwrite_title = "Overwrite file?"
|
||||||
overwrite_body = "Will overwrite the following file:"
|
overwrite_body = "Will overwrite the following file:"
|
||||||
overwrite_origin = "center"
|
overwrite_origin = "center"
|
||||||
overwrite_offset = [0, 0, 50, 15]
|
overwrite_offset = [ 0, 0, 50, 15 ]
|
||||||
|
|
||||||
# quit
|
# quit
|
||||||
quit_title = "Quit?"
|
quit_title = "Quit?"
|
||||||
quit_body = "The following tasks are still running, are you sure you want to quit?"
|
quit_body = "The following tasks are still running, are you sure you want to quit?"
|
||||||
quit_origin = "center"
|
quit_origin = "center"
|
||||||
quit_offset = [0, 0, 50, 15]
|
quit_offset = [ 0, 0, 50, 15 ]
|
||||||
|
|
||||||
[pick]
|
[pick]
|
||||||
open_title = "Open with:"
|
open_title = "Open with:"
|
||||||
open_origin = "hovered"
|
open_origin = "hovered"
|
||||||
open_offset = [0, 1, 50, 7]
|
open_offset = [ 0, 1, 50, 7 ]
|
||||||
|
|
||||||
[which]
|
[which]
|
||||||
sort_by = "none"
|
sort_by = "none"
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,7 @@ pub struct Exclude {
|
||||||
|
|
||||||
/// Context where this exclude rule applies
|
/// Context where this exclude rule applies
|
||||||
/// Supports glob patterns like "/code/**", "sftp://**", "search://**", or "*" for all
|
/// Supports glob patterns like "/code/**", "sftp://**", "search://**", or "*" for all
|
||||||
#[serde(rename = "in")]
|
pub r#in: String,
|
||||||
pub context: String,
|
|
||||||
|
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
compiled: Option<CompiledPatterns>,
|
compiled: Option<CompiledPatterns>,
|
||||||
|
|
@ -78,15 +77,40 @@ impl Exclude {
|
||||||
pub fn matches_path(&self, path: &Path) -> Option<bool> {
|
pub fn matches_path(&self, path: &Path) -> Option<bool> {
|
||||||
let compiled = self.compiled.as_ref()?;
|
let compiled = self.compiled.as_ref()?;
|
||||||
|
|
||||||
|
// For absolute paths, try both the full path and relative components
|
||||||
|
// This helps patterns like **/.git/** match /home/user/project/.git
|
||||||
|
let paths_to_check: Vec<&Path> = if path.is_absolute() {
|
||||||
|
// Also check each component as if it's relative
|
||||||
|
// This allows **/.git/** to match /home/user/.git/config
|
||||||
|
let mut paths = vec![path];
|
||||||
|
|
||||||
|
// Check if any path component matches by checking relative sub-paths
|
||||||
|
// For /home/user/.git/config, we want to match against .git/config too
|
||||||
|
if let Some(components) = path.to_str() {
|
||||||
|
for (i, _) in components.match_indices('/').skip(1) {
|
||||||
|
if let Some(subpath) = components.get(i + 1..) {
|
||||||
|
paths.push(Path::new(subpath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
paths
|
||||||
|
} else {
|
||||||
|
vec![path]
|
||||||
|
};
|
||||||
|
|
||||||
// Check whitelist first (negation takes precedence)
|
// Check whitelist first (negation takes precedence)
|
||||||
if compiled.whitelists.is_match(path) {
|
for p in &paths_to_check {
|
||||||
|
if compiled.whitelists.is_match(p) {
|
||||||
return Some(false); // Explicitly NOT ignored
|
return Some(false); // Explicitly NOT ignored
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check ignore patterns
|
// Check ignore patterns
|
||||||
if compiled.ignores.is_match(path) {
|
for p in &paths_to_check {
|
||||||
|
if compiled.ignores.is_match(p) {
|
||||||
return Some(true); // Should be ignored
|
return Some(true); // Should be ignored
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
None // No match
|
None // No match
|
||||||
}
|
}
|
||||||
|
|
@ -94,23 +118,49 @@ impl Exclude {
|
||||||
/// Check if this exclude rule applies to the given path context
|
/// Check if this exclude rule applies to the given path context
|
||||||
pub fn matches_context(&self, path: &str) -> bool {
|
pub fn matches_context(&self, path: &str) -> bool {
|
||||||
// Wildcard matches everything
|
// Wildcard matches everything
|
||||||
if self.context == "*" {
|
if self.r#in == "*" {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle patterns starting with **/ (e.g., **/target or **/target/**)
|
||||||
|
if self.r#in.starts_with("**/") {
|
||||||
|
let pattern = &self.r#in[3..]; // Remove leading "**/", e.g., "target" or "target/**"
|
||||||
|
|
||||||
|
// Strip trailing /** if present
|
||||||
|
let pattern = if let Some(p) = pattern.strip_suffix("/**") {
|
||||||
|
p
|
||||||
|
} else {
|
||||||
|
pattern
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check if path ends with the pattern (e.g., /home/user/project/target matches **/target)
|
||||||
|
if path.ends_with(&format!("/{}", pattern)) || path.ends_with(pattern) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if path contains the pattern as a directory segment
|
||||||
|
if path.contains(&format!("/{}/", pattern)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Handle glob patterns with wildcard
|
// Handle glob patterns with wildcard
|
||||||
if self.context.ends_with("/**") {
|
if self.r#in.ends_with("/**") {
|
||||||
let prefix = &self.context[..self.context.len() - 3];
|
let prefix = &self.r#in[..self.r#in.len() - 3];
|
||||||
|
|
||||||
// Check if path starts with prefix (absolute path match)
|
// Check if path starts with prefix (absolute path match)
|
||||||
if path.starts_with(prefix) {
|
if path.starts_with(prefix) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if path contains the pattern anywhere (for relative patterns like "/target/**")
|
// Check if path contains the pattern anywhere (for relative patterns like
|
||||||
// This allows "/target/**" to match "/home/user/project/target/debug"
|
// "/target/**") This allows "/target/**" to match
|
||||||
|
// "/home/user/project/target/debug"
|
||||||
if prefix.starts_with('/') && !prefix.starts_with("//") {
|
if prefix.starts_with('/') && !prefix.starts_with("//") {
|
||||||
// Single leading slash means relative pattern - check if path contains this segment
|
// Single leading slash means relative pattern - check if path contains this
|
||||||
|
// segment
|
||||||
let pattern = &prefix[1..]; // Remove leading slash
|
let pattern = &prefix[1..]; // Remove leading slash
|
||||||
if path.contains(&format!("/{}/", pattern)) || path.ends_with(&format!("/{}", pattern)) {
|
if path.contains(&format!("/{}/", pattern)) || path.ends_with(&format!("/{}", pattern)) {
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -121,6 +171,6 @@ impl Exclude {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exact match or prefix match for non-wildcard patterns
|
// Exact match or prefix match for non-wildcard patterns
|
||||||
path == self.context || path.starts_with(&format!("{}/", self.context))
|
path == self.r#in || path.starts_with(&format!("{}/", self.r#in))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,6 @@ use super::Exclude;
|
||||||
/// Configuration for file filtering
|
/// Configuration for file filtering
|
||||||
#[derive(Debug, Deserialize, DeserializeOver2, Default)]
|
#[derive(Debug, Deserialize, DeserializeOver2, Default)]
|
||||||
pub struct Files {
|
pub struct Files {
|
||||||
/// Enable git ignore integration
|
|
||||||
#[serde(default)]
|
|
||||||
pub gitignores: bool,
|
|
||||||
|
|
||||||
/// List of exclude rules with context-specific patterns
|
/// List of exclude rules with context-specific patterns
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub excludes: Vec<Exclude>,
|
pub excludes: Vec<Exclude>,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ name = "yazi-fs"
|
||||||
version = "25.9.15"
|
version = "25.9.15"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["sxyazi <sxyazi@gmail.com>"]
|
authors = [ "sxyazi <sxyazi@gmail.com>" ]
|
||||||
description = "Yazi file system"
|
description = "Yazi file system"
|
||||||
homepage = "https://yazi-rs.github.io"
|
homepage = "https://yazi-rs.github.io"
|
||||||
repository = "https://github.com/sxyazi/yazi"
|
repository = "https://github.com/sxyazi/yazi"
|
||||||
|
|
@ -20,9 +20,7 @@ arc-swap = "1.7.1"
|
||||||
bitflags = { workspace = true }
|
bitflags = { workspace = true }
|
||||||
dirs = { workspace = true }
|
dirs = { workspace = true }
|
||||||
foldhash = { workspace = true }
|
foldhash = { workspace = true }
|
||||||
git2 = { workspace = true }
|
|
||||||
hashbrown = { workspace = true }
|
hashbrown = { workspace = true }
|
||||||
ignore = { workspace = true }
|
|
||||||
parking_lot = { workspace = true }
|
parking_lot = { workspace = true }
|
||||||
percent-encoding = { workspace = true }
|
percent-encoding = { workspace = true }
|
||||||
regex = { workspace = true }
|
regex = { workspace = true }
|
||||||
|
|
@ -36,11 +34,11 @@ libc = { workspace = true }
|
||||||
uzers = { workspace = true }
|
uzers = { workspace = true }
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
windows-sys = { version = "0.61.2", features = ["Win32_Storage_FileSystem"] }
|
windows-sys = { version = "0.61.2", features = [ "Win32_Storage_FileSystem" ] }
|
||||||
|
|
||||||
[target.'cfg(target_os = "macos")'.dependencies]
|
[target.'cfg(target_os = "macos")'.dependencies]
|
||||||
core-foundation-sys = { workspace = true }
|
core-foundation-sys = { workspace = true }
|
||||||
objc = { workspace = true }
|
objc2 = { workspace = true }
|
||||||
|
|
||||||
[target.'cfg(not(target_os = "android"))'.dependencies]
|
[target.'cfg(not(target_os = "android"))'.dependencies]
|
||||||
trash = "5.2.5"
|
trash = "5.2.5"
|
||||||
|
|
|
||||||
|
|
@ -1,171 +1,46 @@
|
||||||
use std::{collections::HashSet, path::{Path, PathBuf}, sync::Arc};
|
use std::{path::Path, sync::Arc};
|
||||||
|
|
||||||
use yazi_shared::url::AsUrl;
|
use yazi_shared::url::AsUrl;
|
||||||
|
|
||||||
/// Filter for ignoring files based on git ignore rules and custom exclude
|
/// Filter for ignoring files based on custom exclude patterns.
|
||||||
/// patterns.
|
|
||||||
///
|
///
|
||||||
/// This filter combines git's native ignore functionality with custom exclude
|
/// Exclude patterns can be context-specific and support negation using the `!`
|
||||||
/// patterns that follow gitignore syntax. Exclude patterns can be
|
/// prefix for whitelisting.
|
||||||
/// context-specific and take precedence over git's ignore rules using the `!`
|
|
||||||
/// prefix for negation.
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct IgnoreFilter {
|
pub struct IgnoreFilter {
|
||||||
/// Set of paths ignored by git (from git status)
|
/// Custom glob-based matcher function for pattern matching
|
||||||
ignored_paths: HashSet<PathBuf>,
|
/// Returns Some(true) if should be ignored, Some(false) if whitelisted, None
|
||||||
/// Custom gitignore matcher for exclude patterns
|
/// if no match
|
||||||
gitignore: Option<ignore::gitignore::Gitignore>,
|
|
||||||
/// Custom glob-based matcher function for advanced pattern matching
|
|
||||||
/// Returns Some(true) if should be ignored, Some(false) if whitelisted, None if no match
|
|
||||||
glob_matcher: Option<Arc<dyn Fn(&Path) -> Option<bool> + Send + Sync>>,
|
glob_matcher: Option<Arc<dyn Fn(&Path) -> Option<bool> + Send + Sync>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for IgnoreFilter {
|
impl std::fmt::Debug for IgnoreFilter {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.debug_struct("IgnoreFilter")
|
f.debug_struct("IgnoreFilter")
|
||||||
.field("ignored_paths", &self.ignored_paths)
|
|
||||||
.field("gitignore", &self.gitignore)
|
|
||||||
.field("glob_matcher", &self.glob_matcher.as_ref().map(|_| "Some(...)"))
|
.field("glob_matcher", &self.glob_matcher.as_ref().map(|_| "Some(...)"))
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IgnoreFilter {
|
impl IgnoreFilter {
|
||||||
/// Creates a new `IgnoreFilter` by checking git ignore status for the given
|
/// Creates a new `IgnoreFilter` from exclude patterns.
|
||||||
/// directory.
|
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `dir` - Directory to check for git ignore status
|
/// * `glob_matcher` - Custom glob-based matcher function for advanced pattern
|
||||||
/// * `exclude_patterns` - Custom gitignore patterns that override git's rules
|
/// matching
|
||||||
/// * `use_git` - Whether to integrate with git ignore rules
|
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
///
|
///
|
||||||
/// `Some(IgnoreFilter)` if git repository is found (when use_git=true) or
|
/// `Some(IgnoreFilter)` if glob_matcher is provided, `None` otherwise.
|
||||||
/// exclude patterns exist, `None` if no git repository and no exclude
|
|
||||||
/// patterns.
|
|
||||||
///
|
|
||||||
/// # Behavior
|
|
||||||
///
|
|
||||||
/// - Discovers the git repository containing `dir` (if use_git=true)
|
|
||||||
/// - Collects all ignored paths from git status
|
|
||||||
/// - Builds a custom gitignore matcher from exclude patterns (relative to
|
|
||||||
/// repo root)
|
|
||||||
/// - Exclude patterns are checked first and take precedence over git ignore
|
|
||||||
/// rules
|
|
||||||
/// - Negation patterns (starting with `!`) can whitelist git-ignored files
|
|
||||||
pub fn from_dir(
|
|
||||||
dir: impl AsRef<Path>,
|
|
||||||
exclude_patterns: &[String],
|
|
||||||
use_git: bool,
|
|
||||||
glob_matcher: Option<Arc<dyn Fn(&Path) -> Option<bool> + Send + Sync>>,
|
|
||||||
) -> Option<Self> {
|
|
||||||
let dir = dir.as_ref();
|
|
||||||
|
|
||||||
let (workdir, ignored_paths) = if use_git {
|
|
||||||
// Try to open the git repository for this directory
|
|
||||||
let repo = git2::Repository::discover(dir).ok()?;
|
|
||||||
|
|
||||||
// Get the workdir (root of the git repository)
|
|
||||||
let workdir = repo.workdir()?.to_path_buf();
|
|
||||||
|
|
||||||
// Get git statuses for the repository
|
|
||||||
let statuses = match repo.statuses(None) {
|
|
||||||
Ok(s) => s,
|
|
||||||
Err(_) => return None,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Build a set of ALL ignored paths from git status
|
|
||||||
let mut ignored_paths = HashSet::new();
|
|
||||||
|
|
||||||
// Manually add .git directory as ignored (like eza does)
|
|
||||||
ignored_paths.insert(workdir.join(".git"));
|
|
||||||
|
|
||||||
// Add all ignored files from git status
|
|
||||||
for status in statuses.iter() {
|
|
||||||
if status.status() == git2::Status::IGNORED
|
|
||||||
&& let Some(path) = status.path()
|
|
||||||
{
|
|
||||||
ignored_paths.insert(workdir.join(path));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(workdir, ignored_paths)
|
|
||||||
} else {
|
|
||||||
// No git integration, use current directory as base
|
|
||||||
(dir.to_path_buf(), HashSet::new())
|
|
||||||
};
|
|
||||||
|
|
||||||
// Build custom gitignore from exclude patterns if provided
|
|
||||||
let gitignore = if !exclude_patterns.is_empty() {
|
|
||||||
let mut builder = ignore::gitignore::GitignoreBuilder::new(&workdir);
|
|
||||||
|
|
||||||
// Add each exclude pattern
|
|
||||||
for pattern in exclude_patterns {
|
|
||||||
let _ = builder.add_line(None, pattern);
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.build().ok()
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
if ignored_paths.is_empty()
|
|
||||||
|| (ignored_paths.len() == 1 && ignored_paths.contains(&workdir.join(".git")))
|
|
||||||
{
|
|
||||||
// If we have no git-ignored paths but we have exclude patterns or glob matcher, still create
|
|
||||||
// the filter
|
|
||||||
if gitignore.is_some() || glob_matcher.is_some() {
|
|
||||||
return Some(Self { ignored_paths, gitignore, glob_matcher });
|
|
||||||
}
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store ALL ignored paths, not just the ones in the current directory
|
|
||||||
// This way, when files are loaded later, we can check them against the full set
|
|
||||||
Some(Self { ignored_paths, gitignore, glob_matcher })
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new `IgnoreFilter` from only exclude patterns without git
|
|
||||||
/// integration.
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// * `dir` - Base directory for pattern matching
|
|
||||||
/// * `patterns` - Gitignore-style patterns to apply
|
|
||||||
///
|
|
||||||
/// # Returns
|
|
||||||
///
|
|
||||||
/// `Some(IgnoreFilter)` if patterns are provided, `None` if patterns is
|
|
||||||
/// empty.
|
|
||||||
///
|
|
||||||
/// This is useful when `gitignores = false` but custom exclude patterns
|
|
||||||
/// are still desired.
|
|
||||||
pub fn from_patterns(
|
pub fn from_patterns(
|
||||||
dir: impl AsRef<Path>,
|
|
||||||
patterns: &[String],
|
|
||||||
glob_matcher: Option<Arc<dyn Fn(&Path) -> Option<bool> + Send + Sync>>,
|
glob_matcher: Option<Arc<dyn Fn(&Path) -> Option<bool> + Send + Sync>>,
|
||||||
) -> Option<Self> {
|
) -> Option<Self> {
|
||||||
if patterns.is_empty() && glob_matcher.is_none() {
|
if glob_matcher.is_none() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let gitignore = if !patterns.is_empty() {
|
Some(Self { glob_matcher })
|
||||||
let dir = dir.as_ref();
|
|
||||||
let mut builder = ignore::gitignore::GitignoreBuilder::new(dir);
|
|
||||||
|
|
||||||
// Add each pattern
|
|
||||||
for pattern in patterns {
|
|
||||||
let _ = builder.add_line(None, pattern);
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.build().ok()
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(Self { ignored_paths: HashSet::new(), gitignore, glob_matcher })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if a file should be ignored based on its URL.
|
/// Checks if a file should be ignored based on its URL.
|
||||||
|
|
@ -180,83 +55,19 @@ impl IgnoreFilter {
|
||||||
///
|
///
|
||||||
/// # Matching Logic
|
/// # Matching Logic
|
||||||
///
|
///
|
||||||
/// 1. Check override patterns first:
|
/// Uses the glob matcher to check if the path should be ignored.
|
||||||
/// - If matched as whitelist (negation `!`), return `false` (not ignored)
|
/// Returns true if matched as ignore, false if whitelisted or no match.
|
||||||
/// - If matched as ignore, return `true` (ignored)
|
|
||||||
/// 2. Check if path is directly in git's ignored set
|
|
||||||
/// 3. Check if any parent directory is ignored by git
|
|
||||||
/// - If parent is ignored, also check if override patterns whitelist it
|
|
||||||
/// - If parent is whitelisted, children are not ignored
|
|
||||||
///
|
|
||||||
/// This ensures override patterns take precedence and negation patterns work
|
|
||||||
/// correctly even when navigating inside ignored directories.
|
|
||||||
pub fn matches_url(&self, url: impl AsUrl) -> bool {
|
pub fn matches_url(&self, url: impl AsUrl) -> bool {
|
||||||
let url = url.as_url();
|
let url = url.as_url();
|
||||||
let path = url.loc.as_path();
|
let path = url.loc.as_path();
|
||||||
|
|
||||||
// First check glob matcher (highest priority)
|
// Check glob matcher
|
||||||
if let Some(ref matcher) = self.glob_matcher {
|
if let Some(ref matcher) = self.glob_matcher {
|
||||||
if let Some(should_ignore) = matcher(path) {
|
if let Some(should_ignore) = matcher(path) {
|
||||||
return should_ignore;
|
return should_ignore;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then check if override patterns apply (they can negate ignores)
|
|
||||||
// Override patterns take absolute priority
|
|
||||||
if let Some(ref gitignore) = self.gitignore {
|
|
||||||
let matched = gitignore.matched(path, path.is_dir());
|
|
||||||
match matched {
|
|
||||||
ignore::Match::None => {
|
|
||||||
// No override pattern matched, fall through to git ignore check
|
|
||||||
}
|
|
||||||
ignore::Match::Ignore(_) => {
|
|
||||||
// Override pattern says to ignore
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
ignore::Match::Whitelist(_) => {
|
|
||||||
// Override pattern says NOT to ignore (negation pattern like !target/)
|
|
||||||
// This takes precedence over git ignore
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check exact match first
|
|
||||||
if self.ignored_paths.contains(path) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if any parent directory is ignored
|
|
||||||
// BUT also check if parent is whitelisted by override patterns
|
|
||||||
let mut current = path;
|
|
||||||
while let Some(parent) = current.parent() {
|
|
||||||
if self.ignored_paths.contains(parent) {
|
|
||||||
// Parent is ignored by git, but check if override patterns whitelist it
|
|
||||||
if let Some(ref gitignore) = self.gitignore {
|
|
||||||
let matched = gitignore.matched(parent, true); // parent is always a directory
|
|
||||||
if matches!(matched, ignore::Match::Whitelist(_)) {
|
|
||||||
// Parent is whitelisted, so children should not be ignored
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
current = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if a path should be ignored
|
|
||||||
pub fn matches_path(&self, path: &Path) -> bool { self.ignored_paths.contains(path) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
#[test]
|
|
||||||
fn test_git_repo_discovery() {
|
|
||||||
// This test assumes we're running in the yazi git repo
|
|
||||||
let current_dir = std::env::current_dir().unwrap();
|
|
||||||
assert!(git2::Repository::discover(¤t_dir).is_ok());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue