file_icons.rs

 1use std::{path::Path, str};
 2
 3use collections::HashMap;
 4
 5use gpui::{AppContext, AssetSource, Global, SharedString};
 6use serde_derive::Deserialize;
 7use settings::Settings;
 8use theme::ThemeSettings;
 9use util::{maybe, paths::PathExt};
10
11#[derive(Deserialize, Debug)]
12pub struct FileIcons {
13    stems: HashMap<String, String>,
14    suffixes: HashMap<String, String>,
15}
16
17impl Global for FileIcons {}
18
19pub const FILE_TYPES_ASSET: &str = "icons/file_icons/file_types.json";
20
21pub fn init(assets: impl AssetSource, cx: &mut AppContext) {
22    cx.set_global(FileIcons::new(assets))
23}
24
25impl FileIcons {
26    pub fn get(cx: &AppContext) -> &Self {
27        cx.global::<FileIcons>()
28    }
29
30    pub fn new(assets: impl AssetSource) -> Self {
31        assets
32            .load(FILE_TYPES_ASSET)
33            .ok()
34            .flatten()
35            .and_then(|file| serde_json::from_str::<FileIcons>(str::from_utf8(&file).unwrap()).ok())
36            .unwrap_or_else(|| FileIcons {
37                stems: HashMap::default(),
38                suffixes: HashMap::default(),
39            })
40    }
41
42    pub fn get_icon(path: &Path, cx: &AppContext) -> Option<SharedString> {
43        let this = cx.try_global::<Self>()?;
44
45        // TODO: Associate a type with the languages and have the file's language
46        //       override these associations
47        maybe!({
48            let suffix = path.icon_stem_or_suffix()?;
49
50            if let Some(type_str) = this.stems.get(suffix) {
51                return this.get_icon_for_type(type_str, cx);
52            }
53
54            this.suffixes
55                .get(suffix)
56                .and_then(|type_str| this.get_icon_for_type(type_str, cx))
57        })
58        .or_else(|| this.get_icon_for_type("default", cx))
59    }
60
61    pub fn get_icon_for_type(&self, typ: &str, cx: &AppContext) -> Option<SharedString> {
62        let theme_settings = ThemeSettings::get_global(cx);
63
64        theme_settings
65            .active_icon_theme
66            .file_icons
67            .get(typ)
68            .map(|icon_definition| icon_definition.path.clone())
69    }
70
71    pub fn get_folder_icon(expanded: bool, cx: &AppContext) -> Option<SharedString> {
72        let icon_theme = &ThemeSettings::get_global(cx).active_icon_theme;
73
74        if expanded {
75            icon_theme.directory_icons.expanded.clone()
76        } else {
77            icon_theme.directory_icons.collapsed.clone()
78        }
79    }
80
81    pub fn get_chevron_icon(expanded: bool, cx: &AppContext) -> Option<SharedString> {
82        let icon_theme = &ThemeSettings::get_global(cx).active_icon_theme;
83
84        if expanded {
85            icon_theme.chevron_icons.expanded.clone()
86        } else {
87            icon_theme.chevron_icons.collapsed.clone()
88        }
89    }
90}