Skip to content

Commit

Permalink
sorting
Browse files Browse the repository at this point in the history
  • Loading branch information
solidiquis committed Nov 29, 2023
1 parent 4297027 commit 93d79b8
Show file tree
Hide file tree
Showing 7 changed files with 275 additions and 97 deletions.
36 changes: 34 additions & 2 deletions src/file/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,17 @@ pub struct File {
unix_attrs: unix::Attrs,
}

/// [`Display`] implementation concerned with human-readable presentation of the file-name.
pub struct DisplayName<'a> {
file: &'a File,
}

/// [`Display`] implementation concerned with human-readable presentation of the file-path.
pub struct DisplayPath<'a> {
file: &'a File,
path_prefix: Option<&'a Path>,
}

impl File {
/// Plain Jane constructor for [`File`].
pub fn new(
Expand Down Expand Up @@ -139,6 +146,10 @@ impl File {
DisplayName { file: self }
}

pub fn display_path<'a>(&'a self, path_prefix: Option<&'a Path>) -> DisplayPath<'a> {
DisplayPath { file: self, path_prefix }
}

#[cfg(unix)]
pub fn unix_attrs(&self) -> &unix::Attrs {
&self.unix_attrs
Expand Down Expand Up @@ -181,11 +192,32 @@ impl Deref for File {
impl Display for DisplayName<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let file_name = self.file.file_name().to_string_lossy();
let link_target = self.file.symlink_target().map(|p| p.canonicalize());

if let Some(link_target) = self.file.symlink_target() {
write!(f, "{file_name} \u{2192} {}", link_target.display())
if let Some(Ok(target)) = link_target {
write!(f, "{file_name} \u{2192} {}", target.display())
} else {
write!(f, "{file_name}")
}
}
}

impl Display for DisplayPath<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let display = match self.path_prefix {
Some(prefix) => {
let path = self.file.path();
path.strip_prefix(prefix).map_or_else(|_| path.display(), |p| p.display())
},
None => self.file.path().display()
};

let link_target = self.file.symlink_target().map(|p| p.canonicalize());

if let Some(Ok(target)) = link_target {
write!(f, "{display} \u{2192} {}", target.display())
} else {
write!(f, "{display}")
}
}
}
74 changes: 54 additions & 20 deletions src/file/order.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,32 @@
use super::File;
use crate::user::{args::{Sort, DirOrder}, Context};
use crate::user::args::{DirOrder, Sort};
use std::cmp::Ordering;

/// Comparator type used to sort [File]s.
pub type FileComparator = dyn Fn(&File, &File) -> Ordering;

/// Yields function pointer to the appropriate `File` comparator.
pub fn comparator(sort: Sort, dir_order: DirOrder) -> Option<Box<FileComparator>> {
if matches!(sort, Sort::None) {
return None;
}

match dir_order {
DirOrder::First => {
Some(Box::new(move |a, b| dir_first_comparator(a, b, base_comparator(sort))))
},
DirOrder::Last => {
Some(Box::new(move |a, b| dir_last_comparator(a, b, base_comparator(sort))))
},
DirOrder::First if matches!(sort, Sort::None) => Some(Box::new(move |a, b| {
dir_first_comparator(a, b)
})),
DirOrder::First => Some(Box::new(move |a, b| {
dir_first_comparator_with_fallback(a, b, base_comparator(sort))
})),
DirOrder::Last if matches!(sort, Sort::None) => Some(Box::new(move |a, b| {
dir_last_comparator(a, b)
})),
DirOrder::Last => Some(Box::new(move |a, b| {
dir_last_comparator_with_fallback(a, b, base_comparator(sort))
})),
DirOrder::None if matches!(sort, Sort::None) => None,
DirOrder::None => Some(base_comparator(sort)),
}
}

/// Orders directories first. Provides a fallback if inputs are not directories.
fn dir_first_comparator(
fn dir_first_comparator_with_fallback(
a: &File,
b: &File,
fallback: impl Fn(&File, &File) -> Ordering,
Expand All @@ -35,8 +38,17 @@ fn dir_first_comparator(
}
}

/// Orders directories first relative to all other file-types.
fn dir_first_comparator(a: &File, b: &File) -> Ordering {
match (a.is_dir(), b.is_dir()) {
(true, false) => Ordering::Greater,
(false, true) => Ordering::Less,
_ => Ordering::Equal
}
}

/// Orders directories last. Provides a fallback if inputs are not directories.
fn dir_last_comparator(
fn dir_last_comparator_with_fallback(
a: &File,
b: &File,
fallback: impl Fn(&File, &File) -> Ordering,
Expand All @@ -48,6 +60,18 @@ fn dir_last_comparator(
}
}

/// Orders directories last relative to all other file-types.
fn dir_last_comparator(
a: &File,
b: &File,
) -> Ordering {
match (a.is_dir(), b.is_dir()) {
(true, false) => Ordering::Less,
(false, true) => Ordering::Greater,
_ => Ordering::Equal
}
}

/// Grabs the comparator for two non-dir type [File]s.
fn base_comparator(sort_type: Sort) -> Box<FileComparator> {
Box::new(match sort_type {
Expand All @@ -61,9 +85,7 @@ fn base_comparator(sort_type: Sort) -> Box<FileComparator> {
Sort::Rcreate => time_stamping::created::rev_comparator,
Sort::Mod => time_stamping::modified::comparator,
Sort::Rmod => time_stamping::modified::rev_comparator,

// Hacky...
Sort::None => unreachable!(),
Sort::None => |_: &File, _: &File| Ordering::Equal,
})
}

Expand All @@ -77,8 +99,14 @@ mod time_stamping {

/// Comparator that sorts [File]s by Last Access timestamp, newer to older.
pub fn comparator(a: &File, b: &File) -> Ordering {
let a_stamp = a.metadata().accessed().unwrap_or_else(|_| SystemTime::now());
let b_stamp = b.metadata().accessed().unwrap_or_else(|_| SystemTime::now());
let a_stamp = a
.metadata()
.accessed()
.unwrap_or_else(|_| SystemTime::now());
let b_stamp = b
.metadata()
.accessed()
.unwrap_or_else(|_| SystemTime::now());
b_stamp.cmp(&a_stamp)
}

Expand Down Expand Up @@ -109,8 +137,14 @@ mod time_stamping {

/// Comparator that sorts [File]s by Alteration timestamp, newer to older.
pub fn comparator(a: &File, b: &File) -> Ordering {
let a_stamp = a.metadata().modified().unwrap_or_else(|_| SystemTime::now());
let b_stamp = b.metadata().modified().unwrap_or_else(|_| SystemTime::now());
let a_stamp = a
.metadata()
.modified()
.unwrap_or_else(|_| SystemTime::now());
let b_stamp = b
.metadata()
.modified()
.unwrap_or_else(|_| SystemTime::now());
b_stamp.cmp(&a_stamp)
}

Expand Down
73 changes: 55 additions & 18 deletions src/file/tree/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use super::order::{self, FileComparator};
use crate::{
error::prelude::*,
file::File,
user::{args::Sort, column, Context},
user::{args::{Layout, SortType, Sort}, column, Context},
};
use super::order::{self, FileComparator};
use ahash::{HashMap, HashSet};
use indextree::{Arena, NodeId};
use std::{ops::Deref, path::PathBuf};
Expand Down Expand Up @@ -108,23 +108,63 @@ impl Tree {
}
}

for (dir_id, dirsize) in dirsize_map.into_iter() {
let dir = arena[dir_id].get_mut();
*dir.size_mut() += dirsize;

if let Some(dirents) = branches.remove(dir.path()) {
for dirent_id in dirents {
dir_id.append(dirent_id, &mut arena);
match order::comparator(ctx.sort, ctx.dir_order) {
Some(comparator) => match ctx.sort_type {
SortType::Flat if matches!(ctx.layout, Layout::Flat) => {
for (dir_id, dirsize) in dirsize_map.into_iter() {
let dir = arena[dir_id].get_mut();
*dir.size_mut() += dirsize;
}

let mut all_dirents = branches
.values()
.flatten()
.filter_map(|n| (*n != root_id).then_some(*n))
.collect::<Vec<_>>();

all_dirents.sort_by(|id_a, id_b| {
let node_a = arena[*id_a].get();
let node_b = arena[*id_b].get();
comparator(node_a, node_b)
});

all_dirents.into_iter().for_each(|n| root_id.append(n, &mut arena));
}
}
_ => {
for (dir_id, dirsize) in dirsize_map.into_iter() {
let dir = arena[dir_id].get_mut();
*dir.size_mut() += dirsize;

if let Some(mut dirents) = branches.remove(dir.path()) {
dirents.sort_by(|id_a, id_b| {
let node_a = arena[*id_a].get();
let node_b = arena[*id_b].get();
comparator(node_a, node_b)
});

for dirent_id in dirents {
dir_id.append(dirent_id, &mut arena);
}
}
}
},
},
None => {
for (dir_id, dirsize) in dirsize_map.into_iter() {
let dir = arena[dir_id].get_mut();
*dir.size_mut() += dirsize;

if let Some(dirents) = branches.remove(dir.path()) {
for dirent_id in dirents {
dir_id.append(dirent_id, &mut arena);
}
}
}
},
}

column_metadata.update_size_width(arena[root_id].get(), ctx);

//if let Some(comparator) = order::comparator(ctx.sort, ctx.dir_order) {
//Self::tree_sort(root_id, &mut arena, comparator);
//}

let tree = Self { root_id, arena };

Ok((tree, column_metadata))
Expand Down Expand Up @@ -236,9 +276,7 @@ impl Tree {
let to_prune = self
.root_id
.descendants(&self.arena)
.filter(|n| {
self.arena[*n].get().is_dir() && n.children(&self.arena).count() == 0
})
.filter(|n| self.arena[*n].get().is_dir() && n.children(&self.arena).count() == 0)
.collect::<Vec<_>>();

to_prune
Expand All @@ -258,7 +296,6 @@ impl Tree {
pub fn tree_sort(root_id: NodeId, arena: &mut Arena<File>, comparator: Box<FileComparator>) {

Check warning on line 296 in src/file/tree/mod.rs

View workflow job for this annotation

GitHub Actions / Check

unused variable: `root_id`

Check warning on line 296 in src/file/tree/mod.rs

View workflow job for this annotation

GitHub Actions / Check

unused variable: `arena`

Check warning on line 296 in src/file/tree/mod.rs

View workflow job for this annotation

GitHub Actions / Check

unused variable: `comparator`

Check warning on line 296 in src/file/tree/mod.rs

View workflow job for this annotation

GitHub Actions / Test Suite

unused variable: `root_id`

Check warning on line 296 in src/file/tree/mod.rs

View workflow job for this annotation

GitHub Actions / Test Suite

unused variable: `arena`

Check warning on line 296 in src/file/tree/mod.rs

View workflow job for this annotation

GitHub Actions / Test Suite

unused variable: `comparator`

Check warning on line 296 in src/file/tree/mod.rs

View workflow job for this annotation

GitHub Actions / Test Suite

unused variable: `root_id`

Check warning on line 296 in src/file/tree/mod.rs

View workflow job for this annotation

GitHub Actions / Test Suite

unused variable: `arena`

Check warning on line 296 in src/file/tree/mod.rs

View workflow job for this annotation

GitHub Actions / Test Suite

unused variable: `comparator`

Check warning on line 296 in src/file/tree/mod.rs

View workflow job for this annotation

GitHub Actions / Check

unused variable: `root_id`

Check warning on line 296 in src/file/tree/mod.rs

View workflow job for this annotation

GitHub Actions / Check

unused variable: `arena`

Check warning on line 296 in src/file/tree/mod.rs

View workflow job for this annotation

GitHub Actions / Check

unused variable: `comparator`
todo!()
}

}

impl Deref for Tree {
Expand Down
14 changes: 7 additions & 7 deletions src/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ mod row;

pub fn output(file_tree: &file::Tree, ctx: &Context) -> Result<String> {
match ctx.layout {
Layout::Regular => tree(file_tree, ctx),
Layout::Inverted => inverted_tree(file_tree, ctx),
Layout::Tree => tree(file_tree, ctx),
Layout::InvertedTree => inverted_tree(file_tree, ctx),
Layout::Flat => flat(file_tree, ctx),
}
}

fn tree(file_tree: &file::Tree, ctx: &Context) -> Result<String> {
fn inverted_tree(file_tree: &file::Tree, ctx: &Context) -> Result<String> {
let arena = file_tree.arena();
let root = file_tree.root_id();
let max_depth = ctx.level();
Expand All @@ -47,7 +47,7 @@ fn tree(file_tree: &file::Tree, ctx: &Context) -> Result<String> {

let mut inherited_prefix_components = vec![""];

let mut formatter = row::formatter(&mut buf, ctx);
let mut formatter = row::formatter(&mut buf, ctx)?;

let mut reverse_traverse = root.reverse_traverse(arena);
reverse_traverse.next();
Expand Down Expand Up @@ -105,7 +105,7 @@ fn tree(file_tree: &file::Tree, ctx: &Context) -> Result<String> {
Ok(buf)
}

pub fn inverted_tree(file_tree: &file::Tree, ctx: &Context) -> Result<String> {
pub fn tree(file_tree: &file::Tree, ctx: &Context) -> Result<String> {
let arena = file_tree.arena();
let root = file_tree.root_id();
let max_depth = ctx.level();
Expand All @@ -120,7 +120,7 @@ pub fn inverted_tree(file_tree: &file::Tree, ctx: &Context) -> Result<String> {

let mut inherited_prefix_components = vec![""];

let mut formatter = row::formatter(&mut buf, ctx);
let mut formatter = row::formatter(&mut buf, ctx)?;

let mut traverse = root.traverse(arena);
traverse.next();
Expand Down Expand Up @@ -188,7 +188,7 @@ fn flat(file_tree: &file::Tree, ctx: &Context) -> Result<String> {
let max_depth = ctx.level();
let mut buf = String::new();

let mut formatter = row::formatter(&mut buf, ctx);
let mut formatter = row::formatter(&mut buf, ctx)?;

for node_edge in root.traverse(arena) {
let node_id = match node_edge {
Expand Down
Loading

0 comments on commit 93d79b8

Please sign in to comment.