feat: new sort_fallback option to control fallback sorting behavior (#3077)

Co-authored-by: sxyazi <sxyazi@gmail.com>
This commit is contained in:
SuniRein 2026-02-15 14:00:58 +08:00 committed by GitHub
parent 13bdb164a4
commit c0f96f553b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 346 additions and 114 deletions

View file

@ -16,8 +16,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/):
- Custom tab name ([#3666])
- Allow using `ps.sub()` in `init.lua` directly without a plugin ([#3638])
- New `sort_fallback` option to control fallback sorting behavior ([#3077])
- New `fs.access()` API to access the filesystem ([#3668])
- New `relay-notify-push` DDS event to allow custom notification handlers ([#3642])
- New `relay-notify-push` DDS event to customize notification handlers ([#3642])
- New `ind-app-title` DDS event to customize the app title ([#3684])
- New `fs.unique()` creates a unique file or directory ([#3677])
- New `cx.which` API to access the which component state ([#3617])
@ -1577,6 +1578,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/):
[#3038]: https://github.com/sxyazi/yazi/pull/3038
[#3059]: https://github.com/sxyazi/yazi/pull/3059
[#3067]: https://github.com/sxyazi/yazi/pull/3067
[#3077]: https://github.com/sxyazi/yazi/pull/3077
[#3083]: https://github.com/sxyazi/yazi/pull/3083
[#3084]: https://github.com/sxyazi/yazi/pull/3084
[#3091]: https://github.com/sxyazi/yazi/pull/3091

283
Cargo.lock generated
View file

@ -171,9 +171,9 @@ checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
[[package]]
name = "arc-swap"
version = "1.8.1"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ded5f9a03ac8f24d1b8a25101ee812cd32cdc8c50a4c50237de2c4915850e73"
checksum = "f9f3647c145568cec02c42054e07bdf9a5a698e15b466fb2341bfc393cd24aa5"
dependencies = [
"rustversion",
]
@ -381,9 +381,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.10.0"
version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
dependencies = [
"serde_core",
]
@ -541,9 +541,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.2.55"
version = "1.2.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29"
checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2"
dependencies = [
"find-msvc-tools",
"jobserver",
@ -835,7 +835,7 @@ version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6"
dependencies = [
"bitflags 2.10.0",
"bitflags 2.11.0",
"crossterm_winapi",
"mio",
"parking_lot",
@ -852,7 +852,7 @@ version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b"
dependencies = [
"bitflags 2.10.0",
"bitflags 2.11.0",
"crossterm_winapi",
"derive_more",
"document-features",
@ -1154,9 +1154,9 @@ dependencies = [
[[package]]
name = "der"
version = "0.8.0-rc.12"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c0182be35043efdd2df327a443bb600606e350cfb090cccb233e9451e76f5a3"
checksum = "71fd89660b2dc699704064e59e9dba0147b903e85319429e131620d022be411b"
dependencies = [
"const-oid 0.10.2",
"pem-rfc7468 1.0.0",
@ -1240,9 +1240,9 @@ dependencies = [
[[package]]
name = "digest"
version = "0.11.0-rc.12"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4b37eb2004a3548553a44cc1e688aac70f0345b896c9d822b4a0e520bc9183b"
checksum = "f8bf3682cdec91817be507e4aa104314898b95b84d74f3d43882210101a545b6"
dependencies = [
"block-buffer 0.11.0",
"const-oid 0.10.2",
@ -1578,6 +1578,12 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "foldhash"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
name = "foldhash"
version = "0.2.0"
@ -1735,6 +1741,19 @@ dependencies = [
"wasip2",
]
[[package]]
name = "getrandom"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec"
dependencies = [
"cfg-if",
"libc",
"r-efi",
"wasip2",
"wasip3",
]
[[package]]
name = "ghash"
version = "0.5.1"
@ -1802,6 +1821,15 @@ version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
version = "0.15.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
dependencies = [
"foldhash 0.1.5",
]
[[package]]
name = "hashbrown"
version = "0.16.1"
@ -1810,7 +1838,7 @@ checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
dependencies = [
"allocator-api2",
"equivalent",
"foldhash",
"foldhash 0.2.0",
"serde",
"serde_core",
]
@ -1936,6 +1964,12 @@ dependencies = [
"cc",
]
[[package]]
name = "id-arena"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
[[package]]
name = "ident_case"
version = "1.0.1"
@ -2019,7 +2053,7 @@ version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3"
dependencies = [
"bitflags 2.10.0",
"bitflags 2.11.0",
"inotify-sys",
"libc",
]
@ -2064,7 +2098,7 @@ checksum = "fe44f2bbd99fcb302e246e2d6bcf51aeda346d02a365f80296a07a8c711b6da6"
dependencies = [
"argon2",
"bcrypt-pbkdf",
"digest 0.11.0-rc.12",
"digest 0.11.0",
"ecdsa",
"ed25519-dalek",
"hex",
@ -2185,6 +2219,12 @@ dependencies = [
"spin",
]
[[package]]
name = "leb128fmt"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
[[package]]
name = "lebe"
version = "0.5.3"
@ -2193,9 +2233,9 @@ checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8"
[[package]]
name = "libc"
version = "0.2.181"
version = "0.2.182"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "459427e2af2b9c839b132acb702a1c654d95e10f8c326bfc2ad11310e458b1c5"
checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112"
[[package]]
name = "libcrux-intrinsics"
@ -2285,7 +2325,7 @@ version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616"
dependencies = [
"bitflags 2.10.0",
"bitflags 2.11.0",
"libc",
]
@ -2295,7 +2335,7 @@ version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f4de44e98ddbf09375cbf4d17714d18f39195f4f4894e8524501726fd9a8a4a"
dependencies = [
"bitflags 2.10.0",
"bitflags 2.11.0",
]
[[package]]
@ -2534,7 +2574,7 @@ version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
dependencies = [
"bitflags 2.10.0",
"bitflags 2.11.0",
"cfg-if",
"cfg_aliases",
"libc",
@ -2572,7 +2612,7 @@ version = "8.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3"
dependencies = [
"bitflags 2.10.0",
"bitflags 2.11.0",
"fsevent-sys",
"inotify",
"kqueue",
@ -2590,7 +2630,7 @@ version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42b8cfee0e339a0337359f3c88165702ac6e600dc01c0cc9579a92d62b08477a"
dependencies = [
"bitflags 2.10.0",
"bitflags 2.11.0",
]
[[package]]
@ -2733,7 +2773,7 @@ version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"
dependencies = [
"bitflags 2.10.0",
"bitflags 2.11.0",
"objc2",
]
@ -2764,7 +2804,7 @@ version = "6.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "336b9c63443aceef14bea841b899035ae3abe89b7c486aaf4c5bd8aafedac3f0"
dependencies = [
"bitflags 2.10.0",
"bitflags 2.11.0",
"libc",
"once_cell",
"onig_sys",
@ -3101,7 +3141,7 @@ version = "0.8.0-rc.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "986d2e952779af96ea048f160fd9194e1751b4faea78bcf3ceb456efe008088e"
dependencies = [
"der 0.8.0-rc.12",
"der 0.8.0",
"spki 0.8.0-rc.4",
]
@ -3138,7 +3178,7 @@ version = "0.11.0-rc.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12922b6296c06eb741b02d7b5161e3aaa22864af38dfa025a1a3ba3f68c84577"
dependencies = [
"der 0.8.0-rc.12",
"der 0.8.0",
"spki 0.8.0-rc.4",
]
@ -3163,11 +3203,11 @@ dependencies = [
[[package]]
name = "png"
version = "0.18.0"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0"
checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61"
dependencies = [
"bitflags 2.10.0",
"bitflags 2.11.0",
"crc32fast",
"fdeflate",
"flate2",
@ -3218,6 +3258,16 @@ dependencies = [
"zerocopy",
]
[[package]]
name = "prettyplease"
version = "0.2.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
dependencies = [
"proc-macro2",
"syn 2.0.115",
]
[[package]]
name = "primeorder"
version = "0.13.6"
@ -3436,7 +3486,7 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ef8dea09a92caaf73bff7adb70b76162e5937524058a7e5bff37869cbbec293"
dependencies = [
"bitflags 2.10.0",
"bitflags 2.11.0",
"compact_str",
"hashbrown 0.16.1",
"indoc",
@ -3501,7 +3551,7 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7dbfa023cd4e604c2553483820c5fe8aa9d71a42eea5aa77c6e7f35756612db"
dependencies = [
"bitflags 2.10.0",
"bitflags 2.11.0",
"hashbrown 0.16.1",
"indoc",
"instability",
@ -3590,7 +3640,7 @@ version = "0.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
dependencies = [
"bitflags 2.10.0",
"bitflags 2.11.0",
]
[[package]]
@ -3692,7 +3742,7 @@ dependencies = [
"const-oid 0.10.2",
"crypto-bigint 0.7.0-rc.18",
"crypto-primes",
"digest 0.11.0-rc.12",
"digest 0.11.0",
"pkcs1",
"pkcs8 0.11.0-rc.11",
"rand_core 0.10.0-rc-3",
@ -3709,7 +3759,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01fe22d10a0e39c1134a971d5b8db8a40357b48ef22d81fa8d6eac22202dd782"
dependencies = [
"aes",
"bitflags 2.10.0",
"bitflags 2.11.0",
"block-padding",
"byteorder",
"bytes",
@ -3815,7 +3865,7 @@ version = "0.38.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
dependencies = [
"bitflags 2.10.0",
"bitflags 2.11.0",
"errno",
"libc",
"linux-raw-sys 0.4.15",
@ -3828,7 +3878,7 @@ version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34"
dependencies = [
"bitflags 2.10.0",
"bitflags 2.11.0",
"errno",
"libc",
"linux-raw-sys 0.11.0",
@ -4057,7 +4107,7 @@ checksum = "3b167252f3c126be0d8926639c4c4706950f01445900c4b3db0fd7e89fcb750a"
dependencies = [
"cfg-if",
"cpufeatures",
"digest 0.11.0-rc.12",
"digest 0.11.0",
]
[[package]]
@ -4079,7 +4129,7 @@ checksum = "7c5f3b1e2dc8aad28310d8410bd4d7e180eca65fca176c52ab00d364475d0024"
dependencies = [
"cfg-if",
"cpufeatures",
"digest 0.11.0-rc.12",
"digest 0.11.0",
]
[[package]]
@ -4166,7 +4216,7 @@ version = "3.0.0-rc.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597a96996ccff7dfa16f052bd995b4cecc72af22c35138738dc029f0ead6608d"
dependencies = [
"digest 0.11.0-rc.12",
"digest 0.11.0",
"rand_core 0.10.0-rc-3",
]
@ -4242,7 +4292,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8baeff88f34ed0691978ec34440140e1572b68c7dd4a495fd14a3dc1944daa80"
dependencies = [
"base64ct",
"der 0.8.0-rc.12",
"der 0.8.0",
]
[[package]]
@ -4407,7 +4457,7 @@ checksum = "4676b37242ccbd1aabf56edb093a4827dc49086c0ffd764a5705899e0f35f8f7"
dependencies = [
"anyhow",
"base64",
"bitflags 2.10.0",
"bitflags 2.11.0",
"fancy-regex",
"filedescriptor",
"finl_unicode",
@ -4823,6 +4873,12 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
[[package]]
name = "unicode-xid"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
[[package]]
name = "universal-hash"
version = "0.5.1"
@ -4853,12 +4909,12 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "uuid"
version = "1.20.0"
version = "1.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee48d38b119b0cd71fe4141b30f5ba9c7c5d9f4e7a3a8b4a674e4b6ef789976f"
checksum = "b672338555252d43fd2240c714dc444b8c6fb0a5c5335e65a07bba7742735ddb"
dependencies = [
"atomic",
"getrandom 0.3.4",
"getrandom 0.4.1",
"js-sys",
"serde_core",
"wasm-bindgen",
@ -4970,6 +5026,15 @@ dependencies = [
"wit-bindgen",
]
[[package]]
name = "wasip3"
version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
dependencies = [
"wit-bindgen",
]
[[package]]
name = "wasm-bindgen"
version = "0.2.108"
@ -5029,6 +5094,40 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "wasm-encoder"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319"
dependencies = [
"leb128fmt",
"wasmparser",
]
[[package]]
name = "wasm-metadata"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909"
dependencies = [
"anyhow",
"indexmap 2.13.0",
"wasm-encoder",
"wasmparser",
]
[[package]]
name = "wasmparser"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
dependencies = [
"bitflags 2.11.0",
"hashbrown 0.15.5",
"indexmap 2.13.0",
"semver",
]
[[package]]
name = "web-sys"
version = "0.3.85"
@ -5516,6 +5615,88 @@ name = "wit-bindgen"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
dependencies = [
"wit-bindgen-rust-macro",
]
[[package]]
name = "wit-bindgen-core"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc"
dependencies = [
"anyhow",
"heck",
"wit-parser",
]
[[package]]
name = "wit-bindgen-rust"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21"
dependencies = [
"anyhow",
"heck",
"indexmap 2.13.0",
"prettyplease",
"syn 2.0.115",
"wasm-metadata",
"wit-bindgen-core",
"wit-component",
]
[[package]]
name = "wit-bindgen-rust-macro"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a"
dependencies = [
"anyhow",
"prettyplease",
"proc-macro2",
"quote",
"syn 2.0.115",
"wit-bindgen-core",
"wit-bindgen-rust",
]
[[package]]
name = "wit-component"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
dependencies = [
"anyhow",
"bitflags 2.11.0",
"indexmap 2.13.0",
"log",
"serde",
"serde_derive",
"serde_json",
"wasm-encoder",
"wasm-metadata",
"wasmparser",
"wit-parser",
]
[[package]]
name = "wit-parser"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736"
dependencies = [
"anyhow",
"id-arena",
"indexmap 2.13.0",
"log",
"semver",
"serde",
"serde_derive",
"serde_json",
"unicode-xid",
"wasmparser",
]
[[package]]
name = "wyz"
@ -5684,7 +5865,7 @@ name = "yazi-config"
version = "26.2.2"
dependencies = [
"anyhow",
"bitflags 2.10.0",
"bitflags 2.11.0",
"crossterm 0.29.0",
"dirs",
"globset",
@ -5835,11 +6016,11 @@ version = "26.2.2"
dependencies = [
"anyhow",
"arc-swap",
"bitflags 2.10.0",
"bitflags 2.11.0",
"core-foundation-sys",
"dirs",
"either",
"foldhash",
"foldhash 0.2.0",
"hashbrown 0.16.1",
"libc",
"objc2",
@ -5874,7 +6055,7 @@ name = "yazi-parser"
version = "26.2.2"
dependencies = [
"anyhow",
"bitflags 2.10.0",
"bitflags 2.11.0",
"crossterm 0.29.0",
"dyn-clone",
"hashbrown 0.16.1",
@ -5959,7 +6140,7 @@ version = "26.2.2"
dependencies = [
"anyhow",
"async-priority-channel",
"foldhash",
"foldhash 0.2.0",
"hashbrown 0.16.1",
"libc",
"lru",
@ -5986,7 +6167,7 @@ dependencies = [
name = "yazi-sftp"
version = "26.2.2"
dependencies = [
"bitflags 2.10.0",
"bitflags 2.11.0",
"parking_lot",
"russh",
"serde",
@ -6001,7 +6182,7 @@ dependencies = [
"anyhow",
"crossterm 0.29.0",
"dyn-clone",
"foldhash",
"foldhash 0.2.0",
"futures",
"hashbrown 0.16.1",
"libc",

View file

@ -29,7 +29,7 @@ debug = false
ansi-to-tui = "8.0.1"
anyhow = "1.0.101"
base64 = "0.22.1"
bitflags = { version = "2.10.0", features = [ "serde" ] }
bitflags = { version = "2.11.0", features = [ "serde" ] }
clap = { version = "4.5.58", features = [ "derive" ] }
core-foundation-sys = "0.8.7"
crossterm = { version = "0.29.0", features = [ "event-stream" ] }
@ -41,7 +41,7 @@ futures = "0.3.31"
globset = "0.4.18"
hashbrown = { version = "0.16.1", features = [ "serde" ] }
indexmap = { version = "2.13.0", features = [ "serde" ] }
libc = "0.2.181"
libc = "0.2.182"
lru = "0.16.3"
mlua = { version = "0.11.6", features = [ "anyhow", "async", "error-send", "lua55", "macros", "serde" ] }
objc2 = "0.6.3"

View file

@ -46,5 +46,6 @@ impl UserData for Preference {
fields.add_field_method_get("sort_reverse", |_, me| Ok(me.sort_reverse));
fields.add_field_method_get("sort_dir_first", |_, me| Ok(me.sort_dir_first));
fields.add_field_method_get("sort_translit", |_, me| Ok(me.sort_translit));
fields.add_field_method_get("sort_fallback", |_, me| Ok(me.sort_fallback.to_string()));
}
}

View file

@ -22,6 +22,7 @@ impl Actor for Sort {
pref.sort_dir_first = opt.dir_first.unwrap_or(pref.sort_dir_first);
pref.sort_sensitive = opt.sensitive.unwrap_or(pref.sort_sensitive);
pref.sort_translit = opt.translit.unwrap_or(pref.sort_translit);
pref.sort_fallback = opt.fallback.unwrap_or(pref.sort_fallback);
let sorter = FilesSorter::from(&*pref);
let hovered = cx.hovered().map(|f| f.urn().to_owned());

View file

@ -9,6 +9,7 @@ sort_sensitive = false
sort_reverse = false
sort_dir_first = true
sort_translit = false
sort_fallback = "alphabetical"
linemode = "none"
show_hidden = false
show_symlink = true

View file

@ -1,7 +1,7 @@
use anyhow::{Result, bail};
use serde::Deserialize;
use yazi_codegen::DeserializeOver2;
use yazi_fs::SortBy;
use yazi_fs::{SortBy, SortFallback};
use yazi_shared::SyncCell;
use super::{MgrRatio, MouseEvents};
@ -16,6 +16,7 @@ pub struct Mgr {
pub sort_reverse: SyncCell<bool>,
pub sort_dir_first: SyncCell<bool>,
pub sort_translit: SyncCell<bool>,
pub sort_fallback: SyncCell<SortFallback>,
// Display
pub linemode: String,

View file

@ -1,5 +1,5 @@
use yazi_config::YAZI;
use yazi_fs::{FilesSorter, SortBy};
use yazi_fs::{FilesSorter, SortBy, SortFallback};
#[derive(Clone, PartialEq)]
pub struct Preference {
@ -14,6 +14,7 @@ pub struct Preference {
pub sort_reverse: bool,
pub sort_dir_first: bool,
pub sort_translit: bool,
pub sort_fallback: SortFallback,
}
impl Default for Preference {
@ -30,6 +31,7 @@ impl Default for Preference {
sort_reverse: YAZI.mgr.sort_reverse.get(),
sort_dir_first: YAZI.mgr.sort_dir_first.get(),
sort_translit: YAZI.mgr.sort_translit.get(),
sort_fallback: YAZI.mgr.sort_fallback.get(),
}
}
}
@ -42,6 +44,7 @@ impl From<&Preference> for FilesSorter {
reverse: value.sort_reverse,
dir_first: value.sort_dir_first,
translit: value.sort_translit,
fallback: value.sort_fallback,
}
}
}

View file

@ -19,7 +19,7 @@ yazi-shim = { path = "../yazi-shim", version = "26.2.2" }
# External dependencies
anyhow = { workspace = true }
arc-swap = "1.8.1"
arc-swap = "1.8.2"
bitflags = { workspace = true }
dirs = { workspace = true }
either = { workspace = true }

View file

@ -4,7 +4,7 @@ use hashbrown::HashMap;
use rand::{RngCore, SeedableRng, rngs::SmallRng};
use yazi_shared::{natsort, path::PathBufDyn, translit::Transliterator, url::UrlLike};
use crate::{File, SortBy};
use crate::{File, SortBy, SortFallback};
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct FilesSorter {
@ -13,6 +13,7 @@ pub struct FilesSorter {
pub reverse: bool,
pub dir_first: bool,
pub translit: bool,
pub fallback: SortFallback,
}
impl FilesSorter {
@ -21,105 +22,116 @@ impl FilesSorter {
return;
}
let by_alphabetical = |a: &File, b: &File| {
if self.sensitive {
self.cmp(a.urn().encoded_bytes(), b.urn().encoded_bytes(), self.promote(a, b))
} else {
self.cmp_insensitive(a.urn().encoded_bytes(), b.urn().encoded_bytes(), self.promote(a, b))
}
};
macro_rules! promote {
($a:ident, $b:ident) => {
if self.dir_first {
match $b.is_dir().cmp(&$a.is_dir()) {
Ordering::Equal => {}
not_eq => return not_eq,
}
}
};
}
match self.by {
SortBy::None => {}
SortBy::Mtime => items.sort_unstable_by(|a, b| {
let ord = self.cmp(a.mtime, b.mtime, self.promote(a, b));
if ord == Ordering::Equal { by_alphabetical(a, b) } else { ord }
promote!(a, b);
self.fallback(a, b, self.cmp(a.mtime, b.mtime))
}),
SortBy::Btime => items.sort_unstable_by(|a, b| {
let ord = self.cmp(a.btime, b.btime, self.promote(a, b));
if ord == Ordering::Equal { by_alphabetical(a, b) } else { ord }
promote!(a, b);
self.fallback(a, b, self.cmp(a.btime, b.btime))
}),
SortBy::Extension => items.sort_unstable_by(|a, b| {
promote!(a, b);
let aa = a.url.ext().filter(|_| a.is_file());
let bb = b.url.ext().filter(|_| b.is_file());
let ord = if self.sensitive {
self.cmp(aa, bb, self.promote(a, b))
self.cmp(aa, bb)
} else {
self.cmp_insensitive(
aa.map_or(&[], |s| s.encoded_bytes()),
bb.map_or(&[], |s| s.encoded_bytes()),
self.promote(a, b),
)
};
if ord == Ordering::Equal { by_alphabetical(a, b) } else { ord }
self.fallback(a, b, ord)
}),
SortBy::Alphabetical => items.sort_unstable_by(|a, b| {
promote!(a, b);
self.sort_alphabetically(a, b)
}),
SortBy::Natural => items.sort_unstable_by(|a, b| {
promote!(a, b);
self.sort_naturally(a, b)
}),
SortBy::Alphabetical => items.sort_unstable_by(by_alphabetical),
SortBy::Natural => self.sort_naturally(items),
SortBy::Size => items.sort_unstable_by(|a, b| {
promote!(a, b);
let aa = if a.is_dir() { sizes.get(&a.urn()).copied() } else { None };
let bb = if b.is_dir() { sizes.get(&b.urn()).copied() } else { None };
let ord = self.cmp(aa.unwrap_or(a.len), bb.unwrap_or(b.len), self.promote(a, b));
if ord == Ordering::Equal { by_alphabetical(a, b) } else { ord }
self.fallback(a, b, self.cmp(aa.unwrap_or(a.len), bb.unwrap_or(b.len)))
}),
SortBy::Random => {
let mut rng = SmallRng::from_os_rng();
items.sort_unstable_by(|a, b| self.cmp(rng.next_u64(), rng.next_u64(), self.promote(a, b)))
items.sort_unstable_by(|a, b| {
promote!(a, b);
self.cmp(rng.next_u64(), rng.next_u64())
})
}
}
}
fn sort_naturally(&self, items: &mut [File]) {
items.sort_unstable_by(|a, b| {
let promote = self.promote(a, b);
if promote != Ordering::Equal {
return promote;
}
let ordering = if self.translit {
natsort(
a.urn().encoded_bytes().transliterate().as_bytes(),
b.urn().encoded_bytes().transliterate().as_bytes(),
!self.sensitive,
)
} else {
natsort(a.urn().encoded_bytes(), b.urn().encoded_bytes(), !self.sensitive)
};
if self.reverse { ordering.reverse() } else { ordering }
});
}
#[inline(always)]
#[allow(clippy::collapsible_else_if)]
fn cmp<T: Ord>(&self, a: T, b: T, promote: Ordering) -> Ordering {
if promote != Ordering::Equal {
promote
fn sort_alphabetically(&self, a: &File, b: &File) -> Ordering {
if self.sensitive {
self.cmp(a.urn().encoded_bytes(), b.urn().encoded_bytes())
} else {
if self.reverse { b.cmp(&a) } else { a.cmp(&b) }
self.cmp_insensitive(a.urn().encoded_bytes(), b.urn().encoded_bytes())
}
}
#[inline(always)]
fn cmp_insensitive(&self, a: &[u8], b: &[u8], promote: Ordering) -> Ordering {
if promote != Ordering::Equal {
return promote;
fn sort_naturally(&self, a: &File, b: &File) -> Ordering {
let ordering = if self.translit {
natsort(
a.urn().encoded_bytes().transliterate().as_bytes(),
b.urn().encoded_bytes().transliterate().as_bytes(),
!self.sensitive,
)
} else {
natsort(a.urn().encoded_bytes(), b.urn().encoded_bytes(), !self.sensitive)
};
if self.reverse { ordering.reverse() } else { ordering }
}
#[inline(always)]
fn fallback(&self, a: &File, b: &File, ord: Ordering) -> Ordering {
if ord != Ordering::Equal {
return ord;
}
match self.fallback {
SortFallback::Alphabetical => self.sort_alphabetically(a, b),
SortFallback::Natural => self.sort_naturally(a, b),
}
}
#[inline(always)]
fn cmp<T: Ord>(&self, a: T, b: T) -> Ordering { if self.reverse { b.cmp(&a) } else { a.cmp(&b) } }
#[inline(always)]
fn cmp_insensitive(&self, a: &[u8], b: &[u8]) -> Ordering {
let l = a.len().min(b.len());
let (lhs, rhs) = if self.reverse { (&b[..l], &a[..l]) } else { (&a[..l], &b[..l]) };
for i in 0..l {
match lhs[i].to_ascii_lowercase().cmp(&rhs[i].to_ascii_lowercase()) {
Ordering::Equal => (),
Ordering::Equal => {}
not_eq => return not_eq,
}
}
if self.reverse { b.len().cmp(&a.len()) } else { a.len().cmp(&b.len()) }
}
#[inline(always)]
fn promote(&self, a: &File, b: &File) -> Ordering {
if self.dir_first { b.is_dir().cmp(&a.is_dir()) } else { Ordering::Equal }
}
}

View file

@ -2,7 +2,8 @@ use std::{fmt::Display, str::FromStr};
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
// --- by
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "kebab-case")]
pub enum SortBy {
#[default]
@ -38,3 +39,29 @@ impl Display for SortBy {
})
}
}
// --- fallback
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "kebab-case")]
pub enum SortFallback {
#[default]
Alphabetical,
Natural,
}
impl FromStr for SortFallback {
type Err = serde::de::value::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::deserialize(serde::de::value::StrDeserializer::new(s))
}
}
impl Display for SortFallback {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
Self::Alphabetical => "alphabetical",
Self::Natural => "natural",
})
}
}

View file

@ -1,7 +1,7 @@
use mlua::{FromLua, IntoLua, Lua, LuaSerdeExt, Value};
use serde::{Deserialize, Serialize};
use yazi_binding::SER_OPT;
use yazi_fs::SortBy;
use yazi_fs::{SortBy, SortFallback};
use yazi_shared::event::CmdCow;
#[derive(Debug, Default, Deserialize, Serialize)]
@ -11,6 +11,7 @@ pub struct SortOpt {
pub dir_first: Option<bool>,
pub sensitive: Option<bool>,
pub translit: Option<bool>,
pub fallback: Option<SortFallback>,
}
impl TryFrom<CmdCow> for SortOpt {
@ -23,6 +24,7 @@ impl TryFrom<CmdCow> for SortOpt {
dir_first: c.get("dir-first").ok(),
sensitive: c.get("sensitive").ok(),
translit: c.get("translit").ok(),
fallback: c.get("fallback").ok().map(str::parse).transpose()?,
})
}
}

View file

@ -48,6 +48,7 @@ fn mgr() -> Composer<ComposerGet, ComposerSet> {
b"sort_reverse" => m.sort_reverse.get().into_lua(lua)?,
b"sort_dir_first" => m.sort_dir_first.get().into_lua(lua)?,
b"sort_translit" => m.sort_translit.get().into_lua(lua)?,
b"sort_fallback" => lua.to_value_with(&m.sort_fallback, SER_OPT)?,
b"linemode" => lua.create_string(&m.linemode)?.into_lua(lua)?,
b"show_hidden" => m.show_hidden.get().into_lua(lua)?,