diff --git a/crates/file_icons/src/file_icons.rs b/crates/file_icons/src/file_icons.rs index 327b1451523748aa91356bdb5854e2ef165a5085..b7322a717d20f232cad7b9239a46a5eb0e124abd 100644 --- a/crates/file_icons/src/file_icons.rs +++ b/crates/file_icons/src/file_icons.rs @@ -52,6 +52,15 @@ impl FileIcons { } } + // handle cases where the file extension is made up of multiple important + // parts (e.g Component.stories.tsx) that refer to an alternative icon style + if let Some(suffix) = path.multiple_extensions() { + let maybe_path = get_icon_from_suffix(suffix.as_str()); + if maybe_path.is_some() { + return maybe_path; + } + } + // primary case: check if the files extension or the hidden file name // matches some icon path if let Some(suffix) = path.extension_or_hidden_file_name() { diff --git a/crates/util/src/paths.rs b/crates/util/src/paths.rs index f9fe0ab33da2dc97b7bb59f9a0c109d0f96a4536..3fe6a526c866ff132b8f77d7efb4673bcc2a65fa 100644 --- a/crates/util/src/paths.rs +++ b/crates/util/src/paths.rs @@ -1,4 +1,5 @@ use globset::{Glob, GlobSet, GlobSetBuilder}; +use itertools::Itertools; use regex::Regex; use serde::{Deserialize, Serialize}; use std::cmp::Ordering; @@ -60,6 +61,7 @@ pub trait PathExt { } } fn local_to_wsl(&self) -> Option; + fn multiple_extensions(&self) -> Option; } impl> PathExt for T { @@ -130,6 +132,27 @@ impl> PathExt for T { Some(new_path.into()) } + + /// Returns a file's "full" joined collection of extensions, in the case where a file does not + /// just have a singular extension but instead has multiple (e.g File.tar.gz, Component.stories.tsx) + /// + /// Will provide back the extensions joined together such as tar.gz or stories.tsx + fn multiple_extensions(&self) -> Option { + let path = self.as_ref(); + let file_name = path.file_name()?.to_str()?; + + let parts: Vec<&str> = file_name + .split('.') + // Skip the part with the file name extension + .skip(1) + .collect(); + + if parts.len() < 2 { + return None; + } + + Some(parts.into_iter().join(".")) + } } /// In memory, this is identical to `Path`. On non-Windows conversions to this type are no-ops. On @@ -1727,4 +1750,23 @@ mod tests { assert_eq!(natural_sort("file-1.2", "file-1.10"), Ordering::Less); assert_eq!(natural_sort("file-1.10", "file-1.2"), Ordering::Greater); } + + #[test] + fn test_multiple_extensions() { + // No extensions + let path = Path::new("/a/b/c/file_name"); + assert_eq!(path.multiple_extensions(), None); + + // Only one extension + let path = Path::new("/a/b/c/file_name.tsx"); + assert_eq!(path.multiple_extensions(), None); + + // Stories sample extension + let path = Path::new("/a/b/c/file_name.stories.tsx"); + assert_eq!(path.multiple_extensions(), Some("stories.tsx".to_string())); + + // Longer sample extension + let path = Path::new("/a/b/c/long.app.tar.gz"); + assert_eq!(path.multiple_extensions(), Some("app.tar.gz".to_string())); + } }