use serde::{Serialize, Serializer};
use std::path::Path;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum FileCategory {
Code,
Image,
Video,
Audio,
Archive,
Document,
Database,
Executable,
Font,
Config,
Data,
Other,
}
impl FileCategory {
pub fn from_path(path: &Path) -> Self {
let ext = match path.extension().and_then(|e| e.to_str()) {
Some(e) => e.to_ascii_lowercase(),
None => return Self::Other,
};
match ext.as_str() {
"rs" | "py" | "js" | "ts" | "tsx" | "jsx" | "go" | "c" | "cpp" | "cc" | "h" | "hpp"
| "java" | "kt" | "swift" | "rb" | "php" | "cs" | "scala" | "lua" | "r" | "m"
| "mm" | "pl" | "pm" | "sh" | "bash" | "zsh" | "fish" | "ps1" | "bat" | "cmd"
| "zig" | "asm" | "s" | "v" | "sv" | "vhd" | "vhdl" | "elm" | "ex" | "exs" | "erl"
| "hs" | "ml" | "mli" | "clj" | "cljs" | "lisp" | "el" | "dart" | "vue" | "svelte"
| "css" | "scss" | "sass" | "less" | "html" | "htm" | "sql" | "graphql" | "gql"
| "proto" | "thrift" | "wasm" | "wat" => Self::Code,
"png" | "jpg" | "jpeg" | "gif" | "bmp" | "svg" | "ico" | "webp" | "tiff" | "tif"
| "psd" | "ai" | "eps" | "raw" | "cr2" | "nef" | "arw" | "dng" | "heic" | "heif"
| "avif" | "jxl" => Self::Image,
"mp4" | "mkv" | "avi" | "mov" | "wmv" | "flv" | "webm" | "m4v" | "mpg" | "mpeg"
| "3gp" | "ogv" => Self::Video,
"mp3" | "flac" | "wav" | "aac" | "ogg" | "wma" | "m4a" | "opus" | "aiff" | "ape"
| "alac" | "mid" | "midi" => Self::Audio,
"zip" | "tar" | "gz" | "bz2" | "xz" | "zst" | "lz4" | "7z" | "rar" | "cab" | "iso"
| "dmg" | "deb" | "rpm" | "pkg" | "msi" | "appimage" | "snap" | "flatpak" | "tgz"
| "tbz2" | "txz" => Self::Archive,
"pdf" | "doc" | "docx" | "xls" | "xlsx" | "ppt" | "pptx" | "odt" | "ods" | "odp"
| "rtf" | "txt" | "md" | "rst" | "tex" | "latex" | "epub" | "mobi" | "pages"
| "numbers" | "key" | "csv" => Self::Document,
"db" | "sqlite" | "sqlite3" | "mdb" | "accdb" | "dbf" | "ldb" => Self::Database,
"exe" | "dll" | "so" | "dylib" | "a" | "lib" | "o" | "obj" | "class" | "pyc"
| "pyo" | "elc" | "beam" => Self::Executable,
"ttf" | "otf" | "woff" | "woff2" | "eot" => Self::Font,
"json" | "yaml" | "yml" | "toml" | "ini" | "cfg" | "conf" | "env" | "xml" | "plist"
| "properties" | "reg" => Self::Config,
"bin" | "dat" | "parquet" | "arrow" | "avro" | "msgpack" | "cbor" | "pb" | "npy"
| "npz" | "hdf5" | "h5" | "nc" | "fits" => Self::Data,
_ => Self::Other,
}
}
pub const ALL: &[FileCategory] = &[
Self::Code,
Self::Image,
Self::Video,
Self::Audio,
Self::Archive,
Self::Document,
Self::Database,
Self::Executable,
Self::Font,
Self::Config,
Self::Data,
Self::Other,
];
pub fn rgb(&self) -> (u8, u8, u8) {
match self {
Self::Code => (86, 156, 214), Self::Image => (206, 145, 52), Self::Video => (214, 86, 86), Self::Audio => (156, 86, 214), Self::Archive => (86, 214, 156), Self::Document => (214, 206, 86), Self::Database => (214, 130, 86), Self::Executable => (180, 86, 86), Self::Font => (150, 150, 150), Self::Config => (120, 180, 120), Self::Data => (86, 136, 214), Self::Other => (100, 100, 120), }
}
pub fn color(&self) -> String {
let (r, g, b) = self.rgb();
format!("#{r:02x}{g:02x}{b:02x}")
}
pub fn label(&self) -> &'static str {
match self {
Self::Code => "Code",
Self::Image => "Image",
Self::Video => "Video",
Self::Audio => "Audio",
Self::Archive => "Archive",
Self::Document => "Document",
Self::Database => "Database",
Self::Executable => "Executable",
Self::Font => "Font",
Self::Config => "Config",
Self::Data => "Data",
Self::Other => "Other",
}
}
}
impl Serialize for FileCategory {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&self.color())
}
}
#[cfg(test)]
#[path = "category_tests.rs"]
mod category_tests;