filter by file selection

This commit is contained in:
rabite 2019-06-30 14:53:44 +02:00
parent c5e0b6fa03
commit 15e2f89a64
4 changed files with 62 additions and 12 deletions

View File

@ -213,6 +213,7 @@ By default hunter uses vi-style keybindings. If you use a QWERTY-like keyboard l
| Alt(space) | select with external program | | Alt(space) | select with external program |
| v | invert selections | | v | invert selections |
| V | clear all selections | | V | clear all selections |
| Alt(v) | only show selected files |
| t | toggle tag | | t | toggle tag |
| h | toggle show hidden | | h | toggle show hidden |
| r | reverse sort | | r | reverse sort |

View File

@ -109,6 +109,7 @@ pub struct Files {
pub reverse: bool, pub reverse: bool,
pub show_hidden: bool, pub show_hidden: bool,
pub filter: Option<String>, pub filter: Option<String>,
pub filter_selected: bool,
pub dirty: DirtyBit, pub dirty: DirtyBit,
pub dirty_meta: AsyncDirtyBit, pub dirty_meta: AsyncDirtyBit,
} }
@ -164,6 +165,7 @@ impl Files {
reverse: false, reverse: false,
show_hidden: true, show_hidden: true,
filter: None, filter: None,
filter_selected: false,
dirty: dirty, dirty: dirty,
dirty_meta: dirty_meta, dirty_meta: dirty_meta,
}; };
@ -221,6 +223,7 @@ impl Files {
reverse: false, reverse: false,
show_hidden: true, show_hidden: true,
filter: None, filter: None,
filter_selected: false,
dirty: dirty, dirty: dirty,
dirty_meta: dirty_meta, dirty_meta: dirty_meta,
}; };
@ -236,6 +239,7 @@ impl Files {
pub fn get_file_mut(&mut self, index: usize) -> Option<&mut File> { pub fn get_file_mut(&mut self, index: usize) -> Option<&mut File> {
let filter = self.filter.clone(); let filter = self.filter.clone();
let filter_selected = self.filter_selected;
let show_hidden = self.show_hidden; let show_hidden = self.show_hidden;
let file = self.files let file = self.files
@ -243,7 +247,8 @@ impl Files {
.filter(|f| .filter(|f|
f.kind == Kind::Placeholder || f.kind == Kind::Placeholder ||
!(filter.is_some() && !(filter.is_some() &&
!f.name.contains(filter.as_ref().unwrap()))) !f.name.contains(filter.as_ref().unwrap())) &&
(!filter_selected || f.selected))
.filter(|f| !(!show_hidden && f.name.starts_with("."))) .filter(|f| !(!show_hidden && f.name.starts_with(".")))
.nth(index); .nth(index);
file file
@ -254,21 +259,25 @@ impl Files {
.iter() .iter()
.filter(|f| .filter(|f|
f.kind == Kind::Placeholder || f.kind == Kind::Placeholder ||
(!(self.filter.is_some() && !(self.filter.is_some() &&
!f.name.contains(self.filter.as_ref().unwrap())))) !f.name.contains(self.filter.as_ref().unwrap())) &&
(!self.filter_selected || f.selected))
.filter(|f| !(!self.show_hidden && f.name.starts_with("."))) .filter(|f| !(!self.show_hidden && f.name.starts_with(".")))
.collect() .collect()
} }
pub fn get_files_mut(&mut self) -> Vec<&mut File> { pub fn get_files_mut(&mut self) -> Vec<&mut File> {
let filter = self.filter.clone(); let filter = self.filter.clone();
let filter_selected = self.filter_selected;
let show_hidden = self.show_hidden; let show_hidden = self.show_hidden;
self.files self.files
.iter_mut() .iter_mut()
.filter(|f| .filter(|f|
f.kind == Kind::Placeholder || f.kind == Kind::Placeholder ||
!(filter.is_some() && !(filter.is_some() &&
!f.name.contains(filter.as_ref().unwrap()))) !f.name.contains(filter.as_ref().unwrap())) &&
(!filter_selected || f.selected))
.filter(|f| !(!show_hidden && f.name.starts_with("."))) .filter(|f| !(!show_hidden && f.name.starts_with(".")))
.collect() .collect()
} }
@ -529,12 +538,20 @@ impl Files {
self.filter.clone() self.filter.clone()
} }
pub fn toggle_filter_selected(&mut self) {
self.filter_selected = !self.filter_selected;
}
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.get_files().len() self.get_files().len()
} }
pub fn get_selected(&self) -> Vec<&File> { pub fn get_selected(&self) -> Vec<&File> {
self.files.iter().filter(|f| f.is_selected()).collect() self.get_files()
.iter()
.filter(|f| f.is_selected())
.map(|f| *f)
.collect()
} }
} }

View File

@ -20,6 +20,7 @@ pub struct DirSettings {
reverse: bool, reverse: bool,
show_hidden: bool, show_hidden: bool,
filter: Option<String>, filter: Option<String>,
filter_selected: bool
} }
impl DirSettings { impl DirSettings {
@ -29,7 +30,8 @@ impl DirSettings {
dirs_first: true, dirs_first: true,
reverse: false, reverse: false,
show_hidden: true, show_hidden: true,
filter: None filter: None,
filter_selected: false
} }
} }
} }
@ -257,6 +259,7 @@ impl FsCache {
files.reverse = tab_settings.dir_settings.reverse; files.reverse = tab_settings.dir_settings.reverse;
files.show_hidden = tab_settings.dir_settings.show_hidden; files.show_hidden = tab_settings.dir_settings.show_hidden;
files.filter = tab_settings.dir_settings.filter.clone(); files.filter = tab_settings.dir_settings.filter.clone();
files.filter_selected = tab_settings.dir_settings.filter_selected;
if tab_settings.multi_selections.len() > 0 { if tab_settings.multi_selections.len() > 0 {
for file in &mut files.files { for file in &mut files.files {
@ -292,6 +295,7 @@ impl FsCache {
reverse: files.reverse, reverse: files.reverse,
show_hidden: files.show_hidden, show_hidden: files.show_hidden,
filter: files.filter.clone(), filter: files.filter.clone(),
filter_selected: files.filter_selected
} }
} }
} }

View File

@ -84,6 +84,7 @@ impl Listable for ListView<Files> {
Key::Char(' ') => self.multi_select_file(), Key::Char(' ') => self.multi_select_file(),
Key::Char('v') => self.invert_selection(), Key::Char('v') => self.invert_selection(),
Key::Char('V') => self.clear_selections(), Key::Char('V') => self.clear_selections(),
Key::Alt('v') => self.toggle_filter_selected(),
Key::Char('t') => self.toggle_tag()?, Key::Char('t') => self.toggle_tag()?,
Key::Char('H') => self.toggle_hidden(), Key::Char('H') => self.toggle_hidden(),
Key::Char('r') => self.reverse_sort(), Key::Char('r') => self.reverse_sort(),
@ -355,17 +356,33 @@ impl ListView<Files>
fn multi_select_file(&mut self) { fn multi_select_file(&mut self) {
self.selected_file_mut().toggle_selection(); self.selected_file_mut().toggle_selection();
let selection = self.get_selection(); if !self.content.filter_selected {
let line = self.render_line(self.selected_file()); let selection = self.get_selection();
self.buffer[selection] = line; let line = self.render_line(self.selected_file());
self.buffer[selection] = line;
self.move_down(); self.move_down();
} else {
if self.content.filter_selected && self.content.len() == 0 {
self.content.toggle_filter_selected();
self.core.show_status("Disabled selection filter!").log();
}
// fix cursor when last file is unselected, etc
self.refresh().log();
}
} }
pub fn invert_selection(&mut self) { pub fn invert_selection(&mut self) {
for file in self.content.get_files_mut() { for file in self.content.get_files_mut() {
file.toggle_selection(); file.toggle_selection();
} }
if self.content.filter_selected && self.content.len() == 0 {
self.content.toggle_filter_selected();
self.core.show_status("Disabled selection filter!").log();
}
self.content.set_dirty(); self.content.set_dirty();
self.refresh().log(); self.refresh().log();
} }
@ -520,6 +537,17 @@ impl ListView<Files>
Ok(()) Ok(())
} }
fn toggle_filter_selected(&mut self) {
self.content.toggle_filter_selected();
if self.content.len() == 0 {
core.show_status("No files selected").log();
self.content.toggle_filter_selected();
}
self.refresh().log();
}
fn render_line(&self, file: &File) -> String { fn render_line(&self, file: &File) -> String {
let icon = if self.core.config().icons { let icon = if self.core.config().icons {
file.icon() file.icon()
@ -607,8 +635,8 @@ impl<T> Widget for ListView<T> where ListView<T>: Listable {
self.on_refresh().log(); self.on_refresh().log();
self.lines = self.len(); self.lines = self.len();
if self.selection >= self.lines && self.selection != 0 { if self.selection >= self.len() && self.selection != 0 {
self.selection -= 1; self.selection = self.len() - 1;
} }
if self.core.is_dirty() || self.buffer.len() != self.len() { if self.core.is_dirty() || self.buffer.len() != self.len() {