Merge pull request #2197 from zed-industries/label-text-cow

Mikayla Maki created

Changed label and text to be generic over static and owned strings

Change summary

crates/auto_update/src/update_notification.rs       |  2 
crates/breadcrumbs/src/breadcrumbs.rs               |  2 
crates/collab_ui/src/collab_titlebar_item.rs        |  6 ++--
crates/collab_ui/src/contact_list.rs                | 10 ++++----
crates/collab_ui/src/incoming_call_notification.rs  |  4 +-
crates/collab_ui/src/notifications.rs               |  8 +++---
crates/collab_ui/src/project_shared_notification.rs |  4 +-
crates/command_palette/src/command_palette.rs       |  2 
crates/diagnostics/src/diagnostics.rs               | 15 +++++--------
crates/diagnostics/src/items.rs                     | 13 ++++-------
crates/editor/src/element.rs                        |  2 
crates/editor/src/items.rs                          |  2 
crates/feedback/src/deploy_feedback_button.rs       |  6 ----
crates/feedback/src/feedback_editor.rs              |  2 
crates/feedback/src/feedback_info_text.rs           |  2 
crates/feedback/src/submit_feedback_button.rs       |  2 
crates/gpui/src/elements/label.rs                   | 16 ++++++--------
crates/gpui/src/elements/text.rs                    |  8 +++---
crates/picker/src/picker.rs                         |  2 
crates/search/src/buffer_search.rs                  |  8 +++---
crates/search/src/project_search.rs                 | 10 ++++----
crates/terminal_view/src/terminal_view.rs           |  2 
crates/theme_testbench/src/theme_testbench.rs       |  2 
crates/workspace/src/workspace.rs                   |  2 
24 files changed, 60 insertions(+), 72 deletions(-)

Detailed changes

crates/auto_update/src/update_notification.rs πŸ”—

@@ -78,7 +78,7 @@ impl View for UpdateNotification {
                 )
                 .with_child({
                     let style = theme.action_message.style_for(state, false);
-                    Text::new("View the release notes".to_string(), style.text.clone())
+                    Text::new("View the release notes", style.text.clone())
                         .contained()
                         .with_style(style.container)
                         .boxed()

crates/breadcrumbs/src/breadcrumbs.rs πŸ”—

@@ -47,7 +47,7 @@ impl View for Breadcrumbs {
         {
             Flex::row()
                 .with_children(Itertools::intersperse_with(breadcrumbs.into_iter(), || {
-                    Label::new(" βŒͺ ".to_string(), theme.breadcrumbs.text.clone()).boxed()
+                    Label::new(" βŒͺ ", theme.breadcrumbs.text.clone()).boxed()
                 }))
                 .contained()
                 .with_style(theme.breadcrumbs.container)

crates/collab_ui/src/collab_titlebar_item.rs πŸ”—

@@ -293,7 +293,7 @@ impl CollabTitlebarItem {
         let titlebar = &theme.workspace.titlebar;
         MouseEventHandler::<Share>::new(0, cx, |state, _| {
             let style = titlebar.share_button.style_for(state, false);
-            Label::new("Share".into(), style.text.clone())
+            Label::new("Share", style.text.clone())
                 .contained()
                 .with_style(style.container)
                 .boxed()
@@ -378,7 +378,7 @@ impl CollabTitlebarItem {
                         .titlebar
                         .sign_in_prompt
                         .style_for(state, false);
-                    Label::new("Sign in".to_string(), style.text.clone())
+                    Label::new("Sign in", style.text.clone())
                         .contained()
                         .with_style(style.container)
                         .boxed()
@@ -531,7 +531,7 @@ impl CollabTitlebarItem {
             client::Status::UpgradeRequired => Some(
                 MouseEventHandler::<ConnectionStatusButton>::new(0, cx, |_, _| {
                     Label::new(
-                        "Please update Zed to collaborate".to_string(),
+                        "Please update Zed to collaborate",
                         theme.workspace.titlebar.outdated_warning.text.clone(),
                     )
                     .contained()

crates/collab_ui/src/contact_list.rs πŸ”—

@@ -749,7 +749,7 @@ impl ContactList {
             )
             .with_children(if is_pending {
                 Some(
-                    Label::new("Calling".to_string(), theme.calling_indicator.text.clone())
+                    Label::new("Calling", theme.calling_indicator.text.clone())
                         .contained()
                         .with_style(theme.calling_indicator.container)
                         .aligned()
@@ -950,7 +950,7 @@ impl ContactList {
                             .boxed(),
                     )
                     .with_child(
-                        Label::new("Screen".into(), row.name.text.clone())
+                        Label::new("Screen", row.name.text.clone())
                             .aligned()
                             .left()
                             .contained()
@@ -994,7 +994,7 @@ impl ContactList {
             Some(
                 MouseEventHandler::<LeaveCall>::new(0, cx, |state, _| {
                     let style = theme.leave_call.style_for(state, false);
-                    Label::new("Leave Session".into(), style.text.clone())
+                    Label::new("Leave Session", style.text.clone())
                         .contained()
                         .with_style(style.container)
                         .boxed()
@@ -1026,7 +1026,7 @@ impl ContactList {
                     .boxed(),
                 )
                 .with_child(
-                    Label::new(text.to_string(), header_style.text.clone())
+                    Label::new(text, header_style.text.clone())
                         .aligned()
                         .left()
                         .contained()
@@ -1126,7 +1126,7 @@ impl ContactList {
                     )
                     .with_children(if calling {
                         Some(
-                            Label::new("Calling".to_string(), theme.calling_indicator.text.clone())
+                            Label::new("Calling", theme.calling_indicator.text.clone())
                                 .contained()
                                 .with_style(theme.calling_indicator.container)
                                 .aligned()

crates/collab_ui/src/incoming_call_notification.rs πŸ”—

@@ -172,7 +172,7 @@ impl IncomingCallNotification {
             .with_child(
                 MouseEventHandler::<Accept>::new(0, cx, |_, cx| {
                     let theme = &cx.global::<Settings>().theme.incoming_call_notification;
-                    Label::new("Accept".to_string(), theme.accept_button.text.clone())
+                    Label::new("Accept", theme.accept_button.text.clone())
                         .aligned()
                         .contained()
                         .with_style(theme.accept_button.container)
@@ -188,7 +188,7 @@ impl IncomingCallNotification {
             .with_child(
                 MouseEventHandler::<Decline>::new(0, cx, |_, cx| {
                     let theme = &cx.global::<Settings>().theme.incoming_call_notification;
-                    Label::new("Decline".to_string(), theme.decline_button.text.clone())
+                    Label::new("Decline", theme.decline_button.text.clone())
                         .aligned()
                         .contained()
                         .with_style(theme.decline_button.container)

crates/collab_ui/src/notifications.rs πŸ”—

@@ -11,8 +11,8 @@ enum Button {}
 
 pub fn render_user_notification<V: View, A: Action + Clone>(
     user: Arc<User>,
-    title: &str,
-    body: Option<&str>,
+    title: &'static str,
+    body: Option<&'static str>,
     dismiss_action: A,
     buttons: Vec<(&'static str, Box<dyn Action>)>,
     cx: &mut RenderContext<V>,
@@ -83,7 +83,7 @@ pub fn render_user_notification<V: View, A: Action + Clone>(
                 .named("contact notification header"),
         )
         .with_children(body.map(|body| {
-            Label::new(body.to_string(), theme.body_message.text.clone())
+            Label::new(body, theme.body_message.text.clone())
                 .contained()
                 .with_style(theme.body_message.container)
                 .boxed()
@@ -97,7 +97,7 @@ pub fn render_user_notification<V: View, A: Action + Clone>(
                         |(ix, (message, action))| {
                             MouseEventHandler::<Button>::new(ix, cx, |state, _| {
                                 let button = theme.button.style_for(state, false);
-                                Label::new(message.to_string(), button.text.clone())
+                                Label::new(message, button.text.clone())
                                     .contained()
                                     .with_style(button.container)
                                     .boxed()

crates/collab_ui/src/project_shared_notification.rs πŸ”—

@@ -175,7 +175,7 @@ impl ProjectSharedNotification {
             .with_child(
                 MouseEventHandler::<Open>::new(0, cx, |_, cx| {
                     let theme = &cx.global::<Settings>().theme.project_shared_notification;
-                    Label::new("Open".to_string(), theme.open_button.text.clone())
+                    Label::new("Open", theme.open_button.text.clone())
                         .aligned()
                         .contained()
                         .with_style(theme.open_button.container)
@@ -194,7 +194,7 @@ impl ProjectSharedNotification {
             .with_child(
                 MouseEventHandler::<Dismiss>::new(0, cx, |_, cx| {
                     let theme = &cx.global::<Settings>().theme.project_shared_notification;
-                    Label::new("Dismiss".to_string(), theme.dismiss_button.text.clone())
+                    Label::new("Dismiss", theme.dismiss_button.text.clone())
                         .aligned()
                         .contained()
                         .with_style(theme.dismiss_button.container)

crates/command_palette/src/command_palette.rs πŸ”—

@@ -257,7 +257,7 @@ impl PickerDelegate for CommandPalette {
                         .filter_map(|(modifier, label)| {
                             if modifier {
                                 Some(
-                                    Label::new(label.into(), key_style.label.clone())
+                                    Label::new(label, key_style.label.clone())
                                         .contained()
                                         .with_style(key_style.container)
                                         .boxed(),

crates/diagnostics/src/diagnostics.rs πŸ”—

@@ -90,14 +90,11 @@ impl View for ProjectDiagnosticsEditor {
     fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
         if self.path_states.is_empty() {
             let theme = &cx.global::<Settings>().theme.project_diagnostics;
-            Label::new(
-                "No problems in workspace".to_string(),
-                theme.empty_message.clone(),
-            )
-            .aligned()
-            .contained()
-            .with_style(theme.container)
-            .boxed()
+            Label::new("No problems in workspace", theme.empty_message.clone())
+                .aligned()
+                .contained()
+                .with_style(theme.container)
+                .boxed()
         } else {
             ChildView::new(&self.editor, cx).boxed()
         }
@@ -697,7 +694,7 @@ pub(crate) fn render_summary(
     theme: &theme::ProjectDiagnostics,
 ) -> ElementBox {
     if summary.error_count == 0 && summary.warning_count == 0 {
-        Label::new("No problems".to_string(), text_style.clone()).boxed()
+        Label::new("No problems", text_style.clone()).boxed()
     } else {
         let icon_width = theme.tab_icon_width;
         let icon_spacing = theme.tab_icon_spacing;

crates/diagnostics/src/items.rs πŸ”—

@@ -178,14 +178,11 @@ impl View for DiagnosticIndicator {
 
         if in_progress {
             element.add_child(
-                Label::new(
-                    "Checking…".into(),
-                    style.diagnostic_message.default.text.clone(),
-                )
-                .aligned()
-                .contained()
-                .with_margin_left(item_spacing)
-                .boxed(),
+                Label::new("Checking…", style.diagnostic_message.default.text.clone())
+                    .aligned()
+                    .contained()
+                    .with_margin_left(item_spacing)
+                    .boxed(),
             );
         } else if let Some(diagnostic) = &self.current_diagnostic {
             let message_style = style.diagnostic_message.clone();

crates/editor/src/element.rs πŸ”—

@@ -1438,7 +1438,7 @@ impl EditorElement {
                     } else {
                         let text_style = self.style.text.clone();
                         Flex::row()
-                            .with_child(Label::new("…".to_string(), text_style).boxed())
+                            .with_child(Label::new("…", text_style).boxed())
                             .with_children(jump_icon)
                             .contained()
                             .with_padding_left(gutter_padding)

crates/editor/src/items.rs πŸ”—

@@ -529,7 +529,7 @@ impl Item for Editor {
     ) -> ElementBox {
         Flex::row()
             .with_child(
-                Label::new(self.title(cx).into(), style.label.clone())
+                Label::new(self.title(cx).to_string(), style.label.clone())
                     .aligned()
                     .boxed(),
             )

crates/feedback/src/deploy_feedback_button.rs πŸ”—

@@ -25,11 +25,7 @@ impl View for DeployFeedbackButton {
                     let theme = &cx.global::<Settings>().theme;
                     let theme = &theme.workspace.status_bar.feedback;
 
-                    Text::new(
-                        "Give Feedback".to_string(),
-                        theme.style_for(state, true).clone(),
-                    )
-                    .boxed()
+                    Text::new("Give Feedback", theme.style_for(state, true).clone()).boxed()
                 })
                 .with_cursor_style(CursorStyle::PointingHand)
                 .on_click(MouseButton::Left, |_, cx| cx.dispatch_action(GiveFeedback))

crates/feedback/src/feedback_editor.rs πŸ”—

@@ -247,7 +247,7 @@ impl Item for FeedbackEditor {
     fn tab_content(&self, _: Option<usize>, style: &theme::Tab, _: &AppContext) -> ElementBox {
         Flex::row()
             .with_child(
-                Label::new("Feedback".to_string(), style.label.clone())
+                Label::new("Feedback", style.label.clone())
                     .aligned()
                     .contained()
                     .boxed(),

crates/feedback/src/feedback_info_text.rs πŸ”—

@@ -30,7 +30,7 @@ impl View for FeedbackInfoText {
     fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
         let theme = cx.global::<Settings>().theme.clone();
         let text = "We read whatever you submit here. For issues and discussions, visit the community repo on GitHub.";
-        Label::new(text.to_string(), theme.feedback.info_text.text.clone())
+        Label::new(text, theme.feedback.info_text.text.clone())
             .contained()
             .aligned()
             .left()

crates/feedback/src/submit_feedback_button.rs πŸ”—

@@ -34,7 +34,7 @@ impl View for SubmitFeedbackButton {
         enum SubmitFeedbackButton {}
         MouseEventHandler::<SubmitFeedbackButton>::new(0, cx, |state, _| {
             let style = theme.feedback.submit_button.style_for(state, false);
-            Label::new("Submit as Markdown".into(), style.text.clone())
+            Label::new("Submit as Markdown", style.text.clone())
                 .contained()
                 .with_style(style.container)
                 .boxed()

crates/gpui/src/elements/label.rs πŸ”—

@@ -1,4 +1,4 @@
-use std::ops::Range;
+use std::{borrow::Cow, ops::Range};
 
 use crate::{
     fonts::TextStyle,
@@ -16,7 +16,7 @@ use serde_json::json;
 use smallvec::{smallvec, SmallVec};
 
 pub struct Label {
-    text: String,
+    text: Cow<'static, str>,
     style: LabelStyle,
     highlight_indices: Vec<usize>,
 }
@@ -44,9 +44,9 @@ impl LabelStyle {
 }
 
 impl Label {
-    pub fn new(text: String, style: impl Into<LabelStyle>) -> Self {
+    pub fn new<I: Into<Cow<'static, str>>>(text: I, style: impl Into<LabelStyle>) -> Self {
         Self {
-            text,
+            text: text.into(),
             highlight_indices: Default::default(),
             style: style.into(),
         }
@@ -138,11 +138,9 @@ impl Element for Label {
         cx: &mut LayoutContext,
     ) -> (Vector2F, Self::LayoutState) {
         let runs = self.compute_runs();
-        let line = cx.text_layout_cache.layout_str(
-            self.text.as_str(),
-            self.style.text.font_size,
-            runs.as_slice(),
-        );
+        let line =
+            cx.text_layout_cache
+                .layout_str(&self.text, self.style.text.font_size, runs.as_slice());
 
         let size = vec2f(
             line.width()

crates/gpui/src/elements/text.rs πŸ”—

@@ -15,7 +15,7 @@ use serde_json::json;
 use std::{borrow::Cow, ops::Range, sync::Arc};
 
 pub struct Text {
-    text: String,
+    text: Cow<'static, str>,
     style: TextStyle,
     soft_wrap: bool,
     highlights: Vec<(Range<usize>, HighlightStyle)>,
@@ -28,9 +28,9 @@ pub struct LayoutState {
 }
 
 impl Text {
-    pub fn new(text: String, style: TextStyle) -> Self {
+    pub fn new<I: Into<Cow<'static, str>>>(text: I, style: TextStyle) -> Self {
         Self {
-            text,
+            text: text.into(),
             style,
             soft_wrap: true,
             highlights: Vec::new(),
@@ -280,7 +280,7 @@ mod tests {
         let (window_id, _) = cx.add_window(Default::default(), |_| TestView);
         let mut presenter = cx.build_presenter(window_id, Default::default(), Default::default());
         fonts::with_font_cache(cx.font_cache().clone(), || {
-            let mut text = Text::new("Hello\r\n".into(), Default::default()).with_soft_wrap(true);
+            let mut text = Text::new("Hello\r\n", Default::default()).with_soft_wrap(true);
             let (_, state) = text.layout(
                 SizeConstraint::new(Default::default(), vec2f(f32::INFINITY, f32::INFINITY)),
                 &mut presenter.build_layout_context(Default::default(), false, cx),

crates/picker/src/picker.rs πŸ”—

@@ -80,7 +80,7 @@ impl<D: PickerDelegate> View for Picker<D> {
                     None
                 } else {
                     Some(
-                        Label::new("No matches".into(), theme.no_matches.label.clone())
+                        Label::new("No matches", theme.no_matches.label.clone())
                             .contained()
                             .with_style(theme.no_matches.container)
                             .boxed(),

crates/search/src/buffer_search.rs πŸ”—

@@ -319,7 +319,7 @@ impl BufferSearchBar {
     fn render_search_option(
         &self,
         option_supported: bool,
-        icon: &str,
+        icon: &'static str,
         option: SearchOption,
         cx: &mut RenderContext<Self>,
     ) -> Option<ElementBox> {
@@ -337,7 +337,7 @@ impl BufferSearchBar {
                     .search
                     .option_button
                     .style_for(state, is_active);
-                Label::new(icon.to_string(), style.text.clone())
+                Label::new(icon, style.text.clone())
                     .contained()
                     .with_style(style.container)
                     .boxed()
@@ -359,7 +359,7 @@ impl BufferSearchBar {
 
     fn render_nav_button(
         &self,
-        icon: &str,
+        icon: &'static str,
         direction: Direction,
         cx: &mut RenderContext<Self>,
     ) -> ElementBox {
@@ -385,7 +385,7 @@ impl BufferSearchBar {
                 .search
                 .option_button
                 .style_for(state, false);
-            Label::new(icon.to_string(), style.text.clone())
+            Label::new(icon, style.text.clone())
                 .contained()
                 .with_style(style.container)
                 .boxed()

crates/search/src/project_search.rs πŸ”—

@@ -189,7 +189,7 @@ impl View for ProjectSearchView {
                 "No results"
             };
             MouseEventHandler::<Status>::new(0, cx, |_, _| {
-                Label::new(text.to_string(), theme.search.results_status.clone())
+                Label::new(text, theme.search.results_status.clone())
                     .aligned()
                     .contained()
                     .with_background_color(theme.editor.background)
@@ -744,7 +744,7 @@ impl ProjectSearchBar {
 
     fn render_nav_button(
         &self,
-        icon: &str,
+        icon: &'static str,
         direction: Direction,
         cx: &mut RenderContext<Self>,
     ) -> ElementBox {
@@ -770,7 +770,7 @@ impl ProjectSearchBar {
                 .search
                 .option_button
                 .style_for(state, false);
-            Label::new(icon.to_string(), style.text.clone())
+            Label::new(icon, style.text.clone())
                 .contained()
                 .with_style(style.container)
                 .boxed()
@@ -792,7 +792,7 @@ impl ProjectSearchBar {
 
     fn render_option_button(
         &self,
-        icon: &str,
+        icon: &'static str,
         option: SearchOption,
         cx: &mut RenderContext<Self>,
     ) -> ElementBox {
@@ -805,7 +805,7 @@ impl ProjectSearchBar {
                 .search
                 .option_button
                 .style_for(state, is_active);
-            Label::new(icon.to_string(), style.text.clone())
+            Label::new(icon, style.text.clone())
                 .contained()
                 .with_style(style.container)
                 .boxed()

crates/terminal_view/src/terminal_view.rs πŸ”—

@@ -680,7 +680,7 @@ impl Item for TerminalView {
 
     fn breadcrumbs(&self, theme: &theme::Theme, cx: &AppContext) -> Option<Vec<ElementBox>> {
         Some(vec![Text::new(
-            self.terminal().read(cx).breadcrumb_text.to_string(),
+            self.terminal().read(cx).breadcrumb_text.clone(),
             theme.breadcrumbs.text.clone(),
         )
         .boxed()])

crates/theme_testbench/src/theme_testbench.rs πŸ”—

@@ -308,7 +308,7 @@ impl Item for ThemeTestbench {
         style: &theme::Tab,
         _: &AppContext,
     ) -> gpui::ElementBox {
-        Label::new("Theme Testbench".into(), style.label.clone())
+        Label::new("Theme Testbench", style.label.clone())
             .aligned()
             .contained()
             .boxed()

crates/workspace/src/workspace.rs πŸ”—

@@ -1958,7 +1958,7 @@ impl Workspace {
                 MouseEventHandler::<DisconnectedOverlay>::new(0, cx, |_, cx| {
                     let theme = &cx.global::<Settings>().theme;
                     Label::new(
-                        "Your connection to the remote project has been lost.".to_string(),
+                        "Your connection to the remote project has been lost.",
                         theme.workspace.disconnected_overlay.text.clone(),
                     )
                     .aligned()