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 ("puppet", &["pp"]),
187 ("python", &["py"]),
188 ("r", &["r", "R"]),
189 ("react", &["cjsx", "ctsx", "jsx", "mjsx", "mtsx", "tsx"]),
190 ("roc", &["roc"]),
191 ("ruby", &["rb"]),
192 ("rust", &["rs"]),
193 ("sass", &["sass", "scss"]),
194 ("scala", &["scala", "sc"]),
195 ("settings", &["conf", "ini", "yaml", "yml"]),
196 ("solidity", &["sol"]),
197 (
198 "storage",
199 &[
200 "accdb", "csv", "dat", "db", "dbf", "dll", "fmp", "fp7", "frm", "gdb", "ib", "jsonc",
201 "ldf", "mdb", "mdf", "myd", "myi", "pdb", "RData", "rdata", "sav", "sdf", "sql",
202 "sqlite", "tsv",
203 ],
204 ),
205 (
206 "stylelint",
207 &[
208 "stylelint.config.cjs",
209 "stylelint.config.js",
210 "stylelint.config.mjs",
211 "stylelintignore",
212 "stylelintrc",
213 "stylelintrc.cjs",
214 "stylelintrc.js",
215 "stylelintrc.json",
216 "stylelintrc.mjs",
217 "stylelintrc.yaml",
218 "stylelintrc.yml",
219 ],
220 ),
221 ("surrealql", &["surql"]),
222 ("svelte", &["svelte"]),
223 ("swift", &["swift"]),
224 ("tcl", &["tcl"]),
225 ("template", &["hbs", "plist", "xml"]),
226 (
227 "terminal",
228 &[
229 "bash",
230 "bash_aliases",
231 "bash_login",
232 "bash_logout",
233 "bash_profile",
234 "bashrc",
235 "fish",
236 "nu",
237 "profile",
238 "ps1",
239 "sh",
240 "zlogin",
241 "zlogout",
242 "zprofile",
243 "zsh",
244 "zsh_aliases",
245 "zsh_histfile",
246 "zsh_history",
247 "zshenv",
248 "zshrc",
249 ],
250 ),
251 ("terraform", &["tf", "tfvars"]),
252 ("toml", &["toml"]),
253 ("typescript", &["cts", "mts", "ts"]),
254 ("v", &["v", "vsh", "vv"]),
255 (
256 "vcs",
257 &[
258 "COMMIT_EDITMSG",
259 "EDIT_DESCRIPTION",
260 "MERGE_MSG",
261 "NOTES_EDITMSG",
262 "TAG_EDITMSG",
263 "gitattributes",
264 "gitignore",
265 "gitkeep",
266 "gitmodules",
267 ],
268 ),
269 ("vbproj", &["vbproj"]),
270 ("video", &["avi", "m4v", "mkv", "mov", "mp4", "webm", "wmv"]),
271 ("vs_sln", &["sln"]),
272 ("vs_suo", &["suo"]),
273 ("vue", &["vue"]),
274 ("vyper", &["vy", "vyi"]),
275 ("wgsl", &["wgsl"]),
276 ("zig", &["zig"]),
277];
278
279/// A mapping of a file type identifier to its corresponding icon.
280const FILE_ICONS: &[(&str, &str)] = &[
281 ("astro", "icons/file_icons/astro.svg"),
282 ("audio", "icons/file_icons/audio.svg"),
283 ("bicep", "icons/file_icons/file.svg"),
284 ("bun", "icons/file_icons/bun.svg"),
285 ("c", "icons/file_icons/c.svg"),
286 ("cairo", "icons/file_icons/cairo.svg"),
287 ("code", "icons/file_icons/code.svg"),
288 ("coffeescript", "icons/file_icons/coffeescript.svg"),
289 ("cpp", "icons/file_icons/cpp.svg"),
290 ("crystal", "icons/file_icons/file.svg"),
291 ("csharp", "icons/file_icons/file.svg"),
292 ("csproj", "icons/file_icons/file.svg"),
293 ("css", "icons/file_icons/css.svg"),
294 ("cue", "icons/file_icons/file.svg"),
295 ("dart", "icons/file_icons/dart.svg"),
296 ("default", "icons/file_icons/file.svg"),
297 ("diff", "icons/file_icons/diff.svg"),
298 ("docker", "icons/file_icons/docker.svg"),
299 ("document", "icons/file_icons/book.svg"),
300 ("elixir", "icons/file_icons/elixir.svg"),
301 ("elm", "icons/file_icons/elm.svg"),
302 ("erlang", "icons/file_icons/erlang.svg"),
303 ("eslint", "icons/file_icons/eslint.svg"),
304 ("font", "icons/file_icons/font.svg"),
305 ("fsharp", "icons/file_icons/fsharp.svg"),
306 ("fsproj", "icons/file_icons/file.svg"),
307 ("gitlab", "icons/file_icons/settings.svg"),
308 ("gleam", "icons/file_icons/gleam.svg"),
309 ("go", "icons/file_icons/go.svg"),
310 ("graphql", "icons/file_icons/graphql.svg"),
311 ("haskell", "icons/file_icons/haskell.svg"),
312 ("hcl", "icons/file_icons/hcl.svg"),
313 ("heroku", "icons/file_icons/heroku.svg"),
314 ("html", "icons/file_icons/html.svg"),
315 ("image", "icons/file_icons/image.svg"),
316 ("java", "icons/file_icons/java.svg"),
317 ("javascript", "icons/file_icons/javascript.svg"),
318 ("json", "icons/file_icons/code.svg"),
319 ("julia", "icons/file_icons/julia.svg"),
320 ("kdl", "icons/file_icons/kdl.svg"),
321 ("kotlin", "icons/file_icons/kotlin.svg"),
322 ("lock", "icons/file_icons/lock.svg"),
323 ("log", "icons/file_icons/info.svg"),
324 ("lua", "icons/file_icons/lua.svg"),
325 ("luau", "icons/file_icons/luau.svg"),
326 ("markdown", "icons/file_icons/book.svg"),
327 ("metal", "icons/file_icons/metal.svg"),
328 ("nim", "icons/file_icons/nim.svg"),
329 ("nix", "icons/file_icons/nix.svg"),
330 ("ocaml", "icons/file_icons/ocaml.svg"),
331 ("phoenix", "icons/file_icons/phoenix.svg"),
332 ("php", "icons/file_icons/php.svg"),
333 ("prettier", "icons/file_icons/prettier.svg"),
334 ("prisma", "icons/file_icons/prisma.svg"),
335 ("puppet", "icons/file_icons/puppet.svg"),
336 ("python", "icons/file_icons/python.svg"),
337 ("r", "icons/file_icons/r.svg"),
338 ("react", "icons/file_icons/react.svg"),
339 ("roc", "icons/file_icons/roc.svg"),
340 ("ruby", "icons/file_icons/ruby.svg"),
341 ("rust", "icons/file_icons/rust.svg"),
342 ("sass", "icons/file_icons/sass.svg"),
343 ("scala", "icons/file_icons/scala.svg"),
344 ("settings", "icons/file_icons/settings.svg"),
345 ("solidity", "icons/file_icons/file.svg"),
346 ("storage", "icons/file_icons/database.svg"),
347 ("stylelint", "icons/file_icons/javascript.svg"),
348 ("surrealql", "icons/file_icons/surrealql.svg"),
349 ("svelte", "icons/file_icons/html.svg"),
350 ("swift", "icons/file_icons/swift.svg"),
351 ("tcl", "icons/file_icons/tcl.svg"),
352 ("template", "icons/file_icons/html.svg"),
353 ("terminal", "icons/file_icons/terminal.svg"),
354 ("terraform", "icons/file_icons/terraform.svg"),
355 ("toml", "icons/file_icons/toml.svg"),
356 ("typescript", "icons/file_icons/typescript.svg"),
357 ("v", "icons/file_icons/v.svg"),
358 ("vbproj", "icons/file_icons/file.svg"),
359 ("vcs", "icons/file_icons/git.svg"),
360 ("video", "icons/file_icons/video.svg"),
361 ("vs_sln", "icons/file_icons/file.svg"),
362 ("vs_suo", "icons/file_icons/file.svg"),
363 ("vue", "icons/file_icons/vue.svg"),
364 ("vyper", "icons/file_icons/vyper.svg"),
365 ("wgsl", "icons/file_icons/wgsl.svg"),
366 ("zig", "icons/file_icons/zig.svg"),
367];
368
369/// Returns a mapping of file associations to icon keys.
370fn icon_keys_by_association(
371 associations_by_icon_key: &[(&str, &[&str])],
372) -> HashMap<String, String> {
373 let mut icon_keys_by_association = HashMap::default();
374 for (icon_key, associations) in associations_by_icon_key {
375 for association in *associations {
376 icon_keys_by_association.insert(association.to_string(), icon_key.to_string());
377 }
378 }
379
380 icon_keys_by_association
381}
382
383/// The name of the default icon theme.
384pub(crate) const DEFAULT_ICON_THEME_NAME: &str = "Zed (Default)";
385
386static DEFAULT_ICON_THEME: LazyLock<Arc<IconTheme>> = LazyLock::new(|| {
387 Arc::new(IconTheme {
388 id: "zed".into(),
389 name: DEFAULT_ICON_THEME_NAME.into(),
390 appearance: Appearance::Dark,
391 directory_icons: DirectoryIcons {
392 collapsed: Some("icons/file_icons/folder.svg".into()),
393 expanded: Some("icons/file_icons/folder_open.svg".into()),
394 },
395 chevron_icons: ChevronIcons {
396 collapsed: Some("icons/file_icons/chevron_right.svg".into()),
397 expanded: Some("icons/file_icons/chevron_down.svg".into()),
398 },
399 file_stems: icon_keys_by_association(FILE_STEMS_BY_ICON_KEY),
400 file_suffixes: icon_keys_by_association(FILE_SUFFIXES_BY_ICON_KEY),
401 file_icons: HashMap::from_iter(FILE_ICONS.iter().map(|(ty, path)| {
402 (
403 ty.to_string(),
404 IconDefinition {
405 path: (*path).into(),
406 },
407 )
408 })),
409 })
410});
411
412/// Returns the default icon theme.
413pub fn default_icon_theme() -> Arc<IconTheme> {
414 DEFAULT_ICON_THEME.clone()
415}