Merge branch 'main' into randomized-tests-operation-script

Antonio Scandurra created

Change summary

assets/keymaps/default.json                            |   1 
crates/activity_indicator/src/activity_indicator.rs    |   8 
crates/auto_update/src/auto_update.rs                  |   8 
crates/auto_update/src/update_notification.rs          |   4 
crates/breadcrumbs/src/breadcrumbs.rs                  |   6 
crates/call/src/call.rs                                |   6 
crates/call/src/room.rs                                |  17 
crates/client/src/client.rs                            |   7 
crates/collab_ui/src/collab_titlebar_item.rs           |   7 
crates/collab_ui/src/collab_ui.rs                      |  10 
crates/collab_ui/src/collaborator_list_popover.rs      |   3 
crates/collab_ui/src/contact_finder.rs                 |   6 
crates/collab_ui/src/contact_list.rs                   |   6 
crates/collab_ui/src/contact_notification.rs           |   6 
crates/collab_ui/src/contacts_popover.rs               |   6 
crates/collab_ui/src/incoming_call_notification.rs     |   7 
crates/collab_ui/src/notifications.rs                  |   5 
crates/collab_ui/src/project_shared_notification.rs    |   6 
crates/collab_ui/src/sharing_status_indicator.rs       |   5 
crates/command_palette/src/command_palette.rs          |   4 
crates/context_menu/src/context_menu.rs                |  14 
crates/copilot/src/copilot.rs                          |   7 
crates/copilot/src/sign_in.rs                          |  16 
crates/copilot_button/src/copilot_button.rs            |   9 
crates/db/src/db.rs                                    |   4 
crates/diagnostics/src/diagnostics.rs                  |  11 
crates/diagnostics/src/items.rs                        |   8 
crates/drag_and_drop/src/drag_and_drop.rs              |  10 
crates/editor/src/display_map.rs                       |  22 
crates/editor/src/display_map/block_map.rs             |   6 
crates/editor/src/display_map/fold_map.rs              |  14 
crates/editor/src/display_map/suggestion_map.rs        |   6 
crates/editor/src/display_map/tab_map.rs               |  10 
crates/editor/src/display_map/wrap_map.rs              |   4 
crates/editor/src/editor.rs                            |  45 +
crates/editor/src/editor_tests.rs                      |  70 +-
crates/editor/src/element.rs                           |  13 
crates/editor/src/hover_popover.rs                     |   7 
crates/editor/src/items.rs                             |  12 
crates/editor/src/link_go_to_definition.rs             |  11 
crates/editor/src/mouse_context_menu.rs                |   4 
crates/editor/src/movement.rs                          |  30 
crates/editor/src/multi_buffer.rs                      |  31 
crates/editor/src/scroll.rs                            |   4 
crates/editor/src/scroll/actions.rs                    |   5 
crates/editor/src/selections_collection.rs             |  18 
crates/editor/src/test.rs                              |   2 
crates/feedback/src/deploy_feedback_button.rs          |   6 
crates/feedback/src/feedback.rs                        |   6 
crates/feedback/src/feedback_editor.rs                 |   7 
crates/feedback/src/feedback_info_text.rs              |   4 
crates/feedback/src/submit_feedback_button.rs          |   4 
crates/feedback/src/system_specs.rs                    |   2 
crates/file_finder/src/file_finder.rs                  |   4 
crates/go_to_line/src/go_to_line.rs                    |   8 
crates/gpui/src/app.rs                                 | 338 +++++------
crates/gpui/src/app/callback_collection.rs             |   6 
crates/gpui/src/app/menu.rs                            |   6 
crates/gpui/src/app/test_app_context.rs                |  35 
crates/gpui/src/app/window_input_handler.rs            |  12 
crates/gpui/src/elements/label.rs                      |   2 
crates/gpui/src/elements/list.rs                       |   4 
crates/gpui/src/elements/mouse_event_handler.rs        |   3 
crates/gpui/src/elements/resizable.rs                  |   6 
crates/gpui/src/elements/text.rs                       |   6 
crates/gpui/src/elements/uniform_list.rs               |   3 
crates/gpui/src/executor.rs                            |   4 
crates/gpui/src/gpui.rs                                |   1 
crates/gpui/src/platform/mac/appearance.rs             |   3 
crates/gpui/src/platform/mac/event.rs                  |   8 
crates/gpui/src/platform/mac/fonts.rs                  |   4 
crates/gpui/src/platform/mac/image_cache.rs            |   4 
crates/gpui/src/platform/mac/platform.rs               |  12 
crates/gpui/src/platform/mac/status_item.rs            |  15 
crates/gpui/src/platform/mac/window.rs                 |  16 
crates/gpui/src/platform/test.rs                       |  25 
crates/gpui/src/presenter.rs                           |  39 
crates/gpui/src/scene/mouse_event.rs                   |   9 
crates/gpui/src/scene/mouse_region.rs                  |  20 
crates/gpui/src/test.rs                                |   7 
crates/gpui/src/text_layout.rs                         |   8 
crates/gpui/src/views.rs                               |   2 
crates/gpui/src/views/select.rs                        |  13 
crates/journal/src/journal.rs                          |   6 
crates/language/src/buffer.rs                          |   4 
crates/language/src/buffer_tests.rs                    |  46 
crates/language/src/language.rs                        |  13 
crates/language_selector/src/active_buffer_language.rs |   5 
crates/language_selector/src/language_selector.rs      |   4 
crates/live_kit_client/examples/test_app.rs            |   2 
crates/outline/src/outline.rs                          |   8 
crates/picker/src/picker.rs                            |   8 
crates/project/src/lsp_command.rs                      |  20 
crates/project/src/project.rs                          |  14 
crates/project/src/project_tests.rs                    |   1 
crates/project/src/worktree.rs                         |   9 
crates/project_panel/src/project_panel.rs              |  40 
crates/project_symbols/src/project_symbols.rs          |   4 
crates/recent_projects/src/recent_projects.rs          |   6 
crates/search/src/buffer_search.rs                     |  13 
crates/search/src/project_search.rs                    |  13 
crates/search/src/search.rs                            |   4 
crates/settings/src/keymap_file.rs                     |   8 
crates/settings/src/settings_file.rs                   |   6 
crates/settings/src/watched_json.rs                    |  12 
crates/staff_mode/src/staff_mode.rs                    |  12 
crates/terminal/src/mappings/mouse.rs                  |  22 
crates/terminal/src/terminal.rs                        |   7 
crates/terminal_view/src/terminal_button.rs            |  10 
crates/terminal_view/src/terminal_element.rs           |   9 
crates/terminal_view/src/terminal_view.rs              |   9 
crates/theme/src/theme.rs                              |   7 
crates/theme/src/ui.rs                                 |  16 
crates/theme_selector/src/theme_selector.rs            |  10 
crates/theme_testbench/src/theme_testbench.rs          |   6 
crates/vim/src/editor_events.rs                        |  12 
crates/vim/src/insert.rs                               |   4 
crates/vim/src/motion.rs                               |   6 
crates/vim/src/normal.rs                               |  12 
crates/vim/src/normal/change.rs                        |   6 
crates/vim/src/normal/delete.rs                        |   6 
crates/vim/src/normal/yank.rs                          |   6 
crates/vim/src/object.rs                               |   6 
crates/vim/src/utils.rs                                |   4 
crates/vim/src/vim.rs                                  |  36 
crates/vim/src/visual.rs                               |  17 
crates/welcome/src/base_keymap_picker.rs               |   4 
crates/welcome/src/welcome.rs                          |   6 
crates/workspace/src/dock.rs                           |   8 
crates/workspace/src/dock/toggle_dock_button.rs        |   5 
crates/workspace/src/item.rs                           |  75 +-
crates/workspace/src/notifications.rs                  |  11 
crates/workspace/src/pane.rs                           | 153 +++-
crates/workspace/src/pane/dragged_item_receiver.rs     |   4 
crates/workspace/src/pane_group.rs                     |   3 
crates/workspace/src/persistence.rs                    |   4 
crates/workspace/src/persistence/model.rs              |   2 
crates/workspace/src/searchable.rs                     |  45 
crates/workspace/src/shared_screen.rs                  |   5 
crates/workspace/src/sidebar.rs                        |   4 
crates/workspace/src/status_bar.rs                     |  17 
crates/workspace/src/toolbar.rs                        |  16 
crates/workspace/src/workspace.rs                      |  52 
crates/zed/src/languages/json.rs                       |   4 
crates/zed/src/languages/yaml.rs                       |   7 
crates/zed/src/main.rs                                 |   8 
crates/zed/src/zed.rs                                  |  69 +
styles/src/styleTree/editor.ts                         |   4 
148 files changed, 1,120 insertions(+), 1,028 deletions(-)

Detailed changes

assets/keymaps/default.json šŸ”—

@@ -477,6 +477,7 @@
             "cmd-c": "project_panel::Copy",
             "cmd-v": "project_panel::Paste",
             "cmd-alt-c": "project_panel::CopyPath",
+            "alt-cmd-shift-c": "project_panel::CopyRelativePath",
             "f2": "project_panel::Rename",
             "backspace": "project_panel::Delete",
             "alt-cmd-r": "project_panel::RevealInFinder"

crates/activity_indicator/src/activity_indicator.rs šŸ”—

@@ -2,8 +2,10 @@ use auto_update::{AutoUpdateStatus, AutoUpdater, DismissErrorMessage};
 use editor::Editor;
 use futures::StreamExt;
 use gpui::{
-    actions, elements::*, platform::CursorStyle, Action, AppContext, Entity, ModelHandle,
-    MouseButton, MutableAppContext, RenderContext, View, ViewContext, ViewHandle,
+    actions,
+    elements::*,
+    platform::{CursorStyle, MouseButton},
+    Action, AppContext, Entity, ModelHandle, RenderContext, View, ViewContext, ViewHandle,
 };
 use language::{LanguageRegistry, LanguageServerBinaryStatus};
 use project::{LanguageServerProgress, Project};
@@ -46,7 +48,7 @@ struct Content {
     action: Option<Box<dyn Action>>,
 }
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(ActivityIndicator::show_error_message);
     cx.add_action(ActivityIndicator::dismiss_error_message);
 }

crates/auto_update/src/auto_update.rs šŸ”—

@@ -5,7 +5,7 @@ use client::{ZED_APP_PATH, ZED_APP_VERSION, ZED_SECRET_CLIENT_TOKEN};
 use db::kvp::KEY_VALUE_STORE;
 use gpui::{
     actions, platform::AppVersion, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle,
-    MutableAppContext, Task, WeakViewHandle,
+    Task, WeakViewHandle,
 };
 use serde::Deserialize;
 use settings::Settings;
@@ -49,7 +49,7 @@ impl Entity for AutoUpdater {
     type Event = ();
 }
 
-pub fn init(http_client: Arc<dyn HttpClient>, server_url: String, cx: &mut MutableAppContext) {
+pub fn init(http_client: Arc<dyn HttpClient>, server_url: String, cx: &mut AppContext) {
     if let Some(version) = (*ZED_APP_VERSION).or_else(|| cx.platform().app_version().ok()) {
         let server_url = server_url;
         let auto_updater = cx.add_model(|cx| {
@@ -95,7 +95,7 @@ pub fn init(http_client: Arc<dyn HttpClient>, server_url: String, cx: &mut Mutab
 
 pub fn notify_of_any_new_update(
     workspace: WeakViewHandle<Workspace>,
-    cx: &mut MutableAppContext,
+    cx: &mut AppContext,
 ) -> Option<()> {
     let updater = AutoUpdater::get(cx)?;
     let version = updater.read(cx).current_version;
@@ -124,7 +124,7 @@ pub fn notify_of_any_new_update(
 }
 
 impl AutoUpdater {
-    pub fn get(cx: &mut MutableAppContext) -> Option<ModelHandle<Self>> {
+    pub fn get(cx: &mut AppContext) -> Option<ModelHandle<Self>> {
         cx.default_global::<Option<ModelHandle<Self>>>().clone()
     }
 

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

@@ -1,8 +1,8 @@
 use crate::ViewReleaseNotes;
 use gpui::{
     elements::{Flex, MouseEventHandler, Padding, ParentElement, Svg, Text},
-    platform::{AppVersion, CursorStyle},
-    Element, Entity, MouseButton, View, ViewContext,
+    platform::{AppVersion, CursorStyle, MouseButton},
+    Element, Entity, View, ViewContext,
 };
 use menu::Cancel;
 use settings::Settings;

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

@@ -1,6 +1,6 @@
 use gpui::{
-    elements::*, AppContext, Entity, MouseButton, RenderContext, Subscription, View, ViewContext,
-    ViewHandle,
+    elements::*, platform::MouseButton, AppContext, Entity, RenderContext, Subscription, View,
+    ViewContext, ViewHandle,
 };
 use itertools::Itertools;
 use search::ProjectSearchView;
@@ -136,7 +136,7 @@ impl ToolbarItemView for Breadcrumbs {
         }
     }
 
-    fn pane_focus_update(&mut self, pane_focused: bool, _: &mut gpui::MutableAppContext) {
+    fn pane_focus_update(&mut self, pane_focused: bool, _: &mut gpui::AppContext) {
         self.pane_focused = pane_focused;
     }
 }

crates/call/src/call.rs šŸ”—

@@ -10,15 +10,15 @@ use futures::{future::Shared, FutureExt};
 use postage::watch;
 
 use gpui::{
-    AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext,
-    Subscription, Task, WeakModelHandle,
+    AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, Subscription, Task,
+    WeakModelHandle,
 };
 use project::Project;
 
 pub use participant::ParticipantLocation;
 pub use room::Room;
 
-pub fn init(client: Arc<Client>, user_store: ModelHandle<UserStore>, cx: &mut MutableAppContext) {
+pub fn init(client: Arc<Client>, user_store: ModelHandle<UserStore>, cx: &mut AppContext) {
     let active_call = cx.add_model(|cx| ActiveCall::new(client, user_store, cx));
     cx.set_global(active_call);
 }

crates/call/src/room.rs šŸ”—

@@ -10,9 +10,7 @@ use client::{
 use collections::{BTreeMap, HashMap, HashSet};
 use fs::Fs;
 use futures::{FutureExt, StreamExt};
-use gpui::{
-    AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext, Task, WeakModelHandle,
-};
+use gpui::{AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, Task, WeakModelHandle};
 use language::LanguageRegistry;
 use live_kit_client::{LocalTrackPublication, LocalVideoTrack, RemoteVideoTrackUpdate};
 use postage::stream::Stream;
@@ -64,16 +62,13 @@ pub struct Room {
 impl Entity for Room {
     type Event = Event;
 
-    fn release(&mut self, cx: &mut MutableAppContext) {
+    fn release(&mut self, cx: &mut AppContext) {
         if self.status.is_online() {
             self.leave_internal(cx).detach_and_log_err(cx);
         }
     }
 
-    fn app_will_quit(
-        &mut self,
-        cx: &mut MutableAppContext,
-    ) -> Option<Pin<Box<dyn Future<Output = ()>>>> {
+    fn app_will_quit(&mut self, cx: &mut AppContext) -> Option<Pin<Box<dyn Future<Output = ()>>>> {
         if self.status.is_online() {
             let leave = self.leave_internal(cx);
             Some(
@@ -176,7 +171,7 @@ impl Room {
         initial_project: Option<ModelHandle<Project>>,
         client: Arc<Client>,
         user_store: ModelHandle<UserStore>,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> Task<Result<ModelHandle<Self>>> {
         cx.spawn(|mut cx| async move {
             let response = client.request(proto::CreateRoom {}).await?;
@@ -219,7 +214,7 @@ impl Room {
         call: &IncomingCall,
         client: Arc<Client>,
         user_store: ModelHandle<UserStore>,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> Task<Result<ModelHandle<Self>>> {
         let room_id = call.room_id;
         cx.spawn(|mut cx| async move {
@@ -257,7 +252,7 @@ impl Room {
         self.leave_internal(cx)
     }
 
-    fn leave_internal(&mut self, cx: &mut MutableAppContext) -> Task<Result<()>> {
+    fn leave_internal(&mut self, cx: &mut AppContext) -> Task<Result<()>> {
         if self.status.is_offline() {
             return Task::ready(Err(anyhow!("room is offline")));
         }

crates/client/src/client.rs šŸ”—

@@ -16,9 +16,10 @@ use futures::{
 };
 use gpui::{
     actions,
+    platform::AppVersion,
     serde_json::{self, Value},
-    AnyModelHandle, AnyViewHandle, AnyWeakModelHandle, AnyWeakViewHandle, AppContext, AppVersion,
-    AsyncAppContext, Entity, ModelHandle, MutableAppContext, Task, View, ViewContext, ViewHandle,
+    AnyModelHandle, AnyViewHandle, AnyWeakModelHandle, AnyWeakViewHandle, AppContext,
+    AsyncAppContext, Entity, ModelHandle, Task, View, ViewContext, ViewHandle,
 };
 use lazy_static::lazy_static;
 use parking_lot::RwLock;
@@ -70,7 +71,7 @@ pub const CONNECTION_TIMEOUT: Duration = Duration::from_secs(5);
 
 actions!(client, [SignIn, SignOut]);
 
-pub fn init(client: Arc<Client>, cx: &mut MutableAppContext) {
+pub fn init(client: Arc<Client>, cx: &mut AppContext) {
     cx.add_global_action({
         let client = client.clone();
         move |_: &SignIn, cx| {

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

@@ -15,8 +15,9 @@ use gpui::{
     geometry::{rect::RectF, vector::vec2f, PathBuilder},
     impl_internal_actions,
     json::{self, ToJson},
-    CursorStyle, Entity, ImageData, ModelHandle, MouseButton, MutableAppContext, RenderContext,
-    Subscription, View, ViewContext, ViewHandle, WeakViewHandle,
+    platform::{CursorStyle, MouseButton},
+    AppContext, Entity, ImageData, ModelHandle, RenderContext, Subscription, View, ViewContext,
+    ViewHandle, WeakViewHandle,
 };
 use settings::Settings;
 use std::{ops::Range, sync::Arc};
@@ -40,7 +41,7 @@ impl_internal_actions!(collab, [LeaveCall]);
 #[derive(Copy, Clone, PartialEq)]
 pub(crate) struct LeaveCall;
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(CollabTitlebarItem::toggle_collaborator_list_popover);
     cx.add_action(CollabTitlebarItem::toggle_contacts_popover);
     cx.add_action(CollabTitlebarItem::share_project);

crates/collab_ui/src/collab_ui.rs šŸ”—

@@ -13,13 +13,13 @@ mod sharing_status_indicator;
 use anyhow::anyhow;
 use call::ActiveCall;
 pub use collab_titlebar_item::{CollabTitlebarItem, ToggleContactsMenu};
-use gpui::{actions, MutableAppContext, Task};
+use gpui::{actions, AppContext, Task};
 use std::sync::Arc;
 use workspace::{AppState, JoinProject, ToggleFollow, Workspace};
 
 actions!(collab, [ToggleScreenSharing]);
 
-pub fn init(app_state: Arc<AppState>, cx: &mut MutableAppContext) {
+pub fn init(app_state: Arc<AppState>, cx: &mut AppContext) {
     collab_titlebar_item::init(cx);
     contact_notification::init(cx);
     contact_list::init(cx);
@@ -35,7 +35,7 @@ pub fn init(app_state: Arc<AppState>, cx: &mut MutableAppContext) {
     });
 }
 
-pub fn toggle_screen_sharing(_: &ToggleScreenSharing, cx: &mut MutableAppContext) {
+pub fn toggle_screen_sharing(_: &ToggleScreenSharing, cx: &mut AppContext) {
     if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() {
         let toggle_screen_sharing = room.update(cx, |room, cx| {
             if room.is_screen_sharing() {
@@ -48,13 +48,13 @@ pub fn toggle_screen_sharing(_: &ToggleScreenSharing, cx: &mut MutableAppContext
     }
 }
 
-fn join_project(action: &JoinProject, app_state: Arc<AppState>, cx: &mut MutableAppContext) {
+fn join_project(action: &JoinProject, app_state: Arc<AppState>, cx: &mut AppContext) {
     let project_id = action.project_id;
     let follow_user_id = action.follow_user_id;
     cx.spawn(|mut cx| async move {
         let existing_workspace = cx.update(|cx| {
             cx.window_ids()
-                .filter_map(|window_id| cx.root_view::<Workspace>(window_id))
+                .filter_map(|window_id| cx.root_view(window_id)?.clone().downcast::<Workspace>())
                 .find(|workspace| {
                     workspace.read(cx).project().read(cx).remote_id() == Some(project_id)
                 })

crates/collab_ui/src/collaborator_list_popover.rs šŸ”—

@@ -2,7 +2,8 @@ use call::ActiveCall;
 use client::UserStore;
 use gpui::Action;
 use gpui::{
-    actions, elements::*, Entity, ModelHandle, MouseButton, RenderContext, View, ViewContext,
+    actions, elements::*, platform::MouseButton, Entity, ModelHandle, RenderContext, View,
+    ViewContext,
 };
 use settings::Settings;
 

crates/collab_ui/src/contact_finder.rs šŸ”—

@@ -1,14 +1,14 @@
 use client::{ContactRequestStatus, User, UserStore};
 use gpui::{
-    elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MouseState, MutableAppContext,
-    RenderContext, Task, View, ViewContext, ViewHandle,
+    elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MouseState, RenderContext, Task,
+    View, ViewContext, ViewHandle,
 };
 use picker::{Picker, PickerDelegate};
 use settings::Settings;
 use std::sync::Arc;
 use util::TryFutureExt;
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     Picker::<ContactFinder>::init(cx);
 }
 

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

@@ -10,8 +10,8 @@ use gpui::{
     geometry::{rect::RectF, vector::vec2f},
     impl_actions, impl_internal_actions,
     keymap_matcher::KeymapContext,
-    AppContext, CursorStyle, Entity, ModelHandle, MouseButton, MutableAppContext, PromptLevel,
-    RenderContext, Subscription, View, ViewContext, ViewHandle,
+    platform::{CursorStyle, MouseButton, PromptLevel},
+    AppContext, Entity, ModelHandle, RenderContext, Subscription, View, ViewContext, ViewHandle,
 };
 use menu::{Confirm, SelectNext, SelectPrev};
 use project::Project;
@@ -24,7 +24,7 @@ use workspace::{JoinProject, OpenSharedScreen};
 impl_actions!(contact_list, [RemoveContact, RespondToContactRequest]);
 impl_internal_actions!(contact_list, [ToggleExpanded, Call]);
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(ContactList::remove_contact);
     cx.add_action(ContactList::respond_to_contact_request);
     cx.add_action(ContactList::cancel);

crates/collab_ui/src/contact_notification.rs šŸ”—

@@ -3,14 +3,14 @@ use std::sync::Arc;
 use crate::notifications::render_user_notification;
 use client::{ContactEventKind, User, UserStore};
 use gpui::{
-    elements::*, impl_internal_actions, Entity, ModelHandle, MutableAppContext, RenderContext,
-    View, ViewContext,
+    elements::*, impl_internal_actions, AppContext, Entity, ModelHandle, RenderContext, View,
+    ViewContext,
 };
 use workspace::notifications::Notification;
 
 impl_internal_actions!(contact_notifications, [Dismiss, RespondToContactRequest]);
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(ContactNotification::dismiss);
     cx.add_action(ContactNotification::respond_to_contact_request);
 }

crates/collab_ui/src/contacts_popover.rs šŸ”—

@@ -1,15 +1,15 @@
 use crate::{contact_finder::ContactFinder, contact_list::ContactList, ToggleContactsMenu};
 use client::UserStore;
 use gpui::{
-    actions, elements::*, Entity, ModelHandle, MouseButton, MutableAppContext, RenderContext, View,
-    ViewContext, ViewHandle,
+    actions, elements::*, platform::MouseButton, AppContext, Entity, ModelHandle, RenderContext,
+    View, ViewContext, ViewHandle,
 };
 use project::Project;
 use settings::Settings;
 
 actions!(contacts_popover, [ToggleContactFinder]);
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(ContactsPopover::toggle_contact_finder);
 }
 

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

@@ -4,8 +4,9 @@ use futures::StreamExt;
 use gpui::{
     elements::*,
     geometry::{rect::RectF, vector::vec2f},
-    impl_internal_actions, CursorStyle, Entity, MouseButton, MutableAppContext, RenderContext,
-    View, ViewContext, WindowBounds, WindowKind, WindowOptions,
+    impl_internal_actions,
+    platform::{CursorStyle, MouseButton, WindowBounds, WindowKind, WindowOptions},
+    AppContext, Entity, RenderContext, View, ViewContext,
 };
 use settings::Settings;
 use util::ResultExt;
@@ -13,7 +14,7 @@ use workspace::JoinProject;
 
 impl_internal_actions!(incoming_call_notification, [RespondToCall]);
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(IncomingCallNotification::respond_to_call);
 
     let mut incoming_call = ActiveCall::global(cx).read(cx).incoming();

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

@@ -1,7 +1,8 @@
 use client::User;
 use gpui::{
-    elements::*, platform::CursorStyle, Action, Element, ElementBox, MouseButton, RenderContext,
-    View,
+    elements::*,
+    platform::{CursorStyle, MouseButton},
+    Action, Element, ElementBox, RenderContext, View,
 };
 use settings::Settings;
 use std::sync::Arc;

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

@@ -5,8 +5,8 @@ use gpui::{
     actions,
     elements::*,
     geometry::{rect::RectF, vector::vec2f},
-    CursorStyle, Entity, MouseButton, MutableAppContext, RenderContext, View, ViewContext,
-    WindowBounds, WindowKind, WindowOptions,
+    platform::{CursorStyle, MouseButton, WindowBounds, WindowKind, WindowOptions},
+    AppContext, Entity, RenderContext, View, ViewContext,
 };
 use settings::Settings;
 use std::sync::Arc;
@@ -14,7 +14,7 @@ use workspace::JoinProject;
 
 actions!(project_shared_notification, [DismissProject]);
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(ProjectSharedNotification::join);
     cx.add_action(ProjectSharedNotification::dismiss);
 

crates/collab_ui/src/sharing_status_indicator.rs šŸ”—

@@ -2,13 +2,14 @@ use call::ActiveCall;
 use gpui::{
     color::Color,
     elements::{MouseEventHandler, Svg},
-    Appearance, Element, ElementBox, Entity, MouseButton, MutableAppContext, RenderContext, View,
+    platform::{Appearance, MouseButton},
+    AppContext, Element, ElementBox, Entity, RenderContext, View,
 };
 use settings::Settings;
 
 use crate::ToggleScreenSharing;
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     let active_call = ActiveCall::global(cx);
 
     let mut status_indicator = None;

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

@@ -4,7 +4,7 @@ use gpui::{
     actions,
     elements::{ChildView, Flex, Label, ParentElement},
     keymap_matcher::Keystroke,
-    Action, AnyViewHandle, Element, Entity, MouseState, MutableAppContext, RenderContext, View,
+    Action, AnyViewHandle, AppContext, Element, Entity, MouseState, RenderContext, View,
     ViewContext, ViewHandle,
 };
 use picker::{Picker, PickerDelegate};
@@ -12,7 +12,7 @@ use settings::Settings;
 use std::cmp;
 use workspace::Workspace;
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(CommandPalette::toggle);
     Picker::<CommandPalette>::init(cx);
 }

crates/context_menu/src/context_menu.rs šŸ”—

@@ -1,20 +1,24 @@
 use gpui::{
-    elements::*, geometry::vector::Vector2F, impl_internal_actions, keymap_matcher::KeymapContext,
-    platform::CursorStyle, Action, AnyViewHandle, AppContext, Axis, Entity, MouseButton,
-    MouseState, MutableAppContext, RenderContext, SizeConstraint, Subscription, View, ViewContext,
+    elements::*,
+    geometry::vector::Vector2F,
+    impl_internal_actions,
+    keymap_matcher::KeymapContext,
+    platform::{CursorStyle, MouseButton},
+    Action, AnyViewHandle, AppContext, Axis, Entity, MouseState, RenderContext, SizeConstraint,
+    Subscription, View, ViewContext,
 };
 use menu::*;
 use settings::Settings;
 use std::{any::TypeId, borrow::Cow, time::Duration};
 
-pub type StaticItem = Box<dyn Fn(&mut MutableAppContext) -> ElementBox>;
+pub type StaticItem = Box<dyn Fn(&mut AppContext) -> ElementBox>;
 
 #[derive(Copy, Clone, PartialEq)]
 struct Clicked;
 
 impl_internal_actions!(context_menu, [Clicked]);
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(ContextMenu::select_first);
     cx.add_action(ContextMenu::select_last);
     cx.add_action(ContextMenu::select_next);

crates/copilot/src/copilot.rs šŸ”—

@@ -6,10 +6,7 @@ use async_compression::futures::bufread::GzipDecoder;
 use async_tar::Archive;
 use collections::HashMap;
 use futures::{future::Shared, Future, FutureExt, TryFutureExt};
-use gpui::{
-    actions, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext,
-    Task,
-};
+use gpui::{actions, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, Task};
 use language::{point_from_lsp, point_to_lsp, Anchor, Bias, Buffer, Language, ToPointUtf16};
 use log::{debug, error};
 use lsp::LanguageServer;
@@ -34,7 +31,7 @@ actions!(copilot_auth, [SignIn, SignOut]);
 const COPILOT_NAMESPACE: &'static str = "copilot";
 actions!(copilot, [NextSuggestion, PreviousSuggestion, Reinstall]);
 
-pub fn init(http: Arc<dyn HttpClient>, node_runtime: Arc<NodeRuntime>, cx: &mut MutableAppContext) {
+pub fn init(http: Arc<dyn HttpClient>, node_runtime: Arc<NodeRuntime>, cx: &mut AppContext) {
     // Disable Copilot for stable releases.
     if *cx.global::<ReleaseChannel>() == ReleaseChannel::Stable {
         cx.update_global::<collections::CommandPaletteFilter, _, _>(|filter, _cx| {

crates/copilot/src/sign_in.rs šŸ”—

@@ -1,7 +1,9 @@
 use crate::{request::PromptUserDeviceFlow, Copilot, Status};
 use gpui::{
-    elements::*, geometry::rect::RectF, ClipboardItem, Element, Entity, MutableAppContext, View,
-    ViewContext, ViewHandle, WindowKind, WindowOptions,
+    elements::*,
+    geometry::rect::RectF,
+    platform::{WindowBounds, WindowKind, WindowOptions},
+    AppContext, ClipboardItem, Element, Entity, View, ViewContext, ViewHandle,
 };
 use settings::Settings;
 use theme::ui::modal;
@@ -14,7 +16,7 @@ struct OpenGithub;
 
 const COPILOT_SIGN_UP_URL: &'static str = "https://github.com/features/copilot";
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     let copilot = Copilot::global(cx).unwrap();
 
     let mut code_verification: Option<ViewHandle<CopilotCodeVerification>> = None;
@@ -57,13 +59,13 @@ pub fn init(cx: &mut MutableAppContext) {
 }
 
 fn create_copilot_auth_window(
-    cx: &mut MutableAppContext,
+    cx: &mut AppContext,
     status: &Status,
     code_verification: &mut Option<ViewHandle<CopilotCodeVerification>>,
 ) {
     let window_size = cx.global::<Settings>().theme.copilot.modal.dimensions();
     let window_options = WindowOptions {
-        bounds: gpui::WindowBounds::Fixed(RectF::new(Default::default(), window_size)),
+        bounds: WindowBounds::Fixed(RectF::new(Default::default(), window_size)),
         titlebar: None,
         center: true,
         focus: true,
@@ -128,7 +130,7 @@ impl CopilotCodeVerification {
                 .with_style(device_code_style.cta.style_for(state, false).container)
                 .boxed()
         })
-        .on_click(gpui::MouseButton::Left, {
+        .on_click(gpui::platform::MouseButton::Left, {
             let user_code = data.user_code.clone();
             move |_, cx| {
                 cx.platform()
@@ -136,7 +138,7 @@ impl CopilotCodeVerification {
                 cx.notify();
             }
         })
-        .with_cursor_style(gpui::CursorStyle::PointingHand)
+        .with_cursor_style(gpui::platform::CursorStyle::PointingHand)
         .boxed()
     }
 

crates/copilot_button/src/copilot_button.rs šŸ”—

@@ -3,8 +3,11 @@ use std::sync::Arc;
 use context_menu::{ContextMenu, ContextMenuItem};
 use editor::Editor;
 use gpui::{
-    elements::*, impl_internal_actions, CursorStyle, Element, ElementBox, Entity, MouseButton,
-    MouseState, MutableAppContext, RenderContext, Subscription, View, ViewContext, ViewHandle,
+    elements::*,
+    impl_internal_actions,
+    platform::{CursorStyle, MouseButton},
+    AppContext, Element, ElementBox, Entity, MouseState, RenderContext, Subscription, View,
+    ViewContext, ViewHandle,
 };
 use settings::{settings_file::SettingsFile, Settings};
 use workspace::{
@@ -43,7 +46,7 @@ impl_internal_actions!(
     ]
 );
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(CopilotButton::deploy_copilot_menu);
     cx.add_action(
         |_: &mut CopilotButton, action: &ToggleCopilotForLanguage, cx| {

crates/db/src/db.rs šŸ”—

@@ -4,7 +4,7 @@ pub mod query;
 // Re-export
 pub use anyhow;
 use anyhow::Context;
-use gpui::MutableAppContext;
+use gpui::AppContext;
 pub use indoc::indoc;
 pub use lazy_static;
 use parking_lot::{Mutex, RwLock};
@@ -239,7 +239,7 @@ macro_rules! define_connection {
     };
 }
 
-pub fn write_and_log<F>(cx: &mut MutableAppContext, db_write: impl FnOnce() -> F + Send + 'static)
+pub fn write_and_log<F>(cx: &mut AppContext, db_write: impl FnOnce() -> F + Send + 'static)
 where
     F: Future<Output = anyhow::Result<()>> + Send,
 {

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

@@ -11,8 +11,8 @@ use editor::{
 };
 use gpui::{
     actions, elements::*, fonts::TextStyle, impl_internal_actions, serde_json, AnyViewHandle,
-    AppContext, Entity, ModelHandle, MutableAppContext, RenderContext, Task, View, ViewContext,
-    ViewHandle, WeakViewHandle,
+    AppContext, Entity, ModelHandle, RenderContext, Task, View, ViewContext, ViewHandle,
+    WeakViewHandle,
 };
 use language::{
     Anchor, Bias, Buffer, Diagnostic, DiagnosticEntry, DiagnosticSeverity, Point, Selection,
@@ -41,7 +41,7 @@ impl_internal_actions!(diagnostics, [Jump]);
 
 const CONTEXT_LINE_COUNT: u32 = 1;
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(ProjectDiagnosticsEditor::deploy);
     items::init(cx);
 }
@@ -1176,10 +1176,7 @@ mod tests {
         });
     }
 
-    fn editor_blocks(
-        editor: &ViewHandle<Editor>,
-        cx: &mut MutableAppContext,
-    ) -> Vec<(u32, String)> {
+    fn editor_blocks(editor: &ViewHandle<Editor>, cx: &mut AppContext) -> Vec<(u32, String)> {
         let mut presenter = cx.build_presenter(editor.id(), 0., Default::default());
         let mut cx = presenter.build_layout_context(Default::default(), false, cx);
         cx.render(editor, |editor, cx| {

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

@@ -1,8 +1,10 @@
 use collections::HashSet;
 use editor::{Editor, GoToDiagnostic};
 use gpui::{
-    elements::*, platform::CursorStyle, serde_json, Entity, ModelHandle, MouseButton,
-    MutableAppContext, RenderContext, Subscription, View, ViewContext, ViewHandle, WeakViewHandle,
+    elements::*,
+    platform::{CursorStyle, MouseButton},
+    serde_json, AppContext, Entity, ModelHandle, RenderContext, Subscription, View, ViewContext,
+    ViewHandle, WeakViewHandle,
 };
 use language::Diagnostic;
 use project::Project;
@@ -17,7 +19,7 @@ pub struct DiagnosticIndicator {
     _observe_active_editor: Option<Subscription>,
 }
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(DiagnosticIndicator::go_to_next_diagnostic);
 }
 

crates/drag_and_drop/src/drag_and_drop.rs šŸ”—

@@ -4,9 +4,9 @@ use collections::HashSet;
 use gpui::{
     elements::{Empty, MouseEventHandler, Overlay},
     geometry::{rect::RectF, vector::Vector2F},
+    platform::{CursorStyle, MouseButton},
     scene::{MouseDown, MouseDrag},
-    CursorStyle, Element, ElementBox, EventContext, MouseButton, MutableAppContext, RenderContext,
-    View, WeakViewHandle,
+    AppContext, Element, ElementBox, EventContext, RenderContext, View, WeakViewHandle,
 };
 
 const DEAD_ZONE: f32 = 4.;
@@ -261,7 +261,7 @@ impl<V: View> DragAndDrop<V> {
             })
     }
 
-    pub fn cancel_dragging<P: Any>(&mut self, cx: &mut MutableAppContext) {
+    pub fn cancel_dragging<P: Any>(&mut self, cx: &mut AppContext) {
         if let Some(State::Dragging {
             payload, window_id, ..
         }) = &self.currently_dragged
@@ -274,13 +274,13 @@ impl<V: View> DragAndDrop<V> {
         }
     }
 
-    fn finish_dragging(&mut self, cx: &mut MutableAppContext) {
+    fn finish_dragging(&mut self, cx: &mut AppContext) {
         if let Some(State::Dragging { window_id, .. }) = self.currently_dragged.take() {
             self.notify_containers_for_window(window_id, cx);
         }
     }
 
-    fn notify_containers_for_window(&mut self, window_id: usize, cx: &mut MutableAppContext) {
+    fn notify_containers_for_window(&mut self, window_id: usize, cx: &mut AppContext) {
         self.containers.retain(|container| {
             if let Some(container) = container.upgrade(cx) {
                 if container.window_id() == window_id {

crates/editor/src/display_map.rs šŸ”—

@@ -843,7 +843,7 @@ pub fn next_rows(display_row: u32, display_map: &DisplaySnapshot) -> impl Iterat
 pub mod tests {
     use super::*;
     use crate::{movement, test::marked_display_snapshot};
-    use gpui::{color::Color, elements::*, test::observe, MutableAppContext};
+    use gpui::{color::Color, elements::*, test::observe, AppContext};
     use language::{Buffer, Language, LanguageConfig, SelectionGoal};
     use rand::{prelude::*, Rng};
     use smol::stream::StreamExt;
@@ -1117,7 +1117,7 @@ pub mod tests {
     }
 
     #[gpui::test(retries = 5)]
-    fn test_soft_wraps(cx: &mut MutableAppContext) {
+    fn test_soft_wraps(cx: &mut AppContext) {
         cx.foreground().set_block_on_ticks(usize::MAX..=usize::MAX);
         cx.foreground().forbid_parking();
 
@@ -1210,7 +1210,7 @@ pub mod tests {
     }
 
     #[gpui::test]
-    fn test_text_chunks(cx: &mut gpui::MutableAppContext) {
+    fn test_text_chunks(cx: &mut gpui::AppContext) {
         cx.set_global(Settings::test(cx));
         let text = sample_text(6, 6, 'a');
         let buffer = MultiBuffer::build_simple(&text, cx);
@@ -1509,9 +1509,9 @@ pub mod tests {
     }
 
     #[gpui::test]
-    fn test_clip_point(cx: &mut gpui::MutableAppContext) {
+    fn test_clip_point(cx: &mut gpui::AppContext) {
         cx.set_global(Settings::test(cx));
-        fn assert(text: &str, shift_right: bool, bias: Bias, cx: &mut gpui::MutableAppContext) {
+        fn assert(text: &str, shift_right: bool, bias: Bias, cx: &mut gpui::AppContext) {
             let (unmarked_snapshot, mut markers) = marked_display_snapshot(text, cx);
 
             match bias {
@@ -1558,10 +1558,10 @@ pub mod tests {
     }
 
     #[gpui::test]
-    fn test_clip_at_line_ends(cx: &mut gpui::MutableAppContext) {
+    fn test_clip_at_line_ends(cx: &mut gpui::AppContext) {
         cx.set_global(Settings::test(cx));
 
-        fn assert(text: &str, cx: &mut gpui::MutableAppContext) {
+        fn assert(text: &str, cx: &mut gpui::AppContext) {
             let (mut unmarked_snapshot, markers) = marked_display_snapshot(text, cx);
             unmarked_snapshot.clip_at_line_ends = true;
             assert_eq!(
@@ -1577,7 +1577,7 @@ pub mod tests {
     }
 
     #[gpui::test]
-    fn test_tabs_with_multibyte_chars(cx: &mut gpui::MutableAppContext) {
+    fn test_tabs_with_multibyte_chars(cx: &mut gpui::AppContext) {
         cx.set_global(Settings::test(cx));
         let text = "āœ…\t\tα\nβ\t\nšŸ€Ī²\t\tγ";
         let buffer = MultiBuffer::build_simple(text, cx);
@@ -1638,7 +1638,7 @@ pub mod tests {
     }
 
     #[gpui::test]
-    fn test_max_point(cx: &mut gpui::MutableAppContext) {
+    fn test_max_point(cx: &mut gpui::AppContext) {
         cx.set_global(Settings::test(cx));
         let buffer = MultiBuffer::build_simple("aaa\n\t\tbbb", cx);
         let font_cache = cx.font_cache();
@@ -1687,7 +1687,7 @@ pub mod tests {
         rows: Range<u32>,
         map: &ModelHandle<DisplayMap>,
         theme: &'a SyntaxTheme,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> Vec<(String, Option<Color>)> {
         chunks(rows, map, theme, cx)
             .into_iter()
@@ -1699,7 +1699,7 @@ pub mod tests {
         rows: Range<u32>,
         map: &ModelHandle<DisplayMap>,
         theme: &'a SyntaxTheme,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> Vec<(String, Option<Color>, Option<Color>)> {
         let snapshot = map.update(cx, |map, cx| map.snapshot(cx));
         let mut chunks: Vec<(String, Option<Color>, Option<Color>)> = Vec::new();

crates/editor/src/display_map/block_map.rs šŸ”—

@@ -1015,7 +1015,7 @@ mod tests {
     }
 
     #[gpui::test]
-    fn test_basic_blocks(cx: &mut gpui::MutableAppContext) {
+    fn test_basic_blocks(cx: &mut gpui::AppContext) {
         cx.set_global(Settings::test(cx));
 
         let family_id = cx
@@ -1191,7 +1191,7 @@ mod tests {
     }
 
     #[gpui::test]
-    fn test_blocks_on_wrapped_lines(cx: &mut gpui::MutableAppContext) {
+    fn test_blocks_on_wrapped_lines(cx: &mut gpui::AppContext) {
         cx.set_global(Settings::test(cx));
 
         let family_id = cx
@@ -1241,7 +1241,7 @@ mod tests {
     }
 
     #[gpui::test(iterations = 100)]
-    fn test_random_blocks(cx: &mut gpui::MutableAppContext, mut rng: StdRng) {
+    fn test_random_blocks(cx: &mut gpui::AppContext, mut rng: StdRng) {
         cx.set_global(Settings::test(cx));
 
         let operations = env::var("OPERATIONS")

crates/editor/src/display_map/fold_map.rs šŸ”—

@@ -1214,7 +1214,7 @@ mod tests {
     use Bias::{Left, Right};
 
     #[gpui::test]
-    fn test_basic_folds(cx: &mut gpui::MutableAppContext) {
+    fn test_basic_folds(cx: &mut gpui::AppContext) {
         cx.set_global(Settings::test(cx));
         let buffer = MultiBuffer::build_simple(&sample_text(5, 6, 'a'), cx);
         let subscription = buffer.update(cx, |buffer, _| buffer.subscribe());
@@ -1287,7 +1287,7 @@ mod tests {
     }
 
     #[gpui::test]
-    fn test_adjacent_folds(cx: &mut gpui::MutableAppContext) {
+    fn test_adjacent_folds(cx: &mut gpui::AppContext) {
         cx.set_global(Settings::test(cx));
         let buffer = MultiBuffer::build_simple("abcdefghijkl", cx);
         let subscription = buffer.update(cx, |buffer, _| buffer.subscribe());
@@ -1334,7 +1334,7 @@ mod tests {
     }
 
     #[gpui::test]
-    fn test_overlapping_folds(cx: &mut gpui::MutableAppContext) {
+    fn test_overlapping_folds(cx: &mut gpui::AppContext) {
         let buffer = MultiBuffer::build_simple(&sample_text(5, 6, 'a'), cx);
         let buffer_snapshot = buffer.read(cx).snapshot(cx);
         let mut map = FoldMap::new(buffer_snapshot.clone()).0;
@@ -1350,7 +1350,7 @@ mod tests {
     }
 
     #[gpui::test]
-    fn test_merging_folds_via_edit(cx: &mut gpui::MutableAppContext) {
+    fn test_merging_folds_via_edit(cx: &mut gpui::AppContext) {
         cx.set_global(Settings::test(cx));
         let buffer = MultiBuffer::build_simple(&sample_text(5, 6, 'a'), cx);
         let subscription = buffer.update(cx, |buffer, _| buffer.subscribe());
@@ -1374,7 +1374,7 @@ mod tests {
     }
 
     #[gpui::test]
-    fn test_folds_in_range(cx: &mut gpui::MutableAppContext) {
+    fn test_folds_in_range(cx: &mut gpui::AppContext) {
         let buffer = MultiBuffer::build_simple(&sample_text(5, 6, 'a'), cx);
         let buffer_snapshot = buffer.read(cx).snapshot(cx);
         let mut map = FoldMap::new(buffer_snapshot.clone()).0;
@@ -1401,7 +1401,7 @@ mod tests {
     }
 
     #[gpui::test(iterations = 100)]
-    fn test_random_folds(cx: &mut gpui::MutableAppContext, mut rng: StdRng) {
+    fn test_random_folds(cx: &mut gpui::AppContext, mut rng: StdRng) {
         cx.set_global(Settings::test(cx));
         let operations = env::var("OPERATIONS")
             .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
@@ -1656,7 +1656,7 @@ mod tests {
     }
 
     #[gpui::test]
-    fn test_buffer_rows(cx: &mut gpui::MutableAppContext) {
+    fn test_buffer_rows(cx: &mut gpui::AppContext) {
         let text = sample_text(6, 6, 'a') + "\n";
         let buffer = MultiBuffer::build_simple(&text, cx);
 

crates/editor/src/display_map/suggestion_map.rs šŸ”—

@@ -578,7 +578,7 @@ impl<'a> Iterator for SuggestionBufferRows<'a> {
 mod tests {
     use super::*;
     use crate::{display_map::fold_map::FoldMap, MultiBuffer};
-    use gpui::MutableAppContext;
+    use gpui::AppContext;
     use rand::{prelude::StdRng, Rng};
     use settings::Settings;
     use std::{
@@ -587,7 +587,7 @@ mod tests {
     };
 
     #[gpui::test]
-    fn test_basic(cx: &mut MutableAppContext) {
+    fn test_basic(cx: &mut AppContext) {
         let buffer = MultiBuffer::build_simple("abcdefghi", cx);
         let buffer_edits = buffer.update(cx, |buffer, _| buffer.subscribe());
         let (mut fold_map, fold_snapshot) = FoldMap::new(buffer.read(cx).snapshot(cx));
@@ -632,7 +632,7 @@ mod tests {
     }
 
     #[gpui::test(iterations = 100)]
-    fn test_random_suggestions(cx: &mut MutableAppContext, mut rng: StdRng) {
+    fn test_random_suggestions(cx: &mut AppContext, mut rng: StdRng) {
         cx.set_global(Settings::test(cx));
         let operations = env::var("OPERATIONS")
             .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))

crates/editor/src/display_map/tab_map.rs šŸ”—

@@ -578,7 +578,7 @@ mod tests {
     use rand::{prelude::StdRng, Rng};
 
     #[gpui::test]
-    fn test_expand_tabs(cx: &mut gpui::MutableAppContext) {
+    fn test_expand_tabs(cx: &mut gpui::AppContext) {
         let buffer = MultiBuffer::build_simple("", cx);
         let buffer_snapshot = buffer.read(cx).snapshot(cx);
         let (_, fold_snapshot) = FoldMap::new(buffer_snapshot.clone());
@@ -591,7 +591,7 @@ mod tests {
     }
 
     #[gpui::test]
-    fn test_long_lines(cx: &mut gpui::MutableAppContext) {
+    fn test_long_lines(cx: &mut gpui::AppContext) {
         let max_expansion_column = 12;
         let input = "A\tBC\tDEF\tG\tHI\tJ\tK\tL\tM";
         let output = "A   BC  DEF G   HI J K L M";
@@ -640,9 +640,7 @@ mod tests {
     }
 
     #[gpui::test]
-    fn test_long_lines_with_character_spanning_max_expansion_column(
-        cx: &mut gpui::MutableAppContext,
-    ) {
+    fn test_long_lines_with_character_spanning_max_expansion_column(cx: &mut gpui::AppContext) {
         let max_expansion_column = 8;
         let input = "abcdefg⋯hij";
 
@@ -657,7 +655,7 @@ mod tests {
     }
 
     #[gpui::test(iterations = 100)]
-    fn test_random_tabs(cx: &mut gpui::MutableAppContext, mut rng: StdRng) {
+    fn test_random_tabs(cx: &mut gpui::AppContext, mut rng: StdRng) {
         let tab_size = NonZeroU32::new(rng.gen_range(1..=4)).unwrap();
         let len = rng.gen_range(0..30);
         let buffer = if rng.gen() {

crates/editor/src/display_map/wrap_map.rs šŸ”—

@@ -7,7 +7,7 @@ use crate::MultiBufferSnapshot;
 use gpui::{
     fonts::{FontId, HighlightStyle},
     text_layout::LineWrapper,
-    Entity, ModelContext, ModelHandle, MutableAppContext, Task,
+    AppContext, Entity, ModelContext, ModelHandle, Task,
 };
 use language::{Chunk, Point};
 use lazy_static::lazy_static;
@@ -79,7 +79,7 @@ impl WrapMap {
         font_id: FontId,
         font_size: f32,
         wrap_width: Option<f32>,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> (ModelHandle<Self>, WrapSnapshot) {
         let handle = cx.add_model(|cx| {
             let mut this = Self {

crates/editor/src/editor.rs šŸ”—

@@ -39,11 +39,10 @@ use gpui::{
     geometry::vector::Vector2F,
     impl_actions, impl_internal_actions,
     keymap_matcher::KeymapContext,
-    platform::CursorStyle,
+    platform::{CursorStyle, MouseButton},
     serde_json::{self, json},
     AnyViewHandle, AppContext, AsyncAppContext, ClipboardItem, Element, ElementBox, Entity,
-    ModelHandle, MouseButton, MutableAppContext, RenderContext, Subscription, Task, View,
-    ViewContext, ViewHandle, WeakViewHandle,
+    ModelHandle, RenderContext, Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle,
 };
 use highlight_matching_bracket::refresh_matching_bracket_highlights;
 use hover_popover::{hide_hover, HideHover, HoverState};
@@ -261,6 +260,8 @@ actions!(
         Format,
         ToggleSoftWrap,
         RevealInFinder,
+        CopyPath,
+        CopyRelativePath,
         CopyHighlightJson
     ]
 );
@@ -295,7 +296,7 @@ pub enum Direction {
     Next,
 }
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(Editor::new_file);
     cx.add_action(Editor::select);
     cx.add_action(Editor::cancel);
@@ -381,6 +382,8 @@ pub fn init(cx: &mut MutableAppContext) {
     cx.add_action(Editor::jump);
     cx.add_action(Editor::toggle_soft_wrap);
     cx.add_action(Editor::reveal_in_finder);
+    cx.add_action(Editor::copy_path);
+    cx.add_action(Editor::copy_relative_path);
     cx.add_action(Editor::copy_highlight_json);
     cx.add_async_action(Editor::format);
     cx.add_action(Editor::restart_language_server);
@@ -1314,7 +1317,7 @@ impl Editor {
         self.buffer().read(cx).title(cx)
     }
 
-    pub fn snapshot(&mut self, cx: &mut MutableAppContext) -> EditorSnapshot {
+    pub fn snapshot(&mut self, cx: &mut AppContext) -> EditorSnapshot {
         EditorSnapshot {
             mode: self.mode,
             display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
@@ -6168,13 +6171,13 @@ impl Editor {
         });
     }
 
-    pub fn longest_row(&self, cx: &mut MutableAppContext) -> u32 {
+    pub fn longest_row(&self, cx: &mut AppContext) -> u32 {
         self.display_map
             .update(cx, |map, cx| map.snapshot(cx))
             .longest_row()
     }
 
-    pub fn max_point(&self, cx: &mut MutableAppContext) -> DisplayPoint {
+    pub fn max_point(&self, cx: &mut AppContext) -> DisplayPoint {
         self.display_map
             .update(cx, |map, cx| map.snapshot(cx))
             .max_point()
@@ -6194,7 +6197,7 @@ impl Editor {
         });
     }
 
-    pub fn display_text(&self, cx: &mut MutableAppContext) -> String {
+    pub fn display_text(&self, cx: &mut AppContext) -> String {
         self.display_map
             .update(cx, |map, cx| map.snapshot(cx))
             .text()
@@ -6226,7 +6229,7 @@ impl Editor {
         cx.notify();
     }
 
-    pub fn set_wrap_width(&self, width: Option<f32>, cx: &mut MutableAppContext) -> bool {
+    pub fn set_wrap_width(&self, width: Option<f32>, cx: &mut AppContext) -> bool {
         self.display_map
             .update(cx, |map, cx| map.set_wrap_width(width, cx))
     }
@@ -6252,6 +6255,26 @@ impl Editor {
         }
     }
 
+    pub fn copy_path(&mut self, _: &CopyPath, cx: &mut ViewContext<Self>) {
+        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
+            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
+                if let Some(path) = file.abs_path(cx).to_str() {
+                    cx.write_to_clipboard(ClipboardItem::new(path.to_string()));
+                }
+            }
+        }
+    }
+
+    pub fn copy_relative_path(&mut self, _: &CopyRelativePath, cx: &mut ViewContext<Self>) {
+        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
+            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
+                if let Some(path) = file.path().to_str() {
+                    cx.write_to_clipboard(ClipboardItem::new(path.to_string()));
+                }
+            }
+        }
+    }
+
     pub fn highlight_rows(&mut self, rows: Option<Range<u32>>) {
         self.highlighted_rows = rows;
     }
@@ -6766,7 +6789,7 @@ pub struct EditorReleased(pub WeakViewHandle<Editor>);
 impl Entity for Editor {
     type Event = Event;
 
-    fn release(&mut self, cx: &mut MutableAppContext) {
+    fn release(&mut self, cx: &mut AppContext) {
         cx.emit_global(EditorReleased(self.handle.clone()));
     }
 }
@@ -6842,7 +6865,7 @@ impl View for Editor {
 
     fn modifiers_changed(
         &mut self,
-        event: &gpui::ModifiersChangedEvent,
+        event: &gpui::platform::ModifiersChangedEvent,
         cx: &mut ViewContext<Self>,
     ) -> bool {
         let pending_selection = self.has_pending_selection();

crates/editor/src/editor_tests.rs šŸ”—

@@ -28,7 +28,7 @@ use workspace::{
 };
 
 #[gpui::test]
-fn test_edit_events(cx: &mut MutableAppContext) {
+fn test_edit_events(cx: &mut AppContext) {
     cx.set_global(Settings::test(cx));
     let buffer = cx.add_model(|cx| {
         let mut buffer = language::Buffer::new(0, "123456", cx);
@@ -155,7 +155,7 @@ fn test_edit_events(cx: &mut MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_undo_redo_with_selection_restoration(cx: &mut MutableAppContext) {
+fn test_undo_redo_with_selection_restoration(cx: &mut AppContext) {
     cx.set_global(Settings::test(cx));
     let mut now = Instant::now();
     let buffer = cx.add_model(|cx| language::Buffer::new(0, "123456", cx));
@@ -225,7 +225,7 @@ fn test_undo_redo_with_selection_restoration(cx: &mut MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_ime_composition(cx: &mut MutableAppContext) {
+fn test_ime_composition(cx: &mut AppContext) {
     cx.set_global(Settings::test(cx));
     let buffer = cx.add_model(|cx| {
         let mut buffer = language::Buffer::new(0, "abcde", cx);
@@ -327,7 +327,7 @@ fn test_ime_composition(cx: &mut MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_selection_with_mouse(cx: &mut gpui::MutableAppContext) {
+fn test_selection_with_mouse(cx: &mut gpui::AppContext) {
     cx.set_global(Settings::test(cx));
 
     let buffer = MultiBuffer::build_simple("aaaaaa\nbbbbbb\ncccccc\nddddddd\n", cx);
@@ -392,7 +392,7 @@ fn test_selection_with_mouse(cx: &mut gpui::MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_canceling_pending_selection(cx: &mut gpui::MutableAppContext) {
+fn test_canceling_pending_selection(cx: &mut gpui::AppContext) {
     cx.set_global(Settings::test(cx));
     let buffer = MultiBuffer::build_simple("aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx);
     let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
@@ -424,7 +424,7 @@ fn test_canceling_pending_selection(cx: &mut gpui::MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_clone(cx: &mut gpui::MutableAppContext) {
+fn test_clone(cx: &mut gpui::AppContext) {
     let (text, selection_ranges) = marked_text_ranges(
         indoc! {"
             one
@@ -480,7 +480,7 @@ fn test_clone(cx: &mut gpui::MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_navigation_history(cx: &mut gpui::MutableAppContext) {
+fn test_navigation_history(cx: &mut gpui::AppContext) {
     cx.set_global(Settings::test(cx));
     cx.set_global(DragAndDrop::<Workspace>::default());
     use workspace::item::Item;
@@ -492,7 +492,7 @@ fn test_navigation_history(cx: &mut gpui::MutableAppContext) {
         let handle = cx.handle();
         editor.set_nav_history(Some(pane.read(cx).nav_history_for_item(&handle)));
 
-        fn pop_history(editor: &mut Editor, cx: &mut MutableAppContext) -> Option<NavigationEntry> {
+        fn pop_history(editor: &mut Editor, cx: &mut AppContext) -> Option<NavigationEntry> {
             editor.nav_history.as_mut().unwrap().pop_backward(cx)
         }
 
@@ -590,7 +590,7 @@ fn test_navigation_history(cx: &mut gpui::MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_cancel(cx: &mut gpui::MutableAppContext) {
+fn test_cancel(cx: &mut gpui::AppContext) {
     cx.set_global(Settings::test(cx));
     let buffer = MultiBuffer::build_simple("aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx);
     let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
@@ -630,7 +630,7 @@ fn test_cancel(cx: &mut gpui::MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_fold_action(cx: &mut gpui::MutableAppContext) {
+fn test_fold_action(cx: &mut gpui::AppContext) {
     cx.set_global(Settings::test(cx));
     let buffer = MultiBuffer::build_simple(
         &"
@@ -717,7 +717,7 @@ fn test_fold_action(cx: &mut gpui::MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_move_cursor(cx: &mut gpui::MutableAppContext) {
+fn test_move_cursor(cx: &mut gpui::AppContext) {
     cx.set_global(Settings::test(cx));
     let buffer = MultiBuffer::build_simple(&sample_text(6, 6, 'a'), cx);
     let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx));
@@ -793,7 +793,7 @@ fn test_move_cursor(cx: &mut gpui::MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_move_cursor_multibyte(cx: &mut gpui::MutableAppContext) {
+fn test_move_cursor_multibyte(cx: &mut gpui::AppContext) {
     cx.set_global(Settings::test(cx));
     let buffer = MultiBuffer::build_simple("ⓐⓑⓒⓓⓔ\nabcde\nαβγΓε\n", cx);
     let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx));
@@ -895,7 +895,7 @@ fn test_move_cursor_multibyte(cx: &mut gpui::MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_move_cursor_different_line_lengths(cx: &mut gpui::MutableAppContext) {
+fn test_move_cursor_different_line_lengths(cx: &mut gpui::AppContext) {
     cx.set_global(Settings::test(cx));
     let buffer = MultiBuffer::build_simple("ⓐⓑⓒⓓⓔ\nabcd\nαβγ\nabcd\nⓐⓑⓒⓓⓔ\n", cx);
     let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx));
@@ -942,7 +942,7 @@ fn test_move_cursor_different_line_lengths(cx: &mut gpui::MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_beginning_end_of_line(cx: &mut gpui::MutableAppContext) {
+fn test_beginning_end_of_line(cx: &mut gpui::AppContext) {
     cx.set_global(Settings::test(cx));
     let buffer = MultiBuffer::build_simple("abc\n  def", cx);
     let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
@@ -1102,7 +1102,7 @@ fn test_beginning_end_of_line(cx: &mut gpui::MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_prev_next_word_boundary(cx: &mut gpui::MutableAppContext) {
+fn test_prev_next_word_boundary(cx: &mut gpui::AppContext) {
     cx.set_global(Settings::test(cx));
     let buffer = MultiBuffer::build_simple("use std::str::{foo, bar}\n\n  {baz.qux()}", cx);
     let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
@@ -1151,7 +1151,7 @@ fn test_prev_next_word_boundary(cx: &mut gpui::MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_prev_next_word_bounds_with_soft_wrap(cx: &mut gpui::MutableAppContext) {
+fn test_prev_next_word_bounds_with_soft_wrap(cx: &mut gpui::AppContext) {
     cx.set_global(Settings::test(cx));
     let buffer = MultiBuffer::build_simple("use one::{\n    two::three::four::five\n};", cx);
     let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
@@ -1330,7 +1330,7 @@ async fn test_delete_to_beginning_of_line(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-fn test_delete_to_word_boundary(cx: &mut gpui::MutableAppContext) {
+fn test_delete_to_word_boundary(cx: &mut gpui::AppContext) {
     cx.set_global(Settings::test(cx));
     let buffer = MultiBuffer::build_simple("one two three four", cx);
     let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx));
@@ -1365,7 +1365,7 @@ fn test_delete_to_word_boundary(cx: &mut gpui::MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_newline(cx: &mut gpui::MutableAppContext) {
+fn test_newline(cx: &mut gpui::AppContext) {
     cx.set_global(Settings::test(cx));
     let buffer = MultiBuffer::build_simple("aaaa\n    bbbb\n", cx);
     let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx));
@@ -1385,7 +1385,7 @@ fn test_newline(cx: &mut gpui::MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_newline_with_old_selections(cx: &mut gpui::MutableAppContext) {
+fn test_newline_with_old_selections(cx: &mut gpui::AppContext) {
     cx.set_global(Settings::test(cx));
     let buffer = MultiBuffer::build_simple(
         "
@@ -1517,7 +1517,7 @@ async fn test_newline_below(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-fn test_insert_with_old_selections(cx: &mut gpui::MutableAppContext) {
+fn test_insert_with_old_selections(cx: &mut gpui::AppContext) {
     cx.set_global(Settings::test(cx));
     let buffer = MultiBuffer::build_simple("a( X ), b( Y ), c( Z )", cx);
     let (_, editor) = cx.add_window(Default::default(), |cx| {
@@ -1836,7 +1836,7 @@ async fn test_indent_outdent_with_hard_tabs(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-fn test_indent_outdent_with_excerpts(cx: &mut gpui::MutableAppContext) {
+fn test_indent_outdent_with_excerpts(cx: &mut gpui::AppContext) {
     cx.set_global(
         Settings::test(cx)
             .with_language_defaults(
@@ -2022,7 +2022,7 @@ async fn test_delete(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-fn test_delete_line(cx: &mut gpui::MutableAppContext) {
+fn test_delete_line(cx: &mut gpui::AppContext) {
     cx.set_global(Settings::test(cx));
     let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx);
     let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
@@ -2062,7 +2062,7 @@ fn test_delete_line(cx: &mut gpui::MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_duplicate_line(cx: &mut gpui::MutableAppContext) {
+fn test_duplicate_line(cx: &mut gpui::AppContext) {
     cx.set_global(Settings::test(cx));
     let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx);
     let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
@@ -2110,7 +2110,7 @@ fn test_duplicate_line(cx: &mut gpui::MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_move_line_up_down(cx: &mut gpui::MutableAppContext) {
+fn test_move_line_up_down(cx: &mut gpui::AppContext) {
     cx.set_global(Settings::test(cx));
     let buffer = MultiBuffer::build_simple(&sample_text(10, 5, 'a'), cx);
     let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
@@ -2206,7 +2206,7 @@ fn test_move_line_up_down(cx: &mut gpui::MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_move_line_up_down_with_blocks(cx: &mut gpui::MutableAppContext) {
+fn test_move_line_up_down_with_blocks(cx: &mut gpui::AppContext) {
     cx.set_global(Settings::test(cx));
     let buffer = MultiBuffer::build_simple(&sample_text(10, 5, 'a'), cx);
     let snapshot = buffer.read(cx).snapshot(cx);
@@ -2230,7 +2230,7 @@ fn test_move_line_up_down_with_blocks(cx: &mut gpui::MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_transpose(cx: &mut gpui::MutableAppContext) {
+fn test_transpose(cx: &mut gpui::AppContext) {
     cx.set_global(Settings::test(cx));
 
     _ = cx
@@ -2524,7 +2524,7 @@ async fn test_paste_multiline(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-fn test_select_all(cx: &mut gpui::MutableAppContext) {
+fn test_select_all(cx: &mut gpui::AppContext) {
     cx.set_global(Settings::test(cx));
     let buffer = MultiBuffer::build_simple("abc\nde\nfgh", cx);
     let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
@@ -2538,7 +2538,7 @@ fn test_select_all(cx: &mut gpui::MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_select_line(cx: &mut gpui::MutableAppContext) {
+fn test_select_line(cx: &mut gpui::AppContext) {
     cx.set_global(Settings::test(cx));
     let buffer = MultiBuffer::build_simple(&sample_text(6, 5, 'a'), cx);
     let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
@@ -2582,7 +2582,7 @@ fn test_select_line(cx: &mut gpui::MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_split_selection_into_lines(cx: &mut gpui::MutableAppContext) {
+fn test_split_selection_into_lines(cx: &mut gpui::AppContext) {
     cx.set_global(Settings::test(cx));
     let buffer = MultiBuffer::build_simple(&sample_text(9, 5, 'a'), cx);
     let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
@@ -2650,7 +2650,7 @@ fn test_split_selection_into_lines(cx: &mut gpui::MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_add_selection_above_below(cx: &mut gpui::MutableAppContext) {
+fn test_add_selection_above_below(cx: &mut gpui::AppContext) {
     cx.set_global(Settings::test(cx));
     let buffer = MultiBuffer::build_simple("abc\ndefghi\n\njk\nlmno\n", cx);
     let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
@@ -4928,7 +4928,7 @@ async fn test_toggle_block_comment(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-fn test_editing_disjoint_excerpts(cx: &mut gpui::MutableAppContext) {
+fn test_editing_disjoint_excerpts(cx: &mut gpui::AppContext) {
     cx.set_global(Settings::test(cx));
     let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(3, 4, 'a'), cx));
     let multibuffer = cx.add_model(|cx| {
@@ -4975,7 +4975,7 @@ fn test_editing_disjoint_excerpts(cx: &mut gpui::MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_editing_overlapping_excerpts(cx: &mut gpui::MutableAppContext) {
+fn test_editing_overlapping_excerpts(cx: &mut gpui::AppContext) {
     cx.set_global(Settings::test(cx));
     let markers = vec![('[', ']').into(), ('(', ')').into()];
     let (initial_text, mut excerpt_ranges) = marked_text_ranges_by(
@@ -5048,7 +5048,7 @@ fn test_editing_overlapping_excerpts(cx: &mut gpui::MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_refresh_selections(cx: &mut gpui::MutableAppContext) {
+fn test_refresh_selections(cx: &mut gpui::AppContext) {
     cx.set_global(Settings::test(cx));
     let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(3, 4, 'a'), cx));
     let mut excerpt1_id = None;
@@ -5134,7 +5134,7 @@ fn test_refresh_selections(cx: &mut gpui::MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_refresh_selections_while_selecting_with_mouse(cx: &mut gpui::MutableAppContext) {
+fn test_refresh_selections_while_selecting_with_mouse(cx: &mut gpui::AppContext) {
     cx.set_global(Settings::test(cx));
     let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(3, 4, 'a'), cx));
     let mut excerpt1_id = None;
@@ -5267,7 +5267,7 @@ async fn test_extra_newline_insertion(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-fn test_highlighted_ranges(cx: &mut gpui::MutableAppContext) {
+fn test_highlighted_ranges(cx: &mut gpui::AppContext) {
     let buffer = MultiBuffer::build_simple(&sample_text(16, 8, 'a'), cx);
 
     cx.set_global(Settings::test(cx));

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

@@ -29,11 +29,10 @@ use gpui::{
         PathBuilder,
     },
     json::{self, ToJson},
-    platform::CursorStyle,
+    platform::{CursorStyle, Modifiers, MouseButton, MouseButtonEvent, MouseMovedEvent},
     text_layout::{self, Line, RunStyle, TextLayoutCache},
     AppContext, Axis, Border, CursorRegion, Element, ElementBox, EventContext, LayoutContext,
-    Modifiers, MouseButton, MouseButtonEvent, MouseMovedEvent, MouseRegion, MutableAppContext,
-    PaintContext, Quad, SceneBuilder, SizeConstraint, ViewContext, WeakViewHandle,
+    MouseRegion, PaintContext, Quad, SceneBuilder, SizeConstraint, ViewContext, WeakViewHandle,
 };
 use itertools::Itertools;
 use json::json;
@@ -103,14 +102,14 @@ impl EditorElement {
         self.view.upgrade(cx).unwrap().read(cx)
     }
 
-    fn update_view<F, T>(&self, cx: &mut MutableAppContext, f: F) -> T
+    fn update_view<F, T>(&self, cx: &mut AppContext, f: F) -> T
     where
         F: FnOnce(&mut Editor, &mut ViewContext<Editor>) -> T,
     {
         self.view.upgrade(cx).unwrap().update(cx, f)
     }
 
-    fn snapshot(&self, cx: &mut MutableAppContext) -> EditorSnapshot {
+    fn snapshot(&self, cx: &mut AppContext) -> EditorSnapshot {
         self.update_view(cx, |view, cx| view.snapshot(cx))
     }
 
@@ -2522,7 +2521,7 @@ mod tests {
     use util::test::sample_text;
 
     #[gpui::test]
-    fn test_layout_line_numbers(cx: &mut gpui::MutableAppContext) {
+    fn test_layout_line_numbers(cx: &mut gpui::AppContext) {
         cx.set_global(Settings::test(cx));
         let buffer = MultiBuffer::build_simple(&sample_text(6, 6, 'a'), cx);
         let (window_id, editor) = cx.add_window(Default::default(), |cx| {
@@ -2542,7 +2541,7 @@ mod tests {
     }
 
     #[gpui::test]
-    fn test_layout_with_placeholder_text_and_blocks(cx: &mut gpui::MutableAppContext) {
+    fn test_layout_with_placeholder_text_and_blocks(cx: &mut gpui::AppContext) {
         cx.set_global(Settings::test(cx));
         let buffer = MultiBuffer::build_simple("", cx);
         let (window_id, editor) = cx.add_window(Default::default(), |cx| {

crates/editor/src/hover_popover.rs šŸ”—

@@ -3,9 +3,8 @@ use gpui::{
     actions,
     elements::{Flex, MouseEventHandler, Padding, Text},
     impl_internal_actions,
-    platform::CursorStyle,
-    Axis, Element, ElementBox, ModelHandle, MouseButton, MutableAppContext, RenderContext, Task,
-    ViewContext,
+    platform::{CursorStyle, MouseButton},
+    AppContext, Axis, Element, ElementBox, ModelHandle, RenderContext, Task, ViewContext,
 };
 use language::{Bias, DiagnosticEntry, DiagnosticSeverity};
 use project::{HoverBlock, Project};
@@ -36,7 +35,7 @@ pub struct HideHover;
 actions!(editor, [Hover]);
 impl_internal_actions!(editor, [HoverAt, HideHover]);
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(hover);
     cx.add_action(hover_at);
     cx.add_action(hide_hover);

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

@@ -7,8 +7,8 @@ use anyhow::{anyhow, Context, Result};
 use collections::HashSet;
 use futures::future::try_join_all;
 use gpui::{
-    elements::*, geometry::vector::vec2f, AppContext, Entity, ModelHandle, MutableAppContext,
-    RenderContext, Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle,
+    elements::*, geometry::vector::vec2f, AppContext, Entity, ModelHandle, RenderContext,
+    Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle,
 };
 use language::{
     proto::serialize_anchor as serialize_text_anchor, Bias, Buffer, OffsetRangeExt, Point,
@@ -48,7 +48,7 @@ impl FollowableItem for Editor {
         project: ModelHandle<Project>,
         remote_id: ViewId,
         state: &mut Option<proto::view::Variant>,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> Option<Task<Result<ViewHandle<Self>>>> {
         let Some(proto::view::Variant::Editor(_)) = state else { return None };
         let Some(proto::view::Variant::Editor(state)) = state.take() else { unreachable!() };
@@ -769,7 +769,7 @@ impl Item for Editor {
             buffer: ModelHandle<Buffer>,
             workspace_id: WorkspaceId,
             item_id: ItemId,
-            cx: &mut MutableAppContext,
+            cx: &mut AppContext,
         ) {
             if let Some(file) = buffer.read(cx).file().and_then(|file| file.as_local()) {
                 let path = file.abs_path(cx);
@@ -1161,7 +1161,7 @@ fn path_for_file<'a>(
 #[cfg(test)]
 mod tests {
     use super::*;
-    use gpui::MutableAppContext;
+    use gpui::AppContext;
     use std::{
         path::{Path, PathBuf},
         sync::Arc,
@@ -1169,7 +1169,7 @@ mod tests {
     };
 
     #[gpui::test]
-    fn test_path_for_file(cx: &mut MutableAppContext) {
+    fn test_path_for_file(cx: &mut AppContext) {
         let file = TestFile {
             path: Path::new("").into(),
             full_path: PathBuf::from(""),
@@ -1,6 +1,6 @@
 use std::ops::Range;
 
-use gpui::{impl_internal_actions, MutableAppContext, Task, ViewContext};
+use gpui::{impl_internal_actions, AppContext, Task, ViewContext};
 use language::{Bias, ToOffset};
 use project::LocationLink;
 use settings::Settings;
@@ -38,7 +38,7 @@ impl_internal_actions!(
     ]
 );
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(update_go_to_definition_link);
     cx.add_action(go_to_fetched_definition);
     cx.add_action(go_to_fetched_type_definition);
@@ -358,7 +358,10 @@ fn go_to_fetched_definition_of_kind(
 #[cfg(test)]
 mod tests {
     use futures::StreamExt;
-    use gpui::{Modifiers, ModifiersChangedEvent, View};
+    use gpui::{
+        platform::{self, Modifiers, ModifiersChangedEvent},
+        View,
+    };
     use indoc::indoc;
     use lsp::request::{GotoDefinition, GotoTypeDefinition};
 
@@ -430,7 +433,7 @@ mod tests {
         // Unpress shift causes highlight to go away (normal goto-definition is not valid here)
         cx.update_editor(|editor, cx| {
             editor.modifiers_changed(
-                &gpui::ModifiersChangedEvent {
+                &platform::ModifiersChangedEvent {
                     modifiers: Modifiers {
                         cmd: true,
                         ..Default::default()

crates/editor/src/mouse_context_menu.rs šŸ”—

@@ -1,6 +1,6 @@
 use context_menu::ContextMenuItem;
 use gpui::{
-    elements::AnchorCorner, geometry::vector::Vector2F, impl_internal_actions, MutableAppContext,
+    elements::AnchorCorner, geometry::vector::Vector2F, impl_internal_actions, AppContext,
     ViewContext,
 };
 
@@ -17,7 +17,7 @@ pub struct DeployMouseContextMenu {
 
 impl_internal_actions!(editor, [DeployMouseContextMenu]);
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(deploy_context_menu);
 }
 

crates/editor/src/movement.rs šŸ”—

@@ -372,9 +372,9 @@ mod tests {
     use settings::Settings;
 
     #[gpui::test]
-    fn test_previous_word_start(cx: &mut gpui::MutableAppContext) {
+    fn test_previous_word_start(cx: &mut gpui::AppContext) {
         cx.set_global(Settings::test(cx));
-        fn assert(marked_text: &str, cx: &mut gpui::MutableAppContext) {
+        fn assert(marked_text: &str, cx: &mut gpui::AppContext) {
             let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
             assert_eq!(
                 previous_word_start(&snapshot, display_points[1]),
@@ -399,9 +399,9 @@ mod tests {
     }
 
     #[gpui::test]
-    fn test_previous_subword_start(cx: &mut gpui::MutableAppContext) {
+    fn test_previous_subword_start(cx: &mut gpui::AppContext) {
         cx.set_global(Settings::test(cx));
-        fn assert(marked_text: &str, cx: &mut gpui::MutableAppContext) {
+        fn assert(marked_text: &str, cx: &mut gpui::AppContext) {
             let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
             assert_eq!(
                 previous_subword_start(&snapshot, display_points[1]),
@@ -433,11 +433,11 @@ mod tests {
     }
 
     #[gpui::test]
-    fn test_find_preceding_boundary(cx: &mut gpui::MutableAppContext) {
+    fn test_find_preceding_boundary(cx: &mut gpui::AppContext) {
         cx.set_global(Settings::test(cx));
         fn assert(
             marked_text: &str,
-            cx: &mut gpui::MutableAppContext,
+            cx: &mut gpui::AppContext,
             is_boundary: impl FnMut(char, char) -> bool,
         ) {
             let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
@@ -465,9 +465,9 @@ mod tests {
     }
 
     #[gpui::test]
-    fn test_next_word_end(cx: &mut gpui::MutableAppContext) {
+    fn test_next_word_end(cx: &mut gpui::AppContext) {
         cx.set_global(Settings::test(cx));
-        fn assert(marked_text: &str, cx: &mut gpui::MutableAppContext) {
+        fn assert(marked_text: &str, cx: &mut gpui::AppContext) {
             let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
             assert_eq!(
                 next_word_end(&snapshot, display_points[0]),
@@ -489,9 +489,9 @@ mod tests {
     }
 
     #[gpui::test]
-    fn test_next_subword_end(cx: &mut gpui::MutableAppContext) {
+    fn test_next_subword_end(cx: &mut gpui::AppContext) {
         cx.set_global(Settings::test(cx));
-        fn assert(marked_text: &str, cx: &mut gpui::MutableAppContext) {
+        fn assert(marked_text: &str, cx: &mut gpui::AppContext) {
             let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
             assert_eq!(
                 next_subword_end(&snapshot, display_points[0]),
@@ -522,11 +522,11 @@ mod tests {
     }
 
     #[gpui::test]
-    fn test_find_boundary(cx: &mut gpui::MutableAppContext) {
+    fn test_find_boundary(cx: &mut gpui::AppContext) {
         cx.set_global(Settings::test(cx));
         fn assert(
             marked_text: &str,
-            cx: &mut gpui::MutableAppContext,
+            cx: &mut gpui::AppContext,
             is_boundary: impl FnMut(char, char) -> bool,
         ) {
             let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
@@ -554,9 +554,9 @@ mod tests {
     }
 
     #[gpui::test]
-    fn test_surrounding_word(cx: &mut gpui::MutableAppContext) {
+    fn test_surrounding_word(cx: &mut gpui::AppContext) {
         cx.set_global(Settings::test(cx));
-        fn assert(marked_text: &str, cx: &mut gpui::MutableAppContext) {
+        fn assert(marked_text: &str, cx: &mut gpui::AppContext) {
             let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
             assert_eq!(
                 surrounding_word(&snapshot, display_points[1]),
@@ -575,7 +575,7 @@ mod tests {
     }
 
     #[gpui::test]
-    fn test_move_up_and_down_with_excerpts(cx: &mut gpui::MutableAppContext) {
+    fn test_move_up_and_down_with_excerpts(cx: &mut gpui::AppContext) {
         cx.set_global(Settings::test(cx));
         let family_id = cx
             .font_cache()

crates/editor/src/multi_buffer.rs šŸ”—

@@ -1489,15 +1489,12 @@ impl MultiBuffer {
 
 #[cfg(any(test, feature = "test-support"))]
 impl MultiBuffer {
-    pub fn build_simple(text: &str, cx: &mut gpui::MutableAppContext) -> ModelHandle<Self> {
+    pub fn build_simple(text: &str, cx: &mut gpui::AppContext) -> ModelHandle<Self> {
         let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
         cx.add_model(|cx| Self::singleton(buffer, cx))
     }
 
-    pub fn build_random(
-        rng: &mut impl rand::Rng,
-        cx: &mut gpui::MutableAppContext,
-    ) -> ModelHandle<Self> {
+    pub fn build_random(rng: &mut impl rand::Rng, cx: &mut gpui::AppContext) -> ModelHandle<Self> {
         cx.add_model(|cx| {
             let mut multibuffer = MultiBuffer::new(0);
             let mutation_count = rng.gen_range(1..=5);
@@ -3729,7 +3726,7 @@ where
 mod tests {
     use super::*;
     use futures::StreamExt;
-    use gpui::{MutableAppContext, TestAppContext};
+    use gpui::{AppContext, TestAppContext};
     use language::{Buffer, Rope};
     use rand::prelude::*;
     use settings::Settings;
@@ -3739,7 +3736,7 @@ mod tests {
     use util::test::sample_text;
 
     #[gpui::test]
-    fn test_singleton(cx: &mut MutableAppContext) {
+    fn test_singleton(cx: &mut AppContext) {
         let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx));
         let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
 
@@ -3766,7 +3763,7 @@ mod tests {
     }
 
     #[gpui::test]
-    fn test_remote(cx: &mut MutableAppContext) {
+    fn test_remote(cx: &mut AppContext) {
         let host_buffer = cx.add_model(|cx| Buffer::new(0, "a", cx));
         let guest_buffer = cx.add_model(|cx| {
             let state = host_buffer.read(cx).to_proto();
@@ -3797,7 +3794,7 @@ mod tests {
     }
 
     #[gpui::test]
-    fn test_excerpt_boundaries_and_clipping(cx: &mut MutableAppContext) {
+    fn test_excerpt_boundaries_and_clipping(cx: &mut AppContext) {
         let buffer_1 = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx));
         let buffer_2 = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'g'), cx));
         let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
@@ -4021,7 +4018,7 @@ mod tests {
     }
 
     #[gpui::test]
-    fn test_excerpt_events(cx: &mut MutableAppContext) {
+    fn test_excerpt_events(cx: &mut AppContext) {
         let buffer_1 = cx.add_model(|cx| Buffer::new(0, sample_text(10, 3, 'a'), cx));
         let buffer_2 = cx.add_model(|cx| Buffer::new(0, sample_text(10, 3, 'm'), cx));
 
@@ -4098,7 +4095,7 @@ mod tests {
     }
 
     #[gpui::test]
-    fn test_push_excerpts_with_context_lines(cx: &mut MutableAppContext) {
+    fn test_push_excerpts_with_context_lines(cx: &mut AppContext) {
         let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(20, 3, 'a'), cx));
         let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
         let anchor_ranges = multibuffer.update(cx, |multibuffer, cx| {
@@ -4172,7 +4169,7 @@ mod tests {
     }
 
     #[gpui::test]
-    fn test_empty_multibuffer(cx: &mut MutableAppContext) {
+    fn test_empty_multibuffer(cx: &mut AppContext) {
         let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
 
         let snapshot = multibuffer.read(cx).snapshot(cx);
@@ -4182,7 +4179,7 @@ mod tests {
     }
 
     #[gpui::test]
-    fn test_singleton_multibuffer_anchors(cx: &mut MutableAppContext) {
+    fn test_singleton_multibuffer_anchors(cx: &mut AppContext) {
         let buffer = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
         let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
         let old_snapshot = multibuffer.read(cx).snapshot(cx);
@@ -4202,7 +4199,7 @@ mod tests {
     }
 
     #[gpui::test]
-    fn test_multibuffer_anchors(cx: &mut MutableAppContext) {
+    fn test_multibuffer_anchors(cx: &mut AppContext) {
         let buffer_1 = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
         let buffer_2 = cx.add_model(|cx| Buffer::new(0, "efghi", cx));
         let multibuffer = cx.add_model(|cx| {
@@ -4260,7 +4257,7 @@ mod tests {
     }
 
     #[gpui::test]
-    fn test_resolving_anchors_after_replacing_their_excerpts(cx: &mut MutableAppContext) {
+    fn test_resolving_anchors_after_replacing_their_excerpts(cx: &mut AppContext) {
         let buffer_1 = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
         let buffer_2 = cx.add_model(|cx| Buffer::new(0, "ABCDEFGHIJKLMNOP", cx));
         let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
@@ -4563,7 +4560,7 @@ mod tests {
     }
 
     #[gpui::test(iterations = 100)]
-    fn test_random_multibuffer(cx: &mut MutableAppContext, mut rng: StdRng) {
+    fn test_random_multibuffer(cx: &mut AppContext, mut rng: StdRng) {
         let operations = env::var("OPERATIONS")
             .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
             .unwrap_or(10);
@@ -4980,7 +4977,7 @@ mod tests {
     }
 
     #[gpui::test]
-    fn test_history(cx: &mut MutableAppContext) {
+    fn test_history(cx: &mut AppContext) {
         cx.set_global(Settings::test(cx));
         let buffer_1 = cx.add_model(|cx| Buffer::new(0, "1234", cx));
         let buffer_2 = cx.add_model(|cx| Buffer::new(0, "5678", cx));

crates/editor/src/scroll.rs šŸ”—

@@ -9,7 +9,7 @@ use std::{
 
 use gpui::{
     geometry::vector::{vec2f, Vector2F},
-    Axis, MutableAppContext, Task, ViewContext,
+    AppContext, Axis, Task, ViewContext,
 };
 use language::{Bias, Point};
 use util::ResultExt;
@@ -369,7 +369,7 @@ impl Editor {
     ///     Ordering::Equal => on screen
     ///     Ordering::Less => above the screen
     ///     Ordering::Greater => below the screen
-    pub fn newest_selection_on_screen(&self, cx: &mut MutableAppContext) -> Ordering {
+    pub fn newest_selection_on_screen(&self, cx: &mut AppContext) -> Ordering {
         let snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
         let newest_head = self
             .selections

crates/editor/src/scroll/actions.rs šŸ”—

@@ -1,6 +1,5 @@
 use gpui::{
-    actions, geometry::vector::Vector2F, impl_internal_actions, Axis, MutableAppContext,
-    ViewContext,
+    actions, geometry::vector::Vector2F, impl_internal_actions, AppContext, Axis, ViewContext,
 };
 use language::Bias;
 
@@ -32,7 +31,7 @@ pub struct Scroll {
 
 impl_internal_actions!(editor, [Scroll]);
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(Editor::next_screen);
     cx.add_action(Editor::scroll);
     cx.add_action(Editor::scroll_cursor_top);

crates/editor/src/selections_collection.rs šŸ”—

@@ -6,7 +6,7 @@ use std::{
 };
 
 use collections::HashMap;
-use gpui::{AppContext, ModelHandle, MutableAppContext};
+use gpui::{AppContext, ModelHandle};
 use itertools::Itertools;
 use language::{Bias, Point, Selection, SelectionGoal, TextDimension, ToPoint};
 use util::post_inc;
@@ -53,7 +53,7 @@ impl SelectionsCollection {
         }
     }
 
-    fn display_map(&self, cx: &mut MutableAppContext) -> DisplaySnapshot {
+    fn display_map(&self, cx: &mut AppContext) -> DisplaySnapshot {
         self.display_map.update(cx, |map, cx| map.snapshot(cx))
     }
 
@@ -136,7 +136,7 @@ impl SelectionsCollection {
     }
 
     // Returns all of the selections, adjusted to take into account the selection line_mode
-    pub fn all_adjusted(&self, cx: &mut MutableAppContext) -> Vec<Selection<Point>> {
+    pub fn all_adjusted(&self, cx: &mut AppContext) -> Vec<Selection<Point>> {
         let mut selections = self.all::<Point>(cx);
         if self.line_mode {
             let map = self.display_map(cx);
@@ -151,7 +151,7 @@ impl SelectionsCollection {
 
     pub fn all_adjusted_display(
         &self,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> (DisplaySnapshot, Vec<Selection<DisplayPoint>>) {
         if self.line_mode {
             let selections = self.all::<Point>(cx);
@@ -198,7 +198,7 @@ impl SelectionsCollection {
 
     pub fn all_display(
         &self,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> (DisplaySnapshot, Vec<Selection<DisplayPoint>>) {
         let display_map = self.display_map(cx);
         let selections = self
@@ -224,7 +224,7 @@ impl SelectionsCollection {
         resolve(self.newest_anchor(), &self.buffer(cx))
     }
 
-    pub fn newest_display(&self, cx: &mut MutableAppContext) -> Selection<DisplayPoint> {
+    pub fn newest_display(&self, cx: &mut AppContext) -> Selection<DisplayPoint> {
         let display_map = self.display_map(cx);
         let selection = self
             .newest_anchor()
@@ -279,7 +279,7 @@ impl SelectionsCollection {
     }
 
     #[cfg(any(test, feature = "test-support"))]
-    pub fn display_ranges(&self, cx: &mut MutableAppContext) -> Vec<Range<DisplayPoint>> {
+    pub fn display_ranges(&self, cx: &mut AppContext) -> Vec<Range<DisplayPoint>> {
         let display_map = self.display_map(cx);
         self.disjoint_anchors()
             .iter()
@@ -324,7 +324,7 @@ impl SelectionsCollection {
 
     pub(crate) fn change_with<R>(
         &mut self,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
         change: impl FnOnce(&mut MutableSelectionsCollection) -> R,
     ) -> (bool, R) {
         let mut mutable_collection = MutableSelectionsCollection {
@@ -345,7 +345,7 @@ impl SelectionsCollection {
 pub struct MutableSelectionsCollection<'a> {
     collection: &'a mut SelectionsCollection,
     selections_changed: bool,
-    cx: &'a mut MutableAppContext,
+    cx: &'a mut AppContext,
 }
 
 impl<'a> MutableSelectionsCollection<'a> {

crates/editor/src/test.rs šŸ”—

@@ -21,7 +21,7 @@ fn init_logger() {
 // Returns a snapshot from text containing '|' character markers with the markers removed, and DisplayPoints for each one.
 pub fn marked_display_snapshot(
     text: &str,
-    cx: &mut gpui::MutableAppContext,
+    cx: &mut gpui::AppContext,
 ) -> (DisplaySnapshot, Vec<DisplayPoint>) {
     let (unmarked_text, markers) = marked_text_offsets(text);
 

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

@@ -1,4 +1,8 @@
-use gpui::{elements::*, CursorStyle, Entity, MouseButton, RenderContext, View, ViewContext};
+use gpui::{
+    elements::*,
+    platform::{CursorStyle, MouseButton},
+    Entity, RenderContext, View, ViewContext,
+};
 use settings::Settings;
 use workspace::{item::ItemHandle, StatusItemView};
 

crates/feedback/src/feedback.rs šŸ”—

@@ -6,7 +6,7 @@ pub mod submit_feedback_button;
 use std::sync::Arc;
 
 mod system_specs;
-use gpui::{actions, impl_actions, ClipboardItem, MutableAppContext, PromptLevel, ViewContext};
+use gpui::{actions, impl_actions, platform::PromptLevel, AppContext, ClipboardItem, ViewContext};
 use serde::Deserialize;
 use system_specs::SystemSpecs;
 use workspace::{AppState, Workspace};
@@ -28,7 +28,7 @@ actions!(
     ]
 );
 
-pub fn init(app_state: Arc<AppState>, cx: &mut MutableAppContext) {
+pub fn init(app_state: Arc<AppState>, cx: &mut AppContext) {
     let system_specs = SystemSpecs::new(&cx);
     let system_specs_text = system_specs.to_string();
 
@@ -37,7 +37,7 @@ pub fn init(app_state: Arc<AppState>, cx: &mut MutableAppContext) {
     cx.add_global_action(move |action: &OpenBrowser, cx| cx.platform().open_url(&action.url));
 
     let url = format!(
-        "https://github.com/zed-industries/community/issues/new?assignees=&labels=defect%2Ctriage&template=2_bug_report.yml&environment={}", 
+        "https://github.com/zed-industries/community/issues/new?assignees=&labels=defect%2Ctriage&template=2_bug_report.yml&environment={}",
         urlencoding::encode(&system_specs_text)
     );
 

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

@@ -11,8 +11,9 @@ use futures::AsyncReadExt;
 use gpui::{
     actions,
     elements::{ChildView, Flex, Label, ParentElement, Svg},
-    serde_json, AnyViewHandle, AppContext, Element, ElementBox, Entity, ModelHandle,
-    MutableAppContext, PromptLevel, RenderContext, Task, View, ViewContext, ViewHandle,
+    platform::PromptLevel,
+    serde_json, AnyViewHandle, AppContext, Element, ElementBox, Entity, ModelHandle, RenderContext,
+    Task, View, ViewContext, ViewHandle,
 };
 use isahc::Request;
 use language::Buffer;
@@ -35,7 +36,7 @@ const FEEDBACK_SUBMISSION_ERROR_TEXT: &str =
 
 actions!(feedback, [GiveFeedback, SubmitFeedback]);
 
-pub fn init(system_specs: SystemSpecs, app_state: Arc<AppState>, cx: &mut MutableAppContext) {
+pub fn init(system_specs: SystemSpecs, app_state: Arc<AppState>, cx: &mut AppContext) {
     cx.add_action({
         move |workspace: &mut Workspace, _: &GiveFeedback, cx: &mut ViewContext<Workspace>| {
             FeedbackEditor::deploy(system_specs.clone(), workspace, app_state.clone(), cx);

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

@@ -1,7 +1,7 @@
 use gpui::{
     elements::{Flex, Label, MouseEventHandler, ParentElement, Text},
-    CursorStyle, Element, ElementBox, Entity, MouseButton, RenderContext, View, ViewContext,
-    ViewHandle,
+    platform::{CursorStyle, MouseButton},
+    Element, ElementBox, Entity, RenderContext, View, ViewContext, ViewHandle,
 };
 use settings::Settings;
 use workspace::{item::ItemHandle, ToolbarItemLocation, ToolbarItemView};

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

@@ -1,7 +1,7 @@
 use gpui::{
     elements::{Label, MouseEventHandler},
-    CursorStyle, Element, ElementBox, Entity, MouseButton, RenderContext, View, ViewContext,
-    ViewHandle,
+    platform::{CursorStyle, MouseButton},
+    Element, ElementBox, Entity, RenderContext, View, ViewContext, ViewHandle,
 };
 use settings::Settings;
 use workspace::{item::ItemHandle, ToolbarItemLocation, ToolbarItemView};

crates/feedback/src/system_specs.rs šŸ”—

@@ -1,5 +1,5 @@
 use client::ZED_APP_VERSION;
-use gpui::{AppContext, AppVersion};
+use gpui::{platform::AppVersion, AppContext};
 use human_bytes::human_bytes;
 use serde::Serialize;
 use std::{env, fmt::Display};

crates/file_finder/src/file_finder.rs šŸ”—

@@ -1,7 +1,7 @@
 use fuzzy::PathMatch;
 use gpui::{
     actions, elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MouseState,
-    MutableAppContext, RenderContext, Task, View, ViewContext, ViewHandle,
+    RenderContext, Task, View, ViewContext, ViewHandle,
 };
 use picker::{Picker, PickerDelegate};
 use project::{PathMatchCandidateSet, Project, ProjectPath, WorktreeId};
@@ -31,7 +31,7 @@ pub struct FileFinder {
 
 actions!(file_finder, [Toggle]);
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(FileFinder::toggle);
     Picker::<FileFinder>::init(cx);
 }

crates/go_to_line/src/go_to_line.rs šŸ”—

@@ -2,8 +2,8 @@ use std::sync::Arc;
 
 use editor::{display_map::ToDisplayPoint, scroll::autoscroll::Autoscroll, DisplayPoint, Editor};
 use gpui::{
-    actions, elements::*, geometry::vector::Vector2F, AnyViewHandle, Axis, Entity,
-    MutableAppContext, RenderContext, View, ViewContext, ViewHandle,
+    actions, elements::*, geometry::vector::Vector2F, AnyViewHandle, AppContext, Axis, Entity,
+    RenderContext, View, ViewContext, ViewHandle,
 };
 use menu::{Cancel, Confirm};
 use settings::Settings;
@@ -12,7 +12,7 @@ use workspace::Workspace;
 
 actions!(go_to_line, [Toggle]);
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(GoToLine::toggle);
     cx.add_action(GoToLine::confirm);
     cx.add_action(GoToLine::cancel);
@@ -140,7 +140,7 @@ impl GoToLine {
 impl Entity for GoToLine {
     type Event = Event;
 
-    fn release(&mut self, cx: &mut MutableAppContext) {
+    fn release(&mut self, cx: &mut AppContext) {
         let scroll_position = self.prev_scroll_position.take();
         self.active_editor.update(cx, |editor, cx| {
             editor.highlight_rows(None);

crates/gpui/src/app.rs šŸ”—

@@ -44,12 +44,13 @@ use crate::{
     elements::ElementBox,
     executor::{self, Task},
     keymap_matcher::{self, Binding, KeymapContext, KeymapMatcher, Keystroke, MatchResult},
-    platform::{self, KeyDownEvent, Platform, PromptLevel, WindowOptions},
+    platform::{
+        self, Appearance, KeyDownEvent, KeyUpEvent, ModifiersChangedEvent, MouseButton,
+        PathPromptOptions, Platform, PromptLevel, WindowBounds, WindowOptions,
+    },
     presenter::Presenter,
     util::post_inc,
-    Appearance, AssetCache, AssetSource, ClipboardItem, FontCache, KeyUpEvent,
-    ModifiersChangedEvent, MouseButton, MouseRegionId, PathPromptOptions, TextLayoutCache,
-    WindowBounds,
+    AssetCache, AssetSource, ClipboardItem, FontCache, MouseRegionId, TextLayoutCache,
 };
 
 use self::ref_counts::RefCounts;
@@ -57,10 +58,10 @@ use self::ref_counts::RefCounts;
 pub trait Entity: 'static {
     type Event;
 
-    fn release(&mut self, _: &mut MutableAppContext) {}
+    fn release(&mut self, _: &mut AppContext) {}
     fn app_will_quit(
         &mut self,
-        _: &mut MutableAppContext,
+        _: &mut AppContext,
     ) -> Option<Pin<Box<dyn 'static + Future<Output = ()>>>> {
         None
     }
@@ -182,17 +183,17 @@ pub trait UpdateView {
 }
 
 #[derive(Clone)]
-pub struct App(Rc<RefCell<MutableAppContext>>);
+pub struct App(Rc<RefCell<AppContext>>);
 
 #[derive(Clone)]
-pub struct AsyncAppContext(Rc<RefCell<MutableAppContext>>);
+pub struct AsyncAppContext(Rc<RefCell<AppContext>>);
 
 impl App {
     pub fn new(asset_source: impl AssetSource) -> Result<Self> {
         let platform = platform::current::platform();
         let foreground = Rc::new(executor::Foreground::platform(platform.dispatcher())?);
         let foreground_platform = platform::current::foreground_platform(foreground.clone());
-        let app = Self(Rc::new(RefCell::new(MutableAppContext::new(
+        let app = Self(Rc::new(RefCell::new(AppContext::new(
             foreground,
             Arc::new(executor::Background::new()),
             platform.clone(),
@@ -220,7 +221,7 @@ impl App {
 
     pub fn on_become_active<F>(self, mut callback: F) -> Self
     where
-        F: 'static + FnMut(&mut MutableAppContext),
+        F: 'static + FnMut(&mut AppContext),
     {
         let cx = self.0.clone();
         self.0
@@ -232,7 +233,7 @@ impl App {
 
     pub fn on_resign_active<F>(self, mut callback: F) -> Self
     where
-        F: 'static + FnMut(&mut MutableAppContext),
+        F: 'static + FnMut(&mut AppContext),
     {
         let cx = self.0.clone();
         self.0
@@ -244,7 +245,7 @@ impl App {
 
     pub fn on_quit<F>(&mut self, mut callback: F) -> &mut Self
     where
-        F: 'static + FnMut(&mut MutableAppContext),
+        F: 'static + FnMut(&mut AppContext),
     {
         let cx = self.0.clone();
         self.0
@@ -257,7 +258,7 @@ impl App {
     /// Handle the application being re-activated when no windows are open.
     pub fn on_reopen<F>(&mut self, mut callback: F) -> &mut Self
     where
-        F: 'static + FnMut(&mut MutableAppContext),
+        F: 'static + FnMut(&mut AppContext),
     {
         let cx = self.0.clone();
         self.0
@@ -269,7 +270,7 @@ impl App {
 
     pub fn on_event<F>(&mut self, mut callback: F) -> &mut Self
     where
-        F: 'static + FnMut(Event, &mut MutableAppContext) -> bool,
+        F: 'static + FnMut(Event, &mut AppContext) -> bool,
     {
         let cx = self.0.clone();
         self.0
@@ -283,7 +284,7 @@ impl App {
 
     pub fn on_open_urls<F>(&mut self, mut callback: F) -> &mut Self
     where
-        F: 'static + FnMut(Vec<String>, &mut MutableAppContext),
+        F: 'static + FnMut(Vec<String>, &mut AppContext),
     {
         let cx = self.0.clone();
         self.0
@@ -295,7 +296,7 @@ impl App {
 
     pub fn run<F>(self, on_finish_launching: F)
     where
-        F: 'static + FnOnce(&mut MutableAppContext),
+        F: 'static + FnOnce(&mut AppContext),
     {
         let platform = self.0.borrow().foreground_platform.clone();
         platform.run(Box::new(move || {
@@ -307,14 +308,14 @@ impl App {
     }
 
     pub fn platform(&self) -> Arc<dyn Platform> {
-        self.0.borrow().platform()
+        self.0.borrow().platform.clone()
     }
 
     pub fn font_cache(&self) -> Arc<FontCache> {
-        self.0.borrow().cx.font_cache.clone()
+        self.0.borrow().font_cache.clone()
     }
 
-    fn update<T, F: FnOnce(&mut MutableAppContext) -> T>(&mut self, callback: F) -> T {
+    fn update<T, F: FnOnce(&mut AppContext) -> T>(&mut self, callback: F) -> T {
         let mut state = self.0.borrow_mut();
         let result = state.update(callback);
         state.pending_notifications.clear();
@@ -333,10 +334,10 @@ impl AsyncAppContext {
     }
 
     pub fn read<T, F: FnOnce(&AppContext) -> T>(&self, callback: F) -> T {
-        callback(self.0.borrow().as_ref())
+        callback(&*self.0.borrow())
     }
 
-    pub fn update<T, F: FnOnce(&mut MutableAppContext) -> T>(&mut self, callback: F) -> T {
+    pub fn update<T, F: FnOnce(&mut AppContext) -> T>(&mut self, callback: F) -> T {
         self.0.borrow_mut().update(callback)
     }
 
@@ -379,7 +380,7 @@ impl AsyncAppContext {
     }
 
     pub fn platform(&self) -> Arc<dyn Platform> {
-        self.0.borrow().platform()
+        self.0.borrow().platform().clone()
     }
 
     pub fn foreground(&self) -> Rc<executor::Foreground> {
@@ -387,7 +388,7 @@ impl AsyncAppContext {
     }
 
     pub fn background(&self) -> Arc<executor::Background> {
-        self.0.borrow().cx.background.clone()
+        self.0.borrow().background.clone()
     }
 }
 
@@ -435,7 +436,7 @@ impl ReadModelWith for AsyncAppContext {
         read: &mut dyn FnMut(&E, &AppContext) -> T,
     ) -> T {
         let cx = self.0.borrow();
-        let cx = cx.as_ref();
+        let cx = &*cx;
         read(handle.read(cx), cx)
     }
 }
@@ -463,37 +464,45 @@ impl ReadViewWith for AsyncAppContext {
         V: View,
     {
         let cx = self.0.borrow();
-        let cx = cx.as_ref();
+        let cx = &*cx;
         read(handle.read(cx), cx)
     }
 }
 
-type ActionCallback =
-    dyn FnMut(&mut dyn AnyView, &dyn Action, &mut MutableAppContext, usize, usize);
-type GlobalActionCallback = dyn FnMut(&dyn Action, &mut MutableAppContext);
-
-type SubscriptionCallback = Box<dyn FnMut(&dyn Any, &mut MutableAppContext) -> bool>;
-type GlobalSubscriptionCallback = Box<dyn FnMut(&dyn Any, &mut MutableAppContext)>;
-type ObservationCallback = Box<dyn FnMut(&mut MutableAppContext) -> bool>;
-type GlobalObservationCallback = Box<dyn FnMut(&mut MutableAppContext)>;
-type FocusObservationCallback = Box<dyn FnMut(bool, &mut MutableAppContext) -> bool>;
-type ReleaseObservationCallback = Box<dyn FnMut(&dyn Any, &mut MutableAppContext)>;
-type ActionObservationCallback = Box<dyn FnMut(TypeId, &mut MutableAppContext)>;
-type WindowActivationCallback = Box<dyn FnMut(bool, &mut MutableAppContext) -> bool>;
-type WindowFullscreenCallback = Box<dyn FnMut(bool, &mut MutableAppContext) -> bool>;
-type WindowBoundsCallback = Box<dyn FnMut(WindowBounds, Uuid, &mut MutableAppContext) -> bool>;
-type KeystrokeCallback = Box<
-    dyn FnMut(&Keystroke, &MatchResult, Option<&Box<dyn Action>>, &mut MutableAppContext) -> bool,
->;
-type ActiveLabeledTasksCallback = Box<dyn FnMut(&mut MutableAppContext) -> bool>;
+type ActionCallback = dyn FnMut(&mut dyn AnyView, &dyn Action, &mut AppContext, usize, usize);
+type GlobalActionCallback = dyn FnMut(&dyn Action, &mut AppContext);
+
+type SubscriptionCallback = Box<dyn FnMut(&dyn Any, &mut AppContext) -> bool>;
+type GlobalSubscriptionCallback = Box<dyn FnMut(&dyn Any, &mut AppContext)>;
+type ObservationCallback = Box<dyn FnMut(&mut AppContext) -> bool>;
+type GlobalObservationCallback = Box<dyn FnMut(&mut AppContext)>;
+type FocusObservationCallback = Box<dyn FnMut(bool, &mut AppContext) -> bool>;
+type ReleaseObservationCallback = Box<dyn FnMut(&dyn Any, &mut AppContext)>;
+type ActionObservationCallback = Box<dyn FnMut(TypeId, &mut AppContext)>;
+type WindowActivationCallback = Box<dyn FnMut(bool, &mut AppContext) -> bool>;
+type WindowFullscreenCallback = Box<dyn FnMut(bool, &mut AppContext) -> bool>;
+type WindowBoundsCallback = Box<dyn FnMut(WindowBounds, Uuid, &mut AppContext) -> bool>;
+type KeystrokeCallback =
+    Box<dyn FnMut(&Keystroke, &MatchResult, Option<&Box<dyn Action>>, &mut AppContext) -> bool>;
+type ActiveLabeledTasksCallback = Box<dyn FnMut(&mut AppContext) -> bool>;
 type DeserializeActionCallback = fn(json: &str) -> anyhow::Result<Box<dyn Action>>;
-type WindowShouldCloseSubscriptionCallback = Box<dyn FnMut(&mut MutableAppContext) -> bool>;
+type WindowShouldCloseSubscriptionCallback = Box<dyn FnMut(&mut AppContext) -> bool>;
+
+pub struct AppContext {
+    models: HashMap<usize, Box<dyn AnyModel>>,
+    views: HashMap<(usize, usize), Box<dyn AnyView>>,
+    pub(crate) parents: HashMap<(usize, usize), ParentId>,
+    windows: HashMap<usize, Window>,
+    globals: HashMap<TypeId, Box<dyn Any>>,
+    element_states: HashMap<ElementStateId, Box<dyn Any>>,
+    background: Arc<executor::Background>,
+    ref_counts: Arc<Mutex<RefCounts>>,
+    font_cache: Arc<FontCache>,
+    platform: Arc<dyn Platform>,
 
-pub struct MutableAppContext {
     weak_self: Option<rc::Weak<RefCell<Self>>>,
     foreground_platform: Rc<dyn platform::ForegroundPlatform>,
     assets: Arc<AssetCache>,
-    cx: AppContext,
     action_deserializers: HashMap<&'static str, (TypeId, DeserializeActionCallback)>,
     capture_actions: HashMap<TypeId, HashMap<TypeId, Vec<Box<ActionCallback>>>>,
     // Entity Types -> { Action Types -> Action Handlers }
@@ -533,7 +542,7 @@ pub struct MutableAppContext {
     active_labeled_tasks: BTreeMap<usize, &'static str>,
 }
 
-impl MutableAppContext {
+impl AppContext {
     fn new(
         foreground: Rc<executor::Foreground>,
         background: Arc<executor::Background>,
@@ -544,21 +553,20 @@ impl MutableAppContext {
         asset_source: impl AssetSource,
     ) -> Self {
         Self {
+            models: Default::default(),
+            views: Default::default(),
+            parents: Default::default(),
+            windows: Default::default(),
+            globals: Default::default(),
+            element_states: Default::default(),
+            ref_counts: Arc::new(Mutex::new(ref_counts)),
+            background,
+            font_cache,
+            platform,
+
             weak_self: None,
             foreground_platform,
             assets: Arc::new(AssetCache::new(asset_source)),
-            cx: AppContext {
-                models: Default::default(),
-                views: Default::default(),
-                parents: Default::default(),
-                windows: Default::default(),
-                globals: Default::default(),
-                element_states: Default::default(),
-                ref_counts: Arc::new(Mutex::new(ref_counts)),
-                background,
-                font_cache,
-                platform,
-            },
             action_deserializers: Default::default(),
             capture_actions: Default::default(),
             actions: Default::default(),
@@ -602,15 +610,15 @@ impl MutableAppContext {
 
         self.update(|cx| {
             for model_id in cx.models.keys().copied().collect::<Vec<_>>() {
-                let mut model = cx.cx.models.remove(&model_id).unwrap();
+                let mut model = cx.models.remove(&model_id).unwrap();
                 futures.extend(model.app_will_quit(cx));
-                cx.cx.models.insert(model_id, model);
+                cx.models.insert(model_id, model);
             }
 
             for view_id in cx.views.keys().copied().collect::<Vec<_>>() {
-                let mut view = cx.cx.views.remove(&view_id).unwrap();
+                let mut view = cx.views.remove(&view_id).unwrap();
                 futures.extend(view.app_will_quit(cx));
-                cx.cx.views.insert(view_id, view);
+                cx.views.insert(view_id, view);
             }
         });
 
@@ -627,28 +635,16 @@ impl MutableAppContext {
     }
 
     pub fn remove_all_windows(&mut self) {
-        for (window_id, _) in self.cx.windows.drain() {
+        for (window_id, _) in self.windows.drain() {
             self.presenters_and_platform_windows.remove(&window_id);
         }
         self.flush_effects();
     }
 
-    pub fn platform(&self) -> Arc<dyn platform::Platform> {
-        self.cx.platform.clone()
-    }
-
-    pub fn font_cache(&self) -> &Arc<FontCache> {
-        &self.cx.font_cache
-    }
-
     pub fn foreground(&self) -> &Rc<executor::Foreground> {
         &self.foreground
     }
 
-    pub fn background(&self) -> &Arc<executor::Background> {
-        &self.cx.background
-    }
-
     pub fn debug_elements(&self, window_id: usize) -> Option<crate::json::Value> {
         self.presenters_and_platform_windows
             .get(&window_id)
@@ -696,7 +692,7 @@ impl MutableAppContext {
         let handler = Box::new(
             move |view: &mut dyn AnyView,
                   action: &dyn Action,
-                  cx: &mut MutableAppContext,
+                  cx: &mut AppContext,
                   window_id: usize,
                   view_id: usize| {
                 let action = action.as_any().downcast_ref().unwrap();
@@ -745,9 +741,9 @@ impl MutableAppContext {
     pub fn add_global_action<A, F>(&mut self, mut handler: F)
     where
         A: Action,
-        F: 'static + FnMut(&A, &mut MutableAppContext),
+        F: 'static + FnMut(&A, &mut AppContext),
     {
-        let handler = Box::new(move |action: &dyn Action, cx: &mut MutableAppContext| {
+        let handler = Box::new(move |action: &dyn Action, cx: &mut AppContext| {
             let action = action.as_any().downcast_ref().unwrap();
             handler(action, cx);
         });
@@ -783,7 +779,7 @@ impl MutableAppContext {
     }
 
     pub fn window_ids(&self) -> impl Iterator<Item = usize> + '_ {
-        self.cx.windows.keys().copied()
+        self.windows.keys().copied()
     }
 
     pub fn activate_window(&self, window_id: usize) {
@@ -792,23 +788,14 @@ impl MutableAppContext {
         }
     }
 
-    pub fn root_view<T: View>(&self, window_id: usize) -> Option<ViewHandle<T>> {
-        self.cx
-            .windows
-            .get(&window_id)
-            .and_then(|window| window.root_view.clone().downcast::<T>())
-    }
-
     pub fn window_is_active(&self, window_id: usize) -> bool {
-        self.cx
-            .windows
+        self.windows
             .get(&window_id)
             .map_or(false, |window| window.is_active)
     }
 
     pub fn window_is_fullscreen(&self, window_id: usize) -> bool {
-        self.cx
-            .windows
+        self.windows
             .get(&window_id)
             .map_or(false, |window| window.is_fullscreen)
     }
@@ -833,12 +820,11 @@ impl MutableAppContext {
         let window_id = params.window_id;
         let view_id = params.view_id;
         let mut view = self
-            .cx
             .views
             .remove(&(window_id, view_id))
             .ok_or_else(|| anyhow!("view not found"))?;
         let element = view.render(params, self);
-        self.cx.views.insert((window_id, view_id), view);
+        self.views.insert((window_id, view_id), view);
         Ok(element)
     }
 
@@ -1005,7 +991,7 @@ impl MutableAppContext {
             entity_id: handle.id(),
             subscription_id,
             callback: Box::new(move |payload, cx| {
-                if let Some(emitter) = H::upgrade_from(&emitter, cx.as_ref()) {
+                if let Some(emitter) = H::upgrade_from(&emitter, cx) {
                     let payload = payload.downcast_ref().expect("downcast is type safe");
                     callback(emitter, payload, cx)
                 } else {
@@ -1042,7 +1028,7 @@ impl MutableAppContext {
 
     fn observe_focus<F, V>(&mut self, handle: &ViewHandle<V>, mut callback: F) -> Subscription
     where
-        F: 'static + FnMut(ViewHandle<V>, bool, &mut MutableAppContext) -> bool,
+        F: 'static + FnMut(ViewHandle<V>, bool, &mut AppContext) -> bool,
         V: View,
     {
         let subscription_id = post_inc(&mut self.next_subscription_id);
@@ -1066,7 +1052,7 @@ impl MutableAppContext {
     pub fn observe_global<G, F>(&mut self, mut observe: F) -> Subscription
     where
         G: Any,
-        F: 'static + FnMut(&mut MutableAppContext),
+        F: 'static + FnMut(&mut AppContext),
     {
         let type_id = TypeId::of::<G>();
         let id = post_inc(&mut self.next_subscription_id);
@@ -1074,7 +1060,7 @@ impl MutableAppContext {
         self.global_observations.add_callback(
             type_id,
             id,
-            Box::new(move |cx: &mut MutableAppContext| observe(cx)),
+            Box::new(move |cx: &mut AppContext| observe(cx)),
         );
         Subscription::GlobalObservation(self.global_observations.subscribe(type_id, id))
     }
@@ -1082,7 +1068,7 @@ impl MutableAppContext {
     pub fn observe_default_global<G, F>(&mut self, observe: F) -> Subscription
     where
         G: Any + Default,
-        F: 'static + FnMut(&mut MutableAppContext),
+        F: 'static + FnMut(&mut AppContext),
     {
         if !self.has_global::<G>() {
             self.set_global(G::default());
@@ -1114,7 +1100,7 @@ impl MutableAppContext {
 
     pub fn observe_actions<F>(&mut self, callback: F) -> Subscription
     where
-        F: 'static + FnMut(TypeId, &mut MutableAppContext),
+        F: 'static + FnMut(TypeId, &mut AppContext),
     {
         let subscription_id = post_inc(&mut self.next_subscription_id);
         self.action_dispatch_observations
@@ -1127,7 +1113,7 @@ impl MutableAppContext {
 
     fn observe_window_activation<F>(&mut self, window_id: usize, callback: F) -> Subscription
     where
-        F: 'static + FnMut(bool, &mut MutableAppContext) -> bool,
+        F: 'static + FnMut(bool, &mut AppContext) -> bool,
     {
         let subscription_id = post_inc(&mut self.next_subscription_id);
         self.pending_effects
@@ -1144,7 +1130,7 @@ impl MutableAppContext {
 
     fn observe_fullscreen<F>(&mut self, window_id: usize, callback: F) -> Subscription
     where
-        F: 'static + FnMut(bool, &mut MutableAppContext) -> bool,
+        F: 'static + FnMut(bool, &mut AppContext) -> bool,
     {
         let subscription_id = post_inc(&mut self.next_subscription_id);
         self.pending_effects
@@ -1161,7 +1147,7 @@ impl MutableAppContext {
 
     fn observe_window_bounds<F>(&mut self, window_id: usize, callback: F) -> Subscription
     where
-        F: 'static + FnMut(WindowBounds, Uuid, &mut MutableAppContext) -> bool,
+        F: 'static + FnMut(WindowBounds, Uuid, &mut AppContext) -> bool,
     {
         let subscription_id = post_inc(&mut self.next_subscription_id);
         self.pending_effects
@@ -1179,12 +1165,7 @@ impl MutableAppContext {
     pub fn observe_keystrokes<F>(&mut self, window_id: usize, callback: F) -> Subscription
     where
         F: 'static
-            + FnMut(
-                &Keystroke,
-                &MatchResult,
-                Option<&Box<dyn Action>>,
-                &mut MutableAppContext,
-            ) -> bool,
+            + FnMut(&Keystroke, &MatchResult, Option<&Box<dyn Action>>, &mut AppContext) -> bool,
     {
         let subscription_id = post_inc(&mut self.next_subscription_id);
         self.keystroke_observations
@@ -1197,7 +1178,7 @@ impl MutableAppContext {
 
     pub fn observe_active_labeled_tasks<F>(&mut self, callback: F) -> Subscription
     where
-        F: 'static + FnMut(&mut MutableAppContext) -> bool,
+        F: 'static + FnMut(&mut AppContext) -> bool,
     {
         let subscription_id = post_inc(&mut self.next_subscription_id);
         self.active_labeled_task_observations
@@ -1208,14 +1189,14 @@ impl MutableAppContext {
         )
     }
 
-    pub fn defer(&mut self, callback: impl 'static + FnOnce(&mut MutableAppContext)) {
+    pub fn defer(&mut self, callback: impl 'static + FnOnce(&mut AppContext)) {
         self.pending_effects.push_back(Effect::Deferred {
             callback: Box::new(callback),
             after_window_update: false,
         })
     }
 
-    pub fn after_window_update(&mut self, callback: impl 'static + FnOnce(&mut MutableAppContext)) {
+    pub fn after_window_update(&mut self, callback: impl 'static + FnOnce(&mut AppContext)) {
         self.pending_effects.push_back(Effect::Deferred {
             callback: Box::new(callback),
             after_window_update: true,
@@ -1343,7 +1324,7 @@ impl MutableAppContext {
 
     pub fn is_action_available(&self, action: &dyn Action) -> bool {
         let action_type = action.as_any().type_id();
-        if let Some(window_id) = self.cx.platform.main_window_id() {
+        if let Some(window_id) = self.platform.main_window_id() {
             if let Some(focused_view_id) = self.focused_view_id(window_id) {
                 for view_id in self.ancestors(window_id, focused_view_id) {
                     if let Some(view) = self.views.get(&(window_id, view_id)) {
@@ -1368,7 +1349,7 @@ impl MutableAppContext {
         &mut self,
         window_id: usize,
         view_id: usize,
-        mut visit: impl FnMut(usize, bool, &mut MutableAppContext) -> bool,
+        mut visit: impl FnMut(usize, bool, &mut AppContext) -> bool,
     ) -> bool {
         // List of view ids from the leaf to the root of the window
         let path = self.ancestors(window_id, view_id).collect::<Vec<_>>();
@@ -1431,9 +1412,9 @@ impl MutableAppContext {
                 .ancestors(window_id, focused_view_id)
                 .collect::<Vec<_>>()
             {
-                if let Some(mut view) = self.cx.views.remove(&(window_id, view_id)) {
+                if let Some(mut view) = self.views.remove(&(window_id, view_id)) {
                     let handled = view.key_down(event, self, window_id, view_id);
-                    self.cx.views.insert((window_id, view_id), view);
+                    self.views.insert((window_id, view_id), view);
                     if handled {
                         return true;
                     }
@@ -1452,9 +1433,9 @@ impl MutableAppContext {
                 .ancestors(window_id, focused_view_id)
                 .collect::<Vec<_>>()
             {
-                if let Some(mut view) = self.cx.views.remove(&(window_id, view_id)) {
+                if let Some(mut view) = self.views.remove(&(window_id, view_id)) {
                     let handled = view.key_up(event, self, window_id, view_id);
-                    self.cx.views.insert((window_id, view_id), view);
+                    self.views.insert((window_id, view_id), view);
                     if handled {
                         return true;
                     }
@@ -1477,9 +1458,9 @@ impl MutableAppContext {
                 .ancestors(window_id, focused_view_id)
                 .collect::<Vec<_>>()
             {
-                if let Some(mut view) = self.cx.views.remove(&(window_id, view_id)) {
+                if let Some(mut view) = self.views.remove(&(window_id, view_id)) {
                     let handled = view.modifiers_changed(event, self, window_id, view_id);
-                    self.cx.views.insert((window_id, view_id), view);
+                    self.views.insert((window_id, view_id), view);
                     if handled {
                         return true;
                     }
@@ -1497,10 +1478,9 @@ impl MutableAppContext {
             let dispatch_path = self
                 .ancestors(window_id, focused_view_id)
                 .filter_map(|view_id| {
-                    self.cx
-                        .views
+                    self.views
                         .get(&(window_id, view_id))
-                        .map(|view| (view_id, view.keymap_context(self.as_ref())))
+                        .map(|view| (view_id, view.keymap_context(self)))
                 })
                 .collect();
 
@@ -1544,7 +1524,7 @@ impl MutableAppContext {
     pub fn default_global<T: 'static + Default>(&mut self) -> &T {
         let type_id = TypeId::of::<T>();
         self.update(|this| {
-            if let Entry::Vacant(entry) = this.cx.globals.entry(type_id) {
+            if let Entry::Vacant(entry) = this.globals.entry(type_id) {
                 entry.insert(Box::new(T::default()));
                 this.notify_global(type_id);
             }
@@ -1555,7 +1535,7 @@ impl MutableAppContext {
     pub fn set_global<T: 'static>(&mut self, state: T) {
         self.update(|this| {
             let type_id = TypeId::of::<T>();
-            this.cx.globals.insert(type_id, Box::new(state));
+            this.globals.insert(type_id, Box::new(state));
             this.notify_global(type_id);
         });
     }
@@ -1563,17 +1543,16 @@ impl MutableAppContext {
     pub fn update_default_global<T, F, U>(&mut self, update: F) -> U
     where
         T: 'static + Default,
-        F: FnOnce(&mut T, &mut MutableAppContext) -> U,
+        F: FnOnce(&mut T, &mut AppContext) -> U,
     {
         self.update(|this| {
             let type_id = TypeId::of::<T>();
             let mut state = this
-                .cx
                 .globals
                 .remove(&type_id)
                 .unwrap_or_else(|| Box::new(T::default()));
             let result = update(state.downcast_mut().unwrap(), this);
-            this.cx.globals.insert(type_id, state);
+            this.globals.insert(type_id, state);
             this.notify_global(type_id);
             result
         })
@@ -1582,13 +1561,13 @@ impl MutableAppContext {
     pub fn update_global<T, F, U>(&mut self, update: F) -> U
     where
         T: 'static,
-        F: FnOnce(&mut T, &mut MutableAppContext) -> U,
+        F: FnOnce(&mut T, &mut AppContext) -> U,
     {
         self.update(|this| {
             let type_id = TypeId::of::<T>();
-            if let Some(mut state) = this.cx.globals.remove(&type_id) {
+            if let Some(mut state) = this.globals.remove(&type_id) {
                 let result = update(state.downcast_mut().unwrap(), this);
-                this.cx.globals.insert(type_id, state);
+                this.globals.insert(type_id, state);
                 this.notify_global(type_id);
                 result
             } else {
@@ -1598,7 +1577,7 @@ impl MutableAppContext {
     }
 
     pub fn clear_globals(&mut self) {
-        self.cx.globals.clear();
+        self.globals.clear();
     }
 
     pub fn add_model<T, F>(&mut self, build_model: F) -> ModelHandle<T>
@@ -1608,10 +1587,10 @@ impl MutableAppContext {
     {
         self.update(|this| {
             let model_id = post_inc(&mut this.next_entity_id);
-            let handle = ModelHandle::new(model_id, &this.cx.ref_counts);
+            let handle = ModelHandle::new(model_id, &this.ref_counts);
             let mut cx = ModelContext::new(this, model_id);
             let model = build_model(&mut cx);
-            this.cx.models.insert(model_id, Box::new(model));
+            this.models.insert(model_id, Box::new(model));
             handle
         })
     }
@@ -1630,7 +1609,7 @@ impl MutableAppContext {
             let root_view = this
                 .build_and_insert_view(window_id, ParentId::Root, |cx| Some(build_root_view(cx)))
                 .unwrap();
-            this.cx.windows.insert(
+            this.windows.insert(
                 window_id,
                 Window {
                     root_view: root_view.clone().into_any(),
@@ -1643,8 +1622,7 @@ impl MutableAppContext {
             root_view.update(this, |view, cx| view.focus_in(cx.handle().into_any(), cx));
 
             let window =
-                this.cx
-                    .platform
+                this.platform
                     .open_window(window_id, window_options, this.foreground.clone());
             this.register_platform_window(window_id, window);
 
@@ -1663,7 +1641,7 @@ impl MutableAppContext {
                 .build_and_insert_view(window_id, ParentId::Root, |cx| Some(build_root_view(cx)))
                 .unwrap();
             let focused_view_id = root_view.id();
-            this.cx.windows.insert(
+            this.windows.insert(
                 window_id,
                 Window {
                     root_view: root_view.clone().into_any(),
@@ -1675,7 +1653,7 @@ impl MutableAppContext {
             );
             root_view.update(this, |view, cx| view.focus_in(cx.handle().into_any(), cx));
 
-            let status_item = this.cx.platform.add_status_item();
+            let status_item = this.platform.add_status_item();
             this.register_platform_window(window_id, status_item);
 
             (window_id, root_view)
@@ -1783,7 +1761,7 @@ impl MutableAppContext {
             let root_view = this
                 .build_and_insert_view(window_id, ParentId::Root, |cx| Some(build_root_view(cx)))
                 .unwrap();
-            let window = this.cx.windows.get_mut(&window_id).unwrap();
+            let window = this.windows.get_mut(&window_id).unwrap();
             window.root_view = root_view.clone().into_any();
             window.focused_view_id = Some(root_view.id());
             root_view
@@ -1791,7 +1769,7 @@ impl MutableAppContext {
     }
 
     pub fn remove_window(&mut self, window_id: usize) {
-        self.cx.windows.remove(&window_id);
+        self.windows.remove(&window_id);
         self.presenters_and_platform_windows.remove(&window_id);
         self.flush_effects();
     }
@@ -1806,8 +1784,8 @@ impl MutableAppContext {
             window_id,
             titlebar_height,
             appearance,
-            self.cx.font_cache.clone(),
-            TextLayoutCache::new(self.cx.platform.fonts()),
+            self.font_cache.clone(),
+            TextLayoutCache::new(self.platform.fonts()),
             self.assets.clone(),
             self,
         )
@@ -1856,20 +1834,20 @@ impl MutableAppContext {
         self.update(|this| {
             let view_id = post_inc(&mut this.next_entity_id);
             // Make sure we can tell child views about their parent
-            this.cx.parents.insert((window_id, view_id), parent_id);
+            this.parents.insert((window_id, view_id), parent_id);
             let mut cx = ViewContext::new(this, window_id, view_id);
             let handle = if let Some(view) = build_view(&mut cx) {
-                this.cx.views.insert((window_id, view_id), Box::new(view));
-                if let Some(window) = this.cx.windows.get_mut(&window_id) {
+                this.views.insert((window_id, view_id), Box::new(view));
+                if let Some(window) = this.windows.get_mut(&window_id) {
                     window
                         .invalidation
                         .get_or_insert_with(Default::default)
                         .updated
                         .insert(view_id);
                 }
-                Some(ViewHandle::new(window_id, view_id, &this.cx.ref_counts))
+                Some(ViewHandle::new(window_id, view_id, &this.ref_counts))
             } else {
-                this.cx.parents.remove(&(window_id, view_id));
+                this.parents.remove(&(window_id, view_id));
                 None
             };
             handle
@@ -1879,7 +1857,7 @@ impl MutableAppContext {
     fn remove_dropped_entities(&mut self) {
         loop {
             let (dropped_models, dropped_views, dropped_element_states) =
-                self.cx.ref_counts.lock().take_dropped();
+                self.ref_counts.lock().take_dropped();
             if dropped_models.is_empty()
                 && dropped_views.is_empty()
                 && dropped_element_states.is_empty()
@@ -1890,7 +1868,7 @@ impl MutableAppContext {
             for model_id in dropped_models {
                 self.subscriptions.remove(model_id);
                 self.observations.remove(model_id);
-                let mut model = self.cx.models.remove(&model_id).unwrap();
+                let mut model = self.models.remove(&model_id).unwrap();
                 model.release(self);
                 self.pending_effects
                     .push_back(Effect::ModelRelease { model_id, model });
@@ -1899,9 +1877,9 @@ impl MutableAppContext {
             for (window_id, view_id) in dropped_views {
                 self.subscriptions.remove(view_id);
                 self.observations.remove(view_id);
-                let mut view = self.cx.views.remove(&(window_id, view_id)).unwrap();
+                let mut view = self.views.remove(&(window_id, view_id)).unwrap();
                 view.release(self);
-                let change_focus_to = self.cx.windows.get_mut(&window_id).and_then(|window| {
+                let change_focus_to = self.windows.get_mut(&window_id).and_then(|window| {
                     window
                         .invalidation
                         .get_or_insert_with(Default::default)
@@ -1913,7 +1891,7 @@ impl MutableAppContext {
                         None
                     }
                 });
-                self.cx.parents.remove(&(window_id, view_id));
+                self.parents.remove(&(window_id, view_id));
 
                 if let Some(view_id) = change_focus_to {
                     self.handle_focus_effect(window_id, Some(view_id));
@@ -1924,7 +1902,7 @@ impl MutableAppContext {
             }
 
             for key in dropped_element_states {
-                self.cx.element_states.remove(&key);
+                self.element_states.remove(&key);
             }
         }
     }
@@ -2028,7 +2006,7 @@ impl MutableAppContext {
                         }
 
                         Effect::ResizeWindow { window_id } => {
-                            if let Some(window) = self.cx.windows.get_mut(&window_id) {
+                            if let Some(window) = self.windows.get_mut(&window_id) {
                                 window
                                     .invalidation
                                     .get_or_insert(WindowInvalidation::default());
@@ -2153,7 +2131,7 @@ impl MutableAppContext {
 
     fn update_windows(&mut self) {
         let mut invalidations: HashMap<_, _> = Default::default();
-        for (window_id, window) in &mut self.cx.windows {
+        for (window_id, window) in &mut self.windows {
             if let Some(invalidation) = window.invalidation.take() {
                 invalidations.insert(*window_id, invalidation);
             }
@@ -2243,13 +2221,7 @@ impl MutableAppContext {
     fn perform_window_refresh(&mut self) {
         let mut presenters = mem::take(&mut self.presenters_and_platform_windows);
         for (window_id, (presenter, window)) in &mut presenters {
-            let mut invalidation = self
-                .cx
-                .windows
-                .get_mut(window_id)
-                .unwrap()
-                .invalidation
-                .take();
+            let mut invalidation = self.windows.get_mut(window_id).unwrap().invalidation.take();
             let mut presenter = presenter.borrow_mut();
             presenter.refresh(
                 invalidation.as_mut().unwrap_or(&mut Default::default()),
@@ -2279,11 +2251,10 @@ impl MutableAppContext {
         observed_view_id: usize,
     ) {
         if self
-            .cx
             .views
             .contains_key(&(observed_window_id, observed_view_id))
         {
-            if let Some(window) = self.cx.windows.get_mut(&observed_window_id) {
+            if let Some(window) = self.windows.get_mut(&observed_window_id) {
                 window
                     .invalidation
                     .get_or_insert_with(Default::default)
@@ -2309,7 +2280,6 @@ impl MutableAppContext {
     fn handle_fullscreen_effect(&mut self, window_id: usize, is_fullscreen: bool) {
         //Short circuit evaluation if we're already g2g
         if self
-            .cx
             .windows
             .get(&window_id)
             .map(|w| w.is_fullscreen == is_fullscreen)
@@ -2319,7 +2289,7 @@ impl MutableAppContext {
         }
 
         self.update(|this| {
-            let window = this.cx.windows.get_mut(&window_id)?;
+            let window = this.windows.get_mut(&window_id)?;
             window.is_fullscreen = is_fullscreen;
 
             let mut fullscreen_observations = this.window_fullscreen_observations.clone();
@@ -2359,7 +2329,6 @@ impl MutableAppContext {
     fn handle_window_activation_effect(&mut self, window_id: usize, active: bool) {
         //Short circuit evaluation if we're already g2g
         if self
-            .cx
             .windows
             .get(&window_id)
             .map(|w| w.is_active == active)
@@ -2369,19 +2338,19 @@ impl MutableAppContext {
         }
 
         self.update(|this| {
-            let window = this.cx.windows.get_mut(&window_id)?;
+            let window = this.windows.get_mut(&window_id)?;
             window.is_active = active;
 
             //Handle focus
             let focused_id = window.focused_view_id?;
             for view_id in this.ancestors(window_id, focused_id).collect::<Vec<_>>() {
-                if let Some(mut view) = this.cx.views.remove(&(window_id, view_id)) {
+                if let Some(mut view) = this.views.remove(&(window_id, view_id)) {
                     if active {
                         view.focus_in(this, window_id, view_id, focused_id);
                     } else {
                         view.focus_out(this, window_id, view_id, focused_id);
                     }
-                    this.cx.views.insert((window_id, view_id), view);
+                    this.views.insert((window_id, view_id), view);
                 }
             }
 
@@ -2394,7 +2363,6 @@ impl MutableAppContext {
 
     fn handle_focus_effect(&mut self, window_id: usize, focused_id: Option<usize>) {
         if self
-            .cx
             .windows
             .get(&window_id)
             .map(|w| w.focused_view_id)
@@ -2404,7 +2372,7 @@ impl MutableAppContext {
         }
 
         self.update(|this| {
-            let blurred_id = this.cx.windows.get_mut(&window_id).and_then(|window| {
+            let blurred_id = this.windows.get_mut(&window_id).and_then(|window| {
                 let blurred_id = window.focused_view_id;
                 window.focused_view_id = focused_id;
                 blurred_id
@@ -2419,9 +2387,9 @@ impl MutableAppContext {
 
             if let Some(blurred_id) = blurred_id {
                 for view_id in blurred_parents.iter().copied() {
-                    if let Some(mut view) = this.cx.views.remove(&(window_id, view_id)) {
+                    if let Some(mut view) = this.views.remove(&(window_id, view_id)) {
                         view.focus_out(this, window_id, view_id, blurred_id);
-                        this.cx.views.insert((window_id, view_id), view);
+                        this.views.insert((window_id, view_id), view);
                     }
                 }
 
@@ -2431,9 +2399,9 @@ impl MutableAppContext {
 
             if let Some(focused_id) = focused_id {
                 for view_id in focused_parents {
-                    if let Some(mut view) = this.cx.views.remove(&(window_id, view_id)) {
+                    if let Some(mut view) = this.views.remove(&(window_id, view_id)) {
                         view.focus_in(this, window_id, view_id, focused_id);
-                        this.cx.views.insert((window_id, view_id), view);
+                        this.views.insert((window_id, view_id), view);
                     }
                 }
 
@@ -2453,7 +2421,7 @@ impl MutableAppContext {
             if let Some(view_id) = view_id {
                 this.halt_action_dispatch = false;
                 this.visit_dispatch_path(window_id, view_id, |view_id, capture_phase, this| {
-                    if let Some(mut view) = this.cx.views.remove(&(window_id, view_id)) {
+                    if let Some(mut view) = this.views.remove(&(window_id, view_id)) {
                         let type_id = view.as_any().type_id();
 
                         if let Some((name, mut handlers)) = this
@@ -2474,7 +2442,7 @@ impl MutableAppContext {
                                 .insert(name, handlers);
                         }
 
-                        this.cx.views.insert((window_id, view_id), view);
+                        this.views.insert((window_id, view_id), view);
                     }
 
                     !this.halt_action_dispatch
@@ -2594,22 +2562,22 @@ impl MutableAppContext {
     }
 
     pub fn write_to_clipboard(&self, item: ClipboardItem) {
-        self.cx.platform.write_to_clipboard(item);
+        self.platform.write_to_clipboard(item);
     }
 
     pub fn read_from_clipboard(&self) -> Option<ClipboardItem> {
-        self.cx.platform.read_from_clipboard()
+        self.platform.read_from_clipboard()
     }
 
     #[cfg(any(test, feature = "test-support"))]
     pub fn leak_detector(&self) -> Arc<Mutex<LeakDetector>> {
-        self.cx.ref_counts.lock().leak_detector.clone()
+        self.ref_counts.lock().leak_detector.clone()
     }
 }
 
-impl ReadModel for MutableAppContext {
+impl ReadModel for AppContext {
     fn read_model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
-        if let Some(model) = self.cx.models.get(&handle.model_id) {
+        if let Some(model) = self.models.get(&handle.model_id) {
             model
                 .as_any()
                 .downcast_ref()
@@ -2620,13 +2588,13 @@ impl ReadModel for MutableAppContext {
     }
 }
 
-impl UpdateModel for MutableAppContext {
+impl UpdateModel for AppContext {
     fn update_model<T: Entity, V>(
         &mut self,
         handle: &ModelHandle<T>,
         update: &mut dyn FnMut(&mut T, &mut ModelContext<T>) -> V,
     ) -> V {
-        if let Some(mut model) = self.cx.models.remove(&handle.model_id) {
+        if let Some(mut model) = self.models.remove(&handle.model_id) {
             self.update(|this| {
                 let mut cx = ModelContext::new(this, handle.model_id);
                 let result = update(

crates/gpui/src/app/callback_collection.rs šŸ”—

@@ -1,4 +1,4 @@
-use crate::MutableAppContext;
+use crate::AppContext;
 use collections::{BTreeMap, HashMap, HashSet};
 use parking_lot::Mutex;
 use std::sync::Arc;
@@ -93,10 +93,10 @@ impl<K: Clone + Hash + Eq + Copy, F> CallbackCollection<K, F> {
         drop(callbacks);
     }
 
-    pub fn emit<C: FnMut(&mut F, &mut MutableAppContext) -> bool>(
+    pub fn emit<C: FnMut(&mut F, &mut AppContext) -> bool>(
         &mut self,
         key: K,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
         mut call_callback: C,
     ) {
         let callbacks = self.internal.lock().callbacks.remove(&key);

crates/gpui/src/app/menu.rs šŸ”—

@@ -1,4 +1,4 @@
-use crate::{Action, App, ForegroundPlatform, MutableAppContext};
+use crate::{platform::ForegroundPlatform, Action, App, AppContext};
 
 pub struct Menu<'a> {
     pub name: &'a str,
@@ -51,7 +51,7 @@ pub enum OsAction {
     Redo,
 }
 
-impl MutableAppContext {
+impl AppContext {
     pub fn set_menus(&mut self, menus: Vec<Menu>) {
         self.foreground_platform
             .set_menus(menus, &self.keystroke_matcher);
@@ -77,7 +77,7 @@ pub(crate) fn setup_menu_handlers(foreground_platform: &dyn ForegroundPlatform,
         let cx = app.0.clone();
         move |action| {
             let mut cx = cx.borrow_mut();
-            if let Some(main_window_id) = cx.cx.platform.main_window_id() {
+            if let Some(main_window_id) = cx.platform.main_window_id() {
                 if let Some(view_id) = cx.focused_view_id(main_window_id) {
                     cx.handle_dispatch_action_from_effect(main_window_id, Some(view_id), action);
                     return;

crates/gpui/src/app/test_app_context.rs šŸ”—

@@ -17,11 +17,14 @@ use parking_lot::{Mutex, RwLock};
 use smol::stream::StreamExt;
 
 use crate::{
-    executor, geometry::vector::Vector2F, keymap_matcher::Keystroke, platform, Action,
-    AnyViewHandle, AppContext, Appearance, Entity, Event, FontCache, Handle, InputHandler,
-    KeyDownEvent, ModelContext, ModelHandle, MutableAppContext, Platform, ReadModelWith,
-    ReadViewWith, RenderContext, Task, UpdateModel, UpdateView, View, ViewContext, ViewHandle,
-    WeakHandle,
+    executor,
+    geometry::vector::Vector2F,
+    keymap_matcher::Keystroke,
+    platform,
+    platform::{Appearance, Event, InputHandler, KeyDownEvent, Platform},
+    Action, AnyViewHandle, AppContext, Entity, FontCache, Handle, ModelContext, ModelHandle,
+    ReadModelWith, ReadViewWith, RenderContext, Task, UpdateModel, UpdateView, View, ViewContext,
+    ViewHandle, WeakHandle,
 };
 use collections::BTreeMap;
 
@@ -31,7 +34,7 @@ use super::{
 
 #[derive(Clone)]
 pub struct TestAppContext {
-    cx: Rc<RefCell<MutableAppContext>>,
+    cx: Rc<RefCell<AppContext>>,
     foreground_platform: Rc<platform::test::ForegroundPlatform>,
     condition_duration: Option<Duration>,
     pub function_name: String,
@@ -49,7 +52,7 @@ impl TestAppContext {
         first_entity_id: usize,
         function_name: String,
     ) -> Self {
-        let mut cx = MutableAppContext::new(
+        let mut cx = AppContext::new(
             foreground,
             background,
             platform,
@@ -150,15 +153,15 @@ impl TestAppContext {
         self.cx.borrow().window_ids().collect()
     }
 
-    pub fn root_view<T: View>(&self, window_id: usize) -> Option<ViewHandle<T>> {
+    pub fn root_view(&self, window_id: usize) -> Option<AnyViewHandle> {
         self.cx.borrow().root_view(window_id)
     }
 
     pub fn read<T, F: FnOnce(&AppContext) -> T>(&self, callback: F) -> T {
-        callback(self.cx.borrow().as_ref())
+        callback(&*self.cx.borrow())
     }
 
-    pub fn update<T, F: FnOnce(&mut MutableAppContext) -> T>(&mut self, callback: F) -> T {
+    pub fn update<T, F: FnOnce(&mut AppContext) -> T>(&mut self, callback: F) -> T {
         let mut state = self.cx.borrow_mut();
         // Don't increment pending flushes in order for effects to be flushed before the callback
         // completes, which is helpful in tests.
@@ -195,7 +198,7 @@ impl TestAppContext {
     }
 
     pub fn font_cache(&self) -> Arc<FontCache> {
-        self.cx.borrow().cx.font_cache.clone()
+        self.cx.borrow().font_cache.clone()
     }
 
     pub fn foreground_platform(&self) -> Rc<platform::test::ForegroundPlatform> {
@@ -203,7 +206,7 @@ impl TestAppContext {
     }
 
     pub fn platform(&self) -> Arc<dyn platform::Platform> {
-        self.cx.borrow().cx.platform.clone()
+        self.cx.borrow().platform.clone()
     }
 
     pub fn foreground(&self) -> Rc<executor::Foreground> {
@@ -397,7 +400,7 @@ impl ReadModelWith for TestAppContext {
         read: &mut dyn FnMut(&E, &AppContext) -> T,
     ) -> T {
         let cx = self.cx.borrow();
-        let cx = cx.as_ref();
+        let cx = &*cx;
         read(handle.read(cx), cx)
     }
 }
@@ -425,7 +428,7 @@ impl ReadViewWith for TestAppContext {
         V: View,
     {
         let cx = self.cx.borrow();
-        let cx = cx.as_ref();
+        let cx = &*cx;
         read(handle.read(cx), cx)
     }
 }
@@ -514,7 +517,7 @@ impl<T: Entity> ModelHandle<T> {
                 loop {
                     {
                         let cx = cx.borrow();
-                        let cx = cx.as_ref();
+                        let cx = &*cx;
                         if predicate(
                             handle
                                 .upgrade(cx)
@@ -601,7 +604,7 @@ impl<T: View> ViewHandle<T> {
                 loop {
                     {
                         let cx = cx.borrow();
-                        let cx = cx.as_ref();
+                        let cx = &*cx;
                         if predicate(
                             handle
                                 .upgrade(cx)

crates/gpui/src/app/window_input_handler.rs šŸ”—

@@ -2,10 +2,10 @@ use std::{cell::RefCell, ops::Range, rc::Rc};
 
 use pathfinder_geometry::rect::RectF;
 
-use crate::{AnyView, AppContext, InputHandler, MutableAppContext};
+use crate::{platform::InputHandler, AnyView, AppContext};
 
 pub struct WindowInputHandler {
-    pub app: Rc<RefCell<MutableAppContext>>,
+    pub app: Rc<RefCell<AppContext>>,
     pub window_id: usize,
 }
 
@@ -23,21 +23,21 @@ impl WindowInputHandler {
         let app = self.app.try_borrow().ok()?;
 
         let view_id = app.focused_view_id(self.window_id)?;
-        let view = app.cx.views.get(&(self.window_id, view_id))?;
+        let view = app.views.get(&(self.window_id, view_id))?;
         let result = f(view.as_ref(), &app);
         Some(result)
     }
 
     fn update_focused_view<T, F>(&mut self, f: F) -> Option<T>
     where
-        F: FnOnce(usize, usize, &mut dyn AnyView, &mut MutableAppContext) -> T,
+        F: FnOnce(usize, usize, &mut dyn AnyView, &mut AppContext) -> T,
     {
         let mut app = self.app.try_borrow_mut().ok()?;
         app.update(|app| {
             let view_id = app.focused_view_id(self.window_id)?;
-            let mut view = app.cx.views.remove(&(self.window_id, view_id))?;
+            let mut view = app.views.remove(&(self.window_id, view_id))?;
             let result = f(self.window_id, view_id, view.as_mut(), &mut *app);
-            app.cx.views.insert((self.window_id, view_id), view);
+            app.views.insert((self.window_id, view_id), view);
             Some(result)
         })
     }

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

@@ -210,7 +210,7 @@ mod tests {
     use crate::fonts::{Properties as FontProperties, Weight};
 
     #[crate::test(self)]
-    fn test_layout_label_with_highlights(cx: &mut crate::MutableAppContext) {
+    fn test_layout_label_with_highlights(cx: &mut crate::AppContext) {
         let default_style = TextStyle::new(
             "Menlo",
             12.,

crates/gpui/src/elements/list.rs šŸ”—

@@ -630,7 +630,7 @@ mod tests {
     use std::env;
 
     #[crate::test(self)]
-    fn test_layout(cx: &mut crate::MutableAppContext) {
+    fn test_layout(cx: &mut crate::AppContext) {
         let mut presenter = cx.build_presenter(0, 0., Default::default());
         let (_, view) = cx.add_window(Default::default(), |_| TestView);
         let constraint = SizeConstraint::new(vec2f(0., 0.), vec2f(100., 40.));
@@ -725,7 +725,7 @@ mod tests {
     }
 
     #[crate::test(self, iterations = 10, seed = 0)]
-    fn test_random(cx: &mut crate::MutableAppContext, mut rng: StdRng) {
+    fn test_random(cx: &mut crate::AppContext, mut rng: StdRng) {
         let operations = env::var("OPERATIONS")
             .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
             .unwrap_or(10);

crates/gpui/src/elements/mouse_event_handler.rs šŸ”—

@@ -5,12 +5,13 @@ use crate::{
         vector::{vec2f, Vector2F},
     },
     platform::CursorStyle,
+    platform::MouseButton,
     scene::{
         CursorRegion, HandlerSet, MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseHover,
         MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut,
     },
     DebugContext, Element, ElementBox, EventContext, LayoutContext, MeasurementContext,
-    MouseButton, MouseRegion, MouseState, PaintContext, RenderContext, SizeConstraint, View,
+    MouseRegion, MouseState, PaintContext, RenderContext, SizeConstraint, View,
 };
 use serde_json::json;
 use std::{marker::PhantomData, ops::Range};

crates/gpui/src/elements/resizable.rs šŸ”—

@@ -4,8 +4,10 @@ use pathfinder_geometry::vector::{vec2f, Vector2F};
 use serde_json::json;
 
 use crate::{
-    geometry::rect::RectF, scene::MouseDrag, Axis, CursorStyle, Element, ElementBox,
-    ElementStateHandle, MouseButton, MouseRegion, RenderContext, View,
+    geometry::rect::RectF,
+    platform::{CursorStyle, MouseButton},
+    scene::MouseDrag,
+    Axis, Element, ElementBox, ElementStateHandle, MouseRegion, RenderContext, View,
 };
 
 use super::{ConstrainedBox, Hook};

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

@@ -271,12 +271,10 @@ pub fn layout_highlighted_chunks<'a>(
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::{
-        elements::Empty, fonts, ElementBox, Entity, MutableAppContext, RenderContext, View,
-    };
+    use crate::{elements::Empty, fonts, AppContext, ElementBox, Entity, RenderContext, View};
 
     #[crate::test(self)]
-    fn test_soft_wrapping_with_carriage_returns(cx: &mut MutableAppContext) {
+    fn test_soft_wrapping_with_carriage_returns(cx: &mut AppContext) {
         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(), || {

crates/gpui/src/elements/uniform_list.rs šŸ”—

@@ -5,9 +5,10 @@ use crate::{
         vector::{vec2f, Vector2F},
     },
     json::{self, json},
+    platform::ScrollWheelEvent,
     presenter::MeasurementContext,
     scene::MouseScrollWheel,
-    ElementBox, MouseRegion, RenderContext, ScrollWheelEvent, View,
+    ElementBox, MouseRegion, RenderContext, View,
 };
 use json::ToJson;
 use std::{cell::RefCell, cmp, ops::Range, rc::Rc};

crates/gpui/src/executor.rs šŸ”—

@@ -17,7 +17,7 @@ use std::{
 
 use crate::{
     platform::{self, Dispatcher},
-    util, MutableAppContext,
+    util, AppContext,
 };
 
 pub enum Foreground {
@@ -941,7 +941,7 @@ impl<T> Task<T> {
 }
 
 impl<T: 'static, E: 'static + Display> Task<Result<T, E>> {
-    pub fn detach_and_log_err(self, cx: &mut MutableAppContext) {
+    pub fn detach_and_log_err(self, cx: &mut AppContext) {
         cx.spawn(|_| async move {
             if let Err(err) = self.await {
                 log::error!("{}", err);

crates/gpui/src/gpui.rs šŸ”—

@@ -28,7 +28,6 @@ pub mod json;
 pub mod keymap_matcher;
 pub mod platform;
 pub use gpui_macros::test;
-pub use platform::*;
 pub use presenter::{
     Axis, DebugContext, EventContext, LayoutContext, MeasurementContext, PaintContext,
     SizeConstraint, Vector2FExt,

crates/gpui/src/platform/mac/appearance.rs šŸ”—

@@ -1,5 +1,6 @@
 use std::ffi::CStr;
 
+use crate::platform::Appearance;
 use cocoa::{
     appkit::{NSAppearanceNameVibrantDark, NSAppearanceNameVibrantLight},
     base::id,
@@ -7,8 +8,6 @@ use cocoa::{
 };
 use objc::{msg_send, sel, sel_impl};
 
-use crate::Appearance;
-
 impl Appearance {
     pub unsafe fn from_native(appearance: id) -> Self {
         let name: id = msg_send![appearance, name];

crates/gpui/src/platform/mac/event.rs šŸ”—

@@ -1,9 +1,11 @@
 use crate::{
     geometry::vector::vec2f,
     keymap_matcher::Keystroke,
-    platform::{Event, NavigationDirection},
-    KeyDownEvent, KeyUpEvent, Modifiers, ModifiersChangedEvent, MouseButton, MouseButtonEvent,
-    MouseExitedEvent, MouseMovedEvent, ScrollDelta, ScrollWheelEvent, TouchPhase,
+    platform::{
+        Event, KeyDownEvent, KeyUpEvent, Modifiers, ModifiersChangedEvent, MouseButton,
+        MouseButtonEvent, MouseExitedEvent, MouseMovedEvent, NavigationDirection, ScrollDelta,
+        ScrollWheelEvent, TouchPhase,
+    },
 };
 use cocoa::{
     appkit::{NSEvent, NSEventModifierFlags, NSEventPhase, NSEventType},

crates/gpui/src/platform/mac/fonts.rs šŸ”—

@@ -498,12 +498,12 @@ extern "C" {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::MutableAppContext;
+    use crate::AppContext;
     use font_kit::properties::{Style, Weight};
     use platform::FontSystem as _;
 
     #[crate::test(self, retries = 5)]
-    fn test_layout_str(_: &mut MutableAppContext) {
+    fn test_layout_str(_: &mut AppContext) {
         // This is failing intermittently on CI and we don't have time to figure it out
         let fonts = FontSystem::new();
         let menlo = fonts.load_family("Menlo", &Default::default()).unwrap();

crates/gpui/src/platform/mac/image_cache.rs šŸ”—

@@ -2,9 +2,9 @@ use super::atlas::{AllocId, AtlasAllocator};
 use crate::{
     fonts::{FontId, GlyphId},
     geometry::{rect::RectI, vector::Vector2I},
-    platform::RasterizationOptions,
+    platform::{FontSystem, RasterizationOptions},
     scene::ImageGlyph,
-    FontSystem, ImageData,
+    ImageData,
 };
 use anyhow::anyhow;
 use metal::{MTLPixelFormat, TextureDescriptor, TextureRef};

crates/gpui/src/platform/mac/platform.rs šŸ”—

@@ -5,8 +5,8 @@ use super::{
 use crate::{
     executor,
     keymap_matcher::KeymapMatcher,
-    platform::{self, CursorStyle},
-    Action, AppVersion, ClipboardItem, Event, Menu, MenuItem,
+    platform::{self, AppVersion, CursorStyle, Event},
+    Action, ClipboardItem, Menu, MenuItem,
 };
 use anyhow::{anyhow, Result};
 use block::ConcreteBlock;
@@ -150,7 +150,7 @@ pub struct MacForegroundPlatformState {
     resign_active: Option<Box<dyn FnMut()>>,
     reopen: Option<Box<dyn FnMut()>>,
     quit: Option<Box<dyn FnMut()>>,
-    event: Option<Box<dyn FnMut(crate::Event) -> bool>>,
+    event: Option<Box<dyn FnMut(platform::Event) -> bool>>,
     menu_command: Option<Box<dyn FnMut(&dyn Action)>>,
     validate_menu_command: Option<Box<dyn FnMut(&dyn Action) -> bool>>,
     will_open_menu: Option<Box<dyn FnMut()>>,
@@ -342,7 +342,7 @@ impl platform::ForegroundPlatform for MacForegroundPlatform {
         self.0.borrow_mut().reopen = Some(callback);
     }
 
-    fn on_event(&self, callback: Box<dyn FnMut(crate::Event) -> bool>) {
+    fn on_event(&self, callback: Box<dyn FnMut(platform::Event) -> bool>) {
         self.0.borrow_mut().event = Some(callback);
     }
 
@@ -577,7 +577,7 @@ impl platform::Platform for MacPlatform {
         }
     }
 
-    fn screen_by_id(&self, id: uuid::Uuid) -> Option<Rc<dyn crate::Screen>> {
+    fn screen_by_id(&self, id: uuid::Uuid) -> Option<Rc<dyn platform::Screen>> {
         Screen::find_by_id(id).map(|screen| Rc::new(screen) as Rc<_>)
     }
 
@@ -864,7 +864,7 @@ impl platform::Platform for MacPlatform {
         "macOS"
     }
 
-    fn os_version(&self) -> Result<crate::AppVersion> {
+    fn os_version(&self) -> Result<crate::platform::AppVersion> {
         unsafe {
             let process_info = NSProcessInfo::processInfo(nil);
             let version = process_info.operatingSystemVersion();

crates/gpui/src/platform/mac/status_item.rs šŸ”—

@@ -6,8 +6,9 @@ use crate::{
     platform::{
         self,
         mac::{platform::NSViewLayerContentsRedrawDuringViewResize, renderer::Renderer},
+        Event, FontSystem, WindowBounds,
     },
-    Event, FontSystem, Scene, WindowBounds,
+    Scene,
 };
 use cocoa::{
     appkit::{NSScreen, NSSquareStatusItemLength, NSStatusBar, NSStatusItem, NSView, NSWindow},
@@ -185,15 +186,15 @@ impl platform::Window for StatusItem {
         0.
     }
 
-    fn appearance(&self) -> crate::Appearance {
+    fn appearance(&self) -> platform::Appearance {
         unsafe {
             let appearance: id =
                 msg_send![self.0.borrow().native_item.button(), effectiveAppearance];
-            crate::Appearance::from_native(appearance)
+            platform::Appearance::from_native(appearance)
         }
     }
 
-    fn screen(&self) -> Rc<dyn crate::Screen> {
+    fn screen(&self) -> Rc<dyn platform::Screen> {
         unsafe {
             Rc::new(Screen {
                 native_screen: self.0.borrow().native_window().screen(),
@@ -205,11 +206,11 @@ impl platform::Window for StatusItem {
         self
     }
 
-    fn set_input_handler(&mut self, _: Box<dyn crate::InputHandler>) {}
+    fn set_input_handler(&mut self, _: Box<dyn platform::InputHandler>) {}
 
     fn prompt(
         &self,
-        _: crate::PromptLevel,
+        _: crate::platform::PromptLevel,
         _: &str,
         _: &[&str],
     ) -> postage::oneshot::Receiver<usize> {
@@ -251,7 +252,7 @@ impl platform::Window for StatusItem {
         unimplemented!()
     }
 
-    fn on_event(&mut self, callback: Box<dyn FnMut(crate::Event) -> bool>) {
+    fn on_event(&mut self, callback: Box<dyn FnMut(platform::Event) -> bool>) {
         self.0.borrow_mut().event_callback = Some(callback);
     }
 

crates/gpui/src/platform/mac/window.rs šŸ”—

@@ -5,14 +5,14 @@ use crate::{
         vector::{vec2f, Vector2F},
     },
     keymap_matcher::Keystroke,
-    mac::platform::NSViewLayerContentsRedrawDuringViewResize,
     platform::{
         self,
-        mac::{renderer::Renderer, screen::Screen},
-        Event, WindowBounds,
+        mac::{
+            platform::NSViewLayerContentsRedrawDuringViewResize, renderer::Renderer, screen::Screen,
+        },
+        Event, InputHandler, KeyDownEvent, ModifiersChangedEvent, MouseButton, MouseButtonEvent,
+        MouseMovedEvent, Scene, WindowBounds, WindowKind,
     },
-    InputHandler, KeyDownEvent, ModifiersChangedEvent, MouseButton, MouseButtonEvent,
-    MouseMovedEvent, Scene, WindowKind,
 };
 use block::ConcreteBlock;
 use cocoa::{
@@ -670,14 +670,14 @@ impl platform::Window for Window {
         self.0.as_ref().borrow().titlebar_height()
     }
 
-    fn appearance(&self) -> crate::Appearance {
+    fn appearance(&self) -> platform::Appearance {
         unsafe {
             let appearance: id = msg_send![self.0.borrow().native_window, effectiveAppearance];
-            crate::Appearance::from_native(appearance)
+            platform::Appearance::from_native(appearance)
         }
     }
 
-    fn screen(&self) -> Rc<dyn crate::Screen> {
+    fn screen(&self) -> Rc<dyn platform::Screen> {
         unsafe {
             Rc::new(Screen {
                 native_screen: self.0.as_ref().borrow().native_window.screen(),

crates/gpui/src/platform/test.rs šŸ”—

@@ -64,7 +64,7 @@ impl super::ForegroundPlatform for ForegroundPlatform {
     fn on_resign_active(&self, _: Box<dyn FnMut()>) {}
     fn on_quit(&self, _: Box<dyn FnMut()>) {}
     fn on_reopen(&self, _: Box<dyn FnMut()>) {}
-    fn on_event(&self, _: Box<dyn FnMut(crate::Event) -> bool>) {}
+    fn on_event(&self, _: Box<dyn FnMut(crate::platform::Event) -> bool>) {}
     fn on_open_urls(&self, _: Box<dyn FnMut(Vec<String>)>) {}
 
     fn run(&self, _on_finish_launching: Box<dyn FnOnce()>) {
@@ -134,11 +134,11 @@ impl super::Platform for Platform {
 
     fn quit(&self) {}
 
-    fn screen_by_id(&self, _id: uuid::Uuid) -> Option<Rc<dyn crate::Screen>> {
+    fn screen_by_id(&self, _id: uuid::Uuid) -> Option<Rc<dyn crate::platform::Screen>> {
         None
     }
 
-    fn screens(&self) -> Vec<Rc<dyn crate::Screen>> {
+    fn screens(&self) -> Vec<Rc<dyn crate::platform::Screen>> {
         Default::default()
     }
 
@@ -158,7 +158,7 @@ impl super::Platform for Platform {
         None
     }
 
-    fn add_status_item(&self) -> Box<dyn crate::Window> {
+    fn add_status_item(&self) -> Box<dyn crate::platform::Window> {
         Box::new(Window::new(vec2f(24., 24.)))
     }
 
@@ -301,11 +301,11 @@ impl super::Window for Window {
         24.
     }
 
-    fn appearance(&self) -> crate::Appearance {
-        crate::Appearance::Light
+    fn appearance(&self) -> crate::platform::Appearance {
+        crate::platform::Appearance::Light
     }
 
-    fn screen(&self) -> Rc<dyn crate::Screen> {
+    fn screen(&self) -> Rc<dyn crate::platform::Screen> {
         Rc::new(Screen)
     }
 
@@ -313,9 +313,14 @@ impl super::Window for Window {
         self
     }
 
-    fn set_input_handler(&mut self, _: Box<dyn crate::InputHandler>) {}
+    fn set_input_handler(&mut self, _: Box<dyn crate::platform::InputHandler>) {}
 
-    fn prompt(&self, _: crate::PromptLevel, _: &str, _: &[&str]) -> oneshot::Receiver<usize> {
+    fn prompt(
+        &self,
+        _: crate::platform::PromptLevel,
+        _: &str,
+        _: &[&str],
+    ) -> oneshot::Receiver<usize> {
         let (done_tx, done_rx) = oneshot::channel();
         self.pending_prompts.borrow_mut().push_back(done_tx);
         done_rx
@@ -343,7 +348,7 @@ impl super::Window for Window {
 
     fn toggle_full_screen(&self) {}
 
-    fn on_event(&mut self, callback: Box<dyn FnMut(crate::Event) -> bool>) {
+    fn on_event(&mut self, callback: Box<dyn FnMut(crate::platform::Event) -> bool>) {
         self.event_handlers.push(callback);
     }
 

crates/gpui/src/presenter.rs šŸ”—

@@ -1,20 +1,19 @@
 use crate::{
-    app::{AppContext, MutableAppContext, WindowInvalidation},
+    app::WindowInvalidation,
     elements::Element,
     font_cache::FontCache,
     geometry::rect::RectF,
     json::{self, ToJson},
-    platform::{CursorStyle, Event},
+    platform::{Appearance, CursorStyle, Event, FontSystem, MouseButton, MouseMovedEvent},
     scene::{
         CursorRegion, MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseEvent, MouseHover,
         MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut, Scene,
     },
     text_layout::TextLayoutCache,
-    Action, AnyModelHandle, AnyViewHandle, AnyWeakModelHandle, AnyWeakViewHandle, Appearance,
-    AssetCache, ElementBox, Entity, FontSystem, ModelHandle, MouseButton, MouseMovedEvent,
-    MouseRegion, MouseRegionId, MouseState, ParentId, ReadModel, ReadView, RenderContext,
-    RenderParams, SceneBuilder, UpgradeModelHandle, UpgradeViewHandle, View, ViewHandle,
-    WeakModelHandle, WeakViewHandle,
+    Action, AnyModelHandle, AnyViewHandle, AnyWeakModelHandle, AnyWeakViewHandle, AppContext,
+    AssetCache, ElementBox, Entity, ModelHandle, MouseRegion, MouseRegionId, MouseState, ParentId,
+    ReadModel, ReadView, RenderContext, RenderParams, SceneBuilder, UpgradeModelHandle,
+    UpgradeViewHandle, View, ViewHandle, WeakModelHandle, WeakViewHandle,
 };
 use anyhow::bail;
 use collections::{HashMap, HashSet};
@@ -56,7 +55,7 @@ impl Presenter {
         font_cache: Arc<FontCache>,
         text_layout_cache: TextLayoutCache,
         asset_cache: Arc<AssetCache>,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> Self {
         Self {
             window_id,
@@ -80,7 +79,7 @@ impl Presenter {
         &mut self,
         invalidation: &mut WindowInvalidation,
         appearance: Appearance,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) {
         cx.start_frame();
         self.appearance = appearance;
@@ -111,7 +110,7 @@ impl Presenter {
         &mut self,
         invalidation: &mut WindowInvalidation,
         appearance: Appearance,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) {
         self.invalidate(invalidation, appearance, cx);
         for (view_id, view) in &mut self.rendered_views {
@@ -138,7 +137,7 @@ impl Presenter {
         window_size: Vector2F,
         scale_factor: f32,
         refreshing: bool,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> Scene {
         let mut scene_builder = SceneBuilder::new(scale_factor);
 
@@ -169,7 +168,7 @@ impl Presenter {
         }
     }
 
-    fn layout(&mut self, window_size: Vector2F, refreshing: bool, cx: &mut MutableAppContext) {
+    fn layout(&mut self, window_size: Vector2F, refreshing: bool, cx: &mut AppContext) {
         if let Some(root_view_id) = cx.root_view_id(self.window_id) {
             self.build_layout_context(window_size, refreshing, cx)
                 .layout(root_view_id, SizeConstraint::strict(window_size));
@@ -180,7 +179,7 @@ impl Presenter {
         &'a mut self,
         window_size: Vector2F,
         refreshing: bool,
-        cx: &'a mut MutableAppContext,
+        cx: &'a mut AppContext,
     ) -> LayoutContext<'a> {
         LayoutContext {
             window_id: self.window_id,
@@ -206,7 +205,7 @@ impl Presenter {
         &'a mut self,
         scene: &'a mut SceneBuilder,
         window_size: Vector2F,
-        cx: &'a mut MutableAppContext,
+        cx: &'a mut AppContext,
     ) -> PaintContext {
         PaintContext {
             scene,
@@ -234,7 +233,7 @@ impl Presenter {
         &mut self,
         event: Event,
         event_reused: bool,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> bool {
         let mut mouse_events = SmallVec::<[_; 2]>::new();
         let mut notified_views: HashSet<usize> = Default::default();
@@ -557,7 +556,7 @@ impl Presenter {
     pub fn build_event_context<'a>(
         &'a mut self,
         notified_views: &'a mut HashSet<usize>,
-        cx: &'a mut MutableAppContext,
+        cx: &'a mut AppContext,
     ) -> EventContext<'a> {
         EventContext {
             font_cache: &self.font_cache,
@@ -595,7 +594,7 @@ pub struct LayoutContext<'a> {
     pub font_system: Arc<dyn FontSystem>,
     pub text_layout_cache: &'a TextLayoutCache,
     pub asset_cache: &'a AssetCache,
-    pub app: &'a mut MutableAppContext,
+    pub app: &'a mut AppContext,
     pub refreshing: bool,
     pub window_size: Vector2F,
     titlebar_height: f32,
@@ -692,7 +691,7 @@ impl<'a> LayoutContext<'a> {
 }
 
 impl<'a> Deref for LayoutContext<'a> {
-    type Target = MutableAppContext;
+    type Target = AppContext;
 
     fn deref(&self) -> &Self::Target {
         self.app
@@ -804,7 +803,7 @@ impl<'a> Deref for PaintContext<'a> {
 pub struct EventContext<'a> {
     pub font_cache: &'a FontCache,
     pub text_layout_cache: &'a TextLayoutCache,
-    pub app: &'a mut MutableAppContext,
+    pub app: &'a mut AppContext,
     pub window_id: usize,
     pub notify_count: usize,
     view_stack: Vec<usize>,
@@ -871,7 +870,7 @@ impl<'a> EventContext<'a> {
 }
 
 impl<'a> Deref for EventContext<'a> {
-    type Target = MutableAppContext;
+    type Target = AppContext;
 
     fn deref(&self) -> &Self::Target {
         self.app

crates/gpui/src/scene/mouse_event.rs šŸ”—

@@ -1,12 +1,13 @@
+use crate::{
+    platform::{MouseButtonEvent, MouseMovedEvent, ScrollWheelEvent},
+    scene::mouse_region::HandlerKey,
+};
+use pathfinder_geometry::{rect::RectF, vector::Vector2F};
 use std::{
     mem::{discriminant, Discriminant},
     ops::Deref,
 };
 
-use pathfinder_geometry::{rect::RectF, vector::Vector2F};
-
-use crate::{scene::mouse_region::HandlerKey, MouseButtonEvent, MouseMovedEvent, ScrollWheelEvent};
-
 #[derive(Debug, Default, Clone)]
 pub struct MouseMove {
     pub region: RectF,

crates/gpui/src/scene/mouse_region.rs šŸ”—

@@ -5,7 +5,7 @@ use collections::HashMap;
 use pathfinder_geometry::rect::RectF;
 use smallvec::SmallVec;
 
-use crate::{EventContext, MouseButton};
+use crate::{platform::MouseButton, EventContext};
 
 use super::{
     mouse_event::{
@@ -290,7 +290,7 @@ impl HandlerSet {
                     handler(e, cx);
                 } else {
                     panic!(
-                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Move, found {:?}", 
+                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Move, found {:?}",
                         region_event);
                 }
             }));
@@ -307,7 +307,7 @@ impl HandlerSet {
                     handler(e, cx);
                 } else {
                     panic!(
-                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::MoveOut, found {:?}", 
+                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::MoveOut, found {:?}",
                         region_event);
                 }
             }));
@@ -325,7 +325,7 @@ impl HandlerSet {
                     handler(e, cx);
                 } else {
                     panic!(
-                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Down, found {:?}", 
+                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Down, found {:?}",
                         region_event);
                 }
             }));
@@ -343,7 +343,7 @@ impl HandlerSet {
                     handler(e, cx);
                 } else {
                     panic!(
-                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Up, found {:?}", 
+                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Up, found {:?}",
                         region_event);
                 }
             }));
@@ -361,7 +361,7 @@ impl HandlerSet {
                     handler(e, cx);
                 } else {
                     panic!(
-                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Click, found {:?}", 
+                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Click, found {:?}",
                         region_event);
                 }
             }));
@@ -379,7 +379,7 @@ impl HandlerSet {
                     handler(e, cx);
                 } else {
                     panic!(
-                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::DownOut, found {:?}", 
+                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::DownOut, found {:?}",
                         region_event);
                 }
             }));
@@ -397,7 +397,7 @@ impl HandlerSet {
                     handler(e, cx);
                 } else {
                     panic!(
-                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::UpOut, found {:?}", 
+                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::UpOut, found {:?}",
                         region_event);
                 }
             }));
@@ -415,7 +415,7 @@ impl HandlerSet {
                     handler(e, cx);
                 } else {
                     panic!(
-                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Drag, found {:?}", 
+                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Drag, found {:?}",
                         region_event);
                 }
             }));
@@ -429,7 +429,7 @@ impl HandlerSet {
                     handler(e, cx);
                 } else {
                     panic!(
-                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Hover, found {:?}", 
+                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Hover, found {:?}",
                         region_event);
                 }
             }));

crates/gpui/src/test.rs šŸ”—

@@ -17,9 +17,10 @@ use crate::{
     elements::Empty,
     executor::{self, ExecutorEvent},
     platform,
+    platform::Platform,
     util::CwdBacktrace,
-    Element, ElementBox, Entity, FontCache, Handle, MutableAppContext, Platform, RenderContext,
-    Subscription, TestAppContext, View,
+    AppContext, Element, ElementBox, Entity, FontCache, Handle, RenderContext, Subscription,
+    TestAppContext, View,
 };
 
 #[cfg(test)]
@@ -40,7 +41,7 @@ pub fn run_test(
     detect_nondeterminism: bool,
     test_fn: &mut (dyn RefUnwindSafe
               + Fn(
-        &mut MutableAppContext,
+        &mut AppContext,
         Rc<platform::test::ForegroundPlatform>,
         Arc<executor::Deterministic>,
         u64,

crates/gpui/src/text_layout.rs šŸ”—

@@ -5,7 +5,9 @@ use crate::{
         rect::RectF,
         vector::{vec2f, Vector2F},
     },
-    platform, scene, FontSystem, PaintContext,
+    platform,
+    platform::FontSystem,
+    scene, PaintContext,
 };
 use ordered_float::OrderedFloat;
 use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard};
@@ -660,7 +662,7 @@ mod tests {
     use crate::fonts::{Properties, Weight};
 
     #[crate::test(self)]
-    fn test_wrap_line(cx: &mut crate::MutableAppContext) {
+    fn test_wrap_line(cx: &mut crate::AppContext) {
         let font_cache = cx.font_cache().clone();
         let font_system = cx.platform().fonts();
         let family = font_cache
@@ -721,7 +723,7 @@ mod tests {
     }
 
     #[crate::test(self, retries = 5)]
-    fn test_wrap_shaped_line(cx: &mut crate::MutableAppContext) {
+    fn test_wrap_shaped_line(cx: &mut crate::AppContext) {
         // This is failing intermittently on CI and we don't have time to figure it out
         let font_cache = cx.font_cache().clone();
         let font_system = cx.platform().fonts();

crates/gpui/src/views.rs šŸ”—

@@ -2,6 +2,6 @@ mod select;
 
 pub use select::{ItemType, Select, SelectStyle};
 
-pub fn init(cx: &mut super::MutableAppContext) {
+pub fn init(cx: &mut super::AppContext) {
     select::init(cx);
 }

crates/gpui/src/views/select.rs šŸ”—

@@ -1,8 +1,8 @@
 use serde::Deserialize;
 
 use crate::{
-    actions, elements::*, impl_actions, AppContext, Entity, MouseButton, MutableAppContext,
-    RenderContext, View, ViewContext, WeakViewHandle,
+    actions, elements::*, impl_actions, platform::MouseButton, AppContext, Entity, RenderContext,
+    View, ViewContext, WeakViewHandle,
 };
 
 pub struct Select {
@@ -12,7 +12,7 @@ pub struct Select {
     item_count: usize,
     is_open: bool,
     list_state: UniformListState,
-    build_style: Option<Box<dyn FnMut(&mut MutableAppContext) -> SelectStyle>>,
+    build_style: Option<Box<dyn FnMut(&mut AppContext) -> SelectStyle>>,
 }
 
 #[derive(Clone, Default)]
@@ -35,7 +35,7 @@ impl_actions!(select, [SelectItem]);
 
 pub enum Event {}
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(Select::toggle);
     cx.add_action(Select::select_item);
 }
@@ -57,10 +57,7 @@ impl Select {
         }
     }
 
-    pub fn with_style(
-        mut self,
-        f: impl 'static + FnMut(&mut MutableAppContext) -> SelectStyle,
-    ) -> Self {
+    pub fn with_style(mut self, f: impl 'static + FnMut(&mut AppContext) -> SelectStyle) -> Self {
         self.build_style = Some(Box::new(f));
         self
     }

crates/journal/src/journal.rs šŸ”—

@@ -1,6 +1,6 @@
 use chrono::{Datelike, Local, NaiveTime, Timelike};
 use editor::{scroll::autoscroll::Autoscroll, Editor};
-use gpui::{actions, MutableAppContext};
+use gpui::{actions, AppContext};
 use settings::{HourFormat, Settings};
 use std::{
     fs::OpenOptions,
@@ -12,11 +12,11 @@ use workspace::AppState;
 
 actions!(journal, [NewJournalEntry]);
 
-pub fn init(app_state: Arc<AppState>, cx: &mut MutableAppContext) {
+pub fn init(app_state: Arc<AppState>, cx: &mut AppContext) {
     cx.add_global_action(move |_: &NewJournalEntry, cx| new_journal_entry(app_state.clone(), cx));
 }
 
-pub fn new_journal_entry(app_state: Arc<AppState>, cx: &mut MutableAppContext) {
+pub fn new_journal_entry(app_state: Arc<AppState>, cx: &mut AppContext) {
     let settings = cx.global::<Settings>();
     let journal_dir = match journal_dir(&settings) {
         Some(journal_dir) => journal_dir,

crates/language/src/buffer.rs šŸ”—

@@ -15,7 +15,7 @@ use anyhow::{anyhow, Result};
 use clock::ReplicaId;
 use fs::LineEnding;
 use futures::FutureExt as _;
-use gpui::{fonts::HighlightStyle, AppContext, Entity, ModelContext, MutableAppContext, Task};
+use gpui::{fonts::HighlightStyle, AppContext, Entity, ModelContext, Task};
 use parking_lot::Mutex;
 use settings::Settings;
 use similar::{ChangeTag, TextDiff};
@@ -232,7 +232,7 @@ pub trait LocalFile: File {
         fingerprint: RopeFingerprint,
         line_ending: LineEnding,
         mtime: SystemTime,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     );
 }
 

crates/language/src/buffer_tests.rs šŸ”—

@@ -2,7 +2,7 @@ use super::*;
 use clock::ReplicaId;
 use collections::BTreeMap;
 use fs::LineEnding;
-use gpui::{ModelHandle, MutableAppContext};
+use gpui::{AppContext, ModelHandle};
 use indoc::indoc;
 use proto::deserialize_operation;
 use rand::prelude::*;
@@ -35,7 +35,7 @@ fn init_logger() {
 }
 
 #[gpui::test]
-fn test_line_endings(cx: &mut gpui::MutableAppContext) {
+fn test_line_endings(cx: &mut gpui::AppContext) {
     cx.set_global(Settings::test(cx));
     cx.add_model(|cx| {
         let mut buffer =
@@ -128,7 +128,7 @@ fn test_select_language() {
 }
 
 #[gpui::test]
-fn test_edit_events(cx: &mut gpui::MutableAppContext) {
+fn test_edit_events(cx: &mut gpui::AppContext) {
     let mut now = Instant::now();
     let buffer_1_events = Rc::new(RefCell::new(Vec::new()));
     let buffer_2_events = Rc::new(RefCell::new(Vec::new()));
@@ -675,7 +675,7 @@ async fn test_symbols_containing(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-fn test_enclosing_bracket_ranges(cx: &mut MutableAppContext) {
+fn test_enclosing_bracket_ranges(cx: &mut AppContext) {
     let mut assert = |selection_text, range_markers| {
         assert_bracket_pairs(selection_text, range_markers, rust_lang(), cx)
     };
@@ -791,9 +791,7 @@ fn test_enclosing_bracket_ranges(cx: &mut MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_enclosing_bracket_ranges_where_brackets_are_not_outermost_children(
-    cx: &mut MutableAppContext,
-) {
+fn test_enclosing_bracket_ranges_where_brackets_are_not_outermost_children(cx: &mut AppContext) {
     let mut assert = |selection_text, bracket_pair_texts| {
         assert_bracket_pairs(selection_text, bracket_pair_texts, javascript_lang(), cx)
     };
@@ -825,7 +823,7 @@ fn test_enclosing_bracket_ranges_where_brackets_are_not_outermost_children(
 }
 
 #[gpui::test]
-fn test_range_for_syntax_ancestor(cx: &mut MutableAppContext) {
+fn test_range_for_syntax_ancestor(cx: &mut AppContext) {
     cx.add_model(|cx| {
         let text = "fn a() { b(|c| {}) }";
         let buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
@@ -863,7 +861,7 @@ fn test_range_for_syntax_ancestor(cx: &mut MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_autoindent_with_soft_tabs(cx: &mut MutableAppContext) {
+fn test_autoindent_with_soft_tabs(cx: &mut AppContext) {
     let settings = Settings::test(cx);
     cx.set_global(settings);
 
@@ -904,7 +902,7 @@ fn test_autoindent_with_soft_tabs(cx: &mut MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_autoindent_with_hard_tabs(cx: &mut MutableAppContext) {
+fn test_autoindent_with_hard_tabs(cx: &mut AppContext) {
     let mut settings = Settings::test(cx);
     settings.editor_overrides.hard_tabs = Some(true);
     cx.set_global(settings);
@@ -946,7 +944,7 @@ fn test_autoindent_with_hard_tabs(cx: &mut MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut MutableAppContext) {
+fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut AppContext) {
     let settings = Settings::test(cx);
     cx.set_global(settings);
 
@@ -1083,7 +1081,7 @@ fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut Muta
 }
 
 #[gpui::test]
-fn test_autoindent_does_not_adjust_lines_within_newly_created_errors(cx: &mut MutableAppContext) {
+fn test_autoindent_does_not_adjust_lines_within_newly_created_errors(cx: &mut AppContext) {
     let settings = Settings::test(cx);
     cx.set_global(settings);
 
@@ -1146,7 +1144,7 @@ fn test_autoindent_does_not_adjust_lines_within_newly_created_errors(cx: &mut Mu
 }
 
 #[gpui::test]
-fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut MutableAppContext) {
+fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut AppContext) {
     cx.set_global(Settings::test(cx));
     cx.add_model(|cx| {
         let mut buffer = Buffer::new(
@@ -1202,7 +1200,7 @@ fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut MutableAppConte
 }
 
 #[gpui::test]
-fn test_autoindent_with_edit_at_end_of_buffer(cx: &mut MutableAppContext) {
+fn test_autoindent_with_edit_at_end_of_buffer(cx: &mut AppContext) {
     cx.set_global(Settings::test(cx));
     cx.add_model(|cx| {
         let text = "a\nb";
@@ -1218,7 +1216,7 @@ fn test_autoindent_with_edit_at_end_of_buffer(cx: &mut MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_autoindent_multi_line_insertion(cx: &mut MutableAppContext) {
+fn test_autoindent_multi_line_insertion(cx: &mut AppContext) {
     cx.set_global(Settings::test(cx));
     cx.add_model(|cx| {
         let text = "
@@ -1258,7 +1256,7 @@ fn test_autoindent_multi_line_insertion(cx: &mut MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_autoindent_block_mode(cx: &mut MutableAppContext) {
+fn test_autoindent_block_mode(cx: &mut AppContext) {
     cx.set_global(Settings::test(cx));
     cx.add_model(|cx| {
         let text = r#"
@@ -1340,7 +1338,7 @@ fn test_autoindent_block_mode(cx: &mut MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_autoindent_block_mode_without_original_indent_columns(cx: &mut MutableAppContext) {
+fn test_autoindent_block_mode_without_original_indent_columns(cx: &mut AppContext) {
     cx.set_global(Settings::test(cx));
     cx.add_model(|cx| {
         let text = r#"
@@ -1418,7 +1416,7 @@ fn test_autoindent_block_mode_without_original_indent_columns(cx: &mut MutableAp
 }
 
 #[gpui::test]
-fn test_autoindent_language_without_indents_query(cx: &mut MutableAppContext) {
+fn test_autoindent_language_without_indents_query(cx: &mut AppContext) {
     cx.set_global(Settings::test(cx));
     cx.add_model(|cx| {
         let text = "
@@ -1461,7 +1459,7 @@ fn test_autoindent_language_without_indents_query(cx: &mut MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_autoindent_with_injected_languages(cx: &mut MutableAppContext) {
+fn test_autoindent_with_injected_languages(cx: &mut AppContext) {
     cx.set_global({
         let mut settings = Settings::test(cx);
         settings.language_overrides.extend([
@@ -1575,7 +1573,7 @@ fn test_autoindent_with_injected_languages(cx: &mut MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_autoindent_query_with_outdent_captures(cx: &mut MutableAppContext) {
+fn test_autoindent_query_with_outdent_captures(cx: &mut AppContext) {
     let mut settings = Settings::test(cx);
     settings.editor_defaults.tab_size = Some(2.try_into().unwrap());
     cx.set_global(settings);
@@ -1618,7 +1616,7 @@ fn test_autoindent_query_with_outdent_captures(cx: &mut MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_language_config_at(cx: &mut MutableAppContext) {
+fn test_language_config_at(cx: &mut AppContext) {
     cx.set_global(Settings::test(cx));
     cx.add_model(|cx| {
         let language = Language::new(
@@ -1705,7 +1703,7 @@ fn test_language_config_at(cx: &mut MutableAppContext) {
 }
 
 #[gpui::test]
-fn test_serialization(cx: &mut gpui::MutableAppContext) {
+fn test_serialization(cx: &mut gpui::AppContext) {
     let mut now = Instant::now();
 
     let buffer1 = cx.add_model(|cx| {
@@ -1746,7 +1744,7 @@ fn test_serialization(cx: &mut gpui::MutableAppContext) {
 }
 
 #[gpui::test(iterations = 100)]
-fn test_random_collaboration(cx: &mut MutableAppContext, mut rng: StdRng) {
+fn test_random_collaboration(cx: &mut AppContext, mut rng: StdRng) {
     let min_peers = env::var("MIN_PEERS")
         .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
         .unwrap_or(1);
@@ -2199,7 +2197,7 @@ fn assert_bracket_pairs(
     selection_text: &'static str,
     bracket_pair_texts: Vec<&'static str>,
     language: Language,
-    cx: &mut MutableAppContext,
+    cx: &mut AppContext,
 ) {
     cx.set_global(Settings::test(cx));
     let (expected_text, selection_ranges) = marked_text_ranges(selection_text, false);

crates/language/src/language.rs šŸ”—

@@ -16,7 +16,7 @@ use futures::{
     future::{BoxFuture, Shared},
     FutureExt, TryFutureExt as _,
 };
-use gpui::{executor::Background, MutableAppContext, Task};
+use gpui::{executor::Background, AppContext, Task};
 use highlight_map::HighlightMap;
 use lazy_static::lazy_static;
 use lsp::CodeActionKind;
@@ -147,7 +147,7 @@ impl CachedLspAdapter {
 
     pub fn workspace_configuration(
         &self,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> Option<BoxFuture<'static, Value>> {
         self.adapter.workspace_configuration(cx)
     }
@@ -223,10 +223,7 @@ pub trait LspAdapter: 'static + Send + Sync {
         None
     }
 
-    fn workspace_configuration(
-        &self,
-        _: &mut MutableAppContext,
-    ) -> Option<BoxFuture<'static, Value>> {
+    fn workspace_configuration(&self, _: &mut AppContext) -> Option<BoxFuture<'static, Value>> {
         None
     }
 
@@ -584,7 +581,7 @@ impl LanguageRegistry {
         result
     }
 
-    pub fn workspace_configuration(&self, cx: &mut MutableAppContext) -> Task<serde_json::Value> {
+    pub fn workspace_configuration(&self, cx: &mut AppContext) -> Task<serde_json::Value> {
         let lsp_adapters = {
             let state = self.state.read();
             state
@@ -769,7 +766,7 @@ impl LanguageRegistry {
         language: Arc<Language>,
         root_path: Arc<Path>,
         http_client: Arc<dyn HttpClient>,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> Option<Task<Result<lsp::LanguageServer>>> {
         #[cfg(any(test, feature = "test-support"))]
         if language.fake_adapter.is_some() {

crates/language_selector/src/active_buffer_language.rs šŸ”—

@@ -1,7 +1,8 @@
 use editor::Editor;
 use gpui::{
-    elements::*, CursorStyle, Entity, MouseButton, RenderContext, Subscription, View, ViewContext,
-    ViewHandle,
+    elements::*,
+    platform::{CursorStyle, MouseButton},
+    Entity, RenderContext, Subscription, View, ViewContext, ViewHandle,
 };
 use settings::Settings;
 use std::sync::Arc;

crates/language_selector/src/language_selector.rs šŸ”—

@@ -5,7 +5,7 @@ use editor::Editor;
 use fuzzy::{match_strings, StringMatch, StringMatchCandidate};
 use gpui::{
     actions, elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MouseState,
-    MutableAppContext, RenderContext, View, ViewContext, ViewHandle,
+    RenderContext, View, ViewContext, ViewHandle,
 };
 use language::{Buffer, LanguageRegistry};
 use picker::{Picker, PickerDelegate};
@@ -16,7 +16,7 @@ use workspace::{AppState, Workspace};
 
 actions!(language_selector, [Toggle]);
 
-pub fn init(app_state: Arc<AppState>, cx: &mut MutableAppContext) {
+pub fn init(app_state: Arc<AppState>, cx: &mut AppContext) {
     Picker::<LanguageSelector>::init(cx);
     cx.add_action({
         let language_registry = app_state.languages.clone();

crates/outline/src/outline.rs šŸ”—

@@ -5,7 +5,7 @@ use editor::{
 use fuzzy::StringMatch;
 use gpui::{
     actions, elements::*, geometry::vector::Vector2F, AnyViewHandle, AppContext, Entity,
-    MouseState, MutableAppContext, RenderContext, Task, View, ViewContext, ViewHandle,
+    MouseState, RenderContext, Task, View, ViewContext, ViewHandle,
 };
 use language::Outline;
 use ordered_float::OrderedFloat;
@@ -16,7 +16,7 @@ use workspace::Workspace;
 
 actions!(outline, [Toggle]);
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(OutlineView::toggle);
     Picker::<OutlineView>::init(cx);
 }
@@ -38,7 +38,7 @@ pub enum Event {
 impl Entity for OutlineView {
     type Event = Event;
 
-    fn release(&mut self, cx: &mut MutableAppContext) {
+    fn release(&mut self, cx: &mut AppContext) {
         self.restore_active_editor(cx);
     }
 }
@@ -100,7 +100,7 @@ impl OutlineView {
         }
     }
 
-    fn restore_active_editor(&mut self, cx: &mut MutableAppContext) {
+    fn restore_active_editor(&mut self, cx: &mut AppContext) {
         self.active_editor.update(cx, |editor, cx| {
             editor.highlight_rows(None);
             if let Some(scroll_position) = self.prev_scroll_position {

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

@@ -3,9 +3,9 @@ use gpui::{
     elements::*,
     geometry::vector::{vec2f, Vector2F},
     keymap_matcher::KeymapContext,
-    platform::CursorStyle,
-    AnyViewHandle, AppContext, Axis, Entity, MouseButton, MouseState, MutableAppContext,
-    RenderContext, Task, View, ViewContext, ViewHandle, WeakViewHandle,
+    platform::{CursorStyle, MouseButton},
+    AnyViewHandle, AppContext, Axis, Entity, MouseState, RenderContext, Task, View, ViewContext,
+    ViewHandle, WeakViewHandle,
 };
 use menu::{Cancel, Confirm, SelectFirst, SelectIndex, SelectLast, SelectNext, SelectPrev};
 use parking_lot::Mutex;
@@ -141,7 +141,7 @@ impl<D: PickerDelegate> View for Picker<D> {
 }
 
 impl<D: PickerDelegate> Picker<D> {
-    pub fn init(cx: &mut MutableAppContext) {
+    pub fn init(cx: &mut AppContext) {
         cx.add_action(Self::select_first);
         cx.add_action(Self::select_last);
         cx.add_action(Self::select_next);

crates/project/src/lsp_command.rs šŸ”—

@@ -4,7 +4,7 @@ use crate::{
 use anyhow::{anyhow, Result};
 use async_trait::async_trait;
 use client::proto::{self, PeerId};
-use gpui::{AppContext, AsyncAppContext, ModelHandle, MutableAppContext};
+use gpui::{AppContext, AsyncAppContext, ModelHandle};
 use language::{
     point_from_lsp, point_to_lsp,
     proto::{deserialize_anchor, deserialize_version, serialize_anchor, serialize_version},
@@ -49,7 +49,7 @@ pub(crate) trait LspCommand: 'static + Sized {
         project: &mut Project,
         peer_id: PeerId,
         buffer_version: &clock::Global,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> <Self::ProtoRequest as proto::RequestMessage>::Response;
     async fn response_from_proto(
         self,
@@ -175,7 +175,7 @@ impl LspCommand for PrepareRename {
         _: &mut Project,
         _: PeerId,
         buffer_version: &clock::Global,
-        _: &mut MutableAppContext,
+        _: &mut AppContext,
     ) -> proto::PrepareRenameResponse {
         proto::PrepareRenameResponse {
             can_rename: range.is_some(),
@@ -296,7 +296,7 @@ impl LspCommand for PerformRename {
         project: &mut Project,
         peer_id: PeerId,
         _: &clock::Global,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> proto::PerformRenameResponse {
         let transaction = project.serialize_project_transaction_for_peer(response, peer_id, cx);
         proto::PerformRenameResponse {
@@ -391,7 +391,7 @@ impl LspCommand for GetDefinition {
         project: &mut Project,
         peer_id: PeerId,
         _: &clock::Global,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> proto::GetDefinitionResponse {
         let links = location_links_to_proto(response, project, peer_id, cx);
         proto::GetDefinitionResponse { links }
@@ -477,7 +477,7 @@ impl LspCommand for GetTypeDefinition {
         project: &mut Project,
         peer_id: PeerId,
         _: &clock::Global,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> proto::GetTypeDefinitionResponse {
         let links = location_links_to_proto(response, project, peer_id, cx);
         proto::GetTypeDefinitionResponse { links }
@@ -658,7 +658,7 @@ fn location_links_to_proto(
     links: Vec<LocationLink>,
     project: &mut Project,
     peer_id: PeerId,
-    cx: &mut MutableAppContext,
+    cx: &mut AppContext,
 ) -> Vec<proto::LocationLink> {
     links
         .into_iter()
@@ -787,7 +787,7 @@ impl LspCommand for GetReferences {
         project: &mut Project,
         peer_id: PeerId,
         _: &clock::Global,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> proto::GetReferencesResponse {
         let locations = response
             .into_iter()
@@ -928,7 +928,7 @@ impl LspCommand for GetDocumentHighlights {
         _: &mut Project,
         _: PeerId,
         _: &clock::Global,
-        _: &mut MutableAppContext,
+        _: &mut AppContext,
     ) -> proto::GetDocumentHighlightsResponse {
         let highlights = response
             .into_iter()
@@ -1130,7 +1130,7 @@ impl LspCommand for GetHover {
         _: &mut Project,
         _: PeerId,
         _: &clock::Global,
-        _: &mut MutableAppContext,
+        _: &mut AppContext,
     ) -> proto::GetHoverResponse {
         if let Some(response) = response {
             let (start, end) = if let Some(range) = response.range {

crates/project/src/project.rs šŸ”—

@@ -21,8 +21,8 @@ use futures::{
     AsyncWriteExt, Future, FutureExt, StreamExt, TryFutureExt,
 };
 use gpui::{
-    AnyModelHandle, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle,
-    MutableAppContext, Task, UpgradeModelHandle, WeakModelHandle,
+    AnyModelHandle, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, Task,
+    UpgradeModelHandle, WeakModelHandle,
 };
 use language::{
     point_to_lsp,
@@ -427,7 +427,7 @@ impl Project {
         user_store: ModelHandle<UserStore>,
         languages: Arc<LanguageRegistry>,
         fs: Arc<dyn Fs>,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> ModelHandle<Self> {
         cx.add_model(|cx: &mut ModelContext<Self>| {
             let (tx, rx) = mpsc::unbounded();
@@ -5902,7 +5902,7 @@ impl Project {
         &mut self,
         project_transaction: ProjectTransaction,
         peer_id: proto::PeerId,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> proto::ProjectTransaction {
         let mut serialized_transaction = proto::ProjectTransaction {
             buffer_ids: Default::default(),
@@ -5960,7 +5960,7 @@ impl Project {
         &mut self,
         buffer: &ModelHandle<Buffer>,
         peer_id: proto::PeerId,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> u64 {
         let buffer_id = buffer.read(cx).remote_id();
         if let Some(project_id) = self.remote_id() {
@@ -6573,7 +6573,7 @@ impl<'a> Iterator for PathMatchCandidateSetIter<'a> {
 impl Entity for Project {
     type Event = Event;
 
-    fn release(&mut self, _: &mut gpui::MutableAppContext) {
+    fn release(&mut self, _: &mut gpui::AppContext) {
         match &self.client_state {
             Some(ProjectClientState::Local { remote_id, .. }) => {
                 let _ = self.client.send(proto::UnshareProject {
@@ -6591,7 +6591,7 @@ impl Entity for Project {
 
     fn app_will_quit(
         &mut self,
-        _: &mut MutableAppContext,
+        _: &mut AppContext,
     ) -> Option<std::pin::Pin<Box<dyn 'static + Future<Output = ()>>>> {
         let shutdown_futures = self
             .language_servers

crates/project/src/project_tests.rs šŸ”—

@@ -2,6 +2,7 @@ use crate::{worktree::WorktreeHandle, Event, *};
 use fs::LineEnding;
 use fs::{FakeFs, RealFs};
 use futures::{future, StreamExt};
+use gpui::AppContext;
 use gpui::{executor::Deterministic, test::subscribe};
 use language::{
     tree_sitter_rust, tree_sitter_typescript, Diagnostic, FakeLspAdapter, LanguageConfig,

crates/project/src/worktree.rs šŸ”—

@@ -16,10 +16,7 @@ use futures::{
 };
 use fuzzy::CharBag;
 use git::{DOT_GIT, GITIGNORE};
-use gpui::{
-    executor, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext,
-    Task,
-};
+use gpui::{executor, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, Task};
 use language::{
     proto::{
         deserialize_fingerprint, deserialize_version, serialize_fingerprint, serialize_line_ending,
@@ -287,7 +284,7 @@ impl Worktree {
         replica_id: ReplicaId,
         worktree: proto::WorktreeMetadata,
         client: Arc<Client>,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> ModelHandle<Self> {
         cx.add_model(|cx: &mut ModelContext<Self>| {
             let snapshot = Snapshot {
@@ -1895,7 +1892,7 @@ impl language::LocalFile for File {
         fingerprint: RopeFingerprint,
         line_ending: LineEnding,
         mtime: SystemTime,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) {
         let worktree = self.worktree.read(cx).as_local().unwrap();
         if let Some(project_id) = worktree.share.as_ref().map(|share| share.project_id) {

crates/project_panel/src/project_panel.rs šŸ”—

@@ -12,9 +12,9 @@ use gpui::{
     geometry::vector::Vector2F,
     impl_internal_actions,
     keymap_matcher::KeymapContext,
-    platform::CursorStyle,
-    AppContext, ClipboardItem, Element, ElementBox, Entity, ModelHandle, MouseButton,
-    MutableAppContext, PromptLevel, RenderContext, Task, View, ViewContext, ViewHandle,
+    platform::{CursorStyle, MouseButton, PromptLevel},
+    AppContext, ClipboardItem, Element, ElementBox, Entity, ModelHandle, RenderContext, Task, View,
+    ViewContext, ViewHandle,
 };
 use menu::{Confirm, SelectNext, SelectPrev};
 use project::{Entry, EntryKind, Project, ProjectEntryId, ProjectPath, Worktree, WorktreeId};
@@ -24,7 +24,7 @@ use std::{
     collections::{hash_map, HashMap},
     ffi::OsStr,
     ops::Range,
-    path::{Path, PathBuf},
+    path::Path,
     sync::Arc,
 };
 use theme::ProjectPanelEntry;
@@ -119,6 +119,7 @@ actions!(
         NewFile,
         Copy,
         CopyPath,
+        CopyRelativePath,
         RevealInFinder,
         Cut,
         Paste,
@@ -132,7 +133,7 @@ impl_internal_actions!(
     [Open, ToggleExpanded, DeployContextMenu, MoveProjectEntry]
 );
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(ProjectPanel::deploy_context_menu);
     cx.add_action(ProjectPanel::expand_selected_entry);
     cx.add_action(ProjectPanel::collapse_selected_entry);
@@ -146,10 +147,11 @@ pub fn init(cx: &mut MutableAppContext) {
     cx.add_async_action(ProjectPanel::delete);
     cx.add_async_action(ProjectPanel::confirm);
     cx.add_action(ProjectPanel::cancel);
+    cx.add_action(ProjectPanel::cut);
     cx.add_action(ProjectPanel::copy);
     cx.add_action(ProjectPanel::copy_path);
+    cx.add_action(ProjectPanel::copy_relative_path);
     cx.add_action(ProjectPanel::reveal_in_finder);
-    cx.add_action(ProjectPanel::cut);
     cx.add_action(
         |this: &mut ProjectPanel, action: &Paste, cx: &mut ViewContext<ProjectPanel>| {
             this.paste(action, cx);
@@ -307,11 +309,16 @@ impl ProjectPanel {
             }
             menu_entries.push(ContextMenuItem::item("New File", NewFile));
             menu_entries.push(ContextMenuItem::item("New Folder", NewDirectory));
-            menu_entries.push(ContextMenuItem::item("Reveal in Finder", RevealInFinder));
             menu_entries.push(ContextMenuItem::Separator);
+            menu_entries.push(ContextMenuItem::item("Cut", Cut));
             menu_entries.push(ContextMenuItem::item("Copy", Copy));
+            menu_entries.push(ContextMenuItem::Separator);
             menu_entries.push(ContextMenuItem::item("Copy Path", CopyPath));
-            menu_entries.push(ContextMenuItem::item("Cut", Cut));
+            menu_entries.push(ContextMenuItem::item(
+                "Copy Relative Path",
+                CopyRelativePath,
+            ));
+            menu_entries.push(ContextMenuItem::item("Reveal in Finder", RevealInFinder));
             if let Some(clipboard_entry) = self.clipboard_entry {
                 if clipboard_entry.worktree_id() == worktree.id() {
                     menu_entries.push(ContextMenuItem::item("Paste", Paste));
@@ -785,10 +792,19 @@ impl ProjectPanel {
 
     fn copy_path(&mut self, _: &CopyPath, cx: &mut ViewContext<Self>) {
         if let Some((worktree, entry)) = self.selected_entry(cx) {
-            let mut path = PathBuf::new();
-            path.push(worktree.root_name());
-            path.push(&entry.path);
-            cx.write_to_clipboard(ClipboardItem::new(path.to_string_lossy().to_string()));
+            cx.write_to_clipboard(ClipboardItem::new(
+                worktree
+                    .abs_path()
+                    .join(&entry.path)
+                    .to_string_lossy()
+                    .to_string(),
+            ));
+        }
+    }
+
+    fn copy_relative_path(&mut self, _: &CopyRelativePath, cx: &mut ViewContext<Self>) {
+        if let Some((_, entry)) = self.selected_entry(cx) {
+            cx.write_to_clipboard(ClipboardItem::new(entry.path.to_string_lossy().to_string()));
         }
     }
 

crates/project_symbols/src/project_symbols.rs šŸ”—

@@ -5,7 +5,7 @@ use editor::{
 use fuzzy::{StringMatch, StringMatchCandidate};
 use gpui::{
     actions, elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MouseState,
-    MutableAppContext, RenderContext, Task, View, ViewContext, ViewHandle,
+    RenderContext, Task, View, ViewContext, ViewHandle,
 };
 use ordered_float::OrderedFloat;
 use picker::{Picker, PickerDelegate};
@@ -17,7 +17,7 @@ use workspace::Workspace;
 
 actions!(project_symbols, [Toggle]);
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(ProjectSymbolsView::toggle);
     Picker::<ProjectSymbolsView>::init(cx);
 }

crates/recent_projects/src/recent_projects.rs šŸ”—

@@ -4,8 +4,8 @@ use fuzzy::{StringMatch, StringMatchCandidate};
 use gpui::{
     actions,
     elements::{ChildView, Flex, ParentElement},
-    AnyViewHandle, Element, ElementBox, Entity, MutableAppContext, RenderContext, Task, View,
-    ViewContext, ViewHandle,
+    AnyViewHandle, AppContext, Element, ElementBox, Entity, RenderContext, Task, View, ViewContext,
+    ViewHandle,
 };
 use highlighted_workspace_location::HighlightedWorkspaceLocation;
 use ordered_float::OrderedFloat;
@@ -18,7 +18,7 @@ use workspace::{
 
 actions!(projects, [OpenRecent]);
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(RecentProjectsView::toggle);
     Picker::<RecentProjectsView>::init(cx);
 }

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

@@ -5,9 +5,12 @@ use crate::{
 use collections::HashMap;
 use editor::Editor;
 use gpui::{
-    actions, elements::*, impl_actions, platform::CursorStyle, Action, AnyViewHandle, AppContext,
-    Entity, MouseButton, MutableAppContext, RenderContext, Subscription, Task, View, ViewContext,
-    ViewHandle,
+    actions,
+    elements::*,
+    impl_actions,
+    platform::{CursorStyle, MouseButton},
+    Action, AnyViewHandle, AppContext, Entity, RenderContext, Subscription, Task, View,
+    ViewContext, ViewHandle,
 };
 use project::search::SearchQuery;
 use serde::Deserialize;
@@ -31,7 +34,7 @@ pub enum Event {
     UpdateLocation,
 }
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(BufferSearchBar::deploy);
     cx.add_action(BufferSearchBar::dismiss);
     cx.add_action(BufferSearchBar::focus_editor);
@@ -45,7 +48,7 @@ pub fn init(cx: &mut MutableAppContext) {
     add_toggle_option_action::<ToggleRegex>(SearchOption::Regex, cx);
 }
 
-fn add_toggle_option_action<A: Action>(option: SearchOption, cx: &mut MutableAppContext) {
+fn add_toggle_option_action<A: Action>(option: SearchOption, cx: &mut AppContext) {
     cx.add_action(move |pane: &mut Pane, _: &A, cx: &mut ViewContext<Pane>| {
         if let Some(search_bar) = pane.toolbar().read(cx).item_of_type::<BufferSearchBar>() {
             if search_bar.update(cx, |search_bar, cx| search_bar.show(false, false, cx)) {

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

@@ -9,9 +9,12 @@ use editor::{
 };
 use futures::StreamExt;
 use gpui::{
-    actions, elements::*, platform::CursorStyle, Action, AnyViewHandle, AppContext, ElementBox,
-    Entity, ModelContext, ModelHandle, MouseButton, MutableAppContext, RenderContext, Subscription,
-    Task, View, ViewContext, ViewHandle, WeakModelHandle, WeakViewHandle,
+    actions,
+    elements::*,
+    platform::{CursorStyle, MouseButton},
+    Action, AnyViewHandle, AppContext, ElementBox, Entity, ModelContext, ModelHandle,
+    RenderContext, Subscription, Task, View, ViewContext, ViewHandle, WeakModelHandle,
+    WeakViewHandle,
 };
 use menu::Confirm;
 use project::{search::SearchQuery, Project};
@@ -36,7 +39,7 @@ actions!(project_search, [SearchInNew, ToggleFocus]);
 #[derive(Default)]
 struct ActiveSearches(HashMap<WeakModelHandle<Project>, WeakViewHandle<ProjectSearchView>>);
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.set_global(ActiveSearches::default());
     cx.add_action(ProjectSearchView::deploy);
     cx.add_action(ProjectSearchBar::search);
@@ -50,7 +53,7 @@ pub fn init(cx: &mut MutableAppContext) {
     add_toggle_option_action::<ToggleRegex>(SearchOption::Regex, cx);
 }
 
-fn add_toggle_option_action<A: Action>(option: SearchOption, cx: &mut MutableAppContext) {
+fn add_toggle_option_action<A: Action>(option: SearchOption, cx: &mut AppContext) {
     cx.add_action(move |pane: &mut Pane, _: &A, cx: &mut ViewContext<Pane>| {
         if let Some(search_bar) = pane.toolbar().read(cx).item_of_type::<ProjectSearchBar>() {
             if search_bar.update(cx, |search_bar, cx| {

crates/search/src/search.rs šŸ”—

@@ -1,11 +1,11 @@
 pub use buffer_search::BufferSearchBar;
-use gpui::{actions, Action, MutableAppContext};
+use gpui::{actions, Action, AppContext};
 pub use project_search::{ProjectSearchBar, ProjectSearchView};
 
 pub mod buffer_search;
 pub mod project_search;
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     buffer_search::init(cx);
     project_search::init(cx);
 }

crates/settings/src/keymap_file.rs šŸ”—

@@ -2,7 +2,7 @@ use crate::{parse_json_with_comments, Settings};
 use anyhow::{Context, Result};
 use assets::Assets;
 use collections::BTreeMap;
-use gpui::{keymap_matcher::Binding, MutableAppContext};
+use gpui::{keymap_matcher::Binding, AppContext};
 use schemars::{
     gen::{SchemaGenerator, SchemaSettings},
     schema::{InstanceType, Schema, SchemaObject, SingleOrVec, SubschemaValidation},
@@ -41,7 +41,7 @@ impl JsonSchema for KeymapAction {
 struct ActionWithData(Box<str>, Box<RawValue>);
 
 impl KeymapFileContent {
-    pub fn load_defaults(cx: &mut MutableAppContext) {
+    pub fn load_defaults(cx: &mut AppContext) {
         for path in ["keymaps/default.json", "keymaps/vim.json"] {
             Self::load(path, cx).unwrap();
         }
@@ -51,13 +51,13 @@ impl KeymapFileContent {
         }
     }
 
-    pub fn load(asset_path: &str, cx: &mut MutableAppContext) -> Result<()> {
+    pub fn load(asset_path: &str, cx: &mut AppContext) -> Result<()> {
         let content = Assets::get(asset_path).unwrap().data;
         let content_str = std::str::from_utf8(content.as_ref()).unwrap();
         parse_json_with_comments::<Self>(content_str)?.add_to_cx(cx)
     }
 
-    pub fn add_to_cx(self, cx: &mut MutableAppContext) -> Result<()> {
+    pub fn add_to_cx(self, cx: &mut AppContext) -> Result<()> {
         for KeymapBlock { context, bindings } in self.0 {
             let bindings = bindings
                 .into_iter()

crates/settings/src/settings_file.rs šŸ”—

@@ -2,7 +2,7 @@ use crate::{update_settings_file, watched_json::WatchedJsonFile, SettingsFileCon
 use anyhow::Result;
 use assets::Assets;
 use fs::Fs;
-use gpui::{AssetSource, MutableAppContext};
+use gpui::{AppContext, AssetSource};
 use std::{io::ErrorKind, path::Path, sync::Arc};
 
 // TODO: Switch SettingsFile to open a worktree and buffer for synchronization
@@ -49,7 +49,7 @@ impl SettingsFile {
     }
 
     pub fn update(
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
         update: impl 'static + Send + FnOnce(&mut SettingsFileContent),
     ) {
         let this = cx.global::<SettingsFile>();
@@ -211,7 +211,7 @@ mod tests {
     }
 
     fn assert_key_bindings_for<'a>(
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
         actions: Vec<(&'static str, &'a dyn Action)>,
         line: u32,
     ) {

crates/settings/src/watched_json.rs šŸ”—

@@ -1,6 +1,6 @@
 use fs::Fs;
 use futures::StreamExt;
-use gpui::{executor, MutableAppContext};
+use gpui::{executor, AppContext};
 use postage::sink::Sink as _;
 use postage::{prelude::Stream, watch};
 use serde::Deserialize;
@@ -67,7 +67,7 @@ pub fn watch_files(
     settings_file: WatchedJsonFile<SettingsFileContent>,
     theme_registry: Arc<ThemeRegistry>,
     keymap_file: WatchedJsonFile<KeymapFileContent>,
-    cx: &mut MutableAppContext,
+    cx: &mut AppContext,
 ) {
     watch_settings_file(defaults, settings_file, theme_registry, cx);
     watch_keymap_file(keymap_file, cx);
@@ -77,7 +77,7 @@ pub(crate) fn watch_settings_file(
     defaults: Settings,
     mut file: WatchedJsonFile<SettingsFileContent>,
     theme_registry: Arc<ThemeRegistry>,
-    cx: &mut MutableAppContext,
+    cx: &mut AppContext,
 ) {
     settings_updated(&defaults, file.0.borrow().clone(), &theme_registry, cx);
     cx.spawn(|mut cx| async move {
@@ -88,7 +88,7 @@ pub(crate) fn watch_settings_file(
     .detach();
 }
 
-fn keymap_updated(content: KeymapFileContent, cx: &mut MutableAppContext) {
+fn keymap_updated(content: KeymapFileContent, cx: &mut AppContext) {
     cx.clear_bindings();
     KeymapFileContent::load_defaults(cx);
     content.add_to_cx(cx).log_err();
@@ -98,7 +98,7 @@ fn settings_updated(
     defaults: &Settings,
     content: SettingsFileContent,
     theme_registry: &Arc<ThemeRegistry>,
-    cx: &mut MutableAppContext,
+    cx: &mut AppContext,
 ) {
     let mut settings = defaults.clone();
     settings.set_user_settings(content, theme_registry, cx.font_cache());
@@ -106,7 +106,7 @@ fn settings_updated(
     cx.refresh_windows();
 }
 
-fn watch_keymap_file(mut file: WatchedJsonFile<KeymapFileContent>, cx: &mut MutableAppContext) {
+fn watch_keymap_file(mut file: WatchedJsonFile<KeymapFileContent>, cx: &mut AppContext) {
     cx.spawn(|mut cx| async move {
         let mut settings_subscription = None;
         while let Some(content) = file.0.recv().await {

crates/staff_mode/src/staff_mode.rs šŸ”—

@@ -1,4 +1,4 @@
-use gpui::MutableAppContext;
+use gpui::AppContext;
 
 #[derive(Debug, Default)]
 pub struct StaffMode(pub bool);
@@ -13,10 +13,7 @@ impl std::ops::Deref for StaffMode {
 
 /// Despite what the type system requires me to tell you, the init function will only be called a once
 /// as soon as we know that the staff mode is enabled.
-pub fn staff_mode<F: FnMut(&mut MutableAppContext) + 'static>(
-    cx: &mut MutableAppContext,
-    mut init: F,
-) {
+pub fn staff_mode<F: FnMut(&mut AppContext) + 'static>(cx: &mut AppContext, mut init: F) {
     if **cx.default_global::<StaffMode>() {
         init(cx)
     } else {
@@ -32,10 +29,7 @@ pub fn staff_mode<F: FnMut(&mut MutableAppContext) + 'static>(
 
 /// Immediately checks and runs the init function if the staff mode is not enabled.
 /// This is only included for symettry with staff_mode() above
-pub fn not_staff_mode<F: FnOnce(&mut MutableAppContext) + 'static>(
-    cx: &mut MutableAppContext,
-    init: F,
-) {
+pub fn not_staff_mode<F: FnOnce(&mut AppContext) + 'static>(cx: &mut AppContext, init: F) {
     if !**cx.default_global::<StaffMode>() {
         init(cx)
     }

crates/terminal/src/mappings/mouse.rs šŸ”—

@@ -6,8 +6,12 @@ use alacritty_terminal::grid::Dimensions;
 /// with modifications for our circumstances
 use alacritty_terminal::index::{Column as GridCol, Line as GridLine, Point, Side};
 use alacritty_terminal::term::TermMode;
+use gpui::platform;
 use gpui::scene::MouseScrollWheel;
-use gpui::{geometry::vector::Vector2F, MouseButtonEvent, MouseMovedEvent, ScrollWheelEvent};
+use gpui::{
+    geometry::vector::Vector2F,
+    platform::{MouseButtonEvent, MouseMovedEvent, ScrollWheelEvent},
+};
 
 use crate::TerminalSize;
 
@@ -78,10 +82,10 @@ impl MouseButton {
     fn from_move(e: &MouseMovedEvent) -> Self {
         match e.pressed_button {
             Some(b) => match b {
-                gpui::MouseButton::Left => MouseButton::LeftMove,
-                gpui::MouseButton::Middle => MouseButton::MiddleMove,
-                gpui::MouseButton::Right => MouseButton::RightMove,
-                gpui::MouseButton::Navigate(_) => MouseButton::Other,
+                platform::MouseButton::Left => MouseButton::LeftMove,
+                platform::MouseButton::Middle => MouseButton::MiddleMove,
+                platform::MouseButton::Right => MouseButton::RightMove,
+                platform::MouseButton::Navigate(_) => MouseButton::Other,
             },
             None => MouseButton::NoneMove,
         }
@@ -89,10 +93,10 @@ impl MouseButton {
 
     fn from_button(e: &MouseButtonEvent) -> Self {
         match e.button {
-            gpui::MouseButton::Left => MouseButton::LeftButton,
-            gpui::MouseButton::Right => MouseButton::MiddleButton,
-            gpui::MouseButton::Middle => MouseButton::RightButton,
-            gpui::MouseButton::Navigate(_) => MouseButton::Other,
+            platform::MouseButton::Left => MouseButton::LeftButton,
+            platform::MouseButton::Right => MouseButton::MiddleButton,
+            platform::MouseButton::Middle => MouseButton::RightButton,
+            platform::MouseButton::Navigate(_) => MouseButton::Other,
         }
     }
 

crates/terminal/src/terminal.rs šŸ”—

@@ -49,8 +49,9 @@ use thiserror::Error;
 use gpui::{
     geometry::vector::{vec2f, Vector2F},
     keymap_matcher::Keystroke,
+    platform::{MouseButton, MouseMovedEvent, TouchPhase},
     scene::{MouseDown, MouseDrag, MouseScrollWheel, MouseUp},
-    ClipboardItem, Entity, ModelContext, MouseButton, MouseMovedEvent, Task,
+    ClipboardItem, Entity, ModelContext, Task,
 };
 
 use crate::mappings::{
@@ -1132,12 +1133,12 @@ impl Terminal {
         let line_height = self.last_content.size.line_height;
         match e.phase {
             /* Reset scroll state on started */
-            Some(gpui::TouchPhase::Started) => {
+            Some(TouchPhase::Started) => {
                 self.scroll_px = 0.;
                 None
             }
             /* Calculate the appropriate scroll lines */
-            Some(gpui::TouchPhase::Moved) => {
+            Some(gpui::platform::TouchPhase::Moved) => {
                 let old_offset = (self.scroll_px / line_height) as i32;
 
                 self.scroll_px += e.delta.pixel_delta(line_height).y() * scroll_multiplier;

crates/terminal_view/src/terminal_button.rs šŸ”—

@@ -1,8 +1,10 @@
 use context_menu::{ContextMenu, ContextMenuItem};
 use gpui::{
-    elements::*, impl_internal_actions, CursorStyle, Element, ElementBox, Entity, MouseButton,
-    MutableAppContext, RenderContext, View, ViewContext, ViewHandle, WeakModelHandle,
-    WeakViewHandle,
+    elements::*,
+    impl_internal_actions,
+    platform::{CursorStyle, MouseButton},
+    AppContext, Element, ElementBox, Entity, RenderContext, View, ViewContext, ViewHandle,
+    WeakModelHandle, WeakViewHandle,
 };
 use settings::Settings;
 use std::any::TypeId;
@@ -21,7 +23,7 @@ pub struct FocusTerminal {
 
 impl_internal_actions!(terminal, [FocusTerminal, DeployTerminalMenu]);
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(TerminalButton::deploy_terminal_menu);
     cx.add_action(TerminalButton::focus_terminal);
 }

crates/terminal_view/src/terminal_element.rs šŸ”—

@@ -7,10 +7,11 @@ use gpui::{
         rect::RectF,
         vector::{vec2f, Vector2F},
     },
+    platform::{CursorStyle, MouseButton},
     serde_json::json,
     text_layout::{Line, RunStyle},
-    Element, ElementBox, EventContext, FontCache, ModelContext, MouseButton, MouseRegion,
-    PaintContext, Quad, SizeConstraint, TextLayoutCache, WeakModelHandle, WeakViewHandle,
+    Element, ElementBox, EventContext, FontCache, ModelContext, MouseRegion, PaintContext, Quad,
+    SizeConstraint, TextLayoutCache, WeakModelHandle, WeakViewHandle,
 };
 use itertools::Itertools;
 use language::CursorShape;
@@ -735,9 +736,9 @@ impl Element for TerminalElement {
             cx.scene.push_cursor_region(gpui::CursorRegion {
                 bounds,
                 style: if layout.hyperlink_tooltip.is_some() {
-                    gpui::CursorStyle::PointingHand
+                    CursorStyle::PointingHand
                 } else {
-                    gpui::CursorStyle::IBeam
+                    CursorStyle::IBeam
                 },
             });
 

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

@@ -16,8 +16,9 @@ use gpui::{
     geometry::vector::Vector2F,
     impl_actions, impl_internal_actions,
     keymap_matcher::{KeymapContext, Keystroke},
-    AnyViewHandle, AppContext, Element, ElementBox, Entity, ModelHandle, MutableAppContext, Task,
-    View, ViewContext, ViewHandle, WeakViewHandle,
+    platform::KeyDownEvent,
+    AnyViewHandle, AppContext, Element, ElementBox, Entity, ModelHandle, Task, View, ViewContext,
+    ViewHandle, WeakViewHandle,
 };
 use project::{LocalWorktree, Project};
 use serde::Deserialize;
@@ -68,7 +69,7 @@ impl_actions!(terminal, [SendText, SendKeystroke]);
 
 impl_internal_actions!(project_panel, [DeployContextMenu]);
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(TerminalView::deploy);
 
     register_deserializable_item::<TerminalView>(cx);
@@ -425,7 +426,7 @@ impl View for TerminalView {
         cx.notify();
     }
 
-    fn key_down(&mut self, event: &gpui::KeyDownEvent, cx: &mut ViewContext<Self>) -> bool {
+    fn key_down(&mut self, event: &KeyDownEvent, cx: &mut ViewContext<Self>) -> bool {
         self.clear_bel(cx);
         self.pause_cursor_blinking(cx);
 

crates/theme/src/theme.rs šŸ”—

@@ -4,7 +4,7 @@ use gpui::{
     color::Color,
     elements::{ContainerStyle, ImageStyle, LabelStyle, Shadow, TooltipStyle},
     fonts::{HighlightStyle, TextStyle},
-    Border, MouseState,
+    platform, Border, MouseState,
 };
 use serde::{de::DeserializeOwned, Deserialize};
 use serde_json::Value;
@@ -754,14 +754,15 @@ impl<T> Interactive<T> {
                 self.hover_and_active
                     .as_ref()
                     .unwrap_or(self.active.as_ref().unwrap_or(&self.default))
-            } else if state.clicked() == Some(gpui::MouseButton::Left) && self.clicked.is_some() {
+            } else if state.clicked() == Some(platform::MouseButton::Left) && self.clicked.is_some()
+            {
                 self.click_and_active
                     .as_ref()
                     .unwrap_or(self.active.as_ref().unwrap_or(&self.default))
             } else {
                 self.active.as_ref().unwrap_or(&self.default)
             }
-        } else if state.clicked() == Some(gpui::MouseButton::Left) && self.clicked.is_some() {
+        } else if state.clicked() == Some(platform::MouseButton::Left) && self.clicked.is_some() {
             self.clicked.as_ref().unwrap()
         } else if state.hovered() {
             self.hover.as_ref().unwrap_or(&self.default)

crates/theme/src/ui.rs šŸ”—

@@ -8,8 +8,10 @@ use gpui::{
     },
     fonts::TextStyle,
     geometry::vector::{vec2f, Vector2F},
+    platform,
+    platform::MouseButton,
     scene::MouseClick,
-    Action, Element, ElementBox, EventContext, MouseButton, MouseState, RenderContext, View,
+    Action, Element, ElementBox, EventContext, MouseState, RenderContext, View,
 };
 use serde::Deserialize;
 
@@ -80,8 +82,10 @@ pub fn checkbox_with_label<T: 'static, V: View>(
             .align_children_center()
             .boxed()
     })
-    .on_click(gpui::MouseButton::Left, move |_, cx| change(!checked, cx))
-    .with_cursor_style(gpui::CursorStyle::PointingHand)
+    .on_click(platform::MouseButton::Left, move |_, cx| {
+        change(!checked, cx)
+    })
+    .with_cursor_style(platform::CursorStyle::PointingHand)
 }
 
 #[derive(Clone, Deserialize, Default)]
@@ -212,7 +216,7 @@ where
             .boxed()
     })
     .on_click(MouseButton::Left, f)
-    .with_cursor_style(gpui::CursorStyle::PointingHand)
+    .with_cursor_style(platform::CursorStyle::PointingHand)
 }
 
 #[derive(Clone, Deserialize, Default)]
@@ -261,11 +265,11 @@ where
                         let style = style.close_icon.style_for(state, false);
                         icon(style).boxed()
                     })
-                    .on_click(gpui::MouseButton::Left, move |_, cx| {
+                    .on_click(platform::MouseButton::Left, move |_, cx| {
                         let window_id = cx.window_id();
                         cx.remove_window(window_id);
                     })
-                    .with_cursor_style(gpui::CursorStyle::PointingHand)
+                    .with_cursor_style(platform::CursorStyle::PointingHand)
                     .aligned()
                     .right()
                     .boxed(),

crates/theme_selector/src/theme_selector.rs šŸ”—

@@ -1,7 +1,7 @@
 use fuzzy::{match_strings, StringMatch, StringMatchCandidate};
 use gpui::{
     actions, elements::*, AnyViewHandle, AppContext, Element, ElementBox, Entity, MouseState,
-    MutableAppContext, RenderContext, View, ViewContext, ViewHandle,
+    RenderContext, View, ViewContext, ViewHandle,
 };
 use picker::{Picker, PickerDelegate};
 use settings::{settings_file::SettingsFile, Settings};
@@ -22,7 +22,7 @@ pub struct ThemeSelector {
 
 actions!(theme_selector, [Toggle, Reload]);
 
-pub fn init(app_state: Arc<AppState>, cx: &mut MutableAppContext) {
+pub fn init(app_state: Arc<AppState>, cx: &mut AppContext) {
     Picker::<ThemeSelector>::init(cx);
     cx.add_action({
         let theme_registry = app_state.themes.clone();
@@ -83,7 +83,7 @@ impl ThemeSelector {
     }
 
     #[cfg(debug_assertions)]
-    pub fn reload(themes: Arc<ThemeRegistry>, cx: &mut MutableAppContext) {
+    pub fn reload(themes: Arc<ThemeRegistry>, cx: &mut AppContext) {
         let current_theme_name = cx.global::<Settings>().theme.meta.name.clone();
         themes.clear();
         match themes.get(&current_theme_name) {
@@ -131,7 +131,7 @@ impl ThemeSelector {
         }
     }
 
-    fn set_theme(theme: Arc<Theme>, cx: &mut MutableAppContext) {
+    fn set_theme(theme: Arc<Theme>, cx: &mut AppContext) {
         cx.update_global::<Settings, _, _>(|settings, cx| {
             settings.theme = theme;
             cx.refresh_windows();
@@ -243,7 +243,7 @@ impl PickerDelegate for ThemeSelector {
 impl Entity for ThemeSelector {
     type Event = Event;
 
-    fn release(&mut self, cx: &mut MutableAppContext) {
+    fn release(&mut self, cx: &mut AppContext) {
         if !self.selection_completed {
             Self::set_theme(self.original_theme.clone(), cx);
         }

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

@@ -6,8 +6,8 @@ use gpui::{
         Padding, ParentElement,
     },
     fonts::TextStyle,
-    AppContext, Border, Element, Entity, ModelHandle, MutableAppContext, Quad, RenderContext, Task,
-    View, ViewContext, ViewHandle, WeakViewHandle,
+    AppContext, Border, Element, Entity, ModelHandle, Quad, RenderContext, Task, View, ViewContext,
+    ViewHandle, WeakViewHandle,
 };
 use project::Project;
 use settings::Settings;
@@ -16,7 +16,7 @@ use workspace::{item::Item, register_deserializable_item, Pane, Workspace};
 
 actions!(theme, [DeployThemeTestbench]);
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(ThemeTestbench::deploy);
 
     register_deserializable_item::<ThemeTestbench>(cx)

crates/vim/src/editor_events.rs šŸ”—

@@ -1,15 +1,15 @@
 use editor::{EditorBlurred, EditorFocused, EditorMode, EditorReleased, Event};
-use gpui::MutableAppContext;
+use gpui::AppContext;
 
 use crate::{state::Mode, Vim};
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.subscribe_global(focused).detach();
     cx.subscribe_global(blurred).detach();
     cx.subscribe_global(released).detach();
 }
 
-fn focused(EditorFocused(editor): &EditorFocused, cx: &mut MutableAppContext) {
+fn focused(EditorFocused(editor): &EditorFocused, cx: &mut AppContext) {
     Vim::update(cx, |vim, cx| {
         if let Some(previously_active_editor) = vim
             .active_editor
@@ -48,7 +48,7 @@ fn focused(EditorFocused(editor): &EditorFocused, cx: &mut MutableAppContext) {
     });
 }
 
-fn blurred(EditorBlurred(editor): &EditorBlurred, cx: &mut MutableAppContext) {
+fn blurred(EditorBlurred(editor): &EditorBlurred, cx: &mut AppContext) {
     Vim::update(cx, |vim, cx| {
         if let Some(previous_editor) = vim.active_editor.clone() {
             if previous_editor == editor.clone() {
@@ -59,7 +59,7 @@ fn blurred(EditorBlurred(editor): &EditorBlurred, cx: &mut MutableAppContext) {
     })
 }
 
-fn released(EditorReleased(editor): &EditorReleased, cx: &mut MutableAppContext) {
+fn released(EditorReleased(editor): &EditorReleased, cx: &mut AppContext) {
     cx.update_default_global(|vim: &mut Vim, _| {
         if let Some(previous_editor) = vim.active_editor.clone() {
             if previous_editor == editor.clone() {
@@ -69,7 +69,7 @@ fn released(EditorReleased(editor): &EditorReleased, cx: &mut MutableAppContext)
     });
 }
 
-fn local_selections_changed(newest_empty: bool, cx: &mut MutableAppContext) {
+fn local_selections_changed(newest_empty: bool, cx: &mut AppContext) {
     Vim::update(cx, |vim, cx| {
         if vim.enabled && vim.state.mode == Mode::Normal && !newest_empty {
             vim.switch_mode(Mode::Visual { line: false }, false, cx)

crates/vim/src/insert.rs šŸ”—

@@ -1,12 +1,12 @@
 use crate::{state::Mode, Vim};
 use editor::{scroll::autoscroll::Autoscroll, Bias};
-use gpui::{actions, MutableAppContext, ViewContext};
+use gpui::{actions, AppContext, ViewContext};
 use language::SelectionGoal;
 use workspace::Workspace;
 
 actions!(vim, [NormalBefore]);
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(normal_before);
 }
 

crates/vim/src/motion.rs šŸ”—

@@ -5,7 +5,7 @@ use editor::{
     display_map::{DisplaySnapshot, ToDisplayPoint},
     movement, Bias, CharKind, DisplayPoint, ToOffset,
 };
-use gpui::{actions, impl_actions, MutableAppContext};
+use gpui::{actions, impl_actions, AppContext};
 use language::{Point, Selection, SelectionGoal};
 use serde::Deserialize;
 use workspace::Workspace;
@@ -80,7 +80,7 @@ actions!(
 );
 impl_actions!(vim, [NextWordStart, NextWordEnd, PreviousWordStart]);
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(|_: &mut Workspace, _: &Left, cx: _| motion(Motion::Left, cx));
     cx.add_action(|_: &mut Workspace, _: &Backspace, cx: _| motion(Motion::Backspace, cx));
     cx.add_action(|_: &mut Workspace, _: &Down, cx: _| motion(Motion::Down, cx));
@@ -116,7 +116,7 @@ pub fn init(cx: &mut MutableAppContext) {
     cx.add_action(|_: &mut Workspace, &NextLineStart, cx: _| motion(Motion::NextLineStart, cx))
 }
 
-pub(crate) fn motion(motion: Motion, cx: &mut MutableAppContext) {
+pub(crate) fn motion(motion: Motion, cx: &mut AppContext) {
     if let Some(Operator::Namespace(_))
     | Some(Operator::FindForward { .. })
     | Some(Operator::FindBackward { .. }) = Vim::read(cx).active_operator()

crates/vim/src/normal.rs šŸ”—

@@ -16,7 +16,7 @@ use editor::{
     scroll::{autoscroll::Autoscroll, scroll_amount::ScrollAmount},
     Anchor, Bias, ClipboardSelection, DisplayPoint, Editor,
 };
-use gpui::{actions, impl_actions, MutableAppContext, ViewContext};
+use gpui::{actions, impl_actions, AppContext, ViewContext};
 use language::{AutoindentMode, Point, SelectionGoal};
 use log::error;
 use serde::Deserialize;
@@ -50,7 +50,7 @@ actions!(
 
 impl_actions!(vim, [Scroll]);
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(insert_after);
     cx.add_action(insert_first_non_whitespace);
     cx.add_action(insert_end_of_line);
@@ -94,7 +94,7 @@ pub fn normal_motion(
     motion: Motion,
     operator: Option<Operator>,
     times: usize,
-    cx: &mut MutableAppContext,
+    cx: &mut AppContext,
 ) {
     Vim::update(cx, |vim, cx| {
         match operator {
@@ -110,7 +110,7 @@ pub fn normal_motion(
     });
 }
 
-pub fn normal_object(object: Object, cx: &mut MutableAppContext) {
+pub fn normal_object(object: Object, cx: &mut AppContext) {
     Vim::update(cx, |vim, cx| {
         match vim.state.operator_stack.pop() {
             Some(Operator::Object { around }) => match vim.state.operator_stack.pop() {
@@ -129,7 +129,7 @@ pub fn normal_object(object: Object, cx: &mut MutableAppContext) {
     })
 }
 
-fn move_cursor(vim: &mut Vim, motion: Motion, times: usize, cx: &mut MutableAppContext) {
+fn move_cursor(vim: &mut Vim, motion: Motion, times: usize, cx: &mut AppContext) {
     vim.update_active_editor(cx, |editor, cx| {
         editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
             s.move_cursors_with(|map, cursor, goal| {
@@ -424,7 +424,7 @@ fn scroll(editor: &mut Editor, amount: &ScrollAmount, cx: &mut ViewContext<Edito
     }
 }
 
-pub(crate) fn normal_replace(text: Arc<str>, cx: &mut MutableAppContext) {
+pub(crate) fn normal_replace(text: Arc<str>, cx: &mut AppContext) {
     Vim::update(cx, |vim, cx| {
         vim.update_active_editor(cx, |editor, cx| {
             editor.transact(cx, |editor, cx| {

crates/vim/src/normal/change.rs šŸ”—

@@ -3,10 +3,10 @@ use editor::{
     char_kind, display_map::DisplaySnapshot, movement, scroll::autoscroll::Autoscroll, CharKind,
     DisplayPoint,
 };
-use gpui::MutableAppContext;
+use gpui::AppContext;
 use language::Selection;
 
-pub fn change_motion(vim: &mut Vim, motion: Motion, times: usize, cx: &mut MutableAppContext) {
+pub fn change_motion(vim: &mut Vim, motion: Motion, times: usize, cx: &mut AppContext) {
     // Some motions ignore failure when switching to normal mode
     let mut motion_succeeded = matches!(
         motion,
@@ -38,7 +38,7 @@ pub fn change_motion(vim: &mut Vim, motion: Motion, times: usize, cx: &mut Mutab
     }
 }
 
-pub fn change_object(vim: &mut Vim, object: Object, around: bool, cx: &mut MutableAppContext) {
+pub fn change_object(vim: &mut Vim, object: Object, around: bool, cx: &mut AppContext) {
     let mut objects_found = false;
     vim.update_active_editor(cx, |editor, cx| {
         // We are swapping to insert mode anyway. Just set the line end clipping behavior now

crates/vim/src/normal/delete.rs šŸ”—

@@ -1,9 +1,9 @@
 use crate::{motion::Motion, object::Object, utils::copy_selections_content, Vim};
 use collections::{HashMap, HashSet};
 use editor::{display_map::ToDisplayPoint, scroll::autoscroll::Autoscroll, Bias};
-use gpui::MutableAppContext;
+use gpui::AppContext;
 
-pub fn delete_motion(vim: &mut Vim, motion: Motion, times: usize, cx: &mut MutableAppContext) {
+pub fn delete_motion(vim: &mut Vim, motion: Motion, times: usize, cx: &mut AppContext) {
     vim.update_active_editor(cx, |editor, cx| {
         editor.transact(cx, |editor, cx| {
             editor.set_clip_at_line_ends(false, cx);
@@ -36,7 +36,7 @@ pub fn delete_motion(vim: &mut Vim, motion: Motion, times: usize, cx: &mut Mutab
     });
 }
 
-pub fn delete_object(vim: &mut Vim, object: Object, around: bool, cx: &mut MutableAppContext) {
+pub fn delete_object(vim: &mut Vim, object: Object, around: bool, cx: &mut AppContext) {
     vim.update_active_editor(cx, |editor, cx| {
         editor.transact(cx, |editor, cx| {
             editor.set_clip_at_line_ends(false, cx);

crates/vim/src/normal/yank.rs šŸ”—

@@ -1,8 +1,8 @@
 use crate::{motion::Motion, object::Object, utils::copy_selections_content, Vim};
 use collections::HashMap;
-use gpui::MutableAppContext;
+use gpui::AppContext;
 
-pub fn yank_motion(vim: &mut Vim, motion: Motion, times: usize, cx: &mut MutableAppContext) {
+pub fn yank_motion(vim: &mut Vim, motion: Motion, times: usize, cx: &mut AppContext) {
     vim.update_active_editor(cx, |editor, cx| {
         editor.transact(cx, |editor, cx| {
             editor.set_clip_at_line_ends(false, cx);
@@ -25,7 +25,7 @@ pub fn yank_motion(vim: &mut Vim, motion: Motion, times: usize, cx: &mut Mutable
     });
 }
 
-pub fn yank_object(vim: &mut Vim, object: Object, around: bool, cx: &mut MutableAppContext) {
+pub fn yank_object(vim: &mut Vim, object: Object, around: bool, cx: &mut AppContext) {
     vim.update_active_editor(cx, |editor, cx| {
         editor.transact(cx, |editor, cx| {
             editor.set_clip_at_line_ends(false, cx);

crates/vim/src/object.rs šŸ”—

@@ -1,7 +1,7 @@
 use std::ops::Range;
 
 use editor::{char_kind, display_map::DisplaySnapshot, movement, Bias, CharKind, DisplayPoint};
-use gpui::{actions, impl_actions, MutableAppContext};
+use gpui::{actions, impl_actions, AppContext};
 use language::Selection;
 use serde::Deserialize;
 use workspace::Workspace;
@@ -43,7 +43,7 @@ actions!(
 );
 impl_actions!(vim, [Word]);
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(
         |_: &mut Workspace, &Word { ignore_punctuation }: &Word, cx: _| {
             object(Object::Word { ignore_punctuation }, cx)
@@ -61,7 +61,7 @@ pub fn init(cx: &mut MutableAppContext) {
     cx.add_action(|_: &mut Workspace, _: &AngleBrackets, cx: _| object(Object::AngleBrackets, cx));
 }
 
-fn object(object: Object, cx: &mut MutableAppContext) {
+fn object(object: Object, cx: &mut AppContext) {
     match Vim::read(cx).state.mode {
         Mode::Normal => normal_object(object, cx),
         Mode::Visual { .. } => visual_object(object, cx),

crates/vim/src/utils.rs šŸ”—

@@ -1,7 +1,7 @@
 use editor::{ClipboardSelection, Editor};
-use gpui::{ClipboardItem, MutableAppContext};
+use gpui::{AppContext, ClipboardItem};
 
-pub fn copy_selections_content(editor: &mut Editor, linewise: bool, cx: &mut MutableAppContext) {
+pub fn copy_selections_content(editor: &mut Editor, linewise: bool, cx: &mut AppContext) {
     let selections = editor.selections.all_adjusted(cx);
     let buffer = editor.buffer().read(cx).snapshot(cx);
     let mut text = String::new();

crates/vim/src/vim.rs šŸ”—

@@ -15,7 +15,7 @@ use std::sync::Arc;
 use collections::CommandPaletteFilter;
 use editor::{Bias, Cancel, Editor, EditorMode};
 use gpui::{
-    actions, impl_actions, MutableAppContext, Subscription, ViewContext, ViewHandle, WeakViewHandle,
+    actions, impl_actions, AppContext, Subscription, ViewContext, ViewHandle, WeakViewHandle,
 };
 use language::CursorShape;
 use motion::Motion;
@@ -38,7 +38,7 @@ struct Number(u8);
 actions!(vim, [Tab, Enter]);
 impl_actions!(vim, [Number, SwitchMode, PushOperator]);
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     editor_events::init(cx);
     normal::init(cx);
     visual::init(cx);
@@ -65,7 +65,7 @@ pub fn init(cx: &mut MutableAppContext) {
         // Otherwise forward cancel on to the editor
         let vim = Vim::read(cx);
         if vim.state.mode != Mode::Normal || vim.active_operator().is_some() {
-            MutableAppContext::defer(cx, |cx| {
+            AppContext::defer(cx, |cx| {
                 Vim::update(cx, |state, cx| {
                     state.switch_mode(Mode::Normal, false, cx);
                 });
@@ -95,7 +95,7 @@ pub fn init(cx: &mut MutableAppContext) {
     .detach();
 }
 
-pub fn observe_keystrokes(window_id: usize, cx: &mut MutableAppContext) {
+pub fn observe_keystrokes(window_id: usize, cx: &mut AppContext) {
     cx.observe_keystrokes(window_id, |_keystroke, _result, handled_by, cx| {
         if let Some(handled_by) = handled_by {
             // Keystroke is handled by the vim system, so continue forward
@@ -131,20 +131,20 @@ pub struct Vim {
 }
 
 impl Vim {
-    fn read(cx: &mut MutableAppContext) -> &Self {
+    fn read(cx: &mut AppContext) -> &Self {
         cx.default_global()
     }
 
-    fn update<F, S>(cx: &mut MutableAppContext, update: F) -> S
+    fn update<F, S>(cx: &mut AppContext, update: F) -> S
     where
-        F: FnOnce(&mut Self, &mut MutableAppContext) -> S,
+        F: FnOnce(&mut Self, &mut AppContext) -> S,
     {
         cx.update_default_global(update)
     }
 
     fn update_active_editor<S>(
         &self,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
         update: impl FnOnce(&mut Editor, &mut ViewContext<Editor>) -> S,
     ) -> Option<S> {
         self.active_editor
@@ -153,7 +153,7 @@ impl Vim {
             .map(|ae| ae.update(cx, update))
     }
 
-    fn switch_mode(&mut self, mode: Mode, leave_selections: bool, cx: &mut MutableAppContext) {
+    fn switch_mode(&mut self, mode: Mode, leave_selections: bool, cx: &mut AppContext) {
         self.state.mode = mode;
         self.state.operator_stack.clear();
 
@@ -188,12 +188,12 @@ impl Vim {
         }
     }
 
-    fn push_operator(&mut self, operator: Operator, cx: &mut MutableAppContext) {
+    fn push_operator(&mut self, operator: Operator, cx: &mut AppContext) {
         self.state.operator_stack.push(operator);
         self.sync_vim_settings(cx);
     }
 
-    fn push_number(&mut self, Number(number): &Number, cx: &mut MutableAppContext) {
+    fn push_number(&mut self, Number(number): &Number, cx: &mut AppContext) {
         if let Some(Operator::Number(current_number)) = self.active_operator() {
             self.pop_operator(cx);
             self.push_operator(Operator::Number(current_number * 10 + *number as usize), cx);
@@ -202,14 +202,14 @@ impl Vim {
         }
     }
 
-    fn pop_operator(&mut self, cx: &mut MutableAppContext) -> Operator {
+    fn pop_operator(&mut self, cx: &mut AppContext) -> Operator {
         let popped_operator = self.state.operator_stack.pop()
             .expect("Operator popped when no operator was on the stack. This likely means there is an invalid keymap config");
         self.sync_vim_settings(cx);
         popped_operator
     }
 
-    fn pop_number_operator(&mut self, cx: &mut MutableAppContext) -> usize {
+    fn pop_number_operator(&mut self, cx: &mut AppContext) -> usize {
         let mut times = 1;
         if let Some(Operator::Number(number)) = self.active_operator() {
             times = number;
@@ -218,7 +218,7 @@ impl Vim {
         times
     }
 
-    fn clear_operator(&mut self, cx: &mut MutableAppContext) {
+    fn clear_operator(&mut self, cx: &mut AppContext) {
         self.state.operator_stack.clear();
         self.sync_vim_settings(cx);
     }
@@ -227,7 +227,7 @@ impl Vim {
         self.state.operator_stack.last().copied()
     }
 
-    fn active_editor_input_ignored(text: Arc<str>, cx: &mut MutableAppContext) {
+    fn active_editor_input_ignored(text: Arc<str>, cx: &mut AppContext) {
         if text.is_empty() {
             return;
         }
@@ -248,7 +248,7 @@ impl Vim {
         }
     }
 
-    fn set_enabled(&mut self, enabled: bool, cx: &mut MutableAppContext) {
+    fn set_enabled(&mut self, enabled: bool, cx: &mut AppContext) {
         if self.enabled != enabled {
             self.enabled = enabled;
             self.state = Default::default();
@@ -259,7 +259,7 @@ impl Vim {
         }
     }
 
-    fn sync_vim_settings(&self, cx: &mut MutableAppContext) {
+    fn sync_vim_settings(&self, cx: &mut AppContext) {
         let state = &self.state;
         let cursor_shape = state.cursor_shape();
 
@@ -291,7 +291,7 @@ impl Vim {
         }
     }
 
-    fn unhook_vim_settings(&self, editor: ViewHandle<Editor>, cx: &mut MutableAppContext) {
+    fn unhook_vim_settings(&self, editor: ViewHandle<Editor>, cx: &mut AppContext) {
         editor.update(cx, |editor, cx| {
             editor.set_cursor_shape(CursorShape::Bar, cx);
             editor.set_clip_at_line_ends(false, cx);

crates/vim/src/visual.rs šŸ”—

@@ -4,7 +4,7 @@ use collections::HashMap;
 use editor::{
     display_map::ToDisplayPoint, movement, scroll::autoscroll::Autoscroll, Bias, ClipboardSelection,
 };
-use gpui::{actions, MutableAppContext, ViewContext};
+use gpui::{actions, AppContext, ViewContext};
 use language::{AutoindentMode, SelectionGoal};
 use workspace::Workspace;
 
@@ -18,14 +18,14 @@ use crate::{
 
 actions!(vim, [VisualDelete, VisualChange, VisualYank, VisualPaste]);
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(change);
     cx.add_action(delete);
     cx.add_action(yank);
     cx.add_action(paste);
 }
 
-pub fn visual_motion(motion: Motion, times: usize, cx: &mut MutableAppContext) {
+pub fn visual_motion(motion: Motion, times: usize, cx: &mut AppContext) {
     Vim::update(cx, |vim, cx| {
         vim.update_active_editor(cx, |editor, cx| {
             editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
@@ -56,7 +56,7 @@ pub fn visual_motion(motion: Motion, times: usize, cx: &mut MutableAppContext) {
     });
 }
 
-pub fn visual_object(object: Object, cx: &mut MutableAppContext) {
+pub fn visual_object(object: Object, cx: &mut AppContext) {
     Vim::update(cx, |vim, cx| {
         if let Operator::Object { around } = vim.pop_operator(cx) {
             vim.update_active_editor(cx, |editor, cx| {
@@ -313,7 +313,7 @@ pub fn paste(_: &mut Workspace, _: &VisualPaste, cx: &mut ViewContext<Workspace>
     });
 }
 
-pub(crate) fn visual_replace(text: Arc<str>, line: bool, cx: &mut MutableAppContext) {
+pub(crate) fn visual_replace(text: Arc<str>, line: bool, cx: &mut AppContext) {
     Vim::update(cx, |vim, cx| {
         vim.update_active_editor(cx, |editor, cx| {
             editor.transact(cx, |editor, cx| {
@@ -646,11 +646,12 @@ mod test {
         );
         cx.simulate_keystroke("p");
         cx.assert_state(
-            indoc! {"
+            &indoc! {"
                 The quick brown
-                the 
+                the_
                 ˇfox jumps over
-                dog"},
+                dog"}
+            .replace("_", " "), // Hack for trailing whitespace
             Mode::Normal,
         );
     }

crates/welcome/src/base_keymap_picker.rs šŸ”—

@@ -2,7 +2,7 @@ use fuzzy::{match_strings, StringMatch, StringMatchCandidate};
 use gpui::{
     actions,
     elements::{ChildView, Element as _, Label},
-    AnyViewHandle, Entity, MutableAppContext, View, ViewContext, ViewHandle,
+    AnyViewHandle, AppContext, Entity, View, ViewContext, ViewHandle,
 };
 use picker::{Picker, PickerDelegate};
 use settings::{settings_file::SettingsFile, BaseKeymap, Settings};
@@ -16,7 +16,7 @@ pub struct BaseKeymapSelector {
 
 actions!(welcome, [ToggleBaseKeymapSelector]);
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     Picker::<BaseKeymapSelector>::init(cx);
     cx.add_action({
         move |workspace, _: &ToggleBaseKeymapSelector, cx| BaseKeymapSelector::toggle(workspace, cx)

crates/welcome/src/welcome.rs šŸ”—

@@ -5,7 +5,7 @@ use std::sync::Arc;
 use db::kvp::KEY_VALUE_STORE;
 use gpui::{
     elements::{Flex, Label, ParentElement},
-    Element, ElementBox, Entity, MutableAppContext, Subscription, View, ViewContext,
+    AppContext, Element, ElementBox, Entity, Subscription, View, ViewContext,
 };
 use settings::{settings_file::SettingsFile, Settings};
 
@@ -18,7 +18,7 @@ use crate::base_keymap_picker::ToggleBaseKeymapSelector;
 
 pub const FIRST_OPEN: &str = "first_open";
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(|workspace: &mut Workspace, _: &Welcome, cx| {
         let welcome_page = cx.add_view(WelcomePage::new);
         workspace.add_item(Box::new(welcome_page), cx)
@@ -27,7 +27,7 @@ pub fn init(cx: &mut MutableAppContext) {
     base_keymap_picker::init(cx);
 }
 
-pub fn show_welcome_experience(app_state: &Arc<AppState>, cx: &mut MutableAppContext) {
+pub fn show_welcome_experience(app_state: &Arc<AppState>, cx: &mut AppContext) {
     open_new(&app_state, cx, |workspace, cx| {
         workspace.toggle_sidebar(SidebarSide::Left, cx);
         let welcome_page = cx.add_view(|cx| WelcomePage::new(cx));

crates/workspace/src/dock.rs šŸ”—

@@ -7,8 +7,10 @@ use gpui::{
     actions,
     elements::{ChildView, Container, Empty, MouseEventHandler, ParentElement, Side, Stack},
     geometry::vector::Vector2F,
-    impl_internal_actions, Border, CursorStyle, Element, ElementBox, MouseButton,
-    MutableAppContext, RenderContext, SizeConstraint, ViewContext, ViewHandle,
+    impl_internal_actions,
+    platform::{CursorStyle, MouseButton},
+    AppContext, Border, Element, ElementBox, RenderContext, SizeConstraint, ViewContext,
+    ViewHandle,
 };
 use settings::{DockAnchor, Settings};
 use theme::Theme;
@@ -36,7 +38,7 @@ actions!(
 );
 impl_internal_actions!(dock, [MoveDock, AddDefaultItemToDock]);
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(Dock::focus_dock);
     cx.add_action(Dock::hide_dock);
     cx.add_action(

crates/workspace/src/dock/toggle_dock_button.rs šŸ”—

@@ -1,7 +1,8 @@
 use gpui::{
     elements::{Empty, MouseEventHandler, Svg},
-    CursorStyle, Element, ElementBox, Entity, MouseButton, View, ViewContext, ViewHandle,
-    WeakViewHandle,
+    platform::CursorStyle,
+    platform::MouseButton,
+    Element, ElementBox, Entity, View, ViewContext, ViewHandle, WeakViewHandle,
 };
 use settings::Settings;
 

crates/workspace/src/item.rs šŸ”—

@@ -15,8 +15,8 @@ use std::{
 use anyhow::Result;
 use client::{proto, Client};
 use gpui::{
-    AnyViewHandle, AppContext, ElementBox, ModelHandle, MutableAppContext, Task, View, ViewContext,
-    ViewHandle, WeakViewHandle,
+    AnyViewHandle, AppContext, ElementBox, ModelHandle, Task, View, ViewContext, ViewHandle,
+    WeakViewHandle,
 };
 use project::{Project, ProjectEntryId, ProjectPath};
 use settings::{Autosave, Settings};
@@ -159,8 +159,8 @@ pub trait Item: View {
 pub trait ItemHandle: 'static + fmt::Debug {
     fn subscribe_to_item_events(
         &self,
-        cx: &mut MutableAppContext,
-        handler: Box<dyn Fn(ItemEvent, &mut MutableAppContext)>,
+        cx: &mut AppContext,
+        handler: Box<dyn Fn(ItemEvent, &mut AppContext)>,
     ) -> gpui::Subscription;
     fn tab_description<'a>(&self, detail: usize, cx: &'a AppContext) -> Option<Cow<'a, str>>;
     fn tab_content(&self, detail: Option<usize>, style: &theme::Tab, cx: &AppContext)
@@ -174,7 +174,7 @@ pub trait ItemHandle: 'static + fmt::Debug {
     fn clone_on_split(
         &self,
         workspace_id: WorkspaceId,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> Option<Box<dyn ItemHandle>>;
     fn added_to_pane(
         &self,
@@ -182,35 +182,34 @@ pub trait ItemHandle: 'static + fmt::Debug {
         pane: ViewHandle<Pane>,
         cx: &mut ViewContext<Workspace>,
     );
-    fn deactivated(&self, cx: &mut MutableAppContext);
-    fn workspace_deactivated(&self, cx: &mut MutableAppContext);
-    fn navigate(&self, data: Box<dyn Any>, cx: &mut MutableAppContext) -> bool;
+    fn deactivated(&self, cx: &mut AppContext);
+    fn workspace_deactivated(&self, cx: &mut AppContext);
+    fn navigate(&self, data: Box<dyn Any>, cx: &mut AppContext) -> bool;
     fn id(&self) -> usize;
     fn window_id(&self) -> usize;
     fn as_any(&self) -> &AnyViewHandle;
     fn is_dirty(&self, cx: &AppContext) -> bool;
     fn has_conflict(&self, cx: &AppContext) -> bool;
     fn can_save(&self, cx: &AppContext) -> bool;
-    fn save(&self, project: ModelHandle<Project>, cx: &mut MutableAppContext) -> Task<Result<()>>;
+    fn save(&self, project: ModelHandle<Project>, cx: &mut AppContext) -> Task<Result<()>>;
     fn save_as(
         &self,
         project: ModelHandle<Project>,
         abs_path: PathBuf,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> Task<Result<()>>;
-    fn reload(&self, project: ModelHandle<Project>, cx: &mut MutableAppContext)
-        -> Task<Result<()>>;
+    fn reload(&self, project: ModelHandle<Project>, cx: &mut AppContext) -> Task<Result<()>>;
     fn git_diff_recalc(
         &self,
         project: ModelHandle<Project>,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> Task<Result<()>>;
     fn act_as_type<'a>(&'a self, type_id: TypeId, cx: &'a AppContext) -> Option<&'a AnyViewHandle>;
     fn to_followable_item_handle(&self, cx: &AppContext) -> Option<Box<dyn FollowableItemHandle>>;
     fn on_release(
         &self,
-        cx: &mut MutableAppContext,
-        callback: Box<dyn FnOnce(&mut MutableAppContext)>,
+        cx: &mut AppContext,
+        callback: Box<dyn FnOnce(&mut AppContext)>,
     ) -> gpui::Subscription;
     fn to_searchable_item_handle(&self, cx: &AppContext) -> Option<Box<dyn SearchableItemHandle>>;
     fn breadcrumb_location(&self, cx: &AppContext) -> ToolbarItemLocation;
@@ -239,8 +238,8 @@ impl dyn ItemHandle {
 impl<T: Item> ItemHandle for ViewHandle<T> {
     fn subscribe_to_item_events(
         &self,
-        cx: &mut MutableAppContext,
-        handler: Box<dyn Fn(ItemEvent, &mut MutableAppContext)>,
+        cx: &mut AppContext,
+        handler: Box<dyn Fn(ItemEvent, &mut AppContext)>,
     ) -> gpui::Subscription {
         cx.subscribe(self, move |_, event, cx| {
             for item_event in T::to_item_events(event) {
@@ -306,7 +305,7 @@ impl<T: Item> ItemHandle for ViewHandle<T> {
     fn clone_on_split(
         &self,
         workspace_id: WorkspaceId,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> Option<Box<dyn ItemHandle>> {
         self.update(cx, |item, cx| {
             cx.add_option_view(|cx| item.clone_on_split(workspace_id, cx))
@@ -493,15 +492,15 @@ impl<T: Item> ItemHandle for ViewHandle<T> {
         });
     }
 
-    fn deactivated(&self, cx: &mut MutableAppContext) {
+    fn deactivated(&self, cx: &mut AppContext) {
         self.update(cx, |this, cx| this.deactivated(cx));
     }
 
-    fn workspace_deactivated(&self, cx: &mut MutableAppContext) {
+    fn workspace_deactivated(&self, cx: &mut AppContext) {
         self.update(cx, |this, cx| this.workspace_deactivated(cx));
     }
 
-    fn navigate(&self, data: Box<dyn Any>, cx: &mut MutableAppContext) -> bool {
+    fn navigate(&self, data: Box<dyn Any>, cx: &mut AppContext) -> bool {
         self.update(cx, |this, cx| this.navigate(data, cx))
     }
 
@@ -529,7 +528,7 @@ impl<T: Item> ItemHandle for ViewHandle<T> {
         self.read(cx).can_save(cx)
     }
 
-    fn save(&self, project: ModelHandle<Project>, cx: &mut MutableAppContext) -> Task<Result<()>> {
+    fn save(&self, project: ModelHandle<Project>, cx: &mut AppContext) -> Task<Result<()>> {
         self.update(cx, |item, cx| item.save(project, cx))
     }
 
@@ -537,23 +536,19 @@ impl<T: Item> ItemHandle for ViewHandle<T> {
         &self,
         project: ModelHandle<Project>,
         abs_path: PathBuf,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> Task<anyhow::Result<()>> {
         self.update(cx, |item, cx| item.save_as(project, abs_path, cx))
     }
 
-    fn reload(
-        &self,
-        project: ModelHandle<Project>,
-        cx: &mut MutableAppContext,
-    ) -> Task<Result<()>> {
+    fn reload(&self, project: ModelHandle<Project>, cx: &mut AppContext) -> Task<Result<()>> {
         self.update(cx, |item, cx| item.reload(project, cx))
     }
 
     fn git_diff_recalc(
         &self,
         project: ModelHandle<Project>,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> Task<Result<()>> {
         self.update(cx, |item, cx| item.git_diff_recalc(project, cx))
     }
@@ -574,8 +569,8 @@ impl<T: Item> ItemHandle for ViewHandle<T> {
 
     fn on_release(
         &self,
-        cx: &mut MutableAppContext,
-        callback: Box<dyn FnOnce(&mut MutableAppContext)>,
+        cx: &mut AppContext,
+        callback: Box<dyn FnOnce(&mut AppContext)>,
     ) -> gpui::Subscription {
         cx.observe_release(self, move |_, cx| callback(cx))
     }
@@ -651,7 +646,7 @@ pub trait FollowableItem: Item {
         project: ModelHandle<Project>,
         id: ViewId,
         state: &mut Option<proto::view::Variant>,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> Option<Task<Result<ViewHandle<Self>>>>;
     fn add_event_to_update_proto(
         &self,
@@ -672,7 +667,7 @@ pub trait FollowableItem: Item {
 
 pub trait FollowableItemHandle: ItemHandle {
     fn remote_id(&self, client: &Arc<Client>, cx: &AppContext) -> Option<ViewId>;
-    fn set_leader_replica_id(&self, leader_replica_id: Option<u16>, cx: &mut MutableAppContext);
+    fn set_leader_replica_id(&self, leader_replica_id: Option<u16>, cx: &mut AppContext);
     fn to_state_proto(&self, cx: &AppContext) -> Option<proto::view::Variant>;
     fn add_event_to_update_proto(
         &self,
@@ -684,7 +679,7 @@ pub trait FollowableItemHandle: ItemHandle {
         &self,
         project: &ModelHandle<Project>,
         message: proto::update_view::Variant,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> Task<Result<()>>;
     fn should_unfollow_on_event(&self, event: &dyn Any, cx: &AppContext) -> bool;
 }
@@ -699,7 +694,7 @@ impl<T: FollowableItem> FollowableItemHandle for ViewHandle<T> {
         })
     }
 
-    fn set_leader_replica_id(&self, leader_replica_id: Option<u16>, cx: &mut MutableAppContext) {
+    fn set_leader_replica_id(&self, leader_replica_id: Option<u16>, cx: &mut AppContext) {
         self.update(cx, |this, cx| {
             this.set_leader_replica_id(leader_replica_id, cx)
         })
@@ -726,7 +721,7 @@ impl<T: FollowableItem> FollowableItemHandle for ViewHandle<T> {
         &self,
         project: &ModelHandle<Project>,
         message: proto::update_view::Variant,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> Task<Result<()>> {
         self.update(cx, |this, cx| this.apply_update_proto(project, message, cx))
     }
@@ -745,8 +740,8 @@ pub(crate) mod test {
     use super::{Item, ItemEvent};
     use crate::{sidebar::SidebarItem, ItemId, ItemNavHistory, Pane, Workspace, WorkspaceId};
     use gpui::{
-        elements::Empty, AppContext, Element, ElementBox, Entity, ModelHandle, MutableAppContext,
-        RenderContext, Task, View, ViewContext, ViewHandle, WeakViewHandle,
+        elements::Empty, AppContext, Element, ElementBox, Entity, ModelHandle, RenderContext, Task,
+        View, ViewContext, ViewHandle, WeakViewHandle,
     };
     use project::{Project, ProjectEntryId, ProjectPath, WorktreeId};
     use smallvec::SmallVec;
@@ -812,7 +807,7 @@ pub(crate) mod test {
     }
 
     impl TestProjectItem {
-        pub fn new(id: u64, path: &str, cx: &mut MutableAppContext) -> ModelHandle<Self> {
+        pub fn new(id: u64, path: &str, cx: &mut AppContext) -> ModelHandle<Self> {
             let entry_id = Some(ProjectEntryId::from_proto(id));
             let project_path = Some(ProjectPath {
                 worktree_id: WorktreeId::from_usize(0),
@@ -824,7 +819,7 @@ pub(crate) mod test {
             })
         }
 
-        pub fn new_untitled(cx: &mut MutableAppContext) -> ModelHandle<Self> {
+        pub fn new_untitled(cx: &mut AppContext) -> ModelHandle<Self> {
             cx.add_model(|_| Self {
                 project_path: None,
                 entry_id: None,

crates/workspace/src/notifications.rs šŸ”—

@@ -1,11 +1,11 @@
 use std::{any::TypeId, ops::DerefMut};
 
 use collections::HashSet;
-use gpui::{AnyViewHandle, Entity, MutableAppContext, View, ViewContext, ViewHandle};
+use gpui::{AnyViewHandle, AppContext, Entity, View, ViewContext, ViewHandle};
 
 use crate::Workspace;
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.set_global(NotificationTracker::new());
     simple_message_notification::init(cx);
 }
@@ -138,8 +138,9 @@ pub mod simple_message_notification {
     use gpui::{
         actions,
         elements::{Flex, MouseEventHandler, Padding, ParentElement, Svg, Text},
-        impl_actions, Action, CursorStyle, Element, Entity, MouseButton, MutableAppContext, View,
-        ViewContext,
+        impl_actions,
+        platform::{CursorStyle, MouseButton},
+        Action, AppContext, Element, Entity, View, ViewContext,
     };
     use menu::Cancel;
     use serde::Deserialize;
@@ -162,7 +163,7 @@ pub mod simple_message_notification {
 
     impl_actions!(message_notifications, [OsOpen]);
 
-    pub fn init(cx: &mut MutableAppContext) {
+    pub fn init(cx: &mut AppContext) {
         cx.add_action(MessageNotification::dismiss);
         cx.add_action(
             |_workspace: &mut Workspace, open_action: &OsOpen, cx: &mut ViewContext<Workspace>| {

crates/workspace/src/pane.rs šŸ”—

@@ -22,10 +22,10 @@ use gpui::{
     },
     impl_actions, impl_internal_actions,
     keymap_matcher::KeymapContext,
-    platform::{CursorStyle, NavigationDirection},
+    platform::{CursorStyle, MouseButton, NavigationDirection, PromptLevel},
     Action, AnyViewHandle, AnyWeakViewHandle, AppContext, AsyncAppContext, Entity, EventContext,
-    ModelHandle, MouseButton, MouseRegion, MutableAppContext, PromptLevel, Quad, RenderContext,
-    Task, View, ViewContext, ViewHandle, WeakViewHandle,
+    ModelHandle, MouseRegion, Quad, RenderContext, Task, View, ViewContext, ViewHandle,
+    WeakViewHandle,
 };
 use project::{Project, ProjectEntryId, ProjectPath};
 use serde::Deserialize;
@@ -46,6 +46,8 @@ actions!(
         CloseActiveItem,
         CloseInactiveItems,
         CloseCleanItems,
+        CloseItemsToTheLeft,
+        CloseItemsToTheRight,
         CloseAllItems,
         ReopenClosedItem,
         SplitLeft,
@@ -106,7 +108,7 @@ const MAX_NAVIGATION_HISTORY_LEN: usize = 1024;
 
 pub type BackgroundActions = fn() -> &'static [(&'static str, &'static dyn Action)];
 
-pub fn init(cx: &mut MutableAppContext) {
+pub fn init(cx: &mut AppContext) {
     cx.add_action(|pane: &mut Pane, action: &ActivateItem, cx| {
         pane.activate_item(action.0, true, true, cx);
     });
@@ -122,6 +124,8 @@ pub fn init(cx: &mut MutableAppContext) {
     cx.add_async_action(Pane::close_active_item);
     cx.add_async_action(Pane::close_inactive_items);
     cx.add_async_action(Pane::close_clean_items);
+    cx.add_async_action(Pane::close_items_to_the_left);
+    cx.add_async_action(Pane::close_items_to_the_right);
     cx.add_async_action(Pane::close_all_items);
     cx.add_async_action(|workspace: &mut Workspace, action: &CloseItem, cx| {
         let pane = action.pane.upgrade(cx)?;
@@ -261,13 +265,6 @@ pub enum ReorderBehavior {
     MoveToIndex(usize),
 }
 
-enum ItemType {
-    Active,
-    Inactive,
-    Clean,
-    All,
-}
-
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
 enum TabBarContextMenuKind {
     New,
@@ -642,7 +639,7 @@ impl Pane {
         self.items.len()
     }
 
-    pub fn items(&self) -> impl Iterator<Item = &Box<dyn ItemHandle>> {
+    pub fn items(&self) -> impl Iterator<Item = &Box<dyn ItemHandle>> + DoubleEndedIterator {
         self.items.iter()
     }
 
@@ -741,7 +738,18 @@ impl Pane {
         _: &CloseActiveItem,
         cx: &mut ViewContext<Workspace>,
     ) -> Option<Task<Result<()>>> {
-        Self::close_main(workspace, ItemType::Active, cx)
+        let pane_handle = workspace.active_pane().clone();
+        let pane = pane_handle.read(cx);
+        let active_item_id = pane.items[pane.active_item_index].id();
+
+        let task = Self::close_items(workspace, pane_handle, cx, move |item_id| {
+            item_id == active_item_id
+        });
+
+        Some(cx.foreground().spawn(async move {
+            task.await?;
+            Ok(())
+        }))
     }
 
     pub fn close_inactive_items(
@@ -749,54 +757,103 @@ impl Pane {
         _: &CloseInactiveItems,
         cx: &mut ViewContext<Workspace>,
     ) -> Option<Task<Result<()>>> {
-        Self::close_main(workspace, ItemType::Inactive, cx)
+        let pane_handle = workspace.active_pane().clone();
+        let pane = pane_handle.read(cx);
+        let active_item_id = pane.items[pane.active_item_index].id();
+
+        let task = Self::close_items(workspace, pane_handle, cx, move |item_id| {
+            item_id != active_item_id
+        });
+
+        Some(cx.foreground().spawn(async move {
+            task.await?;
+            Ok(())
+        }))
     }
 
-    pub fn close_all_items(
+    pub fn close_clean_items(
         workspace: &mut Workspace,
-        _: &CloseAllItems,
+        _: &CloseCleanItems,
         cx: &mut ViewContext<Workspace>,
     ) -> Option<Task<Result<()>>> {
-        Self::close_main(workspace, ItemType::All, cx)
+        let pane_handle = workspace.active_pane().clone();
+        let pane = pane_handle.read(cx);
+
+        let item_ids: Vec<_> = pane
+            .items()
+            .filter(|item| !item.is_dirty(cx))
+            .map(|item| item.id())
+            .collect();
+
+        let task = Self::close_items(workspace, pane_handle, cx, move |item_id| {
+            item_ids.contains(&item_id)
+        });
+
+        Some(cx.foreground().spawn(async move {
+            task.await?;
+            Ok(())
+        }))
     }
 
-    pub fn close_clean_items(
+    pub fn close_items_to_the_left(
         workspace: &mut Workspace,
-        _: &CloseCleanItems,
+        _: &CloseItemsToTheLeft,
         cx: &mut ViewContext<Workspace>,
     ) -> Option<Task<Result<()>>> {
-        Self::close_main(workspace, ItemType::Clean, cx)
+        let pane_handle = workspace.active_pane().clone();
+        let pane = pane_handle.read(cx);
+        let active_item_id = pane.items[pane.active_item_index].id();
+
+        let item_ids: Vec<_> = pane
+            .items()
+            .take_while(|item| item.id() != active_item_id)
+            .map(|item| item.id())
+            .collect();
+
+        let task = Self::close_items(workspace, pane_handle, cx, move |item_id| {
+            item_ids.contains(&item_id)
+        });
+
+        Some(cx.foreground().spawn(async move {
+            task.await?;
+            Ok(())
+        }))
     }
 
-    fn close_main(
+    pub fn close_items_to_the_right(
         workspace: &mut Workspace,
-        close_item_type: ItemType,
+        _: &CloseItemsToTheRight,
         cx: &mut ViewContext<Workspace>,
     ) -> Option<Task<Result<()>>> {
         let pane_handle = workspace.active_pane().clone();
         let pane = pane_handle.read(cx);
-        if pane.items.is_empty() {
-            return None;
-        }
-
         let active_item_id = pane.items[pane.active_item_index].id();
-        let clean_item_ids: Vec<_> = pane
+
+        let item_ids: Vec<_> = pane
             .items()
-            .filter(|item| !item.is_dirty(cx))
+            .rev()
+            .take_while(|item| item.id() != active_item_id)
             .map(|item| item.id())
             .collect();
-        let task =
-            Self::close_items(
-                workspace,
-                pane_handle,
-                cx,
-                move |item_id| match close_item_type {
-                    ItemType::Active => item_id == active_item_id,
-                    ItemType::Inactive => item_id != active_item_id,
-                    ItemType::Clean => clean_item_ids.contains(&item_id),
-                    ItemType::All => true,
-                },
-            );
+
+        let task = Self::close_items(workspace, pane_handle, cx, move |item_id| {
+            item_ids.contains(&item_id)
+        });
+
+        Some(cx.foreground().spawn(async move {
+            task.await?;
+            Ok(())
+        }))
+    }
+
+    pub fn close_all_items(
+        workspace: &mut Workspace,
+        _: &CloseAllItems,
+        cx: &mut ViewContext<Workspace>,
+    ) -> Option<Task<Result<()>>> {
+        let pane_handle = workspace.active_pane().clone();
+
+        let task = Self::close_items(workspace, pane_handle, cx, move |_| true);
 
         Some(cx.foreground().spawn(async move {
             task.await?;
@@ -1037,7 +1094,7 @@ impl Pane {
     pub fn autosave_item(
         item: &dyn ItemHandle,
         project: ModelHandle<Project>,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> Task<Result<()>> {
         if Self::can_autosave_item(item, cx) {
             item.save(project, cx)
@@ -1683,15 +1740,15 @@ fn render_tab_bar_button<A: Action + Clone>(
 }
 
 impl ItemNavHistory {
-    pub fn push<D: 'static + Any>(&self, data: Option<D>, cx: &mut MutableAppContext) {
+    pub fn push<D: 'static + Any>(&self, data: Option<D>, cx: &mut AppContext) {
         self.history.borrow_mut().push(data, self.item.clone(), cx);
     }
 
-    pub fn pop_backward(&self, cx: &mut MutableAppContext) -> Option<NavigationEntry> {
+    pub fn pop_backward(&self, cx: &mut AppContext) -> Option<NavigationEntry> {
         self.history.borrow_mut().pop(NavigationMode::GoingBack, cx)
     }
 
-    pub fn pop_forward(&self, cx: &mut MutableAppContext) -> Option<NavigationEntry> {
+    pub fn pop_forward(&self, cx: &mut AppContext) -> Option<NavigationEntry> {
         self.history
             .borrow_mut()
             .pop(NavigationMode::GoingForward, cx)
@@ -1711,7 +1768,7 @@ impl NavHistory {
         self.mode = NavigationMode::Normal;
     }
 
-    fn pop(&mut self, mode: NavigationMode, cx: &mut MutableAppContext) -> Option<NavigationEntry> {
+    fn pop(&mut self, mode: NavigationMode, cx: &mut AppContext) -> Option<NavigationEntry> {
         let entry = match mode {
             NavigationMode::Normal | NavigationMode::Disabled | NavigationMode::ClosingItem => {
                 return None
@@ -1731,7 +1788,7 @@ impl NavHistory {
         &mut self,
         data: Option<D>,
         item: Rc<dyn WeakItemHandle>,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) {
         match self.mode {
             NavigationMode::Disabled => {}
@@ -1776,7 +1833,7 @@ impl NavHistory {
         self.did_update(cx);
     }
 
-    fn did_update(&self, cx: &mut MutableAppContext) {
+    fn did_update(&self, cx: &mut AppContext) {
         if let Some(pane) = self.pane.upgrade(cx) {
             cx.defer(move |cx| pane.update(cx, |pane, cx| pane.history_updated(cx)));
         }
@@ -1830,7 +1887,7 @@ impl Element for PaneBackdrop {
         let child_view_id = self.child_view;
         cx.scene.push_mouse_region(
             MouseRegion::new::<Self>(child_view_id, 0, visible_bounds).on_down(
-                gpui::MouseButton::Left,
+                gpui::platform::MouseButton::Left,
                 move |_, cx| {
                     let window_id = cx.window_id;
                     cx.focus(window_id, Some(child_view_id))

crates/workspace/src/pane/dragged_item_receiver.rs šŸ”—

@@ -3,9 +3,9 @@ use gpui::{
     color::Color,
     elements::{Canvas, MouseEventHandler, ParentElement, Stack},
     geometry::{rect::RectF, vector::Vector2F},
+    platform::MouseButton,
     scene::MouseUp,
-    AppContext, Element, ElementBox, EventContext, MouseButton, MouseState, Quad, RenderContext,
-    WeakViewHandle,
+    AppContext, Element, ElementBox, EventContext, MouseState, Quad, RenderContext, WeakViewHandle,
 };
 use project::ProjectEntryId;
 use settings::Settings;

crates/workspace/src/pane_group.rs šŸ”—

@@ -4,7 +4,8 @@ use call::{ActiveCall, ParticipantLocation};
 use gpui::{
     elements::*,
     geometry::{rect::RectF, vector::Vector2F},
-    Axis, Border, CursorStyle, ModelHandle, MouseButton, RenderContext, ViewHandle,
+    platform::{CursorStyle, MouseButton},
+    Axis, Border, ModelHandle, RenderContext, ViewHandle,
 };
 use project::Project;
 use serde::Deserialize;

crates/workspace/src/persistence.rs šŸ”—

@@ -6,7 +6,7 @@ use std::path::Path;
 
 use anyhow::{anyhow, bail, Context, Result};
 use db::{define_connection, query, sqlez::connection::Connection, sqlez_macros::sql};
-use gpui::{Axis, WindowBounds};
+use gpui::{platform::WindowBounds, Axis};
 
 use util::{unzip_option, ResultExt};
 use uuid::Uuid;
@@ -566,7 +566,7 @@ mod tests {
                     CREATE TABLE test_table(
                         text TEXT,
                         workspace_id INTEGER,
-                        FOREIGN KEY(workspace_id) 
+                        FOREIGN KEY(workspace_id)
                             REFERENCES workspaces(workspace_id)
                         ON DELETE CASCADE
                     ) STRICT;)],

crates/workspace/src/persistence/model.rs šŸ”—

@@ -6,7 +6,7 @@ use std::{
 use anyhow::{Context, Result};
 
 use async_recursion::async_recursion;
-use gpui::{AsyncAppContext, Axis, ModelHandle, Task, ViewHandle, WindowBounds};
+use gpui::{platform::WindowBounds, AsyncAppContext, Axis, ModelHandle, Task, ViewHandle};
 
 use db::sqlez::{
     bindable::{Bind, Column, StaticColumnCount},

crates/workspace/src/searchable.rs šŸ”—

@@ -1,8 +1,8 @@
 use std::any::Any;
 
 use gpui::{
-    AnyViewHandle, AnyWeakViewHandle, AppContext, MutableAppContext, Subscription, Task,
-    ViewContext, ViewHandle, WeakViewHandle,
+    AnyViewHandle, AnyWeakViewHandle, AppContext, Subscription, Task, ViewContext, ViewHandle,
+    WeakViewHandle,
 };
 use project::search::SearchQuery;
 
@@ -90,34 +90,29 @@ pub trait SearchableItemHandle: ItemHandle {
     fn supported_options(&self) -> SearchOptions;
     fn subscribe_to_search_events(
         &self,
-        cx: &mut MutableAppContext,
-        handler: Box<dyn Fn(SearchEvent, &mut MutableAppContext)>,
+        cx: &mut AppContext,
+        handler: Box<dyn Fn(SearchEvent, &mut AppContext)>,
     ) -> Subscription;
-    fn clear_matches(&self, cx: &mut MutableAppContext);
-    fn update_matches(&self, matches: &Vec<Box<dyn Any + Send>>, cx: &mut MutableAppContext);
-    fn query_suggestion(&self, cx: &mut MutableAppContext) -> String;
-    fn activate_match(
-        &self,
-        index: usize,
-        matches: &Vec<Box<dyn Any + Send>>,
-        cx: &mut MutableAppContext,
-    );
+    fn clear_matches(&self, cx: &mut AppContext);
+    fn update_matches(&self, matches: &Vec<Box<dyn Any + Send>>, cx: &mut AppContext);
+    fn query_suggestion(&self, cx: &mut AppContext) -> String;
+    fn activate_match(&self, index: usize, matches: &Vec<Box<dyn Any + Send>>, cx: &mut AppContext);
     fn match_index_for_direction(
         &self,
         matches: &Vec<Box<dyn Any + Send>>,
         current_index: usize,
         direction: Direction,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> usize;
     fn find_matches(
         &self,
         query: SearchQuery,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> Task<Vec<Box<dyn Any + Send>>>;
     fn active_match_index(
         &self,
         matches: &Vec<Box<dyn Any + Send>>,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> Option<usize>;
 }
 
@@ -136,8 +131,8 @@ impl<T: SearchableItem> SearchableItemHandle for ViewHandle<T> {
 
     fn subscribe_to_search_events(
         &self,
-        cx: &mut MutableAppContext,
-        handler: Box<dyn Fn(SearchEvent, &mut MutableAppContext)>,
+        cx: &mut AppContext,
+        handler: Box<dyn Fn(SearchEvent, &mut AppContext)>,
     ) -> Subscription {
         cx.subscribe(self, move |_, event, cx| {
             if let Some(search_event) = T::to_search_event(event) {
@@ -146,21 +141,21 @@ impl<T: SearchableItem> SearchableItemHandle for ViewHandle<T> {
         })
     }
 
-    fn clear_matches(&self, cx: &mut MutableAppContext) {
+    fn clear_matches(&self, cx: &mut AppContext) {
         self.update(cx, |this, cx| this.clear_matches(cx));
     }
-    fn update_matches(&self, matches: &Vec<Box<dyn Any + Send>>, cx: &mut MutableAppContext) {
+    fn update_matches(&self, matches: &Vec<Box<dyn Any + Send>>, cx: &mut AppContext) {
         let matches = downcast_matches(matches);
         self.update(cx, |this, cx| this.update_matches(matches, cx));
     }
-    fn query_suggestion(&self, cx: &mut MutableAppContext) -> String {
+    fn query_suggestion(&self, cx: &mut AppContext) -> String {
         self.update(cx, |this, cx| this.query_suggestion(cx))
     }
     fn activate_match(
         &self,
         index: usize,
         matches: &Vec<Box<dyn Any + Send>>,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) {
         let matches = downcast_matches(matches);
         self.update(cx, |this, cx| this.activate_match(index, matches, cx));
@@ -170,7 +165,7 @@ impl<T: SearchableItem> SearchableItemHandle for ViewHandle<T> {
         matches: &Vec<Box<dyn Any + Send>>,
         current_index: usize,
         direction: Direction,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> usize {
         let matches = downcast_matches(matches);
         self.update(cx, |this, cx| {
@@ -180,7 +175,7 @@ impl<T: SearchableItem> SearchableItemHandle for ViewHandle<T> {
     fn find_matches(
         &self,
         query: SearchQuery,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> Task<Vec<Box<dyn Any + Send>>> {
         let matches = self.update(cx, |this, cx| this.find_matches(query, cx));
         cx.foreground().spawn(async {
@@ -194,7 +189,7 @@ impl<T: SearchableItem> SearchableItemHandle for ViewHandle<T> {
     fn active_match_index(
         &self,
         matches: &Vec<Box<dyn Any + Send>>,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> Option<usize> {
         let matches = downcast_matches(matches);
         self.update(cx, |this, cx| this.active_match_index(matches, cx))

crates/workspace/src/shared_screen.rs šŸ”—

@@ -8,7 +8,8 @@ use futures::StreamExt;
 use gpui::{
     elements::*,
     geometry::{rect::RectF, vector::vec2f},
-    AppContext, Entity, MouseButton, RenderContext, Task, View, ViewContext,
+    platform::MouseButton,
+    AppContext, Entity, RenderContext, Task, View, ViewContext,
 };
 use settings::Settings;
 use smallvec::SmallVec;
@@ -75,7 +76,7 @@ impl View for SharedScreen {
                         vec2f(frame.width() as f32, frame.height() as f32),
                     );
                     let origin = bounds.origin() + (bounds.size() / 2.) - size / 2.;
-                    cx.scene.push_surface(gpui::mac::Surface {
+                    cx.scene.push_surface(gpui::platform::mac::Surface {
                         bounds: RectF::new(origin, size),
                         image_buffer: frame.image(),
                     });

crates/workspace/src/sidebar.rs šŸ”—

@@ -1,7 +1,7 @@
 use crate::StatusItemView;
 use gpui::{
-    elements::*, impl_actions, platform::CursorStyle, AnyViewHandle, AppContext, Entity,
-    MouseButton, RenderContext, Subscription, View, ViewContext, ViewHandle,
+    elements::*, impl_actions, platform::CursorStyle, platform::MouseButton, AnyViewHandle,
+    AppContext, Entity, RenderContext, Subscription, View, ViewContext, ViewHandle,
 };
 use serde::Deserialize;
 use settings::Settings;

crates/workspace/src/status_bar.rs šŸ”—

@@ -8,9 +8,8 @@ use gpui::{
         vector::{vec2f, Vector2F},
     },
     json::{json, ToJson},
-    AnyViewHandle, DebugContext, ElementBox, Entity, LayoutContext, MeasurementContext,
-    MutableAppContext, PaintContext, RenderContext, SizeConstraint, Subscription, View,
-    ViewContext, ViewHandle,
+    AnyViewHandle, AppContext, DebugContext, ElementBox, Entity, LayoutContext, MeasurementContext,
+    PaintContext, RenderContext, SizeConstraint, Subscription, View, ViewContext, ViewHandle,
 };
 use settings::Settings;
 
@@ -24,11 +23,7 @@ pub trait StatusItemView: View {
 
 trait StatusItemViewHandle {
     fn as_any(&self) -> &AnyViewHandle;
-    fn set_active_pane_item(
-        &self,
-        active_pane_item: Option<&dyn ItemHandle>,
-        cx: &mut MutableAppContext,
-    );
+    fn set_active_pane_item(&self, active_pane_item: Option<&dyn ItemHandle>, cx: &mut AppContext);
 }
 
 pub struct StatusBar {
@@ -130,11 +125,7 @@ impl<T: StatusItemView> StatusItemViewHandle for ViewHandle<T> {
         self
     }
 
-    fn set_active_pane_item(
-        &self,
-        active_pane_item: Option<&dyn ItemHandle>,
-        cx: &mut MutableAppContext,
-    ) {
+    fn set_active_pane_item(&self, active_pane_item: Option<&dyn ItemHandle>, cx: &mut AppContext) {
         self.update(cx, |this, cx| {
             this.set_active_pane_item(active_pane_item, cx)
         });

crates/workspace/src/toolbar.rs šŸ”—

@@ -1,7 +1,7 @@
 use crate::{ItemHandle, Pane};
 use gpui::{
-    elements::*, platform::CursorStyle, Action, AnyViewHandle, AppContext, ElementBox, Entity,
-    MouseButton, MutableAppContext, RenderContext, View, ViewContext, ViewHandle, WeakViewHandle,
+    elements::*, platform::CursorStyle, platform::MouseButton, Action, AnyViewHandle, AppContext,
+    ElementBox, Entity, RenderContext, View, ViewContext, ViewHandle, WeakViewHandle,
 };
 use settings::Settings;
 
@@ -21,7 +21,7 @@ pub trait ToolbarItemView: View {
         current_location
     }
 
-    fn pane_focus_update(&mut self, _pane_focused: bool, _cx: &mut MutableAppContext) {}
+    fn pane_focus_update(&mut self, _pane_focused: bool, _cx: &mut AppContext) {}
 }
 
 trait ToolbarItemViewHandle {
@@ -30,9 +30,9 @@ trait ToolbarItemViewHandle {
     fn set_active_pane_item(
         &self,
         active_pane_item: Option<&dyn ItemHandle>,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> ToolbarItemLocation;
-    fn pane_focus_update(&mut self, pane_focused: bool, cx: &mut MutableAppContext);
+    fn pane_focus_update(&mut self, pane_focused: bool, cx: &mut AppContext);
 }
 
 #[derive(Copy, Clone, Debug, PartialEq)]
@@ -263,7 +263,7 @@ impl Toolbar {
         }
     }
 
-    pub fn pane_focus_update(&mut self, pane_focused: bool, cx: &mut MutableAppContext) {
+    pub fn pane_focus_update(&mut self, pane_focused: bool, cx: &mut AppContext) {
         for (toolbar_item, _) in self.items.iter_mut() {
             toolbar_item.pane_focus_update(pane_focused, cx);
         }
@@ -292,14 +292,14 @@ impl<T: ToolbarItemView> ToolbarItemViewHandle for ViewHandle<T> {
     fn set_active_pane_item(
         &self,
         active_pane_item: Option<&dyn ItemHandle>,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> ToolbarItemLocation {
         self.update(cx, |this, cx| {
             this.set_active_pane_item(active_pane_item, cx)
         })
     }
 
-    fn pane_focus_update(&mut self, pane_focused: bool, cx: &mut MutableAppContext) {
+    fn pane_focus_update(&mut self, pane_focused: bool, cx: &mut AppContext) {
         self.update(cx, |this, cx| this.pane_focus_update(pane_focused, cx));
     }
 }

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

@@ -40,11 +40,13 @@ use gpui::{
     },
     impl_actions, impl_internal_actions,
     keymap_matcher::KeymapContext,
-    platform::{CursorStyle, WindowOptions},
+    platform::{
+        CursorStyle, MouseButton, PathPromptOptions, Platform, PromptLevel, WindowBounds,
+        WindowOptions,
+    },
     Action, AnyModelHandle, AnyViewHandle, AppContext, AsyncAppContext, Entity, ModelContext,
-    ModelHandle, MouseButton, MutableAppContext, PathPromptOptions, Platform, PromptLevel,
-    RenderContext, SizeConstraint, Subscription, Task, View, ViewContext, ViewHandle,
-    WeakViewHandle, WindowBounds,
+    ModelHandle, RenderContext, SizeConstraint, Subscription, Task, View, ViewContext, ViewHandle,
+    WeakViewHandle,
 };
 use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ProjectItem};
 use language::LanguageRegistry;
@@ -245,12 +247,12 @@ impl_internal_actions!(
 );
 impl_actions!(workspace, [ActivatePane]);
 
-pub fn init(app_state: Arc<AppState>, cx: &mut MutableAppContext) {
+pub fn init(app_state: Arc<AppState>, cx: &mut AppContext) {
     pane::init(cx);
     dock::init(cx);
     notifications::init(cx);
 
-    cx.add_global_action(|_: &Open, cx: &mut MutableAppContext| {
+    cx.add_global_action(|_: &Open, cx: &mut AppContext| {
         let mut paths = cx.prompt_for_paths(PathPromptOptions {
             files: true,
             directories: true,
@@ -283,7 +285,7 @@ pub fn init(app_state: Arc<AppState>, cx: &mut MutableAppContext) {
     });
     cx.add_global_action({
         let app_state = Arc::downgrade(&app_state);
-        move |action: &OpenPaths, cx: &mut MutableAppContext| {
+        move |action: &OpenPaths, cx: &mut AppContext| {
             if let Some(app_state) = app_state.upgrade() {
                 open_paths(&action.paths, &app_state, None, cx).detach();
             }
@@ -315,7 +317,7 @@ pub fn init(app_state: Arc<AppState>, cx: &mut MutableAppContext) {
 
     cx.add_global_action({
         let app_state = Arc::downgrade(&app_state);
-        move |_: &NewWindow, cx: &mut MutableAppContext| {
+        move |_: &NewWindow, cx: &mut AppContext| {
             if let Some(app_state) = app_state.upgrade() {
                 open_new(&app_state, cx, |_, cx| cx.dispatch_action(NewFile)).detach();
             }
@@ -323,7 +325,7 @@ pub fn init(app_state: Arc<AppState>, cx: &mut MutableAppContext) {
     });
     cx.add_global_action({
         let app_state = Arc::downgrade(&app_state);
-        move |_: &NewFile, cx: &mut MutableAppContext| {
+        move |_: &NewFile, cx: &mut AppContext| {
             if let Some(app_state) = app_state.upgrade() {
                 open_new(&app_state, cx, |_, cx| cx.dispatch_action(NewFile)).detach();
             }
@@ -444,7 +446,7 @@ type ProjectItemBuilders = HashMap<
     TypeId,
     fn(ModelHandle<Project>, AnyModelHandle, &mut ViewContext<Pane>) -> Box<dyn ItemHandle>,
 >;
-pub fn register_project_item<I: ProjectItem>(cx: &mut MutableAppContext) {
+pub fn register_project_item<I: ProjectItem>(cx: &mut AppContext) {
     cx.update_default_global(|builders: &mut ProjectItemBuilders, _| {
         builders.insert(TypeId::of::<I::Item>(), |project, model, cx| {
             let item = model.downcast::<I::Item>().unwrap();
@@ -458,7 +460,7 @@ type FollowableItemBuilder = fn(
     ModelHandle<Project>,
     ViewId,
     &mut Option<proto::view::Variant>,
-    &mut MutableAppContext,
+    &mut AppContext,
 ) -> Option<Task<Result<Box<dyn FollowableItemHandle>>>>;
 type FollowableItemBuilders = HashMap<
     TypeId,
@@ -467,7 +469,7 @@ type FollowableItemBuilders = HashMap<
         fn(&AnyViewHandle) -> Box<dyn FollowableItemHandle>,
     ),
 >;
-pub fn register_followable_item<I: FollowableItem>(cx: &mut MutableAppContext) {
+pub fn register_followable_item<I: FollowableItem>(cx: &mut AppContext) {
     cx.update_default_global(|builders: &mut FollowableItemBuilders, _| {
         builders.insert(
             TypeId::of::<I>(),
@@ -494,7 +496,7 @@ type ItemDeserializers = HashMap<
         &mut ViewContext<Pane>,
     ) -> Task<Result<Box<dyn ItemHandle>>>,
 >;
-pub fn register_deserializable_item<I: Item>(cx: &mut MutableAppContext) {
+pub fn register_deserializable_item<I: Item>(cx: &mut AppContext) {
     cx.update_default_global(|deserializers: &mut ItemDeserializers, _cx| {
         if let Some(serialized_item_kind) = I::serialized_item_kind() {
             deserializers.insert(
@@ -524,7 +526,7 @@ pub struct AppState {
 
 impl AppState {
     #[cfg(any(test, feature = "test-support"))]
-    pub fn test(cx: &mut MutableAppContext) -> Arc<Self> {
+    pub fn test(cx: &mut AppContext) -> Arc<Self> {
         let settings = Settings::test(cx);
         cx.set_global(settings);
 
@@ -857,7 +859,7 @@ impl Workspace {
         abs_paths: Vec<PathBuf>,
         app_state: Arc<AppState>,
         requesting_window_id: Option<usize>,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> Task<(
         ViewHandle<Workspace>,
         Vec<Option<Result<Box<dyn ItemHandle>, anyhow::Error>>>,
@@ -1097,7 +1099,7 @@ impl Workspace {
         }
     }
 
-    pub fn close_global(_: &CloseWindow, cx: &mut MutableAppContext) {
+    pub fn close_global(_: &CloseWindow, cx: &mut AppContext) {
         let id = cx.window_ids().find(|&id| cx.window_is_active(id));
         if let Some(id) = id {
             //This can only get called when the window's project connection has been lost
@@ -1132,7 +1134,7 @@ impl Workspace {
         let window_id = cx.window_id();
         let workspace_count = cx
             .window_ids()
-            .flat_map(|window_id| cx.root_view::<Workspace>(window_id))
+            .filter_map(|window_id| cx.root_view(window_id)?.clone().downcast::<Workspace>())
             .count();
 
         cx.spawn(|this, mut cx| async move {
@@ -1313,7 +1315,7 @@ impl Workspace {
         project: ModelHandle<Project>,
         abs_path: &Path,
         visible: bool,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> Task<Result<(ModelHandle<Worktree>, ProjectPath)>> {
         let entry = project.update(cx, |project, cx| {
             project.find_or_create_local_worktree(abs_path, visible, cx)
@@ -1405,7 +1407,7 @@ impl Workspace {
         let project = self.project.clone();
         if let Some(item) = self.active_item(cx) {
             if !force_name_change && item.can_save(cx) {
-                if item.has_conflict(cx.as_ref()) {
+                if item.has_conflict(cx) {
                     const CONFLICT_MESSAGE: &str = "This file has changed on disk since you started editing it. Do you want to overwrite it?";
 
                     let mut answer = cx.prompt(
@@ -2669,7 +2671,7 @@ impl Workspace {
     fn load_from_serialized_workspace(
         workspace: WeakViewHandle<Workspace>,
         serialized_workspace: SerializedWorkspace,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) {
         cx.spawn(|mut cx| async move {
             if let Some(workspace) = workspace.upgrade(&cx) {
@@ -2990,15 +2992,15 @@ impl std::fmt::Debug for OpenPaths {
 pub struct WorkspaceCreated(WeakViewHandle<Workspace>);
 
 pub fn activate_workspace_for_project(
-    cx: &mut MutableAppContext,
+    cx: &mut AppContext,
     predicate: impl Fn(&mut Project, &mut ModelContext<Project>) -> bool,
 ) -> Option<ViewHandle<Workspace>> {
     for window_id in cx.window_ids().collect::<Vec<_>>() {
-        if let Some(workspace_handle) = cx.root_view::<Workspace>(window_id) {
+        if let Some(workspace_handle) = cx.root_view(window_id)?.downcast_ref::<Workspace>() {
             let project = workspace_handle.read(cx).project.clone();
             if project.update(cx, &predicate) {
                 cx.activate_window(window_id);
-                return Some(workspace_handle);
+                return Some(workspace_handle.clone());
             }
         }
     }
@@ -3014,7 +3016,7 @@ pub fn open_paths(
     abs_paths: &[PathBuf],
     app_state: &Arc<AppState>,
     requesting_window_id: Option<usize>,
-    cx: &mut MutableAppContext,
+    cx: &mut AppContext,
 ) -> Task<(
     ViewHandle<Workspace>,
     Vec<Option<Result<Box<dyn ItemHandle>, anyhow::Error>>>,
@@ -3066,7 +3068,7 @@ pub fn open_paths(
 
 pub fn open_new(
     app_state: &Arc<AppState>,
-    cx: &mut MutableAppContext,
+    cx: &mut AppContext,
     init: impl FnOnce(&mut Workspace, &mut ViewContext<Workspace>) + 'static,
 ) -> Task<()> {
     let task = Workspace::new_local(Vec::new(), app_state.clone(), None, cx);

crates/zed/src/languages/json.rs šŸ”—

@@ -2,7 +2,7 @@ use anyhow::{anyhow, Result};
 use async_trait::async_trait;
 use collections::HashMap;
 use futures::{future::BoxFuture, FutureExt, StreamExt};
-use gpui::MutableAppContext;
+use gpui::AppContext;
 use language::{LanguageRegistry, LanguageServerBinary, LanguageServerName, LspAdapter};
 use node_runtime::NodeRuntime;
 use serde_json::json;
@@ -125,7 +125,7 @@ impl LspAdapter for JsonLspAdapter {
 
     fn workspace_configuration(
         &self,
-        cx: &mut MutableAppContext,
+        cx: &mut AppContext,
     ) -> Option<BoxFuture<'static, serde_json::Value>> {
         let action_names = cx.all_action_names().collect::<Vec<_>>();
         let theme_names = self

crates/zed/src/languages/yaml.rs šŸ”—

@@ -1,7 +1,7 @@
 use anyhow::{anyhow, Result};
 use async_trait::async_trait;
 use futures::{future::BoxFuture, FutureExt, StreamExt};
-use gpui::MutableAppContext;
+use gpui::AppContext;
 use language::{LanguageServerBinary, LanguageServerName, LspAdapter};
 use node_runtime::NodeRuntime;
 use serde_json::Value;
@@ -99,10 +99,7 @@ impl LspAdapter for YamlLspAdapter {
         .log_err()
     }
 
-    fn workspace_configuration(
-        &self,
-        cx: &mut MutableAppContext,
-    ) -> Option<BoxFuture<'static, Value>> {
+    fn workspace_configuration(&self, cx: &mut AppContext) -> Option<BoxFuture<'static, Value>> {
         let settings = cx.global::<Settings>();
         Some(
             future::ready(serde_json::json!({

crates/zed/src/main.rs šŸ”—

@@ -14,7 +14,7 @@ use futures::{
     channel::{mpsc, oneshot},
     FutureExt, SinkExt, StreamExt,
 };
-use gpui::{Action, App, AssetSource, AsyncAppContext, MutableAppContext, Task, ViewContext};
+use gpui::{Action, App, AppContext, AssetSource, AsyncAppContext, Task, ViewContext};
 use isahc::{config::Configurable, Request};
 use language::LanguageRegistry;
 use log::LevelFilter;
@@ -336,7 +336,7 @@ fn init_panic_hook(app_version: String) {
         let message = match info.location() {
             Some(location) => {
                 format!(
-                    "thread '{}' panicked at '{}': {}:{}{:?}",
+                    "thread '{}' panicked at '{}'\n{}:{}\n{:?}",
                     thread,
                     payload,
                     location.file(),
@@ -345,7 +345,7 @@ fn init_panic_hook(app_version: String) {
                 )
             }
             None => format!(
-                "thread '{}' panicked at '{}'{:?}",
+                "thread '{}' panicked at '{}'\n{:?}",
                 thread, payload, backtrace
             ),
         };
@@ -370,7 +370,7 @@ fn init_panic_hook(app_version: String) {
     }));
 }
 
-fn upload_previous_panics(http: Arc<dyn HttpClient>, cx: &mut MutableAppContext) {
+fn upload_previous_panics(http: Arc<dyn HttpClient>, cx: &mut AppContext) {
     let diagnostics_telemetry = cx.global::<Settings>().telemetry_diagnostics();
 
     cx.background()

crates/zed/src/zed.rs šŸ”—

@@ -19,8 +19,8 @@ use gpui::{
     actions,
     geometry::vector::vec2f,
     impl_actions,
-    platform::{WindowBounds, WindowOptions},
-    AssetSource, Platform, PromptLevel, TitlebarOptions, ViewContext, WindowKind,
+    platform::{Platform, PromptLevel, TitlebarOptions, WindowBounds, WindowKind, WindowOptions},
+    AssetSource, ViewContext,
 };
 use language::Rope;
 pub use lsp;
@@ -72,16 +72,16 @@ actions!(
 
 const MIN_FONT_SIZE: f32 = 6.0;
 
-pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::MutableAppContext) {
+pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::AppContext) {
     terminal_button::init(cx);
     cx.add_action(about);
-    cx.add_global_action(|_: &Hide, cx: &mut gpui::MutableAppContext| {
+    cx.add_global_action(|_: &Hide, cx: &mut gpui::AppContext| {
         cx.platform().hide();
     });
-    cx.add_global_action(|_: &HideOthers, cx: &mut gpui::MutableAppContext| {
+    cx.add_global_action(|_: &HideOthers, cx: &mut gpui::AppContext| {
         cx.platform().hide_other_apps();
     });
-    cx.add_global_action(|_: &ShowAll, cx: &mut gpui::MutableAppContext| {
+    cx.add_global_action(|_: &ShowAll, cx: &mut gpui::AppContext| {
         cx.platform().unhide_other_apps();
     });
     cx.add_action(
@@ -367,10 +367,10 @@ pub fn build_window_options(
     }
 }
 
-fn restart(_: &Restart, cx: &mut gpui::MutableAppContext) {
+fn restart(_: &Restart, cx: &mut gpui::AppContext) {
     let mut workspaces = cx
         .window_ids()
-        .filter_map(|window_id| cx.root_view::<Workspace>(window_id))
+        .filter_map(|window_id| cx.root_view(window_id)?.clone().downcast::<Workspace>())
         .collect::<Vec<_>>();
 
     // If multiple windows have unsaved changes, and need a save prompt,
@@ -411,10 +411,10 @@ fn restart(_: &Restart, cx: &mut gpui::MutableAppContext) {
     .detach_and_log_err(cx);
 }
 
-fn quit(_: &Quit, cx: &mut gpui::MutableAppContext) {
+fn quit(_: &Quit, cx: &mut gpui::AppContext) {
     let mut workspaces = cx
         .window_ids()
-        .filter_map(|window_id| cx.root_view::<Workspace>(window_id))
+        .filter_map(|window_id| cx.root_view(window_id)?.clone().downcast::<Workspace>())
         .collect::<Vec<_>>();
 
     // If multiple windows have unsaved changes, and need a save prompt,
@@ -458,11 +458,7 @@ fn quit(_: &Quit, cx: &mut gpui::MutableAppContext) {
 fn about(_: &mut Workspace, _: &About, cx: &mut gpui::ViewContext<Workspace>) {
     let app_name = cx.global::<ReleaseChannel>().display_name();
     let version = env!("CARGO_PKG_VERSION");
-    cx.prompt(
-        gpui::PromptLevel::Info,
-        &format!("{app_name} {version}"),
-        &["OK"],
-    );
+    cx.prompt(PromptLevel::Info, &format!("{app_name} {version}"), &["OK"]);
 }
 
 fn open_config_file(
@@ -656,9 +652,7 @@ mod tests {
     use super::*;
     use assets::Assets;
     use editor::{scroll::autoscroll::Autoscroll, DisplayPoint, Editor};
-    use gpui::{
-        executor::Deterministic, AssetSource, MutableAppContext, TestAppContext, ViewHandle,
-    };
+    use gpui::{executor::Deterministic, AppContext, AssetSource, TestAppContext, ViewHandle};
     use language::LanguageRegistry;
     use node_runtime::NodeRuntime;
     use project::{Project, ProjectPath};
@@ -717,7 +711,11 @@ mod tests {
         cx.update(|cx| open_paths(&[PathBuf::from("/root/a")], &app_state, None, cx))
             .await;
         assert_eq!(cx.window_ids().len(), 1);
-        let workspace_1 = cx.root_view::<Workspace>(cx.window_ids()[0]).unwrap();
+        let workspace_1 = cx
+            .root_view(cx.window_ids()[0])
+            .unwrap()
+            .downcast::<Workspace>()
+            .unwrap();
         workspace_1.update(cx, |workspace, cx| {
             assert_eq!(workspace.worktrees(cx).count(), 2);
             assert!(workspace.left_sidebar().read(cx).is_open());
@@ -747,7 +745,12 @@ mod tests {
         })
         .await;
         assert_eq!(cx.window_ids().len(), 2);
-        let workspace_1 = cx.root_view::<Workspace>(window_id).unwrap();
+        let workspace_1 = cx
+            .root_view(window_id)
+            .unwrap()
+            .clone()
+            .downcast::<Workspace>()
+            .unwrap();
         workspace_1.read_with(cx, |workspace, cx| {
             assert_eq!(
                 workspace
@@ -775,7 +778,12 @@ mod tests {
         assert_eq!(cx.window_ids().len(), 1);
 
         // When opening the workspace, the window is not in a edited state.
-        let workspace = cx.root_view::<Workspace>(cx.window_ids()[0]).unwrap();
+        let workspace = cx
+            .root_view(cx.window_ids()[0])
+            .unwrap()
+            .clone()
+            .downcast::<Workspace>()
+            .unwrap();
         let editor = workspace.read_with(cx, |workspace, cx| {
             workspace
                 .active_item(cx)
@@ -842,7 +850,12 @@ mod tests {
             .await;
 
         let window_id = *cx.window_ids().first().unwrap();
-        let workspace = cx.root_view::<Workspace>(window_id).unwrap();
+        let workspace = cx
+            .root_view(window_id)
+            .unwrap()
+            .clone()
+            .downcast::<Workspace>()
+            .unwrap();
         let editor = workspace.update(cx, |workspace, cx| {
             workspace
                 .active_item(cx)
@@ -950,7 +963,7 @@ mod tests {
                     .read(cx)
                     .active_item()
                     .unwrap()
-                    .project_path(cx.as_ref()),
+                    .project_path(cx),
                 Some(file2.clone())
             );
         });
@@ -1251,7 +1264,7 @@ mod tests {
         // Edit the file and save it again. This time, there is no filename prompt.
         editor.update(cx, |editor, cx| {
             editor.handle_input(" there", cx);
-            assert!(editor.is_dirty(cx.as_ref()));
+            assert!(editor.is_dirty(cx));
         });
         let save_task = workspace.update(cx, |workspace, cx| workspace.save_active_item(false, cx));
         save_task.await.unwrap();
@@ -1311,7 +1324,7 @@ mod tests {
                 &languages::PLAIN_TEXT
             ));
             editor.handle_input("hi", cx);
-            assert!(editor.is_dirty(cx.as_ref()));
+            assert!(editor.is_dirty(cx));
         });
 
         // Save the buffer. This prompts for a filename.
@@ -1374,7 +1387,7 @@ mod tests {
             assert_ne!(pane_1, pane_2);
 
             let pane2_item = pane_2.read(cx).active_item().unwrap();
-            assert_eq!(pane2_item.project_path(cx.as_ref()), Some(file1.clone()));
+            assert_eq!(pane2_item.project_path(cx), Some(file1.clone()));
 
             pane2_item.downcast::<Editor>().unwrap().downgrade()
         });
@@ -1819,7 +1832,7 @@ mod tests {
     }
 
     #[gpui::test]
-    fn test_bundled_settings_and_themes(cx: &mut MutableAppContext) {
+    fn test_bundled_settings_and_themes(cx: &mut AppContext) {
         cx.platform()
             .fonts()
             .add_fonts(&[
@@ -1850,7 +1863,7 @@ mod tests {
     }
 
     #[gpui::test]
-    fn test_bundled_languages(cx: &mut MutableAppContext) {
+    fn test_bundled_languages(cx: &mut AppContext) {
         let mut languages = LanguageRegistry::test();
         languages.set_executor(cx.background().clone());
         let languages = Arc::new(languages);

styles/src/styleTree/editor.ts šŸ”—

@@ -103,8 +103,8 @@ export default function editor(colorScheme: ColorScheme) {
             modified: foreground(layer, "warning"),
             inserted: foreground(layer, "positive"),
             removedWidthEm: 0.275,
-            widthEm: 0.16,
-            cornerRadius: 0.05,
+            widthEm: 0.22,
+            cornerRadius: 0.2,
         },
         /** Highlights matching occurences of what is under the cursor
          * as well as matched brackets