summaryrefslogtreecommitdiffstats
path: root/src/fs
diff options
context:
space:
mode:
authorDLFW <daniel@llin.info>2022-08-30 19:46:22 +0200
committerGitHub <noreply@github.com>2022-08-30 13:46:22 -0400
commit826e24eaf4a10921bdd087079c4d7330896b79c2 (patch)
treeecce44e4243f7b58d110e071759a5ec32c6be2fb /src/fs
parentedf620b4aceaaadffedd14d85d120d485a6ad8f3 (diff)
Add "Visual-Mode" (#192)
* Add "Visual-Mode" This adds a "visual-mode" file selection feature where a range-selection follows the file-cursor. Description of usage is added to the docs. Also, the "normal" and the new "visual-mode-selection" are now preserved when a `DirList` is reloaded. Wrap-up of changes: * Add command `toggle_visual`, mapped to `V` * Add command `escape`, mapped to `ESCAPE` * Add style `[visual_mode_selection]` for file entries which are "temporarily" selected by visual-mode * For `JoshutoDirEntry`, the attribute `selected` has been renamed to `permanent_selected`, and a second selection-attribute `visual_mode_selected` has been added. "Setters" and "getters" have been adapted/added accordingly. The former "getter" for the `selecetd` attribute still exists and returns `True` for an entry which is "permanant selected" _or_ "visual-mode selected". So any higher logic which acts on selected files does not need to care about "how" and entry is selected. * Each `JoshutoDirList` has an optional index of the file where visual-mode has been entered and re-calculates the "visual-mode selecetd" status for each entry any time the cursor-index changes. * The footer has been extended so it shows a "VIS" marker when the user is in visual-mode. This implementation of visual-mode is a bit different from the ranger one, where the visual-selection is turned into a "normal selection" when a command (like `copy-files`) is issued. This implementation keeps both selections separate until the user toggles back to "normal mode". Only then the visual-selection is taken over to the "normal selection". The user also can withdraw the visual-selection with `escape`. The `escape` command may be used also for other "reset"-actions in the future. * fix syntax for Rust stable * cargo clippy
Diffstat (limited to 'src/fs')
-rw-r--r--src/fs/dirlist.rs62
-rw-r--r--src/fs/entry.rs26
-rw-r--r--src/fs/metadata.rs2
3 files changed, 84 insertions, 6 deletions
diff --git a/src/fs/dirlist.rs b/src/fs/dirlist.rs
index 096c9a0..567b8eb 100644
--- a/src/fs/dirlist.rs
+++ b/src/fs/dirlist.rs
@@ -15,6 +15,8 @@ pub struct JoshutoDirList {
index: Option<usize>,
/// The index in this dir list to start with when rendering the list
viewport_index: usize,
+ /// The index in this dir list where visual mode has started or None if not in visual mode
+ visual_mode_anchor_index: Option<usize>,
_need_update: bool,
}
@@ -24,6 +26,7 @@ impl JoshutoDirList {
contents: Vec<JoshutoDirEntry>,
index: Option<usize>,
viewport_index: usize,
+ visual_mode_anchor_index: Option<usize>,
metadata: JoshutoMetadata,
) -> Self {
Self {
@@ -32,6 +35,7 @@ impl JoshutoDirList {
metadata,
index,
viewport_index,
+ visual_mode_anchor_index,
_need_update: false,
}
}
@@ -55,6 +59,7 @@ impl JoshutoDirList {
_need_update: false,
index,
viewport_index: if let Some(ix) = index { ix } else { 0 },
+ visual_mode_anchor_index: None,
})
}
@@ -62,6 +67,62 @@ impl JoshutoDirList {
self.index
}
+ pub fn get_visual_mode_anchor_index(&self) -> Option<usize> {
+ self.visual_mode_anchor_index
+ }
+
+ fn update_visual_mode_selection(&mut self) {
+ //! To be invoked any time the cursor index, the visual mode anchor index,
+ //! or the shown sub-set of entries changes.
+ if let Some(vmix) = self.visual_mode_anchor_index {
+ if let Some(cix) = self.index {
+ self.iter_mut().enumerate().for_each(|(i, entry)| {
+ entry.set_visual_mode_selected(
+ (if vmix > cix {
+ cix..vmix + 1
+ } else {
+ vmix..cix + 1
+ })
+ .contains(&i),
+ )
+ })
+ }
+ } else {
+ self.iter_mut()
+ .for_each(|entry| entry.set_visual_mode_selected(false))
+ }
+ }
+
+ fn visual_mode_enable(&mut self) {
+ if let Some(ix) = self.index {
+ self.visual_mode_anchor_index = Some(ix)
+ };
+ self.update_visual_mode_selection();
+ }
+
+ fn visual_mode_disable(&mut self) {
+ self.visual_mode_anchor_index = None;
+ self.iter_mut().for_each(|entry| {
+ if entry.is_visual_mode_selected() {
+ entry.set_permanent_selected(true)
+ }
+ });
+ self.update_visual_mode_selection();
+ }
+
+ pub fn visual_mode_cancel(&mut self) {
+ self.visual_mode_anchor_index = None;
+ self.update_visual_mode_selection();
+ }
+
+ pub fn toggle_visual_mode(&mut self) {
+ if self.get_visual_mode_anchor_index().is_none() {
+ self.visual_mode_enable()
+ } else {
+ self.visual_mode_disable()
+ }
+ }
+
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;
@@ -106,6 +167,7 @@ impl JoshutoDirList {
if !ui_context.layout.is_empty() {
self.update_viewport(ui_context, options);
}
+ self.update_visual_mode_selection();
}
pub fn iter(&self) -> Iter<JoshutoDirEntry> {
diff --git a/src/fs/entry.rs b/src/fs/entry.rs
index 8337bc4..f7dae32 100644
--- a/src/fs/entry.rs
+++ b/src/fs/entry.rs
@@ -12,7 +12,10 @@ pub struct JoshutoDirEntry {
label: String,
path: path::PathBuf,
pub metadata: JoshutoMetadata,
- selected: bool,
+ /// Directly selected by the user, _not_ by a current visual mode selection
+ permanent_selected: bool,
+ /// Temporarily selected by the visual mode range
+ visual_mode_selected: bool,
_marked: bool,
}
@@ -63,11 +66,23 @@ impl JoshutoDirEntry {
}
pub fn is_selected(&self) -> bool {
- self.selected
+ self.permanent_selected || self.visual_mode_selected
}
- pub fn set_selected(&mut self, selected: bool) {
- self.selected = selected;
+ pub fn is_permanent_selected(&self) -> bool {
+ self.permanent_selected
+ }
+
+ pub fn is_visual_mode_selected(&self) -> bool {
+ self.visual_mode_selected
+ }
+
+ pub fn set_permanent_selected(&mut self, selected: bool) {
+ self.permanent_selected = selected;
+ }
+
+ pub fn set_visual_mode_selected(&mut self, visual_mode_selected: bool) {
+ self.visual_mode_selected = visual_mode_selected;
}
pub fn get_ext(&self) -> &str {
@@ -102,7 +117,8 @@ impl JoshutoDirEntry {
label,
path,
metadata,
- selected: false,
+ permanent_selected: false,
+ visual_mode_selected: false,
_marked: false,
})
}
diff --git a/src/fs/metadata.rs b/src/fs/metadata.rs
index fd192cc..616e09c 100644
--- a/src/fs/metadata.rs
+++ b/src/fs/metadata.rs
@@ -1,6 +1,6 @@
use std::{fs, io, path, time};
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub enum FileType {
Directory,
File,