mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
Merge branch 'sxyazi:main' into main
This commit is contained in:
commit
c95b3225a0
56 changed files with 431 additions and 199 deletions
186
Cargo.lock
generated
186
Cargo.lock
generated
|
|
@ -60,6 +60,55 @@ dependencies = [
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstream"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"anstyle-parse",
|
||||||
|
"anstyle-query",
|
||||||
|
"anstyle-wincon",
|
||||||
|
"colorchoice",
|
||||||
|
"is-terminal",
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-parse"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
|
||||||
|
dependencies = [
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-query"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-wincon"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.72"
|
version = "1.0.72"
|
||||||
|
|
@ -193,9 +242,9 @@ checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.81"
|
version = "1.0.82"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6c6b2562119bf28c3439f7f02db99faf0aa1a8cdfe5772a2ee155d32227239f0"
|
checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
@ -218,12 +267,59 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "4.3.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c27cdf28c0f604ba3f512b0c9a409f8de8513e4816705deb0498b627e7c3a3fd"
|
||||||
|
dependencies = [
|
||||||
|
"clap_builder",
|
||||||
|
"clap_derive",
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_builder"
|
||||||
|
version = "4.3.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "08a9f1ab5e9f01a9b81f202e8562eb9a10de70abf9eaeac1be465c28b75aa4aa"
|
||||||
|
dependencies = [
|
||||||
|
"anstream",
|
||||||
|
"anstyle",
|
||||||
|
"clap_lex",
|
||||||
|
"strsim",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_derive"
|
||||||
|
version = "4.3.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "color_quant"
|
name = "color_quant"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorchoice"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "concurrent-queue"
|
name = "concurrent-queue"
|
||||||
version = "2.2.0"
|
version = "2.2.0"
|
||||||
|
|
@ -238,6 +334,7 @@ name = "config"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"clap",
|
||||||
"crossterm 0.27.0",
|
"crossterm 0.27.0",
|
||||||
"futures",
|
"futures",
|
||||||
"glob",
|
"glob",
|
||||||
|
|
@ -419,6 +516,27 @@ 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 = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f"
|
||||||
|
dependencies = [
|
||||||
|
"errno-dragonfly",
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno-dragonfly"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "event-listener"
|
name = "event-listener"
|
||||||
version = "2.5.3"
|
version = "2.5.3"
|
||||||
|
|
@ -664,6 +782,12 @@ version = "0.14.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
|
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
|
|
@ -705,9 +829,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "image"
|
name = "image"
|
||||||
version = "0.24.6"
|
version = "0.24.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "527909aa81e20ac3a44803521443a765550f09b5130c2c2fa1ea59c2f8f50a3a"
|
checksum = "6f3dfdbdd72063086ff443e297b61695500514b1e41095b6fb9a5ab48a70a711"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
|
|
@ -768,6 +892,17 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "is-terminal"
|
||||||
|
version = "0.4.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi",
|
||||||
|
"rustix",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.9"
|
version = "1.0.9"
|
||||||
|
|
@ -845,6 +980,12 @@ version = "0.5.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linux-raw-sys"
|
||||||
|
version = "0.4.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
version = "0.4.10"
|
version = "0.4.10"
|
||||||
|
|
@ -1254,6 +1395,19 @@ version = "0.1.23"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustix"
|
||||||
|
version = "0.38.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "172891ebdceb05aa0005f533a6cbfca599ddd7d966f6f5d4d9b2e70478e70399"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.3.3",
|
||||||
|
"errno",
|
||||||
|
"libc",
|
||||||
|
"linux-raw-sys",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.15"
|
version = "1.0.15"
|
||||||
|
|
@ -1283,18 +1437,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.182"
|
version = "1.0.183"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bdb30a74471f5b7a1fa299f40b4bf1be93af61116df95465b2b5fc419331e430"
|
checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.182"
|
version = "1.0.183"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6f4c2c6ea4bc09b5c419012eafcdb0fcef1d9119d626c8f3a0708a5b92d38a70"
|
checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
@ -1424,6 +1578,12 @@ dependencies = [
|
||||||
"lock_api",
|
"lock_api",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.28"
|
version = "2.0.28"
|
||||||
|
|
@ -1488,9 +1648,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tiff"
|
name = "tiff"
|
||||||
version = "0.8.1"
|
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 = "7449334f9ff2baf290d55d73983a7d6fa15e01198faef72af07e2a8db851e471"
|
checksum = "6d172b0f4d3fba17ba89811858b9d3d97f928aece846475bbda076ca46736211"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"flate2",
|
"flate2",
|
||||||
"jpeg-decoder",
|
"jpeg-decoder",
|
||||||
|
|
@ -1741,6 +1901,12 @@ dependencies = [
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8parse"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "valuable"
|
name = "valuable"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
|
||||||
13
README.md
13
README.md
|
|
@ -88,6 +88,19 @@ yazi
|
||||||
|
|
||||||
If you want to use your own config, copy the [config folder](https://github.com/sxyazi/yazi/tree/main/config/preset) to `~/.config/yazi`, and modify it as you like.
|
If you want to use your own config, copy the [config folder](https://github.com/sxyazi/yazi/tree/main/config/preset) to `~/.config/yazi`, and modify it as you like.
|
||||||
|
|
||||||
|
There is a wrapper of yazi that provides the ability to change the current shell's working directory when yazi exited, feel free to use it:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
function ya() {
|
||||||
|
tmp="$(mktemp -t "yazi-cwd")"
|
||||||
|
yazi --cwd-file="$tmp"
|
||||||
|
if cwd="$(cat -- "$tmp")" && [ -n "$cwd" ] && [ "$cwd" != "$PWD" ]; then
|
||||||
|
cd -- "$cwd"
|
||||||
|
fi
|
||||||
|
rm -f -- "$tmp"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Image Preview
|
## Image Preview
|
||||||
|
|
||||||
| Platform | Protocol | Support |
|
| Platform | Protocol | Support |
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ use crate::{Image, Sixel};
|
||||||
|
|
||||||
static IMAGE_SHOWN: AtomicBool = AtomicBool::new(false);
|
static IMAGE_SHOWN: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
static UEBERZUG: Lazy<Option<UnboundedSender<Option<(PathBuf, Rect)>>>> =
|
static UEBERZUG: Lazy<Option<UnboundedSender<Option<(PathBuf, Rect)>>>> =
|
||||||
Lazy::new(|| if PREVIEW.adaptor.needs_ueberzug() { Ueberzug::start().ok() } else { None });
|
Lazy::new(|| if PREVIEW.adaptor.needs_ueberzug() { Ueberzug::start().ok() } else { None });
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{path::{Path, PathBuf}, sync::Arc};
|
use std::{path::{Path, PathBuf}, sync::Arc};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use config::{MANAGER, PREVIEW};
|
use config::{BOOT, PREVIEW};
|
||||||
use image::{imageops::FilterType, DynamicImage, ImageFormat};
|
use image::{imageops::FilterType, DynamicImage, ImageFormat};
|
||||||
use md5::{Digest, Md5};
|
use md5::{Digest, Md5};
|
||||||
use shared::tty_ratio;
|
use shared::tty_ratio;
|
||||||
|
|
@ -57,8 +57,8 @@ impl Image {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn cache(path: &Path) -> PathBuf {
|
pub fn cache(path: &Path) -> PathBuf {
|
||||||
MANAGER
|
BOOT
|
||||||
.cache
|
.cache_dir
|
||||||
.join(format!("{:x}", Md5::new_with_prefix(path.to_string_lossy().as_bytes()).finalize()))
|
.join(format!("{:x}", Md5::new_with_prefix(path.to_string_lossy().as_bytes()).finalize()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
#![allow(clippy::unit_arg)]
|
||||||
|
|
||||||
mod adaptor;
|
mod adaptor;
|
||||||
mod image;
|
mod image;
|
||||||
mod iterm2;
|
mod iterm2;
|
||||||
|
|
@ -5,9 +7,9 @@ mod kitty;
|
||||||
mod sixel;
|
mod sixel;
|
||||||
mod ueberzug;
|
mod ueberzug;
|
||||||
|
|
||||||
pub use crate::adaptor::*;
|
use iterm2::*;
|
||||||
pub use crate::image::*;
|
use kitty::*;
|
||||||
pub(self) use iterm2::*;
|
use sixel::*;
|
||||||
pub(self) use kitty::*;
|
use ueberzug::*;
|
||||||
pub(self) use sixel::*;
|
|
||||||
pub(self) use ueberzug::*;
|
pub use crate::{adaptor::*, image::*};
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ impl Sixel {
|
||||||
}
|
}
|
||||||
|
|
||||||
for y in 0..img.height() {
|
for y in 0..img.height() {
|
||||||
let c = (b'?' + (1 << (y % 6))) as u8 as char;
|
let c = (b'?' + (1 << (y % 6))) as char;
|
||||||
|
|
||||||
let mut last = 0;
|
let mut last = 0;
|
||||||
let mut repeat = 0usize;
|
let mut repeat = 0usize;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
use core::{emit, files::FilesOp, input::InputMode, Event};
|
use core::{emit, files::FilesOp, input::InputMode, Event};
|
||||||
|
use std::os::unix::prelude::OsStrExt;
|
||||||
|
|
||||||
use anyhow::{Ok, Result};
|
use anyhow::{Ok, Result};
|
||||||
use config::keymap::{Control, Key, KeymapLayer};
|
use config::{keymap::{Control, Key, KeymapLayer}, BOOT};
|
||||||
use crossterm::event::KeyEvent;
|
use crossterm::event::KeyEvent;
|
||||||
use shared::{absolute_path, Term};
|
use shared::{absolute_path, Term};
|
||||||
use tokio::sync::oneshot;
|
use tokio::sync::oneshot;
|
||||||
|
|
@ -24,7 +25,10 @@ impl App {
|
||||||
|
|
||||||
while let Some(event) = app.signals.recv().await {
|
while let Some(event) = app.signals.recv().await {
|
||||||
match event {
|
match event {
|
||||||
Event::Quit => break,
|
Event::Quit => {
|
||||||
|
app.dispatch_quit();
|
||||||
|
break;
|
||||||
|
}
|
||||||
Event::Key(key) => app.dispatch_key(key),
|
Event::Key(key) => app.dispatch_key(key),
|
||||||
Event::Paste(str) => app.dispatch_paste(str),
|
Event::Paste(str) => app.dispatch_paste(str),
|
||||||
Event::Render(_) => app.dispatch_render(),
|
Event::Render(_) => app.dispatch_render(),
|
||||||
|
|
@ -37,6 +41,13 @@ impl App {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn dispatch_quit(&mut self) {
|
||||||
|
if let Some(p) = &BOOT.cwd_file {
|
||||||
|
let cwd = self.cx.manager.cwd().as_os_str();
|
||||||
|
std::fs::write(p, cwd.as_bytes()).ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn dispatch_key(&mut self, key: KeyEvent) {
|
fn dispatch_key(&mut self, key: KeyEvent) {
|
||||||
let key = Key::from(key);
|
let key = Key::from(key);
|
||||||
if Executor::handle(&mut self.cx, key) {
|
if Executor::handle(&mut self.cx, key) {
|
||||||
|
|
@ -56,7 +67,7 @@ impl App {
|
||||||
fn dispatch_render(&mut self) {
|
fn dispatch_render(&mut self) {
|
||||||
if let Some(term) = &mut self.term {
|
if let Some(term) = &mut self.term {
|
||||||
let _ = term.draw(|f| {
|
let _ = term.draw(|f| {
|
||||||
f.render_widget(Root::new(&mut self.cx), f.size());
|
f.render_widget(Root::new(&self.cx), f.size());
|
||||||
|
|
||||||
if let Some((x, y)) = self.cx.cursor() {
|
if let Some((x, y)) = self.cx.cursor() {
|
||||||
f.set_cursor(x, y);
|
f.set_cursor(x, y);
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ pub struct Ctx {
|
||||||
impl Ctx {
|
impl Ctx {
|
||||||
pub(super) fn new() -> Self {
|
pub(super) fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
manager: Manager::new(),
|
manager: Manager::make(),
|
||||||
which: Default::default(),
|
which: Default::default(),
|
||||||
select: Default::default(),
|
select: Default::default(),
|
||||||
input: Default::default(),
|
input: Default::default(),
|
||||||
|
|
@ -47,11 +47,7 @@ impl Ctx {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(super) fn image_layer(&self) -> bool {
|
pub(super) fn image_layer(&self) -> bool {
|
||||||
match self.layer() {
|
!matches!(self.layer(), KeymapLayer::Which | KeymapLayer::Tasks)
|
||||||
KeymapLayer::Which => false,
|
|
||||||
KeymapLayer::Tasks => false,
|
|
||||||
_ => true,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn position(&self, pos: Position) -> Position {
|
pub(super) fn position(&self, pos: Position) -> Position {
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ impl Executor {
|
||||||
"back" => cx.manager.active_mut().back(),
|
"back" => cx.manager.active_mut().back(),
|
||||||
"forward" => cx.manager.active_mut().forward(),
|
"forward" => cx.manager.active_mut().forward(),
|
||||||
"cd" => {
|
"cd" => {
|
||||||
let path = exec.args.get(0).map(|s| PathBuf::from(s)).unwrap_or_default();
|
let path = exec.args.get(0).map(PathBuf::from).unwrap_or_default();
|
||||||
emit!(Cd(path));
|
emit!(Cd(path));
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
@ -86,7 +86,7 @@ impl Executor {
|
||||||
"open" => cx.manager.open(exec.named.contains_key("interactive")),
|
"open" => cx.manager.open(exec.named.contains_key("interactive")),
|
||||||
"yank" => cx.manager.yank(exec.named.contains_key("cut")),
|
"yank" => cx.manager.yank(exec.named.contains_key("cut")),
|
||||||
"paste" => {
|
"paste" => {
|
||||||
let dest = cx.manager.current().cwd.clone();
|
let dest = cx.manager.cwd().to_owned();
|
||||||
let (cut, src) = cx.manager.yanked();
|
let (cut, src) = cx.manager.yanked();
|
||||||
|
|
||||||
let force = exec.named.contains_key("force");
|
let force = exec.named.contains_key("force");
|
||||||
|
|
@ -133,7 +133,7 @@ impl Executor {
|
||||||
// Tabs
|
// Tabs
|
||||||
"tab_create" => {
|
"tab_create" => {
|
||||||
let path = if exec.named.contains_key("current") {
|
let path = if exec.named.contains_key("current") {
|
||||||
cx.manager.current().cwd.clone()
|
cx.manager.cwd().to_owned()
|
||||||
} else {
|
} else {
|
||||||
exec.args.get(0).map(|p| p.into()).unwrap_or("/".into())
|
exec.args.get(0).map(|p| p.into()).unwrap_or("/".into())
|
||||||
};
|
};
|
||||||
|
|
@ -182,7 +182,7 @@ impl Executor {
|
||||||
|
|
||||||
"arrow" => {
|
"arrow" => {
|
||||||
let step: isize = exec.args.get(0).and_then(|s| s.parse().ok()).unwrap_or(0);
|
let step: isize = exec.args.get(0).and_then(|s| s.parse().ok()).unwrap_or(0);
|
||||||
if step > 0 { cx.select.next(step as usize) } else { cx.select.prev(step.abs() as usize) }
|
if step > 0 { cx.select.next(step as usize) } else { cx.select.prev(step.unsigned_abs()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => false,
|
_ => false,
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ impl<'a> Widget for Layout<'a> {
|
||||||
let location = if current.in_search {
|
let location = if current.in_search {
|
||||||
format!("{} (search)", readable_home(¤t.cwd))
|
format!("{} (search)", readable_home(¤t.cwd))
|
||||||
} else {
|
} else {
|
||||||
format!("{}", readable_home(¤t.cwd))
|
readable_home(¤t.cwd)
|
||||||
};
|
};
|
||||||
|
|
||||||
Paragraph::new(location).style(Style::new().fg(Color::Cyan)).render(chunks[0], buf);
|
Paragraph::new(location).style(Style::new().fg(Color::Cyan)).render(chunks[0], buf);
|
||||||
|
|
|
||||||
|
|
@ -2,4 +2,4 @@ mod layout;
|
||||||
mod tabs;
|
mod tabs;
|
||||||
|
|
||||||
pub(super) use layout::*;
|
pub(super) use layout::*;
|
||||||
pub(self) use tabs::*;
|
use tabs::*;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use config::LOG;
|
use config::BOOT;
|
||||||
use tracing_appender::non_blocking::WorkerGuard;
|
use tracing_appender::non_blocking::WorkerGuard;
|
||||||
use tracing_subscriber::{fmt, prelude::__tracing_subscriber_SubscriberExt, Registry};
|
use tracing_subscriber::{fmt, prelude::__tracing_subscriber_SubscriberExt, Registry};
|
||||||
|
|
||||||
|
|
@ -7,7 +7,7 @@ pub(super) struct Logs;
|
||||||
|
|
||||||
impl Logs {
|
impl Logs {
|
||||||
pub(super) fn init() -> Result<WorkerGuard> {
|
pub(super) fn init() -> Result<WorkerGuard> {
|
||||||
let appender = tracing_appender::rolling::never(&LOG.root, "yazi.log");
|
let appender = tracing_appender::rolling::never(&BOOT.state_dir, "yazi.log");
|
||||||
let (handle, guard) = tracing_appender::non_blocking(appender);
|
let (handle, guard) = tracing_appender::non_blocking(appender);
|
||||||
|
|
||||||
// let filter = EnvFilter::from_default_env();
|
// let filter = EnvFilter::from_default_env();
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
#![allow(clippy::module_inception)]
|
||||||
|
|
||||||
mod app;
|
mod app;
|
||||||
mod context;
|
mod context;
|
||||||
mod executor;
|
mod executor;
|
||||||
|
|
@ -12,12 +14,12 @@ mod status;
|
||||||
mod tasks;
|
mod tasks;
|
||||||
mod which;
|
mod which;
|
||||||
|
|
||||||
pub(self) use app::*;
|
use app::*;
|
||||||
pub(self) use context::*;
|
use context::*;
|
||||||
pub(self) use executor::*;
|
use executor::*;
|
||||||
pub(self) use logs::*;
|
use logs::*;
|
||||||
pub(self) use root::*;
|
use root::*;
|
||||||
pub(self) use signals::*;
|
use signals::*;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> anyhow::Result<()> {
|
async fn main() -> anyhow::Result<()> {
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ impl<'a> Folder<'a> {
|
||||||
.iter()
|
.iter()
|
||||||
.find(|x| x.matches(&file.path, mimetype.get(&file.path).cloned(), file.meta.is_dir()))
|
.find(|x| x.matches(&file.path, mimetype.get(&file.path).cloned(), file.meta.is_dir()))
|
||||||
.map(|x| x.style.get())
|
.map(|x| x.style.get())
|
||||||
.unwrap_or_else(|| Style::new())
|
.unwrap_or_else(Style::new)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ impl<'a> Widget for Layout<'a> {
|
||||||
|
|
||||||
// Parent
|
// Parent
|
||||||
let block = Block::new().borders(Borders::RIGHT).padding(Padding::new(1, 0, 0, 0));
|
let block = Block::new().borders(Borders::RIGHT).padding(Padding::new(1, 0, 0, 0));
|
||||||
if let Some(ref parent) = manager.parent() {
|
if let Some(parent) = manager.parent() {
|
||||||
Folder::new(self.cx, parent).render(block.inner(chunks[0]), buf);
|
Folder::new(self.cx, parent).render(block.inner(chunks[0]), buf);
|
||||||
}
|
}
|
||||||
block.render(chunks[0], buf);
|
block.render(chunks[0], buf);
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,6 @@ mod folder;
|
||||||
mod layout;
|
mod layout;
|
||||||
mod preview;
|
mod preview;
|
||||||
|
|
||||||
pub(self) use folder::*;
|
use folder::*;
|
||||||
pub(super) use layout::*;
|
pub(super) use layout::*;
|
||||||
pub(self) use preview::*;
|
use preview::*;
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,6 @@ mod progress;
|
||||||
mod right;
|
mod right;
|
||||||
|
|
||||||
pub(super) use layout::*;
|
pub(super) use layout::*;
|
||||||
pub(self) use left::*;
|
use left::*;
|
||||||
pub(self) use progress::*;
|
use progress::*;
|
||||||
pub(self) use right::*;
|
use right::*;
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ impl<'a> Right<'a> {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn position<'b>(&self) -> Vec<Span> {
|
fn position(&self) -> Vec<Span> {
|
||||||
// Colors
|
// Colors
|
||||||
let mode = self.cx.manager.active().mode();
|
let mode = self.cx.manager.active().mode();
|
||||||
let primary = mode.color(&THEME.status.primary);
|
let primary = mode.color(&THEME.status.primary);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
mod clear;
|
mod clear;
|
||||||
mod layout;
|
mod layout;
|
||||||
|
|
||||||
pub(self) use clear::*;
|
use clear::*;
|
||||||
pub(super) use layout::*;
|
pub(super) use layout::*;
|
||||||
|
|
|
||||||
|
|
@ -2,4 +2,4 @@ mod layout;
|
||||||
mod side;
|
mod side;
|
||||||
|
|
||||||
pub(super) use layout::*;
|
pub(super) use layout::*;
|
||||||
pub(self) use side::*;
|
use side::*;
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ shared = { path = "../shared" }
|
||||||
|
|
||||||
# External dependencies
|
# External dependencies
|
||||||
anyhow = "^1"
|
anyhow = "^1"
|
||||||
|
clap = { version = "^4", features = [ "derive" ] }
|
||||||
crossterm = "^0"
|
crossterm = "^0"
|
||||||
futures = "^0"
|
futures = "^0"
|
||||||
glob = "^0"
|
glob = "^0"
|
||||||
|
|
|
||||||
39
config/src/boot/boot.rs
Normal file
39
config/src/boot/boot.rs
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
use std::{env, fs, path::PathBuf};
|
||||||
|
|
||||||
|
use clap::Parser;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Boot {
|
||||||
|
pub cwd: PathBuf,
|
||||||
|
pub cwd_file: Option<PathBuf>,
|
||||||
|
pub cache_dir: PathBuf,
|
||||||
|
pub state_dir: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Parser)]
|
||||||
|
struct Args {
|
||||||
|
/// Write the cwd on exit to this file
|
||||||
|
#[arg(long)]
|
||||||
|
cwd_file: Option<PathBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Boot {
|
||||||
|
fn default() -> Self {
|
||||||
|
let args = Args::parse();
|
||||||
|
let boot = Self {
|
||||||
|
cwd: env::current_dir().unwrap_or("/".into()),
|
||||||
|
cwd_file: args.cwd_file,
|
||||||
|
cache_dir: env::temp_dir().join("yazi"),
|
||||||
|
state_dir: xdg::BaseDirectories::with_prefix("yazi").unwrap().get_state_home(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if !boot.cache_dir.is_dir() {
|
||||||
|
fs::create_dir(&boot.cache_dir).unwrap();
|
||||||
|
}
|
||||||
|
if !boot.state_dir.is_dir() {
|
||||||
|
fs::create_dir_all(&boot.state_dir).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
boot
|
||||||
|
}
|
||||||
|
}
|
||||||
3
config/src/boot/mod.rs
Normal file
3
config/src/boot/mod.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
mod boot;
|
||||||
|
|
||||||
|
pub use boot::*;
|
||||||
|
|
@ -13,11 +13,11 @@ impl From<&str> for Exec {
|
||||||
fn from(value: &str) -> Self {
|
fn from(value: &str) -> Self {
|
||||||
let mut exec = Self::default();
|
let mut exec = Self::default();
|
||||||
for x in value.split_whitespace() {
|
for x in value.split_whitespace() {
|
||||||
if x.starts_with("--") {
|
if let Some(kv) = x.strip_prefix("--") {
|
||||||
let mut it = x[2..].splitn(2, '=');
|
let mut it = kv.splitn(2, '=');
|
||||||
let name = it.next().unwrap();
|
let key = it.next().unwrap();
|
||||||
let value = it.next().unwrap_or("");
|
let value = it.next().unwrap_or("");
|
||||||
exec.named.insert(name.to_string(), value.to_string());
|
exec.named.insert(key.to_string(), value.to_string());
|
||||||
} else if exec.cmd.is_empty() {
|
} else if exec.cmd.is_empty() {
|
||||||
exec.cmd = x.to_string();
|
exec.cmd = x.to_string();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,6 @@ impl ToString for Key {
|
||||||
}
|
}
|
||||||
|
|
||||||
let code = match self.code {
|
let code = match self.code {
|
||||||
KeyCode::Char(' ') => "Space",
|
|
||||||
KeyCode::Backspace => "Backspace",
|
KeyCode::Backspace => "Backspace",
|
||||||
KeyCode::Enter => "Enter",
|
KeyCode::Enter => "Enter",
|
||||||
KeyCode::Left => "Left",
|
KeyCode::Left => "Left",
|
||||||
|
|
@ -150,7 +149,7 @@ impl ToString for Key {
|
||||||
KeyCode::F(12) => "F12",
|
KeyCode::F(12) => "F12",
|
||||||
KeyCode::Esc => "Esc",
|
KeyCode::Esc => "Esc",
|
||||||
|
|
||||||
KeyCode::Char(c) if c == ' ' => "Space",
|
KeyCode::Char(' ') => "Space",
|
||||||
KeyCode::Char(c) => {
|
KeyCode::Char(c) => {
|
||||||
s.push(if self.shift { c.to_ascii_uppercase() } else { c });
|
s.push(if self.shift { c.to_ascii_uppercase() } else { c });
|
||||||
""
|
""
|
||||||
|
|
|
||||||
|
|
@ -54,9 +54,11 @@ impl<'de> Deserialize<'de> for Keymap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Keymap {
|
impl Default for Keymap {
|
||||||
pub fn new() -> Self { toml::from_str(&MERGED_KEYMAP).unwrap() }
|
fn default() -> Self { toml::from_str(&MERGED_KEYMAP).unwrap() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Keymap {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get(&self, layer: KeymapLayer) -> &Vec<Control> {
|
pub fn get(&self, layer: KeymapLayer) -> &Vec<Control> {
|
||||||
match layer {
|
match layer {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
|
#![allow(clippy::module_inception)]
|
||||||
|
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
|
mod boot;
|
||||||
pub mod keymap;
|
pub mod keymap;
|
||||||
mod log;
|
mod log;
|
||||||
pub mod manager;
|
pub mod manager;
|
||||||
|
|
@ -12,18 +15,20 @@ pub mod theme;
|
||||||
pub(crate) use pattern::*;
|
pub(crate) use pattern::*;
|
||||||
pub(crate) use preset::*;
|
pub(crate) use preset::*;
|
||||||
|
|
||||||
static MERGED_KEYMAP: Lazy<String> = Lazy::new(|| Preset::keymap());
|
static MERGED_KEYMAP: Lazy<String> = Lazy::new(Preset::keymap);
|
||||||
static MERGED_THEME: Lazy<String> = Lazy::new(|| Preset::theme());
|
static MERGED_THEME: Lazy<String> = Lazy::new(Preset::theme);
|
||||||
static MERGED_YAZI: Lazy<String> = Lazy::new(|| Preset::yazi());
|
static MERGED_YAZI: Lazy<String> = Lazy::new(Preset::yazi);
|
||||||
|
|
||||||
pub static KEYMAP: Lazy<keymap::Keymap> = Lazy::new(|| keymap::Keymap::new());
|
pub static BOOT: Lazy<boot::Boot> = Lazy::new(Default::default);
|
||||||
pub static LOG: Lazy<log::Log> = Lazy::new(|| log::Log::new());
|
pub static KEYMAP: Lazy<keymap::Keymap> = Lazy::new(Default::default);
|
||||||
pub static MANAGER: Lazy<manager::Manager> = Lazy::new(|| manager::Manager::new());
|
pub static LOG: Lazy<log::Log> = Lazy::new(Default::default);
|
||||||
pub static OPEN: Lazy<open::Open> = Lazy::new(|| open::Open::new());
|
pub static MANAGER: Lazy<manager::Manager> = Lazy::new(Default::default);
|
||||||
pub static PREVIEW: Lazy<preview::Preview> = Lazy::new(|| preview::Preview::new());
|
pub static OPEN: Lazy<open::Open> = Lazy::new(Default::default);
|
||||||
pub static THEME: Lazy<theme::Theme> = Lazy::new(|| theme::Theme::new());
|
pub static PREVIEW: Lazy<preview::Preview> = Lazy::new(Default::default);
|
||||||
|
pub static THEME: Lazy<theme::Theme> = Lazy::new(Default::default);
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
|
Lazy::force(&BOOT);
|
||||||
Lazy::force(&KEYMAP);
|
Lazy::force(&KEYMAP);
|
||||||
Lazy::force(&LOG);
|
Lazy::force(&LOG);
|
||||||
Lazy::force(&MANAGER);
|
Lazy::force(&MANAGER);
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,14 @@
|
||||||
use std::path::PathBuf;
|
use serde::{Deserialize, Deserializer};
|
||||||
|
|
||||||
use serde::{de, Deserialize, Deserializer};
|
|
||||||
|
|
||||||
use crate::MERGED_YAZI;
|
use crate::MERGED_YAZI;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Log {
|
pub struct Log {
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
pub root: PathBuf,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Log {
|
impl Default for Log {
|
||||||
pub fn new() -> Self { toml::from_str(&MERGED_YAZI).unwrap() }
|
fn default() -> Self { toml::from_str(&MERGED_YAZI).unwrap() }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for Log {
|
impl<'de> Deserialize<'de> for Log {
|
||||||
|
|
@ -30,13 +27,6 @@ impl<'de> Deserialize<'de> for Log {
|
||||||
|
|
||||||
let outer = Outer::deserialize(deserializer)?;
|
let outer = Outer::deserialize(deserializer)?;
|
||||||
|
|
||||||
let root = xdg::BaseDirectories::with_prefix("yazi")
|
Ok(Self { enabled: outer.log.enabled })
|
||||||
.map_err(|e| de::Error::custom(e.to_string()))?
|
|
||||||
.get_state_home();
|
|
||||||
if !root.is_dir() {
|
|
||||||
std::fs::create_dir_all(&root).map_err(|e| de::Error::custom(e.to_string()))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Self { enabled: outer.log.enabled, root })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
use std::{env, fs, path::PathBuf};
|
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use super::SortBy;
|
use super::SortBy;
|
||||||
|
|
@ -7,11 +5,6 @@ use crate::MERGED_YAZI;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct Manager {
|
pub struct Manager {
|
||||||
#[serde(skip)]
|
|
||||||
pub cwd: PathBuf,
|
|
||||||
#[serde(skip)]
|
|
||||||
pub cache: PathBuf,
|
|
||||||
|
|
||||||
// Sorting
|
// Sorting
|
||||||
pub sort_by: SortBy,
|
pub sort_by: SortBy,
|
||||||
pub sort_reverse: bool,
|
pub sort_reverse: bool,
|
||||||
|
|
@ -20,21 +13,13 @@ pub struct Manager {
|
||||||
pub show_hidden: bool,
|
pub show_hidden: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Manager {
|
impl Default for Manager {
|
||||||
pub fn new() -> Self {
|
fn default() -> Self {
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct Outer {
|
struct Outer {
|
||||||
manager: Manager,
|
manager: Manager,
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut manager = toml::from_str::<Outer>(&MERGED_YAZI).unwrap().manager;
|
toml::from_str::<Outer>(&MERGED_YAZI).unwrap().manager
|
||||||
|
|
||||||
manager.cwd = env::current_dir().unwrap_or("/".into());
|
|
||||||
manager.cache = env::temp_dir().join("yazi");
|
|
||||||
if !manager.cache.is_dir() {
|
|
||||||
fs::create_dir(&manager.cache).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
manager
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,11 @@ struct OpenRule {
|
||||||
use_: String,
|
use_: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Open {
|
impl Default for Open {
|
||||||
pub fn new() -> Self { toml::from_str(&MERGED_YAZI).unwrap() }
|
fn default() -> Self { toml::from_str(&MERGED_YAZI).unwrap() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Open {
|
||||||
pub fn openers<P, M>(&self, path: P, mime: M) -> Option<Vec<&Opener>>
|
pub fn openers<P, M>(&self, path: P, mime: M) -> Option<Vec<&Opener>>
|
||||||
where
|
where
|
||||||
P: AsRef<Path>,
|
P: AsRef<Path>,
|
||||||
|
|
@ -39,11 +41,8 @@ impl Open {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn common_openers<'a>(
|
pub fn common_openers(&self, targets: &[(impl AsRef<Path>, impl AsRef<str>)]) -> Vec<&Opener> {
|
||||||
&self,
|
let grouped = targets.iter().filter_map(|(p, m)| self.openers(p, m)).collect::<Vec<_>>();
|
||||||
targets: &[(impl AsRef<Path>, impl AsRef<str>)],
|
|
||||||
) -> Vec<&Opener> {
|
|
||||||
let grouped = targets.into_iter().filter_map(|(p, m)| self.openers(p, m)).collect::<Vec<_>>();
|
|
||||||
let flat = grouped.iter().flatten().cloned().collect::<BTreeSet<_>>();
|
let flat = grouped.iter().flatten().cloned().collect::<BTreeSet<_>>();
|
||||||
flat.into_iter().filter(|o| grouped.iter().all(|g| g.contains(o))).collect()
|
flat.into_iter().filter(|o| grouped.iter().all(|g| g.contains(o))).collect()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,12 +28,13 @@ impl Default for PreviewAdaptor {
|
||||||
match env::var("TERM_PROGRAM").unwrap_or_default().as_str() {
|
match env::var("TERM_PROGRAM").unwrap_or_default().as_str() {
|
||||||
"iTerm.app" => return Self::Iterm2,
|
"iTerm.app" => return Self::Iterm2,
|
||||||
"WezTerm" => return Self::Kitty,
|
"WezTerm" => return Self::Kitty,
|
||||||
|
"vscode" => return Self::Sixel,
|
||||||
"Hyper" => return Self::Sixel,
|
"Hyper" => return Self::Sixel,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
match env::var("XDG_SESSION_TYPE").unwrap_or_default().as_str() {
|
match env::var("XDG_SESSION_TYPE").unwrap_or_default().as_str() {
|
||||||
"x11" => return Self::X11,
|
"x11" => Self::X11,
|
||||||
"wayland" => return Self::Wayland,
|
"wayland" => Self::Wayland,
|
||||||
_ => Self::Chafa,
|
_ => Self::Chafa,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -56,11 +57,6 @@ impl ToString for PreviewAdaptor {
|
||||||
impl PreviewAdaptor {
|
impl PreviewAdaptor {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn needs_ueberzug(&self) -> bool {
|
pub fn needs_ueberzug(&self) -> bool {
|
||||||
match self {
|
!matches!(self, PreviewAdaptor::Kitty | PreviewAdaptor::Iterm2 | PreviewAdaptor::Sixel)
|
||||||
PreviewAdaptor::Kitty => false,
|
|
||||||
PreviewAdaptor::Iterm2 => false,
|
|
||||||
PreviewAdaptor::Sixel => false,
|
|
||||||
_ => true,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@ pub struct Preview {
|
||||||
pub max_height: u32,
|
pub max_height: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Preview {
|
impl Default for Preview {
|
||||||
pub fn new() -> Self {
|
fn default() -> Self {
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct Outer {
|
struct Outer {
|
||||||
preview: Preview,
|
preview: Preview,
|
||||||
|
|
|
||||||
|
|
@ -69,8 +69,8 @@ pub struct Theme {
|
||||||
pub icons: Vec<Icon>,
|
pub icons: Vec<Icon>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Theme {
|
impl Default for Theme {
|
||||||
pub fn new() -> Self {
|
fn default() -> Self {
|
||||||
let mut theme: Self = toml::from_str(&MERGED_THEME).unwrap();
|
let mut theme: Self = toml::from_str(&MERGED_THEME).unwrap();
|
||||||
theme.preview.syntect_theme =
|
theme.preview.syntect_theme =
|
||||||
futures::executor::block_on(absolute_path(&theme.preview.syntect_theme));
|
futures::executor::block_on(absolute_path(&theme.preview.syntect_theme));
|
||||||
|
|
|
||||||
4
core/src/external/file.rs
vendored
4
core/src/external/file.rs
vendored
|
|
@ -19,13 +19,13 @@ pub async fn file(files: &[impl AsRef<OsStr>]) -> Result<BTreeMap<PathBuf, Strin
|
||||||
let output = String::from_utf8_lossy(&output.stdout);
|
let output = String::from_utf8_lossy(&output.stdout);
|
||||||
let mimes = BTreeMap::from_iter(
|
let mimes = BTreeMap::from_iter(
|
||||||
files
|
files
|
||||||
.into_iter()
|
.iter()
|
||||||
.zip(output.trim().lines())
|
.zip(output.trim().lines())
|
||||||
.filter(|(_, m)| MimeKind::valid(m))
|
.filter(|(_, m)| MimeKind::valid(m))
|
||||||
.map(|(f, m)| (f.as_ref().into(), m.to_string())),
|
.map(|(f, m)| (f.as_ref().into(), m.to_string())),
|
||||||
);
|
);
|
||||||
|
|
||||||
if mimes.len() == 0 {
|
if mimes.is_empty() {
|
||||||
bail!("failed to get mime types");
|
bail!("failed to get mime types");
|
||||||
}
|
}
|
||||||
Ok(mimes)
|
Ok(mimes)
|
||||||
|
|
|
||||||
2
core/src/external/pdftoppm.rs
vendored
2
core/src/external/pdftoppm.rs
vendored
|
|
@ -15,5 +15,5 @@ pub async fn pdftoppm(src: &Path, dest: impl AsRef<Path>) -> Result<()> {
|
||||||
if !output.status.success() {
|
if !output.status.success() {
|
||||||
bail!("failed to generate PDF thumbnail: {}", String::from_utf8_lossy(&output.stderr));
|
bail!("failed to generate PDF thumbnail: {}", String::from_utf8_lossy(&output.stderr));
|
||||||
}
|
}
|
||||||
Ok(Image::precache_anyway(output.stdout.into(), dest).await?)
|
Image::precache_anyway(output.stdout.into(), dest).await
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
core/src/external/rg.rs
vendored
2
core/src/external/rg.rs
vendored
|
|
@ -13,7 +13,7 @@ pub struct RgOpt {
|
||||||
pub fn rg(opt: RgOpt) -> Result<UnboundedReceiver<Vec<PathBuf>>> {
|
pub fn rg(opt: RgOpt) -> Result<UnboundedReceiver<Vec<PathBuf>>> {
|
||||||
let mut child = Command::new("rg")
|
let mut child = Command::new("rg")
|
||||||
.current_dir(&opt.cwd)
|
.current_dir(&opt.cwd)
|
||||||
.args(&["--color=never", "--files-with-matches", "--smart-case"])
|
.args(["--color=never", "--files-with-matches", "--smart-case"])
|
||||||
.arg(if opt.hidden { "--hidden" } else { "--no-hidden" })
|
.arg(if opt.hidden { "--hidden" } else { "--no-hidden" })
|
||||||
.arg(&opt.subject)
|
.arg(&opt.subject)
|
||||||
.kill_on_drop(true)
|
.kill_on_drop(true)
|
||||||
|
|
|
||||||
4
core/src/external/unar.rs
vendored
4
core/src/external/unar.rs
vendored
|
|
@ -5,8 +5,8 @@ use tokio::{io::{AsyncReadExt, BufReader}, process::Command};
|
||||||
|
|
||||||
pub async fn unar_head(path: &Path, target: &Path) -> Result<Vec<u8>> {
|
pub async fn unar_head(path: &Path, target: &Path) -> Result<Vec<u8>> {
|
||||||
let mut child = Command::new("unar")
|
let mut child = Command::new("unar")
|
||||||
.args(&[path, target])
|
.args([path, target])
|
||||||
.args(&["-o", "-"])
|
.args(["-o", "-"])
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.stderr(Stdio::null())
|
.stderr(Stdio::null())
|
||||||
.kill_on_drop(true)
|
.kill_on_drop(true)
|
||||||
|
|
|
||||||
2
core/src/external/zoxide.rs
vendored
2
core/src/external/zoxide.rs
vendored
|
|
@ -9,7 +9,7 @@ pub struct ZoxideOpt {
|
||||||
|
|
||||||
pub fn zoxide(opt: ZoxideOpt) -> Result<Receiver<Result<PathBuf>>> {
|
pub fn zoxide(opt: ZoxideOpt) -> Result<Receiver<Result<PathBuf>>> {
|
||||||
let child = Command::new("zoxide")
|
let child = Command::new("zoxide")
|
||||||
.args(&["query", "-i", "--exclude"])
|
.args(["query", "-i", "--exclude"])
|
||||||
.arg(opt.cwd)
|
.arg(opt.cwd)
|
||||||
.kill_on_drop(true)
|
.kill_on_drop(true)
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ impl Input {
|
||||||
let snap = self.snap();
|
let snap = self.snap();
|
||||||
let b = self.handle_op(
|
let b = self.handle_op(
|
||||||
if step <= 0 {
|
if step <= 0 {
|
||||||
snap.cursor.saturating_sub(step.abs() as usize)
|
snap.cursor.saturating_sub(step.unsigned_abs())
|
||||||
} else {
|
} else {
|
||||||
snap.count().min(snap.cursor + step as usize)
|
snap.count().min(snap.cursor + step as usize)
|
||||||
},
|
},
|
||||||
|
|
@ -333,11 +333,7 @@ impl Input {
|
||||||
|
|
||||||
pub fn selected(&self) -> Option<Rect> {
|
pub fn selected(&self) -> Option<Rect> {
|
||||||
let snap = self.snap();
|
let snap = self.snap();
|
||||||
let start = if let Some(s) = snap.op.start() {
|
let start = snap.op.start()?;
|
||||||
s
|
|
||||||
} else {
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let (start, end) =
|
let (start, end) =
|
||||||
if start < snap.cursor { (start, snap.cursor) } else { (snap.cursor + 1, start + 1) };
|
if start < snap.cursor { (start, snap.cursor) } else { (snap.cursor + 1, start + 1) };
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ impl InputSnaps {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(super) fn catch(&mut self) {
|
pub(super) fn catch(&mut self) {
|
||||||
let value = mem::replace(&mut self.versions[self.idx].value, String::new());
|
let value = mem::take(&mut self.versions[self.idx].value);
|
||||||
self.versions[self.idx] = self.current.clone();
|
self.versions[self.idx] = self.current.clone();
|
||||||
self.versions[self.idx].value = value;
|
self.versions[self.idx].value = value;
|
||||||
self.versions[self.idx].reset();
|
self.versions[self.idx].reset();
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,10 @@
|
||||||
|
#![allow(
|
||||||
|
clippy::if_same_then_else,
|
||||||
|
clippy::len_without_is_empty,
|
||||||
|
clippy::module_inception,
|
||||||
|
clippy::option_map_unit_fn
|
||||||
|
)]
|
||||||
|
|
||||||
mod blocker;
|
mod blocker;
|
||||||
mod event;
|
mod event;
|
||||||
pub mod external;
|
pub mod external;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{collections::{BTreeMap, BTreeSet, HashMap, HashSet}, env, mem, path::PathBuf};
|
use std::{collections::{BTreeMap, BTreeSet, HashMap, HashSet}, env, mem, path::{Path, PathBuf}};
|
||||||
|
|
||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
use config::{open::Opener, OPEN};
|
use config::{open::Opener, OPEN};
|
||||||
|
|
@ -17,9 +17,9 @@ pub struct Manager {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Manager {
|
impl Manager {
|
||||||
pub fn new() -> Self {
|
pub fn make() -> Self {
|
||||||
Self {
|
Self {
|
||||||
tabs: Tabs::new(),
|
tabs: Tabs::make(),
|
||||||
yanked: Default::default(),
|
yanked: Default::default(),
|
||||||
|
|
||||||
watcher: Watcher::start(),
|
watcher: Watcher::start(),
|
||||||
|
|
@ -28,9 +28,9 @@ impl Manager {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn refresh(&mut self) {
|
pub fn refresh(&mut self) {
|
||||||
env::set_current_dir(&self.current().cwd).ok();
|
env::set_current_dir(self.cwd()).ok();
|
||||||
|
|
||||||
self.watcher.trigger(&self.current().cwd);
|
self.watcher.trigger(self.cwd());
|
||||||
if let Some(p) = self.parent() {
|
if let Some(p) = self.parent() {
|
||||||
self.watcher.trigger(&p.cwd);
|
self.watcher.trigger(&p.cwd);
|
||||||
}
|
}
|
||||||
|
|
@ -174,7 +174,7 @@ impl Manager {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create(&self) -> bool {
|
pub fn create(&self) -> bool {
|
||||||
let cwd = self.current().cwd.clone();
|
let cwd = self.cwd().to_owned();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let result = emit!(Input(InputOpt::top("Create:")));
|
let result = emit!(Input(InputOpt::top("Create:")));
|
||||||
|
|
||||||
|
|
@ -248,7 +248,7 @@ impl Manager {
|
||||||
|
|
||||||
pub fn update_read(&mut self, op: FilesOp) -> bool {
|
pub fn update_read(&mut self, op: FilesOp) -> bool {
|
||||||
let path = op.path();
|
let path = op.path();
|
||||||
let cwd = self.current().cwd.clone();
|
let cwd = self.cwd().to_owned();
|
||||||
let hovered = self.hovered().map(|h| h.path());
|
let hovered = self.hovered().map(|h| h.path());
|
||||||
|
|
||||||
let mut b = if cwd == path && !self.current().in_search {
|
let mut b = if cwd == path && !self.current().in_search {
|
||||||
|
|
@ -277,7 +277,7 @@ impl Manager {
|
||||||
|
|
||||||
pub fn update_search(&mut self, op: FilesOp) -> bool {
|
pub fn update_search(&mut self, op: FilesOp) -> bool {
|
||||||
let path = op.path();
|
let path = op.path();
|
||||||
if self.current().in_search && self.current().cwd == path {
|
if self.current().in_search && self.cwd() == path {
|
||||||
return self.current_mut().update(op);
|
return self.current_mut().update(op);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -293,7 +293,7 @@ impl Manager {
|
||||||
let path = op.path();
|
let path = op.path();
|
||||||
let op = FilesOp::read_empty(&path);
|
let op = FilesOp::read_empty(&path);
|
||||||
|
|
||||||
if path == self.current().cwd {
|
if path == self.cwd() {
|
||||||
self.current_mut().update(op);
|
self.current_mut().update(op);
|
||||||
} else if matches!(self.parent(), Some(p) if p.cwd == path) {
|
} else if matches!(self.parent(), Some(p) if p.cwd == path) {
|
||||||
self.active_mut().parent.as_mut().unwrap().update(op);
|
self.active_mut().parent.as_mut().unwrap().update(op);
|
||||||
|
|
@ -338,6 +338,9 @@ impl Manager {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Manager {
|
impl Manager {
|
||||||
|
#[inline]
|
||||||
|
pub fn cwd(&self) -> &Path { &self.current().cwd }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn tabs(&self) -> &Tabs { &self.tabs }
|
pub fn tabs(&self) -> &Tabs { &self.tabs }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ impl Preview {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn go(&mut self, path: &Path, mime: &str, show_image: bool) {
|
pub fn go(&mut self, path: &Path, mime: &str, show_image: bool) {
|
||||||
let kind = MimeKind::new(&mime);
|
let kind = MimeKind::new(mime);
|
||||||
if !show_image && matches!(kind, MimeKind::Image | MimeKind::Video) {
|
if !show_image && matches!(kind, MimeKind::Image | MimeKind::Video) {
|
||||||
return;
|
return;
|
||||||
} else if self.same(path, mime) {
|
} else if self.same(path, mime) {
|
||||||
|
|
@ -99,7 +99,7 @@ impl Preview {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn folder(path: &Path) -> Result<PreviewData> {
|
pub async fn folder(path: &Path) -> Result<PreviewData> {
|
||||||
emit!(Files(match Files::read_dir(&path).await {
|
emit!(Files(match Files::read_dir(path).await {
|
||||||
Ok(items) => FilesOp::Read(path.to_path_buf(), items),
|
Ok(items) => FilesOp::Read(path.to_path_buf(), items),
|
||||||
Err(_) => FilesOp::IOErr(path.to_path_buf()),
|
Err(_) => FilesOp::IOErr(path.to_path_buf()),
|
||||||
}));
|
}));
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ impl Tab {
|
||||||
Self {
|
Self {
|
||||||
mode: Default::default(),
|
mode: Default::default(),
|
||||||
current: Folder::new(path),
|
current: Folder::new(path),
|
||||||
parent: path.parent().map(|p| Folder::new(p)),
|
parent: path.parent().map(Folder::new),
|
||||||
|
|
||||||
search: None,
|
search: None,
|
||||||
|
|
||||||
|
|
@ -54,7 +54,7 @@ impl Tab {
|
||||||
let ok = if step > 0 {
|
let ok = if step > 0 {
|
||||||
self.current.next(step as usize)
|
self.current.next(step as usize)
|
||||||
} else {
|
} else {
|
||||||
self.current.prev(step.abs() as usize)
|
self.current.prev(step.unsigned_abs())
|
||||||
};
|
};
|
||||||
if !ok {
|
if !ok {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use config::MANAGER;
|
use config::BOOT;
|
||||||
|
|
||||||
use super::Tab;
|
use super::Tab;
|
||||||
use crate::emit;
|
use crate::emit;
|
||||||
|
|
@ -13,8 +13,8 @@ pub struct Tabs {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tabs {
|
impl Tabs {
|
||||||
pub fn new() -> Self {
|
pub fn make() -> Self {
|
||||||
let mut tabs = Self { idx: usize::MAX, items: vec![Tab::new(&MANAGER.cwd)] };
|
let mut tabs = Self { idx: usize::MAX, items: vec![Tab::new(&BOOT.cwd)] };
|
||||||
tabs.set_idx(0);
|
tabs.set_idx(0);
|
||||||
tabs
|
tabs
|
||||||
}
|
}
|
||||||
|
|
@ -53,7 +53,7 @@ impl Tabs {
|
||||||
|
|
||||||
pub fn close(&mut self, idx: usize) -> bool {
|
pub fn close(&mut self, idx: usize) -> bool {
|
||||||
let len = self.items.len();
|
let len = self.items.len();
|
||||||
if len < 2 || idx as usize >= len {
|
if len < 2 || idx >= len {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -70,7 +70,7 @@ impl Tabs {
|
||||||
if rel > 0 {
|
if rel > 0 {
|
||||||
(self.idx + rel as usize).min(self.items.len() - 1)
|
(self.idx + rel as usize).min(self.items.len() - 1)
|
||||||
} else {
|
} else {
|
||||||
self.idx.saturating_sub(rel.abs() as usize)
|
self.idx.saturating_sub(rel.unsigned_abs())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ impl Watcher {
|
||||||
tx.blocking_send(path).ok();
|
tx.blocking_send(path).ok();
|
||||||
tx.blocking_send(parent).ok();
|
tx.blocking_send(parent).ok();
|
||||||
}
|
}
|
||||||
_ => return,
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -111,7 +111,7 @@ impl Watcher {
|
||||||
self.watcher.unwatch(p).ok();
|
self.watcher.unwatch(p).ok();
|
||||||
}
|
}
|
||||||
for p in to_watch.clone().difference(&keys) {
|
for p in to_watch.clone().difference(&keys) {
|
||||||
if self.watcher.watch(&p, RecursiveMode::NonRecursive).is_err() {
|
if self.watcher.watch(p, RecursiveMode::NonRecursive).is_err() {
|
||||||
to_watch.remove(p);
|
to_watch.remove(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,7 @@ impl Running {
|
||||||
pub(super) fn get_mut(&mut self, id: usize) -> Option<&mut Task> { self.all.get_mut(&id) }
|
pub(super) fn get_mut(&mut self, id: usize) -> Option<&mut Task> { self.all.get_mut(&id) }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(super) fn get_id(&self, idx: usize) -> Option<usize> {
|
pub(super) fn get_id(&self, idx: usize) -> Option<usize> { self.values().nth(idx).map(|t| t.id) }
|
||||||
self.values().skip(idx).next().map(|t| t.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(super) fn len(&self) -> usize { self.all.len() }
|
pub(super) fn len(&self) -> usize { self.all.len() }
|
||||||
|
|
|
||||||
|
|
@ -46,16 +46,16 @@ impl Task {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<TaskSummary> for &Task {
|
impl From<&Task> for TaskSummary {
|
||||||
fn into(self) -> TaskSummary {
|
fn from(task: &Task) -> Self {
|
||||||
TaskSummary {
|
TaskSummary {
|
||||||
name: self.name.clone(),
|
name: task.name.clone(),
|
||||||
|
|
||||||
found: self.found,
|
found: task.found,
|
||||||
processed: self.processed,
|
processed: task.processed,
|
||||||
|
|
||||||
todo: self.todo,
|
todo: task.todo,
|
||||||
done: self.done,
|
done: task.done,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ impl Tasks {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::should_implement_trait)]
|
||||||
pub fn next(&mut self) -> bool {
|
pub fn next(&mut self) -> bool {
|
||||||
let limit = Self::limit().min(self.len());
|
let limit = Self::limit().min(self.len());
|
||||||
|
|
||||||
|
|
@ -132,7 +133,7 @@ impl Tasks {
|
||||||
let mut openers = BTreeMap::new();
|
let mut openers = BTreeMap::new();
|
||||||
for (path, mime) in targets {
|
for (path, mime) in targets {
|
||||||
if let Some(opener) = OPEN.openers(path, mime).and_then(|o| o.first().cloned()) {
|
if let Some(opener) = OPEN.openers(path, mime).and_then(|o| o.first().cloned()) {
|
||||||
openers.entry(opener).or_insert_with(|| vec![]).push(path.as_ref());
|
openers.entry(opener).or_insert_with(Vec::new).push(path.as_ref());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (opener, args) in openers {
|
for (opener, args) in openers {
|
||||||
|
|
@ -143,13 +144,13 @@ impl Tasks {
|
||||||
|
|
||||||
pub fn file_open_with(&self, opener: &Opener, args: &[impl AsRef<OsStr>]) -> bool {
|
pub fn file_open_with(&self, opener: &Opener, args: &[impl AsRef<OsStr>]) -> bool {
|
||||||
if opener.spread {
|
if opener.spread {
|
||||||
self.scheduler.process_open(&opener, args);
|
self.scheduler.process_open(opener, args);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for target in args {
|
for target in args {
|
||||||
self.scheduler.process_open(&opener, &[target]);
|
self.scheduler.process_open(opener, &[target]);
|
||||||
}
|
}
|
||||||
return false;
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file_cut(&self, src: &HashSet<PathBuf>, dest: PathBuf, force: bool) -> bool {
|
pub fn file_cut(&self, src: &HashSet<PathBuf>, dest: PathBuf, force: bool) -> bool {
|
||||||
|
|
@ -238,7 +239,7 @@ impl Tasks {
|
||||||
|
|
||||||
pub fn precache_image(&self, mimetype: &BTreeMap<PathBuf, String>) -> bool {
|
pub fn precache_image(&self, mimetype: &BTreeMap<PathBuf, String>) -> bool {
|
||||||
let targets = mimetype
|
let targets = mimetype
|
||||||
.into_iter()
|
.iter()
|
||||||
.filter(|(_, m)| MimeKind::new(m) == MimeKind::Image)
|
.filter(|(_, m)| MimeKind::new(m) == MimeKind::Image)
|
||||||
.map(|(p, _)| p.clone())
|
.map(|(p, _)| p.clone())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
@ -251,7 +252,7 @@ impl Tasks {
|
||||||
|
|
||||||
pub fn precache_video(&self, mimetype: &BTreeMap<PathBuf, String>) -> bool {
|
pub fn precache_video(&self, mimetype: &BTreeMap<PathBuf, String>) -> bool {
|
||||||
let targets = mimetype
|
let targets = mimetype
|
||||||
.into_iter()
|
.iter()
|
||||||
.filter(|(_, m)| MimeKind::new(m) == MimeKind::Video)
|
.filter(|(_, m)| MimeKind::new(m) == MimeKind::Video)
|
||||||
.map(|(p, _)| p.clone())
|
.map(|(p, _)| p.clone())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
@ -264,7 +265,7 @@ impl Tasks {
|
||||||
|
|
||||||
pub fn precache_pdf(&self, mimetype: &BTreeMap<PathBuf, String>) -> bool {
|
pub fn precache_pdf(&self, mimetype: &BTreeMap<PathBuf, String>) -> bool {
|
||||||
let targets = mimetype
|
let targets = mimetype
|
||||||
.into_iter()
|
.iter()
|
||||||
.filter(|(_, m)| MimeKind::new(m) == MimeKind::PDF)
|
.filter(|(_, m)| MimeKind::new(m) == MimeKind::PDF)
|
||||||
.map(|(p, _)| p.clone())
|
.map(|(p, _)| p.clone())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ pub(crate) struct Precache {
|
||||||
pub(crate) enum PrecacheOp {
|
pub(crate) enum PrecacheOp {
|
||||||
Image(PrecacheOpImage),
|
Image(PrecacheOpImage),
|
||||||
Video(PrecacheOpVideo),
|
Video(PrecacheOpVideo),
|
||||||
PDF(PrecacheOpPDF),
|
Pdf(PrecacheOpPDF),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -66,7 +66,7 @@ impl Precache {
|
||||||
Ok(match self.rx.recv().await? {
|
Ok(match self.rx.recv().await? {
|
||||||
PrecacheOp::Image(t) => (t.id, PrecacheOp::Image(t)),
|
PrecacheOp::Image(t) => (t.id, PrecacheOp::Image(t)),
|
||||||
PrecacheOp::Video(t) => (t.id, PrecacheOp::Video(t)),
|
PrecacheOp::Video(t) => (t.id, PrecacheOp::Video(t)),
|
||||||
PrecacheOp::PDF(t) => (t.id, PrecacheOp::PDF(t)),
|
PrecacheOp::Pdf(t) => (t.id, PrecacheOp::Pdf(t)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -91,7 +91,7 @@ impl Precache {
|
||||||
external::ffmpegthumbnailer(&task.target, &cache).await.ok();
|
external::ffmpegthumbnailer(&task.target, &cache).await.ok();
|
||||||
self.sch.send(TaskOp::Adv(task.id, 1, 0))?;
|
self.sch.send(TaskOp::Adv(task.id, 1, 0))?;
|
||||||
}
|
}
|
||||||
PrecacheOp::PDF(task) => {
|
PrecacheOp::Pdf(task) => {
|
||||||
let cache = Image::cache(&task.target);
|
let cache = Image::cache(&task.target);
|
||||||
if fs::metadata(&cache).await.is_ok() {
|
if fs::metadata(&cache).await.is_ok() {
|
||||||
return Ok(self.sch.send(TaskOp::Adv(task.id, 1, 0))?);
|
return Ok(self.sch.send(TaskOp::Adv(task.id, 1, 0))?);
|
||||||
|
|
@ -159,7 +159,7 @@ impl Precache {
|
||||||
pub(crate) fn pdf(&self, id: usize, targets: Vec<PathBuf>) -> Result<()> {
|
pub(crate) fn pdf(&self, id: usize, targets: Vec<PathBuf>) -> Result<()> {
|
||||||
for target in targets {
|
for target in targets {
|
||||||
self.sch.send(TaskOp::New(id, 0))?;
|
self.sch.send(TaskOp::New(id, 0))?;
|
||||||
self.tx.send_blocking(PrecacheOp::PDF(PrecacheOpPDF { id, target }))?;
|
self.tx.send_blocking(PrecacheOp::Pdf(PrecacheOpPDF { id, target }))?;
|
||||||
}
|
}
|
||||||
self.done(id)
|
self.done(id)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,18 +22,14 @@ impl Which {
|
||||||
pub fn show(&mut self, key: &Key, layer: KeymapLayer) -> bool {
|
pub fn show(&mut self, key: &Key, layer: KeymapLayer) -> bool {
|
||||||
self.layer = layer;
|
self.layer = layer;
|
||||||
self.times = 1;
|
self.times = 1;
|
||||||
self.cands = KEYMAP
|
self.cands =
|
||||||
.get(layer)
|
KEYMAP.get(layer).iter().filter(|s| s.on.len() > 1 && s.on[0] == *key).cloned().collect();
|
||||||
.into_iter()
|
|
||||||
.filter(|s| s.on.len() > 1 && s.on[0] == *key)
|
|
||||||
.cloned()
|
|
||||||
.collect();
|
|
||||||
self.switch(true);
|
self.switch(true);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn press(&mut self, key: Key) -> bool {
|
pub fn press(&mut self, key: Key) -> bool {
|
||||||
self.cands = mem::replace(&mut self.cands, Vec::new())
|
self.cands = mem::take(&mut self.cands)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|s| s.on.len() > self.times && s.on[self.times] == key)
|
.filter(|s| s.on.len() > self.times && s.on[self.times] == key)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
@ -49,7 +45,7 @@ impl Which {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.times += 1;
|
self.times += 1;
|
||||||
return true;
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
{"version":"0.2","flagWords":[],"language":"en","words":["Punct","KEYMAP","splitn","crossterm","YAZI","unar","peekable","ratatui","syntect","pbpaste","pbcopy","ffmpegthumbnailer","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","nvim","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp","️ Überzug","️ Überzug","Konsole","Alacritty","Überzug","pkgs","paru","unarchiver","pdftoppm","poppler","prebuild","singlefile","jpegopt","EXIF"]}
|
{"flagWords":[],"words":["Punct","KEYMAP","splitn","crossterm","YAZI","unar","peekable","ratatui","syntect","pbpaste","pbcopy","ffmpegthumbnailer","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","nvim","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp","️ Überzug","️ Überzug","Konsole","Alacritty","Überzug","pkgs","paru","unarchiver","pdftoppm","poppler","prebuild","singlefile","jpegopt","EXIF","rustfmt","mktemp"],"version":"0.2","language":"en"}
|
||||||
|
|
|
||||||
31
rustfmt.toml
Normal file
31
rustfmt.toml
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
color = "Never"
|
||||||
|
condense_wildcard_suffixes = true
|
||||||
|
edition = "2021"
|
||||||
|
enum_discrim_align_threshold = 99
|
||||||
|
fn_single_line = true
|
||||||
|
format_code_in_doc_comments = false
|
||||||
|
format_generated_files = false
|
||||||
|
format_macro_matchers = true
|
||||||
|
format_macro_bodies = true
|
||||||
|
format_strings = false
|
||||||
|
hard_tabs = true
|
||||||
|
hex_literal_case = "Lower"
|
||||||
|
hide_parse_errors = true
|
||||||
|
imports_indent = "Visual"
|
||||||
|
imports_layout = "Horizontal"
|
||||||
|
imports_granularity = "Crate"
|
||||||
|
newline_style = "Unix"
|
||||||
|
normalize_comments = true
|
||||||
|
normalize_doc_attributes = false
|
||||||
|
overflow_delimited_expr = true
|
||||||
|
reorder_impl_items = true
|
||||||
|
group_imports = "StdExternalCrate"
|
||||||
|
reorder_modules = true
|
||||||
|
struct_field_align_threshold = 99
|
||||||
|
tab_spaces = 2
|
||||||
|
unstable_features = true
|
||||||
|
use_field_init_shorthand = true
|
||||||
|
use_small_heuristics = "Max"
|
||||||
|
use_try_shorthand = true
|
||||||
|
version = "Two"
|
||||||
|
wrap_comments = true
|
||||||
|
|
@ -98,6 +98,7 @@ pub fn copy_with_progress(from: &Path, to: &Path) -> mpsc::Receiver<Result<u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert a file mode to a string representation
|
// Convert a file mode to a string representation
|
||||||
|
#[allow(clippy::collapsible_else_if)]
|
||||||
pub fn file_mode(mode: u32) -> String {
|
pub fn file_mode(mode: u32) -> String {
|
||||||
use libc::{S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO, S_IFLNK, S_IFMT, S_IFSOCK, S_IRGRP, S_IROTH, S_IRUSR, S_ISGID, S_ISUID, S_ISVTX, S_IWGRP, S_IWOTH, S_IWUSR, S_IXGRP, S_IXOTH, S_IXUSR};
|
use libc::{S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO, S_IFLNK, S_IFMT, S_IFSOCK, S_IRGRP, S_IROTH, S_IRUSR, S_ISGID, S_ISUID, S_ISVTX, S_IWGRP, S_IWOTH, S_IWUSR, S_IXGRP, S_IXOTH, S_IXUSR};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,19 +28,8 @@ impl MimeKind {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let b = match parts[0] {
|
#[rustfmt::skip]
|
||||||
"application" => true,
|
let b = matches!(parts[0], "application" | "audio" | "example" | "font" | "image" | "message" | "model" | "multipart" | "text" | "video");
|
||||||
"audio" => true,
|
|
||||||
"example" => true,
|
|
||||||
"font" => true,
|
|
||||||
"image" => true,
|
|
||||||
"message" => true,
|
|
||||||
"model" => true,
|
|
||||||
"multipart" => true,
|
|
||||||
"text" => true,
|
|
||||||
"video" => true,
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
b && !parts[1].is_empty()
|
b && !parts[1].is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ impl<T> Throttle<T> {
|
||||||
where
|
where
|
||||||
F: FnOnce(Vec<T>),
|
F: FnOnce(Vec<T>),
|
||||||
{
|
{
|
||||||
let mut buf = mem::replace(&mut *self.buf.lock(), Vec::new());
|
let mut buf = mem::take(&mut *self.buf.lock());
|
||||||
buf.push(data);
|
buf.push(data);
|
||||||
f(buf)
|
f(buf)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue