mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
..
This commit is contained in:
parent
4d01119981
commit
2bbe04fe5d
6 changed files with 132 additions and 16 deletions
12
Cargo.lock
generated
12
Cargo.lock
generated
|
|
@ -177,9 +177,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.21.3"
|
||||
version = "0.21.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53"
|
||||
checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
|
|
@ -1548,9 +1548,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.105"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360"
|
||||
checksum = "2cc66a619ed80bf7a0f6b17dd063a84b88f6dea1813737cf469aef1d081142c2"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
|
|
@ -1880,9 +1880,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.7.7"
|
||||
version = "0.7.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de0a3ab2091e52d7299a39d098e200114a972df0a7724add02a273aa9aada592"
|
||||
checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257"
|
||||
dependencies = [
|
||||
"indexmap 2.0.0",
|
||||
"serde",
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ impl<'a> Widget for Folder<'a> {
|
|||
|
||||
if let Some(idx) = active
|
||||
.finder()
|
||||
.filter(|_| hovered && self.is_find)
|
||||
.filter(|&f| hovered && self.is_find && f.has_matched())
|
||||
.and_then(|finder| finder.matched_idx(f.url()))
|
||||
{
|
||||
let len = active.finder().unwrap().matched().len();
|
||||
|
|
|
|||
|
|
@ -24,18 +24,54 @@ impl Finder {
|
|||
.take(cursor)
|
||||
.rev()
|
||||
.enumerate()
|
||||
.find(|(_, f)| f.name().map_or(false, |n| self.is_match(n)))
|
||||
.find(|(_, f)| f.name().map_or(false, |n| self.matches(n)))
|
||||
.map(|(i, _)| -(i as isize) - 1)
|
||||
} else {
|
||||
files
|
||||
.iter()
|
||||
.skip(cursor + 1)
|
||||
.enumerate()
|
||||
.find(|(_, f)| f.name().map_or(false, |n| self.is_match(n)))
|
||||
.find(|(_, f)| f.name().map_or(false, |n| self.matches(n)))
|
||||
.map(|(i, _)| i as isize + 1)
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn ring(&self, files: &Files, cursor: usize, prev: bool) -> Option<isize> {
|
||||
if prev {
|
||||
files
|
||||
.iter()
|
||||
.take(cursor + 1)
|
||||
.rev()
|
||||
.enumerate()
|
||||
.find(|(_, f)| f.name().map_or(false, |n| self.matches(n)))
|
||||
.map(|(i, _)| -(i as isize))
|
||||
.or_else(|| {
|
||||
files
|
||||
.iter()
|
||||
.skip(cursor + 1)
|
||||
.enumerate()
|
||||
.find(|(_, f)| f.name().map_or(false, |n| self.matches(n)))
|
||||
.map(|(i, _)| i as isize + 1)
|
||||
})
|
||||
} else {
|
||||
files
|
||||
.iter()
|
||||
.skip(cursor)
|
||||
.enumerate()
|
||||
.find(|(_, f)| f.name().map_or(false, |n| self.matches(n)))
|
||||
.map(|(i, _)| i as isize)
|
||||
.or_else(|| {
|
||||
files
|
||||
.iter()
|
||||
.take(cursor)
|
||||
.rev()
|
||||
.enumerate()
|
||||
.find(|(_, f)| f.name().map_or(false, |n| self.matches(n)))
|
||||
.map(|(i, _)| -(i as isize) - 1)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn catchup(&mut self, files: &Files) -> bool {
|
||||
if self.version == files.version() {
|
||||
return false;
|
||||
|
|
@ -44,7 +80,7 @@ impl Finder {
|
|||
|
||||
let mut i = 0u8;
|
||||
for file in files.iter() {
|
||||
if file.name().map(|n| self.is_match(n)) != Some(true) {
|
||||
if file.name().map(|n| self.matches(n)) != Some(true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -61,7 +97,7 @@ impl Finder {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn is_match(&self, name: &OsStr) -> bool {
|
||||
fn matches(&self, name: &OsStr) -> bool {
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
self.query.is_match(name.to_string_lossy().as_bytes())
|
||||
|
|
@ -78,12 +114,15 @@ impl Finder {
|
|||
#[inline]
|
||||
pub fn matched(&self) -> &BTreeMap<Url, u8> { &self.matched }
|
||||
|
||||
#[inline]
|
||||
pub fn has_matched(&self) -> bool { !self.matched.is_empty() }
|
||||
|
||||
#[inline]
|
||||
pub fn matched_idx(&self, url: &Url) -> Option<u8> {
|
||||
if let Some((_, &idx)) = self.matched.iter().find(|(u, _)| *u == url) {
|
||||
return Some(idx);
|
||||
}
|
||||
if url.file_name().map(|n| self.is_match(n)) == Some(true) {
|
||||
if url.file_name().map(|n| self.matches(n)) == Some(true) {
|
||||
return Some(100);
|
||||
}
|
||||
None
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::{borrow::Cow, collections::{BTreeMap, BTreeSet}, ffi::{OsStr, OsString}
|
|||
|
||||
use anyhow::{bail, Error, Result};
|
||||
use config::{keymap::{Exec, KeymapLayer}, open::Opener};
|
||||
use shared::{Defer, Url};
|
||||
use shared::{Debounce, Defer, InputError, Url};
|
||||
use tokio::{pin, task::JoinHandle};
|
||||
use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt};
|
||||
|
||||
|
|
@ -241,12 +241,25 @@ impl Tab {
|
|||
|
||||
pub fn find(&mut self, query: Option<&str>, prev: bool) -> bool {
|
||||
if let Some(query) = query {
|
||||
self.finder = Finder::new(query).ok();
|
||||
return self.find_arrow(prev);
|
||||
let Ok(finder) = Finder::new(query) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
if let Some(step) = finder.ring(&self.current.files, self.current.cursor(), prev) {
|
||||
self.arrow(step);
|
||||
}
|
||||
|
||||
self.finder = Some(finder);
|
||||
return true;
|
||||
}
|
||||
|
||||
tokio::spawn(async move {
|
||||
if let Some(Ok(s)) = emit!(Input(InputOpt::top("Find:"))).recv().await {
|
||||
let rx = emit!(Input(InputOpt::top("Find:").with_realtime()));
|
||||
|
||||
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("find", vec![s]).with_bool("previous", prev).vec(),
|
||||
KeymapLayer::Manager
|
||||
|
|
|
|||
62
shared/src/debounce.rs
Normal file
62
shared/src/debounce.rs
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
use std::{pin::Pin, task::{Context, Poll}, time::Duration};
|
||||
|
||||
use futures::{FutureExt, Stream, StreamExt};
|
||||
use tokio::time::{sleep, Instant, Sleep};
|
||||
|
||||
pub struct Debounce<S>
|
||||
where
|
||||
S: Stream,
|
||||
{
|
||||
stream: S,
|
||||
interval: Duration,
|
||||
|
||||
sleep: Sleep,
|
||||
last: Option<S::Item>,
|
||||
}
|
||||
|
||||
impl<S> Debounce<S>
|
||||
where
|
||||
S: Stream + Unpin,
|
||||
{
|
||||
pub fn new(stream: S, interval: Duration) -> Debounce<S> {
|
||||
Self { stream, interval, sleep: sleep(Duration::ZERO), last: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Stream for Debounce<S>
|
||||
where
|
||||
S: Stream + Unpin,
|
||||
{
|
||||
type Item = S::Item;
|
||||
|
||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
let (mut stream, interval, mut sleep, last) = unsafe {
|
||||
let me = self.get_unchecked_mut();
|
||||
(Pin::new(&mut me.stream), me.interval, Pin::new_unchecked(&mut me.sleep), &mut me.last)
|
||||
};
|
||||
|
||||
if sleep.poll_unpin(cx).is_ready() {
|
||||
if let Some(last) = last.take() {
|
||||
return Poll::Ready(Some(last));
|
||||
}
|
||||
}
|
||||
|
||||
while let Poll::Ready(next) = stream.poll_next_unpin(cx) {
|
||||
match next {
|
||||
Some(next) => {
|
||||
*last = Some(next);
|
||||
}
|
||||
None if last.is_none() => {
|
||||
return Poll::Ready(None);
|
||||
}
|
||||
None => {
|
||||
sleep.reset(Instant::now());
|
||||
return Poll::Pending;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sleep.reset(Instant::now() + interval);
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
#![allow(clippy::option_map_unit_fn)]
|
||||
|
||||
mod chars;
|
||||
mod debounce;
|
||||
mod defer;
|
||||
mod errors;
|
||||
mod fns;
|
||||
|
|
@ -13,6 +14,7 @@ mod time;
|
|||
mod url;
|
||||
|
||||
pub use chars::*;
|
||||
pub use debounce::*;
|
||||
pub use defer::*;
|
||||
pub use errors::*;
|
||||
pub use fns::*;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue