Skip to content

Commit

Permalink
feat: scroll half/full page with arrow percentage supported, and ne…
Browse files Browse the repository at this point in the history
…w Vi-like `<C-u>`, `<C-d>`, `<C-b>`, and `<C-f>` keybindings added (#213)
  • Loading branch information
TD-Sky authored Sep 24, 2023
1 parent d3ed8e7 commit f7fdda9
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 18 deletions.
2 changes: 1 addition & 1 deletion app/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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" => {
Expand Down
5 changes: 5 additions & 0 deletions config/preset/keymap.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ keymap = [
{ on = [ "K" ], exec = "arrow -5", desc = "Move cursor up 5 lines" },
{ on = [ "J" ], exec = "arrow 5", desc = "Move cursor down 5 lines" },

{ on = [ "<C-u>" ], exec = "arrow -50%", desc = "Move cursor up half page" },
{ on = [ "<C-d>" ], exec = "arrow 50%", desc = "Move cursor down half page" },
{ on = [ "<C-b>" ], exec = "arrow -100%", desc = "Move cursor up one page" },
{ on = [ "<C-f>" ], 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" },

Expand Down
4 changes: 3 additions & 1 deletion core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ 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;

pub use blocker::*;
pub use event::*;
pub use highlighter::*;
pub use position::*;
pub use step::*;

pub fn init() { init_blocker(); }
18 changes: 11 additions & 7 deletions core/src/manager/folder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ 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 {
Expand Down Expand Up @@ -58,28 +58,28 @@ impl Folder {
true
}

pub fn next(&mut self, step: usize) -> bool {
pub fn next(&mut self, step: Step) -> bool {
let len = self.files.len();
if len == 0 {
return false;
}

let old = self.cursor;
self.cursor = (self.cursor + step).min(len - 1);
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);

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

old != self.cursor
}

pub fn prev(&mut self, step: usize) -> bool {
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, || MANAGER.layout.folder_height());
self.hovered = self.files.duplicate(self.cursor);
self.set_page(false);

Expand All @@ -105,7 +105,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(Step::from(new - self.cursor))
} else {
self.prev(Step::from(self.cursor - new))
}
}

#[inline]
Expand Down
14 changes: 5 additions & 9 deletions core/src/manager/tab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use tokio::{pin, task::JoinHandle};
use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt};

use super::{Finder, Folder, Mode, Preview, PreviewLock};
use crate::{emit, external::{self, FzfOpt, ZoxideOpt}, files::{File, FilesOp, FilesSorter}, input::InputOpt, Event, BLOCKER};
use crate::{emit, external::{self, FzfOpt, ZoxideOpt}, files::{File, FilesOp, FilesSorter}, input::InputOpt, Event, Step, BLOCKER};

pub struct Tab {
pub(super) mode: Mode,
Expand Down Expand Up @@ -67,12 +67,8 @@ impl Tab {
self.search_stop()
}

pub fn arrow(&mut self, step: isize) -> bool {
let ok = if step > 0 {
self.current.next(step as usize)
} else {
self.current.prev(step.unsigned_abs())
};
pub fn arrow(&mut self, step: Step) -> bool {
let ok = if step.is_positive() { self.current.next(step) } else { self.current.prev(step) };
if !ok {
return false;
}
Expand Down Expand Up @@ -248,7 +244,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);
Expand Down Expand Up @@ -280,7 +276,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
Expand Down
55 changes: 55 additions & 0 deletions core/src/step.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
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<Self, Self::Err> {
Ok(if let Some(s) = s.strip_suffix('%') {
Self::Percent(s.parse()?)
} else {
Self::Fixed(s.parse()?)
})
}
}

impl From<isize> for Step {
fn from(n: isize) -> Self { Self::Fixed(n) }
}

impl From<usize> for Step {
fn from(n: usize) -> Self { Self::Fixed(n as isize) }
}

impl Step {
#[inline]
fn fixed<F: FnOnce() -> 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<F: FnOnce() -> 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 is_positive(&self) -> bool {
match *self {
Self::Fixed(n) => n > 0,
Self::Percent(n) => n > 0,
}
}
}

0 comments on commit f7fdda9

Please sign in to comment.