filetype.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. //! Tests for various types of file (video, image, compressed, etc).
  2. //!
  3. //! Currently this is dependent on the file’s name and extension, because
  4. //! those are the only metadata that we have access to without reading the
  5. //! file’s contents.
  6. //!
  7. //! # Contributors
  8. //! Please keep these lists sorted. If you're using vim, :sort i
  9. use ansi_term::Style;
  10. use phf::{phf_map, Map};
  11. use crate::fs::File;
  12. use crate::theme::FileColours;
  13. #[derive(Debug, Clone)]
  14. pub enum FileType {
  15. Image,
  16. Video,
  17. Music,
  18. Lossless, // Lossless music, rather than any other kind of data...
  19. Crypto,
  20. Document,
  21. Compressed,
  22. Temp,
  23. Compiled,
  24. Immediate // An “immediate” file is something that can be run or activated somehow in order to
  25. // kick off the build of a project. It’s usually only present in directories full of
  26. // source code.
  27. }
  28. /// Mapping from full filenames to file type.
  29. const FILENAME_TYPES: Map<&'static str, FileType> = phf_map! {
  30. /* Immediate file - kick off the build of a project */
  31. "Brewfile" => FileType::Immediate,
  32. "bsconfig.json" => FileType::Immediate,
  33. "BUILD" => FileType::Immediate,
  34. "BUILD.bazel" => FileType::Immediate,
  35. "build.gradle" => FileType::Immediate,
  36. "build.sbt" => FileType::Immediate,
  37. "build.xml" => FileType::Immediate,
  38. "Cargo.lock" => FileType::Immediate,
  39. "Cargo.toml" => FileType::Immediate,
  40. "CMakeLists.txt" => FileType::Immediate,
  41. "composer.json" => FileType::Immediate,
  42. "configure.ac" => FileType::Immediate,
  43. "Configure.ac" => FileType::Immediate,
  44. "Containerfile" => FileType::Immediate,
  45. "Dockerfile" => FileType::Immediate,
  46. "Earthfile" => FileType::Immediate,
  47. "flake.lock" => FileType::Immediate,
  48. "flake.nix" => FileType::Immediate,
  49. "Gemfile" => FileType::Immediate,
  50. "GNUmakefile" => FileType::Immediate,
  51. "Gruntfile.coffee" => FileType::Immediate,
  52. "Gruntfile.js" => FileType::Immediate,
  53. "Justfile" => FileType::Immediate,
  54. "justfile" => FileType::Immediate,
  55. "Makefile" => FileType::Immediate,
  56. "makefile" => FileType::Immediate,
  57. "Makefile.in" => FileType::Immediate,
  58. "makefile.in" => FileType::Immediate,
  59. "meson.build" => FileType::Immediate,
  60. "mix.exs" => FileType::Immediate,
  61. "package.json" => FileType::Immediate,
  62. "Pipfile" => FileType::Immediate,
  63. "PKGBUILD" => FileType::Immediate,
  64. "Podfile" => FileType::Immediate,
  65. "pom.xml" => FileType::Immediate,
  66. "Procfile" => FileType::Immediate,
  67. "Rakefile" => FileType::Immediate,
  68. "RoboFile.php" => FileType::Immediate,
  69. "SConstruct" => FileType::Immediate,
  70. "tsconfig.json" => FileType::Immediate,
  71. "Vagrantfile" => FileType::Immediate,
  72. "webpack.config.cjs" => FileType::Immediate,
  73. "webpack.config.js" => FileType::Immediate,
  74. "WORKSPACE" => FileType::Immediate,
  75. };
  76. /// Mapping from lowercase file extension to file type. If an image, video, music, or lossless
  77. /// extension is added also update the extension icon map.
  78. const EXTENSION_TYPES: Map<&'static str, FileType> = phf_map! {
  79. /* Immediate file - kick off the build of a project */
  80. "ninja" => FileType::Immediate,
  81. /* Image files */
  82. "arw" => FileType::Image,
  83. "avif" => FileType::Image,
  84. "bmp" => FileType::Image,
  85. "cbr" => FileType::Image,
  86. "cbz" => FileType::Image,
  87. "cr2" => FileType::Image,
  88. "dvi" => FileType::Image,
  89. "eps" => FileType::Image,
  90. "gif" => FileType::Image,
  91. "heif" => FileType::Image,
  92. "ico" => FileType::Image,
  93. "j2c" => FileType::Image,
  94. "j2k" => FileType::Image,
  95. "jfi" => FileType::Image,
  96. "jfif" => FileType::Image,
  97. "jif" => FileType::Image,
  98. "jp2" => FileType::Image,
  99. "jpe" => FileType::Image,
  100. "jpeg" => FileType::Image,
  101. "jpf" => FileType::Image,
  102. "jpg" => FileType::Image,
  103. "jpx" => FileType::Image,
  104. "jxl" => FileType::Image,
  105. "nef" => FileType::Image,
  106. "orf" => FileType::Image,
  107. "pbm" => FileType::Image,
  108. "pgm" => FileType::Image,
  109. "png" => FileType::Image,
  110. "pnm" => FileType::Image,
  111. "ppm" => FileType::Image,
  112. "ps" => FileType::Image,
  113. "pxm" => FileType::Image,
  114. "raw" => FileType::Image,
  115. "stl" => FileType::Image,
  116. "svg" => FileType::Image,
  117. "tif" => FileType::Image,
  118. "tiff" => FileType::Image,
  119. "webp" => FileType::Image,
  120. "xpm" => FileType::Image,
  121. /* Video files */
  122. "avi" => FileType::Video,
  123. "flv" => FileType::Video,
  124. "heic" => FileType::Video,
  125. "m2ts" => FileType::Video,
  126. "m2v" => FileType::Video,
  127. "m4v" => FileType::Video,
  128. "mkv" => FileType::Video,
  129. "mov" => FileType::Video,
  130. "mp4" => FileType::Video,
  131. "mpeg" => FileType::Video,
  132. "mpg" => FileType::Video,
  133. "ogm" => FileType::Video,
  134. "ogv" => FileType::Video,
  135. "vob" => FileType::Video,
  136. "webm" => FileType::Video,
  137. "wmv" => FileType::Video,
  138. /* Music files */
  139. "aac" => FileType::Music,
  140. "m4a" => FileType::Music,
  141. "mka" => FileType::Music,
  142. "mp2" => FileType::Music,
  143. "mp3" => FileType::Music,
  144. "ogg" => FileType::Music,
  145. "opus" => FileType::Music,
  146. "wma" => FileType::Music,
  147. /* Lossless music, rather than any other kind of data... */
  148. "alac" => FileType::Lossless,
  149. "ape" => FileType::Lossless,
  150. "flac" => FileType::Lossless,
  151. "wav" => FileType::Lossless,
  152. /* Cryptology files */
  153. "asc" => FileType::Crypto,
  154. "enc" => FileType::Crypto,
  155. "gpg" => FileType::Crypto,
  156. "p12" => FileType::Crypto,
  157. "pfx" => FileType::Crypto,
  158. "pgp" => FileType::Crypto,
  159. "sig" => FileType::Crypto,
  160. "signature" => FileType::Crypto,
  161. /* Document files */
  162. "djvu" => FileType::Document,
  163. "doc" => FileType::Document,
  164. "docx" => FileType::Document,
  165. "eml" => FileType::Document,
  166. "fotd" => FileType::Document,
  167. "key" => FileType::Document,
  168. "keynote" => FileType::Document,
  169. "numbers" => FileType::Document,
  170. "odp" => FileType::Document,
  171. "odt" => FileType::Document,
  172. "pages" => FileType::Document,
  173. "pdf" => FileType::Document,
  174. "ppt" => FileType::Document,
  175. "pptx" => FileType::Document,
  176. "rtf" => FileType::Document,
  177. "xls" => FileType::Document,
  178. "xlsx" => FileType::Document,
  179. /* Compressed/archive files */
  180. "7z" => FileType::Compressed,
  181. "a" => FileType::Compressed,
  182. "ar" => FileType::Compressed,
  183. "bz" => FileType::Compressed,
  184. "bz2" => FileType::Compressed,
  185. "cpio" => FileType::Compressed,
  186. "deb" => FileType::Compressed,
  187. "dmg" => FileType::Compressed,
  188. "gz" => FileType::Compressed,
  189. "iso" => FileType::Compressed,
  190. "lz" => FileType::Compressed,
  191. "lz4" => FileType::Compressed,
  192. "lzh" => FileType::Compressed,
  193. "lzma" => FileType::Compressed,
  194. "lzo" => FileType::Compressed,
  195. "par" => FileType::Compressed,
  196. "rar" => FileType::Compressed,
  197. "rpm" => FileType::Compressed,
  198. "tar" => FileType::Compressed,
  199. "taz" => FileType::Compressed,
  200. "tbz" => FileType::Compressed,
  201. "tbz2" => FileType::Compressed,
  202. "tc" => FileType::Compressed,
  203. "tgz" => FileType::Compressed,
  204. "tlz" => FileType::Compressed,
  205. "txz" => FileType::Compressed,
  206. "tz" => FileType::Compressed,
  207. "tzo" => FileType::Compressed,
  208. "xz" => FileType::Compressed,
  209. "z" => FileType::Compressed,
  210. "zip" => FileType::Compressed,
  211. "zst" => FileType::Compressed,
  212. /* Temporary files */
  213. "bak" => FileType::Temp,
  214. "bk" => FileType::Temp,
  215. "bkp" => FileType::Temp,
  216. "swn" => FileType::Temp,
  217. "swo" => FileType::Temp,
  218. "swp" => FileType::Temp,
  219. "tmp" => FileType::Temp,
  220. /* Compiler output files */
  221. "class" => FileType::Compiled,
  222. "elc" => FileType::Compiled,
  223. "hi" => FileType::Compiled,
  224. "ko" => FileType::Compiled,
  225. "o" => FileType::Compiled,
  226. "pyc" => FileType::Compiled,
  227. "zwc" => FileType::Compiled,
  228. };
  229. impl FileType {
  230. /// Lookup the file type based on the file's name, by the file name
  231. /// lowercase extension, or if the file could be compiled from related
  232. /// source code.
  233. fn get_file_type(file: &File<'_>) -> Option<FileType> {
  234. // Case-insensitive readme is checked first for backwards compatibility.
  235. if file.name.to_lowercase().starts_with("readme") {
  236. return Some(Self::Immediate)
  237. }
  238. if let Some(file_type) = FILENAME_TYPES.get(&file.name) {
  239. return Some(file_type.clone())
  240. }
  241. if let Some(file_type) = file.ext.as_ref().and_then(|ext| EXTENSION_TYPES.get(ext)) {
  242. return Some(file_type.clone())
  243. }
  244. if file.name.ends_with('~') || (file.name.starts_with('#') && file.name.ends_with('#')) {
  245. return Some(Self::Temp)
  246. }
  247. if let Some(dir) = file.parent_dir {
  248. if file.get_source_files().iter().any(|path| dir.contains(path)) {
  249. return Some(Self::Compiled)
  250. }
  251. }
  252. None
  253. }
  254. }
  255. #[derive(Debug)]
  256. pub struct FileTypeColor;
  257. impl FileColours for FileTypeColor {
  258. /// Map from the file type to the display style/color for the file.
  259. fn colour_file(&self, file: &File<'_>) -> Option<Style> {
  260. use ansi_term::Colour::*;
  261. match FileType::get_file_type(file) {
  262. Some(FileType::Compiled) => Some(Yellow.normal()),
  263. Some(FileType::Compressed) => Some(Red.normal()),
  264. Some(FileType::Crypto) => Some(Green.bold()),
  265. Some(FileType::Document) => Some(Green.normal()),
  266. Some(FileType::Image) => Some(Purple.normal()),
  267. Some(FileType::Immediate) => Some(Yellow.bold().underline()),
  268. Some(FileType::Lossless) => Some(Cyan.bold()),
  269. Some(FileType::Music) => Some(Cyan.normal()),
  270. Some(FileType::Temp) => Some(White.normal()),
  271. Some(FileType::Video) => Some(Purple.bold()),
  272. _ => None
  273. }
  274. }
  275. }