Merge remote-tracking branch 'origin/main' into ownership-post

Nathan Sobo created

Change summary

crates/auto_update/src/auto_update.rs         | 47 +++++++++++---------
crates/auto_update/src/update_notification.rs |  4 +
crates/client/src/telemetry.rs                |  8 +--
crates/copilot/src/copilot.rs                 |  9 +--
crates/feature_flags/src/feature_flags.rs     | 16 ++----
crates/gpui/src/platform.rs                   |  3 
crates/gpui/src/platform/mac/metal_atlas.rs   | 14 ------
crates/gpui/src/platform/mac/text_system.rs   | 12 ++++
crates/gpui/src/platform/test/window.rs       |  6 --
crates/gpui/src/text_system.rs                | 19 ++++---
crates/language/src/language.rs               |  2 
crates/lsp/src/lsp.rs                         | 39 +++++++++--------
crates/project_panel/src/file_associations.rs |  6 +-
crates/search/src/buffer_search.rs            |  6 ++
crates/semantic_index/src/semantic_index.rs   |  7 --
crates/vim/src/mode_indicator.rs              |  5 -
crates/workspace/src/item.rs                  | 10 +---
crates/workspace/src/pane.rs                  |  4 
crates/workspace/src/pane_group.rs            |  3 +
crates/workspace/src/workspace.rs             | 11 +---
crates/zed/src/main.rs                        | 16 ++++---
21 files changed, 119 insertions(+), 128 deletions(-)

Detailed changes

crates/auto_update/src/auto_update.rs 🔗

@@ -93,7 +93,9 @@ pub fn init(http_client: Arc<dyn HttpClient>, server_url: String, cx: &mut AppCo
     cx.observe_new_views(|workspace: &mut Workspace, _cx| {
         workspace.register_action(|_, action: &Check, cx| check(action, cx));
 
-        workspace.register_action(|_, action, cx| view_release_notes(action, cx));
+        workspace.register_action(|_, action, cx| {
+            view_release_notes(action, cx);
+        });
 
         // @nate - code to trigger update notification on launch
         // todo!("remove this when Nate is done")
@@ -140,24 +142,23 @@ pub fn check(_: &Check, cx: &mut WindowContext) {
     }
 }
 
-pub fn view_release_notes(_: &ViewReleaseNotes, cx: &mut AppContext) {
-    if let Some(auto_updater) = AutoUpdater::get(cx) {
+pub fn view_release_notes(_: &ViewReleaseNotes, cx: &mut AppContext) -> Option<()> {
+    let auto_updater = AutoUpdater::get(cx)?;
+    let release_channel = cx.try_global::<ReleaseChannel>()?;
+
+    if matches!(
+        release_channel,
+        ReleaseChannel::Stable | ReleaseChannel::Preview
+    ) {
         let auto_updater = auto_updater.read(cx);
         let server_url = &auto_updater.server_url;
+        let release_channel = release_channel.dev_name();
         let current_version = auto_updater.current_version;
-        if cx.has_global::<ReleaseChannel>() {
-            match cx.global::<ReleaseChannel>() {
-                ReleaseChannel::Dev => {}
-                ReleaseChannel::Nightly => {}
-                ReleaseChannel::Preview => {
-                    cx.open_url(&format!("{server_url}/releases/preview/{current_version}"))
-                }
-                ReleaseChannel::Stable => {
-                    cx.open_url(&format!("{server_url}/releases/stable/{current_version}"))
-                }
-            }
-        }
+        let url = format!("{server_url}/releases/{release_channel}/{current_version}");
+        cx.open_url(&url);
     }
+
+    None
 }
 
 pub fn notify_of_any_new_update(cx: &mut ViewContext<Workspace>) -> Option<()> {
@@ -257,11 +258,13 @@ impl AutoUpdater {
             "{server_url}/api/releases/latest?token={ZED_SECRET_CLIENT_TOKEN}&asset=Zed.dmg"
         );
         cx.update(|cx| {
-            if cx.has_global::<ReleaseChannel>() {
-                if let Some(param) = cx.global::<ReleaseChannel>().release_query_param() {
-                    url_string += "&";
-                    url_string += param;
-                }
+            if let Some(param) = cx
+                .try_global::<ReleaseChannel>()
+                .map(|release_channel| release_channel.release_query_param())
+                .flatten()
+            {
+                url_string += "&";
+                url_string += param;
             }
         })?;
 
@@ -313,8 +316,8 @@ impl AutoUpdater {
         let (installation_id, release_channel, telemetry) = cx.update(|cx| {
             let installation_id = cx.global::<Arc<Client>>().telemetry().installation_id();
             let release_channel = cx
-                .has_global::<ReleaseChannel>()
-                .then(|| cx.global::<ReleaseChannel>().display_name());
+                .try_global::<ReleaseChannel>()
+                .map(|release_channel| release_channel.display_name());
             let telemetry = TelemetrySettings::get_global(cx).metrics;
 
             (installation_id, release_channel, telemetry)

crates/auto_update/src/update_notification.rs 🔗

@@ -40,7 +40,9 @@ impl Render for UpdateNotification {
                     .id("notes")
                     .child(Label::new("View the release notes"))
                     .cursor_pointer()
-                    .on_click(|_, cx| crate::view_release_notes(&Default::default(), cx)),
+                    .on_click(|_, cx| {
+                        crate::view_release_notes(&Default::default(), cx);
+                    }),
             )
     }
 }

crates/client/src/telemetry.rs 🔗

@@ -150,11 +150,9 @@ const FLUSH_INTERVAL: Duration = Duration::from_secs(60 * 5);
 
 impl Telemetry {
     pub fn new(client: Arc<dyn HttpClient>, cx: &mut AppContext) -> Arc<Self> {
-        let release_channel = if cx.has_global::<ReleaseChannel>() {
-            Some(cx.global::<ReleaseChannel>().display_name())
-        } else {
-            None
-        };
+        let release_channel = cx
+            .try_global::<ReleaseChannel>()
+            .map(|release_channel| release_channel.display_name());
 
         TelemetrySettings::register(cx);
 

crates/copilot/src/copilot.rs 🔗

@@ -308,11 +308,7 @@ impl EventEmitter<Event> for Copilot {}
 
 impl Copilot {
     pub fn global(cx: &AppContext) -> Option<Model<Self>> {
-        if cx.has_global::<Model<Self>>() {
-            Some(cx.global::<Model<Self>>().clone())
-        } else {
-            None
-        }
+        cx.try_global::<Model<Self>>().map(|model| model.clone())
     }
 
     fn start(
@@ -373,10 +369,11 @@ impl Copilot {
 
     #[cfg(any(test, feature = "test-support"))]
     pub fn fake(cx: &mut gpui::TestAppContext) -> (Model<Self>, lsp::FakeLanguageServer) {
+        use lsp::FakeLanguageServer;
         use node_runtime::FakeNodeRuntime;
 
         let (server, fake_server) =
-            LanguageServer::fake("copilot".into(), Default::default(), cx.to_async());
+            FakeLanguageServer::new("copilot".into(), Default::default(), cx.to_async());
         let http = util::http::FakeHttpClient::create(|_| async { unreachable!() });
         let node_runtime = FakeNodeRuntime::new();
         let this = cx.new_model(|cx| Self {

crates/feature_flags/src/feature_flags.rs 🔗

@@ -57,18 +57,14 @@ impl FeatureFlagAppExt for AppContext {
     }
 
     fn has_flag<T: FeatureFlag>(&self) -> bool {
-        if self.has_global::<FeatureFlags>() {
-            self.global::<FeatureFlags>().has_flag(T::NAME)
-        } else {
-            false
-        }
+        self.try_global::<FeatureFlags>()
+            .map(|flags| flags.has_flag(T::NAME))
+            .unwrap_or(false)
     }
 
     fn is_staff(&self) -> bool {
-        if self.has_global::<FeatureFlags>() {
-            return self.global::<FeatureFlags>().staff;
-        } else {
-            false
-        }
+        self.try_global::<FeatureFlags>()
+            .map(|flags| flags.staff)
+            .unwrap_or(false)
     }
 }

crates/gpui/src/platform.rs 🔗

@@ -201,6 +201,7 @@ pub trait PlatformDispatcher: Send + Sync {
 pub(crate) trait PlatformTextSystem: Send + Sync {
     fn add_fonts(&self, fonts: &[Arc<Vec<u8>>]) -> Result<()>;
     fn all_font_names(&self) -> Vec<String>;
+    fn all_font_families(&self) -> Vec<String>;
     fn font_id(&self, descriptor: &Font) -> Result<FontId>;
     fn font_metrics(&self, font_id: FontId) -> FontMetrics;
     fn typographic_bounds(&self, font_id: FontId, glyph_id: GlyphId) -> Result<Bounds<f32>>;
@@ -282,8 +283,6 @@ pub(crate) trait PlatformAtlas: Send + Sync {
         key: &AtlasKey,
         build: &mut dyn FnMut() -> Result<(Size<DevicePixels>, Cow<'a, [u8]>)>,
     ) -> Result<AtlasTile>;
-
-    fn clear(&self);
 }
 
 #[derive(Clone, Debug, PartialEq, Eq)]

crates/gpui/src/platform/mac/metal_atlas.rs 🔗

@@ -74,20 +74,6 @@ impl PlatformAtlas for MetalAtlas {
             Ok(tile)
         }
     }
-
-    fn clear(&self) {
-        let mut lock = self.0.lock();
-        lock.tiles_by_key.clear();
-        for texture in &mut lock.monochrome_textures {
-            texture.clear();
-        }
-        for texture in &mut lock.polychrome_textures {
-            texture.clear();
-        }
-        for texture in &mut lock.path_textures {
-            texture.clear();
-        }
-    }
 }
 
 impl MetalAtlasState {

crates/gpui/src/platform/mac/text_system.rs 🔗

@@ -85,7 +85,9 @@ impl PlatformTextSystem for MacTextSystem {
         };
         let mut names = BTreeSet::new();
         for descriptor in descriptors.into_iter() {
-            names.insert(descriptor.display_name());
+            names.insert(descriptor.font_name());
+            names.insert(descriptor.family_name());
+            names.insert(descriptor.style_name());
         }
         if let Ok(fonts_in_memory) = self.0.read().memory_source.all_families() {
             names.extend(fonts_in_memory);
@@ -93,6 +95,14 @@ impl PlatformTextSystem for MacTextSystem {
         names.into_iter().collect()
     }
 
+    fn all_font_families(&self) -> Vec<String> {
+        self.0
+            .read()
+            .system_source
+            .all_families()
+            .expect("core text should never return an error")
+    }
+
     fn font_id(&self, font: &Font) -> Result<FontId> {
         let lock = self.0.upgradable_read();
         if let Some(font_id) = lock.font_selections.get(font) {

crates/gpui/src/platform/test/window.rs 🔗

@@ -325,10 +325,4 @@ impl PlatformAtlas for TestAtlas {
 
         Ok(state.tiles[key].clone())
     }
-
-    fn clear(&self) {
-        let mut state = self.0.lock();
-        state.tiles = HashMap::default();
-        state.next_id = 0;
-    }
 }

crates/gpui/src/text_system.rs 🔗

@@ -13,7 +13,7 @@ use crate::{
     SharedString, Size, UnderlineStyle,
 };
 use anyhow::anyhow;
-use collections::{FxHashMap, FxHashSet};
+use collections::{BTreeSet, FxHashMap, FxHashSet};
 use core::fmt;
 use itertools::Itertools;
 use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard};
@@ -66,15 +66,18 @@ impl TextSystem {
     }
 
     pub fn all_font_names(&self) -> Vec<String> {
-        let mut families = self.platform_text_system.all_font_names();
-        families.append(
-            &mut self
-                .fallback_font_stack
+        let mut names: BTreeSet<_> = self
+            .platform_text_system
+            .all_font_names()
+            .into_iter()
+            .collect();
+        names.extend(self.platform_text_system.all_font_families().into_iter());
+        names.extend(
+            self.fallback_font_stack
                 .iter()
-                .map(|font| font.family.to_string())
-                .collect(),
+                .map(|font| font.family.to_string()),
         );
-        families
+        names.into_iter().collect()
     }
     pub fn add_fonts(&self, fonts: &[Arc<Vec<u8>>]) -> Result<()> {
         self.platform_text_system.add_fonts(fonts)

crates/language/src/language.rs 🔗

@@ -951,7 +951,7 @@ impl LanguageRegistry {
         if language.fake_adapter.is_some() {
             let task = cx.spawn(|cx| async move {
                 let (servers_tx, fake_adapter) = language.fake_adapter.as_ref().unwrap();
-                let (server, mut fake_server) = lsp::LanguageServer::fake(
+                let (server, mut fake_server) = lsp::FakeLanguageServer::new(
                     fake_adapter.name.to_string(),
                     fake_adapter.capabilities.clone(),
                     cx.clone(),

crates/lsp/src/lsp.rs 🔗

@@ -972,30 +972,18 @@ pub struct FakeLanguageServer {
 }
 
 #[cfg(any(test, feature = "test-support"))]
-impl LanguageServer {
-    pub fn full_capabilities() -> ServerCapabilities {
-        ServerCapabilities {
-            document_highlight_provider: Some(OneOf::Left(true)),
-            code_action_provider: Some(CodeActionProviderCapability::Simple(true)),
-            document_formatting_provider: Some(OneOf::Left(true)),
-            document_range_formatting_provider: Some(OneOf::Left(true)),
-            definition_provider: Some(OneOf::Left(true)),
-            type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)),
-            ..Default::default()
-        }
-    }
-
+impl FakeLanguageServer {
     /// Construct a fake language server.
-    pub fn fake(
+    pub fn new(
         name: String,
         capabilities: ServerCapabilities,
         cx: AsyncAppContext,
-    ) -> (Self, FakeLanguageServer) {
+    ) -> (LanguageServer, FakeLanguageServer) {
         let (stdin_writer, stdin_reader) = async_pipe::pipe();
         let (stdout_writer, stdout_reader) = async_pipe::pipe();
         let (notifications_tx, notifications_rx) = channel::unbounded();
 
-        let server = Self::new_internal(
+        let server = LanguageServer::new_internal(
             LanguageServerId(0),
             stdin_writer,
             stdout_reader,
@@ -1008,7 +996,7 @@ impl LanguageServer {
             |_| {},
         );
         let fake = FakeLanguageServer {
-            server: Arc::new(Self::new_internal(
+            server: Arc::new(LanguageServer::new_internal(
                 LanguageServerId(0),
                 stdout_writer,
                 stdin_reader,
@@ -1053,6 +1041,21 @@ impl LanguageServer {
     }
 }
 
+#[cfg(any(test, feature = "test-support"))]
+impl LanguageServer {
+    pub fn full_capabilities() -> ServerCapabilities {
+        ServerCapabilities {
+            document_highlight_provider: Some(OneOf::Left(true)),
+            code_action_provider: Some(CodeActionProviderCapability::Simple(true)),
+            document_formatting_provider: Some(OneOf::Left(true)),
+            document_range_formatting_provider: Some(OneOf::Left(true)),
+            definition_provider: Some(OneOf::Left(true)),
+            type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)),
+            ..Default::default()
+        }
+    }
+}
+
 #[cfg(any(test, feature = "test-support"))]
 impl FakeLanguageServer {
     /// See [`LanguageServer::notify`].
@@ -1188,7 +1191,7 @@ mod tests {
     #[gpui::test]
     async fn test_fake(cx: &mut TestAppContext) {
         let (server, mut fake) =
-            LanguageServer::fake("the-lsp".to_string(), Default::default(), cx.to_async());
+            FakeLanguageServer::new("the-lsp".to_string(), Default::default(), cx.to_async());
 
         let (message_tx, message_rx) = channel::unbounded();
         let (diagnostics_tx, diagnostics_rx) = channel::unbounded();

crates/project_panel/src/file_associations.rs 🔗

@@ -42,7 +42,7 @@ impl FileAssociations {
     }
 
     pub fn get_icon(path: &Path, cx: &AppContext) -> Option<Arc<str>> {
-        let this = cx.has_global::<Self>().then(|| cx.global::<Self>())?;
+        let this = cx.try_global::<Self>()?;
 
         // FIXME: Associate a type with the languages and have the file's language
         //        override these associations
@@ -58,7 +58,7 @@ impl FileAssociations {
     }
 
     pub fn get_folder_icon(expanded: bool, cx: &AppContext) -> Option<Arc<str>> {
-        let this = cx.has_global::<Self>().then(|| cx.global::<Self>())?;
+        let this = cx.try_global::<Self>()?;
 
         let key = if expanded {
             EXPANDED_DIRECTORY_TYPE
@@ -72,7 +72,7 @@ impl FileAssociations {
     }
 
     pub fn get_chevron_icon(expanded: bool, cx: &AppContext) -> Option<Arc<str>> {
-        let this = cx.has_global::<Self>().then(|| cx.global::<Self>())?;
+        let this = cx.try_global::<Self>()?;
 
         let key = if expanded {
             EXPANDED_CHEVRON_TYPE

crates/search/src/buffer_search.rs 🔗

@@ -638,6 +638,12 @@ impl BufferSearchBar {
         registrar.register_handler(|this, _: &editor::actions::Cancel, cx| {
             this.dismiss(&Dismiss, cx);
         });
+
+        // register deploy buffer search for both search bar states, since we want to focus into the search bar
+        // when the deploy action is triggered in the buffer.
+        registrar.register_handler(|this, deploy, cx| {
+            this.deploy(deploy, cx);
+        });
         registrar.register_handler_for_dismissed_search(|this, deploy, cx| {
             this.deploy(deploy, cx);
         })

crates/semantic_index/src/semantic_index.rs 🔗

@@ -275,11 +275,8 @@ pub struct SearchResult {
 
 impl SemanticIndex {
     pub fn global(cx: &mut AppContext) -> Option<Model<SemanticIndex>> {
-        if cx.has_global::<Model<Self>>() {
-            Some(cx.global::<Model<SemanticIndex>>().clone())
-        } else {
-            None
-        }
+        cx.try_global::<Model<Self>>()
+            .map(|semantic_index| semantic_index.clone())
     }
 
     pub fn authenticate(&mut self, cx: &mut AppContext) -> bool {

crates/vim/src/mode_indicator.rs 🔗

@@ -28,11 +28,10 @@ impl ModeIndicator {
 
     fn update_mode(&mut self, cx: &mut ViewContext<Self>) {
         // Vim doesn't exist in some tests
-        if !cx.has_global::<Vim>() {
+        let Some(vim) = cx.try_global::<Vim>() else {
             return;
-        }
+        };
 
-        let vim = Vim::read(cx);
         if vim.enabled {
             self.mode = Some(vim.state().mode);
         } else {

crates/workspace/src/item.rs 🔗

@@ -586,13 +586,9 @@ impl<T: Item> ItemHandle for View<T> {
     }
 
     fn to_followable_item_handle(&self, cx: &AppContext) -> Option<Box<dyn FollowableItemHandle>> {
-        if cx.has_global::<FollowableItemBuilders>() {
-            let builders = cx.global::<FollowableItemBuilders>();
-            let item = self.to_any();
-            Some(builders.get(&item.entity_type())?.1(&item))
-        } else {
-            None
-        }
+        let builders = cx.try_global::<FollowableItemBuilders>()?;
+        let item = self.to_any();
+        Some(builders.get(&item.entity_type())?.1(&item))
     }
 
     fn on_release(

crates/workspace/src/pane.rs 🔗

@@ -195,7 +195,7 @@ struct NavHistoryState {
     next_timestamp: Arc<AtomicUsize>,
 }
 
-#[derive(Copy, Clone)]
+#[derive(Debug, Copy, Clone)]
 pub enum NavigationMode {
     Normal,
     GoingBack,
@@ -1462,7 +1462,7 @@ impl Pane {
                                 .icon_size(IconSize::Small)
                                 .on_click({
                                     let view = cx.view().clone();
-                                    move |_, cx| view.update(cx, Self::navigate_backward)
+                                    move |_, cx| view.update(cx, Self::navigate_forward)
                                 })
                                 .disabled(!self.can_navigate_forward())
                                 .tooltip(|cx| Tooltip::for_action("Go Forward", &GoForward, cx)),

crates/workspace/src/pane_group.rs 🔗

@@ -698,6 +698,7 @@ mod element {
             workspace
                 .update(cx, |this, cx| this.schedule_serialize(cx))
                 .log_err();
+            cx.stop_propagation();
             cx.refresh();
         }
 
@@ -754,8 +755,10 @@ mod element {
                                 workspace
                                     .update(cx, |this, cx| this.schedule_serialize(cx))
                                     .log_err();
+
                                 cx.refresh();
                             }
+                            cx.stop_propagation();
                         }
                     }
                 });

crates/workspace/src/workspace.rs 🔗

@@ -616,8 +616,8 @@ impl Workspace {
         let modal_layer = cx.new_view(|_| ModalLayer::new());
 
         let mut active_call = None;
-        if cx.has_global::<Model<ActiveCall>>() {
-            let call = cx.global::<Model<ActiveCall>>().clone();
+        if let Some(call) = cx.try_global::<Model<ActiveCall>>() {
+            let call = call.clone();
             let mut subscriptions = Vec::new();
             subscriptions.push(cx.subscribe(&call, Self::on_active_call_event));
             active_call = Some((call, subscriptions));
@@ -3686,11 +3686,8 @@ impl WorkspaceStore {
         update: proto::update_followers::Variant,
         cx: &AppContext,
     ) -> Option<()> {
-        if !cx.has_global::<Model<ActiveCall>>() {
-            return None;
-        }
-
-        let room_id = ActiveCall::global(cx).read(cx).room()?.read(cx).id();
+        let active_call = cx.try_global::<Model<ActiveCall>>()?;
+        let room_id = active_call.read(cx).room()?.read(cx).id();
         let follower_ids: Vec<_> = self
             .followers
             .iter()

crates/zed/src/main.rs 🔗

@@ -102,13 +102,15 @@ fn main() {
     let open_listener = listener.clone();
     app.on_open_urls(move |urls, _| open_listener.open_urls(&urls));
     app.on_reopen(move |cx| {
-        if cx.has_global::<Weak<AppState>>() {
-            if let Some(app_state) = cx.global::<Weak<AppState>>().upgrade() {
-                workspace::open_new(&app_state, cx, |workspace, cx| {
-                    Editor::new_file(workspace, &Default::default(), cx)
-                })
-                .detach();
-            }
+        if let Some(app_state) = cx
+            .try_global::<Weak<AppState>>()
+            .map(|app_state| app_state.upgrade())
+            .flatten()
+        {
+            workspace::open_new(&app_state, cx, |workspace, cx| {
+                Editor::new_file(workspace, &Default::default(), cx)
+            })
+            .detach();
         }
     });