From 826027445999fbfe2ce347baef5f75da522aac86 Mon Sep 17 00:00:00 2001 From: TD-Sky Date: Sat, 23 Sep 2023 16:00:21 +0800 Subject: [PATCH 1/5] feat(arrow): move cursor in percentage of page --- app/src/executor.rs | 2 +- config/preset/keymap.toml | 6 ++++-- core/src/manager/folder.rs | 40 ++++++++++++++++++++++++++++++++++---- core/src/manager/tab.rs | 15 +++++++------- 4 files changed, 49 insertions(+), 14 deletions(-) diff --git a/app/src/executor.rs b/app/src/executor.rs index 3203a0da3..51e928dbe 100644 --- a/app/src/executor.rs +++ b/app/src/executor.rs @@ -61,7 +61,7 @@ impl Executor { // Navigation "arrow" => { - let step = exec.args.get(0).and_then(|s| s.parse().ok()).unwrap_or(0); + let step = exec.args.get(0).and_then(|s| s.parse().ok()).unwrap_or_default(); cx.manager.active_mut().arrow(step) } "peek" => { diff --git a/config/preset/keymap.toml b/config/preset/keymap.toml index 461e8099f..d9fe1d5e0 100644 --- a/config/preset/keymap.toml +++ b/config/preset/keymap.toml @@ -10,8 +10,10 @@ keymap = [ { on = [ "k" ], exec = "arrow -1", desc = "Move cursor up" }, { on = [ "j" ], exec = "arrow 1", desc = "Move cursor down" }, - { on = [ "K" ], exec = "arrow -5", desc = "Move cursor up 5 lines" }, - { on = [ "J" ], exec = "arrow 5", desc = "Move cursor down 5 lines" }, + { on = [ "" ], exec = "arrow -50%", desc = "Move cursor up half page" }, + { on = [ "" ], exec = "arrow 50%", desc = "Move cursor down half page" }, + { on = [ "" ], exec = "arrow -100%", desc = "Move cursor up one page" }, + { on = [ "" ], exec = "arrow 100%", desc = "Move cursor down one page" }, { on = [ "h" ], exec = "leave", desc = "Go back to the parent directory" }, { on = [ "l" ], exec = "enter", desc = "Enter the child directory" }, diff --git a/core/src/manager/folder.rs b/core/src/manager/folder.rs index 9d1a832ef..ddc494c50 100644 --- a/core/src/manager/folder.rs +++ b/core/src/manager/folder.rs @@ -1,3 +1,5 @@ +use std::{num::ParseIntError, str::FromStr}; + use config::MANAGER; use ratatui::layout::Rect; use shared::Url; @@ -16,6 +18,12 @@ pub struct Folder { pub hovered: Option, } +#[derive(Default)] +pub struct Step { + pub(super) num: isize, + pub(super) percent: bool, +} + impl From for Folder { fn from(cwd: Url) -> Self { Self { cwd, ..Default::default() } } } @@ -24,6 +32,19 @@ impl From<&Url> for Folder { fn from(cwd: &Url) -> Self { Self::from(cwd.clone()) } } +impl FromStr for Step { + type Err = ParseIntError; + + fn from_str(s: &str) -> Result { + Ok(Self { num: s.trim_end_matches('%').parse()?, percent: s.ends_with('%') }) + } +} + +impl From for Step { + #[inline] + fn from(num: isize) -> Self { Self { num, percent: false } } +} + impl Folder { pub fn update(&mut self, op: FilesOp) -> bool { let b = match op { @@ -58,18 +79,21 @@ impl Folder { true } - pub fn next(&mut self, step: usize) -> bool { + pub fn next(&mut self, mut step: usize, percent: bool) -> bool { let len = self.files.len(); if len == 0 { return false; } + let limit = MANAGER.layout.folder_height(); + if percent { + step = ((limit * step) as f64 * 0.01) as usize; + } let old = self.cursor; self.cursor = (self.cursor + step).min(len - 1); self.hovered = self.files.duplicate(self.cursor); self.set_page(false); - let limit = MANAGER.layout.folder_height(); if self.cursor >= (self.offset + limit).min(len).saturating_sub(5) { self.offset = len.saturating_sub(limit).min(self.offset + self.cursor - old); } @@ -77,7 +101,11 @@ impl Folder { old != self.cursor } - pub fn prev(&mut self, step: usize) -> bool { + pub fn prev(&mut self, mut step: usize, percent: bool) -> bool { + if percent { + let limit = MANAGER.layout.folder_height(); + step = ((limit * step) as f64 * 0.01) as usize; + } let old = self.cursor; self.cursor = self.cursor.saturating_sub(step); self.hovered = self.files.duplicate(self.cursor); @@ -105,7 +133,11 @@ impl Folder { pub fn hover(&mut self, url: &Url) -> bool { let new = self.files.position(url).unwrap_or(self.cursor); - if new > self.cursor { self.next(new - self.cursor) } else { self.prev(self.cursor - new) } + if new > self.cursor { + self.next(new - self.cursor, false) + } else { + self.prev(self.cursor - new, false) + } } #[inline] diff --git a/core/src/manager/tab.rs b/core/src/manager/tab.rs index 4e5971c15..bc5765741 100644 --- a/core/src/manager/tab.rs +++ b/core/src/manager/tab.rs @@ -6,7 +6,7 @@ use shared::{Debounce, Defer, InputError, Url}; use tokio::{pin, task::JoinHandle}; use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt}; -use super::{Finder, Folder, Mode, Preview, PreviewLock}; +use super::{Finder, Folder, Mode, Preview, PreviewLock, Step}; use crate::{emit, external::{self, FzfOpt, ZoxideOpt}, files::{File, FilesOp, FilesSorter}, input::InputOpt, Event, BLOCKER}; pub struct Tab { @@ -67,11 +67,12 @@ impl Tab { self.search_stop() } - pub fn arrow(&mut self, step: isize) -> bool { - let ok = if step > 0 { - self.current.next(step as usize) + pub fn arrow(&mut self, step: Step) -> bool { + let Step { num, percent } = step; + let ok = if step.num > 0 { + self.current.next(num as usize, percent) } else { - self.current.prev(step.unsigned_abs()) + self.current.prev(num.unsigned_abs(), percent) }; if !ok { return false; @@ -248,7 +249,7 @@ impl Tab { }; if let Some(step) = finder.ring(&self.current.files, self.current.cursor(), prev) { - self.arrow(step); + self.arrow(step.into()); } self.finder = Some(finder); @@ -280,7 +281,7 @@ impl Tab { let mut b = finder.catchup(&self.current.files); if let Some(step) = finder.arrow(&self.current.files, self.current.cursor(), prev) { - b |= self.arrow(step); + b |= self.arrow(step.into()); } b From e7c4286962180f64d55ea50cadb7595c5d5d337a Mon Sep 17 00:00:00 2001 From: sxyazi Date: Sun, 24 Sep 2023 16:08:16 +0800 Subject: [PATCH 2/5] .. --- config/preset/keymap.toml | 3 ++ core/src/lib.rs | 4 ++- core/src/manager/folder.rs | 42 +++++----------------------- core/src/manager/tab.rs | 11 ++------ core/src/step.rs | 56 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 72 insertions(+), 44 deletions(-) create mode 100644 core/src/step.rs diff --git a/config/preset/keymap.toml b/config/preset/keymap.toml index d9fe1d5e0..939df8078 100644 --- a/config/preset/keymap.toml +++ b/config/preset/keymap.toml @@ -10,6 +10,9 @@ keymap = [ { on = [ "k" ], exec = "arrow -1", desc = "Move cursor up" }, { on = [ "j" ], exec = "arrow 1", desc = "Move cursor down" }, + { on = [ "K" ], exec = "arrow -5", desc = "Move cursor up 5 lines" }, + { on = [ "J" ], exec = "arrow 5", desc = "Move cursor down 5 lines" }, + { on = [ "" ], exec = "arrow -50%", desc = "Move cursor up half page" }, { on = [ "" ], exec = "arrow 50%", desc = "Move cursor down half page" }, { on = [ "" ], exec = "arrow -100%", desc = "Move cursor up one page" }, diff --git a/core/src/lib.rs b/core/src/lib.rs index 3696401fd..e637118f7 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -14,8 +14,9 @@ pub mod help; mod highlighter; pub mod input; pub mod manager; -pub mod position; +mod position; pub mod select; +mod step; pub mod tasks; pub mod which; @@ -23,5 +24,6 @@ pub use blocker::*; pub use event::*; pub use highlighter::*; pub use position::*; +pub use step::*; pub fn init() { init_blocker(); } diff --git a/core/src/manager/folder.rs b/core/src/manager/folder.rs index ddc494c50..172361f74 100644 --- a/core/src/manager/folder.rs +++ b/core/src/manager/folder.rs @@ -1,10 +1,8 @@ -use std::{num::ParseIntError, str::FromStr}; - use config::MANAGER; use ratatui::layout::Rect; use shared::Url; -use crate::{emit, files::{File, Files, FilesOp}}; +use crate::{emit, files::{File, Files, FilesOp}, Step}; #[derive(Default)] pub struct Folder { @@ -18,12 +16,6 @@ pub struct Folder { pub hovered: Option, } -#[derive(Default)] -pub struct Step { - pub(super) num: isize, - pub(super) percent: bool, -} - impl From for Folder { fn from(cwd: Url) -> Self { Self { cwd, ..Default::default() } } } @@ -32,19 +24,6 @@ impl From<&Url> for Folder { fn from(cwd: &Url) -> Self { Self::from(cwd.clone()) } } -impl FromStr for Step { - type Err = ParseIntError; - - fn from_str(s: &str) -> Result { - Ok(Self { num: s.trim_end_matches('%').parse()?, percent: s.ends_with('%') }) - } -} - -impl From for Step { - #[inline] - fn from(num: isize) -> Self { Self { num, percent: false } } -} - impl Folder { pub fn update(&mut self, op: FilesOp) -> bool { let b = match op { @@ -79,18 +58,15 @@ impl Folder { true } - pub fn next(&mut self, mut step: usize, percent: bool) -> bool { + pub fn next(&mut self, step: Step) -> bool { let len = self.files.len(); if len == 0 { return false; } let limit = MANAGER.layout.folder_height(); - if percent { - step = ((limit * step) as f64 * 0.01) as usize; - } let old = self.cursor; - self.cursor = (self.cursor + step).min(len - 1); + self.cursor = step.add(self.cursor, || limit).min(len - 1); self.hovered = self.files.duplicate(self.cursor); self.set_page(false); @@ -101,13 +77,9 @@ impl Folder { old != self.cursor } - pub fn prev(&mut self, mut step: usize, percent: bool) -> bool { - if percent { - let limit = MANAGER.layout.folder_height(); - step = ((limit * step) as f64 * 0.01) as usize; - } + pub fn prev(&mut self, step: Step) -> bool { let old = self.cursor; - self.cursor = self.cursor.saturating_sub(step); + self.cursor = step.add(self.cursor, || 0); self.hovered = self.files.duplicate(self.cursor); self.set_page(false); @@ -134,9 +106,9 @@ impl Folder { pub fn hover(&mut self, url: &Url) -> bool { let new = self.files.position(url).unwrap_or(self.cursor); if new > self.cursor { - self.next(new - self.cursor, false) + self.next(Step::from(new - self.cursor)) } else { - self.prev(self.cursor - new, false) + self.prev(Step::from(self.cursor - new)) } } diff --git a/core/src/manager/tab.rs b/core/src/manager/tab.rs index bc5765741..25f8b3e6f 100644 --- a/core/src/manager/tab.rs +++ b/core/src/manager/tab.rs @@ -6,8 +6,8 @@ use shared::{Debounce, Defer, InputError, Url}; use tokio::{pin, task::JoinHandle}; use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt}; -use super::{Finder, Folder, Mode, Preview, PreviewLock, Step}; -use crate::{emit, external::{self, FzfOpt, ZoxideOpt}, files::{File, FilesOp, FilesSorter}, input::InputOpt, Event, BLOCKER}; +use super::{Finder, Folder, Mode, Preview, PreviewLock}; +use crate::{emit, external::{self, FzfOpt, ZoxideOpt}, files::{File, FilesOp, FilesSorter}, input::InputOpt, Event, Step, BLOCKER}; pub struct Tab { pub(super) mode: Mode, @@ -68,12 +68,7 @@ impl Tab { } pub fn arrow(&mut self, step: Step) -> bool { - let Step { num, percent } = step; - let ok = if step.num > 0 { - self.current.next(num as usize, percent) - } else { - self.current.prev(num.unsigned_abs(), percent) - }; + let ok = if step.positive() { self.current.next(step) } else { self.current.prev(step) }; if !ok { return false; } diff --git a/core/src/step.rs b/core/src/step.rs new file mode 100644 index 000000000..ce42743ad --- /dev/null +++ b/core/src/step.rs @@ -0,0 +1,56 @@ +use std::{num::ParseIntError, str::FromStr}; + +pub enum Step { + Fixed(isize), + Percent(i8), +} + +impl Default for Step { + fn default() -> Self { Self::Fixed(0) } +} + +impl FromStr for Step { + type Err = ParseIntError; + + fn from_str(s: &str) -> Result { + Ok(if let Some(s) = s.strip_suffix('%') { + Self::Percent(s.parse()?) + } else { + Self::Fixed(s.parse()?) + }) + } +} + +impl From for Step { + fn from(n: isize) -> Self { Self::Fixed(n) } +} + +impl From for Step { + fn from(n: usize) -> Self { Self::Fixed(n as isize) } +} + +impl Step { + #[inline] + fn fixed usize>(self, f: F) -> isize { + match self { + Self::Fixed(n) => n, + Self::Percent(0) => 0, + Self::Percent(n) => n as isize * f() as isize / 100, + } + } + + #[inline] + pub fn add usize>(self, pos: usize, f: F) -> usize { + let fixed = self.fixed(f); + if fixed > 0 { pos + fixed as usize } else { pos.saturating_sub(fixed.unsigned_abs()) } + } + + #[inline] + pub fn positive(&self) -> bool { + match self { + Self::Fixed(n) if *n > 0 => true, + Self::Percent(n) if *n > 0 => true, + _ => false, + } + } +} From d8ac32f1fd6931228f6a4e28b914c48cde5989a8 Mon Sep 17 00:00:00 2001 From: sxyazi Date: Sun, 24 Sep 2023 16:20:21 +0800 Subject: [PATCH 3/5] .. --- core/src/manager/folder.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/manager/folder.rs b/core/src/manager/folder.rs index 172361f74..6899d1f7e 100644 --- a/core/src/manager/folder.rs +++ b/core/src/manager/folder.rs @@ -64,8 +64,8 @@ impl Folder { return false; } - let limit = MANAGER.layout.folder_height(); let old = self.cursor; + let limit = MANAGER.layout.folder_height(); self.cursor = step.add(self.cursor, || limit).min(len - 1); self.hovered = self.files.duplicate(self.cursor); self.set_page(false); @@ -79,7 +79,7 @@ impl Folder { pub fn prev(&mut self, step: Step) -> bool { let old = self.cursor; - self.cursor = step.add(self.cursor, || 0); + self.cursor = step.add(self.cursor, || MANAGER.layout.folder_height()); self.hovered = self.files.duplicate(self.cursor); self.set_page(false); From 56650960944feb3c37e1db00a4a4df5b3bae3a5d Mon Sep 17 00:00:00 2001 From: TD-Sky Date: Sun, 24 Sep 2023 16:35:56 +0800 Subject: [PATCH 4/5] chore(step): optimize `positive` and rename it --- core/src/manager/tab.rs | 2 +- core/src/step.rs | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/core/src/manager/tab.rs b/core/src/manager/tab.rs index 25f8b3e6f..b9f14c373 100644 --- a/core/src/manager/tab.rs +++ b/core/src/manager/tab.rs @@ -68,7 +68,7 @@ impl Tab { } pub fn arrow(&mut self, step: Step) -> bool { - let ok = if step.positive() { self.current.next(step) } else { self.current.prev(step) }; + let ok = if step.is_positive() { self.current.next(step) } else { self.current.prev(step) }; if !ok { return false; } diff --git a/core/src/step.rs b/core/src/step.rs index ce42743ad..7584500d9 100644 --- a/core/src/step.rs +++ b/core/src/step.rs @@ -6,6 +6,7 @@ pub enum Step { } impl Default for Step { + #[inline] fn default() -> Self { Self::Fixed(0) } } @@ -22,10 +23,12 @@ impl FromStr for Step { } impl From for Step { + #[inline] fn from(n: isize) -> Self { Self::Fixed(n) } } impl From for Step { + #[inline] fn from(n: usize) -> Self { Self::Fixed(n as isize) } } @@ -46,11 +49,10 @@ impl Step { } #[inline] - pub fn positive(&self) -> bool { - match self { - Self::Fixed(n) if *n > 0 => true, - Self::Percent(n) if *n > 0 => true, - _ => false, + pub fn is_positive(&self) -> bool { + match *self { + Self::Fixed(n) => n > 0, + Self::Percent(n) => n > 0, } } } From 3e617bc7d27c8585f134218f00684dbfe8cfcbd5 Mon Sep 17 00:00:00 2001 From: sxyazi Date: Sun, 24 Sep 2023 17:26:47 +0800 Subject: [PATCH 5/5] .. --- config/preset/keymap.toml | 4 ++-- core/src/step.rs | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/config/preset/keymap.toml b/config/preset/keymap.toml index 939df8078..d21b91ccb 100644 --- a/config/preset/keymap.toml +++ b/config/preset/keymap.toml @@ -13,8 +13,8 @@ keymap = [ { on = [ "K" ], exec = "arrow -5", desc = "Move cursor up 5 lines" }, { on = [ "J" ], exec = "arrow 5", desc = "Move cursor down 5 lines" }, - { on = [ "" ], exec = "arrow -50%", desc = "Move cursor up half page" }, - { on = [ "" ], exec = "arrow 50%", desc = "Move cursor down half page" }, + { on = [ "" ], exec = "arrow -50%", desc = "Move cursor up half page" }, + { on = [ "" ], exec = "arrow 50%", desc = "Move cursor down half page" }, { on = [ "" ], exec = "arrow -100%", desc = "Move cursor up one page" }, { on = [ "" ], exec = "arrow 100%", desc = "Move cursor down one page" }, diff --git a/core/src/step.rs b/core/src/step.rs index 7584500d9..5faa2459c 100644 --- a/core/src/step.rs +++ b/core/src/step.rs @@ -6,7 +6,6 @@ pub enum Step { } impl Default for Step { - #[inline] fn default() -> Self { Self::Fixed(0) } } @@ -23,12 +22,10 @@ impl FromStr for Step { } impl From for Step { - #[inline] fn from(n: isize) -> Self { Self::Fixed(n) } } impl From for Step { - #[inline] fn from(n: usize) -> Self { Self::Fixed(n as isize) } }