feat: add filter command

This commit is contained in:
rolv 2023-12-24 14:41:03 +00:00 committed by sxyazi
parent 82bab0f24a
commit 9873559642
No known key found for this signature in database
8 changed files with 103 additions and 1 deletions

View file

@ -95,6 +95,9 @@ keymap = [
{ on = [ "n" ], exec = "find_arrow" },
{ on = [ "N" ], exec = "find_arrow --previous" },
# Filter
{ on = [ "f" ], exec = "filter" },
# Sorting
{ on = [ ",", "m" ], exec = "sort modified --dir_first", desc = "Sort by modified time" },
{ on = [ ",", "M" ], exec = "sort modified --reverse --dir_first", desc = "Sort by modified time (reverse)" },

View file

@ -149,6 +149,11 @@ search_title = "Search:"
search_origin = "top-center"
search_offset = [ 0, 2, 50, 3 ]
# filter
filter_title = "Filter:"
filter_origin = "top-center"
filter_offset = [ 0, 2, 50, 3 ]
# shell
shell_title = [ "Shell:", "Shell (block):" ]
shell_origin = "top-center"

View file

@ -35,6 +35,11 @@ pub struct Input {
pub find_origin: Origin,
pub find_offset: Offset,
// filter
pub filter_title: String,
pub filter_origin: Origin,
pub filter_offset: Offset,
// search
pub search_title: String,
pub search_origin: Origin,

View file

@ -77,6 +77,16 @@ impl InputCfg {
}
}
#[inline]
pub fn filter() -> Self {
Self {
title: INPUT.filter_title.to_owned(),
position: Position::new(INPUT.filter_origin, INPUT.filter_offset),
realtime: true,
..Default::default()
}
}
#[inline]
pub fn search() -> Self {
Self {

View file

@ -9,6 +9,7 @@ bitflags! {
const VISUAL = 0b0010;
const SELECT = 0b0100;
const SEARCH = 0b1000;
const FILTER = 0b1001;
}
}
@ -20,6 +21,7 @@ impl From<&Exec> for Opt {
b"visual" => acc | Self::VISUAL,
b"select" => acc | Self::SELECT,
b"search" => acc | Self::SEARCH,
b"filter" => acc | Self::FILTER,
_ => acc,
})
}
@ -45,13 +47,23 @@ impl Tab {
#[inline]
fn escape_search(&mut self) -> bool { self.search_stop() }
#[inline]
fn escape_filter(&mut self) -> bool {
if self.current.files.filter_keyword.is_some() {
self.current.files.set_filter_keyword("");
return true;
}
false
}
pub fn escape(&mut self, opt: impl Into<Opt>) -> bool {
let opt = opt.into() as Opt;
if opt.is_empty() {
return self.escape_find()
|| self.escape_visual()
|| self.escape_select()
|| self.escape_search();
|| self.escape_search()
|| self.escape_filter();
}
let mut b = false;
@ -67,6 +79,9 @@ impl Tab {
if opt.contains(Opt::SEARCH) {
b |= self.escape_search();
}
if opt.contains(Opt::FILTER) {
b |= self.escape_filter();
}
b
}
}

View file

@ -0,0 +1,59 @@
use std::time::Duration;
use tokio::pin;
use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt};
use yazi_config::popup::InputCfg;
use yazi_shared::{emit, event::Exec, Debounce, InputError, Layer};
use crate::{input::Input, tab::Tab};
pub struct Opt<'a> {
query: Option<&'a str>,
}
impl<'a> From<&'a Exec> for Opt<'a> {
fn from(e: &'a Exec) -> Self {
Self { query: e.args.first().map(|s| s.as_str()) }
}
}
impl Tab {
pub fn filter<'a>(&mut self, _opt: impl Into<Opt<'a>>) -> bool {
tokio::spawn(async move {
let rx = Input::_show(InputCfg::filter());
let rx = Debounce::new(UnboundedReceiverStream::new(rx), Duration::from_millis(50));
pin!(rx);
while let Some(Ok(s)) | Some(Err(InputError::Typed(s))) = rx.next().await {
emit!(Call(Exec::call("filter_do", vec![s]).vec(), Layer::Manager));
}
});
false
}
pub fn filter_do<'a>(&mut self, opt: impl Into<Opt<'a>>) -> bool {
let opt = opt.into() as Opt;
let Some(query) = opt.query else {
return false;
};
let hovered = &self.current.hovered().map(|f| f.url());
self.current.files.set_filter_keyword(query);
if let Some(hovered_url) = hovered {
match (self.current.files.position(hovered_url), self.current.files.first()) {
(Some(_), _) => {
self.current.hover(hovered_url);
}
(None, Some(first)) => {
self.current.hover(&first.url());
}
(_, _) => {}
}
}
true
}
}

View file

@ -4,6 +4,7 @@ mod cd;
mod copy;
mod enter;
mod escape;
mod filter;
mod find;
mod hidden;
mod jump;

View file

@ -152,6 +152,10 @@ impl<'a> Executor<'a> {
on!(ACTIVE, search);
on!(ACTIVE, jump);
// Filter
on!(ACTIVE, filter);
on!(ACTIVE, filter_do);
// Find
on!(ACTIVE, find);
on!(ACTIVE, find_do);