From 41bef2e444b96b012b5ebf7c156562921caf3702 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Sat, 13 May 2023 02:26:45 -0700 Subject: [PATCH] Refactor out git status into FileName component Integrate file name component into the editor's tab content --- Cargo.lock | 1 + crates/editor/src/items.rs | 23 ++++++++- crates/gpui/src/elements.rs | 9 ++++ crates/project_panel/src/project_panel.rs | 33 +++++-------- crates/theme/Cargo.toml | 1 + crates/theme/src/ui.rs | 57 +++++++++++++++++++++-- 6 files changed, 98 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 81e4a4e025..e009cfd342 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6688,6 +6688,7 @@ name = "theme" version = "0.1.0" dependencies = [ "anyhow", + "fs", "gpui", "indexmap", "parking_lot 0.11.2", diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index e971af943a..80c1009aa4 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -14,7 +14,7 @@ use language::{ proto::serialize_anchor as serialize_text_anchor, Bias, Buffer, OffsetRangeExt, Point, SelectionGoal, }; -use project::{FormatTrigger, Item as _, Project, ProjectPath}; +use project::{repository::GitFileStatus, FormatTrigger, Item as _, Project, ProjectPath}; use rpc::proto::{self, update_view}; use settings::Settings; use smallvec::SmallVec; @@ -27,6 +27,7 @@ use std::{ path::{Path, PathBuf}, }; use text::Selection; +use theme::ui::FileName; use util::{ResultExt, TryFutureExt}; use workspace::item::{BreadcrumbText, FollowableItemHandle}; use workspace::{ @@ -565,8 +566,25 @@ impl Item for Editor { style: &theme::Tab, cx: &AppContext, ) -> AnyElement { + fn git_file_status(this: &Editor, cx: &AppContext) -> Option { + let project_entry_id = this + .buffer() + .read(cx) + .as_singleton()? + .read(cx) + .entry_id(cx)?; + let project = this.project.as_ref()?.read(cx); + let path = project.path_for_entry(project_entry_id, cx)?.path; + let worktree = project.worktree_for_entry(project_entry_id, cx)?.read(cx); + worktree.repo_for(&path)?.status_for_path(&worktree, &path) + } + Flex::row() - .with_child(Label::new(self.title(cx).to_string(), style.label.clone()).aligned()) + .with_child(ComponentHost::new(FileName::new( + self.title(cx).to_string(), + git_file_status(self, cx), + FileName::style(style.label.clone(), &cx.global::().theme), + ))) .with_children(detail.and_then(|detail| { let path = path_for_buffer(&self.buffer, detail, false, cx)?; let description = path.to_string_lossy(); @@ -580,6 +598,7 @@ impl Item for Editor { .aligned(), ) })) + .align_children_center() .into_any() } diff --git a/crates/gpui/src/elements.rs b/crates/gpui/src/elements.rs index e2c4af143c..27b01a8db2 100644 --- a/crates/gpui/src/elements.rs +++ b/crates/gpui/src/elements.rs @@ -578,6 +578,15 @@ pub struct ComponentHost> { view_type: PhantomData, } +impl> ComponentHost { + pub fn new(c: C) -> Self { + Self { + component: c, + view_type: PhantomData, + } + } +} + impl> Deref for ComponentHost { type Target = C; diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 1066875022..bb7f97fbf8 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -6,7 +6,7 @@ use gpui::{ actions, anyhow::{anyhow, Result}, elements::{ - AnchorCorner, ChildView, ContainerStyle, Empty, Flex, Label, MouseEventHandler, + AnchorCorner, ChildView, ComponentHost, ContainerStyle, Empty, Flex, MouseEventHandler, ParentElement, ScrollTarget, Stack, Svg, UniformList, UniformListState, }, geometry::vector::Vector2F, @@ -29,7 +29,7 @@ use std::{ path::Path, sync::Arc, }; -use theme::ProjectPanelEntry; +use theme::{ui::FileName, ProjectPanelEntry}; use unicase::UniCase; use workspace::Workspace; @@ -1083,19 +1083,6 @@ impl ProjectPanel { let kind = details.kind; let show_editor = details.is_editing && !details.is_processing; - // Prepare colors for git statuses - let editor_theme = &cx.global::().theme.editor; - let mut filename_text_style = style.text.clone(); - filename_text_style.color = details - .git_status - .as_ref() - .map(|status| match status { - GitFileStatus::Added => editor_theme.diff.inserted, - GitFileStatus::Modified => editor_theme.diff.modified, - GitFileStatus::Conflict => editor_theme.diff.deleted, - }) - .unwrap_or(style.text.color); - Flex::row() .with_child( if kind == EntryKind::Dir { @@ -1123,12 +1110,16 @@ impl ProjectPanel { .flex(1.0, true) .into_any() } else { - Label::new(details.filename.clone(), filename_text_style) - .contained() - .with_margin_left(style.icon_spacing) - .aligned() - .left() - .into_any() + ComponentHost::new(FileName::new( + details.filename.clone(), + details.git_status, + FileName::style(style.text.clone(), &cx.global::().theme), + )) + .contained() + .with_margin_left(style.icon_spacing) + .aligned() + .left() + .into_any() }) .constrained() .with_height(style.height) diff --git a/crates/theme/Cargo.toml b/crates/theme/Cargo.toml index 67a28397e2..c7dc2938ed 100644 --- a/crates/theme/Cargo.toml +++ b/crates/theme/Cargo.toml @@ -10,6 +10,7 @@ doctest = false [dependencies] gpui = { path = "../gpui" } +fs = { path = "../fs" } anyhow.workspace = true indexmap = "1.6.2" parking_lot.workspace = true diff --git a/crates/theme/src/ui.rs b/crates/theme/src/ui.rs index b86bfca8c4..e4df24c89f 100644 --- a/crates/theme/src/ui.rs +++ b/crates/theme/src/ui.rs @@ -1,9 +1,10 @@ use std::borrow::Cow; +use fs::repository::GitFileStatus; use gpui::{ color::Color, elements::{ - ConstrainedBox, Container, ContainerStyle, Empty, Flex, KeystrokeLabel, Label, + ConstrainedBox, Container, ContainerStyle, Empty, Flex, KeystrokeLabel, Label, LabelStyle, MouseEventHandler, ParentElement, Stack, Svg, }, fonts::TextStyle, @@ -11,11 +12,11 @@ use gpui::{ platform, platform::MouseButton, scene::MouseClick, - Action, Element, EventContext, MouseState, View, ViewContext, + Action, AnyElement, Element, EventContext, MouseState, View, ViewContext, }; use serde::Deserialize; -use crate::{ContainedText, Interactive}; +use crate::{ContainedText, Interactive, Theme}; #[derive(Clone, Deserialize, Default)] pub struct CheckboxStyle { @@ -252,3 +253,53 @@ where .constrained() .with_height(style.dimensions().y()) } + +pub struct FileName { + filename: String, + git_status: Option, + style: FileNameStyle, +} + +pub struct FileNameStyle { + template_style: LabelStyle, + git_inserted: Color, + git_modified: Color, + git_deleted: Color, +} + +impl FileName { + pub fn new(filename: String, git_status: Option, style: FileNameStyle) -> Self { + FileName { + filename, + git_status, + style, + } + } + + pub fn style>(style: I, theme: &Theme) -> FileNameStyle { + FileNameStyle { + template_style: style.into(), + git_inserted: theme.editor.diff.inserted, + git_modified: theme.editor.diff.modified, + git_deleted: theme.editor.diff.deleted, + } + } +} + +impl gpui::elements::Component for FileName { + fn render(&self, _: &mut V, _: &mut ViewContext) -> AnyElement { + // Prepare colors for git statuses + let mut filename_text_style = self.style.template_style.text.clone(); + filename_text_style.color = self + .git_status + .as_ref() + .map(|status| match status { + GitFileStatus::Added => self.style.git_inserted, + GitFileStatus::Modified => self.style.git_modified, + GitFileStatus::Conflict => self.style.git_deleted, + }) + .unwrap_or(self.style.template_style.text.color); + + Label::new(self.filename.clone(), filename_text_style).into_any() + } +}