From 03ec414dfbb6211fe8b602fa5a2f1e85730f7b18 Mon Sep 17 00:00:00 2001 From: Ben S Date: Tue, 17 Jun 2014 09:35:40 +0100 Subject: [PATCH] Move file-type detection to its own module I'd much rather have this separate, as it has the definite potential to balloon up to a huge size and end up making the other parts of the file module hard to read. But on the other hand, it meant making a few more methods public on file... readability over cleanliness, I guess. --- exa.rs | 1 + file.rs | 95 +++--------------------------------------- filetype.rs | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+), 89 deletions(-) create mode 100644 filetype.rs diff --git a/exa.rs b/exa.rs index d24260c..d25b0c7 100644 --- a/exa.rs +++ b/exa.rs @@ -13,6 +13,7 @@ pub mod column; pub mod dir; pub mod format; pub mod file; +pub mod filetype; pub mod unix; pub mod options; pub mod sort; diff --git a/file.rs b/file.rs index 9b01646..226bbf7 100644 --- a/file.rs +++ b/file.rs @@ -1,43 +1,13 @@ +use colours::{Plain, Style, Black, Red, Green, Yellow, Blue, Purple, Cyan, Fixed}; use std::io::fs; use std::io; -use colours::{Plain, Style, Black, Red, Green, Yellow, Blue, Purple, Cyan, Fixed}; 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; use dir::Dir; - -static IMAGE_TYPES: &'static [&'static str] = &[ - "png", "jpeg", "jpg", "gif", "bmp", "tiff", "tif", - "ppm", "pgm", "pbm", "pnm", "webp", "raw", "arw", - "svg", "pdf", "stl", "eps", "dvi", "ps", "cbr", - "cbz", "xpm", "ico" ]; - -static VIDEO_TYPES: &'static [&'static str] = &[ - "avi", "flv", "m2v", "mkv", "mov", "mp4", "mpeg", - "mpg", "ogm", "ogv", "vob", "wmv" ]; - -static MUSIC_TYPES: &'static [&'static str] = &[ - "aac", "m4a", "mp3", "ogg" ]; - -static MUSIC_LOSSLESS: &'static [&'static str] = &[ - "alac", "ape", "flac", "wav" ]; - -static COMPRESSED_TYPES: &'static [&'static str] = &[ - "zip", "tar", "Z", "gz", "bz2", "a", "ar", "7z", - "iso", "dmg", "tc", "rar", "par" ]; - -static DOCUMENT_TYPES: &'static [&'static str] = &[ - "djvu", "doc", "docx", "eml", "eps", "odp", "ods", - "odt", "pdf", "ppt", "pptx", "xls", "xlsx" ]; - -static TEMP_TYPES: &'static [&'static str] = &[ - "tmp", "swp", "swo", "swn", "bak" ]; - -static CRYPTO_TYPES: &'static [&'static str] = &[ - "asc", "gpg", "sig", "signature", "pgp" ]; - +use filetype::FileType; // Instead of working with Rust's Paths, we have our own File object // that holds the Path and various cached information. Each file is @@ -91,7 +61,7 @@ impl<'a> File<'a> { self.name.starts_with(".") } - fn is_tmpfile(&self) -> bool { + pub fn is_tmpfile(&self) -> bool { self.name.ends_with("~") || (self.name.starts_with("#") && self.name.ends_with("#")) } @@ -101,7 +71,7 @@ impl<'a> File<'a> { // content without their source files, such as how .js is valid // without a .coffee. - fn get_source_files(&self) -> Vec { + pub fn get_source_files(&self) -> Vec { match self.ext { Some("class") => vec![self.path.with_extension("java")], // Java Some("elc") => vec![self.path.with_extension("el")], // Emacs Lisp @@ -112,7 +82,7 @@ impl<'a> File<'a> { } } - fn get_source_files_usual(&self) -> Vec { + pub fn get_source_files_usual(&self) -> Vec { match self.ext { Some("js") => vec![self.path.with_extension("coffee"), self.path.with_extension("ts")], // CoffeeScript, TypeScript Some("css") => vec![self.path.with_extension("sass"), self.path.with_extension("less")], // SASS, Less @@ -173,60 +143,7 @@ impl<'a> File<'a> { } fn file_colour(&self) -> Style { - if self.stat.kind == io::TypeDirectory { - Blue.bold() - } - else if self.stat.perm.contains(io::UserExecute) { - Green.bold() - } - else if self.is_tmpfile() { - Fixed(244).normal() // midway between white and black - should show up as grey on all terminals - } - else if self.name.starts_with("README") { - Yellow.bold().underline() - } - else if self.ext.is_some() && IMAGE_TYPES.iter().any(|&s| s == self.ext.unwrap()) { - Fixed(133).normal() - } - else if self.ext.is_some() && VIDEO_TYPES.iter().any(|&s| s == self.ext.unwrap()) { - Fixed(135).normal() - } - else if self.ext.is_some() && MUSIC_TYPES.iter().any(|&s| s == self.ext.unwrap()) { - Fixed(92).normal() - } - else if self.ext.is_some() && MUSIC_LOSSLESS.iter().any(|&s| s == self.ext.unwrap()) { - Fixed(93).normal() - } - else if self.ext.is_some() && CRYPTO_TYPES.iter().any(|&s| s == self.ext.unwrap()) { - Fixed(109).normal() - } - else if self.ext.is_some() && DOCUMENT_TYPES.iter().any(|&s| s == self.ext.unwrap()) { - Fixed(105).normal() - } - else if self.ext.is_some() && COMPRESSED_TYPES.iter().any(|&s| s == self.ext.unwrap()) { - Red.normal() - } - else if self.ext.is_some() && TEMP_TYPES.iter().any(|&s| s == self.ext.unwrap()) { - Fixed(244).normal() - } - else { - let source_files = self.get_source_files(); - if source_files.len() == 0 { - let source_files_usual = self.get_source_files_usual(); - if source_files_usual.iter().any(|path| self.dir.contains(path)) { - Fixed(244).normal() - } - else { - Plain - } - } - else if source_files.iter().any(|path| self.dir.contains(path)) { - Fixed(244).normal() - } - else { - Fixed(137).normal() - } - } + FileType::from_file(self).style() } fn permissions_string(&self) -> String { diff --git a/filetype.rs b/filetype.rs new file mode 100644 index 0000000..ec4f85c --- /dev/null +++ b/filetype.rs @@ -0,0 +1,116 @@ +use colours::{Plain, Style, Black, Red, Green, Yellow, Blue, Purple, Cyan, Fixed}; +use file::File; +use std::io; + +pub enum FileType { + Normal, Directory, Executable, Immediate, Compiled, + Image, Video, Music, Lossless, Compressed, Document, Temp, Crypto, +} + +static IMAGE_TYPES: &'static [&'static str] = &[ + "png", "jpeg", "jpg", "gif", "bmp", "tiff", "tif", + "ppm", "pgm", "pbm", "pnm", "webp", "raw", "arw", + "svg", "stl", "eps", "dvi", "ps", "cbr", + "cbz", "xpm", "ico" ]; + +static VIDEO_TYPES: &'static [&'static str] = &[ + "avi", "flv", "m2v", "mkv", "mov", "mp4", "mpeg", + "mpg", "ogm", "ogv", "vob", "wmv" ]; + +static MUSIC_TYPES: &'static [&'static str] = &[ + "aac", "m4a", "mp3", "ogg" ]; + +static MUSIC_LOSSLESS: &'static [&'static str] = &[ + "alac", "ape", "flac", "wav" ]; + +static COMPRESSED_TYPES: &'static [&'static str] = &[ + "zip", "tar", "Z", "gz", "bz2", "a", "ar", "7z", + "iso", "dmg", "tc", "rar", "par" ]; + +static DOCUMENT_TYPES: &'static [&'static str] = &[ + "djvu", "doc", "docx", "eml", "eps", "odp", "ods", + "odt", "pdf", "ppt", "pptx", "xls", "xlsx" ]; + +static TEMP_TYPES: &'static [&'static str] = &[ + "tmp", "swp", "swo", "swn", "bak" ]; + +static CRYPTO_TYPES: &'static [&'static str] = &[ + "asc", "gpg", "sig", "signature", "pgp" ]; + +impl FileType { + pub fn style(&self) -> Style { + match *self { + Normal => Plain, + Directory => Blue.bold(), + Executable => Green.bold(), + Image => Fixed(133).normal(), + Video => Fixed(135).normal(), + Music => Fixed(92).normal(), + Lossless => Fixed(93).normal(), + Crypto => Fixed(109).normal(), + Document => Fixed(105).normal(), + Compressed => Red.normal(), + Temp => Fixed(244).normal(), + Immediate => Yellow.bold().underline(), + Compiled => Fixed(137).normal(), + } + } + + pub fn from_file(file: &File) -> FileType { + if file.stat.kind == io::TypeDirectory { + return Directory; + } + else if file.stat.perm.contains(io::UserExecute) { + return Executable; + } + else if file.ext.is_some() { + let ext = file.ext.unwrap(); + if IMAGE_TYPES.iter().any(|&s| s == ext) { + return Image; + } + else if VIDEO_TYPES.iter().any(|&s| s == ext) { + return Video; + } + else if MUSIC_TYPES.iter().any(|&s| s == ext) { + return Music; + } + else if MUSIC_LOSSLESS.iter().any(|&s| s == ext) { + return Lossless; + } + else if CRYPTO_TYPES.iter().any(|&s| s == ext) { + return Crypto; + } + else if DOCUMENT_TYPES.iter().any(|&s| s == ext) { + return Document; + } + else if COMPRESSED_TYPES.iter().any(|&s| s == ext) { + return Compressed; + } + else if file.is_tmpfile() || TEMP_TYPES.iter().any(|&s| s == ext) { + return Temp; + } + } + + if file.name.starts_with("README") { + return Immediate; + } + + let source_files = file.get_source_files(); + if source_files.len() == 0 { + let source_files_usual = file.get_source_files_usual(); + if source_files_usual.iter().any(|path| file.dir.contains(path)) { + Temp + } + else { + Normal + } + } + else if source_files.iter().any(|path| file.dir.contains(path)) { + Temp + } + else { + Compiled + } + } +} +