feat: new hovered condition specifying different icons for hovered files (#3728)

Co-authored-by: sxyazi <sxyazi@gmail.com>
This commit is contained in:
Yashank 2026-03-03 07:18:55 -05:00 committed by GitHub
parent 0efeaf5f64
commit b92b576ce1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 30 additions and 19 deletions

View file

@ -59,7 +59,7 @@ jobs:
run: ./scripts/build.sh ${{ matrix.target }} run: ./scripts/build.sh ${{ matrix.target }}
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@v6 uses: actions/upload-artifact@v7
with: with:
name: ${{ matrix.target }} name: ${{ matrix.target }}
path: | path: |
@ -105,7 +105,7 @@ jobs:
Compress-Archive -Path ${env:TARGET_NAME} -DestinationPath "${env:TARGET_NAME}.zip" Compress-Archive -Path ${env:TARGET_NAME} -DestinationPath "${env:TARGET_NAME}.zip"
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@v6 uses: actions/upload-artifact@v7
with: with:
name: ${{ matrix.target }} name: ${{ matrix.target }}
path: yazi-${{ matrix.target }}.zip path: yazi-${{ matrix.target }}.zip
@ -133,7 +133,7 @@ jobs:
run: ./scripts/build.sh ${{ matrix.target }} run: ./scripts/build.sh ${{ matrix.target }}
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@v6 uses: actions/upload-artifact@v7
with: with:
name: ${{ matrix.target }} name: ${{ matrix.target }}
path: | path: |
@ -167,7 +167,7 @@ jobs:
run: mv yazi_*.snap yazi-${{ matrix.arch }}.snap run: mv yazi_*.snap yazi-${{ matrix.arch }}.snap
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@v6 uses: actions/upload-artifact@v7
with: with:
name: snap-${{ matrix.arch }} name: snap-${{ matrix.arch }}
path: yazi-${{ matrix.arch }}.snap path: yazi-${{ matrix.arch }}.snap
@ -176,7 +176,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [build-snap] needs: [build-snap]
steps: steps:
- uses: actions/download-artifact@v7 - uses: actions/download-artifact@v8
with: with:
pattern: snap-* pattern: snap-*
merge-multiple: true merge-multiple: true
@ -205,7 +205,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [build-unix, build-windows, build-musl, build-snap] needs: [build-unix, build-windows, build-musl, build-snap]
steps: steps:
- uses: actions/download-artifact@v7 - uses: actions/download-artifact@v8
with: with:
merge-multiple: true merge-multiple: true
@ -235,7 +235,7 @@ jobs:
- uses: actions/checkout@v6 - uses: actions/checkout@v6
- uses: actions/download-artifact@v7 - uses: actions/download-artifact@v8
with: with:
merge-multiple: true merge-multiple: true

View file

@ -11,7 +11,7 @@ jobs:
winget: winget:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/download-artifact@v7 - uses: actions/download-artifact@v8
with: with:
merge-multiple: true merge-multiple: true
@ -25,7 +25,7 @@ jobs:
snapcraft: snapcraft:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/download-artifact@v7 - uses: actions/download-artifact@v8
with: with:
merge-multiple: true merge-multiple: true

View file

@ -16,6 +16,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/):
- Custom tab name ([#3666]) - Custom tab name ([#3666])
- New `--in` for `search` action to set search directory ([#3696]) - New `--in` for `search` action to set search directory ([#3696])
- New `hovered` condition specifying different icons for hovered files ([#3728])
- Allow using `ps.sub()` in `init.lua` directly without a plugin ([#3638]) - Allow using `ps.sub()` in `init.lua` directly without a plugin ([#3638])
- New `sort_fallback` option to control fallback sorting behavior ([#3077]) - New `sort_fallback` option to control fallback sorting behavior ([#3077])
- New `fs.access()` API to access the filesystem ([#3668]) - New `fs.access()` API to access the filesystem ([#3668])
@ -1670,3 +1671,4 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/):
[#3696]: https://github.com/sxyazi/yazi/pull/3696 [#3696]: https://github.com/sxyazi/yazi/pull/3696
[#3708]: https://github.com/sxyazi/yazi/pull/3708 [#3708]: https://github.com/sxyazi/yazi/pull/3708
[#3725]: https://github.com/sxyazi/yazi/pull/3725 [#3725]: https://github.com/sxyazi/yazi/pull/3725
[#3728]: https://github.com/sxyazi/yazi/pull/3728

View file

@ -65,6 +65,9 @@ impl File {
} }
}) })
} }
#[inline]
fn is_hovered(&self) -> bool { self.idx == self.folder.cursor }
} }
impl UserData for File { impl UserData for File {
@ -73,7 +76,7 @@ impl UserData for File {
cached_field!(fields, bare, |_, me| Ok(yazi_binding::File::new(&**me))); cached_field!(fields, bare, |_, me| Ok(yazi_binding::File::new(&**me)));
fields.add_field_method_get("idx", |_, me| Ok(me.idx + 1)); fields.add_field_method_get("idx", |_, me| Ok(me.idx + 1));
fields.add_field_method_get("is_hovered", |_, me| Ok(me.idx == me.folder.cursor)); fields.add_field_method_get("is_hovered", |_, me| Ok(me.is_hovered()));
fields.add_field_method_get("in_current", |_, me| Ok(ptr::eq(&*me.folder, &me.tab.current))); fields.add_field_method_get("in_current", |_, me| Ok(ptr::eq(&*me.folder, &me.tab.current)));
fields.add_field_method_get("in_preview", |_, me| { fields.add_field_method_get("in_preview", |_, me| {
Ok(me.idx == me.folder.cursor && me.tab.hovered().is_some_and(|f| f.url == me.folder.url)) Ok(me.idx == me.folder.cursor && me.tab.hovered().is_some_and(|f| f.url == me.folder.url))
@ -83,6 +86,11 @@ impl UserData for File {
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) { fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
yazi_binding::impl_file_methods!(methods); yazi_binding::impl_file_methods!(methods);
methods.add_method("icon", |_, me, ()| {
use yazi_binding::Icon;
// TODO: use a cache
Ok(yazi_config::THEME.icon.matches(me, me.is_hovered()).map(Icon::from))
});
methods.add_method("size", |_, me, ()| { methods.add_method("size", |_, me, ()| {
Ok(if me.is_dir() { me.folder.files.sizes.get(&me.urn()).copied() } else { Some(me.len) }) Ok(if me.is_dir() { me.folder.files.sizes.get(&me.urn()).copied() } else { Some(me.len) })
}); });

View file

@ -90,5 +90,11 @@ impl UserData for File {
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) { fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
impl_file_methods!(methods); impl_file_methods!(methods);
methods.add_method("icon", |_, me, ()| {
use crate::Icon;
// TODO: use a cache
Ok(yazi_config::THEME.icon.matches(me, false).map(Icon::from))
});
} }
} }

View file

@ -267,11 +267,5 @@ macro_rules! impl_file_methods {
use yazi_fs::FsHash64; use yazi_fs::FsHash64;
Ok(me.hash_u64()) Ok(me.hash_u64())
}); });
$methods.add_method("icon", |_, me, ()| {
use $crate::Icon;
// TODO: use a cache
Ok(yazi_config::THEME.icon.matches(me).map(Icon::from))
});
}; };
} }

View file

@ -53,7 +53,6 @@ pub fn deserialize_over1(input: TokenStream) -> TokenStream {
quote! { quote! {
impl #ident { impl #ident {
#[inline]
pub(crate) fn deserialize_over_with<'de>(mut self, table: toml::Spanned<toml::de::DeTable<'de>>) -> Result<Self, toml::de::Error> { pub(crate) fn deserialize_over_with<'de>(mut self, table: toml::Spanned<toml::de::DeTable<'de>>) -> Result<Self, toml::de::Error> {
use serde::{Deserialize, de::IntoDeserializer}; use serde::{Deserialize, de::IntoDeserializer};
@ -96,7 +95,6 @@ pub fn deserialize_over2(input: TokenStream) -> TokenStream {
quote! { quote! {
impl #ident { impl #ident {
#[inline]
pub(crate) fn deserialize_over_with<'de>(mut self, table: toml::Spanned<toml::de::DeTable<'de>>) -> Result<Self, toml::de::Error> { pub(crate) fn deserialize_over_with<'de>(mut self, table: toml::Spanned<toml::de::DeTable<'de>>) -> Result<Self, toml::de::Error> {
use serde::{Deserialize, de::IntoDeserializer}; use serde::{Deserialize, de::IntoDeserializer};

View file

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

View file

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

View file

@ -44,7 +44,7 @@ pub struct Icon {
} }
impl Icon { impl Icon {
pub fn matches(&self, file: &File) -> Option<&I> { pub fn matches(&self, file: &File, hovered: bool) -> Option<&I> {
if let Some(i) = self.match_by_glob(file) { if let Some(i) = self.match_by_glob(file) {
return Some(i); return Some(i);
} }
@ -65,6 +65,7 @@ impl Icon {
"sock" => file.is_sock(), "sock" => file.is_sock(),
"exec" => file.is_exec(), "exec" => file.is_exec(),
"sticky" => file.is_sticky(), "sticky" => file.is_sticky(),
"hovered" => hovered,
_ => false, _ => false,
}; };
self.conds.iter().find(|(c, _)| c.eval(f) == Some(true)).map(|(_, i)| i) self.conds.iter().find(|(c, _)| c.eval(f) == Some(true)).map(|(_, i)| i)