From 07436b428420581c6232e3b84847a3d143174373 Mon Sep 17 00:00:00 2001 From: Vivek Pothina <19631108+ViveK-PothinA@users.noreply.github.com> Date: Fri, 30 May 2025 08:32:54 -0700 Subject: [PATCH] breadcrumbs: Stylize filename in breadcrumbs when tab-bar is off and file is dirty (#30507) Closes [#18870](https://github.com/zed-industries/zed/issues/18870) - I like to use Zed with tab_bar off - when the file is modified there is no indicator when tab_bar is off - this PR aims to fix that Thanks to @Qkessler for initial PR - #22418 This is style decided in this discussion - #22418 @iamnbutler @mikayla-maki [subtle style decided](https://github.com/zed-industries/zed/pull/22418#issuecomment-2605253667) Release Notes: - When tab_bar is off, filename in the breadcrumbs will be the indicator when file is unsaved. #### Changes - when tab_bar is off and file is dirty (unsaved) image - when tab_bar is off and file is not dirty (saved) image - when tab_bar is on image image Release Notes: - Changed the highlighting of the current file to represent the current saved state, when the tab bar is turned off. --- Cargo.lock | 1 + crates/breadcrumbs/Cargo.toml | 1 + crates/breadcrumbs/src/breadcrumbs.rs | 65 ++++++++++++++++++++++++--- 3 files changed, 60 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f2b80c980e..6aef35323e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2200,6 +2200,7 @@ dependencies = [ "editor", "gpui", "itertools 0.14.0", + "settings", "theme", "ui", "workspace", diff --git a/crates/breadcrumbs/Cargo.toml b/crates/breadcrumbs/Cargo.toml index 36a713708f..c25cfc3c86 100644 --- a/crates/breadcrumbs/Cargo.toml +++ b/crates/breadcrumbs/Cargo.toml @@ -16,6 +16,7 @@ doctest = false editor.workspace = true gpui.workspace = true itertools.workspace = true +settings.workspace = true theme.workspace = true ui.workspace = true workspace.workspace = true diff --git a/crates/breadcrumbs/src/breadcrumbs.rs b/crates/breadcrumbs/src/breadcrumbs.rs index 57cb2a4df8..8eed7497da 100644 --- a/crates/breadcrumbs/src/breadcrumbs.rs +++ b/crates/breadcrumbs/src/breadcrumbs.rs @@ -1,14 +1,15 @@ use editor::Editor; use gpui::{ - Context, Element, EventEmitter, Focusable, IntoElement, ParentElement, Render, StyledText, - Subscription, Window, + Context, Element, EventEmitter, Focusable, FontWeight, IntoElement, ParentElement, Render, + StyledText, Subscription, Window, }; use itertools::Itertools; +use settings::Settings; use std::cmp; use theme::ActiveTheme; use ui::{ButtonLike, ButtonStyle, Label, Tooltip, prelude::*}; use workspace::{ - ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, + TabBarSettings, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, item::{BreadcrumbText, ItemEvent, ItemHandle}, }; @@ -71,16 +72,23 @@ impl Render for Breadcrumbs { ); } - let highlighted_segments = segments.into_iter().map(|segment| { + let highlighted_segments = segments.into_iter().enumerate().map(|(index, segment)| { let mut text_style = window.text_style(); - if let Some(font) = segment.font { - text_style.font_family = font.family; - text_style.font_features = font.features; + if let Some(ref font) = segment.font { + text_style.font_family = font.family.clone(); + text_style.font_features = font.features.clone(); text_style.font_style = font.style; text_style.font_weight = font.weight; } text_style.color = Color::Muted.color(cx); + if index == 0 && !TabBarSettings::get_global(cx).show && active_item.is_dirty(cx) { + if let Some(styled_element) = apply_dirty_filename_style(&segment, &text_style, cx) + { + return styled_element; + } + } + StyledText::new(segment.text.replace('\n', "⏎")) .with_default_highlights(&text_style, segment.highlights.unwrap_or_default()) .into_any() @@ -184,3 +192,46 @@ impl ToolbarItemView for Breadcrumbs { self.pane_focused = pane_focused; } } + +fn apply_dirty_filename_style( + segment: &BreadcrumbText, + text_style: &gpui::TextStyle, + cx: &mut Context, +) -> Option { + let text = segment.text.replace('\n', "⏎"); + + let filename_position = std::path::Path::new(&segment.text) + .file_name() + .and_then(|f| { + let filename_str = f.to_string_lossy(); + segment.text.rfind(filename_str.as_ref()) + })?; + + let bold_weight = FontWeight::BOLD; + let default_color = Color::Default.color(cx); + + if filename_position == 0 { + let mut filename_style = text_style.clone(); + filename_style.font_weight = bold_weight; + filename_style.color = default_color; + + return Some( + StyledText::new(text) + .with_default_highlights(&filename_style, []) + .into_any(), + ); + } + + let highlight_style = gpui::HighlightStyle { + font_weight: Some(bold_weight), + color: Some(default_color), + ..Default::default() + }; + + let highlight = vec![(filename_position..text.len(), highlight_style)]; + Some( + StyledText::new(text) + .with_default_highlights(&text_style, highlight) + .into_any(), + ) +}