feat: add hovered icons for files and folders

This commit is contained in:
stickyburn 2026-03-02 00:39:11 -05:00 committed by sxyazi
parent 0efeaf5f64
commit ec730960ac
No known key found for this signature in database
5 changed files with 70 additions and 19 deletions

View file

@ -7,8 +7,9 @@ use crate::{Style, cached_field};
pub struct Icon { pub struct Icon {
inner: &'static yazi_config::Icon, inner: &'static yazi_config::Icon,
v_text: Option<Value>, v_text: Option<Value>,
v_style: Option<Value>, v_style: Option<Value>,
v_hovered_text: Option<Value>,
} }
impl Deref for Icon { impl Deref for Icon {
@ -19,7 +20,7 @@ impl Deref for Icon {
impl From<&'static yazi_config::Icon> for Icon { impl From<&'static yazi_config::Icon> for Icon {
fn from(icon: &'static yazi_config::Icon) -> Self { fn from(icon: &'static yazi_config::Icon) -> Self {
Self { inner: icon, v_text: None, v_style: None } Self { inner: icon, v_text: None, v_style: None, v_hovered_text: None }
} }
} }
@ -27,5 +28,8 @@ impl UserData for Icon {
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) { fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
cached_field!(fields, text, |lua, me| lua.create_string(&me.text)); cached_field!(fields, text, |lua, me| lua.create_string(&me.text));
cached_field!(fields, style, |_, me| Ok(Style::from(me.style))); cached_field!(fields, style, |_, me| Ok(Style::from(me.style)));
cached_field!(fields, hovered_text, |lua, me| {
me.hovered_text.as_ref().map(|s| lua.create_string(s)).transpose()
});
} }
} }

View file

@ -997,7 +997,7 @@ conds = [
{ if = "dummy", text = "", fg = "#f44336" }, { if = "dummy", text = "", fg = "#f44336" },
# Fallback # Fallback
{ if = "dir", text = "", fg = "#03a9f4" }, { if = "dir", text = "", fg = "#03a9f4", hovered_text = "" },
{ if = "exec", text = "", fg = "#8bc34a" }, { if = "exec", text = "", fg = "#8bc34a" },
{ if = "!dir", text = "", fg = "#ffffff" }, { if = "!dir", text = "", fg = "#ffffff" },
] ]

View file

@ -2,6 +2,7 @@ use crate::Style;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Icon { pub struct Icon {
pub text: String, pub text: String,
pub style: Style, pub style: Style,
pub hovered_text: Option<String>,
} }

View file

@ -132,15 +132,22 @@ impl<'de> Deserialize<'de> for PatIcons {
{ {
#[derive(Deserialize)] #[derive(Deserialize)]
struct Shadow { struct Shadow {
url: Pattern, url: Pattern,
text: String, text: String,
fg: Option<Color>, fg: Option<Color>,
hovered_text: Option<String>,
} }
Ok(Self( Ok(Self(
<Vec<Shadow>>::deserialize(deserializer)? <Vec<Shadow>>::deserialize(deserializer)?
.into_iter() .into_iter()
.map(|s| (s.url, I { text: s.text, style: Style { fg: s.fg, ..Default::default() } })) .map(|s| {
(s.url, I {
text: s.text,
style: Style { fg: s.fg, ..Default::default() },
hovered_text: s.hovered_text,
})
})
.collect(), .collect(),
)) ))
} }
@ -162,15 +169,22 @@ impl<'de> Deserialize<'de> for StrIcons {
{ {
#[derive(Deserialize)] #[derive(Deserialize)]
struct Shadow { struct Shadow {
name: String, name: String,
text: String, text: String,
fg: Option<Color>, fg: Option<Color>,
hovered_text: Option<String>,
} }
Ok(Self( Ok(Self(
<Vec<Shadow>>::deserialize(deserializer)? <Vec<Shadow>>::deserialize(deserializer)?
.into_iter() .into_iter()
.map(|s| (s.name, I { text: s.text, style: Style { fg: s.fg, ..Default::default() } })) .map(|s| {
(s.name, I {
text: s.text,
style: Style { fg: s.fg, ..Default::default() },
hovered_text: s.hovered_text,
})
})
.collect(), .collect(),
)) ))
} }
@ -192,16 +206,47 @@ impl<'de> Deserialize<'de> for CondIcons {
{ {
#[derive(Deserialize)] #[derive(Deserialize)]
struct Shadow { struct Shadow {
r#if: Condition, r#if: Condition,
text: String, text: String,
fg: Option<Color>, fg: Option<Color>,
hovered_text: Option<String>,
} }
Ok(Self( Ok(Self(
<Vec<Shadow>>::deserialize(deserializer)? <Vec<Shadow>>::deserialize(deserializer)?
.into_iter() .into_iter()
.map(|s| (s.r#if, I { text: s.text, style: Style { fg: s.fg, ..Default::default() } })) .map(|s| {
(s.r#if, I {
text: s.text,
style: Style { fg: s.fg, ..Default::default() },
hovered_text: s.hovered_text,
})
})
.collect(), .collect(),
)) ))
} }
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_icon_struct_with_hovered_text() {
let icon = I {
text: "normal_icon".to_string(),
style: Style::default(),
hovered_text: Some("hovered_icon".to_string()),
};
assert_eq!(icon.text, "normal_icon");
assert_eq!(icon.hovered_text, Some("hovered_icon".to_string()));
}
#[test]
fn test_icon_struct_without_hovered_text() {
let icon =
I { text: "normal_icon".to_string(), style: Style::default(), hovered_text: None };
assert_eq!(icon.text, "normal_icon");
assert_eq!(icon.hovered_text, None);
}
}

View file

@ -30,7 +30,8 @@ function Entity:icon()
if not icon then if not icon then
return "" return ""
elseif self._file.is_hovered then elseif self._file.is_hovered then
return icon.text .. " " local text = icon.hovered_text or icon.text
return text .. " "
else else
return ui.Line(icon.text .. " "):style(icon.style) return ui.Line(icon.text .. " "):style(icon.style)
end end