fix: inability to restore default cursor on Windows

This commit is contained in:
sxyazi 2024-01-05 11:41:24 +08:00
parent 43878fd92e
commit 3fcc2014bc
No known key found for this signature in database
12 changed files with 124 additions and 112 deletions

View File

@ -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<Url> 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<Step>) -> 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<impl AsRef<Url>>) -> 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<impl AsRef<Url>>) -> 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]
}

View File

@ -17,4 +17,5 @@ mod tab_swap;
mod tab_switch;
mod update_files;
mod update_mimetype;
mod update_pages;
mod yank;

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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<usize>,
only_if: Option<Url>,
}
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<Opt>, 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);
}
}

View File

@ -22,12 +22,7 @@ where
impl Tab {
pub fn arrow(&mut self, opt: impl Into<Opt>) {
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;
}

View File

@ -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());

View File

@ -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<Exec>, 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!(),
}
}
}

View File

@ -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);

View File

@ -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();
};

View File

@ -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)?)
}
}

View File

@ -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);
}