From ebe57254e013cb7f990e297bbf66e90c7cda4aea Mon Sep 17 00:00:00 2001 From: Joseph Lyons Date: Fri, 14 Apr 2023 17:46:53 -0400 Subject: [PATCH 1/3] Add tab tooltips --- crates/diagnostics/src/diagnostics.rs | 5 ++ crates/editor/src/items.rs | 17 +++++ crates/feedback/src/feedback_editor.rs | 5 ++ crates/gpui/src/elements/tooltip.rs | 13 ++-- crates/search/src/project_search.rs | 5 ++ crates/terminal_view/src/terminal_view.rs | 5 ++ crates/welcome/src/welcome.rs | 6 +- crates/workspace/src/item.rs | 8 +++ crates/workspace/src/pane.rs | 86 ++++++++++++++--------- crates/workspace/src/shared_screen.rs | 8 ++- 10 files changed, 119 insertions(+), 39 deletions(-) diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index 0ac282d1997760a5298113f688639af96898a9a9..d94d82487accc5bb7f9ad49ed16082f6d55a98ca 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -24,6 +24,7 @@ use settings::Settings; use smallvec::SmallVec; use std::{ any::{Any, TypeId}, + borrow::Cow, cmp::Ordering, ops::Range, path::PathBuf, @@ -531,6 +532,10 @@ impl Item for ProjectDiagnosticsEditor { .update(cx, |editor, cx| editor.navigate(data, cx)) } + fn tab_tooltip_text<'a>(&'a self, _: &'a AppContext) -> Option> { + Some("Project Diagnostics".into()) + } + fn is_dirty(&self, cx: &AppContext) -> bool { self.excerpts.read(cx).is_dirty(cx) } diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index 0f2a98dfe94d49d135214c3500e6e02283186fc5..630b900e275cb72803ae44dfdfd15d033d520c46 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -514,6 +514,23 @@ impl Item for Editor { } } + fn tab_tooltip_text<'a>(&self, cx: &'a AppContext) -> Option> { + let file_path = self + .buffer() + .read(cx) + .as_singleton()? + .read(cx) + .file() + .and_then(|f| f.as_local())? + .abs_path(cx); + + let file_path = util::paths::compact(&file_path) + .to_string_lossy() + .to_string(); + + Some(file_path.into()) + } + fn tab_description<'a>(&'a self, detail: usize, cx: &'a AppContext) -> Option> { match path_for_buffer(&self.buffer, detail, true, cx)? { Cow::Borrowed(path) => Some(path.to_string_lossy()), diff --git a/crates/feedback/src/feedback_editor.rs b/crates/feedback/src/feedback_editor.rs index 15334138db42bd2c76cef5feb60037ffd3edb048..c45c29c9894379b9061dea5668f0016bb852f25e 100644 --- a/crates/feedback/src/feedback_editor.rs +++ b/crates/feedback/src/feedback_editor.rs @@ -1,5 +1,6 @@ use std::{ any::TypeId, + borrow::Cow, ops::{Range, RangeInclusive}, sync::Arc, }; @@ -248,6 +249,10 @@ impl Entity for FeedbackEditor { } impl Item for FeedbackEditor { + fn tab_tooltip_text<'a>(&'a self, _: &'a AppContext) -> Option> { + Some("Send Feedback".into()) + } + fn tab_content(&self, _: Option, style: &theme::Tab, _: &AppContext) -> ElementBox { Flex::row() .with_child( diff --git a/crates/gpui/src/elements/tooltip.rs b/crates/gpui/src/elements/tooltip.rs index 562f12295c4a3cd0dbbba28d46301de41f212ef7..2f26ee116dad86194796a807892de421e3dfaa5c 100644 --- a/crates/gpui/src/elements/tooltip.rs +++ b/crates/gpui/src/elements/tooltip.rs @@ -39,7 +39,7 @@ pub struct TooltipStyle { pub container: ContainerStyle, pub text: TextStyle, keystroke: KeystrokeStyle, - pub max_text_width: f32, + pub max_text_width: Option, } #[derive(Clone, Deserialize, Default)] @@ -140,9 +140,14 @@ impl Tooltip { ) -> impl Element { Flex::row() .with_child({ - let text = Text::new(text, style.text) - .constrained() - .with_max_width(style.max_text_width); + let text = if let Some(max_text_width) = style.max_text_width { + Text::new(text, style.text) + .constrained() + .with_max_width(max_text_width) + } else { + Text::new(text, style.text).constrained() + }; + if measure { text.flex(1., false).boxed() } else { diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index c7660aa33602ba83db950719c2110b28ebc9af6b..b57561a4cc6fdbea7b35be67f0c1d26c9f82408c 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -22,6 +22,7 @@ use settings::Settings; use smallvec::SmallVec; use std::{ any::{Any, TypeId}, + borrow::Cow, mem, ops::Range, path::PathBuf, @@ -225,6 +226,10 @@ impl View for ProjectSearchView { } impl Item for ProjectSearchView { + fn tab_tooltip_text<'a>(&'a self, cx: &'a AppContext) -> Option> { + Some(self.query_editor.read(cx).text(cx).into()) + } + fn act_as_type<'a>( &'a self, type_id: TypeId, diff --git a/crates/terminal_view/src/terminal_view.rs b/crates/terminal_view/src/terminal_view.rs index 3af147b9ff3e1e383ddb9d5045abb36e71cdddcf..99f15c126e5428a090a06fc8707c0c6278b45ac3 100644 --- a/crates/terminal_view/src/terminal_view.rs +++ b/crates/terminal_view/src/terminal_view.rs @@ -3,6 +3,7 @@ pub mod terminal_button; pub mod terminal_element; use std::{ + borrow::Cow, ops::RangeInclusive, path::{Path, PathBuf}, time::Duration, @@ -543,6 +544,10 @@ impl View for TerminalView { } impl Item for TerminalView { + fn tab_tooltip_text<'a>(&'a self, cx: &'a AppContext) -> Option> { + Some(self.terminal().read(cx).title().into()) + } + fn tab_content( &self, _detail: Option, diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index 28b0e43c571fac33d7ee835933a584ef683d8da0..114f3eb88ef3b31b96cc4a7a1241d05c16c84668 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -1,6 +1,6 @@ mod base_keymap_picker; -use std::sync::Arc; +use std::{borrow::Cow, sync::Arc}; use db::kvp::KEY_VALUE_STORE; use gpui::{ @@ -198,6 +198,10 @@ impl WelcomePage { } impl Item for WelcomePage { + fn tab_tooltip_text<'a>(&'a self, _: &'a AppContext) -> Option> { + Some("Welcome to Zed!".into()) + } + fn tab_content( &self, _detail: Option, diff --git a/crates/workspace/src/item.rs b/crates/workspace/src/item.rs index f7ffe64f972d99ccb9b172f3fc70a4a0203f91b4..347a0022cc7bec890631c45d44c7d2f4b52fcbda 100644 --- a/crates/workspace/src/item.rs +++ b/crates/workspace/src/item.rs @@ -44,6 +44,9 @@ pub trait Item: View { fn navigate(&mut self, _: Box, _: &mut ViewContext) -> bool { false } + fn tab_tooltip_text<'a>(&'a self, _: &'a AppContext) -> Option> { + None + } fn tab_description<'a>(&'a self, _: usize, _: &'a AppContext) -> Option> { None } @@ -162,6 +165,7 @@ pub trait ItemHandle: 'static + fmt::Debug { cx: &mut AppContext, handler: Box, ) -> gpui::Subscription; + fn tab_tooltip_text<'a>(&self, cx: &'a AppContext) -> Option>; fn tab_description<'a>(&self, detail: usize, cx: &'a AppContext) -> Option>; fn tab_content(&self, detail: Option, style: &theme::Tab, cx: &AppContext) -> ElementBox; @@ -248,6 +252,10 @@ impl ItemHandle for ViewHandle { }) } + fn tab_tooltip_text<'a>(&self, cx: &'a AppContext) -> Option> { + self.read(cx).tab_tooltip_text(cx) + } + fn tab_description<'a>(&self, detail: usize, cx: &'a AppContext) -> Option> { self.read(cx).tab_description(detail, cx) } diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index a54aed96f464bdcfff03e526ecdb8cd9f5c37963..c394ae4631b57de99c3c8e2c229942c4cfe7481f 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -1386,6 +1386,9 @@ impl Pane { let detail = detail.clone(); let theme = cx.global::().theme.clone(); + let mut tooltip_theme = theme.tooltip.clone(); + tooltip_theme.max_text_width = None; + let tab_tooltip_text = item.tab_tooltip_text(cx).map(|a| a.to_string()); move |mouse_state, cx| { let tab_style = @@ -1393,39 +1396,56 @@ impl Pane { let hovered = mouse_state.hovered(); enum Tab {} - MouseEventHandler::::new(ix, cx, |_, cx| { - Self::render_tab( - &item, - pane.clone(), - ix == 0, - detail, - hovered, - tab_style, - cx, - ) - }) - .on_down(MouseButton::Left, move |_, cx| { - cx.dispatch_action(ActivateItem(ix)); - }) - .on_click(MouseButton::Middle, { - let item = item.clone(); - let pane = pane.clone(); - move |_, cx: &mut EventContext| { - cx.dispatch_action(CloseItemById { - item_id: item.id(), - pane: pane.clone(), - }) - } - }) - .on_down(MouseButton::Right, move |e, cx| { - let item = item.clone(); - cx.dispatch_action(DeployTabContextMenu { - position: e.position, - item_id: item.id(), - pane: pane.clone(), - }); - }) - .boxed() + let mouse_event_handler = + MouseEventHandler::::new(ix, cx, |_, cx| { + Self::render_tab( + &item, + pane.clone(), + ix == 0, + detail, + hovered, + tab_style, + cx, + ) + }) + .on_down(MouseButton::Left, move |_, cx| { + cx.dispatch_action(ActivateItem(ix)); + }) + .on_click(MouseButton::Middle, { + let item = item.clone(); + let pane = pane.clone(); + move |_, cx: &mut EventContext| { + cx.dispatch_action(CloseItemById { + item_id: item.id(), + pane: pane.clone(), + }) + } + }) + .on_down( + MouseButton::Right, + move |e, cx| { + let item = item.clone(); + cx.dispatch_action(DeployTabContextMenu { + position: e.position, + item_id: item.id(), + pane: pane.clone(), + }); + }, + ); + + if let Some(tab_tooltip_text) = tab_tooltip_text { + return mouse_event_handler + .with_tooltip::( + ix, + tab_tooltip_text, + None, + tooltip_theme, + cx, + ) + .boxed(); + } + + mouse_event_handler.boxed() } }); diff --git a/crates/workspace/src/shared_screen.rs b/crates/workspace/src/shared_screen.rs index 7f7bf3b25f418be46ff8e643d4a74ae54af2045f..a1dcb89e44f939f99f3c81090746a4284baaf4da 100644 --- a/crates/workspace/src/shared_screen.rs +++ b/crates/workspace/src/shared_screen.rs @@ -13,7 +13,10 @@ use gpui::{ }; use settings::Settings; use smallvec::SmallVec; -use std::sync::{Arc, Weak}; +use std::{ + borrow::Cow, + sync::{Arc, Weak}, +}; pub enum Event { Close, @@ -92,6 +95,9 @@ impl View for SharedScreen { } impl Item for SharedScreen { + fn tab_tooltip_text<'a>(&'a self, _: &'a AppContext) -> Option> { + Some(format!("{}'s screen", self.user.github_login).into()) + } fn deactivated(&mut self, cx: &mut ViewContext) { if let Some(nav_history) = self.nav_history.as_ref() { nav_history.push::<()>(None, cx); From 9afd804062fbfa777fda7840f90c04df93caf055 Mon Sep 17 00:00:00 2001 From: Joseph Lyons Date: Tue, 18 Apr 2023 14:03:02 -0400 Subject: [PATCH 2/3] Remove unnecessary lifetimes from `tab_tooltip_text` --- crates/diagnostics/src/diagnostics.rs | 2 +- crates/editor/src/items.rs | 2 +- crates/feedback/src/feedback_editor.rs | 2 +- crates/search/src/project_search.rs | 2 +- crates/terminal_view/src/terminal_view.rs | 2 +- crates/welcome/src/welcome.rs | 2 +- crates/workspace/src/item.rs | 6 +++--- crates/workspace/src/shared_screen.rs | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index d94d82487accc5bb7f9ad49ed16082f6d55a98ca..75a95586bebc4043c62c2ee81a4c3fdd4b0d938d 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -532,7 +532,7 @@ impl Item for ProjectDiagnosticsEditor { .update(cx, |editor, cx| editor.navigate(data, cx)) } - fn tab_tooltip_text<'a>(&'a self, _: &'a AppContext) -> Option> { + fn tab_tooltip_text(&self, _: &AppContext) -> Option> { Some("Project Diagnostics".into()) } diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index 630b900e275cb72803ae44dfdfd15d033d520c46..64147effff086a2721ba5f7b2c99d537ce9942c9 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -514,7 +514,7 @@ impl Item for Editor { } } - fn tab_tooltip_text<'a>(&self, cx: &'a AppContext) -> Option> { + fn tab_tooltip_text(&self, cx: &AppContext) -> Option> { let file_path = self .buffer() .read(cx) diff --git a/crates/feedback/src/feedback_editor.rs b/crates/feedback/src/feedback_editor.rs index c45c29c9894379b9061dea5668f0016bb852f25e..f2d6c54aa74dc8ab37223ef6599a4346624fd4e0 100644 --- a/crates/feedback/src/feedback_editor.rs +++ b/crates/feedback/src/feedback_editor.rs @@ -249,7 +249,7 @@ impl Entity for FeedbackEditor { } impl Item for FeedbackEditor { - fn tab_tooltip_text<'a>(&'a self, _: &'a AppContext) -> Option> { + fn tab_tooltip_text(&self, _: &AppContext) -> Option> { Some("Send Feedback".into()) } diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index b57561a4cc6fdbea7b35be67f0c1d26c9f82408c..906a0becfdc41e209595f405521f999365d7d4a3 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -226,7 +226,7 @@ impl View for ProjectSearchView { } impl Item for ProjectSearchView { - fn tab_tooltip_text<'a>(&'a self, cx: &'a AppContext) -> Option> { + fn tab_tooltip_text(&self, cx: &AppContext) -> Option> { Some(self.query_editor.read(cx).text(cx).into()) } diff --git a/crates/terminal_view/src/terminal_view.rs b/crates/terminal_view/src/terminal_view.rs index 99f15c126e5428a090a06fc8707c0c6278b45ac3..e420a3d5e08dcf714847c11efc412364b00a4df9 100644 --- a/crates/terminal_view/src/terminal_view.rs +++ b/crates/terminal_view/src/terminal_view.rs @@ -544,7 +544,7 @@ impl View for TerminalView { } impl Item for TerminalView { - fn tab_tooltip_text<'a>(&'a self, cx: &'a AppContext) -> Option> { + fn tab_tooltip_text(&self, cx: &AppContext) -> Option> { Some(self.terminal().read(cx).title().into()) } diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index 114f3eb88ef3b31b96cc4a7a1241d05c16c84668..80e27666f581c000e169cef5cd0b14e64b313cb3 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -198,7 +198,7 @@ impl WelcomePage { } impl Item for WelcomePage { - fn tab_tooltip_text<'a>(&'a self, _: &'a AppContext) -> Option> { + fn tab_tooltip_text(&self, _: &AppContext) -> Option> { Some("Welcome to Zed!".into()) } diff --git a/crates/workspace/src/item.rs b/crates/workspace/src/item.rs index 347a0022cc7bec890631c45d44c7d2f4b52fcbda..4cf47c77132bce0c3d385bd39b500c4430c7b30e 100644 --- a/crates/workspace/src/item.rs +++ b/crates/workspace/src/item.rs @@ -44,7 +44,7 @@ pub trait Item: View { fn navigate(&mut self, _: Box, _: &mut ViewContext) -> bool { false } - fn tab_tooltip_text<'a>(&'a self, _: &'a AppContext) -> Option> { + fn tab_tooltip_text(&self, _: &AppContext) -> Option> { None } fn tab_description<'a>(&'a self, _: usize, _: &'a AppContext) -> Option> { @@ -165,7 +165,7 @@ pub trait ItemHandle: 'static + fmt::Debug { cx: &mut AppContext, handler: Box, ) -> gpui::Subscription; - fn tab_tooltip_text<'a>(&self, cx: &'a AppContext) -> Option>; + fn tab_tooltip_text<'a>(&'a self, cx: &'a AppContext) -> Option>; fn tab_description<'a>(&self, detail: usize, cx: &'a AppContext) -> Option>; fn tab_content(&self, detail: Option, style: &theme::Tab, cx: &AppContext) -> ElementBox; @@ -252,7 +252,7 @@ impl ItemHandle for ViewHandle { }) } - fn tab_tooltip_text<'a>(&self, cx: &'a AppContext) -> Option> { + fn tab_tooltip_text<'a>(&'a self, cx: &'a AppContext) -> Option> { self.read(cx).tab_tooltip_text(cx) } diff --git a/crates/workspace/src/shared_screen.rs b/crates/workspace/src/shared_screen.rs index a1dcb89e44f939f99f3c81090746a4284baaf4da..a397c3a719fdd12b8b69c7612851a34290d34661 100644 --- a/crates/workspace/src/shared_screen.rs +++ b/crates/workspace/src/shared_screen.rs @@ -95,7 +95,7 @@ impl View for SharedScreen { } impl Item for SharedScreen { - fn tab_tooltip_text<'a>(&'a self, _: &'a AppContext) -> Option> { + fn tab_tooltip_text(&self, _: &AppContext) -> Option> { Some(format!("{}'s screen", self.user.github_login).into()) } fn deactivated(&mut self, cx: &mut ViewContext) { From 304eddbbe4a83482fb3b9e4ab37065a50485e5da Mon Sep 17 00:00:00 2001 From: Joseph Lyons Date: Tue, 18 Apr 2023 14:15:56 -0400 Subject: [PATCH 3/3] Remove unnecessary lifetimes from `tab_description` --- crates/editor/src/items.rs | 2 +- crates/workspace/src/item.rs | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index 64147effff086a2721ba5f7b2c99d537ce9942c9..c5e0e8993e439391f5042ae6bf3e66d682267087 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -531,7 +531,7 @@ impl Item for Editor { Some(file_path.into()) } - fn tab_description<'a>(&'a self, detail: usize, cx: &'a AppContext) -> Option> { + fn tab_description<'a>(&'a self, detail: usize, cx: &'a AppContext) -> Option> { match path_for_buffer(&self.buffer, detail, true, cx)? { Cow::Borrowed(path) => Some(path.to_string_lossy()), Cow::Owned(path) => Some(path.to_string_lossy().to_string().into()), diff --git a/crates/workspace/src/item.rs b/crates/workspace/src/item.rs index 4cf47c77132bce0c3d385bd39b500c4430c7b30e..6c41507478a5185a13c97984ed551aadb69ccdd7 100644 --- a/crates/workspace/src/item.rs +++ b/crates/workspace/src/item.rs @@ -47,7 +47,7 @@ pub trait Item: View { fn tab_tooltip_text(&self, _: &AppContext) -> Option> { None } - fn tab_description<'a>(&'a self, _: usize, _: &'a AppContext) -> Option> { + fn tab_description<'a>(&'a self, _: usize, _: &'a AppContext) -> Option> { None } fn tab_content(&self, detail: Option, style: &theme::Tab, cx: &AppContext) @@ -165,8 +165,8 @@ pub trait ItemHandle: 'static + fmt::Debug { cx: &mut AppContext, handler: Box, ) -> gpui::Subscription; - fn tab_tooltip_text<'a>(&'a self, cx: &'a AppContext) -> Option>; - fn tab_description<'a>(&self, detail: usize, cx: &'a AppContext) -> Option>; + fn tab_tooltip_text<'a>(&self, cx: &'a AppContext) -> Option>; + fn tab_description<'a>(&'a self, detail: usize, cx: &'a AppContext) -> Option>; fn tab_content(&self, detail: Option, style: &theme::Tab, cx: &AppContext) -> ElementBox; fn project_path(&self, cx: &AppContext) -> Option; @@ -252,11 +252,11 @@ impl ItemHandle for ViewHandle { }) } - fn tab_tooltip_text<'a>(&'a self, cx: &'a AppContext) -> Option> { + fn tab_tooltip_text<'a>(&self, cx: &'a AppContext) -> Option> { self.read(cx).tab_tooltip_text(cx) } - fn tab_description<'a>(&self, detail: usize, cx: &'a AppContext) -> Option> { + fn tab_description<'a>(&'a self, detail: usize, cx: &'a AppContext) -> Option> { self.read(cx).tab_description(detail, cx) } @@ -913,7 +913,7 @@ pub(crate) mod test { } impl Item for TestItem { - fn tab_description<'a>(&'a self, detail: usize, _: &'a AppContext) -> Option> { + fn tab_description(&self, detail: usize, _: &AppContext) -> Option> { self.tab_descriptions.as_ref().and_then(|descriptions| { let description = *descriptions.get(detail).or_else(|| descriptions.last())?; Some(description.into())