From 5c336608db98a5d48803ab524aa194b5dce88c14 Mon Sep 17 00:00:00 2001 From: sxyazi Date: Sun, 1 Oct 2023 13:04:53 +0800 Subject: [PATCH] simplify the code --- app/src/app.rs | 4 +- app/src/executor.rs | 2 +- core/src/event.rs | 6 +-- core/src/manager/backstack.rs | 69 +++++++++++++++++++++-------------- core/src/manager/tab.rs | 28 ++++++-------- cspell.json | 2 +- 6 files changed, 60 insertions(+), 51 deletions(-) diff --git a/app/src/app.rs b/app/src/app.rs index 4be52693..761d0917 100644 --- a/app/src/app.rs +++ b/app/src/app.rs @@ -119,9 +119,9 @@ impl App { let manager = &mut self.cx.manager; let tasks = &mut self.cx.tasks; match event { - Event::Cd(url, backstack_push) => { + Event::Cd(url) => { futures::executor::block_on(async { - manager.active_mut().cd(expand_url(url), backstack_push).await; + manager.active_mut().cd(expand_url(url)).await; }); } Event::Refresh => { diff --git a/app/src/executor.rs b/app/src/executor.rs index c617cd2d..d4dd0b21 100644 --- a/app/src/executor.rs +++ b/app/src/executor.rs @@ -78,7 +78,7 @@ impl Executor { if exec.named.contains_key("interactive") { cx.manager.active_mut().cd_interactive(url) } else { - emit!(Cd(url, true)); + emit!(Cd(url)); false } } diff --git a/core/src/event.rs b/core/src/event.rs index 3aab3c37..5537c50a 100644 --- a/core/src/event.rs +++ b/core/src/event.rs @@ -21,7 +21,7 @@ pub enum Event { Call(Vec, KeymapLayer), // Manager - Cd(Url, bool), + Cd(Url), Refresh, Files(FilesOp), Pages(usize), @@ -71,8 +71,8 @@ macro_rules! emit { $crate::Event::Call($exec, $layer).emit(); }; - (Cd($url:expr, $backstack_push:expr)) => { - $crate::Event::Cd($url, $backstack_push).emit(); + (Cd($url:expr)) => { + $crate::Event::Cd($url).emit(); }; (Files($op:expr)) => { $crate::Event::Files($op).emit(); diff --git a/core/src/manager/backstack.rs b/core/src/manager/backstack.rs index bf2681ea..358fa678 100644 --- a/core/src/manager/backstack.rs +++ b/core/src/manager/backstack.rs @@ -1,36 +1,51 @@ -pub struct BackStack { - current: usize, - stack: Vec, +pub struct BackStack { + cursor: usize, + stack: Vec, } -impl BackStack { - pub fn new(item: T) -> Self { Self { current: 0, stack: vec![item] } } +impl BackStack { + pub fn new(item: T) -> Self { Self { cursor: 0, stack: vec![item] } } + + pub fn push(&mut self, item: T) { + if self.stack[self.cursor] == item { + return; + } + + self.cursor += 1; + if self.cursor == self.stack.len() { + self.stack.push(item); + } else { + self.stack[self.cursor] = item; + self.stack.truncate(self.cursor + 1); + } + + // Only keep 30 items before the cursor, the cleanup threshold is 60 + if self.stack.len() > 60 { + let start = self.cursor.saturating_sub(30); + self.stack.drain(..start); + self.cursor -= start; + } + } + + #[inline] + #[cfg(test)] + pub fn current(&self) -> &T { &self.stack[self.cursor] } pub fn shift_backward(&mut self) -> Option<&T> { - if self.current > 0 { - self.current -= 1; - Some(&self.stack[self.current]) + if self.cursor > 0 { + self.cursor -= 1; + Some(&self.stack[self.cursor]) } else { None } } pub fn shift_forward(&mut self) -> Option<&T> { - if self.current + 1 == self.stack.len() { + if self.cursor + 1 == self.stack.len() { None } else { - self.current += 1; - Some(&self.stack[self.current]) - } - } - - pub fn push(&mut self, item: T) { - self.current += 1; - if self.current == self.stack.len() { - self.stack.push(item); - } else { - self.stack[self.current] = item; - self.stack.truncate(self.current + 1); + self.cursor += 1; + Some(&self.stack[self.cursor]) } } } @@ -39,22 +54,20 @@ impl BackStack { mod tests { use super::*; - fn get_current(backstack: &BackStack) -> &T { &backstack.stack[backstack.current] } - #[test] fn test_backstack() { - let mut backstack = BackStack::::new(1); - assert_eq!(get_current(&backstack), &1); + let mut backstack = BackStack::::new(1); + assert_eq!(backstack.current(), &1); backstack.push(2); backstack.push(3); - assert_eq!(get_current(&backstack), &3); + assert_eq!(backstack.current(), &3); assert_eq!(backstack.shift_backward(), Some(&2)); assert_eq!(backstack.shift_backward(), Some(&1)); assert_eq!(backstack.shift_backward(), None); assert_eq!(backstack.shift_backward(), None); - assert_eq!(get_current(&backstack), &1); + assert_eq!(backstack.current(), &1); assert_eq!(backstack.shift_forward(), Some(&2)); assert_eq!(backstack.shift_forward(), Some(&3)); assert_eq!(backstack.shift_forward(), None); @@ -62,7 +75,7 @@ mod tests { backstack.shift_backward(); backstack.push(4); - assert_eq!(get_current(&backstack), &4); + assert_eq!(backstack.current(), &4); assert_eq!(backstack.shift_forward(), None); assert_eq!(backstack.shift_backward(), Some(&2)); } diff --git a/core/src/manager/tab.rs b/core/src/manager/tab.rs index f6e996ec..d14e0f30 100644 --- a/core/src/manager/tab.rs +++ b/core/src/manager/tab.rs @@ -89,7 +89,8 @@ impl Tab { true } - pub async fn cd(&mut self, mut target: Url, backstack_push: bool) -> bool { + // TODO: change to sync, and remove `Event::Cd` + pub async fn cd(&mut self, mut target: Url) -> bool { let Ok(file) = File::from(target.clone()).await else { return false; }; @@ -111,14 +112,11 @@ impl Tab { self.history.insert(rep.cwd.clone(), rep); } - if backstack_push { - self.backstack.push(target.clone()); - } - let rep = self.history_new(&target); let rep = mem::replace(&mut self.current, rep); if rep.cwd.is_regular() { self.history.insert(rep.cwd.clone(), rep); + self.backstack.push(target.clone()); } if let Some(parent) = target.parent_url() { @@ -138,7 +136,7 @@ impl Tab { emit!(Input(InputOpt::top("Change directory:").with_value(target.to_string_lossy()))); if let Some(Ok(s)) = result.recv().await { - emit!(Cd(Url::from(s), true)); + emit!(Cd(Url::from(s))); } }); false @@ -156,6 +154,7 @@ impl Tab { let rep = mem::replace(&mut self.current, rep); if rep.cwd.is_regular() { self.history.insert(rep.cwd.clone(), rep); + self.backstack.push(self.current.cwd.clone()); } if let Some(rep) = self.parent.take() { @@ -163,8 +162,6 @@ impl Tab { } self.parent = Some(self.history_new(&hovered.parent().unwrap())); - self.backstack.push(self.current.cwd.clone()); - emit!(Refresh); true } @@ -193,24 +190,23 @@ impl Tab { let rep = mem::replace(&mut self.current, rep); if rep.cwd.is_regular() { self.history.insert(rep.cwd.clone(), rep); + self.backstack.push(self.current.cwd.clone()); } - self.backstack.push(self.current.cwd.clone()); - emit!(Refresh); true } pub fn back(&mut self) -> bool { - if let Some(url) = self.backstack.shift_backward() { - emit!(Cd(url.clone(), false)); + if let Some(url) = self.backstack.shift_backward().cloned() { + futures::executor::block_on(self.cd(url)); } false } pub fn forward(&mut self) -> bool { - if let Some(url) = self.backstack.shift_forward() { - emit!(Cd(url.clone(), false)); + if let Some(url) = self.backstack.shift_forward().cloned() { + futures::executor::block_on(self.cd(url)); } false } @@ -327,7 +323,7 @@ impl Tab { let mut first = true; while let Some(chunk) = rx.next().await { if first { - emit!(Cd(cwd.clone(), true)); + emit!(Cd(cwd.clone())); first = false; } emit!(Files(FilesOp::Part(cwd.clone(), ticket, chunk))); @@ -363,7 +359,7 @@ impl Tab { if global { external::fzf(FzfOpt { cwd }) } else { external::zoxide(ZoxideOpt { cwd }) }?; if let Ok(target) = rx.await? { - emit!(Cd(target, true)); + emit!(Cd(target)); } Ok::<(), Error>(()) }); diff --git a/cspell.json b/cspell.json index d6760f99..3b0031ae 100644 --- a/cspell.json +++ b/cspell.json @@ -1 +1 @@ -{"language":"en","words":["Punct","KEYMAP","splitn","crossterm","YAZI","unar","peekable","ratatui","syntect","pbpaste","pbcopy","ffmpegthumbnailer","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","nvim","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp","️ Überzug","️ Überzug","Konsole","Alacritty","Überzug","pkgs","paru","unarchiver","pdftoppm","poppler","prebuild","singlefile","jpegopt","EXIF","rustfmt","mktemp","nanos","xclip","xsel","natord","Mintty","nixos","nixpkgs","SIGTSTP","SIGCONT","SIGCONT"],"version":"0.2","flagWords":[]} +{"version":"0.2","words":["Punct","KEYMAP","splitn","crossterm","YAZI","unar","peekable","ratatui","syntect","pbpaste","pbcopy","ffmpegthumbnailer","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","nvim","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp","️ Überzug","️ Überzug","Konsole","Alacritty","Überzug","pkgs","paru","unarchiver","pdftoppm","poppler","prebuild","singlefile","jpegopt","EXIF","rustfmt","mktemp","nanos","xclip","xsel","natord","Mintty","nixos","nixpkgs","SIGTSTP","SIGCONT","SIGCONT","backstack"],"flagWords":[],"language":"en"}