summaryrefslogtreecommitdiffstats
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
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
-rw-r--r--docs/configuration/joshuto.toml.md1
-rw-r--r--src/commands/change_directory.rs3
-rw-r--r--src/commands/cursor_move.rs20
-rw-r--r--src/commands/parent_cursor_move.rs14
-rw-r--r--src/commands/search_glob.rs4
-rw-r--r--src/commands/search_string.rs4
-rw-r--r--src/commands/subdir_fzf.rs4
-rw-r--r--src/commands/tab_ops.rs6
-rw-r--r--src/context/app_context.rs16
-rw-r--r--src/fs/dirlist.rs82
-rw-r--r--src/history.rs40
-rw-r--r--src/preview/preview_default.rs2
-rw-r--r--src/run.rs60
-rw-r--r--src/tab.rs13
-rw-r--r--src/ui/widgets/tui_dirlist.rs33
-rw-r--r--src/ui/widgets/tui_dirlist_detailed.rs64
-rw-r--r--src/ui/widgets/tui_footer.rs2
-rw-r--r--src/util/input.rs3
18 files changed, 234 insertions, 137 deletions
diff --git a/docs/configuration/joshuto.toml.md b/docs/configuration/joshuto.toml.md
index eeacf58..a1171be 100644
--- a/docs/configuration/joshuto.toml.md
+++ b/docs/configuration/joshuto.toml.md
@@ -4,7 +4,6 @@ This file is for general configurations.
All options available and their default values:
```toml
# This is for configuring how many items to reach before 'scrolling' the view
-# CURRENTLY DOES NOT WORK
scroll_offset = 6
# If joshuto does not know how to open the file, it can resort to opening it via xdg settings
diff --git a/src/commands/change_directory.rs b/src/commands/change_directory.rs
index 7b89726..6a39337 100644
--- a/src/commands/change_directory.rs
+++ b/src/commands/change_directory.rs
@@ -13,11 +13,12 @@ pub fn cd(path: &path::Path, context: &mut AppContext) -> std::io::Result<()> {
fn change_directory_helper(path: &path::Path, context: &mut AppContext) -> std::io::Result<()> {
cd(path, context)?;
let options = context.config_ref().display_options_ref().clone();
+ let ui_context = context.ui_context_ref().clone();
context
.tab_context_mut()
.curr_tab_mut()
.history_mut()
- .populate_to_root(path, &options)?;
+ .populate_to_root(path, &ui_context, &options)?;
Ok(())
}
diff --git a/src/commands/cursor_move.rs b/src/commands/cursor_move.rs
index def90b2..5d9430f 100644
--- a/src/commands/cursor_move.rs
+++ b/src/commands/cursor_move.rs
@@ -41,20 +41,24 @@ pub fn lazy_load_directory_size(context: &mut AppContext) {
pub fn cursor_move(context: &mut AppContext, new_index: usize) {
lazy_load_directory_size(context);
let mut new_index = new_index;
+ let ui_context = context.ui_context_ref().clone();
+ let display_options = context.config_ref().display_options_ref().clone();
if let Some(curr_list) = context.tab_context_mut().curr_tab_mut().curr_list_mut() {
if !curr_list.is_empty() {
let dir_len = curr_list.len();
if new_index >= dir_len {
new_index = dir_len - 1;
}
- curr_list.index = Some(new_index);
+ curr_list.set_index(Some(new_index), &ui_context, &display_options);
}
}
}
pub fn up(context: &mut AppContext, u: usize) -> JoshutoResult<()> {
let movement = match context.tab_context_ref().curr_tab_ref().curr_list_ref() {
- Some(curr_list) => curr_list.index.map(|idx| if idx > u { idx - u } else { 0 }),
+ Some(curr_list) => curr_list
+ .get_index()
+ .map(|idx| if idx > u { idx - u } else { 0 }),
None => None,
};
@@ -66,7 +70,7 @@ pub fn up(context: &mut AppContext, u: usize) -> JoshutoResult<()> {
pub fn down(context: &mut AppContext, u: usize) -> JoshutoResult<()> {
let movement = match context.tab_context_ref().curr_tab_ref().curr_list_ref() {
- Some(curr_list) => curr_list.index.map(|idx| idx + u),
+ Some(curr_list) => curr_list.get_index().map(|idx| idx + u),
None => None,
};
if let Some(s) = movement {
@@ -135,9 +139,11 @@ pub fn page_up(context: &mut AppContext, backend: &mut TuiBackend) -> JoshutoRes
let page_size = get_page_size(context, backend).unwrap_or(10);
let movement = match context.tab_context_ref().curr_tab_ref().curr_list_ref() {
- Some(curr_list) => curr_list
- .index
- .map(|idx| if idx > page_size { idx - page_size } else { 0 }),
+ Some(curr_list) => {
+ curr_list
+ .get_index()
+ .map(|idx| if idx > page_size { idx - page_size } else { 0 })
+ }
None => None,
};
@@ -153,7 +159,7 @@ pub fn page_down(context: &mut AppContext, backend: &mut TuiBackend) -> JoshutoR
let movement = match context.tab_context_ref().curr_tab_ref().curr_list_ref() {
Some(curr_list) => {
let dir_len = curr_list.len();
- curr_list.index.map(|idx| {
+ curr_list.get_index().map(|idx| {
if idx + page_size > dir_len - 1 {
dir_len - 1
} else {
diff --git a/src/commands/parent_cursor_move.rs b/src/commands/parent_cursor_move.rs
index d1247d1..3bab3d3 100644
--- a/src/commands/parent_cursor_move.rs
+++ b/src/commands/parent_cursor_move.rs
@@ -8,17 +8,19 @@ pub fn parent_cursor_move(context: &mut AppContext, new_index: usize) -> Joshuto
let mut new_index = new_index;
{
+ let ui_context = context.ui_context_ref().clone();
+ let display_options = context.config_ref().display_options_ref().clone();
let curr_tab = context.tab_context_mut().curr_tab_mut();
if let Some(curr_list) = curr_tab.parent_list_mut() {
- if curr_list.index.is_some() {
+ if curr_list.get_index().is_some() {
let dir_len = curr_list.contents.len();
if new_index >= dir_len {
new_index = dir_len - 1;
}
let entry = &curr_list.contents[new_index];
if entry.file_path().is_dir() {
- curr_list.index = Some(new_index);
- path = Some(entry.file_path().to_path_buf())
+ path = Some(entry.file_path().to_path_buf());
+ curr_list.set_index(Some(new_index), &ui_context, &display_options);
}
}
}
@@ -31,7 +33,9 @@ pub fn parent_cursor_move(context: &mut AppContext, new_index: usize) -> Joshuto
pub fn parent_up(context: &mut AppContext, u: usize) -> JoshutoResult<()> {
let movement = match context.tab_context_ref().curr_tab_ref().parent_list_ref() {
- Some(list) => list.index.map(|idx| if idx > u { idx - u } else { 0 }),
+ Some(list) => list
+ .get_index()
+ .map(|idx| if idx > u { idx - u } else { 0 }),
None => None,
};
@@ -44,7 +48,7 @@ pub fn parent_up(context: &mut AppContext, u: usize) -> JoshutoResult<()> {
pub fn parent_down(context: &mut AppContext, u: usize) -> JoshutoResult<()> {
let movement = match context.tab_context_ref().curr_tab_ref().parent_list_ref() {
- Some(list) => list.index.map(|idx| idx + u),
+ Some(list) => list.get_index().map(|idx| idx + u),
None => None,
};
if let Some(s) = movement {
diff --git a/src/commands/search_glob.rs b/src/commands/search_glob.rs
index a6ca267..c761523 100644
--- a/src/commands/search_glob.rs
+++ b/src/commands/search_glob.rs
@@ -10,7 +10,7 @@ use super::cursor_move;
pub fn search_glob_fwd(curr_tab: &JoshutoTab, glob: &GlobMatcher) -> Option<usize> {
let curr_list = curr_tab.curr_list_ref()?;
- let offset = curr_list.index? + 1;
+ let offset = curr_list.get_index()? + 1;
let contents_len = curr_list.len();
for i in 0..contents_len {
let file_name = curr_list.contents[(offset + i) % contents_len].file_name();
@@ -23,7 +23,7 @@ pub fn search_glob_fwd(curr_tab: &JoshutoTab, glob: &GlobMatcher) -> Option<usiz
pub fn search_glob_rev(curr_tab: &JoshutoTab, glob: &GlobMatcher) -> Option<usize> {
let curr_list = curr_tab.curr_list_ref()?;
- let offset = curr_list.index?;
+ let offset = curr_list.get_index()?;
let contents_len = curr_list.len();
for i in (0..contents_len).rev() {
let file_name = curr_list.contents[(offset + i) % contents_len].file_name();
diff --git a/src/commands/search_string.rs b/src/commands/search_string.rs
index b5ea94a..62d9a7f 100644
--- a/src/commands/search_string.rs
+++ b/src/commands/search_string.rs
@@ -8,7 +8,7 @@ use super::cursor_move;
pub fn search_string_fwd(curr_tab: &JoshutoTab, pattern: &str) -> Option<usize> {
let curr_list = curr_tab.curr_list_ref()?;
- let offset = curr_list.index? + 1;
+ let offset = curr_list.get_index()? + 1;
let contents_len = curr_list.contents.len();
for i in 0..contents_len {
let file_name_lower = curr_list.contents[(offset + i) % contents_len]
@@ -23,7 +23,7 @@ pub fn search_string_fwd(curr_tab: &JoshutoTab, pattern: &str) -> Option<usize>
pub fn search_string_rev(curr_tab: &JoshutoTab, pattern: &str) -> Option<usize> {
let curr_list = curr_tab.curr_list_ref()?;
- let offset = curr_list.index?;
+ let offset = curr_list.get_index()?;
let contents_len = curr_list.contents.len();
for i in (0..contents_len).rev() {
let file_name_lower = curr_list.contents[(offset + i) % contents_len]
diff --git a/src/commands/subdir_fzf.rs b/src/commands/subdir_fzf.rs
index 74c86f2..51de88f 100644
--- a/src/commands/subdir_fzf.rs
+++ b/src/commands/subdir_fzf.rs
@@ -80,8 +80,10 @@ pub fn fzf_change_dir(context: &mut AppContext, path: &Path) -> JoshutoResult<()
};
if let Some(index) = index {
+ let ui_context = context.ui_context_ref().clone();
+ let display_options = context.config_ref().display_options_ref().clone();
if let Some(curr_list) = context.tab_context_mut().curr_tab_mut().curr_list_mut() {
- curr_list.index = Some(index);
+ curr_list.set_index(Some(index), &ui_context, &display_options);
}
}
}
diff --git a/src/commands/tab_ops.rs b/src/commands/tab_ops.rs
index 0d6ff82..dd27998 100644
--- a/src/commands/tab_ops.rs
+++ b/src/commands/tab_ops.rs
@@ -96,7 +96,11 @@ pub fn new_tab_home_path(context: &AppContext) -> path::PathBuf {
pub fn new_tab(context: &mut AppContext) -> JoshutoResult<()> {
let new_tab_path = new_tab_home_path(context);
- let tab = JoshutoTab::new(new_tab_path, context.config_ref().display_options_ref())?;
+ let tab = JoshutoTab::new(
+ new_tab_path,
+ context.ui_context_ref(),
+ context.config_ref().display_options_ref(),
+ )?;
context.tab_context_mut().push_tab(tab);
let new_index = context.tab_context_ref().len() - 1;
context.tab_context_mut().index = new_index;
diff --git a/src/context/app_context.rs b/src/context/app_context.rs
index 30aafae..0bdcf28 100644
--- a/src/context/app_context.rs
+++ b/src/context/app_context.rs
@@ -1,5 +1,6 @@
use std::collections::HashSet;
use std::sync::mpsc;
+use tui::layout::Rect;
use crate::config;
use crate::context::{
@@ -20,6 +21,11 @@ pub enum QuitType {
ChooseFiles,
}
+#[derive(Clone, Debug, PartialEq)]
+pub struct UiContext {
+ pub layout: Vec<Rect>,
+}
+
pub struct AppContext {
pub quit: QuitType,
// event loop querying
@@ -42,6 +48,8 @@ pub struct AppContext {
preview_context: PreviewContext,
// context related to command line
commandline_context: CommandLineContext,
+ // user interface context; data which is input to both, the UI rendering and the app state
+ ui_context: UiContext,
// filesystem watcher to inform about changes in shown directories
#[cfg(target_os = "linux")]
watcher: notify::INotifyWatcher,
@@ -81,6 +89,7 @@ impl AppContext {
message_queue: MessageQueue::new(),
worker_context: WorkerContext::new(event_tx),
preview_context: PreviewContext::new(),
+ ui_context: UiContext { layout: vec![] },
commandline_context,
config,
watcher,
@@ -172,6 +181,13 @@ impl AppContext {
&mut self.preview_context
}
+ pub fn ui_context_ref(&self) -> &UiContext {
+ &self.ui_context
+ }
+ pub fn ui_context_mut(&mut self) -> &mut UiContext {
+ &mut self.ui_context
+ }
+
pub fn worker_context_ref(&self) -> &WorkerContext {
&self.worker_context
}
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> {
diff --git a/src/history.rs b/src/history.rs
index e754705..391cb8d 100644
--- a/src/history.rs
+++ b/src/history.rs
@@ -4,10 +4,16 @@ use std::io;
use std::path::{Path, PathBuf};
use crate::config::option::DisplayOption;
+use crate::context::UiContext;
use crate::fs::{JoshutoDirEntry, JoshutoDirList, JoshutoMetadata};
pub trait DirectoryHistory {
- fn populate_to_root(&mut self, path: &Path, options: &DisplayOption) -> io::Result<()>;
+ fn populate_to_root(
+ &mut self,
+ path: &Path,
+ ui_context: &UiContext,
+ options: &DisplayOption,
+ ) -> io::Result<()>;
fn create_or_soft_update(&mut self, path: &Path, options: &DisplayOption) -> io::Result<()>;
fn create_or_reload(&mut self, path: &Path, options: &DisplayOption) -> io::Result<()>;
fn reload(&mut self, path: &Path, options: &DisplayOption) -> io::Result<()>;
@@ -19,7 +25,12 @@ pub trait DirectoryHistory {
pub type JoshutoHistory = HashMap<PathBuf, JoshutoDirList>;
impl DirectoryHistory for JoshutoHistory {
- fn populate_to_root(&mut self, path: &Path, options: &DisplayOption) -> io::Result<()> {
+ fn populate_to_root(
+ &mut self,
+ path: &Path,
+ ui_context: &UiContext,
+ options: &DisplayOption,
+ ) -> io::Result<()> {
let mut dirlists = Vec::new();
let mut prev: Option<&Path> = None;
@@ -28,7 +39,7 @@ impl DirectoryHistory for JoshutoHistory {
let mut new_dirlist = create_dirlist_with_history(self, curr, options)?;
if let Some(ancestor) = prev.as_ref() {
if let Some(i) = get_index_of_value(&new_dirlist.contents, ancestor) {
- new_dirlist.index = Some(i);
+ new_dirlist.set_index(Some(i), &ui_context, &options);
}
}
dirlists.push(new_dirlist);
@@ -37,7 +48,7 @@ impl DirectoryHistory for JoshutoHistory {
JoshutoDirList::from_path(curr.to_path_buf().clone(), options)?;
if let Some(ancestor) = prev.as_ref() {
if let Some(i) = get_index_of_value(&new_dirlist.contents, ancestor) {
- new_dirlist.index = Some(i);
+ new_dirlist.set_index(Some(i), &ui_context, &options);
}
}
dirlists.push(new_dirlist);
@@ -127,7 +138,7 @@ pub fn create_dirlist_with_history(
None
} else {
match history.get(path) {
- Some(dirlist) => match dirlist.index {
+ Some(dirlist) => match dirlist.get_index() {
Some(i) if i >= contents_len => Some(contents_len - 1),
Some(i) => {
let entry = &dirlist.contents[i];
@@ -143,9 +154,26 @@ pub fn create_dirlist_with_history(
None => Some(0),
}
};
+ let viewport_index: usize = if contents_len == 0 {
+ 0
+ } else {
+ match history.get(path) {
+ Some(dirlist) => match dirlist.first_index_for_viewport() {
+ i if i >= contents_len => contents_len - 1,
+ i => i,
+ },
+ None => 0,
+ }
+ };
let metadata = JoshutoMetadata::from(path)?;
- let dirlist = JoshutoDirList::new(path.to_path_buf(), contents, index, metadata);
+ let dirlist = JoshutoDirList::new(
+ path.to_path_buf(),
+ contents,
+ index,
+ viewport_index,
+ metadata,
+ );
Ok(dirlist)
}
diff --git a/src/preview/preview_default.rs b/src/preview/preview_default.rs
index bda1077..56947b6 100644
--- a/src/preview/preview_default.rs
+++ b/src/preview/preview_default.rs
@@ -44,7 +44,7 @@ pub fn load_preview(context: &mut AppContext, backend: &mut TuiBackend) {
let curr_tab = context.tab_context_ref().curr_tab_ref();
match curr_tab.curr_list_ref() {
Some(curr_list) => {
- if let Some(index) = curr_list.index {
+ if let Some(index) = curr_list.get_index() {
let entry = &curr_list.contents[index];
load_list.push((entry.file_path().to_path_buf(), entry.metadata.clone()));
}
diff --git a/src/run.rs b/src/run.rs
index 7f4cc9f..bfe6b16 100644
--- a/src/run.rs
+++ b/src/run.rs
@@ -12,7 +12,6 @@ use crate::ui::PreviewArea;
use crate::util::input;
use crate::util::to_string::ToString;
-use std::path::{Path, PathBuf};
use std::process;
use std::thread;
use termion::event::{Event, Key};
@@ -26,7 +25,11 @@ pub fn run(
let curr_path = std::env::current_dir()?;
{
// Initialize an initial tab
- let tab = JoshutoTab::new(curr_path, context.config_ref().display_options_ref())?;
+ let tab = JoshutoTab::new(
+ curr_path,
+ context.ui_context_ref(),
+ context.config_ref().display_options_ref(),
+ )?;
context.tab_context_mut().push_tab(tab);
// trigger a preview of child
@@ -36,27 +39,25 @@ pub fn run(
let mut preview_area: Option<PreviewArea> = None;
while context.quit == QuitType::DoNot {
- backend.render(TuiView::new(context));
+ // do the ui
+ if let Ok(area) = backend.terminal_ref().size() {
+ // pre-calculate some ui attributes
+ calculate_ui_context(context, area);
- {
- let config = context.config_ref();
- let preview_options = config.preview_options_ref();
- if let Ok(area) = backend.terminal_ref().size() {
- preview_area = process_preview_on_change(
- &context,
- area,
- preview_area,
- preview_options.preview_shown_hook_script.as_ref(),
- preview_options.preview_removed_hook_script.as_ref(),
- );
- }
+ // render the ui
+ backend.render(TuiView::new(context));
+
+ // invoke preview hooks, if appropriate
+ preview_area = process_preview_on_change(&context, preview_area);
}
+ // wait for an event and pop it
let event = match context.poll_event() {
Ok(event) => event,
Err(_) => return Ok(()), // TODO
};
+ // handle the event
match event {
AppEvent::Termion(Event::Mouse(event)) => {
input::process_mouse(event, context, backend, &keymap_t);
@@ -106,34 +107,41 @@ pub fn run(
}
event => input::process_noninteractive(event, context),
}
+
+ // update the file system supervisor that watches for changes in the FS
context.update_watcher();
- }
+ } // end of main loop
Ok(())
}
-fn process_preview_on_change(
- context: &AppContext,
- area: Rect,
- old_preview_area: Option<PreviewArea>,
- preview_shown_hook_script: Option<&PathBuf>,
- preview_removed_hook_script: Option<&PathBuf>,
-) -> Option<PreviewArea> {
+fn calculate_ui_context(context: &mut AppContext, area: Rect) {
let area = Rect {
y: area.top() + 1,
height: area.height - 2,
..area
};
-
- let constraints = views::get_constraints(&context);
let config = context.config_ref();
let display_options = config.display_options_ref();
+ let constraints = views::get_constraints(&context);
let layout = if display_options.show_borders() {
views::calculate_layout_with_borders(area, constraints)
} else {
views::calculate_layout(area, constraints)
};
- let new_preview_area = views::calculate_preview(&context, layout[2]);
+ context.ui_context_mut().layout = layout;
+}
+
+fn process_preview_on_change(
+ context: &AppContext,
+ old_preview_area: Option<PreviewArea>,
+) -> Option<PreviewArea> {
+ let config = context.config_ref();
+ let preview_options = config.preview_options_ref();
+ let preview_shown_hook_script = preview_options.preview_shown_hook_script.as_ref();
+ let preview_removed_hook_script = preview_options.preview_removed_hook_script.as_ref();
+ let layout = &context.ui_context_ref().layout;
+ let new_preview_area = views::calculate_preview(&context, layout[2]);
match new_preview_area.as_ref() {
Some(new) => {
let should_preview = if let Some(old) = old_preview_area {
diff --git a/src/tab.rs b/src/tab.rs
index 4e2f2e4..190037f 100644
--- a/src/tab.rs
+++ b/src/tab.rs
@@ -1,6 +1,7 @@
use std::path;
use crate::config::option::DisplayOption;
+use crate::context::UiContext;
use crate::fs::JoshutoDirList;
use crate::history::{DirectoryHistory, JoshutoHistory};
@@ -17,9 +18,13 @@ pub struct JoshutoTab {
}
impl JoshutoTab {
- pub fn new(cwd: path::PathBuf, options: &DisplayOption) -> std::io::Result<Self> {
+ pub fn new(
+ cwd: path::PathBuf,
+ ui_context: &UiContext,
+ options: &DisplayOption,
+ ) -> std::io::Result<Self> {
let mut history = JoshutoHistory::new();
- history.populate_to_root(cwd.as_path(), options)?;
+ history.populate_to_root(cwd.as_path(), ui_context, options)?;
Ok(Self { _cwd: cwd, history })
}
@@ -51,7 +56,7 @@ impl JoshutoTab {
pub fn child_list_ref(&self) -> Option<&JoshutoDirList> {
let curr_list = self.curr_list_ref()?;
- let index = curr_list.index?;
+ let index = curr_list.get_index()?;
let path = curr_list.contents[index].file_path();
self.history.get(path)
}
@@ -69,7 +74,7 @@ impl JoshutoTab {
pub fn child_list_mut(&mut self) -> Option<&mut JoshutoDirList> {
let child_path = {
let curr_list = self.curr_list_ref()?;
- let index = curr_list.index?;
+ let index = curr_list.get_index()?;
curr_list.contents[index].file_path().to_path_buf()
};
diff --git a/src/ui/widgets/tui_dirlist.rs b/src/ui/widgets/tui_dirlist.rs
index 9a14e6a..946834b 100644
--- a/src/ui/widgets/tui_dirlist.rs
+++ b/src/ui/widgets/tui_dirlist.rs
@@ -32,8 +32,8 @@ impl<'a> Widget for TuiDirList<'a> {
return;
}
- let curr_index = self.dirlist.index.unwrap();
- let skip_dist = self.dirlist.first_index_for_viewport(area.height as usize);
+ let curr_index = self.dirlist.get_index().unwrap();
+ let skip_dist = self.dirlist.first_index_for_viewport();
let drawing_width = area.width as usize;
@@ -43,26 +43,21 @@ impl<'a> Widget for TuiDirList<'a> {
.enumerate()
.take(area.height as usize)
.for_each(|(i, entry)| {
- let style = style::entry_style(entry);
- print_entry(buf, entry, style, (x + 1, y + i as u16), drawing_width - 1);
- });
-
- // draw selected entry in a different style
- let screen_index = curr_index % area.height as usize;
+ let ix = skip_dist + i;
- let entry = self.dirlist.curr_entry_ref().unwrap();
- let style = style::entry_style(entry).add_modifier(Modifier::REVERSED);
+ let style = if ix == curr_index {
+ style::entry_style(entry).add_modifier(Modifier::REVERSED)
+ } else {
+ style::entry_style(entry)
+ };
- let space_fill = " ".repeat(drawing_width);
- buf.set_string(x, y + screen_index as u16, space_fill.as_str(), style);
+ if ix == curr_index {
+ let space_fill = " ".repeat(drawing_width);
+ buf.set_string(x, y + i as u16, space_fill.as_str(), style);
+ }
- print_entry(
- buf,
- entry,
- style,
- (x + 1, y + screen_index as u16),
- drawing_width - 1,
- );
+ print_entry(buf, entry, style, (x + 1, y + i as u16), drawing_width - 1);
+ });
}
}
diff --git a/src/ui/widgets/tui_dirlist_detailed.rs b/src/ui/widgets/tui_dirlist_detailed.rs
index 7cb0693..f5d07be 100644
--- a/src/ui/widgets/tui_dirlist_detailed.rs
+++ b/src/ui/widgets/tui_dirlist_detailed.rs
@@ -37,7 +37,7 @@ impl<'a> Widget for TuiDirListDetailed<'a> {
let x = area.left();
let y = area.top();
- let curr_index = match self.dirlist.index {
+ let curr_index = match self.dirlist.get_index() {
Some(i) => i,
None => {
let style = Style::default().bg(Color::Red).fg(Color::White);
@@ -47,8 +47,7 @@ impl<'a> Widget for TuiDirListDetailed<'a> {
};
let drawing_width = area.width as usize;
- let skip_dist = self.dirlist.first_index_for_viewport(area.height as usize);
- let screen_index = curr_index % area.height as usize;
+ let skip_dist = self.dirlist.first_index_for_viewport();
let line_num_style = self.display_options.line_nums();
// Length (In chars) of the last entry's index on current page.
// Using this to align all elements
@@ -64,20 +63,38 @@ impl<'a> Widget for TuiDirListDetailed<'a> {
.enumerate()
.take(area.height as usize)
.for_each(|(i, entry)| {
- let style = style::entry_style(entry);
+ let ix = skip_dist + i;
- let line_number_string = match line_num_style {
- LineNumberStyle::Absolute => {
- format!("{:1$} ", skip_dist + i + 1, max_index_length)
+ let style = if ix == curr_index {
+ style::entry_style(entry).add_modifier(Modifier::REVERSED)
+ } else {
+ style::entry_style(entry)
+ };
+
+ let line_number_string = if ix == curr_index {
+ match line_num_style {
+ LineNumberStyle::None => "".to_string(),
+ _ => format!("{:<1$} ", curr_index + 1, max_index_length),
+ }
+ } else {
+ match line_num_style {