mirror of
https://github.com/Llewellynvdm/exa.git
synced 2024-11-29 23:23:53 +00:00
Cache the lowercased extension
Extensions aren't ever displayed in lowercase, just compared case-insensitively, so this makes sense.
This commit is contained in:
parent
22a4dc90b9
commit
da9d1f77d9
11
src/file.rs
11
src/file.rs
@ -1,5 +1,6 @@
|
||||
use std::io::{fs, IoResult};
|
||||
use std::io;
|
||||
use std::ascii::AsciiExt;
|
||||
|
||||
use ansi_term::{ANSIString, Colour, Style};
|
||||
use ansi_term::Style::Plain;
|
||||
@ -370,16 +371,20 @@ impl<'a> File<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract an extension from a string, if one is present.
|
||||
/// Extract an extension from a string, if one is present, in lowercase.
|
||||
///
|
||||
/// The extension is the series of characters after the last dot. This
|
||||
/// deliberately counts dotfiles, so the ".git" folder has the extension "git".
|
||||
///
|
||||
/// ASCII lowercasing is used because these extensions are only compared
|
||||
/// against a pre-compiled list of extensions which are known to only exist
|
||||
/// within ASCII, so it's alright.
|
||||
fn ext<'a>(name: &'a str) -> Option<String> {
|
||||
name.rfind('.').map(|p| name[p+1..].to_string())
|
||||
name.rfind('.').map(|p| name[p+1..].to_ascii_lowercase())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
pub mod test {
|
||||
pub use super::*;
|
||||
pub use column::{Cell, Column};
|
||||
pub use std::io;
|
||||
|
@ -2,13 +2,12 @@ use file::{File, GREY};
|
||||
use self::FileType::*;
|
||||
|
||||
use std::io;
|
||||
use std::ascii::AsciiExt;
|
||||
|
||||
use ansi_term::Style;
|
||||
use ansi_term::Style::Plain;
|
||||
use ansi_term::Colour::{Red, Green, Yellow, Blue, Cyan, Fixed};
|
||||
|
||||
#[derive(Copy)]
|
||||
#[derive(PartialEq, Debug, Copy)]
|
||||
pub enum FileType {
|
||||
Normal, Directory, Executable, Immediate, Compiled, Symlink, Special,
|
||||
Image, Video, Music, Lossless, Compressed, Document, Temp, Crypto,
|
||||
@ -100,30 +99,29 @@ impl<'a> HasType for File<'a> {
|
||||
else if name.starts_with("README") || BUILD_TYPES.iter().any(|&s| s == name) {
|
||||
return Immediate;
|
||||
}
|
||||
else if let Some(ref e) = self.ext {
|
||||
let ext = e.as_slice().to_ascii_lowercase();
|
||||
if IMAGE_TYPES.iter().any(|&s| s == ext) {
|
||||
else if let Some(ref ext) = self.ext {
|
||||
if IMAGE_TYPES.iter().any(|&s| s == *ext) {
|
||||
return Image;
|
||||
}
|
||||
else if VIDEO_TYPES.iter().any(|&s| s == ext) {
|
||||
else if VIDEO_TYPES.iter().any(|&s| s == *ext) {
|
||||
return Video;
|
||||
}
|
||||
else if MUSIC_TYPES.iter().any(|&s| s == ext) {
|
||||
else if MUSIC_TYPES.iter().any(|&s| s == *ext) {
|
||||
return Music;
|
||||
}
|
||||
else if MUSIC_LOSSLESS.iter().any(|&s| s == ext) {
|
||||
else if MUSIC_LOSSLESS.iter().any(|&s| s == *ext) {
|
||||
return Lossless;
|
||||
}
|
||||
else if CRYPTO_TYPES.iter().any(|&s| s == ext) {
|
||||
else if CRYPTO_TYPES.iter().any(|&s| s == *ext) {
|
||||
return Crypto;
|
||||
}
|
||||
else if DOCUMENT_TYPES.iter().any(|&s| s == ext) {
|
||||
else if DOCUMENT_TYPES.iter().any(|&s| s == *ext) {
|
||||
return Document;
|
||||
}
|
||||
else if COMPRESSED_TYPES.iter().any(|&s| s == ext) {
|
||||
else if COMPRESSED_TYPES.iter().any(|&s| s == *ext) {
|
||||
return Compressed;
|
||||
}
|
||||
else if self.is_tmpfile() || TEMP_TYPES.iter().any(|&s| s == ext) {
|
||||
else if self.is_tmpfile() || TEMP_TYPES.iter().any(|&s| s == *ext) {
|
||||
return Temp;
|
||||
}
|
||||
|
||||
@ -135,7 +133,7 @@ impl<'a> HasType for File<'a> {
|
||||
return Temp;
|
||||
}
|
||||
else {
|
||||
if COMPILED_TYPES.iter().any(|&s| s == ext) {
|
||||
if COMPILED_TYPES.iter().any(|&s| s == *ext) {
|
||||
return Compiled;
|
||||
}
|
||||
else {
|
||||
@ -147,3 +145,35 @@ impl<'a> HasType for File<'a> {
|
||||
return Normal; // no filetype
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use file::File;
|
||||
use file::test::dummy_stat;
|
||||
|
||||
#[test]
|
||||
fn lowercase() {
|
||||
let file = File::with_stat(dummy_stat(), &Path::new("/barracks.wav"), None);
|
||||
assert_eq!(FileType::Lossless, file.get_type())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uppercase() {
|
||||
let file = File::with_stat(dummy_stat(), &Path::new("/BARRACKS.WAV"), None);
|
||||
assert_eq!(FileType::Lossless, file.get_type())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cargo() {
|
||||
let file = File::with_stat(dummy_stat(), &Path::new("/Cargo.toml"), None);
|
||||
assert_eq!(FileType::Immediate, file.get_type())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_cargo() {
|
||||
let file = File::with_stat(dummy_stat(), &Path::new("/cargo.toml"), None);
|
||||
assert_eq!(FileType::Normal, file.get_type())
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,8 +8,9 @@ use output::View;
|
||||
use term::dimensions;
|
||||
|
||||
use std::ascii::AsciiExt;
|
||||
use std::slice::Iter;
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt;
|
||||
use std::slice::Iter;
|
||||
|
||||
use self::Misfire::*;
|
||||
|
||||
@ -81,7 +82,7 @@ impl Options {
|
||||
self.view.view(files)
|
||||
}
|
||||
|
||||
/// Transform the files somehow before listing them.
|
||||
/// Transform the files (sorting, reversing, filtering) before listing them.
|
||||
pub fn transform_files<'a>(&self, mut files: Vec<File<'a>>) -> Vec<File<'a>> {
|
||||
|
||||
if !self.show_invisibles {
|
||||
@ -90,13 +91,16 @@ impl Options {
|
||||
|
||||
match self.sort_field {
|
||||
SortField::Unsorted => {},
|
||||
SortField::Name => files.sort_by(|a, b| natord::compare(a.name.as_slice(), b.name.as_slice())),
|
||||
SortField::Name => files.sort_by(|a, b| natord::compare(&*a.name, &*b.name)),
|
||||
SortField::Size => files.sort_by(|a, b| a.stat.size.cmp(&b.stat.size)),
|
||||
SortField::FileInode => files.sort_by(|a, b| a.stat.unstable.inode.cmp(&b.stat.unstable.inode)),
|
||||
SortField::Extension => files.sort_by(|a, b| {
|
||||
let exts = a.ext.clone().map(|e| e.to_ascii_lowercase()).cmp(&b.ext.clone().map(|e| e.to_ascii_lowercase()));
|
||||
let names = a.name.to_ascii_lowercase().cmp(&b.name.to_ascii_lowercase());
|
||||
exts.cmp(&names)
|
||||
if a.ext.cmp(&b.ext) == Ordering::Equal {
|
||||
Ordering::Equal
|
||||
}
|
||||
else {
|
||||
a.name.to_ascii_lowercase().cmp(&b.name.to_ascii_lowercase())
|
||||
}
|
||||
}),
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user