mirror of
https://github.com/Llewellynvdm/zoxide.git
synced 2025-02-02 19:48:24 +00:00
Convert paths to String
This commit is contained in:
parent
3f74a81851
commit
208a6a9eb8
59
Cargo.lock
generated
59
Cargo.lock
generated
@ -67,16 +67,6 @@ dependencies = [
|
|||||||
"constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bstr"
|
|
||||||
version = "0.2.13"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"regex-automata 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
version = "1.3.4"
|
version = "1.3.4"
|
||||||
@ -182,11 +172,6 @@ name = "libc"
|
|||||||
version = "0.2.70"
|
version = "0.2.70"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memchr"
|
|
||||||
version = "2.3.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "ppv-lite86"
|
||||||
version = "0.2.6"
|
version = "0.2.6"
|
||||||
@ -198,9 +183,9 @@ version = "1.0.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro-error-attr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro-error-attr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -209,16 +194,16 @@ name = "proc-macro-error-attr"
|
|||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.12"
|
version = "1.0.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -229,7 +214,7 @@ name = "quote"
|
|||||||
version = "1.0.5"
|
version = "1.0.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -284,14 +269,6 @@ dependencies = [
|
|||||||
"rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex-automata"
|
|
||||||
version = "0.1.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rust-argon2"
|
name = "rust-argon2"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
@ -316,9 +293,9 @@ name = "serde_derive"
|
|||||||
version = "1.0.110"
|
version = "1.0.110"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -343,17 +320,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"proc-macro-error 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro-error 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.21"
|
version = "1.0.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
@ -363,9 +340,9 @@ name = "syn-mid"
|
|||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -439,7 +416,6 @@ version = "0.4.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)",
|
"anyhow 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"bstr 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"dunce 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"dunce 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -460,7 +436,6 @@ dependencies = [
|
|||||||
"checksum bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5753e2a71534719bf3f4e57006c3a4f0d2c672a4b676eec84161f763eca87dbf"
|
"checksum bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5753e2a71534719bf3f4e57006c3a4f0d2c672a4b676eec84161f763eca87dbf"
|
||||||
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||||
"checksum blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a"
|
"checksum blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a"
|
||||||
"checksum bstr 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "31accafdb70df7871592c058eca3985b71104e15ac32f64706022c58867da931"
|
|
||||||
"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
||||||
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||||
"checksum clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129"
|
"checksum clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129"
|
||||||
@ -475,11 +450,10 @@ dependencies = [
|
|||||||
"checksum hermit-abi 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "61565ff7aaace3525556587bd2dc31d4a07071957be715e63ce7b1eccf51a8f4"
|
"checksum hermit-abi 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "61565ff7aaace3525556587bd2dc31d4a07071957be715e63ce7b1eccf51a8f4"
|
||||||
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
"checksum libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)" = "3baa92041a6fec78c687fa0cc2b3fae8884f743d672cf551bed1d6dac6988d0f"
|
"checksum libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)" = "3baa92041a6fec78c687fa0cc2b3fae8884f743d672cf551bed1d6dac6988d0f"
|
||||||
"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
|
|
||||||
"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
|
"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
|
||||||
"checksum proc-macro-error 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98e9e4b82e0ef281812565ea4751049f1bdcdfccda7d3f459f2e138a40c08678"
|
"checksum proc-macro-error 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98e9e4b82e0ef281812565ea4751049f1bdcdfccda7d3f459f2e138a40c08678"
|
||||||
"checksum proc-macro-error-attr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4f5444ead4e9935abd7f27dc51f7e852a0569ac888096d5ec2499470794e2e53"
|
"checksum proc-macro-error-attr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4f5444ead4e9935abd7f27dc51f7e852a0569ac888096d5ec2499470794e2e53"
|
||||||
"checksum proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "8872cf6f48eee44265156c111456a700ab3483686b3f96df4cf5481c89157319"
|
"checksum proc-macro2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "53f5ffe53a6b28e37c9c1ce74893477864d64f74778a93a4beb43c8fa167f639"
|
||||||
"checksum quote 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "42934bc9c8ab0d3b273a16d8551c8f0fcff46be73276ca083ec2414c15c4ba5e"
|
"checksum quote 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "42934bc9c8ab0d3b273a16d8551c8f0fcff46be73276ca083ec2414c15c4ba5e"
|
||||||
"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||||
"checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
"checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
||||||
@ -487,14 +461,13 @@ dependencies = [
|
|||||||
"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||||
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
|
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
|
||||||
"checksum redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431"
|
"checksum redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431"
|
||||||
"checksum regex-automata 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4"
|
|
||||||
"checksum rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017"
|
"checksum rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017"
|
||||||
"checksum serde 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)" = "99e7b308464d16b56eba9964e4972a3eee817760ab60d88c3f86e1fecb08204c"
|
"checksum serde 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)" = "99e7b308464d16b56eba9964e4972a3eee817760ab60d88c3f86e1fecb08204c"
|
||||||
"checksum serde_derive 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)" = "818fbf6bfa9a42d3bfcaca148547aa00c7b915bec71d1757aa2d44ca68771984"
|
"checksum serde_derive 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)" = "818fbf6bfa9a42d3bfcaca148547aa00c7b915bec71d1757aa2d44ca68771984"
|
||||||
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||||
"checksum structopt 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "863246aaf5ddd0d6928dfeb1a9ca65f505599e4e1b399935ef7e75107516b4ef"
|
"checksum structopt 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "863246aaf5ddd0d6928dfeb1a9ca65f505599e4e1b399935ef7e75107516b4ef"
|
||||||
"checksum structopt-derive 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "d239ca4b13aee7a2142e6795cbd69e457665ff8037aed33b3effdc430d2f927a"
|
"checksum structopt-derive 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "d239ca4b13aee7a2142e6795cbd69e457665ff8037aed33b3effdc430d2f927a"
|
||||||
"checksum syn 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "4696caa4048ac7ce2bcd2e484b3cef88c1004e41b8e945a277e2c25dc0b72060"
|
"checksum syn 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)" = "1425de3c33b0941002740a420b1a906a350b88d08b82b2c8a01035a3f9447bac"
|
||||||
"checksum syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a"
|
"checksum syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a"
|
||||||
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||||
"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
|
"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
|
||||||
|
@ -23,9 +23,6 @@ serde = { version = "1.0.106", features = ["derive"] }
|
|||||||
structopt = "0.3.12"
|
structopt = "0.3.12"
|
||||||
uuid = { version = "0.8.1", features = ["v4"] }
|
uuid = { version = "0.8.1", features = ["v4"] }
|
||||||
|
|
||||||
[target.'cfg(unix)'.dependencies]
|
|
||||||
bstr = "0.2.12"
|
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
lto = "fat"
|
lto = "fat"
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::dir::Rank;
|
use crate::db::Rank;
|
||||||
|
|
||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{bail, Context, Result};
|
||||||
|
|
||||||
@ -36,13 +36,13 @@ pub fn zo_maxage() -> Result<Rank> {
|
|||||||
match env::var_os("_ZO_MAXAGE") {
|
match env::var_os("_ZO_MAXAGE") {
|
||||||
Some(maxage_osstr) => match maxage_osstr.to_str() {
|
Some(maxage_osstr) => match maxage_osstr.to_str() {
|
||||||
Some(maxage_str) => {
|
Some(maxage_str) => {
|
||||||
let maxage = maxage_str
|
let maxage = maxage_str.parse::<u64>().with_context(|| {
|
||||||
.parse::<i64>()
|
format!("unable to parse _ZO_MAXAGE as integer: {}", maxage_str)
|
||||||
.context("unable to parse _ZO_MAXAGE as integer")?;
|
})?;
|
||||||
|
|
||||||
Ok(maxage as Rank)
|
Ok(maxage as Rank)
|
||||||
}
|
}
|
||||||
None => bail!("invalid Unicode in _ZO_MAXAGE"),
|
None => bail!("invalid utf-8 sequence in _ZO_MAXAGE"),
|
||||||
},
|
},
|
||||||
None => Ok(1000.0),
|
None => Ok(1000.0),
|
||||||
}
|
}
|
||||||
|
223
src/db.rs
223
src/db.rs
@ -1,15 +1,11 @@
|
|||||||
use crate::dir::{Dir, Epoch, Rank};
|
|
||||||
|
|
||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{bail, Context, Result};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use std::fs::{self, File, OpenOptions};
|
use std::fs::{self, OpenOptions};
|
||||||
use std::io::{self, BufRead, BufReader, Write};
|
use std::io::{self, Write};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
pub use i32 as DBVersion;
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Eq, PartialEq, Serialize)]
|
#[derive(Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||||
struct DbVersion(u32);
|
struct DbVersion(u32);
|
||||||
|
|
||||||
@ -157,158 +153,6 @@ impl Db {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn import<P: AsRef<Path>>(&mut self, path: P, merge: bool) -> Result<()> {
|
|
||||||
if !self.dirs.is_empty() && !merge {
|
|
||||||
bail!(
|
|
||||||
"To prevent conflicts, you can only import from z with an empty zoxide database!\n\
|
|
||||||
If you wish to merge the two, specify the `--merge` flag."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let z_db_file = File::open(path).context("could not open z database file")?;
|
|
||||||
let reader = BufReader::new(z_db_file);
|
|
||||||
|
|
||||||
for (idx, read_line) in reader.lines().enumerate() {
|
|
||||||
let line_number = idx + 1;
|
|
||||||
let line = if let Ok(line) = read_line {
|
|
||||||
line
|
|
||||||
} else {
|
|
||||||
eprintln!(
|
|
||||||
"could not read entry at line {}: {:?}",
|
|
||||||
line_number, read_line
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
let split_line = line.rsplitn(3, '|').collect::<Vec<_>>();
|
|
||||||
|
|
||||||
match split_line.as_slice() {
|
|
||||||
[epoch_str, rank_str, path_str] => {
|
|
||||||
let epoch = match epoch_str.parse::<i64>() {
|
|
||||||
Ok(epoch) => epoch,
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!(
|
|
||||||
"invalid epoch '{}' at line {}: {}",
|
|
||||||
epoch_str, line_number, e
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let rank = match rank_str.parse::<f64>() {
|
|
||||||
Ok(rank) => rank,
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("invalid rank '{}' at line {}: {}", rank_str, line_number, e);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let path_abs = match dunce::canonicalize(path_str) {
|
|
||||||
Ok(path) => path,
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("invalid path '{}' at line {}: {}", path_str, line_number, e);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if merge {
|
|
||||||
// If the path exists in the database, add the ranks and set the epoch to
|
|
||||||
// the largest of the parsed epoch and the already present epoch.
|
|
||||||
if let Some(dir) = self.dirs.iter_mut().find(|dir| dir.path == path_abs) {
|
|
||||||
dir.rank += rank;
|
|
||||||
dir.last_accessed = Epoch::max(epoch, dir.last_accessed);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
self.dirs.push(Dir {
|
|
||||||
path: path_abs,
|
|
||||||
rank,
|
|
||||||
last_accessed: epoch,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
[] | [""] => {} // ignore blank lines
|
|
||||||
line => {
|
|
||||||
eprintln!("invalid entry at line {}: {:?}", line_number, line);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
self.modified = true;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add<P: AsRef<Path>>(&mut self, path: P, max_age: Rank, now: Epoch) -> Result<()> {
|
|
||||||
let path_abs = dunce::canonicalize(&path)
|
|
||||||
.with_context(|| format!("could not access directory: {}", path.as_ref().display()))?;
|
|
||||||
|
|
||||||
match self.dirs.iter_mut().find(|dir| dir.path == path_abs) {
|
|
||||||
None => self.dirs.push(Dir {
|
|
||||||
path: path_abs,
|
|
||||||
last_accessed: now,
|
|
||||||
rank: 1.0,
|
|
||||||
}),
|
|
||||||
Some(dir) => {
|
|
||||||
dir.last_accessed = now;
|
|
||||||
dir.rank += 1.0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let sum_age = self.dirs.iter().map(|dir| dir.rank).sum::<Rank>();
|
|
||||||
|
|
||||||
if sum_age > max_age {
|
|
||||||
let factor = 0.9 * max_age / sum_age;
|
|
||||||
for dir in &mut self.dirs {
|
|
||||||
dir.rank *= factor;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.dirs.retain(|dir| dir.rank >= 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.modified = true;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn query_many<'a>(&'a mut self, keywords: &'a [String]) -> impl Iterator<Item = &'a Dir> {
|
|
||||||
self.query_all()
|
|
||||||
.iter()
|
|
||||||
.filter(move |dir| dir.is_match(keywords))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn query_all(&mut self) -> &[Dir] {
|
|
||||||
let orig_len = self.dirs.len();
|
|
||||||
self.dirs.retain(Dir::is_valid);
|
|
||||||
|
|
||||||
if orig_len != self.dirs.len() {
|
|
||||||
self.modified = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.dirs.as_slice()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remove<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
|
|
||||||
if let Ok(path_abs) = dunce::canonicalize(&path) {
|
|
||||||
self.remove_exact(path_abs)
|
|
||||||
.or_else(|_| self.remove_exact(path))
|
|
||||||
} else {
|
|
||||||
self.remove_exact(path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remove_exact<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
|
|
||||||
if let Some(idx) = self.dirs.iter().position(|dir| dir.path == path.as_ref()) {
|
|
||||||
self.dirs.swap_remove(idx);
|
|
||||||
self.modified = true;
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
bail!(
|
|
||||||
"could not find path in database: {}",
|
|
||||||
path.as_ref().display()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_path<P: AsRef<Path>>(data_dir: P) -> PathBuf {
|
fn get_path<P: AsRef<Path>>(data_dir: P) -> PathBuf {
|
||||||
data_dir.as_ref().join("db.zo")
|
data_dir.as_ref().join("db.zo")
|
||||||
}
|
}
|
||||||
@ -326,3 +170,66 @@ impl Drop for Db {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type Rank = f64;
|
||||||
|
pub type Epoch = i64; // use a signed integer so subtraction can be performed on it
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
pub struct Dir {
|
||||||
|
pub path: String,
|
||||||
|
pub rank: Rank,
|
||||||
|
pub last_accessed: Epoch,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dir {
|
||||||
|
pub fn is_valid(&self) -> bool {
|
||||||
|
self.rank.is_finite() && self.rank >= 1.0 && Path::new(&self.path).is_dir()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_match(&self, query: &[String]) -> bool {
|
||||||
|
let path_lower = self.path.to_lowercase();
|
||||||
|
|
||||||
|
if let Some(query_name) = query
|
||||||
|
.last()
|
||||||
|
.and_then(|query_last| Path::new(query_last).file_name())
|
||||||
|
{
|
||||||
|
if let Some(dir_name) = Path::new(&path_lower).file_name() {
|
||||||
|
// unwrap is safe here because we've already handled invalid UTF-8
|
||||||
|
let dir_name_str = dir_name.to_str().unwrap();
|
||||||
|
let query_name_str = query_name.to_str().unwrap();
|
||||||
|
|
||||||
|
if !dir_name_str.contains(query_name_str) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut subpath = path_lower.as_str();
|
||||||
|
|
||||||
|
for subquery in query.iter() {
|
||||||
|
match subpath.find(subquery) {
|
||||||
|
Some(idx) => subpath = &subpath[idx + subquery.len()..],
|
||||||
|
None => return false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_frecency(&self, now: Epoch) -> Rank {
|
||||||
|
const HOUR: Epoch = 60 * 60;
|
||||||
|
const DAY: Epoch = 24 * HOUR;
|
||||||
|
const WEEK: Epoch = 7 * DAY;
|
||||||
|
|
||||||
|
let duration = now - self.last_accessed;
|
||||||
|
if duration < HOUR {
|
||||||
|
self.rank * 4.0
|
||||||
|
} else if duration < DAY {
|
||||||
|
self.rank * 2.0
|
||||||
|
} else if duration < WEEK {
|
||||||
|
self.rank * 0.5
|
||||||
|
} else {
|
||||||
|
self.rank * 0.25
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
106
src/dir.rs
106
src/dir.rs
@ -1,106 +0,0 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use std::path::{Path, PathBuf};
|
|
||||||
|
|
||||||
pub use f64 as Rank;
|
|
||||||
pub use i64 as Epoch; // use a signed integer so subtraction can be performed on it
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
|
||||||
pub struct Dir {
|
|
||||||
pub path: PathBuf,
|
|
||||||
pub rank: Rank,
|
|
||||||
pub last_accessed: Epoch,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Dir {
|
|
||||||
pub fn is_valid(&self) -> bool {
|
|
||||||
self.rank.is_finite() && self.rank >= 1.0 && self.path.is_dir()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
pub fn is_match(&self, query: &[String]) -> bool {
|
|
||||||
use bstr::ByteSlice;
|
|
||||||
|
|
||||||
use std::ffi::OsStr;
|
|
||||||
use std::os::unix::ffi::OsStrExt;
|
|
||||||
|
|
||||||
let path_lower = self.path.as_os_str().as_bytes().to_lowercase();
|
|
||||||
|
|
||||||
if let Some(query_name) = query
|
|
||||||
.last()
|
|
||||||
.and_then(|query_last| Path::new(query_last).file_name())
|
|
||||||
{
|
|
||||||
if let Some(dir_name) = Path::new(OsStr::from_bytes(&path_lower)).file_name() {
|
|
||||||
let dir_name_bytes = dir_name.as_bytes();
|
|
||||||
let query_name_bytes = query_name.as_bytes();
|
|
||||||
|
|
||||||
if !dir_name_bytes.contains_str(query_name_bytes) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut subpath = path_lower.as_slice();
|
|
||||||
|
|
||||||
for subquery in query.iter() {
|
|
||||||
let subquery_bytes = subquery.as_bytes();
|
|
||||||
match subpath.find(subquery_bytes) {
|
|
||||||
Some(idx) => subpath = &subpath[idx + subquery_bytes.len()..],
|
|
||||||
None => return false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(unix))]
|
|
||||||
pub fn is_match(&self, query: &[String]) -> bool {
|
|
||||||
let path_lower = match self.path.to_str() {
|
|
||||||
Some(path_str) => path_str.to_lowercase(),
|
|
||||||
None => return false, // silently ignore invalid UTF-8
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut subpath = path_lower.as_str();
|
|
||||||
|
|
||||||
if let Some(query_name) = query
|
|
||||||
.last()
|
|
||||||
.and_then(|query_last| Path::new(query_last).file_name())
|
|
||||||
{
|
|
||||||
if let Some(dir_name) = Path::new(&path_lower).file_name() {
|
|
||||||
// unwrap is safe here because we've already handled invalid UTF-8
|
|
||||||
let dir_name_str = dir_name.to_str().unwrap();
|
|
||||||
let query_name_str = query_name.to_str().unwrap();
|
|
||||||
|
|
||||||
if !dir_name_str.contains(query_name_str) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for subquery in query.iter() {
|
|
||||||
match subpath.find(subquery) {
|
|
||||||
Some(idx) => subpath = &subpath[idx + subquery.len()..],
|
|
||||||
None => return false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_frecency(&self, now: Epoch) -> Rank {
|
|
||||||
const HOUR: Epoch = 60 * 60;
|
|
||||||
const DAY: Epoch = 24 * HOUR;
|
|
||||||
const WEEK: Epoch = 7 * DAY;
|
|
||||||
|
|
||||||
let duration = now - self.last_accessed;
|
|
||||||
if duration < HOUR {
|
|
||||||
self.rank * 4.0
|
|
||||||
} else if duration < DAY {
|
|
||||||
self.rank * 2.0
|
|
||||||
} else if duration < WEEK {
|
|
||||||
self.rank / 2.0
|
|
||||||
} else {
|
|
||||||
self.rank / 4.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
88
src/fzf.rs
Normal file
88
src/fzf.rs
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
use crate::db::{Dir, Epoch};
|
||||||
|
use crate::error::SilentExit;
|
||||||
|
|
||||||
|
use anyhow::{bail, Context, Result};
|
||||||
|
|
||||||
|
use std::io::Write;
|
||||||
|
use std::process::{Child, Command, Stdio};
|
||||||
|
use std::str;
|
||||||
|
|
||||||
|
pub struct Fzf {
|
||||||
|
child: Child,
|
||||||
|
lines: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Fzf {
|
||||||
|
pub fn new() -> Result<Self> {
|
||||||
|
let child = Command::new("fzf")
|
||||||
|
.args(&["-n2..", "--no-sort"])
|
||||||
|
.stdin(Stdio::piped())
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.spawn()
|
||||||
|
.context("could not launch fzf")?;
|
||||||
|
|
||||||
|
Ok(Fzf {
|
||||||
|
child,
|
||||||
|
lines: Vec::new(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_dir(&mut self, dir: &Dir, now: Epoch) {
|
||||||
|
let frecency = dir.get_frecency(now);
|
||||||
|
|
||||||
|
let frecency_scaled = if frecency > 9999.0 {
|
||||||
|
9999
|
||||||
|
} else if frecency > 0.0 {
|
||||||
|
frecency as u32
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
self.lines
|
||||||
|
.push(format!("{:>4} {}", frecency_scaled, dir.path));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wait_selection(mut self) -> Result<Option<String>> {
|
||||||
|
// unwrap() here is safe since we have captured `stdin`
|
||||||
|
let stdin = self.child.stdin.as_mut().unwrap();
|
||||||
|
|
||||||
|
self.lines.sort_unstable_by(|line1, line2| line2.cmp(line1));
|
||||||
|
|
||||||
|
for line in self.lines.iter() {
|
||||||
|
writeln!(stdin, "{}", line).context("could not write into fzf stdin")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let output = self
|
||||||
|
.child
|
||||||
|
.wait_with_output()
|
||||||
|
.context("wait failed on fzf")?;
|
||||||
|
|
||||||
|
match output.status.code() {
|
||||||
|
// normal exit
|
||||||
|
Some(0) => {
|
||||||
|
let path_bytes = output
|
||||||
|
.stdout
|
||||||
|
.get(12..output.stdout.len() - 1)
|
||||||
|
.context("fzf returned invalid output")?;
|
||||||
|
|
||||||
|
let path_str =
|
||||||
|
str::from_utf8(path_bytes).context("invalid utf-8 sequence in fzf output")?;
|
||||||
|
|
||||||
|
Ok(Some(path_str.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// no match
|
||||||
|
Some(1) => Ok(None),
|
||||||
|
|
||||||
|
// error
|
||||||
|
Some(2) => bail!("fzf returned an error"),
|
||||||
|
|
||||||
|
// terminated by a signal
|
||||||
|
Some(code @ 130) => bail!(SilentExit { code }),
|
||||||
|
Some(128..=254) | None => bail!("fzf was terminated"),
|
||||||
|
|
||||||
|
// unknown
|
||||||
|
_ => bail!("fzf returned an unknown error"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,9 @@
|
|||||||
|
#![forbid(unsafe_code)]
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
mod db;
|
mod db;
|
||||||
mod dir;
|
|
||||||
mod error;
|
mod error;
|
||||||
|
mod fzf;
|
||||||
mod subcommand;
|
mod subcommand;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
use crate::config;
|
use crate::config;
|
||||||
|
use crate::db::{Dir, Rank};
|
||||||
use crate::util;
|
use crate::util;
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
#[derive(Debug, StructOpt)]
|
#[derive(Debug, StructOpt)]
|
||||||
#[structopt(about = "Add a new directory or increment its rank")]
|
#[structopt(about = "Add a new directory or increment its rank")]
|
||||||
pub struct Add {
|
pub struct Add {
|
||||||
path: Option<PathBuf>,
|
path: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Add {
|
impl Add {
|
||||||
@ -20,20 +20,66 @@ impl Add {
|
|||||||
Some(path) => path,
|
Some(path) => path,
|
||||||
None => {
|
None => {
|
||||||
current_dir = env::current_dir().context("unable to fetch current directory")?;
|
current_dir = env::current_dir().context("unable to fetch current directory")?;
|
||||||
¤t_dir
|
current_dir.to_str().with_context(|| {
|
||||||
|
format!("invalid utf-8 sequence in path: {}", current_dir.display())
|
||||||
|
})?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let excluded_dirs = config::zo_exclude_dirs();
|
add(path)
|
||||||
if excluded_dirs.contains(path) {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add(path: &str) -> Result<()> {
|
||||||
|
let path_abs = dunce::canonicalize(path)
|
||||||
|
.with_context(|| format!("could not resolve directory: {}", path))?;
|
||||||
|
|
||||||
|
let exclude_dirs = config::zo_exclude_dirs();
|
||||||
|
if exclude_dirs
|
||||||
|
.iter()
|
||||||
|
.any(|excluded_path| excluded_path == &path_abs)
|
||||||
|
{
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut db = util::get_db()?;
|
let path_abs_str = path_abs
|
||||||
|
.to_str()
|
||||||
|
.with_context(|| format!("invalid utf-8 sequence in path: {}", path_abs.display()))?;
|
||||||
|
|
||||||
let maxage = config::zo_maxage()?;
|
let mut db = util::get_db()?;
|
||||||
let now = util::get_current_time()?;
|
let now = util::get_current_time()?;
|
||||||
|
|
||||||
db.add(path, maxage, now)
|
let maxage = config::zo_maxage()?;
|
||||||
|
|
||||||
|
match db.dirs.iter_mut().find(|dir| dir.path == path_abs_str) {
|
||||||
|
None => db.dirs.push(Dir {
|
||||||
|
path: path_abs_str.to_string(),
|
||||||
|
last_accessed: now,
|
||||||
|
rank: 1.0,
|
||||||
|
}),
|
||||||
|
Some(dir) => {
|
||||||
|
dir.last_accessed = now;
|
||||||
|
dir.rank += 1.0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let sum_age = db.dirs.iter().map(|dir| dir.rank).sum::<Rank>();
|
||||||
|
|
||||||
|
if sum_age > maxage {
|
||||||
|
let factor = 0.9 * maxage / sum_age;
|
||||||
|
for dir in &mut db.dirs {
|
||||||
|
dir.rank *= factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
for idx in (0..db.dirs.len()).rev() {
|
||||||
|
let dir = &db.dirs[idx];
|
||||||
|
if dir.rank < 1.0 {
|
||||||
|
db.dirs.swap_remove(idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
db.modified = true;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
|
use crate::db::{Db, Dir};
|
||||||
use crate::util;
|
use crate::util;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::{bail, Context, Result};
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::fs;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
#[derive(Debug, StructOpt)]
|
#[derive(Debug, StructOpt)]
|
||||||
#[structopt(about = "Import from z database")]
|
#[structopt(about = "Import from z database")]
|
||||||
@ -16,6 +18,74 @@ pub struct Import {
|
|||||||
|
|
||||||
impl Import {
|
impl Import {
|
||||||
pub fn run(&self) -> Result<()> {
|
pub fn run(&self) -> Result<()> {
|
||||||
util::get_db()?.import(&self.path, self.merge)
|
import(&self.path, self.merge)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn import<P: AsRef<Path>>(path: P, merge: bool) -> Result<()> {
|
||||||
|
let mut db = util::get_db()?;
|
||||||
|
|
||||||
|
if !db.dirs.is_empty() && !merge {
|
||||||
|
bail!(
|
||||||
|
"To prevent conflicts, you can only import from z with an empty zoxide database!\n\
|
||||||
|
If you wish to merge the two, specify the `--merge` flag."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let buffer = fs::read_to_string(&path)
|
||||||
|
.with_context(|| format!("could not read z database: {}", path.as_ref().display()))?;
|
||||||
|
|
||||||
|
for (idx, line) in buffer.lines().enumerate() {
|
||||||
|
if let Err(e) = import_line(&mut db, line) {
|
||||||
|
let line_num = idx + 1;
|
||||||
|
eprintln!("Error on line {}: {}", line_num, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
db.modified = true;
|
||||||
|
println!("Completed import.");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn import_line(db: &mut Db, line: &str) -> Result<()> {
|
||||||
|
let mut split_line = line.rsplitn(3, '|');
|
||||||
|
|
||||||
|
let (path_str, epoch_str, rank_str) = (|| {
|
||||||
|
let epoch_str = split_line.next()?;
|
||||||
|
let rank_str = split_line.next()?;
|
||||||
|
let path_str = split_line.next()?;
|
||||||
|
Some((path_str, epoch_str, rank_str))
|
||||||
|
})()
|
||||||
|
.context("invalid entry")?;
|
||||||
|
|
||||||
|
let epoch = epoch_str
|
||||||
|
.parse::<i64>()
|
||||||
|
.with_context(|| format!("invalid epoch: {}", epoch_str))?;
|
||||||
|
|
||||||
|
let rank = rank_str
|
||||||
|
.parse::<f64>()
|
||||||
|
.with_context(|| format!("invalid rank: {}", rank_str))?;
|
||||||
|
|
||||||
|
let path_abs = dunce::canonicalize(path_str)
|
||||||
|
.with_context(|| format!("could not resolve path: {}", path_str))?;
|
||||||
|
|
||||||
|
let path_abs_str = path_abs
|
||||||
|
.to_str()
|
||||||
|
.with_context(|| format!("invalid utf-8 sequence in path: {}", path_abs.display()))?;
|
||||||
|
|
||||||
|
// If the path exists in the database, add the ranks and set the epoch to
|
||||||
|
// the largest of the parsed epoch and the already present epoch.
|
||||||
|
if let Some(dir) = db.dirs.iter_mut().find(|dir| dir.path == path_abs_str) {
|
||||||
|
dir.rank += rank;
|
||||||
|
dir.last_accessed = epoch.max(dir.last_accessed);
|
||||||
|
} else {
|
||||||
|
db.dirs.push(Dir {
|
||||||
|
path: path_abs_str.to_string(),
|
||||||
|
rank,
|
||||||
|
last_accessed: epoch,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
@ -83,13 +83,13 @@ fn hook_pwd() -> Result<Cow<'static, str>> {
|
|||||||
|
|
||||||
let tmp_path_str = tmp_path
|
let tmp_path_str = tmp_path
|
||||||
.to_str()
|
.to_str()
|
||||||
.context("invalid Unicode in zoxide tmp path")?;
|
.context("invalid utf-8 sequence in zoxide tmp path")?;
|
||||||
|
|
||||||
let pwd_path = tmp_path.join(format!("pwd-{}", Uuid::new_v4()));
|
let pwd_path = tmp_path.join(format!("pwd-{}", Uuid::new_v4()));
|
||||||
|
|
||||||
let pwd_path_str = pwd_path
|
let pwd_path_str = pwd_path
|
||||||
.to_str()
|
.to_str()
|
||||||
.context("invalid Unicode in zoxide pwd path")?;
|
.context("invalid utf-8 sequence in zoxide pwd path")?;
|
||||||
|
|
||||||
let hook_pwd = format!(
|
let hook_pwd = format!(
|
||||||
r#"
|
r#"
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
use crate::db::Db;
|
use crate::fzf::Fzf;
|
||||||
use crate::util;
|
use crate::util;
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use float_ord::FloatOrd;
|
use float_ord::FloatOrd;
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
use std::io::{self, Write};
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
#[derive(Debug, StructOpt)]
|
#[derive(Debug, StructOpt)]
|
||||||
@ -19,37 +18,32 @@ pub struct Query {
|
|||||||
impl Query {
|
impl Query {
|
||||||
pub fn run(&self) -> Result<()> {
|
pub fn run(&self) -> Result<()> {
|
||||||
let path_opt = if self.interactive {
|
let path_opt = if self.interactive {
|
||||||
self.query_interactive()?
|
query_interactive(&self.keywords)?
|
||||||
} else {
|
} else {
|
||||||
let mut db = util::get_db()?;
|
query(&self.keywords)?
|
||||||
self.query(&mut db)?
|
|
||||||
};
|
};
|
||||||
|
|
||||||
match path_opt {
|
match path_opt {
|
||||||
Some(path) => {
|
Some(path) => println!("{}", path),
|
||||||
let stdout = io::stdout();
|
|
||||||
let mut handle = stdout.lock();
|
|
||||||
handle.write_all(&path).unwrap();
|
|
||||||
handle.write_all(b"\n").unwrap();
|
|
||||||
}
|
|
||||||
None => bail!("no match found"),
|
None => bail!("no match found"),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn query(&self, db: &mut Db) -> Result<Option<Vec<u8>>> {
|
fn query(keywords: &[String]) -> Result<Option<String>> {
|
||||||
// if the input is already a valid path, simply return it
|
// if the input is already a valid path, simply return it
|
||||||
if let [path] = self.keywords.as_slice() {
|
if let [path] = keywords {
|
||||||
if Path::new(path).is_dir() {
|
if Path::new(path).is_dir() {
|
||||||
return Ok(Some(path.as_bytes().to_vec()));
|
return Ok(Some(path.to_string()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut db = util::get_db()?;
|
||||||
let now = util::get_current_time()?;
|
let now = util::get_current_time()?;
|
||||||
|
|
||||||
let keywords = self
|
let keywords = keywords
|
||||||
.keywords
|
|
||||||
.iter()
|
.iter()
|
||||||
.map(|keyword| keyword.to_lowercase())
|
.map(|keyword| keyword.to_lowercase())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
@ -71,24 +65,39 @@ impl Query {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = util::path_to_bytes(&dir.path)?.to_vec();
|
let path = &dir.path;
|
||||||
return Ok(Some(path));
|
return Ok(Some(path.to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn query_interactive(&self) -> Result<Option<Vec<u8>>> {
|
fn query_interactive(keywords: &[String]) -> Result<Option<String>> {
|
||||||
let now = util::get_current_time()?;
|
let keywords = keywords
|
||||||
|
|
||||||
let keywords = self
|
|
||||||
.keywords
|
|
||||||
.iter()
|
.iter()
|
||||||
.map(|keyword| keyword.to_lowercase())
|
.map(|keyword| keyword.to_lowercase())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let mut db = util::get_db()?;
|
let mut db = util::get_db()?;
|
||||||
let dirs = db.query_many(&keywords);
|
let now = util::get_current_time()?;
|
||||||
util::fzf_helper(now, dirs)
|
|
||||||
|
let mut fzf = Fzf::new()?;
|
||||||
|
|
||||||
|
for idx in (0..db.dirs.len()).rev() {
|
||||||
|
let dir = &db.dirs[idx];
|
||||||
|
|
||||||
|
if !dir.is_match(&keywords) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !dir.is_valid() {
|
||||||
|
db.dirs.swap_remove(idx);
|
||||||
|
db.modified = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
fzf.write_dir(&dir, now);
|
||||||
|
}
|
||||||
|
|
||||||
|
fzf.wait_selection()
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
|
use crate::fzf::Fzf;
|
||||||
use crate::util;
|
use crate::util;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::{bail, Context, Result};
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
#[derive(Debug, StructOpt)]
|
#[derive(Debug, StructOpt)]
|
||||||
@ -14,28 +15,83 @@ pub struct Remove {
|
|||||||
impl Remove {
|
impl Remove {
|
||||||
pub fn run(&self) -> Result<()> {
|
pub fn run(&self) -> Result<()> {
|
||||||
if self.interactive {
|
if self.interactive {
|
||||||
let mut db = util::get_db()?;
|
remove_interactive(&self.query)
|
||||||
let dirs = db.query_many(&self.query);
|
|
||||||
let now = util::get_current_time()?;
|
|
||||||
|
|
||||||
if let Some(path_bytes) = util::fzf_helper(now, dirs)? {
|
|
||||||
let path = util::bytes_to_path(&path_bytes)?;
|
|
||||||
db.remove_exact(path)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
} else {
|
} else {
|
||||||
match self.query.as_slice() {
|
if let &[path] = &self.query.as_slice() {
|
||||||
[path] => util::get_db()?.remove(path),
|
remove(&path)
|
||||||
_ => clap::Error::with_description(
|
} else {
|
||||||
|
clap::Error::with_description(
|
||||||
&format!(
|
&format!(
|
||||||
"remove requires 1 value in non-interactive mode, but {} were provided",
|
"remove requires 1 value in non-interactive mode, but {} were provided",
|
||||||
self.query.len()
|
self.query.len()
|
||||||
),
|
),
|
||||||
clap::ErrorKind::WrongNumberOfValues,
|
clap::ErrorKind::WrongNumberOfValues,
|
||||||
)
|
)
|
||||||
.exit(),
|
.exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn remove(path: &str) -> Result<()> {
|
||||||
|
let mut db = util::get_db()?;
|
||||||
|
|
||||||
|
if let Some(idx) = db.dirs.iter().position(|dir| &dir.path == path) {
|
||||||
|
db.dirs.swap_remove(idx);
|
||||||
|
db.modified = true;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let path_abs =
|
||||||
|
dunce::canonicalize(path).with_context(|| format!("could not resolve path: {}", path))?;
|
||||||
|
|
||||||
|
let path_abs_str = path_abs
|
||||||
|
.to_str()
|
||||||
|
.with_context(|| format!("invalid utf-8 sequence in path: {}", path_abs.display()))?;
|
||||||
|
|
||||||
|
if let Some(idx) = db.dirs.iter().position(|dir| dir.path == path_abs_str) {
|
||||||
|
db.dirs.swap_remove(idx);
|
||||||
|
db.modified = true;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
bail!("could not find path in database: {}", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_interactive(keywords: &[String]) -> Result<()> {
|
||||||
|
let mut db = util::get_db()?;
|
||||||
|
let now = util::get_current_time()?;
|
||||||
|
|
||||||
|
let keywords = keywords
|
||||||
|
.iter()
|
||||||
|
.map(|keyword| keyword.to_lowercase())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let mut fzf = Fzf::new()?;
|
||||||
|
|
||||||
|
for idx in (0..db.dirs.len()).rev() {
|
||||||
|
let dir = &db.dirs[idx];
|
||||||
|
|
||||||
|
if !dir.is_match(&keywords) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !dir.is_valid() {
|
||||||
|
db.dirs.swap_remove(idx);
|
||||||
|
db.modified = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
fzf.write_dir(&dir, now);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(path) = fzf.wait_selection()? {
|
||||||
|
if let Some(idx) = db.dirs.iter().position(|dir| dir.path == path) {
|
||||||
|
db.dirs.swap_remove(idx);
|
||||||
|
db.modified = true;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bail!("no match found");
|
||||||
|
}
|
||||||
|
124
src/util.rs
124
src/util.rs
@ -1,48 +1,10 @@
|
|||||||
use crate::config;
|
use crate::config;
|
||||||
use crate::db::Db;
|
use crate::db::{Db, Epoch};
|
||||||
use crate::dir::{Dir, Epoch};
|
|
||||||
use crate::error::SilentExit;
|
|
||||||
|
|
||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{Context, Result};
|
||||||
|
|
||||||
use std::cmp::Reverse;
|
|
||||||
use std::io::{Read, Write};
|
|
||||||
use std::path::Path;
|
|
||||||
use std::process::{Command, Stdio};
|
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
pub fn path_to_bytes<P: AsRef<Path>>(path: &P) -> Result<&[u8]> {
|
|
||||||
use std::os::unix::ffi::OsStrExt;
|
|
||||||
|
|
||||||
Ok(path.as_ref().as_os_str().as_bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(unix))]
|
|
||||||
pub fn path_to_bytes<P: AsRef<Path>>(path: &P) -> Result<&[u8]> {
|
|
||||||
match path.as_ref().to_str() {
|
|
||||||
Some(path_str) => Ok(path_str.as_bytes()),
|
|
||||||
None => bail!("invalid Unicode in path"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
pub fn bytes_to_path(bytes: &[u8]) -> Result<&Path> {
|
|
||||||
use std::ffi::OsStr;
|
|
||||||
use std::os::unix::ffi::OsStrExt;
|
|
||||||
|
|
||||||
Ok(Path::new(OsStr::from_bytes(bytes)))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(unix))]
|
|
||||||
pub fn bytes_to_path(bytes: &[u8]) -> Result<&Path> {
|
|
||||||
use std::str;
|
|
||||||
|
|
||||||
str::from_utf8(bytes)
|
|
||||||
.map(Path::new)
|
|
||||||
.context("invalid Unicode in path")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_db() -> Result<Db> {
|
pub fn get_db() -> Result<Db> {
|
||||||
let data_dir = config::zo_data_dir()?;
|
let data_dir = config::zo_data_dir()?;
|
||||||
Db::open(data_dir)
|
Db::open(data_dir)
|
||||||
@ -56,85 +18,3 @@ pub fn get_current_time() -> Result<Epoch> {
|
|||||||
|
|
||||||
Ok(current_time as Epoch)
|
Ok(current_time as Epoch)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fzf_helper<'a, I>(now: Epoch, dirs: I) -> Result<Option<Vec<u8>>>
|
|
||||||
where
|
|
||||||
I: IntoIterator<Item = &'a Dir>,
|
|
||||||
{
|
|
||||||
let mut fzf = Command::new("fzf")
|
|
||||||
.args(&["-n2..", "--no-sort"])
|
|
||||||
.stdin(Stdio::piped())
|
|
||||||
.stdout(Stdio::piped())
|
|
||||||
.spawn()
|
|
||||||
.context("could not launch fzf")?;
|
|
||||||
|
|
||||||
let fzf_stdin = fzf
|
|
||||||
.stdin
|
|
||||||
.as_mut()
|
|
||||||
.context("could not connect to fzf stdin")?;
|
|
||||||
|
|
||||||
let mut dir_frecencies = dirs
|
|
||||||
.into_iter()
|
|
||||||
.map(|dir| (dir, clamp(dir.get_frecency(now), 0.0, 9999.0) as i32))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
dir_frecencies.sort_unstable_by_key(|&(dir, frecency)| Reverse((frecency, &dir.path)));
|
|
||||||
|
|
||||||
for &(dir, frecency) in dir_frecencies.iter() {
|
|
||||||
if let Ok(path_bytes) = path_to_bytes(&dir.path) {
|
|
||||||
(|| {
|
|
||||||
write!(fzf_stdin, "{:>4} ", frecency)?;
|
|
||||||
fzf_stdin.write_all(path_bytes)?;
|
|
||||||
writeln!(fzf_stdin)
|
|
||||||
})()
|
|
||||||
.context("could not write into fzf stdin")?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let fzf_stdout = fzf
|
|
||||||
.stdout
|
|
||||||
.as_mut()
|
|
||||||
.context("could not connect to fzf stdout")?;
|
|
||||||
|
|
||||||
let mut buffer = Vec::new();
|
|
||||||
fzf_stdout
|
|
||||||
.read_to_end(&mut buffer)
|
|
||||||
.context("could not read from fzf stdout")?;
|
|
||||||
|
|
||||||
let status = fzf.wait().context("wait failed on fzf")?;
|
|
||||||
match status.code() {
|
|
||||||
// normal exit
|
|
||||||
Some(0) => match buffer.get(12..buffer.len() - 1) {
|
|
||||||
Some(path) => Ok(Some(path.to_vec())),
|
|
||||||
None => bail!("fzf returned invalid output"),
|
|
||||||
},
|
|
||||||
|
|
||||||
// no match
|
|
||||||
Some(1) => Ok(None),
|
|
||||||
|
|
||||||
// error
|
|
||||||
Some(2) => bail!("fzf returned an error"),
|
|
||||||
|
|
||||||
// terminated by a signal
|
|
||||||
Some(code @ 130) => bail!(SilentExit { code }),
|
|
||||||
Some(128..=254) | None => bail!("fzf was terminated"),
|
|
||||||
|
|
||||||
// unknown
|
|
||||||
_ => bail!("fzf returned an unknown error"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: replace with f64::clamp once it is stable <https://github.com/rust-lang/rust/issues/44095>
|
|
||||||
#[must_use = "method returns a new number and does not mutate the original value"]
|
|
||||||
#[inline]
|
|
||||||
pub fn clamp(val: f64, min: f64, max: f64) -> f64 {
|
|
||||||
assert!(min <= max);
|
|
||||||
|
|
||||||
if val > max {
|
|
||||||
max
|
|
||||||
} else if val > min {
|
|
||||||
val
|
|
||||||
} else {
|
|
||||||
min
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user