diff --git a/yazi-core/src/folder/files.rs b/yazi-core/src/folder/files.rs index 535341d4..24d744e1 100644 --- a/yazi-core/src/folder/files.rs +++ b/yazi-core/src/folder/files.rs @@ -391,6 +391,9 @@ impl Files { } // --- Filter + #[inline] + pub fn filter(&self) -> Option<&Filter> { self.filter.as_ref() } + pub fn set_filter(&mut self, filter: Option) -> bool { if self.filter == filter { return false; diff --git a/yazi-core/src/help/help.rs b/yazi-core/src/help/help.rs index 5028529c..d4741b25 100644 --- a/yazi-core/src/help/help.rs +++ b/yazi-core/src/help/help.rs @@ -54,23 +54,27 @@ impl Help { true } - pub fn type_(&mut self, key: &Key) { + pub fn type_(&mut self, key: &Key) -> bool { let Some(input) = &mut self.in_filter else { - return; + return false; }; if key.is_enter() { self.in_filter = None; - return render!(); + render!(); + return true; } match &key { Key { code: KeyCode::Backspace, shift: false, ctrl: false, alt: false } => { - input.backspace(false) + input.backspace(false); + } + _ => { + input.type_(key); } - _ => input.type_(key), } self.filter_apply(); + true } } diff --git a/yazi-core/src/input/commands/delete.rs b/yazi-core/src/input/commands/delete.rs index c60a99fd..4101bf5d 100644 --- a/yazi-core/src/input/commands/delete.rs +++ b/yazi-core/src/input/commands/delete.rs @@ -1,4 +1,4 @@ -use yazi_shared::event::Exec; +use yazi_shared::{event::Exec, render}; use crate::input::{op::InputOp, Input}; @@ -22,10 +22,8 @@ impl Input { } InputOp::Select(start) => { self.snap_mut().op = InputOp::Delete(opt.cut, opt.insert, start); - // TODO: render - todo!(); - // return self.handle_op(self.snap().cursor, true).then(|| - // self.move_(0)).is_some(); + render!(self.handle_op(self.snap().cursor, true)); + self.move_(0); } InputOp::Delete(..) => { self.snap_mut().op = InputOp::Delete(opt.cut, opt.insert, 0); diff --git a/yazi-core/src/input/commands/escape.rs b/yazi-core/src/input/commands/escape.rs index 59d4dc62..ad713e22 100644 --- a/yazi-core/src/input/commands/escape.rs +++ b/yazi-core/src/input/commands/escape.rs @@ -30,6 +30,7 @@ impl Input { } } } + self.snaps.tag(self.limit()); render!(); } diff --git a/yazi-core/src/input/commands/type_.rs b/yazi-core/src/input/commands/type_.rs index 306f847e..81c88b25 100644 --- a/yazi-core/src/input/commands/type_.rs +++ b/yazi-core/src/input/commands/type_.rs @@ -1,5 +1,5 @@ use yazi_config::keymap::Key; -use yazi_shared::{event::Exec, render}; +use yazi_shared::event::Exec; use crate::input::{Input, InputMode}; @@ -10,14 +10,16 @@ impl From<&Exec> for Opt { } impl Input { - pub fn type_(&mut self, key: &Key) { + pub fn type_(&mut self, key: &Key) -> bool { if self.mode() != InputMode::Insert { - return; + return false; } if let Some(c) = key.plain() { - let mut bits = [0; 4]; - render!(self.type_str(c.encode_utf8(&mut bits))); + self.type_str(c.encode_utf8(&mut [0; 4])); + return true; } + + false } } diff --git a/yazi-core/src/input/commands/yank.rs b/yazi-core/src/input/commands/yank.rs index 3cea620f..7ae6ebb4 100644 --- a/yazi-core/src/input/commands/yank.rs +++ b/yazi-core/src/input/commands/yank.rs @@ -1,4 +1,4 @@ -use yazi_shared::event::Exec; +use yazi_shared::{event::Exec, render}; use crate::input::{op::InputOp, Input}; @@ -10,10 +10,8 @@ impl Input { } InputOp::Select(start) => { self.snap_mut().op = InputOp::Yank(start); - // TODO: render - todo!(); - // return self.handle_op(self.snap().cursor, true).then(|| - // self.move_(0)).is_some(); + render!(self.handle_op(self.snap().cursor, true)); + self.move_(0); } InputOp::Yank(_) => { self.snap_mut().op = InputOp::Yank(0); diff --git a/yazi-core/src/input/input.rs b/yazi-core/src/input/input.rs index 862ac3f4..91ce3484 100644 --- a/yazi-core/src/input/input.rs +++ b/yazi-core/src/input/input.rs @@ -3,7 +3,7 @@ use std::ops::Range; use tokio::sync::mpsc::UnboundedSender; use unicode_width::UnicodeWidthStr; use yazi_config::{popup::Position, INPUT}; -use yazi_shared::InputError; +use yazi_shared::{render, InputError}; use super::{mode::InputMode, op::InputOp, InputSnap, InputSnaps}; use crate::CLIPBOARD; @@ -32,7 +32,7 @@ impl Input { self.position.offset.width.saturating_sub(INPUT.border()) as usize } - pub fn type_str(&mut self, s: &str) -> bool { + pub fn type_str(&mut self, s: &str) { let snap = self.snaps.current_mut(); if snap.cursor < 1 { snap.value.insert_str(0, s); @@ -42,7 +42,7 @@ impl Input { self.move_(s.chars().count() as isize); self.flush_value(); - true + render!(); } pub(super) fn handle_op(&mut self, cursor: usize, include: bool) -> bool { diff --git a/yazi-core/src/manager/commands/peek.rs b/yazi-core/src/manager/commands/peek.rs index 92873393..8bb8ffa1 100644 --- a/yazi-core/src/manager/commands/peek.rs +++ b/yazi-core/src/manager/commands/peek.rs @@ -35,15 +35,15 @@ impl Manager { return render!(self.active_mut().preview.reset()); }; - let opt = opt.into() as Opt; - if matches!(opt.only_if, Some(ref u) if *u != hovered.url) { - return; - } - let hovered = hovered.clone(); if !self.active().preview.same_url(&hovered.url) { self.active_mut().preview.skip = 0; - self.active_mut().preview.reset(); + render!(self.active_mut().preview.reset()); + } + + let opt = opt.into() as Opt; + if matches!(opt.only_if, Some(ref u) if *u != hovered.url) { + return; } if let Some(skip) = opt.skip { diff --git a/yazi-core/src/tab/commands/escape.rs b/yazi-core/src/tab/commands/escape.rs index ba3ac6e6..052443aa 100644 --- a/yazi-core/src/tab/commands/escape.rs +++ b/yazi-core/src/tab/commands/escape.rs @@ -42,20 +42,20 @@ impl Tab { } #[inline] - fn escape_select(&mut self) -> bool { self.current.files.select_all(None) } + fn escape_select(&mut self) -> bool { self.current.files.select_all(Some(false)) } #[inline] fn escape_filter(&mut self) -> bool { - // TODO: render - todo!(); - // self.filter_do(super::filter::Opt { query: "", ..Default::default() }) + let b = self.current.files.filter().is_some(); + self.filter_do(super::filter::Opt { query: "", ..Default::default() }); + b } #[inline] fn escape_search(&mut self) -> bool { + let b = self.current.cwd.is_search(); self.search_stop(); - // TODO: render - false + b } pub fn escape(&mut self, opt: impl Into) { diff --git a/yazi-core/src/tab/commands/select.rs b/yazi-core/src/tab/commands/select.rs index 328432d1..0170f0d5 100644 --- a/yazi-core/src/tab/commands/select.rs +++ b/yazi-core/src/tab/commands/select.rs @@ -9,9 +9,9 @@ pub struct Opt { impl From<&Exec> for Opt { fn from(e: &Exec) -> Self { Self { - state: match e.named.get("state").map(|s| s.as_bytes()) { - Some(b"true") => Some(true), - Some(b"false") => Some(false), + state: match e.named.get("state").map(|s| s.as_str()) { + Some("true") => Some(true), + Some("false") => Some(false), _ => None, }, } diff --git a/yazi-fm/src/app/app.rs b/yazi-fm/src/app/app.rs index 47e840c1..15059a7b 100644 --- a/yazi-fm/src/app/app.rs +++ b/yazi-fm/src/app/app.rs @@ -1,8 +1,10 @@ +use std::sync::atomic::Ordering; + use anyhow::{Ok, Result}; use crossterm::event::KeyEvent; -use yazi_config::{keymap::Key, ARGS}; +use yazi_config::keymap::Key; use yazi_core::input::InputMode; -use yazi_shared::{event::{Event, Exec}, render, term::Term, Layer}; +use yazi_shared::{event::{Event, Exec, NEED_RENDER}, term::Term, Layer}; use crate::{lives::Lives, Ctx, Executor, Logs, Panic, Signals}; @@ -16,47 +18,44 @@ impl App { pub(crate) async fn run() -> Result<()> { Panic::install(); let _log = Logs::init()?; - let term = Term::start()?; let signals = Signals::start()?; Lives::register()?; let mut app = Self { cx: Ctx::make(), term: Some(term), signals }; - app.render()?; - while let Some(event) = app.signals.recv().await { - match event { - Event::Quit(no_cwd_file) => { - app.dispatch_quit(no_cwd_file); - break; + + let mut events = Vec::with_capacity(10); + while app.signals.rx.recv_many(&mut events, 10).await > 0 { + for event in events.drain(..) { + match event { + Event::Quit(no_cwd_file) => { + app.quit(no_cwd_file)?; + break; + } + Event::Key(key) => app.dispatch_key(key), + Event::Paste(str) => app.dispatch_paste(str), + Event::Resize(cols, rows) => app.dispatch_resize(cols, rows)?, + Event::Call(exec, layer) => app.dispatch_call(exec, layer), + event => app.dispatch_module(event), } - Event::Key(key) => app.dispatch_key(key), - Event::Paste(str) => app.dispatch_paste(str), - // TODO: render - // Event::Render(_) => app.render()?, - Event::Resize(cols, rows) => app.dispatch_resize(cols, rows)?, - Event::Call(exec, layer) => app.dispatch_call(exec, layer), - event => app.dispatch_module(event), + } + + if NEED_RENDER.swap(false, Ordering::Relaxed) { + app.render()?; } } Ok(()) } - fn dispatch_quit(&mut self, no_cwd_file: bool) { - if let Some(p) = ARGS.cwd_file.as_ref().filter(|_| !no_cwd_file) { - let cwd = self.cx.manager.cwd().as_os_str(); - std::fs::write(p, cwd.as_encoded_bytes()).ok(); - } - Term::goodbye(|| false); - } - + #[inline] fn dispatch_key(&mut self, key: KeyEvent) { Executor::new(self).handle(Key::from(key)); } fn dispatch_paste(&mut self, str: String) { if self.cx.input.visible { let input = &mut self.cx.input; - if input.mode() == InputMode::Insert && input.type_str(&str) { - render!(); + if input.mode() == InputMode::Insert { + input.type_str(&str); } } } diff --git a/yazi-fm/src/app/commands/mod.rs b/yazi-fm/src/app/commands/mod.rs index c12ef5df..f5d96232 100644 --- a/yazi-fm/src/app/commands/mod.rs +++ b/yazi-fm/src/app/commands/mod.rs @@ -1,3 +1,4 @@ mod plugin; +mod quit; mod render; mod stop; diff --git a/yazi-fm/src/app/commands/quit.rs b/yazi-fm/src/app/commands/quit.rs new file mode 100644 index 00000000..758f5036 --- /dev/null +++ b/yazi-fm/src/app/commands/quit.rs @@ -0,0 +1,26 @@ +use anyhow::Result; +use yazi_config::ARGS; +use yazi_shared::term::Term; + +use crate::app::App; + +pub struct Opt { + no_cwd_file: bool, +} + +impl From for Opt { + fn from(no_cwd_file: bool) -> Self { Self { no_cwd_file } } +} + +impl App { + pub(crate) fn quit(&mut self, opt: impl Into) -> Result<()> { + let opt = opt.into() as Opt; + + if let Some(p) = ARGS.cwd_file.as_ref().filter(|_| !opt.no_cwd_file) { + let cwd = self.cx.manager.cwd().as_os_str(); + std::fs::write(p, cwd.as_encoded_bytes()).ok(); + } + + Term::goodbye(|| false); + } +} diff --git a/yazi-fm/src/executor.rs b/yazi-fm/src/executor.rs index a28c2534..dd1b8bce 100644 --- a/yazi-fm/src/executor.rs +++ b/yazi-fm/src/executor.rs @@ -18,14 +18,12 @@ impl<'a> Executor<'a> { if cx.which.visible { return cx.which.press(key); } - // TODO: render - // if cx.help.visible && cx.help.type_(&key) { - // return true; - // } - // TODO: render - // if cx.input.visible && cx.input.type_(&key) { - // return true; - // } + if cx.help.visible && cx.help.type_(&key) { + return true; + } + if cx.input.visible && cx.input.type_(&key) { + return true; + } if cx.completion.visible { self.matches(Layer::Completion, key) || self.matches(Layer::Input, key) diff --git a/yazi-fm/src/signals.rs b/yazi-fm/src/signals.rs index 450eeda4..17fdfda1 100644 --- a/yazi-fm/src/signals.rs +++ b/yazi-fm/src/signals.rs @@ -5,8 +5,8 @@ use tokio::{select, sync::{mpsc::{self, UnboundedReceiver, UnboundedSender}, one use yazi_shared::event::Event; pub(super) struct Signals { - tx: UnboundedSender, - rx: UnboundedReceiver, + tx: UnboundedSender, + pub(super) rx: UnboundedReceiver, term_stop_tx: Option>, term_stop_rx: Option>, @@ -27,9 +27,6 @@ impl Signals { Ok(signals) } - #[inline] - pub(super) async fn recv(&mut self) -> Option { self.rx.recv().await } - pub(super) fn stop_term(&mut self, state: bool) { if state == self.term_stop_tx.is_none() { return;