summaryrefslogtreecommitdiffstats
path: root/src
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
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')
-rw-r--r--src/commands/escape.rs9
-rw-r--r--src/commands/flat.rs9
-rw-r--r--src/commands/mod.rs2
-rw-r--r--src/commands/quit.rs2
-rw-r--r--src/commands/selection.rs18
-rw-r--r--src/commands/uimodes.rs9
-rw-r--r--src/config/option/sort_type.rs2
-rw-r--r--src/config/theme/app_theme.rs5
-rw-r--r--src/context/app_context.rs2
-rw-r--r--src/fs/dirlist.rs62
-rw-r--r--src/fs/entry.rs26
-rw-r--r--src/fs/metadata.rs2
-rw-r--r--src/history.rs30
-rw-r--r--src/key_command/command.rs2
-rw-r--r--src/key_command/constants.rs2
-rw-r--r--src/key_command/impl_appcommand.rs3
-rw-r--r--src/key_command/impl_appexecute.rs5
-rw-r--r--src/key_command/impl_comment.rs3
-rw-r--r--src/key_command/impl_display.rs2
-rw-r--r--src/key_command/impl_from_str.rs4
-rw-r--r--src/ui/widgets/tui_footer.rs14
-rw-r--r--src/util/style.rs7
22 files changed, 198 insertions, 22 deletions
diff --git a/src/commands/escape.rs b/src/commands/escape.rs
new file mode 100644
index 0000000..1a507df
--- /dev/null
+++ b/src/commands/escape.rs
@@ -0,0 +1,9 @@
+use crate::context::AppContext;
+use crate::error::JoshutoResult;
+
+pub fn escape(context: &mut AppContext) -> JoshutoResult {
+ if let Some(curr_dir_list) = context.tab_context_mut().curr_tab_mut().curr_list_mut() {
+ curr_dir_list.visual_mode_cancel();
+ };
+ Ok(())
+}
diff --git a/src/commands/flat.rs b/src/commands/flat.rs
index c0e9dfb..b9d0a64 100644
--- a/src/commands/flat.rs
+++ b/src/commands/flat.rs
@@ -79,7 +79,14 @@ pub fn flatten(depth: usize, context: &mut AppContext) -> JoshutoResult {
contents.sort_by(|f1, f2| sort_options.compare(f1, f2));
let metadata = JoshutoMetadata::from(path.as_path())?;
- let dirlist = JoshutoDirList::new(path.clone(), contents, index, viewport_index, metadata);
+ let dirlist = JoshutoDirList::new(
+ path.clone(),
+ contents,
+ index,
+ viewport_index,
+ None,
+ metadata,
+ );
history.insert(path, dirlist);
Ok(())
diff --git a/src/commands/mod.rs b/src/commands/mod.rs
index f4e0ee5..c7420e2 100644
--- a/src/commands/mod.rs
+++ b/src/commands/mod.rs
@@ -3,6 +3,7 @@ pub mod change_directory;
pub mod command_line;
pub mod cursor_move;
pub mod delete_files;
+pub mod escape;
pub mod file_ops;
pub mod flat;
pub mod line_nums;
@@ -28,4 +29,5 @@ pub mod sub_process;
pub mod subdir_fzf;
pub mod tab_ops;
pub mod touch_file;
+pub mod uimodes;
pub mod zoxide;
diff --git a/src/commands/quit.rs b/src/commands/quit.rs
index ccc9a8b..165f289 100644
--- a/src/commands/quit.rs
+++ b/src/commands/quit.rs
@@ -3,7 +3,7 @@ use std::io;
use crate::context::AppContext;
use crate::error::{JoshutoError, JoshutoErrorKind, JoshutoResult};
-#[derive(Clone, Copy, Debug, PartialEq)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum QuitAction {
DoNot,
Noop,
diff --git a/src/commands/selection.rs b/src/commands/selection.rs
index a4d26c4..3bfa227 100644
--- a/src/commands/selection.rs
+++ b/src/commands/selection.rs
@@ -23,11 +23,11 @@ fn select_without_pattern(context: &mut AppContext, options: &SelectOption) -> J
if let Some(curr_list) = context.tab_context_mut().curr_tab_mut().curr_list_mut() {
curr_list.iter_mut().for_each(|e| {
if options.reverse {
- e.set_selected(false);
+ e.set_permanent_selected(false);
} else if options.toggle {
- e.set_selected(!e.is_selected());
+ e.set_permanent_selected(!e.is_selected());
} else {
- e.set_selected(true);
+ e.set_permanent_selected(true);
}
});
}
@@ -38,11 +38,11 @@ fn select_without_pattern(context: &mut AppContext, options: &SelectOption) -> J
.and_then(|s| s.curr_entry_mut())
{
if options.reverse {
- entry.set_selected(false);
+ entry.set_permanent_selected(false);
} else if options.toggle {
- entry.set_selected(!entry.is_selected());
+ entry.set_permanent_selected(!entry.is_selected());
} else {
- entry.set_selected(true);
+ entry.set_permanent_selected(true);
}
cursor_move::down(context, 1)?;
}
@@ -64,11 +64,11 @@ fn select_with_pattern(
.for_each(|e| {
found += 1;
if options.reverse {
- e.set_selected(false);
+ e.set_permanent_selected(false);
} else if options.toggle {
- e.set_selected(!e.is_selected());
+ e.set_permanent_selected(!e.is_selected());
} else {
- e.set_selected(true);
+ e.set_permanent_selected(true);
}
});
context
diff --git a/src/commands/uimodes.rs b/src/commands/uimodes.rs
new file mode 100644
index 0000000..480cc75
--- /dev/null
+++ b/src/commands/uimodes.rs
@@ -0,0 +1,9 @@
+use crate::context::AppContext;
+use crate::error::JoshutoResult;
+
+pub fn toggle_visual_mode(context: &mut AppContext) -> JoshutoResult {
+ if let Some(curr_dir_list) = context.tab_context_mut().curr_tab_mut().curr_list_mut() {
+ curr_dir_list.toggle_visual_mode()
+ };
+ Ok(())
+}
diff --git a/src/config/option/sort_type.rs b/src/config/option/sort_type.rs
index 442eb45..a00ad29 100644
--- a/src/config/option/sort_type.rs
+++ b/src/config/option/sort_type.rs
@@ -8,7 +8,7 @@ use serde_derive::Deserialize;
use crate::config::option::SortOption;
use crate::fs::JoshutoDirEntry;
-#[derive(Clone, Copy, Debug, Deserialize, PartialEq)]
+#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq)]
pub enum SortType {
Lexical,
Mtime,
diff --git a/src/config/theme/app_theme.rs b/src/config/theme/app_theme.rs
index 651b2fd..6e3dfec 100644
--- a/src/config/theme/app_theme.rs
+++ b/src/config/theme/app_theme.rs
@@ -13,6 +13,8 @@ pub struct AppThemeRaw {
#[serde(default)]
pub selection: AppStyleRaw,
#[serde(default)]
+ pub visual_mode_selection: AppStyleRaw,
+ #[serde(default)]
pub directory: AppStyleRaw,
#[serde(default)]
pub executable: AppStyleRaw,
@@ -29,6 +31,7 @@ pub struct AppThemeRaw {
impl From<AppThemeRaw> for AppTheme {
fn from(crude: AppThemeRaw) -> Self {
let selection = crude.selection.to_style_theme();
+ let visual_mode_selection = crude.visual_mode_selection.to_style_theme();
let executable = crude.executable.to_style_theme();
let regular = crude.regular.to_style_theme();
let directory = crude.directory.to_style_theme();
@@ -46,6 +49,7 @@ impl From<AppThemeRaw> for AppTheme {
Self {
selection,
+ visual_mode_selection,
executable,
regular,
directory,
@@ -61,6 +65,7 @@ impl From<AppThemeRaw> for AppTheme {
pub struct AppTheme {
pub regular: AppStyle,
pub selection: AppStyle,
+ pub visual_mode_selection: AppStyle,
pub directory: AppStyle,
pub executable: AppStyle,
pub link: AppStyle,
diff --git a/src/context/app_context.rs b/src/context/app_context.rs
index 364b5b1..66ffbc6 100644
--- a/src/context/app_context.rs
+++ b/src/context/app_context.rs
@@ -17,7 +17,7 @@ use crate::Args;
use notify::{RecursiveMode, Watcher};
use std::path;
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UiContext {
pub layout: Vec<Rect>,
}
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,
diff --git a/src/history.rs b/src/history.rs
index 42c5b0a..162c3bd 100644
--- a/src/history.rs
+++ b/src/history.rs
@@ -156,6 +156,8 @@ pub fn create_dirlist_with_history(
) -> io::Result<JoshutoDirList> {
let filter_func = options.filter_func();
let mut contents = read_directory(path, filter_func, options)?;
+
+ // re-use directory size information on reload
for entry in contents.iter_mut() {
if entry.metadata.is_dir() {
if let Some(lst) = history.get(entry.file_path()) {
@@ -164,6 +166,19 @@ pub fn create_dirlist_with_history(
}
}
+ // preserve selection status of entries on reload
+ if let Some(former_dir_list) = history.get(path) {
+ let former_entries_by_file_name = HashMap::<&str, &JoshutoDirEntry>::from_iter(
+ former_dir_list.contents.iter().map(|e| (e.file_name(), e)),
+ );
+ for entry in contents.iter_mut() {
+ if let Some(former_entry) = former_entries_by_file_name.get(entry.file_name()) {
+ entry.set_permanent_selected(former_entry.is_permanent_selected());
+ entry.set_visual_mode_selected(former_entry.is_visual_mode_selected());
+ }
+ }
+ }
+
let sort_options = tab_options.sort_options_ref();
contents.sort_by(|f1, f2| sort_options.compare(f1, f2));
@@ -199,6 +214,20 @@ pub fn create_dirlist_with_history(
None => 0,
}
};
+ let visual_mode_anchor_index = match history.get(path) {
+ None => None,
+ Some(dirlist) => {
+ dirlist
+ .get_visual_mode_anchor_index()
+ .map(|old_visual_mode_anchor_index| {
+ if old_visual_mode_anchor_index < contents_len {
+ old_visual_mode_anchor_index
+ } else {
+ contents_len - 1
+ }
+ })
+ }
+ };
let metadata = JoshutoMetadata::from(path)?;
let dirlist = JoshutoDirList::new(
@@ -206,6 +235,7 @@ pub fn create_dirlist_with_history(
contents,
index,
viewport_index,
+ visual_mode_anchor_index,
metadata,
);
diff --git a/src/key_command/command.rs b/src/key_command/command.rs
index 9ffbe5c..6c698ea 100644
--- a/src/key_command/command.rs
+++ b/src/key_command/command.rs
@@ -7,6 +7,8 @@ use crate::io::FileOperationOptions;
#[derive(Clone, Debug)]
#[allow(clippy::enum_variant_names)]
pub enum Command {
+ Escape,
+ ToggleVisualMode,
BulkRename,
ChangeDirectory(path::PathBuf),
diff --git a/src/key_command/constants.rs b/src/key_command/constants.rs
index 8dd60ed..68b99d2 100644
--- a/src/key_command/constants.rs
+++ b/src/key_command/constants.rs
@@ -69,6 +69,7 @@ cmd_constants![
(CMD_TAB_SWITCH, "tab_switch"),
(CMD_TAB_SWITCH_INDEX, "tab_switch_index"),
(CMD_TOGGLE_HIDDEN, "toggle_hidden"),
+ (CMD_TOGGLE_VISUAL, "toggle_visual"),
(CMD_SWITCH_LINE_NUMBERS, "line_nums"),
(CMD_TOUCH_FILE, "touch"),
(CMD_HELP, "help"),
@@ -77,6 +78,7 @@ cmd_constants![
(CMD_ZOXIDE, "z"),
(CMD_ZOXIDE_INTERACTIVE, "zi"),
(CMD_FLAT, "flat"),
+ (CMD_ESCAPE, "escape"),
];
pub fn complete_command(partial_command: &str) -> Vec<Pair> {
diff --git a/src/key_command/impl_appcommand.rs b/src/key_command/impl_appcommand.rs
index fe7dbc2..f942d82 100644
--- a/src/key_command/impl_appcommand.rs
+++ b/src/key_command/impl_appcommand.rs
@@ -8,6 +8,9 @@ impl AppCommand for Command {
Self::Quit(_) => CMD_QUIT,
+ Self::ToggleVisualMode => CMD_TOGGLE_VISUAL,
+ Self::Escape => CMD_ESCAPE,
+
Self::BulkRename => CMD_BULK_RENAME,
Self::ChangeDirectory(_) => CMD_CHANGE_DIRECTORY,
diff --git a/src/key_command/impl_appexecute.rs b/src/key_command/impl_appexecute.rs
index cd7aacc..65ef504 100644
--- a/src/key_command/impl_appexecute.rs
+++ b/src/key_command/impl_appexecute.rs
@@ -13,7 +13,10 @@ impl AppExecute for Command {
backend: &mut AppBackend,
keymap_t: &AppKeyMapping,
) -> JoshutoResult {
- match &*self {
+ match self {
+ Self::Escape => escape::escape(context),
+ Self::ToggleVisualMode => uimodes::toggle_visual_mode(context),
+
Self::BulkRename => bulk_rename::bulk_rename(context, backend),
Self::ChangeDirectory(p) => {
diff --git a/src/key_command/impl_comment.rs b/src/key_command/impl_comment.rs
index 36697c0..6f56c78 100644
--- a/src/key_command/impl_comment.rs
+++ b/src/key_command/impl_comment.rs
@@ -7,8 +7,11 @@ impl CommandComment for Command {
// These comments are displayed at the help page
fn comment(&self) -> &'static str {
match self {
+ Self::Escape => "Escape from visual mode (cancel)",
Self::BulkRename => "Bulk rename",
+ Self::ToggleVisualMode => "Toggle visual mode",
+
Self::ChangeDirectory(_) => "Change directory",
Self::ParentDirectory => "CD to parent directory",
Self::PreviousDirectory => "CD to the last dir in history",
diff --git a/src/key_command/impl_display.rs b/src/key_command/impl_display.rs
index 9c9a7b4..c414486 100644
--- a/src/key_command/impl_display.rs
+++ b/src/key_command/impl_display.rs
@@ -2,7 +2,7 @@ use super::{AppCommand, Command};
impl std::fmt::Display for Command {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
- match &*self {
+ match self {
Self::ChangeDirectory(p) => write!(f, "{} {:?}", self.command(), p),
Self::CommandLine(s, p) => write!(f, "{} {} {}", self.command(), s, p),
Self::CursorMoveUp(i) => write!(f, "{} {}", self.command(), i),
diff --git a/src/key_command/impl_from_str.rs b/src/key_command/impl_from_str.rs
index 2c9fc96..f358e3e 100644
--- a/src/key_command/impl_from_str.rs
+++ b/src/key_command/impl_from_str.rs
@@ -34,6 +34,10 @@ impl std::str::FromStr for Command {
None => (s, ""),
};
+ simple_command_conversion_case!(command, CMD_ESCAPE, Self::Escape);
+
+ simple_command_conversion_case!(command, CMD_TOGGLE_VISUAL, Self::ToggleVisualMode);
+
simple_command_conversion_case!(command, CMD_NEW_TAB, Self::NewTab);
simple_command_conversion_case!(command, CMD_CLOSE_TAB, Self::CloseTab);
diff --git a/src/ui/widgets/tui_footer.rs b/src/ui/widgets/tui_footer.rs
index 1cc0995..d4fbef7 100644
--- a/src/ui/widgets/tui_footer.rs
+++ b/src/ui/widgets/tui_footer.rs
@@ -26,6 +26,7 @@ impl<'a> Widget for TuiFooter<'a> {
Some(i) if i < self.dirlist.len() => {
let entry = &self.dirlist.contents[i];
+ let visual_mode_style = Style::default().fg(Color::Black).bg(Color::LightRed);
let mode_style = Style::default().fg(Color::Cyan);
let mode_str = unix::mode_to_string(entry.metadata.permissions_ref().mode());
@@ -33,6 +34,19 @@ impl<'a> Widget for TuiFooter<'a> {
let size_str = format::file_size_to_string(entry.metadata.len());
let mut text = vec![
+ Span::styled(
+ if self.dirlist.get_visual_mode_anchor_index().is_none() {
+ ""
+ } else {
+ "VIS"
+ },
+ visual_mode_style,
+ ),
+ Span::raw(if self.dirlist.get_visual_mode_anchor_index().is_none() {
+ ""
+ } else {
+ " "
+ }),
Span::styled(mode_str, mode_style),
Span::raw(" "),
Span::raw(format!("{}/{}", i + 1, self.dirlist.len())),
diff --git a/src/util/style.rs b/src/util/style.rs
index 4312425..6715f50 100644
--- a/src/util/style.rs
+++ b/src/util/style.rs
@@ -10,7 +10,12 @@ pub fn entry_style(entry: &JoshutoDirEntry) -> Style {
let filetype = &metadata.file_type();
let linktype = &metadata.link_type();
- if entry.is_selected() {
+ if entry.is_visual_mode_selected() {
+ Style::default()
+ .fg(THEME_T.visual_mode_selection.fg)
+ .bg(THEME_T.visual_mode_selection.bg)
+ .add_modifier(THEME_T.visual_mode_selection.modifier)
+ } else if entry.is_permanent_selected() {
Style::default()
.fg(THEME_T.selection.fg)
.bg(THEME_T.selection.bg)