mirror of
https://github.com/sayanarijit/xplr.git
synced 2024-11-20 18:42:04 +03:00
vimlike_scrolling -> paginated_scrolling
Inspired by @ElSamhaa 's PR https://github.com/sayanarijit/xplr/pull/704
This commit is contained in:
parent
ce52bcdf94
commit
90df0a2b5a
@ -98,6 +98,7 @@ fn draw_benchmark(c: &mut Criterion) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let lua = mlua::Lua::new();
|
let lua = mlua::Lua::new();
|
||||||
|
let mut ui = ui::UI::new(&lua);
|
||||||
let mut app =
|
let mut app =
|
||||||
app::App::create("xplr".into(), None, PWD.into(), &lua, None, [].into())
|
app::App::create("xplr".into(), None, PWD.into(), &lua, None, [].into())
|
||||||
.expect("failed to create app");
|
.expect("failed to create app");
|
||||||
@ -121,7 +122,7 @@ fn draw_benchmark(c: &mut Criterion) {
|
|||||||
|
|
||||||
c.bench_function("draw on terminal", |b| {
|
c.bench_function("draw on terminal", |b| {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
terminal.draw(|f| ui::draw(f, &mut app, &lua)).unwrap();
|
terminal.draw(|f| ui.draw(f, &app)).unwrap();
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -128,8 +128,10 @@ compatibility.
|
|||||||
and move focused or selected files, without having to change directory.
|
and move focused or selected files, without having to change directory.
|
||||||
- Use `xplr.util.debug()` to debug lua values.
|
- Use `xplr.util.debug()` to debug lua values.
|
||||||
- Since v0.21.8:
|
- Since v0.21.8:
|
||||||
- You can set `xplr.config.general.vimlike_scrolling = true` to enable
|
- Scroll behavior will default to vim-like continuous scrolling. You can set
|
||||||
vim-like scrolling.
|
`xplr.config.general.paginated_scrolling = true` to revert back to the
|
||||||
|
paginated scrolling.
|
||||||
|
- Set `xplr.config.general.scroll_padding` to customize the scroll padding.
|
||||||
|
|
||||||
Thanks to @noahmayr for contributing to a major part of this release.
|
Thanks to @noahmayr for contributing to a major part of this release.
|
||||||
|
|
||||||
|
@ -753,7 +753,6 @@ impl App {
|
|||||||
self.pwd.clone().into(),
|
self.pwd.clone().into(),
|
||||||
focus.as_ref().map(PathBuf::from),
|
focus.as_ref().map(PathBuf::from),
|
||||||
self.directory_buffer.as_ref().map(|d| d.focus).unwrap_or(0),
|
self.directory_buffer.as_ref().map(|d| d.focus).unwrap_or(0),
|
||||||
self.config.general.vimlike_scrolling,
|
|
||||||
) {
|
) {
|
||||||
Ok(dir) => self.set_directory(dir),
|
Ok(dir) => self.set_directory(dir),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -355,7 +355,10 @@ pub struct GeneralConfig {
|
|||||||
pub global_key_bindings: KeyBindings,
|
pub global_key_bindings: KeyBindings,
|
||||||
|
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub vimlike_scrolling: bool,
|
pub paginated_scrolling: bool,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub scroll_padding: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
@ -1,121 +1,7 @@
|
|||||||
use crate::node::Node;
|
use crate::node::Node;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::cmp::Ordering;
|
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)]
|
|
||||||
pub struct ScrollState {
|
|
||||||
pub current_focus: usize,
|
|
||||||
pub last_focus: Option<usize>,
|
|
||||||
pub skipped_rows: usize,
|
|
||||||
/* The number of visible next lines when scrolling towards either ends of the view port */
|
|
||||||
pub initial_preview_cushion: usize,
|
|
||||||
|
|
||||||
pub vimlike_scrolling: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ScrollState {
|
|
||||||
pub fn new(current_focus: usize, total: usize, vimlike_scrolling: bool) -> Self {
|
|
||||||
let initial_preview_cushion = 5;
|
|
||||||
Self {
|
|
||||||
current_focus,
|
|
||||||
last_focus: None,
|
|
||||||
skipped_rows: 0,
|
|
||||||
initial_preview_cushion,
|
|
||||||
vimlike_scrolling,
|
|
||||||
}
|
|
||||||
.update_skipped_rows(initial_preview_cushion + 1, total)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_focus(mut self, current_focus: usize) -> Self {
|
|
||||||
self.last_focus = Some(self.current_focus);
|
|
||||||
self.current_focus = current_focus;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_skipped_rows(self, height: usize, total: usize) -> Self {
|
|
||||||
if self.vimlike_scrolling {
|
|
||||||
self.update_skipped_rows_vimlike(height, total)
|
|
||||||
} else {
|
|
||||||
self.update_skipped_rows_paginated(height)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_skipped_rows_paginated(mut self, height: usize) -> Self {
|
|
||||||
self.skipped_rows = height * (self.current_focus / height.max(1));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_skipped_rows_vimlike(mut self, height: usize, total: usize) -> Self {
|
|
||||||
let preview_cushion = if height >= self.initial_preview_cushion * 3 {
|
|
||||||
self.initial_preview_cushion
|
|
||||||
} else if height >= 9 {
|
|
||||||
3
|
|
||||||
} else if height >= 3 {
|
|
||||||
1
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
let current_focus = self.current_focus;
|
|
||||||
let last_focus = self.last_focus;
|
|
||||||
let first_visible_row = self.skipped_rows;
|
|
||||||
|
|
||||||
// Calculate the cushion rows at the start and end of the view port
|
|
||||||
let start_cushion_row = first_visible_row + preview_cushion;
|
|
||||||
let end_cushion_row = (first_visible_row + height)
|
|
||||||
.saturating_sub(preview_cushion + 1)
|
|
||||||
.min(total.saturating_sub(preview_cushion + 1));
|
|
||||||
|
|
||||||
self.skipped_rows = if current_focus == 0 {
|
|
||||||
// When focus goes to first node
|
|
||||||
0
|
|
||||||
} else if current_focus == total.saturating_sub(1) {
|
|
||||||
// When focus goes to last node
|
|
||||||
total.saturating_sub(height)
|
|
||||||
} else if current_focus > start_cushion_row && current_focus <= end_cushion_row {
|
|
||||||
// If within cushioned area; do nothing
|
|
||||||
first_visible_row
|
|
||||||
} else if let Some(last_focus) = last_focus {
|
|
||||||
match current_focus.cmp(&last_focus) {
|
|
||||||
Ordering::Greater => {
|
|
||||||
// When scrolling down the cushioned area
|
|
||||||
if current_focus > total.saturating_sub(preview_cushion + 1) {
|
|
||||||
// When focusing the last nodes; always view the full last page
|
|
||||||
total.saturating_sub(height)
|
|
||||||
} else {
|
|
||||||
// When scrolling down the cushioned area without reaching the last nodes
|
|
||||||
current_focus
|
|
||||||
.saturating_sub(height.saturating_sub(preview_cushion + 1))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ordering::Less => {
|
|
||||||
// When scrolling up the cushioned area
|
|
||||||
if current_focus < preview_cushion {
|
|
||||||
// When focusing the first nodes; always view the full first page
|
|
||||||
0
|
|
||||||
} else if current_focus > end_cushion_row {
|
|
||||||
// When scrolling up from the last rows; do nothing
|
|
||||||
first_visible_row
|
|
||||||
} else {
|
|
||||||
// When scrolling up the cushioned area without reaching the first nodes
|
|
||||||
current_focus.saturating_sub(preview_cushion)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ordering::Equal => {
|
|
||||||
// Do nothing
|
|
||||||
first_visible_row
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Just entered dir
|
|
||||||
first_visible_row
|
|
||||||
};
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct DirectoryBuffer {
|
pub struct DirectoryBuffer {
|
||||||
pub parent: String,
|
pub parent: String,
|
||||||
@ -149,115 +35,3 @@ fn now() -> OffsetDateTime {
|
|||||||
.ok()
|
.ok()
|
||||||
.unwrap_or_else(OffsetDateTime::now_utc)
|
.unwrap_or_else(OffsetDateTime::now_utc)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_update_skipped_rows_paginated() {
|
|
||||||
let state = ScrollState {
|
|
||||||
current_focus: 10,
|
|
||||||
last_focus: Some(8),
|
|
||||||
skipped_rows: 0,
|
|
||||||
initial_preview_cushion: 5,
|
|
||||||
vimlike_scrolling: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
let height = 5;
|
|
||||||
let total = 100;
|
|
||||||
|
|
||||||
let state = state.update_skipped_rows(height, total);
|
|
||||||
assert_eq!(
|
|
||||||
state.skipped_rows,
|
|
||||||
height * (state.current_focus / height.max(1))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_update_skipped_rows_entered_directory() {
|
|
||||||
let state = ScrollState {
|
|
||||||
current_focus: 100,
|
|
||||||
last_focus: None,
|
|
||||||
skipped_rows: 0,
|
|
||||||
initial_preview_cushion: 5,
|
|
||||||
vimlike_scrolling: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
let height = 5;
|
|
||||||
let total = 200;
|
|
||||||
|
|
||||||
let result = state.update_skipped_rows(height, total).skipped_rows;
|
|
||||||
assert_eq!(result, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_calc_skipped_rows_top_of_directory() {
|
|
||||||
let state = ScrollState {
|
|
||||||
current_focus: 0,
|
|
||||||
last_focus: Some(8),
|
|
||||||
skipped_rows: 5,
|
|
||||||
initial_preview_cushion: 5,
|
|
||||||
vimlike_scrolling: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
let height = 5;
|
|
||||||
let total = 20;
|
|
||||||
|
|
||||||
let result = state.update_skipped_rows(height, total).skipped_rows;
|
|
||||||
assert_eq!(result, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_calc_skipped_rows_bottom_of_directory() {
|
|
||||||
let state = ScrollState {
|
|
||||||
current_focus: 19,
|
|
||||||
last_focus: Some(18),
|
|
||||||
skipped_rows: 15,
|
|
||||||
initial_preview_cushion: 5,
|
|
||||||
vimlike_scrolling: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
let height = 5;
|
|
||||||
let total = 20;
|
|
||||||
|
|
||||||
let result = state.update_skipped_rows(height, total).skipped_rows;
|
|
||||||
assert_eq!(result, 15);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_calc_skipped_rows_scrolling_down() {
|
|
||||||
let state = ScrollState {
|
|
||||||
current_focus: 12,
|
|
||||||
last_focus: Some(10),
|
|
||||||
skipped_rows: 10,
|
|
||||||
initial_preview_cushion: 5,
|
|
||||||
vimlike_scrolling: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
let height = 5;
|
|
||||||
let total = 20;
|
|
||||||
|
|
||||||
let result = state.update_skipped_rows(height, total).skipped_rows;
|
|
||||||
assert_eq!(result, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_calc_skipped_rows_scrolling_up() {
|
|
||||||
let state = ScrollState {
|
|
||||||
current_focus: 8,
|
|
||||||
last_focus: Some(10),
|
|
||||||
skipped_rows: 10,
|
|
||||||
initial_preview_cushion: 5,
|
|
||||||
vimlike_scrolling: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
let height = 5;
|
|
||||||
let total = 20;
|
|
||||||
|
|
||||||
let result = state.update_skipped_rows(height, total).skipped_rows;
|
|
||||||
assert_eq!(result, 7);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add more tests for other scenarios...
|
|
||||||
}
|
|
||||||
|
@ -45,7 +45,6 @@ pub(crate) fn explore_sync(
|
|||||||
parent: PathBuf,
|
parent: PathBuf,
|
||||||
focused_path: Option<PathBuf>,
|
focused_path: Option<PathBuf>,
|
||||||
fallback_focus: usize,
|
fallback_focus: usize,
|
||||||
vimlike_scrolling: bool,
|
|
||||||
) -> Result<DirectoryBuffer> {
|
) -> Result<DirectoryBuffer> {
|
||||||
let nodes = explore(&parent, &config)?;
|
let nodes = explore(&parent, &config)?;
|
||||||
let focus_index = if config.searcher.is_some() {
|
let focus_index = if config.searcher.is_some() {
|
||||||
@ -74,33 +73,26 @@ pub(crate) fn explore_async(
|
|||||||
parent: PathBuf,
|
parent: PathBuf,
|
||||||
focused_path: Option<PathBuf>,
|
focused_path: Option<PathBuf>,
|
||||||
fallback_focus: usize,
|
fallback_focus: usize,
|
||||||
vimlike_scrolling: bool,
|
|
||||||
tx_msg_in: Sender<Task>,
|
tx_msg_in: Sender<Task>,
|
||||||
) {
|
) {
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
explore_sync(
|
explore_sync(config, parent.clone(), focused_path, fallback_focus)
|
||||||
config,
|
.and_then(|buf| {
|
||||||
parent.clone(),
|
tx_msg_in
|
||||||
focused_path,
|
.send(Task::new(
|
||||||
fallback_focus,
|
MsgIn::Internal(InternalMsg::SetDirectory(buf)),
|
||||||
vimlike_scrolling,
|
None,
|
||||||
)
|
))
|
||||||
.and_then(|buf| {
|
.map_err(Error::new)
|
||||||
tx_msg_in
|
})
|
||||||
.send(Task::new(
|
.unwrap_or_else(|e| {
|
||||||
MsgIn::Internal(InternalMsg::SetDirectory(buf)),
|
tx_msg_in
|
||||||
None,
|
.send(Task::new(
|
||||||
))
|
MsgIn::External(ExternalMsg::LogError(e.to_string())),
|
||||||
.map_err(Error::new)
|
None,
|
||||||
})
|
))
|
||||||
.unwrap_or_else(|e| {
|
.unwrap_or_default(); // Let's not panic if xplr closes.
|
||||||
tx_msg_in
|
})
|
||||||
.send(Task::new(
|
|
||||||
MsgIn::External(ExternalMsg::LogError(e.to_string())),
|
|
||||||
None,
|
|
||||||
))
|
|
||||||
.unwrap_or_default(); // Let's not panic if xplr closes.
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +101,6 @@ pub(crate) fn explore_recursive_async(
|
|||||||
parent: PathBuf,
|
parent: PathBuf,
|
||||||
focused_path: Option<PathBuf>,
|
focused_path: Option<PathBuf>,
|
||||||
fallback_focus: usize,
|
fallback_focus: usize,
|
||||||
vimlike_scrolling: bool,
|
|
||||||
tx_msg_in: Sender<Task>,
|
tx_msg_in: Sender<Task>,
|
||||||
) {
|
) {
|
||||||
explore_async(
|
explore_async(
|
||||||
@ -117,7 +108,6 @@ pub(crate) fn explore_recursive_async(
|
|||||||
parent.clone(),
|
parent.clone(),
|
||||||
focused_path,
|
focused_path,
|
||||||
fallback_focus,
|
fallback_focus,
|
||||||
vimlike_scrolling,
|
|
||||||
tx_msg_in.clone(),
|
tx_msg_in.clone(),
|
||||||
);
|
);
|
||||||
if let Some(grand_parent) = parent.parent() {
|
if let Some(grand_parent) = parent.parent() {
|
||||||
@ -126,7 +116,6 @@ pub(crate) fn explore_recursive_async(
|
|||||||
grand_parent.into(),
|
grand_parent.into(),
|
||||||
parent.file_name().map(|p| p.into()),
|
parent.file_name().map(|p| p.into()),
|
||||||
0,
|
0,
|
||||||
vimlike_scrolling,
|
|
||||||
tx_msg_in,
|
tx_msg_in,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -141,7 +130,7 @@ mod tests {
|
|||||||
let config = ExplorerConfig::default();
|
let config = ExplorerConfig::default();
|
||||||
let path = PathBuf::from(".");
|
let path = PathBuf::from(".");
|
||||||
|
|
||||||
let r = explore_sync(config, path, None, 0, false);
|
let r = explore_sync(config, path, None, 0);
|
||||||
|
|
||||||
assert!(r.is_ok());
|
assert!(r.is_ok());
|
||||||
}
|
}
|
||||||
@ -151,7 +140,7 @@ mod tests {
|
|||||||
let config = ExplorerConfig::default();
|
let config = ExplorerConfig::default();
|
||||||
let path = PathBuf::from("/there/is/no/path");
|
let path = PathBuf::from("/there/is/no/path");
|
||||||
|
|
||||||
let r = explore_sync(config, path, None, 0, false);
|
let r = explore_sync(config, path, None, 0);
|
||||||
|
|
||||||
assert!(r.is_err());
|
assert!(r.is_err());
|
||||||
}
|
}
|
||||||
@ -180,7 +169,7 @@ mod tests {
|
|||||||
let path = PathBuf::from(".");
|
let path = PathBuf::from(".");
|
||||||
let (tx_msg_in, rx_msg_in) = mpsc::channel();
|
let (tx_msg_in, rx_msg_in) = mpsc::channel();
|
||||||
|
|
||||||
explore_async(config, path, None, 0, false, tx_msg_in.clone());
|
explore_async(config, path, None, 0, tx_msg_in.clone());
|
||||||
|
|
||||||
let task = rx_msg_in.recv().unwrap();
|
let task = rx_msg_in.recv().unwrap();
|
||||||
let dbuf = extract_dirbuf_from_msg(task.msg);
|
let dbuf = extract_dirbuf_from_msg(task.msg);
|
||||||
|
10
src/init.lua
10
src/init.lua
@ -91,10 +91,16 @@ xplr.config.general.enable_recover_mode = false
|
|||||||
-- Type: boolean
|
-- Type: boolean
|
||||||
xplr.config.general.hide_remaps_in_help_menu = false
|
xplr.config.general.hide_remaps_in_help_menu = false
|
||||||
|
|
||||||
-- Set it to `true` if you want vim-like scrolling.
|
-- Set it to `true` if you want paginated scrolling.
|
||||||
--
|
--
|
||||||
-- Type: boolean
|
-- Type: boolean
|
||||||
xplr.config.general.vimlike_scrolling = false
|
xplr.config.general.paginated_scrolling = false
|
||||||
|
|
||||||
|
-- Set the padding value to the scroll area. Only applicable when
|
||||||
|
-- `xplr.config.general.paginated_scrolling` is set to `false`.
|
||||||
|
--
|
||||||
|
-- Type: boolean
|
||||||
|
xplr.config.general.scroll_padding = 5
|
||||||
|
|
||||||
-- Set it to `true` if you want the cursor to stay in the same position when
|
-- Set it to `true` if you want the cursor to stay in the same position when
|
||||||
-- the focus is on the first path and you navigate to the previous path
|
-- the focus is on the first path and you navigate to the previous path
|
||||||
|
@ -281,7 +281,6 @@ impl Runner {
|
|||||||
app.pwd.clone().into(),
|
app.pwd.clone().into(),
|
||||||
self.focused_path,
|
self.focused_path,
|
||||||
app.directory_buffer.as_ref().map(|d| d.focus).unwrap_or(0),
|
app.directory_buffer.as_ref().map(|d| d.focus).unwrap_or(0),
|
||||||
app.config.general.vimlike_scrolling,
|
|
||||||
tx_msg_in.clone(),
|
tx_msg_in.clone(),
|
||||||
);
|
);
|
||||||
tx_pwd_watcher.send(app.pwd.clone())?;
|
tx_pwd_watcher.send(app.pwd.clone())?;
|
||||||
@ -437,7 +436,6 @@ impl Runner {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|d| d.focus)
|
.map(|d| d.focus)
|
||||||
.unwrap_or(0),
|
.unwrap_or(0),
|
||||||
app.config.general.vimlike_scrolling,
|
|
||||||
tx_msg_in.clone(),
|
tx_msg_in.clone(),
|
||||||
);
|
);
|
||||||
tx_pwd_watcher.send(app.pwd.clone())?;
|
tx_pwd_watcher.send(app.pwd.clone())?;
|
||||||
@ -453,7 +451,6 @@ impl Runner {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|d| d.focus)
|
.map(|d| d.focus)
|
||||||
.unwrap_or(0),
|
.unwrap_or(0),
|
||||||
app.config.general.vimlike_scrolling,
|
|
||||||
tx_msg_in.clone(),
|
tx_msg_in.clone(),
|
||||||
);
|
);
|
||||||
tx_pwd_watcher.send(app.pwd.clone())?;
|
tx_pwd_watcher.send(app.pwd.clone())?;
|
||||||
|
40
src/ui.rs
40
src/ui.rs
@ -743,12 +743,18 @@ pub fn block<'a>(config: PanelUiConfig, default_title: String) -> Block<'a> {
|
|||||||
pub struct UI<'lua> {
|
pub struct UI<'lua> {
|
||||||
pub lua: &'lua Lua,
|
pub lua: &'lua Lua,
|
||||||
pub screen_size: TuiRect,
|
pub screen_size: TuiRect,
|
||||||
|
pub scrolltop: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'lua> UI<'lua> {
|
impl<'lua> UI<'lua> {
|
||||||
pub fn new(lua: &'lua Lua) -> Self {
|
pub fn new(lua: &'lua Lua) -> Self {
|
||||||
let screen_size = Default::default();
|
let screen_size = Default::default();
|
||||||
Self { lua, screen_size }
|
let scrolltop = 0;
|
||||||
|
Self {
|
||||||
|
lua,
|
||||||
|
scrolltop,
|
||||||
|
screen_size,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -766,10 +772,40 @@ impl UI<'_> {
|
|||||||
.directory_buffer
|
.directory_buffer
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|dir| {
|
.map(|dir| {
|
||||||
|
// Scroll
|
||||||
|
if app.config.general.paginated_scrolling {
|
||||||
|
// Paginated scrolling
|
||||||
|
self.scrolltop = height * (dir.focus / height.max(1))
|
||||||
|
} else {
|
||||||
|
// vim-like-scrolling
|
||||||
|
self.scrolltop = match dir.focus.cmp(&self.scrolltop) {
|
||||||
|
Ordering::Greater => {
|
||||||
|
// Scrolling down
|
||||||
|
if dir.focus >= self.scrolltop + height {
|
||||||
|
dir.focus - height + 1
|
||||||
|
} else {
|
||||||
|
self.scrolltop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ordering::Less => dir.focus,
|
||||||
|
Ordering::Equal => self.scrolltop,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add padding if possible
|
||||||
|
let padding = app.config.general.scroll_padding;
|
||||||
|
if padding != 0 {
|
||||||
|
if dir.focus < self.scrolltop + padding {
|
||||||
|
self.scrolltop = dir.focus.saturating_sub(padding);
|
||||||
|
} else if dir.focus >= self.scrolltop + height - padding {
|
||||||
|
self.scrolltop = dir.focus + padding - height + 1;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
dir.nodes
|
dir.nodes
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.skip(height * (dir.focus / height.max(1)))
|
.skip(self.scrolltop)
|
||||||
.take(height)
|
.take(height)
|
||||||
.map(|(index, node)| {
|
.map(|(index, node)| {
|
||||||
let is_focused = dir.focus == index;
|
let is_focused = dir.focus == index;
|
||||||
|
Loading…
Reference in New Issue
Block a user