Skip to main content

yazi_config/
lib.rs

1yazi_macro::mod_pub!(keymap mgr open opener plugin popup preview tasks theme which vfs);
2
3yazi_macro::mod_flat!(icon layout mixing pattern platform preset priority selectable selector style utils yazi);
4
5use std::io::{Read, Write};
6
7use yazi_shim::{cell::{RoCell, SyncCell}, toml::{DeserializeOver, DeserializeOverWith}};
8use yazi_tty::TTY;
9
10pub static YAZI: RoCell<yazi::Yazi> = RoCell::new();
11pub static KEYMAP: RoCell<keymap::Keymap> = RoCell::new();
12pub static THEME: RoCell<theme::Theme> = RoCell::new();
13pub static LAYOUT: SyncCell<Layout> = SyncCell::new(Layout::default());
14
15pub fn init() -> anyhow::Result<()> {
16	if let Err(e) = try_init(true) {
17		wait_for_key(e)?;
18		try_init(false)?;
19	}
20	Ok(())
21}
22
23fn try_init(merge: bool) -> anyhow::Result<()> {
24	let mut yazi = Preset::yazi()?;
25	let mut keymap = Preset::keymap()?;
26
27	if merge {
28		yazi = yazi.deserialize_over(&yazi::Yazi::read()?)?;
29		keymap = keymap.deserialize_over(&keymap::Keymap::read()?)?;
30	}
31
32	YAZI.init(yazi);
33	KEYMAP.init(keymap);
34	Ok(())
35}
36
37pub fn init_flavor(light: bool) -> anyhow::Result<()> {
38	if let Err(e) = try_init_flavor(light, true) {
39		wait_for_key(e)?;
40		try_init_flavor(light, false)?;
41	}
42	Ok(())
43}
44
45fn try_init_flavor(light: bool, merge: bool) -> anyhow::Result<()> {
46	THEME.init(build_flavor(light, merge)?);
47	Ok(())
48}
49
50pub fn build_flavor(light: bool, merge: bool) -> anyhow::Result<theme::Theme> {
51	let mut preset = Preset::theme(light)?;
52
53	if merge {
54		let theme_str = theme::Theme::read()?;
55		let theme = toml::de::DeTable::parse(&theme_str)?;
56
57		let flavor_str = theme::Flavor::from_theme(&theme, &theme_str)?.read(light)?;
58
59		preset = preset.deserialize_over(&flavor_str)?;
60		preset = error_with_input(
61			preset.deserialize_over_with(toml::de::Deserializer::from(theme)),
62			&theme_str,
63		)?;
64	}
65
66	Ok(preset.reshape(light)?)
67}
68
69fn wait_for_key(e: anyhow::Error) -> anyhow::Result<()> {
70	let stdout = &mut *TTY.lockout();
71
72	writeln!(stdout, "{e}")?;
73	if let Some(src) = e.source() {
74		writeln!(stdout, "\nCaused by:\n{src}")?;
75	}
76
77	use crossterm::style::{Attribute, Print, SetAttributes};
78	crossterm::execute!(
79		stdout,
80		SetAttributes(Attribute::Reverse.into()),
81		SetAttributes(Attribute::Bold.into()),
82		Print("Press <Enter> to continue with preset settings..."),
83		SetAttributes(Attribute::Reset.into()),
84		Print("\n"),
85	)?;
86
87	TTY.reader().read_exact(&mut [0])?;
88	Ok(())
89}
90
91pub(crate) fn error_with_input<T>(
92	result: Result<T, toml::de::Error>,
93	input: &str,
94) -> Result<T, toml::de::Error> {
95	result.map_err(|mut err| {
96		err.set_input(Some(input));
97		err
98	})
99}