From c381203bb2c9fd91add74154237dcc93853f73c3 Mon Sep 17 00:00:00 2001 From: rabite Date: Fri, 25 Jan 2019 20:20:34 +0100 Subject: [PATCH] sorting by name and size --- src/files.rs | 106 ++++++++++++++++++++++++++++++++++++------------ src/listview.rs | 30 ++++++++++++++ 2 files changed, 109 insertions(+), 27 deletions(-) diff --git a/src/files.rs b/src/files.rs index 1192659..ba37e04 100644 --- a/src/files.rs +++ b/src/files.rs @@ -4,27 +4,22 @@ use std::path::PathBuf; use std::ffi::OsStr; use std::cmp::{Ord, Ordering}; -pub struct Files(Vec); use lscolors::{LsColors, Style}; -impl Index for Files { - type Output = File; - fn index(&self, pos: usize) -> &Self::Output { - &self.0[pos] - } lazy_static! { static ref COLORS: LsColors = LsColors::from_env().unwrap(); } -impl PartialOrd for File { - fn partial_cmp(&self, other: &File) -> Option { - Some(alphanumeric_sort::compare_str(&self.name, &other.name)) - } +#[derive(PartialEq)] +pub struct Files { + pub files: Vec, + pub sort: SortBy, } -impl Ord for File { - fn cmp(&self, other: &File) -> Ordering { - alphanumeric_sort::compare_str(&self.name, &other.name) +impl Index for Files { + type Output = File; + fn index(&self, pos: usize) -> &Self::Output { + &self.files[pos] } } @@ -41,7 +36,7 @@ impl Files { -> Result> where S: std::convert::AsRef { let mut files = Vec::new(); - let mut dirs = Vec::new(); + for file in std::fs::read_dir(path)? { let file = file?; let name = file.file_name(); @@ -56,26 +51,58 @@ impl Files { None => None }; let file = File::new(&name, path, kind, size as usize, style); - match kind { - Kind::Directory => dirs.push(file), - _ => files.push(file), - } + files.push(file) } + + let mut files = Files { files: files, + sort: SortBy::Name }; + files.sort(); - dirs.sort(); - dirs.append(&mut files); - - let files = dirs; - - Ok(Files(files)) + Ok(files) + } + + pub fn sort(&mut self) { + match self.sort { + SortBy::Name => { + self.files.sort_by(|a,b| { + alphanumeric_sort::compare_str(&a.name, &b.name) + }) + }, + SortBy::Size => { + self.files.sort_by(|a,b| { + if a.size == b.size { + return alphanumeric_sort::compare_str(&b.name, &a.name) + } + a.size.cmp(&b.size).reverse() + }); + }, + _ => {} + }; + + // Direcories first + self.files.sort_by(|a,b| { + if a.is_dir() && !b.is_dir() { + Ordering::Less + } else { Ordering::Equal } + }); + } + + pub fn cycle_sort(&mut self) -> SortBy { + self.sort = match self.sort { + SortBy::Name => SortBy::Size, + SortBy::Size => SortBy::Name, + _ => { SortBy::Name } + }; + self.sort(); + self.sort } pub fn iter(&self) -> std::slice::Iter { - self.0.iter() + self.files.iter() } pub fn len(&self) -> usize { - self.0.len() + self.files.len() } } @@ -87,7 +114,28 @@ pub enum Kind { Pipe } -#[derive(Debug, PartialEq, Eq)] +impl std::fmt::Display for SortBy { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_> ) + -> Result<(), std::fmt::Error> { + let text = match self { + SortBy::Name => "name", + SortBy::Size => "size", + SortBy::MDate => "mdate", + SortBy::CDate => "cdate" + }; + write!(formatter, "{}", text) + } +} + +#[derive(Debug,Copy,Clone,PartialEq)] +pub enum SortBy { + Name, + Size, + MDate, + CDate +} + +#[derive(Debug, PartialEq, Clone)] pub struct File { pub name: String, pub path: PathBuf, @@ -143,6 +191,10 @@ impl File { Some(self.path.parent()?.parent()?.to_path_buf()) } + pub fn is_dir(&self) -> bool { + self.kind == Kind::Directory + } + pub fn path(&self) -> PathBuf { self.path.clone() } diff --git a/src/listview.rs b/src/listview.rs index 93424d7..c29351e 100644 --- a/src/listview.rs +++ b/src/listview.rs @@ -61,6 +61,16 @@ impl ListView where ListView: Widget { self.selection += 1; } + fn set_selection(&mut self, position: usize) { + let ysize = self.dimensions.1 as usize; + let mut offset = 0; + + while position + 1 > ysize + offset { offset += 1 } + + self.offset = offset; + self.selection = position; + } + fn render_line(&self, file: &File) -> String { let name = &file.name; let (size, unit) = file.calculate_size(); @@ -100,6 +110,12 @@ impl ListView where file } + fn clone_selected_file(&self) -> File { + let selection = self.selection; + let file = self.content[selection].clone(); + file + } + fn grand_parent(&self) -> Option { self.selected_file().grand_parent() } @@ -131,6 +147,19 @@ impl ListView where } } } + + fn select_file(&mut self, file: &File) { + let pos = self.content.files.iter().position(|item| item == file).unwrap(); + self.set_selection(pos); + } + + fn cycle_sort(&mut self) { + let file = self.clone_selected_file(); + self.content.cycle_sort(); + self.select_file(&file); + self.refresh(); + self.show_status(&format!("Sorting by: {}", self.content.sort)); + } } @@ -207,6 +236,7 @@ impl Widget for ListView { Key::Right => { self.goto_selected() }, + Key::Char('s') => { self.cycle_sort() } , _ => { self.bad(Event::Key(key)); } } }