mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
Add ignore functionality to file manager
- Introduced `Ignore` actor to manage ignore patterns based on gitignore and user-defined overrides. - Implemented `IgnoreFilter` to handle ignored paths and patterns. - Updated `Files` struct to include an ignore filter, allowing files to be filtered based on ignore rules. - Modified existing actors and managers to apply ignore filters during file operations. - Updated `Cargo.toml` and `Cargo.lock` to include new dependencies related to ignore functionality.
This commit is contained in:
parent
46569a1f48
commit
7bfad2436f
13 changed files with 791 additions and 76 deletions
332
Cargo.lock
generated
332
Cargo.lock
generated
|
|
@ -1011,6 +1011,17 @@ 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.11"
|
version = "0.2.11"
|
||||||
|
|
@ -1275,6 +1286,15 @@ 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"
|
||||||
|
|
@ -1441,6 +1461,19 @@ 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.9.4",
|
||||||
|
"libc",
|
||||||
|
"libgit2-sys",
|
||||||
|
"log",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "globset"
|
name = "globset"
|
||||||
version = "0.4.16"
|
version = "0.4.16"
|
||||||
|
|
@ -1574,12 +1607,135 @@ 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"
|
||||||
|
|
@ -1839,6 +1995,18 @@ 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"
|
||||||
|
|
@ -1855,6 +2023,18 @@ 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"
|
||||||
|
|
@ -1867,6 +2047,12 @@ 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 = "0.4.2"
|
version = "0.4.2"
|
||||||
|
|
@ -2604,6 +2790,15 @@ 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"
|
||||||
|
|
@ -3444,6 +3639,12 @@ 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"
|
||||||
|
|
@ -3495,6 +3696,17 @@ 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"
|
||||||
|
|
@ -3642,6 +3854,16 @@ 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.47.1"
|
version = "1.47.1"
|
||||||
|
|
@ -3933,12 +4155,30 @@ 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"
|
||||||
|
|
@ -3972,6 +4212,12 @@ 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"
|
||||||
|
|
@ -4554,6 +4800,12 @@ 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"
|
||||||
|
|
@ -4838,7 +5090,9 @@ 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",
|
||||||
"objc",
|
"objc",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
|
|
@ -5086,6 +5340,30 @@ 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"
|
||||||
|
|
@ -5106,12 +5384,66 @@ 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"
|
||||||
|
|
|
||||||
40
Cargo.toml
40
Cargo.toml
|
|
@ -30,29 +30,57 @@ crossterm = { version = "0.29.0", features = [ "event-stream" ] }
|
||||||
dirs = "6.0.0"
|
dirs = "6.0.0"
|
||||||
foldhash = "0.2.0"
|
foldhash = "0.2.0"
|
||||||
futures = "0.3.31"
|
futures = "0.3.31"
|
||||||
|
git2 = { version = "0.19.0", default-features = false, features = [
|
||||||
|
"vendored-libgit2",
|
||||||
|
] }
|
||||||
globset = "0.4.16"
|
globset = "0.4.16"
|
||||||
hashbrown = { version = "0.16.0", features = ["serde"] }
|
hashbrown = { version = "0.16.0", features = ["serde"] }
|
||||||
|
ignore = "0.4.23"
|
||||||
indexmap = { version = "2.11.4", features = ["serde"] }
|
indexmap = { version = "2.11.4", features = ["serde"] }
|
||||||
libc = "0.2.177"
|
libc = "0.2.177"
|
||||||
lru = "0.16.1"
|
lru = "0.16.1"
|
||||||
mlua = { version = "0.11.4", features = [ "anyhow", "async", "error-send", "lua54", "macros", "serde" ] }
|
mlua = { version = "0.11.4", features = [
|
||||||
|
"anyhow",
|
||||||
|
"async",
|
||||||
|
"error-send",
|
||||||
|
"lua54",
|
||||||
|
"macros",
|
||||||
|
"serde",
|
||||||
|
] }
|
||||||
objc = "0.2.7"
|
objc = "0.2.7"
|
||||||
ordered-float = { version = "5.1.0", features = ["serde"] }
|
ordered-float = { version = "5.1.0", features = ["serde"] }
|
||||||
parking_lot = "0.12.5"
|
parking_lot = "0.12.5"
|
||||||
paste = "1.0.15"
|
paste = "1.0.15"
|
||||||
percent-encoding = "2.3.2"
|
percent-encoding = "2.3.2"
|
||||||
ratatui = { version = "0.29.0", features = [ "unstable-rendered-line-info", "unstable-widget-ref" ] }
|
ratatui = { version = "0.29.0", features = [
|
||||||
|
"unstable-rendered-line-info",
|
||||||
|
"unstable-widget-ref",
|
||||||
|
] }
|
||||||
regex = "1.12.1"
|
regex = "1.12.1"
|
||||||
russh = { version = "0.54.5", default-features = false, features = [ "ring", "rsa" ] }
|
russh = { version = "0.54.5", default-features = false, features = [
|
||||||
|
"ring",
|
||||||
|
"rsa",
|
||||||
|
] }
|
||||||
scopeguard = "1.2.0"
|
scopeguard = "1.2.0"
|
||||||
serde = { version = "1.0.228", features = ["derive"] }
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
serde_json = "1.0.145"
|
serde_json = "1.0.145"
|
||||||
syntect = { version = "5.3.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 = { version = "1.47.1", features = ["full"] }
|
||||||
tokio-stream = "0.1.17"
|
tokio-stream = "0.1.17"
|
||||||
tokio-util = "0.7.16"
|
tokio-util = "0.7.16"
|
||||||
toml = { version = "0.9.8" }
|
toml = { version = "0.9.8" }
|
||||||
tracing = { version = "0.1.41", features = [ "max_level_debug", "release_max_level_debug" ] }
|
tracing = { version = "0.1.41", features = [
|
||||||
twox-hash = { version = "2.1.2", default-features = false, features = [ "std", "random", "xxhash3_128" ] }
|
"max_level_debug",
|
||||||
|
"release_max_level_debug",
|
||||||
|
] }
|
||||||
|
twox-hash = { version = "2.1.2", default-features = false, features = [
|
||||||
|
"std",
|
||||||
|
"random",
|
||||||
|
"xxhash3_128",
|
||||||
|
] }
|
||||||
unicode-width = { version = "0.2.0", default-features = false }
|
unicode-width = { version = "0.2.0", default-features = false }
|
||||||
uzers = "0.12.1"
|
uzers = "0.12.1"
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ impl Actor for Cd {
|
||||||
err!(Pubsub::pub_after_cd(tab.id, tab.cwd()));
|
err!(Pubsub::pub_after_cd(tab.id, tab.cwd()));
|
||||||
act!(mgr:hidden, cx)?;
|
act!(mgr:hidden, cx)?;
|
||||||
act!(mgr:sort, cx)?;
|
act!(mgr:sort, cx)?;
|
||||||
|
act!(mgr:ignore, cx)?;
|
||||||
act!(mgr:hover, cx)?;
|
act!(mgr:hover, cx)?;
|
||||||
act!(mgr:refresh, cx)?;
|
act!(mgr:refresh, cx)?;
|
||||||
succ!(render!());
|
succ!(render!());
|
||||||
|
|
|
||||||
155
yazi-actor/src/mgr/ignore.rs
Normal file
155
yazi-actor/src/mgr/ignore.rs
Normal file
|
|
@ -0,0 +1,155 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
use yazi_config::YAZI;
|
||||||
|
use yazi_core::tab::Folder;
|
||||||
|
use yazi_fs::{FolderStage, IgnoreFilter};
|
||||||
|
use yazi_macro::{act, render, render_and, succ};
|
||||||
|
use yazi_parser::VoidOpt;
|
||||||
|
use yazi_shared::{data::Data, url::UrlLike};
|
||||||
|
|
||||||
|
use crate::{Actor, Ctx};
|
||||||
|
|
||||||
|
pub struct Ignore;
|
||||||
|
|
||||||
|
impl Actor for Ignore {
|
||||||
|
type Options = VoidOpt;
|
||||||
|
|
||||||
|
const NAME: &str = "ignore";
|
||||||
|
|
||||||
|
fn act(cx: &mut Ctx, _: Self::Options) -> Result<Data> {
|
||||||
|
let gitignore_enabled = YAZI.mgr.gitignore_enable;
|
||||||
|
let override_patterns = &YAZI.mgr.ignore_override;
|
||||||
|
|
||||||
|
// If gitignore is disabled but we have override patterns, apply them
|
||||||
|
if !gitignore_enabled && !override_patterns.is_empty() {
|
||||||
|
// Load ignore filter from override patterns only
|
||||||
|
let ignore_filter = if let Some(path) = cx.cwd().as_path() {
|
||||||
|
IgnoreFilter::from_patterns(path, override_patterns)
|
||||||
|
} 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
|
||||||
|
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 hovered
|
||||||
|
if let Some(h) = cx.hovered_folder_mut() {
|
||||||
|
let hovered_filter = if let Some(path) = h.url.as_path() {
|
||||||
|
IgnoreFilter::from_patterns(path, override_patterns)
|
||||||
|
} 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 gitignore is disabled and no override patterns, remove any ignore filter
|
||||||
|
if !gitignore_enabled {
|
||||||
|
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, override_patterns)
|
||||||
|
} 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_filter = if let Some(path) = h.url.as_path() {
|
||||||
|
IgnoreFilter::from_dir(path, override_patterns)
|
||||||
|
} 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!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -19,6 +19,7 @@ yazi_macro::mod_flat!(
|
||||||
hardlink
|
hardlink
|
||||||
hidden
|
hidden
|
||||||
hover
|
hover
|
||||||
|
ignore
|
||||||
leave
|
leave
|
||||||
linemode
|
linemode
|
||||||
link
|
link
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,9 @@ impl Actor for Refresh {
|
||||||
execute!(TTY.writer(), SetTitle(s)).ok();
|
execute!(TTY.writer(), SetTitle(s)).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply ignore filter before triggering file loads
|
||||||
|
act!(mgr:ignore, cx)?;
|
||||||
|
|
||||||
if let Some(p) = cx.parent() {
|
if let Some(p) = cx.parent() {
|
||||||
Self::trigger_dirs(&[cx.current(), p]);
|
Self::trigger_dirs(&[cx.current(), p]);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,12 @@ pub struct Mgr {
|
||||||
pub scrolloff: SyncCell<u8>,
|
pub scrolloff: SyncCell<u8>,
|
||||||
pub mouse_events: SyncCell<MouseEvents>,
|
pub mouse_events: SyncCell<MouseEvents>,
|
||||||
pub title_format: String,
|
pub title_format: String,
|
||||||
|
|
||||||
|
// Filtering
|
||||||
|
#[serde(default)]
|
||||||
|
pub gitignore_enable: bool,
|
||||||
|
#[serde(default)]
|
||||||
|
pub ignore_override: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mgr {
|
impl Mgr {
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ pub enum Spark<'a> {
|
||||||
Forward(yazi_parser::VoidOpt),
|
Forward(yazi_parser::VoidOpt),
|
||||||
Hardlink(yazi_parser::mgr::HardlinkOpt),
|
Hardlink(yazi_parser::mgr::HardlinkOpt),
|
||||||
Hidden(yazi_parser::mgr::HiddenOpt),
|
Hidden(yazi_parser::mgr::HiddenOpt),
|
||||||
|
Ignore(yazi_parser::VoidOpt),
|
||||||
Hover(yazi_parser::mgr::HoverOpt),
|
Hover(yazi_parser::mgr::HoverOpt),
|
||||||
Leave(yazi_parser::VoidOpt),
|
Leave(yazi_parser::VoidOpt),
|
||||||
Linemode(yazi_parser::mgr::LinemodeOpt),
|
Linemode(yazi_parser::mgr::LinemodeOpt),
|
||||||
|
|
@ -155,6 +156,7 @@ impl<'a> IntoLua for Spark<'a> {
|
||||||
Self::Forward(b) => b.into_lua(lua),
|
Self::Forward(b) => b.into_lua(lua),
|
||||||
Self::Hardlink(b) => b.into_lua(lua),
|
Self::Hardlink(b) => b.into_lua(lua),
|
||||||
Self::Hidden(b) => b.into_lua(lua),
|
Self::Hidden(b) => b.into_lua(lua),
|
||||||
|
Self::Ignore(b) => b.into_lua(lua),
|
||||||
Self::Hover(b) => b.into_lua(lua),
|
Self::Hover(b) => b.into_lua(lua),
|
||||||
Self::Leave(b) => b.into_lua(lua),
|
Self::Leave(b) => b.into_lua(lua),
|
||||||
Self::Linemode(b) => b.into_lua(lua),
|
Self::Linemode(b) => b.into_lua(lua),
|
||||||
|
|
@ -253,6 +255,7 @@ try_from_spark!(
|
||||||
mgr:escape_visual,
|
mgr:escape_visual,
|
||||||
mgr:follow,
|
mgr:follow,
|
||||||
mgr:forward,
|
mgr:forward,
|
||||||
|
mgr:ignore,
|
||||||
mgr:leave,
|
mgr:leave,
|
||||||
mgr:refresh,
|
mgr:refresh,
|
||||||
mgr:search_stop,
|
mgr:search_stop,
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,7 @@ impl<'a> Executor<'a> {
|
||||||
on!(copy);
|
on!(copy);
|
||||||
on!(shell);
|
on!(shell);
|
||||||
on!(hidden);
|
on!(hidden);
|
||||||
|
on!(ignore);
|
||||||
on!(linemode);
|
on!(linemode);
|
||||||
on!(search);
|
on!(search);
|
||||||
on!(search_do);
|
on!(search_do);
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,9 @@ 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 }
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use std::{mem, ops::{Deref, DerefMut, Not}};
|
||||||
use hashbrown::{HashMap, HashSet};
|
use hashbrown::{HashMap, HashSet};
|
||||||
use yazi_shared::{Id, url::{Urn, UrnBuf}};
|
use yazi_shared::{Id, url::{Urn, UrnBuf}};
|
||||||
|
|
||||||
use super::{FilesSorter, Filter};
|
use super::{FilesSorter, Filter, IgnoreFilter};
|
||||||
use crate::{FILES_TICKET, File, SortBy};
|
use crate::{FILES_TICKET, File, SortBy};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
@ -19,6 +19,7 @@ pub struct Files {
|
||||||
sorter: FilesSorter,
|
sorter: FilesSorter,
|
||||||
filter: Option<Filter>,
|
filter: Option<Filter>,
|
||||||
show_hidden: bool,
|
show_hidden: bool,
|
||||||
|
ignore_filter: Option<IgnoreFilter>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for Files {
|
impl Deref for Files {
|
||||||
|
|
@ -257,9 +258,15 @@ impl Files {
|
||||||
|
|
||||||
fn split_files(&self, files: impl IntoIterator<Item = File>) -> (Vec<File>, Vec<File>) {
|
fn split_files(&self, files: impl IntoIterator<Item = File>) -> (Vec<File>, Vec<File>) {
|
||||||
if let Some(filter) = &self.filter {
|
if let Some(filter) = &self.filter {
|
||||||
|
files.into_iter().partition(|f| {
|
||||||
|
(f.is_hidden() && !self.show_hidden)
|
||||||
|
|| !filter.matches(f.urn())
|
||||||
|
|| self.ignore_filter.as_ref().is_some_and(|ig| ig.matches_url(&f.url))
|
||||||
|
})
|
||||||
|
} else if let Some(ignore_filter) = &self.ignore_filter {
|
||||||
files
|
files
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.partition(|f| (f.is_hidden() && !self.show_hidden) || !filter.matches(f.urn()))
|
.partition(|f| (f.is_hidden() && !self.show_hidden) || ignore_filter.matches_url(&f.url))
|
||||||
} else if self.show_hidden {
|
} else if self.show_hidden {
|
||||||
(vec![], files.into_iter().collect())
|
(vec![], files.into_iter().collect())
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -316,6 +323,24 @@ impl Files {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Ignore filter
|
||||||
|
#[inline]
|
||||||
|
pub fn ignore_filter(&self) -> Option<&IgnoreFilter> { self.ignore_filter.as_ref() }
|
||||||
|
|
||||||
|
pub fn set_ignore_filter(&mut self, ignore_filter: Option<IgnoreFilter>) -> bool {
|
||||||
|
if self.ignore_filter.is_none() && ignore_filter.is_none() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ignore_filter = ignore_filter;
|
||||||
|
|
||||||
|
// Re-split files with the new ignore filter
|
||||||
|
let it = mem::take(&mut self.items).into_iter().chain(mem::take(&mut self.hidden));
|
||||||
|
(self.hidden, self.items) = self.split_files(it);
|
||||||
|
self.sorter.sort(&mut self.items, &self.sizes);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
// --- Show hidden
|
// --- Show hidden
|
||||||
pub fn set_show_hidden(&mut self, state: bool) {
|
pub fn set_show_hidden(&mut self, state: bool) {
|
||||||
if self.show_hidden == state {
|
if self.show_hidden == state {
|
||||||
|
|
|
||||||
158
yazi-fs/src/ignore.rs
Normal file
158
yazi-fs/src/ignore.rs
Normal file
|
|
@ -0,0 +1,158 @@
|
||||||
|
use std::{collections::HashSet, path::{Path, PathBuf}};
|
||||||
|
|
||||||
|
use yazi_shared::url::AsUrl;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct IgnoreFilter {
|
||||||
|
ignored_paths: HashSet<PathBuf>,
|
||||||
|
gitignore: Option<ignore::gitignore::Gitignore>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IgnoreFilter {
|
||||||
|
/// Create a new IgnoreFilter by checking git ignore status for files in the
|
||||||
|
/// given directory
|
||||||
|
pub fn from_dir(dir: impl AsRef<Path>, override_patterns: &[String]) -> Option<Self> {
|
||||||
|
let dir = dir.as_ref();
|
||||||
|
|
||||||
|
// 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()?;
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
if let Some(path) = status.path() {
|
||||||
|
ignored_paths.insert(workdir.join(path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build custom gitignore from override patterns if provided
|
||||||
|
let gitignore = if !override_patterns.is_empty() {
|
||||||
|
let mut builder = ignore::gitignore::GitignoreBuilder::new(workdir);
|
||||||
|
|
||||||
|
// Add each override pattern
|
||||||
|
for pattern in override_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 override patterns, still create
|
||||||
|
// the filter
|
||||||
|
if gitignore.is_some() {
|
||||||
|
return Some(Self { ignored_paths, gitignore });
|
||||||
|
}
|
||||||
|
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 })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new IgnoreFilter from only override patterns (no git integration)
|
||||||
|
pub fn from_patterns(dir: impl AsRef<Path>, patterns: &[String]) -> Option<Self> {
|
||||||
|
if patterns.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
let gitignore = builder.build().ok()?;
|
||||||
|
|
||||||
|
Some(Self { ignored_paths: HashSet::new(), gitignore: Some(gitignore) })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if a file should be ignored based on its URL
|
||||||
|
pub fn matches_url(&self, url: impl AsUrl) -> bool {
|
||||||
|
let url = url.as_url();
|
||||||
|
let path = url.loc.as_path();
|
||||||
|
|
||||||
|
// First 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
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if a path should be ignored
|
||||||
|
pub fn matches_path(&self, path: &Path) -> bool { self.ignored_paths.contains(path) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
yazi_macro::mod_pub!(cha error mounts path provider);
|
yazi_macro::mod_pub!(cha error mounts path provider);
|
||||||
|
|
||||||
yazi_macro::mod_flat!(cwd file files filter fns hash op sorter sorting splatter stage url xdg);
|
yazi_macro::mod_flat!(cwd file files filter fns hash ignore op sorter sorting splatter stage url xdg);
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
CWD.init(<_>::default());
|
CWD.init(<_>::default());
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue