mirror of https://github.com/bobwen-dev/hunter
filter by file selection
This commit is contained in:
parent
c5e0b6fa03
commit
15e2f89a64
|
@ -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 |
|
||||||
|
|
27
src/files.rs
27
src/files.rs
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
Loading…
Reference in New Issue