From 2c8ead4423af87a6e0f02788fe40ba176e7588b3 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Wed, 17 Jul 2024 20:11:05 -0400 Subject: [PATCH] Simplify constructing tab content that is purely textual (#14695) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR adds a streamlined way to consistently construct tab content for items that only have textual content in the tabs. The `Item` trait now has a new `tab_content_text` method that can be used to return the textual content for the tab. The `tab_content` method now has a default implementation that—unless overridden—will construct a `Label` out of the text. This default implementation also takes care of setting the label color based on the active state of the tab, something that previously had to be repeated in each `tab_content` implementation. The majority of our tabs are now using `tab_content_text`. Release Notes: - N/A --- crates/assistant/src/assistant_panel.rs | 23 +++------------ crates/collab_ui/src/channel_view.rs | 20 +++++-------- crates/extensions_ui/src/extensions_ui.rs | 13 ++------- crates/language_tools/src/lsp_log.rs | 18 ++++-------- crates/language_tools/src/syntax_tree_view.rs | 18 ++++-------- .../src/markdown_preview_view.rs | 18 ++++-------- crates/search/src/project_search.rs | 19 +++++-------- .../src/project_index_debug_view.rs | 12 ++------ crates/welcome/src/welcome.rs | 18 ++++-------- crates/workspace/src/item.rs | 28 +++++++++++++++++-- crates/workspace/src/shared_screen.rs | 14 +++------- 11 files changed, 77 insertions(+), 124 deletions(-) diff --git a/crates/assistant/src/assistant_panel.rs b/crates/assistant/src/assistant_panel.rs index dbd00e33ebcbf1957370de5d8b667fba24acd269..92e3f215c8637e714d5b31cb66dcffdec335f4a2 100644 --- a/crates/assistant/src/assistant_panel.rs +++ b/crates/assistant/src/assistant_panel.rs @@ -2023,18 +2023,8 @@ impl FocusableView for ContextEditor { impl Item for ContextEditor { type Event = editor::EditorEvent; - fn tab_content(&self, params: item::TabContentParams, cx: &WindowContext) -> AnyElement { - let color = if params.selected { - Color::Default - } else { - Color::Muted - }; - Label::new(util::truncate_and_trailoff( - &self.title(cx), - Self::MAX_TAB_TITLE_LEN, - )) - .color(color) - .into_any_element() + fn tab_content_text(&self, cx: &WindowContext) -> Option { + Some(util::truncate_and_trailoff(&self.title(cx), Self::MAX_TAB_TITLE_LEN).into()) } fn to_item_events(event: &Self::Event, mut f: impl FnMut(item::ItemEvent)) { @@ -2531,13 +2521,8 @@ impl EventEmitter<()> for ContextHistory {} impl Item for ContextHistory { type Event = (); - fn tab_content(&self, params: item::TabContentParams, _: &WindowContext) -> AnyElement { - let color = if params.selected { - Color::Default - } else { - Color::Muted - }; - Label::new("History").color(color).into_any_element() + fn tab_content_text(&self, _cx: &WindowContext) -> Option { + Some("History".into()) } } diff --git a/crates/collab_ui/src/channel_view.rs b/crates/collab_ui/src/channel_view.rs index dfd19264e5aec118bf00785e3fd416e110a3388b..fcf8d31fcf458aedb9c7ccbfd3a64b97f612d359 100644 --- a/crates/collab_ui/src/channel_view.rs +++ b/crates/collab_ui/src/channel_view.rs @@ -11,20 +11,20 @@ use editor::{ EditorEvent, }; use gpui::{ - actions, AnyElement, AnyView, AppContext, ClipboardItem, Entity as _, EventEmitter, - FocusableView, IntoElement as _, Model, Pixels, Point, Render, Subscription, Task, View, - ViewContext, VisualContext as _, WeakView, WindowContext, + actions, AnyView, AppContext, ClipboardItem, Entity as _, EventEmitter, FocusableView, Model, + Pixels, Point, Render, Subscription, Task, View, ViewContext, VisualContext as _, WeakView, + WindowContext, }; use project::Project; use std::{ any::{Any, TypeId}, sync::Arc, }; -use ui::{prelude::*, Label}; +use ui::prelude::*; use util::ResultExt; use workspace::{item::Dedup, notifications::NotificationId}; use workspace::{ - item::{FollowableItem, Item, ItemEvent, ItemHandle, TabContentParams}, + item::{FollowableItem, Item, ItemEvent, ItemHandle}, searchable::SearchableItemHandle, ItemNavHistory, Pane, SaveIntent, Toast, ViewId, Workspace, WorkspaceId, }; @@ -385,7 +385,7 @@ impl Item for ChannelView { } } - fn tab_content(&self, params: TabContentParams, cx: &WindowContext) -> AnyElement { + fn tab_content_text(&self, cx: &WindowContext) -> Option { let label = if let Some(channel) = self.channel(cx) { match ( self.channel_buffer.read(cx).buffer().read(cx).read_only(), @@ -398,13 +398,7 @@ impl Item for ChannelView { } else { "channel notes (disconnected)".to_string() }; - Label::new(label) - .color(if params.selected { - Color::Default - } else { - Color::Muted - }) - .into_any_element() + Some(label.into()) } fn telemetry_event_text(&self) -> Option<&'static str> { diff --git a/crates/extensions_ui/src/extensions_ui.rs b/crates/extensions_ui/src/extensions_ui.rs index 25170970869b10d821a47392defb6951274988ec..d96cf3c74472f3c0b84926c235b9f9c7864fba75 100644 --- a/crates/extensions_ui/src/extensions_ui.rs +++ b/crates/extensions_ui/src/extensions_ui.rs @@ -14,7 +14,7 @@ use editor::{Editor, EditorElement, EditorStyle}; use extension::{ExtensionManifest, ExtensionOperation, ExtensionStore}; use fuzzy::{match_strings, StringMatchCandidate}; use gpui::{ - actions, uniform_list, AnyElement, AppContext, EventEmitter, Flatten, FocusableView, FontStyle, + actions, uniform_list, AppContext, EventEmitter, Flatten, FocusableView, FontStyle, InteractiveElement, KeyContext, ParentElement, Render, Styled, Task, TextStyle, UniformListScrollHandle, View, ViewContext, VisualContext, WeakView, WhiteSpace, WindowContext, }; @@ -25,7 +25,6 @@ use settings::Settings; use theme::ThemeSettings; use ui::{prelude::*, CheckboxWithLabel, ContextMenu, PopoverMenu, ToggleButton, Tooltip}; use vim::VimModeSetting; -use workspace::item::TabContentParams; use workspace::{ item::{Item, ItemEvent}, Workspace, WorkspaceId, @@ -1135,14 +1134,8 @@ impl FocusableView for ExtensionsPage { impl Item for ExtensionsPage { type Event = ItemEvent; - fn tab_content(&self, params: TabContentParams, _: &WindowContext) -> AnyElement { - Label::new("Extensions") - .color(if params.selected { - Color::Default - } else { - Color::Muted - }) - .into_any_element() + fn tab_content_text(&self, _cx: &WindowContext) -> Option { + Some("Extensions".into()) } fn telemetry_event_text(&self) -> Option<&'static str> { diff --git a/crates/language_tools/src/lsp_log.rs b/crates/language_tools/src/lsp_log.rs index 2d0527cb5cdc0fdd597be256434a317d4d7021eb..6bd4c2ca4ffecaeb05007f340bd27369d6570fa4 100644 --- a/crates/language_tools/src/lsp_log.rs +++ b/crates/language_tools/src/lsp_log.rs @@ -3,9 +3,9 @@ use copilot::Copilot; use editor::{actions::MoveToEnd, Editor, EditorEvent}; use futures::{channel::mpsc, StreamExt}; use gpui::{ - actions, div, AnchorCorner, AnyElement, AppContext, Context, EventEmitter, FocusHandle, - FocusableView, IntoElement, Model, ModelContext, ParentElement, Render, Styled, Subscription, - View, ViewContext, VisualContext, WeakModel, WindowContext, + actions, div, AnchorCorner, AppContext, Context, EventEmitter, FocusHandle, FocusableView, + IntoElement, Model, ModelContext, ParentElement, Render, Styled, Subscription, View, + ViewContext, VisualContext, WeakModel, WindowContext, }; use language::{LanguageServerId, LanguageServerName}; use lsp::{IoKind, LanguageServer}; @@ -13,7 +13,7 @@ use project::{search::SearchQuery, Project}; use std::{borrow::Cow, sync::Arc}; use ui::{prelude::*, Button, Checkbox, ContextMenu, Label, PopoverMenu, Selection}; use workspace::{ - item::{Item, ItemHandle, TabContentParams}, + item::{Item, ItemHandle}, searchable::{SearchEvent, SearchableItem, SearchableItemHandle}, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, Workspace, }; @@ -697,14 +697,8 @@ impl Item for LspLogView { Editor::to_item_events(event, f) } - fn tab_content(&self, params: TabContentParams, _: &WindowContext<'_>) -> AnyElement { - Label::new("LSP Logs") - .color(if params.selected { - Color::Default - } else { - Color::Muted - }) - .into_any_element() + fn tab_content_text(&self, _cx: &WindowContext) -> Option { + Some("LSP Logs".into()) } fn telemetry_event_text(&self) -> Option<&'static str> { diff --git a/crates/language_tools/src/syntax_tree_view.rs b/crates/language_tools/src/syntax_tree_view.rs index 906bbee10421e852d714b8043e79344edba255f6..8208c458579750ed8a435ab828cc073d6e5687e3 100644 --- a/crates/language_tools/src/syntax_tree_view.rs +++ b/crates/language_tools/src/syntax_tree_view.rs @@ -1,8 +1,8 @@ use editor::{scroll::Autoscroll, Anchor, Editor, ExcerptId}; use gpui::{ - actions, div, rems, uniform_list, AnyElement, AppContext, Div, EventEmitter, FocusHandle, - FocusableView, Hsla, InteractiveElement, IntoElement, Model, MouseButton, MouseDownEvent, - MouseMoveEvent, ParentElement, Render, Styled, UniformListScrollHandle, View, ViewContext, + actions, div, rems, uniform_list, AppContext, Div, EventEmitter, FocusHandle, FocusableView, + Hsla, InteractiveElement, IntoElement, Model, MouseButton, MouseDownEvent, MouseMoveEvent, + ParentElement, Render, SharedString, Styled, UniformListScrollHandle, View, ViewContext, VisualContext, WeakView, WindowContext, }; use language::{Buffer, OwnedSyntaxLayer}; @@ -11,7 +11,7 @@ use theme::ActiveTheme; use tree_sitter::{Node, TreeCursor}; use ui::{h_flex, ButtonLike, Color, ContextMenu, Label, LabelCommon, PopoverMenu}; use workspace::{ - item::{Item, ItemHandle, TabContentParams}, + item::{Item, ItemHandle}, SplitDirection, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, Workspace, }; @@ -380,14 +380,8 @@ impl Item for SyntaxTreeView { fn to_item_events(_: &Self::Event, _: impl FnMut(workspace::item::ItemEvent)) {} - fn tab_content(&self, params: TabContentParams, _: &WindowContext<'_>) -> AnyElement { - Label::new("Syntax Tree") - .color(if params.selected { - Color::Default - } else { - Color::Muted - }) - .into_any_element() + fn tab_content_text(&self, _cx: &WindowContext) -> Option { + Some("Syntax Tree".into()) } fn telemetry_event_text(&self) -> Option<&'static str> { diff --git a/crates/markdown_preview/src/markdown_preview_view.rs b/crates/markdown_preview/src/markdown_preview_view.rs index 55f1cc5a5b83262bcf58b89128b7b2cd75e1c71a..9c547ee6650177487e67642bad6167fe3df9df24 100644 --- a/crates/markdown_preview/src/markdown_preview_view.rs +++ b/crates/markdown_preview/src/markdown_preview_view.rs @@ -6,13 +6,13 @@ use anyhow::Result; use editor::scroll::{Autoscroll, AutoscrollStrategy}; use editor::{Editor, EditorEvent}; use gpui::{ - list, AnyElement, AppContext, ClickEvent, EventEmitter, FocusHandle, FocusableView, - InteractiveElement, IntoElement, ListState, ParentElement, Render, Styled, Subscription, Task, - View, ViewContext, WeakView, + list, AppContext, ClickEvent, EventEmitter, FocusHandle, FocusableView, InteractiveElement, + IntoElement, ListState, ParentElement, Render, Styled, Subscription, Task, View, ViewContext, + WeakView, }; use language::LanguageRegistry; use ui::prelude::*; -use workspace::item::{Item, ItemHandle, TabContentParams}; +use workspace::item::{Item, ItemHandle}; use workspace::{Pane, Workspace}; use crate::markdown_elements::ParsedMarkdownElement; @@ -456,18 +456,12 @@ impl Item for MarkdownPreviewView { Some(Icon::new(IconName::FileDoc)) } - fn tab_content(&self, params: TabContentParams, _cx: &WindowContext) -> AnyElement { - Label::new(if let Some(description) = &self.tab_description { + fn tab_content_text(&self, _cx: &WindowContext) -> Option { + Some(if let Some(description) = &self.tab_description { description.clone().into() } else { self.fallback_tab_description.clone() }) - .color(if params.selected { - Color::Default - } else { - Color::Muted - }) - .into_any_element() } fn telemetry_event_text(&self) -> Option<&'static str> { diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index aa4d19eb2446b61e00990d0b5862f20f9d60a67d..708916d2f9e6ffe08788b80f408de42831d7ce90 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -35,7 +35,7 @@ use ui::{ }; use util::paths::PathMatcher; use workspace::{ - item::{BreadcrumbText, Item, ItemEvent, ItemHandle, TabContentParams}, + item::{BreadcrumbText, Item, ItemEvent, ItemHandle}, searchable::{Direction, SearchableItem, SearchableItemHandle}, DeploySearch, ItemNavHistory, NewSearch, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, Workspace, WorkspaceId, @@ -374,7 +374,7 @@ impl Item for ProjectSearchView { Some(Icon::new(IconName::MagnifyingGlass)) } - fn tab_content(&self, params: TabContentParams, cx: &WindowContext<'_>) -> AnyElement { + fn tab_content_text(&self, cx: &WindowContext) -> Option { let last_query: Option = self .model .read(cx) @@ -385,16 +385,11 @@ impl Item for ProjectSearchView { let query_text = util::truncate_and_trailoff(&query, MAX_TAB_TITLE_LEN); query_text.into() }); - let tab_name = last_query - .filter(|query| !query.is_empty()) - .unwrap_or_else(|| "Project Search".into()); - Label::new(tab_name) - .color(if params.selected { - Color::Default - } else { - Color::Muted - }) - .into_any_element() + Some( + last_query + .filter(|query| !query.is_empty()) + .unwrap_or_else(|| "Project Search".into()), + ) } fn telemetry_event_text(&self) -> Option<&'static str> { diff --git a/crates/semantic_index/src/project_index_debug_view.rs b/crates/semantic_index/src/project_index_debug_view.rs index 1b183c5169d6d93e2027a44d8a38cfc0352c1d4b..2f7d23663d7dda15e647b3d33a202f8151b85418 100644 --- a/crates/semantic_index/src/project_index_debug_view.rs +++ b/crates/semantic_index/src/project_index_debug_view.rs @@ -9,7 +9,7 @@ use settings::Settings; use std::{path::Path, sync::Arc}; use theme::ThemeSettings; use ui::prelude::*; -use workspace::item::{Item, TabContentParams}; +use workspace::item::Item; pub struct ProjectIndexDebugView { index: Model, @@ -271,14 +271,8 @@ impl EventEmitter<()> for ProjectIndexDebugView {} impl Item for ProjectIndexDebugView { type Event = (); - fn tab_content(&self, params: TabContentParams, _: &WindowContext<'_>) -> AnyElement { - Label::new("Project Index (Debug)") - .color(if params.selected { - Color::Default - } else { - Color::Muted - }) - .into_any_element() + fn tab_content_text(&self, _cx: &WindowContext) -> Option { + Some("Project Index (Debug)".into()) } fn clone_on_split( diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index 98892eb29f62718e5e1cc347578c1c2180ab08f9..3593eea3787a5dbc9a3289cd539562572f1ce9f4 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -5,9 +5,9 @@ mod multibuffer_hint; use client::{telemetry::Telemetry, TelemetrySettings}; use db::kvp::KEY_VALUE_STORE; use gpui::{ - actions, svg, AnyElement, AppContext, EventEmitter, FocusHandle, FocusableView, - InteractiveElement, ParentElement, Render, Styled, Subscription, Task, View, ViewContext, - VisualContext, WeakView, WindowContext, + actions, svg, AppContext, EventEmitter, FocusHandle, FocusableView, InteractiveElement, + ParentElement, Render, Styled, Subscription, Task, View, ViewContext, VisualContext, WeakView, + WindowContext, }; use settings::{Settings, SettingsStore}; use std::sync::Arc; @@ -15,7 +15,7 @@ use ui::{prelude::*, CheckboxWithLabel}; use vim::VimModeSetting; use workspace::{ dock::DockPosition, - item::{Item, ItemEvent, TabContentParams}, + item::{Item, ItemEvent}, open_new, AppState, Welcome, Workspace, WorkspaceId, }; @@ -303,14 +303,8 @@ impl FocusableView for WelcomePage { impl Item for WelcomePage { type Event = ItemEvent; - fn tab_content(&self, params: TabContentParams, _: &WindowContext) -> AnyElement { - Label::new("Welcome to Zed!") - .color(if params.selected { - Color::Default - } else { - Color::Muted - }) - .into_any_element() + fn tab_content_text(&self, _cx: &WindowContext) -> Option { + Some("Welcome to Zed!".into()) } fn telemetry_event_text(&self) -> Option<&'static str> { diff --git a/crates/workspace/src/item.rs b/crates/workspace/src/item.rs index d898d775c3de4373bb863cad2feabbf047464da1..149e949568cfddab08299a5b7bb22c9fa5867bdd 100644 --- a/crates/workspace/src/item.rs +++ b/crates/workspace/src/item.rs @@ -31,7 +31,7 @@ use std::{ time::Duration, }; use theme::Theme; -use ui::{Element as _, Icon}; +use ui::{Color, Element as _, Icon, IntoElement, Label, LabelCommon}; use util::ResultExt; pub const LEADER_UPDATE_THROTTLE: Duration = Duration::from_millis(200); @@ -144,8 +144,30 @@ pub struct TabContentParams { pub trait Item: FocusableView + EventEmitter { type Event; - fn tab_content(&self, _params: TabContentParams, _cx: &WindowContext) -> AnyElement { - gpui::Empty.into_any() + + /// Returns the tab contents. + /// + /// By default this returns a [`Label`] that displays that text from + /// `tab_content_text`. + fn tab_content(&self, params: TabContentParams, cx: &WindowContext) -> AnyElement { + let Some(text) = self.tab_content_text(cx) else { + return gpui::Empty.into_any(); + }; + + let color = if params.selected { + Color::Default + } else { + Color::Muted + }; + + Label::new(text).color(color).into_any_element() + } + + /// Returns the textual contents of the tab. + /// + /// Use this if you don't need to customize the tab contents. + fn tab_content_text(&self, _cx: &WindowContext) -> Option { + None } fn tab_icon(&self, _cx: &WindowContext) -> Option { diff --git a/crates/workspace/src/shared_screen.rs b/crates/workspace/src/shared_screen.rs index 6784a75fb57c3f7e7f3a264ed033ed901ef81324..49af337e09f18de4ace497698fdb80498bb32cbf 100644 --- a/crates/workspace/src/shared_screen.rs +++ b/crates/workspace/src/shared_screen.rs @@ -1,5 +1,5 @@ use crate::{ - item::{Item, ItemEvent, TabContentParams}, + item::{Item, ItemEvent}, ItemNavHistory, WorkspaceId, }; use anyhow::Result; @@ -12,7 +12,7 @@ use gpui::{ WindowContext, }; use std::sync::{Arc, Weak}; -use ui::{prelude::*, Icon, IconName, Label}; +use ui::{prelude::*, Icon, IconName}; pub enum Event { Close, @@ -97,14 +97,8 @@ impl Item for SharedScreen { Some(Icon::new(IconName::Screen)) } - fn tab_content(&self, params: TabContentParams, _: &WindowContext<'_>) -> gpui::AnyElement { - Label::new(format!("{}'s screen", self.user.github_login)) - .color(if params.selected { - Color::Default - } else { - Color::Muted - }) - .into_any_element() + fn tab_content_text(&self, _cx: &WindowContext) -> Option { + Some(format!("{}'s screen", self.user.github_login).into()) } fn telemetry_event_text(&self) -> Option<&'static str> {