Added file suffix and icon associations data
This commit is contained in:
parent
d023189bda
commit
fd72f4526d
32 changed files with 451 additions and 62 deletions
|
@ -10,6 +10,7 @@ doctest = false
|
|||
|
||||
[dependencies]
|
||||
context_menu = { path = "../context_menu" }
|
||||
collections = { path = "../collections" }
|
||||
db = { path = "../db" }
|
||||
drag_and_drop = { path = "../drag_and_drop" }
|
||||
editor = { path = "../editor" }
|
||||
|
|
64
crates/project_panel/src/file_associations.rs
Normal file
64
crates/project_panel/src/file_associations.rs
Normal file
|
@ -0,0 +1,64 @@
|
|||
use std::{path::Path, str, sync::Arc};
|
||||
|
||||
use collections::HashMap;
|
||||
|
||||
use gpui::{AppContext, AssetSource};
|
||||
use serde_derive::Deserialize;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct TypeConfig {
|
||||
icon: Arc<str>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct FileAssociations {
|
||||
suffixes: HashMap<String, String>,
|
||||
types: HashMap<String, TypeConfig>,
|
||||
}
|
||||
|
||||
pub const TEXT_FILE_ASSET: &'static str = "icons/file_icons/quill/file.svg";
|
||||
const DIRECTORY_TYPE: &'static str = "directory";
|
||||
const EXPANDED_DIRECTORY_TYPE: &'static str = "expanded_directory";
|
||||
|
||||
pub fn init(assets: impl AssetSource, cx: &mut AppContext) {
|
||||
cx.set_global(FileAssociations::new(assets))
|
||||
}
|
||||
|
||||
impl FileAssociations {
|
||||
pub fn new(assets: impl AssetSource) -> Self {
|
||||
let file = assets.load("icons/file_icons/file_types.json").unwrap();
|
||||
serde_json::from_str::<FileAssociations>(str::from_utf8(&file).unwrap()).unwrap()
|
||||
}
|
||||
|
||||
pub fn get_icon(path: &Path, cx: &AppContext) -> Option<Arc<str>> {
|
||||
if !cx.has_global::<Self>() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let this = cx.global::<Self>();
|
||||
let suffix = path.extension()?.to_str()?;
|
||||
|
||||
this.suffixes
|
||||
.get(suffix)
|
||||
.and_then(|type_str| this.types.get(type_str))
|
||||
.map(|type_config| type_config.icon.clone())
|
||||
}
|
||||
|
||||
pub fn get_folder_icon(expanded: bool, cx: &AppContext) -> Option<Arc<str>> {
|
||||
if !cx.has_global::<Self>() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let this = cx.global::<Self>();
|
||||
|
||||
let key = if expanded {
|
||||
EXPANDED_DIRECTORY_TYPE
|
||||
} else {
|
||||
DIRECTORY_TYPE
|
||||
};
|
||||
|
||||
this.types
|
||||
.get(key)
|
||||
.map(|type_config| type_config.icon.clone())
|
||||
}
|
||||
}
|
|
@ -1,9 +1,11 @@
|
|||
mod file_associations;
|
||||
mod project_panel_settings;
|
||||
|
||||
use context_menu::{ContextMenu, ContextMenuItem};
|
||||
use db::kvp::KEY_VALUE_STORE;
|
||||
use drag_and_drop::{DragAndDrop, Draggable};
|
||||
use editor::{Cancel, Editor};
|
||||
use file_associations::{FileAssociations, TEXT_FILE_ASSET};
|
||||
use futures::stream::StreamExt;
|
||||
use gpui::{
|
||||
actions,
|
||||
|
@ -15,8 +17,8 @@ use gpui::{
|
|||
geometry::vector::Vector2F,
|
||||
keymap_matcher::KeymapContext,
|
||||
platform::{CursorStyle, MouseButton, PromptLevel},
|
||||
Action, AnyElement, AppContext, AsyncAppContext, ClipboardItem, Element, Entity, ModelHandle,
|
||||
Task, View, ViewContext, ViewHandle, WeakViewHandle, WindowContext,
|
||||
Action, AnyElement, AppContext, AssetSource, AsyncAppContext, ClipboardItem, Element, Entity,
|
||||
ModelHandle, Task, View, ViewContext, ViewHandle, WeakViewHandle, WindowContext,
|
||||
};
|
||||
use menu::{Confirm, SelectNext, SelectPrev};
|
||||
use project::{
|
||||
|
@ -44,7 +46,6 @@ use workspace::{
|
|||
|
||||
const PROJECT_PANEL_KEY: &'static str = "ProjectPanel";
|
||||
const NEW_ENTRY_ID: ProjectEntryId = ProjectEntryId::MAX;
|
||||
const TEXT_FILE_ASSET: &'static str = "icons/radix/file-text.svg";
|
||||
|
||||
pub struct ProjectPanel {
|
||||
project: ModelHandle<Project>,
|
||||
|
@ -131,8 +132,9 @@ pub fn init_settings(cx: &mut AppContext) {
|
|||
settings::register::<ProjectPanelSettings>(cx);
|
||||
}
|
||||
|
||||
pub fn init(cx: &mut AppContext) {
|
||||
pub fn init(assets: impl AssetSource, cx: &mut AppContext) {
|
||||
init_settings(cx);
|
||||
file_associations::init(assets, cx);
|
||||
cx.add_action(ProjectPanel::expand_selected_entry);
|
||||
cx.add_action(ProjectPanel::collapse_selected_entry);
|
||||
cx.add_action(ProjectPanel::select_prev);
|
||||
|
@ -1184,15 +1186,12 @@ impl ProjectPanel {
|
|||
let entry_range = range.start.saturating_sub(ix)..end_ix - ix;
|
||||
for entry in visible_worktree_entries[entry_range].iter() {
|
||||
let status = git_status_setting.then(|| entry.git_status).flatten();
|
||||
|
||||
let is_expanded = expanded_entry_ids.binary_search(&entry.id).is_ok();
|
||||
let icon = show_file_icons
|
||||
.then(|| match entry.kind {
|
||||
EntryKind::File(_) => self
|
||||
.project
|
||||
.read(cx)
|
||||
.icon_for_path(&entry.path)
|
||||
EntryKind::File(_) => FileAssociations::get_icon(&entry.path, cx)
|
||||
.or_else(|| Some(TEXT_FILE_ASSET.into())),
|
||||
_ => None,
|
||||
_ => FileAssociations::get_folder_icon(is_expanded, cx),
|
||||
})
|
||||
.flatten();
|
||||
|
||||
|
@ -1208,7 +1207,7 @@ impl ProjectPanel {
|
|||
depth: entry.path.components().count(),
|
||||
kind: entry.kind,
|
||||
is_ignored: entry.is_ignored,
|
||||
is_expanded: expanded_entry_ids.binary_search(&entry.id).is_ok(),
|
||||
is_expanded,
|
||||
is_selected: self.selection.map_or(false, |e| {
|
||||
e.worktree_id == snapshot.id() && e.entry_id == entry.id
|
||||
}),
|
||||
|
@ -1271,37 +1270,35 @@ impl ProjectPanel {
|
|||
.unwrap_or(style.text.color);
|
||||
|
||||
Flex::row()
|
||||
.with_child(if kind.is_dir() {
|
||||
.with_child(if let Some(icon) = &details.icon {
|
||||
Svg::new(icon.to_string())
|
||||
.with_color(style.icon_color)
|
||||
.constrained()
|
||||
.with_max_width(style.icon_size)
|
||||
.with_max_height(style.icon_size)
|
||||
.aligned()
|
||||
.constrained()
|
||||
.with_width(style.icon_size)
|
||||
} else if kind.is_dir() {
|
||||
if details.is_expanded {
|
||||
Svg::new("icons/chevron_down_8.svg").with_color(style.icon_color)
|
||||
Svg::new("icons/chevron_down_8.svg").with_color(style.chevron_color)
|
||||
} else {
|
||||
Svg::new("icons/chevron_right_8.svg").with_color(style.icon_color)
|
||||
Svg::new("icons/chevron_right_8.svg").with_color(style.chevron_color)
|
||||
}
|
||||
.constrained()
|
||||
.with_max_width(style.directory_icon_size)
|
||||
.with_max_height(style.directory_icon_size)
|
||||
.with_max_width(style.chevron_size)
|
||||
.with_max_height(style.chevron_size)
|
||||
.aligned()
|
||||
.constrained()
|
||||
.with_width(style.directory_icon_size)
|
||||
.with_width(style.chevron_size)
|
||||
} else {
|
||||
if let Some(icon) = &details.icon {
|
||||
Svg::new(icon.to_string())
|
||||
.with_color(style.icon_color)
|
||||
.constrained()
|
||||
.with_max_width(style.file_icon_size)
|
||||
.with_max_height(style.file_icon_size)
|
||||
.aligned()
|
||||
.constrained()
|
||||
.with_width(style.file_icon_size)
|
||||
} else {
|
||||
Empty::new()
|
||||
.constrained()
|
||||
.with_max_width(style.directory_icon_size)
|
||||
.with_max_height(style.directory_icon_size)
|
||||
.aligned()
|
||||
.constrained()
|
||||
.with_width(style.directory_icon_size)
|
||||
}
|
||||
Empty::new()
|
||||
.constrained()
|
||||
.with_max_width(style.chevron_size)
|
||||
.with_max_height(style.chevron_size)
|
||||
.aligned()
|
||||
.constrained()
|
||||
.with_width(style.chevron_size)
|
||||
})
|
||||
.with_child(if show_editor && editor.is_some() {
|
||||
ChildView::new(editor.as_ref().unwrap(), cx)
|
||||
|
@ -2613,7 +2610,7 @@ mod tests {
|
|||
theme::init((), cx);
|
||||
language::init(cx);
|
||||
editor::init_settings(cx);
|
||||
crate::init(cx);
|
||||
crate::init((), cx);
|
||||
workspace::init_settings(cx);
|
||||
Project::init_settings(cx);
|
||||
});
|
||||
|
@ -2628,7 +2625,7 @@ mod tests {
|
|||
language::init(cx);
|
||||
editor::init(cx);
|
||||
pane::init(cx);
|
||||
crate::init(cx);
|
||||
crate::init((), cx);
|
||||
workspace::init(app_state.clone(), cx);
|
||||
Project::init_settings(cx);
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue