mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
Add the excluded command to toggle/show/hide excluded files via keymaps
This commit is contained in:
parent
e32db2a539
commit
f068dafec2
7 changed files with 150 additions and 4 deletions
52
yazi-actor/src/mgr/excluded.rs
Normal file
52
yazi-actor/src/mgr/excluded.rs
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
use yazi_core::tab::Folder;
|
||||||
|
use yazi_fs::FolderStage;
|
||||||
|
use yazi_macro::{act, render, render_and, succ};
|
||||||
|
use yazi_parser::mgr::ExcludedOpt;
|
||||||
|
use yazi_shared::data::Data;
|
||||||
|
|
||||||
|
use crate::{Actor, Ctx};
|
||||||
|
|
||||||
|
pub struct Excluded;
|
||||||
|
|
||||||
|
impl Actor for Excluded {
|
||||||
|
type Options = ExcludedOpt;
|
||||||
|
|
||||||
|
const NAME: &str = "excluded";
|
||||||
|
|
||||||
|
fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data> {
|
||||||
|
let state = opt.state.bool(cx.tab().current.files.show_excluded());
|
||||||
|
let hovered = cx.hovered().map(|f| f.urn().to_owned());
|
||||||
|
|
||||||
|
let apply = |f: &mut Folder| {
|
||||||
|
if f.stage == FolderStage::Loading {
|
||||||
|
render!();
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
f.files.set_show_excluded(state);
|
||||||
|
render_and!(f.files.catchup_revision())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Apply to CWD and parent
|
||||||
|
if let (a, Some(b)) = (apply(cx.current_mut()), cx.parent_mut().map(apply))
|
||||||
|
&& (a | b)
|
||||||
|
{
|
||||||
|
act!(mgr:hover, cx)?;
|
||||||
|
act!(mgr:update_paged, cx)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply to hovered
|
||||||
|
if let Some(h) = cx.hovered_folder_mut()
|
||||||
|
&& apply(h)
|
||||||
|
{
|
||||||
|
render!(h.repos(None));
|
||||||
|
act!(mgr:peek, cx, true)?;
|
||||||
|
} else if hovered.as_deref() != cx.hovered().map(|f| f.urn()) {
|
||||||
|
act!(mgr:peek, cx)?;
|
||||||
|
act!(mgr:watch, cx)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
succ!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,6 +10,7 @@ yazi_macro::mod_flat!(
|
||||||
enter
|
enter
|
||||||
escape
|
escape
|
||||||
exclude_add
|
exclude_add
|
||||||
|
excluded
|
||||||
filter
|
filter
|
||||||
filter_do
|
filter_do
|
||||||
find
|
find
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ pub enum Spark<'a> {
|
||||||
EscapeSelect(yazi_parser::VoidOpt),
|
EscapeSelect(yazi_parser::VoidOpt),
|
||||||
EscapeVisual(yazi_parser::VoidOpt),
|
EscapeVisual(yazi_parser::VoidOpt),
|
||||||
ExcludeAdd(yazi_parser::mgr::ExcludeAddOpt),
|
ExcludeAdd(yazi_parser::mgr::ExcludeAddOpt),
|
||||||
|
Excluded(yazi_parser::mgr::ExcludedOpt),
|
||||||
Filter(yazi_parser::mgr::FilterOpt),
|
Filter(yazi_parser::mgr::FilterOpt),
|
||||||
FilterDo(yazi_parser::mgr::FilterOpt),
|
FilterDo(yazi_parser::mgr::FilterOpt),
|
||||||
Find(yazi_parser::mgr::FindOpt),
|
Find(yazi_parser::mgr::FindOpt),
|
||||||
|
|
@ -149,6 +150,7 @@ impl<'a> IntoLua for Spark<'a> {
|
||||||
Self::EscapeSelect(b) => b.into_lua(lua),
|
Self::EscapeSelect(b) => b.into_lua(lua),
|
||||||
Self::EscapeVisual(b) => b.into_lua(lua),
|
Self::EscapeVisual(b) => b.into_lua(lua),
|
||||||
Self::ExcludeAdd(b) => b.into_lua(lua),
|
Self::ExcludeAdd(b) => b.into_lua(lua),
|
||||||
|
Self::Excluded(b) => b.into_lua(lua),
|
||||||
Self::Filter(b) => b.into_lua(lua),
|
Self::Filter(b) => b.into_lua(lua),
|
||||||
Self::FilterDo(b) => b.into_lua(lua),
|
Self::FilterDo(b) => b.into_lua(lua),
|
||||||
Self::Find(b) => b.into_lua(lua),
|
Self::Find(b) => b.into_lua(lua),
|
||||||
|
|
@ -310,6 +312,7 @@ try_from_spark!(mgr::RevealOpt, mgr:reveal);
|
||||||
try_from_spark!(mgr::SearchOpt, mgr:search, mgr:search_do);
|
try_from_spark!(mgr::SearchOpt, mgr:search, mgr:search_do);
|
||||||
try_from_spark!(mgr::SeekOpt, mgr:seek);
|
try_from_spark!(mgr::SeekOpt, mgr:seek);
|
||||||
try_from_spark!(mgr::ShellOpt, mgr:shell);
|
try_from_spark!(mgr::ShellOpt, mgr:shell);
|
||||||
|
try_from_spark!(mgr::ExcludedOpt, mgr:excluded);
|
||||||
try_from_spark!(mgr::SortOpt, mgr:sort);
|
try_from_spark!(mgr::SortOpt, mgr:sort);
|
||||||
try_from_spark!(mgr::SpotOpt, mgr:spot);
|
try_from_spark!(mgr::SpotOpt, mgr:spot);
|
||||||
try_from_spark!(mgr::TabCloseOpt, mgr:tab_close);
|
try_from_spark!(mgr::TabCloseOpt, mgr:tab_close);
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,7 @@ impl<'a> Executor<'a> {
|
||||||
on!(copy);
|
on!(copy);
|
||||||
on!(shell);
|
on!(shell);
|
||||||
on!(hidden);
|
on!(hidden);
|
||||||
|
on!(excluded);
|
||||||
on!(ignore);
|
on!(ignore);
|
||||||
on!(linemode);
|
on!(linemode);
|
||||||
on!(search);
|
on!(search);
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ pub struct Files {
|
||||||
sorter: FilesSorter,
|
sorter: FilesSorter,
|
||||||
filter: Option<Filter>,
|
filter: Option<Filter>,
|
||||||
show_hidden: bool,
|
show_hidden: bool,
|
||||||
|
show_excluded: bool,
|
||||||
ignore_filter: Option<IgnoreFilter>,
|
ignore_filter: Option<IgnoreFilter>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -261,12 +262,23 @@ impl Files {
|
||||||
files.into_iter().partition(|f| {
|
files.into_iter().partition(|f| {
|
||||||
(f.is_hidden() && !self.show_hidden)
|
(f.is_hidden() && !self.show_hidden)
|
||||||
|| !filter.matches(f.urn())
|
|| !filter.matches(f.urn())
|
||||||
|| self.ignore_filter.as_ref().is_some_and(|ig| ig.matches_url(&f.url))
|
|| (!self.show_excluded
|
||||||
|
&& self.ignore_filter.as_ref().is_some_and(|ig| ig.matches_url(&f.url)))
|
||||||
})
|
})
|
||||||
} else if let Some(ignore_filter) = &self.ignore_filter {
|
} else if let Some(ignore_filter) = &self.ignore_filter {
|
||||||
files
|
if self.show_excluded {
|
||||||
.into_iter()
|
// Show excluded files - only hide based on hidden status
|
||||||
.partition(|f| (f.is_hidden() && !self.show_hidden) || ignore_filter.matches_url(&f.url))
|
if self.show_hidden {
|
||||||
|
(vec![], files.into_iter().collect())
|
||||||
|
} else {
|
||||||
|
files.into_iter().partition(|f| f.is_hidden())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Hide excluded files - apply ignore filter
|
||||||
|
files
|
||||||
|
.into_iter()
|
||||||
|
.partition(|f| (f.is_hidden() && !self.show_hidden) || ignore_filter.matches_url(&f.url))
|
||||||
|
}
|
||||||
} else if self.show_hidden {
|
} else if self.show_hidden {
|
||||||
(vec![], files.into_iter().collect())
|
(vec![], files.into_iter().collect())
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -341,6 +353,26 @@ impl Files {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Show excluded
|
||||||
|
#[inline]
|
||||||
|
pub fn show_excluded(&self) -> bool { self.show_excluded }
|
||||||
|
|
||||||
|
pub fn set_show_excluded(&mut self, state: bool) -> bool {
|
||||||
|
if self.show_excluded == state {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.show_excluded = state;
|
||||||
|
|
||||||
|
// Re-split files with the new state
|
||||||
|
let it = mem::take(&mut self.items).into_iter().chain(mem::take(&mut self.hidden));
|
||||||
|
(self.hidden, self.items) = self.split_files(it);
|
||||||
|
self.sorter.sort(&mut self.items, &self.sizes);
|
||||||
|
self.revision += 1;
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
// --- Show hidden
|
// --- Show hidden
|
||||||
pub fn set_show_hidden(&mut self, state: bool) {
|
pub fn set_show_hidden(&mut self, state: bool) {
|
||||||
if self.show_hidden == state {
|
if self.show_hidden == state {
|
||||||
|
|
|
||||||
56
yazi-parser/src/mgr/excluded.rs
Normal file
56
yazi-parser/src/mgr/excluded.rs
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use mlua::{ExternalError, FromLua, IntoLua, Lua, Value};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use yazi_shared::event::CmdCow;
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct ExcludedOpt {
|
||||||
|
pub state: ExcludedOptState,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<CmdCow> for ExcludedOpt {
|
||||||
|
type Error = anyhow::Error;
|
||||||
|
|
||||||
|
fn try_from(c: CmdCow) -> Result<Self, Self::Error> {
|
||||||
|
Ok(Self { state: c.str(0).parse().unwrap_or_default() })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromLua for ExcludedOpt {
|
||||||
|
fn from_lua(_: Value, _: &Lua) -> mlua::Result<Self> { Err("unsupported".into_lua_err()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoLua for ExcludedOpt {
|
||||||
|
fn into_lua(self, _: &Lua) -> mlua::Result<Value> { Err("unsupported".into_lua_err()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- State
|
||||||
|
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
|
||||||
|
#[serde(rename_all = "kebab-case")]
|
||||||
|
pub enum ExcludedOptState {
|
||||||
|
#[default]
|
||||||
|
None,
|
||||||
|
Show,
|
||||||
|
Hide,
|
||||||
|
Toggle,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for ExcludedOptState {
|
||||||
|
type Err = serde::de::value::Error;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
Self::deserialize(serde::de::value::StrDeserializer::new(s))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExcludedOptState {
|
||||||
|
pub fn bool(self, old: bool) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::None => old,
|
||||||
|
Self::Show => true,
|
||||||
|
Self::Hide => false,
|
||||||
|
Self::Toggle => !old,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,6 +6,7 @@ yazi_macro::mod_flat!(
|
||||||
download
|
download
|
||||||
escape
|
escape
|
||||||
exclude_add
|
exclude_add
|
||||||
|
excluded
|
||||||
filter
|
filter
|
||||||
find
|
find
|
||||||
find_arrow
|
find_arrow
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue