icon_theme.rs

  1use std::sync::{Arc, LazyLock};
  2
  3use collections::HashMap;
  4use gpui::SharedString;
  5
  6use crate::Appearance;
  7
  8/// A family of icon themes.
  9pub struct IconThemeFamily {
 10    /// The unique ID for the icon theme family.
 11    pub id: String,
 12    /// The name of the icon theme family.
 13    pub name: SharedString,
 14    /// The author of the icon theme family.
 15    pub author: SharedString,
 16    /// The list of icon themes in the family.
 17    pub themes: Vec<IconTheme>,
 18}
 19
 20/// An icon theme.
 21#[derive(Debug, PartialEq)]
 22pub struct IconTheme {
 23    /// The unique ID for the icon theme.
 24    pub id: String,
 25    /// The name of the icon theme.
 26    pub name: SharedString,
 27    /// The appearance of the icon theme (e.g., light or dark).
 28    pub appearance: Appearance,
 29    /// The icons used for directories.
 30    pub directory_icons: DirectoryIcons,
 31    /// The icons used for chevrons.
 32    pub chevron_icons: ChevronIcons,
 33    /// The mapping of file stems to their associated icon keys.
 34    pub file_stems: HashMap<String, String>,
 35    /// The mapping of file suffixes to their associated icon keys.
 36    pub file_suffixes: HashMap<String, String>,
 37    /// The mapping of icon keys to icon definitions.
 38    pub file_icons: HashMap<String, IconDefinition>,
 39}
 40
 41/// The icons used for directories.
 42#[derive(Debug, PartialEq)]
 43pub struct DirectoryIcons {
 44    /// The path to the icon to use for a collapsed directory.
 45    pub collapsed: Option<SharedString>,
 46    /// The path to the icon to use for an expanded directory.
 47    pub expanded: Option<SharedString>,
 48}
 49
 50/// The icons used for chevrons.
 51#[derive(Debug, PartialEq)]
 52pub struct ChevronIcons {
 53    /// The path to the icon to use for a collapsed chevron.
 54    pub collapsed: Option<SharedString>,
 55    /// The path to the icon to use for an expanded chevron.
 56    pub expanded: Option<SharedString>,
 57}
 58
 59/// An icon definition.
 60#[derive(Debug, PartialEq)]
 61pub struct IconDefinition {
 62    /// The path to the icon file.
 63    pub path: SharedString,
 64}
 65
 66const FILE_STEMS_BY_ICON_KEY: &[(&str, &[&str])] = &[
 67    ("docker", &["Dockerfile"]),
 68    ("ruby", &["Podfile"]),
 69    ("heroku", &["Procfile"]),
 70];
 71
 72const FILE_SUFFIXES_BY_ICON_KEY: &[(&str, &[&str])] = &[
 73    ("astro", &["astro"]),
 74    (
 75        "audio",
 76        &[
 77            "aac", "flac", "m4a", "mka", "mp3", "ogg", "opus", "wav", "wma", "wv",
 78        ],
 79    ),
 80    ("backup", &["bak"]),
 81    ("bicep", &["bicep"]),
 82    ("bun", &["lockb"]),
 83    ("c", &["c", "h"]),
 84    ("cairo", &["cairo"]),
 85    ("code", &["handlebars", "metadata", "rkt", "scm"]),
 86    ("coffeescript", &["coffee"]),
 87    (
 88        "cpp",
 89        &["c++", "cc", "cpp", "cxx", "hh", "hpp", "hxx", "inl", "ixx"],
 90    ),
 91    ("crystal", &["cr", "ecr"]),
 92    ("csharp", &["cs"]),
 93    ("csproj", &["csproj"]),
 94    ("css", &["css", "pcss", "postcss"]),
 95    ("cue", &["cue"]),
 96    ("dart", &["dart"]),
 97    ("diff", &["diff"]),
 98    (
 99        "document",
100        &[
101            "doc", "docx", "mdx", "odp", "ods", "odt", "pdf", "ppt", "pptx", "rtf", "txt", "xls",
102            "xlsx",
103        ],
104    ),
105    ("elixir", &["eex", "ex", "exs", "heex"]),
106    ("elm", &["elm"]),
107    (
108        "erlang",
109        &[
110            "Emakefile",
111            "app.src",
112            "erl",
113            "escript",
114            "hrl",
115            "rebar.config",
116            "xrl",
117            "yrl",
118        ],
119    ),
120    (
121        "eslint",
122        &[
123            "eslint.config.cjs",
124            "eslint.config.cts",
125            "eslint.config.js",
126            "eslint.config.mjs",
127            "eslint.config.mts",
128            "eslint.config.ts",
129            "eslintrc",
130            "eslintrc.js",
131            "eslintrc.json",
132        ],
133    ),
134    ("font", &["otf", "ttf", "woff", "woff2"]),
135    ("fsharp", &["fs"]),
136    ("fsproj", &["fsproj"]),
137    ("gitlab", &["gitlab-ci.yml"]),
138    ("gleam", &["gleam"]),
139    ("go", &["go", "mod", "work"]),
140    ("graphql", &["gql", "graphql", "graphqls"]),
141    ("haskell", &["hs"]),
142    ("hcl", &["hcl"]),
143    ("html", &["htm", "html"]),
144    (
145        "image",
146        &[
147            "avif", "bmp", "gif", "heic", "heif", "ico", "j2k", "jfif", "jp2", "jpeg", "jpg",
148            "jxl", "png", "psd", "qoi", "svg", "tiff", "webp",
149        ],
150    ),
151    ("java", &["java"]),
152    ("javascript", &["cjs", "js", "mjs"]),
153    ("json", &["json"]),
154    ("julia", &["jl"]),
155    ("kdl", &["kdl"]),
156    ("kotlin", &["kt"]),
157    ("lock", &["lock"]),
158    ("log", &["log"]),
159    ("lua", &["lua"]),
160    ("luau", &["luau"]),
161    ("markdown", &["markdown", "md"]),
162    ("metal", &["metal"]),
163    ("nim", &["nim"]),
164    ("nix", &["nix"]),
165    ("ocaml", &["ml", "mli"]),
166    ("php", &["php"]),
167    (
168        "prettier",
169        &[
170            "prettier.config.cjs",
171            "prettier.config.js",
172            "prettier.config.mjs",
173            "prettierignore",
174            "prettierrc",
175            "prettierrc.cjs",
176            "prettierrc.js",
177            "prettierrc.json",
178            "prettierrc.json5",
179            "prettierrc.mjs",
180            "prettierrc.toml",
181            "prettierrc.yaml",
182            "prettierrc.yml",
183        ],
184    ),
185    ("prisma", &["prisma"]),
186    ("python", &["py"]),
187    ("r", &["r", "R"]),
188    ("react", &["cjsx", "ctsx", "jsx", "mjsx", "mtsx", "tsx"]),
189    ("roc", &["roc"]),
190    ("ruby", &["rb"]),
191    ("rust", &["rs"]),
192    ("sass", &["sass", "scss"]),
193    ("scala", &["scala", "sc"]),
194    ("settings", &["conf", "ini", "yaml", "yml"]),
195    ("solidity", &["sol"]),
196    (
197        "storage",
198        &[
199            "accdb", "csv", "dat", "db", "dbf", "dll", "fmp", "fp7", "frm", "gdb", "ib", "jsonc",
200            "ldf", "mdb", "mdf", "myd", "myi", "pdb", "RData", "rdata", "sav", "sdf", "sql",
201            "sqlite", "tsv",
202        ],
203    ),
204    (
205        "stylelint",
206        &[
207            "stylelint.config.cjs",
208            "stylelint.config.js",
209            "stylelint.config.mjs",
210            "stylelintignore",
211            "stylelintrc",
212            "stylelintrc.cjs",
213            "stylelintrc.js",
214            "stylelintrc.json",
215            "stylelintrc.mjs",
216            "stylelintrc.yaml",
217            "stylelintrc.yml",
218        ],
219    ),
220    ("surrealql", &["surql"]),
221    ("svelte", &["svelte"]),
222    ("swift", &["swift"]),
223    ("tcl", &["tcl"]),
224    ("template", &["hbs", "plist", "xml"]),
225    (
226        "terminal",
227        &[
228            "bash",
229            "bash_aliases",
230            "bash_login",
231            "bash_logout",
232            "bash_profile",
233            "bashrc",
234            "fish",
235            "nu",
236            "profile",
237            "ps1",
238            "sh",
239            "zlogin",
240            "zlogout",
241            "zprofile",
242            "zsh",
243            "zsh_aliases",
244            "zsh_histfile",
245            "zsh_history",
246            "zshenv",
247            "zshrc",
248        ],
249    ),
250    ("terraform", &["tf", "tfvars"]),
251    ("toml", &["toml"]),
252    ("typescript", &["cts", "mts", "ts"]),
253    ("v", &["v", "vsh", "vv"]),
254    (
255        "vcs",
256        &[
257            "COMMIT_EDITMSG",
258            "EDIT_DESCRIPTION",
259            "MERGE_MSG",
260            "NOTES_EDITMSG",
261            "TAG_EDITMSG",
262            "gitattributes",
263            "gitignore",
264            "gitkeep",
265            "gitmodules",
266        ],
267    ),
268    ("vbproj", &["vbproj"]),
269    ("video", &["avi", "m4v", "mkv", "mov", "mp4", "webm", "wmv"]),
270    ("vs_sln", &["sln"]),
271    ("vs_suo", &["suo"]),
272    ("vue", &["vue"]),
273    ("vyper", &["vy", "vyi"]),
274    ("wgsl", &["wgsl"]),
275    ("zig", &["zig"]),
276];
277
278/// A mapping of a file type identifier to its corresponding icon.
279const FILE_ICONS: &[(&str, &str)] = &[
280    ("astro", "icons/file_icons/astro.svg"),
281    ("audio", "icons/file_icons/audio.svg"),
282    ("bicep", "icons/file_icons/file.svg"),
283    ("bun", "icons/file_icons/bun.svg"),
284    ("c", "icons/file_icons/c.svg"),
285    ("cairo", "icons/file_icons/cairo.svg"),
286    ("code", "icons/file_icons/code.svg"),
287    ("coffeescript", "icons/file_icons/coffeescript.svg"),
288    ("cpp", "icons/file_icons/cpp.svg"),
289    ("crystal", "icons/file_icons/file.svg"),
290    ("csharp", "icons/file_icons/file.svg"),
291    ("csproj", "icons/file_icons/file.svg"),
292    ("css", "icons/file_icons/css.svg"),
293    ("cue", "icons/file_icons/file.svg"),
294    ("dart", "icons/file_icons/dart.svg"),
295    ("default", "icons/file_icons/file.svg"),
296    ("diff", "icons/file_icons/diff.svg"),
297    ("docker", "icons/file_icons/docker.svg"),
298    ("document", "icons/file_icons/book.svg"),
299    ("elixir", "icons/file_icons/elixir.svg"),
300    ("elm", "icons/file_icons/elm.svg"),
301    ("erlang", "icons/file_icons/erlang.svg"),
302    ("eslint", "icons/file_icons/eslint.svg"),
303    ("font", "icons/file_icons/font.svg"),
304    ("fsharp", "icons/file_icons/fsharp.svg"),
305    ("fsproj", "icons/file_icons/file.svg"),
306    ("gitlab", "icons/file_icons/settings.svg"),
307    ("gleam", "icons/file_icons/gleam.svg"),
308    ("go", "icons/file_icons/go.svg"),
309    ("graphql", "icons/file_icons/graphql.svg"),
310    ("haskell", "icons/file_icons/haskell.svg"),
311    ("hcl", "icons/file_icons/hcl.svg"),
312    ("heroku", "icons/file_icons/heroku.svg"),
313    ("html", "icons/file_icons/html.svg"),
314    ("image", "icons/file_icons/image.svg"),
315    ("java", "icons/file_icons/java.svg"),
316    ("javascript", "icons/file_icons/javascript.svg"),
317    ("json", "icons/file_icons/code.svg"),
318    ("julia", "icons/file_icons/julia.svg"),
319    ("kdl", "icons/file_icons/kdl.svg"),
320    ("kotlin", "icons/file_icons/kotlin.svg"),
321    ("lock", "icons/file_icons/lock.svg"),
322    ("log", "icons/file_icons/info.svg"),
323    ("lua", "icons/file_icons/lua.svg"),
324    ("luau", "icons/file_icons/luau.svg"),
325    ("markdown", "icons/file_icons/book.svg"),
326    ("metal", "icons/file_icons/metal.svg"),
327    ("nim", "icons/file_icons/nim.svg"),
328    ("nix", "icons/file_icons/nix.svg"),
329    ("ocaml", "icons/file_icons/ocaml.svg"),
330    ("phoenix", "icons/file_icons/phoenix.svg"),
331    ("php", "icons/file_icons/php.svg"),
332    ("prettier", "icons/file_icons/prettier.svg"),
333    ("prisma", "icons/file_icons/prisma.svg"),
334    ("python", "icons/file_icons/python.svg"),
335    ("r", "icons/file_icons/r.svg"),
336    ("react", "icons/file_icons/react.svg"),
337    ("roc", "icons/file_icons/roc.svg"),
338    ("ruby", "icons/file_icons/ruby.svg"),
339    ("rust", "icons/file_icons/rust.svg"),
340    ("sass", "icons/file_icons/sass.svg"),
341    ("scala", "icons/file_icons/scala.svg"),
342    ("settings", "icons/file_icons/settings.svg"),
343    ("solidity", "icons/file_icons/file.svg"),
344    ("storage", "icons/file_icons/database.svg"),
345    ("stylelint", "icons/file_icons/javascript.svg"),
346    ("surrealql", "icons/file_icons/surrealql.svg"),
347    ("svelte", "icons/file_icons/html.svg"),
348    ("swift", "icons/file_icons/swift.svg"),
349    ("tcl", "icons/file_icons/tcl.svg"),
350    ("template", "icons/file_icons/html.svg"),
351    ("terminal", "icons/file_icons/terminal.svg"),
352    ("terraform", "icons/file_icons/terraform.svg"),
353    ("toml", "icons/file_icons/toml.svg"),
354    ("typescript", "icons/file_icons/typescript.svg"),
355    ("v", "icons/file_icons/v.svg"),
356    ("vbproj", "icons/file_icons/file.svg"),
357    ("vcs", "icons/file_icons/git.svg"),
358    ("video", "icons/file_icons/video.svg"),
359    ("vs_sln", "icons/file_icons/file.svg"),
360    ("vs_suo", "icons/file_icons/file.svg"),
361    ("vue", "icons/file_icons/vue.svg"),
362    ("vyper", "icons/file_icons/vyper.svg"),
363    ("wgsl", "icons/file_icons/wgsl.svg"),
364    ("zig", "icons/file_icons/zig.svg"),
365];
366
367/// Returns a mapping of file associations to icon keys.
368fn icon_keys_by_association(
369    associations_by_icon_key: &[(&str, &[&str])],
370) -> HashMap<String, String> {
371    let mut icon_keys_by_association = HashMap::default();
372    for (icon_key, associations) in associations_by_icon_key {
373        for association in *associations {
374            icon_keys_by_association.insert(association.to_string(), icon_key.to_string());
375        }
376    }
377
378    icon_keys_by_association
379}
380
381/// The name of the default icon theme.
382pub(crate) const DEFAULT_ICON_THEME_NAME: &str = "Zed (Default)";
383
384static DEFAULT_ICON_THEME: LazyLock<Arc<IconTheme>> = LazyLock::new(|| {
385    Arc::new(IconTheme {
386        id: "zed".into(),
387        name: DEFAULT_ICON_THEME_NAME.into(),
388        appearance: Appearance::Dark,
389        directory_icons: DirectoryIcons {
390            collapsed: Some("icons/file_icons/folder.svg".into()),
391            expanded: Some("icons/file_icons/folder_open.svg".into()),
392        },
393        chevron_icons: ChevronIcons {
394            collapsed: Some("icons/file_icons/chevron_right.svg".into()),
395            expanded: Some("icons/file_icons/chevron_down.svg".into()),
396        },
397        file_stems: icon_keys_by_association(FILE_STEMS_BY_ICON_KEY),
398        file_suffixes: icon_keys_by_association(FILE_SUFFIXES_BY_ICON_KEY),
399        file_icons: HashMap::from_iter(FILE_ICONS.into_iter().map(|(ty, path)| {
400            (
401                ty.to_string(),
402                IconDefinition {
403                    path: (*path).into(),
404                },
405            )
406        })),
407    })
408});
409
410/// Returns the default icon theme.
411pub fn default_icon_theme() -> Arc<IconTheme> {
412    DEFAULT_ICON_THEME.clone()
413}