mirror of
https://github.com/Llewellynvdm/exa.git
synced 2025-04-01 13:21:50 +00:00
Implement natural sorting on filenames
This commit is contained in:
parent
6edf2c0d4d
commit
4722c8991b
1
exa.rs
1
exa.rs
@ -14,6 +14,7 @@ pub mod format;
|
||||
pub mod file;
|
||||
pub mod unix;
|
||||
pub mod options;
|
||||
pub mod sort;
|
||||
|
||||
fn main() {
|
||||
let args = os::args();
|
||||
|
5
file.rs
5
file.rs
@ -5,6 +5,7 @@ use colours::{Plain, Style, Black, Red, Green, Yellow, Blue, Purple, Cyan};
|
||||
use column::{Column, Permissions, FileName, FileSize, User, Group};
|
||||
use format::{format_metric_bytes, format_IEC_bytes};
|
||||
use unix::{get_user_name, get_group_name};
|
||||
use sort::SortPart;
|
||||
|
||||
static MEDIA_TYPES: &'static [&'static str] = &[
|
||||
"png", "jpeg", "jpg", "gif", "bmp", "tiff", "tif",
|
||||
@ -27,6 +28,7 @@ pub struct File<'a> {
|
||||
pub ext: Option<&'a str>,
|
||||
pub path: &'a Path,
|
||||
pub stat: io::FileStat,
|
||||
pub parts: Vec<SortPart<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> File<'a> {
|
||||
@ -48,6 +50,7 @@ impl<'a> File<'a> {
|
||||
stat: stat,
|
||||
name: filename,
|
||||
ext: File::ext(filename),
|
||||
parts: SortPart::split_into_parts(filename),
|
||||
};
|
||||
}
|
||||
|
||||
@ -66,7 +69,7 @@ impl<'a> File<'a> {
|
||||
pub fn display(&self, column: &Column) -> String {
|
||||
match *column {
|
||||
Permissions => self.permissions_string(),
|
||||
FileName => self.file_colour().paint(self.name.as_slice()),
|
||||
FileName => self.file_colour().paint(self.name),
|
||||
FileSize(use_iec) => self.file_size(use_iec),
|
||||
|
||||
// Display the ID if the user/group doesn't exist, which
|
||||
|
@ -80,7 +80,7 @@ impl Options {
|
||||
.collect();
|
||||
|
||||
match self.sortField {
|
||||
Name => files.sort_by(|a, b| a.name.cmp(&b.name)),
|
||||
Name => files.sort_by(|a, b| a.parts.cmp(&b.parts)),
|
||||
Size => files.sort_by(|a, b| a.stat.size.cmp(&b.stat.size)),
|
||||
Extension => files.sort_by(|a, b| {
|
||||
let exts = a.ext.cmp(&b.ext);
|
||||
|
49
sort.rs
Normal file
49
sort.rs
Normal file
@ -0,0 +1,49 @@
|
||||
// This is an implementation of "natural sort order". See
|
||||
// http://blog.codinghorror.com/sorting-for-humans-natural-sort-order/
|
||||
// for more information and examples. It tries to sort "9" before
|
||||
// "10", which makes sense to those regular human types.
|
||||
|
||||
// It works by splitting an input string into several parts, and then
|
||||
// comparing based on those parts. A SortPart derives TotalOrd, so a
|
||||
// Vec<SortPart> will automatically have natural sorting.
|
||||
|
||||
#[deriving(Eq, Ord, TotalEq, TotalOrd)]
|
||||
pub enum SortPart<'a> {
|
||||
Stringular(&'a str),
|
||||
Numeric(u32),
|
||||
}
|
||||
|
||||
impl<'a> SortPart<'a> {
|
||||
pub fn from_string(is_digit: bool, slice: &'a str) -> SortPart<'a> {
|
||||
if is_digit {
|
||||
Numeric(from_str::<u32>(slice).unwrap())
|
||||
} else {
|
||||
Stringular(slice)
|
||||
}
|
||||
}
|
||||
|
||||
// The logic here is taken from my question at
|
||||
// http://stackoverflow.com/q/23969191/3484614
|
||||
|
||||
pub fn split_into_parts<'a>(input: &'a str) -> Vec<SortPart<'a>> {
|
||||
let mut parts = vec![];
|
||||
|
||||
if input.is_empty() {
|
||||
return parts
|
||||
}
|
||||
|
||||
let mut is_digit = input.char_at(0).is_digit();
|
||||
let mut start = 0;
|
||||
|
||||
for (i, c) in input.char_indices() {
|
||||
if is_digit != c.is_digit() {
|
||||
parts.push(SortPart::from_string(is_digit, input.slice(start, i)));
|
||||
is_digit = !is_digit;
|
||||
start = i;
|
||||
}
|
||||
}
|
||||
|
||||
parts.push(SortPart::from_string(is_digit, input.slice_from(start)));
|
||||
parts
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user