feat: support multiple extensions for file icons
Currently most icon theme extensions already support file types like stories.tsx and stories.svelte. However within Zed itself these file type overrides are not supported yet. This change adds support for those
This commit is contained in:
parent
4e97968bcb
commit
8c0dad104f
2 changed files with 52 additions and 0 deletions
|
@ -42,6 +42,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() {
|
||||
|
@ -62,6 +71,7 @@ impl FileIcons {
|
|||
return maybe_path;
|
||||
}
|
||||
}
|
||||
|
||||
return this.get_icon_for_type("default", cx);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ use std::{
|
|||
};
|
||||
|
||||
use globset::{Glob, GlobSet, GlobSetBuilder};
|
||||
use itertools::Itertools;
|
||||
use regex::Regex;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
@ -22,6 +23,7 @@ pub fn home_dir() -> &'static PathBuf {
|
|||
pub trait PathExt {
|
||||
fn compact(&self) -> PathBuf;
|
||||
fn extension_or_hidden_file_name(&self) -> Option<&str>;
|
||||
fn multiple_extensions(&self) -> Option<String>;
|
||||
fn to_sanitized_string(&self) -> String;
|
||||
fn try_from_bytes<'a>(bytes: &'a [u8]) -> anyhow::Result<Self>
|
||||
where
|
||||
|
@ -86,6 +88,27 @@ impl<T: AsRef<Path>> PathExt for T {
|
|||
.or_else(|| path.file_stem()?.to_str())
|
||||
}
|
||||
|
||||
/// 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<String> {
|
||||
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("."))
|
||||
}
|
||||
|
||||
/// Returns a sanitized string representation of the path.
|
||||
/// Note, on Windows, this assumes that the path is a valid UTF-8 string and
|
||||
/// is not a UNC path.
|
||||
|
@ -1012,6 +1035,25 @@ mod tests {
|
|||
assert_eq!(path.extension_or_hidden_file_name(), Some("eslintrc.js"));
|
||||
}
|
||||
|
||||
#[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()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn edge_of_glob() {
|
||||
let path = Path::new("/work/node_modules");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue