From 3fcc2014bc19f9f31a940ecff1d047d4e0e98a12 Mon Sep 17 00:00:00 2001 From: sxyazi Date: Fri, 5 Jan 2024 11:41:24 +0800 Subject: [PATCH] fix: inability to restore default cursor on Windows --- yazi-core/src/folder/folder.rs | 98 +++++++++---------- yazi-core/src/manager/commands/mod.rs | 1 + yazi-core/src/manager/commands/refresh.rs | 5 +- .../src/manager/commands/update_files.rs | 27 ++--- .../src/manager/commands/update_pages.rs | 50 ++++++++++ yazi-core/src/tab/commands/arrow.rs | 7 +- yazi-core/src/tab/tab.rs | 2 +- yazi-fm/src/app/app.rs | 21 +--- yazi-fm/src/executor.rs | 3 +- yazi-shared/src/event/event.rs | 7 -- yazi-shared/src/term/cursor.rs | 5 - yazi-shared/src/term/term.rs | 10 +- 12 files changed, 124 insertions(+), 112 deletions(-) create mode 100644 yazi-core/src/manager/commands/update_pages.rs diff --git a/yazi-core/src/folder/folder.rs b/yazi-core/src/folder/folder.rs index 4daa3e23..3c28dd27 100644 --- a/yazi-core/src/folder/folder.rs +++ b/yazi-core/src/folder/folder.rs @@ -1,10 +1,10 @@ -use std::time::SystemTime; +use std::{mem, time::SystemTime}; use ratatui::layout::Rect; use yazi_config::LAYOUT; -use yazi_shared::{emit, fs::{File, FilesOp, Url}}; +use yazi_shared::fs::{File, FilesOp, Url}; -use crate::{folder::Files, Step}; +use crate::{folder::Files, manager::Manager, Step}; #[derive(Default)] pub struct Folder { @@ -15,7 +15,8 @@ pub struct Folder { pub offset: usize, pub cursor: usize, - pub page: usize, + pub page: usize, + pub tracing: bool, } impl From for Folder { @@ -47,46 +48,57 @@ impl Folder { FilesOp::Upserting(_, files) => self.files.update_upserting(files), } - // TODO: use a better way to detect if the page is changed - let old = self.page; - self.prev(Default::default()); - - if self.page == old { - self.set_page(true); // Force update + self.arrow(0); + if self.files.is_empty() { + self.tracing = false; } self.files.revision != revision } - pub fn set_page(&mut self, force: bool) { + pub fn arrow(&mut self, step: impl Into) -> bool { + let step = step.into() as Step; + let b = if self.files.is_empty() { + (self.cursor, self.offset, self.tracing) = (0, 0, false); + false + } else if step.is_positive() { + self.next(step) + } else { + self.prev(step) + }; + + self.sync_page(false); + self.tracing |= b; + b + } + + pub fn hover(&mut self, url: &Url) -> bool { + if self.hovered().map(|h| &h.url) == Some(url) { + return false; + } + + let new = self.files.position(url).unwrap_or(self.cursor) as isize; + self.arrow(new - self.cursor as isize) + } + + #[inline] + pub fn repos(&mut self, url: Option>) -> bool { + if let Some(u) = url { self.hover(u.as_ref()) } else { self.arrow(0) } + } + + pub fn sync_page(&mut self, force: bool) { let limit = LAYOUT.load().current.height as usize; if limit == 0 { return; } let new = self.cursor / limit; - if !force && self.page == new { - return; + if mem::replace(&mut self.page, new) != new || force { + Manager::_update_pages_by(new, &self.cwd); } - - // Current page - emit!(Pages(new)); - - // Next page - let max_page = (self.files.len() + limit - 1) / limit; - if new < max_page && new + 1 != self.page { - emit!(Pages(new + 1)); - } - - // Previous page - if new > 1 && new - 1 != self.page { - emit!(Pages(new - 1)); - } - - self.page = new; } - pub fn next(&mut self, step: Step) -> bool { + fn next(&mut self, step: Step) -> bool { let old = (self.cursor, self.offset); let len = self.files.len(); @@ -98,11 +110,10 @@ impl Folder { self.offset.min(len.saturating_sub(1)) }; - self.set_page(false); old != (self.cursor, self.offset) } - pub fn prev(&mut self, step: Step) -> bool { + fn prev(&mut self, step: Step) -> bool { let old = (self.cursor, self.offset); let max = self.files.len().saturating_sub(1); @@ -113,27 +124,8 @@ impl Folder { self.offset.min(max) }; - self.set_page(false); old != (self.cursor, self.offset) } - - pub fn hover(&mut self, url: &Url) -> bool { - if self.hovered().map(|h| &h.url) == Some(url) { - return false; - } - - let new = self.files.position(url).unwrap_or(self.cursor); - if new > self.cursor { - self.next(Step::next(new - self.cursor)) - } else { - self.prev(Step::prev(self.cursor - new)) - } - } - - #[inline] - pub fn repos(&mut self, url: Option>) -> bool { - if let Some(u) = url { self.hover(u.as_ref()) } else { self.prev(Default::default()) } - } } impl Folder { @@ -144,8 +136,8 @@ impl Folder { let len = self.files.len(); let limit = LAYOUT.load().current.height as usize; - let start = (page * limit).min(len.saturating_sub(1)); - let end = (start + limit).min(len); + let start = (page.saturating_sub(1) * limit).min(len.saturating_sub(1)); + let end = ((page + 2) * limit).min(len); &self.files[start..end] } diff --git a/yazi-core/src/manager/commands/mod.rs b/yazi-core/src/manager/commands/mod.rs index 72cef281..7966ee2d 100644 --- a/yazi-core/src/manager/commands/mod.rs +++ b/yazi-core/src/manager/commands/mod.rs @@ -17,4 +17,5 @@ mod tab_swap; mod tab_switch; mod update_files; mod update_mimetype; +mod update_pages; mod yank; diff --git a/yazi-core/src/manager/commands/refresh.rs b/yazi-core/src/manager/commands/refresh.rs index ee91f8fe..ab455d2f 100644 --- a/yazi-core/src/manager/commands/refresh.rs +++ b/yazi-core/src/manager/commands/refresh.rs @@ -2,7 +2,7 @@ use std::env; use yazi_shared::{emit, event::Exec, Layer}; -use crate::manager::Manager; +use crate::{manager::Manager, tasks::Tasks}; impl Manager { #[inline] @@ -10,7 +10,7 @@ impl Manager { emit!(Call(Exec::call("refresh", vec![]).vec(), Layer::Manager)); } - pub fn refresh(&mut self, _: &Exec) { + pub fn refresh(&mut self, _: &Exec, tasks: &Tasks) { env::set_current_dir(self.cwd()).ok(); env::set_var("PWD", self.cwd()); @@ -23,5 +23,6 @@ impl Manager { } self.hover(None); + self.update_pages((), tasks); } } diff --git a/yazi-core/src/manager/commands/update_files.rs b/yazi-core/src/manager/commands/update_files.rs index 6f165af9..7a7aafce 100644 --- a/yazi-core/src/manager/commands/update_files.rs +++ b/yazi-core/src/manager/commands/update_files.rs @@ -19,7 +19,6 @@ impl Manager { if let Some(p) = self.active_mut().parent.as_mut() { render!(p.update(op)); - render!(p.files.catchup_revision()); render!(p.hover(&cwd)); } @@ -29,16 +28,15 @@ impl Manager { } fn update_current(&mut self, op: FilesOp, tasks: &Tasks) { - let hovered = self.hovered().map(|h| h.url()); + let hovered = self.hovered().filter(|_| self.current().tracing).map(|h| h.url()); let calc = !matches!(op, FilesOp::Size(..) | FilesOp::Deleting(..)); - render!(self.current_mut().update(op)); - render!(self.current_mut().files.catchup_revision()); - render!(hovered.as_ref().is_some_and(|h| self.current_mut().hover(h))); - - if hovered.as_ref() != self.hovered().map(|h| &h.url) { - self.hover(None); + if self.current_mut().update(op) { + self.current_mut().repos(hovered.as_ref()); + Self::_hover(None); // Re-hover in next loop + Self::_update_pages(); // Update for paged files in next loop } + if calc { tasks.preload_sorted(&self.current().files); } @@ -46,18 +44,9 @@ impl Manager { fn update_hovered(&mut self, op: FilesOp) { let url = op.url(); - let folder = match self.active_mut().history.get_mut(url) { - Some(f) => f, - None => { - let f = Folder::from(url); - self.active_mut().history.insert(url.clone(), f); - self.active_mut().apply_files_attrs(); - self.active_mut().history.get_mut(url).unwrap() - } - }; + let folder = self.active_mut().history.entry(url.clone()).or_insert_with(|| Folder::from(url)); if folder.update(op) { - folder.files.catchup_revision(); self.peek(true); } } @@ -97,5 +86,7 @@ impl Manager { self.update_history(op); } } + + self.active_mut().apply_files_attrs(); } } diff --git a/yazi-core/src/manager/commands/update_pages.rs b/yazi-core/src/manager/commands/update_pages.rs new file mode 100644 index 00000000..12c8a413 --- /dev/null +++ b/yazi-core/src/manager/commands/update_pages.rs @@ -0,0 +1,50 @@ +use yazi_shared::{emit, event::Exec, fs::Url, Layer}; + +use crate::{manager::Manager, tasks::Tasks}; + +#[derive(Default)] +pub struct Opt { + page: Option, + only_if: Option, +} + +impl From<&Exec> for Opt { + fn from(e: &Exec) -> Self { + Self { + page: e.args.first().and_then(|s| s.parse().ok()), + only_if: e.named.get("only-if").map(Url::from), + } + } +} + +impl From<()> for Opt { + fn from(_: ()) -> Self { Self::default() } +} + +impl Manager { + #[inline] + pub fn _update_pages() { + emit!(Call(Exec::call("update_pages", vec![]).vec(), Layer::Manager)); + } + + #[inline] + pub fn _update_pages_by(page: usize, only_if: &Url) { + emit!(Call( + Exec::call("update_pages", vec![page.to_string()]).with("only-if", only_if.to_string()).vec(), + Layer::Manager + )); + } + + pub fn update_pages(&mut self, opt: impl TryInto, tasks: &Tasks) { + let Ok(opt) = opt.try_into() else { + return; + }; + + if opt.only_if.is_some_and(|u| u != self.current().cwd) { + return; + } + + let targets = self.current().paginate(opt.page.unwrap_or(self.current().page)); + tasks.preload_paged(targets, &self.mimetype); + } +} diff --git a/yazi-core/src/tab/commands/arrow.rs b/yazi-core/src/tab/commands/arrow.rs index 37c6f492..e7512ef5 100644 --- a/yazi-core/src/tab/commands/arrow.rs +++ b/yazi-core/src/tab/commands/arrow.rs @@ -22,12 +22,7 @@ where impl Tab { pub fn arrow(&mut self, opt: impl Into) { let opt = opt.into() as Opt; - let ok = if opt.step.is_positive() { - self.current.next(opt.step) - } else { - self.current.prev(opt.step) - }; - if !ok { + if !self.current.arrow(opt.step) { return; } diff --git a/yazi-core/src/tab/tab.rs b/yazi-core/src/tab/tab.rs index 071bf15c..272c9b6e 100644 --- a/yazi-core/src/tab/tab.rs +++ b/yazi-core/src/tab/tab.rs @@ -74,7 +74,7 @@ impl Tab { pub fn apply_files_attrs(&mut self) { let apply = |f: &mut Folder| { - let hovered = f.hovered().map(|h| h.url()); + let hovered = f.hovered().filter(|_| f.tracing).map(|h| h.url()); f.files.set_show_hidden(self.conf.show_hidden); f.files.set_sorter(self.conf.sorter()); diff --git a/yazi-fm/src/app/app.rs b/yazi-fm/src/app/app.rs index 5ccacb42..2288f3be 100644 --- a/yazi-fm/src/app/app.rs +++ b/yazi-fm/src/app/app.rs @@ -1,4 +1,4 @@ -use std::sync::atomic::Ordering; +use std::{mem, sync::atomic::Ordering}; use anyhow::{Ok, Result}; use crossterm::event::KeyEvent; @@ -37,14 +37,12 @@ impl App { Event::Paste(str) => app.dispatch_paste(str), Event::Quit(no_cwd_file) => { app.quit(no_cwd_file)?; - break; + return Ok(()); } - event => app.dispatch_module(event), } } - if render_in_place { - render_in_place = false; + if mem::replace(&mut render_in_place, false) { app.render()?; } @@ -71,7 +69,7 @@ impl App { self.cx.manager.active_mut().preview.reset(); self.render()?; - self.cx.manager.current_mut().set_page(true); + self.cx.manager.current_mut().sync_page(true); self.cx.manager.peek(false); Ok(()) } @@ -80,15 +78,4 @@ impl App { fn dispatch_call(&mut self, exec: Vec, layer: Layer) { Executor::new(self).dispatch(&exec, layer); } - - fn dispatch_module(&mut self, event: Event) { - let tasks = &mut self.cx.tasks; - match event { - Event::Pages(page) => { - let targets = self.cx.manager.current().paginate(page); - tasks.preload_paged(targets, &self.cx.manager.mimetype); - } - _ => unreachable!(), - } - } } diff --git a/yazi-fm/src/executor.rs b/yazi-fm/src/executor.rs index 2a3fc366..69bc042c 100644 --- a/yazi-fm/src/executor.rs +++ b/yazi-fm/src/executor.rs @@ -108,10 +108,11 @@ impl<'a> Executor<'a> { on!(MANAGER, update_files, &self.app.cx.tasks); on!(MANAGER, update_mimetype, &self.app.cx.tasks); + on!(MANAGER, update_pages, &self.app.cx.tasks); on!(MANAGER, hover); on!(MANAGER, peek); on!(MANAGER, seek); - on!(MANAGER, refresh); + on!(MANAGER, refresh, &self.app.cx.tasks); on!(MANAGER, quit, &self.app.cx.tasks); on!(MANAGER, close, &self.app.cx.tasks); on!(MANAGER, suspend); diff --git a/yazi-shared/src/event/event.rs b/yazi-shared/src/event/event.rs index 1cc2223f..a71d2a55 100644 --- a/yazi-shared/src/event/event.rs +++ b/yazi-shared/src/event/event.rs @@ -14,9 +14,6 @@ pub enum Event { Resize(u16, u16), Paste(String), Quit(bool), // no-cwd-file - - // Manager - Pages(usize), } impl Event { @@ -41,10 +38,6 @@ macro_rules! emit { $crate::event::Event::Call($exec, $layer).emit(); }; - (Pages($page:expr)) => { - $crate::event::Event::Pages($page).emit(); - }; - ($event:ident) => { $crate::event::Event::$event.emit(); }; diff --git a/yazi-shared/src/term/cursor.rs b/yazi-shared/src/term/cursor.rs index caac4169..94d0a5ae 100644 --- a/yazi-shared/src/term/cursor.rs +++ b/yazi-shared/src/term/cursor.rs @@ -49,9 +49,4 @@ impl Term { #[inline] pub fn set_cursor_bar() -> Result<()> { Ok(execute!(stdout(), SetCursorStyle::BlinkingBar)?) } - - #[inline] - pub fn set_cursor_default() -> Result<()> { - Ok(execute!(stdout(), SetCursorStyle::DefaultUserShape)?) - } } diff --git a/yazi-shared/src/term/term.rs b/yazi-shared/src/term/term.rs index 86d6f683..d4ee2437 100644 --- a/yazi-shared/src/term/term.rs +++ b/yazi-shared/src/term/term.rs @@ -37,9 +37,14 @@ impl Term { execute!(stdout(), PopKeyboardEnhancementFlags)?; } - execute!(stdout(), DisableFocusChange, DisableBracketedPaste, LeaveAlternateScreen)?; + execute!( + stdout(), + DisableFocusChange, + DisableBracketedPaste, + LeaveAlternateScreen, + crossterm::cursor::SetCursorStyle::DefaultUserShape + )?; - Self::set_cursor_default()?; self.show_cursor()?; Ok(disable_raw_mode()?) } @@ -55,6 +60,7 @@ impl Term { crossterm::cursor::Show, ) .ok(); + disable_raw_mode().ok(); std::process::exit(f() as i32); }