use linguist;
use std::path::Path;
use crate::parsers::FileType;
macro_rules! file_extension_map {
(
$(
$ft:ident: $($e:literal),+ $(,)?
);+ $(;)?
) => {
&[
$( $( ( $e, FileType::$ft ) ),+ ),+
]
};
}
const FILE_EXTENSION_MAP: &[(&str, FileType)] = file_extension_map! {
Log: "log";
Json: "json";
Text: "txt";
Markdown: "md", "markdown";
Image: "jpg", "jpeg", "png", "gif", "bmp", "tiff", "tif", "webp", "ico", "svg";
Video: "mp4", "mkv", "avi", "mov", "wmv", "flv", "webm", "m4v", "3gp", "ogv";
Audio: "mp3", "flac", "wav", "m4a", "aac", "ogg", "opus", "wma", "ape", "dsd", "dsf", "aif", "aiff", "aifc";
Csv: "csv", "tsv", "tab", "psv";
Html: "html", "htm";
Docx: "docx";
Xlsx: "xlsx";
Pptx: "pptx";
Sqlite: "db", "sqlite", "sqlite3";
Toml: "toml", "lock";
Ini: "ini", "cfg";
Xml: "xml";
Yaml: "yaml", "yml";
Zip: "zip";
Archive: "tar", "gz", "bz2", "xz", "tgz";
Epub: "epub";
Pdf: "pdf";
};
fn get_file_type_from_extension(extension: &str) -> FileType {
FILE_EXTENSION_MAP
.iter()
.find(|(ext, _)| *ext == extension)
.map_or(FileType::Unknown, |(_, file_type)| *file_type)
}
#[must_use]
pub fn get_extensions_for_file_type(file_type: FileType) -> Vec<&'static str> {
FILE_EXTENSION_MAP
.iter()
.filter_map(|(ext, ft)| if *ft == file_type { Some(*ext) } else { None })
.collect()
}
#[must_use]
pub fn is_codec_for_file_type(codec: &str, file_type: FileType) -> bool {
let codec_lower = codec.to_lowercase();
FILE_EXTENSION_MAP
.iter()
.any(|(ext, ft)| *ft == file_type && codec_lower.contains(ext))
}
#[must_use]
pub fn detect_file_type(path: &str) -> FileType {
let lo = path.to_lowercase();
if lo.ends_with(".tar.xz")
|| lo.ends_with(".tar.bz2")
|| lo.ends_with(".tar.gz")
|| lo.ends_with(".tgz")
{
return FileType::Archive;
}
let extension = Path::new(path)
.extension()
.and_then(|ext| ext.to_str())
.map(str::to_lowercase)
.unwrap_or_default();
let file_type = get_file_type_from_extension(&extension);
if file_type == FileType::Unknown {
let p = Path::new(path);
if p.exists() {
let by_ext = linguist::detect_language_by_extension(p)
.ok()
.unwrap_or_default();
if !by_ext.is_empty() {
return FileType::Code;
}
let by_name = linguist::detect_language_by_filename(p)
.ok()
.unwrap_or_default();
if !by_name.is_empty() {
return FileType::Code;
}
}
}
file_type
}