lla 0.5.10

Blazing Fast and highly customizable ls Replacement with Superpowers
use crate::error::Result;
use std::path::PathBuf;

#[derive(Clone, Copy, Default)]
pub struct SortOptions {
    pub reverse: bool,
    pub dirs_first: bool,
    pub case_sensitive: bool,
    pub natural: bool,
}

pub trait FileSorter: Send + Sync {
    fn sort_files_with_metadata(
        &self,
        entries: &mut [(PathBuf, &DecoratedEntry)],
        options: SortOptions,
    ) -> Result<()>;
}

mod alphabetical;
mod date;
mod size;

pub use alphabetical::AlphabeticalSorter;
pub use date::DateSorter;
use lla_plugin_interface::proto::DecoratedEntry;
pub use size::SizeSorter;

pub(crate) fn natural_cmp(a: &str, b: &str) -> std::cmp::Ordering {
    let mut a_chars = a.chars().peekable();
    let mut b_chars = b.chars().peekable();

    while a_chars.peek().is_some() && b_chars.peek().is_some() {
        if a_chars.peek().unwrap().is_ascii_digit() && b_chars.peek().unwrap().is_ascii_digit() {
            let mut a_num = 0u64;
            let mut b_num = 0u64;

            while a_chars.peek().map_or(false, |c| c.is_ascii_digit()) {
                if let Some(digit) = a_chars.next() {
                    a_num = a_num * 10 + digit.to_digit(10).unwrap() as u64;
                }
            }

            while b_chars.peek().map_or(false, |c| c.is_ascii_digit()) {
                if let Some(digit) = b_chars.next() {
                    b_num = b_num * 10 + digit.to_digit(10).unwrap() as u64;
                }
            }

            match a_num.cmp(&b_num) {
                std::cmp::Ordering::Equal => continue,
                other => return other,
            }
        } else {
            match a_chars.next().unwrap().cmp(&b_chars.next().unwrap()) {
                std::cmp::Ordering::Equal => continue,
                other => return other,
            }
        }
    }

    match (a_chars.peek(), b_chars.peek()) {
        (None, None) => std::cmp::Ordering::Equal,
        (None, Some(_)) => std::cmp::Ordering::Less,
        (Some(_), None) => std::cmp::Ordering::Greater,
        _ => unreachable!(),
    }
}