Allow icon themes to provide their own file associations (#24926)
This PR adds the ability for icon themes to provide their own file
associations.
The old `file_types.json` that was previously used to make these
associations has been removed in favor of storing them on the default
theme.
Icon themes have two new fields on them:
- `file_stems`: A mapping of file stems to icon keys.
- `file_suffixes`: A mapping of file suffixes to icon keys.
These mappings produce icon keys which can then be used in `file_icons`
to associate them to a particular icon:
```json
{
  "file_stems": {
    "Makefile": "make"
  },
  "file_suffixes": {
    "idr": "idris"
  },
  "file_icons": {
    "idris": { "path": "./icons/idris.svg" },
    "make": { "path": "./icons/make.svg" }
  }
}
```
When loading an icon theme, the `file_stems` and `file_icons` fields
will be merged with the ones from the base icon theme, with the values
from the icon theme being loaded overriding ones in the base theme.
Release Notes:
- Added the ability for icon themes to provide their own file
associations.
			
			
This commit is contained in:
		
							parent
							
								
									f2776099ab
								
							
						
					
					
						commit
						e60123bbdc
					
				@ -43,10 +43,6 @@ Zed's default icon theme consists of icons that are hand-designed to fit togethe
 | 
			
		||||
 | 
			
		||||
We do not accept PRs for file icons that are just an off-the-shelf SVG taken from somewhere else.
 | 
			
		||||
 | 
			
		||||
### File icon associations
 | 
			
		||||
 | 
			
		||||
We will happily accept PRs that add new file icon associations to [`file_types.json`](assets/icons/file_icons/file_types.json) to allow them to be targeted by [icon themes](https://zed.dev/docs/extensions/icon-themes).
 | 
			
		||||
 | 
			
		||||
### Adding new icons to the Zed icon theme
 | 
			
		||||
 | 
			
		||||
If you would like to add a new icon to the Zed icon theme, [open a Discussion](https://github.com/zed-industries/zed/discussions/new?category=ux-and-design) and we can work with you on getting an icon designed and added to Zed.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										4
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -4704,11 +4704,8 @@ dependencies = [
 | 
			
		||||
name = "file_icons"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "collections",
 | 
			
		||||
 "gpui",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "serde_derive",
 | 
			
		||||
 "serde_json",
 | 
			
		||||
 "settings",
 | 
			
		||||
 "theme",
 | 
			
		||||
 "util",
 | 
			
		||||
@ -16680,7 +16677,6 @@ dependencies = [
 | 
			
		||||
 "feature_flags",
 | 
			
		||||
 "feedback",
 | 
			
		||||
 "file_finder",
 | 
			
		||||
 "file_icons",
 | 
			
		||||
 "fs",
 | 
			
		||||
 "futures 0.3.31",
 | 
			
		||||
 "git",
 | 
			
		||||
 | 
			
		||||
@ -1,260 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
  "stems": {
 | 
			
		||||
    "Dockerfile": "docker",
 | 
			
		||||
    "Podfile": "ruby",
 | 
			
		||||
    "Procfile": "heroku"
 | 
			
		||||
  },
 | 
			
		||||
  "suffixes": {
 | 
			
		||||
    "COMMIT_EDITMSG": "vcs",
 | 
			
		||||
    "EDIT_DESCRIPTION": "vcs",
 | 
			
		||||
    "Emakefile": "erlang",
 | 
			
		||||
    "MERGE_MSG": "vcs",
 | 
			
		||||
    "NOTES_EDITMSG": "vcs",
 | 
			
		||||
    "R": "r",
 | 
			
		||||
    "TAG_EDITMSG": "vcs",
 | 
			
		||||
    "aac": "audio",
 | 
			
		||||
    "accdb": "storage",
 | 
			
		||||
    "app.src": "erlang",
 | 
			
		||||
    "astro": "astro",
 | 
			
		||||
    "avi": "video",
 | 
			
		||||
    "avif": "image",
 | 
			
		||||
    "bak": "backup",
 | 
			
		||||
    "bash": "terminal",
 | 
			
		||||
    "bash_aliases": "terminal",
 | 
			
		||||
    "bash_logout": "terminal",
 | 
			
		||||
    "bash_profile": "terminal",
 | 
			
		||||
    "bashrc": "terminal",
 | 
			
		||||
    "bicep": "bicep",
 | 
			
		||||
    "bmp": "image",
 | 
			
		||||
    "c": "c",
 | 
			
		||||
    "c++": "cpp",
 | 
			
		||||
    "cc": "cpp",
 | 
			
		||||
    "cjs": "javascript",
 | 
			
		||||
    "cjsx": "react",
 | 
			
		||||
    "coffee": "coffeescript",
 | 
			
		||||
    "conf": "settings",
 | 
			
		||||
    "cpp": "cpp",
 | 
			
		||||
    "cr": "crystal",
 | 
			
		||||
    "cs": "csharp",
 | 
			
		||||
    "csproj": "csproj",
 | 
			
		||||
    "css": "css",
 | 
			
		||||
    "csv": "storage",
 | 
			
		||||
    "cts": "typescript",
 | 
			
		||||
    "ctsx": "react",
 | 
			
		||||
    "cue": "cue",
 | 
			
		||||
    "cxx": "cpp",
 | 
			
		||||
    "dart": "dart",
 | 
			
		||||
    "dat": "storage",
 | 
			
		||||
    "db": "storage",
 | 
			
		||||
    "dbf": "storage",
 | 
			
		||||
    "diff": "diff",
 | 
			
		||||
    "dll": "storage",
 | 
			
		||||
    "doc": "document",
 | 
			
		||||
    "docx": "document",
 | 
			
		||||
    "ecr": "crystal",
 | 
			
		||||
    "eex": "elixir",
 | 
			
		||||
    "elm": "elm",
 | 
			
		||||
    "erl": "erlang",
 | 
			
		||||
    "escript": "erlang",
 | 
			
		||||
    "eslint.config.cjs": "eslint",
 | 
			
		||||
    "eslint.config.cts": "eslint",
 | 
			
		||||
    "eslint.config.js": "eslint",
 | 
			
		||||
    "eslint.config.mjs": "eslint",
 | 
			
		||||
    "eslint.config.mts": "eslint",
 | 
			
		||||
    "eslint.config.ts": "eslint",
 | 
			
		||||
    "eslintrc": "eslint",
 | 
			
		||||
    "eslintrc.js": "eslint",
 | 
			
		||||
    "eslintrc.json": "eslint",
 | 
			
		||||
    "ex": "elixir",
 | 
			
		||||
    "exs": "elixir",
 | 
			
		||||
    "fish": "terminal",
 | 
			
		||||
    "flac": "audio",
 | 
			
		||||
    "fmp": "storage",
 | 
			
		||||
    "fp7": "storage",
 | 
			
		||||
    "frm": "storage",
 | 
			
		||||
    "fs": "fsharp",
 | 
			
		||||
    "fsproj": "fsproj",
 | 
			
		||||
    "gdb": "storage",
 | 
			
		||||
    "gif": "image",
 | 
			
		||||
    "gitattributes": "vcs",
 | 
			
		||||
    "gitignore": "vcs",
 | 
			
		||||
    "gitkeep": "vcs",
 | 
			
		||||
    "gitlab-ci.yml": "gitlab",
 | 
			
		||||
    "gitmodules": "vcs",
 | 
			
		||||
    "gleam": "gleam",
 | 
			
		||||
    "go": "go",
 | 
			
		||||
    "gql": "graphql",
 | 
			
		||||
    "graphql": "graphql",
 | 
			
		||||
    "graphqls": "graphql",
 | 
			
		||||
    "h": "c",
 | 
			
		||||
    "handlebars": "code",
 | 
			
		||||
    "hbs": "template",
 | 
			
		||||
    "hcl": "hcl",
 | 
			
		||||
    "heex": "elixir",
 | 
			
		||||
    "heic": "image",
 | 
			
		||||
    "heif": "image",
 | 
			
		||||
    "hh": "cpp",
 | 
			
		||||
    "hpp": "cpp",
 | 
			
		||||
    "hrl": "erlang",
 | 
			
		||||
    "hs": "haskell",
 | 
			
		||||
    "htm": "html",
 | 
			
		||||
    "html": "html",
 | 
			
		||||
    "hxx": "cpp",
 | 
			
		||||
    "ib": "storage",
 | 
			
		||||
    "ico": "image",
 | 
			
		||||
    "ini": "settings",
 | 
			
		||||
    "inl": "cpp",
 | 
			
		||||
    "j2k": "image",
 | 
			
		||||
    "java": "java",
 | 
			
		||||
    "jfif": "image",
 | 
			
		||||
    "jl": "julia",
 | 
			
		||||
    "jp2": "image",
 | 
			
		||||
    "jpeg": "image",
 | 
			
		||||
    "jpg": "image",
 | 
			
		||||
    "js": "javascript",
 | 
			
		||||
    "json": "json",
 | 
			
		||||
    "jsonc": "storage",
 | 
			
		||||
    "jsx": "react",
 | 
			
		||||
    "jxl": "image",
 | 
			
		||||
    "kt": "kotlin",
 | 
			
		||||
    "ldf": "storage",
 | 
			
		||||
    "lock": "lock",
 | 
			
		||||
    "lockb": "bun",
 | 
			
		||||
    "log": "log",
 | 
			
		||||
    "lua": "lua",
 | 
			
		||||
    "luau": "luau",
 | 
			
		||||
    "m4a": "audio",
 | 
			
		||||
    "m4v": "video",
 | 
			
		||||
    "markdown": "markdown",
 | 
			
		||||
    "md": "markdown",
 | 
			
		||||
    "mdb": "storage",
 | 
			
		||||
    "mdf": "storage",
 | 
			
		||||
    "mdx": "document",
 | 
			
		||||
    "metadata": "code",
 | 
			
		||||
    "metal": "metal",
 | 
			
		||||
    "mjs": "javascript",
 | 
			
		||||
    "mjsx": "react",
 | 
			
		||||
    "mka": "audio",
 | 
			
		||||
    "mkv": "video",
 | 
			
		||||
    "ml": "ocaml",
 | 
			
		||||
    "mli": "ocaml",
 | 
			
		||||
    "mod": "go",
 | 
			
		||||
    "mov": "video",
 | 
			
		||||
    "mp3": "audio",
 | 
			
		||||
    "mp4": "video",
 | 
			
		||||
    "mts": "typescript",
 | 
			
		||||
    "mtsx": "react",
 | 
			
		||||
    "myd": "storage",
 | 
			
		||||
    "myi": "storage",
 | 
			
		||||
    "nim": "nim",
 | 
			
		||||
    "nix": "nix",
 | 
			
		||||
    "nu": "terminal",
 | 
			
		||||
    "odp": "document",
 | 
			
		||||
    "ods": "document",
 | 
			
		||||
    "odt": "document",
 | 
			
		||||
    "ogg": "audio",
 | 
			
		||||
    "opus": "audio",
 | 
			
		||||
    "otf": "font",
 | 
			
		||||
    "pcss": "css",
 | 
			
		||||
    "pdb": "storage",
 | 
			
		||||
    "pdf": "document",
 | 
			
		||||
    "php": "php",
 | 
			
		||||
    "plist": "template",
 | 
			
		||||
    "png": "image",
 | 
			
		||||
    "postcss": "css",
 | 
			
		||||
    "ppt": "document",
 | 
			
		||||
    "pptx": "document",
 | 
			
		||||
    "prettier.config.cjs": "prettier",
 | 
			
		||||
    "prettier.config.js": "prettier",
 | 
			
		||||
    "prettier.config.mjs": "prettier",
 | 
			
		||||
    "prettierignore": "prettier",
 | 
			
		||||
    "prettierrc": "prettier",
 | 
			
		||||
    "prettierrc.cjs": "prettier",
 | 
			
		||||
    "prettierrc.js": "prettier",
 | 
			
		||||
    "prettierrc.json": "prettier",
 | 
			
		||||
    "prettierrc.json5": "prettier",
 | 
			
		||||
    "prettierrc.mjs": "prettier",
 | 
			
		||||
    "prettierrc.toml": "prettier",
 | 
			
		||||
    "prettierrc.yaml": "prettier",
 | 
			
		||||
    "prettierrc.yml": "prettier",
 | 
			
		||||
    "prisma": "prisma",
 | 
			
		||||
    "profile": "terminal",
 | 
			
		||||
    "ps1": "terminal",
 | 
			
		||||
    "psd": "image",
 | 
			
		||||
    "py": "python",
 | 
			
		||||
    "qoi": "image",
 | 
			
		||||
    "r": "r",
 | 
			
		||||
    "rb": "ruby",
 | 
			
		||||
    "rebar.config": "erlang",
 | 
			
		||||
    "rkt": "code",
 | 
			
		||||
    "roc": "roc",
 | 
			
		||||
    "rs": "rust",
 | 
			
		||||
    "rtf": "document",
 | 
			
		||||
    "sass": "sass",
 | 
			
		||||
    "sav": "storage",
 | 
			
		||||
    "sc": "scala",
 | 
			
		||||
    "scala": "scala",
 | 
			
		||||
    "scm": "code",
 | 
			
		||||
    "scss": "sass",
 | 
			
		||||
    "sdf": "storage",
 | 
			
		||||
    "sh": "terminal",
 | 
			
		||||
    "sln": "vs_sln",
 | 
			
		||||
    "sol": "solidity",
 | 
			
		||||
    "sql": "storage",
 | 
			
		||||
    "sqlite": "storage",
 | 
			
		||||
    "stylelint.config.cjs": "stylelint",
 | 
			
		||||
    "stylelint.config.js": "stylelint",
 | 
			
		||||
    "stylelint.config.mjs": "stylelint",
 | 
			
		||||
    "stylelintignore": "stylelint",
 | 
			
		||||
    "stylelintrc": "stylelint",
 | 
			
		||||
    "stylelintrc.cjs": "stylelint",
 | 
			
		||||
    "stylelintrc.js": "stylelint",
 | 
			
		||||
    "stylelintrc.json": "stylelint",
 | 
			
		||||
    "stylelintrc.mjs": "stylelint",
 | 
			
		||||
    "stylelintrc.yaml": "stylelint",
 | 
			
		||||
    "stylelintrc.yml": "stylelint",
 | 
			
		||||
    "suo": "vs_suo",
 | 
			
		||||
    "svelte": "svelte",
 | 
			
		||||
    "svg": "image",
 | 
			
		||||
    "swift": "swift",
 | 
			
		||||
    "tcl": "tcl",
 | 
			
		||||
    "tf": "terraform",
 | 
			
		||||
    "tfvars": "terraform",
 | 
			
		||||
    "tiff": "image",
 | 
			
		||||
    "toml": "toml",
 | 
			
		||||
    "ts": "typescript",
 | 
			
		||||
    "tsv": "storage",
 | 
			
		||||
    "tsx": "react",
 | 
			
		||||
    "ttf": "font",
 | 
			
		||||
    "txt": "document",
 | 
			
		||||
    "v": "v",
 | 
			
		||||
    "vbproj": "vbproj",
 | 
			
		||||
    "vsh": "v",
 | 
			
		||||
    "vue": "vue",
 | 
			
		||||
    "vv": "v",
 | 
			
		||||
    "wav": "audio",
 | 
			
		||||
    "webm": "video",
 | 
			
		||||
    "webp": "image",
 | 
			
		||||
    "wma": "audio",
 | 
			
		||||
    "wmv": "video",
 | 
			
		||||
    "woff": "font",
 | 
			
		||||
    "woff2": "font",
 | 
			
		||||
    "work": "go",
 | 
			
		||||
    "wv": "audio",
 | 
			
		||||
    "xls": "document",
 | 
			
		||||
    "xlsx": "document",
 | 
			
		||||
    "xml": "template",
 | 
			
		||||
    "xrl": "erlang",
 | 
			
		||||
    "yaml": "settings",
 | 
			
		||||
    "yml": "settings",
 | 
			
		||||
    "yrl": "erlang",
 | 
			
		||||
    "zig": "zig",
 | 
			
		||||
    "zlogin": "terminal",
 | 
			
		||||
    "zsh": "terminal",
 | 
			
		||||
    "zsh_aliases": "terminal",
 | 
			
		||||
    "zsh_histfile": "terminal",
 | 
			
		||||
    "zsh_profile": "terminal",
 | 
			
		||||
    "zshenv": "terminal",
 | 
			
		||||
    "zshrc": "terminal"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -13,11 +13,8 @@ path = "src/file_icons.rs"
 | 
			
		||||
doctest = false
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
collections.workspace = true
 | 
			
		||||
gpui.workspace = true
 | 
			
		||||
serde.workspace = true
 | 
			
		||||
serde_derive.workspace = true
 | 
			
		||||
serde_json.workspace = true
 | 
			
		||||
settings.workspace = true
 | 
			
		||||
theme.workspace = true
 | 
			
		||||
util.workspace = true
 | 
			
		||||
 | 
			
		||||
@ -1,52 +1,33 @@
 | 
			
		||||
use std::sync::Arc;
 | 
			
		||||
use std::{path::Path, str};
 | 
			
		||||
 | 
			
		||||
use collections::HashMap;
 | 
			
		||||
 | 
			
		||||
use gpui::{App, AssetSource, Global, SharedString};
 | 
			
		||||
use serde_derive::Deserialize;
 | 
			
		||||
use gpui::{App, SharedString};
 | 
			
		||||
use settings::Settings;
 | 
			
		||||
use theme::{IconTheme, ThemeRegistry, ThemeSettings};
 | 
			
		||||
use util::paths::PathExt;
 | 
			
		||||
 | 
			
		||||
#[derive(Deserialize, Debug)]
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct FileIcons {
 | 
			
		||||
    stems: HashMap<String, String>,
 | 
			
		||||
    suffixes: HashMap<String, String>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Global for FileIcons {}
 | 
			
		||||
 | 
			
		||||
pub const FILE_TYPES_ASSET: &str = "icons/file_icons/file_types.json";
 | 
			
		||||
 | 
			
		||||
pub fn init(assets: impl AssetSource, cx: &mut App) {
 | 
			
		||||
    cx.set_global(FileIcons::new(assets))
 | 
			
		||||
    icon_theme: Arc<IconTheme>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl FileIcons {
 | 
			
		||||
    pub fn get(cx: &App) -> &Self {
 | 
			
		||||
        cx.global::<FileIcons>()
 | 
			
		||||
    }
 | 
			
		||||
    pub fn get(cx: &App) -> Self {
 | 
			
		||||
        let theme_settings = ThemeSettings::get_global(cx);
 | 
			
		||||
 | 
			
		||||
    pub fn new(assets: impl AssetSource) -> Self {
 | 
			
		||||
        assets
 | 
			
		||||
            .load(FILE_TYPES_ASSET)
 | 
			
		||||
            .ok()
 | 
			
		||||
            .flatten()
 | 
			
		||||
            .and_then(|file| serde_json::from_str::<FileIcons>(str::from_utf8(&file).unwrap()).ok())
 | 
			
		||||
            .unwrap_or_else(|| FileIcons {
 | 
			
		||||
                stems: HashMap::default(),
 | 
			
		||||
                suffixes: HashMap::default(),
 | 
			
		||||
            })
 | 
			
		||||
        Self {
 | 
			
		||||
            icon_theme: theme_settings.active_icon_theme.clone(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn get_icon(path: &Path, cx: &App) -> Option<SharedString> {
 | 
			
		||||
        let this = cx.try_global::<Self>()?;
 | 
			
		||||
        let this = Self::get(cx);
 | 
			
		||||
 | 
			
		||||
        let get_icon_from_suffix = |suffix: &str| -> Option<SharedString> {
 | 
			
		||||
            this.stems
 | 
			
		||||
            this.icon_theme
 | 
			
		||||
                .file_stems
 | 
			
		||||
                .get(suffix)
 | 
			
		||||
                .or_else(|| this.suffixes.get(suffix))
 | 
			
		||||
                .or_else(|| this.icon_theme.file_suffixes.get(suffix))
 | 
			
		||||
                .and_then(|typ| this.get_icon_for_type(typ, cx))
 | 
			
		||||
        };
 | 
			
		||||
        // TODO: Associate a type with the languages and have the file's language
 | 
			
		||||
 | 
			
		||||
@ -28,12 +28,12 @@ use file_icons::FileIcons;
 | 
			
		||||
use fuzzy::{match_strings, StringMatch, StringMatchCandidate};
 | 
			
		||||
use gpui::{
 | 
			
		||||
    actions, anchored, deferred, div, point, px, size, uniform_list, Action, AnyElement, App,
 | 
			
		||||
    AppContext as _, AssetSource, AsyncWindowContext, Bounds, ClipboardItem, Context, DismissEvent,
 | 
			
		||||
    Div, ElementId, Entity, EventEmitter, FocusHandle, Focusable, HighlightStyle,
 | 
			
		||||
    InteractiveElement, IntoElement, KeyContext, ListHorizontalSizingBehavior, ListSizingBehavior,
 | 
			
		||||
    MouseButton, MouseDownEvent, ParentElement, Pixels, Point, Render, ScrollStrategy,
 | 
			
		||||
    SharedString, Stateful, StatefulInteractiveElement as _, Styled, Subscription, Task,
 | 
			
		||||
    UniformListScrollHandle, WeakEntity, Window,
 | 
			
		||||
    AppContext as _, AsyncWindowContext, Bounds, ClipboardItem, Context, DismissEvent, Div,
 | 
			
		||||
    ElementId, Entity, EventEmitter, FocusHandle, Focusable, HighlightStyle, InteractiveElement,
 | 
			
		||||
    IntoElement, KeyContext, ListHorizontalSizingBehavior, ListSizingBehavior, MouseButton,
 | 
			
		||||
    MouseDownEvent, ParentElement, Pixels, Point, Render, ScrollStrategy, SharedString, Stateful,
 | 
			
		||||
    StatefulInteractiveElement as _, Styled, Subscription, Task, UniformListScrollHandle,
 | 
			
		||||
    WeakEntity, Window,
 | 
			
		||||
};
 | 
			
		||||
use itertools::Itertools;
 | 
			
		||||
use language::{BufferId, BufferSnapshot, OffsetRangeExt, OutlineItem};
 | 
			
		||||
@ -664,9 +664,8 @@ pub fn init_settings(cx: &mut App) {
 | 
			
		||||
    OutlinePanelSettings::register(cx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn init(assets: impl AssetSource, cx: &mut App) {
 | 
			
		||||
pub fn init(cx: &mut App) {
 | 
			
		||||
    init_settings(cx);
 | 
			
		||||
    file_icons::init(assets, cx);
 | 
			
		||||
 | 
			
		||||
    cx.observe_new(|workspace: &mut Workspace, _, _| {
 | 
			
		||||
        workspace.register_action(|workspace, _: &ToggleFocus, window, cx| {
 | 
			
		||||
@ -6641,7 +6640,7 @@ outline: struct OutlineEntryExcerpt
 | 
			
		||||
            workspace::init_settings(cx);
 | 
			
		||||
            Project::init_settings(cx);
 | 
			
		||||
            project_search::init(cx);
 | 
			
		||||
            super::init((), cx);
 | 
			
		||||
            super::init(cx);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -18,8 +18,8 @@ use file_icons::FileIcons;
 | 
			
		||||
use git::status::GitSummary;
 | 
			
		||||
use gpui::{
 | 
			
		||||
    actions, anchored, deferred, div, impl_actions, point, px, size, uniform_list, Action,
 | 
			
		||||
    AnyElement, App, AssetSource, AsyncWindowContext, Bounds, ClipboardItem, Context, DismissEvent,
 | 
			
		||||
    Div, DragMoveEvent, Entity, EventEmitter, ExternalPaths, FocusHandle, Focusable, Hsla,
 | 
			
		||||
    AnyElement, App, AsyncWindowContext, Bounds, ClipboardItem, Context, DismissEvent, Div,
 | 
			
		||||
    DragMoveEvent, Entity, EventEmitter, ExternalPaths, FocusHandle, Focusable, Hsla,
 | 
			
		||||
    InteractiveElement, KeyContext, ListHorizontalSizingBehavior, ListSizingBehavior, MouseButton,
 | 
			
		||||
    MouseDownEvent, ParentElement, Pixels, Point, PromptLevel, Render, ScrollStrategy, Stateful,
 | 
			
		||||
    Styled, Subscription, Task, UniformListScrollHandle, WeakEntity, Window,
 | 
			
		||||
@ -225,9 +225,8 @@ pub fn init_settings(cx: &mut App) {
 | 
			
		||||
    ProjectPanelSettings::register(cx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn init(assets: impl AssetSource, cx: &mut App) {
 | 
			
		||||
pub fn init(cx: &mut App) {
 | 
			
		||||
    init_settings(cx);
 | 
			
		||||
    file_icons::init(assets, cx);
 | 
			
		||||
 | 
			
		||||
    cx.observe_new(|workspace: &mut Workspace, _, _| {
 | 
			
		||||
        workspace.register_action(|workspace, _: &ToggleFocus, window, cx| {
 | 
			
		||||
@ -9484,7 +9483,7 @@ mod tests {
 | 
			
		||||
            theme::init(theme::LoadThemes::JustBase, cx);
 | 
			
		||||
            language::init(cx);
 | 
			
		||||
            editor::init_settings(cx);
 | 
			
		||||
            crate::init((), cx);
 | 
			
		||||
            crate::init(cx);
 | 
			
		||||
            workspace::init_settings(cx);
 | 
			
		||||
            client::init_settings(cx);
 | 
			
		||||
            Project::init_settings(cx);
 | 
			
		||||
@ -9507,7 +9506,7 @@ mod tests {
 | 
			
		||||
            init_settings(cx);
 | 
			
		||||
            language::init(cx);
 | 
			
		||||
            editor::init(cx);
 | 
			
		||||
            crate::init((), cx);
 | 
			
		||||
            crate::init(cx);
 | 
			
		||||
            workspace::init(app_state.clone(), cx);
 | 
			
		||||
            Project::init_settings(cx);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -455,7 +455,6 @@ mod tests {
 | 
			
		||||
    pub(crate) fn init_test(cx: &mut TestAppContext) -> Arc<AppState> {
 | 
			
		||||
        cx.update(|cx| {
 | 
			
		||||
            let state = AppState::test(cx);
 | 
			
		||||
            file_icons::init((), cx);
 | 
			
		||||
            language::init(cx);
 | 
			
		||||
            crate::init(cx);
 | 
			
		||||
            editor::init(cx);
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,5 @@
 | 
			
		||||
use std::sync::{Arc, LazyLock};
 | 
			
		||||
 | 
			
		||||
use collections::HashMap;
 | 
			
		||||
use gpui::SharedString;
 | 
			
		||||
 | 
			
		||||
@ -28,7 +30,11 @@ pub struct IconTheme {
 | 
			
		||||
    pub directory_icons: DirectoryIcons,
 | 
			
		||||
    /// The icons used for chevrons.
 | 
			
		||||
    pub chevron_icons: ChevronIcons,
 | 
			
		||||
    /// The mapping of file types to icon definitions.
 | 
			
		||||
    /// The mapping of file stems to their associated icon keys.
 | 
			
		||||
    pub file_stems: HashMap<String, String>,
 | 
			
		||||
    /// The mapping of file suffixes to their associated icon keys.
 | 
			
		||||
    pub file_suffixes: HashMap<String, String>,
 | 
			
		||||
    /// The mapping of icon keys to icon definitions.
 | 
			
		||||
    pub file_icons: HashMap<String, IconDefinition>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -57,6 +63,209 @@ pub struct IconDefinition {
 | 
			
		||||
    pub path: SharedString,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const FILE_STEMS_BY_ICON_KEY: &[(&str, &[&str])] = &[
 | 
			
		||||
    ("docker", &["Dockerfile"]),
 | 
			
		||||
    ("ruby", &["Podfile"]),
 | 
			
		||||
    ("heroku", &["Procfile"]),
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
const FILE_SUFFIXES_BY_ICON_KEY: &[(&str, &[&str])] = &[
 | 
			
		||||
    ("astro", &["astro"]),
 | 
			
		||||
    (
 | 
			
		||||
        "audio",
 | 
			
		||||
        &[
 | 
			
		||||
            "aac", "flac", "m4a", "mka", "mp3", "ogg", "opus", "wav", "wma", "wv",
 | 
			
		||||
        ],
 | 
			
		||||
    ),
 | 
			
		||||
    ("backup", &["bak"]),
 | 
			
		||||
    ("bicep", &["bicep"]),
 | 
			
		||||
    ("bun", &["lockb"]),
 | 
			
		||||
    ("c", &["c", "h"]),
 | 
			
		||||
    ("code", &["handlebars", "metadata", "rkt", "scm"]),
 | 
			
		||||
    ("coffeescript", &["coffee"]),
 | 
			
		||||
    (
 | 
			
		||||
        "cpp",
 | 
			
		||||
        &["c++", "cc", "cpp", "cxx", "hh", "hpp", "hxx", "inl"],
 | 
			
		||||
    ),
 | 
			
		||||
    ("crystal", &["cr", "ecr"]),
 | 
			
		||||
    ("csharp", &["cs"]),
 | 
			
		||||
    ("csproj", &["csproj"]),
 | 
			
		||||
    ("css", &["css", "pcss", "postcss"]),
 | 
			
		||||
    ("cue", &["cue"]),
 | 
			
		||||
    ("dart", &["dart"]),
 | 
			
		||||
    ("diff", &["diff"]),
 | 
			
		||||
    (
 | 
			
		||||
        "document",
 | 
			
		||||
        &[
 | 
			
		||||
            "doc", "docx", "mdx", "odp", "ods", "odt", "pdf", "ppt", "pptx", "rtf", "txt", "xls",
 | 
			
		||||
            "xlsx",
 | 
			
		||||
        ],
 | 
			
		||||
    ),
 | 
			
		||||
    ("elixir", &["eex", "ex", "exs", "heex"]),
 | 
			
		||||
    ("elm", &["elm"]),
 | 
			
		||||
    (
 | 
			
		||||
        "erlang",
 | 
			
		||||
        &[
 | 
			
		||||
            "Emakefile",
 | 
			
		||||
            "app.src",
 | 
			
		||||
            "erl",
 | 
			
		||||
            "escript",
 | 
			
		||||
            "hrl",
 | 
			
		||||
            "rebar.config",
 | 
			
		||||
            "xrl",
 | 
			
		||||
            "yrl",
 | 
			
		||||
        ],
 | 
			
		||||
    ),
 | 
			
		||||
    (
 | 
			
		||||
        "eslint",
 | 
			
		||||
        &[
 | 
			
		||||
            "eslint.config.cjs",
 | 
			
		||||
            "eslint.config.cts",
 | 
			
		||||
            "eslint.config.js",
 | 
			
		||||
            "eslint.config.mjs",
 | 
			
		||||
            "eslint.config.mts",
 | 
			
		||||
            "eslint.config.ts",
 | 
			
		||||
            "eslintrc",
 | 
			
		||||
            "eslintrc.js",
 | 
			
		||||
            "eslintrc.json",
 | 
			
		||||
        ],
 | 
			
		||||
    ),
 | 
			
		||||
    ("font", &["otf", "ttf", "woff", "woff2"]),
 | 
			
		||||
    ("fsharp", &["fs"]),
 | 
			
		||||
    ("fsproj", &["fsproj"]),
 | 
			
		||||
    ("gitlab", &["gitlab-ci.yml"]),
 | 
			
		||||
    ("gleam", &["gleam"]),
 | 
			
		||||
    ("go", &["go", "mod", "work"]),
 | 
			
		||||
    ("graphql", &["gql", "graphql", "graphqls"]),
 | 
			
		||||
    ("haskell", &["hs"]),
 | 
			
		||||
    ("hcl", &["hcl"]),
 | 
			
		||||
    ("html", &["htm", "html"]),
 | 
			
		||||
    (
 | 
			
		||||
        "image",
 | 
			
		||||
        &[
 | 
			
		||||
            "avif", "bmp", "gif", "heic", "heif", "ico", "j2k", "jfif", "jp2", "jpeg", "jpg",
 | 
			
		||||
            "jxl", "png", "psd", "qoi", "svg", "tiff", "webp",
 | 
			
		||||
        ],
 | 
			
		||||
    ),
 | 
			
		||||
    ("java", &["java"]),
 | 
			
		||||
    ("javascript", &["cjs", "js", "mjs"]),
 | 
			
		||||
    ("json", &["json"]),
 | 
			
		||||
    ("julia", &["jl"]),
 | 
			
		||||
    ("kotlin", &["kt"]),
 | 
			
		||||
    ("lock", &["lock"]),
 | 
			
		||||
    ("log", &["log"]),
 | 
			
		||||
    ("lua", &["lua"]),
 | 
			
		||||
    ("luau", &["luau"]),
 | 
			
		||||
    ("markdown", &["markdown", "md"]),
 | 
			
		||||
    ("metal", &["metal"]),
 | 
			
		||||
    ("nim", &["nim"]),
 | 
			
		||||
    ("nix", &["nix"]),
 | 
			
		||||
    ("ocaml", &["ml", "mli"]),
 | 
			
		||||
    ("php", &["php"]),
 | 
			
		||||
    (
 | 
			
		||||
        "prettier",
 | 
			
		||||
        &[
 | 
			
		||||
            "prettier.config.cjs",
 | 
			
		||||
            "prettier.config.js",
 | 
			
		||||
            "prettier.config.mjs",
 | 
			
		||||
            "prettierignore",
 | 
			
		||||
            "prettierrc",
 | 
			
		||||
            "prettierrc.cjs",
 | 
			
		||||
            "prettierrc.js",
 | 
			
		||||
            "prettierrc.json",
 | 
			
		||||
            "prettierrc.json5",
 | 
			
		||||
            "prettierrc.mjs",
 | 
			
		||||
            "prettierrc.toml",
 | 
			
		||||
            "prettierrc.yaml",
 | 
			
		||||
            "prettierrc.yml",
 | 
			
		||||
        ],
 | 
			
		||||
    ),
 | 
			
		||||
    ("prisma", &["prisma"]),
 | 
			
		||||
    ("python", &["py"]),
 | 
			
		||||
    ("r", &["r", "R"]),
 | 
			
		||||
    ("react", &["cjsx", "ctsx", "jsx", "mjsx", "mtsx", "tsx"]),
 | 
			
		||||
    ("roc", &["roc"]),
 | 
			
		||||
    ("ruby", &["rb"]),
 | 
			
		||||
    ("rust", &["rs"]),
 | 
			
		||||
    ("sass", &["sass", "scss"]),
 | 
			
		||||
    ("scala", &["scala", "sc"]),
 | 
			
		||||
    ("settings", &["conf", "ini", "yaml", "yml"]),
 | 
			
		||||
    ("solidity", &["sol"]),
 | 
			
		||||
    (
 | 
			
		||||
        "storage",
 | 
			
		||||
        &[
 | 
			
		||||
            "accdb", "csv", "dat", "db", "dbf", "dll", "fmp", "fp7", "frm", "gdb", "ib", "jsonc",
 | 
			
		||||
            "ldf", "mdb", "mdf", "myd", "myi", "pdb", "sav", "sdf", "sql", "sqlite", "tsv",
 | 
			
		||||
        ],
 | 
			
		||||
    ),
 | 
			
		||||
    (
 | 
			
		||||
        "stylelint",
 | 
			
		||||
        &[
 | 
			
		||||
            "stylelint.config.cjs",
 | 
			
		||||
            "stylelint.config.js",
 | 
			
		||||
            "stylelint.config.mjs",
 | 
			
		||||
            "stylelintignore",
 | 
			
		||||
            "stylelintrc",
 | 
			
		||||
            "stylelintrc.cjs",
 | 
			
		||||
            "stylelintrc.js",
 | 
			
		||||
            "stylelintrc.json",
 | 
			
		||||
            "stylelintrc.mjs",
 | 
			
		||||
            "stylelintrc.yaml",
 | 
			
		||||
            "stylelintrc.yml",
 | 
			
		||||
        ],
 | 
			
		||||
    ),
 | 
			
		||||
    ("svelte", &["svelte"]),
 | 
			
		||||
    ("swift", &["swift"]),
 | 
			
		||||
    ("tcl", &["tcl"]),
 | 
			
		||||
    ("template", &["hbs", "plist", "xml"]),
 | 
			
		||||
    (
 | 
			
		||||
        "terminal",
 | 
			
		||||
        &[
 | 
			
		||||
            "bash",
 | 
			
		||||
            "bash_aliases",
 | 
			
		||||
            "bash_logout",
 | 
			
		||||
            "bash_profile",
 | 
			
		||||
            "bashrc",
 | 
			
		||||
            "fish",
 | 
			
		||||
            "nu",
 | 
			
		||||
            "profile",
 | 
			
		||||
            "ps1",
 | 
			
		||||
            "sh",
 | 
			
		||||
            "zlogin",
 | 
			
		||||
            "zsh",
 | 
			
		||||
            "zsh_aliases",
 | 
			
		||||
            "zsh_histfile",
 | 
			
		||||
            "zsh_profile",
 | 
			
		||||
            "zshenv",
 | 
			
		||||
            "zshrc",
 | 
			
		||||
        ],
 | 
			
		||||
    ),
 | 
			
		||||
    ("terraform", &["tf", "tfvars"]),
 | 
			
		||||
    ("toml", &["toml"]),
 | 
			
		||||
    ("typescript", &["cts", "mts", "ts"]),
 | 
			
		||||
    ("v", &["v", "vsh", "vv"]),
 | 
			
		||||
    (
 | 
			
		||||
        "vcs",
 | 
			
		||||
        &[
 | 
			
		||||
            "COMMIT_EDITMSG",
 | 
			
		||||
            "EDIT_DESCRIPTION",
 | 
			
		||||
            "MERGE_MSG",
 | 
			
		||||
            "NOTES_EDITMSG",
 | 
			
		||||
            "TAG_EDITMSG",
 | 
			
		||||
            "gitattributes",
 | 
			
		||||
            "gitignore",
 | 
			
		||||
            "gitkeep",
 | 
			
		||||
            "gitmodules",
 | 
			
		||||
        ],
 | 
			
		||||
    ),
 | 
			
		||||
    ("vbproj", &["vbproj"]),
 | 
			
		||||
    ("video", &["avi", "m4v", "mkv", "mov", "mp4", "webm", "wmv"]),
 | 
			
		||||
    ("vs_sln", &["sln"]),
 | 
			
		||||
    ("vs_suo", &["suo"]),
 | 
			
		||||
    ("vue", &["vue"]),
 | 
			
		||||
    ("zig", &["zig"]),
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
/// A mapping of a file type identifier to its corresponding icon.
 | 
			
		||||
const FILE_ICONS: &[(&str, &str)] = &[
 | 
			
		||||
    ("astro", "icons/file_icons/astro.svg"),
 | 
			
		||||
@ -141,12 +350,25 @@ const FILE_ICONS: &[(&str, &str)] = &[
 | 
			
		||||
    ("zig", "icons/file_icons/zig.svg"),
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
/// Returns a mapping of file associations to icon keys.
 | 
			
		||||
fn icon_keys_by_association(
 | 
			
		||||
    associations_by_icon_key: &[(&str, &[&str])],
 | 
			
		||||
) -> HashMap<String, String> {
 | 
			
		||||
    let mut icon_keys_by_association = HashMap::default();
 | 
			
		||||
    for (icon_key, associations) in associations_by_icon_key {
 | 
			
		||||
        for association in *associations {
 | 
			
		||||
            icon_keys_by_association.insert(association.to_string(), icon_key.to_string());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    icon_keys_by_association
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// The name of the default icon theme.
 | 
			
		||||
pub(crate) const DEFAULT_ICON_THEME_NAME: &str = "Zed (Default)";
 | 
			
		||||
 | 
			
		||||
/// Returns the default icon theme.
 | 
			
		||||
pub fn default_icon_theme() -> IconTheme {
 | 
			
		||||
    IconTheme {
 | 
			
		||||
static DEFAULT_ICON_THEME: LazyLock<Arc<IconTheme>> = LazyLock::new(|| {
 | 
			
		||||
    Arc::new(IconTheme {
 | 
			
		||||
        id: "zed".into(),
 | 
			
		||||
        name: DEFAULT_ICON_THEME_NAME.into(),
 | 
			
		||||
        appearance: Appearance::Dark,
 | 
			
		||||
@ -158,6 +380,8 @@ pub fn default_icon_theme() -> IconTheme {
 | 
			
		||||
            collapsed: Some("icons/file_icons/chevron_right.svg".into()),
 | 
			
		||||
            expanded: Some("icons/file_icons/chevron_down.svg".into()),
 | 
			
		||||
        },
 | 
			
		||||
        file_stems: icon_keys_by_association(FILE_STEMS_BY_ICON_KEY),
 | 
			
		||||
        file_suffixes: icon_keys_by_association(FILE_SUFFIXES_BY_ICON_KEY),
 | 
			
		||||
        file_icons: HashMap::from_iter(FILE_ICONS.into_iter().map(|(ty, path)| {
 | 
			
		||||
            (
 | 
			
		||||
                ty.to_string(),
 | 
			
		||||
@ -166,5 +390,10 @@ pub fn default_icon_theme() -> IconTheme {
 | 
			
		||||
                },
 | 
			
		||||
            )
 | 
			
		||||
        })),
 | 
			
		||||
    }
 | 
			
		||||
    })
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/// Returns the default icon theme.
 | 
			
		||||
pub fn default_icon_theme() -> Arc<IconTheme> {
 | 
			
		||||
    DEFAULT_ICON_THEME.clone()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -23,6 +23,10 @@ pub struct IconThemeContent {
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub chevron_icons: ChevronIconsContent,
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub file_stems: HashMap<String, String>,
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub file_suffixes: HashMap<String, String>,
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub file_icons: HashMap<String, IconDefinitionContent>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -11,8 +11,8 @@ use parking_lot::RwLock;
 | 
			
		||||
use util::ResultExt;
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    read_icon_theme, read_user_theme, refine_theme_family, Appearance, AppearanceContent,
 | 
			
		||||
    ChevronIcons, DirectoryIcons, IconDefinition, IconTheme, Theme, ThemeFamily,
 | 
			
		||||
    default_icon_theme, read_icon_theme, read_user_theme, refine_theme_family, Appearance,
 | 
			
		||||
    AppearanceContent, ChevronIcons, DirectoryIcons, IconDefinition, IconTheme, Theme, ThemeFamily,
 | 
			
		||||
    ThemeFamilyContent, DEFAULT_ICON_THEME_NAME,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -80,10 +80,11 @@ impl ThemeRegistry {
 | 
			
		||||
        registry.insert_theme_families([crate::fallback_themes::zed_default_themes()]);
 | 
			
		||||
 | 
			
		||||
        let default_icon_theme = crate::default_icon_theme();
 | 
			
		||||
        registry.state.write().icon_themes.insert(
 | 
			
		||||
            default_icon_theme.name.clone(),
 | 
			
		||||
            Arc::new(default_icon_theme),
 | 
			
		||||
        );
 | 
			
		||||
        registry
 | 
			
		||||
            .state
 | 
			
		||||
            .write()
 | 
			
		||||
            .icon_themes
 | 
			
		||||
            .insert(default_icon_theme.name.clone(), default_icon_theme);
 | 
			
		||||
 | 
			
		||||
        registry
 | 
			
		||||
    }
 | 
			
		||||
@ -263,8 +264,16 @@ impl ThemeRegistry {
 | 
			
		||||
                .into()
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let default_icon_theme = default_icon_theme();
 | 
			
		||||
 | 
			
		||||
        let mut state = self.state.write();
 | 
			
		||||
        for icon_theme in icon_theme_family.themes {
 | 
			
		||||
            let mut file_stems = default_icon_theme.file_stems.clone();
 | 
			
		||||
            file_stems.extend(icon_theme.file_stems);
 | 
			
		||||
 | 
			
		||||
            let mut file_suffixes = default_icon_theme.file_suffixes.clone();
 | 
			
		||||
            file_suffixes.extend(icon_theme.file_suffixes);
 | 
			
		||||
 | 
			
		||||
            let icon_theme = IconTheme {
 | 
			
		||||
                id: uuid::Uuid::new_v4().to_string(),
 | 
			
		||||
                name: icon_theme.name.into(),
 | 
			
		||||
@ -280,6 +289,8 @@ impl ThemeRegistry {
 | 
			
		||||
                    collapsed: icon_theme.chevron_icons.collapsed.map(resolve_icon_path),
 | 
			
		||||
                    expanded: icon_theme.chevron_icons.expanded.map(resolve_icon_path),
 | 
			
		||||
                },
 | 
			
		||||
                file_stems,
 | 
			
		||||
                file_suffixes,
 | 
			
		||||
                file_icons: icon_theme
 | 
			
		||||
                    .file_icons
 | 
			
		||||
                    .into_iter()
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
use std::ops::{Deref, DerefMut};
 | 
			
		||||
 | 
			
		||||
use assets::Assets;
 | 
			
		||||
use editor::test::editor_lsp_test_context::EditorLspTestContext;
 | 
			
		||||
use gpui::{Context, Entity, SemanticVersion, UpdateGlobal};
 | 
			
		||||
use search::{project_search::ProjectSearchBar, BufferSearchBar};
 | 
			
		||||
@ -21,7 +20,7 @@ impl VimTestContext {
 | 
			
		||||
            cx.set_global(settings);
 | 
			
		||||
            release_channel::init(SemanticVersion::default(), cx);
 | 
			
		||||
            command_palette::init(cx);
 | 
			
		||||
            project_panel::init(Assets, cx);
 | 
			
		||||
            project_panel::init(cx);
 | 
			
		||||
            git_ui::init(cx);
 | 
			
		||||
            crate::init(cx);
 | 
			
		||||
            search::init(cx);
 | 
			
		||||
 | 
			
		||||
@ -51,7 +51,6 @@ extensions_ui.workspace = true
 | 
			
		||||
feature_flags.workspace = true
 | 
			
		||||
feedback.workspace = true
 | 
			
		||||
file_finder.workspace = true
 | 
			
		||||
file_icons.workspace = true
 | 
			
		||||
fs.workspace = true
 | 
			
		||||
futures.workspace = true
 | 
			
		||||
git.workspace = true
 | 
			
		||||
 | 
			
		||||
@ -488,9 +488,9 @@ fn main() {
 | 
			
		||||
        tab_switcher::init(cx);
 | 
			
		||||
        outline::init(cx);
 | 
			
		||||
        project_symbols::init(cx);
 | 
			
		||||
        project_panel::init(Assets, cx);
 | 
			
		||||
        project_panel::init(cx);
 | 
			
		||||
        git_ui::git_panel::init(cx);
 | 
			
		||||
        outline_panel::init(Assets, cx);
 | 
			
		||||
        outline_panel::init(cx);
 | 
			
		||||
        component_preview::init(cx);
 | 
			
		||||
        tasks_ui::init(cx);
 | 
			
		||||
        snippets_ui::init(cx);
 | 
			
		||||
@ -555,7 +555,6 @@ fn main() {
 | 
			
		||||
        load_user_themes_in_background(fs.clone(), cx);
 | 
			
		||||
        watch_themes(fs.clone(), cx);
 | 
			
		||||
        watch_languages(fs.clone(), app_state.languages.clone(), cx);
 | 
			
		||||
        watch_file_types(fs.clone(), cx);
 | 
			
		||||
 | 
			
		||||
        cx.set_menus(app_menus());
 | 
			
		||||
        initialize_workspace(app_state.clone(), prompt_builder, cx);
 | 
			
		||||
@ -1158,35 +1157,3 @@ fn watch_languages(fs: Arc<dyn fs::Fs>, languages: Arc<LanguageRegistry>, cx: &m
 | 
			
		||||
 | 
			
		||||
#[cfg(not(debug_assertions))]
 | 
			
		||||
fn watch_languages(_fs: Arc<dyn fs::Fs>, _languages: Arc<LanguageRegistry>, _cx: &mut App) {}
 | 
			
		||||
 | 
			
		||||
#[cfg(debug_assertions)]
 | 
			
		||||
fn watch_file_types(fs: Arc<dyn fs::Fs>, cx: &mut App) {
 | 
			
		||||
    use std::time::Duration;
 | 
			
		||||
 | 
			
		||||
    use file_icons::FileIcons;
 | 
			
		||||
    use gpui::UpdateGlobal;
 | 
			
		||||
 | 
			
		||||
    let path = {
 | 
			
		||||
        let p = Path::new("assets").join(file_icons::FILE_TYPES_ASSET);
 | 
			
		||||
        let Ok(full_path) = p.canonicalize() else {
 | 
			
		||||
            return;
 | 
			
		||||
        };
 | 
			
		||||
        full_path
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    cx.spawn(|cx| async move {
 | 
			
		||||
        let (mut events, _) = fs.watch(path.as_path(), Duration::from_millis(100)).await;
 | 
			
		||||
        while (events.next().await).is_some() {
 | 
			
		||||
            cx.update(|cx| {
 | 
			
		||||
                FileIcons::update_global(cx, |file_types, _cx| {
 | 
			
		||||
                    *file_types = file_icons::FileIcons::new(Assets);
 | 
			
		||||
                });
 | 
			
		||||
            })
 | 
			
		||||
            .ok();
 | 
			
		||||
        }
 | 
			
		||||
    })
 | 
			
		||||
    .detach()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(not(debug_assertions))]
 | 
			
		||||
fn watch_file_types(_fs: Arc<dyn fs::Fs>, _cx: &mut App) {}
 | 
			
		||||
 | 
			
		||||
@ -4198,8 +4198,8 @@ mod tests {
 | 
			
		||||
            editor::init(cx);
 | 
			
		||||
            collab_ui::init(&app_state, cx);
 | 
			
		||||
            git_ui::init(cx);
 | 
			
		||||
            project_panel::init((), cx);
 | 
			
		||||
            outline_panel::init((), cx);
 | 
			
		||||
            project_panel::init(cx);
 | 
			
		||||
            outline_panel::init(cx);
 | 
			
		||||
            terminal_view::init(cx);
 | 
			
		||||
            copilot::copilot_chat::init(
 | 
			
		||||
                app_state.fs.clone(),
 | 
			
		||||
 | 
			
		||||
@ -8,7 +8,7 @@ extend-exclude = [
 | 
			
		||||
    ".mailmap",
 | 
			
		||||
 | 
			
		||||
    # File suffixes aren't typos.
 | 
			
		||||
    "assets/icons/file_icons/file_types.json",
 | 
			
		||||
    "crates/theme/src/icon_theme.rs",
 | 
			
		||||
    "crates/extensions_ui/src/extension_suggest.rs",
 | 
			
		||||
 | 
			
		||||
    # Some countries codes are flagged as typos.
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user