summaryrefslogtreecommitdiffstats
path: root/src/fs
diff options
context:
space:
mode:
authorDLFW <daniel@llin.info>2022-01-04 00:05:15 +0100
committerGitHub <noreply@github.com>2022-01-03 18:05:15 -0500
commita420d6ae3dbc53da4e614b21c96d7b78b364dabb (patch)
treec07b5e7fb059181b376b7e4a4b2388f990ddee40 /src/fs
parent7791f93d95d350bdbb8dbdde4a9ec6fcbd32df41 (diff)
Continuous scrolling (#118)
* Continuous scrolling The scrolling behavior is changed from “paging” to a continuous scrolling. Joshuto keeps a buffer from the cursor to each end of the list, which is configured by `[display] scroll_offset`. If the terminal height is too small to keep the distance, the buffer is set to a value that assures that the cursor is at least as close to the end the user is scrolling towards as to the other end of the visible list. If the window is resized and the cursor jumps out of scope, the viewport is adjusted when changing the index next time. Possible improvements: * Issue a viewport update on terminal geometry change * When scrolling down to the bottom, don't allow an empty section beneath the last entry * Update documentation for scroll_offset * remove unused variable * keep viewport index when replacing dirlist * Don't keep copy of scroll_offset in JoshutoDirList * sanity: remove obsolete parameter
Diffstat (limited to 'src/fs')
-rw-r--r--src/fs/dirlist.rs82
1 files changed, 58 insertions, 24 deletions
diff --git a/src/fs/dirlist.rs b/src/fs/dirlist.rs
index 0c8d6d6..a2d4bb8 100644
--- a/src/fs/dirlist.rs
+++ b/src/fs/dirlist.rs
@@ -1,7 +1,9 @@
+use std::cmp;
use std::path;
use std::slice::{Iter, IterMut};
use crate::config::option::DisplayOption;
+use crate::context::UiContext;
use crate::fs::{JoshutoDirEntry, JoshutoMetadata};
use crate::history::read_directory;
@@ -10,8 +12,10 @@ pub struct JoshutoDirList {
path: path::PathBuf,
pub contents: Vec<JoshutoDirEntry>,
pub metadata: JoshutoMetadata,
- pub index: Option<usize>,
- pub viewport_index: usize,
+ /// The cursor position in this dir list
+ index: Option<usize>,
+ /// The index in this dir list to start with when rendering the list
+ viewport_index: usize,
_need_update: bool,
}
@@ -20,6 +24,7 @@ impl JoshutoDirList {
path: path::PathBuf,
contents: Vec<JoshutoDirEntry>,
index: Option<usize>,
+ viewport_index: usize,
metadata: JoshutoMetadata,
) -> Self {
Self {
@@ -27,7 +32,7 @@ impl JoshutoDirList {
contents,
metadata,
index,
- viewport_index: 0,
+ viewport_index,
_need_update: false,
}
}
@@ -41,17 +46,6 @@ impl JoshutoDirList {
let index = if contents.is_empty() { None } else { Some(0) };
- let viewport_index = match index {
- None => 0,
- Some(index) => {
- if index < options.scroll_offset() {
- 0
- } else {
- index - options.scroll_offset()
- }
- }
- };
-
let metadata = JoshutoMetadata::from(&path)?;
Ok(Self {
@@ -60,10 +54,56 @@ impl JoshutoDirList {
metadata,
_need_update: false,
index,
- viewport_index,
+ viewport_index: if let Some(ix) = index { ix } else { 0 },
})
}
+ pub fn get_index(&self) -> Option<usize> {
+ self.index
+ }
+
+ fn update_viewport(&mut self, ui_context: &UiContext, options: &DisplayOption) {
+ if let Some(ix) = self.index {
+ let height = ui_context.layout[0].height as usize;
+
+ // get scroll buffer size, corrected in case of too small terminal
+ let scroll_offset = if height < 4 {
+ 0
+ } else if options.scroll_offset() * 2 > height - 1 {
+ height / 2 - 1
+ } else {
+ options.scroll_offset()
+ };
+
+ // calculate viewport
+ let viewport_end = self.viewport_index + height;
+ if (viewport_end as i16 - ix as i16 - 1) < scroll_offset as i16 {
+ // cursor too low
+ self.viewport_index = (ix + scroll_offset - height + 1) as usize;
+ } else if (ix as i16 - self.viewport_index as i16) < scroll_offset as i16 {
+ // cursor too high
+ self.viewport_index = cmp::max(ix as i16 - scroll_offset as i16, 0) as usize;
+ }
+ } else {
+ self.viewport_index = 0;
+ }
+ }
+
+ pub fn set_index(
+ &mut self,
+ index: Option<usize>,
+ ui_context: &UiContext,
+ options: &DisplayOption,
+ ) {
+ if index == self.index {
+ return;
+ }
+ self.index = index;
+ if ui_context.layout.len() != 0 {
+ self.update_viewport(ui_context, options);
+ }
+ }
+
pub fn iter(&self) -> Iter<JoshutoDirEntry> {
self.contents.iter()
}
@@ -138,15 +178,9 @@ impl JoshutoDirList {
self.get_curr_mut_(self.index?)
}
- /// For a given number of entries, visible in a UI, this method returns the index of the entry
- /// with which the UI should start to list the entries.
- ///
- /// This method assures that the cursor is always in the viewport of the UI.
- pub fn first_index_for_viewport(&self, viewport_height: usize) -> usize {
- match self.index {
- Some(index) => index / viewport_height as usize * viewport_height as usize,
- None => 0,
- }
+ /// Returns the index of the first entry to be printed in a UI dir list
+ pub fn first_index_for_viewport(&self) -> usize {
+ self.viewport_index
}
fn get_curr_mut_(&mut self, index: usize) -> Option<&mut JoshutoDirEntry> {