diff --git a/Cargo.lock b/Cargo.lock index b7f9f0a3..51578f85 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -328,9 +328,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.16" +version = "1.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" +checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" dependencies = [ "jobserver", "libc", @@ -689,17 +689,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "either" version = "1.15.0" @@ -840,15 +829,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - [[package]] name = "fsevent-sys" version = "4.1.0" @@ -1047,151 +1027,12 @@ dependencies = [ "cc", ] -[[package]] -name = "icu_collections" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locid" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" - -[[package]] -name = "icu_normalizer" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "utf16_iter", - "utf8_iter", - "write16", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" - -[[package]] -name = "icu_properties" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locid_transform", - "icu_properties_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" - -[[package]] -name = "icu_provider" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_provider_macros", - "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "ident_case" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" -[[package]] -name = "idna" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - [[package]] name = "image" version = "0.25.5" @@ -1404,12 +1245,6 @@ version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" -[[package]] -name = "litemap" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" - [[package]] name = "lock_api" version = "0.4.12" @@ -2404,12 +2239,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - [[package]] name = "static_assertions" version = "1.1.0" @@ -2455,17 +2284,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "synstructure" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "syntect" version = "5.2.0" @@ -2620,16 +2438,6 @@ dependencies = [ "time-core", ] -[[package]] -name = "tinystr" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" -dependencies = [ - "displaydoc", - "zerovec", -] - [[package]] name = "tokio" version = "1.44.1" @@ -2870,35 +2678,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" -[[package]] -name = "url" -version = "2.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - [[package]] name = "urlencoding" version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - [[package]] name = "utf8parse" version = "0.2.2" @@ -2926,36 +2711,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "validator" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43fb22e1a008ece370ce08a3e9e4447a910e92621bb49b85d6e48a45397e7cfa" -dependencies = [ - "idna", - "once_cell", - "regex", - "serde", - "serde_derive", - "serde_json", - "url", - "validator_derive", -] - -[[package]] -name = "validator_derive" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7df16e474ef958526d1205f6dda359fdfab79d9aa6d54bafcb92dcd07673dca" -dependencies = [ - "darling", - "once_cell", - "proc-macro-error2", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "valuable" version = "0.1.1" @@ -3301,18 +3056,6 @@ version = "0.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - -[[package]] -name = "writeable" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" - [[package]] name = "yazi-adapter" version = "25.3.7" @@ -3395,7 +3138,7 @@ dependencies = [ "serde", "toml", "tracing", - "validator", + "yazi-codegen", "yazi-fs", "yazi-macro", "yazi-shared", @@ -3645,30 +3388,6 @@ dependencies = [ "yazi-shared", ] -[[package]] -name = "yoke" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - [[package]] name = "zerocopy" version = "0.8.23" @@ -3689,49 +3408,6 @@ dependencies = [ "syn", ] -[[package]] -name = "zerofrom" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerovec" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "zune-core" version = "0.4.12" diff --git a/yazi-adapter/src/drivers/iip.rs b/yazi-adapter/src/drivers/iip.rs index 1f8d6528..5c76fa63 100644 --- a/yazi-adapter/src/drivers/iip.rs +++ b/yazi-adapter/src/drivers/iip.rs @@ -5,7 +5,7 @@ use base64::{Engine, engine::{Config, general_purpose::STANDARD}}; use crossterm::{cursor::MoveTo, queue}; use image::{DynamicImage, ExtendedColorType, ImageEncoder, codecs::{jpeg::JpegEncoder, png::PngEncoder}}; use ratatui::layout::Rect; -use yazi_config::PREVIEW; +use yazi_config::YAZI; use crate::{CLOSE, Emulator, Image, START, adapter::Adapter}; @@ -44,7 +44,7 @@ impl Iip { if img.color().has_alpha() { PngEncoder::new(&mut b).write_image(&img.into_rgba8(), w, h, ExtendedColorType::Rgba8)?; } else { - JpegEncoder::new_with_quality(&mut b, PREVIEW.image_quality).encode_image(&img)?; + JpegEncoder::new_with_quality(&mut b, YAZI.preview.image_quality).encode_image(&img)?; }; let mut buf = String::with_capacity( diff --git a/yazi-adapter/src/drivers/sixel.rs b/yazi-adapter/src/drivers/sixel.rs index 526341ca..c922ac0c 100644 --- a/yazi-adapter/src/drivers/sixel.rs +++ b/yazi-adapter/src/drivers/sixel.rs @@ -5,7 +5,7 @@ use color_quant::NeuQuant; use crossterm::{cursor::MoveTo, queue}; use image::DynamicImage; use ratatui::layout::Rect; -use yazi_config::PREVIEW; +use yazi_config::YAZI; use crate::{CLOSE, ESCAPE, Emulator, Image, START, adapter::Adapter}; @@ -44,7 +44,7 @@ impl Sixel { tokio::task::spawn_blocking(move || { let img = img.into_rgba8(); - let nq = NeuQuant::new(PREVIEW.sixel_fraction as i32, 256 - alpha as usize, &img); + let nq = NeuQuant::new(YAZI.preview.sixel_fraction as i32, 256 - alpha as usize, &img); let mut buf: Vec = Vec::with_capacity(1 << 16); write!(buf, "{START}P0;1;8q\"1;1;{};{}", img.width(), img.height())?; diff --git a/yazi-adapter/src/drivers/ueberzug.rs b/yazi-adapter/src/drivers/ueberzug.rs index addb5a95..7989254b 100644 --- a/yazi-adapter/src/drivers/ueberzug.rs +++ b/yazi-adapter/src/drivers/ueberzug.rs @@ -5,7 +5,7 @@ use image::ImageReader; use ratatui::layout::Rect; use tokio::{io::AsyncWriteExt, process::{Child, Command}, sync::mpsc::{self, UnboundedSender}}; use tracing::{debug, warn}; -use yazi_config::PREVIEW; +use yazi_config::YAZI; use yazi_shared::{LOG_LEVEL, RoCell, env_exists}; use crate::{Adapter, Dimension}; @@ -57,8 +57,8 @@ impl Ueberzug { .map(|(r1, r2)| Rect { x: max.x, y: max.y, - width: max.width.min((w.min(PREVIEW.max_width as _) as f64 / r1).ceil() as _), - height: max.height.min((h.min(PREVIEW.max_height as _) as f64 / r2).ceil() as _), + width: max.width.min((w.min(YAZI.preview.max_width as _) as f64 / r1).ceil() as _), + height: max.height.min((h.min(YAZI.preview.max_height as _) as f64 / r2).ceil() as _), }) .unwrap_or(max); @@ -101,8 +101,8 @@ impl Ueberzug { } fn adjust_rect(mut rect: Rect) -> Rect { - let scale = PREVIEW.ueberzug_scale; - let (x, y, w, h) = PREVIEW.ueberzug_offset; + let scale = YAZI.preview.ueberzug_scale; + let (x, y, w, h) = YAZI.preview.ueberzug_offset; rect.x = 0f32.max(rect.x as f32 * scale + x) as u16; rect.y = 0f32.max(rect.y as f32 * scale + y) as u16; diff --git a/yazi-adapter/src/image.rs b/yazi-adapter/src/image.rs index a2ba06e4..efa4a0b6 100644 --- a/yazi-adapter/src/image.rs +++ b/yazi-adapter/src/image.rs @@ -3,7 +3,7 @@ use std::path::{Path, PathBuf}; use anyhow::Result; use image::{DynamicImage, ExtendedColorType, ImageDecoder, ImageEncoder, ImageError, ImageReader, ImageResult, Limits, codecs::{jpeg::JpegEncoder, png::PngEncoder}, imageops::FilterType, metadata::Orientation}; use ratatui::layout::Rect; -use yazi_config::{PREVIEW, TASKS}; +use yazi_config::YAZI; use crate::Dimension; @@ -12,7 +12,7 @@ pub struct Image; impl Image { pub async fn precache(path: &Path, cache: PathBuf) -> Result<()> { let (mut img, orientation, icc) = Self::decode_from(path).await?; - let (w, h) = Self::flip_size(orientation, (PREVIEW.max_width, PREVIEW.max_height)); + let (w, h) = Self::flip_size(orientation, (YAZI.preview.max_width, YAZI.preview.max_height)); let buf = tokio::task::spawn_blocking(move || { if img.width() > w || img.height() > h { @@ -29,7 +29,7 @@ impl Image { icc.map(|b| encoder.set_icc_profile(b)); encoder.write_image(&rgba, rgba.width(), rgba.height(), ExtendedColorType::Rgba8)?; } else { - let mut encoder = JpegEncoder::new_with_quality(&mut buf, PREVIEW.image_quality); + let mut encoder = JpegEncoder::new_with_quality(&mut buf, YAZI.preview.image_quality); icc.map(|b| encoder.set_icc_profile(b)); encoder.encode_image(&img.into_rgb8())?; } @@ -68,9 +68,9 @@ impl Image { Dimension::ratio() .map(|(r1, r2)| { let (w, h) = ((rect.width as f64 * r1) as u32, (rect.height as f64 * r2) as u32); - (w.min(PREVIEW.max_width), h.min(PREVIEW.max_height)) + (w.min(YAZI.preview.max_width), h.min(YAZI.preview.max_height)) }) - .unwrap_or((PREVIEW.max_width, PREVIEW.max_height)) + .unwrap_or((YAZI.preview.max_width, YAZI.preview.max_height)) } pub(super) fn pixel_area(size: (u32, u32), rect: Rect) -> Rect { @@ -86,7 +86,7 @@ impl Image { #[inline] fn filter() -> FilterType { - match PREVIEW.image_filter.as_str() { + match YAZI.preview.image_filter.as_str() { "nearest" => FilterType::Nearest, "triangle" => FilterType::Triangle, "catmull-rom" => FilterType::CatmullRom, @@ -98,14 +98,14 @@ impl Image { async fn decode_from(path: &Path) -> ImageResult<(DynamicImage, Orientation, Option>)> { let mut limits = Limits::no_limits(); - if TASKS.image_alloc > 0 { - limits.max_alloc = Some(TASKS.image_alloc as u64); + if YAZI.tasks.image_alloc > 0 { + limits.max_alloc = Some(YAZI.tasks.image_alloc as u64); } - if TASKS.image_bound[0] > 0 { - limits.max_image_width = Some(TASKS.image_bound[0] as u32); + if YAZI.tasks.image_bound[0] > 0 { + limits.max_image_width = Some(YAZI.tasks.image_bound[0] as u32); } - if TASKS.image_bound[1] > 0 { - limits.max_image_height = Some(TASKS.image_bound[1] as u32); + if YAZI.tasks.image_bound[1] > 0 { + limits.max_image_height = Some(YAZI.tasks.image_bound[1] as u32); } let path = path.to_owned(); diff --git a/yazi-boot/src/actions/clear_cache.rs b/yazi-boot/src/actions/clear_cache.rs index 2d9fd422..90b03b46 100644 --- a/yazi-boot/src/actions/clear_cache.rs +++ b/yazi-boot/src/actions/clear_cache.rs @@ -1,17 +1,17 @@ -use yazi_config::PREVIEW; +use yazi_config::YAZI; use yazi_fs::Xdg; use super::Actions; impl Actions { pub(super) fn clear_cache() { - if PREVIEW.cache_dir == Xdg::cache_dir() { - println!("Clearing cache directory: \n{:?}", PREVIEW.cache_dir); - std::fs::remove_dir_all(&PREVIEW.cache_dir).unwrap(); + if YAZI.preview.cache_dir == Xdg::cache_dir() { + println!("Clearing cache directory: \n{:?}", YAZI.preview.cache_dir); + std::fs::remove_dir_all(&YAZI.preview.cache_dir).unwrap(); } else { println!( "You've changed the default cache directory, for your data's safety, please clear it manually: \n{:?}", - PREVIEW.cache_dir + YAZI.preview.cache_dir ); } } diff --git a/yazi-boot/src/actions/debug.rs b/yazi-boot/src/actions/debug.rs index 1659964a..ea7340b4 100644 --- a/yazi-boot/src/actions/debug.rs +++ b/yazi-boot/src/actions/debug.rs @@ -56,17 +56,17 @@ impl Actions { writeln!( s, " default : {:?}", - yazi_config::OPEN.openers("f75a.txt", "text/plain").and_then(|a| a.first().cloned()) + yazi_config::YAZI.opener.first(yazi_config::YAZI.open.all("f75a.txt", "text/plain")) )?; writeln!( s, " block-create: {:?}", - yazi_config::OPEN.block_opener("bulk-create.txt", "text/plain") + yazi_config::YAZI.opener.block(yazi_config::YAZI.open.all("bulk-create.txt", "text/plain")) )?; writeln!( s, " block-rename: {:?}", - yazi_config::OPEN.block_opener("bulk-rename.txt", "text/plain") + yazi_config::YAZI.opener.block(yazi_config::YAZI.open.all("bulk-rename.txt", "text/plain")) )?; writeln!(s, "\nMultiplexers")?; diff --git a/yazi-cli/src/args.rs b/yazi-cli/src/args.rs index 7f9f37fe..aecbce7b 100644 --- a/yazi-cli/src/args.rs +++ b/yazi-cli/src/args.rs @@ -69,9 +69,6 @@ pub(super) struct CommandPack { /// Upgrade all packages. #[arg(short = 'u', long)] pub(super) upgrade: bool, - /// Migrate all packages. - #[arg(short = 'm', long)] - pub(super) migrate: bool, // TODO: remove this } #[derive(clap::Args)] diff --git a/yazi-cli/src/main.rs b/yazi-cli/src/main.rs index 9e6029b8..e0257f45 100644 --- a/yazi-cli/src/main.rs +++ b/yazi-cli/src/main.rs @@ -62,10 +62,7 @@ async fn run() -> anyhow::Result<()> { Command::Pack(cmd) => { package::init()?; - package::Package::load().await?.sync().await.ok(); - if cmd.migrate { - outln!("Migration successful")?; - } else if cmd.install { + if cmd.install { package::Package::load().await?.install(false).await?; } else if cmd.list { package::Package::load().await?.print()?; diff --git a/yazi-cli/src/package/deploy.rs b/yazi-cli/src/package/deploy.rs index 403c1e89..663477dd 100644 --- a/yazi-cli/src/package/deploy.rs +++ b/yazi-cli/src/package/deploy.rs @@ -48,17 +48,7 @@ Please manually delete it from `{}` and re-run the command.", }; for file in files { - // TODO: remove this - let (from, to) = if *file == "main.lua" { - if maybe_exists(from.join(file)).await { - (from.join(file), to.join(file)) - } else { - (from.join("init.lua"), to.join("main.lua")) - } - } else { - (from.join(file), to.join(file)) - }; - + let (from, to) = (from.join(file), to.join(file)); copy_and_seal(&from, &to) .await .with_context(|| format!("failed to copy `{}` to `{}`", from.display(), to.display()))?; diff --git a/yazi-cli/src/package/package.rs b/yazi-cli/src/package/package.rs index 994ec66a..05ab7812 100644 --- a/yazi-cli/src/package/package.rs +++ b/yazi-cli/src/package/package.rs @@ -1,9 +1,9 @@ -use std::{path::{Path, PathBuf}, str::FromStr}; +use std::{path::PathBuf, str::FromStr}; use anyhow::{Context, Result, bail}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use tokio::fs; -use yazi_fs::{Xdg, ok_or_not_found, remove_sealed, unique_name}; +use yazi_fs::Xdg; use yazi_macro::outln; use super::Dependency; @@ -84,85 +84,6 @@ impl Package { Ok(()) } - // TODO: remove this - pub(crate) async fn sync(&mut self) -> Result<()> { - async fn make_readonly(p: &Path) -> Result<()> { - let mut perms = fs::metadata(p).await?.permissions(); - perms.set_readonly(true); - fs::set_permissions(p, perms).await?; - Ok(()) - } - - match fs::read_dir(Xdg::config_dir().join("plugins")).await { - Ok(mut it) => { - while let Some(entry) = it.next_entry().await? { - let dir = entry.path(); - if !dir.is_dir() || dir.extension().is_none_or(|s| s != "yazi") { - continue; - } - - match fs::symlink_metadata(dir.join("init.lua")).await { - Ok(_) => {} - Err(e) if e.kind() == std::io::ErrorKind::NotFound => continue, - Err(e) => Err(e)?, - } - - ok_or_not_found( - fs::rename( - dir.join("main.lua"), - unique_name(dir.join("main.lua.bak").into(), async { false }).await?, - ) - .await, - )?; - - ok_or_not_found(fs::rename(dir.join("init.lua"), dir.join("main.lua")).await)?; - } - } - Err(e) if e.kind() == std::io::ErrorKind::NotFound => {} - Err(e) => Err(e) - .context(format!("failed to read `{}`", Xdg::config_dir().join("plugins").display()))?, - } - - for d in &mut self.plugins { - let dir = Xdg::config_dir().join(format!("plugins/{}", d.name)); - for f in ["LICENSE", "README.md", "main.lua"] { - make_readonly(&dir.join(f)).await.ok(); - } - - let tracker = dir.join("DO_NOT_MODIFY_ANYTHING_IN_THIS_DIRECTORY"); - if fs::read(&tracker).await.is_ok_and(|v| v.is_empty()) { - if d.hash.is_empty() { - d.hash = d.hash().await?; - } - remove_sealed(&tracker).await.ok(); - } - } - for d in &mut self.flavors { - let dir = Xdg::config_dir().join(format!("flavors/{}", d.name)); - for f in [ - "LICENSE", - "LICENSE-tmtheme", - "README.md", - "filestyle.toml", - "flavor.toml", - "preview.png", - "tmtheme.xml", - ] { - make_readonly(&dir.join(f)).await.ok(); - } - - let tracker = dir.join("DO_NOT_MODIFY_ANYTHING_IN_THIS_DIRECTORY"); - if fs::read(&tracker).await.is_ok_and(|v| v.is_empty()) { - if d.hash.is_empty() { - d.hash = d.hash().await?; - } - remove_sealed(&tracker).await.ok(); - } - } - - self.save().await - } - async fn add(&mut self, use_: &str) -> Result<()> { let mut dep = Dependency::from_str(use_)?; if let Some(d) = self.identical(&dep) { diff --git a/yazi-codegen/src/lib.rs b/yazi-codegen/src/lib.rs index e1c930bf..8561478a 100644 --- a/yazi-codegen/src/lib.rs +++ b/yazi-codegen/src/lib.rs @@ -1,6 +1,6 @@ use proc_macro::TokenStream; use quote::{format_ident, quote}; -use syn::{FnArg, ItemFn}; +use syn::{Attribute, Data, DeriveInput, Fields, FnArg, ItemFn, parse_macro_input}; #[proc_macro_attribute] pub fn command(_: TokenStream, item: TokenStream) -> TokenStream { @@ -23,7 +23,7 @@ pub fn command(_: TokenStream, item: TokenStream) -> TokenStream { // Add `__` prefix to the original function name let name_ori = f.sig.ident; - f.sig.ident = format_ident!("__{}", name_ori); + f.sig.ident = format_ident!("__{name_ori}"); let name_new = &f.sig.ident; // Collect the rest of the arguments @@ -39,3 +39,146 @@ pub fn command(_: TokenStream, item: TokenStream) -> TokenStream { } .into() } + +#[proc_macro_derive(DeserializeOver1)] +pub fn deserialize_over1(input: TokenStream) -> TokenStream { + // Parse the input tokens into a syntax tree + let input = parse_macro_input!(input as DeriveInput); + + // Get the name of the struct + let name = &input.ident; + let shadow_name = format_ident!("__{name}Shadow"); + + // Process the struct fields + let (shadow_fields, field_calls) = match &input.data { + Data::Struct(struct_) => match &struct_.fields { + Fields::Named(fields) => { + let mut shadow_fields = Vec::with_capacity(fields.named.len()); + let mut field_calls = Vec::with_capacity(fields.named.len()); + + for field in &fields.named { + let name = &field.ident; + let attrs: Vec<&Attribute> = + field.attrs.iter().filter(|&a| a.path().is_ident("serde")).collect(); + + shadow_fields.push(quote! { + #(#attrs)* + pub(crate) #name: Option + }); + field_calls.push(quote! { + if let Some(value) = shadow.#name { + self.#name = self.#name.deserialize_over(value).map_err(serde::de::Error::custom)?; + } + }); + } + + (shadow_fields, field_calls) + } + _ => panic!("DeserializeOver1 only supports structs with named fields"), + }, + _ => panic!("DeserializeOver1 only supports structs"), + }; + + quote! { + #[derive(serde::Deserialize)] + pub(crate) struct #shadow_name { + #(#shadow_fields),* + } + + impl #name { + #[inline] + pub(crate) fn deserialize_over<'de, D>(self, deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + self.deserialize_over_with::(Self::deserialize_shadow(deserializer)?) + } + + #[inline] + pub(crate) fn deserialize_shadow<'de, D>(deserializer: D) -> Result<#shadow_name, D::Error> + where + D: serde::Deserializer<'de>, + { + #shadow_name::deserialize(deserializer) + } + + #[inline] + pub(crate) fn deserialize_over_with<'de, D>(mut self, shadow: #shadow_name) -> Result + where + D: serde::Deserializer<'de>, + { + #(#field_calls)* + Ok(self) + } + } + } + .into() +} + +#[proc_macro_derive(DeserializeOver2)] +pub fn deserialize_over2(input: TokenStream) -> TokenStream { + // Parse the input tokens into a syntax tree + let input = parse_macro_input!(input as DeriveInput); + + // Get the name of the struct + let name = &input.ident; + let shadow_name = format_ident!("__{name}Shadow"); + + // Process the struct fields + let (shadow_fields, field_assignments) = match &input.data { + Data::Struct(struct_) => match &struct_.fields { + Fields::Named(fields) => { + let mut shadow_fields = Vec::with_capacity(fields.named.len()); + let mut field_assignments = Vec::with_capacity(fields.named.len()); + + for field in &fields.named { + let (ty, name) = (&field.ty, &field.ident); + shadow_fields.push(quote! { + pub(crate) #name: Option<#ty> + }); + field_assignments.push(quote! { + if let Some(value) = shadow.#name { + self.#name = value; + } + }); + } + + (shadow_fields, field_assignments) + } + _ => panic!("DeserializeOver2 only supports structs with named fields"), + }, + _ => panic!("DeserializeOver2 only supports structs"), + }; + + quote! { + #[derive(serde::Deserialize)] + pub(crate) struct #shadow_name { + #(#shadow_fields),* + } + + impl #name { + #[inline] + pub(crate) fn deserialize_over<'de, D>(mut self, deserializer: D) -> Result + where + D: serde::Deserializer<'de> + { + Ok(self.deserialize_over_with(Self::deserialize_shadow(deserializer)?)) + } + + #[inline] + pub(crate) fn deserialize_shadow<'de, D>(deserializer: D) -> Result<#shadow_name, D::Error> + where + D: serde::Deserializer<'de> + { + #shadow_name::deserialize(deserializer) + } + + #[inline] + pub(crate) fn deserialize_over_with(mut self, shadow: #shadow_name) -> Self { + #(#field_assignments)* + self + } + } + } + .into() +} diff --git a/yazi-config/Cargo.toml b/yazi-config/Cargo.toml index a37f6a86..30a91e7e 100644 --- a/yazi-config/Cargo.toml +++ b/yazi-config/Cargo.toml @@ -9,9 +9,10 @@ homepage = "https://yazi-rs.github.io" repository = "https://github.com/sxyazi/yazi" [dependencies] -yazi-fs = { path = "../yazi-fs", version = "25.3.7" } -yazi-macro = { path = "../yazi-macro", version = "25.3.7" } -yazi-shared = { path = "../yazi-shared", version = "25.3.7" } +yazi-codegen = { path = "../yazi-codegen", version = "25.3.7" } +yazi-fs = { path = "../yazi-fs", version = "25.3.7" } +yazi-macro = { path = "../yazi-macro", version = "25.3.7" } +yazi-shared = { path = "../yazi-shared", version = "25.3.7" } # External dependencies anyhow = { workspace = true } @@ -24,7 +25,6 @@ regex = { workspace = true } serde = { workspace = true } toml = { workspace = true } tracing = { workspace = true } -validator = { version = "0.20.0", features = [ "derive" ] } [target.'cfg(target_os = "macos")'.dependencies] crossterm = { workspace = true, features = [ "use-dev-tty", "libc" ] } diff --git a/yazi-config/src/keymap/keymap.rs b/yazi-config/src/keymap/keymap.rs index d9803323..980d43c0 100644 --- a/yazi-config/src/keymap/keymap.rs +++ b/yazi-config/src/keymap/keymap.rs @@ -1,23 +1,21 @@ -use std::{collections::HashSet, str::FromStr}; - -use anyhow::Context; -use indexmap::IndexSet; -use serde::{Deserialize, Deserializer}; +use anyhow::Result; +use serde::Deserialize; +use yazi_codegen::DeserializeOver1; use yazi_shared::Layer; -use super::Chord; -use crate::{Preset, keymap::Key}; +use super::{Chord, KeymapRule}; -#[derive(Debug)] +#[derive(Deserialize, DeserializeOver1)] pub struct Keymap { - pub mgr: Vec, - pub tasks: Vec, - pub spot: Vec, - pub pick: Vec, - pub input: Vec, - pub confirm: Vec, - pub help: Vec, - pub cmp: Vec, + #[serde(rename = "manager")] + pub mgr: KeymapRule, + pub tasks: KeymapRule, + pub spot: KeymapRule, + pub pick: KeymapRule, + pub input: KeymapRule, + pub confirm: KeymapRule, + pub help: KeymapRule, + pub cmp: KeymapRule, } impl Keymap { @@ -38,77 +36,17 @@ impl Keymap { } } -impl FromStr for Keymap { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - toml::from_str(s).context("Failed to parse your keymap.toml") - } -} - -impl<'de> Deserialize<'de> for Keymap { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - #[derive(Deserialize)] - struct Shadow { - #[serde(rename = "manager")] - mgr: Inner, // TODO: remove serde(rename) - tasks: Inner, - spot: Inner, - pick: Inner, - input: Inner, - confirm: Inner, - help: Inner, - cmp: Inner, - } - #[derive(Deserialize)] - struct Inner { - keymap: IndexSet, - #[serde(default)] - prepend_keymap: IndexSet, - #[serde(default)] - append_keymap: IndexSet, - } - - fn mix(l: Layer, a: IndexSet, b: IndexSet, c: IndexSet) -> Vec { - #[inline] - fn on(Chord { on, .. }: &Chord) -> [Key; 2] { - [on.first().copied().unwrap_or_default(), on.get(1).copied().unwrap_or_default()] - } - - let a_seen: HashSet<_> = a.iter().map(on).collect(); - let b_seen: HashSet<_> = b.iter().map(on).collect(); - - Preset::mix( - a, - b.into_iter().filter(|v| !a_seen.contains(&on(v))), - c.into_iter().filter(|v| !b_seen.contains(&on(v))), - ) - .filter(|chord| !chord.noop()) - .map(|chord| chord.with_layer(l)) - .collect() - } - - let shadow = Shadow::deserialize(deserializer)?; +impl Keymap { + pub(crate) fn reshape(self) -> Result { Ok(Self { - #[rustfmt::skip] - mgr: mix(Layer::Mgr, shadow.mgr.prepend_keymap, shadow.mgr.keymap, shadow.mgr.append_keymap), - #[rustfmt::skip] - tasks: mix(Layer::Tasks, shadow.tasks.prepend_keymap, shadow.tasks.keymap, shadow.tasks.append_keymap), - #[rustfmt::skip] - spot: mix(Layer::Spot, shadow.spot.prepend_keymap, shadow.spot.keymap, shadow.spot.append_keymap), - #[rustfmt::skip] - pick: mix(Layer::Pick, shadow.pick.prepend_keymap, shadow.pick.keymap, shadow.pick.append_keymap), - #[rustfmt::skip] - input: mix(Layer::Input, shadow.input.prepend_keymap, shadow.input.keymap, shadow.input.append_keymap), - #[rustfmt::skip] - confirm: mix(Layer::Confirm, shadow.confirm.prepend_keymap, shadow.confirm.keymap, shadow.confirm.append_keymap), - #[rustfmt::skip] - help: mix(Layer::Help, shadow.help.prepend_keymap, shadow.help.keymap, shadow.help.append_keymap), - #[rustfmt::skip] - cmp: mix(Layer::Cmp, shadow.cmp.prepend_keymap, shadow.cmp.keymap, shadow.cmp.append_keymap), + mgr: self.mgr.reshape(Layer::Mgr)?, + tasks: self.tasks.reshape(Layer::Tasks)?, + spot: self.spot.reshape(Layer::Spot)?, + pick: self.pick.reshape(Layer::Pick)?, + input: self.input.reshape(Layer::Input)?, + confirm: self.confirm.reshape(Layer::Confirm)?, + help: self.help.reshape(Layer::Help)?, + cmp: self.cmp.reshape(Layer::Cmp)?, }) } } diff --git a/yazi-config/src/keymap/mod.rs b/yazi-config/src/keymap/mod.rs index 49ebdda2..3c8bab95 100644 --- a/yazi-config/src/keymap/mod.rs +++ b/yazi-config/src/keymap/mod.rs @@ -1 +1 @@ -yazi_macro::mod_flat!(chord cow deserializers key keymap); +yazi_macro::mod_flat!(chord cow deserializers key keymap rule); diff --git a/yazi-config/src/keymap/rule.rs b/yazi-config/src/keymap/rule.rs new file mode 100644 index 00000000..80cd8e2b --- /dev/null +++ b/yazi-config/src/keymap/rule.rs @@ -0,0 +1,47 @@ +use std::{collections::HashSet, ops::Deref}; + +use anyhow::Result; +use serde::Deserialize; +use yazi_codegen::DeserializeOver2; +use yazi_shared::Layer; + +use super::Chord; +use crate::{Preset, keymap::Key}; + +#[derive(Default, Deserialize, DeserializeOver2)] +pub struct KeymapRule { + pub keymap: Vec, + #[serde(default)] + prepend_keymap: Vec, + #[serde(default)] + append_keymap: Vec, +} + +impl Deref for KeymapRule { + type Target = Vec; + + fn deref(&self) -> &Self::Target { &self.keymap } +} + +impl KeymapRule { + pub(crate) fn reshape(self, layer: Layer) -> Result { + #[inline] + fn on(Chord { on, .. }: &Chord) -> [Key; 2] { + [on.first().copied().unwrap_or_default(), on.get(1).copied().unwrap_or_default()] + } + + let a_seen: HashSet<_> = self.prepend_keymap.iter().map(on).collect(); + let b_seen: HashSet<_> = self.keymap.iter().map(on).collect(); + + let keymap = Preset::mix( + self.prepend_keymap, + self.keymap.into_iter().filter(|v| !a_seen.contains(&on(v))), + self.append_keymap.into_iter().filter(|v| !b_seen.contains(&on(v))), + ) + .filter(|chord| !chord.noop()) + .map(|chord| chord.with_layer(layer)) + .collect(); + + Ok(Self { keymap, ..Default::default() }) + } +} diff --git a/yazi-config/src/lib.rs b/yazi-config/src/lib.rs index 1f87e7ca..5493d58c 100644 --- a/yazi-config/src/lib.rs +++ b/yazi-config/src/lib.rs @@ -1,25 +1,16 @@ #![allow(clippy::module_inception)] -yazi_macro::mod_pub!(keymap mgr open plugin popup preview tasks theme which); +yazi_macro::mod_pub!(keymap mgr open opener plugin popup preview tasks theme which); -yazi_macro::mod_flat!(layout pattern preset priority); +yazi_macro::mod_flat!(layout pattern preset priority yazi); -use std::{io::{Read, Write}, str::FromStr}; +use std::io::{Read, Write}; use yazi_shared::{RoCell, SyncCell, tty::TTY}; +pub static YAZI: RoCell = RoCell::new(); pub static KEYMAP: RoCell = RoCell::new(); -pub static MGR: RoCell = RoCell::new(); -pub static OPEN: RoCell = RoCell::new(); -pub static PLUGIN: RoCell = RoCell::new(); -pub static PREVIEW: RoCell = RoCell::new(); -pub static TASKS: RoCell = RoCell::new(); pub static THEME: RoCell = RoCell::new(); -pub static INPUT: RoCell = RoCell::new(); -pub static CONFIRM: RoCell = RoCell::new(); -pub static PICK: RoCell = RoCell::new(); -pub static WHICH: RoCell = RoCell::new(); - pub static LAYOUT: SyncCell = SyncCell::new(Layout::default()); pub fn init() -> anyhow::Result<()> { @@ -30,53 +21,47 @@ pub fn init() -> anyhow::Result<()> { Ok(()) } -pub fn init_flavor(light: bool) -> anyhow::Result<()> { - let mut flavor_toml = Preset::flavor(light, true); - if let Err(e) = flavor_toml { - wait_for_key(e)?; - flavor_toml = Preset::flavor(light, false); +fn try_init(merge: bool) -> anyhow::Result<()> { + let mut yazi = Preset::yazi()?; + let mut keymap = Preset::keymap()?; + + if merge { + let dir = yazi_fs::Xdg::config_dir(); + yazi = yazi.deserialize_over(toml::Deserializer::new( + &std::fs::read_to_string(dir.join("yazi.toml")).unwrap_or_default(), + ))?; + keymap = keymap.deserialize_over(toml::Deserializer::new( + &std::fs::read_to_string(dir.join("keymap.toml")).unwrap_or_default(), + ))?; } - let mut theme: theme::Theme = <_>::from_str(&flavor_toml.unwrap())?; - theme.mgr.syntect_theme = theme - .flavor - .syntect_path(light) - .unwrap_or_else(|| yazi_fs::expand_path(&theme.mgr.syntect_theme)); - - THEME.init(theme); + YAZI.init(yazi.reshape()?); + KEYMAP.init(keymap.reshape()?); Ok(()) } -fn try_init(merge: bool) -> anyhow::Result<()> { - let (yazi_toml, keymap_toml) = if merge { - let p = yazi_fs::Xdg::config_dir(); - (Preset::yazi(&p)?, Preset::keymap(&p)?) - } else { - (yazi_macro::config_preset!("yazi"), yazi_macro::config_preset!("keymap")) - }; +pub fn init_flavor(light: bool) -> anyhow::Result<()> { + if let Err(e) = try_init_flavor(light, true) { + wait_for_key(e)?; + try_init_flavor(light, false)?; + } + Ok(()) +} - let keymap = <_>::from_str(&keymap_toml)?; - let mgr = <_>::from_str(&yazi_toml)?; - let open = <_>::from_str(&yazi_toml)?; - let plugin = <_>::from_str(&yazi_toml)?; - let preview = <_>::from_str(&yazi_toml)?; - let tasks = <_>::from_str(&yazi_toml)?; - let input = <_>::from_str(&yazi_toml)?; - let confirm = <_>::from_str(&yazi_toml)?; - let pick = <_>::from_str(&yazi_toml)?; - let which = <_>::from_str(&yazi_toml)?; +fn try_init_flavor(light: bool, merge: bool) -> anyhow::Result<()> { + let mut theme = Preset::theme(light)?; - KEYMAP.init(keymap); - MGR.init(mgr); - OPEN.init(open); - PLUGIN.init(plugin); - PREVIEW.init(preview); - TASKS.init(tasks); - INPUT.init(input); - CONFIRM.init(confirm); - PICK.init(pick); - WHICH.init(which); + if merge { + let shadow = theme::Theme::deserialize_shadow(toml::Deserializer::new( + &std::fs::read_to_string(yazi_fs::Xdg::config_dir().join("theme.toml")).unwrap_or_default(), + ))?; + let flavor = shadow.flavor.as_ref().map(theme::Flavor::from).unwrap_or_default().read(light)?; + theme = theme.deserialize_over_with::(shadow)?; + theme = theme.deserialize_over(toml::Deserializer::new(&flavor))?; + } + + THEME.init(theme.reshape(light)?); Ok(()) } diff --git a/yazi-config/src/mgr/mgr.rs b/yazi-config/src/mgr/mgr.rs index d1932d4d..d080834f 100644 --- a/yazi-config/src/mgr/mgr.rs +++ b/yazi-config/src/mgr/mgr.rs @@ -1,13 +1,11 @@ -use std::str::FromStr; - -use anyhow::Context; +use anyhow::{Result, bail}; use serde::{Deserialize, Serialize}; -use validator::Validate; +use yazi_codegen::DeserializeOver2; use yazi_fs::SortBy; use super::{MgrRatio, MouseEvents}; -#[derive(Debug, Deserialize, Serialize, Validate)] +#[derive(Debug, Deserialize, DeserializeOver2, Serialize)] pub struct Mgr { pub ratio: MgrRatio, @@ -19,7 +17,6 @@ pub struct Mgr { pub sort_translit: bool, // Display - #[validate(length(min = 1, max = 20, message = "must be between 1 and 20 characters"))] pub linemode: String, pub show_hidden: bool, pub show_symlink: bool, @@ -28,20 +25,12 @@ pub struct Mgr { pub title_format: String, } -impl FromStr for Mgr { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - #[derive(Deserialize)] - struct Outer { - #[serde(rename = "manager")] - mgr: Mgr, // TODO: remove serde(rename) +impl Mgr { + pub(crate) fn reshape(self) -> Result { + if self.linemode.is_empty() || self.linemode.len() > 20 { + bail!("[mgr].linemode must be between 1 and 20 characters."); } - let outer = toml::from_str::(s) - .context("Failed to parse the [manager] section in your yazi.toml")?; - outer.mgr.validate()?; - - Ok(outer.mgr) + Ok(self) } } diff --git a/yazi-config/src/open/mod.rs b/yazi-config/src/open/mod.rs index 4ae31041..37a5e305 100644 --- a/yazi-config/src/open/mod.rs +++ b/yazi-config/src/open/mod.rs @@ -1 +1 @@ -yazi_macro::mod_flat!(open opener rule); +yazi_macro::mod_flat!(open rule); diff --git a/yazi-config/src/open/open.rs b/yazi-config/src/open/open.rs index 829a2689..657fd859 100644 --- a/yazi-config/src/open/open.rs +++ b/yazi-config/src/open/open.rs @@ -1,106 +1,74 @@ -use std::{collections::HashMap, path::Path, str::FromStr}; +use std::{ops::Deref, path::Path}; -use anyhow::Context; +use anyhow::Result; use indexmap::IndexSet; -use serde::{Deserialize, Deserializer}; +use serde::Deserialize; +use yazi_codegen::DeserializeOver2; use yazi_shared::MIME_DIR; -use super::Opener; use crate::{Preset, open::OpenRule}; -#[derive(Debug)] +#[derive(Default, Deserialize, DeserializeOver2)] pub struct Open { - rules: Vec, - openers: HashMap>, + rules: Vec, + #[serde(default)] + prepend_rules: Vec, + #[serde(default)] + append_rules: Vec, +} + +impl Deref for Open { + type Target = Vec; + + fn deref(&self) -> &Self::Target { &self.rules } } impl Open { - pub fn openers(&self, path: P, mime: M) -> Option> + pub fn all<'a, 'b, P, M>(&'a self, path: P, mime: M) -> impl Iterator + 'b where - P: AsRef, - M: AsRef, + 'a: 'b, + P: AsRef + 'b, + M: AsRef + 'b, { let is_dir = mime.as_ref() == MIME_DIR; - self.rules.iter().find_map(|rule| { - if rule.mime.as_ref().is_some_and(|p| p.match_mime(&mime)) - || rule.name.as_ref().is_some_and(|p| p.match_path(&path, is_dir)) - { - let openers = rule - .use_ - .iter() - .filter_map(|use_| self.openers.get(use_)) - .flatten() - .collect::>(); - - if openers.is_empty() { None } else { Some(openers) } - } else { - None - } - }) + self + .rules + .iter() + .filter(move |&r| { + r.mime.as_ref().is_some_and(|p| p.match_mime(&mime)) + || r.name.as_ref().is_some_and(|p| p.match_path(&path, is_dir)) + }) + .flat_map(|r| &r.use_) + .map(String::as_str) } - #[inline] - pub fn block_opener(&self, path: P, mime: M) -> Option<&Opener> - where - P: AsRef, - M: AsRef, - { - self.openers(path, mime).and_then(|o| o.into_iter().find(|o| o.block)) - } - - pub fn common_openers(&self, targets: &[(impl AsRef, impl AsRef)]) -> Vec<&Opener> { - let grouped: Vec<_> = targets.iter().filter_map(|(p, m)| self.openers(p, m)).collect(); - let flat: IndexSet<_> = grouped.iter().flatten().copied().collect(); - flat.into_iter().filter(|&o| grouped.iter().all(|g| g.contains(o))).collect() - } -} - -impl FromStr for Open { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - toml::from_str(s).context("Failed to parse the [open] or [opener] section in your yazi.toml") - } -} - -impl<'de> Deserialize<'de> for Open { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - #[derive(Deserialize)] - struct Outer { - opener: HashMap>, - open: OuterOpen, - } - #[derive(Deserialize)] - struct OuterOpen { - rules: Vec, - #[serde(default)] - prepend_rules: Vec, - #[serde(default)] - append_rules: Vec, - } - - let mut outer = Outer::deserialize(deserializer)?; - - if outer.open.append_rules.iter().any(|r| r.any_file()) { - outer.open.rules.retain(|r| !r.any_file()); - } - if outer.open.append_rules.iter().any(|r| r.any_dir()) { - outer.open.rules.retain(|r| !r.any_dir()); - } - - let openers = outer - .opener - .into_iter() - .map(|(k, v)| (k, v.into_iter().filter_map(|o| o.take()).collect::>())) + pub fn common<'a>( + &'a self, + targets: &[(impl AsRef, impl AsRef)], + ) -> IndexSet<&'a str> { + let each: Vec> = targets + .iter() + .map(|(p, m)| self.all(p, m).collect::>()) + .filter(|s| !s.is_empty()) .collect(); + let mut flat: IndexSet<_> = each.iter().flatten().copied().collect(); + flat.retain(|use_| each.iter().all(|e| e.contains(use_))); + flat + } +} + +impl Open { + pub(crate) fn reshape(self) -> Result { + let any_file = self.append_rules.iter().any(|r| r.any_file()); + let any_dir = self.append_rules.iter().any(|r| r.any_dir()); + + let it = + self.rules.into_iter().filter(|r| !(any_file && r.any_file() || any_dir && r.any_dir())); + Ok(Self { - #[rustfmt::skip] - rules: Preset::mix(outer.open.prepend_rules, outer.open.rules, outer.open.append_rules).collect(), - openers, + rules: Preset::mix(self.prepend_rules, it, self.append_rules).collect(), + ..Default::default() }) } } diff --git a/yazi-config/src/open/opener.rs b/yazi-config/src/open/opener.rs deleted file mode 100644 index bf4baab0..00000000 --- a/yazi-config/src/open/opener.rs +++ /dev/null @@ -1,55 +0,0 @@ -use serde::{Deserialize, Deserializer}; - -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Opener { - pub run: String, - pub block: bool, - pub orphan: bool, - pub desc: String, - pub for_: Option, - pub spread: bool, -} - -impl Opener { - pub fn take(mut self) -> Option { - if let Some(for_) = self.for_.take() { - match for_.as_str() { - "unix" if cfg!(unix) => {} - os if os == std::env::consts::OS => {} - _ => return None, - } - } - Some(self) - } -} - -impl<'de> Deserialize<'de> for Opener { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - #[derive(Deserialize)] - pub struct Shadow { - run: String, - #[serde(default)] - block: bool, - #[serde(default)] - orphan: bool, - desc: Option, - #[serde(rename = "for")] - for_: Option, - } - - let shadow = Shadow::deserialize(deserializer)?; - - let run = shadow.run; - if run.is_empty() { - return Err(serde::de::Error::custom("`run` cannot be empty")); - } - - let desc = shadow.desc.unwrap_or_else(|| run.split_whitespace().next().unwrap().to_string()); - - let spread = run.contains("$@") || run.contains("%*") || run.contains("$*"); - Ok(Self { run, block: shadow.block, orphan: shadow.orphan, desc, for_: shadow.for_, spread }) - } -} diff --git a/yazi-config/src/open/rule.rs b/yazi-config/src/open/rule.rs index 3c01c82f..cc5b5898 100644 --- a/yazi-config/src/open/rule.rs +++ b/yazi-config/src/open/rule.rs @@ -5,12 +5,12 @@ use serde::{Deserialize, Deserializer, de::{self, Visitor}}; use crate::pattern::Pattern; #[derive(Debug, Deserialize)] -pub(super) struct OpenRule { - pub(super) name: Option, - pub(super) mime: Option, +pub struct OpenRule { + pub name: Option, + pub mime: Option, #[serde(rename = "use")] #[serde(deserialize_with = "OpenRule::deserialize")] - pub(super) use_: Vec, + pub use_: Vec, } impl OpenRule { @@ -39,7 +39,7 @@ impl OpenRule { where A: de::SeqAccess<'de>, { - let mut uses = vec![]; + let mut uses = Vec::with_capacity(seq.size_hint().unwrap_or(0)); while let Some(use_) = seq.next_element::()? { uses.push(use_); } diff --git a/yazi-config/src/opener/mod.rs b/yazi-config/src/opener/mod.rs new file mode 100644 index 00000000..3e0ae9f0 --- /dev/null +++ b/yazi-config/src/opener/mod.rs @@ -0,0 +1 @@ +yazi_macro::mod_flat!(opener rule); diff --git a/yazi-config/src/opener/opener.rs b/yazi-config/src/opener/opener.rs new file mode 100644 index 00000000..13bc8db1 --- /dev/null +++ b/yazi-config/src/opener/opener.rs @@ -0,0 +1,71 @@ +use std::{collections::HashMap, mem, ops::Deref}; + +use anyhow::Result; +use indexmap::IndexSet; +use serde::Deserialize; + +use super::OpenerRule; + +#[derive(Debug, Deserialize)] +pub struct Opener(HashMap>); + +impl Deref for Opener { + type Target = HashMap>; + + fn deref(&self) -> &Self::Target { &self.0 } +} + +impl Opener { + pub fn all<'a, I>(&'a self, uses: I) -> Vec<&'a OpenerRule> + where + I: Iterator, + { + uses.flat_map(|use_| self.get(use_)).flatten().collect() + } + + pub fn first<'a, 'b, I>(&'a self, uses: I) -> Option<&'a OpenerRule> + where + I: Iterator, + { + uses.flat_map(|use_| self.get(use_)).flatten().next() + } + + pub fn block<'a, I>(&'a self, uses: I) -> Option<&'a OpenerRule> + where + I: Iterator, + { + uses.flat_map(|use_| self.get(use_)).flatten().find(|&o| o.block) + } +} + +impl Opener { + pub(crate) fn reshape(mut self) -> Result { + for rules in self.0.values_mut() { + *rules = mem::take(rules) + .into_iter() + .map(|mut r| (r.for_.take(), r)) + .filter(|(for_, _)| match for_.as_ref().map(|s| s.as_str()) { + Some("unix") if cfg!(unix) => true, + Some(os) if os == std::env::consts::OS => true, + Some(_) => false, + None => true, + }) + .map(|(_, r)| r.reshape()) + .collect::>>()? + .into_iter() + .collect(); + } + + Ok(self) + } + + pub(crate) fn deserialize_over<'de, D>(mut self, deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let map: HashMap> = HashMap::deserialize(deserializer)?; + self.0.extend(map); + + Ok(self) + } +} diff --git a/yazi-config/src/opener/rule.rs b/yazi-config/src/opener/rule.rs new file mode 100644 index 00000000..7b727c87 --- /dev/null +++ b/yazi-config/src/opener/rule.rs @@ -0,0 +1,49 @@ +use anyhow::{Result, bail}; +use serde::Deserialize; + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct OpenerRule { + pub run: String, + #[serde(default)] + pub block: bool, + #[serde(default)] + pub orphan: bool, + #[serde(default)] + pub desc: String, + #[serde(rename = "for")] + pub for_: Option, + #[serde(skip)] + pub spread: bool, +} + +impl OpenerRule { + #[inline] + pub fn desc(&self) -> String { + if !self.desc.is_empty() { + self.desc.clone() + } else if let Some(first) = self.run.split_whitespace().next() { + first.to_owned() + } else { + String::new() + } + } +} + +impl OpenerRule { + pub(super) fn reshape(mut self) -> Result { + if self.run.is_empty() { + bail!("[open].rules.*.run cannot be empty."); + } + + #[cfg(unix)] + { + self.spread = self.run.contains("$@") || self.run.contains("$*"); + } + #[cfg(windows)] + { + self.spread = self.run.contains("%*"); + } + + Ok(self) + } +} diff --git a/yazi-config/src/plugin/plugin.rs b/yazi-config/src/plugin/plugin.rs index b6c8029d..a569c13f 100644 --- a/yazi-config/src/plugin/plugin.rs +++ b/yazi-config/src/plugin/plugin.rs @@ -1,18 +1,39 @@ -use std::{collections::HashSet, path::Path, str::FromStr}; +use std::{collections::HashSet, path::Path}; -use anyhow::Context; -use serde::{Deserialize, Deserializer}; +use anyhow::Result; +use serde::Deserialize; use tracing::warn; +use yazi_codegen::DeserializeOver2; use yazi_fs::File; use super::{Fetcher, Preloader, Previewer, Spotter}; use crate::{Preset, plugin::MAX_PREWORKERS}; +#[derive(Default, Deserialize, DeserializeOver2)] pub struct Plugin { - pub fetchers: Vec, - pub spotters: Vec, - pub preloaders: Vec, - pub previewers: Vec, + pub fetchers: Vec, + #[serde(default)] + prepend_fetchers: Vec, + #[serde(default)] + append_fetchers: Vec, + + pub spotters: Vec, + #[serde(default)] + prepend_spotters: Vec, + #[serde(default)] + append_spotters: Vec, + + pub preloaders: Vec, + #[serde(default)] + prepend_preloaders: Vec, + #[serde(default)] + append_preloaders: Vec, + + pub previewers: Vec, + #[serde(default)] + prepend_previewers: Vec, + #[serde(default)] + append_previewers: Vec, } impl Plugin { @@ -71,90 +92,48 @@ impl Plugin { } } -impl FromStr for Plugin { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - toml::from_str(s).context("Failed to parse the [plugin] section in your yazi.toml") - } -} - -impl<'de> Deserialize<'de> for Plugin { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - #[derive(Deserialize)] - struct Outer { - plugin: Shadow, +impl Plugin { + // TODO: remove .retain() and .collect() + pub(crate) fn reshape(mut self) -> Result { + if self.append_spotters.iter().any(|r| r.any_file()) { + self.spotters.retain(|r| !r.any_file()); + } + if self.append_spotters.iter().any(|r| r.any_dir()) { + self.spotters.retain(|r| !r.any_dir()); + } + if self.append_previewers.iter().any(|r| r.any_file()) { + self.previewers.retain(|r| !r.any_file()); + } + if self.append_previewers.iter().any(|r| r.any_dir()) { + self.previewers.retain(|r| !r.any_dir()); } - #[derive(Deserialize)] - struct Shadow { - fetchers: Vec, - #[serde(default)] - prepend_fetchers: Vec, - #[serde(default)] - append_fetchers: Vec, + self.fetchers = + Preset::mix(self.prepend_fetchers, self.fetchers, self.append_fetchers).collect(); + self.spotters = + Preset::mix(self.prepend_spotters, self.spotters, self.append_spotters).collect(); + self.preloaders = + Preset::mix(self.prepend_preloaders, self.preloaders, self.append_preloaders).collect(); + self.previewers = + Preset::mix(self.prepend_previewers, self.previewers, self.append_previewers).collect(); - spotters: Vec, - #[serde(default)] - prepend_spotters: Vec, - #[serde(default)] - append_spotters: Vec, - - preloaders: Vec, - #[serde(default)] - prepend_preloaders: Vec, - #[serde(default)] - append_preloaders: Vec, - - previewers: Vec, - #[serde(default)] - prepend_previewers: Vec, - #[serde(default)] - append_previewers: Vec, - } - - let mut shadow = Outer::deserialize(deserializer)?.plugin; - if shadow.append_spotters.iter().any(|r| r.any_file()) { - shadow.spotters.retain(|r| !r.any_file()); - } - if shadow.append_spotters.iter().any(|r| r.any_dir()) { - shadow.spotters.retain(|r| !r.any_dir()); - } - if shadow.append_previewers.iter().any(|r| r.any_file()) { - shadow.previewers.retain(|r| !r.any_file()); - } - if shadow.append_previewers.iter().any(|r| r.any_dir()) { - shadow.previewers.retain(|r| !r.any_dir()); - } - - shadow.fetchers = - Preset::mix(shadow.prepend_fetchers, shadow.fetchers, shadow.append_fetchers).collect(); - shadow.spotters = - Preset::mix(shadow.prepend_spotters, shadow.spotters, shadow.append_spotters).collect(); - shadow.preloaders = - Preset::mix(shadow.prepend_preloaders, shadow.preloaders, shadow.append_preloaders).collect(); - shadow.previewers = - Preset::mix(shadow.prepend_previewers, shadow.previewers, shadow.append_previewers).collect(); - - if shadow.fetchers.len() + shadow.preloaders.len() > MAX_PREWORKERS as usize { + if self.fetchers.len() + self.preloaders.len() > MAX_PREWORKERS as usize { panic!("Fetchers and preloaders exceed the limit of {MAX_PREWORKERS}"); } - for (i, p) in shadow.fetchers.iter_mut().enumerate() { + for (i, p) in self.fetchers.iter_mut().enumerate() { p.idx = i as u8; } - for (i, p) in shadow.preloaders.iter_mut().enumerate() { - p.idx = shadow.fetchers.len() as u8 + i as u8; + for (i, p) in self.preloaders.iter_mut().enumerate() { + p.idx = self.fetchers.len() as u8 + i as u8; } Ok(Self { - fetchers: shadow.fetchers, - spotters: shadow.spotters, - preloaders: shadow.preloaders, - previewers: shadow.previewers, + fetchers: self.fetchers, + spotters: self.spotters, + preloaders: self.preloaders, + previewers: self.previewers, + ..Default::default() }) } } diff --git a/yazi-config/src/popup/confirm.rs b/yazi-config/src/popup/confirm.rs index e4cca76d..703102b2 100644 --- a/yazi-config/src/popup/confirm.rs +++ b/yazi-config/src/popup/confirm.rs @@ -1,11 +1,9 @@ -use std::str::FromStr; - -use anyhow::Context; use serde::Deserialize; +use yazi_codegen::DeserializeOver2; use super::{Offset, Origin}; -#[derive(Deserialize)] +#[derive(Deserialize, DeserializeOver2)] pub struct Confirm { // trash pub trash_title: String, @@ -30,22 +28,6 @@ pub struct Confirm { pub quit_offset: Offset, } -impl FromStr for Confirm { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - #[derive(Deserialize)] - struct Outer { - confirm: Confirm, - } - - let outer = toml::from_str::(s) - .context("Failed to parse the [confirm] section in your yazi.toml")?; - - Ok(outer.confirm) - } -} - impl Confirm { pub const fn border(&self) -> u16 { 2 } } diff --git a/yazi-config/src/popup/input.rs b/yazi-config/src/popup/input.rs index f2c05c37..893bbbdb 100644 --- a/yazi-config/src/popup/input.rs +++ b/yazi-config/src/popup/input.rs @@ -1,11 +1,9 @@ -use std::str::FromStr; - -use anyhow::Context; use serde::Deserialize; +use yazi_codegen::DeserializeOver2; use super::{Offset, Origin}; -#[derive(Deserialize)] +#[derive(Deserialize, DeserializeOver2)] pub struct Input { pub cursor_blink: bool, @@ -48,19 +46,3 @@ pub struct Input { impl Input { pub const fn border(&self) -> u16 { 2 } } - -impl FromStr for Input { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - #[derive(Deserialize)] - struct Outer { - input: Input, - } - - let outer = toml::from_str::(s) - .context("Failed to parse the [input] section in your yazi.toml")?; - - Ok(outer.input) - } -} diff --git a/yazi-config/src/popup/options.rs b/yazi-config/src/popup/options.rs index a11fa6b7..2663cabc 100644 --- a/yazi-config/src/popup/options.rs +++ b/yazi-config/src/popup/options.rs @@ -2,7 +2,7 @@ use ratatui::{text::{Line, Text}, widgets::{Paragraph, Wrap}}; use yazi_shared::url::Url; use super::{Offset, Origin, Position}; -use crate::{CONFIRM, INPUT, PICK}; +use crate::YAZI; #[derive(Default)] pub struct InputCfg { @@ -33,8 +33,8 @@ pub struct ConfirmCfg { impl InputCfg { pub fn cd() -> Self { Self { - title: INPUT.cd_title.to_owned(), - position: Position::new(INPUT.cd_origin, INPUT.cd_offset), + title: YAZI.input.cd_title.to_owned(), + position: Position::new(YAZI.input.cd_origin, YAZI.input.cd_offset), completion: true, ..Default::default() } @@ -42,24 +42,24 @@ impl InputCfg { pub fn create(dir: bool) -> Self { Self { - title: INPUT.create_title[dir as usize].to_owned(), - position: Position::new(INPUT.create_origin, INPUT.create_offset), + title: YAZI.input.create_title[dir as usize].to_owned(), + position: Position::new(YAZI.input.create_origin, YAZI.input.create_offset), ..Default::default() } } pub fn rename() -> Self { Self { - title: INPUT.rename_title.to_owned(), - position: Position::new(INPUT.rename_origin, INPUT.rename_offset), + title: YAZI.input.rename_title.to_owned(), + position: Position::new(YAZI.input.rename_origin, YAZI.input.rename_offset), ..Default::default() } } pub fn filter() -> Self { Self { - title: INPUT.filter_title.to_owned(), - position: Position::new(INPUT.filter_origin, INPUT.filter_offset), + title: YAZI.input.filter_title.to_owned(), + position: Position::new(YAZI.input.filter_origin, YAZI.input.filter_offset), realtime: true, ..Default::default() } @@ -67,8 +67,8 @@ impl InputCfg { pub fn find(prev: bool) -> Self { Self { - title: INPUT.find_title[prev as usize].to_owned(), - position: Position::new(INPUT.find_origin, INPUT.find_offset), + title: YAZI.input.find_title[prev as usize].to_owned(), + position: Position::new(YAZI.input.find_origin, YAZI.input.find_offset), realtime: true, ..Default::default() } @@ -76,16 +76,16 @@ impl InputCfg { pub fn search(name: &str) -> Self { Self { - title: INPUT.search_title.replace("{n}", name), - position: Position::new(INPUT.search_origin, INPUT.search_offset), + title: YAZI.input.search_title.replace("{n}", name), + position: Position::new(YAZI.input.search_origin, YAZI.input.search_offset), ..Default::default() } } pub fn shell(block: bool) -> Self { Self { - title: INPUT.shell_title[block as usize].to_owned(), - position: Position::new(INPUT.shell_origin, INPUT.shell_offset), + title: YAZI.input.shell_title[block as usize].to_owned(), + position: Position::new(YAZI.input.shell_origin, YAZI.input.shell_offset), highlight: true, ..Default::default() } @@ -121,8 +121,8 @@ impl ConfirmCfg { pub fn trash(urls: &[yazi_shared::url::Url]) -> Self { Self::new( - Self::replace_number(&CONFIRM.trash_title, urls.len()), - (CONFIRM.trash_origin, CONFIRM.trash_offset), + Self::replace_number(&YAZI.confirm.trash_title, urls.len()), + (YAZI.confirm.trash_origin, YAZI.confirm.trash_offset), None, Self::truncate_list(urls.iter(), urls.len(), 100), ) @@ -130,8 +130,8 @@ impl ConfirmCfg { pub fn delete(urls: &[yazi_shared::url::Url]) -> Self { Self::new( - Self::replace_number(&CONFIRM.delete_title, urls.len()), - (CONFIRM.delete_origin, CONFIRM.delete_offset), + Self::replace_number(&YAZI.confirm.delete_title, urls.len()), + (YAZI.confirm.delete_origin, YAZI.confirm.delete_offset), None, Self::truncate_list(urls.iter(), urls.len(), 100), ) @@ -139,18 +139,18 @@ impl ConfirmCfg { pub fn overwrite(url: &Url) -> Self { Self::new( - CONFIRM.overwrite_title.to_owned(), - (CONFIRM.overwrite_origin, CONFIRM.overwrite_offset), - Some(Text::raw(&CONFIRM.overwrite_content)), + YAZI.confirm.overwrite_title.to_owned(), + (YAZI.confirm.overwrite_origin, YAZI.confirm.overwrite_offset), + Some(Text::raw(&YAZI.confirm.overwrite_content)), Some(url.to_string().into()), ) } pub fn quit(len: usize, names: Vec) -> Self { Self::new( - Self::replace_number(&CONFIRM.quit_title, len), - (CONFIRM.quit_origin, CONFIRM.quit_offset), - Some(Text::raw(&CONFIRM.quit_content)), + Self::replace_number(&YAZI.confirm.quit_title, len), + (YAZI.confirm.quit_origin, YAZI.confirm.quit_offset), + Some(Text::raw(&YAZI.confirm.quit_content)), Self::truncate_list(names.into_iter(), len, 10), ) } @@ -179,15 +179,18 @@ impl ConfirmCfg { impl PickCfg { #[inline] fn max_height(len: usize) -> u16 { - PICK.open_offset.height.min(PICK.border().saturating_add(len as u16)) + YAZI.pick.open_offset.height.min(YAZI.pick.border().saturating_add(len as u16)) } pub fn open(items: Vec) -> Self { let max_height = Self::max_height(items.len()); Self { - title: PICK.open_title.to_owned(), + title: YAZI.pick.open_title.to_owned(), items, - position: Position::new(PICK.open_origin, Offset { height: max_height, ..PICK.open_offset }), + position: Position::new(YAZI.pick.open_origin, Offset { + height: max_height, + ..YAZI.pick.open_offset + }), } } } diff --git a/yazi-config/src/popup/pick.rs b/yazi-config/src/popup/pick.rs index 786fb8a8..cd22be27 100644 --- a/yazi-config/src/popup/pick.rs +++ b/yazi-config/src/popup/pick.rs @@ -1,11 +1,9 @@ -use std::str::FromStr; - -use anyhow::Context; use serde::Deserialize; +use yazi_codegen::DeserializeOver2; use super::{Offset, Origin}; -#[derive(Deserialize)] +#[derive(Deserialize, DeserializeOver2)] pub struct Pick { // open pub open_title: String, @@ -16,19 +14,3 @@ pub struct Pick { impl Pick { pub const fn border(&self) -> u16 { 2 } } - -impl FromStr for Pick { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - #[derive(Deserialize)] - struct Outer { - pick: Pick, - } - - let outer = - toml::from_str::(s).context("Failed to parse the [pick] section in your yazi.toml")?; - - Ok(outer.pick) - } -} diff --git a/yazi-config/src/preset.rs b/yazi-config/src/preset.rs index 3154fe2c..03e180a0 100644 --- a/yazi-config/src/preset.rs +++ b/yazi-config/src/preset.rs @@ -1,35 +1,25 @@ -use std::{borrow::Cow, path::{Path, PathBuf}, str::FromStr}; - -use anyhow::{Context, Result}; -use toml::{Table, Value}; -use yazi_fs::Xdg; - -use crate::theme::Flavor; +use crate::{Yazi, keymap::Keymap, theme::Theme}; pub(crate) struct Preset; impl Preset { - pub(crate) fn yazi(p: &Path) -> Result> { - Self::merge_path(p.join("yazi.toml"), yazi_macro::config_preset!("yazi")) + #[inline] + pub(super) fn yazi() -> Result { + toml::from_str(&yazi_macro::config_preset!("yazi")) } - pub(crate) fn keymap(p: &Path) -> Result> { - Self::merge_path(p.join("keymap.toml"), yazi_macro::config_preset!("keymap")) + #[inline] + pub(super) fn keymap() -> Result { + toml::from_str(&yazi_macro::config_preset!("keymap")) } - pub(crate) fn flavor(light: bool, merge: bool) -> Result> { - let theme = if merge { - std::fs::read_to_string(Xdg::config_dir().join("theme.toml")).unwrap_or_default() + #[inline] + pub(super) fn theme(light: bool) -> Result { + toml::from_str(&if light { + yazi_macro::theme_preset!("light") } else { - Default::default() - }; - - let flavor = Flavor::from_str(&theme)?; - - let preset = - if light { yazi_macro::theme_preset!("light") } else { yazi_macro::theme_preset!("dark") }; - - Self::merge_str(&theme, &Self::merge_str(&flavor.read(light)?, &preset)?) + yazi_macro::theme_preset!("dark") + }) } #[inline] @@ -41,43 +31,4 @@ impl Preset { { a.into_iter().chain(b).chain(c) } - - #[inline] - pub(crate) fn merge_str(user: &str, base: &str) -> Result> { - let mut t = user.parse()?; - Self::merge(&mut t, base.parse()?, 2); - - Ok(t.to_string().into()) - } - - #[inline] - fn merge_path(user: PathBuf, base: Cow) -> Result> { - let s = std::fs::read_to_string(&user).unwrap_or_default(); - if s.is_empty() { - return Ok(base); - } - - Self::merge_str(&s, &base).with_context(|| format!("failed to parse config: {user:?}")) - } - - fn merge(a: &mut Table, b: Table, max: u8) { - for (k, v) in b { - let Some(a) = a.get_mut(&k) else { - a.insert(k, v); - continue; - }; - - if max <= 1 { - continue; - } - - if let Some(a) = a.as_table_mut() { - if let Value::Table(b) = v { - Self::merge(a, b, max - 1); - continue; - } - } - *a = v; - } - } } diff --git a/yazi-config/src/preview/preview.rs b/yazi-config/src/preview/preview.rs index a127dddd..22f2bf38 100644 --- a/yazi-config/src/preview/preview.rs +++ b/yazi-config/src/preview/preview.rs @@ -1,8 +1,8 @@ -use std::{borrow::Cow, path::PathBuf, str::FromStr}; +use std::{borrow::Cow, path::PathBuf}; -use anyhow::Context; -use serde::{Deserialize, Deserializer, Serialize}; -use validator::Validate; +use anyhow::{Context, Result, bail}; +use serde::{Deserialize, Serialize}; +use yazi_codegen::DeserializeOver2; use yazi_fs::{Xdg, expand_path}; use yazi_shared::timestamp_us; @@ -11,7 +11,7 @@ use super::PreviewWrap; #[rustfmt::skip] const TABS: &[&str] = &["", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "]; -#[derive(Debug, Serialize)] +#[derive(Debug, Deserialize, DeserializeOver2, Serialize)] pub struct Preview { pub wrap: PreviewWrap, pub tab_size: u8, @@ -44,70 +44,24 @@ impl Preview { } } -impl FromStr for Preview { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - let preview: Self = - toml::from_str(s).context("Failed to parse the [preview] section in your yazi.toml")?; - - std::fs::create_dir_all(&preview.cache_dir).context("Failed to create cache directory")?; - - Ok(preview) - } -} - -impl<'de> Deserialize<'de> for Preview { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - #[derive(Deserialize)] - struct Outer { - preview: Shadow, - } - #[derive(Deserialize, Validate)] - struct Shadow { - wrap: PreviewWrap, - tab_size: u8, - max_width: u32, - max_height: u32, - - cache_dir: Option, - - #[validate(range(min = 0, max = 100))] - image_delay: u8, - image_filter: String, - #[validate(range(min = 50, max = 90))] - image_quality: u8, - #[validate(range(min = 10, max = 20))] - sixel_fraction: u8, - - ueberzug_scale: f32, - ueberzug_offset: (f32, f32, f32, f32), +impl Preview { + pub(crate) fn reshape(mut self) -> Result { + if self.image_delay > 100 { + bail!("[preview].image_delay must be between 0 and 100."); + } else if self.image_quality < 50 || self.image_quality > 90 { + bail!("[preview].image_quality must be between 50 and 90."); + } else if self.sixel_fraction < 10 || self.sixel_fraction > 20 { + bail!("[preview].sixel_fraction must be between 10 and 20."); } - let preview = Outer::deserialize(deserializer)?.preview; - preview.validate().map_err(serde::de::Error::custom)?; + self.cache_dir = if self.cache_dir.as_os_str().is_empty() { + Xdg::cache_dir() + } else { + expand_path(&self.cache_dir) + }; - Ok(Preview { - wrap: preview.wrap, - tab_size: preview.tab_size, - max_width: preview.max_width, - max_height: preview.max_height, + std::fs::create_dir_all(&self.cache_dir).context("Failed to create cache directory")?; - cache_dir: preview - .cache_dir - .filter(|p| !p.is_empty()) - .map_or_else(Xdg::cache_dir, expand_path), - - image_delay: preview.image_delay, - image_filter: preview.image_filter, - image_quality: preview.image_quality, - sixel_fraction: preview.sixel_fraction, - - ueberzug_scale: preview.ueberzug_scale, - ueberzug_offset: preview.ueberzug_offset, - }) + Ok(self) } } diff --git a/yazi-config/src/tasks/tasks.rs b/yazi-config/src/tasks/tasks.rs index b401e075..3ec2b767 100644 --- a/yazi-config/src/tasks/tasks.rs +++ b/yazi-config/src/tasks/tasks.rs @@ -1,16 +1,11 @@ -use std::str::FromStr; - -use anyhow::Context; +use anyhow::{Result, bail}; use serde::Deserialize; -use validator::Validate; +use yazi_codegen::DeserializeOver2; -#[derive(Debug, Deserialize, Validate)] +#[derive(Debug, Deserialize, DeserializeOver2)] pub struct Tasks { - #[validate(range(min = 1, message = "Cannot be less than 1"))] pub micro_workers: u8, - #[validate(range(min = 1, message = "Cannot be less than 1"))] pub macro_workers: u8, - #[validate(range(min = 1, message = "Cannot be less than 1"))] pub bizarre_retry: u8, pub image_alloc: u32, @@ -19,19 +14,15 @@ pub struct Tasks { pub suppress_preload: bool, } -impl FromStr for Tasks { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - #[derive(Deserialize)] - struct Outer { - tasks: Tasks, +impl Tasks { + pub(crate) fn reshape(self) -> Result { + if self.micro_workers < 1 { + bail!("[tasks].micro_workers must be at least 1."); + } else if self.macro_workers < 1 { + bail!("[tasks].macro_workers must be at least 1."); + } else if self.bizarre_retry < 1 { + bail!("[tasks].bizarre_retry` must be at least 1."); } - - let outer = toml::from_str::(s) - .context("Failed to parse the [tasks] section in your yazi.toml")?; - outer.tasks.validate()?; - - Ok(outer.tasks) + Ok(self) } } diff --git a/yazi-config/src/theme/filetype.rs b/yazi-config/src/theme/filetype.rs index 4e993953..ce2ee5f3 100644 --- a/yazi-config/src/theme/filetype.rs +++ b/yazi-config/src/theme/filetype.rs @@ -1,18 +1,35 @@ -use serde::{Deserialize, Deserializer}; +use std::ops::Deref; + +use serde::Deserialize; +use yazi_codegen::DeserializeOver2; use yazi_fs::File; -use yazi_shared::theme::{Color, Style, StyleShadow}; +use yazi_shared::theme::Style; use super::Is; use crate::Pattern; +#[derive(Deserialize, DeserializeOver2)] pub struct Filetype { - pub is: Is, - pub name: Option, - pub mime: Option, + rules: Vec, +} + +impl Deref for Filetype { + type Target = Vec; + + fn deref(&self) -> &Self::Target { &self.rules } +} + +#[derive(Deserialize)] +pub struct FiletypeRule { + #[serde(default)] + is: Is, + name: Option, + mime: Option, + #[serde(flatten)] pub style: Style, } -impl Filetype { +impl FiletypeRule { pub fn matches(&self, file: &File, mime: &str) -> bool { if !self.is.check(&file.cha) { return false; @@ -22,69 +39,3 @@ impl Filetype { || self.name.as_ref().is_some_and(|n| n.match_path(&file.url, file.is_dir())) } } - -impl Filetype { - pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> - where - D: Deserializer<'de>, - { - #[derive(Deserialize)] - struct FiletypeOuter { - rules: Vec, - } - #[derive(Deserialize)] - struct FiletypeRule { - #[serde(default)] - is: Is, - name: Option, - mime: Option, - - fg: Option, - bg: Option, - #[serde(default)] - bold: bool, - #[serde(default)] - dim: bool, - #[serde(default)] - italic: bool, - #[serde(default)] - underline: bool, - #[serde(default)] - blink: bool, - #[serde(default)] - blink_rapid: bool, - #[serde(default)] - reversed: bool, - #[serde(default)] - hidden: bool, - #[serde(default)] - crossed: bool, - } - - Ok( - FiletypeOuter::deserialize(deserializer)? - .rules - .into_iter() - .map(|r| Filetype { - is: r.is, - name: r.name, - mime: r.mime, - style: StyleShadow { - fg: r.fg, - bg: r.bg, - bold: r.bold, - dim: r.dim, - italic: r.italic, - underline: r.underline, - blink: r.blink, - blink_rapid: r.blink_rapid, - reversed: r.reversed, - hidden: r.hidden, - crossed: r.crossed, - } - .into(), - }) - .collect(), - ) - } -} diff --git a/yazi-config/src/theme/flavor.rs b/yazi-config/src/theme/flavor.rs index 3aea90c2..e486648a 100644 --- a/yazi-config/src/theme/flavor.rs +++ b/yazi-config/src/theme/flavor.rs @@ -1,42 +1,39 @@ -use std::{borrow::Cow, path::PathBuf, str::FromStr}; +use std::path::PathBuf; use anyhow::{Context, Result}; use serde::{Deserialize, Serialize}; +use toml::Value; +use yazi_codegen::DeserializeOver2; use yazi_fs::Xdg; -#[derive(Default, Deserialize, Serialize)] +#[derive(Default, Deserialize, DeserializeOver2, Serialize)] pub struct Flavor { - #[serde(default)] pub dark: String, - #[serde(default)] pub light: String, } -impl FromStr for Flavor { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - #[derive(Deserialize)] - struct Outer { - #[serde(default)] - flavor: Flavor, +impl From<&Value> for Flavor { + fn from(value: &Value) -> Self { + let mut me = Self::default(); + if let Value::Table(t) = value { + if let Some(s) = t.get("dark").and_then(|v| v.as_str()) { + me.dark = s.to_owned(); + } + if let Some(s) = t.get("light").and_then(|v| v.as_str()) { + me.light = s.to_owned(); + } } - - Ok( - toml::from_str::(s) - .context("Failed to parse the [flavor] section in your theme.toml")? - .flavor, - ) + me } } impl Flavor { - pub(crate) fn read(&self, light: bool) -> Result> { + pub(crate) fn read(&self, light: bool) -> Result { Ok(match if light { self.light.as_str() } else { self.dark.as_str() } { - "" => Cow::Borrowed(""), + "" => String::new(), name => { let p = Xdg::config_dir().join(format!("flavors/{name}.yazi/flavor.toml")); - std::fs::read_to_string(&p).with_context(|| format!("Failed to load flavor {p:?}"))?.into() + std::fs::read_to_string(&p).with_context(|| format!("Failed to load flavor {p:?}"))? } }) } diff --git a/yazi-config/src/theme/icon.rs b/yazi-config/src/theme/icon.rs new file mode 100644 index 00000000..9d42115f --- /dev/null +++ b/yazi-config/src/theme/icon.rs @@ -0,0 +1,209 @@ +use std::{collections::HashMap, ops::Deref}; + +use anyhow::Result; +use serde::{Deserialize, Deserializer}; +use yazi_codegen::DeserializeOver2; +use yazi_fs::File; +use yazi_shared::{Condition, theme::{Color, Icon as I, Style}}; + +use crate::Pattern; + +#[derive(Default, Deserialize, DeserializeOver2)] +pub struct Icon { + globs: PatIcons, + #[serde(default)] + prepend_globs: PatIcons, + #[serde(default)] + append_globs: PatIcons, + + dirs: StrIcons, + #[serde(default)] + prepend_dirs: StrIcons, + #[serde(default)] + append_dirs: StrIcons, + + files: StrIcons, + #[serde(default)] + prepend_files: StrIcons, + #[serde(default)] + append_files: StrIcons, + + exts: StrIcons, + #[serde(default)] + prepend_exts: StrIcons, + #[serde(default)] + append_exts: StrIcons, + + conds: CondIcons, + #[serde(default)] + prepend_conds: CondIcons, + #[serde(default)] + append_conds: CondIcons, +} + +impl Icon { + pub fn matches(&self, file: &File) -> Option<&I> { + if let Some(i) = self.match_by_glob(file) { + return Some(i); + } + + if let Some(i) = self.match_by_name(file) { + return Some(i); + } + + let f = |s: &str| match s { + "dir" => file.is_dir(), + "hidden" => file.is_hidden(), + "link" => file.is_link(), + "orphan" => file.is_orphan(), + "dummy" => file.is_dummy(), + "block" => file.is_block(), + "char" => file.is_char(), + "fifo" => file.is_fifo(), + "sock" => file.is_sock(), + "exec" => file.is_exec(), + "sticky" => file.is_sticky(), + _ => false, + }; + self.conds.iter().find(|(c, _)| c.eval(f) == Some(true)).map(|(_, i)| i) + } + + #[inline] + fn match_by_glob(&self, file: &File) -> Option<&I> { + self.globs.iter().find(|(p, _)| p.match_path(&file.url, file.is_dir())).map(|(_, i)| i) + } + + #[inline] + fn match_by_name(&self, file: &File) -> Option<&I> { + let name = file.name().to_str()?; + if file.is_dir() { + self.dirs.get(name).or_else(|| self.dirs.get(&name.to_ascii_lowercase())) + } else { + self + .files + .get(name) + .or_else(|| self.files.get(&name.to_ascii_lowercase())) + .or_else(|| self.match_by_ext(file)) + } + } + + #[inline] + fn match_by_ext(&self, file: &File) -> Option<&I> { + let ext = file.url.extension()?.to_str()?; + self.exts.get(ext).or_else(|| self.exts.get(&ext.to_ascii_lowercase())) + } +} + +impl Icon { + pub(crate) fn reshape(self) -> Result { + Ok(Self { + globs: PatIcons( + self.prepend_globs.0.into_iter().chain(self.globs.0).chain(self.append_globs.0).collect(), + ), + dirs: StrIcons( + self.prepend_dirs.0.into_iter().chain(self.dirs.0).chain(self.append_dirs.0).collect(), + ), + files: StrIcons( + self.prepend_files.0.into_iter().chain(self.files.0).chain(self.append_files.0).collect(), + ), + exts: StrIcons( + self.prepend_exts.0.into_iter().chain(self.exts.0).chain(self.append_exts.0).collect(), + ), + conds: CondIcons( + self.prepend_conds.0.into_iter().chain(self.conds.0).chain(self.append_conds.0).collect(), + ), + ..Default::default() + }) + } +} + +#[derive(Default)] +pub struct PatIcons(Vec<(Pattern, I)>); + +impl Deref for PatIcons { + type Target = Vec<(Pattern, I)>; + + fn deref(&self) -> &Self::Target { &self.0 } +} + +impl<'de> Deserialize<'de> for PatIcons { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + #[derive(Deserialize)] + struct Shadow { + name: Pattern, + text: String, + fg: Option, + } + + Ok(Self( + >::deserialize(deserializer)? + .into_iter() + .map(|s| (s.name, I { text: s.text, style: Style { fg: s.fg, ..Default::default() } })) + .collect(), + )) + } +} + +#[derive(Default)] +pub struct StrIcons(HashMap); + +impl Deref for StrIcons { + type Target = HashMap; + + fn deref(&self) -> &Self::Target { &self.0 } +} + +impl<'de> Deserialize<'de> for StrIcons { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + #[derive(Deserialize)] + struct Shadow { + name: String, + text: String, + fg: Option, + } + + Ok(Self( + >::deserialize(deserializer)? + .into_iter() + .map(|s| (s.name, I { text: s.text, style: Style { fg: s.fg, ..Default::default() } })) + .collect(), + )) + } +} + +#[derive(Default)] +pub struct CondIcons(Vec<(Condition, I)>); + +impl Deref for CondIcons { + type Target = Vec<(Condition, I)>; + + fn deref(&self) -> &Self::Target { &self.0 } +} + +impl<'de> Deserialize<'de> for CondIcons { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + #[derive(Deserialize)] + struct Shadow { + #[serde(rename = "if")] + if_: Condition, + text: String, + fg: Option, + } + + Ok(Self( + >::deserialize(deserializer)? + .into_iter() + .map(|s| (s.if_, I { text: s.text, style: Style { fg: s.fg, ..Default::default() } })) + .collect(), + )) + } +} diff --git a/yazi-config/src/theme/icons.rs b/yazi-config/src/theme/icons.rs deleted file mode 100644 index 561692fb..00000000 --- a/yazi-config/src/theme/icons.rs +++ /dev/null @@ -1,157 +0,0 @@ -use std::collections::HashMap; - -use anyhow::Result; -use serde::{Deserialize, Deserializer}; -use yazi_fs::File; -use yazi_shared::{Condition, theme::{Color, Icon, Style}}; - -use crate::{Pattern, Preset}; - -pub struct Icons { - globs: Vec<(Pattern, Icon)>, - dirs: HashMap, - files: HashMap, - exts: HashMap, - conds: Vec<(Condition, Icon)>, -} - -impl Icons { - pub fn matches(&self, file: &File) -> Option<&Icon> { - if let Some(i) = self.match_by_glob(file) { - return Some(i); - } - - if let Some(i) = self.match_by_name(file) { - return Some(i); - } - - let f = |s: &str| match s { - "dir" => file.is_dir(), - "hidden" => file.is_hidden(), - "link" => file.is_link(), - "orphan" => file.is_orphan(), - "dummy" => file.is_dummy(), - "block" => file.is_block(), - "char" => file.is_char(), - "fifo" => file.is_fifo(), - "sock" => file.is_sock(), - "exec" => file.is_exec(), - "sticky" => file.is_sticky(), - _ => false, - }; - self.conds.iter().find(|(c, _)| c.eval(f) == Some(true)).map(|(_, i)| i) - } - - #[inline] - fn match_by_glob(&self, file: &File) -> Option<&Icon> { - self.globs.iter().find(|(p, _)| p.match_path(&file.url, file.is_dir())).map(|(_, i)| i) - } - - #[inline] - fn match_by_name(&self, file: &File) -> Option<&Icon> { - let name = file.name().to_str()?; - if file.is_dir() { - self.dirs.get(name).or_else(|| self.dirs.get(&name.to_ascii_lowercase())) - } else { - self - .files - .get(name) - .or_else(|| self.files.get(&name.to_ascii_lowercase())) - .or_else(|| self.match_by_ext(file)) - } - } - - #[inline] - fn match_by_ext(&self, file: &File) -> Option<&Icon> { - let ext = file.url.extension()?.to_str()?; - self.exts.get(ext).or_else(|| self.exts.get(&ext.to_ascii_lowercase())) - } -} - -impl<'de> Deserialize<'de> for Icons { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - #[derive(Deserialize)] - pub struct Shadow { - globs: Vec, - #[serde(default)] - prepend_globs: Vec, - #[serde(default)] - append_globs: Vec, - - dirs: Vec, - #[serde(default)] - prepend_dirs: Vec, - #[serde(default)] - append_dirs: Vec, - - files: Vec, - #[serde(default)] - prepend_files: Vec, - #[serde(default)] - append_files: Vec, - - exts: Vec, - #[serde(default)] - prepend_exts: Vec, - #[serde(default)] - append_exts: Vec, - - conds: Vec, - #[serde(default)] - prepend_conds: Vec, - #[serde(default)] - append_conds: Vec, - } - #[derive(Deserialize)] - pub struct ShadowPat { - name: Pattern, - text: String, - fg: Option, - } - #[derive(Deserialize)] - pub struct ShadowStr { - name: String, - text: String, - fg: Option, - } - #[derive(Deserialize)] - pub struct ShadowCond { - #[serde(rename = "if")] - if_: Condition, - text: String, - fg: Option, - } - - let shadow = Shadow::deserialize(deserializer)?; - - let globs = Preset::mix(shadow.prepend_globs, shadow.globs, shadow.append_globs) - .map(|v| (v.name, Icon { text: v.text, style: Style { fg: v.fg, ..Default::default() } })) - .collect(); - - let conds = Preset::mix(shadow.prepend_conds, shadow.conds, shadow.append_conds) - .map(|v| (v.if_, Icon { text: v.text, style: Style { fg: v.fg, ..Default::default() } })) - .collect(); - - fn as_map(it: impl Iterator) -> HashMap { - let mut map = HashMap::with_capacity(it.size_hint().0); - for v in it { - map - .entry(v.name) - .or_insert(Icon { text: v.text, style: Style { fg: v.fg, ..Default::default() } }); - } - map.shrink_to_fit(); - map - } - - Ok(Self { - globs, - dirs: as_map(Preset::mix(shadow.prepend_dirs, shadow.dirs, shadow.append_dirs)), - files: as_map(Preset::mix(shadow.prepend_files, shadow.files, shadow.append_files)), - exts: as_map(Preset::mix(shadow.prepend_exts, shadow.exts, shadow.append_exts)), - conds, - }) - } -} diff --git a/yazi-config/src/theme/mod.rs b/yazi-config/src/theme/mod.rs index 4de4fb71..4ae935a4 100644 --- a/yazi-config/src/theme/mod.rs +++ b/yazi-config/src/theme/mod.rs @@ -1 +1 @@ -yazi_macro::mod_flat!(filetype flavor icons is theme); +yazi_macro::mod_flat!(filetype flavor icon is theme); diff --git a/yazi-config/src/theme/theme.rs b/yazi-config/src/theme/theme.rs index 517523f0..940bd5cb 100644 --- a/yazi-config/src/theme/theme.rs +++ b/yazi-config/src/theme/theme.rs @@ -1,13 +1,14 @@ -use std::{path::PathBuf, str::FromStr}; +use std::path::PathBuf; -use anyhow::Context; +use anyhow::{Result, bail}; use serde::{Deserialize, Serialize}; -use validator::Validate; +use yazi_codegen::{DeserializeOver1, DeserializeOver2}; +use yazi_fs::expand_path; use yazi_shared::theme::Style; -use super::{Filetype, Flavor, Icons}; +use super::{Filetype, Flavor, Icon}; -#[derive(Deserialize, Serialize)] +#[derive(Deserialize, DeserializeOver1, Serialize)] pub struct Theme { pub flavor: Flavor, #[serde(rename = "manager")] @@ -25,25 +26,13 @@ pub struct Theme { pub help: Help, // File-specific styles - #[serde(rename = "filetype", deserialize_with = "Filetype::deserialize", skip_serializing)] - pub filetypes: Vec, - #[serde(rename = "icon", skip_serializing)] - pub icons: Icons, + #[serde(skip_serializing)] + pub filetype: Filetype, + #[serde(skip_serializing)] + pub icon: Icon, } -impl FromStr for Theme { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - let theme: Self = toml::from_str(s).context("Failed to parse your theme.toml")?; - theme.mgr.validate()?; - theme.which.validate()?; - - Ok(theme) - } -} - -#[derive(Deserialize, Serialize, Validate)] +#[derive(Deserialize, DeserializeOver2, Serialize)] pub struct Mgr { cwd: Style, @@ -64,7 +53,6 @@ pub struct Mgr { // Tab tab_active: Style, tab_inactive: Style, - #[validate(range(min = 1, message = "Must be greater than 0"))] tab_width: u8, // Count @@ -80,7 +68,7 @@ pub struct Mgr { pub syntect_theme: PathBuf, } -#[derive(Deserialize, Serialize)] +#[derive(Deserialize, DeserializeOver2, Serialize)] pub struct Mode { pub normal_main: Style, pub normal_alt: Style, @@ -92,7 +80,7 @@ pub struct Mode { pub unset_alt: Style, } -#[derive(Deserialize, Serialize)] +#[derive(Deserialize, DeserializeOver2, Serialize)] pub struct Status { pub overall: Style, pub sep_left: StatusSep, @@ -111,15 +99,14 @@ pub struct Status { pub progress_error: Style, } -#[derive(Deserialize, Serialize)] +#[derive(Deserialize, DeserializeOver2, Serialize)] pub struct StatusSep { pub open: String, pub close: String, } -#[derive(Deserialize, Serialize, Validate)] +#[derive(Deserialize, DeserializeOver2, Serialize)] pub struct Which { - #[validate(range(min = 1, max = 3, message = "Must be between 1 and 3"))] pub cols: u8, pub mask: Style, pub cand: Style, @@ -130,7 +117,7 @@ pub struct Which { pub separator_style: Style, } -#[derive(Deserialize, Serialize)] +#[derive(Deserialize, DeserializeOver2, Serialize)] pub struct Confirm { pub border: Style, pub title: Style, @@ -142,7 +129,7 @@ pub struct Confirm { pub btn_labels: [String; 2], } -#[derive(Deserialize, Serialize)] +#[derive(Deserialize, DeserializeOver2, Serialize)] pub struct Spot { pub border: Style, pub title: Style, @@ -151,7 +138,7 @@ pub struct Spot { pub tbl_cell: Style, } -#[derive(Deserialize, Serialize)] +#[derive(Deserialize, DeserializeOver2, Serialize)] pub struct Notify { pub title_info: Style, pub title_warn: Style, @@ -162,14 +149,14 @@ pub struct Notify { pub icon_error: String, } -#[derive(Deserialize, Serialize)] +#[derive(Deserialize, DeserializeOver2, Serialize)] pub struct Pick { pub border: Style, pub active: Style, pub inactive: Style, } -#[derive(Deserialize, Serialize)] +#[derive(Deserialize, DeserializeOver2, Serialize)] pub struct Input { pub border: Style, pub title: Style, @@ -177,7 +164,7 @@ pub struct Input { pub selected: Style, } -#[derive(Deserialize, Serialize)] +#[derive(Deserialize, DeserializeOver2, Serialize)] pub struct Cmp { pub border: Style, pub active: Style, @@ -188,14 +175,14 @@ pub struct Cmp { pub icon_command: String, } -#[derive(Deserialize, Serialize)] +#[derive(Deserialize, DeserializeOver2, Serialize)] pub struct Tasks { pub border: Style, pub title: Style, pub hovered: Style, } -#[derive(Deserialize, Serialize)] +#[derive(Deserialize, DeserializeOver2, Serialize)] pub struct Help { pub on: Style, pub run: Style, @@ -204,3 +191,20 @@ pub struct Help { pub hovered: Style, pub footer: Style, } + +impl Theme { + pub(crate) fn reshape(mut self, light: bool) -> Result { + if self.mgr.tab_width < 1 { + bail!("[mgr].tab_width must be greater than 0"); + } else if self.which.cols < 1 || self.which.cols > 3 { + bail!("[which].cols must be between 1 and 3"); + } + + self.icon = self.icon.reshape()?; + + self.mgr.syntect_theme = + self.flavor.syntect_path(light).unwrap_or_else(|| expand_path(&self.mgr.syntect_theme)); + + Ok(self) + } +} diff --git a/yazi-config/src/which/which.rs b/yazi-config/src/which/which.rs index d47f73e1..05e43e8c 100644 --- a/yazi-config/src/which/which.rs +++ b/yazi-config/src/which/which.rs @@ -1,12 +1,9 @@ -use std::str::FromStr; - -use anyhow::Context; use serde::{Deserialize, Serialize}; -use validator::Validate; +use yazi_codegen::DeserializeOver2; use super::SortBy; -#[derive(Debug, Deserialize, Serialize, Validate)] +#[derive(Debug, Deserialize, DeserializeOver2, Serialize)] pub struct Which { // Sorting pub sort_by: SortBy, @@ -14,19 +11,3 @@ pub struct Which { pub sort_reverse: bool, pub sort_translit: bool, } - -impl FromStr for Which { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - #[derive(Deserialize)] - struct Outer { - which: Which, - } - - let outer: Outer = - toml::from_str(s).context("Failed to parse the [which] section in your yazi.toml")?; - - Ok(outer.which) - } -} diff --git a/yazi-config/src/yazi.rs b/yazi-config/src/yazi.rs new file mode 100644 index 00000000..9c889371 --- /dev/null +++ b/yazi-config/src/yazi.rs @@ -0,0 +1,37 @@ +use anyhow::Result; +use serde::Deserialize; +use yazi_codegen::DeserializeOver1; + +use crate::{mgr, open, opener, plugin, popup, preview, tasks, which}; + +#[derive(Deserialize, DeserializeOver1)] +pub struct Yazi { + #[serde(rename = "manager")] + pub mgr: mgr::Mgr, // TODO: remove serde(rename) + pub preview: preview::Preview, + pub opener: opener::Opener, + pub open: open::Open, + pub tasks: tasks::Tasks, + pub plugin: plugin::Plugin, + pub input: popup::Input, + pub confirm: popup::Confirm, + pub pick: popup::Pick, + pub which: which::Which, +} + +impl Yazi { + pub(super) fn reshape(self) -> Result { + Ok(Self { + mgr: self.mgr.reshape()?, + preview: self.preview.reshape()?, + opener: self.opener.reshape()?, + open: self.open.reshape()?, + tasks: self.tasks.reshape()?, + plugin: self.plugin.reshape()?, + input: self.input, + confirm: self.confirm, + pick: self.pick, + which: self.which, + }) + } +} diff --git a/yazi-core/src/help/help.rs b/yazi-core/src/help/help.rs index a9c12fc6..7b3a04ab 100644 --- a/yazi-core/src/help/help.rs +++ b/yazi-core/src/help/help.rs @@ -1,7 +1,7 @@ use crossterm::{cursor::SetCursorStyle, event::KeyCode}; use unicode_width::UnicodeWidthStr; use yazi_adapter::Dimension; -use yazi_config::{INPUT, KEYMAP, keymap::{Chord, Key}}; +use yazi_config::{KEYMAP, YAZI, keymap::{Chord, Key}}; use yazi_macro::{render, render_and}; use yazi_shared::Layer; @@ -115,6 +115,10 @@ impl Help { #[inline] pub fn cursor_shape(&self) -> SetCursorStyle { - if INPUT.cursor_blink { SetCursorStyle::BlinkingBlock } else { SetCursorStyle::SteadyBlock } + if YAZI.input.cursor_blink { + SetCursorStyle::BlinkingBlock + } else { + SetCursorStyle::SteadyBlock + } } } diff --git a/yazi-core/src/input/commands/show.rs b/yazi-core/src/input/commands/show.rs index 0c3ea1f2..d17ef3e5 100644 --- a/yazi-core/src/input/commands/show.rs +++ b/yazi-core/src/input/commands/show.rs @@ -1,5 +1,5 @@ use tokio::sync::mpsc; -use yazi_config::{INPUT, popup::InputCfg}; +use yazi_config::{YAZI, popup::InputCfg}; use yazi_macro::render; use yazi_shared::{errors::InputError, event::CmdCow}; use yazi_widgets::input::InputCallback; @@ -45,7 +45,7 @@ impl Input { }); self.inner = yazi_widgets::input::Input::new( opt.cfg.value, - opt.cfg.position.offset.width.saturating_sub(INPUT.border()) as usize, + opt.cfg.position.offset.width.saturating_sub(YAZI.input.border()) as usize, cb, ); diff --git a/yazi-core/src/mgr/commands/bulk_rename.rs b/yazi-core/src/mgr/commands/bulk_rename.rs index c30a8302..e05b067b 100644 --- a/yazi-core/src/mgr/commands/bulk_rename.rs +++ b/yazi-core/src/mgr/commands/bulk_rename.rs @@ -3,7 +3,7 @@ use std::{borrow::Cow, collections::HashMap, ffi::{OsStr, OsString}, io::{Read, use anyhow::{Result, anyhow}; use scopeguard::defer; use tokio::{fs::{self, OpenOptions}, io::AsyncWriteExt}; -use yazi_config::{OPEN, PREVIEW}; +use yazi_config::YAZI; use yazi_dds::Pubsub; use yazi_fs::{File, FilesOp, max_common_root, maybe_exists, paths_to_same_file}; use yazi_proxy::{AppProxy, HIDER, TasksProxy, WATCHER}; @@ -13,7 +13,7 @@ use crate::mgr::Mgr; impl Mgr { pub(super) fn bulk_rename(&self) { - let Some(opener) = OPEN.block_opener("bulk-rename.txt", "text/plain") else { + let Some(opener) = YAZI.opener.block(YAZI.open.all("bulk-rename.txt", "text/plain")) else { return AppProxy::notify_warn("Bulk rename", "No text opener found"); }; @@ -24,7 +24,7 @@ impl Mgr { let cwd = self.cwd().clone(); tokio::spawn(async move { - let tmp = PREVIEW.tmpfile("bulk"); + let tmp = YAZI.preview.tmpfile("bulk"); let s = old.iter().map(|o| o.as_os_str()).collect::>().join(OsStr::new("\n")); OpenOptions::new() .write(true) diff --git a/yazi-core/src/mgr/commands/open.rs b/yazi-core/src/mgr/commands/open.rs index 0caee557..71bcbbd1 100644 --- a/yazi-core/src/mgr/commands/open.rs +++ b/yazi-core/src/mgr/commands/open.rs @@ -2,7 +2,7 @@ use std::{borrow::Cow, ffi::OsString}; use tracing::error; use yazi_boot::ARGS; -use yazi_config::{OPEN, PLUGIN, popup::PickCfg}; +use yazi_config::{YAZI, popup::PickCfg}; use yazi_fs::File; use yazi_macro::emit; use yazi_plugin::isolate; @@ -64,7 +64,7 @@ impl Mgr { } done.extend(files.iter().map(|f| (f.url_owned(), ""))); - for (fetcher, files) in PLUGIN.mime_fetchers(files) { + for (fetcher, files) in YAZI.plugin.mime_fetchers(files) { if let Err(e) = isolate::fetch(CmdCow::from(&fetcher.run), files).await { error!("Fetch mime failed on opening: {e}"); } @@ -90,16 +90,16 @@ impl Mgr { return tasks.process_from_files(opt.cwd, opt.hovered, targets); } - let openers: Vec<_> = OPEN.common_openers(&targets); + let openers: Vec<_> = YAZI.opener.all(YAZI.open.common(&targets).into_iter()); if openers.is_empty() { return; } let urls = [opt.hovered].into_iter().chain(targets.into_iter().map(|(u, _)| u)).collect(); tokio::spawn(async move { - let result = yazi_proxy::PickProxy::show(PickCfg::open( - openers.iter().map(|o| o.desc.clone()).collect(), - )); + let result = + yazi_proxy::PickProxy::show(PickCfg::open(openers.iter().map(|o| o.desc()).collect())); + if let Ok(choice) = result.await { TasksProxy::open_with(Cow::Borrowed(openers[choice]), opt.cwd, urls); } diff --git a/yazi-core/src/mgr/commands/refresh.rs b/yazi-core/src/mgr/commands/refresh.rs index b2d721ca..3cc0b95f 100644 --- a/yazi-core/src/mgr/commands/refresh.rs +++ b/yazi-core/src/mgr/commands/refresh.rs @@ -1,7 +1,7 @@ use std::path::MAIN_SEPARATOR; use crossterm::{execute, terminal::SetTitle}; -use yazi_config::MGR; +use yazi_config::YAZI; use yazi_fs::CWD; use yazi_shared::{event::CmdCow, tty::TTY}; @@ -9,7 +9,7 @@ use crate::{mgr::Mgr, tasks::Tasks}; impl Mgr { pub fn refresh(&mut self, _: CmdCow, tasks: &Tasks) { - if CWD.set(self.cwd()) && !MGR.title_format.is_empty() { + if CWD.set(self.cwd()) && !YAZI.mgr.title_format.is_empty() { execute!(TTY.writer(), SetTitle(self.title())).ok(); } @@ -35,6 +35,6 @@ impl Mgr { format!("{}", self.cwd().display()) }; - MGR.title_format.replace("{cwd}", &cwd) + YAZI.mgr.title_format.replace("{cwd}", &cwd) } } diff --git a/yazi-core/src/mgr/commands/seek.rs b/yazi-core/src/mgr/commands/seek.rs index 146de4bf..b56e9a55 100644 --- a/yazi-core/src/mgr/commands/seek.rs +++ b/yazi-core/src/mgr/commands/seek.rs @@ -1,4 +1,4 @@ -use yazi_config::PLUGIN; +use yazi_config::YAZI; use yazi_plugin::isolate; use yazi_shared::event::{CmdCow, Data}; @@ -24,7 +24,7 @@ impl Mgr { return self.active_mut().preview.reset(); }; - let Some(previewer) = PLUGIN.previewer(&hovered.url, mime) else { + let Some(previewer) = YAZI.plugin.previewer(&hovered.url, mime) else { return self.active_mut().preview.reset(); }; diff --git a/yazi-core/src/pick/pick.rs b/yazi-core/src/pick/pick.rs index dba61eb6..fe788ddd 100644 --- a/yazi-core/src/pick/pick.rs +++ b/yazi-core/src/pick/pick.rs @@ -1,6 +1,6 @@ use anyhow::Result; use tokio::sync::oneshot::Sender; -use yazi_config::{PICK, popup::Position}; +use yazi_config::{YAZI, popup::Position}; #[derive(Default)] pub struct Pick { @@ -24,7 +24,7 @@ impl Pick { #[inline] pub(super) fn limit(&self) -> usize { - self.position.offset.height.saturating_sub(PICK.border()) as usize + self.position.offset.height.saturating_sub(YAZI.pick.border()) as usize } } diff --git a/yazi-core/src/spot/spot.rs b/yazi-core/src/spot/spot.rs index 5c076ddd..bf4ae609 100644 --- a/yazi-core/src/spot/spot.rs +++ b/yazi-core/src/spot/spot.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use tokio_util::sync::CancellationToken; -use yazi_config::PLUGIN; +use yazi_config::YAZI; use yazi_fs::File; use yazi_plugin::{isolate, utils::SpotLock}; use yazi_shared::url::Url; @@ -22,7 +22,7 @@ impl Spot { return; } - let Some(spotter) = PLUGIN.spotter(&file.url, &mime) else { + let Some(spotter) = YAZI.plugin.spotter(&file.url, &mime) else { return self.close(()); }; diff --git a/yazi-core/src/tab/commands/shell.rs b/yazi-core/src/tab/commands/shell.rs index 8a706593..87d083da 100644 --- a/yazi-core/src/tab/commands/shell.rs +++ b/yazi-core/src/tab/commands/shell.rs @@ -1,7 +1,7 @@ use std::{borrow::Cow, fmt::Display}; use anyhow::bail; -use yazi_config::{open::Opener, popup::InputCfg}; +use yazi_config::{opener::OpenerRule, popup::InputCfg}; use yazi_proxy::{AppProxy, InputProxy, TasksProxy}; use yazi_shared::{event::{CmdCow, Data}, url::Url}; @@ -68,7 +68,7 @@ impl Tab { } TasksProxy::open_with( - Cow::Owned(Opener { + Cow::Owned(OpenerRule { run: opt.run.into_owned(), block: opt.block, orphan: opt.orphan, diff --git a/yazi-core/src/tab/folder.rs b/yazi-core/src/tab/folder.rs index ccfaf0e7..4d0845e6 100644 --- a/yazi-core/src/tab/folder.rs +++ b/yazi-core/src/tab/folder.rs @@ -1,6 +1,6 @@ use std::mem; -use yazi_config::{LAYOUT, MGR}; +use yazi_config::{LAYOUT, YAZI}; use yazi_dds::Pubsub; use yazi_fs::{File, Files, FilesOp, FolderStage, Step, cha::Cha}; use yazi_proxy::MgrProxy; @@ -24,7 +24,7 @@ impl Default for Folder { Self { url: Default::default(), cha: Default::default(), - files: Files::new(MGR.show_hidden), + files: Files::new(YAZI.mgr.show_hidden), stage: Default::default(), offset: Default::default(), cursor: Default::default(), @@ -140,7 +140,7 @@ impl Folder { let len = self.files.len(); let limit = LAYOUT.get().limit(); - let scrolloff = (limit / 2).min(MGR.scrolloff as usize); + let scrolloff = (limit / 2).min(YAZI.mgr.scrolloff as usize); self.cursor = new.min(len.saturating_sub(1)); self.offset = if self.cursor < (self.offset + limit).min(len).saturating_sub(scrolloff) { @@ -157,7 +157,7 @@ impl Folder { let max = self.files.len().saturating_sub(1); let limit = LAYOUT.get().limit(); - let scrolloff = (limit / 2).min(MGR.scrolloff as usize); + let scrolloff = (limit / 2).min(YAZI.mgr.scrolloff as usize); self.cursor = new.min(max); self.offset = if self.cursor < self.offset + scrolloff { @@ -174,7 +174,7 @@ impl Folder { let len = self.files.len(); let limit = LAYOUT.get().limit(); - let scrolloff = (limit / 2).min(MGR.scrolloff as usize); + let scrolloff = (limit / 2).min(YAZI.mgr.scrolloff as usize); self.offset = if self.cursor < (self.offset + limit).min(len).saturating_sub(scrolloff) { len.saturating_sub(limit).min(self.offset) diff --git a/yazi-core/src/tab/preference.rs b/yazi-core/src/tab/preference.rs index d5e3241c..d8f766ad 100644 --- a/yazi-core/src/tab/preference.rs +++ b/yazi-core/src/tab/preference.rs @@ -1,4 +1,4 @@ -use yazi_config::MGR; +use yazi_config::YAZI; use yazi_fs::{FilesSorter, SortBy}; #[derive(Clone, PartialEq)] @@ -19,15 +19,15 @@ impl Default for Preference { fn default() -> Self { Self { // Sorting - sort_by: MGR.sort_by, - sort_sensitive: MGR.sort_sensitive, - sort_reverse: MGR.sort_reverse, - sort_dir_first: MGR.sort_dir_first, - sort_translit: MGR.sort_translit, + sort_by: YAZI.mgr.sort_by, + sort_sensitive: YAZI.mgr.sort_sensitive, + sort_reverse: YAZI.mgr.sort_reverse, + sort_dir_first: YAZI.mgr.sort_dir_first, + sort_translit: YAZI.mgr.sort_translit, // Display - linemode: MGR.linemode.to_owned(), - show_hidden: MGR.show_hidden, + linemode: YAZI.mgr.linemode.to_owned(), + show_hidden: YAZI.mgr.show_hidden, } } } diff --git a/yazi-core/src/tab/preview.rs b/yazi-core/src/tab/preview.rs index f8cf4274..b2ed79c7 100644 --- a/yazi-core/src/tab/preview.rs +++ b/yazi-core/src/tab/preview.rs @@ -4,7 +4,7 @@ use tokio::{pin, task::JoinHandle}; use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream}; use tokio_util::sync::CancellationToken; use yazi_adapter::ADAPTOR; -use yazi_config::PLUGIN; +use yazi_config::YAZI; use yazi_fs::{File, Files, FilesOp, cha::Cha}; use yazi_macro::render; use yazi_plugin::{external::Highlighter, isolate, utils::PreviewLock}; @@ -27,7 +27,7 @@ impl Preview { return; } - let Some(previewer) = PLUGIN.previewer(&file.url, &mime) else { + let Some(previewer) = YAZI.plugin.previewer(&file.url, &mime) else { return self.reset(); }; diff --git a/yazi-core/src/tasks/preload.rs b/yazi-core/src/tasks/preload.rs index e39d4519..2254a780 100644 --- a/yazi-core/src/tasks/preload.rs +++ b/yazi-core/src/tasks/preload.rs @@ -1,4 +1,4 @@ -use yazi_config::{PLUGIN, plugin::MAX_PREWORKERS}; +use yazi_config::{YAZI, plugin::MAX_PREWORKERS}; use yazi_fs::{File, Files, SortBy}; use super::Tasks; @@ -10,7 +10,7 @@ impl Tasks { let mut tasks: [Vec<_>; MAX_PREWORKERS as usize] = Default::default(); for f in paged { let hash = f.hash(); - for g in PLUGIN.fetchers(&f.url, mimetype.by_file(f).unwrap_or_default()) { + for g in YAZI.plugin.fetchers(&f.url, mimetype.by_file(f).unwrap_or_default()) { match loaded.get_mut(&hash) { Some(n) if *n & (1 << g.idx) != 0 => continue, Some(n) => *n |= 1 << g.idx, @@ -23,7 +23,7 @@ impl Tasks { drop(loaded); for (i, tasks) in tasks.into_iter().enumerate() { if !tasks.is_empty() { - self.scheduler.fetch_paged(&PLUGIN.fetchers[i], tasks); + self.scheduler.fetch_paged(&YAZI.plugin.fetchers[i], tasks); } } } @@ -32,7 +32,7 @@ impl Tasks { let mut loaded = self.scheduler.prework.loaded.lock(); for f in paged { let hash = f.hash(); - for p in PLUGIN.preloaders(&f.url, mimetype.by_file(f).unwrap_or_default()) { + for p in YAZI.plugin.preloaders(&f.url, mimetype.by_file(f).unwrap_or_default()) { match loaded.get_mut(&hash) { Some(n) if *n & (1 << p.idx) != 0 => continue, Some(n) => *n |= 1 << p.idx, diff --git a/yazi-core/src/tasks/process.rs b/yazi-core/src/tasks/process.rs index 4294755d..f91d3801 100644 --- a/yazi-core/src/tasks/process.rs +++ b/yazi-core/src/tasks/process.rs @@ -1,6 +1,6 @@ use std::{borrow::Cow, collections::HashMap, ffi::OsString, mem}; -use yazi_config::{OPEN, open::Opener}; +use yazi_config::{YAZI, opener::OpenerRule}; use yazi_proxy::options::ProcessExecOpt; use yazi_shared::url::Url; @@ -10,7 +10,7 @@ impl Tasks { pub fn process_from_files(&self, cwd: Url, hovered: Url, targets: Vec<(Url, &str)>) { let mut openers = HashMap::new(); for (url, mime) in targets { - if let Some(opener) = OPEN.openers(&url, mime).and_then(|o| o.first().copied()) { + if let Some(opener) = YAZI.opener.first(YAZI.open.all(&url, mime)) { openers.entry(opener).or_insert_with(|| vec![hovered.clone()]).push(url); } } @@ -26,7 +26,7 @@ impl Tasks { pub fn process_from_opener( &self, cwd: Url, - opener: Cow<'static, Opener>, + opener: Cow<'static, OpenerRule>, mut args: Vec, ) { if opener.spread { diff --git a/yazi-core/src/which/sorter.rs b/yazi-core/src/which/sorter.rs index d9503b24..c5ced22c 100644 --- a/yazi-core/src/which/sorter.rs +++ b/yazi-core/src/which/sorter.rs @@ -1,6 +1,6 @@ use std::{borrow::Cow, mem}; -use yazi_config::{WHICH, keymap::ChordCow, which::SortBy}; +use yazi_config::{YAZI, keymap::ChordCow, which::SortBy}; use yazi_shared::{natsort, translit::Transliterator}; #[derive(Clone, Copy, PartialEq)] @@ -14,10 +14,10 @@ pub struct WhichSorter { impl Default for WhichSorter { fn default() -> Self { Self { - by: WHICH.sort_by, - sensitive: WHICH.sort_sensitive, - reverse: WHICH.sort_reverse, - translit: WHICH.sort_translit, + by: YAZI.which.sort_by, + sensitive: YAZI.which.sort_sensitive, + reverse: YAZI.which.sort_reverse, + translit: YAZI.which.sort_translit, } } } diff --git a/yazi-fm/src/app/commands/mouse.rs b/yazi-fm/src/app/commands/mouse.rs index 56836898..0d969d28 100644 --- a/yazi-fm/src/app/commands/mouse.rs +++ b/yazi-fm/src/app/commands/mouse.rs @@ -1,7 +1,7 @@ use crossterm::event::{MouseEvent, MouseEventKind}; use mlua::{ObjectLike, Table}; use tracing::error; -use yazi_config::MGR; +use yazi_config::YAZI; use yazi_plugin::LUA; use crate::{app::App, lives::Lives}; @@ -24,7 +24,7 @@ impl App { let area = yazi_plugin::elements::Rect::from(size); let root = LUA.globals().raw_get::("Root")?.call_method::
("new", area)?; - if matches!(event.kind, MouseEventKind::Down(_) if MGR.mouse_events.draggable()) { + if matches!(event.kind, MouseEventKind::Down(_) if YAZI.mgr.mouse_events.draggable()) { root.raw_set("_drag_start", event)?; } diff --git a/yazi-fm/src/lives/file.rs b/yazi-fm/src/lives/file.rs index a99039e6..fc8b945e 100644 --- a/yazi-fm/src/lives/file.rs +++ b/yazi-fm/src/lives/file.rs @@ -70,7 +70,7 @@ impl UserData for File { methods.add_method("style", |lua, me, ()| { lua.named_registry_value::("cx")?.borrow_scoped(|cx: &Ctx| { let mime = cx.mgr.mimetype.by_file(me).unwrap_or_default(); - THEME.filetypes.iter().find(|&x| x.matches(me, mime)).map(|x| Style::from(x.style)) + THEME.filetype.iter().find(|&x| x.matches(me, mime)).map(|x| Style::from(x.style)) }) }); methods.add_method("is_hovered", |_, me, ()| Ok(me.idx == me.folder().cursor)); diff --git a/yazi-fm/src/signals.rs b/yazi-fm/src/signals.rs index 3fc31579..f01de8a0 100644 --- a/yazi-fm/src/signals.rs +++ b/yazi-fm/src/signals.rs @@ -2,7 +2,7 @@ use anyhow::Result; use crossterm::event::{Event as CrosstermEvent, EventStream, KeyEvent, KeyEventKind}; use futures::StreamExt; use tokio::{select, sync::{mpsc, oneshot}}; -use yazi_config::MGR; +use yazi_config::YAZI; use yazi_shared::event::Event; pub(super) struct Signals { @@ -62,7 +62,7 @@ impl Signals { Event::Key(key).emit() } CrosstermEvent::Mouse(mouse) => { - if MGR.mouse_events.contains(mouse.kind.into()) { + if YAZI.mgr.mouse_events.contains(mouse.kind.into()) { Event::Mouse(mouse).emit(); } } diff --git a/yazi-fm/src/term.rs b/yazi-fm/src/term.rs index e0d22bf2..f26a03fc 100644 --- a/yazi-fm/src/term.rs +++ b/yazi-fm/src/term.rs @@ -5,7 +5,7 @@ use crossterm::{Command, event::{DisableBracketedPaste, EnableBracketedPaste, Ke use cursor::RestoreCursor; use ratatui::{CompletedFrame, Frame, Terminal, backend::CrosstermBackend, buffer::Buffer, layout::Rect}; use yazi_adapter::{Emulator, Mux}; -use yazi_config::MGR; +use yazi_config::YAZI; use yazi_shared::{SyncCell, tty::{TTY, TtyWriter}}; static CSI_U: AtomicBool = AtomicBool::new(false); @@ -94,7 +94,7 @@ impl Term { PopKeyboardEnhancementFlags.write_ansi(&mut TTY.writer()).ok(); } - if !MGR.title_format.is_empty() { + if !YAZI.mgr.title_format.is_empty() { execute!(TTY.writer(), SetTitle("")).ok(); } @@ -160,13 +160,13 @@ impl DerefMut for Term { // --- Mouse support mod mouse { use crossterm::event::{DisableMouseCapture, EnableMouseCapture}; - use yazi_config::MGR; + use yazi_config::YAZI; pub struct SetMouse(pub bool); impl crossterm::Command for SetMouse { fn write_ansi(&self, f: &mut impl std::fmt::Write) -> std::fmt::Result { - if MGR.mouse_events.is_empty() { + if YAZI.mgr.mouse_events.is_empty() { Ok(()) } else if self.0 { EnableMouseCapture.write_ansi(f) @@ -177,7 +177,7 @@ mod mouse { #[cfg(windows)] fn execute_winapi(&self) -> std::io::Result<()> { - if MGR.mouse_events.is_empty() { + if YAZI.mgr.mouse_events.is_empty() { Ok(()) } else if self.0 { EnableMouseCapture.execute_winapi() diff --git a/yazi-plugin/src/config/plugin.rs b/yazi-plugin/src/config/plugin.rs index 50b483de..478482ca 100644 --- a/yazi-plugin/src/config/plugin.rs +++ b/yazi-plugin/src/config/plugin.rs @@ -1,5 +1,5 @@ use mlua::{Function, IntoLua, Lua, UserData, Value}; -use yazi_config::PLUGIN; +use yazi_config::YAZI; use crate::{Composer, file::FileRef, url::UrlRef}; @@ -21,25 +21,25 @@ impl Plugin { fn fetchers(lua: &Lua) -> mlua::Result { lua.create_function(|lua, (file, mime): (FileRef, mlua::String)| { - lua.create_sequence_from(PLUGIN.fetchers(&file.url, &mime.to_str()?).map(Fetcher)) + lua.create_sequence_from(YAZI.plugin.fetchers(&file.url, &mime.to_str()?).map(Fetcher)) }) } fn spotter(lua: &Lua) -> mlua::Result { lua.create_function(|_, (url, mime): (UrlRef, mlua::String)| { - Ok(PLUGIN.spotter(&url, &mime.to_str()?).map(Spotter)) + Ok(YAZI.plugin.spotter(&url, &mime.to_str()?).map(Spotter)) }) } fn preloaders(lua: &Lua) -> mlua::Result { lua.create_function(|lua, (url, mime): (UrlRef, mlua::String)| { - lua.create_sequence_from(PLUGIN.preloaders(&url, &mime.to_str()?).map(Preloader)) + lua.create_sequence_from(YAZI.plugin.preloaders(&url, &mime.to_str()?).map(Preloader)) }) } fn previewer(lua: &Lua) -> mlua::Result { lua.create_function(|_, (url, mime): (UrlRef, mlua::String)| { - Ok(PLUGIN.previewer(&url, &mime.to_str()?).map(Previewer)) + Ok(YAZI.plugin.previewer(&url, &mime.to_str()?).map(Previewer)) }) } } diff --git a/yazi-plugin/src/config/runtime.rs b/yazi-plugin/src/config/runtime.rs index f65f1a6f..108d564c 100644 --- a/yazi-plugin/src/config/runtime.rs +++ b/yazi-plugin/src/config/runtime.rs @@ -1,7 +1,7 @@ use mlua::{IntoLua, Lua, LuaSerdeExt, SerializeOptions, Value}; use yazi_adapter::EMULATOR; use yazi_boot::ARGS; -use yazi_config::{MGR, PREVIEW, TASKS, THEME}; +use yazi_config::{THEME, YAZI}; use crate::{Composer, url::Url}; @@ -43,21 +43,22 @@ impl<'a> Runtime<'a> { fn mgr(lua: &Lua) -> mlua::Result { Composer::make(lua, 15, |lua, key| { + let m = &YAZI.mgr; match key { - b"ratio" => lua.to_value_with(&MGR.ratio, OPTS)?, + b"ratio" => lua.to_value_with(&m.ratio, OPTS)?, - b"sort_by" => lua.to_value_with(&MGR.sort_by, OPTS)?, - b"sort_sensitive" => lua.to_value_with(&MGR.sort_sensitive, OPTS)?, - b"sort_reverse" => lua.to_value_with(&MGR.sort_reverse, OPTS)?, - b"sort_dir_first" => lua.to_value_with(&MGR.sort_dir_first, OPTS)?, - b"sort_translit" => lua.to_value_with(&MGR.sort_translit, OPTS)?, + b"sort_by" => lua.to_value_with(&m.sort_by, OPTS)?, + b"sort_sensitive" => lua.to_value_with(&m.sort_sensitive, OPTS)?, + b"sort_reverse" => lua.to_value_with(&m.sort_reverse, OPTS)?, + b"sort_dir_first" => lua.to_value_with(&m.sort_dir_first, OPTS)?, + b"sort_translit" => lua.to_value_with(&m.sort_translit, OPTS)?, - b"linemode" => lua.to_value_with(&MGR.linemode, OPTS)?, - b"show_hidden" => lua.to_value_with(&MGR.show_hidden, OPTS)?, - b"show_symlink" => lua.to_value_with(&MGR.show_symlink, OPTS)?, - b"scrolloff" => lua.to_value_with(&MGR.scrolloff, OPTS)?, - b"mouse_events" => lua.to_value_with(&MGR.mouse_events, OPTS)?, - b"title_format" => lua.to_value_with(&MGR.title_format, OPTS)?, + b"linemode" => lua.to_value_with(&m.linemode, OPTS)?, + b"show_hidden" => lua.to_value_with(&m.show_hidden, OPTS)?, + b"show_symlink" => lua.to_value_with(&m.show_symlink, OPTS)?, + b"scrolloff" => lua.to_value_with(&m.scrolloff, OPTS)?, + b"mouse_events" => lua.to_value_with(&m.mouse_events, OPTS)?, + b"title_format" => lua.to_value_with(&m.title_format, OPTS)?, _ => return Ok(Value::Nil), } .into_lua(lua) @@ -66,21 +67,22 @@ impl<'a> Runtime<'a> { fn preview(lua: &Lua) -> mlua::Result { Composer::make(lua, 15, |lua, key| { + let p = &YAZI.preview; match key { - b"wrap" => lua.to_value_with(&PREVIEW.wrap, OPTS)?, - b"tab_size" => lua.to_value_with(&PREVIEW.tab_size, OPTS)?, - b"max_width" => lua.to_value_with(&PREVIEW.max_width, OPTS)?, - b"max_height" => lua.to_value_with(&PREVIEW.max_height, OPTS)?, + b"wrap" => lua.to_value_with(&p.wrap, OPTS)?, + b"tab_size" => lua.to_value_with(&p.tab_size, OPTS)?, + b"max_width" => lua.to_value_with(&p.max_width, OPTS)?, + b"max_height" => lua.to_value_with(&p.max_height, OPTS)?, - b"cache_dir" => lua.to_value_with(&PREVIEW.cache_dir, OPTS)?, + b"cache_dir" => lua.to_value_with(&p.cache_dir, OPTS)?, - b"image_delay" => lua.to_value_with(&PREVIEW.image_delay, OPTS)?, - b"image_filter" => lua.to_value_with(&PREVIEW.image_filter, OPTS)?, - b"image_quality" => lua.to_value_with(&PREVIEW.image_quality, OPTS)?, - b"sixel_fraction" => lua.to_value_with(&PREVIEW.sixel_fraction, OPTS)?, + b"image_delay" => lua.to_value_with(&p.image_delay, OPTS)?, + b"image_filter" => lua.to_value_with(&p.image_filter, OPTS)?, + b"image_quality" => lua.to_value_with(&p.image_quality, OPTS)?, + b"sixel_fraction" => lua.to_value_with(&p.sixel_fraction, OPTS)?, - b"ueberzug_scale" => lua.to_value_with(&PREVIEW.ueberzug_scale, OPTS)?, - b"ueberzug_offset" => lua.to_value_with(&PREVIEW.ueberzug_offset, OPTS)?, + b"ueberzug_scale" => lua.to_value_with(&p.ueberzug_scale, OPTS)?, + b"ueberzug_offset" => lua.to_value_with(&p.ueberzug_offset, OPTS)?, _ => return Ok(Value::Nil), } .into_lua(lua) @@ -89,15 +91,16 @@ impl<'a> Runtime<'a> { fn tasks(lua: &Lua) -> mlua::Result { Composer::make(lua, 10, |lua, key| { + let t = &YAZI.tasks; match key { - b"micro_workers" => lua.to_value_with(&TASKS.micro_workers, OPTS)?, - b"macro_workers" => lua.to_value_with(&TASKS.macro_workers, OPTS)?, - b"bizarre_retry" => lua.to_value_with(&TASKS.bizarre_retry, OPTS)?, + b"micro_workers" => lua.to_value_with(&t.micro_workers, OPTS)?, + b"macro_workers" => lua.to_value_with(&t.macro_workers, OPTS)?, + b"bizarre_retry" => lua.to_value_with(&t.bizarre_retry, OPTS)?, - b"image_alloc" => lua.to_value_with(&TASKS.image_alloc, OPTS)?, - b"image_bound" => lua.to_value_with(&TASKS.image_bound, OPTS)?, + b"image_alloc" => lua.to_value_with(&t.image_alloc, OPTS)?, + b"image_bound" => lua.to_value_with(&t.image_bound, OPTS)?, - b"suppress_preload" => lua.to_value_with(&TASKS.suppress_preload, OPTS)?, + b"suppress_preload" => lua.to_value_with(&t.suppress_preload, OPTS)?, _ => return Ok(Value::Nil), } .into_lua(lua) @@ -108,7 +111,7 @@ impl<'a> Runtime<'a> { // TODO: remove this pub fn install_manager(self) -> mlua::Result { - self.lua.globals().raw_set("MANAGER", self.lua.to_value_with(&*MGR, OPTS)?)?; + self.lua.globals().raw_set("MANAGER", self.lua.to_value_with(&YAZI.mgr, OPTS)?)?; Ok(self) } @@ -120,7 +123,7 @@ impl<'a> Runtime<'a> { // TODO: remove this pub fn install_preview(self) -> mlua::Result { - self.lua.globals().raw_set("PREVIEW", self.lua.to_value_with(&*PREVIEW, OPTS)?)?; + self.lua.globals().raw_set("PREVIEW", self.lua.to_value_with(&YAZI.preview, OPTS)?)?; Ok(self) } } diff --git a/yazi-plugin/src/external/highlighter.rs b/yazi-plugin/src/external/highlighter.rs index b2e2995f..43d1650d 100644 --- a/yazi-plugin/src/external/highlighter.rs +++ b/yazi-plugin/src/external/highlighter.rs @@ -4,7 +4,7 @@ use anyhow::{Result, anyhow}; use ratatui::{layout::Size, text::{Line, Span, Text}}; use syntect::{LoadingError, dumps, easy::HighlightLines, highlighting::{self, Theme, ThemeSet}, parsing::{SyntaxReference, SyntaxSet}}; use tokio::{fs::File, io::{AsyncBufReadExt, BufReader}}; -use yazi_config::{PREVIEW, THEME, preview::PreviewWrap}; +use yazi_config::{THEME, YAZI, preview::PreviewWrap}; use yazi_shared::{Ids, errors::PeekError, replace_to_printable}; static INCR: Ids = Ids::new(); @@ -72,7 +72,7 @@ impl Highlighter { } else if !plain { before.push(String::from_utf8_lossy(&buf).into_owned()); Self::line_height(&before[before.len() - 1], size.width) - } else if PREVIEW.wrap == PreviewWrap::Yes { + } else if YAZI.preview.wrap == PreviewWrap::Yes { Self::line_height(&String::from_utf8_lossy(&buf), size.width) } else { 1 @@ -89,7 +89,7 @@ impl Highlighter { } Ok(if plain { - Text::from(replace_to_printable(&after, PREVIEW.tab_size)) + Text::from(replace_to_printable(&after, YAZI.preview.tab_size)) } else { Self::highlight_with(before, after, syntax.unwrap()).await? }) @@ -113,7 +113,7 @@ impl Highlighter { h.highlight_line(&line, syntaxes).map_err(|e| anyhow!(e))?; } - let indent = PREVIEW.indent(); + let indent = YAZI.preview.indent(); let mut lines = Vec::with_capacity(after.len()); for line in after { if ticket != INCR.current() { @@ -158,11 +158,12 @@ impl Highlighter { } fn line_height(s: &str, width: u16) -> usize { - if PREVIEW.wrap != PreviewWrap::Yes { + if YAZI.preview.wrap != PreviewWrap::Yes { return 1; } - let pad = PREVIEW + let pad = YAZI + .preview .tab_size .checked_sub(1) .map(|n| s.bytes().filter(|&b| b == b'\t').count() * n as usize) diff --git a/yazi-plugin/src/macros.rs b/yazi-plugin/src/macros.rs index 42de2bda..74c9d40f 100644 --- a/yazi-plugin/src/macros.rs +++ b/yazi-plugin/src/macros.rs @@ -110,7 +110,7 @@ macro_rules! impl_file_methods { Ok(match me.icon.get() { IconCache::Missing => { - let matched = yazi_config::THEME.icons.matches(me); + let matched = yazi_config::THEME.icon.matches(me); me.icon.set(matched.map_or(IconCache::Undefined, IconCache::Icon)); matched.map(Icon::from) } diff --git a/yazi-plugin/src/utils/cache.rs b/yazi-plugin/src/utils/cache.rs index 3436639e..085a2cdb 100644 --- a/yazi-plugin/src/utils/cache.rs +++ b/yazi-plugin/src/utils/cache.rs @@ -1,6 +1,6 @@ use mlua::{Function, Lua, Table}; use twox_hash::XxHash3_128; -use yazi_config::PREVIEW; +use yazi_config::YAZI; use super::Utils; use crate::{file::FileRef, url::Url}; @@ -9,7 +9,7 @@ impl Utils { pub(super) fn file_cache(lua: &Lua) -> mlua::Result { lua.create_function(|_, t: Table| { let file: FileRef = t.raw_get("file")?; - if file.url.parent() == Some(&PREVIEW.cache_dir) { + if file.url.parent() == Some(&YAZI.preview.cache_dir) { return Ok(None); } @@ -20,7 +20,7 @@ impl Utils { format!("{:x}", h.finish_128()) }; - Ok(Some(Url::from(PREVIEW.cache_dir.join(hex)))) + Ok(Some(Url::from(YAZI.preview.cache_dir.join(hex)))) }) } } diff --git a/yazi-plugin/src/utils/preview.rs b/yazi-plugin/src/utils/preview.rs index 175d94d7..4452b4dd 100644 --- a/yazi-plugin/src/utils/preview.rs +++ b/yazi-plugin/src/utils/preview.rs @@ -1,5 +1,5 @@ use mlua::{AnyUserData, Function, IntoLuaMulti, Lua, Table, Value}; -use yazi_config::{PREVIEW, preview::PreviewWrap}; +use yazi_config::{YAZI, preview::PreviewWrap}; use yazi_macro::emit; use yazi_shared::{errors::PeekError, event::Cmd}; @@ -51,7 +51,7 @@ impl Utils { lock.data = vec![Renderable::Text(Text { area, inner, - wrap: if PREVIEW.wrap == PreviewWrap::Yes { WRAP } else { WRAP_NO }, + wrap: if YAZI.preview.wrap == PreviewWrap::Yes { WRAP } else { WRAP_NO }, })]; emit!(Call(Cmd::new("mgr:update_peeked").with_any("lock", lock))); diff --git a/yazi-proxy/src/options/open.rs b/yazi-proxy/src/options/open.rs index 22517483..89c9f418 100644 --- a/yazi-proxy/src/options/open.rs +++ b/yazi-proxy/src/options/open.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; -use yazi_config::open::Opener; +use yazi_config::opener::OpenerRule; use yazi_shared::{event::CmdCow, url::Url}; // --- Open @@ -18,7 +18,7 @@ impl From for OpenDoOpt { // --- Open with pub struct OpenWithOpt { - pub opener: Cow<'static, Opener>, + pub opener: Cow<'static, OpenerRule>, pub cwd: Url, pub targets: Vec, } diff --git a/yazi-proxy/src/options/process.rs b/yazi-proxy/src/options/process.rs index e919ce1b..f86dbc9a 100644 --- a/yazi-proxy/src/options/process.rs +++ b/yazi-proxy/src/options/process.rs @@ -1,13 +1,13 @@ use std::{borrow::Cow, ffi::OsString}; use tokio::sync::oneshot; -use yazi_config::open::Opener; +use yazi_config::opener::OpenerRule; use yazi_shared::{event::CmdCow, url::Url}; // --- Exec pub struct ProcessExecOpt { pub cwd: Url, - pub opener: Cow<'static, Opener>, + pub opener: Cow<'static, OpenerRule>, pub args: Vec, pub done: Option>, } diff --git a/yazi-proxy/src/tasks.rs b/yazi-proxy/src/tasks.rs index 91a82723..0dfd4280 100644 --- a/yazi-proxy/src/tasks.rs +++ b/yazi-proxy/src/tasks.rs @@ -1,7 +1,7 @@ use std::{borrow::Cow, ffi::OsString}; use tokio::sync::oneshot; -use yazi_config::open::Opener; +use yazi_config::opener::OpenerRule; use yazi_macro::emit; use yazi_shared::{event::Cmd, url::Url}; @@ -11,7 +11,7 @@ pub struct TasksProxy; impl TasksProxy { #[inline] - pub fn open_with(opener: Cow<'static, Opener>, cwd: Url, targets: Vec) { + pub fn open_with(opener: Cow<'static, OpenerRule>, cwd: Url, targets: Vec) { emit!(Call(Cmd::new("tasks:open_with").with_any("option", OpenWithOpt { opener, cwd, @@ -20,7 +20,7 @@ impl TasksProxy { } #[inline] - pub async fn process_exec(opener: Cow<'static, Opener>, cwd: Url, args: Vec) { + pub async fn process_exec(opener: Cow<'static, OpenerRule>, cwd: Url, args: Vec) { let (tx, rx) = oneshot::channel(); emit!(Call(Cmd::new("tasks:process_exec").with_any("option", ProcessExecOpt { cwd, diff --git a/yazi-scheduler/src/file/file.rs b/yazi-scheduler/src/file/file.rs index 329ab4ec..61595663 100644 --- a/yazi-scheduler/src/file/file.rs +++ b/yazi-scheduler/src/file/file.rs @@ -3,7 +3,7 @@ use std::{borrow::Cow, collections::VecDeque, path::Path}; use anyhow::{Result, anyhow}; use tokio::{fs::{self, DirEntry}, io::{self, ErrorKind::{AlreadyExists, NotFound}}, sync::mpsc}; use tracing::warn; -use yazi_config::TASKS; +use yazi_config::YAZI; use yazi_fs::{calculate_size, cha::Cha, copy_with_progress, maybe_exists, ok_or_not_found, path_relative_to, skip_path}; use yazi_shared::url::Url; @@ -45,7 +45,7 @@ impl File { // Operation not permitted (os error 1) // Attribute not found (os error 93) Err(e) - if task.retry < TASKS.bizarre_retry + if task.retry < YAZI.tasks.bizarre_retry && matches!(e.raw_os_error(), Some(1) | Some(93)) => { task.retry += 1; diff --git a/yazi-scheduler/src/ongoing.rs b/yazi-scheduler/src/ongoing.rs index 21dbbd3d..4c773791 100644 --- a/yazi-scheduler/src/ongoing.rs +++ b/yazi-scheduler/src/ongoing.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use futures::future::BoxFuture; -use yazi_config::TASKS; +use yazi_config::YAZI; use super::{Task, TaskStage}; use crate::TaskKind; @@ -32,7 +32,7 @@ impl Ongoing { #[inline] pub fn len(&self) -> usize { - if TASKS.suppress_preload { + if YAZI.tasks.suppress_preload { self.all.values().filter(|t| t.kind != TaskKind::Preload).count() } else { self.all.len() @@ -44,7 +44,7 @@ impl Ongoing { #[inline] pub fn values(&self) -> Box + '_> { - if TASKS.suppress_preload { + if YAZI.tasks.suppress_preload { Box::new(self.all.values().filter(|t| t.kind != TaskKind::Preload)) } else { Box::new(self.all.values()) diff --git a/yazi-scheduler/src/scheduler.rs b/yazi-scheduler/src/scheduler.rs index 6584c663..9b275456 100644 --- a/yazi-scheduler/src/scheduler.rs +++ b/yazi-scheduler/src/scheduler.rs @@ -4,7 +4,7 @@ use anyhow::Result; use futures::{FutureExt, future::BoxFuture}; use parking_lot::Mutex; use tokio::{fs, select, sync::mpsc::{self, UnboundedReceiver}, task::JoinHandle}; -use yazi_config::{TASKS, plugin::{Fetcher, Preloader}}; +use yazi_config::{YAZI, plugin::{Fetcher, Preloader}}; use yazi_dds::Pump; use yazi_fs::{must_be_dir, remove_dir_clean, unique_name}; use yazi_proxy::{MgrProxy, options::{PluginOpt, ProcessExecOpt}}; @@ -39,14 +39,16 @@ impl Scheduler { micro: micro_tx, prog: prog_tx, - handles: Vec::with_capacity(TASKS.micro_workers as usize + TASKS.macro_workers as usize + 1), + handles: Vec::with_capacity( + YAZI.tasks.micro_workers as usize + YAZI.tasks.macro_workers as usize + 1, + ), ongoing: Default::default(), }; - for _ in 0..TASKS.micro_workers { + for _ in 0..YAZI.tasks.micro_workers { scheduler.handles.push(scheduler.schedule_micro(micro_rx.clone())); } - for _ in 0..TASKS.macro_workers { + for _ in 0..YAZI.tasks.macro_workers { scheduler.handles.push(scheduler.schedule_macro(micro_rx.clone(), macro_rx.clone())); } scheduler.progress(prog_rx); diff --git a/yazi-shared/src/theme/style.rs b/yazi-shared/src/theme/style.rs index b7086c05..4e9db592 100644 --- a/yazi-shared/src/theme/style.rs +++ b/yazi-shared/src/theme/style.rs @@ -4,47 +4,7 @@ use serde::{Deserialize, Serialize, Serializer, ser::SerializeMap}; use super::Color; #[derive(Clone, Copy, Debug, Default, Deserialize)] -#[serde(from = "StyleShadow")] pub struct Style { - pub fg: Option, - pub bg: Option, - pub modifier: Modifier, -} - -impl Serialize for Style { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut map = serializer.serialize_map(Some(3))?; - map.serialize_entry("fg", &self.fg)?; - map.serialize_entry("bg", &self.bg)?; - map.serialize_entry("modifier", &self.modifier.bits())?; - map.end() - } -} - -impl From